/* ── Screens ──────────────────────────────────────────────────────────────
   Title, chapter list, daily calendar, victory. Composition only — every
   colour, size and duration comes from tokens.css; every shared part comes
   from components.css.                                                     */

html, body, #app { height: 100%; width: 100%; overflow: hidden; }

.app { position: relative; display: flex; flex-direction: column; }

.screen {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
}
/* the plain entrance fade, applied only as a class so it never re-fires when a
   transition class is later removed (that re-fire was the settle "blink") */
.screen.pg-fade { animation: fade 0.2s var(--ease) both; }

/* ── page transitions ─────────────────────────────────────────────────────
   Navigation descends a tree. The deeper (child) page rides in and out on the
   right edge; the shallower (parent) page rides the depth axis — receding and
   dimming underneath as a child covers it, then rising back to the front as the
   child leaves. Forward: parent recedes + fades, child moves in from the right +
   fades in. Back: child moves off right + fades out, parent returns from beneath
   + fades in. The child always sits above the parent. */
@keyframes pg-child-in   { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
@keyframes pg-child-out  { from { transform: translateX(0);    opacity: 1; } to { transform: translateX(100%); opacity: 0; } }
@keyframes pg-parent-out { from { transform: scale(1);    opacity: 1; } to { transform: scale(0.9); opacity: 0; } }
@keyframes pg-parent-in  { from { transform: scale(0.9); opacity: 0; } to { transform: scale(1);   opacity: 1; } }
#app.is-transitioning > .pg-child-in   { animation: pg-child-in var(--duration-page) var(--ease) both; z-index: var(--z-chrome); }
#app.is-transitioning > .pg-child-out  { animation: pg-child-out var(--duration-page) var(--ease) both; z-index: var(--z-chrome); }
#app.is-transitioning > .pg-parent-out { animation: pg-parent-out var(--duration-page) var(--ease) both; z-index: var(--z-panel); }
#app.is-transitioning > .pg-parent-in  { animation: pg-parent-in var(--duration-page) var(--ease) both; z-index: var(--z-panel); }
@media (prefers-reduced-motion: reduce) {
  #app.is-transitioning > [class*="pg-"], .screen.pg-fade { animation: none; }
}

.scroll {
  flex: 1; overflow-y: auto; overscroll-behavior: contain;
  padding: 0 var(--space-8) var(--space-11);
}

/* Everything that names something the circuit would also name. */
.eyebrow, .nav h1, .chapter-head .name, .subtitle, .card-name, .counter .k,
.level-tile .idx, .chapter-tag, .cal-dow span {
  font-family: var(--font-mono);
  font-weight: 400;
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
}

/* ── nav ──────────────────────────────────────────────────────────────── */

/* The app bar: one bar, every page — solid surface, hairline divider,
   GHOST icon buttons (no floating boxes; the icon is the button). */
.nav {
  display: flex; align-items: center; gap: var(--space-3);
  min-height: calc(56px + var(--sat));
  padding: calc(var(--space-3) + var(--sat)) var(--space-5) var(--space-3);
  flex: none;
  background: var(--bg);
  border-bottom: var(--hairline) solid var(--line);
}
.nav h1 { font-size: var(--text-sm); color: var(--mute); margin-left: var(--space-2); }
.nav .spacer { flex: 1; }
.nav .icon-btn, .title-theme .icon-btn, .ah-top-acts .icon-btn {
  border-color: transparent; background: none;
}
.nav .icon-btn:hover:not(:disabled),
.title-theme .icon-btn:hover:not(:disabled),
.ah-top-acts .icon-btn:hover:not(:disabled) {
  background: var(--surface); border-color: transparent;
}
.nav .icon-btn:active,
.title-theme .icon-btn:active,
.ah-top-acts .icon-btn:active { background: var(--surface-2); }

/* ── title ────────────────────────────────────────────────────────────── */

.title-screen {
  align-items: center; padding: var(--space-9);
  /* Centred WITHOUT justify-content:center: when the home is taller than the
     viewport (landscape phone, short laptop window) centred flex clips both
     ends unreachably. Auto-margin struts centre the pack when there is room
     and collapse to 0 when there is not — then the screen just scrolls. */
  justify-content: flex-start; overflow-y: auto;
}
.title-screen::before, .title-screen::after { content: ''; margin: auto 0; flex: none; }

.logo-mark { width: 60px; height: 60px; margin-bottom: 28px; }
.logo-mark svg { width: 100%; height: 100%; overflow: visible; }
.logo-mark path, .logo-mark circle, .logo-mark line {
  fill: none; stroke: var(--text); stroke-width: 3; stroke-linecap: round;
}
.logo-mark circle { fill: var(--accent); stroke: var(--accent); }

.title {
  font-family: var(--font-mono);
  font-size: var(--text-3xl);
  font-weight: 500;
  letter-spacing: var(--tracking-title);
  text-indent: var(--tracking-title);
  text-transform: uppercase;
}
.title em { font-style: normal; color: var(--accent); }

.subtitle { margin-top: var(--space-5); font-size: var(--text-xs); color: var(--mute); }

/* ── daily-streak flame (beside the title) ────────────────────────────────
   The streak sits to the left of the game's title; when there's no flame the
   row still centres the title on its own. */
.title-row { display: flex; align-items: center; justify-content: center; gap: var(--space-4); }

/* A Lottie flame (the animation lives in the SVG lottie-web mounts). The box is
   the flame's true aspect (300×436 ≈ 0.69); the number and shield ride on top. */
.flame {
  position: relative; flex: none; display: inline-flex; vertical-align: middle;
  width: var(--flame-size); height: calc(var(--flame-size) * 1.8);
}
.flame-lottie { position: absolute; inset: 0; }
.flame-lottie svg { display: block; width: 100% !important; height: 100% !important; }

/* One gold animation, hue-rotated to each tier; the bright tiers keep a glow
   (drawn before the rotate, so the warm glow turns the tier's colour too). */
.flame-gold .flame-lottie { filter: drop-shadow(0 0 4px var(--flame-glow)); }
.flame-red .flame-lottie { filter: drop-shadow(0 0 4px var(--flame-glow)) hue-rotate(-32deg) saturate(1.18); }
.flame-green .flame-lottie { filter: hue-rotate(86deg) saturate(0.9); }
.flame-purple .flame-lottie { filter: drop-shadow(0 0 5px var(--flame-glow)) hue-rotate(214deg) saturate(1.55) brightness(1.02); }

/* the day count, reading from the flame's lower belly */
.flame-n {
  position: absolute; inset: 0;
  display: flex; align-items: flex-end; justify-content: center;
  padding-bottom: 18%;
  font-family: var(--font-mono); font-weight: 600;
  font-size: calc(var(--flame-size) * 0.4); line-height: 1;
  color: var(--flame-ink);
  text-shadow: 0 1px 2px var(--flame-ink-edge);
  pointer-events: none;
}

/* the grace shield with its days-left count, pinned to the flame's lower-right */
.flame-guard {
  position: absolute; right: -14%; bottom: 4%;
  width: 56%; height: 56%;
  animation: flame-guard-in var(--t) ease-out both;
  pointer-events: none;
}
.flame-guard svg {
  width: 100%; height: 100%;
  fill: var(--flame-shield-fill); stroke: var(--flame-shield-line); stroke-width: 1.4;
  filter: drop-shadow(0 1px 2px var(--flame-ink-edge));
}
.flame-guard-n {
  position: absolute; inset: 0; padding-bottom: 6%;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-weight: 700;
  font-size: calc(var(--flame-size) * 0.2); line-height: 1;
  color: var(--flame-shield-line);
}

@keyframes flame-guard-in {
  from { opacity: 0; transform: scale(0.4) translateY(3px); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}

.title-rule { width: 1px; height: 48px; margin: 36px 0; background: var(--line-2); }

.mode-list { display: flex; flex-direction: column; gap: 1px; width: min(400px, 100%); }

.mode-card {
  display: flex; align-items: center; gap: var(--space-6);
  padding: 18px var(--space-7);
  border: var(--hairline) solid var(--line);
  text-align: left;
  transition: var(--t);
}
.mode-card:first-child { border-radius: var(--radius) var(--radius) 0 0; }
.mode-card:last-child { border-radius: 0 0 var(--radius) var(--radius); }
.mode-card + .mode-card { border-top: 0; }
.mode-card:hover { background: var(--surface); border-color: var(--line-2); }
.mode-card:hover + .mode-card { border-top-color: var(--line-2); }

.mode-card .glyph { width: var(--icon-lg); height: var(--icon-lg); flex: none; color: var(--dim); }
.mode-card .glyph svg {
  width: var(--icon-lg); height: var(--icon-lg);
  fill: none; stroke: currentColor; stroke-width: 1.4;
  stroke-linecap: round; stroke-linejoin: round;
}
.mode-card:hover .glyph { color: var(--accent); }

.mode-card .txt strong {
  display: block; font-size: var(--text-lg); font-weight: 500;
  letter-spacing: 0.01em; margin-bottom: var(--space-1);
}
.mode-card .txt span { font-size: var(--text-base); color: var(--mute); }
.mode-card .chev { margin-left: auto; color: var(--mute); }
.mode-card .chev svg { width: var(--icon-sm); height: var(--icon-sm); fill: none; stroke: currentColor; stroke-width: var(--stroke); }

/* ── game home on its own material: board hero + two smart action buttons ──
   --gh-paper/ink/line/pop are the material contract; a game with a material maps
   them onto its own tokens (set inline), the rest fall back to the app field. */
.gh { --gh-paper: var(--bg); --gh-ink: var(--text); --gh-line: var(--line); --gh-pop: var(--accent); }
.gh-mat { background: var(--gh-paper); gap: 0; padding: var(--space-8); }
/* no justify-content:center here — .title-screen's auto-margin struts centre it
   safely; re-centring would bring back the both-ends clip on short viewports */
/* narrow phones: the flowing content starts at the very top when it overflows,
   which slides the marque card under the absolute back/learn/trophy row —
   reserve that row's band */
@media (max-width: 380px) {
  .gh-mat { padding-top: calc(var(--space-8) + 48px); }
}
.gh-mat .title { color: var(--gh-ink); }
.gh-mat .title-eyebrow { color: var(--gh-pop); }
.gh-mat .subtitle { color: var(--gh-ink); opacity: 0.62; }
.gh-mat .icon-btn { color: var(--gh-ink); }
.gh-mat .title-icon { margin-bottom: var(--space-4); border-radius: 14px; outline: 1.5px solid var(--gh-line); }

/* the board hero — the player's next board, big and tappable (morphs into play) */
.gh2-hero { width: min(220px, 60%); margin: var(--space-5) 0 var(--space-3); cursor: pointer; }
.gh2-hero > * { width: 100%; transition: transform 120ms var(--ease); }
.gh2-hero:hover > * { transform: scale(1.02); }

/* the two hero buttons */
.gh2-acts { display: flex; flex-direction: column; gap: var(--space-4); width: min(400px, 100%); margin-top: var(--space-6); }
.gh2-act { display: flex; align-items: center; gap: var(--space-5); text-align: left;
  padding: 16px var(--space-6); border: var(--hairline) solid var(--gh-line); border-radius: var(--radius);
  background: color-mix(in srgb, var(--gh-paper) 86%, var(--gh-ink)); transition: var(--t); }
.gh2-act:hover { border-color: var(--gh-pop); background: color-mix(in srgb, var(--gh-paper) 78%, var(--gh-ink)); }
.gh2-story { border-color: color-mix(in srgb, var(--gh-pop) 55%, var(--gh-line)); }
.gh2-ring { flex: none; display: inline-flex; }
.gh2-ring .ring-center { color: var(--gh-ink); }
.gh2-glyph { width: 46px; height: 46px; display: grid; place-items: center; color: var(--gh-ink); opacity: 0.7; }
.gh2-glyph svg { width: 24px; height: 24px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.gh2-b { flex: 1; min-width: 0; }
.gh2-k { display: block; font-family: var(--font-mono); font-size: 9px; letter-spacing: var(--tracking-wide);
  text-transform: uppercase; color: var(--gh-pop); margin-bottom: 3px; }
.gh2-b strong { display: block; font-size: var(--text-lg); font-weight: 500; color: var(--gh-ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gh2-b small { display: block; font-size: var(--text-2xs); color: var(--gh-ink); opacity: 0.58; margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gh2-go { flex: none; color: var(--gh-ink); opacity: 0.45; }
.gh2-go svg { width: var(--icon-sm); height: var(--icon-sm); fill: none; stroke: currentColor; stroke-width: var(--stroke); }

/* chapter pips + the streak/chapter line */
.gh2-foot { width: min(400px, 100%); margin-top: var(--space-6); display: flex; flex-direction: column; align-items: center; gap: var(--space-3); }
.gh2-pips { display: flex; gap: 5px; flex-wrap: wrap; justify-content: center; max-width: 100%; padding: 0 var(--space-6); }
.gh2-pip { width: 22px; height: 4px; border-radius: 2px; background: var(--gh-line); position: relative; overflow: hidden; }
.gh2-pip.part::after, .gh2-pip.full::after { content: ''; position: absolute; inset: 0; width: var(--f); background: var(--gh-pop); }
.gh2-pip.full { background: var(--gh-pop); }
.gh2-pip.shut { opacity: 0.4; }
.gh2-pip.here { outline: 1.5px solid var(--gh-pop); outline-offset: 1.5px; }
.gh2-chap { font-family: var(--font-mono); font-size: 10px; letter-spacing: var(--tracking-wide); color: var(--gh-ink); opacity: 0.55; }

/* the flying board clone for the home→play hero morph (hero.js) */
.hero-fly { position: fixed; margin: 0; z-index: 200; pointer-events: none; transform-origin: center; will-change: transform; }

/* Install sits beside the theme switch, and is absent on a device that has
   already installed — so this is one button as often as it is two. */
.title-theme {
  position: absolute; top: calc(var(--space-8) + var(--sat));
  /* hug the 640px content column once the window outgrows it, so the gear
     stays aligned with the list instead of drifting to the far edge */
  right: max(var(--space-8), calc((100% - var(--wrap)) / 2));
  display: flex; gap: var(--space-3);
}

/* The account chip and the star count sit together at the end of the centred
   column, in normal flow — so they can never overlap the content above them
   the way an absolutely-positioned footer did on short screens. */
.title-foot {
  margin-top: var(--space-10);
  display: flex; flex-direction: column; align-items: center; gap: var(--space-4);
}
.title-stars {
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide); color: var(--mute);
}

/* the Circuits home reads as one game under the Logigates umbrella */
.title-back { position: absolute; top: calc(var(--space-8) + var(--sat)); left: var(--space-8); }
.title-eyebrow {
  font-family: var(--font-mono); font-size: var(--text-2xs);
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  color: var(--accent); margin-bottom: var(--space-3);
}

/* ── hub: the launcher for every little game ──────────────────────────── */

.hub-scroll { padding-top: calc(var(--space-9) + var(--sat)); }
.hub-head {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  margin-bottom: var(--space-9);
}
.hub-head .subtitle { margin-top: var(--space-4); }
/* The hub is a directory: sb-brand over the full games list (sb-glist), with a
   sign-in card in between only when signed out. Every value a token; the
   max-640 column collapses full-width on a phone. */

.sb-brand { display: flex; align-items: center; gap: var(--space-5);
  max-width: var(--wrap); margin: 0 auto var(--space-8); }
.sb-brand-logo { width: 26px; height: 26px; flex: none; }
.sb-brand-logo svg { width: 100%; height: 100%; }
.sb-brand-logo path, .sb-brand-logo circle, .sb-brand-logo line { fill: none; stroke: var(--text); stroke-width: 3; }
.sb-brand-logo circle { fill: var(--accent); stroke: var(--accent); }
.sb-brand-h { margin: 0; font-family: var(--font-mono); font-size: var(--text-lg); font-weight: 500;
  letter-spacing: var(--tracking-label); text-transform: uppercase; }
.sb-brand-s { margin: var(--space-2) 0 0; font-size: var(--text-base); color: var(--mute); }
.sb-sec { display: flex; align-items: center; gap: var(--space-4);
  margin: var(--space-8) auto var(--space-5); max-width: var(--wrap);
  font-family: var(--font-mono); font-size: var(--text-2xs);
  letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--mute); font-weight: 400; }
.sb-sec::after { content: ''; flex: 1; height: var(--hairline); background: var(--line); }

/* ── sign-in card: the only thing above the games list, and only when signed out ── */
.sb-caught { display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--space-4);
  max-width: 480px; margin: var(--space-10) auto 0; }
.sb-caught-ic { width: 44px; height: 44px; opacity: 0.7; }
.sb-caught-ic svg { width: 100%; height: 100%; }
.sb-caught-ic path, .sb-caught-ic circle, .sb-caught-ic line { fill: none; stroke: var(--text); stroke-width: 3; }
.sb-caught-ic circle { fill: var(--accent); stroke: var(--accent); }
.sb-caught strong { font-size: var(--text-xl); font-weight: 500; }
.sb-caught p { margin: 0; font-size: var(--text-base); color: var(--mute); line-height: var(--leading-body); }
.sb-signin {
  margin-top: var(--space-5); border: 0; cursor: pointer;
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: var(--space-4) var(--space-6); border-radius: var(--radius);
  background: var(--accent); color: var(--on-accent);
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-label); text-transform: uppercase;
}
.sb-signin .chev { display: inline-flex; }
.sb-signin .chev svg { width: var(--icon-sm); height: var(--icon-sm); fill: none; stroke: currentColor; stroke-width: var(--stroke); }
.sb-signin svg { width: var(--icon-sm); height: var(--icon-sm); fill: none; stroke: currentColor; stroke-width: var(--stroke); }

/* ── the free-play wall (ui/playgate.js): five signed-out games a day, then this ── */
.pg-wall { display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: var(--space-4); max-width: 420px; margin: 16vh auto 0; padding: var(--space-7); }
.pg-wall-ic { width: 44px; height: 44px; opacity: 0.7; }
.pg-wall-ic svg { width: 100%; height: 100%; }
.pg-wall-ic path, .pg-wall-ic circle, .pg-wall-ic line { fill: none; stroke: var(--text); stroke-width: 3; }
.pg-wall-ic circle { fill: var(--accent); stroke: var(--accent); }
.pg-wall strong { font-size: var(--text-xl); font-weight: 500; }
.pg-wall p { margin: 0; font-size: var(--text-base); color: var(--mute); line-height: var(--leading-body); }

/* ── the games list: a CARD grid, same family as the arena's game picker ──
   Icon on top, name beneath, rings at the foot. The .sb-glrow element keeps
   its name (the long-press menu, grip reorder and hidden shelf all target it)
   — only its clothes changed from table row to picker card. */
.sb-glist { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: var(--space-3); max-width: var(--wrap); margin: 0 auto; }
.sb-glrow {
  position: relative;
  display: flex; flex-direction: column;
  background: var(--surface);
  border: var(--hairline) solid var(--line);
  border-radius: var(--radius);
  transition: var(--t);
}
.sb-gl-go {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; align-items: center; gap: var(--space-2);
  padding: var(--space-5) var(--space-2) var(--space-3);
  text-align: center;
}
.sb-glrow.hid { opacity: 0.45; }
/* the long-press row menu: quiet settings-style rows, not shouting pills */
.sb-menu { display: flex; flex-direction: column; margin-top: var(--space-5); }
.sb-mi {
  display: flex; align-items: center; gap: var(--space-6); width: 100%; text-align: left;
  padding: var(--space-6) var(--space-3);
  font-size: var(--text-lg); color: var(--text);
  border-bottom: var(--hairline) solid var(--line);
  transition: var(--t); border-radius: var(--radius-sm);
}
.sb-mi:last-child { border-bottom: 0; }
.sb-mi:hover { background: var(--surface-2); }
.sb-mi:active { background: var(--surface); }
.sb-mi-ic { flex: none; width: 22px; height: 22px; display: grid; place-items: center; color: var(--mute); }
.sb-mi-ic svg { width: 19px; height: 19px; fill: none; stroke: currentColor; stroke-width: var(--stroke); stroke-linecap: round; stroke-linejoin: round; }
/* the reorder grip rides the card's top-left corner */
.sb-grip { position: absolute; top: 2px; left: 2px; z-index: 2;
  width: 28px; height: 28px; display: grid; place-items: center;
  color: var(--dim); cursor: grab; touch-action: none; }
.sb-grip svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-linecap: round; }
/* the lifted card rides the pointer; its old slot stays open as a soft well */
.sb-glrow.sb-lifted {
  background: var(--surface);
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.35), 0 0 0 var(--hairline) var(--line-2);
  transform: scale(1.04);
  z-index: 40;
}
.sb-ph { border-radius: var(--radius); background: var(--surface-2);
  border: var(--hairline) dashed var(--line-2); }
