/* ============================================================================
   LEXUN DECK — one screen per idea, identical on laptop and phone.
   Vertical snap slides + horizontal snap rails. No breakpoint changes the
   structure: the same seven slides, the same order, the same components,
   scaled by clamp() rather than rearranged by media query.
   Loads after the token sheet and the HUD skin. Presentation only.
   ============================================================================ */

:root{
  --hdr:56px;
  --slide-pad-x:clamp(16px,4vw,40px);
  --deck-max:1180px;
  --rail-w:clamp(0px,2.2vw,26px);
  /* width of the fixed chapter rail on the right, reserved as slide padding */
  --rail-gutter:30px;
  /* extra bottom room, switched on only while the storage notice is visible */
  --note-gutter:0px;
}
@media(min-width:64rem){ :root{ --hdr:64px } }

/* ─────────────────── 1 · SNAP CONTAINER ─────────────────── */
html{
  scroll-snap-type:y proximity;
  scroll-padding-top:var(--hdr);
}
@media(prefers-reduced-motion:reduce){ html{scroll-snap-type:none} }

/* the rails scroll horizontally; the page never does */
html,body{overflow-x:clip;max-width:100%}

.slide{
  position:relative;
  scroll-snap-align:start;
  min-height:calc(100svh - var(--hdr));
  display:grid;
  /* an implicit `auto` track is sized by its widest child's min-content, so one
     non-shrinking row (the loop line) used to stretch every sibling past the
     viewport and get clipped by overflow-x. Pinning the track to the container
     width makes inner rails scroll instead of the slide silently overflowing. */
  grid-template-columns:minmax(0,1fr);
  align-content:center;
  gap:clamp(10px,1.5vh,18px);
  /* the right gutter reserves the width of the fixed chapter rail, so no slide
     content is ever printed underneath it; the bottom gutter grows while the
     storage notice is on screen (see §8d) so the notice never covers a link */
  padding:clamp(12px,2vh,24px) calc(var(--slide-pad-x) + var(--rail-gutter))
          calc(clamp(40px,5vh,54px) + var(--note-gutter)) var(--slide-pad-x);
  max-width:none;
  border-top:1px solid var(--line);
}
.slide>*{max-width:var(--deck-max);width:100%;margin-inline:auto}
.slide:first-of-type{border-top:0}

/* corner ticks — the HUD frame, drawn once per slide */
.slide::before,.slide::after{
  content:"";position:absolute;width:16px;height:16px;pointer-events:none;opacity:.5;
  border-color:var(--acc);
}
.slide::before{top:10px;left:10px;border-top:1px solid;border-left:1px solid}
.slide::after{bottom:10px;right:10px;border-bottom:1px solid;border-right:1px solid}

/* ─────────────────── 2 · SLIDE HEAD (3-second layer) ─────────────────── */
.shead{display:grid;gap:6px}
.stag{
  display:flex;align-items:center;gap:10px;
  font-family:var(--sans);font-size:clamp(11px,1.5vw,12.5px);
  letter-spacing:.22em;text-transform:uppercase;color:var(--acc);
}
.stag b{font-weight:400;color:var(--dim)}
.stag::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,rgba(255,255,255,.4),transparent)}
.slide h1,.slide h2{
  font-size:clamp(22px,3.6vw,38px);
  font-weight:400;line-height:1.1;letter-spacing:-.02em;margin:0;
}
.ssub{
  color:var(--mut);font-size:clamp(13px,1.4vw,15.5px);line-height:1.6;
  max-width:62ch;margin:0;
}

/* ─────────────────── 3 · DASHBOARD (slide 1) ─────────────────── */
/* Two panes: the live answer, and the ask. On a phone they are a horizontal
   snap rail — the same mechanic every other rail on the page uses — so the
   answer owns the first screen and the ask is one swipe away. On a laptop the
   identical two panes sit side by side. Nothing is added, removed or reordered
   between the two; only the axis changes. */
