/* ============================================================================
   SHELL v3 — the glass top-bar chrome, the hero, and the home components.
   Loaded after site.css; everything here is scoped under body.shell3 so the
   legacy sidebar-era layout rules cannot fight it.

   BRAND OS v3.0 · ATLAS. Repointed 2026-08-13.

   This file used to carry the heaviest colour debt on the site: 74 lines with
   a literal hex, roughly 40 second-argument fallbacks inside var() that were
   a silently stale copy of the palette, and 34 rgba() encodings of brand
   colours that no hex search could ever find. All three are gone. Every
   colour below is a token.

   THE var() FALLBACKS ARE DELETED, DELIBERATELY. A hardcoded second argument
   looks defensive and is not: it only ever fires when tokens.css is missing
   or a token was renamed, which is exactly the moment it would paint the OLD
   brand over the new one. tokens.css is loaded unconditionally by shell() on
   every route, and this file is loaded by nothing else, so the fallback could
   not fire on a working page and could only lie on a broken one. One copy of
   the palette, in one file.

   THREE DECISIONS WORTH RECORDING, because the values they replaced were the
   only values those rules ever got:

     1. The secondary-text custom property this file referenced on the catalog,
        diagnosis and tri cards was never defined in tokens.css — its fallback
        was doing all the work. Replaced with var(--muted), which is exactly
        that role in v3: secondary text on light, 6.5:1 on white. No new name
        was invented for it.
     2. The card-border custom property was likewise never defined, and its
        fallback was a pale seafoam. Replaced with var(--hairline). v3 draws
        depth with hairlines rather than shadows, so the border token IS the
        hairline token and there is no second one.
     3. The warm-secondary eyebrow colour disagreed with tokens.css even
        before this rebrand (the fallback here and the definition there were
        two different browns) and the whole warm family is removed by law in
        v3. Every use of it was a mono eyebrow on a white card, which in v3 is
        Surface Steel: var(--primary), 7.4:1 on white.

   Ratios published in this file were computed on 2026-08-13 against the token
   they name, not estimated.
   ========================================================================= */

/* neutralize the sidebar-era content offset */
.shell3 .content { margin: 0 !important; max-width: none !important; width: auto !important; padding: 0 !important; }
.shell3 main { display: block; }
.shell3 .content3 { padding-top: 72px !important; }

/* ---------- the glass header ---------- */
/* Sticky chrome gets --blur-1 (the grade the Brand OS assigns it); overlays
   get --blur-2. A third grade makes depth ambiguous, so there are two. */
.hd3 { position: fixed; top: 0; left: 0; right: 0; z-index: 999; transition: background var(--t-release) var(--ease), box-shadow var(--t-release) var(--ease), padding var(--t-release) var(--ease); padding: 14px 0; background: transparent; }
.hd3.scrolled { background: var(--glass-d); -webkit-backdrop-filter: var(--blur-1); backdrop-filter: var(--blur-1); box-shadow: var(--sh-md); padding: 9px 0; border-bottom: 1px solid var(--hairline-d); }
.hd3-in { max-width: 1280px; margin: 0 auto; padding: 0 28px; display: flex; align-items: center; gap: 18px; }
/* The brand row (2026-08-25): the LLM demo's recipe, ported verbatim — icon
   34px, live Plex Mono name, hairline divider, page label. The divider and
   label yield first on narrow screens; the icon and name never do. */
.hd3-brand { display: flex; align-items: center; gap: 14px; text-decoration: none; flex: 0 0 auto; }
.hd3-brandicon { width: 34px; height: 34px; display: block; flex: 0 0 34px; }
.hd3-word { font-family: var(--font-mono); font-weight: 600; font-size: 13px; letter-spacing: .16em; text-transform: uppercase; color: var(--paper); white-space: nowrap; }
.hd3-div { width: 1px; height: 26px; background: var(--hairline-d); }
.hd3-page { color: var(--dim-d); font-family: var(--font-mono); font-size: 11px; font-weight: 600; letter-spacing: .18em; text-transform: uppercase; white-space: nowrap; }
@media (max-width: 760px) { .hd3-div, .hd3-page { display: none; } }
.hd3-nav { display: flex; align-items: center; gap: 2px; margin-left: auto; }
.hd3-nav > a, .h3grp > button { color: var(--dim-d); font-size: 13px; font-weight: 600; font-family: var(--font-display); padding: 7px 10px; border-radius: var(--r-sm); background: none; border: 0; cursor: pointer; transition: color var(--t-hover) var(--ease), background var(--t-hover) var(--ease); text-decoration: none; }
.hd3-nav > a:hover, .h3grp > button:hover, .h3grp.open > button { color: var(--paper); background: color-mix(in srgb, var(--paper) 12%, transparent); }
/* The active page: the LLM chrome's treatment, ported — a True North wash
   under white text with the inset spark underline. A group whose child is
   current takes the underline without the wash, exactly as the demo does. */
.hd3-nav > a[aria-current="page"] { color: var(--paper); background: color-mix(in srgb, var(--spark) 18%, transparent); box-shadow: inset 0 -2px 0 var(--spark); }
.h3grp.on > button { color: var(--paper); box-shadow: inset 0 -2px 0 var(--spark); }
.h3grp { position: relative; }
.h3grp .car { font-size: 10px; opacity: .7; }
.h3dd { position: absolute; top: calc(100% + 8px); left: 0; min-width: 230px; background: var(--ground); border: 1px solid var(--hairline-d); border-radius: var(--r); box-shadow: var(--sh-md); padding: 8px; display: none; flex-direction: column; }
.h3grp.open .h3dd, .h3grp:focus-within .h3dd { display: flex; }
@media (hover: hover) { .h3grp:hover .h3dd { display: flex; } }
.h3dd a { color: var(--dim-d); font-size: 13px; font-weight: 600; padding: 9px 12px; border-radius: var(--r-sm); text-decoration: none; transition: color var(--t-hover) var(--ease), background var(--t-hover) var(--ease); }
.h3dd a:hover { color: var(--paper); background: color-mix(in srgb, var(--paper) 12%, transparent); }
.hd3-right { display: flex; align-items: center; gap: 12px; }
/* THE one True North button. Buttons are --pill in v3, and the label on a
   True North fill is Midnight Green at 5.6:1 — white on it is 2.8:1 and
   illegal, which is what this rule used to ship (see the v3.1 block below,
   where a later `color:#fff !important` overrode the correct value). */
/* DJ's 2026-08-25 CTA ruling: white bold label on the spark fill (his call,
   made knowing the 2.9:1 measurement — the hover state, white over Midnight,
   is the compliant half), the star glyph on a slow loop in place of the
   arrow, and a hover that empties the fill into a glowing spark outline
   while the star ignites and scales. The glow is a deliberate exception to
   the no-halo rule, scoped to this one element by the owner's ruling. */
.hd3-cta { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 44px; background: var(--spark); color: var(--paper) !important; font-family: var(--font-display); font-size: 12.5px; font-weight: 700; letter-spacing: .02em; padding: 0 20px; border-radius: var(--pill); text-decoration: none; box-shadow: var(--sh-md); transition: background var(--t-hover) var(--ease), box-shadow var(--t-hover) var(--ease), border-color var(--t-hover) var(--ease), transform var(--t-press) var(--ease); border: 1px solid transparent; white-space: nowrap; }
.hd3-cta .cta-glyph { display: inline-flex; animation: ctaSpin 9s linear infinite; }
.hd3-cta .cta-glyph svg { display: block; transition: transform var(--t-hover) var(--ease), color var(--t-hover) var(--ease); }
@keyframes ctaSpin { to { transform: rotate(360deg); } }
.hd3-cta:hover { background: transparent; border-color: var(--spark); transform: translateY(-1px); box-shadow: 0 0 0 1px var(--spark), 0 0 16px color-mix(in srgb, var(--spark) 55%, transparent), 0 0 34px color-mix(in srgb, var(--spark) 25%, transparent); }
.hd3-cta:hover .cta-glyph svg { transform: scale(1.18); color: var(--spark); }
@media (prefers-reduced-motion: reduce) { .hd3-cta .cta-glyph, .drw3-cta .cta-glyph { animation: none; } }
/* The burger answers the pointer like everything else in the chrome now: a
   spark border-and-ink shift on --t-hover. It was the one control in the
   header with no hover state at all. */
.hd3-burger { display: none; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; background: var(--hairline-d); border: 1px solid var(--hairline-d); color: var(--paper); border-radius: var(--r-sm); padding: 0 11px; cursor: pointer; transition: border-color var(--t-hover) var(--ease), color var(--t-hover) var(--ease); }
.hd3-burger:hover { border-color: var(--spark); color: var(--spark); }
@media (max-width: 1080px) {
  .hd3-nav { display: none; }
  .hd3-burger { display: inline-flex; }
  .hd3-right { margin-left: auto; }
}
@media (max-width: 560px) { .hd3-cta { display: none; } }

/* on pages without a dark hero the fixed transparent bar needs ground behind
   it immediately; JS adds .solid when the page top is light */
.hd3.solid { background: var(--ground); }

