/* Arclathe — one stylesheet over the tokens (assets/tokens.css).
   No build. Areas colour themselves from the audience they serve, which comes from content, so
   adding an area is a content change, not a CSS change.

   TWO GROUNDS. The topbar and the footer are the logo's own near-black; the
   reading surface between them is paper. That is not decoration — the mark is
   drawn for a dark canvas and looks wrong on white, while research entries and
   CRM tables are not read on black. Each ground has its own verified text
   colours in tokens.css (--on-dark-* against --ink-deep, --ink-* against
   --paper) and they are not interchangeable. */

* { box-sizing: border-box; }
html, body { margin: 0; }
body {
  background: var(--paper); color: var(--ink);
  font-family: var(--sans); font-size: var(--step-0); line-height: var(--leading-normal);
  display: flex; flex-direction: column; min-height: 100vh;
}

/* A SECTION LOCKS TO THE WINDOW. `min-height` is a floor, so a body holding a
 * long tree grows past the viewport and takes the topbar and the footer with
 * it, which is not what a section is: the chrome and the rail stay put and the
 * workspace scrolls inside them.
 *
 * A height and an overflow, and only when a section is being drawn. Every other
 * page is a document and must scroll normally, which is why this is a class the
 * shell sets rather than a rule on `body`.
 *
 * It also gives `.page-section` a DEFINITE height to be a fraction of. Without
 * one, `.sec { height: 100% }` resolves against a content-sized box and means
 * nothing, which is how a fix for a section 44px too tall turned into a section
 * with no ceiling at all. */
body.is-section { height: 100vh; overflow: hidden; }
a { color: inherit; }
code { font-family: var(--mono); font-size: 0.88em; background: var(--sunk); padding: 1px 5px; border-radius: var(--radius-sm); }

/* ---------- chrome: the brand ground ---------- */
.topbar {
  display: flex; align-items: center; gap: var(--s6);
  padding: 0 var(--s6); height: 64px; flex: none;
  background: var(--ink-deep); color: var(--on-dark);
  border-bottom: 1px solid var(--ink-raise);
  /* the mark hangs out of this box */
  overflow: visible; position: relative; z-index: 3;
}
/* The faint constellation behind the mark in the logo, as a ground rather than
   an image: two soft radial washes, no request, no file to keep in sync. */
.topbar {
  background-image:
    radial-gradient(60ch 20ch at 12% 140%, color-mix(in oklab, var(--brand-500) 14%, transparent), transparent 70%),
    radial-gradient(40ch 16ch at 88% -40%, color-mix(in oklab, var(--brand-300) 10%, transparent), transparent 70%);
}

.wordmark {
  display: flex; align-items: center; gap: var(--s3);
  text-decoration: none;
  /* The name is set in the DISPLAY family and in brand green, so the word
     beside the mark reads as the same object the mark is. It was inheriting
     the body face and painted --on-dark, which made it the one piece of
     branding on the page that came from neither the logo nor the ramp.
     --on-dark-accent is brand.300, the step this system reserves for dark
     grounds, measured at 10.39:1 on surface.ink. */
  font-family: var(--display); color: var(--on-dark-accent);
  font-weight: var(--wordmark-weight); font-size: var(--type-size-lg);
  letter-spacing: var(--wordmark-tracking); text-transform: uppercase;
}
.wordmark img {
  width: var(--chrome-mark-size); height: var(--chrome-mark-size); display: block;
  /* WHICH MARK is the brand's to say: `normal` draws the src, a url() draws
     that brand's own (the site system's violet A). Contained, because the A
     is 30x28 and the box is square. */
  content: var(--chrome-mark-image, normal); object-fit: contain;
  /* Hangs past the bottom edge. `position: relative` gives it a stacking
     context so it sits OVER the content it now overlaps rather than under it. */
  position: relative; top: var(--chrome-mark-drop); z-index: 2;
  filter: var(--chrome-mark-glow);
}
.wordmark .division {
  font-size: 11px; font-weight: var(--type-weight-bold); letter-spacing: var(--tagline-tracking);
  color: var(--on-dark-muted); align-self: center; padding-top: var(--space-0-5);
}
.wordmark:hover .division { color: var(--on-dark-accent); }

.nav { display: flex; gap: var(--s5); }
.nav a {
  text-decoration: none; color: var(--on-dark-muted); font-size: 15px; font-weight: var(--type-weight-medium);
  padding: var(--s1) 0; border-bottom: 2px solid transparent;
}
.nav a:hover { color: var(--on-dark); border-bottom-color: var(--brand-500); }
.nav a:active { color: var(--on-dark-accent); }
.nav-lock { color: var(--on-dark-faint); margin-left: var(--s1); }
.account { margin-left: auto; display: flex; align-items: center; gap: var(--s4); font-size: 14px; }
.who { color: var(--on-dark-muted); }

/* Every value here comes from control.button in the design system. It used to
   restate them — 9px 16px, radius 8px, size 14px — which meant a theme could
   change the button token and the site would go on drawing the old one. */
.btn {
  display: inline-block; text-decoration: none;
  /* A <button> does not inherit the page's face — the user-agent stylesheet
     sets its own, and every `<button class="btn">` on this site was rendering
     in Arial while every `<a class="btn">` rendered in Inter. Two typefaces on
     one row of buttons, and nobody could see why. */
  font-family: inherit;
  /* And a <button> keeps the user-agent's `2px outset black` border unless it
     is told otherwise. The fill hid it, so nothing looked wrong; every button
     on the site was wearing a two-pixel black ring under its own background. */
  border: none;
  background: var(--control-button-rest-bg); color: var(--control-button-rest-fg);
  padding: var(--control-button-pad-y) var(--control-button-pad-x);
  border-radius: var(--control-button-radius);
  font-size: var(--control-button-size); font-weight: var(--control-button-weight);
  /* AND A BUTTON IS A POINTER TARGET. A <button> gets `cursor: default` from the
     user agent, so every `.btn` on this platform has been drawing the ordinary
     arrow -- found by adopting this class for the CRM's delete press, which had
     `cursor: pointer` of its own and lost it. An `<a class="btn">` had one all
     along, from the link default, so a row of a link and a button next to each
     other behaved two ways. st-3w28p3a7. */
  cursor: pointer;
}
.btn:hover { background: var(--control-button-hover-bg); }
.btn:active { background: var(--control-button-active-bg); transform: translateY(1px); }
.btn-quiet {
  background: transparent; color: var(--control-button-quiet-fg);
  border: 1px solid var(--control-button-quiet-border);
}
.btn-quiet:hover { background: var(--sunk); color: var(--ink); }
/* A PRESS WITH NOTHING TO DO RIGHT NOW: opacity.dim, and the pointer passes
   through. For a LINK drawn as a press -- a real button says [disabled]. The
   CRM's "Clear all" with no filter on wore this as .crm-filter-foot .is-off.
   st-3w28p3a7, de-q39nyx8t. */
.btn.is-off { opacity: var(--opacity-dim); pointer-events: none; }

/* On the dark chrome a quiet button has to borrow the dark ground's palette,
   or it renders as invisible grey-on-black. */
.topbar .btn-quiet { color: var(--on-dark-muted); border-color: var(--ink-raise); }
.topbar .btn-quiet:hover { background: color-mix(in oklab, var(--on-dark) 8%, transparent); color: var(--on-dark); }
.topbar .btn { background: var(--brand-500); color: var(--ink-deep); }
.topbar .btn:hover { background: var(--brand-400); }

main { flex: 1; width: 100%; max-width: 860px; margin: 0 auto; padding: 56px 28px 72px; }
main.wide { max-width: 1180px; }

.footer {
  flex: none; display: flex; gap: var(--s5); align-items: center;
  padding: 0 var(--s6); height: 56px;
  border-top: 1px solid var(--ink-raise); background: var(--ink-deep);
  font-size: var(--type-size-sm); color: var(--on-dark-faint);
}
.footer-host { margin-left: auto; font-family: var(--mono); }
.footer a { color: var(--on-dark-muted); }

/* ---------- a mounted module's workspace ----------
   Atlas draws its own workspace; the page around it is the host's. These rules
   are the seam: enough to place the module's head and tabs on our page, and no
   opinion about anything inside the mount point. */
.atlas-module-head {
  display: flex; align-items: flex-end; gap: var(--s6); flex-wrap: wrap;
  margin-bottom: var(--s5);
}
.atlas-module-title {
  font-size: var(--step-3); margin: 0;
  font-weight: var(--wordmark-weight); letter-spacing: var(--type-tracking-wide);
}
/* The attribution rides the heading rather than sitting under it: at this size
   a second line would read as a subtitle competing with the lede below. */
.atlas-module-by {
  font-size: var(--step--1); font-weight: var(--type-weight-semibold); letter-spacing: 0.1em;
  color: var(--ink-faint); text-transform: none;
  margin-left: var(--s1);
}
.atlas-module-lede { color: var(--ink-muted); margin: var(--s1) 0 0; max-width: var(--measure); }
.atlas-module-actions { margin-left: auto; display: flex; align-items: center; gap: var(--s3); }
.atlas-module .explorer-mount { margin-top: var(--s5); }

/* Four columns need more room than a reading measure — but NOT unlimited. The
   explorer caps its own view at 1280px and centres it, so a full-width page
   leaves a gap after the rail and pushes the last column off the screen. The
   page is sized to hold the rail plus that view, and no wider. */
/* The explorer was built to own a viewport: a rail on the left and a canvas
   that fills what is left. Inside the page's reading column it has neither, so
   the module goes FULL BLEED — the same geometry it has standalone — while the
   page furniture above it stays in the column where it belongs.

   `width: 100vw` with a negative half-viewport margin is the standard escape.
   `overflow-x: clip` on the page stops the extra width becoming a sideways
   scrollbar on narrow windows. */
main:has(.atlas-module) { max-width: none; padding-left: 0; padding-right: 0; }
/* The work workspace is two panes side by side; at 1180px the rail squeezes the
   document into a column narrower than the prose it holds. Same seam as atlas:
   the HOST widens the page for a module it knows about, rather than the module
   reaching out of its own box with negative margins. */
main:has(.gb) { max-width: 1560px; }
.atlas-module > .atlas-module-head,
.atlas-module > .atlas-module-tabs {
  max-width: 1180px; margin-inline: auto; padding-inline: var(--s6);
}
.atlas-module > .explorer-mount {
  width: 100vw; margin-left: calc(50% - 50vw);
  /* The board is as wide as its columns need. Scroll it rather than clipping —
     `overflow-x: clip` here cut the last column off entirely, which looks like
     a missing column rather than a narrow window. */
  overflow-x: auto;
}

.atlas-module-label { color: var(--ink-faint); font-size: var(--step--1); }
.atlas-module-stamp { color: var(--ink-faint); font-size: var(--step--1); font-family: var(--mono); }
.atlas-module-picker {
  font: inherit; font-family: var(--mono); font-size: var(--step--1);
  color: var(--ink); background: var(--card);
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  padding: var(--s1) var(--s2);
}
.atlas-module-picker:focus-visible { outline: 2px solid var(--brand-500); outline-offset: 1px; }