.dash{
  display:grid;gap:clamp(8px,1.3vh,15px);
  grid-auto-flow:row;align-items:start;
}
.dash>*{min-width:0}
.dcol{display:grid;gap:clamp(8px,1.3vh,15px);align-content:start;min-width:0}
@media(min-width:64rem){
  .dash{
    grid-template-columns:minmax(0,1fr) minmax(0,430px);
    column-gap:clamp(14px,2vw,24px);
  }
  .dash>.dcol{grid-column:1;grid-row:1}
  .dash>.vtile{grid-column:2;grid-row:1}
}

/* command input — the single thing to do on this page */
.cmd{
  display:grid;gap:6px;
  border:1px solid var(--line2);border-radius:var(--r);
  background:linear-gradient(180deg,rgba(33,33,33,.5),rgba(16,16,16,.5));
  padding:clamp(10px,1.6vw,14px);
}
.cmd label{color:var(--dim)}
.cmdrow{display:flex;gap:8px;flex-wrap:wrap}
.cmdrow input{
  flex:1 1 190px;min-width:0;min-height:46px;
  font-family:var(--sans);font-size:15px;color:var(--ink);
  background:var(--surface2,rgba(33,33,33,.62));
  border:1px solid var(--line);border-radius:var(--r);padding:10px 13px;
}
.cmdrow .btn{min-height:46px;flex:1 1 auto}
@media(min-width:40rem){ .cmdrow .btn{flex:0 0 auto} }
.cmdnote{
  font-family:var(--sans);font-size:12.5px;letter-spacing:.06em;
  color:var(--acc);min-height:16px;margin:0;
}

