@import url("./tokens.css");

/* ============================================================
   EverLume site — cinematic layout
   Built to match website/mockups-2026-07-25/v4-cinematic/.

   The rules of that system, in order of importance:
     1. Every section is a full bleed night photograph. Type is
        never in a box, never on a flat panel. It sits directly on
        the picture, in whichever quadrant the picture left dark.
     2. A graded scrim, not a flat overlay, buys that legibility.
        Each stage says which corner it is protecting.
     3. Lume is light inside the photograph: a node, a rule that
        ends in a node, a single accented word, a glow in a corner.
     4. No frames, no cards, no dividers, no hairline boxes. The
        photograph is the container.

   tokens.css carries no box-sizing reset on purpose, so the reset
   below is this build's own. Never hardcode a hex here: if a value
   is missing it belongs in tokens.css. Relative paths only.
   ============================================================ */

/* tokens.css carries no rgb triplets, and this file needs alpha over
   half a dozen of its colours -- every scrim, the copy shade, the glyph
   states. Declaring them once here means a change to --el-void in
   tokens.css can never silently desync the scrims from the page. */
:root {
  --el-void-rgb:  11, 13, 16;
  --el-slate-rgb: 42, 49, 56;
  --el-lume-rgb:  255, 154, 31;
  /* Ash needs one too: a drawing in Slate is correct on Carbon and
     invisible on a night photograph, so anything sitting on a plate
     wants Ash held back by alpha instead of a darker colour. */
  --el-ash-rgb:   107, 116, 126;
}

*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; }
img { display: block; max-width: 100%; }
a { color: inherit; }
h1, h2, h3, p, ol, ul, figure, table { margin: 0; }
ol, ul { padding: 0; list-style: none; }

::selection { background: var(--el-lume-40); color: var(--el-white); }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

/* The void lives on <body>, not on the dark stage. A stage that painted
   its own background would hide its network, which sits at a negative
   z-index inside the stage's isolated stacking context. */
body { background: var(--el-void); overflow-x: hidden; text-rendering: optimizeLegibility; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 99;
  background: var(--el-lume); color: var(--el-void);
  padding: 10px 16px; font-size: var(--el-size-small);
}
.skip:focus { left: 12px; top: 12px; }
:focus-visible { outline: 2px solid var(--el-lume); outline-offset: 3px; }

.wrap {
  width: 100%; max-width: 1440px; margin: 0 auto;
  padding: 0 clamp(22px, 4.6vw, 66px);
}

/* ---------------------------------------------------------- nav */

.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 40;
  transition: background .35s ease, border-color .35s ease;
  border-bottom: var(--el-hairline) solid transparent;
}
.nav.is-stuck {
  background: rgba(var(--el-void-rgb), .86); backdrop-filter: blur(16px);
  border-bottom-color: rgba(var(--el-slate-rgb), .6);
}
.nav__inner { display: flex; align-items: center; height: 82px; gap: clamp(20px, 3vw, 46px); }
.nav__mark { font-size: 17px; text-decoration: none; color: var(--el-white); }
.nav__links { display: flex; gap: clamp(18px, 2.4vw, 38px); margin: 0 auto 0 clamp(24px, 4vw, 70px); }
.nav__links a {
  color: var(--el-mist); text-decoration: none; font-size: var(--el-size-small);
  transition: color .2s ease;
  /* A two word label that wraps inside an 82px bar reads as breakage, not
     as a line break. It must never wrap: if the set stops fitting, the
     breakpoint below hides it rather than folding it. */
  white-space: nowrap;
}
.nav__links a:hover { color: var(--el-white); }
.nav__cta { white-space: nowrap; }
/* Five labels plus the wordmark and the CTA stop fitting just under 1020px. */
@media (max-width: 1020px) { .nav__links { display: none; } .nav__inner { justify-content: space-between; } }

/* ---------------------------------------------------------- the stage

   One cinematic frame. The photograph fills it, the grade protects
   one quadrant, and the copy lands in that quadrant. */

.stage {
  position: relative; overflow: hidden; isolation: isolate;
  min-height: 100svh; display: flex;
  padding: calc(82px + clamp(28px, 4vh, 56px)) 0 clamp(46px, 7vh, 90px);
}
.stage__bg { position: absolute; inset: -4% 0 -4%; z-index: -2; }
.stage__bg img { width: 100%; height: 100%; object-fit: cover; }

/* The scrim is a gradient, never a flat wash: a flat overlay greys the
   photograph out, a gradient keeps the highlights and still buys contrast
   where the type is. Each stage names the corner it protects. */