.atlas-module-tabs { display: flex; gap: var(--s1); border-bottom: 1px solid var(--line); }
.atlas-module-tabs .tab {
  background: none; border: none; cursor: pointer;
  padding: var(--s3) var(--s4);
  font: inherit; font-size: var(--step--1); font-weight: var(--type-weight-semibold);
  color: var(--ink-muted);
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.atlas-module-tabs .tab:hover { color: var(--ink); }
.atlas-module-tabs .tab[aria-selected="true"] { color: var(--brand-700); border-bottom-color: var(--brand-500); }

/* ---------- a gated entry's header ----------
   The mark sits ABOVE the title rather than beside it: at 44px next to a 44px
   heading it would compete, and the point of decoration is to be recognised
   without being read. */
.hero-entry .entry-mark {
  display: block; width: 44px; height: 44px;
  content: var(--chrome-mark-image, normal); object-fit: contain;
  margin: 0 0 var(--s4);
  /* This ground is paper, not chrome, so the mark needs no glow — it is
     navy-on-blue and already has its own contrast here. */
}

/* ---------- sections ---------- */
.hero h1 { font-size: 44px; line-height: 1.1; letter-spacing: var(--type-tracking-tighter); margin: 0 0 var(--s3); }
.hero-sub { font-size: 19px; color: var(--ink-muted); margin: 0 0 var(--s2); max-width: var(--measure); }
.prose { margin-top: 44px; }
.prose h2 { font-size: 22px; letter-spacing: var(--type-tracking-tight); margin: 0 0 var(--s2); }
.prose p { color: var(--ink-muted); margin: 0; max-width: var(--measure); }
/* Paragraphs of one section are apart: a section of three read as one block. */
.prose p + p { margin-top: var(--s3); }
.unknown-kind p { color: var(--warn); background: var(--warn-bg); padding: 12px 14px; border-radius: 8px; }
.areas { margin-top: var(--space-14); }

/* ---------- the area badges ----------
   A card's colour says WHO THE AREA IS FOR: anyone, partners, customers, or
   employees only. The four grounds and the argument for them live in the
   design system under `audience.*`, measured; the level itself is declared in
   content, because which audience an area serves is a fact about the area and
   not a fact about a stylesheet.

   This used to be a hue number per area and a gradient computed from it. That
   put a colour decision in content, where nothing could check it, and the
   numbers were a violet-indigo-blue sweep chosen when the brand was hue 198.
   A card with no level named falls back to `anyone`, which is the most open
   and therefore the safest thing to look like if the declaration is missing. */
.badge-grid { display: grid; gap: var(--s5); grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.aud-anyone    { --badge-from: var(--audience-anyone-from);    --badge-to: var(--audience-anyone-to); }
.aud-partners  { --badge-from: var(--audience-partners-from);  --badge-to: var(--audience-partners-to); }
.aud-customers { --badge-from: var(--audience-customers-from); --badge-to: var(--audience-customers-to); }
.aud-employees { --badge-from: var(--audience-employees-from); --badge-to: var(--audience-employees-to); }
.badge {
  display: block; text-decoration: none;
  background: linear-gradient(160deg,
    var(--badge-from, var(--audience-anyone-from)) 0%,
    var(--badge-to, var(--audience-anyone-to)) 100%);
  color: var(--ink-invert);
  border-radius: var(--radius);
  padding: 26px 24px 22px;
  box-shadow: var(--elevation-raised);
  position: relative; overflow: hidden;
  transition: transform 120ms ease, box-shadow 120ms ease;
}
.badge::after {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(120% 90% at 88% 0%, color-mix(in oklab, var(--on-dark) 12%, transparent), transparent 60%);
  pointer-events: none;
}
a.badge:hover { transform: translateY(-2px); box-shadow: 0 2px 4px color-mix(in oklab, var(--ink-deep) 8%, transparent), 0 14px 34px color-mix(in oklab, var(--ink-deep) 12%, transparent); }
a.badge:active { transform: translateY(0); }

.badge-name {
  display: inline-block;
  font-family: var(--mono); font-size: var(--type-size-xs); font-weight: var(--type-weight-bold);
  letter-spacing: 0.16em;
  background: color-mix(in oklab, var(--ink-deep) 22%, transparent);
  padding: 5px 11px; border-radius: var(--radius-pill);
  margin-bottom: 14px;
}
.badge-title { display: block; font-size: 26px; font-weight: var(--type-weight-bold); letter-spacing: -0.02em; line-height: 1.15; }
.badge-desc { margin: 10px 0 16px; font-size: 15px; line-height: 1.5; color: color-mix(in oklab, var(--on-dark) 92%, transparent); }
.badge-lock, .badge-open {
  display: inline-block; font-size: var(--type-size-xs); font-weight: var(--type-weight-semibold);
  padding: 4px 10px; border-radius: var(--radius-pill);
  background: color-mix(in oklab, var(--ink-deep) 20%, transparent); color: color-mix(in oklab, var(--on-dark) 94%, transparent);
}
.badge-open { background: color-mix(in oklab, var(--on-dark) 22%, transparent); }

.badge-xl { padding: 40px 34px 34px; }
.badge-xl .badge-title { font-size: 40px; }
.badge-xl .badge-desc { font-size: 17px; max-width: 64ch; }
.badge-xl .badge-name { font-size: var(--type-size-sm); }

/* ---------- content sections ----------
   st-dwxe6rh9. Ben: "rather than the grid of tools areas, let's create a site
   section with Left or right image, background gradient, heading, badge, and
   description for each". One band per area, down the page, on the same
   audience grounds the cards used -- `aud-*` above sets --badge-from/--badge-to
   on the section exactly as it did on a card -- with the art alternating sides
   so the eye zig-zags rather than reading four identical rows.

   Every colour and space is a token. The art is white line work drawn for this
   ground (public/assets/areas/*.svg); it is sized here and nowhere else. */
.content-section {
  display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  align-items: center; gap: var(--s8);
  margin-top: var(--s6);
  padding: var(--s8) var(--s10);
  border-radius: var(--radius-xl);
  background: linear-gradient(135deg,
    var(--badge-from, var(--audience-anyone-from)) 0%,
    var(--badge-to, var(--audience-anyone-to)) 100%);
  color: var(--ink-invert);
  box-shadow: var(--elevation-raised);
  position: relative; overflow: hidden;
}
.content-section::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 90% at 88% 0%, color-mix(in oklab, var(--on-dark) 12%, transparent), transparent 60%);
}
.content-section:first-of-type { margin-top: var(--s10); }
.content-section[data-side="right"] { grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); }
.content-section[data-side="right"] .content-section-art { order: 2; }
.content-section-art { display: flex; justify-content: center; position: relative; z-index: 1; }
.content-section-image { display: block; width: 100%; max-width: 280px; height: auto; opacity: 0.92; }
.content-section-body { position: relative; z-index: 1; }
.content-section-body h2 {
  margin: var(--s3) 0 0; font-size: var(--step-3); font-weight: var(--type-weight-bold);
  letter-spacing: -0.02em; line-height: 1.15;
  /* THE BAND'S OWN INK, said rather than inherited: a page's heading rule
     painted it muted, 1.12:1 on the platform's band (st-wbcm6161). */
  color: var(--ink-invert);
}
.content-section-body p {
  margin: var(--s3) 0 var(--s5); font-size: var(--step-0); line-height: 1.55;
  max-width: var(--measure); color: color-mix(in oklab, var(--on-dark) 92%, transparent);
}
.content-section-foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s4); }
.content-section-link {
  color: var(--ink-invert); font-weight: var(--type-weight-semibold); text-decoration: none;
  border-bottom: 1px solid color-mix(in oklab, var(--on-dark) 45%, transparent);
}
.content-section-link:hover { border-bottom-color: var(--ink-invert); }
.content-section-link::after { content: " \2192"; }
@media (max-width: 760px) {
  .content-section, .content-section[data-side="right"] {
    grid-template-columns: minmax(0, 1fr); padding: var(--s6);
  }
  .content-section[data-side="right"] .content-section-art { order: 0; }
  .content-section-image { max-width: 180px; }
}

/* ---------- the chip, which is also the badge, on a band's dark ground ----------
   One pill. Ben: "Badge and Chip should be the same component largely ... so
   the similarity is real not convention." `shared.ChipControl` draws the
   design system's own `.chip` -- the `control.chip` construct further down this
   file -- so a badge IS that chip, not a second pill that looks like it. The
   old card's .badge-name, .badge-lock and .badge-open were three hand-written
   versions of it.

   `control.chip` is a light pill for paper. On a band's gradient it is
   RE-GROUNDED here, the way `.topbar .btn-quiet` re-grounds the quiet button
   for the dark chrome: the same construct, read on a different ground. The
   tone says which pill it is -- `name` for what the area is called, `lock` and
   `open` for whether a reader can go in. */
.content-section .chip {
  border-color: transparent;
  background: color-mix(in oklab, var(--ink-deep) 20%, transparent);
  color: color-mix(in oklab, var(--on-dark) 94%, transparent);
  font-weight: var(--type-weight-semibold);
}
.content-section .chip[data-tone="name"] {
  font-weight: var(--type-weight-bold); letter-spacing: 0.16em;
  background: color-mix(in oklab, var(--ink-deep) 26%, transparent);
}
.content-section .chip[data-tone="open"] { background: color-mix(in oklab, var(--on-dark) 22%, transparent); }

/* ---------- the marketing prototype's grounds and reveal ----------
   st-30gf6mrr. The bar (plan/ui-quality/bar/arclathe-site.dc.html) stands its
   hero on a dark field with a violet glow in one corner, lays faint circuit
   traces under its bands, and fades every block up as it arrives. Those are
   three grounds and one entrance, and each is a PARAMETER of the shared hero
   and section (`data-ground`, `data-reveal`), never a layout of its own:
     gradient  the audience gradient a band already had (the default above)
     grid      the deep ground with hairline traces, drawn as a grid
     glow      the deep ground with the brand glow in its top corner
     none      no band at all: a reading section, `section.prose`
   Every colour, space and time is a token. */
.hero[data-ground="grid"], .hero[data-ground="glow"],
.content-section[data-ground="grid"], .content-section[data-ground="glow"] {
  background-color: var(--ink-deep);
  color: var(--ink-invert);
}
.hero[data-ground="grid"], .content-section[data-ground="grid"] {
  background-image:
    linear-gradient(color-mix(in oklab, var(--brand-500) 14%, transparent) 1px, transparent 1px),
    linear-gradient(90deg, color-mix(in oklab, var(--brand-500) 14%, transparent) 1px, transparent 1px),
    radial-gradient(120% 90% at 100% 0%, color-mix(in oklab, var(--brand-500) 22%, transparent), transparent 60%);
  background-size: var(--s12) var(--s12), var(--s12) var(--s12), auto;
}
.hero[data-ground="glow"], .content-section[data-ground="glow"] {
  background-image:
    radial-gradient(70% 90% at 90% 0%, color-mix(in oklab, var(--brand-500) 30%, transparent), transparent 70%);
}
/* A band on a deep ground draws no second glow over the first. */
.content-section[data-ground="grid"]::after, .content-section[data-ground="glow"]::after { content: none; }
/* A hero on a ground is a panel, the width of the column and the bands under
   it: the brand panel's full-bleed margins were invisible on the page's own ink
   and read as an offset box once it had a glow. */
.hero[data-ground="grid"], .hero[data-ground="glow"] {
  padding: var(--s10) var(--s8);
  border-radius: var(--radius-xl);
  margin: 0 0 var(--s6);
}
.hero[data-ground] + .content-section { margin-top: var(--s6); }
.hero[data-ground="grid"] h1, .hero[data-ground="glow"] h1 { color: var(--ink-invert); }
.hero[data-ground="grid"] .hero-sub, .hero[data-ground="glow"] .hero-sub { color: var(--on-dark-muted); font-size: var(--step-1); }
@media (max-width: 760px) {
  .hero[data-ground="grid"], .hero[data-ground="glow"] { padding: var(--s8) var(--s5); }
}
/* The eyebrow over a hero's heading: the chip, set in the mono face. */
.hero .hero-eyebrow {
  font-family: var(--mono); letter-spacing: var(--type-tracking-wider);
  margin-bottom: var(--s4);
}
.hero[data-ground="grid"] .hero-eyebrow, .hero[data-ground="glow"] .hero-eyebrow {
  border-color: color-mix(in oklab, var(--brand-300) 45%, transparent);
  background: color-mix(in oklab, var(--brand-500) 18%, transparent);
  color: var(--on-dark-accent);
}
/* The ways in, under the line. */
.hero-actions { display: flex; flex-wrap: wrap; gap: var(--s3); margin-top: var(--s5); }
/* On a deep ground the quiet way in is re-grounded the way the topbar's is. */
.hero[data-ground="grid"] .btn-quiet, .hero[data-ground="glow"] .btn-quiet {
  color: var(--on-dark); border-color: color-mix(in oklab, var(--on-dark) 35%, transparent);
}
.hero[data-ground="grid"] .btn-quiet:hover, .hero[data-ground="glow"] .btn-quiet:hover {
  background: color-mix(in oklab, var(--on-dark) 8%, transparent); color: var(--on-dark);
}
.hero-brand .hero-actions { justify-content: center; }
/* A citation: one link per line, its note under it. */
.prose a.cite {
  display: block; padding: var(--s2) 0; border-bottom: 1px solid var(--line);
  max-width: var(--measure);
  color: var(--brand-600); text-decoration: none; font-weight: var(--type-weight-medium);
}
.prose a.cite:hover { text-decoration: underline; }
.prose a.cite:active { color: var(--brand-700); }
.prose a.cite .link-note { font-weight: var(--type-weight-regular); }

/* THE REVEAL: up from below and in, on `motion.reveal` (800ms) and
   `ease.enter` (the prototype's cubic-bezier(.2,.7,.3,1)). A CSS animation and
   not an observer, because this site sends no script; `both` holds the first
   frame until it starts, so nothing flashes in at full ink first. */
@keyframes arc-reveal {
  from { opacity: 0; transform: translateY(var(--s5)); }
  to { opacity: 1; transform: none; }
}
[data-reveal] { animation: arc-reveal var(--motion-reveal) var(--ease-enter) both; }
/* A reader who asked for less motion gets none: the block is simply there. */
@media (prefers-reduced-motion: reduce) {
  [data-reveal] { animation: none; }
}

/* ---------- area index ---------- */
.entries { margin-top: 44px; }
.entries h2 { font-size: 22px; margin: 0 0 var(--s5); }
.entry-grid { display: grid; gap: var(--s4); grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.entry {
  display: block; text-decoration: none;
  background: var(--card); border: 1px solid var(--line-strong);
  border-radius: 12px; padding: var(--s5);
  transition: border-color 120ms ease, transform 120ms ease;
}
.entry:hover { border-color: var(--ink-faint); transform: translateY(-1px); }
.entry:active { transform: translateY(0); }
.entry h3 { margin: 0 0 var(--space-1-5); font-size: 17px; }
.entry p { margin: 0 0 var(--s3); color: var(--ink-muted); font-size: 15px; }
.entry code { font-size: var(--type-size-xs); color: var(--ink-faint); background: var(--sunk); }
.empty { color: var(--ink-muted); background: var(--card); border: 1px dashed var(--line-strong); border-radius: 12px; padding: 22px; }

/* ---------- stub panels ---------- */
/* panel.* in the design system, which is the construct this class IS. */
/* ---------- the surface, and the panel built on it ----------

   st-3w28p3a7. FOUR boxes in two other consoles painted the same three
   declarations a panel does -- gabriela's document tray, parkour's backlog and
   its sprint header, and gabriela's work grid -- and NONE of them wanted a
   panel's inset or its air: the tray is sticky at the top of a column, the
   sprint is a <header> in a flex row, and the grid holds rows that carry their
   own padding. `.panel` imposes `padding: 20px 24px` and `margin-top: 24px`, so
   wearing it would have been three overrides each.

   SO THE SURFACE IS NAMED ON ITS OWN and a panel is the surface plus the inset
   and the air. Same tokens, one declaration: minting `component.surface.bg` as a
   second name for `panel.bg` is the three-names-for-one-shadow mistake
   `component.popover` was promoted to fix. */

.surface, .panel {
  background: var(--panel-bg); border: 1px solid var(--panel-border);
  border-radius: var(--panel-radius);
}
.panel {
  padding: var(--panel-pad-y) var(--panel-pad-x);
  margin-top: var(--s6);
}

/* ---------- component.meter: a proportion of a whole, as a bar ----------

   component.rating's own comment named this gap and left it: "component.meter is
   the proportional one's when somebody builds it." Two consoles had it and the
   TRACK is identical -- gabriela's progress bar beside a number, parkour's under
   a column of work, both sinking the ground and rounding it to a pill. What
   differs is the HEIGHT, 5px and 7px, and the length, both of which are the
   caller's.

   NOT A RATING, which is the distinction that decides whether this is one
   construct or two: a rating is a COUNT out of a fixed scale where a reader
   counts the segments, and this is a proportion where the only thing to read is
   how far along it is.

   A SEGMENTED FILL STAYS WITH THE CALLER. parkour draws done, active and todo as
   three parts of one track, and those are semantic status colours rather than a
   meter's. */

.meter {
  background: var(--component-meter-track-bg);
  border-radius: var(--component-meter-radius);
  overflow: hidden;
}
.meter > i, .meter > span { display: block; height: 100%; }
.panel h3 {
  margin: 0 0 var(--panel-header-gap); font-size: var(--panel-header-size);
  font-weight: var(--panel-header-weight); color: var(--panel-header-fg);
}
.panel dl { display: grid; grid-template-columns: max-content 1fr; gap: var(--s2) var(--s5); margin: 0; font-size: 15px; }
.panel dt { color: var(--ink-faint); }
.panel dd { margin: 0; font-family: var(--mono); font-size: 14px; min-width: 0; overflow-wrap: anywhere; }
/* A RECORD'S FACTS ARE PROSE. The mono face above is right for the stub panels
   it was written for and wrong for a record: a firm's name and a deal's title
   set in monospace read as a config dump. A value that IS a token -- an id --
   keeps the mono face, one step small. The CRM wrote this as .crm-dl; its other
   declarations (13px, a wider gap, the term's ink) were out-specified by the
   rules above and never painted, measured, so they are gone rather than moved.
   st-3w28p3a7, de-6q00090a. */
.panel dl.is-prose dd { font-family: inherit; }
.panel dl.is-prose dd code { font-family: var(--mono); font-size: var(--type-size-xs); }

@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }

/* ---------- tables of contents ----------
   Two kinds: the reading list for an area, and the in-page jump list for one
   piece. Both are navigation, so both are numbered and neither competes with
   the prose for weight. */
.toc {
  background: var(--card);
  border: 1px solid var(--line-strong);
  border-left: 3px solid var(--brand-500);
  border-radius: var(--radius);
  padding: var(--s5) var(--s6);
  margin: var(--s8) 0;
  max-width: var(--measure);
}
.toc-label {
  margin: 0 0 var(--s3);
  font-size: var(--step--1);
  font-weight: var(--type-weight-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.toc ol { margin: 0; padding-left: var(--s5); }
.toc li { margin: var(--s2) 0; }
.toc a { color: var(--brand-600); text-decoration: none; font-weight: var(--type-weight-medium); }
.toc a:hover { text-decoration: underline; }
.toc a:active { color: var(--brand-700); }
.toc-area li { margin: var(--s4) 0; }
.toc-sum { display: block; color: var(--ink-muted); font-size: var(--step--1); margin-top: var(--space-0-5); }

/* ---------- data tables ---------- */
.table-wrap { overflow-x: auto; margin: var(--s4) 0; }
table.data { border-collapse: collapse; width: 100%; font-size: var(--step--1); min-width: 520px; }
table.data th {
  text-align: left; padding: var(--s2) var(--s4) var(--s2) 0;
  border-bottom: 2px solid var(--brand-500);
  font-weight: var(--type-weight-semibold); color: var(--ink);
  white-space: nowrap;
}
table.data td { padding: var(--s2) var(--s4) var(--s2) 0; border-bottom: 1px solid var(--line); vertical-align: top; color: var(--ink-muted); }
table.data td:first-child { color: var(--ink); font-weight: var(--type-weight-medium); white-space: nowrap; }

/* prose sections are anchor targets now — keep the heading clear of the topbar */
.prose[id] { scroll-margin-top: var(--s8); }

/* ---------- citation lists ---------- */
ul.links { list-style: none; margin: var(--s4) 0 0; padding: 0; max-width: var(--measure); }
ul.links li { padding: var(--s2) 0; border-bottom: 1px solid var(--line); }
ul.links a { color: var(--brand-600); text-decoration: none; font-weight: var(--type-weight-medium); }
ul.links a:hover { text-decoration: underline; }
ul.links a:active { color: var(--brand-700); }
.link-note { display: block; color: var(--ink-faint); font-size: var(--step--1); margin-top: var(--space-0-5); }

/* ---------- the brand lockup ----------
   The full drawn mark. Used once, at the top of the public home page: it is the
   one place with room for the illustration, and repeating it would spend the
   impact it has by being rare.

   The asset is a PNG with a real alpha channel, so it sits on any ground. The
   panel behind it stays dark anyway — the artwork's outlines and its glow were
   drawn for a dark canvas and it is simply strongest there — but that is now a
   choice rather than a constraint the file imposes. */
.hero-brand {
  margin: calc(var(--s12) * -1) calc(var(--s6) * -1) var(--s10);
  padding: var(--s8) var(--s6) var(--s10);
  background: var(--ink-deep);
  border-radius: 0 0 var(--radius-xl) var(--radius-xl);
  text-align: center;
}
.hero-brand .emblem {
  display: block; width: 100%; max-width: var(--chrome-emblem-size, 300px); height: auto;
  content: var(--chrome-mark-image, normal);
  margin: 0 auto var(--s5);
}
/* The name, set rather than drawn. Tracked and uppercased to match the
   wordmark in the bar, so the two readings of the same word agree. Its size is
   capped in ch rather than px: this is one word, and a viewport-scaled heading
   that outgrows the emblem above it inverts the hierarchy. */
.hero-brand h1 {
  color: var(--on-dark-accent);
  font-family: var(--display);
  font-weight: var(--wordmark-weight); text-transform: uppercase;
  letter-spacing: var(--type-tracking-wider); font-size: clamp(32px, 7vw, 52px);
  margin: 0 0 var(--s4);
  /* Uppercase tracking adds a trailing gap after the last letter that optical
     centring has to pay back, or the word sits visibly right of the emblem. */
  text-indent: 0.14em;
}
.hero-brand .hero-sub {
  font-size: var(--step-1); max-width: 46ch;
  color: var(--on-dark-muted); margin-left: auto; margin-right: auto;
}

/* ---------- the section shell ------------------------------------------------
 *
 * `ui-architecture` defines the construct and `sectionShell()` emits its
 * structure; this is the only place that says how wide the rail is or what
 * colour it sits on. The markup carries no appearance at all, which is what
 * lets a theme move the rail without anybody editing a renderer.
 *
 * No media queries, deliberately. D5 of `review/section-shells` decided against
 * a responsive collapse this round: these are operator tools used at a desk,
 * and the phone layout is a named limitation rather than an oversight.
 */

/* The section FILLS what the page leaves it, and is told so by the layout
 * rather than by arithmetic. `body` is already a flex column with the topbar
 * and the footer both `flex: none`, so claiming the remainder is one line and
 * it is right at every viewport. */
.page-section { display: block; flex: 1 1 auto; min-height: 0; }

.sec {
  display: grid;
  grid-template-columns: var(--sec-rail-width, 260px) minmax(0, 1fr);
  /* THE SUBNAV GETS ITS OWN ROW, beside the rail rather than inside the
   * workspace. It was the workspace's first child, and the workspace is the box
   * a page's width narrows — so the CRM drew the same six tabs 1180px wide and
   * centred on five pages, and 1448px wide and flush against the rail on the
   * pipeline, which is the one page asking for `full`. The strip moved 134px
   * sideways when you clicked a tab in it.
   *
   * `rail` is named in both lower rows, so it spans them; without that the
   * strip would cut it in half at the top. */
  grid-template-areas: "chrome chrome" "rail tabs" "rail workspace";
  /* FILL, not a minimum. A full-width application inside the workspace has to
   * be able to reach the bottom of the frame: with `min-height` and
   * `align-items: start` it sat at its content height and left the ground
   * showing under its own footer. */
  /* 100% of the slot, NOT 100vh minus a guess. `--chrome-height` was 64px and
   * the real chrome is the topbar AND the footer, so the section came out 44px
   * taller than the space it had and `.page-section`'s overflow:hidden ate the
   * bottom of the rail and the workspace. A number that has to be kept in
   * agreement with two other elements is a number that will stop agreeing. */
  height: 100%;
  /* Chrome, then the subnav, then everything that is left. The tabs row is
   * `auto`, so a section with no tabs contributes no row height and the
   * workspace starts where it always did. */
  grid-template-rows: auto auto minmax(0, 1fr);
  align-items: stretch;
}
/* Only the workspace scrolls. The rail and the chrome stay put, which is what
 * makes a long table feel like a pane rather than a page. */
.page-section { overflow: hidden; }

.sec-chrome {
  grid-area: chrome;
  display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
  padding: var(--s4) var(--s6);
  /* `--line-strong`, not `--line`. Measured at APCA Lc 9 against the card it
   * sits on, which is below the Lc 15 floor where a rule stops being visible at
   * all: a divider nobody can see is dead weight, and this one separates the
   * section's name from its content. */
  border-bottom: 1px solid var(--line-strong);
  background: var(--card);
}
.sec-title {
  font-weight: var(--type-weight-bold); letter-spacing: var(--type-tracking-tight); color: var(--ink);
  text-decoration: none; font-size: var(--step-0);
}
a.sec-title:hover { color: var(--brand-600); }
.sec-chrome-aside { color: var(--ink-muted); font-size: var(--step--1); }

.sec-rail {
  grid-area: rail;
  display: flex; flex-direction: column; gap: var(--s1);
  padding: var(--s4) var(--s3);
  /* `--sunk`, not `--ink-panel`. The ink- family is the DARK ground, and
   * `--ink-panel` is "one step up, for panels on the deep ground": using it
   * here painted a black rail beside a white workspace. `--sunk` is the
   * recessed light surface, which is what a rail beside content is. */
  /* `--line-strong` for the same reason the chrome uses it: measured at APCA
    * Lc 10 against the sunk ground, under the Lc 15 floor where a rule stops
    * being visible. This one is the whole boundary between navigation and
    * content. */
  border-right: 1px solid var(--line-strong);
  background: var(--sunk);
  overflow-y: auto;
}

.sec-rail-row {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s2) var(--s3);
  border-radius: var(--radius-sm);
  color: var(--ink-muted); text-decoration: none;
  font-size: var(--step--1); line-height: 1.3;
  /* A rail row is a target, and 36px is the smallest one worth aiming at with
   * a trackpad. The button token's 44px is for a primary action. */
  min-height: 36px;
  transition: background var(--motion-fast) var(--ease), color var(--motion-fast) var(--ease);
}
.sec-rail-row:hover { background: var(--card); color: var(--ink); }
.sec-rail-row.is-current {
  background: var(--card); color: var(--ink); font-weight: var(--type-weight-semibold);
  /* The marker is on the inline start edge rather than a background change
   * alone: current-ness should survive a theme that flattens the surfaces. */
  box-shadow: var(--section-rail-marker);
}

.sec-rail-icon {
  flex: 0 0 20px; width: 20px; height: 20px;
  display: grid; place-items: center;
  color: currentColor; opacity: 0.85;
}
.sec-rail-row.is-current .sec-rail-icon { opacity: 1; }
/* A tool's own artwork, painted in the row's ink: the svg is the mask and
   currentColor is the paint, so the icon follows the row in either system. */
.sec-rail-art {
  /* Each row names its own artwork inline; none is the honest default. */
  --rail-art: none;
  background-color: currentColor;
  -webkit-mask: var(--rail-art) center / 20px 20px no-repeat;
  mask: var(--rail-art) center / 20px 20px no-repeat;
}
.sec-rail-child .sec-rail-art { -webkit-mask-size: 15px 15px; mask-size: 15px 15px; }
.sec-rail-mono {
  font-size: 11px; font-weight: var(--type-weight-bold); letter-spacing: var(--type-tracking-slight);
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  color: var(--ink-muted);
  /* A LETTER IS TEXT, SO IT IS NOT DIMMED (st-wbcm6161). The icon's 0.85 is for
     artwork; on a monogram it turned the gallery's good-tone brand.600 (5.2:1 on
     the rail's ground) into 3.79:1, which was every one of RailComponent's 236
     measured contrast faults. */
  opacity: 1;
}
.sec-rail-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.sec-workspace {
  grid-area: workspace;
  /* CLEARS THE DOCUMENT'S OWN `main` RULE, which is `margin: 0 auto`. This
   * element is a `<main>`, so it was inheriting those auto margins, and an auto
   * margin absorbs the free space BEFORE `justify-self` is looked at — so the
   * workspace sat centred in its column no matter what the width classes below
   * said about alignment. That is why a wide page's content began 134px to the
   * right of the tab it was reached from while the strip above it started at
   * the rail. */
  margin: 0;
  padding: var(--s6);
  min-width: 0;   /* a grid child that can shrink, or a wide table pushes the rail off */
  /* A COLUMN, so a page that wants the full height can have the height that is
   * actually left. `height: 100%` on the page inside a BLOCK workspace measures
   * the whole workspace and ignores the tab strip above it, which put exactly
   * the strip's height of content under the footer. Nothing stretches by
   * default — flex items are `0 1 auto` — so every ordinary page is unchanged
   * and only a page that asks for `flex: 1` gets the remainder. */
  display: flex; flex-direction: column;
  /* Wide content scrolls INSIDE the workspace, and so does long content. The
   * Everything table is wider than any column it will be given; without this it
   * pushed its own last column off the screen instead of offering a scrollbar. */
  overflow: auto;
}

/* The three widths, and no more. A fourth would be a width per screen, which is
 * how a layout stops being predictable.
 *
 * EACH ONE STATES ITS ALIGNMENT, because a grid item that cannot stretch is
 * centred and `wide` never asked to be. It set a max-width and said nothing
 * else, so a wide page's content sat 134px to the right of the tab it was
 * reached from while the strip above it started at the rail. `reading` was
 * always centred on purpose — it said `margin-inline: auto` out loud, which is
 * how we know the silence on `wide` was an omission rather than a choice. Both
 * say it the same way now. */
.sec-w-reading .sec-workspace { max-width: var(--measure); justify-self: center; }
.sec-w-wide .sec-workspace    { max-width: 1180px; justify-self: start; }
.sec-w-full .sec-workspace    { max-width: none; }

/* THE ONE WAY OUT OF THE GUTTER, declared per tool rather than implied by the
 * width. Only a tool that genuinely draws to the workspace edge wants this, and
 * there is exactly one: atlas, whose explorer fills the space it is given. Every
 * other full-width tool wanted the gutter and had been putting it back by hand. */
.sec-bleed .sec-workspace { padding: 0; }

/* A module's own destinations, as children of its row in the ONE rail.
 * Indented: they are inside the row above them, not beside it.
 *
 * The indent USED to clear the parent's 20px icon so a text-only child lined up
 * under the parent's label. A child carries its own icon now, so that indent
 * would push eleven labels a whole icon further right than the tool naming
 * them. It clears the gutter and nothing else, and the nesting is carried by
 * the rule and the smaller mark. */
.sec-rail-children {
  display: flex; flex-direction: column;
  margin: var(--s1) 0 var(--s2) calc(var(--s3) + var(--s2));
  /* The fourth boundary, measured at Lc 0 against the sunk rail. Every rule
   * this shell draws BETWEEN two things is --line-strong; --line is for rules
   * inside one. */
  border-left: 1px solid var(--line-strong);
}
.sec-rail-child {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s2) var(--s3);
  color: var(--ink-muted); text-decoration: none;
  font-size: var(--step--1); line-height: 1.3;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  transition: background var(--motion-fast) var(--ease), color var(--motion-fast) var(--ease);
}
/* Smaller than the parent's 20px: a destination is subordinate to the tool that
 * holds it, and drawing both marks at one size says they are peers. */
