/* =============================================================================
   ATUM — pages.css
   Section-level layout. Every piece here is built from the tokens in base.css
   and the components in components.css; nothing invents a new scale.
   ========================================================================== */

/* ---------- Hero -----------------------------------------------------------
   The one place the "order out of chaos" idea is used. The figure is static
   and complete: the composition itself shows scatter at the top resolving into
   an ordered line at the horizon. Motion, when allowed, only settles it once.
   ========================================================================== */

.hero {
  position: relative;
  background: var(--night-900);
  color: var(--on-night);
  overflow: hidden;
  isolation: isolate;
}

.hero__fig {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.hero__fig svg { width: 100%; height: 100%; display: block; }

/* Scrim. The figure's warm band near the horizon is too light to carry body
   text, so the text column gets a guaranteed dark ground rather than a hope. */
.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: linear-gradient(180deg,
    rgb(7 11 22 / 0.94) 0%,
    rgb(7 11 22 / 0.90) 48%,
    rgb(7 11 22 / 0.55) 78%,
    rgb(7 11 22 / 0.10) 100%);
}
@media (min-width: 64rem) {
  .hero__scrim {
    background: linear-gradient(96deg,
      rgb(7 11 22 / 0.97) 0%,
      rgb(7 11 22 / 0.93) 34%,
      rgb(7 11 22 / 0.60) 56%,
      rgb(7 11 22 / 0.12) 76%,
      rgb(7 11 22 / 0) 92%);
  }
}

.hero__inner {
  position: relative;
  z-index: 1;
  padding-block: clamp(var(--s8), 9vw, var(--s11)) clamp(var(--s8), 8vw, var(--s10));
  display: grid;
  gap: var(--s6);
  max-width: 46rem;
}
.hero__h1 {
  font-size: var(--t-3xl);
  line-height: var(--lh-tight);
  font-weight: 800;
  letter-spacing: -0.032em;
  text-wrap: balance;
  margin: 0;
}
.hero__h1 em {
  font-style: normal;
  color: var(--sun);
}
.hero__lead {
  font-size: var(--t-md);
  line-height: 1.5;
  color: var(--on-night-2);
  max-width: 40ch;
  text-wrap: pretty;
}
.hero__cta { display: flex; flex-wrap: wrap; gap: var(--s4); align-items: center; }

.hero__trades {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2) var(--s4);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--on-night-3);
  padding-top: var(--s3);
  border-top: var(--border) solid var(--night-700);
  max-width: 40rem;
}
.hero__trades li { white-space: nowrap; }

/* the figure's parts */
.hz-sky-top  { stop-color: var(--sky-top); }
.hz-sky-mid  { stop-color: var(--sky-mid); }
.hz-sky-low  { stop-color: var(--sky-low); }
.hz-sea      { fill: var(--sea); }
.hz-line     { stroke: var(--sky-glow); }
.hz-line-under { stroke: var(--sea); opacity: 0.9; }

/* The sun. It is the only thing in the figure that MOVES between the two
   states, and it has to, because a colour change alone reads as a filter over
   a photograph rather than as the end of a day.

   The translate is on the circle and not on the <g> that clips it. That is
   deliberate and it is the whole trick: the clip path is fixed at the horizon
   in the parent's coordinate space, so as the circle sinks, less of it shows
   above the line. Move the group instead and the clip travels with it, which
   slides a full disc down the page and shows exactly the same amount of it.

   No keyframe writes `transform` here, so the charter's trap cannot bite: a
   transition interpolates from whatever the element is currently at, which is
   also why hammering the demo toggle reverses the sun mid-descent instead of
   snapping it. Percentages resolve against the circle's own box — see the
   --sun-sink comment in base.css for why that matters across two heroes. */
.hz-sun {
  fill: var(--sky-glow);
  opacity: var(--sun-fade);
  transform-box: fill-box;
  transform: translate(var(--sun-drift), var(--sun-sink));
}

/* The marks invert as they resolve: pale against the dark water when they are
   still scattered, solid and dark against the light where they land in a row.
   That is what makes the idea legible in a completely still frame. */
.hz-t {
  fill: var(--tick-loose);
  transform-box: fill-box;
  transform-origin: 50% 100%;
  transform: translate(0, 0) rotate(var(--r, 0deg));
}
.hz-t--lit { fill: var(--tick-set); }

