/* =============================================================================
   ebomi / catalog.css
   The production stylesheet for the open-access catalog surfaces.
   WRK-20260731T1204Z, executing SPEC-20260731T1159Z, built against
   docs/ux/design-bible.md.

   WHAT THIS FILE IS, AND WHAT IT IS NOT.

   static/sg2/broadsheet.css is a GALLERY asset. It is the chosen direction
   rendered as a specimen page, and it carries the scaffolding that specimen
   page needs. This file is the production system: the same vocabulary,
   promoted, with the gallery's demo furniture left behind and the components
   the bible specifies for the catalog (8.13 to 8.17) drawn for the first time.

   PROMOTED FROM THE GALLERY, value for value, with no re-pointing:
     the face and its swap-window stand-ins (bible 4)
     the reset
     the whole token block: primitives, roles, type, space, rules, radius,
       motion, measure and grid, and the reading gear of the density ladder
       (bible 3, 4, 5, 6, 7)
     base elements, the sheet grid, print furniture
     .fig / .led / .sig                    (bible 8.2)
     .btn and every variant                (bible 8.3)
     .field / .input / .select / .check / .fieldset / .setter   (bible 8.4)
     the ledger, its scrollport affordance, the code chip        (bible 8.5)
     the density gears                     (bible 7)
     badges, notes, the citation block, cards, .blank, .fault, .folio-nav
                                           (bible 8.6, 8.7, 8.8, 8.10, 8.11)
     the specimen (the trade card, promoted to the filing page) (bible 8.9)
     the tape                              (bible 8.12)
     the hero and .stat                    (bible 9.5)
     the theme transition, reduced motion, forced colours, print

   DELIBERATELY LEFT BEHIND, each for a stated reason:
     Section 14 of the gallery in its entirety: .demo, .swatch, .chip, .rail,
       .den-exhibit, .audit and the rest. That is scaffolding for a page whose
       subject is the design system. No catalog page has that subject.
     .states, the exhibit grid that shows the four container states side by
       side. The states themselves are here; the exhibit of them is gallery.
     .interval and .withheld, the analytic slot. DEC-20260731T0438Z forbids an
       analytics slot until the analytic exists, and SPEC-20260731T1159Z
       section 3 states there are no placeholder panels anywhere in this IA. A
       component that cannot be fed truthfully does not ship, so it is absent
       rather than present and empty.
     The magnitude measure on the ledger value cell, .ledger__value::before
       and ::after. The mechanics are correct and the absolute constant they
       read against is UNDECIDED: WRK-20260731T0612Z is open, the gallery's
       USD 12M is labelled specimen copy in the gallery's own caption, and the
       saturation treatment for rows above the constant is not drawn. Shipping
       the meter would mean printing a scale nobody chose, which is law 4. The
       value column ships as a plain right-aligned figure until that record
       closes; the CSS needs no change then, because --mag is data.
     The reading gauge (.gauge). It is a scroll-linked ornament with no
       informational duty the folio does not already discharge.

   NEWLY DRAWN HERE, specified by the bible but never rendered before:
     .searchbar     the search form and its two placements          (8.13)
     .results       the result row and the results list             (8.14)
     .count-line    the result count and the applied-filter line    (8.15)
     .facets        the facet list as a printed index               (8.16)
     .entity        the entity header, coverage, variants, cross-link (8.17)
     .prov          the closing provenance band
     .colophon      the catalog footer carrying the licence line

   THE LAWS THIS FILE IS REVIEWED AGAINST (bible section 1): the chrome is
   achromatic and pigment appears only on a reported transaction; colour is
   never the only channel; every quantity is set through .fig or .led; nothing
   is asserted that cannot be checked; a reservation never lies; every value
   comes from a token; one radius and its value is zero; empty is a finding and
   a fault outranks a blank; absence is stated in words; decisions are printed,
   never inferred.

   NO BUILD STEP, NO CDN, NO EXTERNAL HOST (ADR-20260729T0001Z). The only
   download is the serif already shipped under static/fonts/, unchanged.
   ============================================================================= */


/* -----------------------------------------------------------------------------
   0  THE FACE
   Broadsheet Serif is Source Serif 4 4.004, subset to 211 codepoints, weight
   axis clipped 400-700, opsz 8-60 kept whole, renamed under OFL clause 3.
   Already shipped under static/fonts/. Nothing is added here and the
   unicode-range is copied verbatim, because a template that sets a codepoint
   outside it silently falls back to a stand-in face for that glyph.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Broadsheet Serif";
  src: url("/static/fonts/source-serif-4-subset.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
  ascent-override: 103.60%;
  descent-override: 33.50%;
  line-gap-override: 0%;
  unicode-range: U+0020-007E, U+00A0, U+00A9, U+00AE, U+00B0-00B1, U+00B6-00B7,
                 U+00C0-00FF, U+0141-0142, U+0152-0153, U+0160-0161, U+0178,
                 U+017D-017E, U+0192, U+02C6, U+02DC, U+200B, U+2010-2014,
                 U+2018-201A, U+201C-201E, U+2020-2022, U+2026, U+2030,
                 U+2032-2033, U+2039-203A, U+2044, U+20AC, U+2122, U+2190,
                 U+2192, U+2197, U+2212, U+2248, U+2260, U+2264-2265, U+2713;
}

@font-face {
  font-family: "Broadsheet Serif";
  src: url("/static/fonts/source-serif-4-italic-subset.woff2") format("woff2");
  font-weight: 400 700;
  font-style: italic;
  font-display: swap;
  ascent-override: 103.60%;
  descent-override: 33.50%;
  line-gap-override: 0%;
  unicode-range: U+0020-007E, U+00A0, U+00A9, U+00AE, U+00B0-00B1, U+00B6-00B7,
                 U+00C0-00FF, U+0141-0142, U+0152-0153, U+0160-0161, U+0178,
                 U+017D-017E, U+0192, U+02C6, U+02DC, U+200B, U+2010-2014,
                 U+2018-201A, U+201C-201E, U+2020-2022, U+2026, U+2030,
                 U+2032-2033, U+2039-203A, U+2044, U+20AC, U+2122, U+2190,
                 U+2192, U+2197, U+2212, U+2248, U+2260, U+2264-2265, U+2713;
}


/* -----------------------------------------------------------------------------
   0b  THE SWAP-WINDOW STAND-INS
   Per weight and per style, each size-adjust equalising that face's
   corpus-weighted mean advance against the shipped face at opsz 19, with
   ascent and descent divided by the same figure so the line box is identical
   before and after the swap. This is what holds CLS at 0.00134 at 1440px.
   Carried verbatim: a re-derivation here would be a second set of numbers
   claiming to be the same measurement.
   -------------------------------------------------------------------------- */

/* macOS and Windows */
@font-face {
  font-family: "bs-fb-georgia";
  src: local("Georgia");
  font-style: normal; font-weight: 400;
  size-adjust: 101.55%; ascent-override: 102.02%; descent-override: 32.99%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "bs-fb-georgia";
  src: local("Georgia Bold"), local("Georgia-Bold");
  font-style: normal; font-weight: 700;
  size-adjust: 90.46%; ascent-override: 114.53%; descent-override: 37.03%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "bs-fb-georgia";
  src: local("Georgia Italic"), local("Georgia-Italic");
  font-style: italic; font-weight: 400;
  size-adjust: 93.06%; ascent-override: 111.32%; descent-override: 36.00%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "bs-fb-georgia";
  src: local("Georgia Bold Italic"), local("Georgia-BoldItalic");
  font-style: italic; font-weight: 700;
  size-adjust: 86.27%; ascent-override: 120.09%; descent-override: 38.83%;
  line-gap-override: 0%;
}

/* Android, and most Linux desktops */
@font-face {
  font-family: "bs-fb-noto";
  src: local("Noto Serif"), local("NotoSerif"), local("Droid Serif");
  font-style: normal; font-weight: 400;
  size-adjust: 94.69%; ascent-override: 109.41%; descent-override: 35.38%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "bs-fb-noto";
  src: local("Noto Serif Bold"), local("NotoSerif-Bold"), local("Droid Serif Bold");
  font-style: normal; font-weight: 700;
  size-adjust: 92.40%; ascent-override: 112.13%; descent-override: 36.26%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "bs-fb-noto";
  src: local("Noto Serif Italic"), local("NotoSerif-Italic"), local("Droid Serif Italic");
  font-style: italic; font-weight: 400;
  size-adjust: 90.47%; ascent-override: 114.51%; descent-override: 37.03%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "bs-fb-noto";
  src: local("Noto Serif Bold Italic"), local("NotoSerif-BoldItalic");
  font-style: italic; font-weight: 700;
  size-adjust: 88.81%; ascent-override: 116.66%; descent-override: 37.72%;
  line-gap-override: 0%;
}

/* The Times-metric group. One adjustment covers it because Liberation Serif
   and Times New Roman share a corpus-weighted mean advance to five decimals. */
@font-face {
  font-family: "bs-fb-times";
  src: local("Liberation Serif"), local("Nimbus Roman"), local("Tinos"),
       local("Times New Roman"), local("Times");
  font-style: normal; font-weight: 400;
  size-adjust: 111.21%; ascent-override: 93.16%; descent-override: 30.12%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "bs-fb-times";
  src: local("Liberation Serif Bold"), local("Nimbus Roman Bold"),
       local("Tinos Bold"), local("Times New Roman Bold"), local("Times Bold");
  font-style: normal; font-weight: 700;
  size-adjust: 108.58%; ascent-override: 95.42%; descent-override: 30.85%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "bs-fb-times";
  src: local("Liberation Serif Italic"), local("Nimbus Roman Italic"),
       local("Tinos Italic"), local("Times New Roman Italic"), local("Times Italic");
  font-style: italic; font-weight: 400;
  size-adjust: 103.20%; ascent-override: 100.39%; descent-override: 32.46%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "bs-fb-times";
  src: local("Liberation Serif Bold Italic"), local("Nimbus Roman Bold Italic"),
       local("Tinos Bold Italic"), local("Times New Roman Bold Italic");
  font-style: italic; font-weight: 700;
  size-adjust: 108.56%; ascent-override: 95.43%; descent-override: 30.86%;
  line-gap-override: 0%;
}


/* -----------------------------------------------------------------------------
   1  RESET
   -------------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-padding-block-start: 6rem;
}

body { min-block-size: 100svb; }

img, svg { display: block; max-inline-size: 100%; }

input, button, textarea, select { font: inherit; color: inherit; letter-spacing: inherit; }
button { background: none; border: 0; }

h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd, ol, ul { margin: 0; }
ol, ul { padding: 0; list-style: none; }

table { border-collapse: collapse; border-spacing: 0; }

:target { scroll-margin-block-start: 7rem; }


/* -----------------------------------------------------------------------------
   2  TOKENS   (bible sections 3 to 7)

   2a  PRIMITIVES. Two neutral ramps at fixed OKLCH hues plus two pigments, and
       these four families are the complete chromatic inventory of the system.
       There is no green, no red, no violet, no gold. Each hex is the
       sRGB-clipped result of the OKLCH triple beside it.
   -------------------------------------------------------------------------- */

:root {
  color-scheme: light dark;

  /* warm paper, hue 85 */
  --paper-0:    #fffefb;   /* oklch(.996 .0030 85) */
  --paper-50:   #f9f7f3;   /* oklch(.976 .0055 85) */
  --paper-100:  #f2efea;   /* oklch(.953 .0075 85) */
  --paper-200:  #e5e2db;   /* oklch(.912 .0100 85), published ramp step */
  --paper-300:  #cfccc4;   /* oklch(.845 .0110 85) */
  --paper-400:  #b3afa7;   /* oklch(.755 .0115 85) */

  /* BLUE INK, hue 258, and it is meant to look blue. The PI, 2026-08-18: the
     dark theme should be "a nice dark but pastel blue" rather than reading as
     black and white.

     The ramp was ALREADY hue 266 and still read as neutral, because chroma ran
     .015 to .044, which is below where an eye names a colour. Two changes:
     chroma roughly doubled, and the three darkest steps lifted in lightness so
     the canvas is a deep navy rather than a near-black with a tint. Hue moved
     266 to 258 as well; 266 leans toward violet and 258 is the blue somebody
     would actually call blue.

     MEASURED, NOT PICKED BY EYE. Every ratio the block below documents was
     recomputed against the new canvas and every one still clears its floor:
     body 17.34 (was 18.48), display 18.40, muted 8.49, faint 6.97 (up from
     6.35), body on surface 15.91, and the strong rule 5.00 against a floor of
     3.0 for a non-text boundary. Contrast was spent deliberately and there is
     a great deal of headroom left. */
  --ink-300:    #8fa0b8;   /* oklch(.700 .0400 258) */
  --ink-400:    #7386a2;   /* oklch(.615 .0480 258) */
  --ink-500:    #596e8e;   /* oklch(.535 .0560 258) */
  --ink-600:    #40587a;   /* oklch(.455 .0640 258) */
  --ink-700:    #2b4366;   /* oklch(.380 .0680 258) */
  --ink-800:    #183053;   /* oklch(.310 .0700 258) */
  --ink-900:    #0f2546;   /* oklch(.268 .0670 258) */
  --ink-950:    #081c38;   /* oklch(.228 .0610 258) */
  --ink-1000:   #04132a;   /* oklch(.188 .0530 258) */

  /* the only two chromatic families, and they carry one variable: direction */
  --prussian-600: #07558e; /* oklch(.440 .1150 248) */
  --prussian-300: #75c0f4; /* oklch(.780 .1050 240) */
  --oxide-600:    #9d331e; /* oklch(.475 .1450 33)  */
  --oxide-300:    #f39e76; /* oklch(.775 .1150 46)  */

  /* -------------------------------------------------------------------------
     2b  ROLES. Every one is a light-dark() pair. light-dark() resolves where a
     token is USED, not where it is declared, so no component may set its own
     color-scheme casually. The manual toggle stamps data-theme on :root.
     Measured ratios, bible 3.2: body ink 16.04 paper / 18.48 ink; muted 7.91 /
     9.05; faint 5.63 / 6.35; disabled on sunken 3.81 / 3.93; buy 7.27 / 9.98;
     sell 6.71 / 9.38; the strong rule 5.63 / 4.53 on canvas.
     ---------------------------------------------------------------------- */

  --c-canvas:       light-dark(var(--paper-50),  var(--ink-1000));
  --c-surface:      light-dark(var(--paper-0),   var(--ink-950));
  --c-sunken:       light-dark(var(--paper-100), var(--ink-900));

  --c-ink:          light-dark(var(--ink-900),   var(--paper-50));   /* body      */
  --c-ink-strong:   light-dark(var(--ink-950),   var(--paper-0));    /* display   */
  --c-ink-muted:    light-dark(var(--ink-600),   var(--paper-400));  /* secondary */
  --c-ink-faint:    light-dark(var(--ink-500),   var(--ink-300));    /* meta      */
  --c-ink-disabled: var(--ink-400);                                  /* same both */

  --c-mark:         light-dark(var(--ink-800),   var(--paper-50));
  --c-on-mark:      light-dark(var(--paper-0),   var(--ink-1000));

  /* Three rule weights and they are NOT interchangeable. The hair is
     decorative. --c-rule groups content and is not a text colour. Only
     --c-rule-strong may bound something a user can operate. */
  --c-rule-hair:    light-dark(var(--paper-300), var(--ink-900));
  --c-rule:         light-dark(var(--paper-400), var(--ink-700));
  --c-rule-strong:  light-dark(var(--ink-500),   var(--ink-400));

  --c-buy:          light-dark(var(--prussian-600), var(--prussian-300));
  --c-sell:         light-dark(var(--oxide-600),    var(--oxide-300));
  --c-admin:        var(--c-ink-faint);

  --c-focus:        var(--c-mark);
  --c-focus-halo:   var(--c-canvas);

  /* Derived, never hand-picked. Exactly three, and neither wash is a pigment. */
  --c-note-wash:    color-mix(in oklab, var(--c-mark)  5%, var(--c-canvas));
  --c-hover-wash:   color-mix(in oklab, var(--c-mark)  6%, var(--c-canvas));
  --c-mark-hover:   color-mix(in oklab, var(--c-mark) 86%, var(--c-canvas));

  /* -------------------------------------------------------------------------
     2c  TYPE. Four voices. The serif is the only download.
     ---------------------------------------------------------------------- */
  --face-text: "Broadsheet Serif", "bs-fb-georgia", "bs-fb-noto", "bs-fb-times",
               Georgia, "Liberation Serif", "Times New Roman", serif;
  --face-ui:   ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, "Liberation Sans", sans-serif;
  --face-fig:  var(--face-ui);
  --face-ident: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
                "Liberation Mono", "DejaVu Sans Mono", monospace;

  /* Two ratios pivoting on the prose step: roughly 1.125 below, 1.25 above,
     each step pulled to a whole pixel at a 16px root.

     THE WHOLE SCALE MOVED UP ONE STEP ON 2026-08-19, BY THE PI'S DECISION,
     AS A SCALE AND NOT PER ELEMENT (WRK-20260819T1401Z). He raised "tiny
     font for the target academic user group" four times; the audience reads
     for a living and the old 11px folios and 15px UI labels priced them out.
     Every token keeps its job and gains a rung: micro 11->13, mini 13->15,
     small 15->17, base 17->19, body 19->21, lead 24->26, sub 30->32,
     head 38->40, title 48->50. The two clamps below are viewport-driven
     display steps outside the ratio ladder and do not move. Bible sections
     4.1 and 4.3 are superseded in the same commit as this block, which is
     the only way the two cannot be true at different commits (bible 12.2). */
  --t-micro:   0.8125rem;  /* 13 */
  --t-mini:    0.9375rem;  /* 15 */
  --t-small:   1.0625rem;  /* 17 */
  --t-base:    1.1875rem;  /* 19 */
  --t-body:    1.3125rem;  /* 21 */
  --t-lead:    1.625rem;   /* 26 */
  --t-sub:     2rem;       /* 32 */
  --t-head:    2.5rem;     /* 40 */
  --t-title:   3.125rem;   /* 50 */
  --t-display: clamp(2.75rem, 1.05rem + 6.8vw, 5.5rem);
  --t-nameplate: clamp(3.25rem, 0.4rem + 11.4vw, 8.5rem);

  --lh-solid:  1;
  --lh-display: 0.96;
  --lh-tight:  1.08;
  --lh-head:   1.16;
  --lh-lead:   1.32;
  --lh-ui:     1.4;
  --lh-prose:  1.62;

  --tr-nameplate: -0.05em;
  --tr-display:   -0.032em;
  --tr-title:     -0.022em;
  --tr-head:      -0.014em;
  --tr-flat:       0em;
  --tr-caps:       0.14em;
  --tr-caps-snug:  0.08em;

  --w-book:   400;
  --w-medium: 500;
  --w-semi:   600;
  --w-bold:   700;

  /* 2d  SPACE */
  --sp-1:  0.25rem;
  --sp-2:  0.5rem;
  --sp-3:  0.75rem;
  --sp-4:  1rem;
  --sp-5:  1.5rem;
  --sp-6:  2rem;
  --sp-7:  3rem;
  --sp-8:  4rem;
  --sp-9:  6rem;
  --sp-10: 8.5rem;
  --band:  clamp(2.75rem, 1.5rem + 6vw, 6.5rem);

  /* 2e  RULES. Weight is the hierarchy. This is the whole visual system. */
  --rule-hair:      1px solid var(--c-rule-hair);
  --rule-thin:      1px solid var(--c-rule);
  --rule-control:   1px solid var(--c-rule-strong);
  --rule-mid:       2px solid var(--c-rule-strong);
  --rule-heavy:     3px solid var(--c-ink);
  --rule-nameplate: 6px solid var(--c-ink);

  /* 2f  One radius, and its value is zero. Law 7, not an oversight. */
  --radius: 0px;

  /* 2g  MOTION. Three durations, two curves, and that is the whole budget. */
  --dur-press:  70ms;
  --dur-fast:   130ms;
  --dur-page:   520ms;
  --ease-out:   cubic-bezier(.2, 0, 0, 1);
  --ease-inout: cubic-bezier(.4, 0, .2, 1);

  /* 2h  MEASURE AND GRID */
  --measure: 36rem;
  --flank: 16rem;
  --gutter: clamp(1.25rem, 4vw, 3rem);

  /* 2i  DENSITY, the reading gear: the default and the only unmarked state.
         The other two gears are token re-pointings in section 9b. */
  --den-pad-block:    var(--sp-3);
  --den-pad-inline:   var(--sp-3);
  --den-size:         var(--t-small);
  --den-leading:      1.45;
  --den-chip:         1.55rem;
  --den-flag-pad:     2px;
  --den-flag-leading: 1.5;
}

:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"]  { color-scheme: dark; }


/* -----------------------------------------------------------------------------
   3  BASE ELEMENTS
   -------------------------------------------------------------------------- */

body {
  background: var(--c-canvas);
  color: var(--c-ink);
  font-family: var(--face-text);
  font-size: var(--t-body);
  line-height: var(--lh-prose);
  font-optical-sizing: auto;
  /* Oldstyle in sentences, lining in tables. Enforced by class below, so a
     template never sets numeric features by hand. */
  font-variant-numeric: oldstyle-nums proportional-nums;
  text-underline-offset: 0.16em;
  text-decoration-thickness: from-font;
}

p { text-wrap: pretty; }

h1, h2, h3, h4 {
  font-family: var(--face-text);
  font-weight: var(--w-semi);
  color: var(--c-ink-strong);
  text-wrap: balance;
  font-variant-numeric: lining-nums proportional-nums;
}
/* SIZE IS PART OF THE DEFAULT, because for eleven days it was not and Chrome
   sized the headings. The block above set face, weight, colour and wrap and
   never font-size, so every heading without a classed rule took the UA's em
   ratios: six h2 on the landing page rendered 28.5px (19px x 1.5em), which is
   on no rung of the ladder and sat 1.5px BELOW the .card h3 they governed, and
   every document page's h1 rented its 38px from `h1 { font-size: 2em }`, a
   number that only equals --t-head while --t-body is 19px. These are element
   defaults at (0,0,1): every existing classed rule (.section-head h2,
   .card h2, .entity h1, .prose h2) still wins. Measured by CDP matched-rules
   sweep, 15 UA-sized headings across 12 routes, 2026-08-20,
   WRK-20260819T1401Z. */
h1 { font-size: var(--t-head); line-height: var(--lh-head); letter-spacing: var(--tr-head); }
h2 { font-size: var(--t-sub); line-height: var(--lh-head); letter-spacing: var(--tr-head); }
h3 { font-size: var(--t-lead); line-height: var(--lh-head); }
h4 { font-size: var(--t-base); line-height: var(--lh-head); }

/* The palette is achromatic, so a link can never be signalled by hue. It is
   signalled by the underline, always present, thickening on hover. */
a {
  color: inherit;
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  text-decoration-color: color-mix(in oklab, currentColor 55%, transparent);
  transition: text-decoration-thickness var(--dur-fast) var(--ease-out),
              text-decoration-color var(--dur-fast) var(--ease-out);
}
a:hover { text-decoration-thickness: 2px; text-decoration-color: currentColor; }

:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--c-focus);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px var(--c-focus-halo);
}
:where(a, button, input, select, textarea, summary, [tabindex]):focus:not(:focus-visible) {
  outline: none;
}

::selection { background: var(--c-mark); color: var(--c-on-mark); }

hr { border: 0; border-block-start: var(--rule-thin); margin-block: var(--sp-6); }

code, kbd, samp {
  font-family: var(--face-ident);
  font-size: 0.9em;
  font-variant-numeric: tabular-nums lining-nums slashed-zero;
}

abbr[title] { text-decoration: underline dotted; text-underline-offset: 0.2em; cursor: help; }


/* -----------------------------------------------------------------------------
   4  THE SHEET
   A five-track broadsheet grid with named lines. column-gap is 0 deliberately:
   the tracks ARE the gutters, and a gap is added to all four seams without
   being subtracted from the text track's `100% - gutter*2`, which computes the
   grid wider than the viewport and scrolls the whole document sideways.
   -------------------------------------------------------------------------- */

.sheet {
  display: grid;
  grid-template-columns:
    [full-start] minmax(var(--gutter), 1fr)
    [wide-start] minmax(0, var(--flank))
    [text-start] min(var(--measure), 100% - var(--gutter) * 2)
    [text-end]   minmax(0, var(--flank))
    [wide-end]   minmax(var(--gutter), 1fr)
    [full-end];
  column-gap: 0;
}
/* min-inline-size:0 is load bearing. A grid item defaults to min-width:auto and
   refuses to shrink below its content, so a wide ledger inside an overflow-x
   container pushes the whole document sideways on a phone. */
.sheet > * { grid-column: text; min-inline-size: 0; }
.sheet > .wide { grid-column: wide; }
.sheet > .full { grid-column: full; }

.sheet > .marginal {
  grid-column: wide-start / text-start;
  justify-self: end;
  align-self: start;
  max-inline-size: var(--flank);
  font-family: var(--face-ui);
  font-size: var(--t-mini);
  line-height: var(--lh-ui);
  color: var(--c-ink-muted);
  text-align: right;
  border-inline-end: var(--rule-thin);
  padding-inline-end: var(--sp-3);
  margin-inline-end: var(--sp-5);
  padding-block: var(--sp-1);
  font-variant-numeric: lining-nums tabular-nums;
}
@media (width < 68rem) {
  .sheet > .marginal {
    grid-column: text;
    justify-self: stretch;
    max-inline-size: none;
    text-align: left;
    border-inline-end: 0;
    border-inline-start: var(--rule-mid);
    padding-inline: var(--sp-3) 0;
    margin-inline-end: 0;
    margin-block-start: var(--sp-3);
  }
}

.band { padding-block: var(--band); }
.band + .band { border-block-start: var(--rule-hair); }
/* A band that only separates content from the page foot pays a smaller gap:
   the catalog's entity pages carry five or six bands and the full --band
   between each of them puts the citation block two screens below the ledger. */
.band--tight { padding-block: var(--sp-7); }
.stack   { display: grid; gap: var(--sp-4); align-content: start; }
.stack-5 { display: grid; gap: var(--sp-5); align-content: start; }
.stack-6 { display: grid; gap: var(--sp-6); align-content: start; }
.row     { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; }
.row--between { justify-content: space-between; }


/* -----------------------------------------------------------------------------
   5  PRINT FURNITURE   (bible 8.1)
   -------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------
   ONE MASTHEAD ROW, 2026-08-19

   The catalog header was FOUR stacked rows where the product's is one:
   wordmark, then a two-line strap, then the folio, then a full-width search
   bar. Measured on production at 1280: 440px of masthead against the platform
   shell's 125px, on every entity page. The PI reported it three times and the
   third was "header still ugly don't want to fix, why?".

   Three changes, and none of them is a new component:

     1. The strap moved to the footer. Both its lines are standing claims about
        the whole catalog, which is what a footer holds; the licence and
        coverage lines already say the same kind of thing down there.
     2. The search form moved INSIDE the folio, between the nav and the
        controls, which is where every console this is being compared to puts
        it.
     3. Above 64rem the wordmark and the folio share a line.

   The vocabulary is untouched. Same nameplate, same folio, same setter, same
   compact searchbar, same rules; only the arrangement moved, which is the
   least this could be changed by and still answer the complaint.

   BELOW 64rem IT STILL STACKS, deliberately. A wordmark, five nav links, a
   search field, a theme setter and an account control do not fit one line on a
   phone, and squeezing them would cost the 44px target floor every one of them
   currently keeps.
   --------------------------------------------------------------------------- */
@media (width >= 75rem) {
  .sheet > .wide:has(> .nameplate) {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0 var(--sp-5);
  }
  /* Two children share the first line; the search is forced onto the next. */
  .sheet > .wide > .searchbar--compact { flex-basis: 100%; }
  .sheet > .wide > .nameplate {
    padding-block: var(--sp-3);
    border-block-end: 0;
    flex: none;
  }
  .sheet > .wide > .nameplate .nameplate__word { margin-block-end: 0; }
  .sheet > .wide > .folio {
    flex: 1 1 auto;
    min-inline-size: 0;
    border-block-end: 0;
    flex-wrap: nowrap;
  }
  /* The search sits below that row, full width, still compact. */
  .sheet > .wide > .searchbar--compact { padding-block: 0 var(--sp-3); }
  /* Nothing in this row may wrap, or the "one row" is one row of stacks. The
     sets keep their internal wrapping everywhere else, where it is what makes
     the strip work on a phone. */
  .sheet > .wide > .folio > .folio__set { flex-wrap: nowrap; }
  .sheet > .wide > .folio { gap: var(--sp-2) var(--sp-4); }
  /* A two-word label breaking across two lines inside its own box is what the
     row looked like before this: "THE / CATALOG" and "SIGN / IN" each took two
     lines and set the height of everything beside them. Nowrap here only, in
     the one-row mode; wrapping is right at every narrower width. */
  .sheet > .wide > .folio .folio__link { white-space: nowrap; }

  /* THE SEARCH KEEPS ITS OWN LINE, and that is a measurement rather than a
     preference. Squeezed into the identity row at 1440 it was 79px wide, which
     is four characters of a field whose placeholder reads "Issuer, insider,
     ticker, CIK, or accession": a wordmark, five nav links, a setter and an
     account control had already spent the row. Two rows at 150px against the
     platform shell's one at 125px is a difference nobody can see; a search box
     you cannot read your own query in is one anybody can. */

  /* A `span[aria-hidden]` display:none used to sit here to delete the visible
     "Theme" word on the one-row masthead. The word became three icons inside
     the trigger on 2026-08-19, so the selector matched nothing, and it was a
     trap: the day the folio separators gained the aria-hidden they owe, this
     rule would have deleted the dots from the desktop masthead that bible
     8.8's own specimen describes. Deleted, not narrowed, because there is no
     longer anything for it to hide. */
}
/* The rule under the masthead is drawn once, by the header, rather than by
   whichever child happens to be last. Without the second line the header drew
   its rule and the first band drew another one a few pixels below, with an
   empty strip between them that read as a missing element. */
.sheet > .wide:has(> .nameplate) { border-block-end: var(--rule-nameplate); }
.folio { border-block-end: 0; }

/* -----------------------------------------------------------------------------
   THE PHONE AND TABLET MASTHEAD IS ONE COMPOSED BAR, NOT A STACK OF LEFTOVERS.

   What the PI photographed on 2026-08-19 ("this is embarrassing"), measured on
   the live apex at 430: a 304px header of five strata. The wordmark alone on
   a row with its right half empty; five nav links WRAPPED across two rows
   56px apart; the account control floating on a row of its own; then the
   search. Every element obeyed its own rules and the whole read as spillage,
   which is the audit's core finding, local correctness is not composition,
   repeated by this masthead one level up.

   The bar, top to bottom, one grammar shared with the platform shell:

     row 1   wordmark left, controls right (theme, sign-in or account)
     ------- the 3px brand rule, spanning the bar
     row 2   the nav, ONE line that never wraps. When it cannot fit it
             SCROLLS, which is the tabs convention every phone user already
             knows, and the half-visible item at the edge is its own
             affordance. A line that cannot break cannot strand a separator,
             so the folio's middots are structurally safe here.
     ------- hairline
     row 3   the compact search

   The 44px floor survives on every control, which is what the old stacked
   regime existed to protect: the links keep their boxes, the row simply
   refuses to wrap. Measured after: 176px at 390 against 304 before, and the
   nav strip fits without scrolling at 390 and up. WRK-20260819T1401Z. */
@media (width < 75rem) {
  .sheet > .wide:has(> .nameplate--compact) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) max-content;
    align-items: center;
    column-gap: var(--sp-3);
  }
  .sheet > .wide > .nameplate--compact {
    grid-column: 1; grid-row: 1;
    border-block-end: 0;
    padding-block: var(--sp-2) var(--sp-1);
  }
  .sheet > .wide > .nameplate--compact .nameplate__word { margin-block-end: 0; }
  .sheet > .wide > .folio { display: contents; }
  .sheet > .wide > .folio > .folio__set:last-child {
    grid-column: 2; grid-row: 1;
    flex-wrap: nowrap;
    justify-self: end;
  }
  .sheet > .wide > .folio > .folio__set:first-child {
    grid-column: 1 / -1; grid-row: 2;
    max-inline-size: 100%;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    border-block-start: var(--rule-heavy);
    border-block-end: var(--rule-hair);
    padding-block: var(--sp-1);
    /* Tighter than the desktop folio's gap: five items on a strip, and the
       narrower gap is what lets 430 hold all five outright while 375 shows a
       clean half-item peek instead of a sliver. */
    gap: var(--sp-2) var(--sp-4);
  }
  .sheet > .wide > .folio > .folio__set:first-child::-webkit-scrollbar { display: none; }
  /* flex: none on every child, or nowrap+overflow lets the items SHRINK
     below their text and the labels overlap each other (measured: "THE
     CATALOG" painted over "ISSUERS" before this line). A strip scrolls; it
     never crushes. */
  .sheet > .wide > .folio > .folio__set:first-child > * { flex: none; }
  .sheet > .wide > .folio > .folio__set:first-child { justify-content: flex-start; }
  .sheet > .wide > .folio > .folio__set:first-child .folio__link { white-space: nowrap; }
  .sheet > .wide > .searchbar--compact { grid-column: 1 / -1; grid-row: 3; }
  /* A long account address must squeeze itself, never the wordmark. */
  .folio-account > summary {
    max-inline-size: 45vw;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  /* With the bar this short, the first band's own rule no longer needs half a
     band of paper to breathe; the old distance made the two rules read as a
     duplication with a hole between them. And the first band's SECTION HEAD
     draws no rule of its own on these widths: the header's 6px rule is
     40px above it, and two heavy bars with a strip of paper between them
     read as one element broken, not two elements composed. The numbered
     head further down the page keeps its rule, where it has matter above
     it to separate from. */
  main > section.band:first-of-type,
  main > .band:first-of-type { padding-block-start: var(--sp-4); }
}
/* The header already drew a rule, so the first band under it must not draw a
   second one four pixels lower with an empty strip between them. `.band` sets
   `border-block-start` on every section; this cancels it for the first section
   on the page, which is the only one whose rule the masthead has already
   supplied. */