.stage__grade { position: absolute; inset: 0; z-index: -1; pointer-events: none; }
/* The left gradient does most of the legibility work, so the base can stay
   light: the hero's network is inside the photograph now, and a heavy base
   would swallow the connections the picture exists to show. */
.grade--bl .stage__grade {
  background:
    linear-gradient(to top,    rgba(var(--el-void-rgb),.88) 0%, rgba(var(--el-void-rgb),.52) 24%, rgba(var(--el-void-rgb),0) 58%),
    linear-gradient(to right,  rgba(var(--el-void-rgb),.90) 0%, rgba(var(--el-void-rgb),.40) 40%, rgba(var(--el-void-rgb),0) 68%),
    linear-gradient(to bottom, rgba(var(--el-void-rgb),.72) 0%, rgba(var(--el-void-rgb),0) 30%);
}
/* the top-left copy runs long, so the left scrim has to reach further
   down and further right than the mockup's shorter block needed */
.grade--tl .stage__grade {
  background:
    linear-gradient(to bottom, rgba(var(--el-void-rgb),.94) 0%, rgba(var(--el-void-rgb),.72) 38%, rgba(var(--el-void-rgb),0) 78%),
    linear-gradient(to right,  rgba(var(--el-void-rgb),.93) 0%, rgba(var(--el-void-rgb),.66) 34%, rgba(var(--el-void-rgb),.12) 62%, rgba(var(--el-void-rgb),0) 78%),
    linear-gradient(to top,    rgba(var(--el-void-rgb),.66) 0%, rgba(var(--el-void-rgb),0) 34%);
}
/* copy runs the full width along the bottom, so protect the whole base */
.grade--base .stage__grade {
  background:
    linear-gradient(to top,    rgba(var(--el-void-rgb),.96) 0%, rgba(var(--el-void-rgb),.9) 30%, rgba(var(--el-void-rgb),.34) 52%, rgba(var(--el-void-rgb),0) 78%),
    linear-gradient(to bottom, rgba(var(--el-void-rgb),.74) 0%, rgba(var(--el-void-rgb),0) 28%);
}
.grade--flat .stage__grade { background: linear-gradient(to bottom, rgba(var(--el-void-rgb),.7), rgba(var(--el-void-rgb),.4) 40%, rgba(var(--el-void-rgb),.82)); }

.stage__net { position: absolute; inset: 0; width: 100%; height: 100%; z-index: -1; }

/* a soft Lume bloom placed over something in the photograph */
.stage__flare {
  position: absolute; z-index: -1; pointer-events: none; border-radius: 50%;
  background: radial-gradient(closest-side, var(--el-lume-22), var(--el-lume-08) 46%, transparent 74%);
}

/* .stage__breathe removed 2026-07-27. Its only user was the hero, which
   now carries a live network instead, and an animated warm gradient over
   photography is close enough to Daylight's signature device to be worth
   not keeping around unused. Ours is light travelling a network. */


.stage__inner { position: relative; z-index: 1; width: 100%; display: flex; }
.at-bottom { align-items: flex-end; }
.at-top    { align-items: flex-start; }
.at-middle { align-items: center; }

/* ---------------------------------------------------------- type */

.eyebrow { display: block; margin-bottom: 18px; }
.eyebrow--lume { color: var(--el-lume); }

h1, .h1 { font-size: clamp(36px, 3.8vw, 55px); }
h2, .h2 { font-size: clamp(28px, 3vw, 44px); }
.h2--big { font-size: clamp(33px, 3.9vw, 57px); }
h3, .h3 { font-size: clamp(20px, 1.85vw, 26px); font-weight: 700; }

.accent { color: var(--el-lume); }

/* Widths are in px, not ch. A ch max-width on the copy block resolves
   against the block's own 16px body size, not the headline's, which
   crushed every headline into a column a third of the intended width. */
.copy { max-width: 500px; }
.copy--hero { max-width: 640px; }
.copy--wide { max-width: 620px; }
.copy p {
  color: var(--el-mist); font-size: clamp(16px, 1.18vw, 18px); line-height: 1.62;
}
.copy h1 + p, .copy h2 + p { margin-top: 24px; }
.copy p + p { margin-top: 18px; }
.copy p.bright { color: var(--el-white); }
.copy p.quiet { color: var(--el-ash); font-size: clamp(15px, 1.05vw, 16px); }

.acts { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 34px; }

/* ---------------------------------------------------------- CTA

   The mockups draw every CTA as an outlined Lume pill rather than the
   solid pill in tokens.css. The token is left alone; this is the variant. */