/* PHASE-TRANSITIONS:BEGIN — the day/night change, and nothing else.
   Kept in one labelled block on purpose: it is the only place on the site
   where several elements have to move together, and a rule that drifts out of
   this block will fall out of step with the rest of the sky.

   TRANSITIONS, NOT KEYFRAMES, and that is the load-bearing decision. A visitor
   who flips the demo toggle twice in a second interrupts the change halfway;
   a transition reverses from wherever it has got to, while an animation would
   restart from its first frame and jump. There is no state this can be jammed
   in, because there is no state — only two sets of tokens and the browser
   interpolating between them.

   Durations and delays are tokens (base.css). They are zero before the first
   paint and zero under prefers-reduced-motion, in which case every rule below
   becomes an ordinary instant swap and the page is complete either way. */
.hz-sky-top { transition: stop-color var(--ph-sky)  var(--ease-dusk) var(--ph-d-top); }
.hz-sky-mid { transition: stop-color var(--ph-sky)  var(--ease-dusk) var(--ph-d-mid); }
.hz-sky-low { transition: stop-color var(--ph-glow) var(--ease-dusk) var(--ph-d-low); }
.hz-sea     { transition: fill       var(--ph-sky)  var(--ease-dusk) var(--ph-d-mid); }
.hz-line       { transition: stroke var(--ph-glow) var(--ease-dusk) var(--ph-d-low); }
.hz-line-under { transition: stroke var(--ph-sky)  var(--ease-dusk) var(--ph-d-mid); }
.hz-sun {
  transition: transform var(--ph-sun)  var(--ease-sun),
              fill      var(--ph-glow) var(--ease-dusk) var(--ph-d-low),
              opacity   var(--ph-sun)  linear;
}
.hz-t { transition: fill var(--ph-mark) var(--ease-dusk) var(--ph-d-mark); }
/* PHASE-TRANSITIONS:END */

/* Motion path. The keyframe writes `transform`, so it restates the rotation the
   element needs — the trap from the charter. Static state above is complete. */
@media (prefers-reduced-motion: no-preference) {
  .hz-t {
    animation: hz-settle 900ms var(--ease) both;
    animation-delay: var(--d, 0ms);
  }
}
@keyframes hz-settle {
  from { transform: translate(var(--dx, 0), var(--dy, 0)) rotate(var(--r, 0deg)); }
  to   { transform: translate(0, 0) rotate(var(--r, 0deg)); }
}

.hero--slim .hero__inner { padding-block: clamp(var(--s8), 7vw, var(--s10)) clamp(var(--s7), 5vw, var(--s9)); }

/* ---------- Problem picker -------------------------------------------------
   The site's primary navigation device: enter by problem, not by service.
   Built on real <button>s driving real panels. With JS off every panel is
   visible, because the panels are only hidden by script.                     */

.picker { display: grid; gap: var(--s6); }
@media (min-width: 64rem) {
  .picker { grid-template-columns: minmax(0, 21rem) minmax(0, 1fr); gap: var(--s8); align-items: start; }
}

.picker__list { display: grid; gap: var(--s2); }

.picker__btn {
  display: grid;
  grid-template-columns: 1.5rem minmax(0, 1fr);
  gap: var(--s3);
  align-items: start;
  width: 100%;
  padding: var(--s4);
  border: var(--border) solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper);
  color: var(--ink-2);
  font-size: var(--t-base);
  line-height: 1.42;
  font-weight: 500;
  transition: border-color var(--dur-1) var(--ease), background var(--dur-1) var(--ease),
              color var(--dur-1) var(--ease);
}
.picker__btn:hover { border-color: var(--rule-strong); background: var(--paper-2); color: var(--ink); }
.picker__n {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: var(--ink-3);
  padding-top: 0.22em;
}
.picker__btn[aria-selected='true'] {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
  font-weight: 600;
}
.picker__btn[aria-selected='true'] .picker__n { color: var(--sun); }

.picker__panel {
  border-left: 3px solid var(--ochre);
  padding-left: clamp(var(--s5), 3vw, var(--s7));
  display: grid;
  gap: var(--s5);
}
.picker__panel + .picker__panel { margin-top: var(--s7); }
.picker__answer { font-size: var(--t-lg); font-weight: 700; letter-spacing: -0.014em; color: var(--ink); max-width: 26ch; }
.picker__does { display: grid; gap: var(--s3); }

