/* ==========================================================================
   STORM · page-specific
   Tokens, nav, buttons, footer and the reveal all come from site.css. Only what
   is unique to this page lives here.

   Same immersive treatment as the homepage: one fixed painting behind the whole
   page. The Great Wave has no quiet zone, so the veil over it is heavier and
   holds a floor rather than falling away, and the picture stays dimmed
   throughout instead of ever running at full strength under type.
   ========================================================================== */

/* The picture runs behind the whole page, the same way it does on the homepage:
   one fixed layer that the content crawls over. That is what makes it read as a
   surface rather than a picture someone placed in a box.

   The Great Wave cannot sit under type at full strength the way bg-2 can, so the
   veil is heavier here, and it never falls to zero. Even at its thinnest the
   picture stays dimmed, which is what holds the page together as one thing. */
.art {
  background-image: url("/wave-bg-1.png");
  background-image: image-set(
    url("/wave-bg-1.avif") type("image/avif"),
    url("/wave-bg-1.webp") type("image/webp"),
    url("/wave-bg-1.png") type("image/png"));
  background-position: 38% center;
  /* Lighter than Candoor's 1.10 and much lighter than the field's 1.34. The wave
     is the most saturated of the three to begin with, so it only needs enough to
     stop the veil flattening it. */
  filter: saturate(1.08) contrast(1.03);
}

/* Zoom led, where the homepage is pan led. The argument against a visible zoom
   is that nothing in life zooms, so it reads as a slideshow effect. A wave is
   the exception: it is already coming at you, so scaling into it is the motion
   the picture is describing rather than a motion imposed on it. The pan is
   demoted to a drift that only exists to keep the two out of phase.

   Same rules as the homepage. Coprime periods, 41s and 29s, so the turning
   points never coincide and the loop does not close for about forty minutes.
   Overscan governs amplitude: .art keeps transform-origin at 40% 55%, so the
   left edge overhangs by 0.40 x (scale - 1), which is 2.4% at the 1.06 floor.
   Drifting 1% leaves 1.4% in hand.

   Bare .art rather than a modifier, matching the background override above:
   storm.css loads after site.css, so it wins the cascade on order. */
@keyframes st-swell { from { scale: 1.06; } to { scale: 1.16; } }
@keyframes st-drift { from { translate: -1% -0.3%; } to { translate: 1% 0.3%; } }

@media (prefers-reduced-motion: no-preference) {
  .art {
    animation:
      st-swell 41s ease-in-out infinite alternate,
      st-drift 29s ease-in-out infinite alternate;
    animation-delay: -13s, -7s;
  }
}

.storm-hero {
  position: relative;
  min-block-size: 100svh;
  display: flex;
  align-items: center;
  padding-block: 9rem 6rem;
}

/* Heavier than the homepage's, and it holds a floor of 0.3 all the way across.
   A gradient that reaches zero would leave the right-hand side at full
   saturation, and the page would stop reading as one surface. */
.storm-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    /* Clears entirely by 64% rather than holding a floor to the far edge. The
       floor was there to stop the right hand side running at full strength, but a
       cream wash does not dim a picture the way a dark one does, it pulls every
       colour toward the paper. A thin one costs saturation everywhere and buys
       very little, so it is better gone where it is not needed. */
    linear-gradient(100deg,
      rgba(250, 245, 234, 0.82) 0%,
      rgba(250, 245, 234, 0.72) 28%,
      rgba(250, 245, 234, 0.32) 48%,
      rgba(250, 245, 234, 0.06) 58%,
      rgba(250, 245, 234, 0) 64%),
    linear-gradient(to bottom, rgba(250, 245, 234, 0.42) 0%, rgba(250, 245, 234, 0) 20%);
}

.storm-hero .wrap { position: relative; z-index: 1; }

/* The picture has to stay present the whole way down, not just in the hero. At
   site.css's 0.945 the lower page reads as flat beige and the fixed layer stops
   being felt at all.

   The old note here claimed ink clears about 9:1 at 0.86. That was true of --ink
   in the headings and wrong about the body, which runs on --ink-2: sampled
   against the wave's darkest teal under the "How we grade" copy, 0.86 gave 4.97
   against AA's 4.5. Passing, by ten percent, which is not a margin worth having
   on the widest column of the page.

   The trap is that the number was never the whole problem. The same ratio over
   flat paper reads clean; over a cresting wave the eye retunes for every glyph,
   so busy backdrop costs legibility that contrast alone does not price. 0.91
   takes the worst case to about 5.5 and, because a cream wash pulls colour
   toward the paper rather than merely darkening, it calms the wave at the same
   time. One lever, both complaints. Below roughly 0.8 the small muted type
   starts to suffer, which remains the real floor. */
.page {
  background: linear-gradient(to bottom,
    rgba(250, 245, 234, 0) 0,
    rgba(250, 245, 234, 0.8) 11vh,
    rgba(250, 245, 234, 0.91) 38vh);
}

/* Muted type sits on a busier surface here than on the homepage, so the two
   lightest inks step up one level. */
.page .sec__head p,
.page .uses p,
.page .steps p,
.page .grade p,
.page .limits p { color: var(--ink-2); }
.page .label { color: var(--ink-2); }

/* A section head that runs straight into more prose does not need the full
   3.5rem. That gap is sized to separate a heading block from a grid or a figure;
   dropped between two paragraphs of the same argument it reads as a missing
   line, and the eye stops at it. Only the heads that are followed by body copy
   are affected, so the ones sitting above lists and panels keep their air. */
