/* The Eleven Levels — stylesheet.

   DESIGN BAR. Apple's HIG is the standing reference for Alan's sites
   (18 Aug 2026; the enforced translation lives in
   ~/kimchihouse/docs/design-guidelines.md). What that means here: 44px
   minimum hit targets on coarse pointers, 17px body type, reduced-motion
   honoured, two type faces only, and content as the interface.

   THE PALETTE IS THE BOARD. Bone on deep slate are a chessboard's own two
   colours; one vermilion is the only other ink, and it means exactly one
   thing — you. Deliberately NOT the near-black-and-gold that every generated
   landing page wears, which is why there is no gold token here and adding one
   is a regression, not a brightening.

   WHERE "EXPENSIVE" COMES FROM — Alan, 31 Aug 2026, on the first build: "this
   does not look attractive at all… visually pleasing and looking expensive."
   The first build was flat mid-slate with hairlines and no image anywhere, and
   it read as a research paper. The four things that changed it, in order of
   how much they did:

     1. A LIT OBJECT. The lathed Staunton set renders live behind the hero
        (js/hero.js). A page selling chess with no chess on it was the biggest
        single hole, and a photograph would not have moved with the scroll.
     2. VALUE RANGE. The old page lived between #0F and #24 — a 6% spread, so
        nothing could advance or recede. It now runs from --ink-deep to full
        bone. This is the same fault, and the same fix, as the muddy shots in
        ~/animated-channel (docs — the problem was luminance, never hue).
     3. LIGHT HAS A SOURCE. One warm pool top-left, a vignette everywhere else,
        and every surface lit consistently with it. Depth is cheap once the
        page agrees where the light is.
     4. GRAIN. One tiling turbulence over the whole page at 3% opacity. Flat
        dark gradients band on cheap panels; grain hides the banding and is the
        difference between "dark website" and "photographed in a dark room".

   NO CARDS, NO PILLS still holds. Structure is hairline rules, full-bleed
   bands and light — not a grid of rounded boxes with drop shadows. */

/* Self-hosted. This was an @import of Google Fonts: the browser had to fetch
   site.css, THEN the Google stylesheet, THEN the font — three round trips in
   series before the first word could paint (Lighthouse, mobile: 2.3s of it).
   The same two latin variable files Google serves, from our own origin, with
   the font preloaded from index.html so it travels alongside this file. */