/* status strip — six real facts, no invented telemetry */
.strip{
  display:flex;gap:6px;flex-wrap:nowrap;overflow-x:auto;
  scroll-snap-type:x proximity;scrollbar-width:none;
  -webkit-mask-image:linear-gradient(90deg,#000 90%,transparent);
  mask-image:linear-gradient(90deg,#000 90%,transparent);
}
.strip::-webkit-scrollbar{display:none}
.strip .s{
  flex:0 0 auto;scroll-snap-align:start;
  display:inline-flex;align-items:center;gap:6px;
  font-family:var(--mono);font-size:11.5px;letter-spacing:.11em;text-transform:uppercase;
  color:var(--mut);border:1px solid var(--line);border-radius:2px;padding:5px 9px;
  background:rgba(16,16,16,.5);white-space:nowrap;
}
.strip .s i{width:5px;height:5px;border-radius:50%;background:var(--good);flex:0 0 auto}
.strip .s i.off{background:var(--dim)}
@media(min-width:64rem){
  .strip{flex-wrap:wrap;overflow:visible;mask-image:none;-webkit-mask-image:none}
}

/* the live verdict tile */
.vtile{
  border:1px solid var(--line2);border-radius:var(--r);
  background:linear-gradient(180deg,rgba(26,26,26,.7),rgba(13,13,13,.7));
  padding:clamp(12px,1.8vw,18px);display:grid;gap:9px;position:relative;overflow:hidden;
}
/* "LIVE · COMPUTED HERE, NOT FETCHED" is a liveness indicator, not a verdict,
   so it takes the accent rather than --good. Two reasons. The tile it sits on
   already carries accent chips and an accent band, and a green heading above
   blue controls put two saturated colours in one viewport for no informational
   gain. And --good/--warn/--bad have a job on this page — fact, assumption,
   prediction — which a decorative green quietly devalues by using the same
   colour for something that is not a judgement about the answer. */
.vtile .vlive{
  display:inline-flex;align-items:center;gap:6px;
  font-family:var(--sans);font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--acc);
}
.vtile .vlive i{width:6px;height:6px;border-radius:50%;background:var(--acc);animation:vPulse 2.4s ease-in-out infinite}
@keyframes vPulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.35;transform:scale(.75)}}
.vtile .vq{font-size:clamp(13px,1.5vw,14.5px);font-weight:500;line-height:1.55;margin:0}
.vbig{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.vbig .v{
  font-family:var(--mono);font-size:clamp(30px,5.4vw,46px);line-height:1;
  letter-spacing:-.02em;font-weight:400;
}
.vbig .l{font-size:12.5px;color:var(--dim);line-height:1.35}
.meterbar{height:8px;border-radius:2px;background:rgba(255,255,255,.09);position:relative;overflow:hidden}
.meterbar i{position:absolute;top:0;bottom:0;border-radius:2px;transition:left .35s cubic-bezier(.2,.8,.2,1),width .35s cubic-bezier(.2,.8,.2,1)}
.vfacts{display:grid;grid-template-columns:1fr 1fr;gap:8px 12px}
.vfacts .k{font-family:var(--sans);font-size:10.5px;letter-spacing:.13em;text-transform:uppercase;color:var(--dim)}
.vfacts .v{font-size:12.5px;font-weight:500;line-height:1.35;margin-top:2px;min-height:17px}
.vtile canvas{width:100%;height:clamp(52px,8vh,78px);display:block;border-radius:2px;background:rgba(4,4,4,.45)}
.vscen{display:flex;gap:6px;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}
.vscen::-webkit-scrollbar{display:none}
/* all four scenarios have to be visible at a glance — a scenario the reader has
   to scroll to find is a scenario they will not know exists. The chips share the
   row equally and only fall back to scrolling if they genuinely cannot fit. */
.vscen .chip{flex:1 1 auto;min-width:0;min-height:34px;padding:5px 10px;font-size:12.5px;
  justify-content:center;text-align:center}
.vfoot{font-family:var(--sans);font-size:11.5px;letter-spacing:.03em;color:var(--dim);margin:0;line-height:1.6}
.vlegend{display:flex;gap:10px;flex-wrap:wrap;font-size:12px;color:var(--dim)}
.vlegend b{font-weight:500}
.vlegend .f{color:var(--good)} .vlegend .a{color:var(--warn)} .vlegend .p{color:var(--acc)}

/* ─────────────────── 4 · HORIZONTAL RAILS (slide like Aaru) ─────────────────── */
.rail{
  display:flex;gap:10px;flex-wrap:wrap;
}
.rail>*{
  flex:1 1 100%;min-width:0;
  border:1px solid var(--line);border-radius:var(--r);
  background:linear-gradient(180deg,rgba(22,22,22,.55),rgba(13,13,13,.55));
  padding:clamp(11px,1.5vw,16px);
}
.rail>* b,.rail>* .rt{
  display:block;color:var(--ink);font-weight:500;font-size:13.5px;margin-bottom:5px;line-height:1.3;
}
.rail>* p,.rail>* small{color:var(--mut);font-size:12.5px;line-height:1.5;display:block}
.rail .rk{
  font-family:var(--sans);font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--acc);display:block;margin-bottom:5px;
}
a.rcard{text-decoration:none;color:inherit;transition:border-color var(--dur),transform var(--dur)}
@media(hover:hover){ a.rcard:hover{border-color:var(--acc);transform:translateY(-2px)} }
@media(min-width:40rem){
  .rail>*{flex:1 1 calc(50% - 5px)}
}
@media(min-width:64rem){
  .rail>*{flex:1 1 calc(25% - 8px)}
  .rail.r3>*{flex:1 1 calc(33.333% - 7px)}
  .rail.r2>*{flex:1 1 calc(50% - 5px)}
}
/* drag-to-slide affordance, shown only where the rail actually scrolls */
.railhint{display:none}
.railhint-x{
  font-family:var(--sans);font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--dim);margin:0;display:flex;align-items:center;gap:7px;
}
.railhint::before{content:"";width:22px;height:1px;background:linear-gradient(90deg,var(--acc),transparent)}
/* `[hidden]{display:none}` lives in the user-agent stylesheet, and any author
   `display` declaration beats it — so the `display:flex` two lines above meant
   carousel.js could set `hint.hidden = true` and nothing would happen. The
   text hint and the dots that replace it both rendered. Stating it here is the
   fix; it has to sit in the sheet that owns the element, not in a later one,
   because the rule it is overriding is its own. */
.railhint[hidden]{display:none}
@media(min-width:64rem){ .railhint{display:none} }

/* ─────────────────── 5 · SHARED DATA BLOCKS ─────────────────── */
/* Same two-pane mechanic as the dashboard: a swipe rail on a phone, columns on
   a laptop. Identical nodes either way — only the axis changes. */
.duo{
  display:grid;gap:clamp(10px,1.6vh,16px);
  grid-auto-flow:row;align-items:start;
}
.duo>*{min-width:0}
@media(min-width:64rem){
  .duo{
    grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  }
  .duo.wide-left{grid-template-columns:minmax(0,7fr) minmax(0,5fr)}
  /* a pane on its own is not a column of one — it takes the width */
  .duo.one{grid-template-columns:minmax(0,1fr)}
}

