/* == Seven Nights — Warm Observatory (DESIGN.md is canonical) == */
:root{
  --midnight-water:#0B1520;
  --night-air:#0E1D2B;
  --raised-night:#16303C;
  --star-gold:#E7C87A;
  --instrument-brass:#CBA85C;
  --worn-brass:#8C7A4E;
  --far-stars:#8FA6B8;
  --archive-paper:#F3ECDB;
  --reading-ink:#2B2620;
  --first-sun:#F0D48A; /* embargoed: night-7 sunrise only */
  --hairline:rgba(140,122,78,.4);
  --ease:cubic-bezier(.25,1,.5,1);
  --dur-fast:150ms; --dur-base:220ms; --dur-slow:400ms;
  --font-display:'Playfair Display',Georgia,serif;
  --font-letter:'Source Serif 4',Georgia,serif;
  --font-ui:'Inter',system-ui,sans-serif;
  --font-plate:'JetBrains Mono',monospace;
}
*{box-sizing:border-box}
html,body{margin:0;padding:0}
/* the hidden attribute must always win — .btn{display:flex} and friends
   would otherwise override the UA's [hidden] display:none */
[hidden]{display:none!important}
body{
  background:var(--midnight-water);color:var(--archive-paper);
  font:400 .9375rem/1.5 var(--font-ui);-webkit-font-smoothing:antialiased;
}
.device{max-width:1100px;margin:0 auto;padding:12px 24px 80px;min-height:100dvh}

/* home: the sky IS the page — fixed, frameless, behind everything.
   The field glow is a full-bleed CSS layer (fills all corners, breathes);
   the SVG carries only stars, scaled to end above the control cluster. */