@font-face {
  font-family: 'Familjen Grotesk'; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url('/fonts/familjen-grotesk-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Newsreader'; font-style: normal; font-weight: 300 500; font-display: swap;
  src: url('/fonts/newsreader-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --ink-deep: #0B0F11;   /* the floor. js/hero.js fogs to this exact value —
                            change one and you must change both, or the board
                            grows a visible far edge. */
  --ink:    #0F1416;
  --surf:   #161E21;
  --raise:  #1B2529;
  --line:   #242F33;
  --line-2: #334247;
  --bone:   #E9E2D2;
  --white:  #FBF7EE;
  --muted:  #93A5A7;
  --faint:  #63767A;
  --hot:    #E4572E;
  --hot-lo: #B33C1C;
  --hot-ink:#170A05;
  --disp: 'Familjen Grotesk', 'Helvetica Neue', Arial, sans-serif;
  --body: 'Newsreader', Georgia, 'Times New Roman', serif;
  --mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  --gut: 56px;
  --ease: cubic-bezier(.22,.61,.36,1);
  --ease-io: cubic-bezier(.65,0,.35,1);
}
@media (max-width: 1100px) { :root { --gut: 40px; } }
@media (max-width: 760px)  { :root { --gut: 22px; } }

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0; color: var(--bone);
  font: 400 17px/1.62 var(--body);
  -webkit-font-smoothing: antialiased;
  /* Two lights over a deep floor: the warm one is where hero.js puts its key,
     so the page and the render agree about the room. */
  background:
    radial-gradient(1200px 780px at 12% -8%, #22303608 0%, #0000 62%),
    radial-gradient(900px 620px at 88% 6%, #E4572E0F 0%, #0000 58%),
    linear-gradient(180deg, var(--ink) 0%, var(--ink-deep) 46%, #080B0D 100%);
  background-attachment: fixed;
  background-color: var(--ink-deep);
  overflow-x: hidden;
}

/* Grain and vignette. Both are pointer-events:none overlays on <body>, so they
   sit over the WebGL canvas as well — the board is grained with the page
   instead of looking pasted onto it. */
body::before, body::after {
  content: ''; position: fixed; inset: 0; pointer-events: none; z-index: 3;
}
body::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.42'/%3E%3C/svg%3E");
  opacity: .05; mix-blend-mode: overlay;
}
body::after {
  background: radial-gradient(128% 92% at 50% 34%, #0000 42%, #05080966 76%, #050809D9 100%);
}

img, svg { max-width: 100%; display: block; }
a { color: var(--hot); text-decoration: none; transition: color .18s var(--ease); }
a:hover { color: var(--bone); }
:focus-visible { outline: 2px solid var(--hot); outline-offset: 3px; }

.wrap { padding: 0 var(--gut); }
.mono { font-family: var(--mono); }
.dim  { color: var(--muted); }

/* content sits above the fixed canvas and under the grain */
#quiz, #result, footer, #intro { position: relative; z-index: 2; }

/* one thin header, per "content is the interface" */
.top {
  position: fixed; top: 0; left: 0; right: 0; z-index: 6;
  display: flex; justify-content: space-between; align-items: center;
  padding: 18px var(--gut);
  font: 500 11px/1 var(--mono); letter-spacing: .18em; color: var(--faint);
  border-bottom: 1px solid #0000;
  transition: background .3s var(--ease), border-color .3s var(--ease), backdrop-filter .3s;
}
.top.stuck {
  background: #0B0F11CC; border-bottom-color: var(--line);
  -webkit-backdrop-filter: saturate(140%) blur(14px); backdrop-filter: saturate(140%) blur(14px);
}
.top b { color: var(--bone); font-weight: 500; }

/* labels — the only decorative type, and they carry meaning */
.lab {
  font: 600 11px/1 var(--disp); letter-spacing: .2em; text-transform: uppercase;
  color: var(--hot); margin: 0 0 14px;
}

h1, h2 { font-family: var(--disp); font-weight: 600; letter-spacing: -.025em; margin: 0; }
p { margin: 0 0 1.05em; }

[hidden]:not(.qmeta button) { display: none !important; }

/* ── actions ──────────────────────────────────────────────────────────
   Square, 48px, never a pill. The sheen is a single skewed highlight that
   crosses on hover — it is the one place the page admits to being glossy, and
   it is on the button because that is the one thing that must look pressable. */
.btn {
  position: relative; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  min-height: 48px; padding: 16px 30px; border: 1px solid var(--hot);
  background: linear-gradient(180deg, #F2673B, var(--hot) 58%, var(--hot-lo));
  color: var(--hot-ink);
  font: 600 16px/1 var(--disp); cursor: pointer; text-align: center;
  box-shadow: 0 1px 0 #FFFFFF33 inset, 0 10px 30px -12px #E4572E99;
  transition: transform .2s var(--ease), box-shadow .25s var(--ease), filter .2s;
}
.btn::after {
  content: ''; position: absolute; top: -60%; bottom: -60%; width: 42px; left: -80px;
  background: linear-gradient(90deg, #FFF0, #FFFFFF59, #FFF0); transform: skewX(-18deg);
  transition: left .55s var(--ease);
}
.btn:hover { transform: translateY(-2px); box-shadow: 0 1px 0 #FFFFFF40 inset, 0 18px 40px -14px #E4572EB3; filter: brightness(1.05); }
.btn:hover::after { left: 130%; }
.btn:active { transform: translateY(0); }
.btn.ghost {
  background: #E9E2D20A; border-color: var(--line-2); color: var(--muted);
  box-shadow: none;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.btn.ghost:hover { background: #E9E2D214; border-color: var(--faint); color: var(--bone); filter: none; }
.btn.ghost::after { display: none; }
.btn[disabled] { opacity: .5; cursor: default; transform: none; }
@media (pointer: coarse) { .btn { min-height: 52px; } }

/* ── reveal ───────────────────────────────────────────────────────────
   One primitive for the whole page: .rise starts low and blurred, .rise.in is
   at rest. js/motion.js flips the class from an IntersectionObserver and sets
   --d for a stagger. Blur is in the transition because a pure translate reads
   as a slide; a translate through 6px of blur reads as something coming into
   focus, which is the difference in feel Alan asked for. */
.rise {
  opacity: 0; transform: translateY(26px); filter: blur(6px);
  transition: opacity .8s var(--ease) var(--d, 0s),
              transform .9s var(--ease) var(--d, 0s),
              filter .9s var(--ease) var(--d, 0s);
  will-change: opacity, transform;
}
.rise.in { opacity: 1; transform: none; filter: none; }

/* ── the stage ────────────────────────────────────────────────────────
   The live board. Fixed, full-viewport, BEHIND everything (z-index 0) and
   pointer-events:none so it can never eat a scroll or a tap. It fades out as
   the hero leaves rather than being unmounted, because the quiz can send you
   back to the top at any moment. */
#stage {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  opacity: 1; transition: opacity 1.4s var(--ease);
}
/* THE POSTER. A still of this exact scene, captured from js/hero.js itself by
   tools/poster.sh. It is up before a single line of three.js has parsed, and it
   is what a visitor keeps when the live board never runs — no WebGL, too few
   cores, or reduced motion. The fallback for a page whose whole point is that
   it does not look flat cannot itself be a flat gradient. */
#stage .poster {
  position: absolute; inset: 0;
  /* JPEG first as the floor: any engine that does not parse image-set keeps it.
     image-set then upgrades to webp (30 KB against 62 KB) where it is understood. */
  background: url('/img/hero-board.jpg') center / cover no-repeat;
  background-image: image-set(url('/img/hero-board.webp') type('image/webp'),
                              url('/img/hero-board.jpg')  type('image/jpeg'));
  opacity: 1; transition: opacity 1.2s var(--ease);
}
#stage canvas {
  width: 100%; height: 100%; display: block;
  opacity: 0; transition: opacity 1.2s var(--ease);
}
/* .lit is set on the first frame the renderer actually paints, so the still and
   the live board cross-fade and the join is never a gap or a double image. */
#stage.lit .poster { opacity: 0; }
/* Capture mode: settle instantly, so a screenshot is never a half-fade. */
#stage.nofade, #stage.nofade .poster, #stage.nofade canvas { transition: none; }
#stage.lit canvas { opacity: 1; }
body.playing #stage { opacity: 0; }

/* ── hero ─────────────────────────────────────────────────────────────
   Full viewport, copy on the left third, board everywhere. The right column is
   empty on purpose: it is where the board is, and putting a panel there was
   what made the first build look like a spreadsheet with a headline. */
/* THE SCRIM. Type sits over a live render whose content moves, so legibility
   cannot depend on what happens to be behind a given word. A left-to-right wash
   of the page's own floor colour guarantees the copy's contrast no matter where
   the board has drifted, and doubles as the shadow side of the room — the light
   is top-right, so the left going dark is what the render is already doing. */
.hero::before {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    linear-gradient(95deg, var(--ink-deep) 30%, #0B0F11F2 44%, #0B0F11B8 56%, #0B0F1100 74%),
    linear-gradient(0deg, #0B0F11B3 0%, #0B0F1100 24%);
}
.hero > * { position: relative; z-index: 1; }

.hero {
  position: relative; min-height: 100svh;
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, .82fr);
  align-items: center; gap: 40px;
  padding: 120px var(--gut) 96px;
}
/* NOT a ch value. `ch` resolves against THIS element's font, which is the
   17px body serif, so 17ch was ~150px and the 106px headline was breaking one
   word per line and clipping. The column is sized in the grid; this is only a
   ceiling for very wide screens. */
.hero-copy { max-width: 720px; }
.eyebrow {
  display: inline-flex; align-items: center; gap: 10px; margin: 0 0 24px;
  font: 500 11px/1 var(--mono); letter-spacing: .22em; color: var(--faint);
  text-transform: uppercase;
}
.eyebrow::before {
  content: ''; width: 26px; height: 1px; background: var(--hot); flex: none;
  transform-origin: left; animation: sweep 1s .3s var(--ease) both;
}
@keyframes sweep { from { transform: scaleX(0); } to { transform: scaleX(1); } }

.hero h1 {
  font-size: clamp(46px, 7.4vw, 106px); line-height: .93; letter-spacing: -.04em;
  margin: 0 0 26px; max-width: 15ch;
  /* background-clip:text crops to the line box, and at line-height .93 that box
     ends above the tail of a 'g'. The padding gives the descender somewhere to
     be; the negative margin takes the space back off the layout. */
  padding-bottom: .1em; margin-bottom: calc(26px - .1em);
  /* bone at the top falling to slate at the baseline: the same top-lit logic
     the render uses, applied to the type */
  background: linear-gradient(172deg, var(--white) 12%, #C7C0B2 62%, #8C9698 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.hero h1 em { font-style: normal; color: var(--hot); -webkit-text-fill-color: var(--hot); }
.hero .sub {
  font: 300 clamp(19px, 1.65vw, 23px)/1.5 var(--body); color: var(--muted);
  max-width: 38ch; margin: 0 0 38px;
}
.hero .go { display: flex; gap: 18px; align-items: center; flex-wrap: wrap; }
.hero .go .meta {
  font: 400 12px/1.5 var(--mono); letter-spacing: .1em; color: var(--faint);
}
.hero .go .meta b { color: var(--muted); font-weight: 400; }

/* the board's own caption, bottom right — the only thing in the right column */
.shot {
  /* Top of the right column, not the bottom. The board's lit corner is bottom
     right — the one place on the page with real luminance — and a 12px mono
     caption laid over it could not be read at any weight. Up here it is on the
     unlit side of the same picture. */
  align-self: start; justify-self: end; text-align: right; max-width: 26ch;
  font: 400 12px/1.7 var(--mono); letter-spacing: .06em; color: var(--muted);
  border-right: 1px solid var(--line-2); padding-right: 16px;
  /* It is a caption on a photograph, so it needs the contrast a caption on a
     photograph needs — the board is directly behind it at every framing. */
  text-shadow: 0 1px 10px #05080A, 0 0 26px #05080ACC;
}
.shot b { display: block; color: var(--muted); font-weight: 400; letter-spacing: .14em; }

.cue {
  position: absolute; left: var(--gut); bottom: 34px; color: var(--faint);
  min-height: 44px; align-items: center;
  display: flex; align-items: center; gap: 12px;
  font: 400 10px/1 var(--mono); letter-spacing: .24em; color: var(--faint);
  text-transform: uppercase;
}
.cue:hover { color: var(--bone); }
.cue i { display: block; width: 1px; height: 40px; background: linear-gradient(var(--hot), #0000); }
.cue i::after {
  content: ''; display: block; width: 1px; height: 12px; background: var(--hot);
  animation: fall 2.2s var(--ease-io) infinite;
}
@keyframes fall { 0% { transform: translateY(-12px); opacity: 0; } 40% { opacity: 1; } 100% { transform: translateY(40px); opacity: 0; } }

@media (max-width: 980px) {
  .hero { grid-template-columns: 1fr; align-content: center; padding-top: 104px; }
  .hero-copy { max-width: none; }
  .shot { align-self: auto; justify-self: start; text-align: left; border-right: 0;
          border-left: 1px solid var(--line-2); padding: 0 0 0 16px; margin-top: 40px; }
}

/* ── section furniture ────────────────────────────────────────────────
   A band is a full-bleed dark panel with its own hairline top. Sections after
   the hero are opaque so the board reads as being behind a wall, not through
   frosted glass — that gave the first pass a washed-out middle. */
.band {
  position: relative; z-index: 2;
  background: linear-gradient(180deg, #0B0F11F2, var(--ink-deep) 14%, var(--ink-deep));
  border-top: 1px solid var(--line);
}
.band + .band { border-top: 0; background: var(--ink-deep); }
.shead { padding: 96px var(--gut) 0; }
.shead h2 {
  font-size: clamp(32px, 4.2vw, 56px); line-height: 1.02; letter-spacing: -.03em;
  max-width: 17ch; margin: 0 0 18px;
}
.shead p { color: var(--muted); max-width: 52ch; font-size: 19px; margin: 0; }

/* ── the ladder, as a climb ───────────────────────────────────────────
   Eleven rows, lit one at a time as they cross the middle of the screen
   (js/motion.js). The rail on the left fills with the same progress, so the
   section reads as a single ascent rather than eleven list items. */
.climb { display: grid; grid-template-columns: 44px 1fr; gap: 0; padding: 56px var(--gut) 96px; }
.climb .rail-v { position: relative; }
.climb .rail-v::before {
  content: ''; position: absolute; left: 21px; top: 0; bottom: 0; width: 1px; background: var(--line);
}
.climb .rail-v i {
  position: absolute; left: 20px; top: 0; width: 3px; height: 0;
  background: linear-gradient(180deg, var(--hot), var(--hot-lo));
  box-shadow: 0 0 22px 2px #E4572E7A;
  transition: height .18s linear;
}
.steps-v { display: grid; }
.step {
  position: relative; text-decoration: none;
  display: grid; grid-template-columns: 62px minmax(0,1fr) auto 30px; gap: 22px; align-items: baseline;
  padding: 22px 4px 22px 26px; border-bottom: 1px solid var(--line);
  color: var(--faint);
  transition: color .5s var(--ease), background .5s var(--ease), padding-left .35s var(--ease);
}
/* The accent that grows under the cursor, echoing the rail on the left of the
   section — the same gesture the claims use, at rung scale. */
.step::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--hot); transform: scaleY(0); transform-origin: center;
  transition: transform .3s var(--ease);
}
.step:first-child { border-top: 1px solid var(--line); }
.step .n {
  font: 400 13px/1 var(--mono); letter-spacing: .1em; color: var(--line-2);
  font-variant-numeric: tabular-nums; transition: color .5s var(--ease);
}
.step .nm {
  font: 500 clamp(21px, 2.5vw, 32px)/1.1 var(--disp); letter-spacing: -.02em; color: #5E6E71;
  transition: color .5s var(--ease), transform .5s var(--ease);
}
.step .bd { font: 400 12px/1 var(--mono); letter-spacing: .08em; color: var(--line-2); transition: color .5s var(--ease); white-space: nowrap; }
.step.on { color: var(--muted); background: linear-gradient(90deg, #E9E2D20A, #0000 62%); padding-left: 34px; }
.step.on .n  { color: var(--hot); }
.step.on .nm { color: var(--white); }
.step.on .bd { color: var(--faint); }

/* The arrow only exists on hover. A permanent one on eleven rows is eleven
   pieces of chrome; one that arrives under the cursor is an answer to "can I
   click this?" asked at the moment it is asked. */
.step .go {
  justify-self: end; color: var(--hot); font: 400 15px/1 var(--disp);
  opacity: 0; transform: translateX(-8px);
  transition: opacity .3s var(--ease), transform .3s var(--ease);
}
.step:hover, .step:focus-visible {
  color: var(--muted); background: linear-gradient(90deg, #E9E2D216, #0000 66%);
  padding-left: 40px;
}
.step:hover::before, .step:focus-visible::before { transform: scaleY(1); }
.step:hover .n,  .step:focus-visible .n  { color: var(--hot); }
.step:hover .nm, .step:focus-visible .nm { color: var(--white); }
.step:hover .bd, .step:focus-visible .bd { color: var(--muted); }
.step:hover .go, .step:focus-visible .go { opacity: 1; transform: none; }
.step:focus-visible { outline: none; }   /* ::before is the focus ring here */

/* No hover state on a touch screen: it would latch on after a tap and sit
   there lit until you touched something else. */
@media (hover: none) {
  .step:hover { background: none; padding-left: 26px; }
  .step:hover::before { transform: scaleY(0); }
  .step:hover .go { opacity: 0; }
}
@media (max-width: 760px) {
  .climb { grid-template-columns: 18px 1fr; }
  .climb .rail-v::before { left: 8px; } .climb .rail-v i { left: 7px; }
  .step { grid-template-columns: 40px 1fr; gap: 12px; padding-left: 14px; }
  .step .bd { grid-column: 2; }
  .step .go { display: none; }
  .step.on { padding-left: 18px; }
  .step:hover, .step:focus-visible { padding-left: 20px; }
}

/* ── the three claims ─────────────────────────────────────────────────
   Still not cards: a hairline top rule, a numeral, and air. The hover raises
   the rule to vermilion, which is the whole interaction. */
.claims { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; padding: 0 var(--gut) 100px; }
.claim { padding: 30px 34px 0 0; border-top: 1px solid var(--line); position: relative; }
.claim::before {
  content: ''; position: absolute; top: -1px; left: 0; width: 0; height: 1px; background: var(--hot);
  transition: width .6s var(--ease);
}
.claim:hover::before { width: 72px; }
.claim .k { font: 400 12px/1 var(--mono); color: var(--hot); letter-spacing: .16em; }
.claim h3 { font: 500 23px/1.2 var(--disp); letter-spacing: -.02em; margin: 16px 0 12px; color: var(--bone); }
.claim p { color: var(--muted); margin: 0; font-size: 16.5px; }
@media (max-width: 880px) { .claims { grid-template-columns: 1fr; gap: 34px; } .claim { padding-right: 0; } }

/* ── the product ──────────────────────────────────────────────────────
   The guide, shown as an object. The first build sold a PDF without ever
   showing one, which is the oldest mistake there is. Three sheets on a shared
   3D transform: a real page, its next page behind, and a slab of edge to give
   the stack thickness. js/motion.js parallaxes the whole rig on scroll. */
.product { display: grid; grid-template-columns: 1fr 1fr; gap: 72px; align-items: center; padding: 96px var(--gut) 110px; }
.rig { perspective: 1800px; perspective-origin: 60% 40%; }
.stack {
  position: relative; width: min(100%, 440px); aspect-ratio: 1 / 1.414; margin: 0 auto;
  transform-style: preserve-3d;
  transform: rotateX(var(--rx, 8deg)) rotateY(var(--ry, -19deg)) rotateZ(1.5deg) translateY(var(--py, 0px));
  transition: transform .9s var(--ease);
}
.sheet {
  position: absolute; inset: 0; background: #FBF8F1; overflow: hidden;
  box-shadow: 0 60px 90px -40px #000000E6, 0 8px 22px -10px #000000A6;
}
.sheet img { width: 100%; height: 100%; object-fit: cover; object-position: top center; }
/* The sheets behind have to CLEAR the cover, or the stack is one white slab and
   the buyer never sees that the thing has pages in it. The offset is along the
   page's own diagonal so the fan reads as depth rather than as a drop shadow. */
.sheet.back  { transform: translateZ(-18px) translate(42px, 26px); filter: brightness(.84) contrast(1.05); }
.sheet.back2 { transform: translateZ(-34px) translate(76px, 50px); filter: brightness(.55); }
/* the lit edge of the paper, on the side the page's key light comes from */
.stack::after {
  content: ''; position: absolute; top: 0; bottom: 0; left: -9px; width: 9px;
  background: linear-gradient(90deg, #7C7466, #D8D0C0 62%, #FBF8F1);
  transform: rotateY(-90deg); transform-origin: right center;
}
.rig .glow {
  position: absolute; inset: 8% 4% -6%; z-index: -1; border-radius: 50%;
  background: radial-gradient(closest-side, #E4572E33, #0000 72%); filter: blur(30px);
}
.pitch h2 { font-size: clamp(32px, 4vw, 52px); line-height: 1.03; letter-spacing: -.03em; margin: 0 0 20px; max-width: 15ch; }
.pitch > p { color: var(--muted); max-width: 46ch; font-size: 18.5px; }
.spec { list-style: none; margin: 30px 0 34px; padding: 0; display: grid; gap: 0; max-width: 46ch; }
.spec li {
  display: grid; grid-template-columns: 24px 1fr; gap: 14px; align-items: start;
  padding: 15px 0; border-top: 1px solid var(--line); color: var(--muted); font-size: 16.5px;
}
.spec li::before { content: '→'; color: var(--hot); font: 400 14px/1.5 var(--mono); }
.price-line { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; margin-bottom: 26px; }
.price-line .amt { font: 600 clamp(34px,4vw,46px)/1 var(--disp); letter-spacing: -.03em; color: var(--white); font-variant-numeric: tabular-nums; }
.price-line .per { font: 400 13px/1 var(--mono); letter-spacing: .1em; color: var(--faint); }
@media (max-width: 980px) { .product { grid-template-columns: 1fr; gap: 54px; } .rig { order: -1; } }

/* ── closing call ─────────────────────────────────────────────────────
   One line, one button, and the vermilion glow behind it doing the work the
   old page asked a flat rectangle to do alone. */
.close-cta { position: relative; text-align: center; padding: 120px var(--gut) 130px; overflow: hidden; }
.close-cta::before {
  content: ''; position: absolute; left: 50%; top: 40%; width: 720px; height: 420px;
  transform: translate(-50%,-50%); border-radius: 50%; pointer-events: none;
  background: radial-gradient(closest-side, #E4572E26, #0000 70%); filter: blur(24px);
}
.close-cta h2 { position: relative; font-size: clamp(34px, 5vw, 66px); line-height: 1; letter-spacing: -.035em; margin: 0 auto 22px; max-width: 16ch; }
.close-cta p { position: relative; color: var(--muted); max-width: 44ch; margin: 0 auto 38px; font-size: 19px; }
.close-cta .go { position: relative; display: flex; justify-content: center; align-items: center; gap: 18px; flex-wrap: wrap; }
.close-cta .meta { font: 400 12px/1 var(--mono); letter-spacing: .1em; color: var(--faint); }
/* ── the ladder, small ────────────────────────────────────────────────
   The result screen's version of the climb above. Same reading — you are on
   one rung and the ones above you are dimmed — at a size that fits a column. */
.ladder { display: grid; }
.rung {
  display: grid; grid-template-columns: 30px 1fr auto; gap: 12px; align-items: baseline;
  width: 100%; text-align: left; min-height: 44px; padding: 11px 12px;
  background: none; border: 0; border-left: 2px solid var(--line);
  color: var(--muted); font: 400 16px/1.3 var(--disp); cursor: default;
  transition: background .18s var(--ease), border-color .18s var(--ease), color .18s var(--ease);
}
.rung .rn, .rung .rb { font: 400 11px/1 var(--mono); color: var(--faint); }
.rung.above { opacity: .4; }
.rung.you {
  border-left-color: var(--hot); background: linear-gradient(90deg, #E4572E1F, #E4572E03);
  color: var(--white); font-weight: 600; box-shadow: -10px 0 30px -18px #E4572E;
}
.rung.you .rn, .rung.you .rb { color: var(--hot); }
button.rung { cursor: pointer; }
button.rung:hover { background: #E9E2D20D; color: var(--bone); border-left-color: var(--faint); }

/* ── quiz ─────────────────────────────────────────────────────────────── */
#quiz { display: none; padding-bottom: 70px; padding-top: 58px; }
#quiz.on { display: block; }
.qbar { padding: 24px var(--gut) 0; }
.rail { height: 2px; background: var(--line); }
.fill { height: 2px; width: 0; background: var(--hot); transition: width .4s cubic-bezier(.4,0,.2,1); }
.qmeta { display: flex; justify-content: space-between; margin-top: 14px;
         font: 400 12px/1 var(--mono); letter-spacing: .14em; color: var(--faint); }
.qmeta button { background: none; border: 0; color: var(--faint); font: inherit;
                cursor: pointer; padding: 8px 10px; margin: -8px -10px; min-height: 44px; }
.qmeta button:hover { color: var(--bone); }
.qmeta button[hidden] { visibility: hidden; display: inline-block; }
.qhost { padding: 60px var(--gut) 0; max-width: 880px; }
.qhost h2 { font-size: clamp(27px, 4.4vw, 40px); line-height: 1.14; margin-bottom: 34px; }
.opts { display: grid; gap: 10px; }
.opt {
  display: flex; align-items: center; gap: 16px; width: 100%; text-align: left;
  min-height: 60px; padding: 16px 20px;
  background: linear-gradient(180deg, #E9E2D208, #E9E2D203);
  border: 1px solid var(--line); border-left: 2px solid var(--line);
  color: var(--bone); font: 400 17px/1.4 var(--body); cursor: pointer;
  transition: border-color .18s var(--ease), background .18s var(--ease),
              transform .18s var(--ease), box-shadow .18s var(--ease);
}
.opt:hover { border-color: var(--line-2); border-left-color: var(--hot); background: #E9E2D211;
             transform: translateX(4px); box-shadow: -8px 0 24px -14px #E4572EB3; }
.opt .k { flex: none; width: 26px; height: 26px; display: grid; place-items: center;
          border: 1px solid var(--line); font: 400 11px var(--mono); color: var(--faint); }
.opt.pick { border-color: var(--hot); border-left-color: var(--hot); background: #E4572E14;
            box-shadow: 0 0 0 1px #E4572E4D, 0 10px 34px -18px #E4572E; }
.opt.pick .k { border-color: var(--hot); color: var(--hot); }
@media (hover: none) { .opt .k { display: none; } }
.qnote { margin: 28px 0 0; font: 400 13px/1.5 var(--mono); color: var(--faint); }

/* ── result ───────────────────────────────────────────────────────────── */
#result { display: none; padding-bottom: 64px; padding-top: 58px; }
#result.on { display: block; }
.verdict { display: grid; grid-template-columns: auto 1fr; gap: 40px;
           align-items: start; padding: 56px var(--gut) 34px; }
.bignum { font: 700 clamp(78px, 11vw, 128px)/.8 var(--disp); letter-spacing: -.05em;
          color: var(--hot); font-variant-numeric: tabular-nums;
          text-shadow: 0 0 60px #E4572E59; }
.bignum small { display: block; font: 500 11px/1 var(--mono); letter-spacing: .24em;
                color: var(--faint); margin-top: 16px; }
.verdict h1 { font-size: clamp(36px, 5vw, 60px); line-height: 1.02; margin-bottom: 14px;
              background: linear-gradient(168deg, var(--white) 16%, #B9B3A6 100%);
              -webkit-background-clip: text; background-clip: text; color: transparent; }
.verdict .tag { font: 300 clamp(18px, 2.3vw, 21px)/1.45 var(--body); color: var(--muted);
                max-width: 34ch; margin: 0; }
.bands { display: flex; gap: 28px; margin-top: 24px; flex-wrap: wrap;
         font: 500 12px/1 var(--mono); letter-spacing: .08em; color: var(--faint); }
.bands b { color: var(--bone); font-weight: 500; }
@media (max-width: 760px) { .verdict { grid-template-columns: 1fr; gap: 10px; } }

.chart { padding: 0 var(--gut); }
.chart svg { width: 100%; height: auto; }
.drawn { stroke-dasharray: 2600; stroke-dashoffset: 2600;
         animation: draw 1.5s .2s cubic-bezier(.4,0,.2,1) forwards; }
@keyframes draw { to { stroke-dashoffset: 0; } }

.split { display: grid; grid-template-columns: 320px 1fr; gap: 48px;
         padding: 52px var(--gut) 0; align-items: start; }
@media (max-width: 900px) { .split { grid-template-columns: 1fr; gap: 34px; } }
.block { border-top: 1px solid var(--line); padding-top: 26px; }
.block + .block { margin-top: 34px; }
.block p { color: var(--muted); max-width: 58ch; }
.lie { font: 500 clamp(25px, 3.4vw, 34px)/1.22 var(--disp); letter-spacing: -.02em;
       color: var(--bone); max-width: 19ch; margin: 0 0 14px; }
.steps { counter-reset: s; list-style: none; padding: 0; margin: 0; max-width: 58ch; }
.steps li { counter-increment: s; position: relative; padding-left: 40px;
            margin-bottom: 1em; color: var(--muted); }
.steps li::before { content: counter(s, decimal-leading-zero); position: absolute; left: 0;
                    font: 400 12px/1.7 var(--mono); color: var(--hot); }
.acts { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 26px; }
.fine { font: 400 13px/1.55 var(--mono); letter-spacing: .02em; margin-top: 16px; color: var(--faint); max-width: 58ch; }
.msg { font: 400 13px/1.5 var(--mono); margin-top: 12px; min-height: 1.4em; color: var(--muted); }
.msg.err { color: #E4572E; } .msg.ok { color: #8FC08A; }

figure.board { margin: 34px 0 0; border-top: 1px solid var(--line); padding-top: 26px; }
figure.board img { width: 100%; max-width: 460px; }
figure.board figcaption { margin-top: 14px; color: var(--muted); font-size: 15.5px; max-width: 56ch; }

/* ── look inside ──────────────────────────────────────────────────────
   Three pages of the buyer's own guide, fanned like the stack on the landing
   page so the two places the product appears speak the same language. They
   are deliberately small and slightly turned: this is proof that the thing is
   real and full of boards, not a reading copy. Clicking one opens it. */
.peek { margin: 30px 0 0; padding: 0; }
.peek .sheets { display: flex; gap: 14px; perspective: 1400px; }
.peek button {
  flex: 1 1 0; min-width: 0; padding: 0; border: 0; background: none; cursor: zoom-in;
  transform: rotateY(9deg) rotateZ(-1deg); transform-origin: left center;
  transition: transform .35s var(--ease), box-shadow .35s var(--ease);
}
.peek button:nth-child(2) { transform: rotateY(9deg); }
.peek button:nth-child(3) { transform: rotateY(9deg) rotateZ(1deg); }
.peek img {
  width: 100%; height: auto; display: block; background: #FBF8F1;
  box-shadow: 0 18px 34px -18px #000000E6, 0 0 0 1px #FFFFFF14;
}
.peek button:hover, .peek button:focus-visible {
  transform: rotateY(0deg) translateY(-6px) scale(1.03); z-index: 1;
}
.peek button:focus-visible { outline: 2px solid var(--hot); outline-offset: 4px; }
.peek figcaption { margin-top: 14px; font: 400 13px/1.5 var(--mono); color: var(--faint); }
@media (max-width: 560px) { .peek .sheets { gap: 8px; } }

/* ── the lightbox ─────────────────────────────────────────────────────
   One page, full height, on a near-black wash. No library: an <img>, a close
   button, Escape, and a click on the backdrop. */
.lightbox {
  position: fixed; inset: 0; z-index: 40; display: grid; place-items: center;
  padding: 40px 20px; background: #05080AF2;
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  opacity: 0; transition: opacity .25s var(--ease); cursor: zoom-out;
}
.lightbox.on { opacity: 1; }
.lightbox img {
  max-width: min(760px, 100%); max-height: 100%; width: auto; height: auto;
  box-shadow: 0 40px 90px -30px #000; background: #FBF8F1; cursor: default;
}
.lb-close {
  position: absolute; top: 14px; right: 18px; width: 44px; height: 44px;
  background: none; border: 0; color: var(--muted); font: 300 30px/1 var(--disp);
  cursor: pointer;
}
.lb-close:hover { color: var(--bone); }

/* ── the other offers ─────────────────────────────────────────────────
   Quieter than the level's own guide on purpose: ghost buttons and hairlines,
   not a second and third primary action. The struck-through sum is the whole
   argument, and every number in here is computed in levels.py — a typed
   saving becomes a lie the first time a single price moves. */
.offers { margin-top: 34px; padding-top: 26px; border-top: 1px solid var(--line); }
.offer {
  display: flex; gap: 30px; align-items: center; justify-content: space-between;
  flex-wrap: wrap; padding: 20px 0;
}
.offer + .offer { border-top: 1px solid var(--line); }
.offer h4 { font: 500 19px/1.2 var(--disp); letter-spacing: -.01em; color: var(--bone); margin: 0 0 8px; }
.offer p { margin: 0; color: var(--muted); max-width: 44ch; font-size: 16px; }
.offer-buy { display: grid; gap: 12px; justify-items: start; }
.offer-price { display: flex; align-items: baseline; gap: 10px; white-space: nowrap; }
.offer-price span { font: 600 28px/1 var(--disp); letter-spacing: -.03em; color: var(--white); }
.offer-price s { font: 400 14px/1 var(--mono); color: var(--faint); }

/* ── forms ────────────────────────────────────────────────────────────── */
form.mail { display: grid; gap: 10px; max-width: 420px; margin-top: 4px; }
input[type=email] {
  min-height: 52px; padding: 0 18px; font: 400 17px var(--body);
  border: 1px solid var(--line); background: var(--ink); color: var(--bone);
}
input[type=email]::placeholder { color: var(--faint); }
input[type=email]:focus { border-color: var(--hot); outline: none; }
.hp { position: absolute; left: -9999px; }

footer { border-top: 1px solid var(--line); margin-top: 0; background: #070A0B;
         padding: 40px var(--gut) 72px; color: var(--faint); font-size: 14px; }
footer a { color: var(--muted); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
  .drawn { stroke-dashoffset: 0; }
}
