/* =============================================================
   DoveBoard — the home page. "The unfolding."

   Seven sections, one continuous sequence: everything on the page
   descends from the mark. Loaded only by index.html.

   AS WITH site.css THERE IS NO HEX VALUE IN THIS FILE. Colour comes
   from tokens.css through var(), and tools/verify.py fails the build on
   a literal.

   THE MOTION CONTRACT, and it is the same in all seven sections:

     Every scroll-linked value is ONE custom property, and its CSS
     default is the END state. So a browser with no JavaScript, a
     visitor with prefers-reduced-motion, and an old engine all get the
     same thing: the composed, finished picture with every word in it.
     Motion is what happens when assets/js/home.js is allowed to move
     that property backwards to 0 and then forwards again.

     Nothing is revealed BY script. Nothing is hidden on a timer.

   FRAME BUDGET. No filter: blur() anywhere — a single blurred fixed
   layer once took this site from 60fps to 20fps. Glow is layered
   gradients and box-shadows. Everything that animates is transform,
   translate, scale, opacity or a custom property read by those.

   Sections: 1 stage (ignition + split) · 2 emission · 3 corridor
             4 pathway · 5 ownership · 6 get it
   ============================================================= */

/* ---------- registered properties ----------
   Registered so they interpolate and so an unset value is a number
   rather than a string. Every initial-value is the END state. */
@property --split   { syntax: "<number>"; inherits: true; initial-value: 1; }
@property --ignite  { syntax: "<number>"; inherits: true; initial-value: 1; }
@property --corridor{ syntax: "<number>"; inherits: true; initial-value: 0; }

/* =============================================================
   1. THE STAGE — section 1 (ignition) and section 2 (the split)

   One pinned artwork, two screens of content scrolling over it. The
   mark in the artwork is the same object in both: it is whole in
   section 1 and cleaved in section 2, because it is one element being
   driven by one number.
   ============================================================= */

.stage {
  position: relative;
  isolation: isolate;
  background: var(--db-ink);
}

/* Sticky, with its height cancelled out of the flow so the two content
   screens start at the top of the stage and scroll over it.

   THE CANCELLATION IS ON .ig, NOT HERE, and that is load-bearing. A
   sticky element's constraint rectangle is its containing block's
   padding box adjusted by its OWN margins, so `margin-bottom: -100svh`
   on this element pushed that rectangle a full viewport lower and the
   artwork stayed pinned over the whole of section 3. Taking the same
   100svh off the next sibling's top gives the identical layout and
   leaves the constraint rectangle where it belongs. */
.stage-art {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}
.stage > .beat { position: relative; z-index: 1; }
.stage > .ig { margin-top: -100svh; }

/* --- the horizon ------------------------------------------------
   A retro sunset: the signature gradient as a banded disc sitting on
   a horizon line, a perspective grid below it, scanlines over the lot.
   The grid is a plane rotated in 3D with a repeating gradient on it —
   real convergence to a real vanishing point, one composited layer,
   no image request and no filter. ------------------------------- */

/* The horizon sits at --sky, and everything in the artwork is placed
   against that one number rather than against a pile of percentages. */
.stage-art { --sky: 74%; }

.sky {
  position: absolute; inset: 0;
  background:
    radial-gradient(120% 70% at 50% var(--sky),
      color-mix(in srgb, var(--db-plum) 22%, transparent) 0%,
      transparent 58%),
    linear-gradient(to bottom,
      var(--db-ink) 0%,
      color-mix(in srgb, var(--db-indigo) 11%, var(--db-ink)) 52%,
      var(--db-ink) 100%);
}

.sun {
  position: absolute;
  left: 50%; top: var(--sky);
  width: min(430px, 66vw); aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  background: var(--signature-y);
  opacity: .5;
  /* Solid above the waist, banded below it. The bands are a mask, so
     no second element and no blend mode. */
  --bands: repeating-linear-gradient(to bottom,
            black 0 11px, transparent 11px 21px);
  --waist: linear-gradient(to bottom, black 0 46%, transparent 46%);
  mask-image: var(--waist), var(--bands);
  mask-composite: add;
  -webkit-mask-image: var(--waist), var(--bands);
  -webkit-mask-composite: source-over;
}