.sky--page{
  position:fixed;inset:0;margin:0;z-index:0;pointer-events:none;
}
.starscape{position:absolute;inset:0;width:100%;height:100%}
.scene3d{position:absolute;inset:0;width:100%;height:100%}
/* photographic depth: a breath of vignette over the whole stage */
.sky--page::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(ellipse 120% 105% at 50% 46%,
    rgba(11,21,32,0) 62%, rgba(7,13,20,.55) 100%);
}
/* the act title: resolves out of scattered letters mid-fall */
.act-title{
  position:fixed;inset:0;z-index:4;pointer-events:none;
  display:flex;align-items:center;justify-content:center;
  margin:0;color:var(--archive-paper);
  font:500 clamp(3rem, 7vw, 6.5rem)/1.1 var(--font-display);
  letter-spacing:.04em;text-shadow:0 0 34px rgba(231,200,122,.25);
}
.act-title span{display:inline-block;white-space:pre;will-change:transform,opacity,filter}
.sky--page::before{
  content:"";position:absolute;inset:0;
  background:radial-gradient(ellipse 72% 66% at 50% 44%,
    var(--night-air) 0%, #0C1723 58%, rgba(11,21,32,0) 100%);
  animation:skybreathe 16s ease-in-out infinite alternate;
}
.home-counter{position:fixed;top:22px;right:28px;z-index:1}
/* first-visit act: scroll drives the 3D approach (skyscene.js); the page
   only gains a spacer, a cue and the resolving title. Without JS or
   WebGL nothing changes. */
.reveal-space{height:320vh}
.home-overlay,.home-counter,.lang-toggle{
  transition:opacity .8s var(--ease),visibility 0s linear 0s;
}
.is-veiled .home-overlay,.is-veiled .home-counter,.is-veiled .lang-toggle{
  opacity:0;pointer-events:none;visibility:hidden;
  transition:opacity .8s var(--ease),visibility 0s linear .8s;
}
.is-veiled .lightup,
.is-veiled .lightup .lstar,
.is-veiled .lightup .ripple{animation-play-state:paused}
/* the sky page owns the frame: never a scrollbar — the act is a
   permanent scroll resident now (home lives at the bottom of it), so
   the whole page stays scrollable and the bar must never show. The
   page scroller is the ROOT element, not body — Chrome stopped
   propagating scrollbar styles from body, so the hiding lives on html. */
html:has(.sky--page){scrollbar-width:none}
html:has(.sky--page)::-webkit-scrollbar{display:none;width:0;height:0}
/* a star on stage pins the page: scrolling must not rewind the act
   behind the viewer */
body.is-viewing{overflow:hidden}
.sky--page svg{transition:opacity 1.4s var(--ease)}
.is-veiled .sky--page svg{opacity:0}
.scroll-cue{
  position:fixed;left:50%;bottom:26px;z-index:4;pointer-events:none;
  color:var(--far-stars);font:500 .6875rem/1 var(--font-plate);
  letter-spacing:.14em;text-transform:uppercase;
  animation:cuebob 2.4s ease-in-out infinite;
  transition:opacity .5s var(--ease);
}
@keyframes cuebob{0%,100%{transform:translate(-50%,0)}50%{transform:translate(-50%,8px)}}
/* language toggle: mirrors the counter, top-left */
.lang-toggle{
  position:fixed;top:22px;left:28px;z-index:1;
  display:flex;align-items:center;gap:8px;
  text-decoration:none;cursor:pointer;
}
.lang-toggle .lang-side{transition:color var(--dur-base) var(--ease)}
.lang-toggle .is-current{color:var(--star-gold)}
.lang-toggle:hover .toggle-track{border-color:var(--instrument-brass)}
.toggle-track{
  position:relative;width:34px;height:16px;flex:none;
  border:1px solid var(--hairline);border-radius:9px;
  background:var(--night-air);
  transition:border-color var(--dur-fast) var(--ease);
}
.toggle-knob{
  position:absolute;top:2px;left:2px;width:10px;height:10px;
  border-radius:50%;background:var(--instrument-brass);
  transition:transform var(--dur-base) var(--ease);
}
.toggle-track.is-ru .toggle-knob{transform:translateX(18px)}
.home-overlay{
  position:fixed;inset:0;z-index:1;
  display:flex;flex-direction:column;justify-content:flex-end;
  align-items:center;padding:0 24px 18px;
  /* full-viewport container must not eat clicks meant for the corners */
  pointer-events:none;
}
.home-overlay :is(a,button){pointer-events:auto}
.home-overlay .tonight{width:100%;max-width:420px}
.home-overlay .tonight-line{font-size:1.125rem;margin:4px 0 10px}
.home-overlay .next-line{margin-top:10px}
.home-overlay .nights-nav{margin-top:14px}
.home-overlay .devline{margin:12px 0 0}

/* night pages read as a column even on a wide stage */
.intro-line,.sheet,.memory-wrap,.outro-line{max-width:720px;margin-left:auto;margin-right:auto}

/* plates */
.plate{
  font:500 .6875rem/1.2 var(--font-plate);letter-spacing:.16em;
  text-transform:uppercase;color:var(--instrument-brass);
}
.plate--dim{color:var(--worn-brass)}
.replay-form{display:inline}
.plate-btn{background:none;border:none;padding:0;cursor:pointer;
  font:500 .6875rem/1.2 var(--font-plate);letter-spacing:.16em;
  text-transform:uppercase;color:var(--instrument-brass)}
.plate-btn:hover{color:var(--star-gold)}
.plate-btn:focus-visible{outline:2px solid var(--star-gold);outline-offset:2px}
a.plate{text-decoration:none}
a.plate:hover{color:var(--star-gold)}
a.plate:focus-visible{outline:2px solid var(--star-gold);outline-offset:2px}

/* topline */
.topline{
  display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  padding:14px 0 12px;border-bottom:1px solid rgba(140,122,78,.35);
}
.topline h1{
  font:500 1.75rem/1.15 var(--font-display);
  color:var(--archive-paper);margin:0;text-wrap:balance;
}

/* divider motif */
.divider{display:flex;align-items:center;gap:12px;margin:32px 0 24px}
.divider::before,.divider::after{content:"";flex:1;height:1px;background:var(--hairline)}
.divider i{width:7px;height:7px;background:var(--instrument-brass);transform:rotate(45deg);flex:none}

/* sky — the field dissolves into the page: an infinite sky, no frame */
.sky{margin:8px -6px 0}
.sky svg{display:block;width:100%;height:auto}
/* home variant: must come after the generic rule — equal specificity */
.sky--page svg{position:relative;width:100%;height:84%}
/* photoreal bloom: earned stars glow like long-exposure points of light —
   a tight warm core plus a strong wide halo (same objects, same positions).
   The occluder disc beneath keeps the 3D field from shining through. */
.lstar{
  fill:var(--star-gold);
  filter:drop-shadow(0 0 3px rgba(231,200,122,.95))
         drop-shadow(0 0 9px rgba(231,200,122,.6))
         drop-shadow(0 0 26px rgba(231,200,122,.3));
}
.star-hit{fill:transparent;pointer-events:auto}
.star-tip{
  position:fixed;z-index:5;pointer-events:none;
  transform:translate(-50%,-135%);
  font:500 .6875rem/1 var(--font-plate);letter-spacing:.14em;
  text-transform:uppercase;color:var(--star-gold);
  background:rgba(14,29,43,.92);border:1px solid var(--hairline);
  border-radius:4px;padding:5px 9px;
  opacity:0;visibility:hidden;
  transition:opacity var(--dur-base) var(--ease),visibility 0s linear var(--dur-base);
}
.star-tip.is-on{opacity:1;visibility:visible;transition-delay:0s}
/* Star viewer: an earned star, clicked, steps forward as a 3D sun.
   Canvas above everything; caption set low-left like a plate on an
   observatory instrument. While it holds the stage the page chrome
   goes dark (the backdrop is deliberately translucent so the 3D
   field keeps breathing behind the star). */
.is-viewing .home-overlay,.is-viewing .home-counter,.is-viewing .lang-toggle{
  opacity:0;pointer-events:none;
}
.viewer-backdrop{
  position:fixed;inset:0;z-index:6;
  background:radial-gradient(ellipse at 50% 45%,rgba(7,13,20,.78),rgba(4,8,13,.94));
  opacity:0;transition:opacity .6s var(--ease);
}
.viewer-backdrop.is-on{opacity:1}
canvas.star-viewer{
  position:fixed;inset:0;z-index:7;width:100vw;height:100vh;
  cursor:grab;
}
canvas.star-viewer.is-grabbing{cursor:grabbing}
.viewer-name{
  position:fixed;left:7vw;bottom:17vh;z-index:8;margin:0;
  pointer-events:none;
  font-family:var(--font-display);font-weight:500;
  font-size:clamp(2.4rem,4.8vw,4.2rem);line-height:1.05;
  color:var(--archive-paper);
  text-shadow:0 2px 30px rgba(4,8,13,.8);
  opacity:0;transform:translateY(14px);
  transition:opacity .7s var(--ease),transform .7s var(--ease);
}
.viewer-line{
  position:fixed;left:7vw;bottom:calc(17vh - 2.4rem);z-index:8;margin:0;
  pointer-events:none;
  color:var(--instrument-brass);
  text-shadow:0 1px 14px rgba(4,8,13,.95),0 0 4px rgba(4,8,13,.9);
  opacity:0;transform:translateY(10px);
  transition:opacity .7s var(--ease) .08s,transform .7s var(--ease) .08s;
}
.viewer-name.is-on,.viewer-line.is-on{opacity:1;transform:none}
.viewer-line.is-on{opacity:.95}
.viewer-close{
  position:fixed;top:26px;right:30px;z-index:8;
  font-size:1.1rem;line-height:1;padding:8px 12px;
  background:rgba(14,29,43,.7);border:1px solid var(--hairline);
  border-radius:6px;color:var(--worn-brass);cursor:pointer;
  opacity:0;transition:opacity .5s var(--ease),color var(--dur-base) var(--ease);
}
.viewer-close.is-on{opacity:1}
.viewer-close:hover{color:var(--star-gold)}
.bstar{
  fill:var(--far-stars);opacity:.5;
  filter:drop-shadow(0 0 1.5px rgba(143,166,184,.6));
  animation:scintillate var(--twd,5s) ease-in-out var(--twl,0s) infinite alternate;
}
@keyframes scintillate{from{opacity:.3}to{opacity:.62}}
@keyframes skybreathe{from{opacity:.86}to{opacity:1}}
/* parallax layers (driven by sky.js; transform set as SVG attribute) */
#skyBg,#skyGold{will-change:transform}
.pair-ring{fill:none;stroke:var(--star-gold);stroke-opacity:.35;stroke-width:1.5}
.sun{fill:var(--first-sun);opacity:.55}
.sun-core{fill:var(--first-sun)}
/* every visit, the earned sky relights: pair by pair, in reveal order.
   The whole ritual fits a fixed 1.5s budget — one pair savors it, seven
   pairs go rapid — and each star arrives BRIGHTER than its steady state,
   with a radiating ripple, then settles. */
.sky{--n:1}
.lightup{
  --dur:min(1.5s, calc(1.8s / var(--n, 1)));
  --step:calc((1.5s - var(--dur)) / max(var(--n, 1) - 1, 1));
  --dly:calc((var(--day, 1) - 1) * var(--step));
  transform-box:fill-box;transform-origin:center;
  animation:lightup var(--dur) var(--ease) var(--dly) backwards;
}
.lightup-newest{
  animation:lightup var(--dur) var(--ease) var(--dly) backwards,
            twinkle 3.5s ease-in-out calc(var(--dly) + var(--dur) + .3s) infinite alternate;
}
/* settled stars keep a faint breath (the newest pair twinkles instead) */
.lightup:not(.lightup-newest){
  animation:lightup var(--dur) var(--ease) var(--dly) backwards,
            breathe 8s ease-in-out calc(var(--dly) + var(--dur) + 1.2s) infinite alternate;
}
@keyframes breathe{from{opacity:1}to{opacity:.94}}
.lightup .lstar{
  animation:flare var(--dur) var(--ease) var(--dly) backwards;
}
.lightup .ripple{
  fill:none;stroke:var(--star-gold);stroke-width:1.5;opacity:0;
  transform-box:fill-box;transform-origin:center;
  animation:ripple calc(var(--dur) + .25s) var(--ease) var(--dly);
}
@keyframes lightup{
  0%{opacity:0;transform:scale(.2)}
  55%{opacity:1;transform:scale(1.4)}
  100%{opacity:1;transform:none}
}
@keyframes flare{
  0%{fill:var(--star-gold)}
  55%{fill:color-mix(in oklab, var(--star-gold) 45%, var(--archive-paper));
      filter:drop-shadow(0 0 7px rgba(231,200,122,.9))}
  100%{fill:var(--star-gold);filter:none}
}
@keyframes ripple{
  0%{opacity:.6;transform:scale(1)}
  100%{opacity:0;transform:scale(3.4)}
}
@keyframes twinkle{from{opacity:.55}to{opacity:1}}

/* tonight card zone */
.tonight{text-align:center;margin-top:4px}
.tonight-line{font:500 1.25rem/1.35 var(--font-display);margin:8px 0 14px;text-wrap:balance}
.next-line{display:block;margin-top:14px}

/* nights nav */
.nights-nav{display:flex;justify-content:center;gap:18px;margin-top:28px}
.nights-nav .plate--locked{color:rgba(143,166,184,.4)}
.nights-nav .is-current{color:var(--star-gold)}

/* intro / outro lines */
.intro-line{color:var(--far-stars);margin:16px 2px 14px}
.outro-line{color:var(--far-stars);text-align:center;margin:18px 0}

/* game sheet */
.sheet{
  background:var(--raised-night);
  border-top:1px solid var(--hairline);
  border-radius:16px;
  padding:18px 16px;margin-top:6px;
}
.beat{
  font:500 1.375rem/1.25 var(--font-display);
  color:var(--archive-paper);margin:0 0 14px;text-wrap:balance;
}
.clue{margin:0 0 18px}
.clue figcaption{display:block;margin-top:8px;text-align:center}
.clue img{
  display:block;width:100%;border-radius:10px;
  transition:opacity var(--dur-base) var(--ease);
}

/* TIME slider */
.slider{margin:6px 2px}
.slider-readout{display:flex;justify-content:center;margin-bottom:10px}
.slider-input{
  -webkit-appearance:none;appearance:none;
  width:100%;height:44px;background:transparent;margin:0;
}
.slider-input::-webkit-slider-runnable-track{height:2px;background:var(--hairline)}
.slider-input::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;
  width:28px;height:28px;border-radius:50%;
  border:2px solid var(--instrument-brass);background:var(--midnight-water);
  margin-top:-13px;cursor:grab;
  transition:border-color var(--dur-fast) var(--ease);
}
.slider-input::-moz-range-track{height:2px;background:var(--hairline)}
.slider-input::-moz-range-thumb{
  width:24px;height:24px;border-radius:50%;
  border:2px solid var(--instrument-brass);background:var(--midnight-water);cursor:grab;
}
.slider-input:focus-visible{outline:2px solid var(--star-gold);outline-offset:2px}
.slider-ends{display:flex;justify-content:space-between;margin-top:4px}

