/* ============================================================================
   DJ VON FRANK — BRAND OS v3.0 · ATLAS
   ----------------------------------------------------------------------------
   The third system this site has worn, and the first one with a mark of its
   own. Seventeen colours became six. One dark, one warm, one white, two
   signals, one material. There is no seventh, including "just a lighter
   midnight" for large fills.

     · Named tokens only. Never hardcode a hex that has a token.
     · Every colour published with its measured contrast ratio, and its
       FAILURES written down as laws rather than nudged away.
     · Hairlines over shadows. Hover is border-colour plus a 1-2px lift.
     · Exactly one owned motion: THE SURFACE, in three places and no fourth.
       Two owned motions is zero owned motions. The Route, v1's seven-segment
       signal, stays retired and is not revived alongside it.
     · Reduced motion REMOVES movement, never slows it.
     · Derived tokens are formulas, so a palette swap re-renders everything.
       Repoint Midnight Green and the whole page re-renders correctly. That is
       the test this file exists to pass, and the six literals below are the
       only place a repoint has to land.

   Every ratio in this file was measured on 2026-08-13 — computed from these
   exact hexes with the WCAG relative-luminance maths, not carried over from
   v2 and not estimated. Three of the six fail somewhere and all three say so
   in their own definition. One value GAINED in v3: True North reaches 5.6:1
   on Midnight Green and is now legal for body text on dark. That is the only
   place it gained, and on white it is still never type at any size.

   WHAT V3 REMOVED, so nobody re-adds it by reflex: the alert red, the
   text-legal burnt orange, the pale sea-glass voice for dark surfaces and its
   alias, the elevated dark card, the mid-tone teal support, the whole warm
   bronze family, the three chart fills, and the washes and gradients that fed
   them. None of those were repointed. They were deleted by law, and a token
   left defined "just in case" is how an old palette leaks back.

   There is no red in this palette. An error state is carried by a 2px
   Midnight Green border, the glyph, and a line of Plex Mono under the field —
   never by True North, which means action, not failure. Focus is a 2px
   Surface Steel ring, never a glow.
   ========================================================================= */

.legacy {
  /* ---- THE SIX ----------------------------------------------------------
     Three do the work: Midnight Green grounds everything, Paper White carries
     the type, True North is the only warm thing in the system. Two more are
     reserved for signal — they are never decoration and never brand
     furniture. The sixth is not really a colour at all; it is what The
     Surface falls back to when it cannot render.

     These six are the only literal hexes in this file apart from the two
     stops the material owns (see THE MATERIAL). Everything below resolves
     through them. */

  --ink:     #00272C;  /* MIDNIGHT GREEN · PRIMARY · GROUND · INK.
                          White on it 15.8:1 ✓ · On white 15.8:1 ✓
                          The one dark. Heroes, headers, footers, dark bands,
                          and every line of body type on a light page. There
                          is no second dark and no lighter "almost midnight"
                          for large areas. This token is the definition
                          point: every ground and every derived neutral in
                          this file is a formula against it. */

  --spark:   #FF6B1C;  /* TRUE NORTH · SECONDARY · THE NEEDLE.
                          On Midnight 5.6:1 ✓ · On white 2.8:1 ✗
                          Named for the needle it colours. The only warm
                          value in the system, and the only one allowed to
                          move: primary buttons, the eyebrow on dark, the
                          live rule, the needle. Used once per view, twice at
                          most.
                          LAW: on light grounds it is a fill, a rule, or a
                          shape, and body copy on light is --ink. At 5.6:1 on
                          Midnight Green it is legal for body text on dark,
                          and that is the only place it gained over v2.

                          THE STANDING EXCEPTION (owner's ruling, 2026-08-27).
                          Two components carry True North as small type on a
                          light ground, deliberately, at the owner's call:
                          the .kflag section eyebrow (47 instances, 11 pages,
                          2.29:1 to 2.64:1) and the header CTA and its
                          .band-spark relatives (2.85:1). These are labels,
                          not reading matter: an eyebrow names the section
                          the reader is already looking at, and its glyph and
                          rule carry the same colour, so the label is never
                          the only way the meaning arrives. The ruling was
                          made on the measured numbers, not around them.
                          It licenses these two components and nothing else.
                          Any new small-type-on-light use is a fresh ruling,
                          not an extension of this one. */

  --spark-surface: color-mix(in srgb, var(--spark) 96%, var(--ink));
                       /* TRUE NORTH AS A SURFACE THAT CARRIES WHITE TYPE.
                          DJ's call 2026-08-27: the Company OS band should be
                          the flat, vivid orange of the duo card, not the
                          135deg gradient, whose midnight-mixed end stops read
                          gold and brown at the corner rather than brand.

                          Why 96% and not 100%. Paper White on pure #FF6B1C is
                          2.85:1, under the 3:1 large-text floor, and that is
                          the same 2.85:1 the audit found in four places
                          (the duo card, the arc card, the spark spine, and
                          the band headline). 97% is the exact tipping point,
                          3.00:1. 96% clears it at 3.05:1 and is a 4% mix, so
                          the eye reads it as the same orange while the
                          headline becomes legal.

                          The rule: a spark surface that carries PAPER type
                          uses this. A spark surface that carries INK type
                          uses --spark directly, because ink measures 5.56:1
                          on pure spark and gains nothing from the mix. */

  --paper:   #FFFFFF;  /* PAPER WHITE · BASE · CARD · KNOCKOUT.
                          On Midnight 15.8:1 ✓
                          True white, never off-white. Cards, sheets,
                          knockout marks, and all type on dark grounds. The
                          page beneath the cards is --page, a 5% Surface
                          Steel tint, so white sheets have something to sit
                          on. v2's off-white ground is gone; the sheet and
                          the page are now two different values, which is the
                          job --page exists to do. */

  --signal:  #09E85E;  /* LANDFALL · ARRIVAL · LIVE · SHIPPED · PASSING.
                          On Midnight 9.6:1 ✓ · On white 1.7:1 ✗
                          Land sighted. The owner's 2026-08-25 ruling widened
                          this from status-dot duty to a working role: the
                          pulsing dot on live work, the gate seal's tick, the
                          current era on the timeline, PASS states in demos.
                          It still only ever marks what is genuinely running,
                          which is what keeps it meaning something.
                          LAW: never small type on white; type on a Landfall
                          field is --ink, which measures 9.6:1. It marks what
                          is live, never what is merely claimed. */

  --beacon:  #279AF1;  /* MERIDIAN · MOTION · IN PROGRESS · INFORMATION.
                          On Midnight 5.3:1 ✓ · On white 3.0:1 · large only
                          A line of longitude: the thing you are still
                          travelling along. Widened 2026-08-25 to a working
                          role: the Operating Loop's station dots, the
                          .note.info edge and wash, in-progress chips,
                          read-time markers on dark grounds, the second
                          series in a chart.
                          LAW (amended by the owner's ruling, 2026-08-27).
                          The 3.0:1 figure is Meridian on pure white. Body
                          copy does not sit on pure white here: it sits on
                          --page, the 5% Surface Steel tint, where the real
                          rendered value is 2.79:1. The 2026-08-25 link
                          ruling was therefore made on a number this site
                          does not produce. Re-made on the true one: body
                          links stay Meridian at 2.79:1, underlined, and the
                          underline is what carries the affordance. Large
                          display on white keeps its 3.0:1. Small Meridian
                          type still lives on dark everywhere else. */

  --chrome:  #245D63;  /* SURFACE STEEL · STRUCTURE · LINK · LABEL.
                          On white 7.4:1 ✓ · On Midnight 2.1:1 ✗
                          What The Surface collapses to with no WebGL, and
                          since 2026-08-25 the site's structural material:
                          the .band-steel section ground, the data-strips,
                          the .btn.steel tertiary button, the sub-nav hover,
                          plus its old jobs as the link and eyebrow colour
                          on light and the bezel inside the mark.
                          LAW: fails on dark at 2.1:1. A Steel fill on a dark
                          ground is a shape, never a label. Links are Steel
                          with a 1px underline 3px clear of the baseline, on
                          light only. */

  /* THE ROLE PAIR — Landfall and Meridian still only ever mean something;
     the 2026-08-25 expansion widened where they say it, not what they say.
     Landfall = arrived (live, shipped, passing). Meridian = in motion (in
     progress, in review, informational). Allowed: status, dots, ticks,
     chips, washes, chart fills, the .note.info edge, accents inside a demo
     frame. Still never: logos · the header CTA · primary buttons ·
     marketing copy adjacent to the mark. The moment green means "nice
     green" it stops meaning shipped.
     Greyscale separation, measured: Landfall 0.59, Meridian 0.30, Midnight
     0.02 of 1. The three stay apart in a black-and-white print, which is
     why the pair can carry meaning without a shape change. */

  /* ---- GROUNDS — every one resolves through the six --------------------- */
  --ground:    var(--ink);    /* the primary dark ground: heroes, dark bands,
                                 the header when solid. Identical to --ink in
                                 v3, because there is no second dark. */
  --ink-deep:  var(--ink);    /* footers and code excerpts. Was a third dark
                                 in v2; folded in. Kept as a name so existing
                                 rules keep reading. */
  --deep:      var(--ink);    /* the v2 extension's Deep Water, promoted: its
                                 hex became the whole system's ground. Now an
                                 alias, not a distinct value. */
  --card:      var(--paper);  /* the one true white for sheets. Identical to
                                 --paper in v3; the sheet/page distinction is
                                 carried by --page below, not by an
                                 off-white. */

  --page:      color-mix(in srgb, var(--chrome) 5%, var(--paper));
                              /* 5% Steel on white → #F4F7F7. The ground
                                 beneath the cards, so a white sheet has
                                 something to sit on. v3's one genuinely new
                                 value. Midnight on it measures 14.7:1. */
  --band:      color-mix(in srgb, var(--chrome) 8%, var(--paper));
                              /* 8% Steel on white → #EDF2F3. Recessed bands,
                                 table heads. Midnight on it measures
                                 14.0:1. */

  /* ---- DERIVED NEUTRALS — formulas, so a palette swap re-renders --------
     Where the Brand OS prints a swatch hex beside a formula, the formula
     lands within one 8-bit step of it. The formula is the law and the swatch
     is the illustration; the ratios below are computed from what the formula
     actually renders, not from the swatch. */

  --muted: color-mix(in srgb, var(--ink) 72%, var(--paper));
           /* Secondary text on light. Renders #476367, 6.5:1 on white ✓.
              The Brand OS swatch prints #476467 at 6.4:1; one step apart,
              both comfortably AA. */
  --faint: color-mix(in srgb, var(--ink) 65%, var(--paper));
           /* Captions and tertiary labels. Renders #597376, 5.1:1 on white ✓.
              v2 shipped a kit value at 3.9:1 and darkened it rather than
              excusing it; v3 arrives at the same place by formula.
              THE FLOOR, written down: on --page rather than true white —
              which is the ground these two sit on more often — --muted
              measures 6.0:1 and --faint measures 4.7:1. Both still pass AA
              at text sizes. --faint is the floor of this palette and is not
              to be lightened; there is nothing under it. */

  --dim-d:   color-mix(in srgb, var(--paper) 66%, transparent);
             /* Dimmed type on Midnight. Renders #A8B6B7 over --ink, 7.6:1 ✓.
                Was 62% in v2; 66% is the published v3 value. */
  --strong-d: color-mix(in srgb, var(--paper) 88%, transparent);

  --hairline:      color-mix(in srgb, var(--ink) 13%, transparent);
  --hairline-soft: color-mix(in srgb, var(--ink) 8%,  transparent);
  --hairline-d:    color-mix(in srgb, var(--paper) 16%, transparent);
  /* Depth comes from hairlines, not shadows: a one-pixel border and a one-to
     -two-pixel lift. The light hairline tightened from 14% to 13% in v3; the
     dark one is unchanged at 16%. */

  /* ---- VOICES ----------------------------------------------------------- */
  --primary: var(--chrome);  /* THE accent role on light: links, labels,
                                eyebrows, the 2px focus ring. Harbor held
                                this in v2; Surface Steel holds it now, and
                                carries the same law — it fails on dark. */

  --wash-primary: color-mix(in srgb, var(--primary) 7%, var(--card));
  --wash-spark:   color-mix(in srgb, var(--spark) 8%,   var(--card));
  /* 2026-08-25 role-bound expansion: the signal pair earns wash duty.
     Landfall washes ground an arrival moment, Meridian washes ground an
     information moment. Washes are fills, legal on light at any ratio. */
  --wash-signal:  color-mix(in srgb, var(--signal) 9%,  var(--card));
  --wash-beacon:  color-mix(in srgb, var(--beacon) 8%,  var(--card));
  /* Washes are fields, never type grounds for the colour they are made of.
     A True North wash is legal on light because at 8% it is a fill, which is
     the only thing True North is allowed to be there. */

  --glass:   color-mix(in srgb, var(--paper) 86%, transparent);
  --glass-d: color-mix(in srgb, var(--ground) 88%, transparent);
  --blur-1:  saturate(170%) blur(14px);  /* sticky chrome */
  --blur-2:  saturate(140%) blur(22px);  /* overlays */
  /* Two grades of glass. A third makes depth ambiguous. Where blur is
     unsupported the glass falls back to solid Midnight Green; anyone who
     sets reduced transparency gets the solid, not a thinner blur. */

  /* ---- THE MATERIAL -----------------------------------------------------
     THE SURFACE is WebGL. This is its flat cousin, for the places that need
     the same read without a canvas, and for every browser that cannot run
     it. v2 carried two chrome gradients; v3 carries one, because the avoid
     list permits exactly one gradient in this system: The Surface and this
     fallback. Print drops even this and uses flat --chrome.

     The two outer stops are the material's own, published in the Brand OS as
     literals. They are the only hexes here that are not one of the six, and
     they are legal precisely because they have no token name — they are not
     palette colours, they are where the material starts and ends. The middle
     stop is the ground, so a repoint of Midnight Green moves the gradient
     with it. */
  --grad-ground: linear-gradient(158deg, #0A4C4A 0%, var(--ground) 46%, #001A1E 100%);

  --grad-paper:  var(--page);
  /* Retirement stub. v2 lit its light ground with a radial-plus-linear
     gradient; --paper is true white now and a gradient between brand colours
     is on the avoid list, so there is no paper gradient in v3. The name
     survives only so that any rule still calling it resolves to the legal
     light ground instead of falling through to transparent. Remove it once
     nothing references it. */

  /* ---- TYPE -------------------------------------------------------------
     Archivo        — headlines, section heads, card titles, buttons.
                      800-900 for display, 700 for anything under 24px.
     IBM Plex Sans  — body and UI. ~16px over 1.55 leading, 1.65 in long-form.
     IBM Plex Mono  — eyebrows, figures, IDs, file names, code. Tabular
                      figures always, so columns of numbers line up.
     All three are self-hosted latin subsets: /fonts/. Zero external requests.

     Saira Black at wdth 125 is the fourth face in the Brand OS and it is
     deliberately NOT tokenised here. It sets the wordmark and nothing else,
     and the standing rule is that the wordmark is artwork, not live text, in
     production. A --font-wordmark token would invite live text and a font
     request this site does not make. The lockups ship outlined. */
  --font-display: 'Archivo', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --font-body:    'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --font-mono:    'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* ---- CARRIED FORWARD FROM v2 ------------------------------------------
     The type scale and the layout tokens below are v2's, unchanged. v3 does
     not restate them, and that distinction matters: the Brand OS is not
     their source and must not be cited as one. The single exception is
     --measure, which the Brand OS does specify — "holds a 66-character
     measure" — and which happens to already be right.
     The timing, easing, blur and radius values further down ARE restated by
     v3 and are identical to v2's, with one change: buttons move to --pill. */

  --step--1: clamp(0.82rem, 0.79rem + 0.14vw, 0.90rem);
  --step-0:  clamp(1.00rem, 0.97rem + 0.16vw, 1.09rem);
  --step-1:  clamp(1.20rem, 1.13rem + 0.34vw, 1.42rem);
  --step-2:  clamp(1.48rem, 1.34rem + 0.68vw, 1.92rem);
  --step-3:  clamp(1.85rem, 1.58rem + 1.32vw, 2.65rem);
  --step-4:  clamp(2.30rem, 1.79rem + 2.48vw, 3.80rem);
  --step-5:  clamp(2.80rem, 1.86rem + 4.55vw, 5.60rem);

  /* ---- SPACE, RADIUS, MOTION -------------------------------------------- */
  --hd-h:      70px;   /* header height. Anything sticky below it keys off this. */
  --gutter:    clamp(20px, 4.5vw, 44px);
  --wrap:      1180px;
  --wrap-wide: 1420px;
  --measure:   66ch;
  --section:   clamp(60px, 9vw, 124px);

  /* ---- SPACING SCALE (2026-08-25) -----------------------------------------
     The type ramp had steps and the space between things did not: 254 inline
     declarations across the page modules used 22 distinct pixel values. The
     22 collapse onto seven steps, each with one job, and a page module never
     writes a raw spacing pixel again. The mapping that retired each value is
     recorded here so a future eye knows 22px card padding did not vanish, it
     became --sp-4.
       --sp-1   6px   micro: a label to its value, a dot to its word   (4,6)
       --sp-2  10px   small: chips, tight stacks, icon gaps        (8,9,10,12)
       --sp-3  14px   base: text rhythm, a kicker to its headline     (14,16)
       --sp-4  20px   roomy: card padding, grid gaps               (18,20,22)
       --sp-5  26px   panel: feature padding, sub-section air       (24,26,28)
       --sp-6  34px   block: a lede to the proof below it   (30,32,34,36,40)
       --sp-7  48px   group: between the page's big moves         (44,48,52)
     The steps are literal px on purpose: spacing that breathes with the
     viewport already has --gutter and --section, and a third fluid axis
     would make every gap a calculation. */
  --sp-1: 6px;
  --sp-2: 10px;
  --sp-3: 14px;
  --sp-4: 20px;
  --sp-5: 26px;
  --sp-6: 34px;
  --sp-7: 48px;

  --r-sm:  8px;   /* chips, tags */
  --r:     14px;  /* cards, inputs */
  --r-lg:  22px;  /* panels, feature blocks */
  --pill:  999px; /* BUTTONS. They were --r in v2 and are --pill in v3.
                     One True North button per view: a second primary means
                     the first one was not primary. Hit target never below
                     44px. Tiles curve at 22% of tile width, so an app icon
                     and a favicon curve alike. */

  /* Hairlines do the work. These two exist for genuinely floating surfaces,
     and nothing else. --sh-sm lost its second layer in v3: one 3px layer at
     5% for resting sheets, one 30px layer at 22% for floating ones. The base
     is Midnight Green, written as a formula so the shadows follow a repoint
     instead of drifting from it — v2 pasted an rgba that belonged to no
     token and quietly stopped matching the ground. */
  --sh-sm: 0 1px 3px color-mix(in srgb, var(--ink) 5%, transparent);
  --sh-md: 0 12px 30px -14px color-mix(in srgb, var(--ink) 22%, transparent);

  /* The timing budget, fixed. Every STATE CHANGE in this system resolves in
     260ms or less. Hover is a border-colour change plus a 1-2px lift: never a
     scale, never a colour wash across a whole card.

     THE AMBIENT EXCEPTION (owner's ruling, 2026-08-26, the same shape as the
     spark-glow ruling that preceded it). The budget governs state changes,
     which are things a person triggers and then waits on. It does not govern
     continuous ambient surfaces, which nobody is waiting on: The Surface
     itself, the marquee, the traveling rail pulses, and as of this ruling the
     hero's rotating line (a 6s cycle) and its kicker shine (3.6s). The test
     is whether a person is blocked by it. If someone clicked and is waiting,
     260ms. If it simply breathes, it is ambient and exempt.
     Reduced motion still REMOVES all of it rather than shortening it. */
  --t-hover:   170ms;
  --t-press:   90ms;
  --t-release: 200ms;
  --ease:      cubic-bezier(.33, 0, .15, 1);
}

/* ============================================================================
   THE SURFACE — the one piece of decorative motion this brand owns.
   ----------------------------------------------------------------------------
   Not a colour. A material: a slow liquid-chrome field in Midnight Green with
   a low, out-of-phase thread of True North running through it, tone-mapped so
   the brightest band lands on a muted steel instead of blowing to white. It
   is the one texture this brand owns, and owning exactly one is the point.

   Parameters, published: speed 0.12 · amplitude 0.32 · base #00272C ·
   orange thread 0.04. It answers the pointer.

   WHERE IT RENDERS — three places, and there is no fourth:
     1. the site hero,
     2. the Brand OS document cover,
     3. the app icon, exported as a still frame.
   Of those three, exactly one is a web page. On this site The Surface
   renders once, on the homepage hero, and the other two are not ours to
   draw. v2 said "exactly one place" because only the hero existed; the count
   went to three when the document and the icon did, and it stops there.

   Never:  a second instance on this site · behind body text · above the fold
           on any page but the homepage · under a lockup outside the three
           cleared uses · beside a second owned motion. Two owned motions is
           zero owned motions.
   No WebGL: the flat --grad-ground gradient underneath simply shows and
             nothing structural is lost. Print: flat --chrome, no gradient.
   Reduced motion: ONE still frame is drawn at t=8.0 and the loop never
                   starts. Movement is REMOVED, never slowed — a slowed
                   signature reads as broken.
   The Route, v1's seven-segment signal, retired with v1 and stays retired.
   ========================================================================= */

@media (prefers-reduced-motion: reduce) {
  .legacy *,.legacy *::before,.legacy *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ============================================================================
   DJ VON FRANK — SITE
   Components. Every value comes from tokens.css.

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

   Raw hex below this line: SEVEN, all of them inside @media print, all of
   them one-ink reproduction values rather than palette values. The Brand OS
   is explicit that the black master is "100K only" and that print loses the
   surface, the glass and the blur; Midnight Green is not black, so printing
   it as a token would be the wrong claim. Everything that renders on a
   screen is a token. There are no `var(--x, #hex)` fallbacks anywhere in
   this file — a fallback is a second copy of the palette that only ever
   fires when the first copy is missing, which is the one moment it would
   paint the previous brand.

   THE RHYTHM RULE — light-first, dark-punctuated:
   Paper White is true white now and the page beneath the cards is --page, a
   5% Surface Steel tint, so a white sheet has something to sit on. A page
   runs light and uses a dark band to mark a change of subject, roughly one
   band per two screens of scroll. Two dark bands in a row makes the second
   one furniture instead of punctuation. This stylesheet obeys its own rule.

   THE SIX:
     Midnight Green #00272C  ground + ink       white on it 15.8:1
     True North     #FF6B1C  the needle         on Midnight 5.6:1 / on white 2.8:1 FAILS
                                                 except .kflag + header CTA, ruled 2026-08-27
     Paper White    #FFFFFF  card, knockout     on Midnight 15.8:1
     Landfall       #09E85E  shipped / passing  on Midnight 9.6:1 / on white 1.7:1 FAILS
     Meridian       #279AF1  in progress / info on Midnight 5.3:1 / on white 3.0:1 large only
                                                 body links on --page 2.79:1, ruled 2026-08-27
     Surface Steel  #245D63  link, eyebrow      on white 7.4:1 / on Midnight 2.1:1 FAILS
   Ratios recomputed 2026-08-13 against these exact values, not carried over.
   ========================================================================= */

.legacy *,.legacy *::before,.legacy *::after { box-sizing: border-box; }
.legacy :scope { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: calc(var(--hd-h) + 16px); }
.legacy :scope {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.62;
  color: var(--ink);
  background: var(--page);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
.legacy img,.legacy svg,.legacy video { max-width: 100%; height: auto; display: block; }
/* Links are Meridian on light grounds. The 2026-08-25 ruling recorded 3.0:1,
   which is Meridian on pure white; body copy sits on --page, where it really
   measures 2.79:1. Re-ruled on the true number 2026-08-27: links stay
   Meridian, and tokens.css now publishes 2.79:1 instead of the law this rule
   used to contradict. The underline stays one pixel, three pixels clear of
   the baseline, and it is what carries the link
   where the color alone would not. Hover darkens to the ink. On dark grounds
   links are True North instead: see .band-dark a. */
.legacy a { color: var(--beacon); text-decoration-thickness: 1px; text-underline-offset: 3px; }
.legacy a:hover { color: var(--ink); }
.legacy hr { border: 0; border-top: 1px solid var(--hairline); margin: var(--section) 0; }

/* The focus ring is the one element never restyled per component: a 2px
   Surface Steel ring, never a glow. Steel measures 2.1:1 on Midnight Green
   and would vanish there, so on dark grounds the ring is True North (5.6:1)
   — the one colour legal on both sides of that line. */
.legacy #main:focus { outline: none; }
.legacy :focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: 3px; }
.legacy .hd :focus-visible,.legacy .splith :focus-visible,.legacy .proof :focus-visible,.legacy .phero :focus-visible,.legacy .band-dark :focus-visible,.legacy .ft :focus-visible,.legacy .code-pre:focus-visible { outline-color: var(--spark); }
.legacy .skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--ink); color: var(--paper); padding: 12px 18px; border-radius: 0 0 var(--r) 0;
}
.legacy .skip:focus { left: 0; }
.legacy .sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---- LAYOUT -------------------------------------------------------------- */
.legacy .wrap { max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gutter); }
.legacy .wrap--wide { max-width: var(--wrap-wide); }
/* .wrap--measured was called .wrap--narrow, and the rename is the point. It used to
   shrink the whole SECTION to 780px and centre it, which left its headings,
   notes and buttons inset from every other section on the site: a page
   alternating the two containers looked like the layout kept losing its
   nerve. That behaviour was removed, but the name stayed, and a class called
   "narrow" that narrows nothing is a trap for the next person reading the
   markup.

   2026-08-26, the caps came off entirely. The child caps (lists, notes and
   tables at --measure) were the last holders of the old left-pinned pattern:
   a 66ch block against the left rail of an 1180px wrap, which DJ called the
   side-margin problem across seven pages. The measure now lives where the
   writing articles put it, on reading COLUMNS (.art-col and the resources
   article grid), and everything else fills its wrap. The class is kept as a
   no-op so 34 uses of it across the markup stay valid; treat it as a plain
   .wrap and retire it from new markup. */
.legacy .wrap--measured { max-width: var(--wrap); }
.legacy .section { padding-block: var(--section); }
.legacy .section--tight { padding-block: calc(var(--section) * .55); }
.legacy .stack > * + * { margin-top: 1.1em; }
.legacy .grid { display: grid; gap: 18px; grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr)); }
/* .grid--2 means two columns. It used to say "as many 340px tracks as fit",
   which inside the 1092px content column resolves to THREE, so every four-card
   row on the site rendered 3+1 with the fourth card stranded beside two empty
   cells. Home's Selected Work and the brains index, the two rows whose whole
   job is to prove the work, were the worst of it. Declared by intended column
   count now, not by track minimum (2026-08-27). */