/* the panel swap is a cross-fade only when motion is allowed; the change of
   content is instant either way */
@media (prefers-reduced-motion: no-preference) {
  .picker__panel[data-enter] { animation: panel-in var(--dur-3) var(--ease) both; }
}
@keyframes panel-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---------- The spine ------------------------------------------------------
   The completeness argument, drawn: one line, six stations, one customer
   travelling along it. Vertical on small screens, horizontal from 64rem.     */

.spine { position: relative; }

.spine__list {
  display: grid;
  gap: var(--s5);
  position: relative;
  padding-left: var(--s6);
}
.spine__list::before {
  content: '';
  position: absolute;
  left: 5px; top: 0.5rem; bottom: 0.5rem;
  width: 2px;
  background: linear-gradient(180deg, var(--rule-2), var(--ochre));
}

.spine__item { position: relative; }
.spine__item::before {
  content: '';
  position: absolute;
  left: calc(-1 * var(--s6) + 1px);
  top: 0.42rem;
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--paper);
  border: 2px solid var(--rule-strong);
}
.spine__item--end::before { background: var(--ochre); border-color: var(--ochre); }

.spine__stage {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
  display: block;
}
.spine__name {
  font-size: var(--t-base);
  font-weight: 700;
  color: var(--ink);
  text-decoration: none;
  border-bottom: 2px solid var(--paper-3);
  transition: border-color var(--dur-1) var(--ease);
}
.spine__name:hover { border-bottom-color: var(--ochre); }
.spine__desc { font-size: var(--t-sm); color: var(--ink-2); margin-top: var(--s1); max-width: 34ch; }

/* The spine also appears as the jump nav on the platform page's night hero. */
.on-night .spine__stage { color: var(--on-night-3); }
.on-night .spine__name { color: var(--on-night); border-bottom-color: var(--night-600); }
.on-night .spine__name:hover { border-bottom-color: var(--sun); }
.on-night .spine__desc { color: var(--on-night-2); }
.on-night .spine__list::before { background: linear-gradient(180deg, var(--night-600), var(--sun)); }
.on-night .spine__item::before { background: var(--night-900); border-color: var(--night-500); }
.on-night .spine__item--end::before { background: var(--sun); border-color: var(--sun); }

@media (min-width: 64rem) {
  .on-night .spine__list::before { background: linear-gradient(90deg, var(--night-600), var(--sun)); }

  .spine__list {
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: var(--s5);
    padding-left: 0;
    padding-top: var(--s6);
  }
  .spine__list::before {
    left: 0; right: 0; top: 5px; bottom: auto;
    width: auto; height: 2px;
    background: linear-gradient(90deg, var(--rule-2), var(--ochre));
  }
  .spine__item::before { left: 0; top: calc(-1 * var(--s6) + 1px); }
  .spine__desc { max-width: none; }

  /* Every station name must sit on the same baseline however long its stage
     label runs. Reserving a fixed height was the old answer and it broke the
     moment Russian arrived: "ВЫ ВИДИТЕ, СКОЛЬКО ЭТО ПРИНЕСЛО" takes two lines
     where the English takes one, and 2.9em is less than two lines once the
     1.62 body line-height is counted, so station six dropped out of line.

     Subgrid is the answer that cannot be out-grown: the three rows are owned
     by the list, so all six columns share them whatever any language does. */
  .spine__list { grid-template-rows: auto auto auto; }
  .spine__item {
    display: grid;
    grid-row: span 3;
    grid-template-rows: subgrid;
    align-content: start;
    row-gap: 0;
  }
  .spine__stage { line-height: 1.35; }

  /* Fallback where subgrid is unavailable: reserve two real lines. */
  @supports not (grid-template-rows: subgrid) {
    .spine__item { display: block; }
    .spine__stage { min-height: 2.7em; }
  }
}

/* ---------- Timeline (the 02:14 walk-through) ------------------------------
   A real ordered list. Script adds a stepper on top; with script off, or with
   motion off, every step is present and readable in order.                   */

.tl { display: grid; gap: var(--s6); }
@media (min-width: 62rem) {
  .tl { grid-template-columns: minmax(0, 15rem) minmax(0, 1fr); gap: var(--s8); align-items: start; }
}