/* ---------- the drawer ---------- */
.drw3-scrim { position: fixed; inset: 0; background: color-mix(in srgb, var(--ink) 62%, transparent); opacity: 0; pointer-events: none; transition: opacity var(--t-release) var(--ease); z-index: 1000; }
.drw3-scrim.show { opacity: 1; pointer-events: auto; }
.drw3 { position: fixed; top: 0; right: 0; bottom: 0; width: min(320px, 88vw); background: var(--ground); z-index: 1001; transform: translateX(105%); transition: transform var(--t-release) var(--ease); display: flex; flex-direction: column; padding: 18px 20px; overflow-y: auto; }
.drw3.open { transform: none; }
.drw3-h { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.drw3-h b { font-family: var(--font-display); color: var(--paper); font-size: 17px; }
.drw3-h .dot { color: var(--spark); }
.drw3-h button { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; background: none; border: 0; color: var(--dim-d); font-size: 26px; cursor: pointer; line-height: 1; transition: color var(--t-hover) var(--ease); }
.drw3-h button:hover { color: var(--spark); }
.drw3 nav { display: flex; flex-direction: column; gap: 2px; }
/* Drawer links join the hover family: spark ink and a 2px step toward the
   pointer on --t-hover. Spark is 5.6:1 on the Midnight panel, legal as type.
   The CTA opts out; it carries the header CTA treatment below instead. */
.drw3 nav a { color: var(--paper); text-decoration: none; font-size: 15px; font-weight: 600; padding: 9px 10px; border-radius: var(--r-sm); transition: color var(--t-hover) var(--ease), background var(--t-hover) var(--ease), transform var(--t-hover) var(--ease); }
.drw3 nav a:not(.drw3-cta):hover { background: var(--hairline-d); color: var(--spark); transform: translateX(2px); }
.drw3 nav a.drw3-sub { font-size: 13.5px; font-weight: 500; color: var(--dim-d); padding: 7px 10px 7px 22px; }
.drw3-label { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--dim-d); margin: 14px 10px 4px; }
/* The drawer CTA is the header CTA, full width (2026-08-25 rollout): same
   spark fill, same white bold label per DJ's CTA ruling, same star glyph on
   the 9s loop, and the same hover that empties the fill into the glowing
   spark outline. One button, two widths. The compound selector outranks the
   .drw3 nav a rules above, which is what the old !importants were fighting. */
.drw3 nav a.drw3-cta { margin-top: 18px; min-height: 44px; display: flex; align-items: center; justify-content: center; gap: 8px; background: var(--spark); color: var(--paper); text-align: center; border-radius: var(--pill); font-weight: 700; border: 1px solid transparent; transition: background var(--t-hover) var(--ease), color var(--t-hover) var(--ease), border-color var(--t-hover) var(--ease), box-shadow var(--t-hover) var(--ease); }
.drw3-cta .cta-glyph { display: inline-flex; animation: ctaSpin 9s linear infinite; }
.drw3-cta .cta-glyph svg { display: block; transition: transform var(--t-hover) var(--ease), color var(--t-hover) var(--ease); }
.drw3 nav a.drw3-cta:hover { background: transparent; border-color: var(--spark); color: var(--spark); box-shadow: 0 0 0 1px var(--spark), 0 0 16px color-mix(in srgb, var(--spark) 55%, transparent), 0 0 34px color-mix(in srgb, var(--spark) 25%, transparent); }
.drw3-cta:hover .cta-glyph svg { transform: scale(1.18); }
.drw3-f { margin-top: auto; padding-top: 20px; font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .1em; color: var(--dim-d); }
/* site.css draws every focus ring in Surface Steel, which is invisible on the
   Midnight ground its dark-chrome list corrects for — a list written for the
   v2 shell (.hd, .ft) that never learned the v3 names. The header and the
   drawer are that same dark ground, so they take the same True North ring. */
.hd3 :focus-visible, .drw3 :focus-visible { outline-color: var(--spark); }

/* ---------- the hero (home) ---------- */
/* The only gradient this system has is The Surface and its flat fallback, so
   the hero band uses --grad-ground and does not invent a second one. */
/* THE FRAME IS VIEWPORT-AWARE (2026-08-26 hero rebuild). It was 150px over
   92px of fixed padding, which put the section at 963px on a 1440x900 screen
   and pushed the sub-nav and the marquee below the fold on load: roughly
   430px of frame around 530px of content. Padding in vh compresses itself on
   a short laptop instead of overflowing, and the clamp floors keep it from
   collapsing on a phone. margin-top stays at -72px: that is what tucks the
   section under the fixed header, and moving it opens a gap on every load. */
.hero3 { position: relative; margin-top: -72px; padding-block: clamp(64px, 9vh, 104px) clamp(40px, 6vh, 56px); padding-inline: 0; background: var(--grad-ground); color: var(--paper); overflow: hidden; }
.hero3-fx { position: absolute; inset: 0; z-index: 0; }
.hero3-fx canvas { width: 100%; height: 100%; display: block; }
.hero3-scrim { position: absolute; inset: 0; pointer-events: none; background: radial-gradient(ellipse 62% 72% at 30% 52%, color-mix(in srgb, var(--ink) 58%, transparent), transparent 74%); }
.hero3-wrap { position: relative; z-index: 2; max-width: 1180px; margin: 0 auto; padding: 0 28px; }
.glass3 { text-align: center; padding: 32px 44px 30px; border-radius: var(--r-lg); background: color-mix(in srgb, var(--ink) 38%, transparent); border: 1px solid var(--hairline-d); box-shadow: var(--sh-md); -webkit-backdrop-filter: var(--blur-2); backdrop-filter: var(--blur-2); }
/* 168px was the single largest element in the hero and the one visible cut
   the shrink asks for. 116px still reads as a portrait (DJ's call, 2026-08-26)
   and returns 52px of the budget, which is what buys keeping the headline at
   full size. */
/* 133px is 116 +15%, DJ 2026-08-26. */
.hero3-ava { width: 133px; height: 133px; border-radius: 50%; object-fit: cover; border: 3px solid var(--dim-d); box-shadow: 0 0 0 6px var(--hairline-d); margin: 0 auto 16px; display: block; }
/* The eyebrow on dark is True North. 5.6:1 on Midnight Green. */
.hero3-kicker { font-family: var(--font-mono); font-size: 12px; font-weight: 600; letter-spacing: .3em; text-transform: uppercase; color: var(--spark); margin: 0 0 12px; }
/* Was a white-to-Sea-Glass gradient across the name. v3 allows no gradient
   between brand colours, and colour treatment 02 is explicit: on a dark
   ground the wordmark goes to Paper White. 15.8:1, flat, no clip. */
.hero3 h1.grad3 { font-family: var(--font-display); font-weight: 900; font-size: clamp(38px, 6vw, 72px); letter-spacing: -.02em; line-height: 1.04; margin: 0 0 18px; color: var(--paper); }
.hero3-sub { font-size: clamp(15px, 1.6vw, 18px); line-height: 1.65; color: var(--dim-d); max-width: 760px; margin: 0 auto 18px; }
.hero3-sub b { color: var(--paper); }
/* The credential beat. 2026-08-25 copy pass: the hero sub was one 73-word
   block that opened with the positioning and closed with the seven years of
   marketing behind it. Smart Brevity's fix for a wall is not only fewer words,
   it is chunking, so the credential is its own line, set one step quieter so
   it reads as the footnote to the claim above rather than a second claim. */
.hero3-cred { font-size: clamp(13.5px, 1.35vw, 15.5px); color: color-mix(in srgb, var(--dim-d) 82%, transparent); max-width: 620px; margin-top: -8px; }
.hero3-ctas { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
@media (max-width: 620px) { .glass3 { padding: 28px 22px 26px; border-radius: var(--r); } .hero3 { padding: 120px 0 64px; } }

/* ---------- the proof marquee ---------- */
.pmq { background: var(--ground); border-top: 1px solid var(--hairline-d); border-bottom: 1px solid var(--hairline-d); overflow: hidden; padding: 16px 0; position: relative; z-index: 2; }
.pmq-track { display: flex; gap: 12px; width: max-content; animation: pmq-roll 56s linear infinite; }
.pmq:hover .pmq-track { animation-play-state: paused; }
@keyframes pmq-roll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.pmq-chip { display: inline-flex; align-items: baseline; gap: 8px; white-space: nowrap; font-family: var(--font-mono); font-size: 12px; letter-spacing: .06em; color: var(--dim-d); border: 1px solid var(--hairline-d); background: transparent; border-radius: var(--pill); padding: 9px 16px; }
.pmq-chip b { font-family: var(--font-display); font-size: 15px; letter-spacing: 0; color: var(--spark); font-variant-numeric: tabular-nums; }
@media (prefers-reduced-motion: reduce) { .pmq-track { animation: none; flex-wrap: wrap; width: auto; padding: 0 20px; } }

/* ---------- build/adoption two-up under the hero ---------- */
/* THE TWO PILLARS (DJ's 2026-08-25 redesign: the white cards read as
   underwhelming). Midnight feature panels echoing the hero against the
   light band, each with the star glyph as a corner watermark that ignites
   spark on hover, a spark kicker, its own proof stat, and an arrow that
   finally moves. The hover joins the spark-glow family the header CTA and
   hero pair established. */
.duo3 { max-width: 1180px; margin: 56px auto 0; padding: 0 28px; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); gap: 18px; }
.duo3 a { position: relative; overflow: hidden; display: flex; flex-direction: column; background: var(--ground); border: 1px solid var(--hairline-d); border-radius: var(--r); padding: 32px 30px; text-decoration: none; color: var(--paper); box-shadow: var(--sh-sm); transition: border-color var(--t-hover) var(--ease), transform var(--t-hover) var(--ease), box-shadow var(--t-hover) var(--ease); }
.duo3 a .kicker { color: var(--spark); }
.duo3 a > p { color: var(--dim-d); max-width: 46ch; }
.duo3 a:hover { transform: translateY(-2px); border-color: var(--spark); box-shadow: 0 0 0 1px var(--spark), 0 0 16px color-mix(in srgb, var(--spark) 45%, transparent), 0 0 34px color-mix(in srgb, var(--spark) 20%, transparent); }
.duo3 h2 { font-family: var(--font-display); font-size: 23px; margin: 6px 0 8px; color: var(--paper); }
.duo3-stat { font-family: var(--font-mono); font-size: 12px; letter-spacing: .04em; margin-top: 14px; }
.duo3-stat b { color: var(--spark); font-weight: 600; }
.duo3 .go3 { margin-top: auto; padding-top: 16px; font-weight: 700; font-size: 13px; color: var(--paper); display: inline-flex; align-items: center; gap: 6px; transition: gap var(--t-hover) var(--ease), color var(--t-hover) var(--ease); }
.duo3 .go3 .ar { font-style: normal; }
.duo3 a:hover .go3 { gap: 12px; color: var(--spark); }
.duo3-glyph { position: absolute; right: -30px; bottom: -30px; color: var(--paper); opacity: .07; pointer-events: none; transition: color var(--t-release) var(--ease), opacity var(--t-release) var(--ease), transform var(--t-release) var(--ease); }
.duo3 a:hover .duo3-glyph { color: var(--spark); opacity: .2; transform: rotate(45deg) scale(1.05); }
/* The spark twin (DJ's ruling: one card orange, one Midnight). Adoption is
   the value layer, so it takes True North; the label colors follow the CTA
   ruling — white display type, ink working text — and the hover swaps the
   glyph and arrow to paper instead of spark, since the ground already is. */