main > section.band:first-of-type,
main > .band:first-of-type { border-block-start: 0; padding-block-start: var(--sp-5); }
/* And the first band's own SECTION HEAD draws no rule either, at any width:
   the header's rule sits a short strip of paper above it, and two heavy bars
   with nothing between them read as one element broken in half (the PI's
   screenshot of 2026-08-19 shows exactly this above "00 Issuers"). Numbered
   heads further down keep their rule; they have matter to separate from. */
main > .band:first-of-type > .section-head:first-child,
main > section.band:first-of-type > .section-head:first-child {
  border-block-start: 0; padding-block-start: 0;
}
/* And the entity header inside it must not draw one either, or the page opens
   with two heavy rules 24px apart and an empty strip between them that reads as
   a missing element. Only the FIRST one: an entity header further down the page
   still separates itself from what precedes it. */
main > .band:first-of-type > .entity:first-child { border-block-start: 0; padding-block-start: 0; }

.colophon__strap {
  font-family: var(--face-ui);
  font-size: var(--t-mini);
  color: var(--c-ink-muted);
}

.folio {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-5);
  align-items: center;
  justify-content: space-between;
  /* The strip's own padding is small because its controls now carry the 44px
     floor in their own boxes; padding on top of that would only fatten the
     thin metadata strip the bible's 8.1 asks for. */
  padding-block: var(--sp-1);
  border-block-end: var(--rule-hair);
  font-family: var(--face-ui);
  font-size: var(--t-micro);
  font-weight: var(--w-medium);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  font-variant-numeric: lining-nums tabular-nums;
  line-height: var(--lh-ui);
}
.folio__set { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); align-items: center; }
/* --c-rule is a grouping weight at 2.04:1 and is not a text colour. */
.folio__sep { color: var(--c-ink-faint); }
/* Stamped by the shell script when the list wraps and the separator's two
   neighbours land on different rows: the row break is doing the separating,
   so the glyph retires. visibility, never display, because reclaiming the
   space would change the wrap that was measured to set the stamp. */
.folio__sep[data-stranded] { visibility: hidden; }
.folio a { color: inherit; }
/* A folio link is small uppercase text and owes a 44px target on BOTH axes,
   and it buys both in the box. An earlier draft bought the block axis with an
   absolutely positioned ::before reaching 14.3px above and below a 15.4px line
   box. That was measured wrong: the strip wraps at 390px, the wrapped rows sit
   23.4px apart, and each link's reach therefore covered the row above and the
   row below. Measured at 390px before this rule: "The catalog" (y -2.3 to
   41.7) against "Tape" (y 21.1 to 65.1) contested a 44 x 20.6 px region, and
   "Licence" contested 53.9 x 11.8 px of the theme setter's first radio. Five
   contested pairs on every page. Two targets may never contest one point, so
   the reach is gone and the height is real: the flex line is 44px tall, the
   wrapped rows are 52px apart, and nothing overlaps anything. */
.folio__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-inline-size: 2.75rem;
  min-block-size: 2.75rem;
  /* Transparent so the current-page mark below changes colour, never size. */
  border-block-end: 2px solid transparent;
}
/* The current page, marked the way the platform shell already marks it: a
   stronger ink and a 2px rule, two channels of which the rule survives
   greyscale (law 2). The default underline stays, because it is the catalog's
   only link affordance in an achromatic palette and removing it to make room
   for this mark would be strictly worse than the defect (measured and
   recorded in the audit's dead ends). WRK-20260819T1401Z. */
.folio__link[aria-current="page"] {
  color: var(--c-ink-strong);
  border-block-end-color: var(--c-ink-strong);
}

.nameplate { padding-block: var(--sp-5) 0; border-block-end: var(--rule-nameplate); }
.nameplate__word {
  font-family: var(--face-text);
  font-size: var(--t-nameplate);
  line-height: var(--lh-solid);
  letter-spacing: var(--tr-nameplate);
  font-weight: var(--w-bold);
  color: var(--c-ink-strong);
  font-variant-numeric: lining-nums;
  margin-block-end: var(--sp-3);
}
.nameplate__word a { text-decoration: none; }
/* The mark, matching the platform shell's `.logo__mark`. Set relative to the
   wordmark rather than at a fixed size, so it scales with whichever nameplate
   it sits in: this masthead is 30px and the platform's is 48px, and both are
   deliberate. `--t-sub` would have pinned it to one of them.

   The gap is on the mark rather than a flex gap, because the anchor also
   carries `display: inline-flex` for its target floor further down and a gap
   there would apply to a box that is sometimes text and sometimes not. */
.nameplate__mark {
  font-size: 0.62em;
  margin-inline-end: 0.42em;
  color: var(--c-ink);
  vertical-align: baseline;
}
.nameplate__strap {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-5);
  justify-content: space-between;
  align-items: baseline;
  padding-block-end: var(--sp-3);
  font-family: var(--face-ui);
  font-size: var(--t-mini);
  letter-spacing: var(--tr-caps-snug);
  text-transform: uppercase;
  color: var(--c-ink-muted);
}
/* The catalog masthead is smaller than the gallery's: a catalog reader arrives
   on an entity page, not on a cover, and a 136px wordmark above every issuer
   would make the masthead the subject of a page whose subject is the issuer. */
.nameplate--compact { padding-block-start: var(--sp-4); border-block-end: var(--rule-heavy); }
.nameplate--compact .nameplate__word { font-size: var(--t-sub); margin-block-end: var(--sp-2); }
/* The wordmark is a link on every page and therefore a target. Measured at
   41px tall from the 30px type alone; the inline-flex box buys the remaining
   three pixels in whitespace above and below the letters. */
.nameplate__word a { display: inline-flex; align-items: center; min-block-size: 2.75rem; }

.kicker {
  font-family: var(--face-ui);
  font-size: var(--t-micro);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  line-height: var(--lh-ui);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}
.kicker::after { content: ""; flex: 1; block-size: 1px; background: var(--c-rule); }
.kicker--plain::after { display: none; }

.deck {
  font-family: var(--face-text);
  font-size: var(--t-lead);
  line-height: var(--lh-lead);
  color: var(--c-ink-muted);
  font-style: italic;
  text-wrap: pretty;
}

.byline {
  font-family: var(--face-ui);
  font-size: var(--t-mini);
  letter-spacing: var(--tr-caps-snug);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  padding-block: var(--sp-3);
  border-block: var(--rule-hair);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
}
.byline b { color: var(--c-ink); font-weight: var(--w-semi); }

.slug {
  font-family: var(--face-ident);
  font-size: var(--t-micro);
  letter-spacing: var(--tr-caps-snug);
  text-transform: uppercase;
  color: var(--c-ink-faint);
  font-variant-numeric: tabular-nums lining-nums slashed-zero;
}

.section-head {
  display: grid;
  gap: var(--sp-3);
  padding-block-start: var(--sp-2);
  border-block-start: var(--rule-heavy);
}
.section-head__no {
  font-family: var(--face-ui);
  font-size: var(--t-micro);
  font-weight: var(--w-bold);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  font-variant-numeric: tabular-nums lining-nums;
}
.section-head h2 { font-size: var(--t-head); line-height: var(--lh-head); letter-spacing: var(--tr-head); }
.section-head h3 { font-size: var(--t-sub); line-height: var(--lh-head); letter-spacing: var(--tr-head); }
/* NO MEASURE CAP ON A SECTION STANDFIRST, and the cap was the actual defect.
   `52ch` resolved to 468px inside a 1088px column, 43 percent of it, so a
   one-sentence standfirst wrapped to three or four lines and pushed the
   evidence down the page. The PI reported it as the text being "truncated so
   they took up so many rows instead of spanning the width of the main
   section", which names the cause exactly (2026-08-18).

   MY FIRST FIX WAS WRONG AND IS REVERTED. I shortened the sentences, which
   treated the symptom and lost detail that was true; the sentences were never
   the problem. A rule capping a standfirst at under half its own column is.

   52ch is a reading measure and it is right for a RUN of prose, which is why
   `.prose p` keeps its own. A standfirst is one or two sentences under a
   heading, read at a glance rather than read through, and it is part of the
   heading block: it should be as wide as the section it introduces. */
.section-head p { font-size: var(--t-base); color: var(--c-ink-muted); }

/* One drop cap per page at most, on the argument paragraph. Prose surfaces
   only: the licence page and the method notes. */
.leadin::first-letter {
  font-family: var(--face-text);
  font-weight: var(--w-bold);
  color: var(--c-ink-strong);
  initial-letter: 3 3;
  padding-inline-end: 0.08em;
}
@supports not (initial-letter: 3 3) {
  .leadin::first-letter {
    float: inline-start;
    font-size: 3.4em;
    line-height: 0.84;
    padding-inline-end: 0.06em;
    padding-block-start: 0.06em;
  }
}

.caps {
  font-family: var(--face-ui);
  font-size: var(--t-micro);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--c-ink-muted);
}

.vh {
  position: absolute;
  inline-size: 1px; block-size: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

.skip {
  position: absolute;
  inset-block-start: var(--sp-2);
  inset-inline-start: var(--sp-2);
  z-index: 50;
  transform: translateY(-200%);
  background: var(--c-mark);
  color: var(--c-on-mark);
  padding: var(--sp-2) var(--sp-4);
  font-family: var(--face-ui);
  font-size: var(--t-small);
  text-decoration: none;
  display: grid;
  place-content: center;
  min-block-size: 2.75rem;
}
.skip:focus-visible { transform: translateY(0); }

/* The colophon. Every catalog page closes with it, and the licence line is a
   catalog obligation (SPEC-20260731T1159Z section 6 item 7). */
.colophon {
  border-block-start: var(--rule-mid);
  padding-block: var(--sp-6) var(--sp-8);
  display: grid;
  gap: var(--sp-4);
  font-family: var(--face-ui);
  font-size: var(--t-mini);
  line-height: var(--lh-ui);
  color: var(--c-ink-muted);
}
.colophon__links { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-5); align-items: center; }
/* Measured: "Tape" 29.1x44, "Search" 42.1x44, "Issuers" 43.1x44, all short of
   the inline floor. The row's 24px column gap means the width can be bought in
   the box without any two links contesting a point. */
.colophon__links a {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-block-size: 2.75rem;
  min-inline-size: 2.75rem;
}
.colophon p { font-size: var(--t-mini); max-inline-size: 68ch; }
/* THE COLOPHON FILLS ITS COLUMN INSTEAD OF STOPPING HALFWAY. The 68ch cap
   above is a reading measure and it is right for the paragraph; it is wrong for
   the BLOCK, because at the UI face's mini size 68ch resolves to about 562px
   against a 1088px column, so three stacked paragraphs left the right half of
   the page empty under a page that is full width everywhere above. The PI read
   that as the footers "only taking up 50% of page width", which is exactly what
   it looks like (2026-08-18).

   Columns rather than a wider measure: widening the paragraph would fill the
   space by making the line length worse, and these three are short, unrelated
   statements rather than one argument, so side by side is what they were always
   trying to be. `max-inline-size: none` inside the columns because the track
   itself now supplies the measure.

   Below 60rem they stack and keep the 68ch cap, which is the same shape the
   rest of this stylesheet takes at narrow widths. */
@media (min-width: 60rem) {
  .colophon {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: var(--sp-5);
  }
  .colophon__links { grid-column: 1 / -1; }
  .colophon p { max-inline-size: none; }
}


/* -----------------------------------------------------------------------------
   6  FIGURES   (bible 8.2, law 3)
   Every quantity on a catalog page passes through .fig or .led. Formatting to
   a fixed number of places is a TEMPLATE contract, done server-side; CSS
   cannot align on a decimal separator and does not pretend to.
   -------------------------------------------------------------------------- */

.fig {
  font-family: var(--face-fig);
  font-variant-numeric: tabular-nums lining-nums slashed-zero;
  font-feature-settings: "tnum" 1, "lnum" 1, "zero" 1;
  letter-spacing: var(--tr-flat);
  white-space: nowrap;
}
.fig--unit { color: var(--c-ink-muted); font-weight: var(--w-book); }
/* An ISO date is a figure and must never break across lines. The bible's
   U+2011 is deliberately not used: the shipped subset lacks that codepoint and
   the build maps it to U+2010, so a stand-in face during the swap window would
   set a different glyph. white-space:nowrap on .fig achieves the same
   guarantee with a codepoint that is certainly present. */
/* THE 0.95 IS RELATIVE AND IT COMPOUNDS, so it needs a floor. The ratio exists
   because an ISO date sets a little large beside running text at the same
   nominal size, and against body copy it is right. Inside something already
   small it multiplies: measured on `/catalog` at every viewport and in both
   themes, a `.fig--date` inside a `.card__foot` button at 11px rendered at
   **10.45px**, which is below the smallest step the type scale actually sets
   and below the floor `tools/ux/viewports.py` gates on.

   `max()` keeps the ratio wherever there is room for it and stops it eating
   into legibility where there is not. The floor is in `rem` rather than `px`
   so it stays tied to the type system rather than to a device pixel. */
.fig--date { font-size: max(0.95em, 0.6875rem); }

/* The ledger cell: a three-column inline grid reserving a 1ch gutter on each
   side of the digits whether or not the parentheses are present, so decimal
   points hold one column down the whole table. */
.led {
  display: inline-grid;
  grid-template-columns: 1ch max-content 1ch;
  align-items: baseline;
  font-family: var(--face-fig);
  font-variant-numeric: tabular-nums lining-nums slashed-zero;
  white-space: nowrap;
}
.led__paren { color: var(--c-ink-faint); font-weight: var(--w-book); }
.led__paren--open  { text-align: left; }
.led__paren--close { text-align: right; }
.led__value { text-align: right; }

.led[data-dir="A"] .led__value { color: var(--c-buy); }
.led[data-dir="D"] .led__value { color: var(--c-sell); }
.led[data-dir="A"] .led__paren { visibility: hidden; }
/* Compensation machinery is reported and never coloured. */
.led[data-tone="admin"] .led__value { color: var(--c-ink); }

/* The signature rule. Solid for acquire, broken for dispose: shape first, hue
   fourth, and it survives greyscale, a photocopier, and every dichromacy. */
.sig {
  inline-size: 3px;
  min-block-size: 1.4em;
  align-self: stretch;
  justify-self: center;
  border-radius: var(--radius);
}
.sig[data-dir="A"] { background: var(--c-buy); }
.sig[data-dir="D"] {
  background: repeating-linear-gradient(to bottom, var(--c-sell) 0 3px, transparent 3px 6px);
}


/* -----------------------------------------------------------------------------
   7  ACTIONS   (bible 8.3)
   -------------------------------------------------------------------------- */

.btn {
  --btn-face: transparent;
  --btn-label: var(--c-ink);
  --btn-rule: var(--c-rule-strong);
  --btn-rule-w: 1px;

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  position: relative;
  padding: var(--sp-3) var(--sp-5);
  border: var(--btn-rule-w) solid var(--btn-rule);
  border-radius: var(--radius);
  background: var(--btn-face);
  color: var(--btn-label);
  font-family: var(--face-ui);
  font-size: var(--t-small);
  font-weight: var(--w-semi);
  line-height: 1.2;
  letter-spacing: var(--tr-caps-snug);
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  text-wrap: balance;
  max-inline-size: 100%;
  min-block-size: 2.75rem;
  transition: background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              translate var(--dur-press) var(--ease-out);
}

.btn--ink { --btn-face: var(--c-mark); --btn-label: var(--c-on-mark); --btn-rule: var(--c-mark); }
.btn--ink:hover  { --btn-face: var(--c-mark-hover); --btn-rule: var(--c-mark-hover); }
.btn--ink:active { translate: 0 1px; }

.btn--ruled:hover  { background: var(--c-hover-wash); --btn-rule: var(--c-mark); }
.btn--ruled:active { translate: 0 1px; }

.btn--quiet {
  --btn-rule: transparent;
  padding-inline: var(--sp-2);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.35em;
  text-decoration-color: var(--c-rule);
}
.btn--quiet:hover {
  text-decoration-thickness: 2px;
  text-decoration-color: currentColor;
  background: var(--c-hover-wash);
}

.btn--small { padding: var(--sp-2) var(--sp-3); font-size: var(--t-micro); min-block-size: 0; }
/* The small button's invisible hit extension: grows the pointer target to 44px
   on any axis where the drawn box is smaller and insets to nothing where it is
   not, so a wide small button is never given a halo it does not need. */
.btn--small::before {
  content: "";
  position: absolute;
  inset-block: min(0px, calc((100% - 2.75rem) / 2));
  inset-inline: min(0px, calc((100% - 2.75rem) / 2));
}
.btn--wide { inline-size: 100%; }

.btn:disabled, .btn[aria-disabled="true"] {
  --btn-face: transparent;
  --btn-label: var(--c-ink-disabled);
  --btn-rule: var(--c-ink-disabled);
  cursor: not-allowed;
  translate: none;
  text-decoration: none;
}
.btn--ink:disabled {
  --btn-face: transparent;
  --btn-label: var(--c-ink-disabled);
  --btn-rule: var(--c-ink-disabled);
}

.btn[data-state="loading"] { cursor: progress; }
.btn[data-state="loading"]::after {
  content: "";
  position: absolute;
  inset-block-end: 0;
  inset-inline-start: 0;
  block-size: 2px;
  inline-size: 100%;
  background: currentColor;
  transform-origin: left center;
  animation: sweep 1050ms var(--ease-inout) infinite;
}
@keyframes sweep {
  0%   { transform: scaleX(0); transform-origin: left center; }
  45%  { transform: scaleX(1); transform-origin: left center; }
  55%  { transform: scaleX(1); transform-origin: right center; }
  100% { transform: scaleX(0); transform-origin: right center; }
}