body.sb-grabbing, body.sb-grabbing * { cursor: grabbing !important; user-select: none; }
.sb-glrow:not(.soon):hover { border-color: var(--accent-line); background: var(--surface-2); }
.sb-glrow.soon {
  opacity: 0.5;
  display: flex; flex-direction: column; align-items: center; gap: var(--space-2);
  padding: var(--space-5) var(--space-2) var(--space-4);
  text-align: center;
}
.sb-gl-ic { width: 46px; height: 46px; flex: none; }
.sb-gl-ic svg { width: 100%; height: 100%; }
.sb-gl-name {
  font-family: var(--font-mono); font-size: var(--text-2xs); font-weight: 500;
  letter-spacing: var(--tracking-label); color: var(--text);
  line-height: var(--leading-tight);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;
}
.sb-glrow.soon .sb-gl-name { color: var(--dim); }
/* rings foot: a fixed-height slot so cards line up whether or not rings exist */
.sb-gl-rings { display: flex; align-items: center; justify-content: center;
  gap: var(--space-3); min-height: 28px; }
.sb-gl-slot { display: grid; place-items: center; }
.sb-gl-slot:empty { display: none; }
/* unplayed card: a faint ring outline instead of a blank band, so the foot
   reads "nothing yet" rather than "something failed to load" */