/* AT MOST TWO COLUMNS, AND ONLY WHEN THEY FIT (fixed 2026-08-27, second pass).

   First pass forced two columns above a 720px VIEWPORT. That fixed the 3+1 on
   home and /brains/, and broke every .grid--2 nested inside something narrow:
   on /method/ this grid lives in a 411px tab panel, so it produced two 171px
   cards and the word "confidentiality" spilled its box. A viewport media query
   cannot answer "is there room HERE", which was the wrong question to ask.

   The max() term asks the right one. Each track is at least half the container
   minus the gap, so at most two ever fit; but never narrower than 280px, so in
   a tight container the second track cannot fit and the grid collapses to one.
   Percentages resolve against the container, so this is container-aware without
   needing @container support.

     1092px wrap  -> (1092-18)/2 = 537  -> two 537px tracks
     411px panel  -> (411-18)/2  = 196  -> floor is 280, so ONE track */
.legacy .grid--2 {
  /* --g2 is the gap, and the track formula has to read the SAME value or the
     maths is wrong. Third pass on this rule, 2026-08-27. Pass two hardcoded
     18px inside the formula while eight call sites override `gap` inline to
     --sp-6 or --sp-7; at a 48px gap the floor came out ~30px too wide, the
     second track no longer fit, and /about/ silently rendered ONE column.
     Overriding `gap` directly cannot work here. Override --g2 instead and
     both the gap and the formula move together. */
  --g2: 18px;
  gap: var(--g2);
  /* min(280px, 100%) so the floor can never be wider than the container itself.
     Without it a 320px phone, whose content box is 276px after wrap padding,
     got a 280px floor and the page scrolled 3px sideways. */
  grid-template-columns: repeat(auto-fit, minmax(max(min(280px, 100%), (100% - var(--g2)) / 2), 1fr));
}
.legacy .grid--tight { gap: 12px; }

/* ---- TYPE ---------------------------------------------------------------- */
.legacy h1,.legacy h2,.legacy h3,.legacy h4 { margin: 0 0 .5em; line-height: 1.14; font-family: var(--font-display); font-weight: 700; letter-spacing: -.018em; }
.legacy h1,.legacy h2 { font-weight: 800; }
.legacy h1 { font-size: var(--step-4); }
.legacy h2 { font-size: var(--step-3); }
.legacy h3 { font-size: var(--step-1); }
.legacy h4 { font-size: var(--step-0); }
/* THE MEASURE MOVED FROM THE PARAGRAPH TO THE CONTAINER (2026-08-26).
   Every <p> used to cap itself at 66ch, which inside an 1180px wrap pinned
   a 600px text block to the left rail and left the right half of the page
   empty. DJ called it the side-margin problem on seven pages running; the
   writing articles were fixed first by giving the COLUMN the measure
   (.art-col, 760px, centered) and letting paragraphs fill it, and that is
   now the sitewide architecture: containers own width, paragraphs fill
   containers. Long-form still reads at a book measure because long-form
   lives in columns; everything else fills the wrap it sits in. */
.legacy p { margin: 0 0 1.1em; }

.legacy .display {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: var(--step-5);
  line-height: 1.02;
  letter-spacing: -.02em;
}
.legacy .headline { font-size: var(--step-3); letter-spacing: -.022em; }
/* Eyebrows sit above, never below, and on a light ground they are Surface
   Steel: 7.4:1 on white. This used to be the bronze family, which v3 removes
   entirely. On dark the eyebrow is True North — see .band-dark .kicker. */
.legacy .kicker {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--primary);
  margin: 0 0 14px;
}
.legacy .lede { font-size: var(--step-1); line-height: 1.5; color: var(--muted); }
/* THE FULL-WIDTH LEDE (owner's ruling, 2026-08-25): section ledes run the
   width of their headline rather than stopping at the measure. It was thirty
   inline style="max-width:none" declarations; now it is one class, so the
   ruling has a name and a single off-switch. .mw-none is the generic escape
   for any other element the ruling reaches. Article BODY prose is the ruled
   exception and keeps its measure (see .art-col in writing.css). */
.legacy .lede--full,.legacy .mw-none { max-width: none; }
.legacy .mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.legacy .tight { max-width: 54ch; }

/* ---- HEADER — dark glass, the kit's signature chrome ---------------------- */
/* Sticky chrome takes --blur-1; overlays take --blur-2. Two grades, because a
   third makes depth ambiguous. Where blur is unsupported the glass falls back
   to solid Midnight Green, not to a thinner blur. */
.legacy .hd {
  position: sticky; top: 0; z-index: 100;
  background: var(--glass-d);
  backdrop-filter: var(--blur-1); -webkit-backdrop-filter: var(--blur-1);
  border-bottom: 1px solid var(--hairline-d);
  color: var(--paper);
}
@supports not (backdrop-filter: blur(1px)) { .legacy .hd { background: var(--ground); } }
.legacy .hd-in {
  max-width: var(--wrap-wide); margin-inline: auto; padding: 14px var(--gutter); min-height: var(--hd-h);
  display: flex; align-items: center; gap: 28px;
}
.legacy .hd-mark { display: flex; align-items: center; gap: 11px; text-decoration: none; color: var(--paper); flex: 0 0 auto; }
.legacy .hd-mark svg { width: 30px; height: 30px; }
.legacy .hd-mark b { font-family: var(--font-display); font-weight: 800; font-size: 1.06rem; letter-spacing: -.02em; }
.legacy .hd nav { margin-left: auto; display: flex; gap: 4px; align-items: center; }
.legacy .hd nav a {
  font-size: var(--step--1); font-weight: 500; color: var(--dim-d);
  text-decoration: none; padding: 9px 13px; border-radius: var(--r-sm);
  transition: color var(--t-hover) var(--ease), background var(--t-hover) var(--ease);
}
.legacy .hd nav a:hover { color: var(--paper); background: var(--hairline-d); }
.legacy .hd nav a[aria-current="page"] { color: var(--paper); font-weight: 600; }
/* One True North button per view; the label on a True North fill is Midnight
   Green, 5.6:1. Paper White on it is 2.8:1 and is never used. Buttons are
   --pill in v3, and the hit target never drops below 44px. */
.legacy .hd-cta {
  font-size: var(--step--1); font-weight: 600; padding: 9px 17px !important;
  background: var(--spark); color: var(--ink) !important; border-radius: var(--pill);
}
.legacy .hd-cta:hover { background: var(--paper); }
.legacy .hd-burger {
  display: none; margin-left: auto; width: 42px; height: 42px; border-radius: var(--r-sm);
  border: 1px solid var(--hairline-d); background: transparent; cursor: pointer;
  align-items: center; justify-content: center; color: var(--paper);
}
@media (max-width: 900px) {
  .legacy .hd nav { display: none; }
  .legacy .hd nav.open {
    display: flex; flex-direction: column; align-items: stretch; gap: 2px;
    position: absolute; left: 0; right: 0; top: 100%;
    background: var(--ground); border-bottom: 1px solid var(--hairline-d);
    padding: 12px var(--gutter) 20px;
  }
  .legacy .hd nav.open a { padding: 13px 4px; font-size: var(--step-0); }
  .legacy .hd nav.open .hd-cta { text-align: center; margin-top: 8px; }
  .legacy .hd-burger { display: flex; }
}

/* ---- THE SPLIT HERO — the signature device ------------------------------- */
/* THE SURFACE lives behind it on the homepage: a canvas layer under a soft
   darkening scrim so the split copy keeps its contrast over the brightest
   chrome bands. No WebGL, no canvas: the --grad-ground flat fallback below
   simply shows and nothing structural is lost. */
.legacy .splith { background: var(--grad-ground); color: var(--paper); position: relative; overflow: hidden; }
.legacy .splith-fx { position: absolute; inset: 0; z-index: 0; }
.legacy .splith-fx canvas { width: 100%; height: 100%; display: block; }
.legacy .splith-fx::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--ink) 34%, transparent),
    color-mix(in srgb, var(--ink) 68%, transparent));
}
.legacy .splith-in,.legacy .splith > .wrap { position: relative; z-index: 1; }
.legacy .splith-in {
  max-width: var(--wrap-wide); margin-inline: auto; padding: clamp(48px, 7vw, 92px) var(--gutter) 0;
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: end; gap: clamp(20px, 4vw, 56px);
}
.legacy .splith-half { padding-bottom: clamp(40px, 6vw, 76px); text-decoration: none; color: inherit; display: block; }
.legacy .splith-half:last-of-type { text-align: right; }
.legacy .splith-half .kicker { color: var(--spark); }
.legacy .splith-half h2 {
  font-family: var(--font-display); font-weight: 800; font-size: var(--step-3);
  line-height: 1.08; letter-spacing: -.02em; color: var(--paper); margin-bottom: .35em;
  max-width: 15ch;
}
.legacy .splith-half:last-of-type h2 { margin-left: auto; }
.legacy .splith-half p { color: var(--dim-d); font-size: var(--step--1); max-width: 30ch; margin: 0; }
.legacy .splith-half:last-of-type p { margin-left: auto; }
.legacy .splith-half .go {
  display: inline-flex; align-items: center; gap: 7px; margin-top: 18px;
  font-family: var(--font-mono); font-size: var(--step--1); font-weight: 600;
  letter-spacing: .04em; color: var(--spark);
  transition: gap var(--t-hover) var(--ease);
}
/* Hover moves the affordance, not the whole half: the arrow's gap opens and
   nothing washes colour across the block. */
.legacy .splith-half:hover .go { gap: 13px; }

.legacy .splith-portrait { position: relative; align-self: end; width: clamp(180px, 22vw, 300px); }
.legacy .splith-portrait img,.legacy .splith-portrait .ph-figure { width: 100%; display: block; }
.legacy .splith-name {
  position: absolute; left: 50%; transform: translateX(-50%); bottom: -1px;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .22em;
  text-transform: uppercase; color: var(--dim-d); white-space: nowrap;
  background: var(--ink); padding: 0 12px;
}
.legacy .splith-in { position: relative; z-index: 1; }

@media (max-width: 860px) {
  .legacy .splith-in { grid-template-columns: 1fr; text-align: center; padding-top: 36px; }
  .legacy .splith-half,.legacy .splith-half:last-of-type { text-align: center; padding-bottom: 0; }
  .legacy .splith-half h2,.legacy .splith-half p { max-width: none; margin-inline: auto; }
  .legacy .splith-portrait { width: min(220px, 60vw); margin: 24px auto 0; order: -1; }
  .legacy .splith-half + .splith-portrait { order: 0; }
}

/* ---- PROOF STRIP — three to five figures, above the fold ----------------- */
/* Two looks thin, six looks padded. The figures are Paper White on Midnight
   Green at 15.8:1 and tabular, always — a column of numbers that ripples is
   a column of numbers nobody reads. */
.legacy .proof { background: var(--ink-deep); color: var(--paper); }
.legacy .proof-in {
  max-width: var(--wrap-wide); margin-inline: auto; padding: 30px var(--gutter);
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr)); gap: 26px;
}
.legacy .proof-n {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--step-3); font-weight: 600; line-height: 1; color: var(--paper);
  letter-spacing: -.02em;
}
.legacy .proof-l { font-size: var(--step--1); color: var(--dim-d); margin-top: 7px; line-height: 1.35; }

/* ---- DARK BAND — the rhythm rule ---------------------------------------- */
.legacy .band-dark { background: var(--grad-ground); color: var(--paper); }
.legacy .band-dark h2,.legacy .band-dark h3,.legacy .band-dark .display { color: var(--paper); }
.legacy .band-dark .kicker { color: var(--spark); }
.legacy .band-dark p,.legacy .band-dark .lede { color: var(--dim-d); }
/* Links on a dark ground are True North: the owner's 2026-08-25 ruling,
   the pair of the Meridian-on-light rule above. 5.6:1 on Midnight, so this
   half of the pair clears its ratio outright. Hover lifts to Paper. */
.legacy .band-dark a { color: var(--spark); }
.legacy .band-dark a:hover { color: var(--paper); }
/* The ruling's edges: page heroes are dark grounds too, so their links take
   the spark half. The spark band is orange itself, where an orange link
   would vanish, so links there fall back to ink. Buttons everywhere carry
   their own colors and outrank these. */
.legacy .phero a { color: var(--spark); }
.legacy .phero a:hover { color: var(--paper); }
.legacy .band-spark a:not(.btn) { color: var(--ink); }
.legacy .band-sand { background: var(--band); }
/* THE STEEL BAND (2026-08-25 expansion): Surface Steel graduates from link
   and eyebrow duty to structural material. A deeper steel wash than --band,
   for section rhythm where sand and dark are already spoken for. Type on it
   stays ink/muted, which both clear their ratios on this ground. */
.legacy .band-steel { background: color-mix(in srgb, var(--chrome) 14%, var(--paper)); }
.legacy .band-steel .card { background: var(--card); }

/* ---- CARDS --------------------------------------------------------------- */
.legacy .card {
  background: var(--card); border: 1px solid var(--hairline); border-radius: var(--r);
  padding: 22px 22px 20px; text-decoration: none; color: inherit; display: block;
  transition: border-color var(--t-hover) var(--ease), transform var(--t-hover) var(--ease), box-shadow var(--t-hover) var(--ease);
}
/* The spark-glow family (2026-08-25 rollout): every linked card on the site
   hovers the same way the arc and diagnosis cards do. Spark border, 1px ring,
   14px bloom, 2px lift. The glow is the owner's sanctioned exception to the
   no-halo rule, scoped to this one hover family and nothing else. */
.legacy a.card:hover { border-color: var(--spark); transform: translateY(-2px); box-shadow: 0 0 0 1px var(--spark), 0 0 14px color-mix(in srgb, var(--spark) 30%, transparent); }
.legacy .card h3 { margin-bottom: .35em; font-size: var(--step-1); }
.legacy .card p { font-size: var(--step--1); color: var(--muted); margin-bottom: 0; }
.legacy .card .num {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--step-2); font-weight: 600; color: var(--ink); display: block; margin-bottom: 6px;
}
.legacy .card .go {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 14px;
  font-family: var(--font-mono); font-size: var(--step--1); font-weight: 600; color: var(--primary);
  transition: gap var(--t-hover) var(--ease);
}
.legacy a.card:hover .go { gap: 12px; color: var(--ink); }
/* A card on a dark band has no fill of its own. v3 has one dark and no
   elevated "riser" tier, so the card is drawn by its hairline. */
.legacy .band-dark .card { background: transparent; border-color: var(--hairline-d); box-shadow: none; }
.legacy .band-dark .card p { color: var(--dim-d); }
/* Same family on the dark band: spark reads on Midnight, and the glow reads
   better there than anywhere. */
.legacy .band-dark a.card:hover { border-color: var(--spark); box-shadow: 0 0 0 1px var(--spark), 0 0 14px color-mix(in srgb, var(--spark) 30%, transparent); }
.legacy .band-dark .card .go { color: var(--spark); }
/* The hover pair for the rule above (2026-08-26): `a.card:hover .go` sets
   ink for light cards at (0,3,1), which beat this class's (0,3,0) and put a
   midnight label on a midnight card. Same family as the a:hover note at
   .band-dark .btn:hover: the element selector in the generic rule is what
   wins the fight. (0,4,1) settles it. */
.legacy .band-dark a.card:hover .go { color: var(--paper); }

.legacy .card-media {
  aspect-ratio: 16 / 10; border-radius: calc(var(--r) - 4px); overflow: hidden;
  margin: -4px -4px 16px; background: var(--band);
}
.legacy .card-media img,.legacy .card-media svg { width: 100%; height: 100%; object-fit: cover; }

/* ---- BADGES + CHIPS ------------------------------------------------------ */
/* P02 STATUS CHIPS. The law: the dot carries the colour on light, the label
   carries it only on dark. Landfall is 1.7:1 on white and Meridian is 3.0:1
   there (2.79:1 on --page), so neither may ever set this 10.5px label on a
   white card. The dot is a fill, and a fill is legal. The 2026-08-27 link
   ruling does not reach this: it licensed underlined body links, not chips. On Midnight Green the pair measures 9.6:1 and
   5.3:1, so there the label itself may take the colour.
   The three states stay separable in a greyscale print without changing
   shape: Landfall 0.59, Meridian 0.30, Midnight 0.02 of 1. */
