/*
 * Threefold, the design system every page shares.
 *
 * Plain CSS on purpose: the pages take their utilities from the Tailwind Play
 * CDN, which does not process a stylesheet served beside it, so every named
 * piece lives here and depends on no utility class. A page without Tailwind
 * (swagger.html) draws the same shell from this file alone.
 *
 * Order: tokens, base, layout, the shell, primitives, charts, motion. A
 * component reads tokens, never a raw value, so a change to the palette or the
 * rhythm is made once, in :root.
 *
 * Tailwind's preflight gives [type=button] a transparent background at the
 * specificity of one class, and its stylesheet is injected after this one, so
 * a background on a button component is declared for `button.x` as well as
 * `.x`. That is the only reason some selectors below are written twice.
 */

@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');

/* ------------------------------------------------------------------ tokens */

:root {
  /* Ink. The page is a deep ink with one faint violet glow at the top; every
     surface above it is a layered card one step lighter, edged by a hairline. */
  --tf-ink-0: #05070f;
  --tf-bg: #070a14;
  --tf-bg-2: #0a0d18;
  --tf-surface-1: #0e1322;
  --tf-surface-2: #131a2c;
  --tf-surface-3: #1a2238;
  --tf-inset: #080b15;
  --tf-hairline: #1c2438;
  --tf-hairline-strong: #2a3450;
  --tf-highlight: rgba(255, 255, 255, 0.035);
  --tf-glow: rgba(124, 58, 237, 0.11);

  /* Text, measured against --tf-surface-1 (WCAG): primary 16.8:1, secondary
     8.5:1, muted 6.0:1 (5.0:1 on --tf-surface-3), quiet 5.4:1 (4.5:1 on --tf-hairline). Every text
     token clears AA on every surface above; --tf-text-decor is for rules and
     glyphs only, never words. */
  --tf-text: #f2f4fa;
  --tf-text-2: #a7b0c6;
  --tf-text-3: #8a93ab;
  --tf-text-4: #818ba5;
  --tf-text-decor: #4b5470;

  /* The one accent: action and focus. White on --tf-accent-strong is 5.7:1. */
  --tf-accent: #8b5cf6;
  --tf-accent-strong: #7c3aed;
  --tf-accent-hover: #6d28d9;
  --tf-accent-text: #c4b5fd;
  --tf-accent-soft: rgba(139, 92, 246, 0.14);
  --tf-accent-line: rgba(139, 92, 246, 0.45);

  /* Status, reserved: never a series colour, always with an icon or a word.
     -mark is what a chart draws; -text is words on the dark (all >= 8:1 on
     --tf-surface-1); -soft and -line are a chip's fill and edge. */
  --tf-refused: #e11d48;
  --tf-refused-text: #fda4af;
  --tf-refused-soft: rgba(225, 29, 72, 0.13);
  --tf-refused-line: rgba(251, 113, 133, 0.38);
  --tf-observed: #d97706;
  --tf-observed-text: #fcd34d;
  --tf-observed-soft: rgba(217, 119, 6, 0.14);
  --tf-observed-line: rgba(251, 191, 36, 0.36);
  --tf-approved: #0ea572;
  --tf-approved-text: #6ee7b7;
  --tf-approved-soft: rgba(14, 165, 114, 0.13);
  --tf-approved-line: rgba(52, 211, 153, 0.36);
  --tf-info: #0284c7;
  --tf-info-text: #7dd3fc;
  --tf-info-soft: rgba(2, 132, 199, 0.15);
  --tf-info-line: rgba(56, 189, 248, 0.36);

  /* Categorical, for identity (an agent, an origin), never beside a status
     colour in one chart: violet, cyan, magenta, then "Other". */
  --tf-cat-1: #8b5cf6;
  --tf-cat-2: #0891b2;
  --tf-cat-3: #d55181;
  --tf-cat-other: #4b5470;

  /* Palette validation, run with the dataviz skill's validator
     (scripts/validate_palette.js, OKLab dE x100, Machado 2009 CVD at severity 1)
     against the chart surface --tf-surface-1 #0e1322, on 2026-09-25:

     Status series, stacked in this order (refused, would refuse, approved):
       node validate_palette.js "#e11d48,#d97706,#0ea572" --mode dark --surface "#0e1322"
       PASS lightness band (all inside L 0.48-0.67) · PASS chroma floor
       PASS CVD separation, worst adjacent #d97706/#e11d48 dE 9.4 (deutan)
       PASS normal-vision floor, worst adjacent dE 16.6 · PASS contrast, all >= 3:1
     The approved step moved from #059669 to #0ea572: #059669 beside #d97706
     measured dE 7.9 (protan), inside the 6-8 floor band.
     Info #0284c7 is a chip colour, never a mark; #0ea5e9 fell outside the
     dark band (L 0.685).

     Categorical, all pairs (it may colour dots or small multiples):
       node validate_palette.js "#8b5cf6,#0891b2,#d55181" --mode dark --surface "#0e1322" --pairs all
       PASS band · PASS chroma · PASS CVD, worst #0891b2/#d55181 dE 10.4 (deutan)
       PASS normal-vision, worst #0891b2/#8b5cf6 dE 21.1 · PASS contrast
     Rejected: violet with blue (#3987e5) failed both floors (dE 4.1 CVD,
     13.5 normal). The nearest categorical-to-status pairs, magenta/rose dE 8.5
     and cyan/info dE 5.6, are why the two never share a chart. */

  /* Chart chrome: recessive, one step off the surface, solid hairlines. */
  --tf-grid: #1c2438;
  --tf-baseline: #2a3450;
  --tf-axis: #8a93ab;
  --tf-track: #161d31;

  /* Type. Inter for the interface with tight tracking at display sizes,
     JetBrains Mono for code. Display 56/64, h1 40/48, h2 28/36, h3 20/28,
     body 15/24 (16 for ledes), small 13/20, micro 11/16. */
  --tf-font-sans: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --tf-font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --tf-fs-display: 3.5rem;   --tf-lh-display: 4rem;
  --tf-fs-h1: 2.5rem;        --tf-lh-h1: 3rem;
  --tf-fs-h2: 1.75rem;       --tf-lh-h2: 2.25rem;
  --tf-fs-h3: 1.25rem;       --tf-lh-h3: 1.75rem;
  --tf-fs-lede: 1rem;        --tf-lh-lede: 1.625rem;
  --tf-fs-body: 0.9375rem;   --tf-lh-body: 1.5rem;
  --tf-fs-small: 0.8125rem;  --tf-lh-small: 1.25rem;
  --tf-fs-micro: 0.6875rem;  --tf-lh-micro: 1rem;
  --tf-track-display: -0.035em;
  --tf-track-heading: -0.02em;
  --tf-track-caps: 0.06em;
  --tf-measure: 72ch;

  /* Space, on an 8px rhythm with a 4px half step. */
  --tf-space-half: 4px;
  --tf-space-1: 8px;
  --tf-space-1h: 12px;
  --tf-space-2: 16px;
  --tf-space-3: 24px;
  --tf-space-4: 32px;
  --tf-space-5: 40px;
  --tf-space-6: 48px;
  --tf-space-8: 64px;
  --tf-space-10: 80px;

  /* Radii */
  --tf-radius-xs: 4px;
  --tf-radius-sm: 6px;
  --tf-radius: 8px;
  --tf-radius-md: 12px;
  --tf-radius-lg: 16px;
  --tf-radius-xl: 20px;
  --tf-radius-pill: 999px;

  /* Elevation: a hairline and an inner highlight carry most of it; shadows
     are for what floats (menus, the palette, dialogs, toasts). */
  --tf-shadow-1: inset 0 1px 0 0 var(--tf-highlight);
  --tf-shadow-2: inset 0 1px 0 0 var(--tf-highlight), 0 10px 30px -12px rgba(0, 0, 0, 0.6);
  --tf-shadow-3: 0 0 0 1px rgba(255, 255, 255, 0.03), 0 28px 70px -18px rgba(0, 0, 0, 0.85), 0 10px 24px -12px rgba(0, 0, 0, 0.6);

  /* Motion. Everything below is switched off under prefers-reduced-motion. */
  --tf-dur-1: 120ms;
  --tf-dur-2: 200ms;
  --tf-dur-3: 320ms;
  --tf-dur-4: 560ms;
  --tf-dur-count: 700ms;
  --tf-stagger: 45ms;
  --tf-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --tf-ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --tf-ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

  /* Focus: a 2px violet ring, 2px off the element. */
  --tf-focus: #a78bfa;
  --tf-focus-width: 2px;
  --tf-focus-offset: 2px;

  /* Layout and stacking */
  --tf-header-h: 56px;
  --tf-container: 80rem;
  --tf-gutter: 16px;
  --tf-z-header: 40;
  --tf-z-menu: 50;
  --tf-z-overlay: 60;
  --tf-z-palette: 70;
  --tf-z-toast: 80;
  --tf-z-tip: 90;
}
@media (min-width: 768px) { :root { --tf-gutter: 24px; } }

/* -------------------------------------------------------------------- base */

html { color-scheme: dark; -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  color: var(--tf-text);
  background-color: var(--tf-bg);
  background-image:
    radial-gradient(1100px 520px at 50% -140px, var(--tf-glow), transparent 70%),
    linear-gradient(180deg, var(--tf-bg) 0%, var(--tf-bg-2) 100%);
  background-repeat: no-repeat;
  font-family: var(--tf-font-sans);
  font-feature-settings: 'cv11', 'ss01';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}