.el-cta { padding: 14px 26px; font-size: 15px; }
.el-cta--outline {
  background: transparent; color: var(--el-lume);
  border: var(--el-hairline) solid var(--el-lume-40);
  transition: border-color .25s ease, box-shadow .25s ease, background .25s ease;
}
.el-cta--outline:hover {
  border-color: var(--el-lume);
  box-shadow: 0 0 0 1px var(--el-lume-22), 0 0 30px var(--el-lume-22);
  background: var(--el-lume-08);
}
.el-cta--ghost { color: var(--el-mist); transition: border-color .25s ease, color .25s ease; }
.el-cta--ghost:hover { border-color: var(--el-ash); color: var(--el-white); }
.el-cta--lg { padding: 16px 32px; font-size: 16px; }

/* the pill with a lit node inside it, as the closing CTA is drawn */
.el-cta--dot { display: inline-flex; align-items: center; gap: 16px; }
.el-cta--dot::after {
  content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--el-lume);
  box-shadow: 0 0 12px var(--el-lume-40); flex: 0 0 auto;
}

/* ---------------------------------------------------------- the tick

   A Lume rule that begins in a lit node. The signature device of this
   direction: it sits above a column instead of a border around it. */

.tick { display: flex; align-items: center; margin-bottom: 20px; }
.tick b {
  width: 7px; height: 7px; border-radius: 50%; background: var(--el-lume);
  box-shadow: 0 0 12px var(--el-lume-40); flex: 0 0 auto;
  animation: nodePulse 3.6s ease-in-out infinite;
}
.tick i {
  flex: 1 1 auto; height: var(--el-hairline);
  background: linear-gradient(90deg, var(--el-lume), var(--el-lume-22));
  transform-origin: left center; transform: scaleX(0);
  transition: transform 1.05s cubic-bezier(.2, .7, .2, 1);
}
.is-in .tick i, .is-in.tick i { transform: scaleX(1); }
.tick--short { max-width: 240px; }
/* Inline beside a label there is no free space to grow into, so the rule
   needs a real width or it collapses to nothing between its two nodes. */
.tick--label { gap: 18px; margin-bottom: 0; flex: 0 0 auto; }
.tick--label i { flex: 0 0 92px; width: 92px; background: var(--el-lume); }

@keyframes nodePulse {
  0%, 100% { box-shadow: 0 0 9px var(--el-lume-22); }
  50%      { box-shadow: 0 0 22px var(--el-lume-40); }
}

/* label and tick sharing a line, as the closing section draws it */
.eyebrow-row { display: flex; align-items: center; gap: 20px; margin-bottom: 20px; }
.eyebrow-row .eyebrow { margin-bottom: 0; }

/* ---------------------------------------------------------- the stack

   A section head with something structured under it. .stack__lead and
   the whole .cols family (.cols--3, .cols--4, .cols__n) were removed
   2026-07-27: S3 and S5 were their only users and both now carry a
   component instead, the day night beat and the conduit. Taken out
   rather than left dead, because a four column text stack is exactly
   the pattern those two replaced, and the next person should not find
   it sitting here looking supported. */

.stack { width: 100%; }
.stack__head { margin-bottom: clamp(30px, 4vh, 54px); max-width: 660px; }

/* ---------------------------------------------------------- split stage */

.split {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(34px, 5vw, 84px); align-items: center; width: 100%;
}
@media (max-width: 940px) { .split { grid-template-columns: 1fr; gap: 44px; } }

/* the comparison table: hairlines on black, nothing boxed */
.cmp { width: 100%; border-collapse: collapse; text-align: left; }
.cmp caption {
  text-align: left; margin-bottom: 18px;
  font-family: var(--el-font-data); font-size: var(--el-size-label);
  letter-spacing: var(--el-track-label); text-transform: uppercase; color: var(--el-ash);
}
.cmp th, .cmp td {
  padding: 15px 18px 15px 0; vertical-align: top; font-weight: 400;
  border-bottom: var(--el-hairline) solid rgba(var(--el-slate-rgb), .8);
  font-size: clamp(14px, 1vw, 15px); line-height: 1.5;
}
.cmp thead th {
  font-family: var(--el-font-data); font-size: var(--el-size-label);
  letter-spacing: var(--el-track-label); text-transform: uppercase;
  color: var(--el-ash); padding-bottom: 11px;
}
.cmp thead th.is-ours { color: var(--el-lume); }
.cmp tbody th { color: var(--el-white); width: 28%; }
.cmp td { color: var(--el-ash); width: 30%; }
.cmp td.yes { color: var(--el-mist); }
.cmp tbody tr:last-child th, .cmp tbody tr:last-child td { border-bottom: 0; }