.legacy .badge {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; padding: 3px 9px; border-radius: var(--pill);
  border: 1px solid var(--hairline); background: transparent; color: var(--muted);
  vertical-align: middle;
}
.legacy .badge::before {
  content: ""; flex: 0 0 auto; width: 7px; height: 7px; border-radius: 50%;
  background: currentColor;
}
.legacy .badge.live::before { background: var(--signal); }   /* shipped / passing   */
.legacy .badge.demo::before { background: var(--beacon); }   /* in progress / info  */
.legacy .badge.conf::before { background: var(--ink); }      /* there is no red     */
.legacy .badge.soon::before { background: var(--faint); }
.legacy .badge.conf { border-color: var(--ink); color: var(--ink); }
.legacy .badge.soon { color: var(--faint); }
.legacy .band-dark .badge { color: var(--dim-d); border-color: var(--hairline-d); }
.legacy .band-dark .badge.live { color: var(--signal); }
.legacy .band-dark .badge.demo { color: var(--beacon); }
.legacy .band-dark .badge.conf { color: var(--paper); border-color: var(--paper); }
.legacy .band-dark .badge.conf::before { background: var(--paper); }
.legacy .band-dark .badge.soon { color: var(--dim-d); border-color: var(--hairline-d); }
/* The Landfall dot breathes (2026-08-25): live means running right now, so
   the dot carries a slow expanding ring. A fill animating, never type;
   removed entirely under reduced motion. */
.legacy .badge.live::before { animation: livePulse 2.6s var(--ease) infinite; }
@keyframes livePulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--signal) 45%, transparent); }
  70%  { box-shadow: 0 0 0 6px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}
@media (prefers-reduced-motion: reduce) { .legacy .badge.live::before { animation: none; } }

.legacy .chip {
  font-family: var(--font-mono); font-size: var(--step--1); font-weight: 500;
  padding: 7px 14px; border-radius: var(--pill); border: 1px solid var(--hairline);
  background: transparent; color: var(--muted); cursor: pointer;
  transition: color var(--t-hover) var(--ease), border-color var(--t-hover) var(--ease), background var(--t-hover) var(--ease);
}
.legacy .chip:hover { border-color: var(--primary); color: var(--ink); }
.legacy .chip.on { background: var(--ink); border-color: var(--ink); color: var(--paper); }

/* ---- BUTTONS ------------------------------------------------------------- */
/* One True North button per view — .btn.spark is it. A second primary means
   the first one was not primary. Hit target never below 44px, radius is
   --pill, and hover is a border-colour change plus a 1px lift: never a
   scale, never a wash. There is no darker orange to hover into, because a
   seventh colour would be a seventh colour. */
.legacy .btn {
  display: inline-flex; align-items: center; gap: 8px; justify-content: center;
  font-family: var(--font-body); font-size: var(--step-0); font-weight: 600;
  padding: 13px 26px; border-radius: var(--pill); border: 1px solid transparent;
  background: var(--ink); color: var(--paper); text-decoration: none; cursor: pointer;
  min-height: 44px;
  transition: background var(--t-hover) var(--ease), transform var(--t-press) var(--ease), border-color var(--t-hover) var(--ease);
}
/* color is re-declared at hover because the global link hover (Steel to
   ink) otherwise outranks the button and inks the label into its own fill
   (the vanishing-label bug, found twice on 2026-08-25). */
.legacy .btn:hover { border-color: var(--spark); transform: translateY(-1px); color: var(--paper); }
.legacy .btn:active { transform: translateY(1px); }
.legacy .btn.quiet { background: transparent; border-color: var(--hairline); color: var(--ink); }
.legacy .btn.quiet:hover { border-color: var(--ink); background: transparent; color: var(--ink); }
.legacy .btn.spark { background: var(--spark); color: var(--ink); box-shadow: var(--sh-md); }
.legacy .btn.spark:hover { background: var(--spark); color: var(--ink); border-color: var(--ink); }
/* THE STEEL BUTTON (2026-08-25): the tertiary rung of the family, for
   actions that are structure rather than sale. Hollow steel at rest; on
   hover the state swaps — steel fill, Paper label — with the family glow
   in steel. Spark stays the only primary accent. */
.legacy .btn.steel { background: transparent; border-color: var(--chrome); color: var(--chrome); }
.legacy .btn.steel:hover {
  background: var(--chrome); border-color: var(--chrome); color: var(--paper);
  box-shadow: 0 0 0 1px var(--chrome), 0 0 14px color-mix(in srgb, var(--chrome) 40%, transparent);
}
/* Steel fails on Midnight at 2.1:1, so the dark-band variant lifts the steel
   toward Paper for both the border and the label. */
/* The background is re-declared, not inherited, and that is the whole point:
   `.band-dark .btn` fills every button on a dark band with Paper, so a steel
   variant that only sets border and label renders pale steel type on white
   and vanishes. Same family as the hover bug this file already fixed once.
   Declare all three properties or the variant is a trap. */
.legacy .band-dark .btn.steel { background: transparent; border-color: color-mix(in srgb, var(--chrome) 45%, var(--paper)); color: color-mix(in srgb, var(--chrome) 28%, var(--paper)); }
.legacy .band-dark .btn.steel:hover {
  background: color-mix(in srgb, var(--chrome) 45%, var(--paper)); color: var(--ink);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--chrome) 45%, var(--paper)), 0 0 14px color-mix(in srgb, var(--chrome) 30%, transparent);
}
.legacy .band-dark .btn { background: var(--paper); color: var(--ink); }
/* color is DECLARED here, and the reason is specificity, not caution: the
   dark-band link rule `.band-dark a:hover` carries an element selector, so
   at (0,2,1) it outranks `.band-dark .btn` at (0,2,0) and repainted this
   label Paper on a Paper pill. The earlier vanishing-label fixes patched
   .btn rules and never found it because the culprit was never a .btn rule.
   (0,3,0) settles it. If a label vanishes on a colored band again, look for
   an `a` in the winning selector before touching the button rules. */
/* The hero CTA's hover, verbatim (DJ 2026-08-26): a solid button on a dark
   band rests paper and fills spark on hover, white label, the house glow.
   Declaring color here is still load-bearing: .band-dark a:hover at (0,2,1)
   repaints anchor labels and this rule at (0,3,0) is what outranks it. */
.legacy .band-dark .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); }
.legacy .band-dark .btn.quiet { background: transparent; border-color: var(--hairline-d); color: var(--paper); }
.legacy .band-dark .btn.quiet:hover { border-color: var(--spark); color: var(--paper); }
.legacy .btnrow { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 26px; }

/* ---- TABLES -------------------------------------------------------------- */
/* P05: hairline row rules, no vertical rules, no zebra striping. Numbers
   right-aligned and tabular, always. */
.legacy .list-wrap { overflow-x: auto; border: 1px solid var(--hairline); border-radius: var(--r); background: var(--card); }
/* WIDE CONTENT SCROLLS INSIDE ITSELF, never past the page (2026-08-27).
   The brand-os colour-law table could not shrink under its own content, so on
   a 320px screen it pushed the whole document 20px sideways, and on 375 it
   squeezed the reason column into a 72px ribbon of one-word lines. A table
   with real columns has a legitimate minimum; the fix is to let it keep that
   minimum and scroll, not to crush it. min-width is what forces the scroll
   rather than the squeeze. */
.legacy .tablewrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.legacy .tablewrap > table { min-width: 460px; }

.legacy table.list { width: 100%; border-collapse: collapse; font-size: var(--step--1); }
.legacy table.list th {
  background: var(--band); text-align: left; padding: 11px 16px;
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
  border-bottom: 1px solid var(--hairline); white-space: nowrap;
}
.legacy table.list td { padding: 12px 16px; border-bottom: 1px solid var(--hairline); vertical-align: top; }
.legacy table.list tr:last-child td { border-bottom: 0; }
/* No row hover, deliberately (2026-08-26). Both tables using this class are
   non-interactive: the education rows on /experience/ and the brain file
   results, whose rows carry no links and no click handler. A hover wash on
   a row that does nothing is a false affordance, and on the dark education
   band it was worse than false: --band is a light wash and those cells set
   Paper type inline, so hovering painted white text onto near-white. If a
   clickable table.list ever exists, give IT a hover, not the class. */
.legacy table.list td.num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; white-space: nowrap; text-align: right; }

/* ---- NOTES --------------------------------------------------------------- */
.legacy .note {
  border-left: 3px solid var(--primary); background: var(--band);
  padding: 16px 20px; border-radius: 0 var(--r) var(--r) 0;
  font-size: var(--step--1);
}
.legacy .note p:last-child { margin-bottom: 0; }
/* A True North rule is a rule, so it is legal on a light ground. The label
   beside it is not orange, because orange is never type on white. */
.legacy .note.warn { border-left-color: var(--spark); }
/* Meridian is the information rung (2026-08-25): a note that reports state
   rather than warns carries the beacon edge over its own faint wash. The
   rule and the wash are fills, legal on light; the type stays ink/muted. */
.legacy .note.info { border-left-color: var(--beacon); background: var(--wash-beacon); }
/* THERE IS NO RED IN THIS PALETTE. The old .note.flag was the alert red and
   its 7% wash; both are deleted by law, not repointed. The T07 error pattern
   replaces them exactly: a 2px Midnight Green border, the glyph, and a Plex
   Mono line — never True North, which means action, not failure. */
.legacy .note.flag {
  border: 2px solid var(--ink); border-radius: var(--r);
  background: var(--card); padding: 15px 19px;
}
.legacy .note-label {
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--primary);
  display: block; margin-bottom: 6px;
}
.legacy .note.warn .note-label { color: var(--ink); }
.legacy .note.flag .note-label { color: var(--ink); }
.legacy .note.flag .note-label::before { content: "\2715"; margin-right: 8px; font-weight: 700; }

/* ---- STEPS --------------------------------------------------------------- */
.legacy .steps { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr)); counter-reset: s; }
.legacy .step { border-top: 2px solid var(--hairline); padding-top: 16px; counter-increment: s; }
.legacy .step::before {
  content: counter(s, decimal-leading-zero);
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--step--1); font-weight: 600;
  color: var(--primary); display: block; margin-bottom: 8px;
}
.legacy .step h3 { font-size: var(--step-0); margin-bottom: .3em; }
.legacy .step p { font-size: var(--step--1); color: var(--muted); margin: 0; }
.legacy .band-dark .step { border-top-color: var(--hairline-d); }
.legacy .band-dark .step::before { color: var(--spark); }
.legacy .band-dark .step p { color: var(--dim-d); }

/* ---- PILLARS ------------------------------------------------------------- */
.legacy .pillar { border-top: 2px solid var(--ink); padding-top: 18px; }
.legacy .pillar .n {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--step--1); font-weight: 600;
  color: var(--primary); display: block; margin-bottom: 10px; letter-spacing: .08em;
}
.legacy .pillar h3 { font-size: var(--step-1); margin-bottom: .4em; }
.legacy .pillar p { color: var(--muted); font-size: var(--step--1); margin: 0; }
.legacy .band-dark .pillar { border-top-color: var(--hairline-d); }
.legacy .band-dark .pillar .n { color: var(--spark); }

/* ---- QUOTES / TESTIMONIALS ---------------------------------------------- */
.legacy .quote { border-left: 2px solid var(--primary); padding-left: 22px; }
.legacy .band-dark .quote { border-left-color: var(--spark); }
.legacy .quote blockquote {
  margin: 0 0 16px; font-family: var(--font-display);
  font-weight: 500; font-size: var(--step-1); line-height: 1.45; letter-spacing: -.012em;
}
.legacy .quote cite { font-style: normal; font-size: var(--step--1); color: var(--muted); display: block; }
.legacy .quote cite b { color: var(--ink); font-weight: 600; display: block; }
.legacy .band-dark .quote cite { color: var(--dim-d); }
.legacy .band-dark .quote cite b { color: var(--paper); }

/* ---- PLACEHOLDER — every one is visible and labelled -------------------- */
.legacy .ph {
  position: relative; display: grid; place-items: center; text-align: center;
  background:
    repeating-linear-gradient(-45deg, transparent 0 9px, var(--hairline) 9px 10px),
    var(--band);
  border: 1px dashed color-mix(in srgb, var(--spark) 45%, transparent);
  border-radius: var(--r); color: var(--primary);
  font-family: var(--font-mono); font-size: var(--step--1); font-weight: 600;
  letter-spacing: .06em; padding: 24px; min-height: 120px;
}
.legacy .ph small { display: block; font-weight: 400; color: var(--muted); letter-spacing: 0; margin-top: 6px; max-width: 34ch; }
.legacy .ph-figure { aspect-ratio: 4 / 5; }
.legacy .band-dark .ph { background: transparent; border-color: var(--hairline-d); color: var(--spark); }
.legacy .band-dark .ph small { color: var(--dim-d); }

/* ---- FOOTER -------------------------------------------------------------- */
.legacy .ft { background: var(--ink-deep); color: var(--dim-d); font-size: var(--step--1); }
.legacy .ft-in { max-width: var(--wrap-wide); margin-inline: auto; padding: 56px var(--gutter) 40px; }
.legacy .ft-grid { display: grid; gap: 32px; grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr)); }
.legacy .ft h4 {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--paper); margin-bottom: 14px; font-weight: 600;
}
.legacy .ft a { color: var(--dim-d); text-decoration: none; display: block; padding: 5px 0; }
.legacy .ft a:hover { color: var(--spark); }
.legacy .ft-base {
  margin-top: 40px; padding-top: 24px; border-top: 1px solid var(--hairline-d);
  display: flex; flex-wrap: wrap; gap: 16px; justify-content: space-between; align-items: center;
}
.legacy .ft-build { font-family: var(--font-mono); font-size: 11px; color: var(--dim-d); max-width: 62ch; line-height: 1.6; }

/* ---- PAGE HERO (interior pages) ----------------------------------------- */
.legacy .phero { background: var(--grad-ground); color: var(--paper); }
.legacy .phero-in { max-width: var(--wrap); margin-inline: auto; padding: clamp(48px, 7vw, 92px) var(--gutter); }
.legacy .phero h1 { font-family: var(--font-display); font-weight: 800; letter-spacing: -.02em; color: var(--paper); }
.legacy .phero .lede { color: var(--dim-d); }
.legacy .phero .kicker { color: var(--spark); }

/* ---- PRINT --------------------------------------------------------------- */
/* One ink on stock. The black master is 100K only and the surface, the glass
   and every blur come off — so these are reproduction values, not palette
   values, and they are the only literal colours in this file. */
/* ---- the contact photo strip (2026-08-26, DJ's ask) ----------------------
   Four photographs on the one page whose job is being a person. Uniform
   crop height so four different orientations read as one strip; captions in
   the mono voice the site uses for facts, because that is what they are. */
.legacy .pgal { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-top: var(--sp-5); }
.legacy .pgal figure { margin: 0; }
.legacy .pgal img { width: 100%; height: 300px; object-fit: cover; border-radius: var(--r); border: 1px solid var(--hairline); display: block; }
/* A 3:4 portrait dropped into this 300px landscape box crops from the middle,
   which puts the cut straight through the faces. Anchoring to the top keeps
   heads in frame; the empty floor of a portrait is the part to lose. */