::selection { background: rgba(139, 92, 246, 0.38); color: #fff; }
[hidden] { display: none !important; }

/* Every control shows where the keyboard is. */
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible,
textarea:focus-visible, summary:focus-visible, [tabindex]:focus-visible {
  outline: var(--tf-focus-width) solid var(--tf-focus);
  outline-offset: var(--tf-focus-offset);
  border-radius: var(--tf-radius-sm);
}
svg a:focus-visible, svg g:focus-visible { outline: none; }
svg a:focus-visible .tf-mark, svg g:focus-visible .tf-mark { stroke: #ffffff; stroke-width: 2px; }

/* The same as Tailwind's, for a page that does not load it. */
.sr-only, .tf-sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0;
}

.tf-skip {
  position: fixed; left: var(--tf-space-2); top: var(--tf-space-1); z-index: 100;
  transform: translateY(-160%); transition: transform var(--tf-dur-2) var(--tf-ease-out);
  padding: 10px 14px; border-radius: var(--tf-radius); background: var(--tf-accent-strong); color: #fff;
  font: 600 var(--tf-fs-small)/1 var(--tf-font-sans); text-decoration: none; box-shadow: var(--tf-shadow-3);
}
.tf-skip:focus, .tf-skip:focus-visible { transform: translateY(0); }

.tf-mono, .tf-code { font-family: var(--tf-font-mono); }
.tf-break { overflow-wrap: anywhere; word-break: break-word; }
.tf-num { font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------------ layout */

.tf-container { width: 100%; max-width: var(--tf-container); margin-inline: auto; padding-inline: var(--tf-gutter); box-sizing: border-box; }
.tf-main { flex: 1 1 auto; width: 100%; max-width: var(--tf-container); margin-inline: auto; box-sizing: border-box;
  padding: var(--tf-space-4) var(--tf-gutter) var(--tf-space-8); display: flex; flex-direction: column; gap: var(--tf-space-3); }
.tf-main:focus { outline: none; }
@media (min-width: 768px) { .tf-main { padding-top: var(--tf-space-5); gap: var(--tf-space-4); } }

/* A page's head, the one title primitive every page and every screen of the
   dashboard wears: an eyebrow (or, on a screen deeper than a section, the
   breadcrumb in its place), the title and the lede. The eyebrow and the
   breadcrumb are one line of the same height, so the title stands at the
   same place from page to page. */
.tf-page-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: var(--tf-space-3); }
.tf-page-head > :first-child { min-width: 0; flex: 1 1 32rem; }
.tf-page-head .tf-eyebrow { display: flex; }
/* One line whatever its length: a long name ends in an ellipsis rather than
   wrapping, and the padding, taken back by the margins, keeps a link's focus
   ring inside the box that clips the line. */
.tf-crumbs {
  display: flex; align-items: center; gap: 6px; min-width: 0; overflow: hidden; white-space: nowrap;
  padding: 3px; margin: -3px -3px calc(var(--tf-space-1h) - 3px);
  font: 500 0.75rem/var(--tf-lh-micro) var(--tf-font-sans); color: var(--tf-text-3);
}
.tf-crumbs a { flex-shrink: 0; color: var(--tf-text-2); text-decoration: none; }
.tf-crumbs a:hover { color: var(--tf-text); text-decoration: underline; text-underline-offset: 3px; }
.tf-crumbs [aria-current="page"] { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.tf-crumb-sep { flex-shrink: 0; color: var(--tf-text-decor); }
.tf-eyebrow {
  display: inline-flex; align-items: center; gap: var(--tf-space-1); margin: 0 0 var(--tf-space-1h);
  font: 600 var(--tf-fs-micro)/var(--tf-lh-micro) var(--tf-font-sans); letter-spacing: var(--tf-track-caps);
  text-transform: uppercase; color: var(--tf-accent-text);
}
.tf-eyebrow .tf-icon { width: 16px; height: 16px; }
.tf-display { margin: 0; font-size: 2.25rem; line-height: 2.75rem; font-weight: 650; letter-spacing: var(--tf-track-display); color: var(--tf-text); }
@media (min-width: 768px) { .tf-display { font-size: var(--tf-fs-display); line-height: var(--tf-lh-display); } }
.tf-h1 { margin: 0; font-size: 1.75rem; line-height: 2.25rem; font-weight: 650; letter-spacing: var(--tf-track-heading); color: var(--tf-text); }
@media (min-width: 768px) { .tf-h1 { font-size: var(--tf-fs-h1); line-height: var(--tf-lh-h1); letter-spacing: -0.028em; } }
.tf-h2 { margin: 0; font-size: 1.375rem; line-height: 1.875rem; font-weight: 600; letter-spacing: var(--tf-track-heading); color: var(--tf-text); }
@media (min-width: 768px) { .tf-h2 { font-size: var(--tf-fs-h2); line-height: var(--tf-lh-h2); } }
.tf-h3 { margin: 0; font-size: var(--tf-fs-h3); line-height: var(--tf-lh-h3); font-weight: 600; letter-spacing: -0.012em; color: var(--tf-text); }
.tf-lede { margin: var(--tf-space-1h) 0 0; max-width: var(--tf-measure); font-size: var(--tf-fs-lede); line-height: var(--tf-lh-lede); color: var(--tf-text-2); }
.tf-prose { max-width: var(--tf-measure); font-size: var(--tf-fs-small); line-height: 1.375rem; color: var(--tf-text-2); }
.tf-prose p { margin: 0 0 var(--tf-space-1h); }
.tf-prose p:last-child { margin-bottom: 0; }
.tf-small { font-size: var(--tf-fs-small); line-height: var(--tf-lh-small); color: var(--tf-text-2); }
.tf-micro { font-size: var(--tf-fs-micro); line-height: var(--tf-lh-micro); color: var(--tf-text-3); }
.tf-muted { color: var(--tf-text-3); }
.tf-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--tf-space-1); }
.tf-divider { height: 1px; border: 0; margin: 0; background: var(--tf-hairline); }

.tf-footer { border-top: 1px solid var(--tf-hairline); padding: var(--tf-space-3) 0; color: var(--tf-text-3); font-size: var(--tf-fs-micro); line-height: var(--tf-lh-micro); }
.tf-footer .tf-container { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--tf-space-1) var(--tf-space-3); }
.tf-footer a { color: var(--tf-text-2); text-decoration: none; }
.tf-footer a:hover { color: var(--tf-text); text-decoration: underline; text-underline-offset: 3px; }

/* --------------------------------------------------------------- the shell */

.tf-header {
  position: sticky; top: 0; z-index: var(--tf-z-header);
  background: rgba(7, 10, 20, 0.78);
  -webkit-backdrop-filter: saturate(150%) blur(14px); backdrop-filter: saturate(150%) blur(14px);
  border-bottom: 1px solid var(--tf-hairline);
}
.tf-header-inner { display: flex; align-items: center; gap: var(--tf-space-2); height: var(--tf-header-h); }