.sec__head:has(+ .problem__body) { margin-block-end: 1.5rem; }
.storm-hero__text { max-inline-size: 44rem; }
/* The product name leads, the way Candoor's page leads with "Candoor". Two
   product pages that both open on a big serif wordmark read as one family; a
   small mono eyebrow on one and a wordmark on the other does not. */
.storm-mark {
  font-family: var(--serif);
  font-size: clamp(2.8rem, 6.4vw, 5rem);
  line-height: 1;
  letter-spacing: -0.032em;
  margin-block-end: 0.6rem;
}
.storm-hero .label { display: block; margin-block-end: 2rem; }

/* Smaller than it was, because the wordmark now carries the top of the
   hierarchy. Same relationship Candoor has between its name and its line. */
.storm-hero h1 {
  font-size: clamp(1.5rem, 2.9vw, 2.3rem);
  line-height: 1.08;
  letter-spacing: -0.022em;
  max-inline-size: 20ch;
  /* Two sentences at a measure this narrow give a ragged last line often enough
     to be worth balancing. Ignored where unsupported, which costs nothing. */
  text-wrap: balance;
  margin-block-end: 1.6rem;
}
/* Full ink and held inside the heavy part of the veil, for the same reason as
   the homepage: body copy on paper can afford the softer grey, body copy on a
   painting cannot. */
/* Held to 33rem rather than 38. With the veil now clearing at 64% instead of
   holding a floor, a 38rem measure runs its last lines out past the wash and onto
   the wave itself. Narrowing the column is cheaper than putting the veil back,
   and costs nothing visually. */
.storm-hero__sub {
  font-size: clamp(1.05rem, 1.5vw, 1.15rem);
  color: var(--ink);
  max-inline-size: 33rem;
  margin-block-end: 2rem;
}
.storm-hero__cta { display: flex; flex-wrap: wrap; gap: 0.85rem; }

/* ---- The two doors. Same shape Candoor uses to route its two audiences. ---- */
.doors {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  list-style: none;
  margin: 0;
  padding: 0;
}
.door {
  display: block;
  /* The li is a grid item and stretches to the tallest in the row, but the card
     inside it is the thing you can see, and block-size auto left it short. The
     two doors carry different amounts of copy, so the shorter one sat 26px above
     its own row and the pair read as misaligned along the bottom edge only. */
  block-size: 100%;
  padding: 1.9rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
  text-decoration: none;
  transition: border-color 0.28s ease, translate 0.28s ease, box-shadow 0.28s ease;
}
.door:hover, .door:focus-visible { border-color: var(--line-2); translate: 0 -3px; box-shadow: var(--shadow-lg); }
.door--primary { background: var(--accent-soft); border-color: transparent; }
.door .label { display: block; margin-block-end: 1.1rem; }
.door h3 { display: flex; align-items: center; gap: 0.5rem; font-size: 1.35rem; margin-block-end: 0.7rem; }
.door h3 svg { transition: translate 0.24s ease; }
.door:hover h3 svg { translate: 4px 0; }
.door p { color: var(--ink-2); font-size: 0.975rem; }
.door__note { margin-block-start: 0.85rem; font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); }

/* ---- Use cases ---- */
.uses { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; }
.uses li {
  display: grid;
  grid-template-columns: minmax(0, 16rem) minmax(0, 1fr);
  gap: 0.4rem 2.5rem;
  padding-block: 1.5rem;
  border-block-start: 1px solid var(--line);
}
.uses li:last-child { border-block-end: 1px solid var(--line); }
.uses h3 { font-size: 1.15rem; }
.uses p { color: var(--ink-2); font-size: 0.975rem; }

/* ==========================================================================
   USE CASES · the island, and the five panels it swaps

   One engine, five desks. The island picks the desk; the block under it changes.
   Everything from "What it is" downward stays put, because the mechanism does
   not change when the buyer does, and repeating it five times would say the
   opposite.
   ========================================================================== */

/* A control, not navigation, so it hugs its own content rather than spanning the
   column, and it is set in the mono this page reserves for labels and status.
   The border steps up to --line-2: the island has to read as a hard object
   sitting on the paper, and the hairline the panels use disappears against it.

   The selected pill is ink, not orange. Orange has exactly one job on this page,
   which is marking the row worth acting on, and a control that is permanently
   orange spends that meaning on furniture. */
.island {
  position: relative;
  display: flex;
  gap: 0.2rem;
  inline-size: fit-content;
  max-inline-size: 100%;
  margin-block-start: 2.75rem;
  padding: 0.32rem;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  background: var(--surface-2);
  box-shadow: var(--shadow);
  backdrop-filter: blur(6px);
  overflow-x: auto;
  scrollbar-width: none;
  scroll-snap-type: x proximity;
}
.island::-webkit-scrollbar { display: none; }

/* Placed and sized from JS, because the pills are text width and text width is
   not knowable in CSS. Until that first measurement lands the selected tab
   carries the ink itself, so a script that never runs leaves a working control
   rather than five identical pills. */
.island__glide {
  position: absolute;
  inset-block: 0.32rem;
  inset-inline-start: 0;
  inline-size: var(--w, 0);
  translate: var(--x, 0) 0;
  border-radius: 999px;
  background: var(--ink);
}
.island:not(.is-live) .island__glide { display: none; }
.island:not(.is-live) .island__tab[aria-selected="true"] { background: var(--ink); }

