:root {
  --bg: #14151f;
  --surface: #1e1f2e;
  --surface-2: #262838;
  --surface-3: #313348;
  --ink: #e9e9f2;
  --ink-dim: #a6a7bd;
  --ink-faint: #71738c;
  --accent: #8f7cf0;
  --accent-2: #5ec8c0;
  --warm: #e0b15a;
  --good: #63c98a;
  --bad: #e0736b;
  --line: #333552;
  --radius: 16px;
  --radius-sm: 10px;
  --maxw: 720px;
  --tabbar-h: 62px;
  --topbar-h: 50px;
  font-size: 16px;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
/* The `hidden` attribute must win even over elements with an explicit display
   (e.g. #tabbar is display:flex). Without this, hidden bars still show. */
[hidden] { display: none !important; }
html, body { margin: 0; padding: 0; background: var(--bg); color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  line-height: 1.5; overscroll-behavior-y: none; }

#app { max-width: var(--maxw); margin: 0 auto; padding: 18px 18px calc(var(--tabbar-h) + 28px);
  min-height: 100vh; }
/* When the shell (top bar) is present, reserve space so content clears it. */
body.has-shell #app { padding-top: calc(var(--topbar-h) + 12px); }

/* Persistent top bar: home wordmark + How-this-works + Settings, reachable anywhere. */
#topbar { position: fixed; top: 0; left: 0; right: 0; height: var(--topbar-h); z-index: 20;
  display: flex; align-items: center; gap: 4px; padding: 0 14px;
  background: var(--bg); border-bottom: 1px solid var(--line); }
#topbar .tb-brand { border: none; background: transparent; padding: 6px 4px; cursor: pointer;
  font-weight: 800; font-size: 1.1rem; letter-spacing: -0.02em; color: var(--accent);
  /* Repeat the colour cycle (purple → teal → purple) and slowly scroll the
     background — a gentle nod to 90s palette cycling. Seamless because the last
     stop matches the first. */
  background-image: linear-gradient(90deg, var(--accent), var(--accent-2), var(--accent));
  background-size: 200% auto;
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
  animation: brand-cycle 8s linear infinite; }
@keyframes brand-cycle { to { background-position: -200% center; } }
@media (prefers-reduced-motion: reduce) { #topbar .tb-brand { animation: none; } }
#topbar .tb-icon { background: none; border: none; color: var(--ink-dim); font-size: 1.15rem;
  width: 38px; height: 38px; border-radius: 8px; display: inline-flex; align-items: center; justify-content: center; }
#topbar .tb-icon:hover { background: var(--surface-2); color: var(--ink); }
#topbar .tb-icon:active { background: var(--surface-3); }
/* One-time discovery nudge: a gentle, finite pulse the first time there's a
   milestone to see (cleared when Progress is opened). Reduced-motion → static dot. */
#topbar .tb-icon.nudge { color: var(--accent); animation: tb-pulse 1.4s ease-in-out 3; position: relative; }
@keyframes tb-pulse { 0%, 100% { box-shadow: 0 0 0 0 rgba(143,124,240,0); } 50% { box-shadow: 0 0 0 4px rgba(143,124,240,0.35); } }
@media (prefers-reduced-motion: reduce) {
  #topbar .tb-icon.nudge { animation: none; }
  #topbar .tb-icon.nudge::after { content: ''; position: absolute; top: 5px; right: 5px; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); }
}

h1 { font-size: 1.5rem; margin: 0.2em 0 0.4em; letter-spacing: -0.01em; }
h2 { font-size: 1.15rem; margin: 1.1em 0 0.4em; }
h3 { font-size: 1rem; margin: 0.9em 0 0.3em; color: var(--ink-dim); }
p { margin: 0.5em 0; }
small { color: var(--ink-faint); }
a { color: var(--accent-2); }

.muted { color: var(--ink-dim); }
.faint { color: var(--ink-faint); }
.center { text-align: center; }
.mono { font-variant-numeric: tabular-nums; }
.pill { display: inline-block; padding: 2px 10px; border-radius: 999px; font-size: 0.78rem;
  background: var(--surface-3); color: var(--ink-dim); }