.horizon {
  position: absolute; inset-inline: 0; top: var(--sky);
  height: 1px;
  background: var(--signature-x);
}
/* The glow above the line: a short gradient, not a blur. */
.horizon::before {
  content: ""; position: absolute; inset-inline: 0; bottom: 0;
  height: 110px;
  background: linear-gradient(to top,
    color-mix(in srgb, var(--db-rose) 22%, transparent), transparent);
}

/* A plane rotated about its top edge projects part of itself ABOVE that
   edge — those stray diagonals were crossing the sun. The clip box is
   what keeps the grid below the horizon where a grid belongs. */
.grid-clip {
  position: absolute; inset-inline: 0;
  top: var(--sky); bottom: 0;
  overflow: hidden;
  perspective: 300px;
  perspective-origin: 50% 0%;
}
.grid {
  position: absolute;
  left: -60%; width: 220%;
  top: 0; height: 260%;
  --line: color-mix(in srgb, var(--db-indigo) 58%, transparent);
  background-image:
    repeating-linear-gradient(to right, var(--line) 0 1px, transparent 1px 74px),
    repeating-linear-gradient(to bottom, var(--line) 0 1px, transparent 1px 74px);
  transform: rotateX(73deg);
  transform-origin: 50% 0%;
  mask-image: linear-gradient(to bottom, black 0%, transparent 58%);
  -webkit-mask-image: linear-gradient(to bottom, black 0%, transparent 58%);
}

.scan {
  position: absolute; inset: 0;
  background: repeating-linear-gradient(to bottom,
    transparent 0 2px, color-mix(in srgb, var(--db-ink) 62%, transparent) 2px 3px);
  opacity: .7;
}

/* --- the mark, whole then cleft ---------------------------------
   Two paths, both derived from the supplied mark by tools/mark.py.
   At --split 0 they sit exactly where the source mark's halves sit,
   so the pair IS the mark; at 1 they have drifted apart and changed
   colour. Each half is drawn twice, bone over gradient, and the bone
   copy's opacity is what crossfades — one animated property per half
   and no blend mode. ------------------------------------------- */

/* Above the sun's waist, where the disc is still indigo and the bone
   mark has 10.4:1 against it. BRAND.md bars the standard mark from
   mid-tone backgrounds and this is the reason the mark sits high. */
.mark-stage {
  position: absolute;
  left: 50%; top: 38svh;
  width: clamp(148px, 19vw, 236px);
  translate: -50% -50%;
  /* the breath: 2% amplitude, and it never stops — it is the mark
     being alive rather than an entrance */
  animation: breathe 7s var(--ease-in-out) infinite;
}
.mark-stage svg {
  display: block; width: 100%; height: auto; overflow: visible;
  position: relative;   /* above .mark-halo, which is absolute */
}

@keyframes breathe {
  0%, 100% { scale: 1; }
  50%      { scale: 1.02; }
}

/* The halo behind the mark. Two stacked radial gradients, no filter. */
.mark-halo {
  position: absolute; left: 50%; top: 50%;
  width: 260%; aspect-ratio: 1; translate: -50% -50%;
  border-radius: 50%;
  background:
    radial-gradient(closest-side,
      color-mix(in srgb, var(--db-rose) 34%, transparent), transparent 70%);
  animation: halo 7s var(--ease-in-out) infinite;
}
@keyframes halo {
  0%, 100% { opacity: .5; scale: 1; }
  50%      { opacity: .78; scale: 1.07; }
}

/* AT REST THE MARK IS THE MARK. Two adjacent filled paths sharing an
   edge anti-alias to a hairline down the middle, and a logo with a
   crease in it is a logo that has been altered. So section 1 shows the
   supplied path entire, and it hands over to the halves across the
   first eighth of the split — by which point they are five units apart
   and there is a real gap rather than a seam artefact. */
.whole {
  fill: var(--db-bone);
  opacity: clamp(0, calc(1 - var(--split) * 8), 1);
}