/* — recalibration pulse when the range zooms (declared first: heat wins) — */
@keyframes recal{from{transform:scaleX(.98);opacity:.55}to{transform:none;opacity:1}}
.slider.is-recal .slider-input,
.slider.is-recal .slider-ends{animation:recal .18s var(--ease)}

/* — slider states: heat is vibration — */
@keyframes tremor{
  0%{transform:translateX(-.8px)}50%{transform:translateX(.8px)}100%{transform:translateX(-.8px)}
}
@keyframes tremor-hot{
  0%{transform:translateX(-1.4px)}50%{transform:translateX(1.4px)}100%{transform:translateX(-1.4px)}
}
@keyframes burst{
  0%{transform:translateX(0)}15%{transform:translateX(-4px)}30%{transform:translateX(4px)}
  45%{transform:translateX(-3px)}60%{transform:translateX(2px)}80%{transform:translateX(-1px)}
  100%{transform:translateX(0)}
}
/* the tremor lives on the readout plate: visible mid-drag, unlike the
   thumb the pointer is holding still. The plate is also TINTED by
   temperature, so the date always tells the truth — cold reads cold. */
.sheet.temp-warmer .slider-readout .plate{animation:tremor .22s linear infinite}
.sheet.temp-hot .slider-readout .plate{animation:tremor-hot .14s linear infinite}
.sheet.is-burst .slider-readout .plate{animation:burst .5s var(--ease)}
.slider-readout .plate{display:inline-block;transition:color var(--dur-base) var(--ease)}
.sheet.temp-colder .slider-readout .plate{color:var(--far-stars)}
.sheet.temp-warmer .slider-readout .plate{color:var(--instrument-brass)}
.sheet.temp-hot .slider-readout .plate{color:var(--star-gold)}
.sheet.temp-colder .slider-input::-webkit-slider-thumb{border-color:var(--far-stars)}
.sheet.temp-hot .slider-input::-webkit-slider-thumb{border-color:var(--star-gold)}
.sheet.temp-colder .slider-input::-moz-range-thumb{border-color:var(--far-stars)}
.sheet.temp-hot .slider-input::-moz-range-thumb{border-color:var(--star-gold)}