@media (prefers-reduced-motion: no-preference) {
  .island.is-live .island__glide {
    transition:
      translate 0.44s cubic-bezier(0.22, 1, 0.36, 1),
      inline-size 0.44s cubic-bezier(0.22, 1, 0.36, 1);
  }
}

.island__tab {
  position: relative;
  z-index: 1;
  flex: none;
  scroll-snap-align: center;
  appearance: none;
  border: 0;
  background: none;
  cursor: pointer;
  border-radius: 999px;
  padding: 0.68rem 1.1rem;
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-2);
  white-space: nowrap;
  transition: color 0.28s ease;
}
.island__tab:hover { color: var(--accent-deep); }
.island__tab[aria-selected="true"],
.island__tab[aria-selected="true"]:hover { color: #fff8ef; }

/* The panel the island swaps. Blocks inside it are separated by more than the
   gap between a head and its figure, so a long case still reads as three or four
   arguments rather than one unbroken scroll. */
.case { margin-block-start: 4.5rem; }
.case[hidden] { display: none; }
.case__block + .case__block { margin-block-start: clamp(4rem, 7vh, 6rem); }

/* A step down from the section head above the island. At the shared size the two
   read as siblings, and the island ends up floating between two equal headlines
   instead of sitting under one of them. This is the line that says the island is
   a control on this section rather than a divider between two sections. */
.case .sec__head h2 { font-size: clamp(1.7rem, 3.1vw, 2.4rem); }

/* Provenance now lives in each panel's own head and foot instead of as a status
   line under the headline: "Storm pilot · construction group" over the scorecard,
   "Target measures / proposed" over the ones we have not run. Same information,
   attached to the figures it qualifies rather than to the argument. */

/* One movement on swap, rather than every .reveal inside the panel firing at
   once. The script marks the incoming panel's reveals as already arrived and
   lets this carry the entrance, which is the difference between a transition and
   a stampede. */
@media (prefers-reduced-motion: no-preference) {
  .js .case.is-swap { animation: case-in 0.55s cubic-bezier(0.22, 1, 0.36, 1) both; }
}
@keyframes case-in { from { opacity: 0; translate: 0 14px; } to { opacity: 1; translate: 0 0; } }

/* ---- Panels ----
   One shell for every figure in the use-case section: the scorecard, the bar
   panels, the matrix and the trace. The validator, the synthesis, the capability
   map and the readiness report further down each still carry their own copy,
   because they arrived one at a time and rewriting four working figures to prove
   a point is not a reason. Anything new uses this.

   Wider than the 46rem those four use. The scorecard needs two number columns
   beside a sentence, and the bars need a track long enough that the last row, at
   12%, still reads as a bar rather than a dot.

   Left aligned, like every other figure on the page. The whole layout hangs off
   one left margin, and a panel centred in the column breaks that line for the
   sake of balancing whitespace nobody is looking at. */
.panel {
  margin-block-start: 3.5rem;
  max-inline-size: 50rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.panel__head {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  align-items: baseline;
  justify-content: space-between;
  padding: 1rem 1.4rem;
  border-block-end: 1px solid var(--line);
  background: var(--paper-warm);
}
.panel__head b { font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.13em; text-transform: uppercase; font-weight: 600; }
.panel__head span { font-family: var(--mono); font-size: 0.7rem; color: var(--ink-3); }

.panel__foot {
  padding: 0.85rem 1.4rem;
  border-block-start: 1px solid var(--line);
  background: var(--paper-warm);
  font-size: 0.8rem;
  color: var(--ink-3);
}
.panel__foot em { font-family: var(--serif); font-style: italic; color: var(--ink-2); }

/* Before and after, with the arrow as its own column rather than a glyph inside
   one of the numbers. Two columns of mono set to the same width is what makes the
   pairs scan down the panel instead of across it. */
.score__rows { list-style: none; margin: 0; padding: 0; }
.score__row {
  display: grid;
  /* 7.5rem rather than 7. Several of the pilot values are words rather than
     numbers ("self-report", "completions", "panel rounds"), and a wrapped mono
     value breaks the column the whole panel is scanned down. */
  grid-template-columns: minmax(0, 1fr) 7.5rem 2.25rem 7.5rem;
  gap: 0.5rem 1rem;
  align-items: center;
  padding: 1rem 1.4rem;
}
.score__row + .score__row { border-block-start: 1px solid var(--line); }
.score__row h3 { font-family: var(--sans); font-size: 0.95rem; font-weight: 400; letter-spacing: 0; }
.score__was { font-family: var(--mono); font-size: 0.85rem; color: var(--ink-3); text-align: end; }
/* Sea, not orange. Orange on this page means the row worth acting on, and on a
   scorecard where every row improves, five orange numbers would mean nothing.
   Same rule as the bars: at most one row per panel carries it, and it goes on the
   finding that justified the pilot. */
.score__now { font-family: var(--mono); font-size: 0.95rem; color: var(--sea); text-align: end; }
.score__row--mark .score__now { color: var(--accent-deep); font-weight: 600; }
.score__arrow { color: var(--ink-3); justify-self: center; }
.score__arrow svg { display: block; }

@media (max-width: 620px) {
  /* The label takes the full row and the pair sits under it, still in three
     columns, so the arrow keeps pointing at something. */
  .score__row { grid-template-columns: minmax(0, 1fr) 2.25rem minmax(0, 1fr); }
  .score__row h3 { grid-column: 1 / -1; }
  .score__was { text-align: start; }
}

/* ---- Bars ----
   The one panel shape that four of the five cases need, in three flavours: counts
   that narrow down a funnel, scores that fill a track, and a before-and-after that
   grows a second segment out of the first.

   Orange marks one row and never more than one. The capability map further down
   uses it for the function worth spending money on, and the rule here is the
   same, whether the row is the good outcome (six people worth your time) or the
   bad one (the drill that did not move the number). It is the row you act on. */
.bars__rows { list-style: none; margin: 0; padding: 0; }
.bars__row {
  display: grid;
  grid-template-columns: minmax(0, 13rem) minmax(0, 1fr) 5ch;
  gap: 1rem;
  align-items: center;
  padding: 1.05rem 1.4rem;
}
.bars__row + .bars__row { border-block-start: 1px solid var(--line); }
.bars__row h3 { font-family: var(--sans); font-size: 0.95rem; font-weight: 400; letter-spacing: 0; }
.bars__row h3 em { display: block; font-family: var(--sans); font-style: normal; font-size: 0.75rem; line-height: 1.4; color: var(--ink-3); margin-block-start: 0.2rem; }
.bars__bar { position: relative; block-size: 8px; border-radius: 999px; background: rgba(27, 43, 40, 0.07); overflow: hidden; }
.bars__bar span { position: absolute; inset-block: 0; inset-inline-start: 0; border-radius: 999px; background: var(--sea); inline-size: var(--pct); }
.bars__row--mark .bars__bar span { background: var(--accent); }
.bars__n { font-family: var(--mono); font-size: 0.85rem; text-align: end; }
.bars__row--mark .bars__n { color: var(--accent-deep); font-weight: 600; }

/* Two things on one track: where the cohort started, in a grey that reads as
   background, and what the drill added, in sea. The marked row on this flavour is
   the one that barely moved, because a programme that did not work is the finding
   worth having. */
.bars--lift .bars__bar span { background: rgba(27, 43, 40, 0.22); inline-size: var(--from); }
.bars__gain {
  position: absolute;
  inset-block: 0;
  inset-inline-start: var(--from);
  inline-size: calc(var(--pct) - var(--from));
  border-radius: 999px;
  background: var(--sea);
}
.bars__row--mark .bars__gain { background: var(--accent); }

@media (prefers-reduced-motion: no-preference) {
  .js .bars__bar span { inline-size: 0; transition: inline-size 1s cubic-bezier(0.22, 1, 0.36, 1); }
  .js .bars.is-in .bars__bar span { inline-size: var(--pct); }
  .js .bars.is-in .bars__row:nth-child(2) .bars__bar span { transition-delay: 0.14s; }
  .js .bars.is-in .bars__row:nth-child(3) .bars__bar span { transition-delay: 0.28s; }
  /* On the funnel the shortlist arrives last and on its own. Watching four bars
     shorten in sequence is the whole argument of that panel. */
  .js .bars.is-in .bars__row:nth-child(4) .bars__bar span { transition-delay: 0.48s; }
  .js .bars.is-in .bars__row:nth-child(5) .bars__bar span { transition-delay: 0.62s; }

  /* The baseline is already there and the gain grows out of it, which is the
     motion the panel is describing. Written at the same specificity as the two
     rules above and placed after them, so source order settles the tie. */
  .js .bars--lift .bars__bar span,
  .js .bars--lift.is-in .bars__bar span { inline-size: var(--from); transition: none; }
  .js .bars--lift .bars__gain { inline-size: 0; transition: inline-size 0.9s cubic-bezier(0.22, 1, 0.36, 1); }
  .js .bars--lift.is-in .bars__gain { inline-size: calc(var(--pct) - var(--from)); }
  .js .bars--lift.is-in .bars__row:nth-child(2) .bars__gain { transition-delay: 0.14s; }
  .js .bars--lift.is-in .bars__row:nth-child(3) .bars__gain { transition-delay: 0.28s; }
  .js .bars--lift.is-in .bars__row:nth-child(4) .bars__gain { transition-delay: 0.42s; }
}

@media (max-width: 620px) {
  .bars__row { grid-template-columns: minmax(0, 1fr) 5ch; }
  .bars__row h3 { grid-column: 1 / -1; }
  .bars__bar { grid-column: 1; }
}

/* ---- Matrix ----
   Functions down, capabilities across. A grid rather than more bars, because the
   claim this figure makes is that the thin spot is one cell and not one row: the
   operations team is fine at three of the four things it does. Bars cannot say
   that, and a table can, so this is a table.

   The tint is the scan aid and the number is the reading. Mapped from 52 rather
   than from zero, because every score on a grid like this lands somewhere in the
   sixties to nineties: scaled from zero, the strongest cell and the weakest are
   ten points of tint apart and the panel claims a difference the eye cannot see.
   Capped well below full strength so ink stays legible on the darkest cell, which
   also keeps the grid quiet enough for the one orange cell to land. */
.matrix__scroll { overflow-x: auto; }
.matrix__grid { inline-size: 100%; min-inline-size: 32rem; border-collapse: collapse; }
.matrix__grid th,
.matrix__grid td { font-weight: 400; text-align: center; }
.matrix__grid thead th {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 1rem 0.35rem 0.65rem;
}
.matrix__grid tbody th {
  font-family: var(--sans);
  font-size: 0.95rem;
  text-align: start;
  white-space: nowrap;
  padding: 0.4rem 1rem 0.4rem 1.4rem;
}
.matrix__grid td { padding: 0.4rem 0.35rem; }
.matrix__grid tr > :last-child { padding-inline-end: 1.4rem; }
.matrix__grid tbody tr + tr > * { border-block-start: 1px solid var(--line); }
.matrix__cell {
  display: block;
  padding-block: 0.55rem;
  border-radius: 8px;
  font-family: var(--mono);
  font-size: 0.8rem;
  color: var(--ink);
  background: color-mix(in srgb, var(--sea) max(4%, calc((var(--v) - 52) * 1.5%)), transparent);
}
.matrix__cell--gap {
  background: var(--accent-soft);
  color: var(--accent-deep);
  font-weight: 600;
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* ---- Trace ----
   What the agent actually did, in order. The rail exists so the list reads as one
   run rather than five findings, which is the difference between a trajectory and
   a checklist: step four is only alarming because steps one to three were right. */
.trace__rows { list-style: none; margin: 0; padding: 1.35rem 1.4rem; }
.trace__row {
  position: relative;
  display: grid;
  grid-template-columns: 1.5rem minmax(0, 1fr);
  gap: 0 0.9rem;
  padding-block: 0.72rem;
}
.trace__row:not(:last-child)::before {
  content: "";
  position: absolute;
  inset-block: 2.4rem -0.9rem;
  inset-inline-start: 0.72rem;
  inline-size: 1px;
  background: var(--line-2);
}
.trace__row i {
  display: grid;
  place-items: center;
  inline-size: 1.5rem;
  block-size: 1.5rem;
  margin-block-start: 0.15rem;
  border-radius: 999px;
  background: rgba(61, 107, 107, 0.14);
  color: var(--sea);
  font-style: normal;
  font-size: 0.72rem;
}
.trace__row b { display: block; font-family: var(--sans); font-size: 0.95rem; font-weight: 400; }
.trace__row em {
  display: block;
  font-family: var(--mono);
  font-style: normal;
  font-size: 0.68rem;
  letter-spacing: 0.03em;
  color: var(--ink-3);
  margin-block-start: 0.28rem;
}
.trace__row--breach i { background: var(--accent-soft); color: var(--accent-deep); }
.trace__row--breach b { color: var(--accent-deep); }
.trace__row--breach em { color: var(--accent-deep); }

/* The list of what comes off the desk reuses .uses, which carries no margin of
   its own because upstream it always follows a .sec__head. Same reasoning for the
   shout under it: its own 2.5rem is tuned to follow a paragraph, and the thing
   above it here is a hard-ruled list. */
.panel + .uses { margin-block-start: 3.5rem; }
.uses + .shout { margin-block-start: 3rem; }

/* ---- Roles ----
   Ten job titles as tags. Deliberately not the mono caps of .chip elsewhere: caps
   is for labels, and ten of them in a row reads as a wall rather than a list of
   jobs. Serif at reading size makes the same point the copy makes, which is that
   these are real trades and not categories. */
.rolestrip { list-style: none; margin: 3rem 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.6rem; }
/* Matches the gap above the strip. The shout's own 2.5rem is tuned to follow a
   paragraph, and half a rem of difference is visible when the thing above is a
   hard-edged row of tags rather than a ragged block of text. */
.rolestrip + .shout { margin-block-start: 3rem; }
.rolestrip .chip {
  display: inline-block;
  font-family: var(--serif);
  font-size: 0.98rem;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-2);
  background: var(--surface-2);
  padding: 0.35rem 0.8rem;
  border-radius: 999px;
}

/* ---- Build steps ---- */
.steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 2.25rem; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.steps li { border-block-start: 2px solid var(--ink); padding-block-start: 1.15rem; }
.steps b { display: block; font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.13em; color: var(--accent); margin-block-end: 0.7rem; }
.steps h3 { font-size: 1.15rem; margin-block-end: 0.5rem; }
.steps p { color: var(--ink-2); font-size: 0.95rem; }

/* ---- Grading principles ---- */
.grade { display: grid; gap: 2.5rem; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); list-style: none; margin: 0; padding: 0; }
.grade li { border-block-start: 2px solid var(--accent); padding-block-start: 1.25rem; }
.grade h3 { font-size: 1.3rem; margin-block-end: 0.7rem; }
.grade p { color: var(--ink-2); font-size: 0.975rem; }
.grade code {
  display: inline-block;
  margin-block-start: 0.9rem;
  font-family: var(--mono);
  font-size: 0.775rem;
  color: var(--sea);
  background: rgba(61, 107, 107, 0.08);
  padding: 0.35rem 0.6rem;
  border-radius: 5px;
}

/* ---- Citation validator ---- */
.validator {
  margin-block-start: 4.5rem;
  max-inline-size: 50rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.validator__head {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  align-items: baseline;
  justify-content: space-between;
  padding: 1rem 1.4rem;
  border-block-end: 1px solid var(--line);
  background: var(--paper-warm);
}
.validator__head b { font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.13em; text-transform: uppercase; font-weight: 600; }
.validator__head span { font-family: var(--mono); font-size: 0.7rem; color: var(--ink-3); }

.validator__rows { list-style: none; margin: 0; padding: 0; }
.validator__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.75rem 1rem;
  align-items: center;
  padding: 1rem 1.4rem;
}
.validator__row + .validator__row { border-block-start: 1px solid var(--line); }
.validator__row p { font-size: 0.95rem; }
.validator__row code { display: block; margin-block-start: 0.3rem; font-family: var(--mono); font-size: 0.72rem; color: var(--sea); }
.validator__row--gap code { color: var(--accent-deep); }

.verdict {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.28rem 0.6rem;
  border-radius: 5px;
  white-space: nowrap;
  background: rgba(61, 107, 107, 0.1);
  color: var(--sea);
}
.verdict--gap { background: var(--accent-soft); color: var(--accent-deep); }

/* Sentence case deliberately. The chips above are uppercase because they are
   labels; this is a sentence, and a sentence in caps is a wall. */
.validator__foot {
  padding: 0.85rem 1.4rem;
  border-block-start: 1px solid var(--line);
  background: var(--paper-warm);
  font-size: 0.8rem;
  color: var(--ink-3);
}
.validator__foot em { font-family: var(--serif); font-style: italic; color: var(--ink-2); }

/* Opacity lives inside the no-preference query so the reduced-motion kill
   switch in site.css cannot strand a row at zero. */
@media (prefers-reduced-motion: no-preference) {
  .js .validator__row { opacity: 0; }
  .js .validator.is-in .validator__row { animation: row-in 0.55s cubic-bezier(0.22, 1, 0.36, 1) both; }
  .js .validator.is-in .validator__row:nth-child(1) { animation-delay: 0.15s; }
  .js .validator.is-in .validator__row:nth-child(2) { animation-delay: 0.45s; }
  .js .validator.is-in .validator__row:nth-child(3) { animation-delay: 0.75s; }
  .js .validator.is-in .validator__row:nth-child(4) { animation-delay: 1.05s; }

  .js .validator__row .verdict { opacity: 0; }
  .js .validator.is-in .verdict { animation: stamp 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) both; }
  .js .validator.is-in .validator__row:nth-child(1) .verdict { animation-delay: 0.5s; }
  .js .validator.is-in .validator__row:nth-child(2) .verdict { animation-delay: 0.8s; }
  .js .validator.is-in .validator__row:nth-child(3) .verdict { animation-delay: 1.1s; }
  /* The extra beat before "Insufficient" is the point of the panel. */
  .js .validator.is-in .validator__row:nth-child(4) .verdict { animation-delay: 1.5s; }
}
@keyframes row-in { from { opacity: 0; translate: 0 10px; } to { opacity: 1; translate: 0 0; } }
@keyframes stamp { from { opacity: 0; scale: 0.86; } to { opacity: 1; scale: 1; } }