.tl__rail { display: grid; gap: 0; }
.tl__tick {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--s4);
  align-items: start;
  width: 100%;
  padding: var(--s3) 0;
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  font-variant-numeric: tabular-nums;
  color: var(--on-night-3);
  border: 0;
  border-left: 2px solid var(--night-700);
  padding-left: var(--s4);
  transition: color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease);
}
.tl__tick:hover { color: var(--on-night); border-left-color: var(--night-500); }
.tl__tick[aria-selected='true'] { color: var(--sun); border-left-color: var(--sun); }
.tl__tick-label {
  font-family: var(--font-sans);
  font-size: var(--t-sm);
  line-height: 1.35;
  letter-spacing: 0;
  text-align: left;
  font-weight: 600;
}
.tl__tick > span:first-child { padding-top: 0.06em; }

/* the honesty caption above a worked example — a note, not a headline */
.tl__caption {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  line-height: 1.5;
  letter-spacing: 0.02em;
  color: var(--on-night-3);
  max-width: 54ch;
  border-left: 2px solid var(--night-600);
  padding-left: var(--s3);
}

.tl__body { display: grid; gap: var(--s5); align-content: start; }
.tl__step { display: grid; gap: var(--s4); }
.tl__time {
  font-family: var(--font-mono);
  font-size: var(--t-xl);
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--sun);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.tl__what { font-size: var(--t-lg); font-weight: 700; color: var(--on-night); letter-spacing: -0.014em; max-width: 24ch; }
.tl__detail { color: var(--on-night-2); max-width: var(--measure); }

.tl__nav { display: flex; gap: var(--s3); align-items: center; padding-top: var(--s3); }
.tl__count {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: var(--on-night-3);
  letter-spacing: 0.08em;
  font-variant-numeric: tabular-nums;
}
.tl__btn {
  width: 2.5rem; height: 2.5rem;
  display: grid; place-items: center;
  border: var(--border) solid var(--night-500);
  border-radius: var(--radius);
  color: var(--on-night);
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease);
}
.tl__btn:hover:not(:disabled) { background: var(--night-700); }
.tl__btn:disabled { opacity: 0.35; cursor: default; }

@media (prefers-reduced-motion: no-preference) {
  .tl__step[data-enter] { animation: panel-in var(--dur-3) var(--ease) both; }
}

/* When script has not run, every step shows, stacked, with a rule between. */
.tl__body:not([data-stepper]) .tl__step + .tl__step {
  padding-top: var(--s6);
  border-top: var(--border) solid var(--night-700);
}
.tl__body:not([data-stepper]) { gap: var(--s6); }
.tl:not([data-ready]) .tl__nav,
.tl:not([data-ready]) .tl__rail { display: none; }

/* ---------- Proof slot ----------------------------------------------------- */

/* ---------- Product screenshots --------------------------------------------
   The only photographs on this site are pictures of the software running.
   That is a decision, not a shortage: a stock image of a technician beside a
   van is the clearest possible signal that a company has nothing of its own
   to show, and every trades owner has seen the same four of them.

   The frame is deliberately plain. Three dots and a label, in the site's own
   tokens, so a screen capture reads as a screen and not as an illustration —
   and so the image inside it is the only thing asking for attention.        */

.shot { margin: 0; }

.shot__frame {
  border: var(--border) solid var(--night-600);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--night-850);
  box-shadow: 0 30px 70px -34px rgb(3 5 10 / 0.9);
}
.shot__chrome {
  display: flex;
  align-items: center;
  gap: var(--s2);
  padding: var(--s3) var(--s4);
  background: var(--night-800);
  border-bottom: var(--border) solid var(--night-700);
}
.shot__dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--night-600);
  flex: none;
}
.shot__url {
  margin-left: var(--s3);
  color: var(--on-night-3);
  font-size: var(--t-2xs);
  letter-spacing: 0.1em;
  text-transform: none;
}
/* The capture must never be cropped by its container: `width: 100%` plus the
   intrinsic width/height on the <img> AND on the <source> reserve the right
   box before the file arrives, so nothing below it jumps when it loads.

   <picture> is inline by default, which leaves a baseline gap under the image
   inside the frame. It is a block here. */
.shot__frame picture { display: block; }
.shot__frame img { width: 100%; height: auto; display: block; }