.legacy .pgal img.pgal-top { object-position: 50% 0%; }
.legacy .pgal figcaption { margin-top: 8px; font-family: var(--font-mono); font-size: 11px; letter-spacing: .06em; color: var(--muted); }
@media (max-width: 900px) { .legacy .pgal { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .legacy .pgal img { height: 200px; } }

@media print {
  .legacy .hd,.legacy .ft,.legacy .skip,.legacy .btnrow,.legacy .splith-fx { display: none !important; }
  .legacy :scope { background: #fff; color: #000; font-size: 10.5pt; }
  .legacy .band-dark,.legacy .phero,.legacy .proof,.legacy .splith { background: #fff !important; color: #000 !important; }
  .legacy .band-dark *,.legacy .phero *,.legacy .proof *,.legacy .splith * { color: #000 !important; }
  .legacy a { text-decoration: none; color: #000; }
  .legacy .card { border: 1px solid #ccc; break-inside: avoid; }
  .legacy .section { padding-block: 18pt; }
}

/* ---- ANNOTATED SOURCE EXCERPTS ------------------------------------------- */
/* The syntax palette was seven off-token colours measured against a ground
   that had already moved twice — one comment claimed #002B2B, another
   claimed #0D0F11, and the file rendered on neither. It is rebuilt here from
   the six, on one ground, with one set of numbers.

   THE GROUND is --ink-deep, which in v3 is Midnight Green #00272C. Every
   ratio below was computed against that exact value on 2026-08-13:

     plain    --paper    #FFFFFF  15.83:1  code, the default
     comment  --dim-d    #A8B6B7   7.57:1  66% white on Midnight, prose in source
     keyword  --beacon   #279AF1   5.26:1  Meridian
     string   --signal   #09E85E   9.59:1  Landfall
     number   --signal   #09E85E   9.59:1  a literal is a literal; they share
     regex    --spark    #FF6B1C   5.56:1  True North. The patterns ARE the
                                           argument in these excerpts, and this
                                           is the one ground where orange is
                                           legal as body-sized type.
     call     --paper    #FFFFFF  15.83:1  distinguished by WEIGHT, not by a
                                           seventh colour
     numbers  --dim-d    #A8B6B7   7.57:1  line numbers. The old value measured
                                           4.72:1; this one is not a nudge, it
                                           is the token that already existed.

   The signal pair is allowed here and nowhere else on a light page: the
   Brand OS clears it "inside a product demo or diagram frame only, where the
   frame makes clear it is not chrome." The .code-head names the source file,
   so the frame is doing exactly that job. */

.legacy .code {
  margin: 34px 0 0; padding: 0;
  border: 1px solid var(--hairline); border-radius: var(--r);
  overflow: hidden; background: var(--card);
}
.legacy .code-head {
  display: flex; flex-wrap: wrap; gap: 6px 18px; align-items: baseline;
  justify-content: space-between;
  padding: 12px 18px; background: var(--band);
  border-bottom: 1px solid var(--hairline);
}
.legacy .code-file { font-size: var(--step--1); font-weight: 600; color: var(--ink); word-break: break-all; }
.legacy .code-repo { font-size: 11px; letter-spacing: .10em; text-transform: uppercase; color: var(--faint); }
.legacy .code-cap {
  margin: 0; padding: 14px 18px; font-size: var(--step--1); line-height: 1.6;
  color: var(--muted); border-bottom: 1px solid var(--hairline); max-width: none;
}
.legacy .code-body {
  display: grid; grid-template-columns: minmax(0, 1fr) 300px;
  gap: 0; align-items: stretch;
}
@media (max-width: 1040px) { .legacy .code-body { grid-template-columns: minmax(0, 1fr); } }

.legacy .code-pre {
  margin: 0; padding: 18px 0; overflow-x: auto; background: var(--ink-deep);
  font-family: var(--font-mono); font-size: 13px; line-height: 1.62;
  color: var(--paper); tab-size: 2; font-variant-numeric: tabular-nums;
}
.legacy .code-pre code { display: block; min-width: max-content; }

/* The left inset gives the rail marker its own lane so it never crowds a
   two-digit line number. */
.legacy .ln { display: block; position: relative; padding: 0 18px 0 20px; }
.legacy .ln-n {
  display: inline-block; width: 3.2em; padding-right: 1.1em; text-align: right;
  color: var(--dim-d); user-select: none; -webkit-user-select: none;
}
.legacy .ln-c { white-space: pre; }
/* A marked line gets a rule and a tint, and carries the rail's number at the
   end so the pairing survives when the rail wraps underneath on a phone. */
.legacy .ln--mark { background: color-mix(in srgb, var(--spark) 13%, transparent); box-shadow: inset 3px 0 0 var(--spark); }
.legacy .ln--gap .ln-c { color: var(--dim-d); font-style: italic; }
/* The rail marker lives in the left gutter, beside the right-aligned line
   number. It was originally floated right and sticky, which kept it in view
   while the excerpt scrolled horizontally but sat it directly on top of the
   code. A marker that obscures the line it is pointing at has defeated itself.
   The disc is a True North fill and its digit is Midnight Green at 5.6:1 —
   it used to be Paper White on burnt orange, and white on True North is
   2.8:1. */
.legacy .ln-b {
  position: absolute; left: 1px; top: 2px;
  width: 16px; height: 16px;
  border-radius: 50%; background: var(--spark); color: var(--ink);
  font-size: 9.5px; font-weight: 700; line-height: 16px; text-align: center;
}

.legacy .code-rail {
  padding: 18px; background: var(--card);
  border-left: 1px solid var(--hairline);
}
@media (max-width: 1040px) { .legacy .code-rail { border-left: 0; border-top: 1px solid var(--hairline); } }
/* Self-contained so an excerpt can appear on a page that does not load
   brain.css. Same visual language as the brain-demo rail. */
.legacy .code-rail .anno { border-left: 2px solid var(--spark); padding: 2px 0 2px 14px; margin-bottom: 20px; position: relative; }
.legacy .code-rail .anno:last-child { margin-bottom: 0; }
.legacy .code-rail .anno-l {
  font-family: var(--font-mono); font-size: 10px; font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--primary); display: block; margin-bottom: 5px;
}
.legacy .code-rail .anno p { font-size: var(--step--1); line-height: 1.55; color: var(--muted); margin: 0; max-width: none; }
.legacy .anno--num .anno-n {
  position: absolute; left: -10px; top: 0;
  width: 17px; height: 17px; border-radius: 50%;
  background: var(--spark); color: var(--ink);
  font-family: var(--font-mono); font-size: 10px; font-weight: 700;
  line-height: 17px; text-align: center;
}
.legacy .anno--num { padding-left: 20px; border-left: 0; }

@media print {
  .legacy .code-pre { background: #fff; color: #000; }
  /* Colour set on the token spans beats colour inherited from the <pre>, so
     without this the syntax palette prints light-on-white and the excerpt is
     effectively blank on paper. (This block once served the /resume/ page,
     which is gone; it stays because printed excerpts are still a real
     output.) */
  .legacy .code-pre [class^="t-"] { color: #000; }
  .legacy .ln--gap .ln-c { color: #444; }
  .legacy .ln-n { color: #666; }
  .legacy .ln--mark { background: #f0f0f0; box-shadow: none; }
  .legacy .code-body { grid-template-columns: 1fr; }
  .legacy .code,.legacy .code-pre { break-inside: avoid; }
}

/* ---- PRESS FEEDBACK, SITE-WIDE ------------------------------------------- */
/* Same asymmetry as the brain demo: acknowledge in --t-press, settle in
   --t-release. The card already lifts on hover, so on press it returns to the
   ground rather than lifting further. A thing you push should go down. */
.legacy .card,.legacy .btn,.legacy .go,.legacy .splith-half { transition-duration: var(--t-release); }
.legacy .card:active,.legacy .btn:active,.legacy .go:active { transition-duration: var(--t-press); }
.legacy .card:active { transform: none; border-color: var(--primary); }
.legacy .cl summary:active,.legacy details > summary:active { transition-duration: var(--t-press); }

/* ---- THE OTHER TWO PREFERENCES ------------------------------------------
   Reduced motion was handled from the start. These two were not, and the
   header is the reason they matter: it is a translucent layer over scrolling
   content, which is exactly the construct both preferences exist to opt out of.

   Neither is a hypothetical. `prefers-reduced-transparency` is what a reader
   with a vestibular or focus condition sets when blurred chrome makes text
   swim, and `prefers-contrast` is set by readers who need edges rather than
   suggestions. A site arguing that accessibility is a pass rather than an
   afterthought should answer all three signals, not the one that was easy.

   The Brand OS says the same thing about the glass: anyone who sets reduced
   transparency gets the solid, not a thinner blur.
   ------------------------------------------------------------------------ */
@media (prefers-reduced-transparency: reduce) {
  .legacy .hd {
    background: var(--ground);
    backdrop-filter: none; -webkit-backdrop-filter: none;
    border-bottom: 1px solid var(--hairline-d);
  }
  .legacy .bd-tabs { background: var(--paper); background-attachment: scroll; }
  .legacy .splith-fx { display: none; }
}

@media (prefers-contrast: more) {
  .legacy {
    /* Hairlines become visible edges, and the tertiary text tier stops being
       tertiary. --faint measures 5.1:1 on white, which passes and still reads
       as low contrast by design; at this setting that intent is wrong. */
    --hairline:   color-mix(in srgb, var(--ink) 42%, transparent);
    --hairline-d: color-mix(in srgb, var(--paper) 46%, transparent);
    --faint:      var(--muted);
    --dim-d:      color-mix(in srgb, var(--paper) 82%, transparent);
  }
  .legacy .hd { background: var(--ground); backdrop-filter: none; -webkit-backdrop-filter: none; }
  .legacy .card,.legacy .code,.legacy .bd-detail { border-width: 2px; }
  .legacy .btn { border-width: 2px; }
  .legacy a:not(.btn) { text-decoration: underline; text-underline-offset: 2px; }
  .legacy .bd-tab[aria-selected="true"] { border-bottom-width: 3px; }
}

/* The syntax colours documented above. Every one is a token; the ground they
   are measured against is --ink-deep, #00272C. */
.legacy .t-c { color: var(--dim-d); font-style: italic; }  /* comment   7.57:1  */
.legacy .t-k { color: var(--beacon); }                     /* keyword   5.26:1  */
.legacy .t-s { color: var(--signal); }                     /* string    9.59:1  */
.legacy .t-r { color: var(--spark); }                      /* regex     5.56:1  */
.legacy .t-n { color: var(--signal); }                     /* number    9.59:1  */
.legacy .t-f { color: var(--paper); font-weight: 600; }    /* call     15.83:1  */
.legacy .t-p { color: var(--paper); }                      /* plain    15.83:1  */

/* ---- MOBILE NAV ENTRANCE -------------------------------------------------
   The menu is a panel growing out of the header, so it enters from the edge
   it is anchored to: a short fade and settle downward, 200ms. It previously
   appeared with no bridge at all. Exit stays instant, deliberately: the
   panel is display-toggled, and a dismissal should never make the user wait.
   Reduced motion removes this via the global rule in tokens.css. */
@media (max-width: 900px) {
  .legacy .hd nav.open { animation: navIn var(--t-release) var(--ease); }
}
@keyframes navIn { from { opacity: 0; transform: translateY(-6px); } }


/* ---- THE LOOP STRIP (homepage) ------------------------------------------- */
/* The seven-step operating loop as one readable line. Scrolls in its own row
   on small screens, per the house rule that the page never scrolls sideways. */
.legacy .loop-strip { display: flex; gap: 0; overflow-x: auto; padding: 26px 0 10px; scrollbar-width: thin; }
.legacy .loop-step { flex: 1 0 130px; min-width: 130px; position: relative; padding: 0 18px 0 0; }
.legacy .loop-step + .loop-step { padding-left: 18px; border-left: 1px solid var(--hairline-d); }
.legacy .loop-k { font-family: var(--font-mono); font-size: 10.5px; font-weight: 600; letter-spacing: .14em; color: var(--spark); display: block; margin-bottom: 6px; }
.legacy .loop-t { font-weight: 600; font-size: var(--step--1); color: var(--paper); display: block; margin-bottom: 4px; }
.legacy .loop-d { font-size: 12.5px; line-height: 1.5; color: var(--dim-d); display: block; max-width: 24ch; }

/* ---- THE SIDEBAR SHELL ----------------------------------------------------
   Layout pivot, 2026-08-11, on DJ's direction: a fixed left rail in the manner
   of the Sidefolio template, with the split-persona hero kept from the Adham
   Dannaway lineage the original hero already followed. The brand tokens are
   unchanged on purpose: the references contribute ARCHITECTURE and air, not a
   new identity. Below 1024px the rail hands over to the existing top bar. */
.legacy .sb {
  position: fixed; inset-block: 0; left: 0; width: 264px; z-index: 90;
  display: flex; flex-direction: column; gap: 26px;
  padding: 30px 26px 26px; overflow-y: auto;
  background: var(--card); border-right: 1px solid var(--hairline);
}
.legacy .sb-mark { display: flex; gap: 12px; align-items: center; text-decoration: none; color: var(--ink); }
.legacy .sb-mark b { font-family: var(--font-display); font-weight: 800; font-size: 1.05rem; letter-spacing: -.02em; display: block; line-height: 1.15; }
/* THE NEEDLE, ON A WHITE GROUND.
   True North is never type on white at any size — 2.8:1, and the law is
   flat. The wordmark's period is therefore not set as a glyph here: the
   character is made transparent and a square takes its place, because on
   light this colour is a fill, a rule, or a shape and nothing else. On the
   dark header the glyph stands on its own at 5.6:1, so it needs no shape. */
.legacy .sb-mark b .dot { color: transparent; position: relative; }
.legacy .sb-mark b .dot::after {
  content: ""; position: absolute; left: .02em; bottom: .05em;
  width: .18em; height: .18em; border-radius: 1px; background: var(--spark);
}
.legacy .hd-mark b .dot { color: var(--spark); }
.legacy .sb-mark i { font-style: normal; font-size: 11.5px; color: var(--faint); display: block; margin-top: 2px; }
.legacy .sb-nav { display: flex; flex-direction: column; gap: 2px; }
.legacy .sb-nav a {
  font-size: .92rem; font-weight: 500; color: var(--muted); text-decoration: none;
  padding: 8px 10px; border-radius: var(--r-sm); position: relative;
  transition: color var(--t-hover) var(--ease), background var(--t-hover) var(--ease);
}
.legacy .sb-nav a:hover { color: var(--ink); background: var(--band); }
.legacy .sb-nav a:active { transition-duration: var(--t-press); background: var(--band); }
.legacy .sb-nav a[aria-current="page"] { color: var(--ink); font-weight: 600; background: var(--band); }
.legacy .sb-nav a[aria-current="page"]::before {
  content: ""; position: absolute; left: 0; top: 9px; bottom: 9px; width: 2.5px;
  border-radius: 2px; background: var(--spark);
}
.legacy .sb-nav--dim a { font-size: .85rem; color: var(--faint); }
.legacy .sb-sep { display: block; height: 1px; background: var(--hairline); }
.legacy .sb-foot { margin-top: auto; display: flex; flex-direction: column; gap: 14px; }
.legacy .sb-cta {
  width: 100%; font-size: var(--step--1); padding: 11px 18px; min-height: 44px;
  background: var(--spark); color: var(--ink); box-shadow: var(--sh-sm);
}
.legacy .sb-cta:hover { background: var(--spark); color: var(--ink); border-color: var(--ink); }
.legacy .sb-soc { display: flex; gap: 14px; }
.legacy .sb-soc a { font-size: .82rem; color: var(--muted); }
.legacy .sb-loc { margin: 0; font-family: var(--font-mono); font-size: 10.5px; color: var(--faint); }

.legacy .content { min-width: 0; }
@media (min-width: 1024px) {
  .legacy .hd { display: none; }
  .legacy .content { margin-left: 264px; }
  /* the fixed-position rail owns the left edge; wide wraps breathe less */
  .legacy .content .wrap--wide { max-width: 1240px; }
}
@media (max-width: 1023.9px) {
  .legacy .sb { display: none; }
}

/* Softer card language, from the references: a touch more radius and a resting
   shadow, lift kept subtle. Two shadow grades exist and there is no third:
   0 1px 3px at 5% for resting sheets, 0 12px 30px -14px at 22% for floating. */
.legacy .card { border-radius: var(--r); box-shadow: var(--sh-sm); }
.legacy .card:hover { box-shadow: var(--sh-md); }

/* ---- SIDEBAR v2: profile header, group labels, dropdowns ------------------ */
.legacy .sb { gap: 18px; }
.legacy .sb-ava { width: 44px; height: 44px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; }
.legacy .sb-label {
  font-family: var(--font-mono); font-size: 10px; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--faint);
  padding: 10px 10px 0; border-top: 1px solid var(--hairline); margin-top: 6px;
}
.legacy .sb-dd summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; justify-content: space-between;
  font-size: .92rem; font-weight: 500; color: var(--muted);
  padding: 8px 10px; border-radius: var(--r-sm); user-select: none;
  transition: color var(--t-hover) var(--ease), background var(--t-hover) var(--ease);
}
.legacy .sb-dd summary::-webkit-details-marker { display: none; }
.legacy .sb-dd summary::after {
  content: ""; width: 7px; height: 7px; flex: 0 0 auto;
  border-right: 1.6px solid var(--faint); border-bottom: 1.6px solid var(--faint);
  transform: rotate(-45deg); transition: transform var(--t-hover) var(--ease); margin-right: 3px;
}
.legacy .sb-dd[open] summary::after { transform: rotate(45deg); }
.legacy .sb-dd summary:hover { color: var(--ink); background: var(--band); }
.legacy .sb-sub { display: flex; flex-direction: column; gap: 1px; padding: 2px 0 4px 12px; border-left: 1px solid var(--hairline); margin-left: 12px; }
.legacy .sb-sub a { font-size: .85rem !important; padding: 6px 10px !important; }

/* ---- TESTIMONIAL MARQUEE (home) ------------------------------------------ */
/* One slow horizontal loop of the seven cards, duplicated once for seamless
   wrap. Pauses on hover. Under reduced motion the loop is REMOVED, never
   slowed: the track becomes a scrollable row. */
.legacy .tmq { overflow: hidden; margin-top: 26px; }
.legacy .tmq-track { display: flex; gap: 16px; width: max-content; padding-inline: var(--gutter);
  animation: tmq 80s linear infinite; }
.legacy .tmq:hover .tmq-track { animation-play-state: paused; }
@keyframes tmq { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.legacy .tmq-card {
  flex: 0 0 340px; margin: 0; background: var(--card); border: 1px solid var(--hairline);
  border-radius: var(--r); box-shadow: var(--sh-sm); padding: 22px;
}
.legacy .tmq-card blockquote { margin: 0 0 14px; font-size: var(--step--1); line-height: 1.6; color: var(--ink); }
.legacy .tmq-card figcaption { border-top: 1px solid var(--hairline); padding-top: 10px; }
.legacy .tmq-card figcaption strong { display: block; font-size: .9rem; }
.legacy .tmq-card figcaption span { font-size: 12px; color: var(--muted); }
@media (prefers-reduced-motion: reduce) {
  .legacy .tmq { overflow-x: auto; }
  .legacy .tmq-track { animation: none; }
}

/* ==== SYSTEM SCREENSHOT FIGURES (2026-08-26 image placement) ==============
   The frame is a link, so it needs the interactive treatment the rest of the
   site gives links: the spark-glow family on hover, and a real focus ring.
   The image is capped at 1000px because that is the widest any of these is
   legible inline, and the file behind it is 2000px so the cap is a 2x source
   on a retina screen rather than a smudge.

   The caption carries two things: what the figure shows, and, on the six
   reconstructions, the disclosure. The disclosure is set apart visually but
   NOT dimmed below the caption it sits in, because a disclaimer nobody can
   read is a disclaimer that was not made. */
.legacy .sfig { margin: var(--sp-6) 0; max-width: 1000px; }
.legacy .sfig--wide { max-width: none; }
.legacy .sfig-frame {
  display: block; border: 1px solid var(--hairline); border-radius: var(--r);
  overflow: hidden; background: var(--card); text-decoration: none;
  transition: border-color var(--t-hover) var(--ease), box-shadow var(--t-hover) var(--ease), transform var(--t-hover) var(--ease);
}
.legacy .sfig-frame img { display: block; width: 100%; height: auto; }
.legacy .sfig-frame:hover {
  border-color: var(--spark); transform: translateY(-2px);
  box-shadow: 0 0 0 1px var(--spark), 0 0 14px color-mix(in srgb, var(--spark) 30%, transparent);
}
.legacy .sfig-frame:focus-visible { outline: 2px solid var(--spark); outline-offset: 3px; }
.legacy .sfig figcaption {
  margin-top: var(--sp-3); font-size: var(--step--1); line-height: 1.55;
  color: var(--muted); max-width: var(--measure);
}
.legacy .sfig-recon { display: block; margin-top: var(--sp-1); font-family: var(--font-mono); font-size: 12px; line-height: 1.5; color: var(--muted); }
/* padding-block is the target, not decoration (2026-08-27). At 11.5px this
   link boxed out at 109x18, under the 24px floor, and it is a standalone
   control rather than a link inside a sentence, so the exemption does not
   reach it. The negative inline margin keeps it optically flush with the
   caption above while the hit area grows. */
.legacy .sfig-open {
  display: inline-block; margin-top: var(--sp-2); font-family: var(--font-mono);
  font-size: 11.5px; letter-spacing: .08em; text-transform: uppercase;
  padding-block: 5px; margin-inline: -2px; padding-inline: 2px;
}
.legacy .band-dark .sfig figcaption,.legacy .band-dark .sfig-recon { color: var(--dim-d); }
.legacy .band-dark .sfig-frame { border-color: var(--hairline-d); background: transparent; }

/* ---- PHOTOGRAPHS --------------------------------------------------------- */
.legacy .pfig { margin: var(--sp-6) 0; }
.legacy .pfig img { display: block; width: 100%; height: auto; border-radius: var(--r); }
.legacy .pfig figcaption { margin-top: var(--sp-3); font-size: var(--step--1); line-height: 1.55; color: var(--muted); }
.legacy .band-dark .pfig figcaption { color: var(--dim-d); }
/* The portrait crop earns a two-column layout rather than a full-width band:
   at full width a 3:4 image becomes a wall. The text column carries the
   argument and the picture sits beside it. */
.legacy .photo-two { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 320px); gap: var(--sp-7); align-items: center; }
.legacy .photo-two .pfig { margin: 0; }
@media (max-width: 720px) {
  .legacy .photo-two { grid-template-columns: minmax(0, 1fr); gap: var(--sp-5); }
  .legacy .photo-two .pfig { max-width: 320px; }
}

/* ============================================================================
   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 */
.legacy .shell3 .content { margin: 0 !important; max-width: none !important; width: auto !important; padding: 0 !important; }
.legacy .shell3 main { display: block; }
.legacy .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. */
.legacy .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; }
.legacy .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); }
.legacy .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. */
.legacy .hd3-brand { display: flex; align-items: center; gap: 14px; text-decoration: none; flex: 0 0 auto; }
.legacy .hd3-brandicon { width: 34px; height: 34px; display: block; flex: 0 0 34px; }
.legacy .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; }
.legacy .hd3-div { width: 1px; height: 26px; background: var(--hairline-d); }
.legacy .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) { .legacy .hd3-div,.legacy .hd3-page { display: none; } }
.legacy .hd3-nav { display: flex; align-items: center; gap: 2px; margin-left: auto; }
.legacy .hd3-nav > a,.legacy .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; }
.legacy .hd3-nav > a:hover,.legacy .h3grp > button:hover,.legacy .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. */
.legacy .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); }
.legacy .h3grp.on > button { color: var(--paper); box-shadow: inset 0 -2px 0 var(--spark); }
.legacy .h3grp { position: relative; }
.legacy .h3grp .car { font-size: 10px; opacity: .7; }
.legacy .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; }
.legacy .h3grp.open .h3dd,.legacy .h3grp:focus-within .h3dd { display: flex; }
@media (hover: hover) { .legacy .h3grp:hover .h3dd { display: flex; } }
.legacy .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); }
.legacy .h3dd a:hover { color: var(--paper); background: color-mix(in srgb, var(--paper) 12%, transparent); }
.legacy .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. */
.legacy .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; }
.legacy .hd3-cta .cta-glyph { display: inline-flex; animation: ctaSpin 9s linear infinite; }
.legacy .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); } }
.legacy .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); }
.legacy .hd3-cta:hover .cta-glyph svg { transform: scale(1.18); color: var(--spark); }
@media (prefers-reduced-motion: reduce) { .legacy .hd3-cta .cta-glyph,.legacy .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. */
.legacy .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); }
.legacy .hd3-burger:hover { border-color: var(--spark); color: var(--spark); }
@media (max-width: 1080px) {
  .legacy .hd3-nav { display: none; }
  .legacy .hd3-burger { display: inline-flex; }
  .legacy .hd3-right { margin-left: auto; }
}
@media (max-width: 560px) { .legacy .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 */
.legacy .hd3.solid { background: var(--ground); }

/* ---------- the drawer ---------- */
.legacy .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; }
.legacy .drw3-scrim.show { opacity: 1; pointer-events: auto; }
.legacy .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; }
.legacy .drw3.open { transform: none; }
.legacy .drw3-h { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.legacy .drw3-h b { font-family: var(--font-display); color: var(--paper); font-size: 17px; }
.legacy .drw3-h .dot { color: var(--spark); }
.legacy .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); }
.legacy .drw3-h button:hover { color: var(--spark); }
.legacy .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. */
.legacy .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); }
.legacy .drw3 nav a:not(.drw3-cta):hover { background: var(--hairline-d); color: var(--spark); transform: translateX(2px); }
.legacy .drw3 nav a.drw3-sub { font-size: 13.5px; font-weight: 500; color: var(--dim-d); padding: 7px 10px 7px 22px; }
.legacy .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. */
.legacy .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); }
.legacy .drw3-cta .cta-glyph { display: inline-flex; animation: ctaSpin 9s linear infinite; }
.legacy .drw3-cta .cta-glyph svg { display: block; transition: transform var(--t-hover) var(--ease), color var(--t-hover) var(--ease); }
.legacy .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); }
.legacy .drw3-cta:hover .cta-glyph svg { transform: scale(1.18); }
.legacy .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. */
.legacy .hd3 :focus-visible,.legacy .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. */
.legacy .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; }
.legacy .hero3-fx { position: absolute; inset: 0; z-index: 0; }
.legacy .hero3-fx canvas { width: 100%; height: 100%; display: block; }
.legacy .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%); }
.legacy .hero3-wrap { position: relative; z-index: 2; max-width: 1180px; margin: 0 auto; padding: 0 28px; }
.legacy .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. */
.legacy .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. */
.legacy .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. */
.legacy .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); }
/* 1000px, not 760 (DJ's call, 2026-08-28). The glass card's inner width is
   1034px at a 1280 viewport, so a 760px cap left 274px of the card unused
   and wrapped this to three lines. Measured wrap points for this exact
   string: three lines up to 940px, two from 980px. 1000px is chosen to sit
   clear of that 980 boundary, because a cap sitting ON the boundary
   re-wraps the moment a webfont loads slightly wider than the fallback. */