/* ---- The six steps ---- */
.method { list-style: none; margin: 3.5rem 0 0; padding: 0; display: grid; gap: 0 3.5rem; }
@media (min-width: 900px) { .method { grid-template-columns: 1fr 1fr; } }
.method li {
  display: grid;
  grid-template-columns: 2.75rem minmax(0, 1fr);
  gap: 0.3rem 0.75rem;
  padding-block: 1.5rem;
  border-block-start: 1px solid var(--line);
}
.method b { grid-row: span 2; font-family: var(--mono); font-size: 0.78rem; color: var(--accent); padding-block-start: 0.3rem; }
.method h3 { font-size: 1.1rem; }
.method p { color: var(--ink-2); font-size: 0.95rem; }

/* ---- Synthesis ----
   The input side of the capability map: three kinds of evidence converging into
   one picture. Deliberately not colour coded three ways like the old version was.
   This palette runs on two accents, and a third hue would read as decoration
   rather than meaning. Sea, orange and grey are enough to separate three rows. */
.synth {
  margin-block-start: 3.5rem;
  max-inline-size: 46rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.synth__head {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  align-items: baseline;
  justify-content: space-between;
  padding: 1rem 1.4rem;
  border-block-end: 1px solid var(--line);
  background: var(--paper-warm);
}
.synth__head b { font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.13em; text-transform: uppercase; font-weight: 600; }
.synth__head span { font-family: var(--mono); font-size: 0.7rem; color: var(--ink-3); }

.synth__body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 4.5rem minmax(0, 1fr);
  align-items: center;
  gap: 1.5rem;
  padding: 1.9rem 1.4rem;
}