.shot__cap {
  margin-top: var(--s4);
  display: grid;
  gap: var(--s2);
  max-width: var(--measure);
}
/* Amber is a DARK-GROUND colour. The home page's shots sit inside .on-night so
   --sun is right there; the one on platform.html sits on paper, where --sun is
   2.33:1 and fails AA outright. This is the palette's standing rule and it was
   broken here first time round: ochre on light, sun on dark, never the other
   way. Caught by the contrast pass, not by eye. */
.shot__tag { color: var(--ochre); letter-spacing: 0.12em; }
.on-night .shot__tag { color: var(--sun); }
.on-night .shot__cap .small { color: var(--on-night-2); }   /* a caption is read, not skimmed */

/* ---------- The two founders, and the two photograph slots ------------------
   Two real people is the strongest thing a company this size can show, so
   each one gets the same parts in the same order: a portrait slot, a name, a
   role, the one factual line, and a biography. Structural equality is the
   whole point. The section says a client deals with both of them, and a
   layout where one is the main figure and the other is a caption would
   contradict it before anybody read a word.

   Neither photograph exists. The frames are drawn in the same loud dashed
   idiom as every other placeholder on this site, because filler that looks
   plausible is how a placeholder ships to production by accident.           */

.team-block { display: grid; gap: var(--s2); }

/* auto-fit rather than a media query, because the width available here is NOT
   monotonic in the viewport width. The label rail takes 19rem from 60rem up
   and 23rem from 80rem up, so this block is ~767px wide at a 834px viewport
   and ~637px wide at 1440. A breakpoint written against the viewport would be
   guessing at that; an intrinsic track measures it. Two columns appear the
   moment two 17rem columns and their gap fit, and not before.

   FOUR SHARED ROWS, and both people are subgridded onto them: name, role, the
   factual line, the biography. Without it the block rags the moment the two
   people's lines differ in count — a two-line name against a one-line one, or
   a Thai role that wraps where the other does not — and one person's portrait
   then sits a line below the other's, which reads as a pair of accidents
   rather than a pair of people. A reserved min-height would be a guess about
   a name or a language not written yet; subgrid measures the real thing and
   cannot be out-grown. Same lesson as the six-station spine.

   row-gap is 0 on purpose: these four rows are the INTERNAL rhythm of a
   person, set by each row's own margin. The space between two stacked people
   comes from the person's padding instead, so it cannot leak into the gap
   between a name and a role.

   THE PORTRAIT OCCUPIES EXACTLY ONE ROW, and that is not a detail. A grid
   hands a spanning item's surplus height to every auto row it crosses, and a
   portrait is always taller than the two or three lines of type beside it. An
   earlier version had it spanning the name, the role and the factual line: at
   a 515px single column that sprayed 128px of surplus through the type and
   opened a visible hole under the name and under the role. Freezing those
   rows at min-content does NOT fix it — measured, not assumed: when every
   spanned track is frozen the algorithm distributes equally anyway. So the
   name and the role take the full column above, and the portrait sits in a
   band of its own with the factual line beside it. Nothing can inflate the
   type, and the name gets the whole column, which is also why it stops
   wrapping. */
.team {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  grid-template-rows: repeat(4, auto);
  column-gap: var(--s7);
  row-gap: 0;
}

/* The portrait is a column-width fraction, never the whole column. A frame as
   wide as the column would be two empty 294px rectangles at 1440, a wall of
   dashes where the people should be, and once the real pictures land, two
   portraits so large they outweigh the section they sit in. At 120 to 160px
   it stays a portrait, the factual line uses the space beside it, and the
   biography keeps the full column underneath.

   align-items: start, not the default stretch — the slot carries an
   aspect-ratio and a stretched grid item would be pulled off it. */
.team__person {
  display: grid;
  grid-row: span 4;
  grid-template-rows: subgrid;
  grid-template-columns: clamp(7.5rem, 40%, 10rem) minmax(0, 1fr);
  column-gap: var(--s4);
  align-items: start;
  border-top: var(--border) solid var(--rule-strong);
  padding-block: var(--s4) var(--s5);
}
.on-night .team__person { border-color: var(--night-500); }

.team__name  { grid-column: 1 / -1; grid-row: 1; }
.team__role  { grid-column: 1 / -1; grid-row: 2; }
.team__photo { grid-column: 1;      grid-row: 3; margin: var(--s4) 0 0; }
.team__meta  { grid-column: 2;      grid-row: 3; }
.team__bio   { grid-column: 1 / -1; grid-row: 4; }