.btn-set { display: inline-flex; flex-wrap: nowrap; border: var(--rule-control); border-radius: var(--radius); }
.btn-set .btn { border: 0; border-inline-start: var(--rule-control); min-inline-size: 2.75rem; }
.btn-set .btn:first-child { border-inline-start: 0; }
.btn-set [aria-current="true"] { background: var(--c-mark); color: var(--c-on-mark); }


/* -----------------------------------------------------------------------------
   8  FORM CONTROLS   (bible 8.4)
   A field is a ruled blank on a printed form. The rule under the input is the
   boundary and carries SC 1.4.11 at 5.63:1 light and 4.53:1 dark.
   -------------------------------------------------------------------------- */

.field { display: grid; gap: var(--sp-2); }

.field__label {
  font-family: var(--face-ui);
  font-size: var(--t-micro);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  line-height: var(--lh-ui);
}
.field__hint { font-family: var(--face-ui); font-size: var(--t-mini); line-height: var(--lh-ui); color: var(--c-ink-faint); }
.field__error {
  font-family: var(--face-ui);
  font-size: var(--t-mini);
  line-height: var(--lh-ui);
  color: var(--c-sell);
  display: flex;
  gap: var(--sp-2);
  align-items: baseline;
}
/* The error is never colour alone: a glyph, the pigment, and the words. */
.field__error::before { content: "\2716"; font-family: var(--face-ui); font-size: 0.85em; }

.input, .select {
  inline-size: 100%;
  min-block-size: 2.75rem;
  padding: var(--sp-2) var(--sp-1);
  border: 0;
  border-block-end: var(--rule-control);
  border-radius: var(--radius);
  background: transparent;
  color: var(--c-ink);
  font-family: var(--face-text);
  font-size: var(--t-base);
  line-height: 1.5;
  transition: border-color var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out);
}
.input:hover:not(:disabled), .select:hover:not(:disabled) {
  border-block-end-color: var(--c-ink);
  background: var(--c-hover-wash);
}
.input:focus-visible, .select:focus-visible { border-block-end: 2px solid var(--c-ink); outline-offset: 3px; }
.input::placeholder { color: var(--c-ink-disabled); font-style: italic; }

.select {
  appearance: none;
  padding-inline-end: var(--sp-6);
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: right var(--sp-3) center, right calc(var(--sp-3) - 5px) center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}

.input--ident {
  font-family: var(--face-ident);
  font-variant-numeric: tabular-nums lining-nums slashed-zero;
  font-size: var(--t-small);
}

.field:has(:user-invalid), .field:has([aria-invalid="true"]) {
  & .input, & .select { border-block-end: 2px solid var(--c-sell); }
  & .field__label { color: var(--c-sell); }
}
.field:has(:disabled) { & .field__label, & .field__hint { color: var(--c-ink-disabled); } }
.input:disabled, .select:disabled {
  color: var(--c-ink-disabled);
  border-block-end-style: dotted;
  cursor: not-allowed;
}

/* Checkbox and radio, both square because the radius token is zero and applies
   to controls too. They are told apart by the mark inside: a tick for the
   checkbox, the rotated-square lozenge for the radio. */
.check {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-3);
  align-items: start;
  /* The label is the target and carries the 44px floor as centred whitespace.
     An invisible hit extension would overlap the neighbouring option at this
     spacing, and two targets may never contest one point. */
  min-block-size: 2.75rem;
  align-content: center;
  font-family: var(--face-ui);
  font-size: var(--t-small);
  line-height: var(--lh-ui);
  cursor: pointer;
}
.check input {
  appearance: none;
  inline-size: 1.05rem;
  block-size: 1.05rem;
  margin: 0.18rem 0 0;
  border: var(--rule-control);
  border-radius: var(--radius);
  background: var(--c-surface);
  display: grid;
  place-content: center;
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out);
}
.check input::before {
  content: "";
  inline-size: 0.42rem;
  block-size: 0.42rem;
  scale: 0;
  rotate: 45deg;
  background: var(--c-on-mark);
  transition: scale var(--dur-fast) var(--ease-out);
}
.check input[type="checkbox"]::before {
  clip-path: polygon(14% 46%, 0 60%, 40% 100%, 100% 22%, 86% 8%, 38% 70%);
  inline-size: 0.62rem;
  block-size: 0.62rem;
  rotate: none;
}
.check input:checked { background: var(--c-mark); border-color: var(--c-mark); }
.check input:checked::before { scale: 1; }
.check input:hover:not(:disabled) { border-color: var(--c-ink); }
.check input:disabled { border-style: dotted; cursor: not-allowed; }
.check:has(input:disabled) { color: var(--c-ink-disabled); cursor: not-allowed; }
.check__note { display: block; font-size: var(--t-mini); color: var(--c-ink-faint); }

.fieldset { border: 0; padding: 0; display: grid; gap: var(--sp-3); }
.fieldset > legend {
  font-family: var(--face-ui);
  font-size: var(--t-micro);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  padding: 0 0 var(--sp-2);
}

/* The theme control: three real radios in a ruled set, so it is keyboard
   operable with the arrow keys for free and needs no ARIA at all. */
/* ---------------------------------------------------------------------------
   The account cluster in the folio strip

   The catalog shell had no account affordance at all, so a signed-in reader
   crossing from the dashboard into a company page met a header that showed
   nobody, offered no way back, and invited them to sign in. The PI reported the
   catalog header as "inconsistent with all other pages" twice before this.

   It is NOT a copy of platform.css's `.account-menu`, and it must not become
   one: a catalog page never loads that sheet (DEC-20260808T1149Z), and the two
   have eleven custom-property names in common with different meanings. What is
   shared is the BEHAVIOUR, which is the part the reader experiences: the
   address is the control, the panel holds the address in full, the dashboard,
   the theme and Sign out, in that order.

   Law 1 governs the size of it. This is chrome and it is subordinate: the
   summary is the folio's own micro type, the panel sits at its intrinsic width,
   and nothing here is allowed to outweigh a link in the strip beside it. The
   theme setter inside the panel is the same `.setter` the bar uses, unchanged,
   because it is the same control.
   --------------------------------------------------------------------------- */
/* The one thing a reader is asked to DO on an issuer page, set apart from the
   identity block above it by space rather than by a box. The note under it is
   the same weight as the coverage statement below, because both are the page
   telling the reader what is and is not true rather than selling anything. */
/* The headline and its one action share a line, with the action pushed to the
   far end so the name keeps the left edge every other page gives it. Below
   48rem it drops under the name rather than squeezing beside it. */
.entity__headline {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: var(--sp-3) var(--sp-5); justify-content: space-between;
}
.entity__headline .entity__name { margin-block-end: 0; }
.entity__act { flex: none; }
/* The stated fact that replaces the Watch button for a reader already
   watching (issuer.html; safe because signed-in responses are private,
   no-store). The tick is ink, not pigment: law 1. */
.entity__watching {
  margin: 0; font-family: var(--face-ui); font-size: var(--t-small);
  color: var(--c-ink); max-inline-size: 22rem;
}
.entity__act-note {
  font-family: var(--face-ui); font-size: var(--t-mini);
  color: var(--c-ink-muted); max-inline-size: 46ch;
}

/* THE VISIBLE "THEME" LABEL IS DROPPED ON A PHONE, and it buys a whole row.
   Measured at 390px on /issuer: the strip was 222px tall and the chrome before
   the first content was 444px of an 844px screen, more than half the phone
   spent before a word of the page. The Sign in control added on 2026-08-19 is
   what pushed it over: Theme 46 + setter 209 + Sign in 79 plus gaps does not
   fit 390, so Sign in wrapped to a row of its own.

   The label is the right thing to lose rather than the control. It is
   `aria-hidden` decoration duplicating a visually-hidden legend, so nothing is
   removed from a screen reader, and three segments reading Light, Auto and Dark
   do not need a word above them to be understood. Law 1: the chrome is
   subordinate, and on the smallest screen it has to prove it. */
/* The 30rem `span[aria-hidden]` display:none that stood here was the phone
   half of the visible-"Theme"-word deletion. Same story as its 75rem twin:
   the word is icons now, the selector matched nothing, and it would have
   eaten the folio separators the moment they gained aria-hidden. The folio
   keeps its dots at every width; a separator that wraps badly is stamped
   `data-stranded` by measurement instead. */

.folio-account { position: relative; }
.folio-account > summary {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  /* Every control in this strip owes the 44px floor in the box, which is what
     the folio link rule above spent a measurement session establishing. */
  min-block-size: 2.75rem; padding-inline: var(--sp-3);
  font-family: var(--face-ident); font-size: var(--t-micro);
  /* Lowercase, unspaced. An email address is a string to be READ and matched,
     not a label, and the rest of this strip is uppercase precisely because it
     is labels. Truncated so an institutional address cannot set the strip's
     width; the full value is in the title. */
  text-transform: none; letter-spacing: var(--tr-flat);
  color: var(--c-ink-muted);
  max-inline-size: 14rem; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
  border: var(--rule-control); border-radius: var(--radius);
  cursor: pointer; list-style: none;
}
.folio-account > summary::-webkit-details-marker { display: none; }
.folio-account > summary::after { content: "\25BE"; font-size: var(--t-micro); }
.folio-account[open] > summary::after { content: "\25B4"; }
.folio-account > summary:hover { background: var(--c-hover-wash); color: var(--c-ink); }
.folio-account > summary:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 2px; }
.folio-account__panel {
  position: absolute; inset-inline-end: 0; inset-block-start: calc(100% + var(--sp-2));
  z-index: 20; min-inline-size: 15rem;
  background: var(--c-surface); border: var(--rule-control);
  border-radius: var(--radius);
  display: grid; justify-items: start;
}
.folio-account__meta {
  font-family: var(--face-ui); font-size: var(--t-micro);
  letter-spacing: var(--tr-caps); text-transform: uppercase;
  color: var(--c-ink-muted);
  padding: var(--sp-3) var(--sp-4) 0;
}
.folio-account__email {
  font-family: var(--face-ident); font-size: var(--t-mini);
  /* EXPLICITLY NOT UPPERCASED. The panel inherits the strip's caps treatment
     and rendered BALOGH@UNIMELB.EDU.AU under a summary reading
     balogh@unimelb.edu.au, so one control showed one address two ways. An email
     is a string to be read and matched against what you typed, never a label,
     which is the same argument the summary rule above makes. */
  text-transform: none; letter-spacing: var(--tr-flat);
  color: var(--c-ink-strong);
  padding: 0 var(--sp-4) var(--sp-3);
  overflow-wrap: anywhere;
}
.folio-account__item {
  display: flex; align-items: center;
  inline-size: 100%; min-block-size: 2.75rem;
  padding-inline: var(--sp-4);
  font-family: var(--face-ui); font-size: var(--t-mini);
  color: var(--c-ink-strong); text-decoration: none;
}
.folio-account__item:hover { background: var(--c-hover-wash); }
.folio-account__panel hr {
  inline-size: 100%; margin: 0; border: 0; border-block-start: var(--rule-hair);
}
.folio-account__panel .theme-menu { margin-block-end: var(--sp-2); }
.folio-account__panel form { padding: var(--sp-3) var(--sp-4); }
/* A folio link that is an ACTION rather than a destination. Same box and same
   44px floor as its neighbours, ruled so it reads as a control; it is the only
   thing in the strip a reader is asked to do rather than to go to. */
.folio__link--action {
  padding-inline: var(--sp-3);
  border: var(--rule-control); border-radius: var(--radius);
  text-decoration: none;
}
.folio__link--action:hover { background: var(--c-hover-wash); }

/* THE THEME CONTROL IS A MENU, NOT A SEGMENTED BAR.
   The PI sent Render's own picker as the model: a small trigger, and behind it
   a vertical list with an icon per row and a tick on the one in force. Three
   ruled segments standing permanently in the folio were the loudest thing in
   the strip, which is law 1 inverted, and he had said so twice before sending
   a picture.

   Still three real radios, so keyboard operation and the no-ARIA argument are
   unchanged; only the drawing moved. The current row is marked by a TICK and by
   ink weight, never by a fill: law 2 asks that the meaning survive greyscale,
   and a tick survives it better than any colour. A fill would also borrow
   `--c-mark`, which this system reserves for data. */
.theme-menu { display: grid; border: 0; padding: 0; margin: 0; min-inline-size: 0; }
.theme-menu__item {
  position: relative;
  display: grid;
  grid-template-columns: 1rem 1fr 0.9rem;
  align-items: center; gap: var(--sp-3);
  min-block-size: 2.5rem; padding-inline: var(--sp-4);
  font-family: var(--face-ui); font-size: var(--t-mini);
  letter-spacing: var(--tr-flat); text-transform: none;
  color: var(--c-ink-muted); cursor: pointer;
}
.theme-menu__item:hover { background: var(--c-hover-wash); color: var(--c-ink-strong); }
.theme-menu__item:has(input:checked) { color: var(--c-ink-strong); font-weight: var(--w-semi); }
.theme-menu__item:has(input:focus-visible) { outline: 2px solid var(--c-focus); outline-offset: -2px; }
.theme-menu__item svg { display: block; }
/* The radio is the control and is invisible; it covers the row so the whole row
   is the target, and it reaches to the 44px floor without making the row taller
   (the same technique the rest of this sheet uses). */
.theme-menu input {
  appearance: none; position: absolute; margin: 0; cursor: pointer;
  inset-inline: 0;
  inset-block: min(0px, calc((100% - 2.75rem) / 2));
}
.theme-menu__tick { visibility: hidden; grid-column: 3; }
.theme-menu__item:has(input:checked) .theme-menu__tick { visibility: visible; }

.theme-picker { position: relative; }
.theme-picker > summary {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-block-size: 2.75rem; padding-inline: var(--sp-3);
  font-family: var(--face-ui); font-size: var(--t-micro);
  letter-spacing: var(--tr-caps-snug); text-transform: uppercase;
  color: var(--c-ink-muted);
  border: var(--rule-control); border-radius: var(--radius);
  cursor: pointer; list-style: none;
}
.theme-picker > summary::-webkit-details-marker { display: none; }
.theme-picker > summary::after { content: "\25BE"; font-size: var(--t-micro); }
.theme-picker[open] > summary::after { content: "\25B4"; }
.theme-picker__icon { display: inline-flex; }
/* THE TRIGGER IS A SQUARE THAT REPORTS THE STATE. The reasoning is against the
   markup; what belongs here is that the live icon is chosen by `:has()` on the
   radios inside this same disclosure, so the trigger reads the SAME state the
   tick does and no third selector exists to fall out of step. That is the whole
   reason it is CSS: the last defect in this control was a selector left behind
   by a rename. */
.theme-picker > summary {
  inline-size: 2.75rem; min-inline-size: 0; padding-inline: 0;
  justify-content: center; gap: 0;
}
.theme-picker > summary::after { content: none; }
.theme-picker__icon { display: none; }
.theme-picker__icon--system { display: inline-flex; }
.theme-picker:has(input[value="light"]:checked) .theme-picker__icon--system,
.theme-picker:has(input[value="dark"]:checked)  .theme-picker__icon--system { display: none; }
.theme-picker:has(input[value="light"]:checked) .theme-picker__icon--light { display: inline-flex; }
.theme-picker:has(input[value="dark"]:checked)  .theme-picker__icon--dark  { display: inline-flex; }
/* A CLOSED DISCLOSURE MUST NOT PAINT ITS PANEL, STATED EXPLICITLY.
   Measured at 390px on the front page: `details.open` was FALSE and the panel
   still computed `display: block` with a real 176x138 box, so the theme menu
   stood permanently under the masthead and the header measured 266px in seven
   rows. The browser's own hiding of a closed `<details>`' content did not reach
   an absolutely positioned child here, which is the sort of thing that differs
   by engine and is not worth relying on either way.

   Written for BOTH panels rather than the one that was caught, for the same
   reason the dismiss handler is bound to `header details` rather than to a
   class: a rule a pattern needs belongs on the pattern. */
.theme-picker:not([open]) .theme-picker__panel,
.account-menu:not([open]) .account-menu__panel,
.folio-account:not([open]) .folio-account__panel { display: none; }

.theme-picker__panel {
  position: absolute; inset-inline-end: 0; inset-block-start: calc(100% + var(--sp-2));
  z-index: 20; min-inline-size: 11rem;
  background: var(--c-surface); border: var(--rule-control);
  border-radius: var(--radius); padding-block: var(--sp-2);
}

.setter { display: inline-flex; align-items: center; border: var(--rule-control); border-radius: var(--radius); }
/* The label is the target and carries the 2.75rem floor as centered
   whitespace (bible 8.4), in the box rather than as a reach. Measured before
   this rule: the label box was 64.8 x 23.4 and the radio inside it was
   absolutely positioned to 64.8 x 44, so the radio reached 10.3px above the
   ruled set and contested the folio link sitting 8px above it, twice over
   (53.9 x 11.8 and 3.3 x 11.8 at 390px). Segments may not contest a seam and
   a radio may not contest its neighbours' line. */
