/* ============================================================================
 * THE LEDGER — component layer
 * Implements BUILD-CONTRACT.md §1 (tokens) and §2 (components).
 *
 * Deliberately PLAIN CSS, not Tailwind utilities. The production box has no
 * node toolchain and a compiled Tailwind build only contains classes it can
 * find; specifying these as literal CSS means a new component can never
 * silently render unstyled. See docs/frontend-build.md.
 *
 * Values are lifted from handoff/reference-mock-the-ledger.html. Where the
 * contract's §1/§2 state an explicit value that differs from the mock, the
 * contract wins (it is the governing document); those cases are marked.
 * ==========================================================================*/

/* ── Fonts ─────────────────────────────────────────────────────────────── */
@font-face { font-family:'Newsreader'; font-style:normal; font-weight:400;
  src:url('../fonts/newsreader-400-normal.woff2') format('woff2'); font-display:swap; }
@font-face { font-family:'Newsreader'; font-style:italic; font-weight:400;
  src:url('../fonts/newsreader-400-italic.woff2') format('woff2'); font-display:swap; }
@font-face { font-family:'Newsreader'; font-style:normal; font-weight:500;
  src:url('../fonts/newsreader-500-normal.woff2') format('woff2'); font-display:swap; }
@font-face { font-family:'Newsreader'; font-style:italic; font-weight:500;
  src:url('../fonts/newsreader-500-italic.woff2') format('woff2'); font-display:swap; }
@font-face { font-family:'Newsreader'; font-style:normal; font-weight:600;
  src:url('../fonts/newsreader-600-normal.woff2') format('woff2'); font-display:swap; }
@font-face { font-family:'Newsreader'; font-style:italic; font-weight:600;
  src:url('../fonts/newsreader-600-italic.woff2') format('woff2'); font-display:swap; }

/* ── §1 Tokens ─────────────────────────────────────────────────────────── */
:root {
  --lg-bg:          #07090d;
  --lg-bg-deep:     #05070a;
  --lg-row:         #10151f;   /* row rule                */
  --lg-rule:        #1a2235;   /* section rule            */
  --lg-rule-strong: #243049;   /* head rule / box border  */
  --lg-divider:     #141b29;   /* stat column divider     */
  --lg-hover:       #0a0e17;   /* ledger row hover        */

  --lg-ink-100: #eef2fa;       /* figures, active nav     */
  --lg-ink-200: #dfe7f4;       /* primary row text        */
  --lg-ink-300: #d0e7ff;       /* muted body — WCAG 7.07:1 */
  --lg-ink-400: #88a6d6;       /* micro/aside ONLY        */
  --lg-ink-500: #526c94;       /* pending / axis ticks    */
  --lg-nav-idle:#bed6ff;

  --lg-accent:  #38bdf8;
  --lg-link:    #7dd3fc;
  --lg-link-hi: #bae6fd;

  --lg-good: #34d399;
  --lg-warn: #fbbf24;
  --lg-bad:  #fb7185;
  --lg-info: #38bdf8;

  --lg-band-24: #fbbf24;
  --lg-band-5:  #38bdf8;
  --lg-band-6:  #e879f9;

  --lg-bar-track: #10151f;
  --lg-bar-fill:  #a0beee;

  --lg-t-hover: 120ms;
  --lg-t-panel: 220ms;
  --lg-t-drawer: 350ms;
  --lg-ease-panel: cubic-bezier(.2,.8,.2,1);
}

/* ── §2.1 Page frame ───────────────────────────────────────────────────── */
body.lg-body {
  margin:0; background:var(--lg-bg); color:#cbd5e6;
  font-family:'Inter var',Inter,ui-sans-serif,system-ui,sans-serif;
  background-image:none;               /* .grid-bg wash is deleted */
}
.lg-frame { max-width:1560px; margin:0 auto; padding:22px 40px 60px; }
.lg-body a { color:var(--lg-link); text-decoration:none; }
.lg-body a:hover { color:var(--lg-link-hi); text-decoration:underline; }

/* ── §2.2 Masthead ─────────────────────────────────────────────────────── */
/* §2.2 masthead — a brand band carrying the Observatory dome (static/brand/
   masthead.jpg). The gradient darkens left→right so the wordmark reads over the
   image and the meta/whoami on the right sits on near-black. Authenticated
   shell only; the login page is untouched. */
