/* ============================================================================
   CetusEd public site — LAYOUT SHELL
   Ledger item P0-3 · Spec: base audit §5.0 "Layout grammar" + Addendum A Part E
   ----------------------------------------------------------------------------
   THE PROBLEM THIS REPLACES. The current site is "everything centred in one
   ~1,100px column. Every grid is even. No margin column, no asymmetry, no
   full-bleed" (base audit §4.1). One section unit — kicker, tinted headline,
   subhead, 3–4 card grid — repeated ~34 times.

   THE REPLACEMENT, in three moves:
     1. An ASYMMETRIC two-column grid. A narrow margin column carries § numbers,
        citations, provenance markers and annotations; the wide column carries
        content. This breaks the centred read instantly AND gives citations a
        real home, which is what a compliance product needs and a SaaS template
        never has.
     2. HAIRLINES, NOT CARDS. Card grids are allowed AT MOST TWICE PER PAGE.
        Everything else is rule-separated blocks, definition lists, real tables.
     3. THREE WIDTH TIERS, not one container (Addendum A Part E).

   ⛔ NO CARD COMPONENT IS DEFINED IN THIS FILE, DELIBERATELY (base audit Phase 0
   item 3) — so that nothing defaults to a card. The two permitted card uses per
   page opt in explicitly via .cards, defined at the bottom with its budget
   stated. The current site's failure was that the card was the only structure
   available, so relational content became containers of prose.
   ========================================================================= */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body { margin: 0; background: var(--sky); color: var(--star); }

/* ── THREE WIDTH TIERS ────────────────────────────────────────────────────
   Reading = prose. Plate = instruments. Ambient = full bleed.
   Content caps at --w-plate on large displays so text does not stretch past
   readability; the surplus goes to the margin column, not to empty gutters. */
.tier-reading { max-width: var(--w-reading); margin-inline: auto; }
.tier-plate   { max-width: var(--w-plate);   margin-inline: auto; }
.tier-ambient { width: 100%; }

/* ── THE ASYMMETRIC TWO-COLUMN SECTION ────────────────────────────────────
   <section class="sect">
     <aside class="margin-col"> § 003 · citations · provenance </aside>
     <div class="main-col">    content </div>
   </section>
   Below 1024px the margin column collapses ABOVE the content rather than
   disappearing, so § numbers and citations survive on mobile as inline
   marginalia (they are information, not decoration). */
/* 🪤 minmax(0, 1fr), NOT 1fr. A grid track's default minimum is `auto`, which
   resolves to its content's MIN-CONTENT size — so a table carrying min-width:44rem
   pushed the track past the viewport and the page scrolled sideways, while
   .tbl-wrap's overflow-x:auto never fired because the wrapper had been widened
   rather than constrained. The scroll container can only work if something above
   it refuses to grow. */
.sect {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem 2.5rem;
  max-width: var(--w-plate);
  margin-inline: auto;
  padding: clamp(3rem, 7vh, 6rem) clamp(1.25rem, 4vw, 3rem);
}
.margin-col { min-width: 0; }
.main-col   { min-width: 0; }

@media (min-width: 1024px) {
  .sect { grid-template-columns: var(--margin-col) minmax(0, 1fr); gap: 0 3rem; }
  /* Marginalia sit at the TOP of their row and stay put while content scrolls
     past — they annotate the section, they are not a second column of prose. */
  .margin-col { position: sticky; top: 6rem; align-self: start; }
}

/* On ultrawide the margin column widens and annotations that are inline on
   smaller screens move out into it as true marginalia. Addendum A Part E calls
   this "the single most distinctive thing the layout can do at that width, and
   almost nobody does it" — a real use of a 3440px display rather than a centred
   column floating in a void. */
@media (min-width: 1800px) {
  .sect { gap: 0 4.5rem; }
  .margin-col .m-inline-only { display: block; }
}
.margin-col .m-inline-only { display: none; }

/* ── THE MARGIN COLUMN'S CONTENTS ─────────────────────────────────────────── */
.margin-col .sec-n     { display: block; margin-bottom: 0.75rem; }
.margin-col .cite      { display: block; color: var(--star-dim); margin-bottom: 0.5rem; }
.margin-col .prov      { display: block; margin-bottom: 0.4rem; }
.g-chart .margin-col .cite, .g-chart-soft .margin-col .cite { color: var(--text-ink-lo); }

/* ── PROVENANCE MARKERS (base audit §3.7) ─────────────────────────────────
   The stat grid currently mixes four incompatible kinds of number — product
   inventory, state-document facts, design guarantees, and vanity counts —
   presented identically, so the weakest contaminate the strongest.
   ⛔ EVERY figure on the site carries one of these. No exceptions.
   The marker is a small square glyph plus a word; never colour alone. */
.prov { font-family: var(--f-data); font-size: var(--m-tick); color: var(--star-dim);
        letter-spacing: 0.03em; white-space: nowrap; }