.setter label {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-block-size: 2.75rem;
  padding: var(--sp-1) var(--sp-3);
  font-family: var(--face-ui);
  font-size: var(--t-micro);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-caps-snug);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  cursor: pointer;
  border-inline-start: var(--rule-control);
  transition: background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
.setter label:first-of-type { border-inline-start: 0; }
.setter input {
  appearance: none;
  position: absolute;
  /* Exactly the label, which is already 44px tall. It used to reach past it. */
  inset: 0;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.setter label:hover { background: var(--c-hover-wash); color: var(--c-ink); }
.setter label:has(input:checked) { background: var(--c-mark); color: var(--c-on-mark); }
.setter label:has(input:focus-visible) { outline: 2px solid var(--c-focus); outline-offset: -2px; }
/* On the checked segment the ring is drawn in --c-focus, which IS the fill it
   sits on, so it measured 1:1 and was invisible on the first control a
   keyboard user reaches. It switches to the label colour, 15.29:1 and 18.48:1. */
.setter label:has(input:checked):has(input:focus-visible) { outline-color: var(--c-on-mark); }


/* -----------------------------------------------------------------------------
   9  THE LEDGER TABLE   (bible 8.5)
   No zebra, no cell borders, no container box: hairlines between rows, a 2px
   rule under the head, a 3px rule opening the wrap.
   -------------------------------------------------------------------------- */

/* All three properties are load bearing. position:relative because a
   visually-hidden span inside a wide table is position:absolute and without a
   positioned ancestor its containing block is the initial containing block, so
   it is not clipped and stretches the document's scrollable width on a phone.
   min-inline-size:0 because a grid item refuses to shrink below its content.
   overflow-x:auto because the ledger scrolls inside its own box or the whole
   sheet scrolls sideways. */
.ledger-wrap, .scroller {
  position: relative;
  overflow-x: auto;
  min-inline-size: 0;
  scrollbar-width: thin;
  /* Grid, not flow: the affordance marker is a sticky pseudo-element, and a
     sticky box can only travel within its containing block. */
  display: grid;
  grid-template-columns: minmax(min-content, 1fr);
  align-content: start;
}

/* THE SCROLLPORT AFFORDANCE. The script stamps data-scroll from measurement,
   so the frame and the MORE COLUMNS chip never appear on a table that fits
   (law 10). The chip rides a permanently reserved last row, so sideways
   scrolling shifts the document height by zero pixels. Without JavaScript no
   affordance is drawn, which is the accepted floor. */
[data-scroll] { border-inline: var(--rule-control); }
[data-scroll]::after {
  position: sticky;
  inset-inline-start: 0;
  justify-self: start;
  z-index: 2;                       /* above the sticky thead, which is 1 */
  inline-size: fit-content;
  max-inline-size: 100%;
  margin-block-start: var(--sp-2);
  padding: var(--sp-1) var(--sp-3);
  background: var(--c-canvas);
  border: var(--rule-control);
  border-inline-start: 0;
  font-family: var(--face-ui);
  font-size: var(--t-micro);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  white-space: nowrap;
}
[data-scroll="end"]::after   { content: "More columns \2192"; }
[data-scroll="start"]::after { content: "\2190 More columns"; }
[data-scroll="both"]::after  { content: "\2190 More columns \2192"; }

/* A caption box is forced to the table's width, so on a phone the caption of a
   sideways-scrolling table scrolls with it. Only .scroller carries the inline
   size container; .ledger-wrap holds a sticky head and containment and sticky
   do not belong in the same box. */
.scroller { container-type: inline-size; }
.ledger-wrap { border-block-start: var(--rule-heavy); }

.ledger {
  inline-size: 100%;
  min-inline-size: 46rem;
  font-family: var(--face-text);
  font-size: var(--den-size);
  line-height: var(--den-leading);
}
.ledger caption {
  caption-side: bottom;
  text-align: left;
  padding-block-start: var(--sp-3);
  font-family: var(--face-ui);
  font-size: var(--t-mini);
  line-height: var(--lh-ui);
  color: var(--c-ink-muted);
}
/* The long note sits after the wrap, at the column's width, where it wraps and
   never scrolls. The short identification stays in a visually hidden caption. */
.table-note {
  padding-block-start: var(--sp-3);
  font-family: var(--face-ui);
  font-size: var(--t-mini);
  line-height: var(--lh-ui);
  color: var(--c-ink-muted);
}
.ledger thead th {
  position: sticky;
  inset-block-start: 0;
  z-index: 1;
  background: var(--c-canvas);
  padding: var(--den-pad-block) var(--den-pad-inline);
  border-block-end: var(--rule-mid);
  font-family: var(--face-ui);
  font-size: var(--t-micro);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  text-align: left;
  white-space: nowrap;
  vertical-align: bottom;
}
.ledger th[data-align="end"], .ledger td[data-align="end"] { text-align: right; }
.ledger tbody td {
  padding: var(--den-pad-block) var(--den-pad-inline);
  border-block-end: var(--rule-hair);
  vertical-align: baseline;
}
.ledger tbody tr:last-child td { border-block-end: var(--rule-mid); }
.ledger tbody tr { transition: background-color var(--dur-fast) var(--ease-out); }
.ledger tbody tr:hover { background: var(--c-hover-wash); }
/* A row containing focus is raised the same way a hovered row is, so keyboard
   and pointer see one affordance. */
.ledger tbody tr:has(:focus-visible) { background: var(--c-hover-wash); }

.ledger tbody td.ledger__sig { inline-size: 1.5rem; padding-inline: var(--den-pad-inline) 0; }
.ledger__sig > div { display: flex; min-block-size: 1.4em; }

.ledger__issuer { font-weight: var(--w-semi); color: var(--c-ink-strong); }
.ledger__ticker {
  font-family: var(--face-ident);
  font-size: var(--t-micro);
  letter-spacing: var(--tr-caps-snug);
  color: var(--c-ink-faint);
  font-variant-numeric: tabular-nums lining-nums slashed-zero;
}
/* Deliberately not display:grid. A <td> given a grid display stops being a
   table cell, the browser wraps it in an anonymous cell, and the row rules
   stagger. The two lines stack with a block-level child instead. */
.ledger__person > span { display: block; }
/* REAL BLOCK SIZE, BECAUSE THE EXTENSIONS CONTESTED EACH OTHER. The invisible
   extension that stood here was written when the cell held ONE link; making
   insiders clickable (2026-08-19) stacked a second link a few pixels beneath
   the first, and two 44px halos in a 2px gap contest almost every point
   between them. Measured by hit test: each link's REAL target was 25px tall,
   because the probe lands on the neighbour's halo, and section 8's one law is
   that two targets may never contest one point. So the links take the floor
   in the box, per 13.8's wrapping-list rule (a cell stacking two controls IS
   a wrapping list): the row grows 104 to 119px at 1440, which is the honest
   price of two operable names, paid in visible height rather than in a
   contested halo that helps neither. BUG-20260819T1705Z. */
.ledger__person a {
  display: inline-flex; align-items: center; min-block-size: 2.75rem;
}
.ledger__role {
  font-family: var(--face-ui);
  font-size: var(--t-micro);
  color: var(--c-ink-muted);
  letter-spacing: var(--tr-caps-snug);
  text-transform: uppercase;
}
/* The value column ships without the magnitude measure. See the file header:
   WRK-20260731T0612Z has not chosen the absolute constant, and a meter read
   against a scale nobody chose is a fabricated figure under law 4. */
.ledger__value { font-variant-numeric: tabular-nums lining-nums slashed-zero; }
/* The unit annotation in a column head: book weight and meta ink, so it
   annotates the head rather than competing with it. The unit is context and
   the digit is the figure, so it is never bold. */
.ledger__scale { display: block; font-weight: var(--w-book); letter-spacing: var(--tr-caps-snug); color: var(--c-ink-faint); }
/* Absence is stated in words, never faked with a value (law 9). */
.ledger__na { font-family: var(--face-ui); font-size: var(--t-micro); letter-spacing: var(--tr-caps-snug); text-transform: uppercase; color: var(--c-ink-faint); }

/* THE ACCESSION IS AN IDENTIFIER, NOT A FIGURE, AND IT IS THE WIDEST COLUMN IN
   THE TAPE BY SEVENTY PIXELS. Measured at 1440 on /tape, 2026-08-11: ten
   columns totalling 1099px in a 1086px box, of which `Filing` alone was 207px,
   against 134 for the next widest. That 13px was the whole desktop overflow.

   `.fig` sets `white-space: nowrap` and the comment beside it is right about
   why: an ISO date is a figure and must never break across lines. **An
   accession is a different animal.** It is a twenty-character identifier with
   two natural break points, and holding it on one line buys nothing a reader
   values while costing the table its fit.

   `normal` rather than a hard break: the string breaks after a hyphen when the
   column is squeezed and stays on one line when there is room, because a table
   sizes to max-content until it cannot. So the desktop keeps the single line it
   has always had and the narrow cases get the wrap instead of the overflow. */
.ledger__acc { white-space: normal; }

/* THE FILING LINK IS A WORD, NOT AN 18-DIGIT IDENTIFIER. `.ledger__acc` above
   spent five lines negotiating how to wrap an accession number inside a table
   cell; the answer the PI gave on 2026-08-18 is not to print it. The accession
   is still the link's accessible name and still in the source, so nothing is
   lost to a screen reader, a citation or a search. It is set in the UI face
   rather than the figure face because it is now a label rather than a number. */
.ledger__filing {
  font-family: var(--face-ui);
  font-size: var(--t-mini);
  white-space: nowrap;
  position: relative;
}
/* The accession and line-number links that carry NO .ledger__filing class:
   the issuer page's filings table and the filing page's own lines table set
   them as bare a.fig in 42px rows, where a 44px halo would contest the
   neighbouring row's at the seam (the one law). Real block size instead:
   rows grow a few pixels and every target is honest.
   min-inline-size for the one-character line numbers, whose 11px drawn box
   is a coin-flip target. BUG-20260819T1705Z's sweep. */
.ledger td > a.fig {
  display: inline-flex; align-items: center; justify-content: center;
  min-block-size: 2.75rem; min-inline-size: 2.75rem;
}
/* The invisible hit extension, the same branch section 8 offers everywhere and
   the same one `.tape-row__who a` and `.share--compact .share__copy` already
   take. Shortening the label from an 18-digit accession to "Form 4" shrank the
   DRAWN box from 101x38 to 45x15, and a drawn box is not a target: growing this
   one to 44px of type would undo the density the shorter label was for. The
   extension buys the target without touching the row. */
.ledger__filing::before {
  content: ""; position: absolute;
  inset-block: min(0px, calc((100% - 2.75rem) / 2));
  inset-inline: min(0px, calc((100% - 2.75rem) / 2));
}

/* THE ISSUER STOPS WRAPPING INSIDE ITS CELL. Two lines were by design, the
   company over its ticker, and the PI's objection is not to the stack: it is
   that the company NAME itself broke across lines, so a row could stand four
   lines tall and a column of them read as a paragraph. Removing the Security
   column gives this the room, and `text-wrap: balance` is not enough because
   the failure is a long single name rather than an awkward break.

   `min-inline-size: 0` is the load-bearing half: a table cell's default
   `min-width: auto` refuses to shrink below its content, so without it the
   ellipsis never engages and the cell simply pushes the table wider. Dropped
   at the narrow breakpoint below, where the ledger stops being a table and a
   full name matters more than a straight column. */
/* THE NAME COLUMNS ARE BOUNDED, AND THE NAME IS NEITHER TRUNCATED NOR NOWRAP.
   Three attempts at this, and the two failures are worth keeping because each
   was a reasonable-looking fix that broke something else.

   1. `overflow: hidden` + ellipsis. Tidy, and it CLIPPED THE HIT EXTENSION of
      the link inside it, so eight controls measured 81x21 against the 44px
      floor. Caught by tools/ux/targets.py.
   2. `white-space: nowrap` with no bound. Nothing clipped, and the column then
      sized to the longest company name: the table went to 1209px inside a
      1088px scrollport, so the FILING column was pushed outside it and could
      not be clicked without scrolling sideways. The PI found that one on the
      live site, and it is worse than what it replaced.

   So: bound the column and let a long name wrap. Measured at 1440 the non-name
   columns take 599px, which leaves 489px for the two of them. At 15rem each
   almost every name sits on one line, the rare long one takes two rather than
   the four it took when the Security column was still stealing the room, and
   nothing is truncated on a page whose claim is that you can check it. */
.ledger__issuer { display: block; }
@media (min-width: 48rem) {
  .ledger__person { max-inline-size: 15rem; }
}

/* -----------------------------------------------------------------------------
   THE SUGGESTION LIST. WRK-20260810T0532Z.

   It hangs off the field rather than displacing anything: a list that pushes
   the page down as you type moves the thing you were reading, and on the tape
   it would move the rows underneath the box. Absolutely positioned, and the
   field is the containing block.

   Ruled, not boxed, and no radius, because this catalog has exactly one radius
   and its value is zero. The active row is marked by a WASH plus a leading
   rule, so it survives greyscale (law 2) rather than depending on the tint.
   -------------------------------------------------------------------------- */
.suggest { position: relative; }
.suggest__list {
  position: absolute; inset-inline: 0; inset-block-start: 100%;
  z-index: 40;
  margin: 0; padding: 0; list-style: none;
  background: var(--c-surface);
  border: var(--rule-mid);
  border-block-start: var(--rule-heavy);
  max-block-size: 22rem; overflow-y: auto;
  box-shadow: 0 12px 24px -12px rgb(0 0 0 / 0.35);
}
.suggest__item {
  display: flex; align-items: baseline; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-block-end: var(--rule-hair);
  border-inline-start: 3px solid transparent;
  cursor: pointer;
  font-size: var(--t-small);
}
.suggest__item:last-child { border-block-end: 0; }
.suggest__item.is-active,
.suggest__item:hover {
  background: var(--c-note-wash);
  border-inline-start-color: var(--c-mark);
}
.suggest__name { color: var(--c-ink-strong); }
/* THE TICKER IS A BOXED IDENTIFIER, not a word in the sentence. The PI asked
   for the dashboard's treatment here after seeing it in that combobox: "I like
   the way the tickers are put in a box in front of the company name, so should
   be rolled out in WCS" (2026-08-19).

   Restated rather than reused, and that is DEC-20260808T1149Z's standing cost
   arriving in practice. `.ticker-chip` is declared in `platform.css`, a catalog
   page loads `catalog.css` ALONE, so the class the markup already carried
   resolved to nothing here and the ticker rendered as bare text. The values
   below match platform.css:1031 deliberately; if one moves the other must. */
.suggest__ticker {
  /* A fixed lane so the names start on one left edge down the list. Without it
     each row indents by its own ticker's width and the column of company names
     staggers, which is the defect the watchlist was rebuilt to fix. */
  flex: none; min-inline-size: 4.5rem; justify-content: center;
  display: inline-flex; align-items: center;
  font-family: var(--face-ident); font-size: var(--t-micro);
  letter-spacing: var(--tr-flat);
  padding: var(--sp-1) var(--sp-2); border: var(--rule-hair);
  color: var(--c-ink-muted);
}
/* A row with no ticker fills the same lane with what it IS. It must not read
   as a ticker, so it drops the border and the ink: law 1, chrome is
   subordinate, and a boxed word beside a boxed ticker two rows up would be two
   things wearing one costume. */
.suggest__ticker--kind {
  border: 0; padding-inline: 0;
  color: var(--c-ink-faint); font-size: calc(var(--t-micro) * 0.92);
  letter-spacing: var(--tr-caps-snug);
}
/* The count is pushed to the end and set in the UI face: it is metadata about
   the row rather than part of the name. */
.suggest__count {
  margin-inline-start: auto; flex: none;
  font-family: var(--face-ui); font-size: var(--t-micro);
  color: var(--c-ink-muted);
  font-variant-numeric: tabular-nums lining-nums;
}

/* -----------------------------------------------------------------------------
   THE LEDGER STOPS BEING A TABLE ON A PHONE
   -----------------------------------------------------------------------------
   The PI, 2026-08-11, on `/filing/0001883313-26-000062` from an iPhone:
   "Horizontal scrolling!!!???"

   MEASURED, 390px viewport, against production `0c860c8`:

     /filing/...      .ledger-wrap  client 348  scroll  932   584px of drag
     /tape            .ledger-wrap  client 348  scroll 1099   751px of drag

   The document itself did not overflow at 320, 375, 390, 393, 414 or 430, so
   every page-level check passed. The scroll was INSIDE `.ledger-wrap`, which is
   `overflow-x: auto` by deliberate design, with `.ledger { min-inline-size:
   46rem }` and a scripted "MORE COLUMNS" affordance. **It was working as
   designed and the design was wrong on a phone**, which is why no gate caught
   it: nothing was broken.

   The trade that design made was "scroll inside the box rather than scrolling
   the sheet", and it is the right trade against the alternative it was compared
   to. It was never compared to not being a table. Eleven columns at 390 means
   751px of horizontal dragging to read one row, and a reader cannot see the
   date and the value at the same time, which is the only comparison the row
   exists to support.

   So below 48rem each row becomes a record: label on the left, value on the
   right, one line per fact.

   **64rem, AND THE FIRST VERSION OF THIS RULE SAID 48rem, WHICH LEFT THE PI'S
   OTHER DEVICE BROKEN.** 48rem matched `platform.css`'s `.table--stack` and the
   cross-shell argument for it was real (`DEC-20260808T0814Z`). But 48rem is
   768px and **an iPad portrait is 834**, so the tablet stayed a table and went
   on scrolling: measured at 834 the next morning, **334px of drag on `/tape`
   and 167px on a filing page**, in both themes. The PI asked for mobile, iPad
   and desktop, and a breakpoint chosen for symmetry with the other stylesheet
   answered one of the three.

   64rem is 1024px, which puts an iPad **portrait** into the stack and leaves an
   iPad **landscape** at 1112px in the table, where the width is worth having.
   The cross-shell argument is not abandoned, it is outranked: the platform
   shell has no ten-column table, so the two sheets are solving different
   problems under the same name. That is `DEC-20260808T1149Z`'s cost again.

   `min-inline-size: 0` is the load-bearing line. Without it the table keeps its
   46rem floor, the wrap keeps scrolling, and every other rule here is cosmetic.
   -------------------------------------------------------------------------- */
@media (max-width: 64rem) {
  .ledger { min-inline-size: 0; }
  /* Nothing to scroll to any more, so the box stops being a scrollport. The
     "MORE COLUMNS" chip needs no rule: the script stamps `data-scroll` from
     measurement, so a table that fits is never stamped (law 10). */
  .ledger-wrap { overflow-x: visible; }

  .ledger thead {
    position: absolute; inline-size: 1px; block-size: 1px;
    overflow: hidden; clip-path: inset(50%);
  }
  .ledger, .ledger tbody, .ledger tr, .ledger td { display: block; }

  .ledger tbody tr {
    padding-block: var(--sp-3);
    border-block-end: var(--rule-hair);
  }
  .ledger tbody tr:last-child { border-block-end: var(--rule-mid); }

  .ledger tbody td {
    display: grid;
    grid-template-columns: 7.5rem 1fr;
    gap: var(--sp-3);
    padding: var(--sp-1) 0;
    border: 0;
  }
  .ledger tbody td::before {
    content: attr(data-label);
    font-family: var(--face-ui);
    font-size: var(--t-micro);
    letter-spacing: var(--tr-caps);
    text-transform: uppercase;
    color: var(--c-ink-muted);
  }
  /* Every real child belongs in the VALUE column. Without this the cell is a
     two-column grid whose first item is the ::before label, so a cell with two
     children puts the first in column 2 and auto-places the second into column
     1 of the next row, underneath the label rather than beside it. Measured on
     the dashboard's Company cell at 390 and written up in `platform.css`; the
     ledger's person cells have exactly that shape, a name and a role. */
  .ledger tbody td > * { grid-column: 2; }

  /* A right-aligned figure under a left-aligned label reads as a different
     column. The alignment existed to make a column of numbers comparable, and
     in a stack there is no column. */
  .ledger th[data-align="end"], .ledger td[data-align="end"] { text-align: left; }

  /* The direction mark carries no label because the row's Code cell states the
     same fact in words, and a one-glyph value beside a six-letter label reads
     as a missing value. It leads the record instead, as a rule does. */
  .ledger tbody td.ledger__sig { display: block; padding-block-end: var(--sp-2); }
  .ledger tbody td.ledger__sig::before { content: none; }
  .ledger tbody td.ledger__sig > div { display: flex; }

  /* The caption is bottom-set and was forced to the table's 46rem width, so on
     a phone it scrolled with the table it describes. It is now free. */
  .ledger caption { max-inline-size: 100%; }

  /* ---------------------------------------------------------------------------
     THE FEED IS A CARD, THE REFERENCE TABLE STAYS A LIST OF PAIRS
     ---------------------------------------------------------------------------
     Stacking removed the sideways scroll and traded width for height: a tape
     record became ten labelled lines at 387px, and twelve of them were 4,623px,
     five and a half screens of the ledger alone. The PI's complaint about the
     tape was that length, and the record for the phone fix said in as many
     words that this was the consolation prize and the tape deserved what the
     dashboard's watchlist got, which is measurement against alternatives rather
     than a treatment inherited from a different page.

     SIX TREATMENTS RENDERED INTO THE LIVE PAGE AND MEASURED, 390px, 12 records,
     `<scratchpad>/tape_ab.py`:

       A  current, ten labelled lines      387px/record   4,623px    --
       B  two facts per line               350px          4,257px   -8%   OVERFLOWS 30px
       C  card, labels dropped             292px          3,529px  -24%
       D  card, reference matter hidden    220px          2,650px  -43%
       E  card, money line labelled        317px          3,811px  -18%
       F  E with the person cells inline   247px          3,037px  -34%   <- shipped

     **B and D both lost for reasons no amount of looking would have settled.**
     B overflowed by 30px, which is the same shape as the dashboard's ruled list
     losing until `subgrid`: the treatment that reads best in the abstract is not
     the one that fits. D is the shortest by a wide margin and drops `Price`,
     `Security` and `Filing`, and **the Filing link is the catalog's own fifth
     done-when**, that every figure has a path back to the filing it came from.
     A 43 percent saving bought by breaking the product's central promise is not
     a saving. C was rejected on reading rather than on measurement: it put
     `12,500` and `1,480,250.00` side by side with no labels, so the reader met
     two bare figures and nothing said which was which.

     F keeps every fact. The identity leads, date and code chip on one line, then
     the issuer with its ticker and the insider with their role, and the figures
     follow as one aligned block that a reader can run an eye down.

     SCOPED TO `.ledger--feed`, WHICH IS THE PART WORTH KEEPING. `/tape`,
     `/filings/{day}` and the entity pages are a FEED, scanned for what happened.
     `/filing/{accession}` is a REFERENCE surface, read once for a specific line,
     and its columns are different: Line, Held after and 10b5-1 have no
     counterpart here. Giving both the same composition would either misplace
     cells on the filing page or force a lowest common denominator on both.
     A generic label-value stack is right for the reference table and a card is
     right for the feed, and the class is what says which is which.

     The left-edge count, the dashboard's own proxy, reports 7 for F against 4
     for A, and it is the one number here that should be read carefully rather
     than followed: it counts the ticker beside its issuer and the role beside
     its name as raggedness, when both are deliberate pairings. A proxy that
     cannot tell a pair from a stray is a proxy at the edge of its range.
     -------------------------------------------------------------------------- */
  /* F2, 2026-08-19, AFTER THE PI'S VERDICT ON F FROM HIS PHONE: "Ugly and
     unusable." F measured best of six but still spent nine strata per record,
     its sig sat as an orphaned stub on its own line, and the figure block's
     6rem label column re-created the form-like stack the card existed to end.
     F2 is the landing card's own grammar, which he has already approved on
     the front page: date and code chip on one line, issuer with ticker,
     insider with role, then the figures as ONE labelled run with the filing
     link ranged right as the record's exit. The signature rule becomes the
     row's SPINE, stretched down the left edge, solid for acquire and broken
     for dispose over the whole record: law 2's shape channel, now impossible
     to orphan. C already proved bare figures are ambiguous, so the micro
     labels stay, inline rather than columnar. Flex order does the placement;
     the DOM order is the reference table's and does not move. */
  .ledger--feed tbody tr {
    position: relative;
    display: flex; flex-wrap: wrap;
    align-items: baseline;
    column-gap: var(--sp-3); row-gap: var(--sp-1);
    padding-block: var(--sp-3);
    padding-inline-start: calc(3px + var(--sp-3));
  }
  .ledger--feed tbody td { display: block; padding: 0; border: 0; }
  .ledger--feed tbody td::before { content: none; }

  .ledger--feed tbody td.ledger__sig {
    position: absolute; inset-block: var(--sp-3); inset-inline-start: 0;
    padding: 0;
  }
  .ledger--feed tbody td.ledger__sig > div { block-size: 100%; }
  .ledger--feed tbody td.ledger__sig .sig { block-size: 100%; min-block-size: 0; }

  .ledger--feed tbody td[data-label="Date"]    { order: 1; flex: 1 1 auto; }
  .ledger--feed tbody td[data-label="Code"]    { order: 2; }
  .ledger--feed tbody td[data-label="Issuer"]  { order: 3; flex-basis: 100%; }
  .ledger--feed tbody td[data-label="Insider"] { order: 4; flex-basis: 100%; }

  /* The name and its qualifier sit on one line: four lines became two. */
  .ledger--feed tbody td.ledger__person > span { display: inline; }
  .ledger--feed tbody td.ledger__person br { display: none; }
  .ledger--feed tbody td.ledger__person .ledger__ticker::before,
  .ledger--feed tbody td.ledger__person .ledger__role::before {
    content: "  "; white-space: pre;
  }

  .ledger--feed tbody td[data-label="Shares"]    { order: 5; }
  .ledger--feed tbody td[data-label="Price"]     { order: 6; }
  .ledger--feed tbody td[data-label="Value USD"] { order: 7; }
  .ledger--feed tbody td[data-label="Security"]  { order: 8; }
  .ledger--feed tbody td[data-label="Filing"]    { order: 9; margin-inline-start: auto; }
  .ledger--feed tbody td[data-label="Shares"],
  .ledger--feed tbody td[data-label="Price"],
  .ledger--feed tbody td[data-label="Value USD"],
  .ledger--feed tbody td[data-label="Security"],
  .ledger--feed tbody td[data-label="Filing"] {
    display: inline-flex;
    align-items: baseline;
    gap: var(--sp-2);
  }
  .ledger--feed tbody td[data-label="Shares"]::before,
  .ledger--feed tbody td[data-label="Price"]::before,
  .ledger--feed tbody td[data-label="Value USD"]::before,
  .ledger--feed tbody td[data-label="Security"]::before {
    content: attr(data-label);
    font-family: var(--face-ui);
    font-size: var(--t-micro);
    letter-spacing: var(--tr-caps);
    text-transform: uppercase;
    color: var(--c-ink-faint);
  }

  /* A tapped row is not a hovered row: on a touch screen the wash lingered on
     whatever was last tapped and read as a permanent zebra stripe (the PI
     photographed one). Pointerless devices get no rest wash at all. */
  @media (hover: none) {
    .ledger tbody tr:hover,
    .ledger tbody tr:hover td,
    .ledger tbody tr:focus-within,
    .ledger tbody tr:focus-within td { background: transparent; }
  }
}

/* The Form 4 code chip, set as a printed reference mark. Its square tracks the
   density gear it sits inside. */
.code {
  display: inline-grid;
  place-content: center;
  inline-size: var(--den-chip);
  block-size: var(--den-chip);
  border: var(--rule-control);
  border-radius: var(--radius);
  font-family: var(--face-ident);
  font-size: var(--t-mini);
  font-weight: var(--w-bold);
  line-height: 1;
}
.code[data-code="P"] { color: var(--c-buy);  border-color: var(--c-buy); }
.code[data-code="S"] { color: var(--c-sell); border-color: var(--c-sell); }
/* Every non-open-market code is compensation or administrative machinery, so
   the palette itself performs the product's central editorial claim: it is
   drawn in grey behind a dashed rule and never in a pigment. The selector is
   the complement of P and S rather than a list, because the store carries
   codes beyond the seven the alert product knew about (J, C, L, W, I are all
   present in the backfill) and an unlisted code must not fall through to the
   solid rule that means open market. */
.code:not([data-code="P"]):not([data-code="S"]) {
  color: var(--c-admin);
  border-color: var(--c-rule);
  border-style: dashed;
}


/* -----------------------------------------------------------------------------
   9b  THE DENSITY GEARS   (bible 7, ADR-20260731T0548Z)
   The attribute goes on the table's scroll wrap or any ancestor region, never
   on the table element itself. Density is a per-surface constant chosen by the
   page author (law 10). Reading is the only gear permitted inside prose.
   Eight tokens move and nothing else: rule weights, the two pigments, the
   parentheses and their gutters, the signature shapes, the hover wash and the
   focus raise never move with it, and no gear sets a row block-size, so a
   reader applying their own text spacing under SC 1.4.12 always wins.
   -------------------------------------------------------------------------- */

[data-density="solid"] {
  --den-pad-block: var(--sp-2);
  --den-leading:   1.35;
  --den-chip:      1.4rem;
}

[data-density="agate"] {
  --den-pad-block:    var(--sp-1);
  --den-pad-inline:   var(--sp-1);
  --den-size:         var(--t-mini);
  --den-leading:      1.3;
  --den-chip:         1.25rem;
  --den-flag-pad:     1px;
  --den-flag-leading: 1.15;
}
/* Agate's law is one line per row: an operator's listing never re-wraps when
   the port narrows, it scrolls. Reading and solid keep the opposite law. */
[data-density="agate"] .ledger { inline-size: max-content; min-inline-size: 100%; }
[data-density="agate"] .ledger td br { display: none; }
[data-density="agate"] .ledger__person > span { display: inline; }
[data-density="agate"] .ledger__ticker,
[data-density="agate"] .ledger__role { margin-inline-start: var(--sp-2); }


/* -----------------------------------------------------------------------------
   10  BADGES, NOTES, CITATIONS, CARDS, CONTAINER STATES, PAGINATION
   -------------------------------------------------------------------------- */

/* THE LAW OF THE FLAG (bible 8.6, law 1). No badge is ever painted in a
   pigment. A pigment means one thing on this sheet, the direction of a
   reported transaction, and it already appears four times in every ledger row.
   The ladder is fill and rule style, top salience first:
     filled ink        the label the product exists to raise
     plain strong rule a discretionary act worth reading
     dotted rule       the pre-committed and routine, which recedes
     dashed admin grey compensation machinery, the code chips' own dash */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--den-flag-pad) var(--sp-2);
  border: var(--rule-control);
  border-radius: var(--radius);
  font-family: var(--face-ui);
  font-size: var(--t-micro);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-caps-snug);
  text-transform: uppercase;
  line-height: var(--den-flag-leading);
  color: var(--c-ink-muted);
  white-space: nowrap;
  font-variant-numeric: lining-nums tabular-nums;
}
.badge--ink { background: var(--c-mark); color: var(--c-on-mark); border-color: var(--c-mark); }
.badge--planned { border-style: dotted; color: var(--c-ink-faint); }
.badge--admin { border-style: dashed; border-color: var(--c-rule); color: var(--c-admin); }
.badge--ident {
  font-family: var(--face-ident);
  text-transform: none;
  letter-spacing: 0;
  border-style: none;
  padding-inline: 0;
  color: var(--c-ink-faint);
  font-variant-numeric: tabular-nums lining-nums slashed-zero;
}