.pill.good { background: rgba(99,201,138,0.18); color: var(--good); }
.pill.warm { background: rgba(224,177,90,0.18); color: var(--warm); }
.pill.accent { background: rgba(143,124,240,0.2); color: var(--accent); }
.stack > * + * { margin-top: 12px; }
.row { display: flex; gap: 10px; align-items: center; }
.row.wrap { flex-wrap: wrap; }
.spacer { flex: 1; }
.hidden { display: none !important; }

/* "How this works" in-page anchors — offset so headings clear the fixed top bar. */
.about-anchor { scroll-margin-top: calc(var(--topbar-h) + 14px); }

/* Onboarding track selection */
.track-card.selected { border-color: var(--accent); background: rgba(143,124,240,0.12); }
.track-check { color: var(--accent); font-weight: 700; font-size: 1.2rem; width: 22px; text-align: center; }

/* Boot splash / error fallback */
.boot-splash { display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 16px; min-height: 70vh; text-align: center; padding: 0 18px; }
.spinner { width: 28px; height: 28px; border: 3px solid var(--surface-3); border-top-color: var(--accent);
  border-radius: 50%; animation: spin 0.8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* Cards */
.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 16px; }
.card.tap { cursor: pointer; transition: transform 0.08s, border-color 0.15s; }
.card.tap:active { transform: scale(0.985); }
.card.accent-edge { border-left: 3px solid var(--accent); }
.card-title { font-weight: 600; }
/* Cards/grids placed directly in the page column (screens that don't wrap their
   content in a .stack) would otherwise touch — give adjacent siblings a gap.
   Scoped to `#app >` so stacks and card-grids, which handle their own spacing,
   are unaffected (no double margins). */
#app > .card + .card,
#app > .card + .card-grid,
#app > .card-grid + .card,
#app > .card-grid + .card-grid { margin-top: 12px; }
/* Responsive card grid: 1 column on phones, filling into 2–3 as width allows.
   Used by the content-rich screens (Map, Progress, Library) so wide viewports
   aren't a narrow column stranded in empty margin. */
.card-grid { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr)); }
@media (min-width: 900px) {
  body[data-route="map"] #app,
  body[data-route="progress"] #app,
  body[data-route="library"] #app { max-width: 1080px; }
}
/* The scenario/context block. Uses the card background + a teal left stripe so it
   reads as "the situation" and is clearly distinct from the surface-2 option rows
   (.opt), which previously shared its background and looked like part of it. */
.vignette { background: var(--surface); border-left: 3px solid var(--accent-2);
  border-radius: var(--radius-sm); padding: 13px 16px 13px 15px;
  font-size: 1.02rem; line-height: 1.55; }
.vignette .vtitle { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--ink-faint); margin-bottom: 6px; }

/* Buttons */
button { font: inherit; cursor: pointer; }
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  border: none; border-radius: var(--radius-sm); padding: 13px 18px; font-weight: 600;
  background: var(--surface-3); color: var(--ink); transition: opacity 0.15s, background 0.15s; }