.legacy .hero3-sub { font-size: clamp(15px, 1.6vw, 18px); line-height: 1.65; color: var(--dim-d); max-width: 1000px; margin: 0 auto 18px; }
.legacy .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. */
/* One line, which is what a credential line should be. It broke at 620px;
   measured, it fits on one from 760px up, so 820px carries real margin
   past that. Narrower than .hero3-sub on purpose: this is the quieter of
   the two lines and a shorter measure keeps that hierarchy. */
.legacy .hero3-cred { font-size: clamp(13.5px, 1.35vw, 15.5px); color: color-mix(in srgb, var(--dim-d) 82%, transparent); max-width: 820px; margin-top: -8px; }
.legacy .hero3-ctas { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
@media (max-width: 620px) { .legacy .glass3 { padding: 28px 22px 26px; border-radius: var(--r); } .legacy .hero3 { padding: 120px 0 64px; } }

/* ---------- the proof marquee ---------- */
.legacy .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; }
.legacy .pmq-track { display: flex; gap: 12px; width: max-content; animation: pmq-roll 56s linear infinite; }
.legacy .pmq:hover .pmq-track { animation-play-state: paused; }
@keyframes pmq-roll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.legacy .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; }
.legacy .pmq-chip b { font-family: var(--font-display); font-size: 15px; letter-spacing: 0; color: var(--spark); font-variant-numeric: tabular-nums; }
/* Reduced motion gets a readable STRIP, not a wall (fixed 2026-08-27).
   Stopping the animation and wrapping left all 36 chips in flow: measured
   2,049px tall at 390px wide, every fact printed twice, 13 chips clipped by
   the parent's overflow:hidden with no ellipsis. The document never scrolled
   sideways, so an overflow probe cannot see this at all.
   Now: drop the duplicate half, let a chip wrap its own text, and cap the
   strip so it stays a strip. */
@media (prefers-reduced-motion: reduce) {
  .legacy .pmq-track { animation: none; flex-wrap: wrap; width: auto; padding: 0 20px; justify-content: center; }
  .legacy .pmq-dupe { display: none; }
  .legacy .pmq-chip { white-space: normal; max-width: 100%; }
}

/* ---------- 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. */
.legacy .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; }
.legacy .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); }
.legacy .duo3 a .kicker { color: var(--spark); }
.legacy .duo3 a > p { color: var(--dim-d); max-width: 46ch; }
.legacy .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); }
.legacy .duo3 h2 { font-family: var(--font-display); font-size: 23px; margin: 6px 0 8px; color: var(--paper); }
.legacy .duo3-stat { font-family: var(--font-mono); font-size: 12px; letter-spacing: .04em; margin-top: 14px; }
.legacy .duo3-stat b { color: var(--spark); font-weight: 600; }
.legacy .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); }
.legacy .duo3 .go3 .ar { font-style: normal; }
.legacy .duo3 a:hover .go3 { gap: 12px; color: var(--spark); }
.legacy .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); }
.legacy .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. */
.legacy .duo3 a.duo3-spark { background: var(--spark-surface); border-color: transparent; }
.legacy .duo3 a.duo3-spark .kicker { color: var(--ink); }
.legacy .duo3 a.duo3-spark > p { color: color-mix(in srgb, var(--ink) 86%, var(--spark)); }
.legacy .duo3 a.duo3-spark h2 { color: var(--paper); }
.legacy .duo3 a.duo3-spark .duo3-stat b { color: var(--ink); }
.legacy .duo3 a.duo3-spark .go3 { color: var(--ink); }
.legacy .duo3 a.duo3-spark .duo3-glyph { color: var(--ink); opacity: .1; }
.legacy .duo3 a.duo3-spark:hover { border-color: var(--paper); }
.legacy .duo3 a.duo3-spark:hover .go3 { color: var(--paper); }
.legacy .duo3 a.duo3-spark:hover .duo3-glyph { color: var(--paper); opacity: .24; }

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

/* catalog cards (websites page) */
.legacy .cat3 { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(250px, 100%), 1fr)); gap: 14px; margin-top: 22px; }
.legacy .cat3 a,.legacy .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); }
.legacy .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); }
.legacy .cat3 .t { font-family: var(--font-display); font-weight: 700; font-size: 15.5px; }
.legacy .cat3 .d { font-size: 12.5px; color: var(--muted); margin: 0; }
.legacy .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. */
.legacy .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; }
.legacy .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. */
.legacy .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); }
.legacy .vid3:hover .vid3-play { transform: translateY(-2px); }
.legacy .vid3 iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* THE FACADE WITH A REAL STILL BEHIND IT (2026-08-27, DJ's ask).
   The card used to be a flat --ground rectangle with a play disc on it, which
   told the reader nothing about what they were about to watch. Now the frame
   from the keynote sits behind, dimmed enough that Paper White type and the
   spark disc still clear their floors on top of it.

   The scrim is doing contrast work, not styling. Over the lit projector screen
   in this photo, white label text measured under 3:1 unscrimmed. The 58% ink
   wash is what buys it back, and it deepens on hover rather than lifting, so
   the image never competes with the disc the eye is meant to land on. */
.legacy .vid3--shot .vid3-thumb { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block; }
.legacy .vid3--shot .vid3-inner { background: color-mix(in srgb, var(--ink) 58%, transparent);
  transition: background var(--t-hover) var(--ease); }
.legacy .vid3--shot:hover .vid3-inner { background: color-mix(in srgb, var(--ink) 46%, transparent); }
/* Full-strength Paper, no opacity. An earlier pass dimmed this line to 82%
   for a softer look, which pushed it from 4.67:1 to 3.74:1 over the
   lightest part of the photo, under the 4.5:1 body floor. The scrim is
   what creates the hierarchy here; the text does not also need to fade. */
.legacy .vid3--shot .vid3-inner > span:last-child { color: var(--paper); }

/* The photo sitting under the facade in the same column: it is supporting
   evidence, not a second hero, so it gets a tighter top gap and a smaller
   caption than a standalone .pfig. */
.legacy .pfig--tight { margin-top: 14px; }
.legacy .pfig--tight figcaption { font-size: 12.5px; }

/* 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. */
.legacy .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); }
.legacy .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); }
.legacy .hero3-ctas .btn.quiet { background: transparent; color: var(--paper); border-color: var(--hairline-d); }
.legacy .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. */
.legacy .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); }
.legacy .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; }
.legacy .h3grp:hover .h3dd,.legacy .h3grp:focus-within .h3dd,.legacy .h3grp.open .h3dd { opacity: 1; visibility: visible; transform: none; }
@media (hover: hover) { .legacy .h3grp:hover .h3dd { opacity: 1; visibility: visible; transform: none; } }
.legacy .h3grp > button { display: inline-flex; align-items: center; gap: 5px; }
.legacy .h3grp:hover .car { transform: rotate(180deg); }
.legacy .h3grp .car { display: inline-block; transition: transform var(--t-hover) var(--ease); }

/* ---- hero identity block ---- */
.legacy .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)) {
  .legacy .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) {
  .legacy .hero3-kicker { background-image: none; color: var(--spark); -webkit-text-fill-color: var(--spark); animation: none; }
}
.legacy .hero3 h1.grad3 { text-align: center; margin-bottom: 10px; font-size: clamp(36px, 5.4vw, 66px); }
.legacy .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. */
.legacy .hero3-line { min-height: calc(3 * 1.25em); }
@media (min-width: 375px) { .legacy .hero3-line { min-height: calc(2 * 1.25em); } }
@media (min-width: 700px) { .legacy .hero3-line { min-height: calc(1 * 1.25em); } }
.legacy .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) { .legacy .tl-caret { display: none; } }
.legacy .hero3-sub { text-align: center; }
.legacy .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; }
.legacy .hero3-id span { color: var(--spark); margin: 0 6px; }
.legacy .br-sm { display: none; }
@media (min-width: 700px) { .legacy .br-sm { display: inline; } .legacy .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. ---- */
.legacy .layers { margin: 34px 0 0; display: flex; flex-direction: column; }
.legacy .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); }
.legacy .layer > div { flex: 1; display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.legacy .layer b { font-family: var(--font-display); font-weight: 700; font-size: 19px; color: var(--ink); transition: color var(--t-hover) var(--ease); }
.legacy .layer-sub { font-family: var(--font-mono); font-size: 14.5px; color: var(--muted); transition: color var(--t-hover) var(--ease); }
.legacy .layer-star { display: inline-flex; color: var(--chrome); transition: color var(--t-hover) var(--ease), transform var(--t-release) var(--ease); }
.legacy .layer:hover { background: var(--ground); border-color: var(--ground); transform: translateX(6px); }
.legacy .layer:hover b { color: var(--paper); }
.legacy .layer:hover .layer-sub { color: var(--spark); }
.legacy .layer:hover .layer-star { color: var(--spark); transform: rotate(45deg); }
.legacy .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; }
.legacy .layers-eq { width: 2px; height: 26px; background: var(--spark); margin: 8px auto; }
.legacy .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); }
.legacy .layers-result .cta-glyph { display: inline-flex; animation: ctaSpin 9s linear infinite; }
.legacy .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. */
.legacy .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. */
.legacy .layer-d { display: block; }
.legacy .layer-d > summary { cursor: pointer; list-style: none; }
.legacy .layer-d > summary::-webkit-details-marker { display: none; }
.legacy .layer-d > summary::marker { content: ''; }
.legacy .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);
}
.legacy .layer:hover .layer-more { color: var(--spark); }
.legacy .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. */
.legacy .layer-d[open] > .layer { border-radius: var(--r-sm) var(--r-sm) 0 0; background: var(--ground); border-color: var(--ground); transform: none; }
.legacy .layer-d[open] > .layer b { color: var(--paper); }
.legacy .layer-d[open] > .layer .layer-sub { color: var(--spark); }
.legacy .layer-d[open] > .layer .layer-star { color: var(--spark); transform: rotate(45deg); }
.legacy .layer-d[open] > .layer:hover { transform: none; }

.legacy .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);
}
.legacy .layer-body p { max-width: none; font-size: 14.5px; line-height: 1.62; }
.legacy .layer-body .starlist { margin: var(--sp-4) 0; }
.legacy .layer-body .starlist li { color: var(--paper); font-size: 14px; }
.legacy .layer-body .starlist li::before { background: var(--spark); }
.legacy .layer-go { margin: 0; }
.legacy .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); }
.legacy .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. */
.legacy .layer-d--result[open] > .layers-result { border-radius: var(--r-lg) var(--r-lg) 0 0; }
.legacy .layer-d--result > summary .layer-more { color: color-mix(in srgb, var(--ink) 70%, var(--spark)); }
.legacy .layer-d--result[open] > summary .layer-more { color: var(--paper); }
.legacy .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) { .legacy .layer-body { animation: none; } }
@media (prefers-reduced-motion: reduce) { .legacy .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. */
.legacy .band-spark { position: relative; background: var(--spark-surface); }
.legacy .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"); }
.legacy .band-spark .wrap { position: relative; }
.legacy .band-spark .kicker { color: var(--ink); }
.legacy .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. */
.legacy .band-spark p { color: var(--ink); }
.legacy .band-spark .btn { background: var(--ground); color: var(--paper); border: 1px solid transparent; }
.legacy .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. */
.legacy .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. */
.legacy .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. */
.legacy .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%); }
.legacy .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"); }
.legacy .band-steel-deep .wrap { position: relative; }
.legacy .band-steel-deep h2,.legacy .band-steel-deep h3,.legacy .band-steel-deep .headline { color: var(--paper); }
.legacy .band-steel-deep .kflag,.legacy .band-steel-deep .kflag svg { color: var(--paper); }
.legacy .band-steel-deep .kflag::after { background: color-mix(in srgb, var(--paper) 30%, transparent); }
.legacy .band-steel-deep p,.legacy .band-steel-deep .lede { color: color-mix(in srgb, var(--paper) 85%, transparent); }
.legacy .band-steel-deep a { color: var(--paper); }
.legacy .band-steel-deep a:hover { color: var(--paper); }
.legacy .band-steel-deep .btn { background: var(--paper); color: var(--ink); border: 1px solid transparent; }
.legacy .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); }
.legacy .band-steel-deep .btn.quiet { background: transparent; color: var(--paper); border-color: color-mix(in srgb, var(--paper) 45%, transparent); }
.legacy .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. */
.legacy .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); }
.legacy .subnav-in { max-width: 1280px; margin: 0 auto; padding: 0 28px; display: flex; gap: 4px; overflow-x: auto; }
.legacy .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. */
.legacy .subnav a:hover { color: color-mix(in srgb, var(--chrome) 30%, var(--paper)); }
.legacy .subnav a.on { color: var(--spark); border-bottom-color: var(--spark); }
.legacy 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. */
.legacy .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); }
.legacy .kflag svg { color: var(--spark); flex: 0 0 auto; }
.legacy .kflag span { white-space: nowrap; }
.legacy .kflag::after { content: ''; flex: 1; height: 1px; background: color-mix(in srgb, var(--spark) 30%, transparent); }
.legacy .band-spark .kflag,.legacy .band-spark .kflag svg { color: var(--ink); }
.legacy .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. */
.legacy .kflag--center { justify-content: center; max-width: none; margin-inline: auto; }
.legacy .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. */
.legacy .arc { position: relative; margin-top: 40px; }
.legacy .arc-line { position: absolute; top: 14px; left: 0; right: 0; height: 2px; background: var(--hairline); }
.legacy .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) { .legacy .arc-line { display: none; } }
.legacy .arc-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; position: relative; }
@media (max-width: 900px) { .legacy .arc-grid { grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)); } .legacy .arc-card { margin-top: 0 !important; } .legacy .arc-era { margin-top: 0 !important; } }
.legacy .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. */
.legacy .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); }
.legacy .arc-card h3 { font-family: var(--font-display); font-size: 17px; margin: 0 0 6px; }
.legacy .arc-card p:last-child { font-size: 14px; color: var(--muted); margin: 0; }
.legacy .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); }
.legacy .arc-card:hover .arc-era { border-color: var(--spark); color: var(--ink); }
.legacy .arc-spark { background: var(--spark-surface); border-color: transparent; }
.legacy .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. */
.legacy .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; }
.legacy .arc-spark h3 { color: var(--paper); }
.legacy .arc-spark p:last-child { color: color-mix(in srgb, var(--ink) 86%, var(--spark)); }
.legacy .arc-spark:hover { border-color: var(--paper); }
.legacy .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. */
.legacy .wcard { overflow: hidden; }
.legacy .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; }
.legacy .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); }
.legacy .wcard:hover .wthumb-glyph { color: var(--spark); transform: rotate(45deg); }
.legacy .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; }
.legacy .wthumb-steel { background: var(--chrome); }
.legacy .wthumb-conf { background: color-mix(in srgb, var(--ink) 86%, var(--paper)); }
.legacy .wthumb-img { padding: 0; overflow: hidden; }
.legacy .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. */
.legacy .section.seal { padding: 44px 0; }
.legacy .seal-in { display: flex; align-items: center; gap: 24px; flex-wrap: wrap; }
.legacy .seal-glyph { display: inline-flex; flex: 0 0 auto; color: var(--spark); animation: ctaSpin 14s linear infinite; }
.legacy .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. */
.legacy .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) { .legacy .seal-t::before { animation: none; } }
.legacy .seal-t { font-family: var(--font-display); font-weight: 700; font-size: 19px; color: var(--paper); margin: 0 0 4px; }
.legacy .seal-s { font-size: 13.5px; color: var(--dim-d); margin: 0; max-width: none; }
.legacy .seal .btn { flex: 0 0 auto; }
@media (prefers-reduced-motion: reduce) { .legacy .seal-glyph { animation: none; } }

/* ---- the marquee: hover moves the border, and nothing else ---- */
.legacy .pmq-chip { transition: border-color var(--t-hover) var(--ease); }
.legacy .pmq:hover .pmq-chip { border-color: var(--hairline-d); }
.legacy .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. */
.legacy .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. */
.legacy .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. */
.legacy .diag-card::before { content: ''; position: absolute; inset: 0 0 auto 0; height: 3px; background: var(--spark); }
.legacy .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); }
.legacy .diag-card:hover .diag-fix { border-top-color: var(--spark); }
.legacy .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. */
.legacy .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; }
.legacy .diag-k { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .18em; text-transform: uppercase; color: var(--primary); margin: 0 0 4px; }
.legacy .diag-card h3 { font-family: var(--font-display); font-size: 20px; margin: 0; color: var(--ink); line-height: 1.25; }
.legacy .diag-sym { list-style: none; padding: 0; margin: 18px 0 0; flex: 1 0 auto; }
.legacy .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. */
.legacy .diag-sym li::before,.legacy .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. */
.legacy .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); }
.legacy .diag-fix .diag-k { color: var(--spark); }
.legacy .diag-fix ul { list-style: none; padding: 0; margin: 10px 0 0; }
.legacy .diag-fix li { position: relative; padding-left: 26px; margin: 8px 0; font-size: 14px; color: var(--paper); font-weight: 500; }
.legacy .diag-fix li::before { background: var(--spark); }
.legacy .diag-foot { margin-top: 26px; color: var(--muted); max-width: none; }

/* ---- the operating rail ---- */
.legacy .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); }
}
.legacy .rail-node { position: relative; padding: 34px 16px 20px 0; }
/* --i is the step's place in the order; the delay is --i times three. */
.legacy .rail-node { --i: 0; }
.legacy .rail-node:nth-child(2) { --i: 1; }
.legacy .rail-node:nth-child(3) { --i: 2; }
.legacy .rail-node:nth-child(4) { --i: 3; }
.legacy .rail-node:nth-child(5) { --i: 4; }
.legacy .rail-node:nth-child(6) { --i: 5; }
.legacy .rail-node:nth-child(7) { --i: 6; }
.legacy .rail-node::after  { animation: railStepDot 21s calc(var(--i) * 3s) infinite both; }
.legacy .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. */
.legacy .rail-node:hover::after,.legacy .rail-node:hover .rail-num { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .legacy .rail-node::after,.legacy .rail-node .rail-num { animation: none; }
}
.legacy .rail-node > * { transition: transform var(--t-hover) var(--ease); }
.legacy .rail-node:hover > * { transform: translateY(-3px); }
.legacy .rail-node::before { content: ''; position: absolute; top: 12px; left: 0; right: 0; height: 2px; background: var(--hairline-d); }
.legacy .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. */
.legacy .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); }
.legacy .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); }
.legacy .rail-node:hover .rail-num { color: var(--paper); }
.legacy .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; }
.legacy .rail-key { display: block; font-family: var(--font-mono); font-size: 10px; letter-spacing: .2em; color: var(--spark); margin: 2px 0 8px; }
.legacy .rail-node h3 { font-family: var(--font-display); font-size: 15px; color: var(--paper); margin: 0 0 6px; line-height: 1.25; }
.legacy .rail-node p { font-size: 12.5px; line-height: 1.55; color: var(--dim-d); margin: 0; }
@media (max-width: 1100px) { .legacy .rail { grid-template-columns: repeat(4, 1fr); } .legacy .rail-node:nth-child(4)::before { right: calc(100% - 13px); } }
@media (max-width: 720px) { .legacy .rail { grid-template-columns: repeat(2, 1fr); } .legacy .rail-node:nth-child(2n)::before { right: calc(100% - 13px); } }
@media (max-width: 460px) { .legacy .rail { grid-template-columns: 1fr; } .legacy .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. */
.legacy .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); }
.legacy .trust:hover { border-color: color-mix(in srgb, var(--spark) 45%, transparent); }
.legacy .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; }
.legacy .trust-l svg { color: var(--spark); }
.legacy .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); }
.legacy .trust-c:hover { transform: translateY(-1px); }
.legacy .trust-c.t1 { background: var(--paper); color: var(--ink); box-shadow: inset 3px 0 0 var(--spark); font-weight: 700; }
.legacy .trust-c.t1:hover { box-shadow: inset 3px 0 0 var(--spark), 0 0 14px color-mix(in srgb, var(--spark) 45%, transparent); }
.legacy .trust-c.t2 { background: transparent; border: 1px solid color-mix(in srgb, var(--paper) 55%, transparent); color: var(--paper); }
.legacy .trust-c.t3 { background: transparent; border: 1px solid var(--hairline-d); color: var(--dim-d); }
.legacy .trust-c.t4 { background: none; color: var(--dim-d); font-weight: 500; font-size: 12.5px; font-family: var(--font-mono); padding: 0; }
.legacy .trust-c.t4 b { color: var(--spark); font-weight: 600; }
.legacy .trust-s { color: var(--dim-d); font-size: 16px; line-height: 1; }
.legacy .trust:hover .trust-s { animation: chevIgnite 1.3s var(--ease) infinite; }
.legacy .trust:hover .trust-s:nth-of-type(2) { animation-delay: .16s; }
.legacy .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) { .legacy .trust:hover .trust-s { animation: none; } }

/* ---- the three-step cards ---- */
.legacy .tri { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr)); gap: 20px; margin-top: 36px; }
.legacy .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); }
.legacy .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. */
.legacy .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); }
.legacy .tri-card:hover::after { transform: scaleX(1); }
.legacy .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; }
.legacy .tri-k { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .2em; text-transform: uppercase; color: var(--primary); margin: 0 0 6px; }
.legacy .tri-card h3 { font-family: var(--font-display); font-size: 20px; margin: 0 0 10px; color: var(--ink); }
.legacy .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. */
.legacy .rv { opacity: 0; transform: translateY(16px); transition: opacity var(--t-release) var(--ease), transform var(--t-release) var(--ease); }
.legacy .rv.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .legacy .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. */
.legacy .hero3-kicker,.legacy .hero3-id { max-width: none !important; margin-left: auto !important; margin-right: auto !important; }
.legacy .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. */
.legacy .shell3 .phero { position: relative; overflow: hidden; margin-top: -72px; padding-top: 72px;
  background: var(--grad-ground); }