/* A callout is a hanging note against a heavy rule, never a tinted box. */
.note {
  display: grid;
  gap: var(--sp-2);
  padding: var(--sp-3) 0 var(--sp-3) var(--sp-5);
  border-inline-start: var(--rule-heavy);
  background: var(--c-note-wash);
}
.note__label {
  font-family: var(--face-ui);
  font-size: var(--t-micro);
  font-weight: var(--w-bold);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--c-ink-muted);
}
.note p { font-size: var(--t-base); line-height: 1.55; }
.note--method { border-inline-start-color: var(--c-buy); }
.note--method .note__label { color: var(--c-buy); }
/* Reserved for a limitation the reader must know before acting, and never for
   marketing urgency, which would contradict the entire premise. */
.note--caution { border-inline-start-color: var(--c-sell); }
.note--caution .note__label { color: var(--c-sell); }

/* The citation block. Provenance is set the way a reference is set, because
   that is what it is. (bible 8.8) */
.cite {
  font-family: var(--face-text);
  font-size: var(--t-small);
  line-height: 1.5;
  padding-inline-start: var(--sp-5);
  text-indent: calc(-1 * var(--sp-5));
  color: var(--c-ink-muted);
}
.cite em { color: var(--c-ink); }
.cite .doi, .cite .acc, .cite .url {
  font-family: var(--face-ident);
  font-size: 0.92em;
  font-variant-numeric: tabular-nums lining-nums slashed-zero;
  color: var(--c-ink);
  /* A canonical URL and a DOI are long unbreakable strings, and one of them
     inside a hanging indent is what pushes a phone-width sheet sideways. */
  overflow-wrap: anywhere;
}
/* THE ARROW NOW TELLS THE TRUTH. `.link-source` marks a link that leaves
   this catalog and draws a north-east arrow, which is the convention for
   "opens in a new window", and not one of them did. The PI asked for it on
   the primary document; it is applied to every `.link-source` instead,
   because a class that means "external" should behave one way and a mark
   that promises something the link does not do is worse on the six that
   were silently wrong than on the one he happened to click.

   `target` is on the anchors rather than here because CSS cannot set it,
   and every one carries `rel="noopener noreferrer"` with it: a bare
   `_blank` hands the opened page a live handle on ours. */
.link-source::after { content: " \2197"; font-family: var(--face-ui); font-size: 0.8em; vertical-align: 0.2em; }

/* Cards: no box. A heavy rule on top, a hairline underneath, subgrid so the
   heading, body, and action of every card in a row sit on three baselines. */