.prov::before { content: '\25AA\00A0'; }           /* ▪ */
.prov-product::before  { content: '\25AA\00A0'; }  /* filled  — product inventory */
.prov-state::before    { content: '\25A0\00A0'; }  /* square  — state document */
.prov-measured::before { content: '\25C6\00A0'; }  /* diamond — measured */
.prov-estimate::before { content: '\25AB\00A0'; }  /* hollow  — estimate */
/* ⛔ RECONSTRUCTION — added 2026-08-16, and it is the marker that was missing.
   panels.js's own header declares "Each panel's caption states what is the
   product's own and what is simulated. That sentence is load-bearing — it is
   the difference between a reconstruction and a claim about a screenshot."
   Measured against the seven shipped panels: ZERO said so. Three asserted the
   opposite — "counted live", "already computed", "computed from the same data
   the dashboards draw" — over hand-authored markup with fixed dates in it.
   A contract stated in a comment with nothing enforcing it, violated by every
   member: the hollowing class this project keeps finding in its own guards.
   The panels ARE faithful reconstructions of real screens, which is worth
   saying plainly. What they are not is running software, and a compliance
   product does not get to blur that on its own marketing page. */
.prov-reconstruction::before { content: '\25CB\00A0'; }  /* hollow circle — reconstruction */
.g-chart .prov { color: var(--text-ink-lo); }

/* ── HAIRLINES, NOT CARDS ─────────────────────────────────────────────────── */
.rule      { border: 0; border-top: var(--hair) solid color-mix(in srgb, currentColor 18%, transparent); margin: 0; }
.block     { padding-block: clamp(1.5rem, 3vh, 2.5rem); border-top: var(--hair) solid color-mix(in srgb, currentColor 18%, transparent); }
.block:first-child { border-top: 0; }

/* Definition list — the correct form for "term: what it is" content that the
   current site renders as a card grid. */
.deflist { display: grid; gap: 0; margin: 0; }
.deflist > div { display: grid; gap: 0.25rem 2rem; padding-block: 1rem;
                 border-top: var(--hair) solid color-mix(in srgb, currentColor 15%, transparent); }
@media (min-width: 720px) { .deflist > div { grid-template-columns: 15rem minmax(0,1fr); } }
.deflist dt { font-family: var(--f-display); font-size: var(--d5); font-weight: 400; margin: 0; }
.deflist dd { margin: 0; color: color-mix(in srgb, currentColor 78%, transparent); }

/* ── THE WATERLINE ────────────────────────────────────────────────────────
   ⛔ A 1px RULE. Never a fill, never a background, never a type colour.
   ⛔ EXACTLY ONE PER VIEWPORT.
   It is the site's structural horizon: the nav's bottom edge, the first section
   rule, diagram baselines, and the element that carries across page transitions
   (view-transition-name is assigned in motion.css). */
.waterline {
  border: 0;
  border-top: var(--hair) solid var(--waterline);
  width: 100%;
  margin: 0;
}

/* ── DIAGRAM PLATES ───────────────────────────────────────────────────────
   Full-bleed on --deep. THE ONLY DARK SURFACES ON A LIGHT PAGE ARE DIAGRAMS, so
   "dark = this is a diagram" becomes a signal the reader learns (base audit §5.0).
   ⛔ Zero radius. Charts have square corners (Addendum C Part G). */
.plate {
  background: var(--deep);
  color: var(--star);
  border-radius: var(--r-plate);
  padding: clamp(1.25rem, 3vw, 2.5rem);
  container-type: inline-size;   /* diagrams size to THEIR width, not the viewport */
  container-name: plate;
  min-width: 0;                  /* same reason as .sect's minmax(0,1fr) above */
}
.plate-bleed { width: 100vw; margin-inline: calc(50% - 50vw); border-radius: 0; }

/* Container queries, not viewport media queries, for every visual component.
   The matrix appears full-bleed on Home AND inset within a column on /record —
   same component, two contexts, one set of rules (Addendum A Part E). */

/* ── PLATE BREAK-OUT ──────────────────────────────────────────────────────
   A plate inside .main-col is strangled by the margin column: measured, the
   matrix got 952px of container at a 3440px viewport while the section itself
   had 1432px to give. The base audit is explicit that diagram plates go
   full-bleed; this is the in-section form of that -- the plate spans BOTH grid
   columns so an instrument gets the whole width and prose keeps its measure.
   Marginalia for a bleeding plate go inside it (.plate-ticks, .badge-legend),
   not in .margin-col, because there is no margin column beside it. */
.sect > .bleed { grid-column: 1 / -1; }

/* ── COORDINATE TICKS ─────────────────────────────────────────────────────
   Every plate carries a minimal tick scale on at least one edge, and THE TICKS
   ARE ALWAYS REAL — days, grades, ages, magnitudes, depths. Never decorative
   gradations (Addendum C Part G). */
.plate-ticks { display: flex; justify-content: space-between; gap: 0.5rem;
               border-top: var(--hair) solid color-mix(in srgb, var(--star) 22%, transparent);
               padding-top: 0.4rem; margin-top: 0.75rem; }
.plate-ticks > * { font-family: var(--f-data); font-size: var(--m-tick);
                   color: var(--star-dim); letter-spacing: 0.02em; }