.sec-rail-child .sec-rail-icon { flex: 0 0 16px; width: 16px; height: 16px; }
.sec-rail-child .sec-rail-icon svg { width: 15px; height: 15px; }
.sec-rail-child:hover { background: var(--card); color: var(--ink); }
.sec-rail-child.is-current {
  color: var(--ink); font-weight: var(--type-weight-semibold); background: var(--card);
  box-shadow: var(--section-rail-marker);
}

/* The other mode: a strip across the top of the workspace, which is the pattern
 * CRM drew for itself before this was canonical. */
.sec-tabs {
  grid-area: tabs;
  display: flex; gap: var(--s5);
  /* Its OWN padding, not a negative margin cancelling somebody else's. The strip
   * used to live inside the workspace and pull itself back out by exactly that
   * box's padding, which worked and tied the two together: the strip could only
   * ever be as wide as the page beneath it. It is a row of the section now, so
   * it spans the workspace column whatever width the page asked for, and it
   * lines its tabs up with the page's gutter by matching it. */
  padding: 0 var(--s6);
  /* The third of the three, measured at Lc 10. Every boundary this shell draws
   * uses --line-strong; --line is for rules INSIDE a surface, not between two. */
  border-bottom: 1px solid var(--line-strong);
}
/* A bleeding workspace has no gutter to line up with, so the strip keeps a
 * smaller one of its own rather than running its first tab into the rail. */