.duo3 a.duo3-spark { background: var(--spark-surface); border-color: transparent; }
.duo3 a.duo3-spark .kicker { color: var(--ink); }
.duo3 a.duo3-spark > p { color: color-mix(in srgb, var(--ink) 86%, var(--spark)); }
.duo3 a.duo3-spark h2 { color: var(--paper); }
.duo3 a.duo3-spark .duo3-stat b { color: var(--ink); }
.duo3 a.duo3-spark .go3 { color: var(--ink); }
.duo3 a.duo3-spark .duo3-glyph { color: var(--ink); opacity: .1; }
.duo3 a.duo3-spark:hover { border-color: var(--paper); }
.duo3 a.duo3-spark:hover .go3 { color: var(--paper); }
.duo3 a.duo3-spark:hover .duo3-glyph { color: var(--paper); opacity: .24; }

/* generic content cushion: content never touches the footer */
.shell3 main > section:last-child, .shell3 main > .section:last-child { padding-bottom: 110px; }

/* catalog cards (websites page) */
.cat3 { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(250px, 100%), 1fr)); gap: 14px; margin-top: 22px; }
.cat3 a, .cat3 div.cat3-cell { background: var(--card); border: 1px solid var(--hairline); border-radius: var(--r); padding: 18px 18px 16px; text-decoration: none; color: inherit; display: flex; flex-direction: column; gap: 6px; transition: border-color var(--t-hover) var(--ease), transform var(--t-hover) var(--ease), box-shadow var(--t-hover) var(--ease); }
.cat3 a:hover { transform: translateY(-2px); border-color: var(--spark); box-shadow: 0 0 0 1px var(--spark), 0 0 14px color-mix(in srgb, var(--spark) 30%, transparent); }
.cat3 .t { font-family: var(--font-display); font-weight: 700; font-size: 15.5px; }
.cat3 .d { font-size: 12.5px; color: var(--muted); margin: 0; }
.cat3 .u { font-family: var(--font-mono); font-size: 10.5px; color: var(--faint); margin-top: auto; padding-top: 8px; word-break: break-all; }

/* video facade (Hide In Plain Sight) */
/* width:100% is load-bearing (2026-08-27). This is a <button>, and a button
   sizes shrink-to-fit no matter what display it is given. Its only child is
   position:absolute, so it contributed no in-flow width either: the facade
   rendered 14 x 8 pixels inside a 522px cell on both pages that use it, which
   clipped away the 74px play disc, the label and the line under it, broke the
   44px hit-target floor, and left about 500px of dark band reading as empty. */
.vid3 { position: relative; display: block; width: 100%; border-radius: var(--r); overflow: hidden; background: var(--ground); aspect-ratio: 16/9; border: 1px solid var(--hairline); cursor: pointer; padding: 0; text-align: inherit; font: inherit; }
.vid3 .vid3-inner { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; color: var(--paper); text-align: center; padding: 20px; }
/* A True North fill on a dark ground: legal, and the glow it used to carry is
   not — depth in this system comes from hairlines, never from a halo. */
.vid3 .vid3-play { width: 74px; height: 74px; border-radius: 50%; background: var(--spark); display: grid; place-items: center; box-shadow: var(--sh-md); transition: transform var(--t-hover) var(--ease); }
.vid3:hover .vid3-play { transform: translateY(-2px); }
.vid3 iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* THE HERO PAIR (DJ's 2026-08-25 ruling). Left, the Paper Primary: a white
   pill with a bold Midnight label whose hover is a light switch — spark
   fill, white label, lift, glow. Right, the Inverse Twin: a ghost that
   fills with spark on hover. Label colors are set explicitly on every
   state because the global link hover (Steel to ink) otherwise outranks
   the button and inks the label into its own fill — the vanishing-text
   bug this block also fixes. The glow is the owner's sanctioned exception
   to the no-halo rule, scoped to the spark hover family. */
.hero3-ctas .btn { background: var(--paper); color: var(--ink); font-weight: 700; border: 1px solid transparent; transition: background var(--t-hover) var(--ease), color var(--t-hover) var(--ease), border-color var(--t-hover) var(--ease), box-shadow var(--t-hover) var(--ease), transform var(--t-press) var(--ease); }
.hero3-ctas .btn:hover { background: var(--spark); color: var(--paper); border-color: transparent; transform: translateY(-1px); box-shadow: 0 0 0 1px var(--spark), 0 0 16px color-mix(in srgb, var(--spark) 55%, transparent), 0 0 34px color-mix(in srgb, var(--spark) 25%, transparent); }
.hero3-ctas .btn.quiet { background: transparent; color: var(--paper); border-color: var(--hairline-d); }
.hero3-ctas .btn.quiet:hover { background: var(--spark); color: var(--paper); border-color: var(--spark); transform: translateY(-1px); box-shadow: 0 0 0 1px var(--spark), 0 0 16px color-mix(in srgb, var(--spark) 55%, transparent), 0 0 34px color-mix(in srgb, var(--spark) 25%, transparent); }

/* ============================================================ v3.1 =======
   DJ's review round: hover dropdowns, the hero identity block, and three
   sections rebuilt as designed components.
   ======================================================================== */

/* ---- nav: hover, not click. The 8px gap between the button and the panel
   was a dead zone that closed the menu on the way down; the panel now owns
   that space as transparent padding, so the pointer never leaves the group. */
.h3dd { top: 100%; padding: 10px 8px 8px; background: transparent; border: 0; box-shadow: none; display: block; opacity: 0; visibility: hidden; transform: translateY(-4px); transition: opacity var(--t-hover) var(--ease), transform var(--t-hover) var(--ease), visibility var(--t-hover); }
.h3dd-in { display: flex; flex-direction: column; background: color-mix(in srgb, var(--ink) 97%, transparent); -webkit-backdrop-filter: var(--blur-2); backdrop-filter: var(--blur-2); border: 1px solid color-mix(in srgb, var(--paper) 18%, transparent); border-radius: 12px; box-shadow: 0 18px 44px color-mix(in srgb, var(--ink) 50%, transparent); padding: 8px; }
.h3grp:hover .h3dd, .h3grp:focus-within .h3dd, .h3grp.open .h3dd { opacity: 1; visibility: visible; transform: none; }
@media (hover: hover) { .h3grp:hover .h3dd { opacity: 1; visibility: visible; transform: none; } }
.h3grp > button { display: inline-flex; align-items: center; gap: 5px; }
.h3grp:hover .car { transform: rotate(180deg); }
.h3grp .car { display: inline-block; transition: transform var(--t-hover) var(--ease); }

/* ---- hero identity block ---- */
.hero3-kicker { text-align: center !important; }
/* THE SHINE SWEEP (2026-08-26, reactbits shiny-text). Written as an
   enhancement rather than an override on purpose: the base rule above keeps
   `color: var(--spark)`, and only a browser that actually supports
   background-clip:text ever makes the text transparent. Reversed, the
   fallback is invisible text, which is the worst failure mode this file has.

   CONTRAST FLOOR, NON-NEGOTIABLE. The darkest stop in the gradient IS
   var(--spark), the colour this label already was, and the sweep only ever
   travels toward Paper White. So every frame measures at or above the
   ratio the solid version shipped with, and 12px type never dips under it
   mid-animation. Shining toward the ground instead would have looked the
   same in a screenshot and failed AA in motion. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .hero3-kicker {
    background-image: linear-gradient(100deg,
      var(--spark) 0%,
      var(--spark) 40%,
      color-mix(in srgb, var(--paper) 70%, var(--spark)) 50%,
      var(--spark) 60%,
      var(--spark) 100%);
    background-size: 220% 100%;
    background-repeat: no-repeat;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
    animation: kickerShine 3.6s linear infinite;
  }
}
/* THE SWEEP MUST NEVER LEAVE THE TEXT. This ran 120% to -120%, and that is
   why the kicker came and went: the text is transparent and painted only by
   this background, so the moment the 220%-wide image slid past the element
   there was nothing left to clip and the label vanished until the next pass.
   For a background wider than its box, 0% and 100% are the two positions
   where the image still covers the box completely, so the travel is clamped
   to that range. The highlight still crosses the full label, because at 100%
   it sits just off the left edge and at 0% just off the right. Same sweep,
   nothing disappears. */
@keyframes kickerShine { from { background-position: 100% 0; } to { background-position: 0% 0; } }
@media (prefers-reduced-motion: reduce) {
  .hero3-kicker { background-image: none; color: var(--spark); -webkit-text-fill-color: var(--spark); animation: none; }
}
.hero3 h1.grad3 { text-align: center; margin-bottom: 10px; font-size: clamp(36px, 5.4vw, 66px); }
.hero3-line { font-family: var(--font-display); font-weight: 700; font-size: clamp(19px, 2.5vw, 30px); line-height: 1.25; color: var(--paper); text-align: center; max-width: 22ch; margin: 0 auto 14px; letter-spacing: -.01em; }
/* THE ROTATION (2026-08-26). Five lines type and delete in place, so the box
   has to be tall enough for the longest one BEFORE it arrives, or the hero
   jumps on every cycle and takes CLS with it.

   The three reservations are MEASURED off the built page, not estimated, and
   they differ because the line box does: 22ch caps it at 249px on a normal
   phone, but under roughly 355px the viewport squeezes it below that cap and
   "I turn company knowledge into something AI can use." goes from two rows to
   three. Reserving three rows everywhere would have been safe and would have
   wasted 23px on the breakpoint where the hero is already tallest, so each
   band gets exactly what its longest line needs.
     under 375px  three rows  (longest line 71px, the rest 48px)
     375 to 699   two rows    (all five lines 48px)
     700 and up   one row     (the 22ch cap lifts, everything fits on one)

   The caret is a 1px block on its own blink timer, inside the aria-hidden
   span, so nothing announces it. */
.hero3-line { min-height: calc(3 * 1.25em); }
@media (min-width: 375px) { .hero3-line { min-height: calc(2 * 1.25em); } }
@media (min-width: 700px) { .hero3-line { min-height: calc(1 * 1.25em); } }
.tl-caret { display: inline-block; width: 1px; height: .95em; margin-left: 3px; vertical-align: -.08em; background: var(--spark); animation: tlBlink 1s step-end infinite; }
@keyframes tlBlink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
/* Reduced motion removes the movement rather than shortening it: typeline.js
   returns before it touches the DOM, so line one stays, and the caret goes
   with the animation it belongs to. */
@media (prefers-reduced-motion: reduce) { .tl-caret { display: none; } }
.hero3-sub { text-align: center; }
.hero3-id { margin: 22px 0 0; font-family: var(--font-mono); font-size: 11.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--dim-d); text-align: center; font-variant-numeric: tabular-nums; }
.hero3-id span { color: var(--spark); margin: 0 6px; }
.br-sm { display: none; }
@media (min-width: 700px) { .br-sm { display: inline; } .hero3-line { max-width: none; } }

