/* ==========================================================================
   ŽOGU FABRIKA — Internal Portal Design Tokens
   v1.0 · dark theme · single source of truth
   --------------------------------------------------------------------------
   Serve this file centrally (e.g. /static/zf-tokens.css from the portal shell)
   and link it from every section app. Never redefine a raw hex downstream —
   always reference a token.

   Every colour pair used for text in this file has been measured with the
   WCAG 2.1 relative-luminance formula. Ratios are noted inline.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. PRIMITIVES — raw ramps. Do not use these directly in components.
   Use the semantic aliases in section 2.
   -------------------------------------------------------------------------- */
:root {
  /* Brand anchor, sampled from the logo ------------------------------------ */
  --zf-logo-gray:        #808080; /* the logo disc. OKLCH L .600 C .000       */
  --zf-logo-ink:         #111111; /* the logo wordmark                        */
  --zf-logo-line:        #FFFFFF; /* the chain-link mesh                      */

  /* Neutral ramp — cool-tinted (OKLCH hue ≈ 232°, chroma ≤ .02).
     Tinted, not pure gray, so it sits under the cyan accent without the
     muddy green cast pure-neutral grays get next to cyan.                    */
  --zf-neutral-0:        #0A0D10;
  --zf-neutral-50:       #0E1317;
  --zf-neutral-100:      #11171B;
  --zf-neutral-200:      #161D22;
  --zf-neutral-300:      #1E262C;
  --zf-neutral-400:      #232C33;
  --zf-neutral-500:      #2C373F;
  --zf-neutral-600:      #3D4A53;
  --zf-neutral-700:      #626F79;
  --zf-neutral-800:      #8695A0;
  --zf-neutral-900:      #A8B6C0;
  --zf-neutral-950:      #EAF0F4;

  /* Cyan ramp — OKLCH hue 212.3°, generated from the accent anchor.
     Ordinal/sequential encoding uses 100→600 only (700 is below the 2:1
     floor against the card surface and is for fills/borders).               */
  --zf-cyan-100:         #BCF3FF;
  --zf-cyan-200:         #93DBEB;
  --zf-cyan-300:         #4FC3D9; /* ← brand accent anchor */
  --zf-cyan-400:         #2AA6BC; /* ← chart series slot 1 */
  --zf-cyan-500:         #02899D;
  --zf-cyan-600:         #016D7D;
  --zf-cyan-700:         #01515E;

  /* Amber ramp — OKLCH hue 73.0°. Secondary accent + chart series slot 2.    */
  --zf-amber-100:        #FFE3C1;
  --zf-amber-200:        #F6C483;
  --zf-amber-300:        #F0A83C; /* ← secondary accent anchor */
  --zf-amber-400:        #C98500; /* ← chart series slot 2 */
  --zf-amber-500:        #A66D01;
  --zf-amber-600:        #835501;
  --zf-amber-700:        #633F00;
}

/* --------------------------------------------------------------------------
   2. SEMANTIC TOKENS — this is what components reference.
   -------------------------------------------------------------------------- */