.sec-bleed .sec-tabs { padding: 0 var(--s5); }
.sec-tab {
  padding: var(--s3) 2px;
  color: var(--ink-muted); text-decoration: none;
  font-size: var(--step-0); font-weight: var(--type-weight-medium);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.sec-tab:hover { color: var(--ink); }
.sec-tab.is-current { color: var(--ink); font-weight: var(--type-weight-semibold); border-bottom-color: var(--brand-600); }

/* ---------- page.header: the slot, dressed ----------

   D2 of the ui-architecture round fixes `header` as a slot on `page`, and the
   `page.*` tokens have been in the design system since before anything drew a
   page. Nothing filled the slot, so seven wrappers grew — `crm-head`,
   `crm-topbar`, `ru-head`, `gb-view`, `rv-card`, `dg-head`, `hero` — with four
   different opinions about the size of a title. This is the one dressing, and
   it reads the tokens rather than restating them. */

.pg-head { margin-bottom: var(--page-gap); }

/* A ROW OF LABELS, aligned on the baseline so a 31px title and an 11px count
   sit on the same line rather than on the same box. */
.pg-row { display: flex; align-items: baseline; gap: var(--s4); flex-wrap: wrap; }

.pg-title {
  margin: 0;
  font-size: var(--page-title-size);
  font-weight: var(--page-title-weight);
  letter-spacing: var(--page-title-tracking);
  color: var(--ink);
}

.pg-count { color: var(--ink-faint); font-size: var(--type-size-xs); font-family: var(--mono); }

.pg-mark {
  display: inline-block; font-size: var(--control-chip-size);
  padding: var(--control-chip-pad-y) var(--control-chip-pad-x);
  border-radius: var(--control-chip-radius);
  background: var(--control-chip-bg); color: var(--control-chip-fg);
  border: 1px solid var(--control-chip-border);
}

/* A NUMBER AND WHAT IT COUNTS, value first and larger. The board's running
   totals, which were `crm-figure` and so could not travel to any other tool. */
.pg-figure { color: var(--ink-faint); font-size: var(--type-size-xs); white-space: nowrap; }
.pg-figure b {
  font-size: var(--type-size-lg); font-weight: var(--type-weight-bold);
  letter-spacing: -0.02em; color: var(--ink); margin-right: var(--s1);
}
/* `.pg-figure:first-of-type b { color: var(--brand-700) }` WAS HERE AND IS GONE.
 *
 * It was DORMANT on every page that ever existed: figures were direct children of
 * `.pg-row` beside a `span.pg-count`, which is a span and comes first, so no
 * figure was ever the first span of its parent. The CRM's declared title bar gave
 * each region a wrapper, the rule woke up, and that console carried a selector
 * whose only job was to undo it.
 *
 * SO THE QUESTION IT ASKED IS ANSWERED BY ITS OWN DORMANCY: whether the first
 * running total should be brand-green is a decision nobody has ever seen the
 * result of. Deleting it changes no page a reader has looked at, and it takes a
 * hack out of a console's stylesheet with it. st-3w28p3a7. */
/* The same token the stale card wears, so a board's two ways of saying "this
   has not moved" cannot drift apart. */
.pg-figure[data-tone="stale"] b { color: var(--component-board-stale-fg); }

.pg-spacer { flex: 1; }
/* Centred, not baselined: a button's baseline is its label, which hangs it
   below a 31px heading that shares the row. */
.pg-actions { display: flex; align-items: center; gap: var(--s3); align-self: center; }

.pg-back {
  display: inline-block; margin-bottom: var(--s3);
  color: var(--ink-faint); text-decoration: none; font-size: var(--type-size-sm);
}
.pg-back:hover { color: var(--ink); }

.pg-lede {
  margin: var(--s3) 0 0; max-width: var(--page-measure-prose);
  color: var(--page-lede-fg); font-size: var(--page-lede-size);
}

/* THE PINNED VARIANT, for a page whose body scrolls under its header — the
   pipeline, whose board is the only thing that should move. It bleeds the
   workspace gutter so the bar reaches both edges, and it is a MODIFIER: same
   element, same heading, same size. Being unable to say that in one component
   is what bought the CRM a second title bar with a 25px h1 in it. */
.pg-head.is-sticky {
  /* Out by the workspace gutter, then back in by exactly the same amount. The
     TOP has to match `--s6` rather than being tightened to taste: the negative
     margin and the padding cancel, so the title lands on the same line as it
     does on a page with no pinned bar. Tightened to `--s4` it sat 8px higher,
     which is the original complaint at one third the size — the heading still
     moved when you opened the board. Buying that back costs 8px of board. */
  margin: calc(-1 * var(--s6)) calc(-1 * var(--s6)) var(--s5);
  padding: var(--s6) var(--s6) var(--s3);
  background: var(--card);
  /* z-index 10, not 3. A pinned header holds the page's controls, and a
     control's popover has to paint over the content it acts on. At 3 this tied
     with board-ui's sticky column heads, which are also 3 and come later in the
     document, so the CRM's filter popover rendered UNDERNEATH the board it
     filters. Nothing in this system sits between 3 and 30, so raising the
     header clears the board and still passes under `.sync-panel` at 30. */
  position: sticky; top: calc(-1 * var(--s6)); z-index: 10;
}

/* ---------- the sync control, in the section chrome ---------- */

/* It lives in the chrome's aside, which had been an empty slot since the shell
 * was written, and it is drawn only where it can run: a laptop with a cloud-sql
 * proxy. The deployment renders nothing rather than a button that cannot work. */
.sync { position: relative; }

/* THE REVIEW GUIDE (public/lib/review-guide.mjs, st-wbcm6161): a card per
   landed visual change, in the topbar beside the account. Roles the site already
   has, placed by data attribute, so a review aid adds no vocabulary. */
/* HOW A TRACED CALL ENDED (st-my98rx56, F9): a note after the call's name and
   data-outcome on its row, so a failure reads as one at a glance -- red for a
   call that threw or a recovery that failed, amber for one that refused,
   recovered or fell back -- and the row is only faintly washed, so the trace
   stays readable. The semantic ramp tokens.css publishes; no class added. */
span[data-outcome="threw"], span[data-outcome="failed"] { color: var(--color-semantic-danger-fg); font-weight: var(--type-weight-semibold); }
span[data-outcome="refused"], span[data-outcome="recovered"], span[data-outcome="fell-back"], span[data-recovery] { color: var(--color-semantic-warn-fg); font-weight: var(--type-weight-semibold); }
tr[data-outcome="threw"] > td, tr[data-outcome="failed"] > td { background: color-mix(in oklab, var(--color-semantic-danger-fg) 7%, transparent); }
[data-recovery] { font-variant-numeric: tabular-nums; }

[data-guide] { position: relative; }
[data-guide] > summary { list-style: none; }
[data-guide] > summary::-webkit-details-marker { display: none; }
[data-guide-panel] {
  position: absolute; right: 0; top: calc(100% + var(--s2)); z-index: 30;
  width: min(440px, 90vw); max-height: 70vh; overflow-y: auto; padding: var(--s4);
  color: var(--ink);
}
[data-guide-panel] ol { list-style: none; margin: 0; padding: 0; }
[data-guide-panel] li .kicker { display: block; }
[data-guide-panel] a { color: var(--ink); text-decoration: none; }
[data-guide-panel] a:hover { text-decoration: underline; }
[data-guide-panel] [aria-current="page"] { border-left-color: var(--brand-500); }
.sync-open {
  list-style: none; cursor: pointer; user-select: none;
  padding: var(--s2) var(--s4); border-radius: var(--radius-sm);
  border: 1px solid var(--line-strong); background: var(--card);
  font-size: var(--step--1); font-weight: var(--type-weight-semibold); color: var(--ink-muted);
}
.sync-open::-webkit-details-marker { display: none; }
.sync-open:hover { color: var(--ink); background: var(--sunk); }
.sync[open] .sync-open { color: var(--ink); background: var(--sunk); }
/* ---------- component.popover: a surface that floats over the page ----------

   st-3w28p3a7. FIVE of these were written five times -- this one, the CRM's
   filter popover, gabriela's filter menu, its cell menu and its modal -- and the
   ground, the border and the elevation are IDENTICAL in all five. Measured
   rather than read, because the three stylesheets reach them through three token
   names holding one value each: control.selector.popup.bg and background.panel
   are both #ffffff, and control.selector.popup.elevation, elevation.overlay and
   shadow-deep are all `0 8px 24px -8px rgb(24 31 37 / 18%)`. Three names for one
   shadow is how five surfaces stayed the same by accident.

   THE RADIUS IS WHAT DRIFTED: two at 6px, three at 10px, and the split is not by
   kind -- gabriela drew one menu at 6 and another at 10. control.selector.radius
   is 6px and a popover IS a selector's popup, so that is the answer.

   WHAT A CALLER KEEPS IS WHERE IT SITS: position, the anchor, the z-index, the
   width and the padding. None of that is paint, so the conversion census does
   not count it, which is exactly the line the census draws. */

/* ---------- control.selector.trigger: the box you press to open a selector ----

   st-3w28p3a7. This construct published a trigger's ground, its border, its
   radius and its ceiling, and NO ROLE read them -- `control-selector-trigger-max-width`
   had no reader at all. The CRM's filter card painted the whole thing by hand
   out of those same tokens, which the census counted as a private look because
   the RULE was in a console's sheet. Every value in it was the system's.

   A SUMMARY IS A CONTROL, so `cursor` and `list-style` belong here rather than
   in the caller: a <summary> draws a disclosure triangle until it is told not
   to, and a box that opens something is a box a pointer changes over.

   WHAT A CALLER KEEPS is the row inside it -- which of its own parts sit where,
   and how far apart. None of that is paint. */

.selector-trigger {
  display: flex; align-items: center; gap: var(--control-selector-gap);
  cursor: pointer; list-style: none;
  background: var(--control-selector-trigger-bg);
  border: 1px solid var(--control-selector-trigger-border);
  border-radius: var(--control-selector-radius);
  padding: var(--control-field-pad-y) var(--control-field-pad-x);
  min-height: var(--control-field-min-target);
  font-size: var(--control-selector-trigger-size);
}
.selector-trigger::-webkit-details-marker { display: none; }
/* AND ITS THREE STATES, which are the same border in three places: the pointer
   over it, the keyboard on it, and the thing it opens being open. A trigger that
   looked the same open and shut is a control with no feedback at all. */
.selector-trigger:hover { border-color: var(--control-field-border-focus); }
[open] > .selector-trigger { border-color: var(--control-field-border-focus); }
.selector-trigger:focus-visible {
  outline: var(--control-focus-width) solid var(--control-focus-ring);
  outline-offset: var(--control-focus-offset);
}
/* WHAT A TRIGGER SAYS BEFORE IT IS OPENED, which is the whole of its job -- a
   filter you cannot see the state of is a filter that gets left on. Three
   parts, named inside the role the way .stat-tile names its own: the key (small
   capitals, faint) with the count of choices on in the press colours, the value
   that is chosen (full ink, cut short rather than wrapped), and the tally (mono,
   faint). The CRM's filter card painted all three privately, every value a
   token. st-3w28p3a7, de-6q00090a. */
.selector-trigger .k { color: var(--ink-faint); font-size: var(--type-size-xs); text-transform: uppercase; letter-spacing: var(--type-tracking-wider); }
.selector-trigger .k b { color: var(--control-button-rest-fg); background: var(--control-button-rest-bg); border-radius: var(--radius-pill); padding: 0 var(--s2); margin-left: var(--s1); }
.selector-trigger .v { color: var(--ink); font-weight: var(--type-weight-semibold); max-width: 30ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.selector-trigger .n { color: var(--ink-faint); font-family: var(--mono); font-size: var(--type-size-xs); }

.popover {
  background: var(--component-popover-bg);
  border: 1px solid var(--component-popover-border);
  border-radius: var(--component-popover-radius);
  box-shadow: var(--component-popover-elevation);
}
/* THE POPOVER'S FOOT: a rule across, and the actions under it. The CRM's filter
   popover drew it as .crm-filter-foot. st-3w28p3a7. */
.popover-foot { border-top: 1px solid var(--line); padding-top: var(--s4); }
/* A POPOVER THAT DOCKS ON A PHONE stops floating and joins the page under its
   trigger, so it stops casting a shadow too. At the sheet's own phone width,
   760px: the CRM docked its filter at 640, a third number the platform does not
   have, and two files disagreeing about where a phone starts is how a system
   ends up with three. st-3w28p3a7. */
@media (max-width: 760px) {
  .popover.is-docking { position: static; width: auto; box-shadow: none; }
}
/* A REGION WHOSE CONTENTS ARE BEING REPLACED: present, and not the subject until
   the new contents land -- opacity.mute, de-q39nyx8t's step for exactly that.
   The CRM's filter writes data-busy on its disclosure while the board is
   fetched; it was 0.6, which is the same intention one step off the scale. */
[data-busy] { opacity: var(--opacity-mute); }
/* A SMALL HEADING IN CAPITALS over a group of choices or after a term --
   "OWNER" over a filter's options, "·SEALED" after a panel's heading. Faint,
   the smallest step, semibold, spaced. The CRM wrote it twice, as a filter
   group's h4 and as .crm-sealed. st-3w28p3a7. */
.kicker {
  color: var(--ink-faint); font-size: var(--type-size-xs); font-weight: var(--type-weight-semibold);
  text-transform: uppercase; letter-spacing: var(--type-tracking-wider);
}

/* ---------- control.selector.option: one choice among several ----------

   THE TRIGGER HAD A ROLE AND THE OPTION DID NOT, so the CRM drew the option three
   times under three names -- .crm-chip (a filter's choice, a pill),
   .crm-type (which pipeline, a pill with a glyph and a count) and
   .crm-type-current (the saved deal's type, a card) -- and every value in all
   three already read control.selector.option. record-ui's .ru-card is the same
   option as a checkable card, and folding it is what repays this.
   st-3w28p3a7, de-6q00090a.

   WHAT A CALLER KEEPS is the box's arrangement -- padding, the target height,
   the gap between a glyph and its word. None of that is paint.

   ON IS A GROUND AND A BORDER AND A RING, because a ground alone is the one state
   people miss on a choice they did not make themselves. A TOGGLE that is
   pressed also says so with a tick, which is aria-pressed's job and not a
   class's: a link to a pipeline is current, not pressed. */
.selector-option {
  text-decoration: none; cursor: pointer;
  background: var(--control-selector-option-bg);
  color: var(--control-selector-option-fg);
  border: 1px solid var(--control-selector-option-border);
  border-radius: var(--radius-pill);
  font-size: var(--type-size-sm);
  font-weight: var(--control-selector-option-weight);
  transition: background var(--motion-fast) var(--ease), border-color var(--motion-fast) var(--ease);
}
.selector-option:hover { border-color: var(--control-field-border-focus); }
.selector-option:focus-visible {
  outline: var(--control-focus-width) solid var(--control-focus-ring);
  outline-offset: var(--control-focus-offset);
}
.selector-option.is-on {
  background: var(--control-selector-option-bg-active);
  border-color: var(--control-selector-option-border-active);
  box-shadow: inset 0 0 0 1px var(--control-selector-option-border-active);
}
.selector-option[aria-pressed="true"]::after { content: " \2713"; color: var(--brand-700); margin-left: var(--s1); }
/* QUIET: muted ink at rest, full ink under the pointer or when on. For a row of
   options that sits above what it selects -- the pipeline's type rail -- where
   five full-ink labels would outweigh the board. The label inside is medium,
   and semibold once it is the one chosen. */
.selector-option.is-quiet { color: var(--ink-muted); font-weight: var(--type-weight-regular); }
.selector-option.is-quiet:hover, .selector-option.is-quiet.is-on { color: var(--ink); }
.selector-option.is-quiet.is-on { font-weight: var(--type-weight-semibold); }
.selector-option .l { font-weight: var(--type-weight-medium); }
/* AN OPTION'S COUNT, mono so a row of them line up, in a sunk pill that turns to
   the card's ground when its option is on. Same reading as .stat-tile .n: a
   part of the role, named inside it. */
.selector-option .n {
  font-family: var(--mono); font-size: var(--type-size-xs);
  color: var(--ink-faint); background: var(--sunk);
  border-radius: var(--radius-pill); padding: 0 var(--s2);
}
.selector-option.is-on .n { color: var(--ink); background: var(--card); }
/* AS A CARD: the option that stands for a choice already made and opens the
   picker. Square-ish, body ink at the body's size, and a sentence under the
   word in the muted ink. */
.selector-option.is-card {
  border-radius: var(--radius-md); color: var(--ink);
  font-size: inherit; font-weight: inherit;
}
.selector-option-desc { color: var(--ink-muted); font-size: var(--type-size-sm); }
/* A CARD'S GLYPH IS THE GLYPH SIZE. A bare svg is as wide as its container, so
   an option card with a glyph draws it the width of the panel -- which the deal
   page's type card did twice: before 4e0e96f5 gave it a box, and again once
   0683dbaa deleted the box's rule with record-ui's radio cards. Sized here, on
   the role, with no name of its own to delete. */
.selector-option.is-card svg {
  display: block; width: var(--component-family-glyph-size); height: var(--component-family-glyph-size);
  margin-bottom: var(--s1); color: var(--ink-faint);
}

/* THE SYNC PANEL IS WHERE IT SITS, and nothing else. It was the fifth hand
   written copy of the four declarations above. */
.sync-panel {
  position: absolute; right: 0; top: calc(100% + var(--s2)); z-index: 30;
  width: min(520px, 80vw); padding: var(--s4);
}
.sync-dirs { display: flex; gap: var(--s3); margin-bottom: var(--s3); }

/* Which tools to compare, chosen before anything is compared. A tool that may
   not travel is drawn with its reason rather than left out: one missing from
   the list reads as one that synced. */
.sync-pick { display: flex; flex-wrap: wrap; gap: var(--s3); margin-bottom: var(--s3); }
.sync-pick-one { display: inline-flex; align-items: center; gap: var(--space-1-5); font-size: var(--step--1); cursor: pointer; }
.sync-pick-one.is-off { opacity: 0.55; cursor: default; }
.sync-pick-one input { cursor: inherit; }
/* The log is monospace and scrolls itself: the run is a sequence of short
 * lines, and a panel that grew with them would push the page around while
 * somebody is reading it. */
.sync-log {
  margin: 0; max-height: 300px; overflow: auto;
  padding: var(--s3); border-radius: var(--radius-sm);
  background: var(--sunk); border: 1px solid var(--line);
  font-family: var(--mono); font-size: var(--type-size-xs); line-height: 1.5;
  color: var(--ink-muted); white-space: pre-wrap;
}
.sync-log:empty { display: none; }
.sync-log .bad { color: var(--stop); font-weight: var(--type-weight-semibold); }

/* ---------- the sync manifest ----------
   A TABLE OF PROPOSALS, each one a switch. Nothing in it has happened: the
   point of drawing it is that somebody reads it before it does. */
.sync-table { max-height: 46vh; overflow: auto; margin: var(--s3) 0; }
.sync-tool { display: flex; gap: var(--s2); align-items: baseline; padding: var(--s3) 0 var(--s2); }
.sync-tool b { font-size: var(--step--1); }
.sync-skip { color: var(--ink-faint); font-size: var(--step--1); }
.sync-rows { width: 100%; border-collapse: collapse; font-size: var(--step--1); }
.sync-rows th { text-align: left; font-weight: var(--type-weight-regular); color: var(--ink-faint);
  padding: 2px 8px 4px 0; border-bottom: 1px solid var(--line); }
.sync-rows td { padding: 4px 8px 4px 0; border-bottom: 1px solid var(--line);
  vertical-align: top; }
.sync-rows td:first-child, .sync-rows th:first-child { width: 24px; }
.sync-rows td:nth-child(3) { white-space: nowrap; color: var(--ink-muted); }
.sync-rows td:last-child { color: var(--ink-faint); }
/* A conflict is the row nobody should apply without reading it, so it is the
   row that does not look like the others. */
.sync-rows tr.is-conflict td { background: color-mix(in srgb, var(--stop) 7%, transparent); }
.sync-rows tr.is-conflict td:nth-child(3) { color: var(--stop); font-weight: var(--type-weight-semibold); }
.sync-progress { display: flex; align-items: center; gap: var(--s3); margin: var(--s3) 0 0; }
.sync-bar { flex: 1; height: 6px; accent-color: var(--brand-600); }
.sync-now { font-size: var(--step--1); color: var(--ink-faint); font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 40ch; }
/* A row that has landed is no longer a proposal, and says so where its
   direction used to be. */
.sync-rows tr.is-applied td { color: var(--ink-faint); }
.sync-rows tr.is-applied td:nth-child(3) { color: var(--brand-600); font-weight: var(--type-weight-semibold); }


/* ---------------------------------------------------------------------------
   SHARED CONTROLS, FROM THE DESIGN SYSTEM'S OWN TOKENS.

   The system emits `--control-*` for atoms and `--component-*` for
   compositions, and this stylesheet was consuming NONE of them: every field,
   table and chip on the site carried a value somebody typed here instead. So a
   token changed in the design system changed nothing on the page, which is the
   whole point of having tokens.

   These are written once, here, so the next screen has a field and a table
   rather than inventing them again. Nothing below decides a value; every one
   comes from the system.
   --------------------------------------------------------------------------- */

.field { display: flex; flex-direction: column; gap: var(--control-label-gap); }
.field > .label { font-size: var(--control-label-size); font-weight: var(--control-label-weight); color: var(--control-label-fg); }
.field > .hint { font-size: var(--control-hint-size); color: var(--control-hint-fg); }
/* THE FIELD, AND IT IS ONE CONTROL ON THIS PLATFORM NOW. st-3w28p3a7,
   de-6q00090a: the CRM painted every native control under .crm itself, and
   record-ui's .ru-control paints the same box -- both at the small step, both
   ringed by control.focus. This role was the third answer and the odd one: the
   body's size, and a focus ring mixed by hand out of the border colour instead
   of the ring the system publishes. It reads control.focus now, sets the small
   step the two consoles agreed on, and carries the textarea, the invalid state
   and the file picker the CRM had to write for itself. Folding .ru-control onto
   it is what repays this. */
.field input, .field select, .input {
  min-height: var(--control-field-min-target);
  padding: var(--control-field-pad-y) var(--control-field-pad-x);
  background: var(--control-field-bg); color: var(--control-field-fg);
  border: 1px solid var(--control-field-border); border-radius: var(--control-field-radius);
  font: inherit; font-size: var(--type-size-sm); }
textarea.input { min-height: calc(var(--control-field-min-target) * 2.5); line-height: var(--leading-normal); resize: vertical; }
.field input::placeholder, .input::placeholder { color: var(--control-field-placeholder); }
.field input:focus-visible, .input:focus-visible {
  outline: var(--control-focus-width) solid var(--control-focus-ring); outline-offset: var(--control-focus-offset);
  border-color: var(--control-field-border-focus); }
.field input:invalid:not(:placeholder-shown) { border-color: var(--control-field-border-invalid); }
.input[aria-invalid="true"] { border-color: var(--control-field-border-invalid); }
/* A FILE PICKER: a dashed box on the sunk ground, muted, and the browser's own
   button inside it drawn as the system's press. */
.input[type="file"] {
  color: var(--ink-muted); background: var(--sunk);
  border-style: dashed; padding: var(--control-field-pad-x);
}
.input[type="file"]::file-selector-button {
  font: inherit; font-size: var(--control-button-size); font-weight: var(--control-button-weight);
  background: var(--control-button-rest-bg); color: var(--control-button-rest-fg);
  border: none; border-radius: var(--control-button-radius);
  padding: var(--control-button-pad-y) var(--control-button-pad-x); margin-right: var(--s3); cursor: pointer;
}
.input[type="file"]::file-selector-button:hover { background: var(--control-button-hover-bg); }

.form { display: flex; flex-direction: column; gap: var(--component-form-gap); max-width: var(--component-form-measure); }
.form-row { display: flex; flex-wrap: wrap; gap: var(--component-form-gap); }
.form-row > .field { flex: 1 1 14rem; }

.chip { display: inline-flex; align-items: center;
  padding: var(--control-chip-pad-y) var(--control-chip-pad-x);
  background: var(--control-chip-bg); color: var(--control-chip-fg);
  border: 1px solid var(--control-chip-border); border-radius: var(--control-chip-radius);
  font-size: var(--control-chip-size); font-family: var(--control-chip-face);
  /* THE WEIGHT AND THE TRACKING ARE control.chip's TOO, and this rule ignored
     both: the CRM's .crm-tag wrote them back in because the role would not.
     de-6q00090a, st-3w28p3a7. */
  font-weight: var(--control-chip-weight); letter-spacing: var(--control-chip-tracking);
  white-space: nowrap; }
/* A CHIP'S TONE IS WHAT IT SAYS ABOUT THE THING, and these three are a state's:
   under way, landed, and over. The CRM coloured its stages by NAME --
   .crm-tag[data-rel="diligence"] -- which is a rule only the CRM could use; it
   maps a stage to one of these now and the chip says the meaning. The values
   are the ones it drew. st-3w28p3a7. */
.chip[data-tone="active"] {
  background: var(--brand-tint); color: var(--brand-800);
  border-color: color-mix(in oklab, var(--brand-500) 26%, var(--brand-tint));
}
.chip[data-tone="ok"] {
  background: var(--ok-bg); color: var(--ok);
  border-color: color-mix(in oklab, var(--ok) 22%, var(--ok-bg));
}
.chip[data-tone="quiet"] { color: var(--ink-faint); }
/* WHERE IT IS NOW, filled: the one chip in a row of presses that is not a
   press. Drawn as a bordered pill it weighed the same as the presses beside it,
   so the one thing the row exists to say was the hardest thing on it to see. */
.chip[data-tone="current"] {
  background: var(--control-button-rest-bg); color: var(--control-button-rest-fg);
  border-color: var(--control-button-rest-bg); font-weight: var(--type-weight-bold);
  padding: var(--control-chip-pad-y) var(--s3);
}
/* A CHIP THAT IS A PRESS: the stage mover's arrows and stages. It answers the
   pointer in the brand's tint and, when there is nowhere to go, is
   opacity.dim -- the scale's step for a control that cannot be pressed. */
button.chip { cursor: pointer; line-height: inherit; }
button.chip:hover:not([disabled]) { background: var(--brand-tint); color: var(--brand-800); border-color: var(--brand-500); }
button.chip[disabled] { opacity: var(--opacity-dim); cursor: default; }

.table { width: 100%; border-collapse: collapse; font-size: var(--component-table-size); }
.table th, .table td { padding: var(--component-table-cell-pad-y) var(--component-table-cell-pad-x);
  border-bottom: 1px solid var(--component-table-border); text-align: left; vertical-align: middle; }
/* THE HEAD READS ALL OF component.table.head NOW. It read the ground and the ink
   and nothing else, so five published head tokens -- size, weight, tracking,
   transform and the heavier rule under it -- were answered by nobody, and the
   CRM wrote all five into its own .crm-table to get the head the system had
   already decided. de-6q00090a named this; st-3w28p3a7 fixed it here rather than
   keeping a second table. The api-keys page is the other wearer and gains the
   same small-caps head. */
.table thead th { background: var(--component-table-head-bg); color: var(--component-table-head-fg);
  font-size: var(--component-table-head-size); font-weight: var(--component-table-head-weight);
  letter-spacing: var(--component-table-head-tracking); text-transform: var(--component-table-head-transform);
  border-bottom-color: var(--component-table-head-border); white-space: nowrap; }
.table tbody tr:hover { background: var(--component-table-row-hover); }
.table tbody tr:last-child td { border-bottom: 0; }
/* A LINK IN A CELL is the way into the row's record: brand ink, no underline at
   rest, and the CRM's tables were the ones drawing it. Same three values as
   ul.links a, at the table's semibold. */
.table a { color: var(--brand-600); text-decoration: none; font-weight: var(--type-weight-semibold); }
.table a:hover { text-decoration: underline; }
.table a:active { color: var(--brand-700); }

/* A SECOND `.callout` RULE WAS HERE AND IT WAS ENTIRELY DEAD. It set padding,
   background and border-radius; the tone-aware `.callout` four hundred lines down
   sets all three and six more, and at equal specificity the later rule wins. Even
   the ground was invisible: `--component-callout-bg` and
   `--component-callout-info-bg` are both #edf7f3, which is why nobody caught two
   definitions of one class in one sheet. st-3w28p3a7, found while adopting the
   callout for the CRM's stop notice. */

/* ---------- component.tabs: a row of areas, the current one underlined ----------

   st-3w28p3a7. THREE CONSOLES WROTE THIS STRIP: `.crm-tabs`, `.ov-tabs` and
   `.gb-tabs`, eight declarations each, the same picture. Measured in a browser
   rather than read off the source: crm and overlook paint 13px at weight 600
   with 12px/16px of padding and a 2px marker, to the pixel; gabriela paints it
   one step smaller, which is `.tabs.is-dense`.

   AND ONE OF THE THREE WAS UNREADABLE. `.crm-tabs a` coloured its rest state
   from `--chrome-nav-fg`, the DARK top bar's ink: #addeca on the workspace
   measures 1.44:1 where SC 1.4.3 asks 4.5:1. The other two say
   `--component-tabs-fg` and measure 7.07:1. That is what three writings of one
   rule buys you.

   IT NEVER RENDERED, AND THAT IS NOT A MITIGATION. The CRM's areas strip is the
   fallback for a bare mount; the pipeline page's five areas are drawn by the
   SHELL as `.sec-tab` at 7.07:1. An unused fallback written by hand is the one
   that is wrong when somebody finally mounts it bare.

   THE CURRENT TAB IS MARKED THREE WAYS AND ALL THREE ARE DRESSED, because all
   three are correct for their own markup: `aria-current="page"` for a strip of
   destinations, `aria-selected="true"` for a real tablist, and `.is-current`
   for what `shared.LinkControl` writes when the declaration says which one is
   here. A role that dressed one of them would silently fail the other two.

   NOT `.sec-tab`, which is the SHELL's strip and measures a different picture on
   purpose: 16px at weight 500 with 12px/2px of padding, because its tabs line up
   with the workspace gutter instead of sitting inside a page. Folding the two is
   a change to the chrome on every screen, so it is a decision and not a
   conversion. `atlas/assets/app.css` carries a fifth, in a document that loads
   its own stylesheet and never this one. */

.tabs {
  display: flex; gap: var(--component-tabs-gap);
  border-bottom: 1px solid var(--component-tabs-rule);
  margin-bottom: var(--component-tabs-gap-under);
}
.tabs a, .tabs .tab {
  padding: var(--component-tabs-pad-y) var(--component-tabs-pad-x);
  text-decoration: none; color: var(--component-tabs-fg);
  font-size: var(--component-tabs-size); font-weight: var(--component-tabs-weight);
  /* The marker's track, transparent until it is the current one, so a tab does
     not move by two pixels when it becomes current. */
  border-bottom: var(--component-tabs-marker-width) solid transparent;
  margin-bottom: -1px;
}
.tabs a:hover, .tabs .tab:hover { color: var(--component-tabs-hover-fg); }
/* A ring none of the three strips had. A row of links with no focus state is
   navigable by keyboard and invisible while you do it. */
.tabs a:focus-visible, .tabs .tab:focus-visible {
  outline: var(--control-focus-width) solid var(--control-focus-ring);
  outline-offset: var(--control-focus-offset);
}
.tabs a[aria-current="page"], .tabs a[aria-selected="true"], .tabs a.is-current,
.tabs .tab[aria-current="page"], .tabs .tab[aria-selected="true"], .tabs .tab.is-current {
  color: var(--component-tabs-current-fg);
  border-bottom-color: var(--component-tabs-marker);
}

/* A strip inside a card rather than under a page head. */
.tabs.is-dense {
  border-bottom-color: var(--component-tabs-dense-rule);
  margin-bottom: var(--component-tabs-dense-gap-under);
}
.tabs.is-dense a, .tabs.is-dense .tab {
  padding: var(--component-tabs-dense-pad-y) var(--component-tabs-dense-pad-x);
  font-size: var(--component-tabs-dense-size);
}

/* The modal. Native <dialog>, so focus trapping, Escape and inertness are the
   browser's job rather than ours — and every value is `component.dialog`, the
   same declaration the whiteboard's confirm renders from. One dialog in the
   system, two callers. */
.modal { padding: 0; border: 0; background: transparent; max-width: none; max-height: none; }
.modal::backdrop { background: var(--component-dialog-scrim); }
.modal[open] { animation: modal-in var(--component-dialog-enter) var(--component-dialog-ease) both; }
.modal[open]::backdrop { animation: modal-in var(--component-dialog-enter) var(--component-dialog-ease) both; }
.modal-panel { width: min(var(--component-dialog-max-width), calc(100vw - 2rem));
  display: flex; flex-direction: column; gap: var(--component-dialog-gap);
  padding: var(--component-dialog-pad-y) var(--component-dialog-pad-x);
  background: var(--component-dialog-bg); color: var(--component-dialog-fg);
  border: 1px solid var(--component-dialog-border);
  border-radius: var(--component-dialog-radius); box-shadow: var(--component-dialog-shadow);
  font-size: var(--component-dialog-size); }
.modal-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3); }
.modal-head h2 { margin: 0; font-size: 1.15em; }
.modal-foot { display: flex; gap: var(--s3); justify-content: flex-end; }