/* ---- THE FOUR LAYERS (DJ's 2026-08-25 redesign: the SVG row read as
   static and unbalanced). Layers drawn as an actual stack: four interactive
   rows joined by the formula's own plus marks, a spark connector, and the
   result as a solid True North bar with the spinning star. Hover a layer
   and it fills Midnight and steps forward; hover anywhere in the stack and
   the result bar takes the glow — touching the layers lights the outcome,
   which is the section's whole argument. ---- */
.layers { margin: 34px 0 0; display: flex; flex-direction: column; }
.layer { display: flex; align-items: center; gap: 14px; background: var(--card); border: 1px solid var(--hairline); border-radius: var(--r-sm); padding: 18px 26px; transition: background var(--t-hover) var(--ease), border-color var(--t-hover) var(--ease), transform var(--t-hover) var(--ease); }
.layer > div { flex: 1; display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.layer b { font-family: var(--font-display); font-weight: 700; font-size: 19px; color: var(--ink); transition: color var(--t-hover) var(--ease); }
.layer-sub { font-family: var(--font-mono); font-size: 14.5px; color: var(--muted); transition: color var(--t-hover) var(--ease); }
.layer-star { display: inline-flex; color: var(--chrome); transition: color var(--t-hover) var(--ease), transform var(--t-release) var(--ease); }
.layer:hover { background: var(--ground); border-color: var(--ground); transform: translateX(6px); }
.layer:hover b { color: var(--paper); }
.layer:hover .layer-sub { color: var(--spark); }
.layer:hover .layer-star { color: var(--spark); transform: rotate(45deg); }
.layer-plus { text-align: center; font-family: var(--font-mono); font-weight: 600; font-size: 15px; color: var(--faint); margin: 3px 0; line-height: 1; }
.layers-eq { width: 2px; height: 26px; background: var(--spark); margin: 8px auto; }
.layers-result { display: flex; align-items: center; justify-content: center; gap: 10px; background: var(--spark-surface); color: var(--paper); font-family: var(--font-display); font-weight: 700; font-size: 18px; text-align: center; border-radius: var(--pill); padding: 18px 28px; transition: box-shadow var(--t-hover) var(--ease), transform var(--t-hover) var(--ease); }
.layers-result .cta-glyph { display: inline-flex; animation: ctaSpin 9s linear infinite; }
.layers:hover .layers-result { transform: translateY(-1px); box-shadow: 0 0 0 1px var(--spark), 0 0 16px color-mix(in srgb, var(--spark) 55%, transparent), 0 0 34px color-mix(in srgb, var(--spark) 25%, transparent); }
/* max-width:none is load-bearing here, not tidying. The base `p` rule caps
   every paragraph at the measure, so a centered caption was centering inside
   a 66ch box pinned to the left edge rather than inside the section. One
   short line hid it. The longer line this section now carries did not. */
.layers-cap { font-size: var(--step--1); color: var(--muted); text-align: center; margin: 14px auto 0; max-width: none; }

/* ==== THE LAYERS OPEN (2026-08-26, DJ's ask) ==========================
   Each row is a native <details>. Native, not a scripted modal, for three
   reasons that all point the same way: the panel content ships in the HTML
   so the build gate resolves its links and a crawler reads it, the keyboard
   and screen-reader behaviour arrive for free and correct, and with JS
   blocked the rows still open. A modal would have failed the first test,
   which is the one this site actually enforces.

   The summary keeps every .layer style it already had. What changes is the
   marker (the browser's triangle is replaced by a + that becomes an x on
   open) and the corners, which square off while a row is open so the panel
   below reads as the same object rather than a second one. */
.layer-d { display: block; }
.layer-d > summary { cursor: pointer; list-style: none; }
.layer-d > summary::-webkit-details-marker { display: none; }
.layer-d > summary::marker { content: ''; }
.layer-more {
  flex: 0 0 auto; font-family: var(--font-mono); font-size: 17px; font-weight: 600;
  line-height: 1; color: var(--faint); margin-left: var(--sp-2);
  transition: transform var(--t-release) var(--ease), color var(--t-hover) var(--ease);
}
.layer:hover .layer-more { color: var(--spark); }
.layer-d[open] > .layer .layer-more { transform: rotate(45deg); color: var(--spark); }
/* The lift is a hover affordance for a closed row. An open row is already
   the thing you chose, so it stays still and lets the panel be the motion. */
.layer-d[open] > .layer { border-radius: var(--r-sm) var(--r-sm) 0 0; background: var(--ground); border-color: var(--ground); transform: none; }
.layer-d[open] > .layer b { color: var(--paper); }
.layer-d[open] > .layer .layer-sub { color: var(--spark); }
.layer-d[open] > .layer .layer-star { color: var(--spark); transform: rotate(45deg); }
.layer-d[open] > .layer:hover { transform: none; }

.layer-body {
  background: var(--ground); color: var(--dim-d);
  border: 1px solid var(--ground); border-top: 0;
  border-radius: 0 0 var(--r-sm) var(--r-sm);
  padding: var(--sp-1) var(--sp-5) var(--sp-5);
  animation: layerOpen var(--t-release) var(--ease);
}
.layer-body p { max-width: none; font-size: 14.5px; line-height: 1.62; }
.layer-body .starlist { margin: var(--sp-4) 0; }
.layer-body .starlist li { color: var(--paper); font-size: 14px; }
.layer-body .starlist li::before { background: var(--spark); }
.layer-go { margin: 0; }
.layer-go a { color: var(--spark); font-family: var(--font-mono); font-size: 12.5px; letter-spacing: .06em; text-transform: uppercase; text-decoration: none; border-bottom: 1px solid color-mix(in srgb, var(--spark) 45%, transparent); padding-bottom: 2px; transition: color var(--t-hover) var(--ease), border-color var(--t-hover) var(--ease); }
.layer-go a:hover { color: var(--paper); border-bottom-color: var(--paper); }
@keyframes layerOpen { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }

/* The result pill opens too, and it is already spark, so its panel inverts:
   midnight body under an orange head, with the pill corners squared on open
   the same way the rows are. */
.layer-d--result[open] > .layers-result { border-radius: var(--r-lg) var(--r-lg) 0 0; }
.layer-d--result > summary .layer-more { color: color-mix(in srgb, var(--ink) 70%, var(--spark)); }
.layer-d--result[open] > summary .layer-more { color: var(--paper); }
.layer-d--result .layer-body { border-radius: 0 0 var(--r-lg) var(--r-lg); padding-inline: var(--sp-6); }
@media (prefers-reduced-motion: reduce) { .layer-body { animation: none; } }
@media (prefers-reduced-motion: reduce) { .layers-result .cta-glyph { animation: none; } }

/* ---- THE SPARK BAND (DJ's 2026-08-25 ruling): the one full True North
   band on the homepage, carrying the Company OS statement. The gradient and
   the grain are the owner's deliberate exceptions to the one-gradient law,
   scoped to this class. Gradient stays inside the spark family via
   color-mix; the grain is an inline feTurbulence SVG at 5%, so no asset and
   no request. Buttons on this ground: solid Midnight with a paper-glow
   hover, and a ghost that fills Midnight. ---- */
/* Re-tuned 2026-08-26, DJ's call: the old first stop was only 70% True North
   and the corner read brown, not brand. The band now OPENS on pure spark and
   deepens toward midnight-mixed spark, so the muddying runs away from the
   corner the eye lands on. The deepening is not decoration: it is what holds
   Paper White at the large-text floor across the headline's zone, and if the
   headline ever dips under 3:1 the fix is deeper end stops, never a darker
   corner and never reverting the white headline (his ruling, same as the
   header CTA). */
/* Flat, DJ's call 2026-08-27. The gradient was there to hold Paper White at
   3:1 by deepening toward midnight, and it bought that legibility with the
   muddy gold corner he objected to. --spark-surface holds the same white at
   3.05:1 without any deepening at all, so the band can be one flat vivid
   value and match the duo card it sits above. The grain stays. */
.band-spark { position: relative; background: var(--spark-surface); }
.band-spark::before { content: ''; position: absolute; inset: 0; pointer-events: none; opacity: .05; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); }
.band-spark .wrap { position: relative; }
.band-spark .kicker { color: var(--ink); }
.band-spark .headline { color: var(--paper); }
/* ONE COLOUR FOR EVERY WORD ON THIS BAND (DJ's call, 2026-08-27).

   This used to be three rules. Body copy took a steel-and-midnight mix so it
   would read as the palette's blue against the orange, bold words took pure
   Midnight, and a third rule caught paragraphs with no bold in them. DJ
   looked at the result and said the bold was a different colour from the
   text around it, which it was: #184c51 beside #00272C in the same sentence.

   The measurement agreed with his eye. On this band the steel mix runs
   3.14:1, under the 4.5:1 body floor, while Midnight runs 5.19:1. So the
   colour that looked wrong was also the one that failed, and collapsing to
   Midnight fixes the appearance and the contrast in the same edit.

   Emphasis is carried by weight alone now, which is what <strong> is for.
   The earlier note that "nothing legible sits at 4.5 on saturated orange"
   was true of the old gradient's deep corner; the band is flat now, so
   Midnight clears the floor everywhere on it. */