:root {
  color-scheme: dark;

  /* Surfaces --------------------------------------------------------------- */
  --zf-bg-page:          var(--zf-neutral-50);   /* app background            */
  --zf-bg-sunken:        var(--zf-neutral-0);    /* wells, code, chart plots  */
  --zf-bg-inset:         var(--zf-neutral-100);  /* inputs, table headers     */
  --zf-bg-surface:       var(--zf-neutral-200);  /* cards, tiles, panels      */
  --zf-bg-surface-hover: var(--zf-neutral-300);  /* card/row hover            */
  --zf-bg-surface-raised:var(--zf-neutral-300);  /* menus, popovers, tooltips */
  --zf-bg-nav:           var(--zf-neutral-100);  /* sidebar + top bar         */

  /* Ink -------------------------------------------------------------------- */
  --zf-text-primary:     var(--zf-neutral-950);  /* 14.8:1 on surface  · AAA  */
  --zf-text-secondary:   var(--zf-neutral-900);  /*  8.2:1 on surface  · AAA  */
  --zf-text-muted:       var(--zf-neutral-800);  /*  5.5:1 on surface  · AA   */
  --zf-text-disabled:    var(--zf-neutral-700);  /*  3.3:1 · large text only  */
  --zf-text-on-accent:   var(--zf-neutral-50);   /*  9.0:1 on cyan-300 · AA   */
  --zf-text-inverse:     var(--zf-neutral-50);

  /* Lines ------------------------------------------------------------------ */
  --zf-border-subtle:    var(--zf-neutral-400);  /* table rules, dividers     */
  --zf-border-default:   var(--zf-neutral-500);  /* card + input outlines     */
  --zf-border-strong:    var(--zf-neutral-600);  /* hovered/active outlines   */
  --zf-border-accent:    var(--zf-cyan-300);

  /* Accent ----------------------------------------------------------------- */
  --zf-accent:           var(--zf-cyan-300);     /*  8.2:1 on surface  · AA   */
  --zf-accent-hover:     var(--zf-cyan-200);
  --zf-accent-active:    var(--zf-cyan-400);
  --zf-accent-quiet:     var(--zf-cyan-500);
  --zf-accent-wash:      rgba(79, 195, 217, .12);/* nav-active, selected rows */
  --zf-accent-wash-hi:   rgba(79, 195, 217, .20);

  --zf-accent-2:         var(--zf-amber-300);    /*  8.4:1 on surface  · AA   */
  --zf-accent-2-wash:    rgba(240, 168,  60, .12);

  /* Focus ------------------------------------------------------------------ */
  --zf-focus-ring:       var(--zf-cyan-300);
  --zf-focus-ring-width: 2px;
  --zf-focus-ring-offset:2px;

  /* Status — reserved meaning. NEVER reuse as a chart series colour.
     `-fill` is for dots/bars/badge backgrounds, `-text` for label text
     (the fills for `good` and `critical` are below 4.5:1 as text).           */
  --zf-status-good-fill:      #0CA30C;  /* 5.1:1 on surface */
  --zf-status-good-text:      #3FD07A;  /* 8.5:1 on surface · AA */
  --zf-status-warning-fill:   #FAB219;  /* 9.3:1 */
  --zf-status-warning-text:   #FAB219;  /* 9.3:1 · AA */
  --zf-status-serious-fill:   #EC835A;  /* 6.5:1 */
  --zf-status-serious-text:   #EC835A;  /* 6.5:1 · AA */
  --zf-status-critical-fill:  #D03B3B;  /* 3.5:1 — non-text use only */
  --zf-status-critical-text:  #EF7A7A;  /* 6.3:1 · AA */
  --zf-status-neutral-fill:   var(--zf-neutral-700);
  --zf-status-neutral-text:   var(--zf-neutral-800);

  /* Delta cues. Named by MEANING, not by arrow direction — in an energy
     context a rise in consumption is bad, so it is red and points up.
     Binding these to "up"/"down" is how dashboards end up colouring a cost
     overrun green.                                                          */
  --zf-delta-good:       #3FD07A;
  --zf-delta-bad:        #EF7A7A;
  --zf-delta-flat:       var(--zf-neutral-800);

  /* ---- CHART TOKENS ------------------------------------------------------ */
  /* Categorical: fixed order, assigned in sequence, NEVER cycled.
     Validated on the dark card surface (#161D22):
       worst adjacent CVD ΔE 13.0 (deutan) — target ≥ 8
       worst adjacent normal-vision ΔE 19.3 — floor ≥ 15
     Slots 1–3 additionally clear the all-pairs test (CVD ΔE 8.9 /
     normal 19.3), so scatter, bubble and small-multiples charts —
     where any two marks can touch — cap at THREE series. Past three,
     fold to "Other" or facet.                                               */
  --zf-series-1:         #2AA6BC;  /* cyan   — brand                         */
  --zf-series-2:         #C98500;  /* amber  — brand secondary               */
  --zf-series-3:         #D55181;  /* rose                                   */
  --zf-series-4:         #008300;  /* green                                  */
  --zf-series-5:         #3987E5;  /* blue                                   */
  --zf-series-6:         #199E70;  /* teal                                   */
  --zf-series-7:         #9085E9;  /* violet                                 */
  --zf-series-8:         #E66767;  /* red                                    */
  --zf-series-other:     var(--zf-neutral-700); /* the "Other" bucket        */

  /* Sequential (magnitude): one hue, light→dark. Heatmaps, choropleths.      */
  --zf-seq-1:            var(--zf-cyan-100);
  --zf-seq-2:            var(--zf-cyan-200);
  --zf-seq-3:            var(--zf-cyan-300);
  --zf-seq-4:            var(--zf-cyan-400);
  --zf-seq-5:            var(--zf-cyan-500);
  --zf-seq-6:            var(--zf-cyan-600);

  /* Diverging (polarity): cyan ↔ amber, neutral gray midpoint.
     e.g. consumption vs. target, over/under budget.                         */
  --zf-div-neg-3:        var(--zf-cyan-500);
  --zf-div-neg-2:        var(--zf-cyan-400);
  --zf-div-neg-1:        var(--zf-cyan-300);
  --zf-div-mid:          #39434B; /* deliberately off-ramp — between neutral-500
                                     and -600 — so the midpoint reads as "nothing"
                                     rather than as a ramp step */
  --zf-div-pos-1:        var(--zf-amber-300);
  --zf-div-pos-2:        var(--zf-amber-400);
  --zf-div-pos-3:        var(--zf-amber-500);

  /* Chart chrome ----------------------------------------------------------- */
  --zf-chart-surface:    var(--zf-bg-surface);
  --zf-chart-grid:       var(--zf-neutral-400); /* hairline, recessive */
  --zf-chart-axis:       var(--zf-neutral-500); /* baseline */
  --zf-chart-label:      var(--zf-text-muted);
  --zf-chart-crosshair:  rgba(168, 182, 192, .35);
  --zf-chart-mark-ring:  var(--zf-bg-surface); /* 2px ring on overlapping marks */

  /* ---- TYPOGRAPHY -------------------------------------------------------- */
  --zf-font-sans: "Inter", "Inter var", -apple-system, BlinkMacSystemFont,
                  "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --zf-font-mono: ui-monospace, SFMono-Regular, "SF Mono", "JetBrains Mono",
                  Menlo, Consolas, monospace;

  --zf-fs-11:   11px;  --zf-lh-11: 16px;   /* micro label, uppercase        */
  --zf-fs-12:   12px;  --zf-lh-12: 16px;   /* caption, axis tick            */
  --zf-fs-13:   13px;  --zf-lh-13: 20px;   /* table cell, dense body        */
  --zf-fs-14:   14px;  --zf-lh-14: 21px;   /* BODY BASE                     */
  --zf-fs-16:   16px;  --zf-lh-16: 24px;   /* lead paragraph, card title lg */
  --zf-fs-20:   20px;  --zf-lh-20: 28px;   /* section heading (h2)          */
  --zf-fs-24:   24px;  --zf-lh-24: 32px;   /* page title (h1)               */
  --zf-fs-32:   32px;  --zf-lh-32: 38px;   /* stat-tile value               */
  --zf-fs-40:   40px;  --zf-lh-40: 46px;   /* hero figure                   */

  --zf-fw-regular:  400;
  --zf-fw-medium:   500;
  --zf-fw-semibold: 600;
  --zf-fw-bold:     700;

  --zf-ls-tight:  -0.02em;  /* ≥ 24px */
  --zf-ls-snug:   -0.01em;  /* 16–20px */
  --zf-ls-normal:  0;
  --zf-ls-wide:    0.06em;  /* uppercase micro labels */

  /* ---- SPACE / SHAPE / MOTION -------------------------------------------- */
  --zf-space-1:   4px;
  --zf-space-2:   8px;
  --zf-space-3:  12px;
  --zf-space-4:  16px;
  --zf-space-5:  20px;
  --zf-space-6:  24px;
  --zf-space-8:  32px;
  --zf-space-10: 40px;
  --zf-space-12: 48px;

  --zf-radius-sm:   4px;   /* badges, chart bar ends */
  --zf-radius-md:   6px;   /* buttons, inputs        */
  --zf-radius-lg:  10px;   /* cards, tiles, panels   */
  --zf-radius-xl:  14px;   /* modals                 */
  --zf-radius-pill: 999px;

  /* On dark, elevation reads from the BORDER first and the shadow second.
     Shadows alone are nearly invisible against a dark page.                  */
  --zf-elev-0: none;
  --zf-elev-1: 0 1px 2px rgba(0,0,0,.40);
  --zf-elev-2: 0 4px 12px rgba(0,0,0,.45);
  --zf-elev-3: 0 12px 32px rgba(0,0,0,.55);

  --zf-dur-fast:  120ms;
  --zf-dur-base:  180ms;
  --zf-ease:      cubic-bezier(.2, 0, .2, 1);

  --zf-sidebar-w:        232px;
  --zf-sidebar-w-collapsed: 60px;
  --zf-topbar-h:         56px;
  --zf-content-max:      1440px;
}