.tf-brand { display: inline-flex; align-items: center; gap: 10px; flex-shrink: 0; color: var(--tf-text); text-decoration: none; border-radius: var(--tf-radius); }
.tf-brand-mark {
  display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: 9px; color: #fff;
  background: radial-gradient(120% 120% at 20% 0%, #a78bfa 0%, #7c3aed 45%, #5b21b6 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28), 0 6px 18px -6px rgba(124, 58, 237, 0.7);
}
.tf-brand-mark .tf-icon { width: 18px; height: 18px; }
.tf-brand-text { display: none; line-height: 1rem; }
@media (min-width: 640px) { .tf-brand-text { display: block; } }
.tf-brand-name { display: block; font-size: 0.875rem; font-weight: 700; letter-spacing: -0.01em; color: var(--tf-text); }
.tf-brand-sub { display: block; font-size: var(--tf-fs-micro); color: var(--tf-text-3); }

/* The header's mount point, and the plain links it holds before script runs. */
.tf-nav-mount { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; justify-content: flex-end; }
.tf-nav-fallback { display: flex; flex-wrap: wrap; gap: 4px 14px; font-size: var(--tf-fs-small); }
.tf-nav-fallback a { color: var(--tf-text-2); }

/* What mountNav draws into the header's mount point. */
.tf-shell { display: flex; align-items: center; gap: var(--tf-space-1); flex: 1 1 auto; min-width: 0; justify-content: flex-end; }
.tf-nav { display: none; align-items: center; gap: 2px; margin: 0; padding: 0; }
@media (min-width: 1024px) { .tf-nav { display: flex; margin-right: auto; margin-left: var(--tf-space-2); } }
.tf-nav-link, button.tf-nav-link {
  display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 10px; border-radius: var(--tf-radius);
  font: 500 var(--tf-fs-small)/1 var(--tf-font-sans); color: var(--tf-text-2); text-decoration: none; white-space: nowrap;
  background: transparent; border: 0; cursor: pointer; position: relative;
  transition: color var(--tf-dur-1), background-color var(--tf-dur-1);
}
.tf-nav-link:hover, button.tf-nav-link:hover { color: var(--tf-text); background: var(--tf-surface-2); }
.tf-nav-current, button.tf-nav-current, .tf-nav-link[aria-current="page"] { color: var(--tf-text); background: var(--tf-surface-2); }
.tf-nav .tf-nav-current::after, .tf-nav .tf-nav-link[aria-current="page"]::after {
  content: ''; position: absolute; left: 10px; right: 10px; bottom: -12px; height: 2px; border-radius: 2px; background: var(--tf-accent);
}
.tf-nav-link .tf-icon { width: 16px; height: 16px; opacity: 0.85; }
.tf-nav-link .tf-chevron { width: 14px; height: 14px; transition: transform var(--tf-dur-2) var(--tf-ease-out); }
.tf-nav-link[aria-expanded="true"] .tf-chevron { transform: rotate(180deg); }
.tf-nav-dot { width: 6px; height: 6px; border-radius: 99px; background: var(--tf-accent); }

.tf-more { position: relative; }
.tf-popover {
  position: absolute; top: calc(100% + 10px); left: 0; z-index: var(--tf-z-menu); min-width: 232px; padding: 6px;
  background: var(--tf-surface-2); border: 1px solid var(--tf-hairline-strong); border-radius: var(--tf-radius-md);
  box-shadow: var(--tf-shadow-3); animation: tf-pop var(--tf-dur-2) var(--tf-ease-out);
}
.tf-menu-item {
  display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: var(--tf-radius);
  font: 500 var(--tf-fs-small)/1.25 var(--tf-font-sans); color: var(--tf-text-2); text-decoration: none;
}
.tf-menu-item:hover, .tf-menu-item:focus-visible { background: var(--tf-surface-3); color: var(--tf-text); }
.tf-menu-item[aria-current="page"] { color: var(--tf-text); background: var(--tf-accent-soft); }
.tf-menu-item .tf-icon { width: 16px; height: 16px; color: var(--tf-text-3); flex-shrink: 0; }
.tf-menu-item[aria-current="page"] .tf-icon { color: var(--tf-accent-text); }
.tf-menu-label { display: block; padding: 8px 10px 4px; font: 600 var(--tf-fs-micro)/1 var(--tf-font-sans); letter-spacing: var(--tf-track-caps); text-transform: uppercase; color: var(--tf-text-3); }

.tf-tools { display: flex; align-items: center; gap: var(--tf-space-1); min-width: 0; }
.tf-tools-wide { display: none; align-items: center; gap: var(--tf-space-1); }
@media (min-width: 768px) { .tf-tools-wide { display: flex; } }

.tf-cmdk, button.tf-cmdk {
  display: inline-flex; align-items: center; gap: 8px; height: 32px; padding: 0 6px 0 10px; border-radius: var(--tf-radius);
  background: var(--tf-surface-1); border: 1px solid var(--tf-hairline); color: var(--tf-text-3); cursor: pointer;
  font: 500 var(--tf-fs-small)/1 var(--tf-font-sans); transition: border-color var(--tf-dur-1), color var(--tf-dur-1), background-color var(--tf-dur-1);
}
.tf-cmdk:hover, button.tf-cmdk:hover { border-color: var(--tf-hairline-strong); color: var(--tf-text); background: var(--tf-surface-2); }
.tf-cmdk .tf-icon { width: 16px; height: 16px; }
.tf-cmdk-words { display: none; }
.tf-cmdk .tf-kbd-group { display: none; }
@media (min-width: 1100px) {
  .tf-cmdk { min-width: 184px; }
  .tf-cmdk-words { display: inline; margin-right: auto; }
  .tf-cmdk .tf-kbd-group { display: inline-flex; }
}

.tf-kbd {
  display: inline-flex; align-items: center; justify-content: center; min-width: 20px; height: 20px; padding: 0 5px; box-sizing: border-box;
  border-radius: var(--tf-radius-xs); border: 1px solid var(--tf-hairline-strong); border-bottom-width: 2px;
  background: var(--tf-inset); color: var(--tf-text-2); font: 500 10.5px/1 var(--tf-font-mono);
}
.tf-kbd-group { display: inline-flex; align-items: center; gap: 3px; }

.tf-icon-btn, button.tf-icon-btn {
  display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px; flex-shrink: 0;
  border-radius: var(--tf-radius); color: var(--tf-text-2); border: 1px solid var(--tf-hairline-strong); background: var(--tf-surface-1); cursor: pointer;
  transition: background-color var(--tf-dur-1), color var(--tf-dur-1);
}
.tf-icon-btn:hover, button.tf-icon-btn:hover { background: var(--tf-surface-2); color: var(--tf-text); }
.tf-icon-btn .tf-icon { width: 18px; height: 18px; }
.tf-menu-btn { display: inline-flex; }
@media (min-width: 1024px) { .tf-menu-btn, button.tf-menu-btn { display: none; } }

/* The menu sheet on a narrow screen: the same items as the bar, larger. */
.tf-sheet, .tf-menu {
  position: fixed; left: 0; right: 0; top: var(--tf-header-h); z-index: var(--tf-z-menu);
  height: calc(100vh - var(--tf-header-h)); height: calc(100dvh - var(--tf-header-h)); overflow-y: auto; overscroll-behavior: contain;
  padding: var(--tf-space-2) var(--tf-gutter) var(--tf-space-3); box-sizing: border-box;
  background: var(--tf-bg); border-bottom: 1px solid var(--tf-hairline-strong); box-shadow: 0 30px 60px -20px rgba(0, 0, 0, 0.9);
  animation: tf-sheet var(--tf-dur-3) var(--tf-ease-out);
}
.tf-sheet.hidden, .tf-menu.hidden { display: none; }
@media (min-width: 1024px) { .tf-sheet, .tf-menu { display: none !important; } }
.tf-sheet-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.tf-sheet-link {
  display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 0 12px; border-radius: var(--tf-radius-md);
  background: var(--tf-surface-1); border: 1px solid var(--tf-hairline); color: var(--tf-text-2); text-decoration: none;
  font: 500 0.875rem/1.2 var(--tf-font-sans);
}
.tf-sheet-link:hover { color: var(--tf-text); border-color: var(--tf-hairline-strong); }
.tf-sheet-link[aria-current="page"] { color: var(--tf-text); border-color: var(--tf-accent-line); background: var(--tf-accent-soft); }
.tf-sheet-link .tf-icon { width: 18px; height: 18px; color: var(--tf-text-3); flex-shrink: 0; }
.tf-sheet-link[aria-current="page"] .tf-icon { color: var(--tf-accent-text); }
.tf-sheet-section { margin-top: var(--tf-space-2); }
.tf-sheet-section:first-child { margin-top: 0; }
.tf-sheet-title { margin: 0 0 var(--tf-space-1); font: 600 var(--tf-fs-micro)/1 var(--tf-font-sans); letter-spacing: var(--tf-track-caps); text-transform: uppercase; color: var(--tf-text-3); }
.tf-sheet-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--tf-space-1); padding-top: var(--tf-space-2); margin-top: var(--tf-space-2); border-top: 1px solid var(--tf-hairline); }

/* ------------------------------------------------------------- primitives */

/* Icons: one set, stroke 1.5 on a 20px grid, drawn by Threefold.icon(). */
.tf-icon { display: inline-block; flex-shrink: 0; vertical-align: -0.2em; }
/* A placeholder a static page writes; the icon drawn into it lays out as if it
   were the placeholder itself. */
[data-tf-icon]:not([class]) { display: contents; }

/* Cards and panels */
.tf-card {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0) 140px), var(--tf-surface-1);
  border: 1px solid var(--tf-hairline); border-radius: var(--tf-radius-lg); box-shadow: var(--tf-shadow-1);
}
.tf-card-quiet { background: var(--tf-inset); border: 1px solid var(--tf-hairline); border-radius: var(--tf-radius-md); }
.tf-card-link { display: block; color: inherit; text-decoration: none;
  transition: border-color var(--tf-dur-2) var(--tf-ease-out), background-color var(--tf-dur-2), transform var(--tf-dur-2) var(--tf-ease-out), box-shadow var(--tf-dur-2); }
.tf-card-link:hover { border-color: var(--tf-accent-line); background-color: var(--tf-surface-2); transform: translateY(-1px); box-shadow: var(--tf-shadow-2); }
.tf-card-link:active { transform: translateY(0); }

.tf-panel { padding: var(--tf-space-2) var(--tf-space-2) var(--tf-space-3); }
@media (min-width: 640px) { .tf-panel { padding: var(--tf-space-3); } }
.tf-panel-head {
  display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: var(--tf-space-1h) var(--tf-space-2);
  padding-bottom: var(--tf-space-2); margin-bottom: var(--tf-space-2); border-bottom: 1px solid var(--tf-hairline);
}
.tf-panel-head > :first-child { min-width: 0; flex: 1 1 18rem; }
.tf-panel-title { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font: 600 1rem/1.5rem var(--tf-font-sans); letter-spacing: -0.01em; color: var(--tf-text); }
.tf-panel-title .tf-icon { width: 18px; height: 18px; color: var(--tf-accent-text); }
.tf-panel-sub { margin: 4px 0 0; max-width: var(--tf-measure); font-size: var(--tf-fs-small); line-height: var(--tf-lh-small); color: var(--tf-text-3); }
.tf-panel-body { display: flex; flex-direction: column; gap: var(--tf-space-2); }

.tf-section-title { margin: 0; font-size: 0.9375rem; line-height: 1.375rem; font-weight: 600; letter-spacing: -0.01em; color: var(--tf-text); }
.tf-section-sub { margin: 2px 0 0; font-size: 0.75rem; line-height: 1.125rem; color: var(--tf-text-3); }