.btn.primary { background: var(--accent); color: #14121f; }
.btn.wide { width: 100%; }
.btn.ghost { background: transparent; border: 1px solid var(--line); color: var(--ink-dim); }
.btn:disabled { cursor: not-allowed; opacity: 0.65; }
/* Disabled primary: read as intentionally inactive (crisp neutral), not a washed-out
   accent that looks broken. */
.btn.primary:disabled { background: var(--surface-3); color: var(--ink-dim); opacity: 1; box-shadow: inset 0 0 0 1px var(--line); }
.btn.sm { padding: 8px 12px; font-size: 0.85rem; }
/* Selected state for segmented toggle buttons (load-bearing/decoration, analogy
   rows). Declared after .ghost so it wins — previously toggling .primary onto a
   .ghost button had no visible effect (ghost's background overrode it). */
.btn.selected { background: var(--accent); color: #14121f; border-color: transparent; font-weight: 700; }

textarea, input[type=text], input[type=password], input[type=number], input[type=url], input[type=email] {
  width: 100%; background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius-sm); color: var(--ink); padding: 12px; font: inherit; }
input[type=text] + .btn.wide, textarea + .btn.wide { margin-top: 8px; }
/* Two stacked full-width buttons must never touch. The exercise/arc stages are
   plain divs without .stack spacing, so a second wide button (or a wide button
   following another) needs its own breathing room. */
.btn.wide + .btn.wide { margin-top: 12px; }
textarea { resize: vertical; }
textarea:focus, input:focus, select:focus { outline: none; border-color: var(--accent); }

/* Settings: one calm description style for all helper text (was a mix of
   small/faint/muted/p at several sizes). */
.setting-desc { font-size: 0.9rem; color: var(--ink-dim); line-height: 1.45; }
.setting-card .card-title { font-size: 1.02rem; display: flex; align-items: center; }
/* Small "?" help affordance next to a section title. */
.help-dot { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px;
  margin-left: 8px; border-radius: 50%; border: 1px solid var(--line); background: var(--surface-2);
  color: var(--ink-dim); font-size: 0.72rem; font-weight: 700; line-height: 1; }
.help-dot:hover { color: var(--ink); border-color: var(--ink-faint); }
.help-sheet { max-height: 82vh; overflow-y: auto; }
.help-sheet h3 { margin: 0.7em 0 0.2em; }
.help-list { list-style: none; padding: 0; margin: 0.4em 0; display: flex; flex-direction: column; gap: 10px; }
.help-list li { color: var(--ink-dim); font-size: 0.95rem; line-height: 1.5; }

/* Choice options */
.opt { display: block; width: 100%; text-align: left; background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 13px 14px; margin: 8px 0;
  color: var(--ink); cursor: pointer; box-shadow: inset 3px 0 0 var(--surface-3);
  transition: border-color 0.12s, background 0.12s, box-shadow 0.12s; }
/* Resting left stripe + hover distinguish tappable options from the flat vignette card. */
.opt:hover { background: var(--surface-3); border-color: var(--ink-faint); box-shadow: inset 3px 0 0 var(--accent); }
.opt:active { background: var(--surface-3); }
.opt.selected { border-color: var(--accent); background: rgba(143,124,240,0.12); box-shadow: inset 3px 0 0 var(--accent); }
.opt.correct { border-color: var(--good); background: rgba(99,201,138,0.14); }
.opt.wrong { border-color: var(--bad); background: rgba(224,115,107,0.14); }
.opt.disabled { pointer-events: none; }

/* Progress dots */
.dots { display: flex; gap: 6px; margin: 6px 0 14px; }
.dots .d { flex: 1; height: 4px; border-radius: 2px; background: var(--surface-3); }
.dots .d.on { background: var(--accent); }
.dots .d.done { background: var(--accent-2); }

/* Tabbar */
#tabbar { position: fixed; left: 0; right: 0; bottom: 0; height: var(--tabbar-h);
  display: flex; background: var(--surface); border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom); z-index: 30; }
#tabbar .tab { flex: 1; background: none; border: none; color: var(--ink-faint);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  font-size: 0.66rem; padding: 6px 0; }
#tabbar .tab .ti { font-size: 1.15rem; line-height: 1; }
/* Inline SVG nav icons scale with the icon font-size (so the desktop enlargement
   below applies to them too) and inherit colour via currentColor. */
#tabbar .tab .ti svg, #topbar .tb-icon svg { width: 1em; height: 1em; display: block; }
#tabbar .tab.active { color: var(--accent); }
#tabbar .tab.locked { opacity: 0.45; }
/* On wide/desktop viewports the full-stretch tabs look sparse and their icons feel
   too small — center the group and scale the icons/labels up. */