/* ── TEXT-EQUIVALENT TABLES ───────────────────────────────────────────────
   ⛔ EVERY plate ships one (base audit §6.7). BUILD THE TABLE FIRST, then the
   visual on top of it — that ordering makes the mobile fallback free and
   satisfies accessibility by construction rather than as a retrofit
   (Addendum A Part E).
   .plate-alt is visually hidden but present for screen readers and find-in-page;
   at <768px several diagrams promote it to visible and hide the visual instead. */
/* 🪤 THE HIDDEN ELEMENT MUST BE A BLOCK WRAPPER, NOT THE TABLE ITSELF.
   Measured 2026-08-13: with the class ON the table, the page scrolled
   horizontally at every viewport — scrollWidth 1885 against a 1440 client. A
   table ignores width:1px (its min-content width wins) and overflow:hidden does
   not clip it, so an absolutely-positioned 1758px table sat in the scroll
   extent, invisible.
   ⛔ AND THE OBVIOUS FIX IS WRONG. `display:block` on the table would clip it —
   and would also strip its table semantics from assistive technology, silently
   destroying the exact affordance this element exists to provide. The text
   equivalent must stay a real table. So the WRAPPER is hidden and the table
   inside it is untouched:
     <div class="plate-alt"><table> ... </table></div>  */
/* 🪤 AND IT MUST NOT BE ABSOLUTELY POSITIONED EITHER. .plate sets
   container-type: inline-size, which implies layout containment and therefore
   makes the plate a CONTAINING BLOCK for absolutely-positioned descendants. So
   a `position:absolute` hidden span inside a scrolling table positioned against
   the PLATE, escaped .tbl-wrap's clipping completely, and extended the document
   scroll box — measured: html scrollWidth 705 against a 390 client, while body,
   main, section and the plate all reported exactly 390 and no unclipped element
   could be found. An escapee is invisible to a search that assumes overflow
   ancestors clip, because for an abspos element they only clip when they are
   also its containing block.
   A STATIC 1px box with overflow:hidden cannot escape anything. */
.plate-alt {
  display: inline-block;
  width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); border: 0;
  white-space: nowrap;
}
.plate-alt table { white-space: nowrap; }
.plate-alt-shown { display: block; width: auto; height: auto; margin: 0;
                   overflow: visible; clip-path: none; white-space: normal; }
.plate-alt-shown table { white-space: normal; }

/* ── REAL TABLES ──────────────────────────────────────────────────────────
   Styled as chart plates. Figures in mono with tabular numerals (type.css).
   Wide tables scroll inside their own container; the page never scrolls
   horizontally. */
.tbl-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table.plate-tbl { border-collapse: collapse; width: 100%; font-size: var(--t-small); }
table.plate-tbl th, table.plate-tbl td {
  text-align: left; padding: 0.6rem 0.9rem; vertical-align: top;
  border-bottom: var(--hair) solid color-mix(in srgb, currentColor 15%, transparent);
}
table.plate-tbl thead th {
  font-family: var(--f-data); font-size: var(--m-small); font-weight: 500;
  letter-spacing: 0.02em; color: var(--star-dim);
  border-bottom: var(--hair-strong) solid color-mix(in srgb, currentColor 35%, transparent);
}
/* ⛔ REMOVED: `.g-chart table.plate-tbl thead th { color: var(--text-ink-lo) }`
   An instance patch that assumed a table inside a light section sits ON the
   light ground. It does not — plate tables sit inside a .plate, which paints
   its own near-black. The rule forced chart-paper ink onto a #05080F plate
   and measured 3.40:1. The ground/token pairing in cetus-site.css now colours
   these headers correctly from --star-dim without a per-component override. */
table.plate-tbl td.num { text-align: right; }
/* Sticky first column for the vendor matrix (base audit §5.7) */
table.sticky-1 th:first-child, table.sticky-1 td:first-child {
  position: sticky; left: 0; background: inherit;
}

/* ── SKIP LINK + FOCUS ────────────────────────────────────────────────────── */
.skip-link { position: absolute; left: -9999px; top: 0; z-index: 100; padding: 0.75rem 1rem;
             background: var(--waterline); color: var(--deep); border-radius: 0 0 var(--r-interactive) 0; }
.skip-link:focus { left: 0; }
:focus-visible { outline: 2px solid var(--waterline); outline-offset: 3px; }

/* ── THE CARD, WITH ITS BUDGET STATED ─────────────────────────────────────
   ⛔ AT MOST TWICE PER PAGE (base audit §5.0). Legitimate uses, per Addendum A
   Part F: the /documents resource grid and the mobile vendor accordion — items
   that ARE peer resources.
   ⛔ NOT for relational content. Ten relational structures rendered as card grids
   is the finding the whole redesign follows from (base audit §4.2). If the
   content is a matrix, a sequence, a dependency chain, a taxonomy or a boundary,
   it is a plate, not cards.
   ⛔ No drop shadow. Shadow implies a light source above a LIGHT surface; on
   --sky it is invisible. Elevation reads as a hairline border (Addendum A Part A). */
.cards { display: grid; gap: 1px; background: color-mix(in srgb, currentColor 15%, transparent);
         border: var(--hair) solid color-mix(in srgb, currentColor 15%, transparent);
         border-radius: var(--r-interactive); overflow: hidden; }