.legacy .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%); }
.legacy .shell3 .phero::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: var(--hairline-d); }
.legacy .shell3 .phero-in { position: relative; z-index: 1; }
.legacy .shell3 .phero h1 { font-size: clamp(30px, 4.4vw, 50px); line-height: 1.08; }
.legacy .shell3 .phero .kicker { letter-spacing: .28em; }
.legacy .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. */
.legacy .shell3 .phero .lede--full { max-width: none; }

/* The 404 keeps the plain band: an error page should not look designed. */
.legacy .shell3 .phero.plain::before,.legacy .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. */
.legacy ul.starlist { list-style: none; padding: 0; margin: 18px 0 0; }
.legacy .starlist li { position: relative; padding-left: 26px; margin: 8px 0; }
.legacy .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); }
.legacy .band-dark .starlist li::before { background: var(--spark); }
.legacy .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. */
.legacy .rowlist > a,.legacy .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); }
.legacy .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. */
.legacy .rowlist .t { font-family: var(--font-display); font-weight: 700; font-size: 15.5px; }
.legacy .rowlist .d { font-size: 12.5px; color: var(--muted); margin: 0; }
.legacy .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. */
.legacy .section.has-mark { position: relative; overflow: hidden; }
.legacy .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. */
.legacy .pjt { margin-top: var(--sp-7); }
.legacy .pjt-era { display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 0 var(--sp-4); position: relative; padding-bottom: var(--sp-7); }
.legacy .pjt-era--last { padding-bottom: 0; }
.legacy .pjt-rail { position: relative; }
.legacy .pjt-rail::before { content: ''; position: absolute; top: 6px; bottom: calc(-1 * var(--sp-7)); left: 10px; width: 2px; background: var(--hairline); }
.legacy .pjt-era--last .pjt-rail::before { bottom: 0; }
.legacy .pjt-node { position: absolute; top: 4px; left: 4px; width: 14px; height: 14px; border-radius: 50%; background: var(--paper); border: 2px solid var(--chrome); }
.legacy .pjt-era--now .pjt-node { border-color: var(--signal); }
.legacy .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) { .legacy .pjt-era--now .pjt-node::after { animation: none; } }
.legacy .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); }
.legacy .pjt-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(330px, 100%), 1fr)); gap: var(--sp-3); margin-top: var(--sp-4); }
.legacy .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); }
.legacy 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); }
.legacy a.pj:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.legacy .pj-tag { font-family: var(--font-mono); font-size: 10px; font-weight: 600; letter-spacing: .14em; color: var(--primary); }
.legacy .pj-t { font-family: var(--font-display); font-weight: 700; font-size: 15.5px; line-height: 1.3; color: var(--ink); }
.legacy .pj-d { font-size: 13px; line-height: 1.55; color: var(--muted); max-width: none; }
.legacy .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); }
.legacy a.pj:hover .pj-go { color: var(--ink); }
@media (max-width: 560px) { .legacy .pjt-era { grid-template-columns: 14px minmax(0, 1fr); gap: 0 var(--sp-2); } .legacy .pjt-rail::before { left: 6px; } .legacy .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. */
.legacy .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); }
.legacy .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); }
.legacy .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); }
.legacy .cs-sum::-webkit-details-marker { display: none; }
.legacy .cs-sum::marker { content: ''; }
.legacy .cs-sum--growth { grid-template-columns: minmax(0, 1fr) auto; padding: var(--sp-3) var(--sp-4); }
.legacy .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; }
.legacy .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); }
.legacy .cs-d:hover .cs-thumb .wthumb-glyph { color: var(--spark); transform: rotate(45deg); }
.legacy .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; }
.legacy .cs-thumb img { width: 100%; height: 100%; object-fit: cover; object-position: top; display: block; }
.legacy .cs-ttl { display: flex; flex-direction: column; gap: var(--sp-1); padding: var(--sp-3) 0; min-width: 0; }
.legacy .cs-ttl .badge { align-self: flex-start; }
.legacy .cs-ttl b { font-family: var(--font-display); font-weight: 700; font-size: 17px; line-height: 1.3; color: var(--ink); }
.legacy .cs-hook { font-size: 13.5px; line-height: 1.5; color: var(--muted); }
.legacy .cs-d[open] > .cs-sum .layer-more { transform: rotate(45deg); color: var(--spark); }
.legacy .cs-body { padding: var(--sp-1) var(--sp-5) var(--sp-5); animation: layerOpen var(--t-release) var(--ease); }
.legacy .cs-body p { max-width: var(--measure); }
.legacy .band-sand .cs-d { background: var(--card); }
@media (prefers-reduced-motion: reduce) { .legacy .cs-body { animation: none; } }
@media (max-width: 640px) {
  .legacy .cs-sum { grid-template-columns: minmax(0, 1fr) auto; padding: 0 var(--sp-4); }
  .legacy .cs-thumb { display: none; }
  .legacy .cs-ttl { padding: var(--sp-3) 0; }
}

/* ============================================================================
   tabs.css — the vertical rail for The Company OS Method cluster, plus the
   hero breadcrumb those ten routes share.
   ----------------------------------------------------------------------------
   Loaded only by the ten routes that share the rail (the page module exports
   `css`), so the shared sheets stay the size they are. Everything is scoped
   under .tabs so it cannot leak into another grid — with one named exception,
   .tabs-crumb, which renders in the page hero above the grid and is documented
   at its rule below.

   The rail rows are <a> links to the sibling routes, not tab buttons: each
   route is a distinct document now (see src/pages/ai-system.mjs for why), and
   the current row is marked with aria-current="page". The visual treatment is
   unchanged from the tab era on purpose — same rail, same active row — so the
   consolidation reads the same while every URL carries only its own content.

   The pattern was specified from a Flowbite vertical-tab example. That example
   is Tailwind and this site has no Tailwind, so nothing was pasted: the same
   shape is rebuilt here on the tokens in tokens.css and the conventions in
   shell3.css.

   ONE DELIBERATE DEPARTURE FROM THE SPEC, AND THE MEASUREMENT BEHIND IT.
   Recomputed for Brand OS v3.0 "Atlas", 2026-08-13. The brief asked for the
   active tab to be --spark with white text. Paper White on True North
   (#FFFFFF on #FF6B1C) measures 2.85:1. AA needs 4.5:1 for text and 3:1 even
   for large text, so it fails at every size, and v3 raises that from an
   observation to the one explicitly labelled LAW in the whole colour section:
   True North is "never type on white at any size. On light grounds it is a
   fill, a rule, or a shape." A site whose argument is that it writes its
   contrast failures down as rules rather than nudging them away cannot ship
   that combination in its own navigation.

   So the active tab is Midnight Green filled with Paper White text, which
   measures 15.83:1 — the single pair v3 collapsed the old five-dark ladder
   into, and the same treatment the site's existing tab pattern already uses.
   The brand colour still marks the active row, in the one role it is legal
   for on a dark ground: a shape, not type. It is the 3px edge bar and the
   icon. Identical read at a glance, legible for everyone, no law broken.

   Every ratio in this file was recomputed against the v3 hexes, not carried
   over. The two that moved: 11.9:1 -> 15.83:1 for ink on paper, because both
   ends of that pair changed, and 4.0:1 -> 5.56:1 for True North on the dark
   ground, which is the one place in the whole palette that GAINED — at 5.56:1
   it is now legal for body text on Midnight Green.
   ========================================================================= */

.legacy .tabs {
  display: grid;
  gap: 22px;
  align-items: start;
}

@media (min-width: 768px) {
  .legacy .tabs { grid-template-columns: 258px minmax(0, 1fr); gap: 30px; }
}

/* ---- the rail -------------------------------------------------------------
   Vertical from 768px up. Below that it becomes a horizontal strip that
   scrolls, because ten stacked rows above every panel would push the content
   off a phone screen entirely. */
.legacy .tabs-rail {
  display: flex;
  gap: 4px;
  flex-direction: row;
  overflow-x: auto;
  overflow-y: hidden;
  padding-bottom: 6px;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
}

@media (min-width: 768px) {
  .legacy .tabs-rail {
    flex-direction: column;
    overflow: visible;
    padding-bottom: 0;
    position: sticky;
    top: calc(var(--hd-h) + 14px);
  }
}

.legacy .tabs-tab {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  flex: none;
  width: auto;
  text-align: left;
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 600;
  line-height: 1.25;
  color: var(--muted);
  /* These rows are links now, but they must not read as prose links: the rail
     is navigation chrome, and ten underlines would be ten shouts. */
  text-decoration: none;
  background: transparent;
  border: 1px solid transparent;
  border-left: 3px solid transparent;
  border-radius: var(--r);
  padding: 11px 14px;
  white-space: nowrap;
  scroll-snap-align: start;
  transition: background var(--t-hover) var(--ease), color var(--t-hover) var(--ease), border-color var(--t-hover) var(--ease);
}

@media (min-width: 768px) {
  .legacy .tabs-tab { width: 100%; white-space: normal; }
}

.legacy .tabs-tab:hover { background: var(--band); color: var(--ink); }
.legacy .tabs-tab:active { transition-duration: var(--t-press); }

.legacy .tabs-tab[aria-current="page"] {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
  border-left-color: var(--spark);
}

/* The icon is the second place the brand colour marks the active row, and on
   the Midnight fill it is a shape on a dark ground — where True North measures
   5.56:1 and would be legal even as type. */
.legacy .tabs-tab[aria-current="page"] .tabs-ic { color: var(--spark); }

/* The focus ring is 2px Surface Steel, never a glow (§8.7). Steel measures
   7.44:1 on white, which is what an unselected tab sits on.

   The current row is Midnight, and Steel on Midnight is 2.13:1 — v3 writes
   that failure down as a law rather than nudging it. So the ring on the
   current row switches to Paper White at 15.83:1. It is the same 2px ring,
   not a second style: only the ground changed, so only the colour did. */
.legacy .tabs-tab:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}
.legacy .tabs-tab[aria-current="page"]:focus-visible { outline-color: var(--paper); }

.legacy .tabs-ic {
  width: 16px;
  height: 16px;
  flex: none;
  color: var(--faint);
  transition: color var(--t-hover) var(--ease);
}
.legacy .tabs-tab:hover .tabs-ic { color: var(--primary); }

/* A number that says how far down the rail you are. Role-bound colours
   (2026-08-25): Surface Steel at rest, which is exactly what a mono figure
   on a light ground takes, at 7.4:1 full strength rather than dimmed
   through an opacity that quietly broke the ratio. On the current row the
   ground is Midnight, where Steel fails by law, so the numeral goes spark:
   5.6:1 there, legal even as type. */
.legacy .tabs-n {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .08em;
  color: var(--chrome);
  display: none;
}
.legacy .tabs-tab[aria-current="page"] .tabs-n { color: var(--spark); }
@media (min-width: 768px) { .legacy .tabs-n { display: inline; } }

/* ---- the Company OS breadcrumb -------------------------------------------
   One line between the h1 and the lede on all ten routes, naming where the
   page sits inside the Company OS. The one selector in this file not scoped
   under .tabs, because it renders in the page hero above the grid — still
   contained, because this sheet loads only on the ten routes that carry it.
   It sits on the hero's dark ground, so it takes --dim-d (the dark-ground dim
   token the lede already uses there) rather than --muted, which is mixed for
   light grounds. Mono and dimmed on purpose: it is wayfinding, not a second
   subtitle, and it must not compete with the lede below it. */
.legacy .tabs-crumb {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: .04em;
  line-height: 1.5;
  color: var(--dim-d);
  margin: 10px 0 0;
  max-width: 68ch;
}

/* ---- the panel ----------------------------------------------------------
   One per page now: the route's own content, in the card the tab panels used
   to share. Keeping the class keeps every content rule below working
   unchanged. */
.legacy .tabs-panel {
  background: var(--card);
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  padding: clamp(22px, 3.2vw, 40px);
  min-width: 0;
}

.legacy .tabs-panel > :first-child { margin-top: 0; }
.legacy .tabs-panel h2 { font-size: var(--step-2); letter-spacing: -.018em; margin-top: 2em; }
.legacy .tabs-panel h2:first-of-type { margin-top: 0; }
.legacy .tabs-panel h3 { margin-top: 1.6em; }
.legacy .tabs-panel .card h3 { margin-top: 0; }
.legacy .tabs-panel p { max-width: var(--measure); }
.legacy .tabs-panel .grid p,.legacy .tabs-panel .note p { max-width: none; }

/* The panel entrance animation left with the client-side switching: a real
   navigation paints a whole new page, and animating one card inside it would
   read as a glitch, not a transition. */
@media (prefers-reduced-motion: reduce) {
  .legacy .tabs-tab { transition: none; }
}

/* ============================================================================
   THE AGENT ROSTER — rendered inside the Agents panel.
   ----------------------------------------------------------------------------
   Two rules the markup exists to enforce:

   1. The refusal renders at the same weight as the role. It is the through-line
      of the whole roster, not a footnote, because a refusal is testable and an
      aspiration is not.
   2. No status chip uses the orange accent. Orange is the site's one "look
      here" colour, and if RUNNING wore it then thirty rows would compete with
      every real call to action on the page. v3 turns that judgement into a
      count: "one True North button per view. A second primary means the first
      one was not primary."

   ---- THE v3 REBUILD OF THE FIVE STATUSES -----------------------------------

   Three of the five were carried by tokens v3 deletes. --bronze is gone with
   its whole warm-secondary family (seventh-colour violation) and --flag is
   gone because "there is no red in this palette" — errors and refusals are
   carried by a 2px Midnight Green border, the glyph, and a Plex Mono line,
   never by a hue.

   The five now run on the pattern v3 publishes for status (P02): ON A LIGHT
   GROUND THE DOT CARRIES THE COLOUR AND THE LABEL DOES NOT. That is the rule
   that lets the signal pair appear here at all — status is the one thing
   Landfall and Meridian are FOR — while keeping every label above 6.4:1,
   which neither signal colour manages on white (1.65:1 and 3.01:1).

     status      dot            label       container
     running     Meridian       Midnight    Meridian wash + Meridian hairline
     built       Landfall       Steel       hairline only
     gated       Steel          muted       --band fill, hairline
     buildable   hollow ring    faint       dashed hairline, no fill
     blocked     Midnight       Midnight    2px Midnight border, no fill

   They still separate in greyscale and for anyone who does not distinguish
   these hues, because the container does the work: wash, hairline, band,
   dashed, and a doubled border are five different objects before they are five
   different colours. Blocked is the heaviest thing on the page, which is the
   correct weight for a refusal and the reason it never needed to be red.
   ========================================================================= */

.legacy .ledger {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(148px, 100%), 1fr));
  gap: 10px;
  margin: 22px 0 0;
  padding: 0;
  list-style: none;
}

.legacy .ledger li {
  border: 1px solid var(--hairline);
  border-radius: var(--r);
  padding: 14px 15px;
  background: var(--card);
}

.legacy .ledger .n {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--step-3);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

/* The label is inline-flex so it can carry the dot that now holds the colour.
   --st-dot defaults to nothing visible; the two statuses that get a signal
   colour set it, and the other three separate on the container instead. */
.legacy .ledger .k {
  /* flex, not inline-flex: this label used to be display:block and has to keep
     breaking the line after the figure above it. */
  display: flex;
  align-items: center;
  gap: 7px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  margin-top: 8px;
}
.legacy .ledger .k::before {
  content: "";
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--st-dot, transparent);
  box-shadow: inset 0 0 0 1px var(--st-dot, var(--hairline));
}

.legacy .ledger .b { display: block; font-size: 12px; color: var(--muted); margin-top: 6px; }

.legacy .ledger li.is-running {
  --st-dot: var(--beacon);
  border-color: color-mix(in srgb, var(--beacon) 40%, transparent);
  background: color-mix(in srgb, var(--beacon) 7%, var(--card));
}
.legacy .ledger li.is-running .k   { color: var(--ink); }
.legacy .ledger li.is-built        { --st-dot: var(--signal); }
.legacy .ledger li.is-built .k     { color: var(--primary); }
.legacy .ledger li.is-gated        { --st-dot: var(--chrome); background: var(--band); }
.legacy .ledger li.is-gated .k     { color: var(--muted); }
.legacy .ledger li.is-buildable    { border-style: dashed; }
.legacy .ledger li.is-buildable .k { color: var(--faint); }
/* No red anywhere in v3. A blocked agent is the only cell with a doubled
   Midnight border, which reads heavier than any of the four above it. */
.legacy .ledger li.is-blocked      { --st-dot: var(--ink); border: 2px solid var(--ink); padding: 13px 14px; }
.legacy .ledger li.is-blocked .k   { color: var(--ink); }

.legacy .dept { margin-top: 44px; }
.legacy .dept-h { display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px; }
.legacy .dept-id {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .12em;
  color: var(--faint);
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  padding: 2px 7px;
}
.legacy .dept-remit { color: var(--muted); font-size: var(--step--1); }
.legacy .dept-drop { font-size: var(--step--1); color: var(--faint); }
.legacy .dept-drop b { color: var(--muted); font-weight: 600; }

.legacy .ag-list { display: grid; gap: 10px; margin-top: 18px; }

.legacy .ag {
  border: 1px solid var(--hairline);
  border-radius: var(--r);
  background: var(--card);
  padding: 16px 18px;
}

.legacy .ag-top { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; }
.legacy .ag-top h4 { font-family: var(--font-display); font-size: var(--step-0); font-weight: 700; margin: 0; }

/* One glyph per row. It is a tile rather than a bare icon so that forty-five
   rows read as a list of things rather than a wall of text with decoration
   in the margin. The wash is --primary, never --spark: the status chip to the
   right of it is already carrying meaning, and two coloured objects competing
   in one line is how a row stops being scannable. */
.legacy .ag-ic {
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  display: inline-grid;
  place-items: center;
  background: var(--wash-primary);
  border: 1px solid color-mix(in srgb, var(--primary) 18%, transparent);
  color: var(--primary);
}
.legacy .ag-ic .ic { width: 17px; height: 17px; }
/* --mist is one of the eleven tints v3 absorbed into --band and --page. This
   is a chip on a card, so it takes --band: 8% Surface Steel on white, with
   Steel type over it at 6.59:1. */
.legacy .ag-cmd {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--primary);
  background: var(--band);
  border-radius: var(--r-sm);
  padding: 2px 8px;
}
.legacy .ag-cmd.is-quiet { color: var(--faint); background: transparent; border: 1px dashed var(--hairline); }

/* Role and refusal: identical type, identical spacing, one label apiece. The
   only difference between them is which word starts the line. */
.legacy .ag-line { display: grid; grid-template-columns: 74px minmax(0, 1fr); gap: 12px; margin-top: 12px; align-items: start; }
.legacy .ag-line > span:first-child {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--faint);
  padding-top: 3px;
}
.legacy .ag-line > p { margin: 0; font-size: var(--step--1); color: var(--ink); max-width: none; }
/* The REFUSES label was red. There is no red. It goes to full Midnight Green
   at 15.83:1 against the card, which makes it the darkest label in the row —
   the correct emphasis for the line that carries the whole roster's argument,
   and the same "weight, not hue" move v3 makes for every failure state. */
.legacy .ag-line.is-no > span:first-child { color: var(--ink); font-weight: 600; }
/* The skill rows use the same two-line anatomy as the agent rows: what it does,
   and the thing it is answerable to. For an agent that is the refusal; for a
   skill it is the reference it adapts, which is the equivalent constraint. */
.legacy .ag-line.is-ref > span:first-child { color: var(--primary); }
.legacy .ag-line.is-ref > p { color: var(--muted); }
.legacy .ag-note { margin: 10px 0 0; font-size: 12px; color: var(--muted); max-width: none; }

/* The chip, rebuilt on P02. The dot is the only thing allowed to be Landfall
   or Meridian here, because the chip sits on a white card and "signal colours
   never set small type on white". */
.legacy .ag-st {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  border-radius: var(--pill);
  padding: 3px 10px;
  border: 1px solid transparent;
  white-space: nowrap;
}
.legacy .ag-st::before {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--st-dot, transparent);
  box-shadow: inset 0 0 0 1px var(--st-dot, var(--hairline));
}
.legacy .ag-st.is-running   { --st-dot: var(--beacon); color: var(--ink);     background: color-mix(in srgb, var(--beacon) 7%, var(--card)); border-color: color-mix(in srgb, var(--beacon) 34%, transparent); }
.legacy .ag-st.is-built     { --st-dot: var(--signal); color: var(--primary); background: var(--card); border-color: var(--hairline); }
.legacy .ag-st.is-gated     { --st-dot: var(--chrome); color: var(--muted);   background: var(--band); border-color: var(--hairline); }
.legacy .ag-st.is-buildable { color: var(--faint);     background: transparent; border-color: var(--hairline); border-style: dashed; }
/* the heaviest chip in the row, and the only 2px border on the page */
.legacy .ag-st.is-blocked   { --st-dot: var(--ink); color: var(--ink); background: transparent; border: 2px solid var(--ink); padding: 2px 9px; }