/* — found: the thumb goes gold and glows (light emission, not elevation) — */
.sheet.is-found .slider-input::-webkit-slider-thumb{
  border-color:var(--star-gold);
  box-shadow:0 0 0 5px rgba(231,200,122,.16), 0 0 18px rgba(231,200,122,.35);
}
.sheet.is-found .slider-input::-moz-range-thumb{
  border-color:var(--star-gold);
  box-shadow:0 0 0 5px rgba(231,200,122,.16), 0 0 18px rgba(231,200,122,.35);
}
.sheet.is-found .slider-readout .plate{color:var(--star-gold)}


/* warmth: temperature tints on the readout plate and thumb (no meter) */
.sheet.temp-colder .slider-readout .plate{color:var(--far-stars)}
.sheet.temp-warmer .slider-readout .plate{color:var(--instrument-brass)}
.sheet.temp-hot .slider-readout .plate{color:var(--star-gold)}
.sheet.temp-colder .slider-input::-webkit-slider-thumb{border-color:var(--far-stars)}
.sheet.temp-hot .slider-input::-webkit-slider-thumb{border-color:var(--star-gold)}
.sheet.temp-colder .slider-input::-moz-range-thumb{border-color:var(--far-stars)}
.sheet.temp-hot .slider-input::-moz-range-thumb{border-color:var(--star-gold)}
.hint-note{text-align:center;margin:12px 0 0}