@media (min-width: 720px)  { .cards-2 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 960px)  { .cards-3 { grid-template-columns: repeat(3, 1fr); } }
.card { background: var(--sky); padding: clamp(1.25rem, 2.5vw, 1.75rem); }
.g-surface .card { background: var(--surface); }
.g-chart .card   { background: var(--chart); }
.card:hover { border-color: var(--star-dim); }

/* ── THE PAGE CHROME ──────────────────────────────────────────────────────
   Emitted by site-next/build/shell.js on every page (ledger C17). Styled here
   rather than in a sixth stylesheet so the core manifest stays at five and a
   page cannot link the chrome without linking the layout it depends on.
   Replaces the inline style= attributes that had started accumulating in the
   hand-written demo shells — the first step toward the "CSS selectors on
   literal inline-style bytes" debt CLAUDE.md lists. */
.site-head {
  position: sticky; top: 0; z-index: 20;
  background: color-mix(in srgb, var(--sky) 92%, transparent);
  backdrop-filter: blur(8px);
}
.site-head-in {
  max-width: var(--w-plate); margin-inline: auto;
  display: flex; align-items: baseline; gap: 1.5rem; flex-wrap: wrap;
  padding: 0.85rem clamp(1.25rem, 4vw, 3rem);
}
.brand {
  font-family: var(--f-data); font-size: var(--m-body); color: var(--star);
  text-decoration: none; letter-spacing: 0.01em; flex: none;
}
.site-nav { display: flex; gap: 1.1rem; flex-wrap: wrap; margin-left: auto; }
.nav-link {
  font-size: var(--t-small); color: var(--star-dim); text-decoration: none;
  padding-block: 0.15rem; border-bottom: var(--hair) solid transparent;
}
.nav-link:hover { color: var(--star); }
/* The current page is marked by the WATERLINE colour — the site's one structural
   accent — not by a semantic accent. --mira means statute and nothing else. */
.nav-link.is-current { color: var(--star); border-bottom-color: var(--waterline); }

/* FOOTER CLEARANCE IS DERIVED FROM THE CHROME IT MUST CLEAR, not guessed.
   .mark (bottom-left) and .rail (bottom-right) are position:fixed at
   bottom: clamp(.9rem, 2.2vh, 1.8rem), z-index 90, so they float OVER the footer
   and this padding is the only thing keeping the last footer row out from under them.
   MEASURED in Chromium, scrolled to the end, 390x600 through 1512x1600: the taller
   element (.rail-toggle, 53px at --chrome-scale 1.25) needs 61-72px of clearance.
   3rem = 48px was SHORT AT EVERY VIEWPORT TESTED, and it showed as a real overlap of
   4-8px on tall desktop and 5px on phone portrait -- the founder's "some orientations
   and devices". It read as clear on laptop only because the centred footer text does
   not reach horizontally into the corners where the chrome sits.
   The clamp term tracks the chrome's own offset so short viewports do not get the
   dead space that got a flat 4.5rem rejected here before. */
.site-foot { padding-bottom: calc(clamp(.9rem, 2.2vh, 1.8rem) + 3.5rem); }
.site-foot-in {
  max-width: var(--w-plate); margin-inline: auto;
  padding: 2rem clamp(1.25rem, 4vw, 3rem) 0;
  display: grid; gap: 0.6rem;
}
/* .foot-status and .foot-disclose were removed here: 0 of 21 built pages carry them.
   .foot-dev STAYS -- it is live on conductor.html, the self-labelled dev page. */
.foot-dev { color: var(--star-dim); max-width: 62ch; margin: 0; }

/* ── HERO ─────────────────────────────────────────────────────────────────
   A real component, because both demo pages improvised one and both ended up
   with a large dead vertical gap under the lead. A hero is a section whose
   margin column is empty and whose vertical rhythm is its own.
   Eleven pages would otherwise each invent this. */
.hero { padding-block: clamp(2.5rem, 8vh, 5rem) clamp(2rem, 5vh, 3.5rem); }
.hero .lead { margin-top: 1.25rem; }
.hero-actions { display: flex; gap: 1rem; flex-wrap: wrap; align-items: center; margin-top: 1.75rem; }
/* align-items:center, because a flex button defaults to `stretch` and grew to
   the height of its row the moment the layout put something tall beside it. */
.btn {
  display: inline-block; padding: 0.7rem 1.15rem; border-radius: var(--r-interactive);
  text-decoration: none; font-size: var(--t-small);
  border: var(--hair) solid color-mix(in srgb, var(--star) 35%, transparent);
  color: var(--star);
}
.btn:hover { border-color: var(--star); }
.btn-primary { background: color-mix(in srgb, var(--star) 10%, transparent); }

/* ── PHOTOGRAPHY ──────────────────────────────────────────────────────────
   Addendum B Part C. Photography is the EVIDENCE layer and must read as the
   same material family as the diagram plates, not as decoration bolted on.
   ⛔ NEVER round the corners of a photograph on this site — sharp edges are
   what distinguish the evidence layer from the interactive layer.
   ⛔ The AI-disclosure line in the footer is not optional while these are used;
   the shell emits it on every page. */