.sb-gl-slot.sb-gl-zero { display: block; width: 26px; height: 26px;
  border-radius: var(--radius-full); border: 1.5px dashed var(--line-2); }
.sb-gl-rings:has(.sb-gl-slot:not(.sb-gl-zero):not(:empty)) .sb-gl-zero { display: none; }
.sb-gl-tag { display: inline-flex; align-items: center; gap: 4px;
  font-family: var(--font-mono); font-size: var(--text-2xs);
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--mute);
  min-height: 28px; }
.sb-gl-tag svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: var(--stroke); }
.sb-gl-lock svg { width: var(--icon); height: var(--icon); fill: none; stroke: currentColor; stroke-width: var(--stroke); }

/* the story-ring count sits inside a ring on the games list and the game home */
.gc-rn { font-family: var(--font-mono); font-size: var(--text-2xs); font-weight: 500; color: var(--dim); }

/* ── phone ── */
@media (max-width: 520px) {
  .sb-brand, .sb-sec, .sb-glist { max-width: none; }
}

/* the puzzle-scene marque icon — shared by hub cards and each game's home */
.game-icon { display: block; width: 100%; height: 100%; }

/* the game home wears its icon large, above the title */
.title-icon { width: 76px; height: 76px; margin-bottom: var(--space-5); }

.hub-foot { display: flex; justify-content: center; margin-top: var(--space-9); }

/* ── chapters ─────────────────────────────────────────────────────────── */