.team__slot {
  aspect-ratio: 4 / 5;
  border: 2px dashed var(--rule-strong);
  border-radius: var(--radius-lg);
  /* a single minmax(0, 1fr) track, NOT place-content: center — an auto track
     sizes to max-content and a long label in a 120px frame would then hang
     out of the dashed border instead of wrapping inside it. Russian's
     "ФОТОГРАФИЯ" is the longest of the six and it is wider than the frame. */
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-content: center;
  padding: var(--s3);
  text-align: center;
  background: var(--paper-2);
}
.team__slot-label { color: var(--ochre-2); letter-spacing: 0.1em; max-width: none; }
.on-night .team__slot { border-color: var(--night-500); background: rgb(85 104 156 / 0.07); }
.on-night .team__slot-label { color: var(--sun); }

/* Each row sets its own top margin. base.css puts var(--s4) on p + p, which
   is the body rhythm and far too loose for a name over a role; a class
   selector out-ranks it. max-width: none because base.css caps every <p> at
   the reading measure and these are labels, not paragraphs. */
.team__name { font-size: var(--t-md); font-weight: 700; letter-spacing: var(--track-h4); max-width: none; }
.team__role { color: var(--ochre); max-width: none; margin-top: var(--s2); }
.team__meta { max-width: none; margin-top: var(--s4); }
.on-night .team__role { color: var(--sun); }

/* --t-sm rather than body size: a 45-word paragraph at 17px in a 294px column
   is eight ragged lines that swamp the section. --ink-2 rather than --ink-3,
   because these are read rather than skimmed — a biography is not a caption. */
.team__bio {
  font-size: var(--t-sm);
  line-height: 1.6;
  color: var(--ink-2);
  margin-top: var(--s4);
}
.on-night .team__bio { color: var(--on-night-2); }
.team__note { max-width: var(--measure); }

/* ---------- Pricing --------------------------------------------------------- */

.price {
  display: grid;
  gap: var(--s5);
}
@media (min-width: 54rem) { .price { grid-template-columns: 1fr 1fr; gap: var(--s6); } }

.price__part {
  border-top: 3px solid var(--ochre);
  padding-top: var(--s5);
  display: grid;
  gap: var(--s3);
  align-content: start;
}
.price__part:last-child { border-top-color: var(--ink); }
.price__n {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.price__amount {
  display: flex;
  align-items: baseline;
  gap: var(--s3);
  flex-wrap: wrap;
}

/* ---------- Platform sections ---------------------------------------------- */

.piece { scroll-margin-top: 9rem; }
.piece + .piece { margin-top: var(--section-y); }
/* nested inside a stack — sub-sections of one argument, not top-level ones */
.stack-6 > .piece + .piece { margin-top: var(--s8); }
.piece__num {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  font-weight: 500;
  letter-spacing: 0.12em;
  color: var(--ochre);
  display: block;
  margin-bottom: var(--s2);
}
.piece__what {
  font-size: var(--t-md);
  line-height: 1.5;
  color: var(--ink);
  font-weight: 600;
  max-width: 44ch;
  margin-top: var(--s4);
}
.piece__todo {
  margin-top: var(--s5);
  padding: var(--s4) var(--s5);
  background: var(--paper-2);
  border-left: 3px solid var(--rule-strong);
  border-radius: 0 var(--radius) var(--radius) 0;
  font-size: var(--t-sm);
  color: var(--ink-2);
  max-width: var(--measure);
}
.piece__todo strong { color: var(--ink); }

/* ---------- Disclosure (progressive detail) --------------------------------
   Native <details>. Short answer visible, detail one click away, nothing that
   matters hidden. Works with no script at all.                               */

.dis {
  border-top: var(--border) solid var(--rule);
}
.dis:last-of-type { border-bottom: var(--border) solid var(--rule); }
.dis__sum {
  display: flex;
  align-items: center;
  gap: var(--s4);
  padding: var(--s4) 0;
  cursor: pointer;
  font-weight: 650;
  font-size: var(--t-base);
  list-style: none;
  color: var(--ink);
}
.dis__sum::-webkit-details-marker { display: none; }
.dis__sum::after {
  content: '';
  margin-left: auto;
  flex: none;
  width: 0.85rem; height: 0.85rem;
  border-right: 2px solid var(--ink-3);
  border-bottom: 2px solid var(--ink-3);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform var(--dur-2) var(--ease);
}
.dis[open] .dis__sum::after { transform: rotate(-135deg) translate(-2px, -2px); }
.dis__body { padding: 0 0 var(--s5); display: grid; gap: var(--s4); }

/* ---------- Form -----------------------------------------------------------
   A real form UI that transmits nothing. It never shows a success state; on
   submit it says plainly that it is not connected and gives the real route.  */

.form { display: grid; gap: var(--s5); max-width: 38rem; }
.field { display: grid; gap: var(--s2); }
.field__label { font-size: var(--t-sm); font-weight: 650; color: var(--ink); }
.field__hint { font-size: var(--t-xs); color: var(--ink-3); font-family: var(--font-mono); letter-spacing: 0.04em; }
.field input,
.field select,
.field textarea {
  width: 100%;
  padding: 0.7rem 0.8rem;
  background: var(--paper);
  border: var(--border) solid var(--rule-strong);
  border-radius: var(--radius);
  font-size: var(--t-base);
  color: var(--ink);
  transition: border-color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease);
}
.field textarea { min-height: 7rem; resize: vertical; }
.field input:hover, .field textarea:hover, .field select:hover { border-color: var(--ink-3); }
.field input:focus, .field textarea:focus, .field select:focus {
  border-color: var(--ochre);
  box-shadow: 0 0 0 3px rgb(158 84 16 / 0.15);
}
.field__row { display: grid; gap: var(--s5); }
@media (min-width: 40rem) { .field__row { grid-template-columns: 1fr 1fr; } }