/* --------------------------------------------------------------------------
   3. SELF-HOSTED INTER
   Drop InterVariable.woff2 + InterVariable-Italic.woff2 (≈110 KB each) into
   /static/fonts/. One variable file covers weights 400–700 — no CDN call,
   no FOUT beyond the first paint, nothing to renew.
   -------------------------------------------------------------------------- */
/* Inter, self-hosted, split latin / latin-ext.
   latin-ext is REQUIRED — it carries ā č ē ģ ī ķ ļ ņ š ū ž and Ž.
   The latin subset alone has none of them. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/static/fonts/inter-latin-wght-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/static/fonts/inter-latin-ext-wght-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
  font-family: "Inter";
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url("/static/fonts/inter-latin-wght-italic.woff2") format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url("/static/fonts/inter-latin-ext-wght-italic.woff2") format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

/* --------------------------------------------------------------------------
   4. BASE
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
button, input, select, textarea { font-feature-settings: "cv05" 1, "ss03" 1; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--zf-bg-page);
  color: var(--zf-text-primary);
  font-family: var(--zf-font-sans);
  font-size: var(--zf-fs-14);
  line-height: var(--zf-lh-14);
  font-weight: var(--zf-fw-regular);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-feature-settings: "cv05" 1, "ss03" 1; /* Inter: open 'l', flat-top '3' */
}