.chapter { margin: 0 auto var(--space-10); max-width: 720px; }
/* a chapter you have not reached shows its name and keeps its levels to itself */
.chapter.shut { margin-bottom: 18px; }
.chapter.shut .chapter-head { border-bottom-color: transparent; margin-bottom: 0; }
.chapter.shut .chapter-head .name { color: var(--dim); }

.chapter-head {
  display: flex; align-items: center; gap: var(--space-6);
  padding-bottom: var(--space-5);
  border-bottom: var(--hairline) solid var(--line);
  margin-bottom: 18px;
}
.chapter-head .greek {
  font-family: var(--font-mono); font-size: var(--text-2xl);
  font-weight: 400; line-height: 1;
  color: var(--accent); min-width: 26px;
}
.chapter-head .greek.locked { color: var(--mute); }
.chapter-head .name { font-size: var(--text-sm); color: var(--text); }
.chapter-head .name small {
  display: block; margin-top: var(--space-2);
  font-family: var(--font-sans); font-size: var(--text-base); font-weight: 400;
  letter-spacing: var(--tracking-none); text-transform: none; color: var(--mute);
}
.chapter-head .tally {
  margin-left: auto;
  font-family: var(--font-mono); font-size: var(--text-md); color: var(--mute);
}
.chapter-head .tally b { color: var(--text); font-weight: 400; }

.level-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(116px, 1fr)); gap: var(--space-4); }

.level-tile {
  position: relative;
  aspect-ratio: 1 / 0.92;
  display: flex; flex-direction: column;
  align-items: flex-start; justify-content: space-between;
  padding: var(--space-5);
  border: var(--hairline) solid var(--line);
  border-radius: var(--radius);
  transition: var(--t);
  text-align: left;
}
.level-tile:not(.locked):hover { border-color: var(--line-2); background: var(--surface); }
.level-tile .idx { font-size: var(--text-2xs); color: var(--mute); }
.level-tile .ttl { font-size: var(--text-base); line-height: var(--leading-tight); color: var(--text); }
.level-tile.locked { opacity: 0.35; }
.level-tile .lock { position: absolute; top: 11px; right: 11px; color: var(--mute); }
.level-tile .lock svg { width: var(--icon-sm); height: var(--icon-sm); fill: none; stroke: currentColor; stroke-width: var(--stroke); }

/* ── story: chapters as cards ─────────────────────────────────────────── */

.chapter-grid, .lvcard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--space-5);
  max-width: 720px; margin: 0 auto;
}

.chapter-card {
  position: relative;
  aspect-ratio: 1 / 1;
  display: flex; flex-direction: column;
  align-items: flex-start; justify-content: space-between;
  padding: var(--space-6);
  border: var(--hairline) solid var(--line);
  border-radius: var(--radius);
  transition: var(--t);
  text-align: left;
  animation: pop var(--duration-2) var(--ease) both;
}
.chapter-card:not(.locked):hover { border-color: var(--line-2); background: var(--surface); }
.chapter-card.locked { opacity: 0.35; }

.cc-mark {
  font-family: var(--font-mono); font-size: var(--text-2xl);
  line-height: 1; color: var(--accent); margin-top: var(--space-2);
}
.cc-lock { color: var(--mute); }
.cc-lock svg { width: var(--icon-lg); height: var(--icon-lg); fill: none; stroke: currentColor; stroke-width: var(--stroke); }
.cc-name { font-size: var(--text-lg); color: var(--text); line-height: var(--leading-tight); }
.cc-tally {
  font-family: var(--font-mono); font-size: var(--text-md); color: var(--mute);
}
.cc-tally b { color: var(--text); font-weight: 400; }

/* ── story: the ROAD (chapters as stops on a spine + a Resume button) ──── */

.rd { padding-top: 2px; max-width: var(--wrap); margin: 0 auto; width: 100%; }

/* the Resume button — the one thing a returning player wants, at the top */
.resume { display: flex; align-items: center; gap: var(--space-4); width: 100%; text-align: left;
  padding: var(--space-4) var(--space-5); margin-bottom: var(--space-7);
  border: var(--hairline) solid var(--accent-line); border-radius: var(--radius-lg);
  background: var(--accent-dim); color: inherit; cursor: pointer; transition: var(--t); }
.resume:hover { border-color: var(--accent); }
.resume .cc-glyph { color: var(--accent); }
.resume-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.resume-k { font-family: var(--font-mono); font-size: var(--text-2xs); letter-spacing: var(--tracking-wide);
  text-transform: uppercase; color: var(--accent); }
.resume-nm { font-size: var(--text-lg); color: var(--text); line-height: var(--leading-tight); }
.resume-sub { font-size: var(--text-base); color: var(--dim); }
.resume-go { flex: none; font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  background: var(--accent); color: var(--on-accent); border-radius: var(--radius);
  padding: var(--space-3) var(--space-4); }

/* the spine: stops with no gaps between them so the rail runs continuous */
.rd-spine { display: flex; flex-direction: column; }
.rd-stop { position: relative; display: flex; gap: var(--space-4); width: 100%; text-align: left;
  padding: 0; background: none; border: 0; color: inherit; cursor: pointer; }
.rd-stop:disabled { cursor: default; }
/* the rail runs from this node down to the NEXT node's centre so the segments
   join into one line (starts below this node, ends at the next node's centre),
   drawn behind the ring either way */
.rd-rail { position: absolute; left: 19px; top: 40px; bottom: -20px; width: 2px; background: var(--accent); }
.rd-stop.current .rd-rail, .rd-stop.ahead .rd-rail, .rd-stop.locked .rd-rail {
  background: none; border-left: 2px dashed var(--line-2); width: 0; }
.rd-spine .rd-stop:last-child .rd-rail { display: none; }
/* the node sits ABOVE the rail with an opaque disc at the page-ground colour
   behind its ring/lock, so the dashed rail connects BETWEEN stops instead of
   running through the ring's hollow centre */
.rd-node { flex: none; width: 40px; display: grid; place-items: center; position: relative; z-index: 1; }
.rd-node::before { content: ''; position: absolute; width: 30px; height: 30px;
  border-radius: var(--radius-full); background: var(--bg); z-index: -1; }
.rd-node .cc-lock { color: var(--mute); }
.rd-node .cc-lock svg { width: var(--icon-lg); height: var(--icon-lg); fill: none; stroke: currentColor; stroke-width: var(--stroke); }
.rd-body { flex: 1; min-width: 0; padding: 2px 0 var(--space-6); display: flex; flex-direction: column; gap: var(--space-2); }
.rd-name { font-size: var(--text-lg); color: var(--text); line-height: var(--leading-tight); }
.rd-stop.cleared .rd-name, .rd-stop.locked .rd-name { color: var(--dim); }
.rd-stop.current .rd-name { color: var(--accent); font-weight: 500; }
.rd-teach { font-size: var(--text-base); color: var(--dim); line-height: var(--leading-body); }
.rd-stop.locked .rd-teach, .rd-stop.cleared .rd-teach { color: var(--mute); }
.rd-foot { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.rd-here { font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--on-accent); background: var(--accent);
  padding: 2px 6px; border-radius: var(--radius-sm); }
.rd-stop.locked { opacity: 0.6; }

/* progress pips + inline notes on a stop */
.pips { display: flex; gap: 3px; flex-wrap: wrap; }
.pip { width: 6px; height: 6px; border-radius: var(--radius-full); background: var(--line-2); flex: none; }
.pip.on { background: var(--accent); }
.pip.next { background: none; box-shadow: inset 0 0 0 1.5px var(--accent); }
.note { font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--mute); }
.note.left { color: var(--red); }
.note.done { display: inline-flex; align-items: center; gap: 4px; color: var(--accent); }
.note.done svg { width: 11px; height: 11px; fill: none; stroke: currentColor; stroke-width: 2; }

/* ── one chapter: levels as cards with a truth-table thumbnail ─────────── */

.lvcard {
  position: relative;
  display: flex; flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-5);
  border: var(--hairline) solid var(--line);
  border-radius: var(--radius);
  transition: var(--t);
  text-align: left;
  animation: pop var(--duration-2) var(--ease) both;
}
.lvcard:not(.locked):hover { border-color: var(--line-2); background: var(--surface); }
.lvcard.locked { opacity: 0.35; }