/* A callout: a hint, a warning, a promise. Tone by modifier; always words. */
.tf-callout {
  display: flex; gap: var(--tf-space-1h); padding: var(--tf-space-1h) var(--tf-space-2); border-radius: var(--tf-radius-md);
  background: var(--tf-surface-2); border: 1px solid var(--tf-hairline); font-size: var(--tf-fs-small); line-height: var(--tf-lh-small); color: var(--tf-text-2);
}
.tf-callout > .tf-icon, .tf-callout > [data-tf-icon] > .tf-icon { width: 18px; height: 18px; margin-top: 1px; color: var(--tf-text-3); }
.tf-callout-body { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 6px; }
.tf-callout-body p { margin: 0; }
.tf-callout-title { margin: 0; font-weight: 600; color: var(--tf-text); }
.tf-callout-info { background: var(--tf-info-soft); border-color: var(--tf-info-line); }
.tf-callout-info > .tf-icon, .tf-callout-info > [data-tf-icon] > .tf-icon, .tf-callout-info .tf-callout-title { color: var(--tf-info-text); }
.tf-callout-ok { background: var(--tf-approved-soft); border-color: var(--tf-approved-line); }
.tf-callout-ok > .tf-icon, .tf-callout-ok > [data-tf-icon] > .tf-icon, .tf-callout-ok .tf-callout-title { color: var(--tf-approved-text); }
.tf-callout-warn { background: var(--tf-observed-soft); border-color: var(--tf-observed-line); }
.tf-callout-warn > .tf-icon, .tf-callout-warn > [data-tf-icon] > .tf-icon, .tf-callout-warn .tf-callout-title { color: var(--tf-observed-text); }
.tf-callout-danger { background: var(--tf-refused-soft); border-color: var(--tf-refused-line); }
.tf-callout-danger > .tf-icon, .tf-callout-danger > [data-tf-icon] > .tf-icon, .tf-callout-danger .tf-callout-title { color: var(--tf-refused-text); }
.tf-callout-accent { background: var(--tf-accent-soft); border-color: var(--tf-accent-line); }
.tf-callout-accent > .tf-icon, .tf-callout-accent > [data-tf-icon] > .tf-icon, .tf-callout-accent .tf-callout-title { color: var(--tf-accent-text); }

/* Buttons: primary, secondary (the default), ghost, danger; sm, default, lg;
   aria-busy="true" shows the loading state and holds the width. */