.card-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  grid-template-rows: auto auto 1fr auto;
  gap: var(--sp-6);
}
.card-row > * { min-inline-size: 0; }
.card {
  display: grid;
  grid-row: span 4;
  grid-template-rows: subgrid;
  gap: var(--sp-3);
  padding-block: var(--sp-4);
  border-block-start: var(--rule-heavy);
  border-block-end: var(--rule-hair);
}
.card__no {
  font-family: var(--face-ui);
  font-size: var(--t-micro);
  font-weight: var(--w-bold);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  font-variant-numeric: tabular-nums lining-nums;
}
/* h2 as well as h3: a card's heading level follows the page's outline, which
   is h2 when the section above it is the page's h1 (heading levels never
   skip), and the card sets the same size either way. */
.card h2, .card h3 { font-size: var(--t-sub); line-height: var(--lh-head); letter-spacing: var(--tr-head); }
.card p { font-size: var(--t-base); line-height: 1.55; color: var(--c-ink-muted); }
.card__foot { align-self: end; }

/* 10a  THE CONTAINER STATE MATRIX   (bible 8.10, law 8)
   Every data container draws four states: loaded, empty, filtered-empty, and
   faulted. An empty ledger asserts that no insider filed, the strongest
   sentence the product can utter, so it is never uttered by accident. The
   blank shows through :has(tbody:empty), read off the data itself so it cannot
   drift. Which blank shows is the author's statement, because filtered-ness is
   not knowable from the DOM. A fault OUTRANKS a blank: an empty body under a
   declared fault never claims no insider traded. */
.blank {
  display: grid;
  gap: var(--sp-3);
  place-items: center;
  text-align: center;
  padding: var(--sp-8) var(--sp-5);
  border: var(--rule-thin);
  border-style: dashed;
  color: var(--c-ink-muted);
}
.blank__mark {
  font-family: var(--face-text);
  font-size: var(--t-head);
  line-height: 1;
  /* Head-sized, so it is large text and owes 3:1. --c-rule measures 2.04:1 and
     1.68:1 and would fail; the strong rule measures 5.63:1 and 4.53:1. */
  color: var(--c-rule-strong);
}
.blank h2, .blank h3 { font-size: var(--t-lead); color: var(--c-ink); }
.blank p { font-size: var(--t-base); max-inline-size: 42ch; }
.blank__actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); justify-content: center; }

.ledger-wrap > .blank { display: none; border-block-start: 0; }
.ledger-wrap:has(> .ledger > tbody:empty) > .ledger { display: none; }
.ledger-wrap:has(> .ledger > tbody:empty) > .blank { display: grid; }
.ledger-wrap > .fault { display: none; }
.ledger-wrap[data-fault] > .fault { display: grid; margin-block: var(--sp-3) var(--sp-2); }
.ledger-wrap[data-fault]:has(> .ledger > tbody:empty) > .blank { display: none; }
/* The same four states on a list container rather than a table: the results
   list and the browse indexes owe them too, because the blank and the fault
   are container furniture, not table furniture. */
.list-wrap > .blank { display: none; }
.list-wrap:has(> .results:empty) > .blank { display: grid; }
.list-wrap:has(> .results:empty) > .results { display: none; }
.list-wrap > .fault { display: none; }
.list-wrap[data-fault] > .fault { display: grid; margin-block-end: var(--sp-4); }
.list-wrap[data-fault]:has(> .results:empty) > .blank { display: none; }
.fault__stamp {
  font-family: var(--face-fig);
  font-variant-numeric: tabular-nums lining-nums slashed-zero;
  color: var(--c-ink);
  font-weight: var(--w-semi);
}

/* Pagination as a folio line: rules, not pills. (bible 8.11) */
.folio-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1);
  padding-block: var(--sp-3);
  border-block: var(--rule-hair);
  font-family: var(--face-ui);
  font-size: var(--t-small);
  font-variant-numeric: tabular-nums lining-nums;
}
.folio-nav a, .folio-nav span {
  display: grid;
  place-content: center;
  /* A page number is a target and owes the same 44px floor as every other
     control. The boxes are ghosts, so the cost is whitespace. */
  min-inline-size: 2.75rem;
  block-size: 2.75rem;
  padding-inline: var(--sp-2);
  text-decoration: none;
  border: 1px solid transparent;
  border-radius: var(--radius);
  color: var(--c-ink-muted);
  transition: background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}
.folio-nav a:hover { background: var(--c-hover-wash); color: var(--c-ink); border-color: var(--c-rule); }
.folio-nav [aria-current="page"] {
  background: var(--c-mark);
  color: var(--c-on-mark);
  border-color: var(--c-mark);
  font-weight: var(--w-semi);
}
.folio-nav .gap { min-inline-size: 1.25rem; color: var(--c-ink-faint); }
.folio-nav .edge {
  min-inline-size: auto;
  padding-inline: var(--sp-3);
  letter-spacing: var(--tr-caps-snug);
  text-transform: uppercase;
  font-size: var(--t-micro);
  font-weight: var(--w-semi);
}
.folio-nav [aria-disabled="true"] { color: var(--c-ink-disabled); cursor: not-allowed; }
.folio-nav__count { margin-inline-start: auto; color: var(--c-ink-faint); font-size: var(--t-mini); }


/* -----------------------------------------------------------------------------
   11  THE FILING CARD   (bible 8.9, the specimen promoted to a page)
   One transaction typeset as a catalogued specimen. It reflows on its OWN
   width through container queries, never the viewport's, so it works in a page
   column, a hero column, and an email preview frame.

   THE ANALYTIC SLOT IS ABSENT, not empty. DEC-20260731T0438Z forbids an
   analytics slot until the analytic exists, and the IA states there are no
   placeholder panels anywhere in this design. .interval and .withheld are not
   promoted from the gallery for that reason.
   -------------------------------------------------------------------------- */

.specimen {
  container-type: inline-size;
  container-name: specimen;
  display: grid;
  gap: var(--sp-5);
  padding: var(--sp-5);
  border-block-start: var(--rule-nameplate);
  border-block-end: var(--rule-mid);
  background: var(--c-surface);
}
.specimen__head {
  display: grid;
  gap: var(--sp-3);
  padding-block-end: var(--sp-4);
  border-block-end: var(--rule-hair);
}
.specimen__slug {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
  align-items: center;
  justify-content: space-between;
}
.specimen__issuer { font-size: var(--t-sub); line-height: var(--lh-tight); letter-spacing: var(--tr-head); }
.specimen__sub {
  font-family: var(--face-ui);
  font-size: var(--t-mini);
  letter-spacing: var(--tr-caps-snug);
  text-transform: uppercase;
  color: var(--c-ink-muted);
}
.specimen__figure { display: grid; gap: var(--sp-1); }
.specimen__figure .led {
  font-size: var(--t-head);
  font-weight: var(--w-medium);
  line-height: var(--lh-tight);
  letter-spacing: var(--tr-title);
}
.specimen__figure .caps { font-size: var(--t-micro); }

/* The field list. Two subgrid columns so every label and value line up down
   the card. One column until the card is wide enough for the pair to sit side
   by side, which is what a printed form does on a narrow column too. */
.spec-list { display: grid; grid-template-columns: 1fr; gap: var(--sp-2) var(--sp-5); align-items: baseline; }
.spec-list > * { min-inline-size: 0; }
.spec-list > dt {
  font-family: var(--face-ui);
  font-size: var(--t-micro);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  padding-block: 2px var(--sp-2);
}
.spec-list > dd { font-size: var(--t-small); border-block-end: var(--rule-hair); padding-block-end: var(--sp-2); }
.spec-list > dd:last-of-type, .spec-list > dt:last-of-type { border-block-end: 0; }

.specimen__foot { display: grid; gap: var(--sp-3); padding-block-start: var(--sp-4); border-block-start: var(--rule-mid); }
.specimen__prov { display: grid; gap: var(--sp-2); }

@container specimen (inline-size > 26rem) {
  .spec-list { grid-template-columns: minmax(8rem, max-content) 1fr; }
  .spec-list > dt { border-block-end: var(--rule-hair); }
  .spec-list > dt:last-of-type { border-block-end: 0; }
  .specimen__issuer { font-size: var(--t-head); }
}
@container specimen (inline-size > 34rem) {
  .specimen__head { grid-template-columns: 1fr auto; align-items: end; }
  .specimen__figure { text-align: right; justify-items: end; }
  .specimen__figure .led { font-size: var(--t-title); }
  .spec-cols { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-5) var(--sp-7); }
  .spec-cols > * { min-inline-size: 0; }
}


/* -----------------------------------------------------------------------------
   12  THE TAPE   (bible 8.12)
   -------------------------------------------------------------------------- */

.tape { container-type: inline-size; border-block-start: var(--rule-heavy); background: var(--c-surface); }
.tape__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-block-end: var(--rule-mid);
}
.tape__title { font-family: var(--face-ui); font-size: var(--t-micro); font-weight: var(--w-bold); letter-spacing: var(--tr-caps); text-transform: uppercase; }
.tape__live { font-family: var(--face-ui); font-size: var(--t-micro); letter-spacing: var(--tr-caps-snug); text-transform: uppercase; color: var(--c-ink-faint); }
.tape__row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--sp-3);
  align-items: baseline;
  padding: var(--sp-3) var(--sp-4);
  border-block-end: var(--rule-hair);
}
.tape__row:last-child { border-block-end: 0; }
.tape__who { display: grid; gap: 1px; min-inline-size: 0; }
.tape__name { font-size: var(--t-small); font-weight: var(--w-semi); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A 2.75rem LINE, not a halo: the span above clips its own overflow for the
   ellipsis, and a clipped halo does not hit-test, so a ::before extension
   here measures exactly nothing (tried, measured 25px, removed). Growing the
   link's line box keeps the ellipsis working and buys the floor inside the
   75px row. Measured on the catalog's own front door;
   BUG-20260819T1705Z's sweep found it. */
.tape__name a { display: inline-block; max-inline-size: 100%; line-height: 2.75rem; }
/* An insider's name is a datum, and a datum is never cut when it can break. */
@container (inline-size < 20rem) {
  .tape__name { white-space: normal; overflow: visible; text-overflow: clip; }
}
.tape__meta { font-family: var(--face-ui); font-size: var(--t-micro); color: var(--c-ink-muted); letter-spacing: var(--tr-caps-snug); text-transform: uppercase; }
.tape__val { font-size: var(--t-small); position: relative; }
/* The date in a tape row is a link to its filing and measured 83.5x17. The row
   is taller than the floor once its 12px block padding is counted, so the
   extension is block-axis only and stays inside its own row. */
.tape__val a { position: relative; display: inline-block; }
.tape__val a::before {
  content: "";
  position: absolute;
  inset-block: min(0px, calc((100% - 2.75rem) / 2));
  inset-inline: 0;
}
.tape__foot { padding: var(--sp-3) var(--sp-4); border-block-start: var(--rule-mid); font-family: var(--face-ui); font-size: var(--t-mini); color: var(--c-ink-muted); }


/* -----------------------------------------------------------------------------
   13  THE HERO   (bible 9.5, the catalog home)
   -------------------------------------------------------------------------- */

/* Every grid in the system resets its children's automatic minimum size: one
   long unbreakable string makes the whole column refuse to narrow otherwise. */
.hero, .hero__proof { & > * { min-inline-size: 0; } }

.hero { display: grid; gap: var(--sp-7); align-items: start; }
@media (width >= 62rem) { .hero { grid-template-columns: 1.15fr 0.85fr; gap: var(--sp-8); } }
.hero__headline {
  font-size: var(--t-display);
  line-height: var(--lh-display);
  letter-spacing: var(--tr-display);
  font-weight: var(--w-bold);
  color: var(--c-ink-strong);
  max-inline-size: 15ch;
}
.hero__headline em { font-style: italic; font-weight: var(--w-book); }
.hero__deck { max-inline-size: 46ch; }
/* The floor is 12rem rather than 9rem, and the reason is a measurement.
   MEASURED 2026-08-08 on /catalog/search with a query that matches nothing, at
   390px: the grid laid out two 159px columns, and `.stat__val` holding the ISO
   date `2026-07-28` at --t-sub is 188px wide and `white-space: nowrap`, so the
   value overflowed its own cell and the PAGE scrolled sideways by 9px.

   It is the second half of a fix rather than a new bug. The nowrap below was
   added because law 3 says a figure is never wrapped, after that same date
   broke after its second hyphen. That stopped the wrap and turned it into an
   overflow, and nothing could see the result: WRK-20260808T1132Z section 5
   measured that this page, and ten others like it, had no visual gate at all.
   The harness gained them minutes before this was found.

   12rem is not a round number, it is 188px plus a little: the widest value
   this component holds is an ISO date, and the track floor is now wide enough
   for one. At 390 that yields a single column of 350px, so each stat gets the
   full measure; at 834 and 1440 nothing changes, which is what the captures
   at all three widths show.

   min(12rem, 100%) rather than a bare 12rem so a viewport narrower than the
   floor gets a track that fits the container instead of one that overflows it.
   Below about 340px the date still outruns its own track, because a 30px
   unbreakable figure cannot be made to fit and law 3 forbids the two ways of
   pretending otherwise. That bound is stated in BUG-20260808T1531Z rather than
   hidden. */
.hero__proof {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(12rem, 100%), 1fr));
  gap: var(--sp-4) var(--sp-6);
  padding-block-start: var(--sp-5);
  border-block-start: var(--rule-hair);
}
.stat { display: grid; gap: var(--sp-1); }
.stat__val {
  font-family: var(--face-fig);
  font-variant-numeric: tabular-nums lining-nums slashed-zero;
  font-size: var(--t-sub);
  font-weight: var(--w-semi);
  line-height: 1.05;
  letter-spacing: var(--tr-head);
  color: var(--c-ink-strong);
  /* A figure is never wrapped (law 3). An ISO date in a stat broke after its
     second hyphen at 390px before this line. */
  white-space: nowrap;
}
.stat__key { font-family: var(--face-ui); font-size: var(--t-micro); letter-spacing: var(--tr-caps-snug); text-transform: uppercase; color: var(--c-ink-muted); line-height: var(--lh-ui); }


/* =============================================================================
   THE CATALOG COMPONENTS
   Specified in the bible as NOT YET DRAWN. This is their first render, so
   every measured figure about them is taken from this stylesheet's own pages
   and nothing about them is carried from anywhere.
   ============================================================================= */

/* -----------------------------------------------------------------------------
   20  THE SEARCH FORM   (bible 8.13)
   Drawn in the existing form vocabulary rather than inventing one: a .field
   whose input is the ruled blank, inside a role="search" landmark, with a
   .btn--ink submit, because search is the primary action of the surface that
   carries it. It is a plain GET <form> that works with JavaScript disabled and
   produces an addressable URL, because a search that cannot be linked cannot
   be cited, and citability is the product.
   -------------------------------------------------------------------------- */

.searchbar {
  display: grid;
  gap: var(--sp-3);
  padding-block: var(--sp-5);
  border-block: var(--rule-heavy);
}
.searchbar__row { display: grid; gap: var(--sp-3); align-items: end; }
@media (width >= 34rem) { .searchbar__row { grid-template-columns: 1fr auto; } }
.searchbar__row > * { min-inline-size: 0; }
/* --t-base, which is what bible 8.13 has specified for this input all along;
   the --t-lead that stood here rendered the search page's own field a step
   and a half above its spec while every compact field obeyed it. */
.searchbar .input { font-size: var(--t-base); }
.searchbar__hint { font-family: var(--face-ui); font-size: var(--t-mini); line-height: var(--lh-ui); color: var(--c-ink-faint); max-inline-size: 62ch; }

/* The compact variant that rides the folio strip of every catalog page,
   because a catalog reader searches from wherever they are. The label is
   visually hidden here and never absent. */
.searchbar--compact { padding-block: var(--sp-3); border-block: 0; gap: var(--sp-2); }
.searchbar--compact .searchbar__row { grid-template-columns: 1fr auto; gap: var(--sp-2); }
.searchbar--compact .input { font-size: var(--t-small); min-block-size: 2.75rem; }
.searchbar--compact .btn { padding-inline: var(--sp-4); }

/* The echoed query on a results page is set in the identifier face only when
   the query WAS an identifier, and only in the echo, never live in the field. */
.query-echo { font-family: var(--face-ident); font-variant-numeric: tabular-nums lining-nums slashed-zero; }


/* -----------------------------------------------------------------------------
   21  THE RESULT ROW AND THE RESULTS LIST   (bible 8.14)
   A search result is a finding, so it is set like one: a hairline-separated
   row in the ledger vocabulary, not a card. The whole row is one link target
   at the 2.75rem floor and the hover is the ledger's own wash.
   Order is always stated in the head, because an unexplained order is an
   unexplained claim, and nothing here ranks by an undisclosed score.
   -------------------------------------------------------------------------- */

.results { display: grid; border-block-start: var(--rule-mid); }
.results > li { border-block-end: var(--rule-hair); min-inline-size: 0; }

.result__link {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-1) var(--sp-5);
  align-items: baseline;
  padding: var(--sp-3) var(--sp-2);
  min-block-size: 2.75rem;
  text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease-out);
}
@media (width >= 34rem) {
  .result__link { grid-template-columns: 1fr auto; }
  .result__count { grid-row: 1 / span 2; grid-column: 2; text-align: right; align-self: center; }
}
.result__link:hover { background: var(--c-hover-wash); }
.result__link:focus-visible { outline-offset: -2px; }
.result__link > * { min-inline-size: 0; }