/* buttons */
.btn{
  display:flex;align-items:center;justify-content:center;gap:10px;
  width:100%;min-height:48px;padding:14px 24px;
  font:500 .9375rem/1 var(--font-ui);letter-spacing:.01em;
  background:transparent;border-radius:10px;cursor:pointer;
  text-decoration:none;
  transition:background var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease);
}
.btn:focus-visible{outline:2px solid var(--star-gold);outline-offset:2px}
.btn-primary{color:var(--star-gold);border:1px solid rgba(231,200,122,.35)}
.btn-primary:hover{background:rgba(231,200,122,.08);border-color:rgba(231,200,122,.7)}
.btn-primary:active{background:rgba(231,200,122,.14)}
.btn-quiet{color:var(--instrument-brass);border:1px solid transparent;min-height:44px;padding:12px 20px;font-weight:400}
.btn-quiet:hover{border-color:rgba(140,122,78,.5);color:var(--star-gold)}
.btn-filled{color:var(--midnight-water);background:var(--instrument-brass);border:1px solid var(--instrument-brass)}
.actions{display:flex;flex-direction:column;gap:6px;margin-top:18px}

/* hint rungs */
.hint-rungs{display:inline-flex;gap:5px}
.hint-rungs i{width:6px;height:6px;border-radius:50%;background:var(--worn-brass);opacity:.5}
.hint-rungs i.is-spent{background:var(--star-gold);opacity:1}