.lvcard-top { display: flex; align-items: center; justify-content: space-between; }
.lvcard-idx { font-family: var(--font-mono); font-size: var(--text-2xs); color: var(--mute); }
.lvcard-ttl { font-size: var(--text-base); line-height: var(--leading-tight); color: var(--text); }

.lvcard-mini {
  display: flex; align-items: center; justify-content: center;
  min-height: 60px; overflow: hidden;
  padding: var(--space-4) 0;
  border-top: var(--hairline) solid var(--line);
  border-bottom: var(--hairline) solid var(--line);
}
.lvcard-lock { color: var(--mute); }
.lvcard-lock svg { width: var(--icon-lg); height: var(--icon-lg); fill: none; stroke: currentColor; stroke-width: var(--stroke); }

/* the shared truth table, shrunk to a fingerprint of the goal */
.lvcard-mini .ttable { font-size: 7px; }
.lvcard-mini .ttable th, .lvcard-mini .ttable td { padding: 1px 2px; }
.lvcard-mini .cell-switch, .lvcard-mini .cell-led { height: 10px; }

/* ── one chapter: NEXT UP (one hero + a fluid shelf of solved boards) ──── */

.nu { max-width: var(--wrap); margin: 0 auto; }

/* the hero: the next level, big */
.nu-hero { position: relative; display: flex; gap: var(--space-6); flex-wrap: wrap;
  padding: var(--space-6); margin-bottom: var(--space-7);
  border: var(--hairline) solid var(--accent-line); border-radius: var(--radius-lg);
  background: var(--accent-dim); cursor: pointer; transition: var(--t); }
.nu-hero:not(.done):hover { border-color: var(--accent); }
.nu-hero-board { flex: 0 0 clamp(116px, 34%, 168px); align-self: flex-start;
  aspect-ratio: 1; display: grid; place-items: center; overflow: hidden; border-radius: var(--radius); }
.nu-hero-board > * { width: 100%; }
/* .no-mini (Nonogram) is a hard 44×44; let it fill the big hero frame instead */
.nu-hero-board .no-mini { width: 100%; height: auto; aspect-ratio: 1; }
.nu-hero-board .ttable { font-size: 11px; }
.nu-hero-side { flex: 1 1 200px; display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.nu-kick { font-family: var(--font-mono); font-size: var(--text-2xs); letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--accent); }
.nu-tag { margin: 0; font-size: var(--text-xl); font-weight: 400; line-height: var(--leading-tight); color: var(--text); }
.nu-teach { margin: 0; font-size: 13px; line-height: 1.55; color: var(--dim);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.nu-cta { display: flex; align-items: center; gap: var(--space-5); margin-top: auto; padding-top: 6px; }
.nu-play { flex: none; }
.nu-pos { font-family: var(--font-mono); font-size: var(--text-2xs); color: var(--mute); }
.nu-hero.done { border-color: var(--line); background: var(--surface); cursor: default; }
.nu-hero.done .nu-kick { color: var(--dim); }

/* the solved shelf: fluid tiles that fill the column at any width */
.nu-shelf-h { display: flex; align-items: baseline; gap: 8px; margin: 0 0 var(--space-4); }
.nu-shelf-h span { font-family: var(--font-mono); font-size: var(--text-2xs);
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--mute); }
.nu-shelf-h .nu-count { color: var(--dim); }
.nu-shelf { display: grid; grid-template-columns: repeat(auto-fill, minmax(66px, 1fr));
  gap: var(--space-5); margin-bottom: var(--space-6); }
.nu-tile { margin: 0; display: flex; flex-direction: column; gap: 5px; }
.nu-tile-b { position: relative; aspect-ratio: 1; display: grid; place-items: center;
  padding: 5px; overflow: hidden; border: var(--hairline) solid var(--line);
  border-radius: var(--radius-sm); background: var(--surface); cursor: pointer; transition: var(--t); }
.nu-tile-b:hover { border-color: var(--line-2); }
.nu-tile-b > *:first-child { width: 100%; }
.nu-tile-b .no-mini { width: 100%; height: auto; aspect-ratio: 1; }
.nu-tile-b .ttable { font-size: 5px; margin: 0; table-layout: fixed; }
/* the base glyphs are 19px tall — eight rows of that is 170px in a 70px tile.
   The tile is a glance, exactly like the goal-mini: shrink everything. */
.nu-tile-b .ttable th, .nu-tile-b .ttable td { padding: 0.5px 1px; }
.nu-tile-b .cell-switch, .nu-tile-b .cell-led { height: 7px; }
.nu-tick { position: absolute; top: 3px; right: 3px; }
.nu-tick .pz-done svg { width: 11px; height: 11px; }
.nu-cap { display: flex; align-items: center; justify-content: space-between; gap: 4px; padding: 0 1px; }
.nu-cap .nu-t { font-family: var(--font-mono); font-size: 9px; color: var(--text); }
.nu-cap .nu-i { font-family: var(--font-mono); font-size: 8px; color: var(--mute); }
.nu-cap .stars svg { width: 8px; height: 8px; }

/* locked ahead: faint, count only */
.nu-locked { display: flex; align-items: center; justify-content: center; gap: 7px;
  padding: var(--space-5); border: var(--hairline) dashed var(--line); border-radius: var(--radius);
  font-size: 12px; color: var(--mute); }
.nu-locked .lvcard-lock svg { width: var(--icon-sm); height: var(--icon-sm); }
.nu-none { margin: 0 0 var(--space-6); padding: var(--space-6); text-align: center; font-size: 12px;
  color: var(--mute); border: var(--hairline) dashed var(--line); border-radius: var(--radius); }

/* ── circuits story: chapter accordion + horizontal level shelves ──────────
   The whole story on one screen. A chapter is a row (ring/lock · name · count ·
   chevron); the open one reveals its levels as one horizontal, snap-scrolled
   shelf of cards. States: locked (lock glyph, faint), solved (the player's own
   mini circuit + tick + stars), next (accent border + Play/Resume flag). */

.cs { max-width: 560px; margin: 0 auto; display: flex; flex-direction: column; }
.cs-ch { border-bottom: var(--hairline) solid var(--line); }
.cs-ch:last-child { border-bottom: none; }
.cs-head { display: flex; align-items: center; gap: var(--space-4); width: 100%;
  padding: var(--space-4) 2px; text-align: left; cursor: pointer; transition: var(--t); }
.cs-head:disabled { cursor: default; }
.cs-ch.locked .cs-head { opacity: 0.55; }
.cs-node { flex: none; display: grid; place-items: center; width: 40px; height: 40px; }
.cs-b { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cs-name { font-size: var(--text-base); color: var(--text); }
.cs-ch.open .cs-name { color: var(--accent); font-weight: 500; }
.cs-ch.locked .cs-name { color: var(--dim); }
.cs-sub { display: flex; align-items: center; gap: 6px; min-height: 13px; }
.cs-count { font-family: var(--font-mono); font-size: var(--text-2xs); color: var(--mute); }
.cs-chev { flex: none; color: var(--mute); transition: transform var(--t); }
.cs-chev svg { width: var(--icon); height: var(--icon); fill: none; stroke: currentColor;
  stroke-width: var(--stroke); stroke-linecap: round; stroke-linejoin: round; }
.cs-ch.open .cs-chev { transform: rotate(90deg); color: var(--accent); }

.cs-body { display: none; }
.cs-ch.open .cs-body { display: block; animation: pop var(--duration-2) var(--ease) both; }
.cs-strip { display: flex; gap: var(--space-4); overflow-x: auto; padding: 2px 2px var(--space-5);
  scroll-snap-type: x proximity; scrollbar-width: thin;
  /* the last card clips at the edge — fade it so "there's more" reads */
  mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 32px), transparent);
  -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 32px), transparent); }