/* Numerals that must align in a column get tabular figures.
   Standalone display numbers keep the default proportional figures. */
.zf-tnum, table, .zf-chart .tick, .zf-tile__delta { font-variant-numeric: tabular-nums; }

h1, h2, h3, h4 { margin: 0; font-weight: var(--zf-fw-semibold); }
h1 { font-size: var(--zf-fs-24); line-height: var(--zf-lh-24); letter-spacing: var(--zf-ls-tight); }
h2 { font-size: var(--zf-fs-20); line-height: var(--zf-lh-20); letter-spacing: var(--zf-ls-snug); }
h3 { font-size: var(--zf-fs-16); line-height: var(--zf-lh-16); letter-spacing: var(--zf-ls-snug); }
h4 { font-size: var(--zf-fs-14); line-height: var(--zf-lh-14); }

a { color: var(--zf-accent); text-decoration-color: rgba(79,195,217,.4); text-underline-offset: 2px; }
a:hover { color: var(--zf-accent-hover); text-decoration-color: currentColor; }

/* One focus treatment everywhere. Keyboard only — never suppress it. */
:focus-visible {
  outline: var(--zf-focus-ring-width) solid var(--zf-focus-ring);
  outline-offset: var(--zf-focus-ring-offset);
  border-radius: var(--zf-radius-sm);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* --------------------------------------------------------------------------
   5. COMPONENT RECIPES
   -------------------------------------------------------------------------- */

/* --- Card / tile ---------------------------------------------------------- */
.zf-card {
  background: var(--zf-bg-surface);
  border: 1px solid var(--zf-border-default);
  border-radius: var(--zf-radius-lg);
  padding: var(--zf-space-5);
  box-shadow: var(--zf-elev-1);
}
.zf-card__header {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--zf-space-3); margin-bottom: var(--zf-space-4);
}
.zf-card__title { font-size: var(--zf-fs-14); font-weight: var(--zf-fw-semibold); color: var(--zf-text-primary); }
.zf-card__meta  { font-size: var(--zf-fs-12); color: var(--zf-text-muted); }