@media (min-width: 900px) {
  /* Taller top bar so it isn't dwarfed by the enlarged bottom nav (content
     offset tracks this via body.has-shell #app padding-top). */
  :root { --topbar-h: 58px; }
  /* Align both bars with the 720px content column instead of floating full-bleed
     — the full-width chrome around a narrow column is what read as "detached". */
  #topbar { left: 50%; right: auto; transform: translateX(-50%); width: 100%; max-width: var(--maxw); padding: 0 18px; }
  #topbar .tb-brand { font-size: 1.4rem; }
  #topbar .tb-icon { width: 42px; height: 42px; font-size: 1.3rem; }
  #tabbar { left: 50%; right: auto; transform: translateX(-50%); width: 100%; max-width: var(--maxw);
    justify-content: center; gap: 6px; border-radius: 16px 16px 0 0; }
  #tabbar .tab { flex: 0 1 128px; gap: 5px; padding: 8px 0; font-size: 0.78rem; border-radius: 12px; }
  #tabbar .tab .ti { font-size: 1.5rem; }
  #tabbar .tab:hover { color: var(--ink-dim); background: var(--surface-2); }
  #tabbar .tab.active:hover { color: var(--accent); }
}

/* Capture FAB */
#capture-fab { position: fixed; right: 18px; bottom: calc(var(--tabbar-h) + 16px + env(safe-area-inset-bottom));
  width: 54px; height: 54px; border-radius: 50%; border: none; background: var(--accent);
  color: #14121f; font-size: 1.8rem; line-height: 1; z-index: 31; box-shadow: 0 6px 20px rgba(0,0,0,0.4); }