.cs-lv { flex: none; width: 92px; display: flex; flex-direction: column; gap: 5px;
  text-align: left; cursor: pointer; scroll-snap-align: start; }
.cs-lv:disabled { cursor: default; }
.cs-lv-b { position: relative; aspect-ratio: 1; display: grid; place-items: center;
  padding: 5px; overflow: hidden; border: var(--hairline) solid var(--line);
  border-radius: var(--radius-sm); background: var(--surface); transition: var(--t); }
.cs-lv:not(:disabled):hover .cs-lv-b { border-color: var(--line-2); }
.cs-lv.next .cs-lv-b { border-color: var(--accent); }
.cs-lv.locked .cs-lv-b { opacity: 0.45; background: none; border-style: dashed; }
.cs-lv-b > *:first-child { width: 100%; }
.cs-lv-b .ttable { font-size: 5px; margin: 0; table-layout: fixed; }
.cs-lv-b .ttable th, .cs-lv-b .ttable td { padding: 0.5px 1px; }
.cs-lv-b .cell-switch, .cs-lv-b .cell-led { height: 7px; }
.cs-lock { display: grid; place-items: center; color: var(--mute); }
.cs-lock svg { width: var(--icon); height: var(--icon); fill: none; stroke: currentColor; stroke-width: var(--stroke); }
.cs-tick { position: absolute; top: 3px; right: 3px; }
.cs-tick .pz-done svg { width: 11px; height: 11px; }
.cs-lv-f { position: relative; display: flex; align-items: center; justify-content: space-between; gap: 4px;
  padding: 0 1px; min-height: 14px; }
.cs-lv-i { font-family: var(--font-mono); font-size: 8px; color: var(--mute); }
.cs-lv-f .stars svg { width: 8px; height: 8px; }
/* centred under its own card, so it never pairs visually with the NEXT card's id */
.cs-go { position: absolute; left: 50%; transform: translateX(-50%);
  font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--accent); }

/* ── calendar ─────────────────────────────────────────────────────────── */

.cal { max-width: 480px; margin: var(--space-4) auto; }
.cal-head {
  display: flex; align-items: center; justify-content: center;
  gap: 18px; margin-bottom: var(--space-7);
}
.cal-head .month {
  font-family: var(--font-mono); font-size: var(--text-md);
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  min-width: 180px; text-align: center;
}
.cal-dow { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--space-2); margin-bottom: var(--space-3); }
.cal-dow span { text-align: center; font-size: var(--text-2xs); color: var(--mute); }
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--space-2); }

/* the month carousel: a strip of full-width pages you drag between. We drive the
   track's translateX ourselves (no native scroll/snap), so paging is exact and
   prepending older months never fights the browser for the scroll position. */
.cal-carousel {
  overflow: hidden;
  touch-action: pan-y;                  /* vertical scroll stays the page's; we own the horizontal drag */
  overscroll-behavior: contain;
  user-select: none; cursor: grab;
}
.cal-carousel.dragging { cursor: grabbing; }
.cal-track { display: flex; will-change: transform; visibility: hidden; }
.cal-carousel.cal-ready .cal-track { visibility: visible; }
.cal-page { flex: 0 0 100%; min-width: 0; }
.cal-hint {
  text-align: center; margin-top: var(--space-4);
  font-size: var(--text-2xs); color: var(--mute);
  letter-spacing: var(--tracking-label); text-transform: uppercase;
}

.cal-cell {
  aspect-ratio: 1; border-radius: var(--radius-sm);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-3);
  border: var(--hairline) solid transparent;
  font-family: var(--font-mono); font-size: var(--text-md); color: var(--dim);
  transition: var(--t);
}
.cal-cell.blank { pointer-events: none; }
.cal-cell.play { border-color: var(--line); }
.cal-cell.play:hover { border-color: var(--line-2); background: var(--surface); }
.cal-cell.future { color: var(--mute); opacity: 0.3; pointer-events: none; }
.cal-cell.today { border-color: var(--accent-line); color: var(--accent); }
.cal-cell.done { background: var(--surface); border-color: var(--line-2); }
.cal-cell .dot { width: 3px; height: 3px; border-radius: var(--radius-full); background: var(--accent); opacity: 0; }
.cal-cell.done .dot { opacity: 1; }

/* ── daily, refined: streak hero + a carousel of three compact heatmaps ─── */

/* the tracker tile: rings · run number · (i) — no sentences */
.sb-flame-hero { display: flex; align-items: center; gap: var(--space-6);
  max-width: 480px; margin: var(--space-5) auto var(--space-6);
  padding: var(--space-5) var(--space-6); border: var(--hairline) solid var(--line);
  border-radius: var(--radius-lg); background: var(--surface); }
.sb-flame-hero .n { font-family: var(--font-mono); font-size: 44px; line-height: 1; color: var(--text); font-weight: 500; }
.sb-flame-hero .spacer { flex: 1; }
.sb-hero-info { align-self: flex-start; margin: calc(-1 * var(--space-2)) calc(-1 * var(--space-2)) 0 0; }

/* the shield box — moved off the main screen, built on demand behind the (i) */
.sb-shieldbox { max-width: 480px; margin: var(--space-6) auto 0; padding: var(--space-5) var(--space-6);
  border-left: 2px solid var(--cyan); border-radius: var(--radius);
  background: color-mix(in srgb, var(--cyan) 10%, transparent);
  font-size: var(--text-base); line-height: var(--leading-prose); color: var(--dim); }
.sb-shieldbox b { color: var(--text); font-weight: 500; }
.sb-shieldbox .hd { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-3); }
.sb-shieldbox .hd svg { width: 15px; height: 15px; fill: var(--cyan); }
.sb-shieldbox .hd span { font-family: var(--font-mono); font-size: var(--text-2xs);
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--cyan); }

/* one per-difficulty heatmap; --hc (its heat colour) is set inline per block */
.sb-hm { max-width: 480px; margin: 0 auto; padding: var(--space-6) 0 var(--space-4); border-top: var(--hairline) solid var(--line); }
.sb-hm:first-of-type { border-top: none; }
.sb-hm-head { display: flex; align-items: center; gap: var(--space-4); margin-bottom: var(--space-5); }
.sb-hm-dot { width: 11px; height: 11px; border-radius: var(--radius-full); background: var(--hc); flex: none; }
.sb-hm-name { font-family: var(--font-mono); font-size: var(--text-sm); letter-spacing: var(--tracking-label);
  text-transform: uppercase; color: var(--text); }
.sb-hm-head .spacer { flex: 1; }
.sb-hm-sub { font-family: var(--font-mono); font-size: var(--text-2xs); color: var(--mute); }
.sb-hm-play { display: inline-flex; align-items: center; gap: var(--space-3);
  min-height: 40px; padding: 6px 16px 6px 18px; border-radius: var(--radius-full);
  border: 1.4px solid var(--hc); background: none; color: var(--hc);
  font-family: var(--font-mono); font-size: var(--text-2xs); letter-spacing: var(--tracking-label);
  text-transform: uppercase; cursor: pointer; transition: var(--t); flex: none; }
.sb-hm-play:hover { background: var(--hc); color: var(--bg); }
.sb-hm-play svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.sb-hm-play.done { border-color: var(--line-2); color: var(--dim); }
.sb-hm-play.done:hover { background: none; color: var(--text); }
.sb-hm-play.locked { border-color: var(--line-2); color: var(--mute); }
.sb-hm-play.locked:hover { background: none; color: var(--dim); }

/* 14 columns — two weeks per row, so a month is ~2-3 rows; days flow
   chronologically (no weekday header), the date numeral a faint hint */
.sb-hm-grid { display: grid; grid-template-columns: repeat(14, 1fr); gap: 2px; max-width: 336px; margin: 0 auto; }
.sb-cell { position: relative; aspect-ratio: 1; border-radius: 3px; display: grid; place-items: center;
  border: 1px solid transparent; background: var(--surface); }
