/* Copyright (c) 2026, One Guy Hacking LLC. All rights reserved */
:root {
  /* Horizontal gutters. --nav-pad = main nav bar, --page-pad = page content.
     They step up only when the viewport can afford it (see the media queries
     below), so the toolbar keeps word-labeled buttons instead of going icon-only. */
  --nav-pad:12px; --page-pad:16px;
  /* Font size shared by buttons, chips, inputs and dropdowns so a row of
     controls reads as one line. Matches the button label size. */
  --control-font:14px;
  --accent:#1565c0; --ink:#111827; --muted:#6b7280; --line:#e5e7eb; --err:#b91c1c;
  /* The nav bar's colour, and the colour of every dropdown that hangs off it —
     one variable so the two can never drift apart (0.314). */
  --nav-bg:#f2e1b6;
  --grid-line:#444444; --cell-black:#000000;
  --cur:#ffde00; --act:#c6e2ff; --act-cross:#e3f1ff; --ok:#1565c0; --mark:#ffc9e0;
}
* { box-sizing: border-box; }
@media (min-width:1000px) { :root { --nav-pad:24px; --page-pad:36px; } }
@media (min-width:1280px) { :root { --nav-pad:0.5in; --page-pad:1in; } }
body { margin:0; font:16px/1.5 system-ui, sans-serif; color:var(--ink); }
#app { height:100vh; height:100dvh; display:flex; flex-direction:column; overflow:hidden; }
.chrome, .ph-wrap, .toolbar, .cluebar, .banner, .kbd { flex:0 0 auto; }
.muted { color:var(--muted); }
.chrome { z-index:20; background:#fff; }
.topbar { display:flex; justify-content:space-between; align-items:center; gap:12px; padding:10px 16px; border-bottom:1px solid var(--line); }
.chrome-left { font-weight:600; }
.topright { display:flex; align-items:center; gap:8px; }
.puzzle-title { font-weight:600; }
.version-pill { font-size:12px; color:var(--muted); border:1px solid var(--line); border-radius:999px; padding:1px 8px; }
.linkbtn { border:0; background:none; color:var(--accent); font:inherit; cursor:pointer; padding:4px 8px; }
/* Last resort when even the collapsed tabs do not fit: the bar scrolls
   sideways (0.314). No visible scrollbar — a bar with a scrollbar under it
   reads as a list. Children keep their natural width (flex:0 0 auto) so there
   is something to scroll; before this the tabs absorbed every squeeze and the
   bar never overflowed, so nothing could be reached by scrolling. */
.tabbar { display:flex; align-items:center; gap:8px; padding:6px var(--nav-pad); border-bottom:1px solid var(--line); background:var(--nav-bg); overflow-x:auto; scrollbar-width:none; }
.tabbar::-webkit-scrollbar { display:none; }
.tabbar > * { flex:0 0 auto; }
.brand { font-weight:800; font-size:17px; color:var(--ink); letter-spacing:.2px; white-space:nowrap; padding-right:4px; user-select:none; }
/* .tabs is the measured element: it is given the room left over by the brand
   and the right-hand group, and fitNavTabs compares the strip against it. */
.tabs { display:flex; align-items:center; gap:4px; flex:1 1 auto; min-width:0; }
.tabstrip { display:flex; gap:4px; }
/* Both of these must out-specify `.menu { display:inline-block }`, which is
   declared further down the file — an unqualified `.nav-overflow` ties with it
   on specificity and loses on source order, which is why the dropdown sat
   beside the full tab strip at 0.314 instead of hiding. Scoped to .tabs on
   purpose; do not simplify them back. */
.tabs .nav-overflow { display:none; }
.tabs.collapsed .tabstrip { display:none; }
.tabs.collapsed .nav-overflow { display:inline-block; }
.navright { display:flex; align-items:center; gap:10px; flex:0 0 auto; margin-left:auto; }
/* A nav-bar dropdown is the bar's colour THROUGHOUT (0.315) — the button as
   well as the panel it opens. At 0.314 only the panel was changed, which left
   the white pill in the bar that this was about in the first place. The border
   stays so it still reads as something you can press; hover darkens the bar
   colour rather than going grey. */
.navuser { display:inline-flex; align-items:center; gap:4px; border:1px solid var(--line); background:var(--nav-bg); font:inherit; cursor:pointer; padding:5px 10px; border-radius:8px; color:var(--ink); }
@media (hover:hover) { .navuser:hover { background:rgba(0,0,0,.07); } }
.navuser .icon { width:16px; height:16px; }
.tab { border:0; background:none; padding:10px 14px; font:inherit; color:var(--muted); cursor:pointer; border-radius:8px 8px 0 0; white-space:nowrap; }
@media (hover:hover) { .tab:hover { background:#f3f4f6; } }
.tab.active { color:var(--accent); font-weight:600; box-shadow:inset 0 -2px 0 var(--accent); }
.content { padding:24px var(--page-pad); flex:1 1 auto; min-height:0; overflow-y:auto; }
.content h1 { margin:0 0 12px; font-size:22px; }
.list { display:flex; flex-direction:column; gap:8px; }
.row { text-align:left; border:1px solid var(--line); background:#fff; border-radius:10px; padding:12px 14px; font:inherit; cursor:pointer; }
@media (hover:hover) { .row:hover { background:#f9fafb; } }
.row.done { border-color:var(--ok); }
.row-title { font-weight:600; }
.row-sub { font-size:13px; }
.gbtn { display:inline-flex; align-items:center; justify-content:center; height:31px; box-sizing:border-box; margin:8px 0; padding:0 16px; font:inherit; font-size:14px; line-height:1; color:#fff; background:var(--accent); border:0; border-radius:6px; cursor:pointer; }
@media (hover:hover) { .gbtn:hover { filter:brightness(.92); } }
.err { color:var(--err); }
.version { color:var(--muted); font-size:12px; margin-top:28px; }
.banner { background:var(--ok); color:#fff; text-align:center; padding:8px; font-weight:600; }
.banner.paused-banner { background:#374151; font-size:18px; letter-spacing:.3em; padding:14px; cursor:pointer; }
.cluebar { display:flex; align-items:center; gap:8px; padding:8px var(--page-pad); border-bottom:1px solid var(--line); background:#f9fafb; min-height:42px; }
.cluebar-nav { flex:0 0 auto; width:30px; height:30px; border:1px solid var(--line); background:#fff; border-radius:6px; font-size:20px; line-height:1; color:var(--accent); cursor:pointer; }
@media (hover:hover) { .cluebar-nav:hover { background:var(--accent); color:#fff; } }
.cluebar-body { flex:1 1 auto; min-width:0; cursor:pointer; display:flex; flex-wrap:wrap; align-items:baseline; gap:2px 10px; }
.cluebar-label { font-weight:700; color:var(--accent); }
.cluebar-annot { font-style:italic; color:var(--muted); }
.cluebar-annot::before { content:'\270E  '; color:var(--accent); font-style:normal; }
.ph-wrap { border-bottom:1px solid var(--line); }
.ph-line { display:flex; align-items:center; }
.puzzle-header { flex:1 1 auto; min-width:0; white-space:nowrap; overflow-x:auto; overflow-y:hidden; -webkit-overflow-scrolling:touch; scrollbar-width:none; padding:8px var(--page-pad); cursor:text; }
.puzzle-header::-webkit-scrollbar { display:none; }
.puzzle-header.dragging { cursor:grabbing; }
.ph-track { display:inline-flex; align-items:baseline; gap:10px; }
.ph-title { font-weight:600; }
.ph-author { font-size:14px; }
.toolbar { display:flex; align-items:center; gap:8px; padding:8px var(--page-pad); border-bottom:1px solid var(--line); }
.toolbar-left, .toolbar-right { display:flex; align-items:center; gap:8px; flex:1 1 0; }
.toolbar-right { justify-content:flex-end; }
.toolbar-center { display:flex; align-items:center; }
.tb-lead { display:flex; align-items:center; gap:8px; }
.tb-cosolve { flex:1 1 0; display:flex; justify-content:center; }
/* every toolbar button: outline by default, fills on hover; solid when active */
.tbtn { display:inline-flex; align-items:center; justify-content:center; gap:6px; height:31px; box-sizing:border-box; border:1px solid var(--accent); background:#fff; color:var(--accent); border-radius:6px; padding:0 10px; font:inherit; font-size:var(--control-font); line-height:1; cursor:pointer; }
@media (hover:hover) { .tbtn:hover { background:var(--accent); color:#fff; } }
.tbtn.on { background:var(--accent); color:#fff; }
.tbtn:disabled { border-color:var(--line); color:var(--muted); background:#fff; cursor:default; opacity:.55; }
.tbtn:disabled:hover { background:#fff; color:var(--muted); }
.icon-btn { padding:0 8px; }
.icon { width:16px; height:16px; display:block; }
.dropdown { padding-right:8px; }
.dropdown .icon { width:14px; height:14px; margin-left:-1px; }
.timer-btn { justify-content:center; }
.timer-btn.icon-only { min-width:auto; }
.timer { font-variant-numeric:tabular-nums; font-weight:600; }
.menu { position:relative; display:inline-block; }
.menu-pop { position:absolute; top:calc(100% + 4px); left:0; z-index:10; background:#fff; border:1px solid var(--line); border-radius:8px; box-shadow:0 6px 20px rgba(0,0,0,.12); min-width:150px; padding:4px; }
/* A dropdown hanging off the nav bar (0.314). FIXED, because the bar scrolls
   and a scroll container clips its absolute descendants in both axes; top and
   left are set by openNavPop from the button's live rectangle. Coloured to
   match the bar it belongs to rather than floating white above it. */
.menu-pop.navpop { position:fixed; top:auto; left:auto; right:auto; background:var(--nav-bg); z-index:60; }
.menu-pop.navpop .menu-item.active { color:var(--accent); font-weight:600; }
@media (hover:hover) { .menu-pop.navpop .menu-item:hover { background:rgba(0,0,0,.07); } }
.menu-dot { display:inline-block; width:8px; height:8px; border-radius:50%; background:var(--err); margin-left:8px; vertical-align:middle; }
.nav-overflow .tab-dot { top:2px; right:2px; }
.nav-overflow .navuser { position:relative; }
.menu-pop.hidden { display:none; }
.toolbar-right .menu-pop { left:auto; right:0; }
/* The assistant floats midway between the timer and the rest of the right group. */
.toolbar-right .assist-btn { margin-left:auto; margin-right:auto; }
.toolbar.compact .toolbar-right .assist-btn { margin-left:0; margin-right:0; }
/* Right-aligned when it is an ordinary absolute popup. A .navpop is not: it is
   fixed and openNavPop sets its coordinates, so it must not be pinned to the
   right edge of anything — hence :not(). Relying on source order for this was
   one edit away from breaking. */
.navright .menu-pop:not(.navpop) { left:auto; right:0; }
/* Also used for <a> items (the Policies menu), hence the explicit colour and
   the removed underline — a bare anchor here would not match the buttons. */
.menu-item { display:block; width:100%; text-align:left; border:0; background:none; padding:8px 10px; font:inherit; cursor:pointer; border-radius:6px; color:var(--ink); text-decoration:none; }
@media (hover:hover) { .menu-item:hover { background:#f3f4f6; } }
/* puzzle grid — square cells so a filled row never grows taller */
.puzzle { display:flex; gap:28px; padding:20px var(--page-pad); align-items:flex-start; flex:1 1 auto; min-height:0; overflow:hidden; }
.board { position:relative; display:grid; grid-template-columns:repeat(var(--cols), 1fr); box-sizing:content-box; width:calc(100% - 2px); border:1px solid var(--grid-line); user-select:none; align-self:flex-start; flex:0 0 auto; }
.cell { position:relative; aspect-ratio:1; overflow:hidden; border:1px solid var(--grid-line); background:#fff; display:flex; align-items:center; justify-content:center; cursor:pointer; user-select:none; -webkit-user-select:none; -webkit-touch-callout:none; touch-action:manipulation; }
.cell.wrong { background:#ffd0d0; }
.cell.black { background:var(--cell-black); cursor:default; }
.cell.active { background:var(--act); }
.cell.marked { background:var(--mark); }
.cell.cursor { background:var(--cur); }
.cell.wrong .cellfill { color:#c00000; }
.cell.pencil .cellfill { color:var(--muted); }
.clue-annot { display:block; font-style:italic; color:var(--muted); font-size:13px; margin:2px 0 0 18px; }
.clue-annot::before { content:'\270E  '; color:var(--accent); font-style:normal; }
.cell.revealed .cellfill { color:var(--accent); }
.cell.good .cellfill { color:var(--accent); }
.cell.revealed::after { content:''; position:absolute; top:0; right:0; width:0; height:0; border-top:7px solid var(--accent); border-left:7px solid transparent; }
.cellnum { position:absolute; top:1px; left:2px; font-size:calc(var(--cell-px, 34px) * 0.28); line-height:1; color:var(--muted); }
.cellfill { font-size:calc(var(--cell-px, 34px) * 0.62); line-height:1; font-weight:600; text-transform:uppercase; }
.cellfill.rebus { font-size:min(calc(var(--cell-px, 34px) * 0.62), calc(var(--cell-px, 34px) * 1.45 / var(--rebus-len, 1))); letter-spacing:-.03em; padding:0; overflow:hidden; white-space:nowrap; }
.clues { display:flex; gap:28px; flex:1 1 auto; min-width:240px; min-height:0; height:100%; }
.clues.side { flex-direction:row; }
.clues.stacked { flex-direction:column; }
.cluecol { flex:1 1 0; min-height:0; display:flex; flex-direction:column; }
.cluecol h2 { font-size:14px; text-transform:uppercase; letter-spacing:.04em; color:var(--muted); margin:0 0 8px; flex:0 0 auto; }
.cluelist { list-style:none; margin:0; padding:0 4px 0 0; font-size:14px; flex:1 1 auto; min-height:0; overflow-y:auto; }
.clue { padding:3px 6px; border-radius:6px; cursor:pointer; }
@media (hover:hover) { .clue:hover { background:rgba(128,128,128,.15); } }
.clue.active { background:var(--act); color:#000; }
.clue.cross  { background:var(--act-cross); color:#000; }
.clue.done { color:var(--muted); }
.cluenum { font-weight:600; }

.hidden { display:none; }
.modal-overlay { position:fixed; inset:0; background:rgba(0,0,0,.4); display:flex; align-items:center; justify-content:center; z-index:100; }
/* A notice (0.312) is the same box, but NOT a .modal-overlay: closeModals()
   sweeps that class, and a notice must survive whatever renders under it and go
   away only when its button is pressed. Sits above the rest for the same reason. */
.notice-overlay { position:fixed; inset:0; background:rgba(0,0,0,.4); display:flex; align-items:center; justify-content:center; z-index:120; padding:16px; }
.notice-modal { background:#fff; border-radius:12px; padding:20px 22px; width:min(620px, 94vw); max-height:86vh; overflow-y:auto; box-shadow:0 20px 60px rgba(0,0,0,.25); }
.notice-modal h3 { margin:0 0 12px; font-size:20px; }
.notice-modal p { margin:0; line-height:1.5; }
.notice-modal p + p { margin-top:14px; }
.notice-modal .setting-opt { display:flex; align-items:center; gap:8px; margin-top:18px; }
.notice-modal .modal-actions { display:flex; justify-content:flex-end; align-items:center; gap:8px; margin-top:16px; }
.modal { background:#fff; border-radius:12px; padding:20px 22px; width:min(360px, 92vw); box-shadow:0 20px 60px rgba(0,0,0,.25); }
.modal h3 { margin:0 0 8px; font-size:18px; }
.modal p { margin:0; }
.modal p + p { margin-top:14px; }   /* blank line between paragraphs in confirmations */
.modal-input { width:100%; box-sizing:border-box; font:inherit; font-size:20px; letter-spacing:.3em; text-align:center; padding:10px; border:1px solid var(--line); border-radius:8px; margin-top:6px; }
.prompt-input { width:100%; box-sizing:border-box; font:inherit; font-size:18px; padding:10px; border:1px solid var(--line); border-radius:8px; margin-top:6px; }
.prompt-input:focus { outline:none; border-color:var(--accent); box-shadow:0 0 0 2px rgba(21,101,192,.18); }
/* An empty or half-typed field is not an ERROR: red is reserved for failures.
   Browsers (Firefox especially) paint :invalid inputs red on their own, so the
   UA styling is explicitly overridden here. */
.prompt-input:invalid, .prompt-input:-moz-ui-invalid { border-color:var(--line); box-shadow:none; }
.prompt-input:invalid:focus, .prompt-input:-moz-ui-invalid:focus { border-color:var(--accent); box-shadow:0 0 0 2px rgba(21,101,192,.18); }
.prompt-input.upper { text-transform:uppercase; }
.modal-err { color:var(--err); font-size:13px; margin:8px 0 0; }
.modal-actions { display:flex; justify-content:flex-end; align-items:center; gap:8px; margin-top:16px; }
.modal-actions .tbtn, .modal-actions .gbtn { padding:0 16px; margin:0; }

.modal-wide { width:min(760px, 95vw); }
.settings-form { display:grid; grid-template-columns:1fr 1fr; gap:12px 18px; margin-top:10px; }
.setting-group { border:1px solid var(--line); border-radius:8px; padding:8px 10px; margin:0; }
.setting-group legend { font-size:12px; font-weight:600; color:var(--muted); padding:0 4px; }
.setting-opt { display:block; font-size:14px; padding:2px 0; cursor:pointer; }
.setting-opt input { margin-right:4px; }
@media (max-width:540px) { .settings-form { grid-template-columns:1fr; } }

.end-btn { border-color:var(--err); color:var(--err); }
@media (hover:hover) { .end-btn:hover { background:var(--err); color:#fff; } }
.grid-area { display:flex; flex-direction:column; flex:0 0 auto; align-self:flex-start; }
.copyright { font-size:12px; font-style:italic; color:var(--ink); text-align:left; margin-top:8px; max-width:min(560px, 92vw); }
.note-toggle { display:inline-flex; align-items:center; gap:6px; margin-left:auto; flex:0 0 auto; border:0; background:none; font:inherit; font-weight:600; color:var(--accent); cursor:pointer; padding:8px var(--page-pad); white-space:nowrap; }
.note-caret { width:16px; height:16px; transition:transform .2s ease; }
.note-toggle.collapsed .note-caret { transform:rotate(-90deg); }
.note-body { padding:6px var(--page-pad) 10px; font-style:italic; color:var(--muted); }
.note-body.collapsed { display:none; }
.note-body-inner { font-style:italic; }
.menu-item:disabled { color:var(--muted); cursor:default; background:none; }
.menu-item:disabled:hover { background:none; }

.cell.circled::before { content:''; position:absolute; inset:7%; border:1.5px solid rgba(0,0,0,.5); border-radius:50%; pointer-events:none; }
/* Barred crosswords: heavy walls on a cell's right / bottom edge instead of
   black squares. Drawn as an inset shadow so they never affect layout and clip
   at the cell edge (the cell has overflow:hidden). */
/* Barred crosswords: all walls drawn in one SVG overlay stretched over the whole
   board (grid-unit coordinates), so bars sit centred on the shared boundary and
   perpendicular bars meet in a squared corner. */
.board-bars { position:absolute; inset:0; width:100%; height:100%; pointer-events:none; z-index:3; }

.toast-host { position:fixed; top:20px; left:24px; z-index:1000; display:flex; flex-direction:column; gap:8px; max-width:min(360px, 92vw); }
.toast { background:#fff; border:1px solid var(--line); border-left-width:4px; border-radius:6px; padding:10px 14px; font-size:14px; line-height:1.35; box-shadow:0 2px 12px rgba(0,0,0,.16); opacity:0; transform:translateX(-12px); transition:opacity .2s ease, transform .2s ease; cursor:pointer; }
.toast.show { opacity:1; transform:none; }
.toast-success, .toast-info { color:var(--ink); border-left-color:#555; }
.toast-warning { color:#8a5a00; border-left-color:#f0ad4e; }
.toast-error   { color:#b00020; border-left-color:#d32f2f; }


/* small + medium screens: Android-style single-clue layout (no full clue lists) */
@media (max-width: 900px) {
  .cellfill { transform: translateY(0.12em); }
  .clues { display:none; }
  .puzzle { flex-direction:column; padding:12px; align-items:center; overflow:auto; }
  .grid-area { align-self:center; }
  .board { width:min(96vw, 68vh); }
  .cluebar { position:sticky; top:0; z-index:5; }
  .cluebar-text { font-size:15px; }
}

.kbd { background:#dfe3e8; padding:6px 4px calc(6px + env(safe-area-inset-bottom, 0px)); display:flex; flex-direction:column; gap:6px; user-select:none; -webkit-user-select:none; }
.kbd-row { display:flex; gap:5px; justify-content:center; }
.kbd-key { flex:1 1 0; max-width:46px; height:46px; padding:0; border:0; border-radius:6px; background:#fff; box-shadow:0 1px 1.5px rgba(0,0,0,.3); font:600 18px/1 system-ui, sans-serif; color:var(--ink); cursor:pointer; touch-action:manipulation; }
.kbd-key.wide { flex:1.6 1 0; max-width:70px; font-size:20px; }
.kbd-key:active { background:#c9ced4; }
.kbd-key:disabled { opacity:.4; }

.dual-btn { display:inline-flex; align-items:center; }
.tb-ico { display:none; }
.tb-ico .icon { display:block; }
.toolbar.compact .tb-lbl { display:none; }
.toolbar.compact .tb-ico { display:inline-flex; align-items:center; }
/* timer is inverse: pause/play icon shows on wide, hides when compact */
.timer-btn .tb-ico { display:inline-flex; align-items:center; }
.toolbar.compact .timer-btn .tb-ico { display:none; }

.toolbar.compact { gap:5px; padding-left:8px; padding-right:8px; }
.toolbar.compact .tbtn { padding:0 7px; gap:4px; }
.toolbar.compact .dual-btn { padding:0 6px; }

.modal.has-kbd { width:min(96vw, 520px); }
.modal-kbd { margin-top:12px; background:transparent; padding:0; }

/* Friends tab */
.friends-card { border:1px solid var(--line); border-radius:10px; padding:14px; margin-bottom:16px; max-width:640px; }
.friends-card-label { font-size:13px; margin-bottom:8px; }
.code-row { display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.code-value { font-size:22px; font-weight:600; letter-spacing:1px; font-family:ui-monospace, SFMono-Regular, Menlo, monospace; }
.code-tag { font-size:12px; border:1px solid var(--line); border-radius:999px; padding:1px 8px; }
.friends-actions { display:flex; gap:8px; flex-wrap:wrap; margin-top:12px; }
.friends-actions .tbtn { margin:0; }
.add-row { display:flex; gap:8px; align-items:center; max-width:640px; }
.add-row .prompt-input { margin-top:0; font-size:16px; }
.add-row .gbtn, .add-row .tbtn { margin:0; flex:0 0 auto; }
.friends-h { font-size:16px; margin:22px 0 10px; }
.friend-row { display:flex; align-items:center; justify-content:space-between; gap:12px; border:1px solid var(--line); background:#fff; border-radius:10px; padding:10px 14px; max-width:640px; }
.friend-info { min-width:0; display:flex; flex-direction:column; gap:2px; }
.friend-name { font-weight:600; display:flex; align-items:center; gap:8px; }
.friend-sub { font-size:13px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.friend-muted-tag { font-size:11px; font-weight:400; border:1px solid var(--line); border-radius:999px; padding:0 7px; }
.friend-actions { display:flex; gap:6px; flex:0 0 auto; }
.mini-btn { height:28px; padding:0 10px; font:inherit; font-size:13px; line-height:1; border:1px solid var(--line); background:#fff; color:var(--ink); border-radius:6px; cursor:pointer; }
.mini-btn.danger { border-color:var(--err); color:var(--err); }
@media (hover:hover) { .mini-btn:hover { background:#f3f4f6; } .mini-btn.danger:hover { background:#fef2f2; } }

/* Friends tab: subtabs + invitations layout */
.subtab-bar { display:flex; gap:2px; border-bottom:1px solid var(--line); margin:6px 0 20px; }
.subtab { appearance:none; background:transparent; border:none; border-bottom:2px solid transparent; margin-bottom:-1px; padding:8px 16px; font:inherit; font-size:15px; color:var(--muted); cursor:pointer; }
.subtab:hover { color:var(--ink); }
.subtab.active { color:var(--ink); font-weight:600; border-bottom-color:var(--accent); }
.inv-section { margin-bottom:20px; }
.inv-section + .inv-section { border-top:1px solid var(--line); padding-top:18px; }
.field-label { font-weight:700; font-size:15px; margin:0 0 10px; }
.personal-code-row { display:flex; align-items:center; flex-wrap:wrap; gap:10px; margin-bottom:10px; }
.personal-code-label { font-weight:700; }
.personal-code { font-family:ui-monospace, SFMono-Regular, Menlo, monospace; font-weight:700; font-size:18px; letter-spacing:.18em; padding:6px 12px; border:1px solid var(--line); background:#f9fafb; color:var(--ink); border-radius:6px; cursor:pointer; }
.personal-code.empty { cursor:default; color:var(--muted); letter-spacing:.3em; }
@media (hover:hover) { .personal-code:not(.empty):hover { background:#eef2ff; } }
.help-italic { font-style:italic; color:var(--muted); font-size:13px; line-height:1.5; max-width:60ch; margin:0 0 12px; }
.empty-none { font-style:italic; color:var(--muted); margin:0; }
.change-form { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-top:10px; }
.code-chip { font-family:ui-monospace, SFMono-Regular, Menlo, monospace; font-weight:600; letter-spacing:.1em; height:28px; padding:0 10px; border:1px solid var(--line); background:#f9fafb; color:var(--ink); border-radius:6px; cursor:pointer; }
@media (hover:hover) { .code-chip:hover { background:#eef2ff; } }

/* Series tab */
.series-head { display:flex; align-items:center; gap:12px; margin-bottom:4px; }
.series-head h1 { margin:0; margin-right:auto; }
.series-head .gbtn { margin:0; }
.linklike { appearance:none; background:none; border:none; padding:0; color:var(--accent); cursor:pointer; font:inherit; text-align:left; }
.linklike:hover { text-decoration:underline; }
.series-org { margin-top:-2px; }
.series-card { border:1px solid var(--line); border-radius:8px; padding:14px 16px; margin:14px 0; background:#f9fafb; }
.series-card .field-label { margin-bottom:10px; }
.series-members { font-style:italic; }
.role-badge { display:inline-block; margin-left:6px; font-size:11px; font-weight:600; padding:1px 6px; border-radius:4px; background:#eef2ff; color:var(--accent); vertical-align:middle; }
.status-badge { display:inline-block; margin-left:6px; font-size:11px; padding:1px 6px; border-radius:4px; vertical-align:middle; }
.status-badge.pending { background:#fff4e5; color:#8a5a00; }
.status-badge.declined { background:#fef2f2; color:var(--err); }
.picker { position:relative; }
.picker-menu { position:absolute; top:calc(100% + 2px); left:0; right:0; z-index:30; background:#fff; border:1px solid var(--line); border-radius:6px; box-shadow:0 6px 20px rgba(0,0,0,.12); max-height:240px; overflow-y:auto; }
.picker-menu.hidden { display:none; }
.picker-item { display:block; width:100%; text-align:left; padding:8px 12px; background:none; border:none; font:inherit; font-size:var(--control-font); cursor:pointer; }
.picker-item:hover { background:#f3f4f6; }
.member-chips { display:flex; flex-wrap:wrap; gap:6px; margin-top:8px; }
.member-chip { display:inline-flex; align-items:center; gap:6px; background:#eef2ff; border-radius:12px; padding:3px 6px 3px 10px; font-size:13px; }
.chip-x { appearance:none; background:none; border:none; cursor:pointer; font-size:16px; line-height:1; color:var(--muted); padding:0 2px; }
.field-label-sub { font-weight:600; font-size:13px; margin:12px 0 4px; }

/* ── Cosolve ─────────────────────────────────────────────────────────────── */
.cosolve-bar { display:flex; align-items:center; gap:12px; flex-wrap:wrap; padding:8px var(--page-pad); border-bottom:1px solid var(--line); margin-bottom:10px; }
.conn-badge { font-size:12px; font-weight:600; padding:2px 8px; border-radius:10px; background:#eef2ff; color:var(--accent); }
.conn-badge.conn-connected { background:#dcfce7; color:#166534; }
.conn-badge.conn-connecting { background:#fef9c3; color:#854d0e; }
.conn-badge.conn-closed, .conn-badge.conn-kicked, .conn-badge.conn-error { background:#fef2f2; color:var(--err); }
.participant-bar { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-right:auto; }
.cosolve-participant { display:inline-flex; align-items:center; gap:5px; font-size:var(--control-font); padding:2px 8px; border-radius:12px; background:#f3f4f6; }
.cosolve-participant.disconnected { opacity:1; }   /* the hollow marker carries the meaning, not dimmed text */
.cosolve-participant .pdot { width:9px; height:9px; border-radius:50%; display:inline-block; flex:0 0 auto; }
.peer-cursor { position:absolute; inset:1px; pointer-events:none; border-radius:2px; }
.cosolve-placeholder { display:flex; flex-direction:column; align-items:flex-start; gap:12px; padding:24px var(--page-pad); }

/* In Progress sections + unseen-invitation dot */
.tab { position:relative; }
.tab-dot { position:absolute; top:6px; right:6px; width:8px; height:8px; border-radius:50%; background:var(--err); }
.section-head { font-size:12px; text-transform:uppercase; letter-spacing:.05em; font-weight:700; color:var(--muted); margin:18px 0 6px; }
.content > .section-head:first-of-type { margin-top:10px; }

/* My Account modal */
.account-title { margin:0 0 12px; }
.account-row { display:flex; align-items:center; justify-content:space-between; gap:16px; padding:10px 0; border-bottom:1px solid var(--line); }
.account-label { font-size:13px; flex:0 0 auto; }
.account-value { display:flex; align-items:center; gap:10px; text-align:right; word-break:break-word; }
.account-name { font-weight:600; }
.account-actions { justify-content:space-between; }

/* Cosolve markers: hollow when disconnected, star for the primary (admins) */
.pdot { box-sizing:border-box; }
.pdot.hollow { background:transparent; border:1.5px solid; }
.pstar { font-size:var(--control-font); line-height:1; flex:0 0 auto; }
.timer-display { display:inline-flex; align-items:center; padding:6px 10px; }

/* Admin indicator (debug) */
.admin-pill { align-self:center; margin-left:6px; background:var(--err); color:#fff; font-size:11px; font-weight:700; letter-spacing:.06em; padding:2px 8px; border-radius:10px; }

/* Cosolve invite row */
.cosolve-invite { display:flex; align-items:center; gap:8px; margin-left:auto; flex:0 0 auto; }
.cosolve-invite .picker { position:relative; }
.cosolve-invite .prompt-input { width:180px; height:31px; box-sizing:border-box; padding:0 8px; font-size:var(--control-font); margin-top:0; border-radius:6px; }
.role-select { font:inherit; font-size:var(--control-font); height:31px; box-sizing:border-box; padding:0 6px; border:1px solid var(--line); border-radius:6px; background:#fff; }

/* ===================================================================
   Library bookcase (mirrors the old UI / Android BookshelfView).
   Brown case, three shelves, horizontally draggable book rows whose
   end-walls translate and clamp flush.
   =================================================================== */
.lib-head { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-bottom:12px; }
.lib-actions { display:flex; align-items:center; gap:8px; }
.lib-actions-right { margin-left:auto; }

.bookcase {
    --bc-wood: #5C3010;
    --bc-edge: #3A1E08;
    --bc-bg:   #2C1500;
    --bc-wall: 14px;
    --bc-book-w: 100px;
    --bc-book-h: 144px;
    --bc-gap: 12px;
    --bc-pad: 10px;
    --bc-plank-h: 30px;
    --bc-board-h: 24px;
    display: flex;
    flex-direction: column;
    background: var(--bc-bg);
    border-radius: 4px;
    overflow: hidden;
    box-shadow: 0 6px 20px rgba(0,0,0,.30);
    user-select: none;
    -webkit-user-select: none;
}
.bc-board { flex: 0 0 var(--bc-board-h); height: var(--bc-board-h); background: var(--bc-wood); }
.bc-board-top    { box-shadow: inset 0 -3px 0 var(--bc-edge); }
.bc-board-bottom { box-shadow: inset 0  3px 0 var(--bc-edge); }

.bc-shelf { position: relative; display: flex; flex-direction: column; }
.bc-shelf-viewport { position: relative; overflow: hidden; width: 100%; height: calc(var(--bc-book-h) + 6px); touch-action: pan-y; }
/* Written across the top shelf's book space. Absolute, over the track rather
   than after it: the track fills the viewport's whole height and the viewport
   clips, so a static note is pushed out of sight — which is exactly what
   happened between 0.282 and 0.284, when this rule was lost and only the
   element shipped. White, because the case interior is dark. */
.bc-empty-note { position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
                 margin:0; color:#fff; font-size:16px; text-shadow:0 1px 2px rgba(0,0,0,.45);
                 pointer-events:none; padding:0 var(--bc-wall); text-align:center; }
.bc-track {
    display: flex; align-items: flex-end; height: 100%;
    width: max-content; min-width: 100%;
    transition: transform .18s ease-out; will-change: transform;
}
.bc-shelf.bc-dragging .bc-track { transition: none; cursor: grabbing; }

.bc-wall { flex: 0 0 var(--bc-wall); width: var(--bc-wall); align-self: stretch; background: var(--bc-wood); }
.bc-wall-left  { box-shadow: inset -3px 0 0 var(--bc-edge); }
.bc-wall-right { box-shadow: inset  3px 0 0 var(--bc-edge); }

.bc-books { flex: 1 0 auto; display: flex; align-items: flex-end; gap: var(--bc-gap); padding: 0 var(--bc-pad) 0; min-height: 100%; }

.bc-plank {
    position: relative; height: var(--bc-plank-h); background: var(--bc-wood);
    display: flex; align-items: center; justify-content: center;
    box-shadow: inset 0 2px 0 rgba(255,255,255,.06), inset 0 -3px 0 var(--bc-edge);
}
.bc-plank-label { color:#fff; font-weight:700; font-size:.72rem; letter-spacing:.02em; text-shadow:0 1px 2px rgba(0,0,0,.45); }

.bc-filler {
    flex: 1 1 auto; min-height: 18px; background: var(--bc-bg);
    box-shadow: inset var(--bc-wall) 0 0 var(--bc-wood), inset calc(-1 * var(--bc-wall)) 0 0 var(--bc-wood);
}

.bc-book {
    flex: 0 0 var(--bc-book-w); width: var(--bc-book-w); height: var(--bc-book-h);
    margin-bottom: 2px; padding: 0; border: 0; border-radius: 3px;
    position: relative; overflow: hidden; background: transparent; cursor: pointer;
    box-shadow: 0 2px 4px rgba(0,0,0,.40); transition: transform .12s ease-out;
}
.bc-book:hover { transform: translateY(-3px); }
.bc-shelf.bc-dragging .bc-book { transition: none; }
.bc-shelf.bc-dragging .bc-book:hover { transform: none; }

.bc-book-cover { width:100%; height:100%; object-fit:cover; display:block; border-radius:3px; -webkit-user-drag:none; user-drag:none; }
.bc-book-colour {
    background: var(--cc, #444);
    box-shadow: 0 2px 4px rgba(0,0,0,.40), inset 0 4px 0 rgba(255,255,255,.16), inset 0 -6px 0 rgba(0,0,0,.26);
}
.bc-book-face { position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:flex-start; padding:14px 8px 10px; text-align:center; color:#fff; }
.bc-book-title { font-weight:700; font-size:.72rem; line-height:1.15; text-shadow:0 1px 2px rgba(0,0,0,.35); display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical; overflow:hidden; }
.bc-book-rule { width:70%; height:1px; background:rgba(255,255,255,.5); margin:.35rem 0 .3rem; }
.bc-book-author { font-size:.62rem; line-height:1.1; opacity:.92; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }

/* Grid / clues split: draggable divider (ported from the old UI) and a grid
   column that scrolls on its own when the viewport is too short. */
.puzzle { --grid-frac: 60%; }
.grid-area { flex:0 0 var(--grid-frac); min-width:0; min-height:0; max-height:100%; overflow-y:auto; overflow-x:hidden; scrollbar-gutter:stable; padding-right:2px; }
/* .board width is set above (content-box) so the divider resizes the puzzle. */
.grid-divider {
    flex:0 0 4px; width:4px; align-self:stretch; cursor:col-resize; background:#ccc;
    display:flex; align-items:center; justify-content:center;
    transition:background-color .12s; user-select:none; touch-action:none;
}
.grid-divider:hover, .grid-divider.dragging { background:var(--accent); }
.grid-divider-grip { color:#888; font-size:1rem; pointer-events:none; }
.clues { flex:1 1 auto; min-width:0; }
.placeholder-actions { display:flex; align-items:center; gap:8px; }
/* The divider is pointless without clue columns to trade against. */
@media (max-width:900px) { .grid-divider { display:none; } .grid-area { flex:1 1 auto; } }

/* Host / cohost menu on a participant chip */
.cosolve-participant.manageable { border:0; background:none; font:inherit; cursor:pointer; padding:2px 4px; border-radius:6px; }
.cosolve-participant.manageable:hover { background:rgba(0,0,0,.06); }
.participant-menu { position:fixed; z-index:60; min-width:170px; background:#fff; border:1px solid var(--line); border-radius:8px; box-shadow:0 8px 24px rgba(0,0,0,.16); padding:4px; }
.participant-menu .menu-head { font-size:12px; font-weight:700; color:var(--muted); padding:6px 10px 4px; }
.participant-menu .menu-item { display:block; width:100%; text-align:left; padding:8px 10px; background:none; border:0; font:inherit; font-size:var(--control-font); border-radius:6px; cursor:pointer; }
.participant-menu .menu-item:hover { background:rgba(0,0,0,.06); }
.participant-menu .menu-item.danger { color:var(--err); }

/* Spectators observe only: no pointer affordance on the grid. */
.board.readonly .cell { cursor:default; }
.participant-menu .menu-sep { height:1px; background:var(--line); margin:4px 6px; }

/* ── Book viewer ─────────────────────────────────────────────────────────────
   Ported from the old UI's open-book spread: cream pages, a leather spine, real
   grid thumbnails, solved overlays. */
.bv-root { display:flex; flex-direction:column; flex:1 1 auto; min-height:0; }
.bv-bar { flex:0 0 48px; display:flex; align-items:center; gap:12px; background:#D4C9A8; padding:0 var(--page-pad); color:#3A2A0A; }
.bv-close { border:0; background:transparent; color:#3A2A0A; font-size:.9rem; font-weight:600; cursor:pointer; padding:6px 8px; border-radius:6px; }
.bv-close:hover { background:rgba(0,0,0,.08); }
.bv-title { font-weight:700; font-size:.95rem; color:#3A2A0A; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.bv-spread { flex:1 1 auto; display:flex; min-height:0; background:#F5F0E8; padding:8px var(--page-pad); touch-action:none; }
.bv-page { flex:1 1 0; position:relative; min-width:0; background:#FAF6EE; overflow:hidden; box-shadow:0 1px 3px rgba(0,0,0,.15); }
.bv-spread.bv-wide .bv-page-left  { border-radius:6px 0 0 6px; }
.bv-spread.bv-wide .bv-page-right { border-radius:0 6px 6px 0; }
.bv-spread:not(.bv-wide) .bv-page { border-radius:6px; }
.bv-page-left::after { content:""; position:absolute; top:0; bottom:0; right:0; width:14px; background:linear-gradient(to left, rgba(0,0,0,.18), transparent); pointer-events:none; }
.bv-page-right::before { content:""; position:absolute; top:0; bottom:0; left:0; width:14px; background:linear-gradient(to right, rgba(0,0,0,.18), transparent); pointer-events:none; }
.bv-spine { flex:0 0 6px; background:#8B7355; }
.bv-grid { display:grid; gap:8px; padding:16px; align-content:start; height:100%; box-sizing:border-box; }
.bv-cell { display:flex; flex-direction:column; align-items:center; gap:4px; min-width:0; padding:4px; border:0; border-radius:6px; background:transparent; cursor:pointer; }
.bv-cell:hover { background:rgba(0,0,0,.05); }
.bv-icon { position:relative; width:var(--icon, 96px); height:var(--icon, 96px); display:block; }
.bv-icon svg { width:100%; height:100%; display:block; border-radius:3px; }
.bv-icon-ph { display:block; width:100%; height:100%; border-radius:3px; background:#fff; border:1px solid #d8d2c4; }
.bv-icon-solved { position:absolute; inset:0; pointer-events:none; }
.bv-cell-label { font-size:.72rem; line-height:1.15; color:#3A2A0A; text-align:center; max-width:100%; overflow-wrap:anywhere; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
.bv-pagenum { position:absolute; bottom:6px; font-size:.72rem; color:#8B7355; pointer-events:none; }
.bv-pagenum-left { left:12px; } .bv-pagenum-right { right:12px; }
.bv-nav { flex:0 0 44px; display:flex; align-items:center; justify-content:center; gap:20px; background:#D4C9A8; color:#3A2A0A; padding:0 var(--page-pad); }
.bv-page-btn { width:40px; height:40px; border:0; background:transparent; color:#3A2A0A; font-size:1.4rem; font-weight:700; line-height:1; border-radius:6px; cursor:pointer; }
.bv-page-btn:hover:not(:disabled) { background:rgba(0,0,0,.08); }
.bv-page-btn:disabled { color:#B0A890; cursor:default; }
.bv-page-ind { font-size:.72rem; color:#6b5a3a; min-width:120px; text-align:center; }

/* Library: books not downloaded to this device show a download badge and read
   slightly muted; a downloaded book looks normal. */
.bc-book-remote { opacity:.72; }
.bc-book-remote:hover { opacity:.9; }
.bc-download-badge { position:absolute; right:6px; bottom:6px; width:26px; height:26px; border-radius:50%; background:rgba(20,20,20,.72); color:#fff; display:flex; align-items:center; justify-content:center; pointer-events:none; }
.bc-download-badge svg { width:16px; height:16px; }
.gbtn.danger { background:var(--err); border-color:var(--err); }
.gbtn.danger:hover { filter:brightness(.94); }

/* Solo-solve back arrow, left of the title. */
.ph-back { flex:0 0 auto; align-self:center; margin-left:var(--page-pad); width:28px; height:28px; display:flex; align-items:center; justify-content:center; border:0; background:transparent; color:var(--muted); font-size:20px; line-height:1; border-radius:6px; cursor:pointer; }
.ph-back:hover { background:rgba(0,0,0,.06); color:var(--fg); }
/* With a back arrow present, the title's own left gutter would double the gap. */
.ph-line:has(.ph-back) .puzzle-header { padding-left:8px; }

/* In-Progress stash rows: not clickable as a whole; title left, buttons right. */
.row-static { display:flex; align-items:center; gap:12px; cursor:default; }
.row-static .row-info { flex:1 1 auto; min-width:0; }
.row-static .row-actions { flex:0 0 auto; display:flex; gap:8px; }

/* Inbox rows: unread titles are bold; the expiry hint sits beside the title. */
.row.unread .row-title { font-weight:700; }
.inbox-expires { margin-left:8px; font-weight:400; font-size:12px; }

/* Store: a responsive grid of book cards, matching the old UI's card look. */
.store-grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(400px, 1fr)); gap:14px; align-items:start; }
/* Cover left, everything else right. Cards size to their content: nothing in a
   shop window may be cut off. */
.store-card { border:1px solid var(--line); border-radius:10px; padding:14px; background:#fff; display:flex; flex-direction:row; gap:14px; align-items:flex-start; }
.store-body { display:flex; flex-direction:column; gap:8px; flex:1 1 auto; min-width:0; }
.store-head { display:flex; align-items:baseline; gap:8px; }
/* The Library's book size, so the same book looks the same on both screens. */
.store-cover {
    flex:0 0 var(--bc-book-w, 100px); width:var(--bc-book-w, 100px); height:var(--bc-book-h, 144px);
    position:relative; overflow:hidden; border-radius:3px; box-shadow:0 2px 4px rgba(0,0,0,.40);
}
.store-cover-img { width:100%; height:100%; object-fit:cover; display:block; }
.store-cover-colour { background:linear-gradient(90deg, rgba(0,0,0,.28) 0 6px, rgba(255,255,255,.10) 6px 9px, var(--cc) 9px); }
.store-cover-face { position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:flex-start; padding:14px 8px 10px; text-align:center; color:#fff; }
.store-cover-title { font-weight:700; font-size:.72rem; line-height:1.15; text-shadow:0 1px 2px rgba(0,0,0,.35); overflow-wrap:anywhere; }
.store-cover-rule { width:70%; height:1px; background:rgba(255,255,255,.5); margin:.35rem 0 .3rem; }
.store-cover-author { font-size:.62rem; line-height:1.1; opacity:.92; overflow-wrap:anywhere; }
.store-shelf-title { font-size:15px; font-weight:700; color:var(--ink); margin:18px 0 8px; }
/* The calendar line, at the foot of a series card's own text column. */
.cal-line { display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin-top:8px; }
.cal-line-label { font-size:13px; }
.cal-provider { font-size:12px; padding:3px 10px; }
.cal-aside { font-size:12px; margin-left:4px; }
.store-shelf-title:first-of-type { margin-top:8px; }
/* Never truncated: wraps to as many lines as the title needs. */
.store-title { font-weight:600; min-width:0; overflow-wrap:anywhere; }
.store-owned { margin-left:auto; flex:0 0 auto; font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:.03em; color:#137a3f; background:#e7f6ed; border-radius:10px; padding:2px 8px; }
.store-meta { font-size:13px; overflow-wrap:anywhere; }
/* Full description, always. A shopper decides from this text. */
.store-desc { font-size:13px; margin:0; color:var(--ink); overflow-wrap:anywhere; }
.store-foot { margin-top:6px; display:flex; align-items:center; gap:8px; }
@media (max-width:520px) {
    /* Too narrow for a side-by-side card: cover on top, text beneath — still
       nothing truncated. */
    .store-grid { grid-template-columns:1fr; }
    .store-card { flex-direction:column; align-items:stretch; }
    .store-cover { align-self:flex-start; }
}
.mini-btn.primary { border-color:var(--accent); color:#fff; background:var(--accent); }
@media (hover:hover) { .mini-btn.primary:hover { filter:brightness(.95); background:var(--accent); } }
.mini-btn.primary:disabled { opacity:.7; cursor:default; }

/* ── Admin ───────────────────────────────────────────────────────────────────
   Native replacements for the Bootstrap primitives the old admin page used:
   a sub-tab strip, panes, tables, a modal, form controls. Web-only, admin-only. */
.admin-root { display:flex; flex-direction:column; gap:12px; }
.adm-tabstrip { display:flex; gap:4px; border-bottom:1px solid var(--line); }
.adm-tab { border:0; background:transparent; padding:8px 14px; font-size:14px; font-weight:600; color:var(--muted); cursor:pointer; border-bottom:2px solid transparent; margin-bottom:-1px; }
.adm-tab:hover { color:var(--ink); }
.adm-tab.active { color:var(--accent); border-bottom-color:var(--accent); }
.adm-pane { padding-top:12px; }
.adm-help { color:var(--muted); font-size:13px; margin:0 0 12px; max-width:60ch; }
.adm-muted { color:var(--muted); font-size:13px; }

.adm-toggle { display:inline-flex; align-items:center; gap:8px; font-weight:600; cursor:pointer; margin-bottom:14px; }
.adm-inline-form { display:flex; gap:8px; margin-bottom:16px; max-width:520px; }
.adm-input { flex:1 1 auto; padding:7px 10px; border:1px solid var(--line); border-radius:6px; font-size:14px; }
.adm-input:focus { outline:none; border-color:var(--accent); }

.adm-table { width:100%; max-width:640px; border-collapse:collapse; font-size:14px; }
.adm-table th { text-align:left; font-weight:600; color:var(--muted); font-size:12px; text-transform:uppercase; letter-spacing:.03em; padding:6px 10px; border-bottom:1px solid var(--line); }
.adm-table td { padding:8px 10px; border-bottom:1px solid var(--line); }
.adm-actions-col { text-align:right; width:1%; white-space:nowrap; }

.adm-btn { border:1px solid var(--line); background:#fff; color:var(--ink); padding:7px 12px; border-radius:6px; font-size:14px; font-weight:600; cursor:pointer; }
.adm-btn:hover { background:#f7f8fa; }
.adm-btn.sm { padding:4px 9px; font-size:13px; }
.adm-btn.primary { background:var(--accent); border-color:var(--accent); color:#fff; }
.adm-btn.primary:hover { filter:brightness(.95); background:var(--accent); }
.adm-btn.danger { background:var(--err); border-color:var(--err); color:#fff; }
.adm-btn.danger:hover { filter:brightness(.95); background:var(--err); }
.adm-btn:disabled { opacity:.6; cursor:default; }

.adm-modal-overlay { position:fixed; inset:0; background:rgba(0,0,0,.4); display:flex; align-items:center; justify-content:center; z-index:1000; padding:20px; }
.adm-modal { background:#fff; border-radius:12px; padding:20px; max-width:560px; width:100%; max-height:85vh; overflow:auto; box-shadow:0 12px 40px rgba(0,0,0,.25); }
.adm-modal.wide { max-width:720px; }
/* Wide enough for a whole puzzle row (grip, number, name, type, subtype, badge,
   Replace) without wrapping; capped so it still has a margin on a small screen. */
.adm-modal.widest { max-width:min(1100px, calc(100vw - 40px)); }
.adm-modal.widest .adm-pz-row { flex-wrap:nowrap; }
.adm-pz-type { flex:0 0 8rem; }
.adm-pz-subtype { flex:0 0 8rem; }
/* scroll layout: body scrolls, footer pinned */
.adm-modal.scroll { display:flex; flex-direction:column; overflow:hidden; }
.adm-modal.scroll .adm-modal-title { flex:0 0 auto; }
.adm-modal.scroll .adm-modal-body { flex:1 1 auto; overflow-y:auto; padding-right:4px; }
.adm-modal-footer { flex:0 0 auto; display:flex; justify-content:space-between; align-items:center; gap:8px; padding-top:14px; margin-top:6px; border-top:1px solid var(--line); }
.adm-modal-title { margin:0 0 12px; font-size:18px; }
.adm-actions { display:flex; justify-content:flex-end; gap:8px; margin-top:16px; }

/* Admin catalog + shared form/table extras. */
.adm-toolbar { display:flex; gap:8px; margin-bottom:12px; }
.adm-grant { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-bottom:16px; padding:10px 12px; background:#f7f8fa; border-radius:8px; }
.adm-table-wrap { overflow-x:auto; }
.adm-table-wide { max-width:none; }
.adm-table th.adm-sortable { cursor:pointer; user-select:none; white-space:nowrap; }
.adm-r { text-align:right; } .adm-c { text-align:center; }
.adm-pill { display:inline-block; font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:.03em; border-radius:10px; padding:2px 8px; }
.adm-pill.ok { color:#137a3f; background:#e7f6ed; }
.adm-pill.muted { color:var(--muted); background:#eceef1; }
.adm-invalid { border-color:var(--err) !important; }
.adm-danger { color:var(--err); }

.adm-field { display:flex; flex-direction:column; gap:4px; margin-bottom:10px; }
.adm-field-label { font-size:12px; font-weight:600; color:var(--muted); text-transform:uppercase; letter-spacing:.03em; }
.adm-field textarea.adm-input { min-height:64px; resize:vertical; font-family:inherit; }
.adm-check { display:flex; align-items:center; gap:8px; margin:8px 0; font-weight:500; }
.adm-check input { flex:0 0 auto; }

.adm-cover-row { display:flex; align-items:center; gap:10px; margin-bottom:12px; }
.adm-cover-preview { width:48px; height:48px; border-radius:6px; background-size:cover; background-position:center; border:1px solid var(--line); flex:0 0 auto; }

.adm-pz-list { border:1px solid var(--line); border-radius:8px; padding:6px; margin:8px 0; max-height:340px; overflow:auto; }
.adm-pz-row { display:flex; align-items:center; gap:8px; padding:5px 4px; border-bottom:1px solid var(--line); }
.adm-pz-row:last-child { border-bottom:0; }
.adm-pz-grip { cursor:grab; flex:0 0 auto; color:var(--muted); }
.adm-pz-num { flex:0 0 1.8rem; color:var(--muted); font-size:13px; }
.adm-pz-file { flex:1 1 auto; min-width:0; word-break:break-all; font-size:13px; }
.adm-pz-name { flex:0 0 12rem; }
.adm-pz-badge { flex:0 0 auto; font-size:11px; color:var(--muted); background:#eceef1; border-radius:6px; padding:2px 6px; white-space:nowrap; }

.adm-versions { border:1px solid var(--line); border-radius:8px; padding:4px 10px; max-height:200px; overflow:auto; }
.adm-version { display:flex; align-items:center; justify-content:space-between; gap:8px; padding:5px 0; border-bottom:1px solid var(--line); font-size:13px; }
.adm-version:last-child { border-bottom:0; }
.adm-actions-split { justify-content:space-between; }
.adm-actions-right { display:flex; gap:8px; }

/* Admin tab lives on the right, by the name dropdown (not in the left strip). */
.admin-tab { border:0; background:transparent; font-size:14px; font-weight:600; color:var(--muted); cursor:pointer; padding:6px 10px; border-radius:6px; }
.admin-tab:hover { color:var(--ink); background:rgba(0,0,0,.05); }
.admin-tab.active { color:var(--accent); }

/* Admin: paired fields, grant/revoke lines, autocomplete, cover toggle, caret. */
.adm-pair { display:flex; gap:12px; }
.adm-pair-cell { flex:1 1 0; min-width:0; margin-bottom:10px; }
.adm-check-cell { flex-direction:row; align-items:center; align-self:flex-end; padding-bottom:8px; }

.adm-ent { display:flex; flex-direction:column; gap:1em; margin-bottom:16px; padding:10px 12px; background:#f7f8fa; border-radius:8px; }
.adm-ent-line { display:flex; align-items:center; gap:8px; justify-content:flex-start; }
.adm-ent-label { flex:0 0 6.5rem; font-size:13px; font-weight:600; color:var(--muted); }
/* Email column is capped so the Book field sits a few ems to its right rather
   than being pushed to the far edge; both lines share the width so they align. */
.adm-ac { position:relative; flex:0 0 20rem; min-width:0; }   /* fixed email column so grant/revoke align */
.adm-ent-email { width:100%; min-width:0; }
.adm-ent-book { flex:0 0 auto; }   /* width set inline from the longest title so it never varies with the selection */
.adm-ent-line .adm-btn { flex:0 0 6rem; text-align:center; }   /* Grant and Revoke same width */
/* The email/book inputs on the entitlement line have a fixed width, so override
   the flex-grow the generic .adm-input carries. */
.adm-ent-line .adm-input { flex:none; }

.adm-ac-menu { position:absolute; top:100%; left:0; right:0; z-index:50; background:#fff; border:1px solid var(--line); border-radius:6px; margin-top:2px; box-shadow:0 6px 20px rgba(0,0,0,.12); max-height:220px; overflow:auto; }
.adm-ac-menu.hidden { display:none; }
.adm-ac-opt { padding:7px 10px; font-size:13px; cursor:pointer; }
.adm-ac-opt:hover { background:#eef3fb; }

.adm-cover-line { display:flex; align-items:center; gap:12px; margin-bottom:12px; }
.adm-seg { display:inline-flex; border:1px solid var(--line); border-radius:6px; overflow:hidden; }
.adm-seg-btn { border:0; background:#fff; padding:5px 12px; font-size:13px; font-weight:600; color:var(--muted); cursor:pointer; }
.adm-seg-btn.active { background:var(--accent); color:#fff; }
.adm-cover-side { display:flex; align-items:center; gap:8px; }
.adm-color-input { width:44px; height:28px; padding:0; border:1px solid var(--line); border-radius:4px; background:none; cursor:pointer; }
.adm-swatch { width:28px; height:28px; border-radius:4px; border:1px solid var(--line); }
.adm-cover-thumb { width:40px; height:40px; border-radius:4px; border:1px solid var(--line); background-size:cover; background-position:center; flex:0 0 auto; }
.adm-cover-thumb.checker { background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%); background-size:12px 12px; background-position:0 0,0 6px,6px -6px,-6px 0; background-color:#fff; }

.adm-collapse { display:flex; align-items:center; gap:6px; border:0; background:transparent; padding:8px 0; font-size:12px; font-weight:600; color:var(--muted); text-transform:uppercase; letter-spacing:.03em; cursor:pointer; }
.adm-caret { font-size:10px; }

/* Admin: Users/Email/Config/Recovery extras. */
.adm-h2 { font-size:16px; font-weight:700; margin:18px 0 8px; }
.adm-h2:first-child { margin-top:0; }
.adm-pill.warn { color:#8a5a00; background:#fdf0d5; }
.adm-pill.danger { color:#b3261e; background:#fce8e6; }
.adm-email-row { display:flex; align-items:center; gap:8px; padding:6px 0; border-bottom:1px solid var(--line); }
.adm-email-addr { flex:1 1 auto; min-width:0; }
.adm-emails { border:1px solid var(--line); border-radius:8px; padding:4px 10px; margin-bottom:6px; }
.adm-ent-list { margin:0; padding-left:18px; }
.adm-recovery-status { margin-bottom:8px; font-size:14px; }
.adm-recovery-maint { display:flex; align-items:center; gap:10px; margin:14px 0; }
.adm-restore-cmd { margin-top:12px; }
.adm-cmd-pre { background:#0f172a; color:#e2e8f0; padding:12px; border-radius:8px; overflow-x:auto; font-size:12px; white-space:pre-wrap; word-break:break-all; }

/* Admin config: a simple two-column key/value list. */
.adm-config-dl { display:grid; grid-template-columns:auto 1fr; gap:6px 16px; margin-bottom:14px; font-size:14px; max-width:640px; }
.adm-config-key { font-weight:600; color:var(--muted); }

/* Login screen: title, version, and two grey boxes (Google, Email/Password). */
.login { max-width:400px; margin:8vh auto 0; display:flex; flex-direction:column; gap:14px; padding:0 20px; }
.login.wide { max-width:600px; }
.login-linktext { color:var(--muted); font-size:14px; }
.login-linkrow.one { gap:8px; }
.login h1 { text-align:center; margin:0; font-size:28px; }
.login-version { text-align:center; color:var(--muted); font-size:12px; margin:2px 0 6px; }
.login-alert { margin:0; padding:10px 12px; border-radius:8px; font-size:14px; }
.login-alert.err { background:#fce8e6; color:#b3261e; }
.login-alert.ok { background:#e7f6ed; color:#137a3f; }

/* Grey boxes, matching the Admin grant/revoke panel. */
.login-box { background:#f7f8fa; border-radius:8px; padding:16px; display:flex; flex-direction:column; gap:12px; }
.login-box-title { font-size:13px; font-weight:600; color:var(--muted); text-transform:uppercase; letter-spacing:.03em; }
.login-note { margin:0; font-size:12.5px; font-style:italic; color:var(--muted); }

.login-form { display:flex; flex-direction:column; gap:10px; margin:0; }
/* Google + Sign In buttons: normal-sized, equal fixed width, not full-span. */
.login-box .gbtn { width:11rem; min-width:11rem; align-self:center; margin:0; }
.login-field { display:flex; flex-direction:column; gap:4px; font-size:13px; font-weight:600; color:var(--muted); }
.login-input { padding:9px 11px; border:1px solid var(--line); border-radius:8px; font-size:15px; }
.login-input:focus { outline:none; border-color:var(--accent); }

/* Link row: Forgot on the left, Create Account on the right. */
.login-linkrow { display:flex; justify-content:space-between; align-items:center; margin-top:2px; }
.login-linkrow.one { justify-content:center; }
.login-link { color:var(--accent); font-size:14px; text-decoration:none; cursor:pointer; }
.login-link:hover { text-decoration:underline; }

/* Turnstile widget on the login screen. */
.login-turnstile { display:flex; justify-content:center; min-height:0; }
.login-turnstile:empty { display:none; }

/* Why-Google modal. */
.why-modal { width:min(540px, 94vw); text-align:left; max-height:88vh; display:flex; flex-direction:column; }
.why-title { margin:0 0 10px; font-size:18px; flex:0 0 auto; }
.why-modal > p { flex:0 0 auto; }
.why-scroll { flex:1 1 auto; overflow-y:auto; margin:0; min-height:0; }
.why-list { margin:8px 0 0; padding-left:20px; display:flex; flex-direction:column; gap:8px; }
.why-list li { line-height:1.4; }
.why-modal .modal-actions { flex:0 0 auto; }


/* Browsing the library on behalf of a cosolve (see UISpec 14.2e). */
.picking-banner { display:flex; align-items:center; gap:12px; background:#FDF1DC;
  color:#7A4E00; font-size:.85rem; padding:10px 14px; }
.picking-banner .mini-btn { margin-left:auto; }


/* Series schedule editor (UISpec 13.5). */
.sched-row { display:flex; align-items:center; gap:10px; margin:8px 0; }
.sched-row > .field-label { flex:0 0 7.5rem; margin:0; }
.sched-row input[type=number] { width:4rem; }
.sched-row input[type=text], .sched-row input[type=time] { flex:1 1 auto; min-width:0; }
.sched-days { display:flex; flex-wrap:wrap; gap:6px; }
.sched-day { display:flex; align-items:center; gap:4px; font-size:.85rem;
  border:1px solid var(--line); border-radius:6px; padding:3px 7px; cursor:pointer; }
.sched-inline { display:flex; gap:8px; flex:1 1 auto; min-width:0; }

/* Series detail section headers: bigger than a field label, because they head a
   section rather than label a control. */
.section-title { font-weight:700; font-size:19px; margin:18px 0 8px; }
.series-card .section-title { margin-top:0; }

/* Time zone typeahead (UISpec 13.6). */
.tz-wrap { position:relative; flex:1 1 auto; min-width:0; display:flex; }
.tz-wrap > input { flex:1 1 auto; min-width:0; }
.tz-list { position:absolute; top:100%; left:0; right:0; z-index:40; max-height:220px;
  overflow-y:auto; background:#fff; border:1px solid var(--line); border-radius:6px;
  box-shadow:0 6px 18px rgba(0,0,0,.12); }
.tz-option { padding:6px 10px; font-size:14px; cursor:pointer; }
.tz-option:hover { background:var(--act); }
.tbtn.danger { border-color:var(--err); color:var(--err); }
@media (hover:hover) { .tbtn.danger:hover { background:var(--err); color:#fff; } }
.series-sched { color:var(--ink); }


/* ── Solving assistant (Anagramming) ─────────────────────────────────────── */
.assist-modal { width:min(560px, 96vw); max-height:92vh; overflow-y:auto; display:flex; flex-direction:column; gap:10px; }
.assist-title { text-align:center; }
/* The modal header is a tool picker, so it is a select that reads as a title
   rather than a control bolted beside one. */
.assist-title-select { display:block; margin:0 auto 8px; border:1px solid var(--line); border-radius:8px;
                       background:#fff; font-size:18px; font-weight:700; color:var(--ink);
                       padding:4px 28px 4px 10px; cursor:pointer; text-align:center; text-align-last:center; }
.assist-title-select:hover { border-color:var(--accent); }
.assist-alpha { display:flex; flex-direction:column; gap:4px; }
.assist-alpha-row { display:flex; gap:4px; justify-content:center; }
.assist-key { width:30px; height:32px; border:1px solid var(--line); background:#f8f9fb; border-radius:5px; font:inherit; font-size:14px; font-weight:600; color:var(--ink); cursor:pointer; padding:0; user-select:none; -webkit-user-select:none; }
@media (hover:hover) { .assist-key:hover { background:var(--accent); color:#fff; } }
.assist-clue { text-align:center; line-height:1.9; }
.assist-clue-label { font-weight:700; color:var(--accent); margin-right:6px; }
.assist-word { display:inline-block; border:0; background:none; font:inherit; color:var(--ink); cursor:pointer; padding:1px 3px; margin:0 1px; border-radius:4px; text-decoration:underline dotted var(--muted); text-underline-offset:3px; user-select:none; -webkit-user-select:none; }
@media (hover:hover) { .assist-word:hover { background:var(--act-cross); } }
.assist-word.plain { text-decoration:none; cursor:default; }
.assist-word.plain:hover { background:none; }
.assist-fodder { position:relative; height:190px; border:1px dashed var(--line); border-radius:10px; overflow:hidden; touch-action:none; }
.assist-tile { position:absolute; transform:translate(-50%,-50%); width:34px; height:34px; display:flex; align-items:center; justify-content:center; background:#fff; border:1px solid var(--grid-line); border-radius:6px; font-size:18px; font-weight:700; cursor:grab; user-select:none; -webkit-user-select:none; box-shadow:0 1px 3px rgba(0,0,0,.15); touch-action:none; }
.assist-tile.used { color:#b7bcc4; border-color:var(--line); box-shadow:none; }
/* Letter Bank. A tile is never spent, so it is never grayed or hidden: red
   until the letter appears in the answer, black once it does. */
.assist-tile.bank-off { color:#c0392b; border-color:#c0392b; }
.assist-tile.bank-on  { color:var(--ink); }
.assist-tile.selected { outline:3px solid var(--cur); }
.assist-tile.dragging { opacity:.25; }
.assist-ghost { position:fixed; transform:translate(-50%,-50%); z-index:200; pointer-events:none; width:34px; height:34px; display:flex; align-items:center; justify-content:center; background:#fff; border:1px solid var(--grid-line); border-radius:6px; font-size:18px; font-weight:700; box-shadow:0 6px 18px rgba(0,0,0,.3); }
.assist-answer { display:flex; flex-wrap:wrap; align-items:center; justify-content:center; gap:4px; min-height:44px; }
.assist-slot { min-width:36px; height:40px; display:flex; align-items:center; justify-content:center; gap:1px; padding:0 3px; border:2px solid var(--grid-line); border-radius:4px; background:#fff; touch-action:none; }
.assist-slot.locked { background:#eef4fb; border-color:var(--accent); }
.assist-slot-letter { font-size:20px; font-weight:700; color:var(--ink); cursor:grab; user-select:none; -webkit-user-select:none; touch-action:none; }
.assist-slot.locked .assist-slot-letter { cursor:default; }
.assist-slot-letter.red { color:var(--err); }
.assist-slot-letter.blue { color:var(--accent); }
/* Rebus entries shrink to fit, same idea as the grid. */
.assist-slot:has(.assist-slot-letter:nth-child(2)) .assist-slot-letter { font-size:14px; }
.assist-slot:has(.assist-slot-letter:nth-child(4)) .assist-slot-letter { font-size:11px; }
.assist-sep { display:inline-flex; align-items:center; font-size:20px; font-weight:700; color:var(--muted); }
.assist-sep.gap { width:14px; }
.assist-warning { text-align:center; font-size:13px; color:var(--err); }
.assist-controls { display:flex; justify-content:center; gap:10px; }
.assist-rebus.on { background:var(--accent); color:#fff; }
.assist-modal .modal-actions { display:flex; justify-content:flex-end; gap:10px; }


/* ── Site tour (0.250) ─────────────────────────────────────────────────── */
/* The dim layer is the cut-out's giant box-shadow, so the highlighted
   control shows through undimmed. The root blocks all interaction; only the
   bubble's own controls are clickable. */
.tour-overlay { position:fixed; inset:0; z-index:400; overflow:hidden; }
.tour-mask { position:absolute; inset:0; width:100%; height:100%; pointer-events:none; }
.tour-bubble { position:absolute; width:min(380px, calc(100vw - 16px)); max-width:calc(100vw - 16px); box-sizing:border-box; background:#fff; border:1px solid var(--line); border-radius:12px; box-shadow:0 10px 34px rgba(0,0,0,.3); padding:14px 16px; }
.tour-head { display:flex; align-items:baseline; justify-content:space-between; gap:10px; margin-bottom:6px; }
.tour-section { font-weight:700; color:var(--accent); }
.tour-progress { font-size:12px; color:var(--muted); white-space:nowrap; }
.tour-text { margin:0 0 10px; font-size:14px; line-height:1.45; color:var(--ink); }
/* Test-system marker in the nav bar. Deliberately loud and deliberately black
   rather than an accent colour: it is not part of the interface, it is a
   warning that the interface is not the real one. */
.beta-flag { align-self:center; margin-left:14px; font-size:18px; font-weight:800; letter-spacing:.04em; color:#000; white-space:nowrap; }

.tour-btns { display:flex; align-items:center; justify-content:flex-end; gap:10px; }
/* margin-right:auto keeps Exit at the left edge with the other two at the
   right. No padding override any more: it is a .tbtn now and wants the same
   box as Next Section. */
.tour-btns .tour-exit { margin-right:auto; }
.tour-btns .gbtn { margin:0; }
.tour-text p { margin:0 0 8px; }
.tour-text p:last-child { margin-bottom:0; }
.tour-note { font-style:italic; color:var(--ink); }
/* The account dropdown sits above the modal backdrop during the tour's My
   Account steps, so it stays visible behind the modal it opened. */
.menu-pop.tour-lift { z-index:150; }
/* Video-call link: far right of the title bar, baseline-aligned with its label. */
.ph-video { display:flex; align-items:baseline; gap:6px; flex:0 0 auto; margin-left:auto;
            padding:8px var(--page-pad) 8px 12px; white-space:nowrap; font-size:14px; }
.ph-video-label { color:var(--muted); }
.ph-video-link { color:var(--accent); text-decoration:underline; }

/* Policy links under the login box, and the Policies dropdown in the nav. */
.login-policies { margin:16px 0 0; text-align:center; font-size:13px; color:var(--muted); }
.login-policies a { color:var(--muted); text-decoration:underline; }
.login-policies a:hover { color:var(--ink); }

/* The processing screen: shown between a sign-in and the answer to it. */
.busy-screen { display:flex; flex-direction:column; align-items:center; justify-content:center;
               gap:14px; min-height:60vh; padding:24px; }
.busy-text { margin:0; font-size:17px; color:var(--ink); }
.busy-spinner { width:34px; height:34px; border-radius:50%; border:3px solid var(--line);
                border-top-color:var(--accent); animation:busy-spin .8s linear infinite; }
@keyframes busy-spin { to { transform:rotate(360deg); } }
/* A person who has asked for reduced motion gets the message without the
   spinning; the text is what carries the meaning anyway. */
@media (prefers-reduced-motion: reduce) { .busy-spinner { animation:none; } }

/* An empty Store still draws the bookcase; the message sits inside it, written
   across the top shelf (see .bc-empty-note). */
.store-empty { position:relative; }

/* My Account: the Membership row now carries a date and a button, so the modal
   is sized to hold a whole row on one line rather than wrapping it. */
.modal.account-modal { width:min(520px, 94vw); }
.modal.account-modal .account-row { display:flex; align-items:center; gap:12px; }
.modal.account-modal .account-row > :last-child { margin-left:auto; display:flex; align-items:center; gap:10px; }