@media (max-width: 560px) {
  .cmp th, .cmp td { padding: 12px 9px 12px 0; font-size: 13px; }
}

/* ---------------------------------------------------------- footer */

.foot {
  background: var(--el-void); padding: clamp(40px, 5vh, 62px) 0 clamp(28px, 3vh, 40px);
  border-top: var(--el-hairline) solid rgba(var(--el-slate-rgb), .55);
}
.foot__inner { display: grid; grid-template-columns: 1fr auto; gap: clamp(32px, 5vw, 80px); align-items: start; }
.foot__mark { font-size: clamp(24px, 2.4vw, 34px); display: block; }
.foot__tag { color: var(--el-mist); margin-top: 10px; font-size: var(--el-size-body); }
.foot__cols { display: grid; grid-template-columns: repeat(4, minmax(110px, 1fr)); gap: clamp(28px, 4vw, 62px); }
.foot__cols .eyebrow { margin-bottom: 14px; }
.foot__cols a {
  display: block; color: var(--el-mist); text-decoration: none;
  font-size: var(--el-size-small); padding: 5px 0; transition: color .2s ease;
}
.foot__cols a:hover { color: var(--el-white); }
/* the rule runs the full width; only the text is measured */
.foot__legal {
  margin-top: clamp(34px, 4vh, 50px); padding-top: 22px;
  border-top: var(--el-hairline) solid rgba(var(--el-slate-rgb), .45);
}
.foot__legal p { color: var(--el-ash); font-size: 12px; line-height: 1.65; max-width: 88ch; }
@media (max-width: 860px) {
  .foot__inner { grid-template-columns: 1fr; }
  .foot__cols { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) { .foot__cols { grid-template-columns: 1fr; gap: 24px; } }

/* ---------------------------------------------------------- reveal */

.reveal { opacity: 0; transform: translateY(18px); }
.reveal.is-in {
  opacity: 1; transform: none;
  transition: opacity 1s ease, transform 1s cubic-bezier(.2, .7, .2, 1);
}

@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal.is-in { opacity: 1; transform: none; transition: none; }
  .tick i { transform: scaleX(1); transition: none; }
  .tick b { animation: none; }
  .stage__bg { inset: 0; }
}

/* ============================================================
   COMPONENTS PORTED FROM ../lab/ · 2026-07-27

   Everything below was built and judged in website/lab/ against the
   real plates and the real tokens before it came here. Option B
   (instrument plates) and Option C (chapters) were both cut; the
   conduit below is the one that shipped. The lab page keeps all
   three so the choice stays checkable.
   ============================================================ */

/* ---------------------------------------------------- atmosphere layer

   screen, not soft-light or overlay: both of those are no-ops against
   pure black, which is exactly where the banding is. screen also makes a
   dead canvas invisible instead of a grey wash over the page, so a lost
   context or a failed shader compile costs nothing.

   The vignette sits BELOW the canvas so the shader's dither fixes the
   vignette's own gradient banding rather than adding new banding above
   it. That ordering is load bearing. */
.atmos {
  position: fixed; inset: 0; z-index: 35; pointer-events: none;
  width: 100%; height: 100%;
  mix-blend-mode: screen;
  opacity: 0; transition: opacity .8s ease;
}
.atmos.is-on { opacity: 1; }

.vignette {
  position: fixed; inset: 0; z-index: 34; pointer-events: none;
  background: radial-gradient(ellipse at center,
    rgba(var(--el-void-rgb), 0) 46%, rgba(var(--el-void-rgb), .32) 100%);
}

/* A still photograph never looks still enough. Scale only, never below 1,
   and on the img rather than .stage__bg, because the parallax writes its
   transform to the parent and would clobber anything set here. No
   will-change: it would pin all eight into permanent composited layers. */
@keyframes plateDrift {
  from { transform: scale(1); }
  to   { transform: scale(1.028); }
}
.stage__bg img { animation: plateDrift 38s ease-in-out infinite alternate; }
.stage:nth-of-type(even) .stage__bg img { animation-delay: -13s; }

/* ---------------------------------------------------------- the network */

.stage__wire {
  position: absolute; inset: 0; z-index: 1;
  width: 100%; height: 100%; pointer-events: none;
}

/* The dawn plate's own scrim. grade--bl was cut for a plate whose subject
   sat low and whose left side needed protecting; this one is the
   opposite. Its subject is the arch at the top of the frame and the
   quadrant the copy lands in is already the darkest part of the picture,
   so there is no top gradient at all and the left protection stops well
   short of the arch. */