.half--l { translate: calc(var(--split) * -38.5px) 0; }
.half--r { translate: calc(var(--split) *  38.5px) 0; }
.half-bone { fill: var(--db-bone); opacity: calc(1 - var(--split)); }
.half-hot  { fill: url(#warm); }
.half-cool { fill: url(#cool); }

/* The seam. Opens with the split and stays. */
.seam {
  position: absolute; left: 50%; top: 0; bottom: 0;
  width: 2px; translate: -50% 0;
  background: var(--signature-y);
  scale: 1 var(--split);
  transform-origin: 50% 38svh;
  opacity: var(--split);
}
.seam::before {
  content: ""; position: absolute; inset-block: 0; left: 50%;
  width: 190px; translate: -50% 0;
  background: linear-gradient(to right,
    transparent, color-mix(in srgb, var(--db-rose) 16%, transparent),
    transparent);
}

/* --- beat 1: ignition ------------------------------------------- */

.beat { min-height: 100svh; display: grid; align-content: center; }
.beat > .shell { width: 100%; }

/* The wordmark's position is pinned to the artwork's, not centred and
   hoped for: the mark's centre is at 41svh and its clear space is 25%
   of its height, so the lockup starts at 60svh whatever the viewport
   does. It is still ordinary flow content — only the box is placed. */
.ig { text-align: center; position: relative; }
.ig > .shell {
  position: absolute; inset-inline: 0; top: 57svh;
  /* --ignite is 1 at rest and 0 once the lockup has risen to where the
     pinned mark is. See the note in home.js initStage: without it the
     wordmark scrolls straight through the logo. Default 1, so a still
     page shows it. */
  opacity: var(--ignite);
}
.ig-word {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(20px, 3.4vw, 34px);
  letter-spacing: .4em;          /* BRAND.md: ~0.4em as a logotype */
  text-indent: .4em;             /* re-centres the trailing letterspace */
  margin: 0;
  color: var(--db-bone);
}
.ig-cue {
  margin: clamp(26px, 5svh, 52px) 0 0;
  font: 500 11px/1 var(--font-mono);
  letter-spacing: .22em; text-transform: uppercase;
  color: var(--db-text-muted);
}
.ig-cue::after {
  content: ""; display: block;
  width: 1px; height: 40px; margin: 14px auto 0;
  background: linear-gradient(to bottom, var(--db-text-muted), transparent);
}

/* --- beat 2 and 3: the split ------------------------------------ */

.sp { min-height: auto; display: block; padding-block: 0 14svh; }

/* The scroll room the held words occupy. --split is measured off the
   words' own box, so this height IS the length of the split. */
.sp-hold { min-height: 172svh; padding-top: 96svh; }

.sp-words {
  position: sticky;
  top: 35svh;                  /* level with the mark, which is at 38svh */
  display: flex; justify-content: space-between; align-items: center;
  gap: clamp(12px, 4vw, 60px);
  margin: 0;
  font-size: clamp(26px, 5.4vw, 62px);
  letter-spacing: -.03em;
  text-wrap: nowrap;
}
/* Display use of the two anchors, at display size. BRAND.md bars rose
   and coral from small text and from anything interactive; large
   non-interactive display type is exactly what they are for. Measured
   on ink: rose 5.10:1, indigo-300 5.79:1. */
.sp-word--life { color: var(--db-display-rose); text-align: left; }
.sp-word--biz  { color: var(--db-indigo-300); text-align: right; }
.sp-word {
  opacity: var(--split);
  translate: calc((1 - var(--split)) * var(--from, 0px)) 0;
}
.sp-word--life { --from: 40px; }
.sp-word--biz  { --from: -40px; }

.sp-copy {
  display: grid; gap: clamp(18px, 3vw, 40px);
  grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  max-width: 980px; margin-inline: auto;
  text-align: left;
}
.sp-copy h2 { font-size: clamp(24px, 3vw, 34px); }
.sp-copy p { color: var(--db-text-muted); }
/* Eyebrows are 12px. The lens colours do not come down to that size —
   BRAND.md bars rose and coral from small text — so the personal side
   takes the text-safe secondary and the business side the text-safe
   primary. The lens still reads, and neither can be mistaken for an
   error state. */
.sp-copy .eyebrow--life { color: var(--db-secondary); }
.sp-copy .eyebrow--biz  { color: var(--db-primary); }

/* =============================================================
   2. EMISSION — section 3

   Seven shards leave the seam, each a contiguous run of the mark's own
   segments (tools/mark.py proves it), and each becomes one capability.
   The card's own text is what trails behind its shard: the words are
   the card's content, so with no script they are simply a paragraph.
   ============================================================= */

.em { position: relative; padding-block: clamp(60px, 8vw, 110px) var(--band); }

/* The seam continues out of section 2 and is where the shards come
   from — so it is the same line, not a new decoration. */
.em-origin {
  position: absolute; left: 50%; top: 0;
  width: 2px; height: clamp(90px, 13vw, 190px);
  translate: -50% 0;
  background: linear-gradient(to bottom, var(--db-coral), transparent);
}

.em-cards {
  list-style: none; margin: clamp(34px, 5vw, 66px) 0 0; padding: 0;
  display: grid; gap: clamp(14px, 1.8vw, 22px);
  grid-template-columns: repeat(auto-fit, minmax(272px, 1fr));
}

.em-card {
  position: relative;
  padding: clamp(18px, 2vw, 26px);
  background: var(--glass);
  border: 1px solid var(--hair-soft);
  border-radius: var(--r);
  /* the unfold: default is unfolded, so this is what a static render
     shows and what reduced motion keeps */
  transform-origin: 50% 0%;
}
.em-card h3 { margin: 14px 0 .4em; font-size: 19px; }
.em-card h3 a {
  color: inherit; text-decoration: none;
}
.em-card h3 a:hover { color: var(--db-primary); }
.em-card h3 a::after {
  content: ""; position: absolute; inset: 0; border-radius: var(--r);
}
.em-card:has(a:focus-visible) {
  outline: 2px solid var(--db-primary); outline-offset: 3px;
}
.em-card h3 a:focus-visible { outline: none; }
.em-card p { color: var(--db-text-muted); font-size: 15.5px; margin: 0; }

.em-shard {
  display: block; width: 46px; height: auto; overflow: visible;
}
.em-shard path { fill: url(#shard); }

/* Word spans exist only once home.js has split the paragraph. Until
   then the paragraph is a paragraph. */
.em-w { display: inline-block; will-change: auto; }

/* =============================================================
   3. THE CORRIDOR — section 4

   The grid from section 1 becomes a corridor, and the panels passing
   on either side are real text. --corridor is metres travelled, driven
   by scroll velocity: the reader is doing the driving.
   ============================================================= */

.co { position: relative; overflow: hidden; background: var(--db-ink); }
.co-head { position: relative; z-index: 2; }

/* Floor and ceiling, each in its OWN clip box. A rotated plane projects
   part of itself past the edge it turns about, so two unclipped planes
   in one perspective container drew a pair of enormous diagonals across
   the section instead of a corridor. Same fix as the hero grid: give
   each half a box and let it clip. */
.co-tube { position: absolute; inset: 0; pointer-events: none; }
.co-half {
  position: absolute; inset-inline: 0; height: 50%;
  overflow: hidden;
  perspective: 460px;
}
.co-half--floor { top: 50%; perspective-origin: 50% 0%; }
.co-half--roof  { bottom: 50%; perspective-origin: 50% 100%; }

.co-wall {
  position: absolute; left: -50%; width: 200%; height: 300%;
  --line: color-mix(in srgb, var(--db-plum) 72%, transparent);
  --cell: 78px;
  background-image:
    repeating-linear-gradient(to right, var(--line) 0 1px, transparent 1px var(--cell)),
    repeating-linear-gradient(to bottom, var(--line) 0 1px, transparent 1px var(--cell));
}
/* The travel is a TRANSFORM, applied after the rotation so it slides
   along the plane rather than down the screen — which is what going
   down a corridor is. home.js wraps --corridor-wrap to one cell, so the
   grid scrolls forever off one compositor property and never repaints. */
.co-half--floor .co-wall {
  top: 0; transform-origin: 50% 0%;
  transform: rotateX(74deg) translate3d(0, calc(var(--corridor-wrap, 0) * 1px), 0);
  mask-image: linear-gradient(to bottom, black 4%, transparent 34%);
  -webkit-mask-image: linear-gradient(to bottom, black 4%, transparent 34%);
}
.co-half--roof .co-wall {
  bottom: 0; transform-origin: 50% 100%;
  transform: rotateX(-74deg) translate3d(0, calc(var(--corridor-wrap, 0) * -1px), 0);
  mask-image: linear-gradient(to top, black 4%, transparent 34%);
  -webkit-mask-image: linear-gradient(to top, black 4%, transparent 34%);
}

.co-panels {
  list-style: none; margin: 0; padding: 0;
  position: relative; z-index: 1;
}
.co-panel {
  padding: 16px 18px;
  background: color-mix(in srgb, var(--db-surface-raised) 88%, transparent);
  border: 1px solid var(--hair);
  border-left: 2px solid var(--db-secondary);
  border-radius: var(--r-sm);
}
/* "Luminous panels", without a filter: the glow is two spread shadows
   in the palette. A blur() here on a 3D-transformed layer is exactly
   the thing that cost this site 40fps once. */
html.js .co.is-flying .co-panel {
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--db-secondary) 45%, transparent),
    0 0 34px color-mix(in srgb, var(--db-plum) 40%, transparent),
    0 0 90px color-mix(in srgb, var(--db-indigo) 26%, transparent);
}
.co-panel b { display: block; font-family: var(--font-display); font-size: 17px; }
.co-panel span { font-size: 14.5px; color: var(--db-text-muted); }

/* Static presentation: an ordinary two-column list of the panels. This
   is what JS-off and reduced-motion get, and it says the same thing. */
.co-panels {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  margin-top: clamp(28px, 4vw, 52px);
}

/* The flythrough only exists when script is running and motion is
   welcome. It is opted INTO, never opted out of.

   --corridor is how far the reader has driven, in px of corridor, and it
   is CLAMPED by home.js to the length of the run. So the panels arrive,
   pass, and stop; nothing recycles, so nothing ever pops into existence
   at the far end. Driving to the end and stopping is also the honest
   behaviour for a section that has an end. */
html.js .co.is-flying .co-panels {
  display: block; height: 76svh; margin: 0;
  perspective: 800px;
  perspective-origin: 50% 50%;
}
/* THE NUMBERS ARE A READABILITY BUDGET, not a look. An element at
   translateZ(z) under perspective P draws at P/(P-z) of its size, so at
   P=800 a panel is half-size at z=-800 and a quarter at z=-2400. The
   first pass spaced seven panels over 3120px of depth and every one of
   them was a 50px smudge in the middle of the screen. These values keep
   two or three panels in view, entering at 41% and passing at full
   size, which is the point of a flythrough: you can read what goes by.
   --gap must match SPACING in home.js. */
html.js .co.is-flying .co-panel {
  position: absolute; top: 50%; width: 320px;
  backface-visibility: hidden;
  --gap: 420px;
  /* the -340 is a lead-in: at --corridor 0 the nearest panel is
     still approaching rather than parked at the eye */
  --z: calc((var(--corridor) * 1px) - (var(--i) * var(--gap)) - 340px);
  transform:
    translate3d(calc(var(--side) * 380px), calc(-50% + var(--side) * 62px), var(--z))
    rotateY(calc(var(--side) * -54deg));
  /* In from the distance, out as it passes the eye. Two ramps
     multiplied, so a panel is never abruptly there or gone. */
  opacity: calc(
    clamp(0, (var(--z) + 1150px) / 530, 1) *
    clamp(0, (260px - var(--z)) / 300, 1));
}
html.js .co.is-flying .co-panel:nth-child(odd)  { --side: -1; }
html.js .co.is-flying .co-panel:nth-child(even) { --side:  1; }

.co-cue {
  position: relative; z-index: 2;
  margin: 24px 0 0;
  font: 500 11px/1 var(--font-mono);
  letter-spacing: .2em; text-transform: uppercase;
  color: var(--db-text-muted);
}

/* =============================================================
   4. THE PATHWAY — section 5

   A branching tour. Every step is in the document as a real heading
   and a real illustration, so with no script it reads top to bottom as
   the same journey written out. With script, one step shows at a time
   and the choices become buttons.
   ============================================================= */

.pw { position: relative; }

.pw-note {
  display: block;
  margin: 0 0 clamp(22px, 3vw, 34px);
  padding: 11px 15px;
  border: 1px dashed var(--db-secondary);
  border-radius: var(--r-sm);
  background: var(--glass);
  font: 500 13px/1.5 var(--font-mono);
  color: var(--db-text);
  max-width: 62ch;
}
.pw-note b {
  display: inline-block; margin-right: 6px;
  color: var(--db-secondary); letter-spacing: .1em; text-transform: uppercase;
}

.pw-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 26px; }

.pw-step {
  border: 1px solid var(--hair-soft);
  border-radius: var(--r-lg);
  background: var(--glass);
  padding: clamp(18px, 2.2vw, 28px);
}
.pw-step > .eyebrow { margin-bottom: 8px; }
.pw-step h3 { font-size: clamp(20px, 2.4vw, 26px); }
.pw-step > p { color: var(--db-text-muted); max-width: 68ch; }

/* the choices */
.pw-choices {
  display: flex; flex-wrap: wrap; gap: 10px;
  margin-top: 20px; padding: 0; list-style: none;
}
.pw-choices li { margin: 0; }

/* With script: one step at a time, and a trail of where you have been. */
html.js .pw-steps > .pw-step[hidden] { display: none; }
.pw-trail {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin: 0 0 18px; padding: 0; list-style: none;
  font: 400 12.5px/1 var(--font-mono);
  color: var(--db-text-muted);
}
.pw-trail li { display: flex; align-items: center; gap: 8px; }
.pw-trail li:not(:first-child)::before { content: "\2192"; opacity: .6; }
.pw-trail button {
  background: none; border: 0; padding: 3px 2px; cursor: pointer;
  color: var(--db-primary); font: inherit;
  text-decoration: underline; text-underline-offset: 3px;
}
.pw-trail li:last-child button { color: var(--db-text-muted); text-decoration: none; cursor: default; }

/* the illustration: hand-built HTML, and labelled as a drawing */
.pw-mock {
  margin-top: 22px;
  border: 1px solid var(--hair);
  border-radius: var(--r);
  overflow: hidden;
  background: var(--db-surface-sunken);
}
.pw-mock-bar {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--hair-soft);
  font: 400 12px/1 var(--font-mono); color: var(--db-text-muted);
}
.pw-mock-bar .right { margin-left: auto; letter-spacing: .08em; }
.pw-mock-body { display: grid; grid-template-columns: 148px minmax(0, 1fr); }
.pw-side {
  border-right: 1px solid var(--hair-soft);
  padding: 12px 10px;
  display: grid; gap: 3px; align-content: start;
}
.pw-side span {
  font: 400 12.5px/1 var(--font-mono);
  color: var(--db-text-muted);
  padding: 7px 8px; border-radius: 6px;
}
.pw-side span.on {
  background: color-mix(in srgb, var(--db-primary) 22%, transparent);
  color: var(--db-text);
}
.pw-main { padding: 16px 18px; display: grid; gap: 10px; align-content: start; }
.pw-crumb {
  font: 400 11.5px/1 var(--font-mono); letter-spacing: .1em;
  text-transform: uppercase; color: var(--db-text-muted);
}
.pw-title { font-family: var(--font-display); font-weight: 600; font-size: 18px; }
.pw-row {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 11px; border-radius: 7px;
  background: var(--glass); font-size: 14px;
}
.pw-row .tag {
  margin-left: auto;
  font: 500 10.5px/1 var(--font-mono); letter-spacing: .08em;
  text-transform: uppercase;
  padding: 4px 7px; border-radius: 20px;
  border: 1px solid var(--hair);
  color: var(--db-text-muted);
}
.pw-row .tag--on {
  border-color: color-mix(in srgb, var(--db-primary) 60%, transparent);
  color: var(--db-primary);
}
.pw-row .box {
  width: 14px; height: 14px; border-radius: 4px;
  border: 1.5px solid var(--hair); flex: none;
}
.pw-row .box--done {
  border-color: var(--db-secondary);
  background: var(--db-secondary);
}
.pw-figs { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; }
.pw-fig { padding: 11px 12px; border: 1px solid var(--hair-soft); border-radius: 8px; }
.pw-fig .k { font: 400 11px/1.4 var(--font-mono); letter-spacing: .09em;
             text-transform: uppercase; color: var(--db-text-muted); }
.pw-fig .v { font-family: var(--font-display); font-weight: 600; font-size: 21px; }

/* =============================================================
   5. OWNERSHIP — section 6

   After all that, stop. Ink, bone, four sentences, no movement.
   ============================================================= */

.own-quiet {
  padding-block: clamp(90px, 13vw, 190px);
  background: var(--db-ink);
  border-top: 1px solid var(--hair-soft);
  border-bottom: 1px solid var(--hair-soft);
}
.own-quiet h2 {
  font-size: clamp(28px, 4.6vw, 52px);
  max-width: 30ch;
}
.own-claims {
  list-style: none; margin: clamp(40px, 6vw, 76px) 0 0; padding: 0;
  display: grid; gap: 0;
  grid-template-columns: repeat(auto-fit, minmax(215px, 1fr));
  border-top: 1px solid var(--hair-soft);
}
.own-claims li {
  padding: 26px 22px 26px 0;
  border-bottom: 1px solid var(--hair-soft);
}
.own-claims b {
  display: block;
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(19px, 2.2vw, 24px);
  color: var(--db-bone);
  margin-bottom: 7px;
}
.own-claims span { font-size: 15px; color: var(--db-text-muted); }
.own-more { margin-top: clamp(34px, 5vw, 56px); max-width: 70ch; }
.own-more p { color: var(--db-text-muted); }

/* =============================================================
   6. GET IT — section 7
   Prices are stamped from data/pricing.json by tools/pricing.py.
   ============================================================= */

.get-plans {
  display: grid; gap: clamp(16px, 2vw, 24px);
  grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  align-items: start;
  margin-top: clamp(26px, 3vw, 42px);
}
.get-plan {
  padding: clamp(20px, 2.4vw, 30px);
  border: 1px solid var(--hair);
  border-radius: var(--r-lg);
  background: var(--glass);
}
.get-plan h3 { font-size: 21px; margin-bottom: 2px; }
.get-kind { font: 400 13px/1.5 var(--font-mono); color: var(--db-text-muted); margin: 0 0 16px; }
.get-price { display: flex; align-items: baseline; gap: 9px; margin: 0 0 6px; }
.get-price b {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(30px, 3.6vw, 42px); letter-spacing: -.03em;
}
.get-price span { font-size: 14px; color: var(--db-text-muted); }
.get-alt { margin: 0 0 16px; font-size: 14px; color: var(--db-text-muted); }
.get-plan p:last-child { color: var(--db-text-muted); font-size: 15px; }
.get-foot { margin-top: clamp(26px, 3vw, 40px); font-size: 14.5px; color: var(--db-text-muted); }

/* =============================================================
   Reduced motion. Not a stripped page — the same page, composed.
   Every --custom-property is already at its end state, so all that is
   left is to stop the two things that loop.
   ============================================================= */
@media (prefers-reduced-motion: reduce) {
  .mark-stage, .mark-halo { animation: none; }
  .mark-halo { opacity: .6; }

  /* NOTHING IS PINNED AND NOTHING IS OVERLAID.

     A still page does not need a sticky layer, and with one it inherits
     the pinned-mark problem with no fade available to solve it: the
     wordmark scrolled straight through the logo, and then through two
     attempts at overlaying it a fixed distance below.

     So under this query the stage is simply three stacked pictures, in
     ordinary flow, that cannot collide by construction:

       1  the artwork — the mark already cleaved, on the sunset
       2  the wordmark and the scroll cue
       3  the two words, and the copy

     --split defaults to 1, so the whole idea is legible in the first
     picture without anything having to move.  */
  .stage-art {
    position: relative; height: 100svh;
    margin-bottom: 0;
  }
  .stage > .ig { margin-top: 0; min-height: auto; }
  .ig { position: static; }
  .ig > .shell {
    position: static; top: auto;
    padding-block: clamp(26px, 5svh, 60px) 0;
    opacity: 1;                    /* --ignite is never driven here */
  }
  .sp-hold { min-height: auto; padding-top: 0;
             margin-bottom: clamp(22px, 4svh, 48px); }
  .sp-words { position: static; }
  .sp { padding-block: clamp(44px, 9svh, 96px) clamp(40px, 8svh, 90px); }
  /* the corridor never enters flythrough — home.js checks the query
     too, this is the belt to that braces */
  html.js .co.is-flying .co-panels { display: grid; height: auto; }
  html.js .co.is-flying .co-panel {
    position: static; width: auto; transform: none; opacity: 1;
  }
}

/* =============================================================
   Responsive
   ============================================================= */
@media (max-width: 820px) {
  /* No padding here: the lockup's position is set by .ig > .shell, and
     a leftover 40svh of padding from the first layout pushed the
     wordmark clean off the bottom of a 915px viewport. */
  .ig-word { letter-spacing: .3em; text-indent: .3em; }
  .sp-words { font-size: clamp(23px, 7.4vw, 40px); }
  .pw-mock-body { grid-template-columns: 1fr; }
  .pw-side {
    border-right: 0; border-bottom: 1px solid var(--hair-soft);
    display: flex; flex-wrap: wrap; gap: 4px;
  }
  html.js .co.is-flying .co-panels { display: grid; height: auto; }
  html.js .co.is-flying .co-panel {
    position: static; width: auto; transform: none; opacity: 1;
  }
}
@media (max-width: 560px) {
  .sp-words { flex-direction: column; align-items: flex-start; gap: 6px; }
  .sp-word--biz { text-align: left; }
  .own-claims li { padding-right: 0; }
}