/* The grid's own header: a title on the left, the action that fills it on the right. */
.grid-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s4); margin-bottom: var(--s3); }
.grid-head h3 { margin: 0; }
tr.is-revoked { color: var(--ink-faint); }

/* The scope picker inside the issue dialog. */
.scope-list { display: flex; flex-direction: column; gap: var(--s2); }
.scope-row { display: flex; align-items: flex-start; gap: var(--s2); cursor: pointer; }
.scope-row .hint { font-size: var(--control-hint-size); color: var(--control-hint-fg); }
.hint { font-size: var(--control-hint-size); color: var(--control-hint-fg); }
.code-block { margin: var(--s3) 0; padding: var(--s3); overflow-x: auto;
  background: var(--component-code-bg); color: var(--component-code-fg);
  border-radius: var(--component-code-radius); font-family: var(--mono); font-size: var(--step--1); }

/* ---------- the trace button, and the modal it opens ---------- */
/*
 * Ben, 2026-10-16: "every page that uses the footer has a button that triggers
 * the trace modal ... This should come for free every time."
 *
 * THE BUTTON READS AS THE FOOTER'S OWN TEXT, which is what makes it free rather
 * than loud: it sits beside the host name in the same muted ink, and the pointer
 * is the only thing that says it does something. A page gets one by existing, so
 * it must not be the brightest thing on the page.
 */
.footer-trace {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--on-dark-muted);
  cursor: pointer;
  text-decoration: underline;
  text-decoration-style: dotted;
  text-underline-offset: 3px;
}
.footer-trace:hover { color: var(--on-dark); }

/* A NATIVE DIALOG, so the backdrop, the focus trap, ESC and the top layer are the
 * browser's rather than four things to reimplement. */
/*
 * A WIDE DIALOG, added to the system rather than to this caller. 66ch is a
 * column of prose and a trace is a dense table; the next wide dialog reads this
 * instead of inventing a width of its own. It overrides the TOKEN, so padding,
 * radius, scrim and the enter animation all still come from `component.dialog`.
 */
.modal-wide .modal-panel {
  width: min(var(--component-dialog-max-width-wide), calc(100vw - 2rem));
  /* AND AS TALL AS THE CANONICAL DIALOG WAS. 82vh was right for an indented tree
   * that stopped when it ran out of spans; two panes of a diagram use every row
   * they are given, and the view scrolls inside the panel rather than the panel
   * growing past the window. */
  gap: 0; padding: 0; height: min(92vh, 1100px); max-height: 92vh;
}
.modal-wide .modal-head {
  padding: var(--component-dialog-pad-y) var(--component-dialog-pad-x);
  border-bottom: 1px solid var(--component-dialog-border);
  justify-content: flex-start;
  gap: var(--s3);
}

/* THE TRACE VIEW'S OWN PARTS, which are the only things here the system did not
 * have. Two panes of one request: the same call tree as a conversation and as
 * every class and method, which is what the component gallery has drawn since
 * `st-dwxe6rh9` and what every page now opens.
 *
 * WHAT WENT: eleven rules drawing an indented tree -- `.tr-row`, `.tr-layer`,
 * `.tr-what`, `.tr-ms` and the rest -- for a FOURTH trace viewer that only
 * existed because `/assets/trace.mjs` drew its own. The diagram replaced it, so
 * the rules that dressed it are gone rather than left for the next reader to
 * wonder about. */
.trace-count { color: var(--ink-muted); font-size: var(--type-size-xs); }
.trace-raw { margin-left: auto; font-size: var(--type-size-xs); color: var(--ink-muted); }
.trace-close { font-size: var(--type-size-lg); line-height: 1; padding: 0 var(--s2); }

/* SIDE BY SIDE, and stacked when neither column would be readable. Two 500px
 * halves of a sequence diagram is two unreadable halves, so under 1100px the
 * panes are one above the other and the dialog scrolls. */
.trace-view {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 1px;
  background: var(--component-dialog-border);
  /* THE PANEL IS A COLUMN FLEX BOX, so the view has to be told it may grow AND
   * that it may shrink: without `min-height: 0` a flex child refuses to go below
   * its content, and a 600-row diagram would push the dialog past the viewport
   * instead of scrolling inside it. */
  flex: 1;
  min-height: 0;
  overflow: auto;
}
@media (max-width: 1100px) { .trace-view { grid-template-columns: minmax(0, 1fr); } }
.trace-pane {
  background: var(--component-dialog-bg);
  padding: var(--s4);
  min-width: 0;
  overflow: auto;
}
.trace-pane h3 {
  margin: 0 0 var(--s3);
  font-size: var(--type-size-xs);
  font-weight: var(--type-weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--type-tracking-wide);
  color: var(--ink-muted);
}

/* ---------- the callout: a sentence the page says about itself -------------- */
/*
 * `st-3w28p3a7`. FOUR CONSOLES DRESSED THIS FOUR WAYS and the library had the
 * component all along: `shared.AlertComponent` exists, and its own comment names
 * `crm-uisvc`'s `div.crm-warn`, `overlook`'s `div.ov-problems` and review-loop's
 * third copy as the string renderers it was built to replace. What stopped them
 * folding onto it was not the markup. It was that the library's rule -- a
 * control names no class of its own, because a frame that did would know which
 * console it is on -- left the APPEARANCE with nowhere to live but each host's
 * sheet.
 *
 * SO THE TONE CARRIES THE LOOK. `shared.AlertComponent` already writes
 * `data-tone` from its record; every value under this rule is a
 * `component.callout` token; and a console passes `className: 'callout'`, which
 * is this sheet's name rather than its own. The component still names no class,
 * the look is the system's, and retuning a warning retunes every console's at
 * once instead of four of them disagreeing.
 *
 * A STOP GETS A STRIPE AND THE OTHER THREE DO NOT. That distinction is the CRM's
 * and it is right: a page that is interrupted should not look like a page that
 * is merely annotated, and at a glance the stripe is what says which.
 */
.callout {
  border-radius: var(--component-callout-radius);
  padding: var(--component-callout-pad-y) var(--component-callout-pad-x);
  margin-bottom: var(--s6);
  font-size: var(--type-size-base);
  background: var(--component-callout-info-bg);
  color: var(--component-callout-info-fg);
  border: 1px solid var(--component-callout-info-border);
}
.callout[data-tone="ok"] {
  background: var(--component-callout-ok-bg);
  color: var(--component-callout-ok-fg);
  border-color: var(--component-callout-ok-border);
}
.callout[data-tone="warn"] {
  background: var(--component-callout-warn-bg);
  color: var(--component-callout-warn-fg);
  border-color: var(--component-callout-warn-border);
  padding: var(--s3) var(--component-callout-pad-x);
  font-size: var(--type-size-sm);
  margin-bottom: var(--s4);
}
.callout[data-tone="stop"] {
  background: var(--component-callout-stop-bg);
  color: var(--component-callout-stop-fg);
  border-color: var(--component-callout-stop-border);
  border-left: var(--component-callout-stripe-width) solid var(--color-semantic-danger-fg);
  max-width: 68ch;
}
.callout:focus-visible {
  outline: var(--control-focus-width) solid var(--control-focus-ring);
  outline-offset: var(--control-focus-offset);
}
/* The alert's own two regions, which the library names and nothing dressed. */
.callout .lib-alert-message { margin: 0; }
.callout .lib-alert-message b { font-weight: var(--type-weight-semibold); }
.callout ul { margin: var(--s2) 0 0; padding-left: var(--s5); }
.callout .lib-alert-reason { font-size: var(--type-size-sm); }
/* A STOP THAT EXPLAINS ITSELF: a heading in the error ink, then paragraphs in
   the muted ink at the body's size. The CRM's stop notice wore the box already
   and dressed its heading and paragraphs as .crm-stop h3 and .crm-stop p; a stop
   is the one tone that interrupts a page, so it is the one that gets a heading.
   st-3w28p3a7, de-6q00090a. */