.lg-masthead {
  display:flex; align-items:center; justify-content:space-between;
  min-height:86px; padding:14px 22px; margin-bottom:8px;
  border:1px solid var(--lg-rule,#1b2536);
  background-image:
    linear-gradient(90deg, rgba(5,7,10,.40) 0%, rgba(5,7,10,.58) 50%, rgba(5,7,10,.88) 100%),
    url('../brand/masthead.jpg');
  background-size:cover; background-position:center 30%; background-repeat:no-repeat;
}
.lg-brand {
  font:500 27px 'Newsreader',Georgia,serif; color:var(--lg-ink-100);
  font-style:italic; text-decoration:none; text-shadow:0 1px 14px rgba(0,0,0,.65);
}
.lg-brand:hover { color:var(--lg-ink-100); text-decoration:none; }
.lg-masthead-meta { display:flex; gap:22px; align-items:center; }
.lg-clock { font:400 12px 'JetBrains Mono',ui-monospace,monospace; color:var(--lg-ink-400); }
.lg-whoami { font:400 12px 'JetBrains Mono',ui-monospace,monospace; color:var(--lg-ink-300); }
.lg-whoami button {
  background:none; border:0; padding:0; cursor:pointer;
  font:inherit; color:var(--lg-link);
}
.lg-whoami button:hover { color:var(--lg-link-hi); text-decoration:underline; }

/* ── §2.3 Primary nav ──────────────────────────────────────────────────── */
.lg-nav {
  display:flex; gap:34px; margin-top:16px; align-items:baseline;
  border-bottom:3px double var(--lg-ink-500);
}
.lg-nav a {
  font:600 13px 'Inter var',Inter,sans-serif; letter-spacing:.14em;
  text-transform:uppercase; color:var(--lg-nav-idle);
  padding-bottom:9px; text-decoration:none;
  transition:color var(--lg-t-hover) ease-out;
}
.lg-nav a:hover { color:var(--lg-ink-200); text-decoration:none; }
.lg-nav a.is-active {
  font-weight:700; color:var(--lg-ink-100);
  border-bottom:2px solid var(--lg-accent);
}
.lg-nav .lg-nav-spacer { flex:1; }

/* ── §2.12 Trail ───────────────────────────────────────────────────────── */
.lg-trail {
  font:400 11px 'JetBrains Mono',ui-monospace,monospace;
  color:var(--lg-ink-400); padding-bottom:9px;
}
.lg-trail a { color:var(--lg-link); }
.lg-trail .lg-trail-sep { color:var(--lg-ink-500); padding:0 3px; }

/* ── §2.4 Sub-nav ──────────────────────────────────────────────────────── */
.lg-subnav {
  display:flex; gap:24px; padding:9px 0; flex-wrap:wrap;
  border-bottom:1px solid var(--lg-rule);
}
.lg-subnav a {
  font:500 13px 'Inter var',Inter,sans-serif; color:var(--lg-ink-300);
  text-decoration:none; transition:color var(--lg-t-hover) ease-out;
}
.lg-subnav a:hover { color:var(--lg-ink-200); text-decoration:none; }
.lg-subnav a.is-active { font-weight:600; color:var(--lg-link); }

/* ── §2.5 Dateline / insight line ──────────────────────────────────────── */
.lg-dateline {
  display:flex; justify-content:space-between; align-items:baseline; gap:8px 24px;
  flex-wrap:wrap; padding:9px 0; border-bottom:1px solid var(--lg-rule);
}
/* Contract §1 specifies 12.5/1.6; the mock renders 11/1.5. Contract wins. */
.lg-insight {
  font:400 13.5px/1.6 'Inter var',Inter,sans-serif;
  color:var(--lg-ink-300); font-style:italic;
  /* A basis, so it is never the only thing that can shrink. Against a nowrap
     sibling with no basis it collapses to a one-word column rather than the
     row wrapping — which is exactly what happened as the meta tail grew. */
  flex:1 1 22em; min-width:0;
}
.lg-insight b, .lg-insight strong { color:var(--lg-ink-100); font-weight:600; }
.lg-insight .good { color:var(--lg-good); } .lg-insight .warn { color:var(--lg-warn); }
.lg-insight .bad  { color:var(--lg-bad);  } .lg-insight .info { color:var(--lg-info); }

/* Semantic ink INSIDE a table row. Every earlier good/warn/bad rule is
   container-scoped (.lg-chip.good, .lg-insight .good, …) so a bare class on a
   row cell had no reachable rule: the span inherited body ink and
   .lg-dot{background:currentColor} painted a near-white circle whatever the
   status. That white dot is how a wrong status comparison stayed invisible
   for weeks — the two bugs masked each other. */
.lg-table-row .good { color:var(--lg-good); }
.lg-table-row .warn { color:var(--lg-warn); }
.lg-table-row .bad  { color:var(--lg-bad); }

.lg-livepill {
  font:400 11px 'JetBrains Mono',ui-monospace,monospace;
  color:var(--lg-ink-400); white-space:nowrap;
}
/* Everything to the right of the insight sentence: the pill, then the meta
   figures. One flex child so `space-between` has two sides to work with, and
   the run reads as continuous right-aligned text that wraps at the edge. */
.lg-dateline-meta {
  flex:1 1 20em; min-width:0; text-align:right;
}
/* The figures themselves. Same type as the pill, but WRAPPABLE — this text has
   no bound (freshness, cadence, laggard, APs, fleets, areas, indexed
   identities) and it used to sit inside the nowrap pill above. */
.lg-dateline-tail {
  font:400 11px 'JetBrains Mono',ui-monospace,monospace;
  color:var(--lg-ink-400); white-space:normal;
}
.lg-livedot {
  display:inline-block; width:6px; height:6px; border-radius:50%;
  background:var(--lg-good); vertical-align:1px; animation:lg-livepulse 2s infinite;
}
@keyframes lg-livepulse { 0%,100%{opacity:1} 50%{opacity:.35} }

/* ── §2.6 Verdict line ─────────────────────────────────────────────────── */
.lg-verdict {
  display:flex; gap:14px; align-items:baseline;
  padding:12px 0; border-bottom:1px solid var(--lg-rule);
}
.lg-verdict-label {
  font:700 10px 'Inter var',Inter,sans-serif; letter-spacing:.16em;
  text-transform:uppercase; color:var(--lg-ink-300); white-space:nowrap;
}
.lg-verdict-text {
  font:400 15px/1.55 'Newsreader',Georgia,serif; font-style:italic; color:var(--lg-ink-200);
}
.lg-verdict-text .good { color:var(--lg-good); } .lg-verdict-text .warn { color:var(--lg-warn); }
.lg-verdict-text .bad  { color:var(--lg-bad);  } .lg-verdict-text .info { color:var(--lg-info); }

/* ── §1 Display type ───────────────────────────────────────────────────── */
.lg-title { font:500 30px/1.15 'Newsreader',Georgia,serif; color:var(--lg-ink-100); margin:0; }
.lg-figure { font:500 52px/1.05 'Newsreader',Georgia,serif; color:var(--lg-ink-100); }
.lg-figure-sm { font:500 40px/1.05 'Newsreader',Georgia,serif; color:var(--lg-ink-100); }
.lg-figure .lg-figure-sub { font-size:24px; color:var(--lg-ink-400); }

.lg-sec-head {
  font:600 11px/1 'Inter var',Inter,sans-serif; letter-spacing:.12em;
  text-transform:uppercase; color:var(--lg-ink-300);
}
.lg-col-head {
  font:600 10px/1 'Inter var',Inter,sans-serif; letter-spacing:.1em;
  text-transform:uppercase; color:var(--lg-ink-400);
}
.lg-mono { font-family:'JetBrains Mono',ui-monospace,monospace; font-variant-ligatures:none; font-variant-numeric:tabular-nums; }

/* ── §2.7 Stat block ───────────────────────────────────────────────────── */
.lg-stat {
  display:grid; grid-auto-flow:column; grid-auto-columns:1fr;
  padding:20px 0 18px; border-bottom:1px solid var(--lg-rule);
}
/* min-width:0 — a grid item defaults to min-width:auto, so an over-long
   figure pushes the whole row wider instead of the column shrinking, and the
   last tile bleeds into the rail (operator screenshot, 2026-07-31). */
.lg-stat > div { border-right:1px solid var(--lg-divider); padding:0 18px; min-width:0; }
.lg-stat > div:first-child { padding-left:0; }
.lg-stat > div:last-child  { border-right:0; padding-right:0; }
.lg-stat-label { font:600 11px 'Inter var',Inter,sans-serif; letter-spacing:.12em;
  text-transform:uppercase; color:var(--lg-ink-300); }
/* §15.3 — 44px, sized for five digits. A hero figure is ONE number, so the
   character-count classes (is-xl/is-lg/is-md) are DELETED rather than tuned:
   with no composite string in a hero slot the overrun cannot recur. */
.lg-stat-figure { font:500 44px/1.05 'Newsreader',Georgia,serif; color:var(--lg-ink-100);
  margin-top:8px; white-space:nowrap; }
/* Four tiles, the fourth wider for the estate split. */
.lg-stat-4 { grid-auto-flow:unset; grid-template-columns:1fr 1fr 1fr 1.15fr; }

/* §15.2 — estates separate by INK WEIGHT, never a new hue. Aruba sits at the
   product accent; Cisco at FULL ink, because near-white holds at small
   quantity on this background and the 6% estate must stay legible in every
   stacked bar and legend without special-casing. */
.lg-est-aruba { color:var(--lg-info); }
.lg-est-cisco { color:var(--lg-ink-100); }
i.lg-est-aruba { background:var(--lg-info); }
i.lg-est-cisco { background:var(--lg-ink-100); }

.lg-split-bars { display:grid; grid-template-columns:26px 1fr 62px;
  gap:3px 8px; align-items:baseline; margin-top:9px; }
.lg-split-tag { font:600 9.5px 'JetBrains Mono',ui-monospace,monospace; }
.lg-split-bar { height:9px; background:var(--lg-rule); }
.lg-split-bar > i { display:block; height:9px; }
.lg-split-num { font:500 15px 'JetBrains Mono',ui-monospace,monospace;
  color:var(--lg-ink-100); text-align:right; }

/* §15.4 — the coverage band. One labelled group, each figure carrying a 2px
   FULL-INK left edge; the same edge and the same words mark a partial panel
   further down the page, so the convention is recognised rather than re-read. */
.lg-covband { border-top:1px solid var(--lg-divider); padding:10px 0 11px;
  display:grid; grid-auto-flow:column; grid-auto-columns:minmax(0,1fr);
  gap:0 24px; align-items:start; }
.lg-covband-head { font:600 10px 'Inter var',Inter,sans-serif; letter-spacing:.16em;
  color:var(--lg-ink-100); }
.lg-covband-note { font:400 10px/1.5 'JetBrains Mono',ui-monospace,monospace;
  color:var(--lg-ink-400); padding-top:4px; }
.lg-covitem { border-left:2px solid var(--lg-ink-100); padding-left:12px; }
.lg-covitem-label { font:600 10.5px 'Inter var',Inter,sans-serif; letter-spacing:.12em;
  text-transform:uppercase; color:var(--lg-ink-300); }
.lg-covitem-figure { font:500 26px/1.1 'Newsreader',Georgia,serif;
  color:var(--lg-ink-100); margin-top:4px; }
.lg-covitem-foot { font:400 10.5px 'JetBrains Mono',ui-monospace,monospace;
  color:var(--lg-ink-400); margin-top:4px; }
/* The same mark on a partial panel further down. */
.lg-partial { border-left:2px solid var(--lg-ink-100); padding-left:12px; }
.lg-stat-figure.good { color:var(--lg-good); } .lg-stat-figure.warn { color:var(--lg-warn); }
.lg-stat-figure.bad  { color:var(--lg-bad);  }
.lg-stat-foot { font:400 11px 'JetBrains Mono',ui-monospace,monospace;
  color:var(--lg-ink-400); margin-top:8px; }

/* ── §2.8 Ledger table ─────────────────────────────────────────────────── */
.lg-table { display:block; }
.lg-table-head, .lg-table-row { display:grid; gap:0 16px; align-items:center; }
.lg-table-head { padding-bottom:6px; border-bottom:1px solid var(--lg-rule-strong); }
.lg-table-head > span {
  font:600 10px 'Inter var',Inter,sans-serif; letter-spacing:.1em;
  text-transform:uppercase; color:var(--lg-ink-400);
}
.lg-table-row { padding:7px 0; border-bottom:1px solid var(--lg-row); }
.lg-table-row.is-link { cursor:pointer; }
.lg-table-row.is-link:hover { background:var(--lg-hover); }
.lg-num { font:500 13.5px 'JetBrains Mono',ui-monospace,monospace;
  color:var(--lg-ink-100); text-align:right; font-variant-numeric:tabular-nums; }
.lg-name { font:600 13.5px 'Inter var',Inter,sans-serif; color:var(--lg-ink-200); }
.lg-ident { font:500 13px 'JetBrains Mono',ui-monospace,monospace; color:var(--lg-ink-200); }
/* Used by 14 tables to keep a long name inside its grid cell. It was never
   defined, so those cells have been blowing their column out and pushing the
   row's later columns off their grid track. */
.lg-trunc { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0; }
.lg-asof { font:400 11px 'JetBrains Mono',ui-monospace,monospace;
  color:var(--lg-ink-400); text-align:right; white-space:nowrap; }
.lg-bar { height:3px; background:var(--lg-bar-track); }
.lg-bar > i { display:block; height:3px; background:var(--lg-bar-fill); }
.lg-bar > i.good { background:var(--lg-good); } .lg-bar > i.warn { background:var(--lg-warn); }
.lg-bar > i.bad  { background:var(--lg-bad);  } .lg-bar > i.info { background:var(--lg-info); }
.lg-empty { padding:18px 0; font:400 13px 'Inter var',Inter,sans-serif;
  color:var(--lg-ink-400); font-style:italic; border-bottom:1px solid var(--lg-row); }

/* ── §2.10 Chips & facets ──────────────────────────────────────────────── */
.lg-chip {
  display:inline-flex; align-items:center; gap:5px; white-space:nowrap;
  font:500 11px 'JetBrains Mono',ui-monospace,monospace;
  border:1px solid var(--lg-rule-strong); border-radius:2px; padding:2px 7px;
  color:var(--lg-ink-300);
}
.lg-chip.good { color:var(--lg-good); border-color:rgba(52,211,153,.4); }
.lg-chip.warn { color:var(--lg-warn); border-color:rgba(251,191,36,.4); }
.lg-chip.bad  { color:var(--lg-bad);  border-color:rgba(251,113,133,.4); }
.lg-chip.info { color:var(--lg-info); border-color:rgba(56,189,248,.4); }
.lg-chip.silent { border-style:dashed; color:#6f84ab; }
.lg-chip-key { opacity:.6; }
.lg-dot { display:inline-block; width:6px; height:6px; border-radius:50%; background:currentColor; }

/* ── §2.11 Section rule ────────────────────────────────────────────────── */
.lg-sec {
  display:flex; justify-content:space-between; align-items:baseline; gap:16px;
  padding-bottom:8px; border-bottom:1px solid var(--lg-rule-strong);
}
.lg-sec-summary { font:400 11px 'JetBrains Mono',ui-monospace,monospace;
  color:var(--lg-ink-400); text-transform:none; letter-spacing:0; }
.lg-sec-summary.good { color:var(--lg-good); }
.lg-sec-link { font:400 11px 'JetBrains Mono',ui-monospace,monospace; color:var(--lg-link); }

/* ── Rail box ──────────────────────────────────────────────────────────── */
.lg-box { border:1px solid var(--lg-rule-strong); padding:14px 16px; }
.lg-rail { border-left:1px solid var(--lg-rule); padding:20px 0 0 28px; }
.lg-split { display:grid; grid-template-columns:2.05fr 1fr; }
.lg-split > .lg-main { padding-right:30px; min-width:0; }

/* ── §2.13 Sticky page index ───────────────────────────────────────────── */
.lg-index { position:sticky; top:24px; width:132px; }
.lg-index a { display:block; font:400 12px/1.9 'Inter var',Inter,sans-serif; color:var(--lg-ink-300); }

/* ── §2.14 Loading system ──────────────────────────────────────────────── */
/* 5px, not the spec's 2px — operator ruling 2026-08-02: at 2px the strip was
   barely noticeable on a page load, and a loading signal nobody sees is a
   page that looks hung. */
.lg-strip {
  position:fixed; top:0; left:0; right:0; height:5px; z-index:2200;
  overflow:hidden; display:none; background:transparent;
}
.lg-strip.is-on { display:block; }
.lg-strip::after {
  content:''; position:absolute; inset:0 auto 0 0; width:30%;
  background:linear-gradient(90deg,transparent,var(--lg-accent),transparent);
  animation:lg-sweep 1.6s linear infinite;
}
@keyframes lg-sweep { from { transform:translateX(-100%);} to { transform:translateX(433%);} }

.lg-evidence {
  position:fixed; right:22px; bottom:22px; width:340px; z-index:2100;
  background:#090d16; border:1px solid var(--lg-rule-strong); padding:13px 15px;
  display:none;
}
.lg-evidence.is-on { display:block; }
.lg-evidence-head {
  display:flex; justify-content:space-between; align-items:baseline;
  font:600 11px 'Inter var',Inter,sans-serif; letter-spacing:.12em;
  text-transform:uppercase; color:var(--lg-ink-300); margin-bottom:9px;
}
.lg-evidence-elapsed { font:400 11px 'JetBrains Mono',ui-monospace,monospace;
  color:var(--lg-ink-400); text-transform:none; letter-spacing:0; }
.lg-evidence-elapsed.is-long { color:var(--lg-warn); }
.lg-evidence-row {
  font:400 12px/1.8 'JetBrains Mono',ui-monospace,monospace; color:var(--lg-ink-300);
  display:flex; gap:7px;
}
.lg-evidence-row .glyph { width:9px; flex:none; }
.lg-evidence-row .dur { color:var(--lg-ink-500); }
.lg-evidence-row.pending  { color:var(--lg-ink-500); }
.lg-evidence-row.running  .glyph { color:var(--lg-link); }
.lg-evidence-row.returned .glyph { color:var(--lg-good); }
.lg-evidence-row.failed   .glyph { color:var(--lg-bad); }
.lg-evidence-row.failed   .dur   { color:var(--lg-bad); }
.lg-evidence-row.partial  .glyph { color:var(--lg-warn); }
.lg-evidence-row.partial  .dur   { color:var(--lg-warn); }
.lg-evidence-note { font:400 11px/1.5 'Inter var',Inter,sans-serif;
  color:var(--lg-ink-400); margin-top:8px; font-style:italic; }

.lg-degraded {
  border:1px solid rgba(251,191,36,.4); background:rgba(251,191,36,.06);
  padding:9px 14px; margin:12px 0;
  font:400 12.5px 'Inter var',Inter,sans-serif; color:var(--lg-warn);
}

.lg-shimmer {
  height:11px; margin:7px 0; background:linear-gradient(90deg,#141b29,#1a2235,#141b29);
  background-size:200% 100%; animation:lg-shim 1.4s ease-in-out infinite;
}
@keyframes lg-shim { from{background-position:200% 0} to{background-position:-200% 0} }

/* ── §2.14/§2.15 Reduced motion ────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .lg-strip::after { animation:none; width:100%; opacity:.5; }
  .lg-shimmer { animation:none; }
  .lg-livedot { animation:none; }
  .lg-body *, .lg-body *::before, .lg-body *::after {
    transition-duration:0.01ms !important; animation-duration:0.01ms !important;
    animation-iteration-count:1 !important;
  }
}

/* ── Footer status bar ─────────────────────────────────────────────────── */
.lg-footer {
  display:flex; justify-content:space-between; gap:24px; flex-wrap:wrap;
  margin-top:38px; padding-top:12px; border-top:1px solid var(--lg-rule);
  font:400 11px 'JetBrains Mono',ui-monospace,monospace; color:var(--lg-ink-400);
}
.lg-footer .ok { color:var(--lg-good); }
.lg-footer .warn { color:var(--lg-warn); }

/* ── Small helpers used by migrated pages ──────────────────────────────── */
.lg-pillrow { display:flex; gap:8px; padding:12px 0 0;
  font:500 12px 'Inter var',Inter,sans-serif; align-items:center; }
.lg-pill { color:var(--lg-ink-300); border:1px solid var(--lg-rule); padding:3px 12px;
  text-decoration:none; transition:color var(--lg-t-hover) ease-out; }
.lg-pill:hover { color:var(--lg-ink-200); text-decoration:none; }
.lg-pill.is-active { color:var(--lg-ink-100); border-color:var(--lg-accent); }
.lg-note { font:400 11px 'JetBrains Mono',ui-monospace,monospace; color:var(--lg-ink-400); }

/* §8.1 — authority is a function of freshness. A STALE figure does not gain a
   badge; it loses weight, falling from full ink to body tone so it stops being
   the brightest thing on the page. Amber lives only in the stamp, never in the
   figure. Applied by the {% figure_class %} tag, never hand-typed. */
.lg-dim { color: var(--lg-ink-300) !important; font-weight: 400 !important; }

/* §8.4 — a table row is a LINK.
   The identifying cell carries a real <a href>, so middle-click, cmd-click,
   copy-link and keyboard all work because they are genuinely links. Hover
   belongs to the ROW (not the anchor), so the whole row still tints and the
   identity underlines. Focus renders identically to hover PLUS a 2px accent
   left edge, so mouse and keyboard converge on one visual. */
.lg-table-row.is-link { position: relative; }
.lg-table-row.is-link .lg-rowlink { color: inherit; text-decoration: none; }
.lg-table-row.is-link:hover .lg-rowlink,
.lg-table-row.is-link:focus-within .lg-rowlink { text-decoration: underline; }
.lg-table-row.is-link:focus-within {
  box-shadow: inset 2px 0 0 var(--lg-accent);
}
.lg-table-row.is-link .lg-rowlink:focus { outline: none; }
.lg-table-row.is-link .lg-rowlink:focus-visible { outline: none; }

/* ── Search: manual merge + grouped-identity edge bar ──────────────────────
   The merge bar is sticky so a selection made far down the result list stays
   actionable (§5 Search). Flat rules only — no card. */
.lg-mergebar {
  position: sticky; top: 0; z-index: 30;
  display: flex; align-items: center; gap: 12px;
  margin: 6px 0 0; padding: 9px 12px;
  background: #0c1220;
  border: 1px solid var(--lg-accent-dim, #1e3a5f);
  border-left: 2px solid var(--lg-accent);
}
.lg-mergebar b { color: var(--lg-accent); font-variant-numeric: tabular-nums; }

/* A button that reads as a link — the Ledger has no filled buttons in-flow. */
.lg-linkbtn {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--lg-link); font: 400 12px 'Inter var', Inter, sans-serif;
}
.lg-linkbtn:hover { color: var(--lg-ink-100); text-decoration: underline; }
.lg-linkbtn.is-strong { color: var(--lg-accent); font-weight: 600; }

/* Grouped identity: a left edge bar states grouping confidence. Never hidden
   (§5) — a merge the tool is unsure about must say so. */
.lg-group {
  padding: 12px 0 6px 12px;
  border-bottom: 1px solid var(--lg-rule);
  border-left: 2px solid var(--lg-ink-600, #4c628a);
}
.lg-group.is-high   { border-left-color: var(--lg-good); }
.lg-group.is-medium { border-left-color: var(--lg-warn); }
.lg-group.is-low    { border-left-color: var(--lg-bad); }

.lg-merge-cb { accent-color: var(--lg-accent); width: 12px; height: 12px; margin: 0; }

/* Alerts: click-to-drill bucket panel (§5). A bordered band, not a card. */
.lg-drill {
  margin: 10px 0 4px; padding: 9px 12px;
  border: 1px solid var(--lg-rule); border-left: 2px solid var(--lg-accent);
  background: #0b1018;
}

/* Clients: the column chooser sits above the grid as a rule, not a popover —
   §5 wants the 20 available columns legible at a glance. */
.lg-cols { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px;
  padding: 8px 0 6px; border-bottom: 1px solid var(--lg-rule); }
.lg-cols label { color: var(--lg-ink-300); font: 400 11.5px 'JetBrains Mono', monospace; }

/* Heatmap scrubber — a flat rail, in keeping with the rest of the shell. */
.lg-scrub { -webkit-appearance: none; appearance: none; flex: 1; height: 2px;
  background: var(--lg-rule); outline: none; }
.lg-scrub::-webkit-slider-thumb { -webkit-appearance: none; appearance: none;
  width: 9px; height: 9px; border-radius: 50%; background: var(--lg-accent); cursor: pointer; }
.lg-scrub::-moz-range-thumb { width: 9px; height: 9px; border: 0; border-radius: 50%;
  background: var(--lg-accent); cursor: pointer; }

/* Ranked lists (Hotspots) — the position gutter. Muted: the rank orders the
   rows, it is not the fact being read. */
.lg-rank { font: 400 11px 'JetBrains Mono', monospace; color: var(--lg-ink-500); }

/* The switch port you arrived through, marked rather than merely tinted. */
.lg-table-row.is-arrival { border-left: 2px solid var(--lg-accent); background: #0c1220; }

/* Entity tags + notes fragments (loaded async into the detail pages). */
.lg-tags { display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  padding: 8px 0; border-bottom: 1px solid var(--lg-rule); position: relative; z-index: 30; }
.lg-tagchip { display: inline-flex; align-items: center; gap: 4px;
  border: 1px solid; border-radius: 999px; padding: 1px 8px;
  font: 400 11.5px 'JetBrains Mono', monospace; }
.lg-tagadd { position: relative; margin-left: auto; }
.lg-tagadd > summary { list-style: none; cursor: pointer;
  font: 400 11.5px 'JetBrains Mono', monospace; color: var(--lg-ink-400); }
.lg-tagadd > summary::-webkit-details-marker { display: none; }
.lg-tagadd > summary:hover { color: var(--lg-accent); }
.lg-tagpop { position: absolute; right: 0; top: 100%; margin-top: 5px; width: 290px;
  z-index: 40; background: #0c1220; border: 1px solid var(--lg-rule); padding: 8px; }
.lg-notes { padding: 8px 0; }

/* Platform: the editable credential console. Fields are rules, not boxes —
   an input is a labelled underline, in keeping with the rest of the shell. */
.lg-cfg-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px 34px; padding-top: 12px; }
.lg-cfg label { display: block; padding: 6px 0; color: var(--lg-ink-400);
  font: 400 11.5px 'JetBrains Mono', monospace; }
.lg-cfg label input[type=text], .lg-cfg label input[type=password], .lg-cfg label textarea {
  display: block; width: 100%; margin-top: 3px; background: #0a0e17; border: 0;
  border-bottom: 1px solid var(--lg-rule); color: var(--lg-ink-100);
  font: 400 13px 'JetBrains Mono', monospace; padding: 3px 2px; }
.lg-cfg label input:focus, .lg-cfg label textarea:focus {
  outline: none; border-bottom-color: var(--lg-accent); }
.lg-cfg label.lg-cfg-check { display: flex; align-items: center; gap: 7px; }
.lg-cfg label.lg-cfg-check input { width: auto; margin: 0; }

/* Loading & motion spec page: the evidence rows, rendered live rather than
   pictured, so CSS drift shows up on the page that documents it. */
.lg-evi { display: flex; align-items: baseline; gap: 8px; padding: 4px 0;
  font: 400 12px 'JetBrains Mono', monospace; color: var(--lg-ink-200); }
.lg-evi > span:last-child { margin-left: auto; }
.lg-evi.is-pending { color: var(--lg-ink-500); }
.lg-evi.is-running { color: var(--lg-ink-100); }
.lg-evi.is-failed  { color: var(--lg-ink-300); }
.lg-strip.is-demo { display: block; opacity: 1; }

/* ── §2 .lg-scrollbox — bounded, scrollable region (contract §6.4) ─────────
   Height is measured in ROWS, not pixels, so it survives density modes: the
   row height comes from --lg-rowh, which density-compact overrides.

   Both scroll signals are present deliberately. The edge fades say "there is
   more"; the 2px thumb says "you can drag this". A fade alone is ambiguous on
   a trackpad, where there is no persistent scrollbar to notice. */
:root { --lg-rowh: 30px; --lg-scroll-rows: 8; }
.density-compact { --lg-rowh: 25px; }

.lg-scrollbox {
  position: relative;
  max-height: calc(var(--lg-rowh) * var(--lg-scroll-rows));
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;                                  /* Firefox */
  scrollbar-color: var(--lg-rule) transparent;
}
.lg-scrollbox.is-expanded { max-height: none; overflow-y: visible; }

/* Sticky column head. The head must be INSIDE the scroll container for this,
   which is the markup-shape change §6.4 accepts. */
.lg-scrollbox > .lg-table-head {
  position: sticky; top: 0; z-index: 5;
  background: var(--lg-bg); }

/* WebKit: no track chrome; a rule-coloured thumb only once you are in it. */
.lg-scrollbox::-webkit-scrollbar { width: 6px; }
.lg-scrollbox::-webkit-scrollbar-track { background: transparent; }
.lg-scrollbox::-webkit-scrollbar-thumb { background: transparent; border-radius: 0; }
.lg-scrollbox:hover::-webkit-scrollbar-thumb,
.lg-scrollbox.is-scrolling::-webkit-scrollbar-thumb {
  background: var(--lg-rule);
  border-left: 2px solid var(--lg-rule); }

/* Edge fades. Wrapper owns them so they do not scroll with the content. */
.lg-scrollwrap { position: relative; }
.lg-scrollwrap::before,
.lg-scrollwrap::after {
  content: ""; position: absolute; left: 0; right: 6px; height: 22px;
  pointer-events: none; opacity: 0; transition: opacity 120ms ease-out; z-index: 6; }
.lg-scrollwrap::before {
  top: var(--lg-rowh);                       /* below the sticky head */
  background: linear-gradient(to bottom, var(--lg-bg), transparent); }
/* Boxes with no sticky .lg-table-head fade from the actual top edge —
   otherwise the "more above" gradient paints over row 2. */
.lg-scrollwrap.no-head::before { top: 0; }
.lg-scrollwrap::after {
  bottom: 0;
  background: linear-gradient(to top, var(--lg-bg), transparent); }
.lg-scrollwrap.at-top::after,
.lg-scrollwrap.mid::after    { opacity: 1; }
.lg-scrollwrap.mid::before,
.lg-scrollwrap.at-end::before { opacity: 1; }

/* Count line + expand/collapse. The region is the default; expand is the escape. */
.lg-scrollcount {
  display: flex; align-items: baseline; gap: 12px; padding: 7px 0 0;
  font: 400 11.5px 'JetBrains Mono', monospace; color: var(--lg-ink-400); }

/* Window pills surfaced beside a chart (§6.3). Same control as the page
   window — styled as a pill row so it reads as the one truth, not a second. */
.lg-winpill { display:inline-block; padding:1px 8px; margin-left:4px;
  border:1px solid transparent; border-radius:2px;
  font:500 11px 'JetBrains Mono',monospace; color:var(--lg-ink-400); }
.lg-winpill:hover { color:var(--lg-ink-100); }
.lg-winpill.is-active { color:var(--lg-accent); border-color:rgba(56,189,248,.4); }

/* ── §6.9 Attribute-history popover ────────────────────────────────────────
   Identity fields that held ≥2 distinct values in the window get a (N) badge
   and a dotted underline; hover OR keyboard focus opens the distinct-values
   popover. Anchors below the tile; z-index above the sticky page index. */
.lg-attr-tile { position:relative; }
.lg-attr-n { color:var(--lg-link); font-weight:600; letter-spacing:0; }
.lg-attr-age { font:400 9.5px 'JetBrains Mono',ui-monospace,monospace;
  color:var(--lg-ink-500); letter-spacing:0; text-transform:none; }
.lg-attr-val-hist { border-bottom:1px dotted var(--lg-ink-500);
  display:inline-block; cursor:help; }
.lg-attr-val-hist:focus { outline:none;
  border-bottom-color:var(--lg-link); }
.lg-attr-pop { display:none; position:absolute; top:100%; left:0; margin-top:6px;
  z-index:60; background:#0c1220; border:1px solid var(--lg-rule-strong);
  padding:9px 12px; min-width:250px; box-shadow:0 8px 24px rgba(0,0,0,.5); }
.lg-attr-tile:hover .lg-attr-pop,
.lg-attr-tile:focus-within .lg-attr-pop { display:block; }
.lg-attr-pop-head { font:600 9.5px 'Inter var',Inter,sans-serif;
  letter-spacing:.14em; text-transform:uppercase; color:var(--lg-ink-400);
  padding-bottom:6px; border-bottom:1px solid var(--lg-rule); margin-bottom:5px; }
.lg-attr-pop-row { display:flex; gap:8px; align-items:center; padding:2.5px 0; }
.lg-attr-dot { width:5px; height:5px; border-radius:50%; flex:none;
  background:var(--lg-ink-500); }
.lg-attr-dot.is-current { background:var(--lg-good); }
.lg-attr-pop-val { font:500 11.5px 'JetBrains Mono',ui-monospace,monospace;
  color:var(--lg-ink-300); flex:1; white-space:nowrap; }
.lg-attr-pop-val.is-current { color:var(--lg-ink-100); }
.lg-attr-pop-span { font:400 10.5px 'JetBrains Mono',ui-monospace,monospace;
  color:var(--lg-ink-400); white-space:nowrap; }
.lg-attr-pop-foot { font:400 10px 'JetBrains Mono',ui-monospace,monospace;
  color:var(--lg-ink-500); padding-top:5px; }
.lg-attr-pop-foot .is-current { color:var(--lg-good); }

/* §6.15 — nav alert chip. Ink when quiet; amber warnings-only; rose criticals. */
.lg-nav-alerts { font:500 10.5px 'JetBrains Mono',ui-monospace,monospace;
  letter-spacing:.08em; color:var(--lg-ink-400);
  border:1px solid var(--lg-rule-strong); border-radius:2px;
  padding:2px 8px; margin-left:14px; align-self:center; white-space:nowrap; }
.lg-nav-alerts:hover { color:var(--lg-ink-200); text-decoration:none; }
.lg-nav-alerts.is-warn { color:var(--lg-warn); border-color:rgba(251,191,36,.45); }
.lg-nav-alerts.is-crit { color:var(--lg-bad); border-color:rgba(251,113,133,.5); }


/* §8.3 — the window control. One component, one placement. Disabled options
   still render (with their reason on hover) so the operator learns a retention
   limit from the control rather than from an empty chart. */
.lg-winctl { display:inline-flex; align-items:baseline; gap:10px; flex-wrap:wrap; }
.lg-winctl .lg-win { color: var(--lg-ink-400); text-decoration: none; }
.lg-winctl .lg-win:hover { color: var(--lg-ink-100); }
.lg-winctl .lg-win.is-active {
  color: var(--lg-ink-100); border-bottom: 1px solid var(--lg-accent);
}
.lg-winctl .lg-win.is-off {
  color: var(--lg-ink-600, #576686); cursor: not-allowed;
  text-decoration: line-through; text-decoration-thickness: 1px;
}
.lg-win-note { font: 400 11px 'JetBrains Mono', ui-monospace, monospace;
               color: var(--lg-ink-400); }

/* ── §10-C2 · Operations journal ──────────────────────────────────────────
   The log control sits in the masthead because an event belongs to a scope and
   a span, not to whichever page you were standing on. It is a quiet outline —
   always available, never the loudest thing in the rule. */
.lg-logbtn {
  background:transparent; color:var(--lg-accent);
  border:1px solid var(--lg-rule-strong); border-radius:2px;
  padding:2px 9px; margin-right:14px; cursor:pointer;
  font:400 11px/1.5 'JetBrains Mono',ui-monospace,monospace;
}
.lg-logbtn:hover { border-color:var(--lg-accent); background:rgba(56,189,248,.08); }

.lg-dialog {
  background:var(--lg-bg-1,#0b0f18); color:var(--lg-ink-200);
  border:1px solid var(--lg-rule-strong); border-radius:3px;
  padding:0; width:min(520px,92vw);
}
.lg-dialog::backdrop { background:rgba(2,6,14,.72); }
.lg-dialog form { display:flex; flex-direction:column; gap:10px; padding:18px 20px 16px; }
.lg-dialog-head {
  font:600 13px/1 'Inter var',Inter,sans-serif; letter-spacing:.02em;
  padding-bottom:6px; border-bottom:1px solid var(--lg-rule);
}
.lg-dialog label {
  display:flex; flex-direction:column; gap:4px;
  font:400 10px/1.4 'Inter',system-ui,sans-serif; letter-spacing:.08em;
  text-transform:uppercase; color:var(--lg-ink-400);
}
.lg-dialog input, .lg-dialog select, .lg-dialog textarea {
  background:rgba(255,255,255,.03); color:var(--lg-ink-100);
  border:1px solid var(--lg-rule-strong); border-radius:2px; padding:5px 7px;
  font:400 13.5px/1.4 'Inter var',Inter,sans-serif; text-transform:none;
  letter-spacing:0;
}
.lg-dialog input:focus, .lg-dialog select:focus, .lg-dialog textarea:focus {
  outline:none; border-color:var(--lg-accent);
}
.lg-dialog-when { display:grid; grid-template-columns:1fr 1fr; gap:12px; }
.lg-dialog-foot {
  display:flex; justify-content:space-between; align-items:center; gap:12px;
  padding-top:8px; border-top:1px solid var(--lg-rule);
}
.lg-dialog-foot button {
  background:transparent; color:var(--lg-ink-400);
  border:1px solid var(--lg-rule-strong); border-radius:2px;
  padding:4px 12px; margin-left:8px; cursor:pointer;
  font:400 11px/1.4 'Inter',system-ui,sans-serif;
  letter-spacing:.06em; text-transform:uppercase;
}
.lg-dialog-foot button.is-primary { color:var(--lg-accent); border-color:var(--lg-accent); }
.lg-dialog-foot button:hover { background:rgba(56,189,248,.1); }

/* An entry outside the active scope filter DIMS rather than disappearing —
   it is still evidence that something else was happening at the same time. */
.lg-jrow.is-out { opacity:.35; }
.lg-jrow.is-superseded .lg-jwhat { text-decoration:line-through; text-decoration-thickness:1px; }
.lg-jspan { font:400 11px 'JetBrains Mono',ui-monospace,monospace; color:var(--lg-ink-400); }
.lg-jflag {
  display:inline-block; min-width:15px; text-align:center;
  border:1px solid var(--lg-accent); color:var(--lg-accent); border-radius:2px;
  font:400 10px/1.5 'JetBrains Mono',ui-monospace,monospace; padding:0 3px;
}
.lg-jflag.is-wide { border-color:var(--lg-ink-400); color:var(--lg-ink-400); }

/* ── §10-C5 · The empty state as a dispatcher ────────────────────────────
   An empty page owes an ACTION, not just an apology. The offer is a link at
   body weight rather than a button: it is the useful next step, not a call to
   action, and the count beside it is what makes it worth clicking. */
.lg-dispatch { display:flex; flex-direction:column; gap:7px; }
.lg-dispatch-say { color:var(--lg-ink-300); }
.lg-dispatch-row { display:flex; gap:10px; align-items:baseline; flex-wrap:wrap; }
.lg-dispatch-act {
  font:500 13.5px 'Inter var',Inter,sans-serif; color:var(--lg-link);
}
.lg-dispatch-act:hover { color:var(--lg-link-hi); }

/* ── §9-B12 · Sign-in audit ──────────────────────────────────────────────
   Failures render in rose IN PLACE, never in a separate table: hammering is
   only visible interleaved. */
.lg-table-row.pa-failed .lg-ident { color:var(--lg-bad); }
.pa-rate { display:flex; align-items:flex-end; gap:3px; height:40px; padding-top:10px; }
.pa-rate-day { flex:1 1 0; display:flex; flex-direction:column-reverse; height:100%; }
.pa-rate-day > i { display:block; width:100%; }
.pa-rate .pa-ok  { background:var(--lg-ink-500); }
.pa-rate .pa-bad { background:var(--lg-bad); opacity:.85; }

/* ── §9-B10 · Alert clustering strip ─────────────────────────────────────
   Bars, not a chart: eight rows read faster than a plot and each one is a
   filter. The selected bar keeps an accent rule so the page never shows a
   filtered list without showing what filtered it. */
.al-strip { display:flex; flex-direction:column; gap:3px; padding:10px 0 2px; }
.al-brow {
  display:grid; grid-template-columns:220px 1fr 40px; gap:12px;
  align-items:center; padding:2px 0; text-decoration:none;
}
.al-brow:hover { text-decoration:none; }
.al-brow:hover .al-btrack > i { opacity:.95; }
.al-brow.is-on { border-left:2px solid var(--lg-accent); padding-left:8px; }
.al-bname {
  font:500 13px 'Inter var',Inter,sans-serif; color:var(--lg-ink-200);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
/* The track is a STACK: length = open alerts, colour = what they are. A solid
   red bar made a building of 22 info alerts look like 22 criticals. */
.al-btrack { height:9px; background:rgba(255,255,255,.03); display:flex; }
.al-btrack > i { display:block; height:9px; background:var(--lg-bad); opacity:.75; }
.al-btrack > i.sev-critical { background:var(--lg-bad); }
.al-btrack > i.sev-warning  { background:var(--lg-warn); }
.al-btrack > i.sev-info     { background:var(--lg-info); }
/* An unknown severity is neutral, never coloured as benign. */
.al-btrack > i.sev-other    { background:var(--lg-ink-400); }
.al-blegend { display:flex; gap:14px; padding:6px 0 0; }
.al-bkey {
  display:inline-flex; align-items:center; gap:5px;
  font:500 11px 'Inter var',Inter,sans-serif; color:var(--lg-ink-400);
}
.al-bkey > i { width:9px; height:9px; display:block; opacity:.75; }
.al-bkey > i.sev-critical { background:var(--lg-bad); }
.al-bkey > i.sev-warning  { background:var(--lg-warn); }
.al-bkey > i.sev-info     { background:var(--lg-info); }
.al-bnum {
  font:500 12.5px 'JetBrains Mono',ui-monospace,monospace;
  color:var(--lg-ink-200); text-align:right;
}

/* §9-B5 — an org-wide figure sitting in a per-network row. Dimmed so it cannot
   be read as this network's share; never grouped away, never split. */
.ssid-orgwide { color:var(--lg-ink-400); }

/* ── §15.1 small multiples ──────────────────────────────────────────────
   Two panels side by side, each at its OWN scale with the range printed, so
   a 17x disparity between estates does not make one of them unreadable.
   Line-only: a fill would make the larger estate's ink dominate a comparison
   that is explicitly about shape. */
.lg-mult { display:grid; grid-template-columns:1fr 1fr; gap:0 22px; padding-top:8px; }
.lg-mult-head { display:flex; justify-content:space-between; align-items:baseline;
  font:600 10px 'Inter var',Inter,sans-serif; letter-spacing:.12em;
  text-transform:uppercase; }
.lg-mult-axis { font:400 10px 'JetBrains Mono',ui-monospace,monospace;
  color:var(--lg-ink-400); letter-spacing:0; text-transform:none; }

/* §15.6 — the group rule inside a scrollbox. */
.lg-modelgroup { display:flex; justify-content:space-between; align-items:baseline;
  border-bottom:1px solid var(--lg-rule); padding:8px 0 4px; margin-top:6px;
  font:600 10.5px 'Inter var',Inter,sans-serif; letter-spacing:.12em;
  text-transform:uppercase; }
.lg-modelgroup:first-child { margin-top:0; }
.lg-modelgroup-n { font:400 10px 'JetBrains Mono',ui-monospace,monospace;
  color:var(--lg-ink-400); letter-spacing:0; text-transform:none; }

/* §15.5 — an unobserved estate is a warning about the TOOL, not a calm
   network, so the qualified all-clear sits in an amber rule rather than in the
   quiet empty-state ink. */
.lg-blindframe { border:1px solid rgba(251,191,36,.4); border-left-width:2px;
  border-left-color:var(--lg-warn); padding:9px 11px; margin-top:2px;
  font:400 11.5px/1.6 'JetBrains Mono',ui-monospace,monospace;
  color:var(--lg-ink-300); }
.lg-blindframe b { color:var(--lg-ink-100); font-weight:500; }

/* ── §16 The Cluster page: bands, and the survival bar ────────────────────
   §16.5 kills the cards. A rule and a 3px left edge, because the Ledger has no
   cards anywhere else — and four cards of unequal weight in a 2x2 grid let a
   5% service set the row height of a 46% one. */
.lg-nohead-note {
  font: 400 13px/1.65 'Inter var', Inter, sans-serif; color: var(--lg-ink-300);
  font-style: italic; padding: 12px 0 4px; border-bottom: 1px solid var(--lg-rule);
}
.lg-ledger-head {
  display: flex; align-items: baseline; gap: 12px; padding: 22px 0 8px;
}
.lg-ledger-name {
  font: 600 12px 'Inter var', Inter, sans-serif; letter-spacing: .16em;
}
.lg-ledger-meta, .lg-ledger-right {
  font: 400 11.5px 'JetBrains Mono', monospace; color: var(--lg-ink-500);
}
.lg-ledger-right { margin-left: auto; }
/* Larger estate first, then a double rule, then the smaller. Never side by
   side — §16.5 orders by weight. */
.lg-ledger-rule { border-top: 3px double var(--lg-rule-strong); margin: 26px 0 0; }

.lg-band {
  border-left: 3px solid var(--lg-rule-strong);
  border-bottom: 1px solid var(--lg-rule);
  padding: 12px 0 14px 14px; margin-top: 2px;
}
.lg-band-aruba { border-left-color: var(--lg-accent, #38bdf8); }
.lg-band-cisco { border-left-color: #eef2fa; }
.lg-band-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.lg-band-tag {
  font: 400 9.5px 'JetBrains Mono', monospace; letter-spacing: .14em;
}
.lg-band-name { font: 500 15px 'Inter var', Inter, sans-serif; color: var(--lg-ink-100); }
.lg-band-sub, .lg-band-verdict {
  font: 400 11.5px 'JetBrains Mono', monospace; color: var(--lg-ink-500);
}
.lg-band-verdict {
  margin-left: auto; font-family: 'Newsreader', Georgia, serif;
  font-style: italic; font-size: 13.5px; color: var(--lg-ink-300);
}
/* §16.6 — the cascade, in the §15.4 coverage register. */
.lg-band-coverage {
  border-left: 2px solid var(--lg-warn); padding: 5px 0 5px 9px; margin: 8px 0 2px;
  font: 400 12px/1.55 'Inter var', Inter, sans-serif; color: var(--lg-ink-300);
}
.lg-band-cols {
  display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 0 26px; padding-top: 10px;
}
.lg-col-head {
  font: 400 10px 'JetBrains Mono', monospace; letter-spacing: .16em;
  text-transform: uppercase; color: var(--lg-ink-500); padding-bottom: 6px;
}
.lg-col-head-row { display: flex; justify-content: space-between; align-items: baseline; }
.lg-col-sub { font: 400 10px 'JetBrains Mono', monospace; color: var(--lg-ink-500); }

/* §16.2 THE SURVIVAL BAR — a new component. The C3 headroom bar extended from
   a target to a PROJECTION: fill is the projected load, the tick is the
   survivor's own ceiling, and any fill past the tick is the shortfall. */
.lg-surv { padding: 4px 0 10px; }
.lg-surv-top { display: flex; justify-content: space-between; align-items: baseline; }
.lg-surv-site { font: 400 12px 'Inter var', Inter, sans-serif; color: var(--lg-ink-300); }
.lg-surv-verdict {
  font: 400 12px 'JetBrains Mono', monospace; color: var(--lg-ink-300);
}
.lg-surv-verdict.is-over { color: var(--lg-warn); }
.lg-surv-verdict.is-edge { color: var(--lg-ink-200); }
.lg-surv-track {
  position: relative; height: 9px; margin-top: 5px;
  background: var(--lg-row); overflow: hidden;
}
.lg-surv-fill { position: absolute; left: 0; top: 0; bottom: 0; background: var(--lg-ink-400); }
/* The shortfall is amber and sits PAST the tick — the only part of the bar
   that is not simply load. */
.lg-surv-over { position: absolute; top: 0; bottom: 0; background: var(--lg-warn); }
.lg-surv-tick { position: absolute; top: -2px; bottom: -2px; width: 1px; background: #eef2fa; }
.lg-surv-say {
  font: 400 11px 'JetBrains Mono', monospace; color: var(--lg-ink-500); padding-top: 4px;
}
/* §16.7 — the question left unanswered, with a route to the collector that
   owes the data. A dashed frame, because nothing has been measured. */
.lg-surv-none {
  border: 1px dashed var(--lg-rule-strong); padding: 9px 10px; margin: 4px 0 10px;
  font: 400 12px/1.55 'Inter var', Inter, sans-serif; color: var(--lg-ink-400);
}
.lg-surv-route { display: block; padding-top: 5px; font: 400 11px 'JetBrains Mono', monospace; }

.lg-gauge { padding: 4px 0 9px; }
.lg-gauge-top {
  display: flex; justify-content: space-between; align-items: baseline;
  font: 400 12px 'Inter var', Inter, sans-serif; color: var(--lg-ink-300);
}
.lg-gauge-num { font-family: 'JetBrains Mono', monospace; font-size: 11.5px; }
/* §16.4 — an absent ceiling renders NO TRACK AT ALL. An empty track reads as
   0% utilised, or as a rendering bug. The reason takes the track's place. */
.lg-gauge-why {
  font: 400 11px/1.5 'JetBrains Mono', monospace; color: var(--lg-ink-500); padding-top: 3px;
}

/* §16.3 — group by the pair. Two halves side by side means a 10-controller
   service is five rows tall AND the list teaches the failover dimension. */
.lg-halves { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }
.lg-half-head {
  display: flex; justify-content: space-between; align-items: baseline;
  font: 400 10px 'JetBrains Mono', monospace; letter-spacing: .12em;
  text-transform: uppercase; color: var(--lg-ink-500);
  border-bottom: 1px solid var(--lg-row); padding-bottom: 3px;
}
.lg-half-models { text-transform: none; letter-spacing: 0; }
.lg-half-row {
  display: grid; grid-template-columns: 9px 1fr auto auto; gap: 0 6px;
  align-items: baseline; padding: 3px 0;
  font: 400 11.5px 'JetBrains Mono', monospace; color: var(--lg-ink-300);
}
.lg-half-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The controller's management IP, shown here (in the member list) rather than in
   the uplink-graph tooltip, which now reads by controller name. Muted so the
   name still leads; the load figure stays hard-right. */
.lg-half-ip { font-size: 10px; color: var(--lg-ink-500); white-space: nowrap; }
/* Emerald claims health and rose claims down, so an UNMEASURED controller gets
   neither — a hollow amber dot, because unknown is its own state. */
.lg-dot-up, .lg-dot-down, .lg-dot-quiet {
  width: 6px; height: 6px; border-radius: 50%; display: inline-block;
}
.lg-dot-up { background: var(--lg-good); }
.lg-dot-down { background: var(--lg-bad); }
.lg-dot-quiet { background: transparent; border: 1px solid var(--lg-warn); }
.lg-quiet { color: var(--lg-ink-500); }
.lg-half-worst, .lg-half-perdev {
  font: 400 10.5px/1.5 'JetBrains Mono', monospace; color: var(--lg-ink-500);
  padding-top: 5px; border-top: 1px solid var(--lg-row); margin-top: 4px;
}
/* An out-of-range device is promoted AUTOMATICALLY — no interaction, because
   this page is read on a wall display during an incident. */
.lg-half-exception {
  font: 400 11px 'JetBrains Mono', monospace; color: var(--lg-warn); padding: 2px 0;
}
.lg-health-switch { font: 400 10px 'JetBrains Mono', monospace; color: var(--lg-ink-500); }
.lg-health-opt {
  background: none; border: 0; padding: 0 3px; cursor: pointer;
  font: inherit; color: var(--lg-ink-500);
}
.lg-health-opt.is-active { color: var(--lg-link); }

/* §16.5 — warnings are GRADED, not adjacent equals. */
.lg-band-action {
  font: 400 11.5px 'JetBrains Mono', monospace; color: var(--lg-warn); padding-top: 8px;
}
.lg-band-note {
  font: 400 11.5px 'JetBrains Mono', monospace; color: var(--lg-ink-500); padding-top: 4px;
}
.lg-claim {
  display: grid; grid-template-columns: 1fr 1fr; gap: 0 30px;
  padding: 22px 0 10px; margin-top: 18px; border-top: 1px solid var(--lg-rule);
}
.lg-claim p {
  font: 400 12.5px/1.6 'Inter var', Inter, sans-serif; color: var(--lg-ink-400);
  margin: 0 0 8px;
}

/* ── §12 The diagnostics bench ────────────────────────────────────────────
   It PUSHES, it does not cover. No scrim, no dim, no modal — the page it is
   diagnosing stays fully legible beside it, because the comparison is the
   reason the operator opened it. Rules, not cards: one hairline down the left
   edge and hairlines between results; the Ledger has no cards and the bench
   does not introduce one. */
body.lg-bench-open .lg-frame { margin-right: var(--lg-bench-w, 420px); }
.lg-frame { transition: margin-right .18s ease-out; }

.lg-bench {
  position: fixed; right: 0; top: 0; height: 100dvh; z-index: 900;
  background: var(--lg-bg); border-left: 1px solid var(--lg-rule-strong);
  display: flex; flex-direction: column; overflow: hidden;
}
.lg-bench-grip {
  position: absolute; left: 0; top: 0; bottom: 0; width: 5px;
  cursor: col-resize; background: transparent;
}
.lg-bench-grip:hover { background: rgba(56, 189, 248, .25); }
.lg-bench-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 10px; padding: 13px 16px 11px; border-bottom: 1px solid var(--lg-rule-strong);
}
.lg-bench-target {
  font: 400 11.5px 'JetBrains Mono', monospace; color: var(--lg-ink-400);
  padding-top: 3px; word-break: break-all;
}
.lg-bench-body { flex: 1; overflow-y: auto; padding: 0 16px 24px; }

.lg-bench-listhead {
  display: flex; justify-content: space-between; align-items: baseline;
  padding: 12px 0 6px;
  font: 400 10.5px 'JetBrains Mono', monospace; letter-spacing: .14em;
  text-transform: uppercase; color: var(--lg-ink-500);
}
.lg-bench-check { padding: 6px 0; border-bottom: 1px solid var(--lg-row); }
.lg-bench-check-main { display: flex; align-items: baseline; gap: 8px; }
.lg-bench-state {
  /* Fixed and clipped: if this ever renders something unexpected it must not
     push the label sideways. It rendered "undefined" once, over the label. */
  flex: 0 0 12px; width: 12px; overflow: hidden; white-space: nowrap;
  font: 400 12px 'JetBrains Mono', monospace; color: var(--lg-ink-400);
}
.lg-bench-check.running .lg-bench-state { color: var(--lg-link); }
.lg-bench-check.done    .lg-bench-state { color: var(--lg-good); }
.lg-bench-check.failed  .lg-bench-state { color: var(--lg-bad); }
.lg-bench-run {
  background: none; border: 0; padding: 0; cursor: pointer; text-align: left;
  font: 500 13px 'Inter var', Inter, sans-serif; color: var(--lg-link);
}
.lg-bench-run[disabled] { color: var(--lg-ink-500); cursor: default; }
.lg-bench-check-meta {
  padding: 2px 0 0 20px;
  font: 400 11px 'JetBrains Mono', monospace; color: var(--lg-ink-500);
}
.lg-bench-na { color: var(--lg-ink-500); }

.lg-bench-results { padding-top: 4px; }
.lg-bench-result { border-top: 1px solid var(--lg-rule); }

.lg-diag { border-left: 2px solid var(--lg-rule-strong); padding: 12px 0 14px 12px; }
.lg-diag-head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 10px; padding-bottom: 6px;
}
.lg-diag-label {
  font: 400 10.5px 'JetBrains Mono', monospace; letter-spacing: .14em;
  text-transform: uppercase; color: var(--lg-ink-400);
}
.lg-diag-prov {
  font: 400 10.5px 'JetBrains Mono', monospace; color: var(--lg-ink-500);
  text-align: right;
}
/* The verdict voice: serif italic, the same register the rest of the product
   uses when it is telling the operator what something MEANS. */
/* The verdict voice, matching .lg-verdict-text exactly — Newsreader italic is
   the register this product uses when telling the operator what something
   MEANS. Source Serif is not loaded here and would have fallen back silently
   to Georgia, which reads as a different product. */
.lg-diag-verdict {
  font: 400 14px/1.45 'Newsreader', Georgia, serif; font-style: italic;
  color: var(--lg-ink-200); padding-bottom: 5px;
}
.lg-diag-verdict.is-warn { color: var(--lg-warn); }
.lg-diag-verdict.is-bad  { color: var(--lg-bad); }
.lg-diag-verdict.is-na   { color: var(--lg-ink-400); }
.lg-diag-body {
  font: 400 13px/1.6 'Inter var', Inter, sans-serif; color: var(--lg-ink-300);
  padding-bottom: 8px;
}
.lg-diag-values { padding: 2px 0 6px; }
.lg-diag-kv {
  display: grid; grid-template-columns: 108px 1fr; gap: 0 10px; padding: 2px 0;
  font: 400 12px 'JetBrains Mono', monospace;
}
.lg-diag-k { color: var(--lg-ink-500); }
.lg-diag-v { color: var(--lg-ink-200); word-break: break-word; }
.lg-diag-v.good { color: var(--lg-good); }
.lg-diag-v.warn { color: var(--lg-warn); }
.lg-diag-v.bad  { color: var(--lg-bad); }
.lg-diag-raw {
  display: flex; flex-wrap: wrap; gap: 10px; align-items: baseline;
  padding: 6px 0 0; border-top: 1px solid var(--lg-row); margin-top: 6px;
  font: 400 11px 'JetBrains Mono', monospace; color: var(--lg-ink-500);
}
.lg-diag-rawitem b { color: var(--lg-ink-300); font-weight: 400; }
.lg-diag-retry { padding-top: 6px; }

/* Destructive actions sit at the FOOT, dim until confirmed, with the
   consequence stated in operator terms. In the drawer this was the brightest
   element in the panel and fired unconfirmed. */
.lg-bench-destructive { margin-top: 22px; padding-top: 10px; border-top: 1px solid var(--lg-rule); }
.lg-bench-destructive-head {
  font: 400 10.5px 'JetBrains Mono', monospace; letter-spacing: .16em;
  color: var(--lg-bad); padding-bottom: 6px;
}
.lg-bench-destructive-item { opacity: .55; padding: 6px 0; }
.lg-bench-destructive-item:hover { opacity: 1; }
.lg-bench-destructive-label {
  font: 500 13px 'Inter var', Inter, sans-serif; color: var(--lg-ink-300);
}
.lg-bench-destructive-why {
  font: 400 12px/1.5 'Inter var', Inter, sans-serif; color: var(--lg-ink-500);
}


/* ── §19 campus-map instrument ─────────────────────────────────────────── */
.lg-glassrail {
  position:absolute; box-sizing:border-box;
  background:rgba(6,9,15,.86); border:1px solid #1a2235;
  backdrop-filter:blur(9px); -webkit-backdrop-filter:blur(9px);
  padding:10px 13px 11px; z-index:6;
  font:400 12px 'Inter var',Inter,sans-serif; color:var(--lg-ink-200);
}
.lg-glass-head { font:600 9.5px 'Inter var',Inter,sans-serif; letter-spacing:.16em;
  text-transform:uppercase; color:#88a6d6; padding-bottom:7px; }
.lg-glass-row { display:flex; gap:9px; align-items:center; padding:4px 0;
  color:#d0e7ff; text-decoration:none; transition:background 140ms; }
.lg-glass-row.is-on { color:#eef2fa; background:rgba(56,189,248,.08);
  margin:0 -13px; padding-left:13px; padding-right:13px; }
.lg-glass-bar { width:2px; height:13px; background:#1a2235; flex:0 0 2px; }
.lg-glass-row.is-on .lg-glass-bar { background:#38bdf8; }
.lg-glass-mode { display:flex; gap:8px; padding-bottom:8px; }
.lg-glass-mode span { font:500 11px 'Inter var',Inter,sans-serif; padding:3px 10px;
  border:1px solid #131a29; color:#88a6d6; }
.lg-glass-mode .is-on { border-color:#a78bfa; color:#eef2fa; }
.lg-glass-cov { font:400 10.5px/1.55 'JetBrains Mono',ui-monospace,monospace; color:#d0e7ff; }
.lg-glass-join { font:400 10px/1.5 'JetBrains Mono',ui-monospace,monospace; color:#5c74a0; padding-top:4px; }
.lg-navbtn { width:24px; height:22px; border:1px solid #243049; background:transparent;
  color:var(--lg-ink-200); font-size:13px; cursor:pointer; }
.lg-navbtn:hover { border-color:#4d7ea8; }
.lg-map-label { position:absolute; transform:translate(-50%,-50%);
  font:500 11.5px 'Inter var',Inter,sans-serif; color:#dfe7f4;
  text-shadow:0 0 3px #04060a, 0 0 7px #04060a, 0 0 12px #04060a;
  white-space:nowrap; pointer-events:none; }
.lg-map-label.is-code { font:600 10.5px 'Inter var',Inter,sans-serif; letter-spacing:.09em; }
@media (prefers-reduced-motion: reduce) {
  .zone { transition:none; }
}
/* ── Collector lanes — the Freshness r axis (§20 g4) and the Platform
   collection schedule (§20 g5), one idiom. Positions are data (updated once
   a second like text); the 900 ms tween on top is motion, and motion means
   live (§21.1). Reduced motion keeps the updates and drops every tween. */
.fx-head { font:600 10.5px 'Inter var',Inter,sans-serif; letter-spacing:.12em; text-transform:uppercase; color:var(--lg-ink-300); }
.fx-head-sub { color:var(--lg-ink-400); letter-spacing:0; font-weight:400; text-transform:none; }
.fx-grid { display:grid; grid-template-columns:186px 1fr 96px; gap:0 14px; }
/* A4 — the schedule strip's four columns: job · lane · next · run count.
   The Freshness page keeps the 3-column fx-grid; only the health page's
   clock-space strip carries the per-lane run count. */
.fx-grid4 { display:grid; grid-template-columns:186px 1fr 92px 30px; gap:0 14px; }
.fx-n { font:400 11px 'JetBrains Mono',monospace; color:var(--lg-ink-400); text-align:right; }
.fx-band-lbl { font:600 9px 'Inter var',Inter,sans-serif; letter-spacing:.12em; padding-bottom:4px; }
.fx-band-lbl.good { color:var(--lg-good); } .fx-band-lbl.mid { color:var(--lg-ink-300); } .fx-band-lbl.warn { color:var(--lg-warn); }
.fx-job { font:400 11.5px 'JetBrains Mono',monospace; color:var(--lg-ink-200); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.fx-lane { position:relative; height:15px; }
.fx-wash { position:absolute; top:0; bottom:0; }
.fx-wash.good { background:rgba(52,211,153,.07); } .fx-wash.mid { background:rgba(139,154,184,.07); } .fx-wash.warn { background:rgba(251,191,36,.07); }
.fx-rule { position:absolute; top:0; bottom:0; width:1px; opacity:.3; }
.fx-rule.good { background:var(--lg-good); } .fx-rule.warn { background:var(--lg-warn); }
.fx-trail { position:absolute; top:50%; height:1px; opacity:.3; background:currentColor; transition:left 900ms linear, width 900ms linear; }
.fx-dot { position:absolute; top:50%; width:7px; height:7px; transform:translate(-50%,-50%); background:currentColor; transition:left 900ms linear; }
.fx-dot.is-fired { animation:fx-fired 900ms ease-out; }
@keyframes fx-fired { 0% { transform:translate(-50%,-50%) scaleY(2.2); } 100% { transform:translate(-50%,-50%) scaleY(1); } }
.fx-state-fresh .fx-lane, .fx-state-fresh .fx-r,
.fx-state-ok .fx-lane, .fx-state-ok .fx-r { color:var(--lg-good); }
.fx-state-ageing .fx-lane, .fx-state-ageing .fx-r,
.fx-state-late .fx-lane, .fx-state-late .fx-r { color:var(--lg-ink-300); }
.fx-state-stale .fx-lane, .fx-state-stale .fx-r { color:var(--lg-warn); }
.fx-r { font:500 11px 'JetBrains Mono',monospace; text-align:right; }
.fx-r.never { color:var(--lg-ink-500); font-weight:400; }
.fx-meta-l { font:400 10px 'JetBrains Mono',monospace; color:var(--lg-ink-500); text-align:right; }
.fx-meta-note { font:400 10px 'JetBrains Mono',monospace; color:var(--lg-ink-400); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.fx-ticks { position:relative; height:14px; border-top:1px solid var(--lg-divider); }
.fx-tick { position:absolute; top:2px; font:400 10px 'JetBrains Mono',monospace; color:var(--lg-ink-500); transform:translateX(-50%); }
.fx-off { border:1px dashed var(--lg-ink-500); padding:8px 11px; }
.sk-mark { position:absolute; top:2px; bottom:2px; width:2px; background:currentColor; opacity:.42; transition:left 900ms linear; }
.sk-mark.first { opacity:1; }
.sk-mark.is-fired { animation:fx-fired 900ms ease-out; }
.sk-late { position:absolute; left:0; top:45%; height:1px; background:currentColor; opacity:.5; }
.sk-hist { display:flex; gap:1px; height:34px; align-items:flex-end; }
.sk-bin { flex:1; background:rgba(56,189,248,.30); transition:height 400ms ease; }
.sk-bin.hot { background:rgba(56,189,248,.62); }
.sk-bin.empty { background:transparent; }
@media (prefers-reduced-motion: reduce) {
  .fx-dot, .fx-trail, .sk-mark, .sk-bin { transition:none; }
  .fx-dot.is-fired, .sk-mark.is-fired { animation:none; }
}

/* §23.4 — the tool-wide row-list cap. One primitive, 392px, thin scrollbar.
   §23.5: no caption ever asserts the scroll — an overflowing region shows its
   scrollbar and a short one says nothing. (.lg-scrollbox keeps its §6.4
   row-count semantics for the regions ruled at 8/12 rows; .lgcap is the
   generic cap for everything else.) */
.lgcap {
  max-height: 392px;
  overflow-y: auto;
  scrollbar-width: thin;                                  /* Firefox */
  scrollbar-color: var(--lg-rule) transparent;
}
/* A1 — the split note: load-bearing italic under the Platform-health title. */
.lg-splitnote { font:italic 400 13.5px/1.6 'Inter var',Inter,sans-serif;
  color:var(--lg-ink-300); padding:2px 0 6px; max-width:1000px; }
.lg-splitnote b { color:var(--lg-ink-100); font-weight:600; }
/* A — the health page's own footer rollup (same strings as the section-1
   heading; the clock rewrites both from one derivation). */
.lg-pagefoot { display:flex; justify-content:space-between; gap:16px;
  border-top:1px solid var(--lg-rule); margin-top:26px; padding:10px 0 2px;
  font:400 11px 'JetBrains Mono',ui-monospace,monospace; color:var(--lg-ink-400); }
.lgcap::-webkit-scrollbar { width: 6px; }
.lgcap::-webkit-scrollbar-thumb { background: var(--lg-rule); }
/* A capped table keeps its head: sticky inside the cap, same idiom as the
   journal's day headers. The head scrolling away would decapitate the sort
   affordance (§6.13) along with the labels. */
.lgcap .lg-table-head { position: sticky; top: 0; background: var(--lg-bg); z-index: 5; }

/* §21.6 — arrival motion: the page body enters with a 9px rise and a fade,
   one shot, then completely still. Liveness motion (§21.1-21.3) is the only
   continuous kind — because arrival ENDS, stillness after settle still means
   "not live". Sub-navigation colour transitions are already 170ms-class via
   the link rules. */
@keyframes lg-enter {
  from { opacity: 0; transform: translateY(9px); }
  to   { opacity: 1; transform: none; }
}
.lg-page { animation: lg-enter 300ms cubic-bezier(.2,.8,.2,1); }
@media (prefers-reduced-motion: reduce) {
  .lg-page { animation: none; }
}

/* §22.6 — THE estate chip: same chip, same position, same styling on every
   entity list (H1). ARU wears the estate's sky, CIS near-white, both violet. */
.lg-estchip { font:600 9px 'JetBrains Mono',monospace; letter-spacing:.08em;
              padding:1px 5px; border:1px solid; margin-right:6px;
              vertical-align:1px; white-space:nowrap; }
.lg-estchip.aru  { color:var(--lg-link); border-color:rgba(56,189,248,.4); }
.lg-estchip.cis  { color:var(--lg-ink-100); border-color:rgba(238,242,250,.3); }
.lg-estchip.both { color:#a78bfa; border-color:rgba(167,139,250,.4); }
/* A table head inside a §6.4 scrollbox sticks like the journal's day
   headers — sorting scrolls you to the top row, not into headless data. */
.lg-scrollbox .lg-table-head { position: sticky; top: 0; background: var(--lg-bg); z-index: 5; }

/* §18.1 — one region, two states. Reading = compact grid; bench = six
   full-width lanes with label and peak columns. */
/* NOTE the name: .lg-bench is the DIAGNOSTICS side panel (fixed overlay);
   the chart bench is .lg-chartbench — reusing the name painted six lanes
   over the masthead as a fixed column. */
.lg-chartbench.is-collapsed { display:grid; grid-template-columns:repeat(3,1fr); gap:22px 34px; }
.lg-chartbench.is-collapsed .lg-lane { display:block; }
.lg-chartbench.is-collapsed .lg-lane-chart { height:104px; }
.lg-chartbench.is-collapsed .lg-lane-peaks { display:none; }
.lg-chartbench.is-collapsed .lg-lane-src { display:none !important; }
.lg-chartbench.is-expanded { display:block; }
.lg-chartbench.is-expanded .lg-lane {
  display:grid; grid-template-columns:200px 1fr 128px; gap:0 18px;
  align-items:center; padding:10px 0; border-bottom:1px solid var(--lg-row);
}
.lg-chartbench.is-expanded .lg-lane-chart { height:112px; }
.lg-lane-peaks { font-size:10px; line-height:1.8; text-align:right; color:var(--lg-ink-300); }
.lg-lane-label { min-width:0; }

/* §21.1 — THE breathing dot: the one continuously animating element on a
   building page, beside `clients now`. 2.4s, opacity .55 ↔ 1. */
.lg-breathe { display:inline-block; width:7px; height:7px; border-radius:50%;
  background:var(--lg-good); vertical-align:1px; margin-right:2px;
  animation: lgBreathe 2.4s ease-in-out infinite; }
@keyframes lgBreathe { 0%,100%{opacity:.55} 50%{opacity:1} }
@media (prefers-reduced-motion: reduce) { .lg-breathe { animation:none; } }

/* ── Configuration (handoff-17 surface B) — read-first cells ─────────────
   The page rendered ~150 input boxes open at all times and ran 6,710px on
   the real estate; the mock is 1,031px. The difference is the interaction
   model, not the paint: a cell shows its VALUES, and ✎ opens that section's
   editor in place with the consequence of saving stated (operator ruling,
   2026-08-02). */
.pc-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:18px 40px;
  padding-top:14px; align-items:start; }
.pc-cell { min-width:0; }
.pc-head { display:flex; justify-content:space-between; align-items:baseline;
  gap:10px; border-bottom:1px solid var(--lg-rule); padding-bottom:5px; }
.pc-label { font:600 10px 'Inter var',Inter,sans-serif; letter-spacing:.14em;
  text-transform:uppercase; color:#88a6d6; white-space:nowrap; }
.pc-edit { background:none; border:0; padding:0; cursor:pointer; text-align:right;
  font:400 10.5px 'JetBrains Mono',monospace; color:var(--lg-link); }
.pc-edit:hover { color:var(--lg-ink-100); }
.pc-kv { display:flex; justify-content:space-between; align-items:baseline;
  gap:12px; padding:6px 0; border-bottom:1px solid #10151f; }
.pc-kv:last-child { border-bottom:0; }
.pc-k { font:400 11.5px 'Inter var',Inter,sans-serif; color:var(--lg-ink-300);
  white-space:nowrap; }
.pc-v { font:400 11.5px 'JetBrains Mono',monospace; color:var(--lg-ink-100);
  text-align:right; overflow:hidden; text-overflow:ellipsis; }
.pc-v.dim { color:var(--lg-ink-500); }
.pc-foot { font:400 10.5px/1.55 'JetBrains Mono',monospace; color:var(--lg-ink-500);
  padding-top:6px; }
/* The editor: same fields as before, revealed in place. */
.pc-form { padding-top:8px; }
.pc-form label { display:block; font:400 11px 'Inter var',Inter,sans-serif;
  color:var(--lg-ink-400); padding:5px 0 0; }
.pc-form input[type=text], .pc-form input[type=password], .pc-form input[type=number],
.pc-form input[type=email], .pc-form textarea, .pc-form select {
  display:block; width:100%; margin-top:3px; background:#0a0e17; border:0;
  border-bottom:1px solid var(--lg-rule); color:var(--lg-ink-100);
  font:400 12.5px 'JetBrains Mono',monospace; padding:3px 2px; box-sizing:border-box; }
.pc-form input:focus, .pc-form textarea:focus, .pc-form select:focus {
  outline:none; border-bottom-color:var(--lg-accent); }
.pc-form .pc-check { display:flex; align-items:center; gap:7px; padding:6px 0 0; }
.pc-form .pc-check input { width:auto; margin:0; }
.pc-save { display:flex; align-items:baseline; gap:14px; padding:10px 0 2px;
  border-top:1px solid var(--lg-rule); margin-top:10px; }
/* A capped cell list — shorter than .lgcap because it lives inside a cell. */
.pc-cap { max-height:196px; overflow-y:auto; scrollbar-width:thin;
  scrollbar-color:var(--lg-rule) transparent; }
.pc-cap::-webkit-scrollbar { width:6px; }
.pc-cap::-webkit-scrollbar-thumb { background:var(--lg-rule); }

/* §30.4 / §29.4 — a micro-grid is already phone-sized. Fixed tracks summing
   under ~120px must keep their columns through any responsive collapse: the
   label↔bar↔count pairing IS the graphic, and one-column stacking triples
   its height. The tracks live in --lgmicro so desktop and phone cannot
   drift. */
.lgmicro { grid-template-columns: var(--lgmicro) !important; }

/* ═══════════════════════════════════════════════════════════════════════════
   §29 — RESPONSIVE (handoff round 22, docs/ledger-handoff-29/). These rules
   cannot be inline — a media query has nowhere to live in a style attribute —
   so this block is the legitimate exception that carries nothing which could
   have been inline. !important throughout: an author !important beats an
   inline declaration, and every layout in this product is inline. Substring
   selectors are written in BOTH spaced and unspaced forms (§29.7).
   NOTE §29.2: horizontal overflow is never HIDDEN on a page container — the one
   overflow:hidden below is the map canvas clipping its own statically
   repositioned rails, not a page hiding its defects.
   ═══════════════════════════════════════════════════════════════════════ */

/* Touch has no hover (§29.6): the scroll affordance must be permanent, or a
   capped list on a phone gives no sign it holds more. */
@media (hover: none) {
  .lgsb::-webkit-scrollbar { width: 3px; }
  .lgsb::-webkit-scrollbar-thumb { background: #243049; }
}

/* ── tablet / narrow desktop ── */
@media (max-width: 900px) {
  .lg-frame { padding: 18px 22px 48px !important; }
}

/* ── phone ── */
@media (max-width: 560px) {
  .lg-frame {
    padding: 14px 16px 40px !important;
    padding-left: calc(16px + env(safe-area-inset-left)) !important;
    padding-right: calc(16px + env(safe-area-inset-right)) !important;
    min-height: 100dvh !important;
  }

  /* masthead and nav stack and wrap rather than compressing */
  .lg-masthead { flex-direction: column !important; align-items: flex-start !important; gap: 5px !important; }
  .lg-masthead-meta { flex-direction: column !important; gap: 2px !important; align-items: flex-start !important; }
  .lg-nav { gap: 0 18px !important; flex-wrap: wrap !important; row-gap: 4px !important; }
  .lg-subnav { gap: 0 16px !important; flex-wrap: wrap !important; row-gap: 4px !important; overflow-x: visible !important; }

  /* a tap target is 44px (§29.6) */
  .lg-nav a, .lg-subnav a, .lg-pill, .lg-tab, .lg-logbtn {
    min-height: 44px !important; display: inline-flex !important;
    align-items: center !important;
  }

  /* THE TABLE PATTERN (§29.3) — a row becomes a record, each cell names
     itself via data-l; the header strip is removed. */
  .lg-table-head { display: none !important; }
  .lg-table-row { display: block !important; padding: 13px 0 14px !important; }
  .lg-table-row > * { text-align: left !important; }
  .lg-table-row > [data-l]::before,
  .lgrow > [data-l]::before {
    content: attr(data-l); display: block;
    font: 600 8px 'Inter var', Inter, sans-serif; letter-spacing: .14em;
    color: #3d4d6b; padding-top: 9px;
  }
  .lghead { display: none !important; }
  .lgrow { display: block !important; padding: 13px 0 14px !important; }
  .lgrow > * { text-align: left !important; }

  /* a pair that must be read together is never split (§29.4) */
  .lgpair { display: grid !important; grid-template-columns: 1fr 1fr !important; gap: 0 16px !important; }

  /* capped lists are shallower — the phone screen is the cap */
  .lgcap { max-height: 60dvh !important; }

  /* CANVAS SURFACES (§29.5) — rails cannot float over 393px of map. */
  .lgcanvas { margin: 0 -16px !important; height: 52dvh !important; min-height: 0 !important; overflow: hidden !important; }
  .lgcanvas > * { max-width: 100% !important; }
  .lg-maprail {
    position: static !important; width: auto !important; max-width: none !important;
    left: auto !important; right: auto !important; top: auto !important;
    bottom: auto !important; max-height: none !important;
    backdrop-filter: none !important; -webkit-backdrop-filter: none !important;
    background: #080c13 !important; margin: 10px 16px 0 !important;
  }
  .lgrail-hide { display: none !important; }

  /* OVERFLOW (§29.2). Everything wraps EXCEPT what declares itself
     inseparable; long identifiers break rather than push. */
  .lg-frame [style*="display: flex"], .lg-frame [style*="display:flex"] { flex-wrap: wrap !important; }
  .lg-frame [style*="grid-template-columns"] { grid-template-columns: 1fr !important; }
  .lg-frame .lgpair { grid-template-columns: 1fr 1fr !important; }
  .lg-frame .lgmicro { grid-template-columns: var(--lgmicro) !important; }
  .lg-frame [style*="flex: none"], .lg-frame [style*="flex:none"],
  .lg-frame [style*="flex: 0 0 auto"], .lg-frame [style*="flex:0 0 auto"] { flex: 0 1 auto !important; }
  .lg-frame .lgpair, .lg-frame [data-nowrap] { flex-wrap: nowrap !important; }
  .lg-frame > *, .lg-table-row > *, .lgrow > * { min-width: 0 !important; }
  .lg-frame { overflow-wrap: anywhere !important; }

  /* the reference prose folds away (§29.1) — the Method link stays */
  .lgfold { display: none !important; }

  /* iOS zooms the page when a focused input is under 16px (§29.6). */
  input, select, textarea { font-size: 16px !important; }
}

/* §29 continued — class-defined grids escape the inline-substring collapse
   and need their own phone rules. Micro-grids (fixed tracks < ~120px:
   .lg-split-bars 88px, .fx-grid label rows) keep their shape; page-layout
   grids stack. */
@media (max-width: 560px) {
  .lg-split { grid-template-columns: 1fr !important; }          /* main + rail stack */
  .lg-stat-4 { grid-template-columns: 1fr !important; }         /* tiles become records */
  .lg-cfg-grid, .lg-chartbench.is-collapsed, .pc-grid { grid-template-columns: 1fr !important; }
  .lg-mult, .lg-halves { grid-template-columns: 1fr !important; }
  .fx-grid { grid-template-columns: 120px 1fr 60px !important; }
  .fx-grid4 { grid-template-columns: 100px 1fr 60px 24px !important; }
}
@media (max-width: 560px) {
  /* §29.6 — every control on the sheet is a 44px target */
  .lg-maprail button, .lg-maprail a { min-width: 44px; min-height: 44px; }
}
@media (max-width: 560px) {
  /* clients grid: cells already name themselves via data-col — reuse it */
  .lg-crow > [data-col]:not([data-col="status"]):not([data-col="description"])::before {
    content: attr(data-col); display: block; text-transform: uppercase;
    font: 600 8px 'Inter var', Inter, sans-serif; letter-spacing: .14em;
    color: #3d4d6b; padding-top: 9px;
  }
}

/* §29 — full-bleed rows (map/floorplan/wrapper use margin:0 -30px to reach
   the frame edge) must track the frame's own padding at each breakpoint, or
   they push 8px/14px of horizontal overflow (review 2026-08-10). */
@media (max-width: 900px) {
  [style*="margin:0 -30px"], [style*="margin: 0 -30px"],
  #lg-map-wrap { margin-left: -22px !important; margin-right: -22px !important; }
}
@media (max-width: 560px) {
  [style*="margin:0 -30px"], [style*="margin: 0 -30px"],
  #lg-map-wrap { margin-left: -16px !important; margin-right: -16px !important; }
}