.dpanel{
  border:1px solid var(--line);border-radius:var(--r);
  background:linear-gradient(180deg,rgba(22,22,22,.5),rgba(13,13,13,.5));
  padding:clamp(11px,1.6vw,17px);min-width:0;
}
.dpanel>h3{
  font-family:var(--sans);font-size:11px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--dim);font-weight:400;margin-bottom:10px;
}

.stat{display:grid;grid-template-columns:repeat(auto-fit,minmax(128px,1fr));gap:9px}
.stat .c{border:1px solid var(--line);border-radius:2px;padding:9px 10px;background:rgba(16,16,16,.4);min-width:0}
.stat .c .k{font-family:var(--sans);font-size:10.5px;letter-spacing:.13em;text-transform:uppercase;color:var(--dim)}
.stat .c .v{font-size:clamp(15px,2.1vw,21px);font-weight:400;margin-top:3px;line-height:1.15;overflow-wrap:anywhere}
/* a link standing alone as a stat value is a pointer target, not a word in a
   sentence: give it a 24px box (WCAG 2.2 2.5.8) without moving the type */
.stat .c .v a{display:inline-block;padding:3px 0;margin:-3px 0;min-height:24px}
.stat .c .s{font-size:12.5px;color:var(--mut);margin-top:3px;line-height:1.45}

.bars .brow{display:grid;grid-template-columns:minmax(88px,110px) 1fr 56px;gap:9px;align-items:center;margin-bottom:9px;font-size:12.5px}
.bars .brow:last-child{margin-bottom:0}
.bars .brow .lbl{color:var(--mut);font-weight:500;min-width:0;overflow-wrap:anywhere}
.bars .track{height:8px;border-radius:2px;background:rgba(255,255,255,.09);overflow:hidden;position:relative}
.bars .track i{position:absolute;top:0;bottom:0;left:0;border-radius:2px;transition:width .5s cubic-bezier(.2,.8,.2,1)}
.bars .val{text-align:right;font-weight:500;font-size:12.5px;font-family:var(--mono)}

.simscene{position:relative}
.simscene canvas{
  width:100%;height:clamp(150px,26vh,290px);display:block;
  border:1px solid var(--line);border-radius:var(--r);background:rgba(4,4,4,.4);
}
.simcount{
  font-family:var(--mono);font-size:12.5px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--acc);margin:0 0 7px;
}

.receipt{
  font-family:var(--mono);font-size:12px;line-height:1.65;color:var(--mut);
  background:rgba(4,4,4,.5);border:1px solid var(--line);border-radius:2px;
  padding:10px;word-break:break-all;
}

table.mini{width:100%;border-collapse:collapse;font-size:12.5px}
table.mini caption{position:absolute;left:-9999px}
table.mini th{text-align:left;padding:6px 8px;border-bottom:1px solid var(--line)}
table.mini td{padding:6px 8px;border-bottom:1px solid var(--line);color:var(--mut)}
table.mini tr:last-child td{border-bottom:0}
table.mini td b{color:var(--ink);font-weight:500}
/* .tblwrap is defined once, in the shared stylesheet. */

.loopline{display:flex;gap:7px;align-items:center;flex-wrap:wrap}
.loopline .stepp{
  border:1px solid var(--line2);border-radius:2px;padding:6px 11px;
  font-family:var(--sans);font-size:11.5px;letter-spacing:.11em;text-transform:uppercase;color:var(--mut);
  background:rgba(16,16,16,.5);
}
.loopline .arr{color:var(--dim);font-size:12px}

.notefoot{font-size:14px;color:var(--dim);margin:0;line-height:1.6;max-width:72ch}
.notefoot a{color:var(--acc)}

.acts{display:flex;gap:9px;flex-wrap:wrap;align-items:center}
.acts .btn{min-height:46px;flex:1 1 148px;justify-content:center;text-align:center}
@media(min-width:40rem){ .acts .btn{flex:0 0 auto} }