.callout[data-tone="stop"] h3 { margin: 0 0 var(--s3); font-size: var(--type-size-md); color: var(--panel-error-fg); }
.callout[data-tone="stop"] p { margin: 0 0 var(--s3); color: var(--ink-muted); font-size: var(--type-size-base); line-height: var(--leading-normal); }

/*
 * THE SENTENCE UNDER A PANEL'S HEADING, dressed once for every host.
 *
 * `st-3w28p3a7`. The CRM's panels wrote this as an inline style on a `<p>`, and
 * converting them onto `shared.FrameLayout` turned it into a class -- a declared
 * screen asks for one. Putting that class in the CONSOLE's sheet raised its
 * private vocabulary from 46 to 47, and the census said so the same minute: the
 * number the whole conversion plan exists to drive down had gone up while a
 * conversion was being celebrated.
 *
 * So it is here, keyed to `component.panel`'s own tokens, and a console passes
 * `panel-note` -- the system's name rather than its own. Same answer as the
 * callout, which is now the second time this shape has come up.
 */
.panel-note {
  color: var(--panel-note-fg);
  font-size: var(--panel-note-size);
  max-width: var(--panel-note-measure);
}

/*
 * THE ACTION UNDER A PANEL'S SENTENCE. Three CRM panels wrote
 * `style="margin-top:var(--s4)"` on the form beneath their prose; a declared
 * screen asks for a class and the gap is `component.panel`'s own. st-3w28p3a7.
 */
.panel-foot { margin-top: var(--panel-foot-gap); }

/*
 * THE ASIDE BETWEEN A HEADING AND WHAT IT QUALIFIES, and the gap is below it.
 * The CRM's deals panel says its organisation's relationship is derived from the
 * deals under it, at the hint colour and the scale's 12px, with
 * `margin: 0 0 var(--s4)` -- a zero top, because the heading is already above
 * it. st-3w28p3a7.
 */
.panel-lede {
  color: var(--panel-lede-fg);
  font-size: var(--panel-lede-size);
  margin: 0 0 var(--panel-lede-gap);
  /* AND A LEDE IS PROSE, SO IT HAS A MEASURE. st-3w28p3a7: the CRM's rubric said
     `max-width:62ch` inline and its deals panel said nothing, which is the same
     line read two ways -- 66ch is the system's answer and `measure.prose` is
     where it lives. The deals lede gets narrower by adopting it, which is the
     measure doing its job: a 12px line the full width of a panel is a line a
     reader loses. */
  max-width: var(--measure-prose);
}

/*
 * A SECOND GROUP UNDER ONE PANEL'S FRAME. Open deals, then closed ones, with the
 * second heading pushed down a step further than an action would be: a group
 * break reads as a bigger pause. st-3w28p3a7.
 *
 * AND IT IS WRITTEN AS THE PANEL'S OWN CHILD BECAUSE A BARE CLASS LOST.
 * `.panel h3` above sets `margin: 0 0 var(--panel-header-gap)` -- one class and
 * one element -- so `.panel-split` alone is out-specified and the margin-top it
 * asks for resolves to 0. The markup was right and the two groups ran together;
 * `detail-screens.ui.test.mjs` measured 24px become 0px, which is the whole
 * reason a painted test exists beside a DOM diff.
 */
.panel > .panel-split { margin-top: var(--panel-split-gap); }

/*
 * THE ACTION INSIDE A CARD, one step of air above it rather than two. Each note
 * on a CRM record carries its own delete press, and a card's action sits inside a
 * stack of cards: the gap has to read as belonging to the card it is in.
 * st-3w28p3a7.
 */
.card-foot { margin-top: var(--component-card-action-gap); }

/*
 * THE TWO TEXT ROLES EVERY CONSOLE WAS WRITING FOR ITSELF.
 *
 * `.meta` is a small factual line -- a timestamp, a byline, who did it -- and
 * `.num` is a number in a cell. Four consoles each dressed their own: the CRM
 * wrote `.meta`, `.when` and `.n`, gabriela writes `gb-meta`, `gb-view-meta` and
 * `gb-date`, overlook writes `ov-who`, parkour writes `pk-board-meta`. Every one
 * is faint and mono, and most are one step smaller than the body.
 *
 * `.num` CARRIES NO SIZE, which is the difference between the two: a figure in a
 * table reads at the table's size and the one thing it must not do is wander
 * across its column. st-3w28p3a7.
 */
.meta {
  color: var(--component-meta-fg);
  font-size: var(--component-meta-size);
  font-family: var(--component-meta-face);
}

/* A VALUE THAT IS NOT THERE, which is a state and not a size: an em-dash where a
   field has nothing in it, faint so a reader can tell "no email" from "the email
   did not arrive". One declaration, and TWO consoles wrote it -- the CRM as
   `.crm-dl dd.is-empty` and record-ui as `.ru-value.is-empty`, through two token
   names holding the same #61717f.

   TEN NAMES HOLD THAT COLOUR and most mean a version of this: placeholder, hint,
   option-desc, typeahead-empty, panel-empty, panel-lede, board-card-meta,
   document-value-empty, meta, and the primitive. A system is meant to have
   semantic aliases so one can be retuned alone -- but ten is a lot of places to
   retune together, and whether any two would ever differ is the platform's own
   half of de-sb3k15ct. This reads the primitive meanwhile, which is what 18 other
   rules in this sheet already do. st-3w28p3a7. */
.is-empty { color: var(--ink-faint); }

/* A SMALL FACT THAT IS THE WAY SOMEWHERE. No underline at rest, because a page
   of faint mono ids underlined is a page of rules; both back on hover, and one
   step darker rather than the full ink -- a fact that goes dark reads as a
   heading arriving instead of the same fact lit up.

   st-3w28p3a7. `parkour`'s `.pk-gov-id` was this written privately, and it is
   the eighth of twelve mono facts across five consoles that `.meta` now dresses. */
a.meta { text-decoration: none; }
a.meta:hover { color: var(--component-meta-hover-fg); text-decoration: underline; }

.num {
  color: var(--component-num-fg);
  font-family: var(--component-num-face);
}

/* ---------- component.rel: the name of an edge, as a tag ----------

   st-3w28p3a7, and the strongest case this conversion met: `.gb-rel` and
   `.ov-rel` were the SAME SIX DECLARATIONS, character for character, in two
   stylesheets. gabriela's node page and overlook's connections table both draw
   the relationship a row stands in, and each wrote the tag for it.

   NOT `.chip`, which is the same idea in the other tone. A chip is a tag
   somebody put on a thing: sunk ground, muted ink, a pill. This is STRUCTURAL
   vocabulary -- contains, governs, blocks -- so it is brand ink on a brand tint,
   and the radius is square-ish because it reads as a type name rather than a
   label.

   AND AN EDGE POINTING THE OTHER WAY IS A TONE OF IT, which gabriela drew and
   overlook did not: an edge you are the target of is not an edge you declared. */

.rel {
  font-family: var(--component-rel-face);
  font-size: var(--component-rel-size);
  color: var(--component-rel-fg);
  background: var(--component-rel-bg);
  padding: var(--component-rel-pad-y) var(--component-rel-pad-x);
  border-radius: var(--component-rel-radius);
  white-space: nowrap;
}
.rel[data-dir="in"] {
  color: var(--component-rel-in-fg);
  background: var(--component-rel-in-bg);
}

/*
 * A PANEL WITH NOTHING IN IT. The panel's own colours, a dashed edge to say the
 * box is a placeholder rather than content, and the words in the middle.
 *
 * NOT `.empty`, which is the content site's: left-aligned, ink-muted, a 12px
 * radius and 22px of padding, none of it token-keyed. Unifying the two would
 * change the public site's pages, which is a decision about the brand rather
 * than about a console. st-3w28p3a7.
 */
.panel-empty {
  color: var(--panel-empty-fg);
  background: var(--panel-bg);
  border: 1px dashed var(--panel-border);
  border-radius: var(--panel-radius);
  padding: var(--panel-empty-pad);
  text-align: center;
}
/* AN EMPTY PANEL THAT SAYS HOW TO START: the sentence, then the press under it
   (shared.TableComponent's emptyAction, st-9p0ckejn criterion 10). */
.panel-empty > p { margin: 0 0 var(--s4); }

/*
 * ONE BIG NUMBER WITH A CAPTION. `component.stat` has held every value of this
 * since the construct was written -- the box, the padding, the value's size,
 * weight, colour, tracking and leading, and the caption's colour and size -- and
 * the CRM was the only thing drawing it, under a name only the CRM knew.
 *
 * `stat-tile` AND NOT `stat`, BECAUSE THAT NAME IS ALREADY TAKEN TWICE. A global
 * class is a shared namespace: `review.css` dresses `.stat` as a sunk box with no
 * border, and `arcana.css` dresses `#arcana .stat` as a small faint right-aligned
 * count with no box at all. A rule here called `.stat` adds a border to the first
 * and a bordered, padded tile to the second -- two pages changed by a promotion
 * that was about neither of them. The first draft did exactly that, and the only
 * thing that found it was going to look.
 *
 * `is-lead` IS THE ONE THAT MATTERS MOST ON THE PAGE, in the brand's own colour.
 * A tile is not special because it is first; it is special because a screen says
 * so. st-3w28p3a7.
 */
.stat-tile {
  background: var(--component-stat-bg);
  border: 1px solid var(--component-stat-border);
  border-radius: var(--component-stat-radius);
  padding: var(--component-stat-pad-y) var(--component-stat-pad-x);
}

.stat-tile .n {
  display: block;
  font-size: var(--component-stat-value-size);
  font-weight: var(--component-stat-value-weight);
  color: var(--component-stat-value-fg);
  letter-spacing: var(--component-stat-value-tracking);
  line-height: var(--component-stat-value-leading);
}

.stat-tile .k {
  display: block;
  color: var(--component-stat-label-fg);
  font-size: var(--component-stat-label-size);
  margin-top: var(--space-1);
}

.stat-tile.is-lead .n { color: var(--brand-700); }

/*
 * THE PRESS THAT DELETES SOMETHING. The quiet button, with the danger signal for
 * its words and a danger wash under the pointer.
 *
 * A MODIFIER ON `.btn` LIKE `.btn-quiet`, so it inherits the face, the padding,
 * the radius and the size rather than restating them -- which is what the CRM's
 * own `.crm-danger` did, six declarations deep, because it was used on a bare
 * button with no `.btn` beside it.
 *
 * THREE CONSOLES HAD WRITTEN THIS: crm-danger, ov-danger, pk-btn-stop,
 * pk-danger -- and overlook had already called one of them btn-danger, which is
 * the name this takes. st-3w28p3a7.
 */
.btn-danger {
  background: transparent;
  color: var(--control-button-danger-fg);
  border: 1px solid var(--control-button-quiet-border);
}

.btn-danger:hover {
  background: var(--control-button-danger-hover-bg);
  border-color: var(--control-button-danger-fg);
  color: var(--control-button-danger-fg);
}

/*
 * AND THE ROW OF TILES. `component.stat` holds both numbers: the gap between
 * tiles, and the width below which one wraps to its own row rather than being
 * squeezed. A console that had the tile and not the row would still be deciding
 * the arrangement itself. st-3w28p3a7.
 */
.stat-grid {
  display: grid;
  gap: var(--component-stat-gap);
  margin-bottom: var(--space-8);
  grid-template-columns: repeat(auto-fit, minmax(var(--component-stat-min-width), 1fr));
}

/*
 * A CALLOUT INSIDE A PANEL, and a list inside a callout. Both are the system's
 * question rather than a console's: how far a notice sits from what it annotates,
 * and how far a list indents. No new class for either -- the CRM's import summary
 * wrote both as inline styles on `.callout` and on a bare `<ul>`.
 *
 * A PANEL LEADS WITH ITS HEADING, so a callout is never the first thing in one
 * and the margin always has something above it to sit under. st-3w28p3a7.
 */
.panel .callout { margin-top: var(--component-callout-gap); }

.callout ul {
  margin: var(--component-callout-list-gap) 0 0;
  padding-left: var(--component-callout-list-indent);
}

/*
 * A BOX SOMEBODY PASTES DATA INTO. Mono and one step small, because the thing it
 * must do is line columns up -- the same two properties `.meta` gives a
 * timestamp, and for the same reason. How TALL the box is belongs to the screen
 * that asks for it. st-3w28p3a7.
 */
.field-code {
  font-family: var(--component-code-face);
  font-size: var(--component-code-size);
  min-height: var(--component-code-entry-height);
}

/*
 * A SCORE OUT OF FIVE, AS A ROW OF SEGMENTS. The scale is how many there are and
 * a reader counts them, which is why the segments have a fixed size rather than
 * sharing a track: this is a COUNT out of five, not a proportion of a whole --
 * parkour's progress bar is the other picture and will have its own name.
 * st-3w28p3a7.
 */
.rating { display: inline-flex; gap: var(--component-rating-gap); }

.rating i {
  display: inline-block;
  width: var(--component-rating-segment-width);
  height: var(--component-rating-segment-height);
  border-radius: var(--component-rating-radius);
  background: var(--component-rating-segment-bg);
}