/* riddle verse — Alex-authored text, so it speaks in the letter's voice */
.verse{
  font:400 1.0625rem/1.7 var(--font-letter);
  color:var(--archive-paper);
  white-space:pre-line;text-wrap:pretty;
  margin:0 0 20px;padding:0 4px;
}

/* WORD widget: slots above, letter bank below */
.wordgame{margin:6px 0}
.chips{display:flex;flex-wrap:wrap;gap:8px}
.chip{
  width:44px;height:44px;
  background:var(--raised-night);color:var(--archive-paper);
  border:1px solid var(--hairline);border-radius:4px;
  font:500 1.125rem/1 var(--font-ui);cursor:pointer;
  transition:transform var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease);
}
.chip:hover{transform:translateY(-2px);border-color:rgba(203,168,92,.7)}
.chip:focus-visible{outline:2px solid var(--star-gold);outline-offset:2px}
.slots{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:18px;justify-content:center}
.slot-gap{width:18px;flex:none}
.chip.slot{background:transparent;border-style:dashed}
.chip.slot.is-placed{background:var(--raised-night);border-style:solid;border-color:rgba(203,168,92,.7)}
.chip.slot.is-locked{
  background:var(--star-gold);color:var(--midnight-water);
  border-color:var(--star-gold);font-weight:600;pointer-events:none;
}
.chips{justify-content:center}
.chip.is-spent-chip{opacity:.22;pointer-events:none;transform:none}

/* ЧГК dress: the call plate and a minute that costs nothing */
.chgk-head{display:flex;align-items:center;justify-content:space-between;gap:16px;margin:2px 0 6px}
.chgk-minute{position:relative;width:56px;height:56px;flex:none}
.chgk-minute svg{width:100%;height:100%;transform:rotate(-90deg)}
.chgk-track,.chgk-run{fill:none;stroke-width:2}
.chgk-track{stroke:var(--hairline)}
.chgk-run{stroke:var(--instrument-brass);transition:stroke-dashoffset .25s linear}
.chgk-sec{
  position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  font:500 .8125rem/1 var(--font-plate);letter-spacing:.06em;
  color:var(--instrument-brass);font-variant-numeric:tabular-nums;
}
.chgk-minute.is-out .chgk-run,
.chgk-minute.is-held .chgk-run{stroke:var(--hairline);transition:stroke var(--dur-base) var(--ease)}
.chgk-minute.is-out .chgk-sec{color:var(--far-stars)}
.chgk-minute.is-held{opacity:.45;transition:opacity var(--dur-base) var(--ease)}
.chgk-out{margin:0 0 14px;font-family:var(--font-letter);font-style:italic;font-size:.9375rem;color:var(--far-stars)}
@media (prefers-reduced-motion: reduce){.chgk-run{transition:none}}

/* ЧГК explainer: the comment that lands with the revealed answer */
.chgk-explainer{
  margin:22px 0 4px;padding:18px 20px;
  border-left:2px solid var(--instrument-brass);
  background:rgba(140,122,78,.07);border-radius:0 6px 6px 0;
  animation:explainer-in .5s var(--ease);
}
.chgk-explainer p{
  margin:0 0 16px;font:400 1rem/1.6 var(--font-letter);
  color:var(--archive-paper);text-wrap:pretty;white-space:pre-line;
}
.chgk-explainer .btn{margin:0}
.explainer-img{display:block;width:100%;max-width:520px;height:auto;margin:0 auto 16px;border-radius:6px}
/* bare «Next» beat: no comment, no box — just the button */
.chgk-explainer.is-bare{border-left:none;background:none;padding:0;margin:18px 0 4px}
@keyframes explainer-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion: reduce){.chgk-explainer{animation:none}}

/* the reveal card, when it takes its own screen after the blitz */
.memory-wrap.reveal-screen{animation:reveal-screen-in 1.1s var(--ease)}
@keyframes reveal-screen-in{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion: reduce){.memory-wrap.reveal-screen{animation:none}}

/* PLACE widget: the treasure map */
.mapwrap{position:relative;margin:6px 0;cursor:crosshair}
.mapwrap img{display:block;width:100%;border-radius:10px;user-select:none}
.map-pin{
  position:absolute;width:26px;height:26px;border-radius:50%;
  border:2.5px solid var(--star-gold);background:rgba(231,200,122,.12);
  transform:translate(-50%,-50%);pointer-events:none;
  transition:border-color var(--dur-fast) var(--ease);
}
.map-pin::after{
  content:"";position:absolute;left:50%;top:50%;width:4px;height:4px;
  border-radius:50%;background:var(--star-gold);transform:translate(-50%,-50%);
}
.map-region{
  position:absolute;aspect-ratio:1;border-radius:50%;
  border:2px dashed rgba(140,122,78,.75);
  transform:translate(-50%,-50%);pointer-events:none;
}