.grade--dawn .stage__grade {
  background:
    linear-gradient(to right,
      rgba(var(--el-void-rgb), .84) 0%,
      rgba(var(--el-void-rgb), .44) 30%,
      rgba(var(--el-void-rgb), 0) 58%),
    linear-gradient(to top,
      rgba(var(--el-void-rgb), .62) 0%,
      rgba(var(--el-void-rgb), .22) 26%,
      rgba(var(--el-void-rgb), 0) 48%);
}

/* .stage--void had no rule at all and worked by accident, off the body
   background. Stated now, so a change to either one cannot silently
   break the other. It keeps no photograph, which is why its network sits
   in markup rather than on a plate. */
.stage--void { background: var(--el-void); }

/* ------------------------------------------------------ the copy shade

   Type was bleeding into the photograph. brand-guidelines gives exactly
   one sanctioned answer to that and forbids the obvious one: never set
   type "on a busy area of photography without a scrim" (S4), and "no drop
   shadows anywhere -- they don't exist in a world lit by one light source
   on the horizon" (S7). So this is more shade under the type, never an
   outline or a glow around it.

   .stage__grade already protects a quadrant, but a quadrant is a fixed
   shape and the copy is not: it reflows, it doubles in height on a phone,
   and on S5 four different photographs pass under it. This pool is
   anchored to the block instead, so wherever the type lands it lands on
   its own floor.

   Two rules keep it invisible as a shape. It is an ellipse, so there is
   no straight edge anywhere near the text, and it resolves to zero well
   OUTSIDE the block on all four sides, so the fade finishes off the end
   of the type rather than under it where you would read the boundary as
   a smudge.

   isolation, not a bare z-index: .reveal carries a transform while it
   animates, which would otherwise trap the pseudo-element in a stacking
   context of its own and paint it over the words. */
.copy--shade { position: relative; isolation: isolate; }
.copy--shade::before {
  content: '';
  position: absolute;
  inset: -13% -24% -18% -28%;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(118% 104% at 26% 58%,
    rgba(var(--el-void-rgb), .74) 0%,
    rgba(var(--el-void-rgb), .52) 32%,
    rgba(var(--el-void-rgb), .20) 60%,
    rgba(var(--el-void-rgb), 0) 84%);
}

/* A phone gives the copy most of the frame and the plate almost none of
   it, so the pool has to reach further and sit deeper -- but it also has
   less room to fade in, hence the tighter negative inset on the sides. */
@media (max-width: 720px) {
  .copy--shade::before {
    inset: -10% -16% -14% -18%;
    background: radial-gradient(132% 112% at 30% 56%,
      rgba(var(--el-void-rgb), .84) 0%,
      rgba(var(--el-void-rgb), .64) 34%,
      rgba(var(--el-void-rgb), .28) 62%,
      rgba(var(--el-void-rgb), 0) 86%);
  }
}

/* -------------------------------------------------------- the step glyphs

   One sprite, referenced by <use>, which puts the drawing in a shadow
   tree. A descendant selector never crosses that boundary, so `.elg
   .g-line` matches nothing and every glyph renders as an invisible black
   shape. Two things do get through: a bare class selector, because the
   clone keeps its class attribute, and custom properties, because they
   inherit. So all the paint is variables set on .elg and read by ancestor
   free rules, and the state lives entirely in the variables.

   Slate is right for a hairline rule and far too dark for a drawing on a
   night photograph: at 30px the strokes disappear. So the dim state is
   Ash held back by opacity rather than a darker colour, which keeps the
   structure legible and still leaves the lit step obviously the only one
   that is on. Never light everything. */
.elg {
  display: block; overflow: visible; width: 30px; height: 30px;
  opacity: var(--g-alpha, .5); transition: opacity .55s ease;
  --g-struct: var(--el-ash);     /* the structure: roof, baseline, links */
  --g-lit:    var(--el-ash);     /* the one element that is this step */
  --g-node:   var(--el-ash);     /* the light itself */
  --g-halo:   transparent;
  --g-scan:   transparent;
  --g-draw:   60;                /* dashoffset: 60 hidden, 0 drawn */
  --g-play:   paused;
}