.sb-cell .cn { font-family: var(--font-mono); font-size: 7px; line-height: 1; color: var(--mute); opacity: 0.55; }
.sb-cell.on { background: var(--hc); border-color: var(--hc); }
.sb-cell.on .cn { color: var(--bg); opacity: 0.65; }
.sb-cell.open { background: color-mix(in srgb, var(--hc) 14%, transparent); border-style: dashed; border-color: var(--hc); }
.sb-cell.open .cn { color: var(--dim); opacity: 0.9; }
.sb-cell.shut { background: none; border-color: var(--line); }
.sb-cell.shut .cn { color: var(--mute); opacity: 0.5; }
.sb-cell.today { outline: 1.2px solid var(--text); outline-offset: 1px; }
.sb-cell.future { background: none; border-color: var(--line); opacity: 0.25; }
.sb-cell.future .cn { color: var(--mute); }
.sb-cell.pre { background: none; border: none; }
.sb-cell.pre .cn { opacity: 0.12; }

/* the shared month pager driving all three heatmaps */
.sb-cal2-head { display: flex; align-items: center; justify-content: center; gap: var(--space-5);
  margin: 0 auto var(--space-5); max-width: 300px; }
.sb-cal2-month { font-family: var(--font-mono); font-size: var(--text-sm);
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text);
  min-width: 150px; text-align: center; }
.sb-pg { width: 40px; height: 40px; flex: none; display: grid; place-items: center;
  border: var(--hairline) solid var(--line); border-radius: var(--radius-sm);
  background: none; color: var(--dim); cursor: pointer; transition: var(--t); }
.sb-pg:hover:not(:disabled) { border-color: var(--accent-line); color: var(--accent); }
.sb-pg:disabled { opacity: 0.25; cursor: default; }
.sb-pg svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: var(--stroke); stroke-linecap: round; stroke-linejoin: round; }
.sb-pg.next svg { transform: rotate(180deg); }
.sb-months { touch-action: pan-y; }
@keyframes sb-from-left  { from { transform: translateX(-26px); opacity: 0.25; } to { transform: none; opacity: 1; } }
@keyframes sb-from-right { from { transform: translateX(26px);  opacity: 0.25; } to { transform: none; opacity: 1; } }
.sb-months.from-left  { animation: sb-from-left  var(--duration-3) var(--ease); }
.sb-months.from-right { animation: sb-from-right var(--duration-3) var(--ease); }

/* tablets & desktop: the calendar block scales up instead of clumping in a
   phone-sized column with half the page dead */
@media (min-width: 760px) {
  .sb-flame-hero, .sb-hm { max-width: 620px; }
  .sb-hm-grid { max-width: 448px; }
  .sb-cell { border-radius: 5px; }
  .sb-cell .cn { font-size: 9px; }
}

/* the info sheet behind the (i): heading + the grid legend */
.sb-info-h { max-width: 480px; margin: var(--space-8) auto var(--space-3);
  font-family: var(--font-mono); font-size: var(--text-2xs); letter-spacing: var(--tracking-label);
  text-transform: uppercase; color: var(--mute); font-weight: 400; }
.sb-hm-legend { max-width: 480px; margin: var(--space-5) auto var(--space-7); display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-6); }
.sb-hm-legend > span { display: flex; align-items: center; gap: var(--space-3); font-size: var(--text-2xs); color: var(--mute); }
.sb-hm-legend i { width: 13px; height: 13px; border-radius: 4px; flex: none; --hc: var(--dim); border: 1.3px solid var(--hc); }
.sb-hm-legend i.on { background: var(--hc); }
.sb-hm-legend i.open { background: none; border-style: dashed; }
.sb-hm-legend i.shut { border-color: var(--line); }

/* ── victory ──────────────────────────────────────────────────────────── */

.victory { text-align: center; }
/* the cat delivers the win from INSIDE the sheet — the same portrait + speech
   bubble as her request menu (.pet-menu-head/.pet-menu-prompt in css/pet.css) */
.vic-head { display: flex; align-items: flex-end; gap: var(--space-3); text-align: left; margin-bottom: var(--space-5); }
.vic-cat { flex: none; display: block; min-width: 34px; }
.vic-head .pet-menu-prompt { flex: 1; min-width: 0; }
/* her menu: one column of the same request rows */
.vic-menu { display: flex; flex-direction: column; gap: var(--space-3); margin-top: var(--space-7); text-align: left; }
.vic-menu .pet-mi-t { display: flex; flex-direction: column; gap: 1px; }
.vic-menu .pet-mi-t small { color: var(--mute); font-size: var(--text-2xs); }
.vic-menu .pet-mi.dim { opacity: 0.5; cursor: default; }
.vic-menu .pet-mi.dim:hover { border-color: var(--line); }
/* continuous-play progress line: "Story 7/24 · next chapter in 2" */
.victory-prog { font-family: var(--font-mono); font-size: var(--text-sm); letter-spacing: 0.02em; color: var(--accent); margin: var(--space-3) 0 var(--space-2); }
.victory-prog span { color: var(--dim); }
.victory .big-stars { display: flex; justify-content: center; gap: var(--space-5); margin: var(--space-8) 0 var(--space-3); }
.victory .big-stars svg { width: 34px; height: 34px; }
/* `both` already holds the `from` state through the delay. Setting opacity:0
   here as well makes the implicit `to` state resolve to 0 too, and the stars
   fade from invisible to invisible. */
.victory .big-stars .slot { display: inline-flex; animation: fade var(--duration-3) var(--ease) both; }
.victory .big-stars .slot:nth-child(1) { animation-delay: 0.05s }
.victory .big-stars .slot:nth-child(2) { animation-delay: 0.15s }
.victory .big-stars .slot:nth-child(3) { animation-delay: 0.25s }
.victory .earned { fill: var(--accent); stroke: none; }
.victory .missed { fill: var(--line-2); stroke: none; }

/* daily-win celebration — the streak flame + its reward, above the sheet copy */
.celeb {
  display: flex; align-items: center; justify-content: center; gap: var(--space-6);
  margin: var(--space-3) 0 var(--space-7);
  animation: celeb-in var(--duration-3) var(--ease) both;
}
.celeb-flame { position: relative; display: inline-flex; }
.celeb-side { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-3); }
.celeb-cap {
  margin: 0; font-family: var(--font-mono); font-size: var(--text-2xs);
  letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--mute);
}
.celeb.is-zone .celeb-cap { color: var(--zone); }
.celeb-ring-n { font-family: var(--font-mono); font-size: var(--text-2xs); color: var(--dim); }

/* the zone burst — a shockwave of the new tier's colour taking over */
.celeb-burst {
  position: absolute; left: 50%; top: 54%; width: 8px; height: 8px;
  margin: -4px 0 0 -4px; border-radius: 50%;
  background: var(--zone); opacity: 0; transform: scale(0);
  pointer-events: none;
}
.celeb.go .celeb-burst { animation: celeb-burst 900ms var(--ease) forwards; }