/* ─────────────────── 6 · CHAPTER RAIL + PROGRESS ─────────────────── */
#deckbar{
  position:fixed;top:var(--hdr);left:0;right:0;height:2px;z-index:880;
  background:rgba(255,255,255,.10);pointer-events:none;
}
#deckbar i{
  display:block;height:100%;width:0;
  background:linear-gradient(90deg,var(--acc),var(--acc2));
  box-shadow:0 0 10px rgba(255,255,255,.5);
  transition:width .12s linear;
}
#deckrail{
  position:fixed;right:clamp(6px,1.4vw,16px);top:50%;transform:translateY(-50%);
  z-index:880;display:flex;flex-direction:column;gap:clamp(8px,1.4vh,13px);
  padding:9px 5px;border:1px solid var(--line);border-radius:999px;
  background:rgba(4,4,4,.55);backdrop-filter:blur(8px);
}
#deckrail a{
  display:block;width:24px;height:24px;position:relative;text-decoration:none;
  display:grid;place-items:center;
}
#deckrail a i{
  display:block;width:6px;height:6px;border-radius:50%;
  background:rgba(255,255,255,.32);transition:background var(--dur),transform var(--dur),box-shadow var(--dur);
}
#deckrail a[aria-current="true"] i{
  background:var(--acc);transform:scale(1.55);box-shadow:0 0 10px rgba(255,255,255,.8);
}
#deckrail a span{
  position:absolute;right:calc(100% + 8px);top:50%;transform:translateY(-50%);
  font-family:var(--sans);font-size:11px;letter-spacing:.15em;text-transform:uppercase;
  color:var(--ink);background:rgba(4,4,4,.9);border:1px solid var(--line);
  padding:4px 8px;border-radius:2px;white-space:nowrap;
  opacity:0;pointer-events:none;transition:opacity var(--dur);
}
@media(hover:hover){ #deckrail a:hover span{opacity:1} }
#deckrail a:focus-visible span{opacity:1}
@media(prefers-reduced-motion:reduce){
  #deckrail a i,#deckbar i{transition:none}
}

/* ─────────────────── 7 · ENTRANCE CHOREOGRAPHY ─────────────────── */
/* The entrance choreography used to pre-hide every section's content with
   opacity:0 until an IntersectionObserver added .on — which is exactly why
   phones saw blank black and white viewports while scrolling, and why the
   whole page below the hero vanished when JavaScript failed. Content is now
   simply there. The one entrance kept is the hero's own, which is gated on
   JavaScript proving it can un-hide (html.lxs2). */

/* ─────────────────── 8 · FINAL SLIDE ─────────────────── */
.slide.finish{text-align:center;justify-items:center}
.slide.finish .shead{justify-items:center}
.slide.finish .stag::after{display:none}
.slide.finish .stag{justify-content:center}
.slide.finish .ssub{margin-inline:auto}
.slide.finish .acts{justify-content:center}
.slide.finish .rail{text-align:left}
.brandline{
  font-family:var(--sans);font-size:12px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--dim);margin:0;
}

/* ─────────── 8b · SLIDE 01 DENSITY ───────────
   The dashboard is the only slide carrying a full instrument panel, so it gets
   its own compaction rather than shrinking every slide to suit it. Everything
   below is size, not structure — the phone and the laptop show the same nodes. */
#s-decide{gap:clamp(8px,1.2vh,16px)}
#s-decide h1{font-size:clamp(21px,3.9vw,42px)}
#s-decide .ssub{font-size:clamp(12.5px,1.4vw,16px);max-width:58ch}
#s-decide .stat{grid-template-columns:1fr 1fr;gap:8px}
#s-decide .stat .c .s{font-size:12px}
#s-decide .vtile{gap:clamp(6px,.9vh,10px)}
#s-decide .cmd{gap:5px}
/* on a short phone the live answer still has to clear the fold, so the
   restatement sentence and the sub-captions go before the numbers do */
@media(max-height:700px) and (max-width:63.99rem){
  #s-decide .ssub{display:none}
  #s-decide .vlegend{font-size:11.5px}
  #s-decide .stat .c .s{display:none}
  #s-decide .vtile canvas{height:clamp(40px,6vh,60px)}
}