/* Stat tile: label (11px caps) → value (32px) → delta (12px) */
.zf-tile__label {
  font-size: var(--zf-fs-11); line-height: var(--zf-lh-11);
  font-weight: var(--zf-fw-medium); letter-spacing: var(--zf-ls-wide);
  text-transform: uppercase; color: var(--zf-text-muted);
}
.zf-tile__value {
  font-size: var(--zf-fs-32); line-height: var(--zf-lh-32);
  font-weight: var(--zf-fw-semibold); letter-spacing: var(--zf-ls-tight);
  color: var(--zf-text-primary); margin-top: var(--zf-space-2);
}
.zf-tile__unit { font-size: var(--zf-fs-14); font-weight: var(--zf-fw-medium); color: var(--zf-text-muted); margin-left: 4px; }
.zf-tile__delta { font-size: var(--zf-fs-12); margin-top: var(--zf-space-2); display: flex; align-items: center; gap: 5px; }
.zf-tile__delta--good { color: var(--zf-delta-good); }
.zf-tile__delta--bad  { color: var(--zf-delta-bad); }
.zf-tile__delta--flat { color: var(--zf-delta-flat); }
/* The ▲ / ▼ glyph carries direction; the colour carries judgement. Both
   always ship, so direction never rests on colour alone. */

/* --- Buttons -------------------------------------------------------------- */
.zf-btn {
  display: inline-flex; align-items: center; gap: var(--zf-space-2);
  height: 34px; padding: 0 var(--zf-space-4);
  font-family: var(--zf-font-sans); font-size: var(--zf-fs-13);
  font-weight: var(--zf-fw-medium); line-height: 1;
  border-radius: var(--zf-radius-md); border: 1px solid transparent;
  cursor: pointer; white-space: nowrap;
  transition: background var(--zf-dur-fast) var(--zf-ease),
              border-color var(--zf-dur-fast) var(--zf-ease),
              color var(--zf-dur-fast) var(--zf-ease);
}
.zf-btn--primary   { background: var(--zf-accent); color: var(--zf-text-on-accent); font-weight: var(--zf-fw-semibold); }
.zf-btn--primary:hover  { background: var(--zf-accent-hover); }
.zf-btn--primary:active { background: var(--zf-accent-active); }

.zf-btn--secondary { background: var(--zf-bg-surface); color: var(--zf-text-primary); border-color: var(--zf-border-default); }
.zf-btn--secondary:hover { background: var(--zf-bg-surface-hover); border-color: var(--zf-border-strong); }

.zf-btn--ghost     { background: transparent; color: var(--zf-text-secondary); }
.zf-btn--ghost:hover { background: var(--zf-bg-surface-hover); color: var(--zf-text-primary); }

.zf-btn--danger    { background: transparent; color: var(--zf-status-critical-text); border-color: rgba(239,122,122,.35); }
.zf-btn--danger:hover { background: rgba(208,59,59,.14); border-color: var(--zf-status-critical-text); }

.zf-btn:disabled   { color: var(--zf-text-disabled); background: var(--zf-bg-inset); border-color: var(--zf-border-subtle); cursor: not-allowed; }
.zf-btn--sm        { height: 28px; padding: 0 var(--zf-space-3); font-size: var(--zf-fs-12); }

/* --- Inputs --------------------------------------------------------------- */
.zf-input, .zf-select {
  height: 34px; padding: 0 var(--zf-space-3);
  background: var(--zf-bg-inset);
  color: var(--zf-text-primary);
  border: 1px solid var(--zf-border-default);
  border-radius: var(--zf-radius-md);
  font-family: var(--zf-font-sans); font-size: var(--zf-fs-13);
  font-weight: var(--zf-fw-regular); line-height: 1;
}
.zf-input::placeholder { color: var(--zf-text-muted); } /* placeholders are text — not exempt */
.zf-input:hover, .zf-select:hover { border-color: var(--zf-border-strong); }