/* Mapping (drag/tap-to-place) */
.map-grid { display: grid; grid-template-columns: 1fr; gap: 10px; }
.map-row { background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 12px; }
.map-row .role { font-size: 0.85rem; color: var(--ink-dim); margin-bottom: 8px; }
.map-slots { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.slot { min-height: 44px; border: 1px dashed var(--line); border-radius: 8px; padding: 8px;
  font-size: 0.9rem; display: flex; align-items: center; }
.slot.filled { border-style: solid; border-color: var(--accent-2); background: rgba(94,200,192,0.1); }
.slot.strained { border-color: var(--warm); }
.chip-tray { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0; }
.chip { background: var(--surface-3); border: 1px solid var(--line); border-radius: 999px;
  padding: 8px 13px; font-size: 0.88rem; color: var(--ink); }
.chip.selected { border-color: var(--accent); color: var(--accent); background: rgba(143,124,240,0.14); }
.chip.used { opacity: 0.35; pointer-events: none; }
.slot.droppable { border-color: var(--accent); background: rgba(143,124,240,0.08); color: var(--accent); }
.slot.dragover { border-color: var(--accent); background: rgba(143,124,240,0.16); }
.slot.empty { color: var(--ink-faint); justify-content: center; cursor: pointer; }
.slot.correct { border-color: var(--good); background: rgba(99,201,138,0.14); }
.slot.incorrect { border-color: var(--bad); background: rgba(224,115,107,0.12); color: var(--bad); justify-content: center; }
.slot.filled:not(.correct) { cursor: grab; }
.chip { cursor: grab; }
.chip.dragging { opacity: 0.5; }

/* Sortable list (drag to reorder) */
.sortable-item { cursor: grab; }
.sortable-item.dragging { opacity: 0.5; }
.sortable-item.dragover { border-color: var(--accent); box-shadow: inset 0 2px 0 var(--accent); }
.sortable-item .grip { color: var(--ink-faint); font-size: 1rem; cursor: grab; user-select: none; }

.map-status { color: var(--ink-dim); }
.map-status.good { color: var(--good); }
.map-status.warm { color: var(--warm); }

/* Coverage map nodes */
.map-nodes { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.node { display: inline-flex; align-items: center; gap: 6px; padding: 8px 12px; border-radius: 10px;
  font-size: 0.85rem; border: 1px solid var(--line); background: var(--surface-2); color: var(--ink); }
.node .node-tag { font-size: 0.75rem; opacity: 0.8; }
.node.state-Introduced { border-color: var(--accent); background: rgba(143,124,240,0.12); }
.node.state-Recognized { border-color: var(--accent-2); background: rgba(94,200,192,0.12); }
.node.state-Owned { border-color: var(--good); background: rgba(99,201,138,0.14); }
.node.state-Productive { border-color: var(--warm); background: rgba(224,177,90,0.16); }
.node.node-available { cursor: pointer; border-style: dashed; color: var(--ink-dim); }
.node.node-locked { color: var(--ink-dim); background: transparent; border-style: dashed; padding: 8px;
  min-width: 40px; min-height: 40px; justify-content: center; font-size: 1.3rem; line-height: 1; }
.strain-note { color: var(--warm); font-size: 0.85rem; margin-top: 8px; }

/* Diff / reveal */
.diff .cap { color: var(--good); }
.diff .miss { color: var(--warm); text-decoration: underline dotted; }
.reveal-name { font-size: 1.8rem; font-weight: 700; letter-spacing: -0.01em; text-align: center;
  margin: 10px 0; background: linear-gradient(90deg, var(--accent), var(--accent-2));
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }

/* rank list */
.rank-list { list-style: none; padding: 0; margin: 10px 0; }
.rank-list li { background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 12px; margin: 8px 0; display: flex; align-items: center; gap: 10px; }
.rank-list .rk-btns { display: flex; flex-direction: column; gap: 4px; }
.rank-list .rk-btns button { width: 30px; height: 24px; border: 1px solid var(--line);
  background: var(--surface-3); border-radius: 6px; color: var(--ink-dim); }
.rank-num { width: 26px; height: 26px; flex: 0 0 26px; align-self: flex-start; margin-top: 2px;
  border-radius: 50%; background: var(--accent);
  color: #14121f; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 0.85rem; }

/* toast / feedback banner */
.banner { border-radius: var(--radius-sm); padding: 12px 14px; margin: 10px 0; font-size: 0.95rem; }
.banner.good { background: rgba(99,201,138,0.14); border: 1px solid rgba(99,201,138,0.4); }
.banner.bad { background: rgba(224,115,107,0.14); border: 1px solid rgba(224,115,107,0.4); }
.banner.info { background: var(--surface-2); border: 1px solid var(--line); }
.banner.warm { background: rgba(224,177,90,0.12); border: 1px solid rgba(224,177,90,0.4); }

/* mastery states */
.state-chip { font-size: 0.72rem; padding: 2px 9px; border-radius: 999px; font-weight: 600; }
.state-Locked { background: var(--surface-3); color: var(--ink-faint); }
.state-Introduced { background: rgba(143,124,240,0.18); color: var(--accent); }
.state-Recognized { background: rgba(94,200,192,0.18); color: var(--accent-2); }
.state-Owned { background: rgba(99,201,138,0.2); color: var(--good); }
.state-Productive { background: rgba(224,177,90,0.2); color: var(--warm); }

/* sheet (capture) */
.sheet-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,0.55); z-index: 40;
  display: flex; align-items: flex-end; }
.sheet { background: var(--surface); width: 100%; max-width: var(--maxw); margin: 0 auto;
  border-radius: 20px 20px 0 0; padding: 20px 18px calc(24px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line); }
.sheet h2 { margin-top: 0; }
/* A bottom sheet is a phone ergonomic (thumb reach); on desktop-width screens
   it feels detached from the control you clicked, so the sheet drops from the
   top instead — rounded bottom corners, flush to the top edge. */
@media (min-width: 900px) {
  .sheet-backdrop { align-items: flex-start; }
  .sheet { border-radius: 0 0 20px 20px; padding: 20px 18px 24px;
    border-top: none; border-bottom: 1px solid var(--line); }
}

.evidence-bar { height: 6px; background: var(--surface-3); border-radius: 3px; overflow: hidden; margin: 4px 0; }
.evidence-bar > span { display: block; height: 100%; background: var(--accent-2); }

.list-plain { list-style: none; padding: 0; margin: 0.4em 0; }
.list-plain li { padding: 6px 0; border-bottom: 1px solid var(--line); }
.list-plain li:last-child { border-bottom: none; }

.hero { padding: 28px 4px; }
hr { border: none; border-top: 1px solid var(--line); margin: 18px 0; }