.tf-btn, button.tf-btn {
  position: relative; display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 36px; padding: 0 14px; box-sizing: border-box; border-radius: var(--tf-radius);
  font: 600 var(--tf-fs-small)/1 var(--tf-font-sans); letter-spacing: -0.005em; white-space: nowrap; text-decoration: none; cursor: pointer;
  color: var(--tf-text); background: var(--tf-surface-2); border: 1px solid var(--tf-hairline-strong);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
  transition: background-color var(--tf-dur-1), border-color var(--tf-dur-1), color var(--tf-dur-1), transform var(--tf-dur-1), opacity var(--tf-dur-1);
}
.tf-btn:hover, button.tf-btn:hover { background: var(--tf-surface-3); border-color: #36416a; }
.tf-btn:active, button.tf-btn:active { transform: translateY(1px); }
.tf-btn .tf-icon { width: 16px; height: 16px; }
.tf-btn-secondary, button.tf-btn-secondary { background: var(--tf-surface-2); }
.tf-btn-primary, button.tf-btn-primary {
  color: #fff; background: var(--tf-accent-strong); border-color: #8b5cf6;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 8px 22px -10px rgba(124, 58, 237, 0.8);
}
.tf-btn-primary:hover, button.tf-btn-primary:hover { background: var(--tf-accent-hover); border-color: #a78bfa; }
.tf-btn-ghost, button.tf-btn-ghost, .tf-btn-quiet, button.tf-btn-quiet { background: transparent; border-color: transparent; box-shadow: none; color: var(--tf-text-2); }
.tf-btn-ghost:hover, button.tf-btn-ghost:hover, .tf-btn-quiet:hover, button.tf-btn-quiet:hover { background: var(--tf-surface-2); border-color: transparent; color: var(--tf-text); }
.tf-btn-danger, button.tf-btn-danger { background: var(--tf-refused-soft); border-color: var(--tf-refused-line); color: var(--tf-refused-text); }
.tf-btn-danger:hover, button.tf-btn-danger:hover { background: rgba(225, 29, 72, 0.24); border-color: rgba(251, 113, 133, 0.6); }
.tf-btn-good, button.tf-btn-good { background: var(--tf-approved-soft); border-color: var(--tf-approved-line); color: var(--tf-approved-text); }
.tf-btn-good:hover, button.tf-btn-good:hover { background: rgba(14, 165, 114, 0.24); }
.tf-btn-warn, button.tf-btn-warn { background: var(--tf-observed-soft); border-color: var(--tf-observed-line); color: var(--tf-observed-text); }
.tf-btn-warn:hover, button.tf-btn-warn:hover { background: rgba(217, 119, 6, 0.26); }
.tf-btn-sm, button.tf-btn-sm { height: 28px; padding: 0 10px; gap: 6px; font-size: 0.75rem; border-radius: var(--tf-radius-sm); }
.tf-btn-sm .tf-icon { width: 14px; height: 14px; }
.tf-btn-lg, button.tf-btn-lg { height: 44px; padding: 0 20px; font-size: 0.9375rem; border-radius: 10px; }
.tf-btn-block { width: 100%; }
.tf-btn:disabled, .tf-btn[aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; transform: none; }
.tf-btn[aria-busy="true"] { cursor: progress; pointer-events: none; }
.tf-btn[aria-busy="true"]::before {
  content: ''; width: 14px; height: 14px; flex-shrink: 0; box-sizing: border-box; border-radius: 50%;
  border: 2px solid currentColor; border-right-color: transparent; animation: tf-spin 700ms linear infinite;
}
.tf-btn[aria-busy="true"] > .tf-icon { display: none; }

/* A button that reads as a link. */
.tf-link-btn, button.tf-link-btn {
  display: inline-flex; align-items: center; gap: 6px; padding: 2px 0; border: 0; background: none; cursor: pointer;
  font: 500 var(--tf-fs-micro)/1rem var(--tf-font-sans); color: var(--tf-text-3); text-decoration: underline; text-decoration-color: var(--tf-hairline-strong); text-underline-offset: 3px;
}
.tf-link-btn:hover, button.tf-link-btn:hover { color: var(--tf-text); text-decoration-color: currentColor; }
.tf-link-btn .tf-icon { width: 14px; height: 14px; }

/* Links */
.tf-link { color: var(--tf-accent-text); text-decoration: underline; text-decoration-color: rgba(196, 181, 253, 0.4); text-underline-offset: 3px; }
.tf-link:hover { color: #ddd6fe; text-decoration-color: currentColor; }
.tf-link-quiet { color: var(--tf-text); text-decoration: none; }
.tf-link-quiet:hover { color: var(--tf-accent-text); text-decoration: underline; text-underline-offset: 3px; }
.tf-link-row { display: flex; border-radius: var(--tf-radius-sm); padding: 2px 4px; margin: -2px -4px; color: inherit; text-decoration: none; }
.tf-link-row:hover { background: var(--tf-surface-2); }
.tf-num-link { font-variant-numeric: tabular-nums; border-radius: var(--tf-radius-xs); padding: 0 4px; color: inherit; }
.tf-num-link:hover { background: var(--tf-surface-3); text-decoration: underline; text-underline-offset: 2px; }
.tf-spec-link {
  display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border-radius: var(--tf-radius-pill);
  font: 500 var(--tf-fs-micro)/1rem var(--tf-font-mono); color: var(--tf-accent-text); text-decoration: none;
  background: var(--tf-accent-soft); border: 1px solid rgba(139, 92, 246, 0.3); white-space: nowrap;
}
.tf-spec-link:hover { border-color: var(--tf-accent-line); color: #ddd6fe; }
.tf-spec-link .tf-icon { width: 12px; height: 12px; }

/* Chips: a status is always an icon and a word, never colour alone. */
.tf-chip {
  display: inline-flex; align-items: center; gap: 5px; height: 22px; padding: 0 8px; box-sizing: border-box; border-radius: var(--tf-radius-pill);
  font: 600 0.6875rem/1 var(--tf-font-sans); letter-spacing: 0.005em; white-space: nowrap; text-decoration: none;
  border: 1px solid var(--tf-hairline-strong); background: var(--tf-surface-2); color: var(--tf-text-2);
}
.tf-chip .tf-icon, .tf-chip svg { width: 13px; height: 13px; flex-shrink: 0; }
.tf-chip-gray { background: var(--tf-surface-2); color: #c9cfdd; border-color: var(--tf-hairline-strong); }
.tf-chip-sky { background: var(--tf-info-soft); color: var(--tf-info-text); border-color: var(--tf-info-line); }
.tf-chip-emerald { background: var(--tf-approved-soft); color: var(--tf-approved-text); border-color: var(--tf-approved-line); }
.tf-chip-amber { background: var(--tf-observed-soft); color: var(--tf-observed-text); border-color: var(--tf-observed-line); }
.tf-chip-rose { background: var(--tf-refused-soft); color: var(--tf-refused-text); border-color: var(--tf-refused-line); }
.tf-chip-purple { background: var(--tf-accent-soft); color: var(--tf-accent-text); border-color: rgba(139, 92, 246, 0.4); }
.tf-chip-button, button.tf-chip-button { cursor: pointer; background: var(--tf-surface-1); color: var(--tf-text-2); border-color: var(--tf-hairline-strong); transition: background-color var(--tf-dur-1), color var(--tf-dur-1); }
.tf-chip-button:hover, button.tf-chip-button:hover { background: var(--tf-surface-3); color: var(--tf-text); }
a.tf-chip:hover { filter: brightness(1.15); }
.tf-chip-lg { height: 26px; padding: 0 10px; font-size: 0.75rem; }
/* A status chip without an inline icon (where a panel must hold no <svg> of
   its own) still leads with a mark before its word. */
.tf-chip-dot::before { content: ''; width: 6px; height: 6px; border-radius: 99px; background: currentColor; flex-shrink: 0; }
.tf-dot { width: 8px; height: 8px; border-radius: 99px; display: inline-block; flex-shrink: 0; background: currentColor; }
/* Where a project's calls come from (Threefold.sourceChip): identity, so a
   dot in a categorical hue beside a word. The service's own probes take the
   neutral of "other" with a hatch, never a series hue of their own. */
.tf-src { gap: 6px; }
.tf-src::before { content: ''; width: 7px; height: 7px; border-radius: 99px; background: var(--tf-cat-other); flex-shrink: 0; }
.tf-src[data-src="fleet"]::before { background: var(--tf-cat-1); }
.tf-src[data-src="live"]::before { background: var(--tf-cat-3); }
.tf-src[data-src="sandbox"]::before { background: var(--tf-cat-2); }
.tf-src[data-src="probe"]::before { background: repeating-linear-gradient(135deg, var(--tf-cat-other) 0 2px, var(--tf-text-3) 2px 3px); }

/* A code block with a copy button that confirms. */
.tf-command { position: relative; }
.tf-pre {
  margin: 0; padding: 14px 92px 14px 16px; border-radius: var(--tf-radius-md); background: var(--tf-ink-0);
  border: 1px solid var(--tf-hairline); font: 400 0.8125rem/1.6 var(--tf-font-mono); color: #dde1ea;
  white-space: pre-wrap; overflow-wrap: anywhere; box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.4);
}
.tf-pre code { font: inherit; }
.tf-pre-plain { padding-right: 16px; }
/* A block that keeps its lines whole and scrolls sideways (pre.code) would
   run its first line under the copy button at the start of the scroll, where
   the right padding does not reach. The button gets a strip of its own above
   the code instead. */
.tf-command > pre.code { padding-top: 44px; padding-right: 16px; }
.tf-prompt { color: var(--tf-text-decor); user-select: none; }
.tf-copy, button.tf-copy {
  position: absolute; top: 8px; right: 8px; display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 10px;
  border-radius: var(--tf-radius-sm); font: 600 0.75rem/1 var(--tf-font-sans); cursor: pointer;
  background: var(--tf-surface-2); color: var(--tf-text-2); border: 1px solid var(--tf-hairline-strong);
  transition: background-color var(--tf-dur-1), color var(--tf-dur-1), border-color var(--tf-dur-1);
}
.tf-copy:hover, button.tf-copy:hover { background: var(--tf-surface-3); color: var(--tf-text); }
.tf-copy .tf-icon { width: 14px; height: 14px; }
.tf-copy .tf-icon-done { display: none; }
.tf-copy.is-copied, button.tf-copy.is-copied { color: var(--tf-approved-text); border-color: var(--tf-approved-line); background: var(--tf-approved-soft); }
.tf-copy.is-copied .tf-icon-idle { display: none; }
.tf-copy.is-copied .tf-icon-done { display: inline-block; }

/* Form fields */
.tf-input, .tf-select, .tf-textarea {
  box-sizing: border-box; min-width: 0; height: 36px; padding: 0 12px; border-radius: var(--tf-radius);
  background: var(--tf-inset); border: 1px solid var(--tf-hairline-strong); color: var(--tf-text);
  font: 400 var(--tf-fs-small)/1.25rem var(--tf-font-sans); transition: border-color var(--tf-dur-1), box-shadow var(--tf-dur-1);
}
.tf-textarea { height: auto; padding: 10px 12px; line-height: 1.5; resize: vertical; }
.tf-input.tf-mono, .tf-textarea.tf-mono { font-family: var(--tf-font-mono); font-size: 0.78rem; }
.tf-input::placeholder, .tf-textarea::placeholder { color: var(--tf-text-4); }
.tf-input:hover, .tf-select:hover, .tf-textarea:hover { border-color: #36416a; }
.tf-input:focus, .tf-select:focus, .tf-textarea:focus { border-color: var(--tf-accent); outline: none; box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.22); }
.tf-input-sm, .tf-select.tf-input-sm { height: 30px; font-size: 0.75rem; padding: 0 10px; }
.tf-label { display: block; margin-bottom: 6px; font: 600 var(--tf-fs-micro)/1rem var(--tf-font-sans); letter-spacing: var(--tf-track-caps); text-transform: uppercase; color: var(--tf-text-3); }
.tf-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.tf-field .tf-label { margin: 0; }
.tf-help { margin: 0; font-size: 0.75rem; line-height: 1.125rem; color: var(--tf-text-3); }
.tf-check { display: inline-flex; align-items: center; gap: 8px; font-size: var(--tf-fs-small); color: var(--tf-text-2); cursor: pointer; }
.tf-check input { width: 16px; height: 16px; accent-color: var(--tf-accent); }

.tf-segmented { display: inline-flex; flex-wrap: wrap; padding: 3px; gap: 2px; border-radius: 10px; background: var(--tf-inset); border: 1px solid var(--tf-hairline); }
.tf-segmented > * { padding: 5px 11px; border-radius: 7px; font: 500 0.75rem/1.125rem var(--tf-font-sans); color: var(--tf-text-2); text-decoration: none; }
.tf-segmented > *:hover { color: var(--tf-text); }
.tf-segmented > [aria-pressed="true"], .tf-segmented > [aria-current="true"] { background: var(--tf-surface-3); color: var(--tf-text); box-shadow: inset 0 0 0 1px var(--tf-hairline-strong), 0 1px 2px rgba(0, 0, 0, 0.4); }

/* Tabs: ARIA tabs, arrow keys move between them (threefold.js). */
.tf-tabs { display: inline-flex; flex-wrap: wrap; gap: 2px; padding: 3px; border-radius: 10px; background: var(--tf-inset); border: 1px solid var(--tf-hairline); }
.tf-tab, button.tf-tab {
  display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 12px; border: 0; border-radius: 7px; cursor: pointer;
  background: transparent; color: var(--tf-text-2); font: 500 var(--tf-fs-small)/1 var(--tf-font-sans); transition: background-color var(--tf-dur-1), color var(--tf-dur-1);
}
.tf-tab:hover, button.tf-tab:hover { color: var(--tf-text); }
.tf-tab[aria-selected="true"], button.tf-tab[aria-selected="true"] { background: var(--tf-surface-3); color: var(--tf-text); box-shadow: inset 0 0 0 1px var(--tf-hairline-strong), 0 1px 2px rgba(0, 0, 0, 0.4); }
.tf-tab .tf-icon { width: 15px; height: 15px; }
.tf-tabpanel { margin-top: var(--tf-space-1h); }
.tf-tabpanel:focus-visible { outline-offset: 4px; }

/* Tables: a sticky header, no zebra, a row lifts on hover, and on a phone
   .tf-table-stack turns each row into a card of label and value. */
.tf-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: var(--tf-fs-small); line-height: var(--tf-lh-small); }
.tf-table th {
  position: sticky; top: 0; z-index: 1; text-align: left; padding: 10px 12px 10px 0; white-space: nowrap;
  font: 600 var(--tf-fs-micro)/1rem var(--tf-font-sans); letter-spacing: var(--tf-track-caps); text-transform: uppercase; color: var(--tf-text-3);
  background: var(--tf-surface-1); border-bottom: 1px solid var(--tf-hairline-strong);
}
.tf-table td, .tf-table tbody th { padding: 11px 12px 11px 0; border-bottom: 1px solid var(--tf-hairline); vertical-align: top; color: var(--tf-text-2); }
.tf-table tbody tr:last-child td, .tf-table tbody tr:last-child th { border-bottom: 0; }
/* A row's own header cell reads as data, not as a column heading. */
.tf-table tbody th { position: static; text-transform: none; letter-spacing: normal; font-size: var(--tf-fs-small); font-weight: 500; color: var(--tf-text); white-space: normal; background: none; }
.tf-table tbody tr { transition: background-color var(--tf-dur-1); }
.tf-table tbody tr:hover { background: rgba(26, 34, 56, 0.55); }
.tf-table tbody tr[data-selected="true"] { background: var(--tf-accent-soft); }
.tf-table .num { text-align: right; font-family: var(--tf-font-mono); font-variant-numeric: tabular-nums; }
.tf-table th.num { font-family: var(--tf-font-sans); }
.tf-table :is(th, td):first-child { padding-left: 4px; }
.tf-scroll-x { overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch; }
.tf-table-scroll { max-height: 70vh; overflow: auto; }
.tf-row-link { cursor: pointer; }
@media (max-width: 639px) {
  .tf-table-stack thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0, 0, 0, 0); }
  .tf-table-stack, .tf-table-stack tbody, .tf-table-stack tr, .tf-table-stack td, .tf-table-stack tbody th { display: block; width: auto; }
  .tf-table-stack tr { padding: 12px 14px; margin-bottom: 8px; border-radius: var(--tf-radius-md); background: var(--tf-inset); border: 1px solid var(--tf-hairline); }
  /* A cell of prose keeps its flow: the label sits above it. A number sits
     beside its label, on the same line. */
  .tf-table-stack td, .tf-table-stack tbody th { padding: 5px 0; border: 0; text-align: left; overflow-wrap: anywhere; }
  .tf-table-stack td.num { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; text-align: right; }
  .tf-table-stack td[data-label]::before, .tf-table-stack tbody th[data-label]::before {
    content: attr(data-label); display: block; margin-bottom: 2px; font: 600 var(--tf-fs-micro)/1.25rem var(--tf-font-sans);
    letter-spacing: var(--tf-track-caps); text-transform: uppercase; color: var(--tf-text-3);
  }
  .tf-table-stack td.num[data-label]::before { display: inline; margin: 0; flex-shrink: 0; }
  .tf-table-stack td[colspan] { display: block; text-align: center; }
  .tf-table-stack td[colspan]::before { content: none; }
}

/* A disclosure: what most readers never need, one click away. */
.tf-disclosure { border: 1px solid var(--tf-hairline); border-radius: var(--tf-radius-md); background: var(--tf-surface-1); }
.tf-disclosure > summary {
  display: flex; align-items: center; gap: 10px; padding: 12px 16px; cursor: pointer; list-style: none; border-radius: var(--tf-radius-md);
  font: 500 var(--tf-fs-small)/1.25rem var(--tf-font-sans); color: var(--tf-text-2);
}
.tf-disclosure > summary::-webkit-details-marker { display: none; }
.tf-disclosure > summary:hover { color: var(--tf-text); }
.tf-disclosure > summary .tf-icon { width: 16px; height: 16px; color: var(--tf-text-3); }
.tf-disclosure > summary::after {
  content: ''; margin-left: auto; width: 8px; height: 8px; border-right: 1.5px solid var(--tf-text-3); border-bottom: 1.5px solid var(--tf-text-3);
  transform: rotate(45deg) translateY(-2px); transition: transform var(--tf-dur-2) var(--tf-ease-out);
}
.tf-disclosure[open] > summary::after { transform: rotate(225deg) translateY(-2px); }
.tf-disclosure[open] > summary { border-bottom: 1px solid var(--tf-hairline); border-radius: var(--tf-radius-md) var(--tf-radius-md) 0 0; }
.tf-disclosure-body { padding: 16px; display: flex; flex-direction: column; gap: 12px; }
.tf-summary-note { margin-left: 4px; font-weight: 400; color: var(--tf-text-3); }
@media (max-width: 639px) { .tf-summary-note { display: none; } }

/* A toolbar: the controls that scope what is below them, in one row. */
.tf-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; }
.tf-toolbar .tf-grow { flex: 1 1 14rem; min-width: 0; }
.tf-toolbar-end { margin-left: auto; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }

/* A meter: severity in the fill, the track a quieter step of the same ramp. */
.tf-meter { height: 8px; border-radius: 4px; overflow: hidden; background: rgba(14, 165, 114, 0.16); }
.tf-meter-fill { height: 100%; border-radius: 0 4px 4px 0; background: var(--tf-approved); transition: width var(--tf-dur-4) var(--tf-ease-out); }
.tf-meter-warn { background: rgba(217, 119, 6, 0.18); }
.tf-meter-warn .tf-meter-fill { background: var(--tf-observed); }
.tf-meter-danger { background: rgba(225, 29, 72, 0.18); }
.tf-meter-danger .tf-meter-fill { background: var(--tf-refused); }

/* A definition list of label and value, as the detail panels use. */
.tf-dl { margin: 0; display: flex; flex-direction: column; }
.tf-dl-row { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; padding: 8px 0; border-bottom: 1px solid var(--tf-hairline); font-size: var(--tf-fs-small); line-height: 1.25rem; }
.tf-dl-row:last-child { border-bottom: 0; }
.tf-dl-row dt { color: var(--tf-text-3); flex-shrink: 0; }
.tf-dl-row dd { margin: 0; min-width: 0; text-align: right; font-family: var(--tf-font-mono); font-size: 0.78rem; color: var(--tf-text); overflow-wrap: anywhere; }
.tf-good { color: var(--tf-approved-text) !important; }
.tf-bad { color: var(--tf-refused-text) !important; }
.tf-warn-text { color: var(--tf-observed-text) !important; }
.tf-accent-text { color: var(--tf-accent-text) !important; }

/* Stat tiles: a label in plain words, the value, a sub-line that says what it
   means, and optionally a sparkline, a delta and the rows behind it. */
.tf-tile { display: flex; flex-direction: column; gap: 6px; padding: 18px 18px 16px; min-width: 0; box-sizing: border-box; }
.tf-tile-label { display: flex; align-items: flex-start; gap: 6px; font: 500 var(--tf-fs-small)/1.25rem var(--tf-font-sans); color: var(--tf-text-2); text-transform: none; letter-spacing: normal; }
.tf-tile-label .tf-icon { width: 16px; height: 16px; margin-top: 2px; color: var(--tf-text-3); }
.tf-tile-row { display: flex; align-items: flex-end; justify-content: space-between; gap: 8px; min-width: 0; }
.tf-tile-value { font: 650 2rem/2.25rem var(--tf-font-sans); letter-spacing: -0.03em; color: var(--tf-text); font-variant-numeric: proportional-nums; }
.tf-tile-sub { font-size: 0.75rem; line-height: 1.125rem; color: var(--tf-text-3); }
.tf-tile-term { font: 500 var(--tf-fs-micro)/1rem var(--tf-font-mono); color: var(--tf-text-4); }
.tf-tile-more { display: inline-flex; align-items: center; gap: 4px; margin-top: auto; padding-top: 6px; font: 500 0.75rem/1rem var(--tf-font-sans); color: var(--tf-text-3); transition: color var(--tf-dur-1), gap var(--tf-dur-2) var(--tf-ease-out); }
.tf-tile-more .tf-icon { width: 14px; height: 14px; }
.tf-card-link:hover .tf-tile-more { color: var(--tf-accent-text); gap: 7px; }
/* The value keeps its width; the sparkline gives way to it, scaled down
   whole rather than running out of a narrow tile. */
.tf-tile-value { flex-shrink: 0; }
.tf-tile-spark { flex: 0 1 auto; min-width: 0; display: inline-flex; justify-content: flex-end; }
.tf-tile-spark > svg { display: block; max-width: 100%; height: auto; }
.tf-delta { display: inline-flex; align-items: center; gap: 3px; font: 600 0.75rem/1rem var(--tf-font-sans); color: var(--tf-text-3); }
.tf-delta .tf-icon { width: 13px; height: 13px; }
.tf-delta-good { color: var(--tf-approved-text); }
.tf-delta-bad { color: var(--tf-refused-text); }