.synth__sources { list-style: none; margin: 0; padding: 0; display: grid; gap: 1rem; }
.synth__sources li { display: flex; align-items: baseline; gap: 0.7rem; }
.synth__dot { inline-size: 7px; block-size: 7px; border-radius: 50%; background: var(--sea); flex: none; }
.synth__sources li:nth-child(2) .synth__dot { background: var(--accent); }
.synth__sources li:nth-child(3) .synth__dot { background: var(--ink-3); }
.synth__sources b { display: block; font-weight: 500; font-size: 0.95rem; }
.synth__sources em { display: block; font-style: normal; font-size: 0.78rem; color: var(--ink-3); margin-block-start: 0.15rem; }

.synth__link svg { display: block; inline-size: 100%; block-size: auto; }
.synth__link path { fill: none; stroke: var(--ink-3); stroke-width: 1.25; stroke-dasharray: 3 3; opacity: 0.8; }

.synth__out .label { display: block; margin-block-end: 0.6rem; }
.synth__out p { font-family: var(--serif); font-size: 1.1rem; line-height: 1.35; }

@media (prefers-reduced-motion: no-preference) {
  .js .synth__sources li,
  .js .synth__link,
  .js .synth__out { opacity: 0; }
  .js .synth.is-in .synth__sources li { animation: row-in 0.5s cubic-bezier(0.22, 1, 0.36, 1) both; }
  .js .synth.is-in .synth__sources li:nth-child(1) { animation-delay: 0.1s; }
  .js .synth.is-in .synth__sources li:nth-child(2) { animation-delay: 0.25s; }
  .js .synth.is-in .synth__sources li:nth-child(3) { animation-delay: 0.4s; }
  /* The join appears only once all three sources are on screen, then the result. */
  .js .synth.is-in .synth__link { animation: fade-in 0.6s ease both 0.62s; }
  .js .synth.is-in .synth__out { animation: row-in 0.5s cubic-bezier(0.22, 1, 0.36, 1) both 0.85s; }
}
@keyframes fade-in { to { opacity: 1; } }