/* temperature on the new widgets (the sheet carries the temp class) */
.sheet.temp-warmer .slots{animation:tremor .22s linear infinite}
.sheet.temp-hot .slots{animation:tremor-hot .14s linear infinite}
.sheet.is-burst .slots{animation:burst .5s var(--ease)}
.sheet.temp-colder .map-pin{border-color:var(--far-stars)}
.sheet.temp-warmer .map-pin{border-color:var(--instrument-brass);animation:tremor .22s linear infinite}
.sheet.temp-hot .map-pin{border-color:var(--star-gold);animation:tremor-hot .14s linear infinite}
.sheet.is-burst .map-pin{animation:burst .5s var(--ease)}
.sheet.is-found .map-pin{
  border-color:var(--star-gold);
  box-shadow:0 0 0 6px rgba(231,200,122,.16), 0 0 20px rgba(231,200,122,.4);
}
.sheet.is-found .slot{background:var(--star-gold);color:var(--midnight-water);border-color:var(--star-gold)}

/* memory card */
.memory-wrap{margin-top:8px}
.memory{
  background:var(--archive-paper);color:var(--reading-ink);
  border-radius:16px;padding:22px;
  box-shadow:0 12px 40px -12px rgba(4,10,18,.7);
}
.memory .plate{color:var(--worn-brass);display:block;margin-bottom:8px}
.memory h3{
  font:500 1.375rem/1.25 var(--font-display);
  color:var(--reading-ink);margin:0 0 12px;text-wrap:balance;
}
.memory p{font:400 1.0625rem/1.6 var(--font-letter);margin:0;text-wrap:pretty;white-space:pre-line}
.memory img{
  display:block;width:calc(100% + 12px);margin:14px -6px;border-radius:10px;
}
.memory-wrap .btn{margin-top:8px}

/* unlock */
.unlock{display:flex;flex-direction:column;justify-content:center;min-height:80dvh;text-align:center;max-width:440px;margin:0 auto}
.unlock-title{font:500 2rem/1.15 var(--font-display);margin:0 0 8px}
.unlock-sub{color:var(--far-stars);margin:0 0 28px}
.unlock-form{display:flex;flex-direction:column;gap:12px}
.unlock-hint{margin:0}
.input-answer{
  background:var(--night-air);color:var(--archive-paper);
  border:1px solid var(--hairline);border-radius:10px;
  height:52px;padding:14px 16px;width:100%;
  font:400 1rem/1.4 var(--font-ui);
  transition:border-color var(--dur-fast) var(--ease);
}
.input-answer::placeholder{color:var(--far-stars)}
.input-answer:focus{border-color:var(--star-gold);outline:2px solid var(--star-gold);outline-offset:2px}

/* not yet */
.notyet{text-align:center;padding-top:48px}
.notyet-sub{color:var(--far-stars)}

/* debug */
.debug-grid{display:grid;grid-template-columns:auto 1fr;gap:6px 16px;font-size:.8125rem}
.debug-grid dt{color:var(--worn-brass)}
.debug-grid dd{margin:0;font-family:var(--font-plate)}
.debug-table{width:100%;border-collapse:collapse;margin-top:16px;font-size:.8125rem}
.debug-table th,.debug-table td{border:1px solid var(--hairline);padding:6px 8px;text-align:left}
.debug-lint li{color:var(--star-gold)}
/* spoiler pills: redacted words inside a verse — the two she must
   supply. SpoilerJS (Telegram's own particle look) dresses them; the
   spans are EMPTY, so clicks are dead and there is nothing to reveal
   in the document. */
.spoiler{
  display:inline-block;height:.9em;vertical-align:-.08em;
  border-radius:4px;
  background:linear-gradient(100deg,
    rgba(140,122,78,.35) 0%, rgba(93,109,126,.5) 40%,
    rgba(140,122,78,.35) 80%);
  background-size:200% 100%;
  animation:spoiler-shimmer 3.2s ease-in-out infinite;
}
@keyframes spoiler-shimmer{
  0%,100%{background-position:0% 0}
  50%{background-position:100% 0}
}
@media (prefers-reduced-motion: reduce){.spoiler{animation:none}}
/* day steppers: a fingertip cannot land on one day of nine hundred on
   a phone track — these walk the timeline a day at a time (hold to
   run). Big targets, calm plate voice. */