.notice {
  border: var(--border) solid var(--rule-strong);
  border-left: 3px solid var(--ochre);
  background: var(--paper-2);
  border-radius: 0 var(--radius) var(--radius) 0;
  padding: var(--s4) var(--s5);
  display: grid;
  gap: var(--s2);
}
.notice__title { font-weight: 700; font-size: var(--t-sm); color: var(--ink); }

/* ---------- The same components, on a night band ---------------------------
   The contact section and the report notice sit on dark ground. Without these
   the labels are ink on ink and effectively invisible.                       */

.on-night .field__label { color: var(--on-night); }
.on-night .field__hint  { color: var(--on-night-3); }
.on-night .notice {
  background: var(--night-800);
  border-color: var(--night-500);
  border-left-color: var(--sun);
}
.on-night .notice p,
.on-night .notice .small { color: var(--on-night-2); }
/* after the rule above: .notice__title is itself a <p>, so it needs to win */
.on-night .notice p.notice__title { color: var(--on-night); }
.on-night .contact__row { border-color: var(--night-700); }
.on-night .contact__k { color: var(--on-night-3); }
.on-night .piece__todo {
  background: var(--night-800);
  border-left-color: var(--night-500);
  color: var(--on-night-2);
}
.on-night .piece__todo strong { color: var(--on-night); }
.on-night .piece__what { color: var(--on-night); }
.on-night .dis { border-color: var(--night-700); }
.on-night .dis:last-of-type { border-bottom-color: var(--night-700); }
.on-night .dis__sum { color: var(--on-night); }
.on-night .dis__sum::after { border-color: var(--on-night-3); }

/* ---------- Contact rows ---------------------------------------------------- */

.contact { display: grid; gap: var(--s4); }
.contact__row {
  display: grid;
  grid-template-columns: 6.5rem minmax(0, 1fr);
  gap: var(--s4);
  align-items: baseline;
  padding-block: var(--s3);
  border-bottom: var(--border) solid var(--rule);
}
.contact__k {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* ---------- Night bands ------------------------------------------------------
   Full-bleed dark sections. Used three times across the site, never more:
   the hero, the night walk-through, and the proof slot.                       */

.band-night {
  background: var(--night-900);
  color: var(--on-night);
}
.band-night .horizon-rule { background: var(--night-600); }
.band-paper2 { background: var(--paper-2); }

/* ---------- Closing call ----------------------------------------------------- */

.close-cta {
  display: grid;
  gap: var(--s6);
  max-width: 44rem;
}
.close-cta__h { font-size: var(--t-xl); font-weight: 750; letter-spacing: -0.022em; }