@keyframes celeb-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes celeb-burst {
  0% { transform: scale(0); opacity: 0.5; }
  70% { opacity: 0.16; }
  100% { transform: scale(16); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .celeb.go .celeb-burst { animation: none; } }

.score-row {
  display: flex; justify-content: center; gap: 36px; margin: var(--space-7) 0 var(--space-2);
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: 0.1em; color: var(--mute);
}
.score-row b {
  display: block; font-size: var(--text-2xl); color: var(--text);
  font-weight: 400; margin-bottom: var(--space-2); letter-spacing: var(--tracking-none);
}
.score-row .met b { color: var(--accent); }

/* ── Android app link on the title screen ───────────────────────────────── */
.apk-link {
  display: inline-flex; align-items: center; gap: var(--space-4);
  margin-top: var(--space-7); padding: var(--space-4) var(--space-6);
  border: var(--hairline) solid var(--line-2); border-radius: var(--radius);
  color: var(--dim); font-size: var(--text-md);
  transition: var(--t);
}
.apk-link:hover { border-color: var(--accent-line); color: var(--accent); }
.apk-link svg {
  width: var(--icon); height: var(--icon);
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
}

/* ── sign-in wall ───────────────────────────────────────────────────────── */
.auth-gate {
  position: fixed; inset: 0; z-index: 1000;
  display: grid; place-items: center; padding: var(--space-8);
  background: var(--bg);
}
.auth-gate[hidden] { display: none; }
body.gated { overflow: hidden; }

.auth-card { max-width: 340px; text-align: center; }
.auth-mark { width: 64px; height: 64px; margin: 0 auto var(--space-6); }
.auth-mark svg { width: 100%; height: 100%; overflow: visible; }
.auth-mark path, .auth-mark line, .auth-mark circle {
  fill: none; stroke: var(--text); stroke-width: 3; stroke-linecap: round;
}
.auth-mark circle { fill: var(--accent); stroke: var(--accent); }
.auth-title {
  font-family: var(--font-mono); font-size: var(--text-2xl); font-weight: 500;
  letter-spacing: var(--tracking-title); margin: 0 0 var(--space-3);
}
.auth-title em { color: var(--accent); font-style: normal; }
.auth-sub {
  font-family: var(--font-mono); font-size: var(--text-sm); color: var(--mute);
  letter-spacing: var(--tracking-label); margin: 0 0 var(--space-8);
}
.auth-note {
  font-size: var(--text-base); color: var(--dim); line-height: var(--leading-body);
  margin: 0 0 var(--space-7);
}
.auth-btn {
  display: inline-flex; align-items: center; gap: var(--space-4);
  padding: var(--space-5) var(--space-7);
  border: var(--hairline) solid var(--line-2); border-radius: var(--radius);
  color: var(--text); font-size: var(--text-lg); background: none;
  cursor: pointer; transition: var(--t);
}
.auth-btn:hover { border-color: var(--accent-line); color: var(--accent); }
.auth-btn:disabled { opacity: 0.55; cursor: default; }
.auth-btn svg {
  width: var(--icon); height: var(--icon);
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
}
.auth-hint {
  margin-top: var(--space-6); font-family: var(--font-mono);
  font-size: var(--text-xs); color: var(--mute); letter-spacing: var(--tracking-label);
}

/* ── account chip (title screen) ────────────────────────────────────────── */
.title-account { min-height: var(--control-sm); }

.acct-in {
  display: inline-flex; align-items: center; gap: var(--space-4);
  padding: var(--space-4) var(--space-6);
  border: var(--hairline) solid var(--line-2); border-radius: var(--radius);
  color: var(--dim); font-size: var(--text-md); background: none;
  cursor: pointer; transition: var(--t);
}
.acct-in:hover { border-color: var(--accent-line); color: var(--accent); }
.acct-in svg {
  width: var(--icon); height: var(--icon);
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
}

.acct-chip {
  display: inline-flex; align-items: center; gap: var(--space-4);
  padding: var(--space-3) var(--space-3) var(--space-3) var(--space-3);
  border: var(--hairline) solid var(--line); border-radius: var(--radius-full);
  padding-right: var(--space-5);
}
.acct-ava {
  width: 24px; height: 24px; border-radius: var(--radius-full);
  object-fit: cover; flex: none;
}
.acct-ava--txt {
  display: grid; place-items: center;
  background: var(--accent-dim); color: var(--accent);
  font-family: var(--font-mono); font-size: var(--text-sm); font-weight: 500;
}
.acct-name {
  font-size: var(--text-md); color: var(--text);
  max-width: 12ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.acct-out {
  display: grid; place-items: center; background: none; border: none;
  color: var(--mute); cursor: pointer; padding: var(--space-2); border-radius: var(--radius-sm);
  transition: var(--t);
}
.acct-out:hover { color: var(--accent); }
.acct-out svg {
  width: var(--icon-sm); height: var(--icon-sm);
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
}

/* ── signup form ────────────────────────────────────────────────────────────
   The four questions that unlock the game, in the same full-screen register as
   the sign-in wall — but scrollable, because on a short phone in landscape the
   whole form does not fit and a cover you cannot reach the bottom of is a cover
   you cannot get past. */
.signup {
  position: fixed; inset: 0; z-index: 1000;
  overflow-y: auto; overscroll-behavior: contain;
  padding: var(--space-9) var(--space-6) calc(var(--space-9) + var(--sab));
  background: var(--bg);
}
.signup[hidden] { display: none; }
body.gated-signup { overflow: hidden; }

.signup-card { max-width: 380px; margin: 0 auto; }
.signup-title {
  font-family: var(--font-mono); font-size: var(--text-2xl); font-weight: 500;
  letter-spacing: var(--tracking-title); margin: 0 0 var(--space-4);
}
.signup-sub {
  font-size: var(--text-base); color: var(--dim); line-height: var(--leading-body);
  margin: 0 0 var(--space-9);
}

.signup-field { display: block; margin-bottom: var(--space-7); }
.signup-label {
  display: block;
  font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  color: var(--mute); margin-bottom: var(--space-4);
}
.signup-input {
  width: 100%;
  padding: var(--space-5);
  background: var(--surface);
  border: var(--hairline) solid var(--line-2);
  border-radius: var(--radius);
  color: var(--text);
  font-family: inherit;
  font-size: var(--text-lg);
}
.signup-input:focus { outline: none; border-color: var(--accent); }
/* the native arrow is the one control we cannot restyle — give it room instead */
select.signup-input { appearance: none; padding-right: var(--space-9); cursor: pointer; }

.signup-err {
  margin: 0 0 var(--space-5);
  font-size: var(--text-sm); color: var(--danger-text);
}
.signup-err[hidden] { display: none; }

.signup-go {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-4);
  width: 100%;
  padding: var(--space-5) var(--space-7);
  background: var(--accent); color: var(--on-accent);
  border: 0; border-radius: var(--radius);
  font-family: var(--font-mono); font-size: var(--text-lg);
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  cursor: pointer; transition: var(--t);
}
.signup-go:hover { filter: brightness(1.06); }
.signup-go:disabled { opacity: 0.55; cursor: default; }
.signup-go.busy span::after { content: '…'; }
.signup-go svg {
  width: var(--icon); height: var(--icon);
  fill: none; stroke: currentColor; stroke-width: var(--stroke);
  stroke-linecap: round; stroke-linejoin: round;
}

/* ── the player's mini circuit on chapter cards ── */
.mini-circ { display: block; width: 100%; height: auto; }
.mini-circ .mc-bed { fill: var(--surface-2); stroke: var(--line); stroke-width: 1; }
.mini-circ .mc-wire { stroke: var(--line-2); stroke-width: 1.6; stroke-linecap: round; }
.mini-circ .mc-node { fill: var(--surface); stroke: var(--mute); stroke-width: 1.2; }
.mini-circ .mc-node.in { stroke: var(--mute); fill: var(--surface-2); }
.mini-circ .mc-node.out { stroke: var(--accent); fill: var(--accent-dim); }

/* the chapter hero cycles goal-table ↔ the player's board, 3s a side, pure CSS */
.nu-cycle { position: relative; display: block; }
.nu-cycle .nu-face { display: block; width: 100%; }
.nu-cycle .nu-face.b { position: absolute; inset: 0; display: grid; align-items: center; }
.nu-cycle .nu-face.a { animation: nu-cycle-a 6s ease-in-out infinite; }
.nu-cycle .nu-face.b { animation: nu-cycle-b 6s ease-in-out infinite; }
@keyframes nu-cycle-a { 0%, 42% { opacity: 1; } 50%, 92% { opacity: 0; } 100% { opacity: 1; } }
@keyframes nu-cycle-b { 0%, 42% { opacity: 0; } 50%, 92% { opacity: 1; } 100% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .nu-cycle .nu-face { animation: none; } .nu-cycle .nu-face.b { opacity: 0; } }

/* lock cards: one per locked level, quiet */
.nu-tile.lock .nu-tile-b { display: grid; place-items: center; background: var(--surface); opacity: 0.55; cursor: default; }
.nu-tile.lock .lvcard-lock svg { width: 18px; height: 18px; }