@media (max-width: 620px) {
  .synth__body { grid-template-columns: minmax(0, 1fr); gap: 1.25rem; }
  .synth__link { display: none; }
  .synth__out { border-block-start: 1px solid var(--line); padding-block-start: 1.25rem; }
}

/* ---- Capability map ---- */
.capmap {
  margin-block-start: 3.5rem;
  max-inline-size: 46rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.capmap__head {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  align-items: baseline;
  justify-content: space-between;
  padding: 1rem 1.4rem;
  border-block-end: 1px solid var(--line);
  background: var(--paper-warm);
}
.capmap__head b { font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.13em; text-transform: uppercase; font-weight: 600; }
.capmap__head span { font-family: var(--mono); font-size: 0.7rem; color: var(--ink-3); }

.capmap__rows { list-style: none; margin: 0; padding: 0; }
.capmap__row {
  display: grid;
  grid-template-columns: 7rem minmax(0, 1fr) 3ch 5.5ch;
  gap: 1rem;
  align-items: center;
  padding: 0.95rem 1.4rem;
}
.capmap__row + .capmap__row { border-block-start: 1px solid var(--line); }
.capmap__row h3 { font-family: var(--sans); font-size: 0.95rem; font-weight: 400; letter-spacing: 0; }
.capmap__bar { block-size: 6px; border-radius: 999px; background: rgba(27, 43, 40, 0.09); overflow: hidden; }
.capmap__bar span { display: block; block-size: 100%; border-radius: 999px; background: var(--sea); inline-size: var(--pct); }
/* Orange marks the function that is actually a problem, so the eye lands on the
   row worth spending money on rather than on the highest number. */
.capmap__row--low .capmap__bar span { background: var(--accent); }
.capmap__pct { font-family: var(--mono); font-size: 0.8rem; text-align: end; }
.capmap__gaps { font-family: var(--mono); font-size: 0.7rem; color: var(--ink-3); text-align: end; }

.capmap__foot {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.75rem;
  padding: 0.95rem 1.4rem;
  border-block-start: 1px solid var(--line);
  background: var(--paper-warm);
  font-family: var(--mono);
  font-size: 0.72rem;
  color: var(--ink-2);
}
.capmap__foot em { font-family: var(--serif); font-size: 0.85rem; font-style: italic; color: var(--ink-3); margin-inline-start: auto; }

/* Transition rather than keyframes, so the bar can animate to a width carried in
   a custom property without the value being baked into the animation. */
@media (prefers-reduced-motion: no-preference) {
  .js .capmap__bar span { inline-size: 0; transition: inline-size 1.1s cubic-bezier(0.22, 1, 0.36, 1); }
  .js .capmap.is-in .capmap__bar span { inline-size: var(--pct); }
  .js .capmap.is-in .capmap__row:nth-child(2) .capmap__bar span { transition-delay: 0.12s; }
  .js .capmap.is-in .capmap__row:nth-child(3) .capmap__bar span { transition-delay: 0.24s; }
  .js .capmap.is-in .capmap__row:nth-child(4) .capmap__bar span { transition-delay: 0.36s; }
}

@media (max-width: 620px) {
  .capmap__row { grid-template-columns: minmax(0, 1fr) 3ch 5.5ch; }
  .capmap__row h3 { grid-column: 1 / -1; }
}

/* ---- Readiness report ----
   The only panel that argues rather than illustrates: one rubric, two operators,
   and the agent losing on the row that matters. Teal is the human baseline, grey
   is the agent, and orange appears exactly once, on the line the agent failed.
   The colour is the argument. */
.rr {
  margin-block-start: 3rem;
  max-inline-size: 48rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.rr__head {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  align-items: baseline;
  justify-content: space-between;
  padding: 1rem 1.4rem;
  border-block-end: 1px solid var(--line);
  background: var(--paper-warm);
}
.rr__head b { font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.13em; text-transform: uppercase; font-weight: 600; }
.rr__head span { font-family: var(--mono); font-size: 0.7rem; color: var(--ink-3); }

.rr__task { padding: 1.25rem 1.4rem; border-block-end: 1px solid var(--line); }
.rr__task h3 { font-size: 1.1rem; margin-block-end: 0.35rem; }
.rr__task p { font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); }

.rr__rows { list-style: none; margin: 0; padding: 0; }
.rr__row,
.rr__cols {
  display: grid;
  grid-template-columns: 8.5rem minmax(0, 1fr) minmax(0, 1fr);
  gap: 0.9rem 1.5rem;
  align-items: center;
  padding: 0.85rem 1.4rem;
}
.rr__cols { padding-block: 0.9rem 0.35rem; }
.rr__cols span { font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-3); }
.rr__row + .rr__row { border-block-start: 1px solid var(--line); }
.rr__row h4 { font-family: var(--sans); font-size: 0.92rem; font-weight: 400; }