.g-line, .g-lit, .g-bar, .g-scan, .g-halo {
  fill: none; stroke-linecap: round; stroke-linejoin: round;
}
.g-line { stroke: var(--g-struct); stroke-width: 1.3; transition: stroke .55s ease; }
.g-lit  { stroke: var(--g-lit);    stroke-width: 1.3; transition: stroke .55s ease; }
.g-bar  { stroke: var(--g-struct); stroke-width: 2.4; transition: stroke .55s ease; }
.g-bar.g-lit { stroke: var(--g-lit); }
.g-node { fill: var(--g-node);   stroke: none; transition: fill .55s ease; }
.g-dot  { fill: var(--g-struct); stroke: none; transition: fill .55s ease; }
.g-halo { stroke: var(--g-halo); stroke-width: 1; transition: stroke .55s ease; }
.g-scan { stroke: var(--g-scan); stroke-width: .95; }

.is-done .elg {
  --g-alpha: .68;
  --g-lit: var(--el-lume-40);
  --g-node: var(--el-lume-40);
  --g-draw: 0;
}
.is-active .elg {
  --g-alpha: 1;
  --g-lit: var(--el-lume);
  --g-node: var(--el-lume);
  --g-halo: var(--el-lume-22);
  --g-scan: var(--el-lume-40);
  --g-draw: 0;
  --g-play: running;
}

/* The lit element draws itself in on arrival and retracts on the way
   out. A transition rather than an animation, because an animation that
   has already run will not run again when the sequence comes back round.
   One dasharray for every path: 60 user units is longer than the longest
   of the four, so nothing has to be measured. */
.g-draw {
  stroke-dasharray: 60; stroke-dashoffset: var(--g-draw);
  transition: stroke-dashoffset .85s cubic-bezier(.2, .7, .2, 1), stroke .55s ease;
}

@keyframes gScan {
  0%   { transform: translateY(-3.5px); opacity: 0; }
  18%  { opacity: 1; }
  70%  { transform: translateY(4px); opacity: 1; }
  100% { transform: translateY(4px); opacity: 0; }
}
.g-scan { animation: gScan 2.6s ease-in-out infinite; animation-play-state: var(--g-play); }

@keyframes gHalo {
  from { transform: scale(.86); opacity: .3; }
  to   { transform: scale(1.1); opacity: 1; }
}
.g-halo {
  transform-origin: 12px 12px;
  animation: gHalo 2.8s ease-in-out infinite alternate;
  animation-play-state: var(--g-play);
}

/* ------------------------------------------------------- S5 · the conduit

   No card, no frame, no container: the whole doctrine is type directly on
   the photograph, so the only structure here is the cable.

   The cable is a canvas that reads its node positions out of the live
   layout, so it has no idea whether it is horizontal or vertical. CSS
   turns the row into a column at 860 and the cable follows, which is why
   the phone gets the same travelling light the desktop does instead of a
   dead grey line. */

.cd { position: relative; width: 100%; }
.cd__cable {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; pointer-events: none;
}
.cd__track {
  position: relative; z-index: 1;
  display: grid; grid-template-columns: repeat(4, 1fr);
  column-gap: clamp(16px, 2.2vw, 38px);
}
/* the step is a wrapper for meaning, not for layout: its two children
   become grid items themselves, so the titles sit in one row and the
   bodies share a single cell underneath without the paragraph ever
   leaving the step that owns it in the markup. */
.cd__step { display: contents; }

.cd__hit {
  grid-row: 1; display: block; width: 100%; text-align: left;
  background: transparent; border: 0; padding: 0 0 6px; color: inherit;
  font: inherit; cursor: pointer;
}
.cd__node { display: block; width: 34px; height: 34px; margin-bottom: 15px; }
.cd__node .elg { width: 34px; height: 34px; }
.cd__n {
  display: block; font-family: var(--el-font-data); font-weight: 700;
  font-size: 15px; color: var(--el-slate); margin-bottom: 5px;
  transition: color .45s ease;
}
.cd__ttl {
  display: block; font-family: var(--el-font-display); font-weight: 700;
  font-size: clamp(17px, 1.5vw, 22px); line-height: 1.2;
  letter-spacing: var(--el-track-display);
  color: var(--el-ash); transition: color .45s ease;
}
.cd__step.is-done .cd__n { color: var(--el-lume-40); }
.cd__step.is-active .cd__n { color: var(--el-lume); }
.cd__step.is-done .cd__ttl { color: var(--el-mist); }
.cd__step.is-active .cd__ttl { color: var(--el-white); }
.cd__hit:hover .cd__ttl { color: var(--el-white); }

/* all four bodies share one cell, so the row is as tall as the longest
   of them and nothing below ever jumps */