@media (max-width: 520px) {
  .legacy .ag-st { margin-left: 0; }
  .legacy .ag-line { grid-template-columns: 1fr; gap: 2px; }
}

/* ============================================================================
   THE REFUSAL DEMO — folded into the Guardrails panel.
   ----------------------------------------------------------------------------
   It used to be its own route with its own nested tab strip. Nested tabs inside
   a tabpanel is a bad experience for keyboard users and a worse one for screen
   readers, and the four answers read better together anyway: two builds beside
   two refusals is the comparison, and hiding three of them behind a control was
   hiding exactly that.
   ========================================================================= */
.legacy .rf { margin-top: 22px; }
.legacy .rf + .rf { margin-top: 18px; }

.legacy .rf-req {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  line-height: 1.6;
  background: var(--band);
  border-radius: var(--r);
  padding: 15px 17px;
  color: var(--ink);
}
/* --faint on --band measures 4.49:1, a hair under AA at 10px. It steps to
   --muted, 5.72:1 on the same fill. */
.legacy .rf-req::before {
  content: "THE REQUEST";
  display: block;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .12em;
  color: var(--muted);
  margin-bottom: 8px;
}

.legacy .rf-res {
  border-left: 3px solid var(--primary);
  border-radius: 0 var(--r) var(--r) 0;
  background: var(--wash-primary);
  padding: 15px 17px 15px 19px;
  margin-top: 10px;
}
/* A refusal is not an error and it is certainly not red — v3 has neither
   colour available. It is marked by weight: the accepted answer carries a 3px
   Surface Steel rule and a Steel wash, the refused one carries a 3px Midnight
   Green rule and no wash at all. The absence is the point. */
.legacy .rf-res.is-no { border-left-color: var(--ink); border-left-width: 4px; background: transparent; }
.legacy .rf-res::before {
  content: "THE SYSTEM ANSWERS";
  display: block;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .12em;
  color: var(--faint);
  margin-bottom: 8px;
}
.legacy .rf-res p { margin: 0; font-size: var(--step--1); max-width: none; }

.legacy .rf-verdict {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  padding: 3px 10px;
  border-radius: var(--pill);
  margin-bottom: 10px;
}
.legacy .rf-verdict.is-yes { background: var(--card); color: var(--primary); border: 1px solid color-mix(in srgb, var(--primary) 34%, transparent); }
.legacy .rf-verdict.is-no  { background: var(--card); color: var(--ink);     border: 2px solid var(--ink); padding: 2px 9px; }

.legacy .rf-why { font-size: var(--step--1); color: var(--muted); margin-top: 10px; max-width: none; }
.legacy .rf-why b { color: var(--ink); }

/* ---- the intake form list, folded into The Intake panel ------------------ */
.legacy .intake { list-style: none; margin: 0; padding: 0; }
.legacy .intake li {
  padding: 8px 0;
  border-top: 1px solid var(--hairline-soft);
  font-size: .9rem;
  color: var(--ink);
}
.legacy .intake li:first-child { border-top: 0; }
/* The required-field marker. It was --spark-ink, v2's burnt orange, which
   existed only so that something orange-flavoured could be legal as type on
   light. v3 deletes it and offers no replacement: on light, True North is a
   fill, a rule or a shape, full stop. A required marker is type, so it takes
   the label colour v3 does assign on light — Surface Steel, 7.44:1. */
.legacy .req { color: var(--primary); text-decoration: none; cursor: help; font-size: .85em; margin-right: 6px; }

/* ============================================================================
   BRAIN DEMO — the interactive company-brain explorer.

   This is the centrepiece of the portfolio. It renders a normalised JSON
   description of a company brain as a browsable system: folder tree,
   constitution, rules, skills, agents, changelog, brand OS.

   Two things here exist in no brain DJ has shipped, and that is the point:
     1. A real collapsible folder tree. The earlier builds render theirs as a
        static ASCII block or a flat table.
     2. An ANNOTATION LAYER — margin notes explaining why each decision
        exists. Without it this is a file dump; with it, it is an argument.

   BRAND OS v3.0 "ATLAS". Four things in this sheet ran on tokens v3 deletes,
   and each one is rewritten rather than repointed, because in every case the
   colour was carrying meaning that v3 assigns somewhere else:

     --spark-ink   the eyebrow orange on light. Deleted with no replacement:
                   v3 has no text-legal orange at any size. Eyebrows and mono
                   labels on a light ground are Surface Steel, 7.44:1.
     --flag        the refusal red. Deleted: "there is no red in this palette."
                   A refusal is now carried by a 2px Midnight Green border and
                   the glyph — by weight, not by hue.
     --accent      the pale sea glass that spoke on dark. Deleted; on a
                   Midnight ground the voice is Paper White at 15.83:1, or
                   True North at 5.56:1 where it must stand apart.
     --data-1/2/3  the three-hue chart set. Deleted. v3 does data as "fills
                   only" in the signal pair, and the two charts here were
                   already single-measure, so each is now one flat fill —
                   which also retires the two gradients they were built on.
   ========================================================================= */

/* ---- SHELL --------------------------------------------------------------- */
.legacy .bd { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: clamp(24px, 4vw, 52px); align-items: start; }
@media (max-width: 1040px) { .legacy .bd { grid-template-columns: minmax(0, 1fr); } }

/* ---- TABS ---------------------------------------------------------------- */
.legacy .bd-tabs {
  display: flex; gap: 2px; flex-wrap: wrap; border-bottom: 1px solid var(--hairline);
  margin-bottom: 28px; position: sticky; top: var(--hd-h); z-index: 20;
  background: var(--grad-paper); background-attachment: fixed; padding-top: 4px;
}
.legacy .bd-tab {
  appearance: none; background: transparent; border: 0; cursor: pointer;
  font-family: var(--font-mono); font-size: var(--step--1); font-weight: 600;
  letter-spacing: .04em; color: var(--faint); padding: 12px 15px;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  transition: color var(--t-hover) var(--ease), border-color var(--t-hover) var(--ease);
}
.legacy .bd-tab:hover { color: var(--ink); }
.legacy .bd-tab[aria-selected="true"] { color: var(--ink); border-bottom-color: var(--spark); }
.legacy .bd-panel { display: none; }
.legacy .bd-panel.on { display: block; animation: bdIn 260ms var(--ease); }
@keyframes bdIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* ---- FOLDER TREE --------------------------------------------------------- */
.legacy .tree { font-family: var(--font-mono); font-size: var(--step--1); line-height: 1.75; overflow-x: auto; }
.legacy .tree ul { list-style: none; margin: 0; padding-left: 19px; border-left: 1px solid var(--hairline); }
.legacy .tree > ul { padding-left: 0; border-left: 0; }
.legacy .tree li { position: relative; }
.legacy .tree-row {
  display: flex; align-items: baseline; gap: 8px; padding: 3px 8px 3px 4px;
  border-radius: var(--r-sm); cursor: pointer; width: 100%; text-align: left;
  background: transparent; border: 0; font: inherit; color: var(--ink);
  transition: background var(--t-hover) var(--ease);
}
.legacy .tree-row:hover { background: var(--wash-primary); }
.legacy .tree-row.sel { background: var(--ink); color: var(--paper); }
.legacy .tree-row.sel .tree-meta { color: var(--dim-d); }
.legacy .tree-tw {
  flex: 0 0 12px; color: var(--faint); font-size: 10px; line-height: 1.9;
  transition: transform 180ms var(--ease);
}
.legacy .tree-row[aria-expanded="true"] .tree-tw { transform: rotate(90deg); }
.legacy .tree-row.leaf .tree-tw { visibility: hidden; }
.legacy .tree-nm { font-weight: 500; min-width: 0; overflow-wrap: anywhere; }
.legacy .tree-row.dir .tree-nm { color: var(--primary); font-weight: 600; }
/* One row is selected at a time, so the directory name inside it is the one
   place on this panel True North appears — 5.56:1 on the Midnight fill, which
   is the only ground in the system where it is legal as type. */
.legacy .tree-row.sel.dir .tree-nm { color: var(--spark); }
.legacy .tree-meta { margin-left: auto; color: var(--faint); font-size: 10.5px; white-space: nowrap; }
.legacy .tree li[data-open="false"] > ul { display: none; }

/* ---- NODE DETAIL --------------------------------------------------------- */
.legacy .bd-detail {
  border: 1px solid var(--hairline); border-radius: var(--r); background: var(--card);
  padding: 20px 22px; margin-top: 18px; min-height: 150px;
}
.legacy .bd-detail-path {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .04em;
  color: var(--faint); margin-bottom: 10px; word-break: break-all;
}
.legacy .bd-detail h4 { font-size: var(--step-1); margin-bottom: .4em; }
.legacy .bd-detail .excerpt {
  font-family: var(--font-mono); font-size: 12.5px; line-height: 1.7;
  background: var(--band); border-radius: var(--r-sm); padding: 14px 16px;
  margin-top: 14px; white-space: pre-wrap; overflow-x: auto; color: var(--muted);
}
.legacy .bd-empty { color: var(--faint); font-size: var(--step--1); font-style: italic; }

/* ---- ANNOTATION RAIL — the thing no brain of his has ------------------- */
.legacy .bd-rail { position: sticky; top: calc(var(--hd-h) + 50px); }
@media (max-width: 1040px) { .legacy .bd-rail { position: static; margin-top: 32px; } }
.legacy .anno {
  border-left: 2px solid var(--spark); padding: 2px 0 2px 16px; margin-bottom: 22px;
}
.legacy .anno-l {
  font-family: var(--font-mono); font-size: 10px; font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--primary); display: block; margin-bottom: 5px;
}
.legacy .anno p { font-size: var(--step--1); line-height: 1.55; color: var(--muted); margin: 0; max-width: none; }
.legacy .anno q { font-style: italic; }

/* ---- CONSTITUTION -------------------------------------------------------- */
.legacy .const-sec { border-top: 1px solid var(--hairline); padding: 22px 0; }
.legacy .const-sec:first-child { border-top: 0; padding-top: 0; }
.legacy .const-n {
  font-family: var(--font-mono); font-size: var(--step--1); font-weight: 600;
  color: var(--primary); margin-right: 10px;
}
.legacy .const-sec h3 { display: inline; font-size: var(--step-1); }
.legacy .const-body { margin-top: 14px; }
.legacy .const-body p { font-size: var(--step--1); }
.legacy .const-body ul { font-size: var(--step--1); color: var(--muted); padding-left: 20px; }
.legacy .const-body li { margin-bottom: 7px; }
.legacy .const-body li strong { color: var(--ink); }

/* ---- RULES / SKILLS / AGENTS -------------------------------------------- */
.legacy .rule {
  border: 1px solid var(--hairline); border-radius: var(--r); padding: 16px 18px;
  background: var(--card); display: flex; gap: 14px; align-items: flex-start;
}
/* The NEVER marker on a rule. Red is not available and no other hue may stand
   in for it, so it takes the shape v3 gives every failure state: a 2px
   Midnight Green border, the glyph, no fill. Midnight on the card is 15.83:1
   and the doubled border makes it the heaviest object in the row, which is
   what the red was doing before it was a colour. */
.legacy .rule-x {
  flex: 0 0 auto; font-family: var(--font-mono); font-size: 12px; font-weight: 700;
  color: var(--ink); border: 2px solid var(--ink);
  background: transparent; border-radius: var(--r-sm); padding: 2px 7px; line-height: 1.4;
}
.legacy .rule p { margin: 0; font-size: var(--step--1); }
.legacy .rule b { display: block; margin-bottom: 3px; }

.legacy .skill { border: 1px solid var(--hairline); border-radius: var(--r); padding: 16px 18px; background: var(--card); }
.legacy .skill h4 { font-family: var(--font-mono); font-size: var(--step--1); color: var(--primary); margin-bottom: .45em; letter-spacing: .02em; }
.legacy .skill p { font-size: var(--step--1); color: var(--muted); margin: 0; }

/* ---- CHANGELOG ----------------------------------------------------------- */
.legacy .cl { border: 1px solid var(--hairline); border-radius: var(--r); overflow: hidden; background: var(--card); }
.legacy .cl details { border-bottom: 1px solid var(--hairline-soft); }
.legacy .cl details:last-child { border-bottom: 0; }
.legacy .cl summary {
  cursor: pointer; padding: 13px 18px; display: flex; gap: 14px; align-items: baseline;
  font-size: var(--step--1); list-style: none;
}
.legacy .cl summary::-webkit-details-marker { display: none; }
.legacy .cl summary:hover { background: var(--wash-primary); }
.legacy .cl summary::after { content: "+"; margin-left: auto; color: var(--faint); font-family: var(--font-mono); }
.legacy .cl details[open] summary::after { content: "\2013"; }
.legacy .cl-date { font-family: var(--font-mono); font-size: 11.5px; color: var(--faint); flex: 0 0 88px; }
.legacy .cl-body { padding: 0 18px 16px 120px; font-size: var(--step--1); color: var(--muted); }
@media (max-width: 620px) { .legacy .cl-body { padding-left: 18px; } }

/* ---- BRAND OS SWATCHES --------------------------------------------------- */
.legacy .sw { border: 1px solid var(--hairline); border-radius: var(--r); overflow: hidden; background: var(--card); }
.legacy .sw-chip { height: 76px; }
.legacy .sw-meta { padding: 11px 14px; }
.legacy .sw-nm { font-size: var(--step--1); font-weight: 600; }
.legacy .sw-hex { font-family: var(--font-mono); font-size: 11px; color: var(--faint); text-transform: uppercase; }
.legacy .sw-rule { font-size: 11.5px; color: var(--muted); margin-top: 6px; line-height: 1.45; }

/* ---- FILE INDEX SEARCH --------------------------------------------------- */
.legacy .bd-toolbar { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-bottom: 16px; }
.legacy .bd-search {
  flex: 1 1 240px; font-family: var(--font-body); font-size: var(--step--1);
  padding: 11px 15px; border: 1px solid var(--hairline); border-radius: var(--r);
  background: var(--card); color: var(--ink); min-height: 44px;
}
.legacy .bd-count { font-family: var(--font-mono); font-size: 11.5px; color: var(--faint); }

/* ---- SCRUB BANNER — visible on every confidential demo ------------------ */
.legacy .scrub {
  border: 1px solid color-mix(in srgb, var(--spark) 40%, transparent);
  background: var(--wash-spark); border-radius: var(--r);
  padding: 16px 20px; margin-bottom: 30px; font-size: var(--step--1);
}
/* The border and the wash are True North as a rule and a fill, which is legal
   on a light ground. The label is not: it is Midnight Green at 14.55:1 over the
   8% orange wash. Same banner, one law obeyed. */
.legacy .scrub b { display: block; font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink); margin-bottom: 6px; }
.legacy .scrub p { margin: 0; max-width: 78ch; }

/* ---- EVOLUTION CHART ----------------------------------------------------- */
/* ONE MEASURE, ONE HUE, ONE FLAT FILL. The bars were a two-stop gradient
   between --data-2 and --data-1; v3 allows exactly one gradient in the whole
   system and it is not this one. The fill is Meridian, which is what the
   signal pair is actually for — "data visualisation: fills only. Bars, nodes,
   tree branches, stat tiles. Never the axis, never the label."

   The labels flip to Midnight Green as a direct consequence. Paper White on
   Meridian is 3.01:1 and fails; Midnight Green on Meridian is 5.26:1 and
   passes at every size, which is the same measurement read the other way.

   The 11px key line carried opacity .86, which dropped it to 4.24:1 and under
   AA. The opacity is removed rather than nudged; the two lines already
   separate on size and weight. */
.legacy .evo { display: grid; gap: 3px; grid-template-columns: repeat(4, 1fr); align-items: end; height: 190px; margin: 30px 0 10px; }
.legacy .evo-bar { background: var(--beacon); border-radius: var(--r-sm) var(--r-sm) 0 0; position: relative; display: flex; flex-direction: column; justify-content: flex-end; padding: 10px; }
.legacy .evo-bar .v { font-family: var(--font-mono); font-size: var(--step-1); font-weight: 600; color: var(--ground); line-height: 1; }
.legacy .evo-bar .k { font-size: 11px; color: var(--ground); margin-top: 5px; }
.legacy .evo-x div { font-family: var(--font-mono); font-size: 11px; color: var(--dim-d); padding: 10px 0 0; border-top: 1px solid var(--hairline-d); max-width: 70ch; line-height: 1.5; }

/* ---- MOBILE --------------------------------------------------------------
   At 375px the seven tabs wrapped to three rows of sticky chrome, which with
   the header consumed a third of the viewport before any content. One
   scrollable row instead. */
@media (max-width: 700px) {
  .legacy .bd-tabs {
    flex-wrap: nowrap; overflow-x: auto; scroll-snap-type: x proximity;
    scrollbar-width: none; -ms-overflow-style: none;
  }
  .legacy .bd-tabs::-webkit-scrollbar { display: none; }
  .legacy .bd-tab { flex: 0 0 auto; scroll-snap-align: start; }
  .legacy .tree-meta { display: none; }          /* line counts are decoration; the width is not */
  .legacy .evo { grid-template-columns: 1fr; height: auto; gap: 8px; }
  .legacy .evo-bar { height: auto !important; min-height: 58px; flex-direction: row; align-items: baseline; gap: 12px; }
}

/* ---- PRESS FEEDBACK ------------------------------------------------------
   Every interactive surface in the brain demo previously responded only on
   click. Nothing acknowledged the press itself, which is the one thing that
   makes a control feel connected to the finger rather than to a callback.

   The asymmetry is deliberate and is what the two existing timing tokens were
   written for: --t-press (90ms) going in, --t-release (200ms) coming back.
   Fast to acknowledge, unhurried to let go. Reversing those two values makes
   the same interface feel broken, which is a good way to prove the point.

   No transform on the tree rows. They sit inside a scrollable monospace grid
   where a 1px nudge would fight the alignment that makes a tree readable.
   Colour carries the press instead.
   ------------------------------------------------------------------------ */
.legacy .bd-tab,.legacy .tree-row { transition-duration: var(--t-release); }
.legacy .bd-tab:active,.legacy .tree-row:active { transition-duration: var(--t-press); }

.legacy .bd-tab:active { color: var(--ink); background: var(--wash-primary); }
.legacy .tree-row:active { background: color-mix(in srgb, var(--primary) 16%, var(--card)); }
.legacy .tree-row.sel:active { background: color-mix(in srgb, var(--ink) 88%, var(--paper)); }

.legacy .cl summary,.legacy .cl details > summary { cursor: pointer; }
.legacy .cl summary:active { background: var(--wash-primary); transition-duration: var(--t-press); }

/* Coarse pointers get a real target without changing the density a file tree
   depends on. A 30px row is fine under a mouse and a coin toss under a thumb. */
@media (pointer: coarse) {
  .legacy .tree-row { padding-top: 7px; padding-bottom: 7px; }
  .legacy .bd-tab { padding-top: 15px; padding-bottom: 15px; }
}

/* ---- HORIZONTAL BAR CHART ------------------------------------------------
   Companion to .evo, for a measure whose values span two orders of magnitude
   (0, 3, 76, 5). Vertical bars at that spread cannot hold their own labels, so
   the labels move outside the marks: name left, bar centre, value right.
   Single measure, one hue, direct labels. The palette validator failed the
   three --data tokens as a CATEGORICAL set, which is fine, because nothing
   here is categorical: every chart on this site is one measure in one hue.

   v3 settled that argument by deleting the three tokens outright. The hue is
   Meridian, the fill is flat, and because the value sits OUTSIDE the bar on
   the dark ground rather than on the fill, it keeps Paper White at 15.83:1. */
.legacy .hbar { display: grid; gap: 10px; margin: 30px 0 10px; }
.legacy .hbar-row { display: grid; grid-template-columns: 110px 1fr 44px; gap: 12px; align-items: center; }
.legacy .hbar-k { font-size: 11px; color: var(--dim-d); text-align: right; }
.legacy .hbar-track { height: 14px; border-radius: 3px; background: color-mix(in srgb, var(--paper) 7%, transparent); position: relative; }
.legacy .hbar-fill { position: absolute; inset: 0 auto 0 0; border-radius: 3px; background: var(--beacon); min-width: 2px; }
.legacy .hbar-fill.zero { background: transparent; border-left: 2px solid var(--dim-d); border-radius: 0; min-width: 0; }
.legacy .hbar-v { font-family: var(--font-mono); font-size: var(--step--1); font-weight: 600; color: var(--paper); }
@media (max-width: 700px) { .legacy .hbar-row { grid-template-columns: 84px 1fr 40px; } }

/* ---- CHANGELOG OPEN ------------------------------------------------------
   details/summary snapped open with no bridge. The reveal now announces
   itself: content fades and settles in 200ms. State indication, occasional
   frequency, inside the 260ms budget. The global reduced-motion rule in
   tokens.css removes it entirely rather than slowing it. */
.legacy .cl details[open] .cl-body { animation: clOpen 200ms var(--ease); }
@keyframes clOpen { from { opacity: 0; transform: translateY(-4px); } }

/* ============================================================================
   catalog.css — the logo chip and the "coming soon" card for /websites/.

   Loaded only by the pages that need it (page modules export `css`), so the
   shared sheets stay the size they are. Everything here is scoped under .cat3
   so it cannot leak into another grid.

   BRAND OS v3.0 "ATLAS". One rule changed here and it changed for a measured
   reason: the "coming soon" line used to be True North text on a white card.
   v3 §1.2 states it as a LAW — "never type on white at any size" — and the
   measurement is 2.85:1, which fails AA at every size. So the line follows the
   v3 status-chip pattern instead (P02): on a light ground the DOT carries the
   colour and the label does not. The label is now Midnight Green at 15.8:1 and
   the dot is Meridian, which is the signal colour for in progress.
   ========================================================================= */