.rr__side { display: grid; grid-template-columns: minmax(0, 1fr) 3ch; gap: 0.75rem; align-items: center; }
.rr__bar { block-size: 5px; border-radius: 999px; background: rgba(27, 43, 40, 0.09); overflow: hidden; }
.rr__bar i { display: block; block-size: 100%; border-radius: 999px; background: var(--sea); inline-size: var(--pct); }
.rr__side--agent .rr__bar i { background: var(--ink-3); }
.rr__row--fail .rr__side--agent .rr__bar i { background: var(--accent); }
.rr__side b { font-family: var(--mono); font-size: 0.78rem; font-weight: 400; text-align: end; }
.rr__row--fail .rr__side--agent b { color: var(--accent-deep); font-weight: 600; }

.rr__verdict {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.5rem;
  align-items: center;
  padding: 1.1rem 1.4rem;
  border-block: 1px solid var(--line);
  background: var(--paper-warm);
}
.rr__verdict span { display: inline-flex; align-items: center; gap: 0.55rem; font-size: 0.9rem; }
.rr__verdict b { font-family: var(--mono); font-size: 1.05rem; margin-inline-start: 0.15rem; }
.rr__verdict .rr__total--low { color: var(--accent-deep); }
.rr__verdict .rr__total--ok { color: var(--sea); }