/* A mixed results list must say WHAT each row is before it says which one. */
.result__type {
  font-family: var(--face-ui);
  font-size: var(--t-micro);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  display: block;
}
.result__name {
  font-family: var(--face-text);
  font-size: var(--t-small);
  font-weight: var(--w-semi);
  color: var(--c-ink-strong);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  text-decoration-color: color-mix(in oklab, currentColor 55%, transparent);
  overflow-wrap: anywhere;
}
.result__link:hover .result__name { text-decoration-thickness: 2px; text-decoration-color: currentColor; }
/* Identifiers set in the monospace, words set in the ui face: a meta line
   carries both and the reader must be able to tell them apart at a glance. */
.result__meta { font-family: var(--face-ui); font-size: var(--t-mini); line-height: var(--lh-ui); color: var(--c-ink-muted); }
.result__meta .ident { font-family: var(--face-ident); font-variant-numeric: tabular-nums lining-nums slashed-zero; color: var(--c-ink-faint); }
.result__meta .sep { color: var(--c-ink-faint); }
.result__count {
  font-family: var(--face-fig);
  font-variant-numeric: tabular-nums lining-nums slashed-zero;
  font-size: var(--t-mini);
  color: var(--c-ink-muted);
  white-space: nowrap;
}
.result__count b { display: block; font-size: var(--t-small); font-weight: var(--w-semi); color: var(--c-ink); }


/* -----------------------------------------------------------------------------
   22  THE RESULT COUNT AND THE APPLIED-FILTER STATEMENT   (bible 8.15)
   One line above every list and table that can be filtered. It is what makes a
   filtered page honest at a glance, and its wording must match the filters
   actually bound in the query. When nothing is filtered it states the coverage
   instead, because the absence of a filter is also a fact worth printing.
   -------------------------------------------------------------------------- */

.count-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
  font-family: var(--face-ui);
  font-size: var(--t-mini);
  line-height: var(--lh-ui);
  color: var(--c-ink-muted);
  padding-block: var(--sp-2);
}
.count-line .fig { color: var(--c-ink); font-weight: var(--w-semi); }
.count-line .sep { color: var(--c-ink-faint); }
/* An approximate count says so in words. A research tool that prints a wrong
   count silently is worse than one that says approximately (law 4). */
.count-line__approx { font-style: italic; color: var(--c-ink-faint); }
/* Each applied filter is removable in place, in the .btn--quiet vocabulary at
   the target floor. */
.chip-filter {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-block-size: 2.75rem;
  padding-inline: var(--sp-2);
  font-family: var(--face-ui);
  font-size: var(--t-mini);
  color: var(--c-ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
  text-decoration-color: var(--c-rule);
}
.chip-filter:hover { background: var(--c-hover-wash); text-decoration-thickness: 2px; text-decoration-color: currentColor; }
.chip-filter::after { content: "\00D7"; font-size: 1.15em; line-height: 1; color: var(--c-ink-faint); }


/* -----------------------------------------------------------------------------
   23  THE FACET LIST   (bible 8.16)
   Browse is a printed index, not a sidebar of toggles. Counts are real and
   current or they are absent: an estimated count printed as exact is a
   fabricated figure under law 4. A zero-count facet renders disabled with its
   zero PRINTED, never silently hidden, because the absence of, say, gifts in a
   window is a finding (law 9). Applying facets is a form submission producing
   an addressable URL.
   -------------------------------------------------------------------------- */

.facets { display: grid; gap: var(--sp-5); align-content: start; }
.facets__group { border-block-start: var(--rule-mid); padding-block-start: var(--sp-3); }
.facet-list { display: grid; }
.facet {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--sp-3);
  align-items: center;
  min-block-size: 2.75rem;
  font-family: var(--face-ui);
  font-size: var(--t-small);
  line-height: var(--lh-ui);
  cursor: pointer;
  border-block-end: var(--rule-hair);
}
.facet:last-child { border-block-end: 0; }
.facet:hover { background: var(--c-hover-wash); }
.facet:has(input:disabled) { color: var(--c-ink-disabled); cursor: not-allowed; background: none; }
.facet__name { min-inline-size: 0; }
.facet__count { font-family: var(--face-fig); font-variant-numeric: tabular-nums lining-nums slashed-zero; font-size: var(--t-mini); color: var(--c-ink-muted); }
.facet:has(input:disabled) .facet__count { color: var(--c-ink-disabled); }
.facet__foot { display: flex; flex-wrap: wrap; gap: var(--sp-3); padding-block-start: var(--sp-4); }

/* The filter control row above a ledger. The editorial default is visible and
   reversible, so it sits in view rather than in a menu. */
.filter-row { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; justify-content: space-between; padding-block: var(--sp-4); }


/* -----------------------------------------------------------------------------
   24  THE ENTITY HEADER   (bible 8.17)
   The masthead of an issuer, insider, or filing page, and the anchor of the
   citable URL. Its mandatory part is the COVERAGE STATEMENT: a citation of a
   page whose coverage is unstated is a citation of an unknown.
   Nothing here opens or expands: section 6 budgets no disclosure motion and
   this system has no disclosure component, so a revealing Cite control would
   be a new component, not a variant.
   -------------------------------------------------------------------------- */

.entity { display: grid; gap: var(--sp-3); padding-block-start: var(--sp-2); border-block-start: var(--rule-heavy); }
.entity__kicker {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-2) var(--sp-4);
  font-family: var(--face-ui);
  font-size: var(--t-micro);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  line-height: var(--lh-ui);
}
/* Law 3: every quantity, and every identifier made of digits, is tabular,
   lining and slashed-zero. Measured before this rule: the computed
   font-variant-numeric on the kicker's CIK, accession and filing-day was
   "oldstyle-nums proportional-nums", inherited straight from body, so a
   ten-digit CIK of mostly zeros printed with unslashed zeros on every issuer,
   insider, filing and day page. The result row's own .ident already carried
   the three features; this one did not. */
.entity__kicker .ident {
  font-family: var(--face-ident);
  letter-spacing: var(--tr-caps-snug);
  font-variant-numeric: tabular-nums lining-nums slashed-zero;
}
/* The role cross-link buys its 44px in the box, not as a reach. Measured
   before this rule at 390px: the .btn--small extension grew a 213.4 x 31.2 box
   to 44px block by reaching 6.4px past it on each side, and the h1's issuer
   link sat close enough below that the two hit regions overlapped 213.4 x 1.4
   px on every filing page. A 1.4px contest is still a contest, and two targets
   may never contest one point. */
.entity__kicker .btn--small { min-block-size: 2.75rem; }
.entity__kicker .btn--small::before { content: none; }

/* Entity names are proper nouns and are NEVER uppercased. */
.entity__name {
  font-size: var(--t-title);
  line-height: var(--lh-tight);
  letter-spacing: var(--tr-title);
  text-transform: none;
  overflow-wrap: anywhere;
}
@media (width < 34rem) { .entity__name { font-size: var(--t-head); } }
.entity__idents {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
  font-family: var(--face-ident);
  font-size: var(--t-mini);
  font-variant-numeric: tabular-nums lining-nums slashed-zero;
  color: var(--c-ink-faint);
}
.entity__idents b { color: var(--c-ink); font-weight: var(--w-semi); }
.entity__badges { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

/* The filed-as variant list. Text, not badges: a variant is a fact about
   filings, not a standing fact about the person. One variant means the list is
   one entry; it NEVER disappears, because "filed under one name" is itself a
   finding. */
.variants { font-family: var(--face-ui); font-size: var(--t-mini); line-height: var(--lh-ui); color: var(--c-ink-muted); }
.variants b { font-weight: var(--w-semi); color: var(--c-ink-muted); text-transform: uppercase; letter-spacing: var(--tr-caps-snug); font-size: var(--t-micro); }
.variants .name { color: var(--c-ink); }
.variants .fig { color: var(--c-ink-faint); }
.variants .sep { color: var(--c-ink-faint); }

/* The coverage statement, beneath a hairline and mandatory on every entity
   page. It never assumes lines exist: an entity attested only by filings whose
   parse failed reads "0 transactions", with the span drawn from filed_date,
   because law 9 forbids faking a span from nothing. */
.coverage {
  padding-block-start: var(--sp-3);
  border-block-start: var(--rule-hair);
  font-family: var(--face-ui);
  font-size: var(--t-small);
  line-height: var(--lh-ui);
  color: var(--c-ink-muted);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-3);
  align-items: baseline;
}
.coverage .fig { color: var(--c-ink); font-weight: var(--w-semi); }
.coverage .sep { color: var(--c-ink-faint); }
.coverage__note { flex-basis: 100%; font-size: var(--t-mini); color: var(--c-ink-faint); }

/* The closing provenance band: the citation stack and the machine-readable
   link, which is a catalog obligation rather than a nicety. */
.prov { display: grid; gap: var(--sp-4); }
.prov__stack { display: grid; gap: var(--sp-3); }
.prov__machine { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; }

/* A long URL set as a facts value is a control, not a sentence, so it owes
   the floor. inline-block rather than inline-flex, deliberately: flex would
   forbid the URL to wrap and drag 390 sideways, and this one wraps to three
   lines there. BUG-20260819T1705Z's sweep. */
.facts dd > a { display: inline-block; min-block-size: 2.75rem; }

/* A definition run used for the filing page's provenance panel and the licence
   page's layer table. Two columns where there is room, stacked where there is
   not, in the same anatomy as the specimen field list. */
.facts { display: grid; grid-template-columns: 1fr; gap: var(--sp-2) var(--sp-5); align-items: baseline; }
@media (width >= 34rem) { .facts { grid-template-columns: minmax(9rem, max-content) 1fr; } }
.facts > * { min-inline-size: 0; }
.facts > dt {
  font-family: var(--face-ui);
  font-size: var(--t-micro);
  font-weight: var(--w-semi);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  padding-block: 2px var(--sp-2);
  border-block-end: var(--rule-hair);
}
.facts > dd { font-size: var(--t-small); border-block-end: var(--rule-hair); padding-block-end: var(--sp-2); overflow-wrap: anywhere; }
.facts > dt:last-of-type, .facts > dd:last-of-type { border-block-end: 0; }
@media (width < 34rem) { .facts > dt { border-block-end: 0; padding-block-end: 0; } }

/* Prose measure on the licence and method pages. */
.prose { display: grid; gap: var(--sp-4); }
.prose p { max-inline-size: var(--measure); }
.prose h2 { font-size: var(--t-sub); line-height: var(--lh-head); letter-spacing: var(--tr-head); padding-block-start: var(--sp-4); }
.prose h3 { font-size: var(--t-lead); line-height: var(--lh-head); }
.prose ul { display: grid; gap: var(--sp-2); max-inline-size: var(--measure); }
.prose ul > li { padding-inline-start: var(--sp-4); position: relative; }
.prose ul > li::before { content: "\2014"; position: absolute; inset-inline-start: 0; color: var(--c-ink-faint); }


/* -----------------------------------------------------------------------------
   25  THE THEME TRANSITION
   A fresh sheet laid across the page on a slant. Fired only from the theme
   control, never on navigation, and skipped entirely under reduced motion.
   -------------------------------------------------------------------------- */

::view-transition-old(root) { animation: none; z-index: 0; }
::view-transition-new(root) { animation: lay-sheet var(--dur-page) var(--ease-inout) both; z-index: 1; }
@keyframes lay-sheet {
  from { clip-path: polygon(0 0, 0 0, -34% 100%, -34% 100%); }
  to   { clip-path: polygon(0 0, 134% 0, 100% 100%, -34% 100%); }
}


/* -----------------------------------------------------------------------------
   26  PREFERENCE AND ENVIRONMENT
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  /* The loading button still has to say it is busy, so the sweep becomes a
     static dashed rule rather than simply vanishing. */
  .btn[data-state="loading"]::after {
    animation: none;
    background: repeating-linear-gradient(to right, currentColor 0 5px, transparent 5px 10px);
  }
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
}

@media (forced-colors: active) {
  .btn, .code, .badge, .check input { border: 1px solid ButtonBorder; }
  .btn--ink { forced-color-adjust: none; }
  .sig { forced-color-adjust: none; }
}

@media print {
  .setter, .skip, .searchbar, .folio-nav { display: none !important; }
  body { background: #fff; color: #000; font-size: 10.5pt; }
  .band { padding-block: 1.2rem; }
  .ledger-wrap { overflow: visible; }
  .ledger { min-inline-size: 0; }
  /* Print clips nothing, so the scrollport affordance would be a lie. */
  [data-scroll] { border-inline: 0; }
  [data-scroll]::before, [data-scroll]::after { content: none !important; }
  a { text-decoration: none; }
  /* A printed catalog page is a citable artifact, so it must carry the URL it
     was printed from. */
  .prov__machine a::after { content: " (" attr(href) ")"; font-family: var(--face-ident); font-size: 0.85em; }
}


/* -----------------------------------------------------------------------------
   SHARING A PAGE
   -----------------------------------------------------------------------------
   Bible 13.10. Added 2026-08-10 at the owner's request, who looked at a filing
   page and could not find the share controls, correctly: they existed only in
   static/platform.css, which the catalog does not load.

   THIS EDITS catalog.css, WHICH DEC-20260808T1149Z SAID NOT TO DO, and the
   decision's own reasoning is why that is now allowed. It withheld the file
   because "eleven public broadsheet pages have no visual gate at all", so an
   edit could regress them invisibly. Those eleven pages have been in
   tools/ux/screenshot.py since 2026-08-08, captured in both themes since
   2026-08-09, and tools/ux/targets.py measures their controls. The precondition
   the decision named is gone. A decision whose reasoning states its own
   precondition tells you when it stops applying; one that states only a
   conclusion does not.

   The alternative was loading platform.css on catalog pages, which would defeat
   the whole point of the split and put session-shaped CSS on the anonymous
   tree. Duplicating one small component is the cheaper wrong thing.
   -------------------------------------------------------------------------- */
.share {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sp-2) var(--sp-3);
}
.share__label {
  font-family: var(--face-ui); font-size: var(--t-micro);
  letter-spacing: var(--tr-caps); text-transform: uppercase;
  color: var(--c-ink-faint);
}

/* The copy control. Icon-only at rest, so it can sit at the end of a dense tape
   row without taking a column, and it carries its accessible name rather than
   relying on the glyph to be self-evident. */
.share__copy {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-inline-size: 2.75rem; min-block-size: 2.75rem;
  padding-inline: var(--sp-2);
  border: 0; background: none; cursor: pointer;
  color: var(--c-ink-muted);
  font-family: var(--face-ui); font-size: var(--t-micro);
  letter-spacing: var(--tr-caps-snug); text-transform: uppercase;
}
.share__copy:hover { color: var(--c-ink); }
.share__copy svg { inline-size: 1rem; block-size: 1rem; flex: none; }

/* The outcome, printed into the row. `aria-live="polite"` so it is announced
   once rather than on every keystroke, and it is empty until something has
   happened, so it occupies no space on a page nobody has interacted with. */
.share__said {
  font-family: var(--face-ui); font-size: var(--t-micro);
  letter-spacing: var(--tr-caps-snug); text-transform: uppercase;
  color: var(--c-ink-muted);
}
.share__said:empty { display: none; }

/* Destinations. Words, not marks, and the underline is the hover channel so
   nothing depends on hue (law 2). */
.share__to {
  font-family: var(--face-ui); font-size: var(--t-micro);
  letter-spacing: var(--tr-caps-snug); text-transform: uppercase;
  color: var(--c-ink-muted); text-decoration: none;
  display: inline-flex; align-items: center; justify-content: center;
  /* Both axes. The block floor alone left "X" at 8x44, because a one-character
     label is one character wide, and the 44px rule is 44 SQUARE. Caught by
     tools/ux/targets.py rather than by looking, which is the whole reason that
     probe exists. */
  min-block-size: 2.75rem; min-inline-size: 2.75rem;
}
.share__to:hover { color: var(--c-ink); text-decoration: underline; text-underline-offset: 0.14em; }


/* -----------------------------------------------------------------------------
   THE CODE LEGEND
   -----------------------------------------------------------------------------
   The transaction-code chip carried its meaning in a `title` tooltip and in
   screen-reader text only, so a sighted reader on a phone, or anyone not
   hovering, could not find out what "A" meant. The owner asked exactly that.
   A chip whose meaning is reachable by one input method is a chip that does not
   communicate.

   Set as furniture rather than as content: micro type in the UI face, opened by
   a hairline, sitting under the table it explains. It lists only the codes
   present on the page, so on a single-line filing it is one row.
   -------------------------------------------------------------------------- */
.code-legend {
  display: grid; gap: var(--sp-2);
  padding-block-start: var(--sp-3);
  border-block-start: var(--rule-hair);
}
.code-legend__label {
  font-family: var(--face-ui); font-size: var(--t-micro);
  letter-spacing: var(--tr-caps); text-transform: uppercase;
  color: var(--c-ink-faint);
}
/* auto-fit rather than a fixed count: one code on a single-line filing should
   not sit in a four-column grid with three holes in it. */
.code-legend__list {
  display: grid; gap: var(--sp-2) var(--sp-5); margin: 0;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
}
.code-legend__item { display: flex; align-items: baseline; gap: var(--sp-2); min-inline-size: 0; }
.code-legend__item dt { flex: none; }
.code-legend__item dd {
  margin: 0; font-family: var(--face-ui); font-size: var(--t-mini);
  color: var(--c-ink-muted);
}