/* Stepper: numbered steps with a connector; done, current, todo. */
.tf-stepper { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--tf-space-2); counter-reset: tf-step; }
@media (min-width: 768px) { .tf-stepper { grid-auto-flow: column; grid-auto-columns: 1fr; gap: var(--tf-space-3); } }
.tf-stepper-item { position: relative; display: flex; gap: var(--tf-space-1h); min-width: 0; }
@media (min-width: 768px) {
  .tf-stepper-item { flex-direction: column; gap: var(--tf-space-1h); }
  .tf-stepper-item:not(:last-child)::after {
    content: ''; position: absolute; top: 14px; left: 40px; right: calc(-1 * var(--tf-space-3) + 12px); height: 1px; background: var(--tf-hairline-strong);
  }
  .tf-stepper-item[data-state="done"]:not(:last-child)::after { background: var(--tf-accent-line); }
}
.tf-stepper-title { margin: 0; font: 600 var(--tf-fs-small)/1.25rem var(--tf-font-sans); color: var(--tf-text); }
.tf-stepper-text { margin: 4px 0 0; font-size: 0.8125rem; line-height: 1.25rem; color: var(--tf-text-2); }
.tf-step { display: flex; gap: 14px; }
.tf-step-num {
  width: 28px; height: 28px; border-radius: 99px; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; box-sizing: border-box;
  font: 700 0.75rem/1 var(--tf-font-sans); border: 1px solid var(--tf-hairline-strong); background: var(--tf-surface-2); color: var(--tf-text-2);
  transition: background-color var(--tf-dur-3) var(--tf-ease-out), border-color var(--tf-dur-3), color var(--tf-dur-3);
}
.tf-step-num[data-state="current"], [data-state="current"] > .tf-step-num { background: var(--tf-accent-strong); border-color: #a78bfa; color: #fff; box-shadow: 0 0 0 4px var(--tf-accent-soft); }
.tf-step-num[data-state="done"], [data-state="done"] > .tf-step-num { background: var(--tf-approved-soft); border-color: var(--tf-approved-line); color: var(--tf-approved-text); }
.tf-step-num .tf-icon { width: 14px; height: 14px; }

/* A state a whole panel is in: signed out, an error. */
.tf-state { display: flex; flex-direction: column; gap: var(--tf-space-2); padding: var(--tf-space-3); }
.tf-state-head { display: flex; align-items: flex-start; gap: var(--tf-space-1h); }
.tf-state-icon { display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px; flex-shrink: 0; border-radius: 10px; border: 1px solid var(--tf-hairline-strong); background: var(--tf-surface-2); color: var(--tf-text-2); }
.tf-state-copy { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.tf-state-title { margin: 0; font: 600 1rem/1.5rem var(--tf-font-sans); letter-spacing: -0.01em; color: var(--tf-text); }
.tf-state-text { margin: 0; max-width: var(--tf-measure); font-size: var(--tf-fs-small); line-height: var(--tf-lh-small); color: var(--tf-text-2); }
.tf-state-body { display: flex; flex-direction: column; gap: var(--tf-space-1); }
.tf-state-body p { margin: 0; }
.tf-state-foot { margin: 0; padding-top: var(--tf-space-2); border-top: 1px solid var(--tf-hairline); font-size: 0.75rem; line-height: 1.125rem; color: var(--tf-text-3); }
.tf-state-warn { border-color: var(--tf-observed-line); }
.tf-state-warn .tf-state-icon { background: var(--tf-observed-soft); border-color: var(--tf-observed-line); color: var(--tf-observed-text); }
.tf-state-danger { border-color: var(--tf-refused-line); }
.tf-state-danger .tf-state-icon { background: var(--tf-refused-soft); border-color: var(--tf-refused-line); color: var(--tf-refused-text); }
.tf-state-danger .tf-state-title { color: var(--tf-refused-text); }

/* Shown from a tablet up; on a phone it lives in the menu sheet. */
.tf-wide-only { display: none; }
@media (min-width: 1280px) { .tf-wide-only { display: inline-flex; } }

/* Empty state: an icon, one sentence, one action. */
.tf-empty {
  display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--tf-space-1h);
  padding: var(--tf-space-5) var(--tf-space-3); border-radius: var(--tf-radius-lg); border: 1px dashed var(--tf-hairline-strong);
  background: rgba(8, 11, 21, 0.5);
}
.tf-empty-icon { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; border-radius: 12px; color: var(--tf-accent-text); background: var(--tf-accent-soft); border: 1px solid rgba(139, 92, 246, 0.3); }
.tf-empty-icon .tf-icon { width: 20px; height: 20px; }
.tf-empty-text { margin: 0; max-width: 46ch; font-size: 0.875rem; line-height: 1.375rem; color: var(--tf-text-2); }

/* Loading */
.tf-skeleton {
  display: block; border-radius: var(--tf-radius);
  background: linear-gradient(90deg, var(--tf-surface-2) 0%, var(--tf-surface-3) 50%, var(--tf-surface-2) 100%);
  background-size: 200% 100%; animation: tf-shimmer 1.4s ease-in-out infinite;
}
.tf-skeleton-line { height: 12px; }
.tf-skeleton-stack { display: flex; flex-direction: column; gap: 10px; }

/* Waiting for the first call: the one thing that loops. */
.tf-waiting { display: inline-flex; align-items: center; gap: 10px; color: var(--tf-text-2); font-size: var(--tf-fs-small); }
.tf-waiting-dot { position: relative; width: 10px; height: 10px; border-radius: 99px; background: var(--tf-accent); flex-shrink: 0; }
.tf-waiting-dot::after { content: ''; position: absolute; inset: 0; border-radius: inherit; background: inherit; animation: tf-ping 1.6s var(--tf-ease-out) infinite; }

/* Toasts: aria-live, bottom centre on a phone, bottom right on a desk. */
.tf-toast-root {
  position: fixed; left: 50%; bottom: 16px; transform: translateX(-50%); z-index: var(--tf-z-toast);
  display: flex; flex-direction: column; gap: 8px; width: calc(100% - 32px); max-width: 28rem; pointer-events: none;
}
@media (min-width: 768px) { .tf-toast-root { left: auto; right: 24px; bottom: 24px; transform: none; } }
.tf-toast {
  pointer-events: auto; display: flex; align-items: center; gap: 12px; padding: 12px 12px 12px 14px; border-radius: var(--tf-radius-md);
  background: var(--tf-surface-2); border: 1px solid var(--tf-hairline-strong); box-shadow: var(--tf-shadow-3);
  font-size: var(--tf-fs-small); line-height: var(--tf-lh-small); color: var(--tf-text);
  animation: tf-toast-in var(--tf-dur-3) var(--tf-ease-out);
}
.tf-toast > .tf-icon { width: 18px; height: 18px; color: var(--tf-text-3); }
.tf-toast-ok > .tf-icon { color: var(--tf-approved-text); }
.tf-toast-warn > .tf-icon { color: var(--tf-observed-text); }
.tf-toast-danger > .tf-icon { color: var(--tf-refused-text); }
.tf-toast-text { flex: 1; min-width: 0; overflow-wrap: anywhere; }

/* Dialog: focus-trapped, Escape closes (threefold.js). */
.tf-overlay {
  position: fixed; inset: 0; z-index: var(--tf-z-overlay); display: flex; align-items: flex-end; justify-content: center; padding: 0;
  background: rgba(3, 5, 12, 0.66); -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); animation: tf-fade var(--tf-dur-2) ease-out;
}
@media (min-width: 640px) { .tf-overlay { align-items: center; padding: 24px; } }
.tf-dialog {
  width: 100%; max-width: 40rem; max-height: 92vh; overflow-y: auto; box-sizing: border-box;
  background: var(--tf-surface-1); border: 1px solid var(--tf-hairline-strong); border-radius: 16px 16px 0 0; box-shadow: var(--tf-shadow-3);
  animation: tf-dialog-in var(--tf-dur-3) var(--tf-ease-out);
}
@media (min-width: 640px) { .tf-dialog { border-radius: 16px; } }
.tf-dialog-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; padding: 20px 20px 14px; border-bottom: 1px solid var(--tf-hairline); }
.tf-dialog-title { margin: 0; font: 600 1.0625rem/1.5rem var(--tf-font-sans); letter-spacing: -0.01em; color: var(--tf-text); }
.tf-dialog-body { padding: 16px 20px; display: flex; flex-direction: column; gap: 14px; font-size: var(--tf-fs-small); line-height: 1.375rem; color: var(--tf-text-2); }
.tf-dialog-foot { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; padding: 14px 20px 20px; border-top: 1px solid var(--tf-hairline); }
html.tf-lock, html.tf-lock body { overflow: hidden; }