.slider-steps{display:flex;justify-content:center;gap:14px;margin-top:16px}
.btn-step{
  min-width:104px;min-height:48px;padding:10px 18px;
  font:500 .8125rem/1 var(--font-plate);letter-spacing:.14em;
  color:var(--instrument-brass);background:rgba(14,29,43,.6);
  border:1px solid var(--hairline);border-radius:8px;cursor:pointer;
  touch-action:manipulation;user-select:none;-webkit-user-select:none;
  transition:color var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease);
}
.btn-step:active{color:var(--star-gold);border-color:rgba(231,200,122,.5)}
.btn-step:focus-visible{outline:2px solid var(--star-gold);outline-offset:2px}
@media (pointer:coarse){
  .slider-input{height:44px}
  .slider-input::-webkit-slider-thumb{width:28px;height:28px}
  .slider-input::-moz-range-thumb{width:28px;height:28px}
}
.debug-goto{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}
.debug-goto .btn{width:auto;min-height:36px;padding:8px 14px;font-size:.8125rem;
  border:1px solid var(--hairline)}
.devline{text-align:center;margin-top:28px}

/* TEXT widget: the open answer line */
.textinput{margin:10px 0 6px}
/* wrong answer: an unmistakable no — shake + cooled border */
@keyframes shake-no{
  0%,100%{transform:translateX(0)}
  20%,60%{transform:translateX(-8px)}
  40%,80%{transform:translateX(8px)}
}
.sheet.is-wrong .textinput .input-answer{
  border-color:var(--far-stars);
  animation:shake-no .4s var(--ease);
}
/* the checked-and-wrong shake lands on whatever holds the answer */
.sheet.is-wrong .slider-readout .plate{
  display:inline-block;
  animation:shake-no .4s var(--ease);
}
.sheet.is-wrong .slots{animation:shake-no .4s var(--ease)}
.sheet.temp-warmer .textinput .input-answer{border-color:var(--instrument-brass);animation:tremor .22s linear infinite}
.sheet.temp-hot .textinput .input-answer{border-color:var(--star-gold);animation:tremor-hot .14s linear infinite}
.sheet.temp-colder .textinput .input-answer{border-color:var(--far-stars)}
.sheet.is-burst .textinput .input-answer{animation:burst .5s var(--ease)}

/* GEO widget: the real map, framed like an instrument window */
.geowrap{
  margin:6px 0;border:1px solid var(--hairline);border-radius:10px;
  overflow:hidden;transition:border-color var(--dur-fast) var(--ease);
}
#geomap{height:440px;width:100%;background:var(--night-air);cursor:crosshair}
.leaflet-container{font:400 .75rem/1.4 var(--font-ui)}
.leaflet-control-attribution{
  background:rgba(11,21,32,.7) !important;color:var(--far-stars) !important;
}
.leaflet-control-attribution a{color:var(--far-stars) !important}
.map-label{
  background:var(--archive-paper);color:var(--reading-ink);
  border:1px solid var(--worn-brass);border-radius:4px;
  font:500 .6875rem/1.2 var(--font-plate);letter-spacing:.04em;
  padding:3px 7px;box-shadow:none;
}
.map-label::before{border-top-color:var(--worn-brass)}
/* the true spot, once earned: a slow paper-white pulse */
.target-beacon{animation:beacon 2.2s ease-in-out infinite}
@keyframes beacon{
  0%,100%{stroke-opacity:1;fill-opacity:.25;stroke-width:2.5}
  50%{stroke-opacity:.45;fill-opacity:.1;stroke-width:5}
}
.sheet.temp-colder .geowrap{border-color:var(--far-stars)}
.sheet.temp-warmer .geowrap{border-color:var(--instrument-brass)}
.sheet.temp-hot .geowrap{border-color:var(--star-gold);box-shadow:0 0 0 3px rgba(231,200,122,.18)}
.sheet.is-found .geowrap{
  border-color:var(--star-gold);
  box-shadow:0 0 0 4px rgba(231,200,122,.16), 0 0 24px rgba(231,200,122,.35);
}

/* the earned beat: a name surfacing after a solved step */
.beat-reveal{
  margin:16px 0 4px;text-align:center;
  font:600 1.25rem/1.4 var(--font-display);color:var(--star-gold);
  letter-spacing:.01em;
}

@media (prefers-reduced-motion: reduce){
  *{transition-duration:0ms !important;animation:none !important}
}