.band-spark p { color: var(--ink); }
.band-spark .btn { background: var(--ground); color: var(--paper); border: 1px solid transparent; }
.band-spark .btn:hover { background: var(--ground); color: var(--paper); border-color: var(--paper); transform: translateY(-1px); box-shadow: 0 0 0 1px var(--paper), 0 0 16px color-mix(in srgb, var(--paper) 40%, transparent); }
/* The quiet button is the hero's "Walk the live demo" button, adapted for
   this ground. Resting label is ink, not white, because white on the
   deepened orange is roughly 3.2:1 and a button label is small text that
   owes 4.5:1. The border lifts to 55% so the hairline reads at the hero's
   weight against a busier ground. The hover moved twice on 2026-08-26:
   first to a midnight fill (spark would vanish on a spark band), then to
   DJ's final call, a paper fill with a spark label, which is the rule
   below. */
.band-spark .btn.quiet { background: transparent; color: var(--ink); border-color: color-mix(in srgb, var(--ink) 55%, transparent); }
/* Hover flipped from midnight-fill to paper-fill with a spark label, DJ's
   2026-08-26 call. Spark on white is 2.85:1 for a small bold label; shipped
   on his ruling, the same one the header CTA carries. */
.band-spark .btn.quiet:hover { background: var(--paper); color: var(--spark); border-color: transparent; transform: translateY(-1px); box-shadow: 0 0 0 1px var(--paper), 0 0 16px color-mix(in srgb, var(--paper) 55%, transparent), 0 0 34px color-mix(in srgb, var(--paper) 25%, transparent); }

/* ==== THE DEEP STEEL BAND ==================================================
   Built 2026-08-26 as the homepage closer's ground; DJ chose spark for the
   closer the same day, so nothing wears this band right now. It stays: it is
   the designed deep-steel variant the other pages' closers can take without
   re-deriving it, and white measures 7.4:1 on its lightest stop.
   -------------------------------------------------------------------------
   The homepage closer was the page's third band-dark and it abutted the
   band-dark seal directly above it, so the two read as one continuous dark
   region and the closer disappeared into it. This is the closer's own
   ground: Surface Steel at full depth, the same gradient-plus-grain recipe
   the other bands wear so it belongs to the family. NOT the same thing as
   .band-steel in site.css, which is a 14% LIGHT wash for section rhythm;
   this one is a dark ground and carries the full dark-band treatment set.
   Landfall and Meridian were considered and refused: both are signal-bound
   and a large field of either breaks the published law.
   White on pure Surface Steel is 7.4:1 (the Brand OS's own figure) and the
   gradient only deepens from there, so Paper type needs no compromise.
   Spark fails on this ground (about 2.6:1), which is why the kflag and the
   links here are Paper, not the spark they wear on Midnight. Every hover
   below DECLARES its color: see the specificity note at
   .band-dark .btn:hover in site.css before assuming that is redundant. */
.band-steel-deep { position: relative; color: var(--paper); background: linear-gradient(135deg, var(--chrome) 0%, color-mix(in srgb, var(--chrome) 90%, var(--ink)) 45%, color-mix(in srgb, var(--chrome) 78%, var(--ink)) 100%); }
.band-steel-deep::before { content: ''; position: absolute; inset: 0; pointer-events: none; opacity: .05; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); }
.band-steel-deep .wrap { position: relative; }
.band-steel-deep h2, .band-steel-deep h3, .band-steel-deep .headline { color: var(--paper); }
.band-steel-deep .kflag, .band-steel-deep .kflag svg { color: var(--paper); }
.band-steel-deep .kflag::after { background: color-mix(in srgb, var(--paper) 30%, transparent); }
.band-steel-deep p, .band-steel-deep .lede { color: color-mix(in srgb, var(--paper) 85%, transparent); }
.band-steel-deep a { color: var(--paper); }
.band-steel-deep a:hover { color: var(--paper); }
.band-steel-deep .btn { background: var(--paper); color: var(--ink); border: 1px solid transparent; }
.band-steel-deep .btn:hover { background: var(--paper); color: var(--ink); border-color: var(--spark); transform: translateY(-1px); box-shadow: 0 0 0 1px var(--spark), 0 0 16px color-mix(in srgb, var(--spark) 45%, transparent); }
.band-steel-deep .btn.quiet { background: transparent; color: var(--paper); border-color: color-mix(in srgb, var(--paper) 45%, transparent); }
.band-steel-deep .btn.quiet:hover { background: var(--paper); color: var(--ink); border-color: var(--paper); transform: translateY(-1px); box-shadow: 0 0 0 1px var(--paper), 0 0 16px color-mix(in srgb, var(--paper) 40%, transparent); }


/* ==================================================== homepage audit ====
   DJ's 2026-08-25 homepage audit round: the LLM-style sub-nav with
   scrollspy, kicker flags that actually pop, the arc timeline, work-card
   data-thumbs, and the gate seal strip. All new components live here.
   ======================================================================== */

/* The section bar. Sticky under the fixed header; the links are real
   anchors, subnav.js only paints the active state. */
/* Opaque ground (2026-08-27). At 72% ink this was tuned as if it sits on
   Midnight, but it sits AFTER the hero, so for most of the scroll it
   composited over light page content to about rgb(67,97,101): idle links
   measured 3.95:1 and the ACTIVE link, the one item whose entire job is to
   say where you are, measured 2.34:1. Measured on all four subnav pages.
   An opaque ink ground makes the published Midnight ratios the real ones. */
.subnav { position: sticky; top: 56px; z-index: 900; background: var(--ink); -webkit-backdrop-filter: var(--blur-1); backdrop-filter: var(--blur-1); border-bottom: 1px solid var(--hairline-d); }
.subnav-in { max-width: 1280px; margin: 0 auto; padding: 0 28px; display: flex; gap: 4px; overflow-x: auto; }
.subnav a { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--dim-d); padding: 11px 12px; text-decoration: none; border-bottom: 2px solid transparent; transition: color var(--t-hover) var(--ease), border-color var(--t-hover) var(--ease); white-space: nowrap; }
/* Hover is the steel family lifted for the dark bar (2026-08-25 role-bound
   colors): a resting-structure hover distinct from the spark active state. */
.subnav a:hover { color: color-mix(in srgb, var(--chrome) 30%, var(--paper)); }
.subnav a.on { color: var(--spark); border-bottom-color: var(--spark); }
section[id] { scroll-margin-top: 118px; }

/* The kicker flag: glyph, spark label, and a rule running out to the right.
   The section's opening gesture, distinct from every other mono label. */
.kflag { display: flex; align-items: center; gap: 10px; margin: 0 0 12px; font-family: var(--font-mono); font-size: 11px; font-weight: 600; letter-spacing: .2em; text-transform: uppercase; color: var(--spark); }
.kflag svg { color: var(--spark); flex: 0 0 auto; }
.kflag span { white-space: nowrap; }
.kflag::after { content: ''; flex: 1; height: 1px; background: color-mix(in srgb, var(--spark) 30%, transparent); }
.band-spark .kflag, .band-spark .kflag svg { color: var(--ink); }
.band-spark .kflag::after { background: color-mix(in srgb, var(--ink) 35%, transparent); }
/* max-width:none is the fix, not the flourish (2026-08-26): the base `p`
   measure cap was boxing this flex row at 66ch of 11px mono, so the label
   centred inside a 435px box pinned to the wrap's left edge. Eleven pages
   use this class; releasing the cap here centres all of them. */
.kflag--center { justify-content: center; max-width: none; margin-inline: auto; }
.kflag--center::after { display: none; }

/* The arc timeline: era chips sitting on a connector line that carries the
   same traveling pulse as the Operating Loop, one register calmer. The
   final era is the spark card: the arc arrives at the brand color. */
.arc { position: relative; margin-top: 40px; }
.arc-line { position: absolute; top: 14px; left: 0; right: 0; height: 2px; background: var(--hairline); }
.arc-line::after { content: ''; position: absolute; top: -1px; left: -8%; width: 72px; height: 4px; border-radius: 2px; background: linear-gradient(90deg, transparent, var(--spark), transparent); animation: railPulse 8s linear infinite; }
@media (max-width: 900px), (prefers-reduced-motion: reduce) { .arc-line { display: none; } }
.arc-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; position: relative; }
@media (max-width: 900px) { .arc-grid { grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)); } .arc-card { margin-top: 0 !important; } .arc-era { margin-top: 0 !important; } }
.arc-card { background: var(--card); border: 1px solid var(--hairline); border-radius: var(--r); padding: 20px 20px 18px; margin-top: 28px; transition: transform var(--t-hover) var(--ease), border-color var(--t-hover) var(--ease), box-shadow var(--t-hover) var(--ease); }
/* display:flex + fit-content, not inline-flex (2026-08-27): the -34px top
   margin is what lifts the era chip out of the card to straddle the timeline
   rail, and it was not moving the box. The rail rendered as a stray hairline
   attached to nothing while a lone pulse animated across empty space on both
   .arc pages. fit-content keeps the pill hugging its own text. */
.arc-era { position: relative; display: flex; width: fit-content; font-family: var(--font-mono); font-size: 11px; letter-spacing: .06em; background: var(--paper); border: 1px solid var(--hairline); border-radius: var(--pill); padding: 4px 12px; margin: -34px 0 12px; color: var(--muted); transition: border-color var(--t-hover) var(--ease), color var(--t-hover) var(--ease); }
.arc-card h3 { font-family: var(--font-display); font-size: 17px; margin: 0 0 6px; }
.arc-card p:last-child { font-size: 14px; color: var(--muted); margin: 0; }
.arc-card:hover { transform: translateY(-2px); border-color: var(--spark); box-shadow: 0 0 0 1px var(--spark), 0 0 14px color-mix(in srgb, var(--spark) 30%, transparent); }
.arc-card:hover .arc-era { border-color: var(--spark); color: var(--ink); }
.arc-spark { background: var(--spark-surface); border-color: transparent; }
.arc-spark .arc-era { background: var(--ink); color: var(--paper); border-color: transparent; }
/* The current era carries the Landfall dot (2026-08-25 role-bound colors):
   this one is running right now. 9.6:1 on the ink chip, and it is a fill. */