.cd__body {
  grid-row: 2; grid-column: 1 / -1;
  margin-top: clamp(22px, 3.2vh, 38px); max-width: 560px;
  color: var(--el-mist); font-size: clamp(16px, 1.18vw, 18px); line-height: 1.62;
  opacity: 0; transform: translateY(9px);
  transition: opacity .55s ease, transform .55s cubic-bezier(.2, .7, .2, 1);
}
.cd__body.is-on { opacity: 1; transform: none; }

@media (max-width: 860px) {
  .cd__track { grid-template-columns: 1fr; }
  .cd__step { display: block; position: relative; padding: 0 0 clamp(18px, 2.6vh, 26px) 48px; }
  /* Roomy: the cable is only as long as the gap between two nodes, and
     clear space eats 19px at each end of it. At the tight spacing the
     visible run between steps is a stub, so the vertical version reads as
     dots rather than as one line, and the glyphs crowd their titles. More
     air per step buys back both. */
  .cd--roomy .cd__step { padding: 0 0 clamp(38px, 5.4vh, 54px) 56px; }
  .cd--roomy .cd__node { width: 38px; height: 38px; }
  .cd--roomy .cd__node .elg { width: 38px; height: 38px; }
  .cd__step:last-child { padding-bottom: 0; }
  .cd__hit { padding-bottom: 0; }
  .cd__node { position: absolute; left: 0; top: 1px; margin: 0; }
  .cd__n { display: inline; margin: 0; font-size: 13px; }
  .cd__n::after { content: " ·"; color: var(--el-slate); }
  .cd__ttl { display: inline; font-size: 19px; }
  /* 0fr to 1fr animates a height the browser has to measure anyway, so
     the paragraph opens under its own title without a magic max-height */
  .cd__body {
    display: grid; grid-template-rows: 0fr; grid-column: auto;
    margin-top: 0; transform: none; opacity: 0;
    transition: grid-template-rows .6s cubic-bezier(.2, .7, .2, 1),
                opacity .45s ease, margin-top .6s ease;
  }
  .cd__body > span { overflow: hidden; }
  .cd__body.is-on { grid-template-rows: 1fr; opacity: 1; margin-top: 12px; }
}

/* Four plates in one stage, cross faded. They are stacked rather than
   swapped by src so nothing ever has to decode mid transition. */
.stage__swap { position: absolute; inset: 0; opacity: 0; transition: opacity 1.15s ease; }
.stage__swap.is-on { opacity: 1; }

/* --------------------------------------------- S3 · the day night beat */

.beat {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, .92fr);
  gap: clamp(30px, 4.6vw, 76px); align-items: end; width: 100%;
}
.beat__copy { max-width: 620px; }
.beat__lines { margin-top: clamp(24px, 3.4vh, 38px); display: grid; gap: 16px; }
.beat__lines li {
  position: relative; padding-left: 22px;
  color: var(--el-mist); font-size: clamp(16px, 1.15vw, 17px); line-height: 1.56;
  opacity: 0; transform: translateY(10px);
  transition: opacity .7s ease, transform .7s cubic-bezier(.2, .7, .2, 1);
}
.beat__lines li::before {
  content: ""; position: absolute; left: 0; top: .58em;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--el-slate); transition: background .6s ease, box-shadow .6s ease;
}
.beat__lines li.is-on { opacity: 1; transform: none; }
.beat__lines li.is-on::before { background: var(--el-lume); box-shadow: 0 0 12px var(--el-lume-40); }
/* the third line is the load bearing one, so it is the one that stays lit */
.beat__lines li.is-key.is-on { color: var(--el-white); }

.beat__fig { margin: 0; }
.beat__fig figcaption { color: var(--el-ash); margin-bottom: 14px; }
.beat__fig canvas { display: block; width: 100%; height: auto; }
.beat__key { display: flex; flex-wrap: wrap; gap: 20px; margin-top: 14px; }
.beat__k, .curve__k {
  font-family: var(--el-font-data); font-size: var(--el-size-label);
  letter-spacing: var(--el-track-label); text-transform: uppercase;
  color: var(--el-ash); display: flex; align-items: center; gap: 8px;
}
.beat__k::before, .curve__k::before {
  content: ""; width: 14px; height: var(--el-hairline); background: currentColor;
}
.beat__k--make { color: var(--el-lume); }
.beat__k--use  { color: var(--el-mist); }
.curve__k--dem { color: var(--el-lume); }
.curve__k--sup { color: var(--el-mist); }

@media (max-width: 900px) {
  .beat { grid-template-columns: 1fr; gap: 30px; align-items: start; }
  /* Figure follows the copy on one column. The three lines are the argument
     and the drawing is the evidence, so the drawing cannot arrive first --
     it was ordered above the copy here until 2026-07-27. */
}