/* ⛔ EVERY PHOTOGRAPH IS CAPPED. The cap used to live on .photo-open only, so
   any frame emitted at full width under a different aspect class had no bound
   at all — measured 3360px on a 3440px display for the two using .photo-32,
   asking 2.92x of a 1152px frame. Fixing those two call sites would have left
   the next aspect class equally unbounded, so the cap is on the CLASS: .photo.
   Bands opt out below, to the wider band measure. */
.photo { display: block; position: relative; border-radius: var(--r-plate); overflow: hidden; background: var(--deep);
         max-width: var(--w-open-max); margin-inline: auto; }
.photo img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* The ink veil: photos sit UNDER the page's ground temperature so a warm frame
   cannot pull the section out of the palette. Addendum B allows 25–40%.
   ⚠ AT THE LOW END DELIBERATELY. The frames are now luminance-NORMALISED in the
   pipeline (build-photos.js measures each and solves a gamma to one target), so
   the veil no longer has to compensate for a 3.5x spread across the set. At 34%
   on un-normalised frames the dark end fell to Y=40 and the home band read as a
   black rectangle. Normalise the source, then veil lightly — not the reverse. */
.photo::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: color-mix(in srgb, var(--sky) 22%, transparent);
}
.g-deep .photo::after, .g-surface .photo::after { background: color-mix(in srgb, var(--deep) 25%, transparent); }
.g-chart .photo::after { background: transparent; }

/* ── FULL-BLEED BAND = a full-bleed GROUND with the photograph set into it ────
   (constraint C18.)

   It used to be 100vw of photograph with `aspect-ratio: 21/9` on the FIGURE.
   Two things were wrong with that and only one of them was the one being
   chased:

   1. RESOLUTION. On a 3440px display it asked a 1376px frame to cover 3440px —
      2.50x. Nine of fourteen frames could not fill their slot.
   2. PROPORTION, which nobody had noticed. Aspect on a 100vw figure means the
      HEIGHT scales with the viewport too: 3440 / (21/9) = a 1474px-tall band.
      That is not a band, it is a screen. It was wrong at every resolution and
      would still have been wrong with perfect photographs.

   Both close with the same move. The figure keeps the bleed and carries the
   GROUND; the aspect moves onto the picture, which caps at --w-band-max and
   centres. So the band still runs edge to edge, the photograph holds a fixed
   editorial measure, and its height stops growing with the display.

   At 3440: ground 3440 wide, image 1760x754 centred, feathered into the ground
   at each edge so it dissolves instead of ending on a seam.
   At 1440 and below: the image is the full width and no feather is applied. */
.photo-band { max-width: none; width: 100vw; margin-inline: calc(50% - 50vw); }
.photo-band > picture {
  display: block;
  width: min(100%, var(--w-band-max));
  margin-inline: auto;
  aspect-ratio: 21 / 9;
}
/* The ink veil follows the IMAGE, not the bleed — otherwise it tints the ground
   as well and the inset stops reading as an inset. */
.photo-band::after {
  left: 50%; right: auto; transform: translateX(-50%);
  width: min(100%, var(--w-band-max));
}
/* Feather only where the cap actually bites. Below the cap the image IS the
   full width and a mask would just vignette the screen edges for no reason. */