/* --- Sidebar navigation --------------------------------------------------- */
.zf-sidebar {
  width: var(--zf-sidebar-w);
  background: var(--zf-bg-nav);
  border-right: 1px solid var(--zf-border-subtle);
  display: flex; flex-direction: column;
}
.zf-nav__group {
  font-size: var(--zf-fs-11); line-height: var(--zf-lh-11);
  font-weight: var(--zf-fw-semibold); letter-spacing: var(--zf-ls-wide);
  text-transform: uppercase; color: var(--zf-text-muted);
  padding: var(--zf-space-5) var(--zf-space-4) var(--zf-space-2);
}
.zf-nav__item {
  display: flex; align-items: center; gap: var(--zf-space-3);
  height: 36px; margin: 1px var(--zf-space-2);
  padding: 0 var(--zf-space-3);
  border-radius: var(--zf-radius-md);
  font-size: var(--zf-fs-13); font-weight: var(--zf-fw-medium);
  color: var(--zf-text-secondary); text-decoration: none;
  position: relative;
}
.zf-nav__item:hover { background: var(--zf-bg-surface-hover); color: var(--zf-text-primary); }
/* Unread counter in the sidebar. Pushed to the right edge of the row and given
   the critical fill, because its whole job is to be noticed from across a
   desk — and it is only ever drawn when the number is above zero. */
.zf-nav__count {
  margin-left: auto; min-width: 18px; padding: 0 6px;
  border-radius: 999px; text-align: center;
  font-size: var(--zf-fs-11); font-weight: var(--zf-fw-semibold);
  line-height: 18px; color: #fff; background: var(--zf-status-critical-fill);
}
/* Active state carries THREE cues — wash, ink, and a 3px rail — so it never
   depends on colour alone. */
.zf-nav__item--active {
  background: var(--zf-accent-wash);
  color: var(--zf-accent);
  font-weight: var(--zf-fw-semibold);
}
.zf-nav__item--active::before {
  content: ""; position: absolute; left: -8px; top: 8px; bottom: 8px;
  width: 3px; border-radius: 0 2px 2px 0; background: var(--zf-accent);
}

/* Pages within the open section. Indented to align with the parent's label
   rather than its icon, and hung off a hairline so the group reads as one
   block even when a child is active and the parent is not. */
.zf-nav__sub {
  margin: 2px var(--zf-space-2) var(--zf-space-2) calc(var(--zf-space-4) + 13px);
  padding-left: var(--zf-space-3);
  border-left: 1px solid var(--zf-border-subtle);
  display: flex; flex-direction: column;
}
.zf-nav__subitem {
  display: flex; align-items: center; min-height: 30px;
  padding: var(--zf-space-1) var(--zf-space-3);
  border-radius: var(--zf-radius-sm);
  font-size: var(--zf-fs-12); line-height: var(--zf-lh-12);
  color: var(--zf-text-muted); text-decoration: none;
}
.zf-nav__subitem:hover { background: var(--zf-bg-surface-hover); color: var(--zf-text-primary); }
.zf-nav__subitem--active { color: var(--zf-accent); font-weight: var(--zf-fw-semibold); }

/* --- Top bar -------------------------------------------------------------- */
.zf-topbar {
  height: var(--zf-topbar-h);
  background: var(--zf-bg-nav);
  border-bottom: 1px solid var(--zf-border-subtle);
  display: flex; align-items: center; gap: var(--zf-space-4);
  padding: 0 var(--zf-space-6);
}

/* --- Table ---------------------------------------------------------------- */
.zf-table { width: 100%; border-collapse: collapse; font-size: var(--zf-fs-13); }
.zf-table thead th {
  text-align: left; padding: var(--zf-space-2) var(--zf-space-3);
  background: var(--zf-bg-inset);
  font-size: var(--zf-fs-11); line-height: var(--zf-lh-11);
  font-weight: var(--zf-fw-semibold); letter-spacing: var(--zf-ls-wide);
  text-transform: uppercase; color: var(--zf-text-muted);
  border-bottom: 1px solid var(--zf-border-default);
  position: sticky; top: 0;
}
.zf-table tbody td {
  padding: var(--zf-space-3);
  border-bottom: 1px solid var(--zf-border-subtle);
  color: var(--zf-text-secondary);
}
.zf-table tbody tr:hover td { background: var(--zf-bg-surface-hover); color: var(--zf-text-primary); }
.zf-table tbody tr:last-child td { border-bottom: 0; }
.zf-table .zf-num { text-align: right; font-variant-numeric: tabular-nums; color: var(--zf-text-primary); }
/* No zebra striping: on dark it fights the hover state and adds a second
   horizontal rhythm. One hairline rule per row is enough. */