/* --------------------------------------------- S2 · the unlabelled gap */

.curve {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, .9fr);
  gap: clamp(30px, 4.6vw, 72px);
  align-items: start; padding-top: clamp(0px, 2vh, 24px); width: 100%;
}
.curve__fig { margin: 0; }
.curve__fig canvas { display: block; width: 100%; height: auto; }
.curve__key { display: flex; flex-wrap: wrap; gap: 20px; margin-top: 14px; }
@media (max-width: 900px) { .curve { grid-template-columns: 1fr; gap: 28px; } }

/* ------------------------------------------------ S4 · $0 as a figure */

.figset {
  display: flex; align-items: flex-start; gap: clamp(18px, 2.4vw, 30px);
  margin-top: clamp(24px, 3.4vh, 38px);
}
.figset__fig {
  position: relative; display: inline-flex; align-items: flex-start;
  font-family: var(--el-font-data); font-variant-numeric: tabular-nums;
  line-height: 1;
}
/* The light sits behind the zero, it is not a fill inside it: guidelines
   allow Lume on the single most important figure, and this page has
   exactly one. Sized in em on the glyph's own element, because an em on
   the flex parent resolves against the 16px body size and collapses the
   halo to a ring. */
.figset__glow {
  position: absolute; left: 62%; top: 52%;
  width: 2.6em; height: 2.6em; border-radius: 50%; pointer-events: none;
  font-size: clamp(64px, 7.4vw, 108px);
  transform: translate(-50%, -50%) scale(.72); opacity: 0;
  background: radial-gradient(closest-side,
    var(--el-lume-22), var(--el-lume-08) 46%, transparent 72%);
  transition: transform 1.6s cubic-bezier(.2, .7, .2, 1), opacity 1.6s ease;
}
.figset__fig.is-lit .figset__glow { transform: translate(-50%, -50%) scale(1); opacity: 1; }
.figset__cur {
  font-size: clamp(24px, 2.2vw, 32px); font-weight: 300;
  color: var(--el-ash); margin-right: .1em;
  padding-top: clamp(9px, 1.05vw, 15px);          /* ride the cap height */
}
.figset__num {
  font-size: clamp(64px, 7.4vw, 108px); font-weight: 300;
  color: var(--el-lume); letter-spacing: -.02em;
}
.figset__lab {
  font-family: var(--el-font-data); font-size: var(--el-size-label);
  letter-spacing: var(--el-track-label); text-transform: uppercase;
  color: var(--el-white); line-height: 2;
  padding-top: clamp(14px, 1.7vw, 24px);
}
.figset__lab i { color: var(--el-ash); font-style: normal; }

/* ------------------------------------------- reduced motion, components

   Every step complete, nothing sequencing. The glyphs keep their dim
   state so the page still says which step is which, but nothing draws
   itself in, nothing sweeps and nothing breathes. */
@media (prefers-reduced-motion: reduce) {
  .atmos { display: none; }
  .stage__bg img { animation: none; }
  .stage__swap { transition: none; }

  .beat__lines li { opacity: 1; transform: none; transition: none; }
  .beat__lines li::before { background: var(--el-lume); }
  .figset__glow { opacity: 1; transform: translate(-50%, -50%) scale(1); transition: none; }

  .g-scan, .g-halo { animation: none; }
  .g-draw { transition: none; }
  .elg { --g-scan: transparent; }

  .cd__track { grid-template-columns: 1fr; }
  .cd__step { display: block; position: relative; padding: 0 0 22px 48px; }
  .cd__node { position: absolute; left: 0; top: 1px; margin: 0; }
  .cd__body {
    grid-row: auto; grid-column: auto; opacity: 1; transform: none;
    transition: none; display: block; margin-top: 10px;
  }
}

/* <picture> is inline by default, and the swap rules are written for a
   box that fills the stage. See index.html S5 for why the mobile crops
   exist at all. */
.stage__bg picture { display: block; }
.stage__bg picture img { width: 100%; height: 100%; object-fit: cover; }

/* The -m plates are cut to 0.430, just wider than a tall phone's stage box
   (390x911 is 0.4279), so the height binds there and this does nothing.
   It is here for SHORT phones -- an SE's box is 0.52, wide enough that the
   WIDTH binds instead and cover starts trimming top and bottom. Left at the
   default it would trim the subject symmetrically; biased up, it takes the
   trim out of the black padding at the bottom where nothing lives. */
@media (max-width: 720px) {
  .stage__bg picture img { object-position: 50% 24%; }
}