/* The mark. One 44px slot for every card, whether the file behind it is a
   fetched brand logo with its own background (Legacy Steel Works), a
   transparent PNG that floats on the card (Leixir), or a full-bleed lettermark
   tile. object-fit: contain is what makes those three read as one row: nothing
   is cropped and nothing is stretched, so a wordmark and a monogram sit at the
   same optical weight. */
.legacy .cat3 .cat3-logo {
  width: 44px;
  height: 44px;
  /* v3 §3.5: a tile's corner radius is 22% of its width, "so an app icon and a
     favicon curve alike". 44 x 0.22 = 9.68px. These are other people's marks,
     not DJVF's, but the container they sit in is this site's. */
  border-radius: calc(44px * .22);
  object-fit: contain;
  display: block;
  margin-bottom: 4px;
  /* Fetched marks are drawn for a light ground, and the card is --card white,
     so this only matters if a sheet ever flips the card dark. */
  background: var(--card);
}

/* A hover rule used to sit here declaring a bare .18s transition on the
   logo: a raw duration the timing budget never owned, on a rule that named
   no property and so animated nothing. Deleted in the 2026-08-25 rollout.
   The card hover itself lives in shell3.css and carries the spark-glow
   family; the logo rides along without motion of its own. */

/* ---- The unlinked card ----------------------------------------------------
   Homeowner Insights has no public URL yet: the only build of it is a preview
   carrying a "not approved for publication" banner, so the card must not be
   clickable. shell3.css already gives div.cat3-cell the card shell; this adds
   the part that says "this one is deliberately not a link" — no hover lift, no
   pointer, and a badge where the URL line would be. */
.legacy .cat3 div.cat3-cell { cursor: default; }

/* The status line. Label in Midnight Green (15.8:1 on the white card), dot in
   Meridian — "in progress / information", which is exactly what an unpublished
   site is. Meridian measures 3.0:1 on white, which is why it is a 6px shape
   here and never the words. */
.legacy .cat3 .cat3-soon {
  font-family: var(--font-mono, monospace);
  font-size: 10.5px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--ink);
  margin-top: auto;
  padding-top: 8px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.legacy .cat3 .cat3-soon::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--beacon);
  flex: none;
}

/* The URL line sets word-break: break-all so a long domain wraps instead of
   overflowing. That is right for the domain and wrong for the words after it,
   which were breaking mid-syllable ("read the b / uild"), so the call to
   action opts out of the rule the domain needs. */
.legacy .cat3 .cat3-go {
  word-break: normal;
  overflow-wrap: normal;
  white-space: nowrap;
  color: var(--primary);
}

/* ---- The partner-microsite diagram ----------------------------------------
   It stands where fourteen cards used to. The cards named every partner and
   linked into live pages on the employer's domain; the diagram says the same
   thing about the ARCHITECTURE, which is the part that is DJ's to show.

   The SVG is inline and uses the site's own tokens, so it re-skins with the
   palette like everything else and adds no request. It scrolls inside its own
   box rather than shrinking below legibility: fourteen tiles at phone width
   would be fourteen grey specks. */
.legacy .ms {
  margin: 26px 0 0;
  background: var(--band);
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  padding: clamp(16px, 2.4vw, 28px);
  overflow-x: auto;
}

.legacy .ms svg {
  display: block;
  width: 100%;
  min-width: 660px;
  height: auto;
}

.legacy .ms figcaption {
  margin-top: 14px;
  font-size: var(--step--1);
  color: var(--muted);
  max-width: 62ch;
}

/* ============================================================================
   shots.css: screenshot previews for /work/ and the project pages.

   Loaded per page from src/pages/work.mjs. Two jobs:
     1. .shot        the full-width preview that sits near the top of a
                     project page, under the hero.
     2. .shot-thumb  the 16/10 thumbnail on a /work/ index card, plus
                     .shot-pending for the one card that has no shot to show.

   Every rule here is scoped to a .shot* class so nothing leaks into the
   shared card and figure styles in site.css.

   BRAND OS v3.0 "ATLAS". This sheet had the last three pasted hexes on the
   route: a #D9ECE7 frame that predated the token file and two rgba(0,26,26)
   shadow stacks. Both are gone. v3 §8.4 allows exactly two shadows — "0 1px 3px
   at 5% for resting sheets, 0 12px 30px -14px at 22% for floating ones.
   Nothing else" — which are --sh-sm and --sh-md, so those are what a screenshot
   frame uses now. Depth otherwise comes from a hairline, per law 3.
   ========================================================================= */

/* ---- FULL-WIDTH PREVIEW -------------------------------------------------- */

.legacy .shot-band {
  background: var(--paper);
  padding-top: clamp(30px, 4.5vw, 54px);
}

/* Sits directly under a stats band on pages that have one, so the top
   padding above collapses to nothing there and the shot rides up close. */
.legacy .proof + .shot-band { padding-top: clamp(24px, 3.5vw, 40px); }

.legacy .shot {
  margin: 0;
  max-width: 100%;
}

.legacy .shot img {
  display: block;
  width: 100%;
  max-width: 100%;
  height: auto;
  border-radius: var(--r);
  border: 1px solid var(--hairline);
  box-shadow: var(--sh-md);
  background: var(--band);
}

.legacy .shot figcaption {
  margin-top: 12px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--faint);
}

/* ---- CARD THUMBNAILS ----------------------------------------------------- */

/* Rides on .card-media from site.css, which already supplies the 16/10 box,
   the clipping and the object-fit. This only adds the frame. */
.legacy .card-media.shot-thumb {
  border: 1px solid var(--hairline);
  background: var(--band);
}

.legacy .card-media.shot-thumb img {
  display: block;
  width: 100%;
  max-width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
}

/* The card whose site is not published yet. Same box as a thumbnail so the
   grid stays level, but plainly not an image. */
.legacy .shot-pending {
  aspect-ratio: 16 / 10;
  margin: -4px -4px 16px;
  border-radius: calc(var(--r) - 4px);
  border: 1px dashed var(--hairline);
  background:
    repeating-linear-gradient(-45deg, transparent 0 9px, var(--hairline-soft) 9px 10px),
    var(--band);
  display: grid;
  place-items: center;
  overflow: hidden;
  padding: 18px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 600;
  line-height: 1.6;
  letter-spacing: .1em;
  text-transform: uppercase;
  /* --faint on --band is 4.49:1, a hair under AA at 10.5px. --muted on the
     same fill is 5.72:1. */
  color: var(--muted);
}

/* The label wraps to two tidy lines rather than one line that grazes the box
   edge on a narrow card. */
.legacy .shot-pending span { display: block; max-width: 22ch; }

/* ---- SMALL SCREENS ------------------------------------------------------- */

/* Nothing here is allowed to exceed its container at 375px. The widths above
   are already fluid; this trims the radius so the frame does not look
   oversized next to body text on a phone. The shadow does not get a third
   value: a phone-sized variant of --sh-md would be the fourth shadow in a
   system that publishes two. It steps DOWN a rung to the resting sheet
   instead, which is the same move the reproduction ladder makes. */
@media (max-width: 560px) {
  .legacy .shot img {
    border-radius: var(--r-sm);
    box-shadow: var(--sh-sm);
  }
  .legacy .shot figcaption { letter-spacing: .06em; }
}

/* demos.css — the shared kit for the four interactive proof demos
   (generic-vs-OS on /brand-os/, conflicting sources on /method/guardrails/,
   the live-data loop on /company-os/, the pricing engine on /work/).
   One file so the four read as one system. Everything draws from tokens.css;
   no new colors are invented here. States are attribute-driven
   ([aria-pressed], [data-state]) because the demo scripts must stay
   CSP-clean: no inline handlers, so no inline state styles either.

   2026-08-25: this file was calling two tokens that have never existed
   (--mono, --r-md) and their hardcoded fallbacks were doing all the work,
   which is exactly the failure shell3.css wrote down: a fallback only fires
   on a broken page, and then it paints the wrong value. Every var() below
   now names a real token from tokens.css and carries no second argument.
   Timing joined the house budget at the same pass: the pills transition on
   --t-hover and settle on --t-release, same as every control on the site. */

.legacy .demo {
  background: var(--card);
  border: 1px solid var(--hairline);
  border-radius: var(--r);
  padding: 26px 26px 24px;
  margin-top: 30px;
}
.legacy .demo-label {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  color: var(--muted);
  margin: 0 0 18px;
  padding-bottom: 12px;
  border-bottom: 1px dashed var(--hairline);
}

/* Task / question pickers. aria-pressed carries the state so a screen reader
   and the stylesheet read the same truth. */
.legacy .demo-tabs { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 18px; }
.legacy .demo-tab {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  padding: 8px 14px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  transition: background var(--t-hover) var(--ease), color var(--t-hover) var(--ease), border-color var(--t-hover) var(--ease);
}
.legacy .demo-tab:hover { border-color: var(--muted); }
.legacy .demo-tab:active { transition-duration: var(--t-press); }
.legacy .demo-tab[aria-pressed="true"] {
  background: var(--primary);
  color: var(--paper);
  border-color: var(--primary);
}
.legacy .demo-tab:focus-visible { outline: 2px solid var(--spark); outline-offset: 2px; }

/* Two-column compare (stacks on phones). */
.legacy .demo-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 700px) { .legacy .demo-cols { grid-template-columns: 1fr; } }
.legacy .demo-col {
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  padding: 16px 18px;
  min-width: 0;
}
.legacy .demo-col-k {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 10px;
}
.legacy .demo-col.is-os { border-color: var(--spark); }
.legacy .demo-col.is-os .demo-col-k { color: var(--spark); }

/* Output blocks: rendered "work", set apart from page prose. */
.legacy .demo-out {
  font-size: var(--step--1);
  line-height: 1.55;
  background: var(--paper);
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  padding: 14px 16px;
  overflow-x: auto;
}
.legacy .demo-out .demo-flag { text-decoration: underline dotted var(--spark); text-underline-offset: 3px; }
.legacy .demo-out table { border-collapse: collapse; width: 100%; font-variant-numeric: tabular-nums; }
.legacy .demo-out th,.legacy .demo-out td { text-align: right; padding: 4px 10px; border-bottom: 1px solid var(--hairline); font-size: var(--step--1); }
.legacy .demo-out th:first-child,.legacy .demo-out td:first-child { text-align: left; }

/* Stage rail for stepped demos (the loop). */
.legacy .demo-steps { list-style: none; display: flex; flex-wrap: wrap; gap: 6px; padding: 0; margin: 0 0 18px; }
.legacy .demo-steps li {
  font-family: var(--font-mono);
  font-size: 11.5px;
  letter-spacing: .06em;
  padding: 6px 12px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  color: var(--muted);
  transition: background var(--t-hover) var(--ease), color var(--t-hover) var(--ease), border-color var(--t-hover) var(--ease);
}
.legacy .demo-steps li[data-state="on"] {
  color: var(--paper);
  background: var(--primary);
  border-color: var(--primary);
}
.legacy .demo-steps li[data-state="done"] { color: var(--primary); border-color: var(--primary); }

/* Verdict rows: a gate result, a resolution, a filing. Semantic state via
   data-state, not color alone: each carries its own mono prefix text. */
.legacy .demo-verdict {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  border-left: 3px solid var(--hairline);
  padding: 6px 0 6px 14px;
  margin: 10px 0;
}
.legacy .demo-verdict[data-state="pass"] { border-left-color: var(--primary); }
.legacy .demo-verdict[data-state="fail"] { border-left-color: var(--spark); }
.legacy .demo-verdict[data-state="unknown"] { border-left-color: var(--muted); }

/* Source cards for the conflict demo. */
.legacy .demo-src { position: relative; }
.legacy .demo-src[data-state="wins"] { border-color: var(--primary); }
.legacy .demo-src[data-state="loses"] { opacity: .62; }
.legacy .demo-src-tag {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .1em;
  color: var(--muted);
}

/* Controls. */
.legacy .demo-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 18px; align-items: center; }
.legacy .demo-range { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin: 14px 0; }
.legacy .demo-range input[type="range"] { flex: 1 1 220px; accent-color: var(--spark); }
.legacy .demo-range output { font-family: var(--font-mono); font-variant-numeric: tabular-nums; min-width: 72px; }

/* Simple chart frame (pricing demo draws into an SVG inside this). */
.legacy .demo-chart { margin-top: 16px; border: 1px solid var(--hairline); border-radius: var(--r-sm); padding: 10px; overflow-x: auto; }
.legacy .demo-chart svg { display: block; width: 100%; height: auto; min-width: 420px; }

@media (prefers-reduced-motion: no-preference) {
  .legacy .demo-col,.legacy .demo-out,.legacy .demo-verdict { transition: opacity var(--t-release) var(--ease), border-color var(--t-release) var(--ease); }
}

/* /writing/ — the reference library.
   ---------------------------------------------------------------------------
   Deliberately thin. The articles reuse the site's existing typography
   (rc-article from resources.css carries the long-form heading scale), so this
   file holds only what /resources/ never needed: the diagram figures and the
   index list. If a rule here starts duplicating resources.css, it belongs
   there instead. */

/* ---- Diagram figures ------------------------------------------------------
   Every diagram is inline SVG in the locked style: monochrome line work on the
   card ground, one accent, mono labels, a caption underneath. The frame owns
   horizontal overflow so a diagram can keep a minimum legible width on a phone
   and scroll inside itself rather than breaking the page. */
.legacy .wfig { margin: 34px 0; }
.legacy .wfig-frame {
  border: 1px solid var(--hairline);
  border-radius: var(--r);
  background: var(--card);
  padding: clamp(14px, 3vw, 26px);
  overflow-x: auto;
}
.legacy .wfig-frame svg { display: block; width: 100%; height: auto; }
.legacy .wfig figcaption {
  margin-top: 10px;
  font-size: var(--step--1);
  line-height: 1.55;
  color: var(--muted);
}

/* ---- The index list -------------------------------------------------------
   Same shape as the reading path on /resources/, widened to carry a one-line
   summary. A numbered list rather than a card grid: seven reference pieces
   read as a shelf, not a feed. */
.legacy .wi-list { list-style: none; margin: 26px 0 0; padding: 0; display: grid; gap: 10px; }
.legacy .wi-list a {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  gap: 16px;
  align-items: start;
  padding: 18px 20px;
  border: 1px solid var(--hairline);
  border-radius: var(--r);
  background: var(--card);
  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);
}
/* Joined to the spark-glow family (2026-08-25 rollout), on the house timing
   tokens: this row ran its own .15s ease, the one timing on the site the
   budget did not own. */
.legacy .wi-list a:hover { border-color: var(--spark); transform: translateX(2px); box-shadow: 0 0 0 1px var(--spark), 0 0 14px color-mix(in srgb, var(--spark) 30%, transparent); }
.legacy .wi-list a:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.legacy .wi-n {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .06em;
  color: var(--spark);
  padding-top: 3px;
}
.legacy .wi-t { display: block; min-width: 0; }
.legacy .wi-t b {
  display: block;
  font-family: var(--font-display);
  font-size: var(--step-0);
  font-weight: 700;
  line-height: 1.3;
  /* Owned, not inherited (2026-08-26 hover audit): the row anchor inherits
     its colour from the section, so on the band-dark article closers the
     title was Paper on the white card, invisible at rest, and the summary
     line below it was carrying the whole row. The card fill is var(--card)
     on every ground this list renders on, so the title is ink on its own
     authority and no anchor-colour rule can repaint it. */
  color: var(--ink);
}
.legacy .wi-t span {
  display: block;
  margin-top: 6px;
  font-size: var(--step--1);
  line-height: 1.55;
  color: var(--muted);
}
.legacy .wi-t i {
  display: block;
  font-style: normal;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--faint);
  margin-top: 8px;
}

/* ---- The reading column (2026-08-25, DJ's margin fix) ---------------------
   The article ran down the left rail of a 1280px wrap with a measure-capped
   paragraph, which read as a page with its right half missing. The column
   itself now carries the measure and sits centered, so the whitespace is
   symmetric and deliberate. Diagrams fill the same column. */
.legacy .art-col { max-width: 760px; margin-inline: auto; }
.legacy .art-col .rc-article p { max-width: none; }
.legacy .art-col .note { max-width: none; }

/* The article hero centers with it: same dark ground, editorial axis. */
.legacy .phero--art .phero-in { text-align: center; }
.legacy .phero--art h1 { margin-inline: auto; max-width: 20ch; }
.legacy .phero--art .lede { margin-inline: auto; max-width: 62ch; }
.legacy .art-byline { font-size: 12px; color: var(--beacon); margin-top: 14px; }

/* ---- THE BOOKSHELF (2026-08-25, DJ's call) --------------------------------
   The index is a shelf and each reference piece is a spine. The six palette
   values do shelf duty (the owner's role-bound expansion): ink, spark, steel
   carry Paper type, Landfall and Meridian carry ink per their ratios, and
   the paper spine takes a hairline so it never floats. Heights vary the way
   a real shelf does. Books lift on hover; the star at the foot ignites. */
.legacy .shelf {
  display: flex; align-items: flex-end; gap: 12px;
  /* safe centring (2026-08-27): a centred flex row that overflows spills
     equally off BOTH edges, and you can only ever scroll toward the right
     one, so the first spine was unreachable between about 721px and 936px.
     `safe` falls back to flex-start the moment content stops fitting. */
  justify-content: flex-start;
  justify-content: safe center;
  margin-top: 34px; padding: 24px 18px 0;
  border-bottom: 10px solid var(--ink);
  overflow-x: auto;
}
.legacy .book {
  position: relative; flex: 0 0 auto; width: 96px;
  border-radius: 6px 6px 0 0;
  display: flex; flex-direction: column; align-items: center;
  padding: 14px 10px 12px;
  text-decoration: none;
  box-shadow: inset -8px 0 14px color-mix(in srgb, var(--ink) 22%, transparent);
  transition: transform var(--t-hover) var(--ease), box-shadow var(--t-hover) var(--ease);
}
.legacy .book::before,.legacy .book::after {
  content: ''; position: absolute; left: 9px; right: 9px; height: 1px;
  background: currentColor; opacity: .3;
}
.legacy .book::before { top: 36px; }
.legacy .book::after { bottom: 44px; }
.legacy .book:hover {
  transform: translateY(-10px);
  box-shadow: inset -8px 0 14px color-mix(in srgb, var(--ink) 22%, transparent),
              0 14px 26px color-mix(in srgb, var(--ink) 30%, transparent);
}
/* Was `2px solid var(--spark)`, which measured 2.64:1 against the light
    spines and quietly overrode the site's own :focus-visible. A focus
    indicator is a non-text UI component and owes 3:1. --primary is the
    site ring and clears it on every spine in the set (2026-08-27). */
.legacy .book:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; }
.legacy .book-n { font-family: var(--font-mono); font-size: 11px; font-weight: 600; letter-spacing: .08em; }
.legacy .book-t {
  flex: 1; display: flex; align-items: center;
  writing-mode: vertical-rl;
  font-family: var(--font-display); font-weight: 700; font-size: 13.5px;
  line-height: 1.25; letter-spacing: .01em;
  margin: 12px 0 10px; max-height: 100%;
}
.legacy .book-b { display: flex; flex-direction: column; align-items: center; gap: 5px; }
.legacy .book-b svg { display: block; transition: transform var(--t-hover) var(--ease); }
.legacy .book:hover .book-b svg { transform: rotate(45deg); }
.legacy .book-b i { font-style: normal; font-family: var(--font-mono); font-size: 10px; letter-spacing: .06em; }
/* the six spines */
.legacy .book-c0 { background: var(--ink); color: var(--paper); }
.legacy .book-c1 { background: var(--spark-surface); color: var(--paper); }
.legacy .book-c2 { background: var(--chrome); color: var(--paper); }
/* Hover re-declares the authored colour (2026-08-26): the global
   `a:hover { color: var(--ink) }` in site.css outranks a plain class, so
   the three Paper-type spines were going midnight on hover. On the
   midnight spine that meant ink on ink, fully invisible; on spark and
   steel it was merely wrong quietly. The three ink-type spines need
   nothing: the global rule paints them the colour they already are. */
.legacy .book-c0:hover,.legacy .book-c1:hover,.legacy .book-c2:hover { color: var(--paper); }
.legacy .book-c3 { background: var(--signal); color: var(--ink); }
.legacy .book-c4 { background: var(--beacon); color: var(--ink); }
.legacy .book-c5 { background: var(--paper); color: var(--ink); border: 1px solid var(--hairline); border-bottom: 0; }
/* the four heights */
.legacy .book-h0 { height: 372px; }
.legacy .book-h1 { height: 336px; }
.legacy .book-h2 { height: 356px; }
.legacy .book-h3 { height: 344px; }
.legacy .shelf-cap { margin-top: 14px; font-size: 11px; letter-spacing: .08em; color: var(--faint); max-width: none; }
@media (max-width: 720px) {
  .legacy .shelf { justify-content: flex-start; }
}
@media (prefers-reduced-motion: reduce) {
  .legacy .book,.legacy .book-b svg { transition: none; }
  .legacy .book:hover { transform: none; }
}