@media (min-width: 1761px) {
  /* ⚠ THE VEIL MUST BE MASKED TOO. It is a hard-edged rectangle at the same
     capped width; feathering only the image would leave the TINT ending on the
     seam the feather was there to remove — the edge would still be visible,
     just in a different colour. Both layers take the same gradient. */
  .photo-band > picture,
  .photo-band::after {
    -webkit-mask-image: linear-gradient(90deg, transparent 0,
      #000 var(--photo-feather), #000 calc(100% - var(--photo-feather)), transparent 100%);
    mask-image: linear-gradient(90deg, transparent 0,
      #000 var(--photo-feather), #000 calc(100% - var(--photo-feather)), transparent 100%);
  }
}
/* Openers are PLATES, not bleeds: capped and centred, with a defined edge.
   No feather here — a plate is supposed to end somewhere, and dissolving its
   edge would make it read as a failed band rather than a deliberate plate.
   The cap itself now comes from .photo above; this only sets proportion. */
.photo-open { aspect-ratio: 16 / 9; }
.photo-32   { aspect-ratio: 3 / 2; }
.photo-45   { aspect-ratio: 4 / 5; }

.photo-cap { display: block; margin-top: .6rem; color: var(--star-dim); }
.g-chart .photo-cap { color: var(--text-ink-lo); }

/* ⚠ A frame that cannot fill its slot is marked in the DOM, not hidden. The
   attribute is what the verification pass greps for; see photos.json
   coversUltrawide. */
.photo[data-short] { }

/* ── THE DOCUMENTS GRID — the one sanctioned card use ─────────────────────
   Addendum A Part F: "this is where the brief's grid pattern genuinely fits,
   because the items ARE peer resources." 24px+ padding, hairline border rather
   than a shadow on the dark ground, hover raising the border over 200ms.
   ⛔ Not for relational content — that is the trap the current site fell into. */
.doc-grid { margin-top: .5rem; }
.doc-card { display: grid; gap: .45rem; align-content: start; padding: clamp(1.25rem, 2.4vw, 1.6rem); }
.doc-n { color: var(--star-dim); letter-spacing: .08em; }
.doc-t { margin: 0; }
.doc-d { color: color-mix(in srgb, currentColor 70%, transparent); margin: 0; }
.doc-a { color: var(--star-dim); margin: .15rem 0 0; }
.doc-s { margin: .5rem 0 0; }
.g-chart .doc-n, .g-chart .doc-a { color: var(--text-ink-lo); }
.g-chart .doc-card { background: var(--chart); }
.g-chart .cards { background: color-mix(in srgb, var(--text-ink) 14%, transparent);
                  border-color: color-mix(in srgb, var(--text-ink) 14%, transparent); }

/* ── VISUALLY HIDDEN ──────────────────────────────────────────────────────
   ⛔ Clip, never display:none or visibility:hidden. Both of those remove the
   element from the accessibility tree, which defeats the entire purpose — a
   heading nobody can see AND nobody can hear is just absent. Used by the
   landing page, whose h1 must exist for identification while the design shows
   the photograph alone. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ══ SECTION NOTES ══════════════════════════════════════════════════════════
   Citations and provenance used to stack in a left rail beside every section,
   where they read as navigation. They sit under the passage they support now:
   one quiet line, clearly subordinate, obviously not a menu.

   ⚠ They are NOT decoration and must not be tuned away. Every figure on this
   site carries a provenance marker and every legal claim its source; that is
   the audit's honesty rule and the reason a district can check anything here.
   Quieter, yes. Absent, never. */
.sect-notes {
  margin: 1.6rem 0 0;
  padding-top: .7rem;
  border-top: var(--hair) solid color-mix(in srgb, currentColor 12%, transparent);
  display: flex;
  flex-wrap: wrap;
  gap: .3rem 1.2rem;
  font-family: var(--f-data);
  font-size: var(--m-tick);
  letter-spacing: .02em;
  color: color-mix(in srgb, currentColor 46%, transparent);
}
.sect-notes .cite,
.sect-notes .prov { display: inline; margin: 0; color: inherit; }
.g-chart .sect-notes, .g-chart-soft .sect-notes { color: color-mix(in srgb, var(--text-ink) 52%, transparent); }

/* The margin column is empty now on every section that used sect()/plateSect(),
   so the grid collapses to one column and the content uses the full measure. */
@media (min-width: 1024px) {
  .sect:not(:has(.margin-col)) { grid-template-columns: minmax(0, 1fr); }
}

/* ══ THE HIGHLIGHT FIGURE ═══════════════════════════════════════════════════
   Two to four numbers, large, with the registry they came from named under
   them and a door to the full reference. This is what replaced the inline
   matrices on the marketing pages: the same facts, stated rather than
   enumerated. Every number is read from a registry at build time. */
.figs { display: grid; gap: 1.25rem; justify-items: center; text-align: center; }
/* 🪤 align-items: start, OR THE LABELS COME UNSTUCK FROM THEIR NUMBERS.
   A flex row stretches its children to the tallest by default, so each .fig
   grid grew to match the tallest and distributed the slack between its two
   rows. Measured at 1440: a one-line label sat 117px below its number while a
   two-line label sat higher, and the row read as three unrelated pairs. */
.figs-row {
  display: flex; flex-wrap: wrap; justify-content: center;
  align-items: start;
  gap: clamp(1.5rem, 6vw, 4.5rem);
}
.fig {
  display: grid; gap: .35rem; align-content: start;
  justify-items: center; max-width: 14rem;
}
.fig-n {
  font-family: var(--f-display);
  font-size: clamp(2.75rem, 9vw, 5rem);
  line-height: .95;
  color: var(--star);
  font-variant-numeric: tabular-nums;
}
.fig-l {
  font-size: var(--m-body, 1rem);
  color: color-mix(in srgb, var(--star) 82%, transparent);
  text-wrap: balance;
}
.fig-src {
  color: color-mix(in srgb, var(--star) 55%, transparent);
  letter-spacing: .05em;
}
.fig-more { margin: 0; }
.btn-quiet {
  background: none;
  border: var(--hair) solid color-mix(in srgb, var(--star) 32%, transparent);
}
.btn-quiet:hover { border-color: var(--star); }

/* ── THE REFERENCE PAPERS ──────────────────────────────────────────────────
   A paper is for READING and its plates are for STUDYING, so they sit in
   document flow at full size — no pinning, no scale-to-fit. The bounded panel
   is right for a marketing page that highlights and wrong for a reference that
   enumerates: a reviewer wants to scroll a long table, not step through it. */
.paper-kind { color: var(--waterline); letter-spacing: .12em; text-transform: uppercase; }
.paper-src { color: color-mix(in srgb, currentColor 70%, transparent); max-width: 62ch; }


/* ══ A FIGURE THAT OPENS ════════════════════════════════════════════════════
   Founder direction 2026-08-14: the numbers alone are meaningless to a reader —
   "18 clocks" is a fact about the software. What a director recognises is the
   list: MTSS, Special education, EL/ML, Section 504, Health. So a figure can be
   opened, and what it opens to is its members, read from the registry.

   ⛔ <details>, NOT HOVER. Hover was the suggestion and it is the wrong
   mechanism on its own: half this audience is on a phone or a touchscreen and
   has no hover at all. A real disclosure opens on click, tap, Enter and Space,
   announces itself to a screen reader as expandable, and needs no script. */
details.fig { max-width: 15rem; }
.fig-sum {
  display: grid;
  justify-items: center;
  gap: .35rem;
  cursor: pointer;
  list-style: none;
  border-radius: .5rem;
  padding: .25rem .35rem;
  transition: background var(--t-hover, 180ms) var(--e-out, ease);
}
.fig-sum::-webkit-details-marker { display: none; }
.fig-sum:hover { background: color-mix(in srgb, var(--star) 7%, transparent); }
.fig-sum:focus-visible { outline: var(--hair-strong) solid var(--waterline); outline-offset: 2px; }

/* The cue is the affordance. Without it an openable figure looks exactly like
   a closed one, which is the same defect as a plate hidden behind a tap with
   nothing to say it is there. */
.fig-cue {
  color: var(--waterline);
  letter-spacing: .05em;
}
.fig-cue::after { content: ' +'; }
details.fig[open] .fig-cue::after { content: ' \2212'; }

.fig-list {
  margin: .6rem 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: .3rem;
  text-align: center;
}
.fig-list li {
  font-size: var(--m-tick);
  font-family: var(--f-data);
  color: color-mix(in srgb, var(--star) 88%, transparent);
  line-height: 1.45;
}

@media (prefers-reduced-motion: reduce) {
  .fig-sum { transition: none; }
}


/* ══ WHAT YOU DO, AND WHAT IT LEAVES BEHIND ═════════════════════════════════
   The middle rhetorical beat: between the claim and the evidence, the verbs.
   Two columns of meaning per row — the action, and the record it produces —
   because for this reader the second is the one that matters. An action that
   leaves nothing behind is not defensible six months later.

   The "leaves" tick is deliberately quiet. It is a label on a relationship,
   not a heading, and it repeats down the list; at full weight it would read as
   a column header that had come loose. */
/* ⛔ THE BREAK AFTER A HEADING MUST EXCEED THE BREAK BETWEEN ITEMS.
   `margin: 0` removed the top margin outright, so a does-block sat FLUSH
   against the heading above it. Measured across the five pages that pair the
   two: 0px after the title against 18px between items — the hierarchy exactly
   inverted, which reads as the heading belonging to the first item rather than
   to the list. This is a large part of the "spacing" fault in the founder's
   note, and it was invisible to every suite: nothing overflowed, nothing
   overlapped, contrast was fine.
   The margin only applies after a preceding sibling, so a does-block that
   opens a panel still starts flush against the panel's own padding. */
.does { margin: 0; display: grid; gap: 1.1rem; }
/* ⛔ .deflist WAS MISSED WHEN THIS WAS WRITTEN. The rule was scoped to .does,
   and /pilot uses .deflist-tight — a different list component whose row-gap is
   deliberately 0. With no after-heading margin either, the heading sat FLUSH
   against the first term and the hierarchy check read `after-title 0px <=
   between 0px`. A tight list is a legitimate choice about the space BETWEEN
   ITEMS; it says nothing about the space after the heading that introduces
   them, and conflating the two is what glued a heading to a term.
   :is() so the next list component is one token here, not one more rule
   somebody has to remember to write. */
* + :is(.does, .deflist) { margin-top: clamp(1.7rem, 3.4vh, 2.6rem); }
.does > div { display: grid; gap: .2rem; }
.does dt {
  font-family: var(--f-display);
  font-size: clamp(1.05rem, 2.1vw, 1.3rem);
  line-height: 1.25;
  color: var(--star);
  text-wrap: balance;
}
.does dd {
  margin: 0;
  font-size: var(--m-small, .95rem);
  line-height: 1.5;
  color: color-mix(in srgb, var(--star) 74%, transparent);
}
.does-out {
  color: var(--waterline);
  letter-spacing: .06em;
  text-transform: uppercase;
  margin-inline-end: .4rem;
}
@media (max-width: 700px) {
  .does { gap: .85rem; }
}


/* The relationship between the two halves is shown, now that it is no longer
   asserted by a word. A rule and a mark do the job a dangling "then" was
   failing at, and they cannot be misread as part of the sentence. */
.does > div {
  border-inline-start: var(--hair) solid color-mix(in srgb, var(--star) 18%, transparent);
  padding-inline-start: .9rem;
}
.does dd { position: relative; }
.does dd::before {
  content: '\2192';                     /* an arrow, decorative only */
  position: absolute;
  inset-inline-start: -1.55rem;
  color: var(--waterline);
  opacity: .85;
}
@media (max-width: 700px) {
  .does > div { padding-inline-start: .7rem; }
  .does dd::before { inset-inline-start: -1.35rem; }
}

/* ══ THE PULL QUOTE ═══════════════════════════════════════════
   The state's own words, at the size the sentence deserves. It replaced a
   figure whose number was the digit 1 — see quote() in build-site.js. */
/* ⛔ THE QUOTE SAT LEFT WHILE THE FIGURES ABOVE IT SAT CENTRED. Adjacent
   panels on the same page disagreeing about alignment reads as a rendering
   fault rather than a choice — reported as "confounding left aligned with
   center aligned text in sections". .figs centres itself; .pq did not, so the
   pair fell out of step. It now follows the figures. */
.pq {
  margin: clamp(1.4rem, 3vh, 2.4rem) auto 0;
  max-width: 34ch;
  text-align: center;
}
.pq-t {
  margin: 0; font-size: clamp(1.5rem, 3.2vw, 2.5rem); line-height: 1.18;
  font-weight: 400; letter-spacing: -0.012em; text-wrap: balance;
  /* ⛔ DARK INK ON A DARK PHOTOGRAPH — THE QUOTE WAS EFFECTIVELY INVISIBLE.
     When the contrast failure on .pq-a and .pq-x was fixed, this line was
     missed, so the attribution under the quote was legible and the quote
     itself was not. The a11y gate did not catch it because its selector lists
     p / li / dd / dt / td / th / h1-h3 and this is a <blockquote>; the
     selector has been widened. */
  color: var(--star);
}
/* ⛔ --text-ink-lo IS A LIGHT-SURFACE TOKEN AND THIS BLOCK SITS ON A PHOTO.
   The fallback chain var(--text-ink-lo, var(--star-dim)) resolved the FIRST
   value on .canvas-zenith — a dark photographic ground — and measured 2.81:1,
   well under AA. A fallback only fires when the variable is undefined, and
   --text-ink-lo is defined everywhere; it is simply wrong here. Mixed off
   --star, which is the token this surface actually sets. */
.pq-a { margin: .7rem 0 0; font-size: var(--m-tick); letter-spacing: .04em; color: color-mix(in srgb, var(--star) 82%, transparent); }
.pq-x { margin: .55rem 0 0; max-width: 46ch; color: color-mix(in srgb, var(--star) 86%, transparent); }
/* on a dark chart surface the tokens flip with the plate */
.g-chart .pq-t, .g-chart-soft .pq-t { color: var(--star); }
.g-chart .pq-a, .g-chart .pq-x, .g-chart-soft .pq-a, .g-chart-soft .pq-x { color: var(--star-dim); }
.figs-src { margin: .8rem 0 0; color: color-mix(in srgb, var(--star) 86%, transparent); }
.g-chart .figs-src, .g-chart-soft .figs-src { color: var(--star-dim); }

/* THE FOOTER CONTACT LINE (here, not starmap.css - that sheet is landing-only,
   so the first attempt changed nothing on /pilot where the defect was reported). Measured on /pilot at 1440x900 before this: the line
   ran x=48-678 while the beat dots sit FIXED at x=637-803, y=837 - overlapping
   in both axes, which is what put it under the wordmark. It is centred so it
   shares the dots axis rather than crossing it, and the footer reserves the
   height of the fixed beacon so the line settles just above the dots instead of
   behind them. */
.foot-contact { text-align: center; margin-inline: auto; }
/* .foot-legal HAD NO RULE IN ANY STYLESHEET — it was left-aligned by default while both
   its siblings were explicitly centred, and that is the "rows misalign" the founder
   reported. MEASURED at 1280x800 before this: the three blocks began at L48 (legal,
   align:start), L288 (disclosure) and L547 (contact) — three left edges and two
   different alignments in one three-row footer.
   ⚠ lint-unstyled-element did not catch it: the element also carries `.small`, so the
   ELEMENT is targeted even though the .foot-legal hook is not. The lint's subject is
   elements, not class hooks — a real bound, not a fault.
   One axis, one measure, matching .foot-honest so the three read as a single column. */
.foot-legal { text-align: center; margin-inline: auto; max-width: 44rem; }

/* THE HONEST FRAME (FD-017). Deliberately NOT .foot-credit and deliberately NOT
   var(--star-dim): the form the founder rejected was a bare phrase at credit size in
   low-contrast grey, painting behind the wordmark. This inherits the centring the
   comment above measured as the fix for that exact collision — centred shares the
   beat-dots axis instead of crossing it, and the footer already reserves the beacon's
   height — and it takes the PRIMARY text colour so it reads as a statement rather than
   a disclaimer someone hoped you would skip. max-width keeps it to one comfortable
   measure so it does not sprawl into the dots at wide viewports. */
.foot-honest {
  text-align: center;
  margin-inline: auto;
  margin-block-start: .35rem;
  max-width: 44rem;
  color: var(--star);
}


/* THE PILOT PHASES. A definition list because that is what it is - a term and
   what happens under it - and the same shape the page already uses for
   'What is missing'. One measure shared with the prose around it. */
.pilot-phases { margin: 1.4rem 0 0; max-width: 46rem; }
.pilot-phases > div { margin-top: 1.1rem; }
.pilot-phases dt { font-weight: 600; letter-spacing: .01em; }
.pilot-phases dd { margin: .3rem 0 0; }