/* The command palette */
.tf-palette-overlay {
  position: fixed; inset: 0; z-index: var(--tf-z-palette); display: flex; justify-content: center; align-items: flex-start;
  padding: 10vh 16px 16px; box-sizing: border-box; background: rgba(3, 5, 12, 0.62);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); animation: tf-fade var(--tf-dur-2) ease-out;
}
.tf-palette {
  width: 100%; max-width: 640px; max-height: 76vh; display: flex; flex-direction: column; overflow: hidden;
  background: var(--tf-surface-1); border: 1px solid var(--tf-hairline-strong); border-radius: 16px; box-shadow: var(--tf-shadow-3);
  animation: tf-dialog-in var(--tf-dur-3) var(--tf-ease-out);
}
.tf-palette-search { display: flex; align-items: center; gap: 12px; padding: 0 14px 0 16px; border-bottom: 1px solid var(--tf-hairline); }
.tf-palette-search > .tf-icon { width: 20px; height: 20px; color: var(--tf-text-3); }
.tf-palette-input {
  flex: 1; min-width: 0; height: 56px; border: 0; outline: none; background: transparent; color: var(--tf-text);
  font: 400 1rem/1.5rem var(--tf-font-sans); letter-spacing: -0.005em;
}
.tf-palette-input::placeholder { color: var(--tf-text-4); }
.tf-palette-input:focus-visible { outline: none; }
.tf-palette-list { flex: 1; overflow-y: auto; padding: 6px 8px 10px; overscroll-behavior: contain; }
.tf-palette-group { padding: 12px 10px 6px; font: 600 var(--tf-fs-micro)/1rem var(--tf-font-sans); letter-spacing: var(--tf-track-caps); text-transform: uppercase; color: var(--tf-text-3); }
.tf-palette-item {
  display: flex; align-items: center; gap: 12px; min-height: 44px; padding: 8px 10px; box-sizing: border-box; border-radius: 10px;
  color: var(--tf-text-2); text-decoration: none; cursor: pointer; scroll-margin: 8px;
}
.tf-palette-item:hover { background: var(--tf-surface-2); color: var(--tf-text); }
.tf-palette-item[aria-selected="true"] { background: var(--tf-surface-3); color: var(--tf-text); box-shadow: inset 2px 0 0 var(--tf-accent); }
.tf-palette-icon { display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; flex-shrink: 0; border-radius: 8px; background: var(--tf-surface-2); border: 1px solid var(--tf-hairline); color: var(--tf-text-3); }
.tf-palette-item[aria-selected="true"] .tf-palette-icon { color: var(--tf-accent-text); border-color: var(--tf-accent-line); background: var(--tf-accent-soft); }
.tf-palette-icon .tf-icon { width: 16px; height: 16px; }
.tf-palette-text { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.tf-palette-label { font: 500 0.875rem/1.25rem var(--tf-font-sans); color: inherit; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tf-palette-label mark { background: none; color: var(--tf-accent-text); font-weight: 600; }
.tf-palette-hint { font-size: 0.75rem; line-height: 1rem; color: var(--tf-text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tf-palette-go { color: var(--tf-text-4); opacity: 0; transition: opacity var(--tf-dur-1); }
.tf-palette-go .tf-icon { width: 16px; height: 16px; }
.tf-palette-item[aria-selected="true"] .tf-palette-go { opacity: 1; }
.tf-palette-empty { padding: 32px 16px; text-align: center; font-size: var(--tf-fs-small); color: var(--tf-text-3); }
.tf-palette-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; padding: 10px 16px; border-top: 1px solid var(--tf-hairline); background: var(--tf-inset); font-size: var(--tf-fs-micro); color: var(--tf-text-3); }
.tf-palette-foot span { display: inline-flex; align-items: center; gap: 6px; }
@media (max-width: 639px) { .tf-palette-overlay { padding-top: 12px; } .tf-palette { max-height: calc(100dvh - 24px); } .tf-palette-foot { display: none; } }
/* On a phone a project's hint (its stage, where its calls come from, how
   many) wraps rather than losing its end to an ellipsis. */
@media (max-width: 639px) { .tf-palette-hint { white-space: normal; } }

/* The tooltip every chart mark shares: value first, label after. */
.tf-tip {
  position: fixed; left: 0; top: 0; z-index: var(--tf-z-tip); pointer-events: none; max-width: 260px;
  padding: 8px 10px; border-radius: var(--tf-radius); background: #161d31; border: 1px solid var(--tf-hairline-strong);
  box-shadow: var(--tf-shadow-3); color: var(--tf-text-2); font-size: 0.75rem; line-height: 1.125rem;
  opacity: 0; transform: translateY(4px); transition: opacity var(--tf-dur-1), transform var(--tf-dur-1) var(--tf-ease-out);
}
.tf-tip[data-show="true"] { opacity: 1; transform: none; }
.tf-tip-value { display: flex; align-items: center; gap: 8px; font: 650 0.875rem/1.25rem var(--tf-font-sans); color: var(--tf-text); font-variant-numeric: tabular-nums; }
.tf-tip-key { width: 12px; height: 3px; border-radius: 2px; flex-shrink: 0; }
.tf-tip-label { display: block; color: var(--tf-text-2); }
.tf-tip-action { display: block; margin-top: 2px; color: var(--tf-text-3); font-size: var(--tf-fs-micro); }

/* ------------------------------------------------------------------ charts */

.tf-figure { margin: 0; min-width: 0; }
.tf-svg { overflow: visible; display: block; }
.tf-axis { fill: var(--tf-axis); font-size: 11px; font-family: var(--tf-font-sans); font-variant-numeric: tabular-nums; }
.tf-chart-label { fill: var(--tf-text-2); font: 600 11px var(--tf-font-sans); font-variant-numeric: tabular-nums; }
.tf-donut-value { fill: var(--tf-text); font: 650 22px var(--tf-font-sans); letter-spacing: -0.02em; }
.tf-mark { transition: opacity var(--tf-dur-2) var(--tf-ease-out), filter var(--tf-dur-1); }
.tf-hit { fill: transparent; }
/* Hovering or focusing one mark recedes the rest, so the one read stands out. */
.tf-svg:has(a:hover, a:focus-visible, g[data-tf-tip]:hover, g[data-tf-tip]:focus-visible) .tf-mark { opacity: 0.45; }
.tf-svg:has(a:hover, a:focus-visible, g[data-tf-tip]:hover, g[data-tf-tip]:focus-visible) :is(a:hover, a:focus-visible, g[data-tf-tip]:hover, g[data-tf-tip]:focus-visible) .tf-mark { opacity: 1; filter: brightness(1.12); }
.tf-svg a, .tf-svg [data-tf-tip] { cursor: pointer; }
.tf-chart-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px; margin-top: 12px; }
.tf-legend { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 0; padding: 0; list-style: none; font-size: 0.75rem; line-height: 1rem; color: var(--tf-text-2); }
.tf-figure > .tf-legend { margin-top: 12px; }
.tf-legend li { display: inline-flex; align-items: center; gap: 6px; }
.tf-swatch { width: 10px; height: 10px; border-radius: 3px; display: inline-block; flex-shrink: 0; }
.tf-swatch-line { width: 14px; height: 2px; border-radius: 2px; }
/* The table view: read by a screen reader always, shown on request. A table
   ignores the 1px width .sr-only gives it and lays out at its content's width,
   so on a phone the hidden table pushed the page 6px wide; its own box keeps it
   in, and scrolls sideways once it is shown. */
.tf-chart-table { position: relative; max-width: 100%; overflow: hidden; }
.tf-figure[data-table="open"] .tf-chart-table { overflow-x: auto; }
.tf-figure[data-table="open"] .tf-chart-table > table.sr-only {
  position: static; width: 100%; height: auto; margin: 12px 0 0; overflow: visible; clip: auto; white-space: normal;
  border-collapse: separate; border-spacing: 0; font-size: 0.75rem;
}
.tf-chart-table caption { text-align: left; padding-bottom: 6px; color: var(--tf-text-3); font-size: var(--tf-fs-micro); }
.tf-chart-table th, .tf-chart-table td { padding: 6px 12px 6px 0; border-bottom: 1px solid var(--tf-hairline); text-align: right; font-variant-numeric: tabular-nums; color: var(--tf-text-2); }
.tf-chart-table th:first-child { text-align: left; }
.tf-chart-table thead th { font-weight: 600; color: var(--tf-text-3); }

/* The ring: its legend beside it, each row a link to the rows behind it. */
.tf-donut { display: flex; align-items: center; gap: var(--tf-space-2); flex-wrap: wrap; }
.tf-donut > svg { flex-shrink: 0; }
.tf-donut-legend { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; min-width: 0; flex: 1 1 8rem; font-size: 0.75rem; line-height: 1.125rem; }
.tf-donut-row { display: flex; align-items: center; gap: 8px; }
.tf-donut-label { color: var(--tf-text-2); }
.tf-donut-num { margin-left: auto; padding-left: 12px; font-family: var(--tf-font-mono); font-variant-numeric: tabular-nums; color: var(--tf-text-3); }
a.tf-donut-row:hover .tf-donut-label { color: var(--tf-text); }

/* Horizontal bars: HTML, so the data end is a true 4px round at any width. */
.tf-hbars { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 14px; }
.tf-hbar-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; font-size: 0.75rem; line-height: 1.125rem; }
.tf-hbar-head > :first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--tf-font-mono); color: var(--tf-text); }
.tf-hbar-value { flex-shrink: 0; font-family: var(--tf-font-mono); font-variant-numeric: tabular-nums; color: var(--tf-text-2); }
.tf-hbar { display: flex; height: 8px; margin-top: 6px; border-radius: 4px; background: var(--tf-track); }
.tf-hbar-fill { display: flex; gap: 2px; height: 100%; min-width: 0; }
.tf-hbar-seg { display: block; height: 100%; min-width: 3px; flex: 1 1 0; background: var(--tf-accent); transition: filter var(--tf-dur-1), opacity var(--tf-dur-2); }
.tf-hbar-seg:last-child { border-radius: 0 4px 4px 0; }
.tf-hbar-seg:hover, .tf-hbar-seg:focus-visible { filter: brightness(1.18); }
.tf-hbar:hover .tf-hbar-seg { opacity: 0.6; }
.tf-hbar:hover .tf-hbar-seg:hover { opacity: 1; }
.tf-hbar-seg:focus-visible { outline: 2px solid var(--tf-focus); outline-offset: 2px; border-radius: 2px; }
.tf-hbar-sub { margin: 4px 0 0; font-size: var(--tf-fs-micro); line-height: 1rem; color: var(--tf-text-3); }

/* A reader's own name for a project, shown beside the alias the API knows. It
   is kept in this browser alone and is never sent anywhere, so it is drawn
   quieter than the alias and never in the alias's monospace. */
.tf-local-name {
  font-family: var(--tf-font-sans); font-weight: 400;
  color: var(--tf-text-2); overflow-wrap: anywhere; word-break: break-word;
}

/* ------------------------------------------------------------------ motion */

.tf-reveal { animation: tf-rise var(--tf-dur-3) var(--tf-ease-out) both; animation-delay: var(--tf-delay, 0ms); }
.tf-pulse { animation: tf-pulse-ring 1100ms var(--tf-ease-out) 1; }
.tf-pulse-ok { --tf-pulse-color: rgba(14, 165, 114, 0.55); }
.tf-pulse-danger { --tf-pulse-color: rgba(225, 29, 72, 0.6); }
.tf-pulse-warn { --tf-pulse-color: rgba(217, 119, 6, 0.55); }
.tf-spin { animation: tf-spin 800ms linear infinite; transform-origin: 50% 50%; }

@keyframes tf-rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes tf-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes tf-pop { from { opacity: 0; transform: translateY(-4px) scale(0.98); } to { opacity: 1; transform: none; } }
@keyframes tf-sheet { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }
@keyframes tf-dialog-in { from { opacity: 0; transform: translateY(10px) scale(0.985); } to { opacity: 1; transform: none; } }
@keyframes tf-toast-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes tf-shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
@keyframes tf-spin { to { transform: rotate(360deg); } }
@keyframes tf-ping { 0% { transform: scale(1); opacity: 0.7; } 80%, 100% { transform: scale(2.6); opacity: 0; } }
@keyframes tf-pulse-ring {
  0% { box-shadow: 0 0 0 0 var(--tf-pulse-color, rgba(139, 92, 246, 0.6)); }
  100% { box-shadow: 0 0 0 14px rgba(0, 0, 0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .tf-reveal, .tf-pulse, .tf-skeleton, .tf-waiting-dot::after, .tf-palette, .tf-palette-overlay, .tf-overlay, .tf-dialog,
  .tf-toast, .tf-popover, .tf-sheet, .tf-menu, .tf-spin, .tf-btn[aria-busy="true"]::before { animation: none !important; }
  .tf-card-link:hover { transform: none; }
  * { scroll-behavior: auto !important; transition-duration: 1ms !important; }
}

@media (forced-colors: active) {
  .tf-chip, .tf-btn, .tf-card, .tf-callout { border: 1px solid CanvasText; }
  .tf-hbar-seg, .tf-mark { forced-color-adjust: none; }
}