.arc-spark .arc-era::before { content: ''; flex: 0 0 auto; width: 7px; height: 7px; border-radius: 50%; background: var(--signal); margin-right: 7px; align-self: center; }
.arc-spark h3 { color: var(--paper); }
.arc-spark p:last-child { color: color-mix(in srgb, var(--ink) 86%, var(--spark)); }
.arc-spark:hover { border-color: var(--paper); }
.arc-spark:hover .arc-era { border-color: var(--paper); color: var(--paper); }

/* Work-card thumbs: an honest visual header per card. Real screenshot
   where one exists; a Midnight data-strip with the ghost glyph and the
   card's own numbers where the work is internal. */
.wcard { overflow: hidden; }
.wthumb { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; aspect-ratio: 16 / 7; background: var(--ground); border-radius: calc(var(--r) - 1px) calc(var(--r) - 1px) 0 0; margin: -22px -22px 16px; }
.wthumb-glyph { display: inline-flex; color: color-mix(in srgb, var(--paper) 20%, transparent); transition: color var(--t-release) var(--ease), transform var(--t-release) var(--ease); }
.wcard:hover .wthumb-glyph { color: var(--spark); transform: rotate(45deg); }
.wthumb-cap { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--dim-d); padding: 0 14px; text-align: center; }
.wthumb-steel { background: var(--chrome); }
.wthumb-conf { background: color-mix(in srgb, var(--ink) 86%, var(--paper)); }
.wthumb-img { padding: 0; overflow: hidden; }
.wthumb-img img { width: 100%; height: 100%; object-fit: cover; object-position: top; display: block; }

/* The gate seal: Verified-Not-Asserted compressed to a stamp. */
.section.seal { padding: 44px 0; }
.seal-in { display: flex; align-items: center; gap: 24px; flex-wrap: wrap; }
.seal-glyph { display: inline-flex; flex: 0 0 auto; color: var(--spark); animation: ctaSpin 14s linear infinite; }
.seal-in > div { flex: 1 1 380px; }
/* The seal's Landfall tick (2026-08-25 role-bound colors): the gates run on
   every build and they are passing right now, which is exactly what the
   Landfall dot means. It breathes on the same livePulse as .badge.live. */
.seal-t::before { content: ''; display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--signal); margin-right: 10px; vertical-align: 2px; animation: livePulse 2.6s var(--ease) infinite; }
@media (prefers-reduced-motion: reduce) { .seal-t::before { animation: none; } }
.seal-t { font-family: var(--font-display); font-weight: 700; font-size: 19px; color: var(--paper); margin: 0 0 4px; }
.seal-s { font-size: 13.5px; color: var(--dim-d); margin: 0; max-width: none; }
.seal .btn { flex: 0 0 auto; }
@media (prefers-reduced-motion: reduce) { .seal-glyph { animation: none; } }

/* ---- the marquee: hover moves the border, and nothing else ---- */
.pmq-chip { transition: border-color var(--t-hover) var(--ease); }
.pmq:hover .pmq-chip { border-color: var(--hairline-d); }
.pmq-chip:hover { border-color: var(--spark); }

/* ---- the diagnosis pair ---- */
/* minmax(min(320px, 100%), 1fr), not minmax(320px, 1fr) (2026-08-27). A bare
   track minimum is a floor the track cannot go under, so at a 320px viewport
   each card stayed 320px wide inside a 280px content box and pushed the whole
   document 20px past the screen. Every other grid in this codebase already
   carries the min(..., 100%) guard; these two were the exceptions. */
.diag { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); gap: 20px; margin-top: 34px; }
/* flex column so the dark block always reaches the card's bottom edge
   (DJ 2026-08-27). The grid already stretched the cards to equal height,
   but the shorter card's .diag-fix stopped early and left a white strip
   under it, so the pair read as mismatched even though they were not.
   .diag-sym takes the slack, which keeps the 22px gap above the block. */
.diag-card { display: flex; flex-direction: column; background: var(--card); border: 1px solid var(--hairline); border-radius: var(--r); padding: 28px 26px 24px; box-shadow: var(--sh-sm); position: relative; overflow: hidden; transition: transform var(--t-hover) var(--ease), box-shadow var(--t-hover) var(--ease), border-color var(--t-hover) var(--ease); }
/* P03: the True North rule at the top is the only accent on the card. It is
   a rule, not type, so it is legal on white. It used to fade out to
   transparent, which made it a gradient; v3 allows one gradient and this is
   not it. */
.diag-card::before { content: ''; position: absolute; inset: 0 0 auto 0; height: 3px; background: var(--spark); }
.diag-card:hover { transform: translateY(-2px); border-color: var(--spark); box-shadow: 0 0 0 1px var(--spark), 0 0 16px color-mix(in srgb, var(--spark) 45%, transparent), 0 0 34px color-mix(in srgb, var(--spark) 20%, transparent); }
.diag-card:hover .diag-fix { border-top-color: var(--spark); }
.diag-card header { display: flex; gap: 16px; align-items: flex-start; }
/* A 40px numeral is type. True North is never type on white at any size, so
   the ghost numeral is a Surface Steel tint instead — the same treatment
   .tri-n already used. */
.diag-n { font-family: var(--font-display); font-weight: 900; font-size: 40px; line-height: 1; color: color-mix(in srgb, var(--primary) 26%, transparent); flex: 0 0 auto; font-variant-numeric: tabular-nums; }
.diag-k { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .18em; text-transform: uppercase; color: var(--primary); margin: 0 0 4px; }
.diag-card h3 { font-family: var(--font-display); font-size: 20px; margin: 0; color: var(--ink); line-height: 1.25; }
.diag-sym { list-style: none; padding: 0; margin: 18px 0 0; flex: 1 0 auto; }
.diag-sym li { position: relative; padding-left: 26px; margin: 8px 0; font-size: 14px; color: var(--muted); }
/* THE STATUS MARKERS (DJ's 2026-08-25 redesign: diagnosis in daylight, fix
   in midnight). The signal-pair dots retired; both lists now carry the star
   glyph as their marker, drawn through a mask so the colour stays a token:
   Surface Steel on the light symptom zone, True North inside the midnight
   fix zone, where spark is legal at any size. The mask data-URI is the
   library glyph's own path (03-icons/djvf-glyph.svg), filled for masking. */