.rr__evidence { padding: 1.1rem 1.4rem; }
.rr__evidence .label { display: block; margin-block-end: 0.8rem; }
.rr__evidence ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5rem; }
.rr__evidence li { display: grid; grid-template-columns: 1.1rem minmax(0, 1fr); gap: 0.5rem; font-family: var(--mono); font-size: 0.76rem; color: var(--ink-2); }
.rr__evidence li i { font-style: normal; color: var(--sea); }
.rr__evidence li.is-breach { color: var(--accent-deep); }
.rr__evidence li.is-breach i { color: var(--accent); }

.rr__foot { padding: 0.85rem 1.4rem; border-block-start: 1px solid var(--line); background: var(--paper-warm); font-size: 0.8rem; color: var(--ink-3); }
.rr__foot em { font-family: var(--serif); font-style: italic; color: var(--ink-2); }

@media (prefers-reduced-motion: no-preference) {
  .js .rr__bar i { inline-size: 0; transition: inline-size 0.95s cubic-bezier(0.22, 1, 0.36, 1); }
  .js .rr.is-in .rr__bar i { inline-size: var(--pct); }
  .js .rr.is-in .rr__row:nth-child(2) .rr__bar i { transition-delay: 0.1s; }
  .js .rr.is-in .rr__row:nth-child(3) .rr__bar i { transition-delay: 0.2s; }
  .js .rr.is-in .rr__row:nth-child(4) .rr__bar i { transition-delay: 0.3s; }
  /* The safety row arrives last and alone. It is the whole point of the panel. */
  .js .rr.is-in .rr__row--fail .rr__bar i { transition-delay: 0.5s; }

  .js .rr__verdict, .js .rr__evidence li { opacity: 0; }
  .js .rr.is-in .rr__verdict { animation: fade-in 0.5s ease both 1.15s; }
  .js .rr.is-in .rr__evidence li { animation: row-in 0.45s cubic-bezier(0.22, 1, 0.36, 1) both; }
  .js .rr.is-in .rr__evidence li:nth-child(1) { animation-delay: 1.4s; }
  .js .rr.is-in .rr__evidence li:nth-child(2) { animation-delay: 1.55s; }
  .js .rr.is-in .rr__evidence li:nth-child(3) { animation-delay: 1.85s; }
}

@media (max-width: 720px) {
  .rr__cols { display: none; }
  .rr__row { grid-template-columns: minmax(0, 1fr); gap: 0.55rem; }
  .rr__row h4 { font-weight: 500; }
  .rr__side { grid-template-columns: 3.6rem minmax(0, 1fr) 3ch; }
  .rr__side::before {
    content: "Human";
    font-family: var(--mono);
    font-size: 0.64rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-3);
  }
  .rr__side--agent::before { content: "Agent"; }
}

/* ---- Human or agent ---- */
.doubled { display: grid; gap: 1.5rem; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); margin-block: 2.5rem; }
.doubled div { padding: 1.6rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface-2); }
.doubled .label { display: block; margin-block-end: 0.8rem; }
.doubled p { font-family: var(--serif); font-size: 1.3rem; line-height: 1.3; }
.shout {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(1.5rem, 3.4vw, 2.4rem);
  line-height: 1.25;
  max-inline-size: 26rem;
  color: var(--ink);
  margin-block-start: 2.5rem;
}

/* ---- Limits ---- */
.limits { list-style: none; margin: 0; padding: 0; display: grid; gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }
.limits li { border-block-start: 2px solid var(--ink); padding-block-start: 1.15rem; }
.limits h3 { font-size: 1.15rem; margin-block-end: 0.5rem; }
.limits p { color: var(--ink-2); font-size: 0.95rem; }

@media (max-width: 860px) {
  .uses li { grid-template-columns: minmax(0, 1fr); gap: 0.3rem; }

  /* site.css does this for .hero and the reasoning carries over: the desktop wash
     runs at 100deg and clears the right hand side entirely, because on a wide
     screen the type occupies one half and the picture gets the other. On a phone
     the column spans the full width, so the veil has to run top to bottom with it.

     It also cannot fall to zero the way the homepage's does. bg-2 has a pale sky
     to hand the last lines over to; the wave has whitecaps and dark troughs in the
     same square inch, and the sub is the longest block of small type on the page.
     0.3 at the very bottom is the floor that keeps the last line readable while
     still letting the crest through. */
  .storm-hero::before {
    background: linear-gradient(to bottom,
      rgba(250, 245, 234, 0.86) 0%,
      rgba(250, 245, 234, 0.8) 58%,
      rgba(250, 245, 234, 0.55) 82%,
      rgba(250, 245, 234, 0.3) 100%);
  }
}