/* --- Badges (status) ------------------------------------------------------ */
.zf-badge {
  display: inline-flex; align-items: center; gap: 6px;
  height: 22px; padding: 0 var(--zf-space-2) 0 6px;
  border-radius: var(--zf-radius-sm);
  font-size: var(--zf-fs-12); font-weight: var(--zf-fw-medium);
  background: var(--zf-bg-inset); border: 1px solid var(--zf-border-subtle);
}
/* The label wears the -text step (AA as text); the 7px dot is non-text, so it
   wears the more saturated -fill step. */
.zf-badge::before { content: ""; width: 7px; height: 7px; border-radius: 50%; flex: none;
                    background: var(--zf-status-neutral-fill); }
.zf-badge--good     { color: var(--zf-status-good-text); }
.zf-badge--good::before     { background: var(--zf-status-good-fill); }
.zf-badge--warning  { color: var(--zf-status-warning-text); }
.zf-badge--warning::before  { background: var(--zf-status-warning-fill); }
.zf-badge--serious  { color: var(--zf-status-serious-text); }
.zf-badge--serious::before  { background: var(--zf-status-serious-fill); }
.zf-badge--critical { color: var(--zf-status-critical-text); }
.zf-badge--critical::before { background: var(--zf-status-critical-fill); }
.zf-badge--neutral  { color: var(--zf-status-neutral-text); }
/* The dot is decoration; the WORD is the meaning. Always ship both. */

/* --- Chart ---------------------------------------------------------------- */
.zf-chart { color: var(--zf-chart-label); font-size: var(--zf-fs-12); }
.zf-chart .grid   { stroke: var(--zf-chart-grid); stroke-width: 1; shape-rendering: crispEdges; }
.zf-chart .axis   { stroke: var(--zf-chart-axis); stroke-width: 1; }
.zf-chart .tick   { fill: var(--zf-chart-label); font-size: var(--zf-fs-12); }
.zf-chart .line   { fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.zf-chart .marker { r: 4px; stroke: var(--zf-chart-mark-ring); stroke-width: 2; }
/* Bars are <path>, never <rect rx>. `rx` rounds all four corners; the spec is a
   rounded VALUE end with the baseline end square and anchored. Build the path
   with the two corners at the value end rounded — see the mockup for geometry.
   Note `r`/`rx` in a stylesheet need units; unitless is only legal as an SVG
   presentation attribute. */
/* Direct labels and value labels use --zf-text-* , never the series colour. */
.zf-chart .direct-label { fill: var(--zf-text-secondary); font-weight: var(--zf-fw-semibold); }

.zf-tooltip {
  background: var(--zf-bg-surface-raised);
  border: 1px solid var(--zf-border-strong);
  border-radius: var(--zf-radius-md);
  box-shadow: var(--zf-elev-2);
  padding: var(--zf-space-2) var(--zf-space-3);
  font-size: var(--zf-fs-12);
  color: var(--zf-text-primary);
  pointer-events: none;
}

.zf-legend { display: flex; flex-wrap: wrap; gap: var(--zf-space-4); font-size: var(--zf-fs-12); color: var(--zf-text-secondary); }
.zf-legend__swatch { width: 10px; height: 10px; border-radius: 2px; flex: none; }

/* --------------------------------------------------------------------------
   6. FORCED-COLORS / PRINT FALLBACK
   Where the OS overrides colour, identity must survive. Series get a texture.
   -------------------------------------------------------------------------- */
@media (forced-colors: active) {
  .zf-card, .zf-btn, .zf-input { border: 1px solid CanvasText; }
  .zf-nav__item--active::before { background: Highlight; }
}