.rating i.on { background: var(--component-rating-on-bg); }
/*
 * A SCORE AS A SMALL BADGE: "14/20", the total bold and the denominator one step
 * down. The CRM's deal card drew this privately as .crm-card .rank, every value
 * already a token. st-3w28p3a7, de-6q00090a: promoted because nothing here was
 * this shape -- .chip is a pill in the chip's ground and .rel is brand ink in
 * mono, and a score is neither a label nor an edge.
 *
 * WEIGHT AND NOT HUE CARRIES THE BAND. A board's lanes already use colour to
 * mean stage, so a second colour scale on top would be two meanings in one
 * channel; the top two bands go full ink on the brand's lightest tint.
 *
 * AND THE BOTTOM BAND IS LIGHTER BY WEIGHT, NOT BY ALPHA. It was opacity 0.7
 * over faint ink, which on the sunk ground is under 4.5:1 -- the failure the
 * denominator's own note already refused. de-q39nyx8t's scale has no step for
 * "less of the subject but still read", and mute (0.55) would fail worse, so
 * the regular weight says it instead and the ink keeps its contrast.
 *
 * The deals table writes a .rank too, undressed; wearing this there is the
 * second caller and a change somebody should see first.
 */
.score-badge {
  flex: 0 0 auto; font-variant-numeric: tabular-nums;
  font-size: var(--type-size-xs); font-weight: var(--type-weight-bold); color: var(--ink-faint);
  padding: var(--space-0-25) var(--s1); border-radius: var(--radius-xs); background: var(--sunk);
}
.score-badge i { font-style: normal; font-weight: var(--type-weight-regular); font-size: var(--type-size-2xs); color: var(--ink-muted); }
.score-badge[data-band="4"], .score-badge[data-band="5"] { color: var(--ink); background: var(--brand-100); }
.score-badge[data-band="1"] { font-weight: var(--type-weight-regular); }
/* PART-SCORED IS MARKED, so 12/15 does not read as a bad twenty. */
.score-badge.is-partial { border: 1px dashed var(--line-strong); padding: 0 calc(var(--s1) - 1px); }
/* NOT SCORED YET: an em dash, on the badge's own ground so it never sits on a
   tinted lane at ghost contrast. */
.score-badge.is-none { color: var(--ink-faint); font-weight: var(--type-weight-regular); }
/*
 * A TOTAL UNDER WHAT IT TOTALS: "15 of 20" below a rubric, the figure large and
 * full ink, the rest of the sentence muted at the small step. The CRM wrote it as
 * .crm-rank-total. .pg-figure is the same idea at the page head's scale -- xs,
 * faint, a bold figure -- and folding the two onto one role with a size step is
 * what repays this one. st-3w28p3a7.
 */
.tally { font-size: var(--type-size-sm); color: var(--ink-muted); }
.tally b { font-size: var(--type-size-lg); color: var(--ink); font-variant-numeric: tabular-nums; }
/*
 * WHAT HAPPENED, IN ORDER: one event per row -- when, what, and who at the end.
 * The small step, because a history is read down, not across. The CRM's stage
 * history drew it as .crm-history; gabriela's .gb-history is the same list of
 * the same events with a rule under each row, and folding it is what repays
 * this. st-3w28p3a7, de-6q00090a.
 *
 * The date and the actor wear .meta; what this adds is where they sit: a date
 * that wraps is a date in two columns, and the actor goes to the end.
 */
.history { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s2); font-size: var(--type-size-sm); }
.history li { display: flex; gap: var(--s3); align-items: baseline; }
.history .when { white-space: nowrap; }
.history .who { margin-left: auto; }
/*
 * ONE ENTRY IN A LIST OF WRITING -- a note on a record -- set off by
 * component.list's divider down its left and its gap between entries, the words
 * in full ink at the small step, line breaks kept. The CRM's notes drew it as
 * .crm-note. st-3w28p3a7.
 */
.list-entry { border-left: 2px solid var(--component-list-divider); padding: 0 0 0 var(--s4); margin: var(--component-list-gap) 0; }
.list-entry p { margin: var(--s1) 0 0; white-space: pre-wrap; color: var(--ink); font-size: var(--type-size-sm); line-height: var(--leading-normal); }
/*
 * WHERE YOU ARE IN A LONG LIST, and the way to the pages either side: faint at
 * the small step, the links in brand ink. The CRM's lists and access log drew it
 * as .crm-page. st-3w28p3a7.
 */
/* MUTED, NOT FAINT (st-wbcm6161): the faint step measured 4.47:1 on the sunk
   ground, under the 4.5 small text needs. */
.pager { display: flex; gap: var(--s3); align-items: center; font-size: var(--type-size-sm); color: var(--ink-muted); }
.pager a { color: var(--brand-600); text-decoration: none; font-weight: var(--type-weight-semibold); }

/*
 * THE DESIGN SWITCH. One button, drawn by assets/design-switch.mjs on every page
 * shell() renders, that swaps the whole design system by setting one attribute
 * on html. It wears the tokens like everything else, so it repaints with the
 * page it switches: the swatch is the active brand's own mark colour.
 *
 * Fixed above the footer's height rather than over it, so the footer's trace
 * button stays pressable. The class name was grepped across the repository
 * before it was taken; nothing else dresses it.
 */
.arc-design-switch {
  position: fixed; right: var(--s4); bottom: calc(var(--s16) + var(--s2)); z-index: 40;
  display: inline-flex; align-items: center; gap: var(--s2);
  padding: var(--s2) var(--s4);
  border: 1px solid var(--ink-raise); border-radius: var(--radius-pill);
  background: var(--component-toast-bg); color: var(--on-dark);
  font: var(--type-weight-semibold) var(--control-button-size) / 1 var(--sans);
  box-shadow: var(--elevation-floating);
  cursor: pointer;
  transition: border-color var(--motion-fast) var(--ease), box-shadow var(--motion-fast) var(--ease);
}
.arc-design-switch:hover { border-color: var(--brand-500); }
.arc-design-switch:focus-visible {
  outline: var(--control-focus-width) solid var(--control-focus-ring);
  outline-offset: var(--control-focus-offset);
}
.arc-design-switch-swatch {
  width: var(--s3); height: var(--s3); border-radius: var(--radius-pill);
  background: var(--brand-500);
}
.arc-design-switch-kicker {
  font-family: var(--mono); font-size: var(--type-size-2xs); font-weight: var(--type-weight-medium);
  letter-spacing: var(--type-tracking-wider); text-transform: uppercase; color: var(--on-dark-muted);
}

/* THE FADE A SCROLLING STRIP WEARS WHILE MORE OF IT WAITS, run on the strip's
   own scroll timeline by the phone rules below (st-9p0ckejn criterion 10). */
@keyframes strip-has-more {
  from {
    -webkit-mask-image: linear-gradient(to right, currentColor calc(100% - var(--s8)), transparent);
    mask-image: linear-gradient(to right, currentColor calc(100% - var(--s8)), transparent);
  }
  to { -webkit-mask-image: none; mask-image: none; }
}

/* ---------- the chrome on a phone (st-wbcm6161) ----------
   At the platform's one phone width, 760px, every screen measured the same two
   faults before anything of its own: the topbar's nav ran the page sideways,
   and every link in the chrome was a press target under 44px (11 to 25 per
   screen, 1,970 across the sweep). So on a phone the chrome becomes a touch
   surface:
   - the nav takes a row of its own and scrolls inside itself, so the page
     never does;
   - the section stacks: chrome, then the rail as a strip that scrolls across,
     then the tabs, then the workspace. A 260px rail beside a 375px screen left
     the workspace 115px;
   - every press target in the chrome reaches control.button.min-target, the
     token the target check measures against (WCAG 2.2 SC 2.5.5).
   Desktop keeps its density: the check, and the thumb, are on the phone. */
@media (max-width: 760px) {
  .topbar { flex-wrap: wrap; height: auto; gap: 0 var(--s4); padding: var(--s2) var(--s4); }
  .nav {
    order: 3; flex: 1 0 100%; gap: var(--s2);
    overflow-x: auto; scrollbar-width: none; overscroll-behavior-x: contain;
  }
  .nav::-webkit-scrollbar { display: none; }
  .nav a, .account a, .account .btn, .account button, .footer a, .footer button,
  .wordmark, .sec-rail-row, .sec-rail-child, .sec-tab, .sec-title, .sync-open {
    display: inline-flex; align-items: center;
    min-height: var(--control-button-min-target); min-width: var(--control-button-min-target);
  }
  .nav a { flex: none; padding: 0 var(--s2); }
  /* AND THE LIBRARY'S OWN PRESSES, which the sweep could not see while the page
     ran sideways: a button, a toolbar's actions, a date picker's presets, a
     pager's links and a section's call to action measured 20 to 34px tall. */
  /* By role and data attribute, not by the controls' own class names, so the
     site's vocabulary does not grow (ui-vocabulary-only-falls). */
  .btn, [role="toolbar"] button, [data-control="date-picker"] button, .pager a, .content-section-link {
    display: inline-flex; align-items: center;
    min-height: var(--control-button-min-target);
  }
  .pager a { min-width: var(--control-button-min-target); justify-content: center; }
  .footer { flex-wrap: wrap; height: auto; padding: var(--s2) var(--s4); gap: 0 var(--s4); }

  .sec {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "chrome" "rail" "tabs" "workspace";
    grid-template-rows: auto auto auto minmax(0, 1fr);
  }
  .sec-chrome { padding: var(--s2) var(--s4); }
  /* ONLY THE SECTION'S OWN RAIL BECOMES A STRIP. A rail drawn on its own -- the
     gallery's specimen -- keeps its column, or its rows reach past the screen. */
  .sec > .sec-rail {
    flex-direction: row; align-items: center; gap: var(--s1);
    padding: var(--s2) var(--s4); overflow-x: auto; overflow-y: hidden;
    scrollbar-width: none; overscroll-behavior-x: contain;
  }
  /* THE RULE MOVES FROM THE RAIL'S SIDE TO ITS FOOT, on the rail itself: its
     paint names no section, so the section is not counted a painted role. */
  .sec-rail { border-right: none; border-bottom: 1px solid var(--line-strong); }
  .sec > .sec-rail::-webkit-scrollbar { display: none; }
  .sec > .sec-rail .sec-rail-row, .sec > .sec-rail .sec-rail-child { flex: none; white-space: nowrap; }
  .sec > .sec-rail .sec-rail-children { display: contents; }
  .sec-tabs { overflow-x: auto; scrollbar-width: none; }

  /* COMPOSED FOR THE PHONE, NOT SQUEEZED ONTO IT (st-9p0ckejn criterion 10).
     The judged rubric's first fix for CRM organizations and the UI assessor
     at 375px was this chrome, not either screen:
     - A TAB NEVER SHRINKS BELOW ITS WORD. A tab was a shrinkable flex item, so
       the strip pressed "Organizations" into a box narrower than the word,
       which ran into "People", and "Access log" broke onto two lines. The
       strip scrolls; its tabs keep their size. */
  .sec-tab { flex: none; white-space: nowrap; }
  /* - A STRIP THAT SCROLLS SAYS SO, AND ONE THAT FITS DOES NOT. The nav, the
       rail and the tabs scrolled sideways with no scrollbar, so "Research" and
       "Par" were simply cut off. The trailing edge fades over --s8 while there
       is more to the right: the fade is an animation on the strip's own scroll,
       so it lifts when the strip reaches its end, and a strip that does not
       scroll has an inactive timeline and no fade at all. currentColor is the
       mask's opaque half: only its alpha is read. */
  .nav, .sec > .sec-rail, .sec-tabs {
    animation: strip-has-more linear both;
    animation-timeline: scroll(self inline);
  }
  /* - HOME IS THE WORDMARK'S JOB. The wordmark beside it already goes home,
       and dropping the duplicate is what lets the signed-in nav fit a phone. */
  .nav a[href="/"] { display: none; }
  .nav { gap: 0; }
  /* - THE SECTION CHROME STEPS ASIDE. It was a row of its own between the
       topbar and the rail: the section's name, which the nav and the rail's
       current row already say, and Sync, which compares this machine's
       checkout with the deployment -- a desk's operation, with no checkout
       on a phone. Its box steps aside (display: contents) and both go. ONLY A
       SECTION WHOSE CHROME HOLDS SYNC: the gallery's chrome says what it is
       in words, and its rail is a list, so it keeps its own rows. */
  .sec:has(> .sec-chrome .sync) {
    grid-template-areas: "rail" "tabs" "workspace";
    grid-template-rows: auto auto minmax(0, 1fr);
  }
  .sec:has(> .sec-chrome .sync) > .sec-chrome { display: contents; }
  .sec:has(> .sec-chrome .sync) > .sec-chrome .sec-title,
  .sec:has(> .sec-chrome .sync) > .sec-chrome .sec-chrome-aside { display: none; }
  /* - THE RAIL AND THE TABS ARE EACH ONE STRIP THAT SCROLLS (st-p454gzzq).
       Scrolled, the rubric called them clipped; wrapped, it said they should
       be "one horizontally scrolling strip". Ben chose once, round
       ui-component-library Q21 (f13, 2026-10-28): "One scrolling strip with
       a visible cue: a cut-off last tab and an edge fade." The fade is the
       strip-has-more animation above; the cut-off tab is the strip's own
       width, which ends part-way through a word rather than at a gap, and the
       rule is plan/ui-quality/rubric.md's, so a run stops flipping it.
       rail-current.mjs scrolls the place you are on into view. */
  .sec > .sec-rail, .sec-tabs { flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden; }
  /* The cut has to be seen through the --s8 fade, so the strips are spaced
     for the phone: the tabs at the phone's own --s4 gutter rather than the
     desktop's --s6, closer together, and the rail's rows at --s1 inside
     their 44px boxes. At 375px CRM's "Access log" and the rail's
     "Whiteboard" then show about half their word before the edge. */
  .sec-tabs { gap: var(--s2); padding-inline: var(--s4); }
  /* Two rows, not three: on the strip a row is its name, at the gutter's
     padding, with the mark left to the desktop rail where there is room for
     both. The current row keeps its fill and its edge. */
  .sec > .sec-rail { gap: 0; }
  .sec > .sec-rail .sec-rail-row { padding: 0 var(--s1); justify-content: center; }
  .sec > .sec-rail .sec-rail-icon { display: none; }
  .sec-tab { padding: 0 var(--s1); }
  /* - THE ACCOUNT SHARES THE WORDMARK'S ROW. The address beside Sign out took
       a row of its own and pushed the page's title 50px further down an 812px
       screen. It is still read out, and still on the desktop chrome; on a
       phone Sign out is the account's one press. */
  .account .who {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap;
  }
  /* - AND THE FOOTER IS ONE ROW. The tagline repeats the wordmark above it and
       took a row of the workspace's height on every section screen. */
  .footer > span:first-child { display: none; }
  .sec-workspace { padding: var(--s4); }
}