/* ─────────── 8b-ii · SLIDE 06 METRIC STRIP ───────────
   The record strip carries four cells, and auto-fit resolves them to a single
   column below ~265px of available width — which on a 320px phone stacks four
   full-width rows and makes DEFEND the tallest slide in the deck. Two columns
   is the same decision already taken for slide 01, so it is applied here rather
   than inventing a second behaviour. Size only; the nodes do not change. */
@media(max-width:34.99rem){
  #s-defend .stat{grid-template-columns:1fr 1fr;gap:8px}
  #s-defend .stat .c .s{font-size:12px}
}

/* ─────────── 8c · TOUCH TARGETS ───────────
   The legacy hero card carried its own 44px link padding; the deck carries it
   here, for every inline link inside a data block. */
@media(max-width:63.99rem){
  .vtile a,.notefoot a,.vfoot a,.railhint a{
    display:inline-block;padding:11px 2px;margin:-11px -2px;
  }
  .vscen .chip,.acts .btn,.cmdrow .btn,.cmdrow input{min-height:44px}
}

/* ─────────── 8d · STORAGE NOTICE CLEARANCE ───────────
   PECR requires the storage notice to be genuinely readable, and a notice that
   covers the content it is describing is a dark pattern. While it is on screen
   the deck reserves real space for it instead of letting it float over a slide,
   so no link, footnote or rail hint is ever obscured. `.cnote-on` is set on
   <html> by the notice script and removed the moment it is acknowledged. */
html.cnote-on{ --note-gutter:72px }
@media(min-width:64rem){ html.cnote-on{ --note-gutter:56px } }
@media(max-width:63.99rem){
  /* one compact row on a phone: the notice has to be readable without eating
     the screen it is explaining */
  #cnote{
    left:8px;right:8px;bottom:8px;max-width:none;padding:10px 12px;
    display:none;align-items:center;gap:12px;
  }
  #cnote.show{display:flex}
  #cnote p{flex:1 1 auto;font-size:12.5px;line-height:1.4}
  #cnote .row{margin-top:0;flex:0 0 auto}
  /* the back-to-top button must not land on the notice either */
  html.cnote-on #lxTop{bottom:calc(8px + var(--note-gutter) - 18px)}
  /* slide 01 is already exactly one screen; while the notice occupies the
     bottom strip, the line that restates what is above it stands down and
     returns the instant the notice is acknowledged.

     The rail hint used to stand down with it, which was exactly backwards:
     the only people who ever see the storage notice are first-time visitors,
     and they are the only people who do not already know the block swipes.
     The hint is an affordance, not restated copy, so it stays. It costs one
     line; .ssub gives back three. */
  html.cnote-on #s-decide .ssub{display:none}
}

/* ─────────────────── 9 · SAFETY OVERRIDES ─────────────────── */
/* the deck supplies its own rhythm — neutralise the pre-deck section padding */
.slide.slide{
  padding-top:clamp(14px,2.6vh,30px);
  padding-bottom:calc(clamp(52px,7vh,72px) + var(--note-gutter));
}
/* keep the back-to-top button clear of the chapter rail */
#lxTop{right:clamp(52px,7vw,68px)}

/* The chapter rail is a desktop instrument, and on a phone it was standing on
   the writing. Measured at 320, 390 and 414px it overlapped the opening's own
   body copy — a fixed column of dots laid over a sentence, which reads as a
   rendering fault rather than as navigation. It could not be padded around
   either: the copy it covers is centred, so reserving a lane on one side
   throws the whole column off centre, and reserving it on both leaves 204px
   of measure at 320px.
   It is also the wrong control for the device. The labels that say what each
   dot means are behind @media(hover:hover), so a touch visitor gets six
   unnamed circles; the jump-between-snapped-slides job they do does not exist
   here either, because the phone deck does not snap. What a phone reader
   actually needs from it — where am I in this — is already on screen as
   #deckbar, the 2px progress line under the header, which covers nothing.
   So below the breakpoint the rail stands down and the progress line does the
   work. This is the same call the short-viewport rule below already makes.
   51.99rem is --bp-xl's max complement — the same rung the opening's two-stage
   treatment branches on, so the rail disappears exactly where the phone
   opening appears rather than at a width of its own. */