.diag-sym li::before, .diag-fix li::before { content: ''; position: absolute; left: 2px; top: .32em; width: 13px; height: 13px; -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Cpath d='M100 10 L114 86 L190 100 L114 114 L100 190 L86 114 L10 100 L86 86 Z'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Cpath d='M100 10 L114 86 L190 100 L114 114 L100 190 L86 114 L10 100 L86 86 Z'/%3E%3C/svg%3E") center / contain no-repeat; background: var(--chrome); }
/* THE FIX ZONE. The lower half of the card is a midnight panel bled to the
   card's own edges: the card literally darkens where the engineering
   starts. Its top edge ignites spark when the card is hovered. */
.diag-fix { margin: 22px -26px -24px; padding: 20px 26px 22px; background: var(--ground); border-top: 2px solid transparent; border-radius: 0 0 var(--r) var(--r); transition: border-top-color var(--t-hover) var(--ease); }
.diag-fix .diag-k { color: var(--spark); }
.diag-fix ul { list-style: none; padding: 0; margin: 10px 0 0; }
.diag-fix li { position: relative; padding-left: 26px; margin: 8px 0; font-size: 14px; color: var(--paper); font-weight: 500; }
.diag-fix li::before { background: var(--spark); }
.diag-foot { margin-top: 26px; color: var(--muted); max-width: none; }

/* ---- the operating rail ---- */
.rail { list-style: none; display: grid; grid-template-columns: repeat(7, 1fr); gap: 0; margin: 34px 0 0; padding: 0; counter-reset: rail; position: relative; }
/* ---- THE OPERATING LOOP: ONE STEP AT A TIME ---------------------------
   DJ's call 2026-08-27, replacing the single orange bar that slid along the
   rail. Two things were wrong with the bar. It implied a signal moving
   through the pipeline but never told you WHICH step you were looking at,
   and it had to be hidden below 1100px because once the grid wraps, one
   straight track across the top is a lie.

   The per-step highlight has neither problem. It names the step it is on,
   and it works at every width because it never assumes the seven steps sit
   on a single line. Seven steps at three seconds each, so the cycle is 21s
   and each node's delay is its index times three.

   The lit state is deliberately the SAME treatment as :hover. The animation
   teaches the affordance rather than competing with it, and a visitor who
   mouses onto a step sees the thing they were already watching. */
/* railPulse is still live: the Arc timeline on /home/ and /experience/ runs
   a travelling pulse along .arc-line, and that one is correct there because
   the arc IS a single continuous line of time. Only the Operating Loop's
   copy of the effect was replaced. Deleting these keyframes with the loop
   would have silently killed the arc's animation on two pages. */
@keyframes railPulse { from { left: -8%; } to { left: 104%; } }

@keyframes railStepDot {
  0%      { background: var(--ground); border-color: color-mix(in srgb, var(--beacon) 75%, var(--dim-d)); box-shadow: 0 0 0 0 transparent; }
  2%      { background: var(--spark); border-color: var(--spark); box-shadow: 0 0 0 4px color-mix(in srgb, var(--spark) 28%, transparent), 0 0 14px color-mix(in srgb, var(--spark) 60%, transparent); }
  12%     { background: var(--spark); border-color: var(--spark); box-shadow: 0 0 0 4px color-mix(in srgb, var(--spark) 28%, transparent), 0 0 14px color-mix(in srgb, var(--spark) 60%, transparent); }
  14.29%  { background: var(--ground); border-color: color-mix(in srgb, var(--beacon) 75%, var(--dim-d)); box-shadow: 0 0 0 0 transparent; }
  100%    { background: var(--ground); border-color: color-mix(in srgb, var(--beacon) 75%, var(--dim-d)); box-shadow: 0 0 0 0 transparent; }
}
@keyframes railStepNum {
  0%, 14.29%, 100% { color: var(--dim-d); }
  2%, 12%          { color: var(--paper); }
}
.rail-node { position: relative; padding: 34px 16px 20px 0; }
/* --i is the step's place in the order; the delay is --i times three. */
.rail-node { --i: 0; }
.rail-node:nth-child(2) { --i: 1; }
.rail-node:nth-child(3) { --i: 2; }
.rail-node:nth-child(4) { --i: 3; }
.rail-node:nth-child(5) { --i: 4; }
.rail-node:nth-child(6) { --i: 5; }
.rail-node:nth-child(7) { --i: 6; }
.rail-node::after  { animation: railStepDot 21s calc(var(--i) * 3s) infinite both; }
.rail-node .rail-num { animation: railStepNum 21s calc(var(--i) * 3s) infinite both; }
/* Hover outranks the cycle: a pointer on a step wins over the clock. */
.rail-node:hover::after,
.rail-node:hover .rail-num { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .rail-node::after, .rail-node .rail-num { animation: none; }
}
.rail-node > * { transition: transform var(--t-hover) var(--ease); }
.rail-node:hover > * { transform: translateY(-3px); }
.rail-node::before { content: ''; position: absolute; top: 12px; left: 0; right: 0; height: 2px; background: var(--hairline-d); }
.rail-node.is-end::before { right: calc(100% - 13px); }
/* The station dots ride Meridian (2026-08-25 role-bound colors): the loop's
   steps are work in motion, and Meridian is the in-motion color. The spark
   pulse still owns the line; hover still ignites the station. A 12px dot is
   a shape, so the 5.3:1 on Midnight is comfortable. */
.rail-node::after { content: ''; position: absolute; top: 7px; left: 0; width: 12px; height: 12px; border-radius: 50%; background: var(--ground); border: 2px solid color-mix(in srgb, var(--beacon) 75%, var(--dim-d)); transition: background var(--t-hover) var(--ease), border-color var(--t-hover) var(--ease), box-shadow var(--t-hover) var(--ease); }
.rail-node:hover::after { background: var(--spark); border-color: var(--spark); box-shadow: 0 0 0 4px color-mix(in srgb, var(--spark) 28%, transparent), 0 0 14px color-mix(in srgb, var(--spark) 60%, transparent); }
.rail-node:hover .rail-num { color: var(--paper); }
.rail-num { display: block; font-family: var(--font-display); font-weight: 900; font-size: 13px; color: var(--dim-d); letter-spacing: .04em; font-variant-numeric: tabular-nums; }
.rail-key { display: block; font-family: var(--font-mono); font-size: 10px; letter-spacing: .2em; color: var(--spark); margin: 2px 0 8px; }
.rail-node h3 { font-family: var(--font-display); font-size: 15px; color: var(--paper); margin: 0 0 6px; line-height: 1.25; }
.rail-node p { font-size: 12.5px; line-height: 1.55; color: var(--dim-d); margin: 0; }
@media (max-width: 1100px) { .rail { grid-template-columns: repeat(4, 1fr); } .rail-node:nth-child(4)::before { right: calc(100% - 13px); } }
@media (max-width: 720px) { .rail { grid-template-columns: repeat(2, 1fr); } .rail-node:nth-child(2n)::before { right: calc(100% - 13px); } }
@media (max-width: 460px) { .rail { grid-template-columns: 1fr; } .rail-node::before { right: calc(100% - 13px); } }

/* ---- the trust order bar ---- */
/* Was a lighter-midnight fill on a Midnight band. There is no second dark in
   v3 and no "almost midnight" for large areas, so the bar is defined by its
   hairline and holds no fill at all. */
/* THE TRUST ORDER (DJ's 2026-08-25 redesign): a precedence flow, not a
   caption. Four rungs at four weights of presence — a Paper crown carrying
   the spark edge-bar motif, an outlined second, a dim third, then mono
   prose where UNKNOWN itself sparks. Hovering the strip runs a cascade of
   spark down the chevrons, showing which way authority flows. */
.trust { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; margin-top: 34px; background: transparent; border: 1px solid var(--hairline-d); border-radius: var(--r); padding: 18px 22px; transition: border-color var(--t-hover) var(--ease); }
.trust:hover { border-color: color-mix(in srgb, var(--spark) 45%, transparent); }
.trust-l { display: inline-flex; align-items: center; gap: 8px; font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .18em; text-transform: uppercase; color: var(--dim-d); margin-right: 6px; }
.trust-l svg { color: var(--spark); }
.trust-c { font-size: 13.5px; font-weight: 600; padding: 7px 16px; border-radius: var(--pill); transition: transform var(--t-hover) var(--ease), box-shadow var(--t-hover) var(--ease); }
.trust-c:hover { transform: translateY(-1px); }
.trust-c.t1 { background: var(--paper); color: var(--ink); box-shadow: inset 3px 0 0 var(--spark); font-weight: 700; }
.trust-c.t1:hover { box-shadow: inset 3px 0 0 var(--spark), 0 0 14px color-mix(in srgb, var(--spark) 45%, transparent); }
.trust-c.t2 { background: transparent; border: 1px solid color-mix(in srgb, var(--paper) 55%, transparent); color: var(--paper); }
.trust-c.t3 { background: transparent; border: 1px solid var(--hairline-d); color: var(--dim-d); }
.trust-c.t4 { background: none; color: var(--dim-d); font-weight: 500; font-size: 12.5px; font-family: var(--font-mono); padding: 0; }
.trust-c.t4 b { color: var(--spark); font-weight: 600; }
.trust-s { color: var(--dim-d); font-size: 16px; line-height: 1; }
.trust:hover .trust-s { animation: chevIgnite 1.3s var(--ease) infinite; }
.trust:hover .trust-s:nth-of-type(2) { animation-delay: .16s; }
.trust:hover .trust-s:nth-of-type(3) { animation-delay: .32s; }
@keyframes chevIgnite { 0%, 100% { color: var(--dim-d); } 30% { color: var(--spark); } }
@media (prefers-reduced-motion: reduce) { .trust:hover .trust-s { animation: none; } }

/* ---- the three-step cards ---- */
.tri { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr)); gap: 20px; margin-top: 36px; }
.tri-card { position: relative; background: var(--card); border: 1px solid var(--hairline); border-radius: var(--r); padding: 30px 28px 26px; box-shadow: var(--sh-sm); overflow: hidden; transition: transform var(--t-hover) var(--ease), box-shadow var(--t-hover) var(--ease), border-color var(--t-hover) var(--ease); }
.tri-card::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: var(--spark); transform: scaleX(0); transform-origin: left; transition: transform var(--t-release) var(--ease); }
/* Joined to the spark-glow family (2026-08-25 rollout): the tri cards were
   the last light cards still hovering steel-and-shadow. Same ring and bloom
   as .arc-card, so the three-step grid answers the same way the arc does. */
.tri-card:hover { transform: translateY(-2px); border-color: var(--spark); box-shadow: 0 0 0 1px var(--spark), 0 0 14px color-mix(in srgb, var(--spark) 30%, transparent); }
.tri-card:hover::after { transform: scaleX(1); }
.tri-n { position: absolute; top: 10px; right: 18px; font-family: var(--font-display); font-weight: 900; font-size: 84px; line-height: 1; color: color-mix(in srgb, var(--primary) 9%, transparent); pointer-events: none; font-variant-numeric: tabular-nums; }
.tri-k { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .2em; text-transform: uppercase; color: var(--primary); margin: 0 0 6px; }
.tri-card h3 { font-family: var(--font-display); font-size: 20px; margin: 0 0 10px; color: var(--ink); }
.tri-card p:last-child { font-size: 14px; line-height: 1.62; color: var(--muted); margin: 0; }

/* ---- reveal on scroll, sitewide ---- */
/* A reveal is a state change, so it lives inside the 260ms budget. This used
   to run 550ms. Reduced motion removes it entirely rather than slowing it.
   Ambient surfaces (The Surface, the marquee, the rail pulses, the hero's
   rotating line and kicker shine) are exempt per the 2026-08-26 ruling in
   tokens.css. A reveal is not one of them: it fires because you scrolled. */
.rv { opacity: 0; transform: translateY(16px); transition: opacity var(--t-release) var(--ease), transform var(--t-release) var(--ease); }
.rv.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .rv { opacity: 1; transform: none; transition: none; } }

/* The hero's one-line blocks inherit a max-width from the base paragraph
   rule, so centering their TEXT centered it inside a narrow box that still
   sat left. They need the box centered too, not just the text in it. */
.hero3-kicker, .hero3-id { max-width: none !important; margin-left: auto !important; margin-right: auto !important; }
.hero3-sub { margin-left: auto !important; margin-right: auto !important; }

/* ---- inner page heroes ------------------------------------------------
   Every page except the homepage opened on a flat colour band while the
   homepage had depth, so the site read as two designs. These get the same
   treatment at lower volume: the fixed header sits over them (hence the
   negative top margin and the padding that replaces it), a soft radial
   lifts the left side, and a hairline closes the band. No markup changed,
   so all sixteen pages inherit it.

   The closing rule used to fade Sea Glass into Electric Orange across the
   band — a gradient between two brand colours, which v3 forbids outright,
   and one of the two colours no longer exists. It is a hairline now. The
   letterhead law says the same thing about the footer rule: it is a
   hairline, always. */
.shell3 .phero { position: relative; overflow: hidden; margin-top: -72px; padding-top: 72px;
  background: var(--grad-ground); }