@media(max-width:51.99rem){
  #deckrail{display:none}
}

/* very short viewports (landscape phones): let a slide grow rather than clip */
@media(max-height:520px){
  .slide{min-height:0;padding-block:26px}
  html{scroll-snap-type:none}
  #deckrail{display:none}
}
/* print: no snapping, no fixed chrome */
@media print{
  html{scroll-snap-type:none}
  #deckrail,#deckbar,#lxTop{display:none}
  .slide{min-height:0;page-break-inside:avoid;border-top:1px solid #ccc}
}

/* Each chapter paints its own canvas. Without this the body background shows
   through, so a light chapter cannot sit between two dark ones. */
.slide{background-color:var(--bg)}


/* ── v171: the planet is the picture (moved here from index.html, which sits at its 150 kB budget).
   Every selector carries an html prefix so it outranks the equal-specificity rules in the page's own
   #lxopen-css and v145 blocks, which load after this sheet. ── */
/* v171: the planet is the picture. The two veils that used to black out most
   of the film — a linear one to solid black by 46vh and a radial one at .68
   behind the words — are cut to what legibility needs: a soft shade behind the
   words, a narrow scrim under the form, and a fade to black only in the last
   fifth of the entrance so the next section still arrives on black. */
html .lxstage::before{background:linear-gradient(180deg,transparent,rgba(0,0,0,.10) 30%,rgba(0,0,0,.26) 62%,rgba(0,0,0,.72) 86%,#000)}
html .lxstage::after{background:radial-gradient(58% 54% at 50% 42%,rgba(0,0,0,.34),rgba(0,0,0,.14) 60%,transparent)}
html .lxopen .lxkick, html .lxopen .lxh1, html .lxopen .lxsub, html .lxopen .lxtrust, html .lxopen .lxrail li{text-shadow:0 1px 26px rgba(0,0,0,.95),0 1px 5px rgba(0,0,0,.95),0 0 2px rgba(0,0,0,.9)}
html .lxopen .lxrail li::before{text-shadow:none}
/* the kicker crosses the sunrise: lift it from muted grey to near-white so it stays readable over the limb */
html .lxopen .lxkick{color:rgba(255,255,255,.88)}
/* the form floats as glass over the planet instead of a solid box hiding it */
html .lxopen .cmd{background:rgba(6,8,12,.58);border-color:rgba(255,255,255,.16);box-shadow:0 30px 80px -30px rgba(0,0,0,.9),inset 0 1px 0 rgba(255,255,255,.06)}
@media(min-width:64rem) and (hover:hover){
  html .lxopen .cmd{background:rgba(6,8,12,.42);-webkit-backdrop-filter:blur(18px) saturate(1.25);backdrop-filter:blur(18px) saturate(1.25)}
  /* a lift in the film's own light on screens that can afford the filter; never on phones */
  html .lxearth video, html .lxearth img{filter:brightness(1.1) contrast(1.05) saturate(1.14)}
  /* the words start a little lower, so the first screen opens on more planet; the form stays above the fold */
  html .lxopen>.lxstage{padding-top:calc(var(--hdr) + 7vh)}
}
@media(max-width:63.99rem){
  /* the phone shows the film full-bleed; the words begin lower so the planet owns the opening */
  html .lxopen>.lxstage{padding-top:calc(var(--hdr) + 30svh)}
  html .lxearth img, html .lxearth video{object-position:50% 20%}
}
/* the scroll rise used to open a black strip under the planet that the old veil hid: rise 3%, not 6%, so the 6% swell covers it */
html .lxearth img, html .lxearth .lxlive, html .lxearth .lxintro{transform:translate3d(0,calc(-3% * var(--lxgu,0)),0) scale(var(--lxgs,1))}
/* the words now cover the foot of the entrance at every width, so the scroll hint has nothing to point at */
html .lxdown{display:none}
@media(max-width:63.99rem){html .lxstage::after{background:radial-gradient(70% 60% at 50% 46%,rgba(0,0,0,.50),rgba(0,0,0,.22) 60%,transparent)}}
@media(prefers-reduced-motion:reduce){html .lxearth video,html .lxearth img{filter:none}html .lxearth img,html .lxearth .lxlive,html .lxearth .lxintro{transform:none}}