.shell3 .phero::before { content: ''; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(ellipse 52% 78% at 12% 30%, color-mix(in srgb, var(--paper) 8%, transparent), transparent 70%); }
.shell3 .phero::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: var(--hairline-d); }
.shell3 .phero-in { position: relative; z-index: 1; }
.shell3 .phero h1 { font-size: clamp(30px, 4.4vw, 50px); line-height: 1.08; }
.shell3 .phero .kicker { letter-spacing: .28em; }
.shell3 .phero .lede { max-width: 68ch; }
/* A hero lede is capped at 68ch by the rule above, which outranks the
   .lede--full utility three classes to one. That is the right default, and it
   is also exactly how a utility class turns into a lie: applied, ignored,
   and nobody can see why. So the utility gets a rule at matching specificity,
   here rather than in site.css because this sheet loads second. Heroes stay
   capped unless someone asks for full width on purpose. */
.shell3 .phero .lede--full { max-width: none; }

/* The 404 keeps the plain band: an error page should not look designed. */
.shell3 .phero.plain::before, .shell3 .phero.plain::after { display: none; }

/* ================================================= shared utilities ====
   The 2026-08-25 sitewide rollout: three generic classes the page modules
   adopt so every page stops hand-rolling its own version of the same three
   ideas. They live here because the shell is the one sheet every page loads.
   ======================================================================== */

/* ---- .starlist: the star-bullet list, generalised ----
   The diagnosis cards drew their markers through a mask so the colour stays
   a token; this is that marker with the card scoping removed. Same data-URI,
   same geometry. Steel on light, spark on the dark band, ink on the spark
   band: the marker is a shape, so every one of those grounds is legal. */
ul.starlist { list-style: none; padding: 0; margin: 18px 0 0; }
.starlist li { position: relative; padding-left: 26px; margin: 8px 0; }
.starlist li::before { content: ''; position: absolute; left: 2px; top: .32em; width: 13px; height: 13px; -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Cpath d='M100 10 L114 86 L190 100 L114 114 L100 190 L86 114 L10 100 L86 86 Z'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Cpath d='M100 10 L114 86 L190 100 L114 114 L100 190 L86 114 L10 100 L86 86 Z'/%3E%3C/svg%3E") center / contain no-repeat; background: var(--chrome); }
.band-dark .starlist li::before { background: var(--spark); }
.band-spark .starlist li::before { background: var(--ink); }

/* ---- .rowlist: the quiet hover for flat link-row pages ----
   Rows drawn by their bottom hairline, not by boxes. Hover recesses the row
   into the band and runs the 3px spark edge down the left, the same edge
   the trust crown wears. No underline, no lift: a row is not a card. */
.rowlist > a, .rowlist > div.cat3-cell { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 14px; padding: 12px 10px; border-bottom: 1px solid var(--hairline); text-decoration: none; color: inherit; transition: background var(--t-hover) var(--ease), box-shadow var(--t-hover) var(--ease); }
.rowlist > a:hover { background: var(--band); box-shadow: inset 3px 0 0 var(--spark); text-decoration: none; }
/* The row typography is the catalog card's own set, re-scoped: /projects/
   moved its groups from the cat3 card grid into these rows, and the t/d/u
   spans must not render unstyled there. The .u keeps its mono but gives up
   the flex-leftover margin, which means nothing in a wrapping row. */
.rowlist .t { font-family: var(--font-display); font-weight: 700; font-size: 15.5px; }
.rowlist .d { font-size: 12.5px; color: var(--muted); margin: 0; }
.rowlist .u { font-family: var(--font-mono); font-size: 10.5px; color: var(--faint); margin: 0; word-break: break-all; }

/* ---- .bandmark: the compass watermark for dark bands ----
   An <img> of the brand compass icon, bled off the bottom-right corner at
   7%, the same register the duo3 glyph rests at. The section opts in with
   .has-mark, which also takes the overflow clip the bleed needs. */
.section.has-mark { position: relative; overflow: hidden; }
.bandmark { position: absolute; right: -30px; bottom: -40px; width: clamp(140px, 18vw, 220px); height: auto; opacity: .07; pointer-events: none; }

/* ==== THE CAREER SPINE, /projects/ (2026-08-26 redesign) ==================
   One vertical line runs the career and each era is a node on it: the same
   timeline language the arc and the receipts already speak, applied to the
   census. Entries sit beside the spine as compact aligned cards instead of
   the full-width text rows DJ called a dump, so the page reads as columns
   of labelled evidence rather than a scroll of paragraphs. The newest node
   carries the Landfall dot, the arc's own rule: this era is running now. */
.pjt { margin-top: var(--sp-7); }
.pjt-era { display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 0 var(--sp-4); position: relative; padding-bottom: var(--sp-7); }
.pjt-era--last { padding-bottom: 0; }
.pjt-rail { position: relative; }
.pjt-rail::before { content: ''; position: absolute; top: 6px; bottom: calc(-1 * var(--sp-7)); left: 10px; width: 2px; background: var(--hairline); }
.pjt-era--last .pjt-rail::before { bottom: 0; }
.pjt-node { position: absolute; top: 4px; left: 4px; width: 14px; height: 14px; border-radius: 50%; background: var(--paper); border: 2px solid var(--chrome); }
.pjt-era--now .pjt-node { border-color: var(--signal); }
.pjt-era--now .pjt-node::after { content: ''; position: absolute; inset: 2px; border-radius: 50%; background: var(--signal); animation: livePulse 2.6s var(--ease) infinite; }
@media (prefers-reduced-motion: reduce) { .pjt-era--now .pjt-node::after { animation: none; } }
.pjt-chip { display: inline-block; font-size: 11px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); border: 1px solid var(--hairline); border-radius: var(--pill); padding: 3px 12px; margin: 0 0 var(--sp-2); background: var(--card); }
.pjt-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(330px, 100%), 1fr)); gap: var(--sp-3); margin-top: var(--sp-4); }
.pj { display: flex; flex-direction: column; gap: var(--sp-1); background: var(--card); border: 1px solid var(--hairline); border-radius: var(--r-sm); padding: var(--sp-4); text-decoration: none; color: inherit; transition: border-color var(--t-hover) var(--ease), transform var(--t-hover) var(--ease), box-shadow var(--t-hover) var(--ease); }
a.pj:hover { transform: translateY(-2px); border-color: var(--spark); box-shadow: 0 0 0 1px var(--spark), 0 0 14px color-mix(in srgb, var(--spark) 30%, transparent); }
a.pj:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.pj-tag { font-family: var(--font-mono); font-size: 10px; font-weight: 600; letter-spacing: .14em; color: var(--primary); }
.pj-t { font-family: var(--font-display); font-weight: 700; font-size: 15.5px; line-height: 1.3; color: var(--ink); }
.pj-d { font-size: 13px; line-height: 1.55; color: var(--muted); max-width: none; }
.pj-go { margin-top: auto; padding-top: var(--sp-1); font-family: var(--font-mono); font-size: 10.5px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--primary); }
a.pj:hover .pj-go { color: var(--ink); }
@media (max-width: 560px) { .pjt-era { grid-template-columns: 14px minmax(0, 1fr); gap: 0 var(--sp-2); } .pjt-rail::before { left: 6px; } .pjt-node { left: 0; } }

/* ==== THE CASE FOLD, /case-studies/ (2026-08-26 redesign) =================
   Four full-length cases stacked open ran the page to six screens, so each
   is now a details row: the Four Layers pattern, same reasons (content in
   the HTML, keyboard for free, works with JS off). A closed row still
   argues: thumb, badge, title and a one-line hook from the case's own copy.
   The first ships open so the page never reads as a wall of shut doors. */
.cs-d { background: var(--card); border: 1px solid var(--hairline); border-radius: var(--r); margin-bottom: var(--sp-3); overflow: hidden; transition: border-color var(--t-hover) var(--ease), box-shadow var(--t-hover) var(--ease); }
.cs-d:hover { border-color: var(--spark); box-shadow: 0 0 0 1px var(--spark), 0 0 14px color-mix(in srgb, var(--spark) 30%, transparent); }
.cs-sum { display: grid; grid-template-columns: 168px minmax(0, 1fr) auto; gap: var(--sp-4); align-items: center; cursor: pointer; list-style: none; padding-right: var(--sp-4); }
.cs-sum::-webkit-details-marker { display: none; }
.cs-sum::marker { content: ''; }
.cs-sum--growth { grid-template-columns: minmax(0, 1fr) auto; padding: var(--sp-3) var(--sp-4); }
.cs-thumb { align-self: stretch; min-height: 104px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--sp-1); background: var(--ground); overflow: hidden; }
.cs-thumb .wthumb-glyph { display: inline-flex; color: color-mix(in srgb, var(--paper) 20%, transparent); transition: color var(--t-release) var(--ease), transform var(--t-release) var(--ease); }
.cs-d:hover .cs-thumb .wthumb-glyph { color: var(--spark); transform: rotate(45deg); }
.cs-thumb .wthumb-cap { font-family: var(--font-mono); font-size: 10px; letter-spacing: .1em; text-transform: uppercase; color: var(--dim-d); padding: 0 var(--sp-2); text-align: center; }
.cs-thumb img { width: 100%; height: 100%; object-fit: cover; object-position: top; display: block; }
.cs-ttl { display: flex; flex-direction: column; gap: var(--sp-1); padding: var(--sp-3) 0; min-width: 0; }
.cs-ttl .badge { align-self: flex-start; }
.cs-ttl b { font-family: var(--font-display); font-weight: 700; font-size: 17px; line-height: 1.3; color: var(--ink); }
.cs-hook { font-size: 13.5px; line-height: 1.5; color: var(--muted); }
.cs-d[open] > .cs-sum .layer-more { transform: rotate(45deg); color: var(--spark); }
.cs-body { padding: var(--sp-1) var(--sp-5) var(--sp-5); animation: layerOpen var(--t-release) var(--ease); }
.cs-body p { max-width: var(--measure); }
.band-sand .cs-d { background: var(--card); }
@media (prefers-reduced-motion: reduce) { .cs-body { animation: none; } }
@media (max-width: 640px) {
  .cs-sum { grid-template-columns: minmax(0, 1fr) auto; padding: 0 var(--sp-4); }
  .cs-thumb { display: none; }
  .cs-ttl { padding: var(--sp-3) 0; }
}
