/* ============================================================================
   Patitur Design System — Color & Type Tokens
   ----------------------------------------------------------------------------
   Single source of truth for color + typography tokens used across Patitur.
   Derived from patitur-service-frontend/flask_app/static/css/design-system.css
   and patitur-auth.css. Names follow the codebase conventions where possible.
   ============================================================================ */

/* ─── Fonts ──────────────────────────────────────────────────────────────── */
/* The product ships with two web fonts loaded from Google Fonts:
     - Ubuntu Sans  (display / headings — Patitur's signature face)
     - Inter        (UI text, body, tables, charts)
   Plus a system monospace stack for IDs, codes, packet payloads.
   See fonts/README.md if you need to swap in self-hosted files. */
@import url("https://fonts.googleapis.com/css2?family=Ubuntu+Sans:ital,wght@0,100..800;1,100..800&family=Inter:wght@300;400;500;600;700&display=swap");

:root {
    /* ─── Brand color ─────────────────────────────────────────────────── */
    /* Primary "Green/100" — the Patitur logo green, used for CTA buttons,
       focus rings, active table links, brand banners. */
    --color-brand-green: #25af88;
    --color-brand-green-hover: #1e9a73;
    --color-brand-green-deep: #047857; /* emerald-700, used for hover on internal links */
    --color-brand-green-bright: #01e4bf; /* legacy auth-page accent (bright teal) */
    --color-brand-green-secondary: #0fb39c;
    --color-brand-green-300: #5bdcc6; /* chart bars / decorative */

    /* ─── Neutrals ────────────────────────────────────────────────────── */
    /* Text */
    --fg-1: #101828; /* heading / strong */
    --fg-2: #333333; /* body */
    --fg-3: #4a5565; /* secondary body */
    --fg-4: #6b7280; /* muted */
    --fg-5: #9ca3af; /* placeholder / disabled */
    --fg-on-dark: #ffffff;

    /* Backgrounds */
    --bg-app: #ffffff;
    --bg-page: #f9fafb; /* #content base, soft */
    --bg-canvas: #f8f9fa; /* dashboard outer */
    --bg-card: #ffffff;
    --bg-secondary-medium: #f5f5f5; /* badge backgrounds */
    --bg-sidebar: #1e2939; /* slate-800 — dark nav rail */
    --bg-sidebar-hover: var(
        --fg-body-strong
    ); /* gray-700 — hover row in sidebar */

    /* Borders */
    --border-base: #e5e7eb; /* default 1px */
    --border-medium: #d1d5db;
    --border-strong: #9ca3af;

    /* ─── Semantic colors ─────────────────────────────────────────────── */
    /* Status pills */
    --status-online-bg: #e8f9f3;
    --status-online-fg: #1a7f5f;
    --status-danger-bg: #ffe8e8;
    --status-danger-fg: #c93636;
    --status-warning-bg: #fff3e8;
    --status-warning-fg: #b86e0f;
    --status-info-bg: #e8f6ff;
    --status-info-fg: #2e7db5;
    --status-neutral-bg: #f3f4f6;
    --status-neutral-fg: #6b7280;

    /* Severity badges (alerts) */
    --sev-low-bg: var(--status-info-bg);
    --sev-low-border: var(--hex-gw-1);
    --sev-low-fg: #1c398e;
    --sev-medium-bg: #fff8f1;
    --sev-medium-border: #fcd9bd;
    --sev-medium-fg: #8b0836;
    --sev-high-bg: #fef0f2;
    --sev-high-border: #ffccd3;
    --sev-high-fg: #8b0836;
    --sev-critical-bg: #fef0f2;
    --sev-critical-border: #ffccd3;
    --sev-critical-fg: #8b0836;

    /* Severity dots (8px circles in alert lists) */
    --sev-dot-high: #ff5e5e; /* coral red */
    --sev-dot-medium: #fe9239; /* warm orange */
    --sev-dot-info: #51c0ff; /* sky blue */
    --sev-dot-low: #51c0ff;

    /* Chart palette (donuts, bars, line) */
    --chart-status-online: #22e5a1;
    --chart-status-offline: #ff5e5e;
    --chart-importance-low: #51c0ff;
    --chart-importance-medium: #fe9239;
    --chart-importance-high: #ff5e5e;
    --chart-alert-bar: #5bdcc6;
    --chart-line-info: #2563eb;

    /* Banners */
    --banner-soft-start: #e8f9f3; /* light green org dashboard banner */
    --banner-soft-end: #d4f1e8;
    --banner-tenant-start: #0f4f3b; /* dark gradient when scoped to a tenant */
    --banner-tenant-end: #25af88;
    --banner-tenant-border: #0d4532;

    --row-highlight: var(--status-info-bg); /* selected row in tables */

    /* ─── Hex map metric ramps ────────────────────────────────────────
       Geographic H3-aggregated maps (tenant detail Heat Map sub-tab,
       network-health overview, future device-density views) use one of
       three pre-defined color ramps depending on the active metric. Each
       cell carries all three metrics; the toggle only changes the fill.

       Pick by metric character:
         - Density        → sequential single-hue brand green (monotonic)
         - Gateways heard → sequential single-hue blue (monotonic, different
                            hue from density so legends can't be confused)
         - RSSI / signal  → diverging 7-band red→green (has a "good" end)

       Each cell is rendered with both `color` and `fillColor` set to the
       same hex; only `fillOpacity` varies across stops. Stroke weight is
       always 1.2px. See components-hexmap.html and colors-hexmap.html. */

    /* Density (5 stops, sparse → very dense) */
    --hex-density-1: #5bdcc6;
    --hex-density-1-alpha: 0.3; /* 1–2 devices */
    --hex-density-2: #25af88;
    --hex-density-2-alpha: 0.45; /* 3–8 */
    --hex-density-3: #0fb39c;
    --hex-density-3-alpha: 0.55; /* 9–18 */
    --hex-density-4: #047857;
    --hex-density-4-alpha: 0.65; /* 19–30 */
    --hex-density-5: #064e3b;
    --hex-density-5-alpha: 0.78; /* 30+ */

    /* Gateways heard (4 stops, single → fully redundant) */
    --hex-gw-1: #bfdbfe;
    --hex-gw-1-alpha: 0.4; /* 1 gateway */
    --hex-gw-2: #60a5fa;
    --hex-gw-2-alpha: 0.55; /* 2 gateways */
    --hex-gw-3: #3b82f6;
    --hex-gw-3-alpha: 0.6; /* 3 gateways */
    --hex-gw-4: #1d4ed8;
    --hex-gw-4-alpha: 0.7; /* 4+ gateways */

    /* RSSI signal zones (7-band, weak → strong) */
    --hex-rssi-critical: #991b1b; /* < -115 dBm */
    --hex-rssi-poor: #ef4444; /* -115 to -110 */
    --hex-rssi-marginal: #f97316; /* -110 to -105 */
    --hex-rssi-fair: #f59e0b; /* -105 to -100 */
    --hex-rssi-good: #eab308; /* -100 to -90 */
    --hex-rssi-very-good: #84cc16; /* -90 to -80 */
    --hex-rssi-excellent: #22c55e; /* > -80 */
    --hex-rssi-fill-opacity: 0.6; /* same across all 7 bands */

    /* Gateway marker (sits on top of hex cells, also used on the
       message-flow + device-detail maps). Amber-400 dot with a dark
       slate border and a 3px white halo so it reads on any tile. */
    --gw-marker-fill: #fbbf24;
    --gw-marker-border: #1f2937;
    --gw-marker-halo: #ffffff;

    /* ─── Positioning-tier palette ────────────────────────────────────
       Used by the device-positioning view (map-view.html) where SHAPE
       encodes the position method emitted by the analytics engine
       (`DevicePositionPayload.method`). Color is layered on top so an
       operator can ALSO read confidence at a glance — the system never
       has to choose one channel for two meanings.

       Aligned with the brand semantic palette so positioning tiers are
       readable next to severity badges without re-introducing a new hue.
       See positioning-visibility.md §4 and preview/colors-positioning.html. */

    --tier-tri: #25af88; /* Trilateration (3+ gateways) — brand green, highest confidence */
    --tier-bi: #fe9239; /* Bilateration  (2 gateways)  — sev-medium orange, ambiguous */
    --tier-rad: #51c0ff; /* Radial        (1 gateway)   — sev-low blue, lowest confidence */
    --tier-outlier: #ff5e5e; /* Cluster outlier ring (is_outlier=true) — sev-high coral */
    --tier-cluster: #7c3aed; /* Cluster prior — violet (prior family, not gateway geometry) */
    --tier-terrain: #0d9488; /* Terrain + Habitat — teal (strongest; prior family) */

    /* Confidence channels (paired with shape, not stand-alone) */
    --tier-tri-fill-alpha: 0.13;
    --tier-bi-cand2-alpha: 0.5; /* second bilateration candidate (the "or here") */
    --tier-rad-ring-alpha: 0.3; /* bare radial ring */
    --tier-rad-arc-base: 0.12; /* dim trough on von-Mises arc */
    --tier-rad-arc-peak: 0.92; /* peak of the arc, in the believed bearing */

    /* ─── Typography (primitives) ─────────────────────────────────────── */
    --font-display: "Ubuntu Sans", "Ubuntu Sans-Medium", Helvetica, sans-serif;
    --font-base:
        "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        sans-serif;
    --font-mono:
        ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
        "Liberation Mono", "Courier New", monospace;

    /* Micro-labels on dense chrome — chips, pills, badges, axis and sidebar
       labels. Added 2026-08-23: 15 declarations across 8 files had converged on
       10px for exactly this job while the scale stopped at 11px. Fifteen
       independent uses of one value for one purpose is a missing step, not
       fifteen mistakes, and naming it changes nothing on screen. */
    --fs-2xs: 10px;
    --fs-xs: 11px;
    --fs-sm: 12px;
    --fs-base: 14px;
    --fs-md: 16px;
    --fs-lg: 18px;
    --fs-xl: 24px;
    --fs-2xl: 30px; /* page titles — patitur-main-page-title */
    --fs-3xl: 36px; /* big stat counters */
    --fs-display: 64px; /* dashboard count display */

    /* Icon geometry. Deliberately separate from the --fs-* type scale: an icon
       is sized by its box, not by its text, and two of these steps (20px, 32px)
       are not type sizes at all. Each is applied as width, height AND font-size
       so one class covers an inline SVG and a Font Awesome glyph. */
    --icon-xs: 10px;
    --icon-sm: 12px;
    --icon-md: 14px;
    --icon-base: 16px;
    --icon-lg: 20px;
    --icon-xl: 24px;
    --icon-2xl: 32px;
    --icon-3xl: 64px;

    --lh-tight: 1;
    --lh-snug: 1.3;
    --lh-base: 1.4;
    --lh-relaxed: 1.6;
    /* 16px text in a 24px line box. Added 2026-08-23: three declarations needed
       exactly this and the scale jumped 1.4 -> 1.6, so they were carrying a bare
       ratio instead. */
    --lh-normal: 1.5;

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

    /* ─── Spacing ─────────────────────────────────────────────────────── */
    --sp-0: 0;
    --sp-0_5: 2px;
    --sp-1: 4px;
    --sp-1_5: 6px;
    --sp-2: 8px;
    --sp-3: 12px;
    --sp-4: 16px;
    --sp-5: 20px;
    --sp-6: 24px;
    --sp-8: 32px;
    --sp-10: 40px;
    --sp-11: 44px;
    --sp-12: 48px;
    --sp-14: 56px;

    /* Page chrome (from design-system.css) */
    --page-max-width: 110rem; /* analyze + compliance pages */
    --page-max-width-narrow: 1280px; /* dashboard + auth-style pages */
    --page-padding: 1rem 1.25rem;
    --page-rail-width: 240px; /* main + rail two-column stage */

    /* ─── Radii ───────────────────────────────────────────────────────── */
    --radius-xs: 4px; /* badges */
    --radius-sm: 6px; /* small buttons, inputs */
    --radius-md: 8px; /* buttons, alert rows */
    --radius-lg: 12px; /* cards */
    --radius-xl: 16px; /* auth card, top-of-page panels */
    --radius-pill: 9999px;

    /* ─── Shadows ─────────────────────────────────────────────────────── */
    /* Patitur uses subtle elevation. The most common card shadow is almost
       imperceptible (1px). The brand "glow" is reserved for focus rings
       and auth surfaces. */
    --shadow-xs: 0 1px 0.5px 0.05px rgba(29, 41, 61, 0.02);
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
    --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
    --shadow-lg: 0 8px 25px rgba(0, 212, 170, 0.4); /* brand-tinted */
    --shadow-glow: 0 0 0 2px rgba(37, 175, 136, 0.15); /* focus ring  */
    --shadow-modal: 0 10px 35px rgba(0, 0, 0, 0.18);

    /* ─── Transitions ─────────────────────────────────────────────────── */
    --t-fast: 0.15s ease;
    --t-base: 0.2s ease;
    --t-slow: 0.3s ease;

    /* Dashboard summary-card icon. Was defined in flask_app/constants/dashboard.py
       and injected into :root through a <style> block in dashboard.html, which
       made Python a source of CSS colour. */
    --color-metric-icon: #004f3b;
    --color-metric-icon-bg: #e6f7ed;

    /* Policy editor cards — the border that marks a customised scope */
    --editor-org-border: #93c5fd; /* .editor-card--customized-org    */
    --editor-tenant-border: #86efac; /* .editor-card--customized-tenant */

    /* ─── The tail, named 2026-08-24 ──────────────────────────────────────
       One-offs and small families, named so nothing outside this file holds a
       colour. Each carries the selector it was read from, because a name for a
       single-use colour is only checkable against what it paints. */

    /* Flash messages — completes the Bootstrap-derived set above */
    --flash-success-fg: #155724; /* .flash.success text        */
    --flash-success-border: #a5f3eb; /* .flash.success border      */
    --flash-info-fg: #0c5460; /* .flash.info text           */
    --flash-info-border: #b3e5fc; /* .flash.info border         */
    --flash-warning-border: #ffd43b; /* .flash.warning border      */

    /* Positioning terrain pills — .dd-pp--* */
    --pos-terrain-border: #b6e3d0; /* .pos-tier-terrain-badge    */
    --pos-land-fg: #2f7d4a; /* .dd-pp--land               */
    --pos-water-fg: #1f6fb0; /* .dd-pp--water              */
    --pos-indoor-fg: #4338ca; /* .dd-pp--indoor             */
    --pos-indoor-border: #d8dcff; /* .dd-pp--indoor             */

    /* Glossary overview cards */
    --glossary-icon-blue: #0284c7; /* .glossary-overview-card__icon-wrap  */
    --glossary-icon-violet: #9333ea; /* ″                                   */
    --glossary-compliance-border: #fae8ff; /* .glossary-overview-card--compliance */

    /* Policy comparison */
    --policy-changed-bg: #fefce8; /* .cascade-table td.diff-changed */
    --policy-tenant-fg: #14532d; /* .source-badge.source-tenant    */

    /* Faceted search pills */
    --facet-pill-border: #7fcbaf; /* .faceted-pill                */
    --facet-pill-remove-fg: #3f9e81; /* .faceted-pill__remove        */

    /* Network health — completes robust / mixed / fragile */
    --health-robust-fg: #4d8a3a; /* legend swatch                */

    /* Chart series — the categorical ramp, distinct from any semantic family */
    --chart-series-violet: #8b5cf6;
    --chart-series-pink: #ec4899;
    --chart-series-cyan: #06b6d4;
    --chart-green-deep: #00a085; /* PATITUR_COLORS.secondaryDark */
    --chart-green-darkest: #166534; /* success ramp, last step      */
    --chart-teal-dark: #017a6b; /* device-charts fallback       */

    /* Remaining one-offs */
    --alert-error-fg: #cc0000; /* .analytics-error-alert       */
    --nav-sub-fg: #a0b3b8; /* sidebar sub-nav link         */
    --nav-idle-fg: #d1d5dc; /* sidebar nav label, resting   */
    --sev-info-fg: #0891b2; /* .alert-icon.severity-info    */
    --notification-count-bg: #f44336; /* .notification-count          */
    --success-icon-fg: #198754; /* .green.icon list items       */
    --bg-sidebar-setup: #2d1f1a; /* viewing-context "setup" row  */
    --pulse-orange-mid: #fdba74; /* pulse-orange keyframe, 50%   */
    --auth-error-fg: #ff6b7a;
    --danger-border: #fca5a5; /* --cp-red-border, compliance   */ /* .patitur-alert-error         */

    /* ─── Named 2026-08-24, third batch ───────────────────────────────────
       The last colours that had no name anywhere. */

    /* The drop shadow four surfaces share, black at 25% alpha */
    --shadow-color: #00000040;

    /* The breakdown grid's sequential ramp. Deliberately its own family and
       NOT the RSSI ladder — a cell painted green here means "highest of these
       seven", and borrowing the band palette made that read as "Excellent
       coverage" from the map's own legend two inches away. Five ordered steps;
       they are a scale, so they are numbered rather than named. */
    --breakdown-ramp-1: #eef2f6;
    --breakdown-ramp-2: #c3d3e0;
    --breakdown-ramp-3: #8fb0c8;
    --breakdown-ramp-4: #5b87a8;
    --breakdown-ramp-5: #2f5f80;

    /* A brand-green wash for a control that sits on a light ground */
    --brand-green-tint: #06966515;

    /* ─── Isometric terrain chrome ──────────────────────────────────────────
       The gateway tower, the elevation ramp and the tile outline on the iso
       terrain view. These lived as bare hexes in flask_app/iso/render.py, which
       paints SVG server-side while terrain-canvas.js paints the same scene to a
       canvas — so the palette had to travel through Python and out through the
       geometry payload to reach either one. The SVG now takes classes and the
       canvas reads these tokens directly. */
    --iso-tower: #2d3a52;
    --iso-beacon: #f49a1c;
    --iso-ink: #1b2435;
    --iso-tile-stroke: #36445e29;

    /* Elevation ramp endpoints — low ground to high. The legend draws the
       gradient between them; the mesh whitens each tile toward --fg-on-dark by
       its own elevation instead. */
    --iso-elev-lo: #8a94a8;
    --iso-elev-hi: #eef2f8;

    /* The shade a tile's side face is mixed toward, so relief reads at a
       glance. Consumed by per-cell arithmetic rather than a class: every tile
       computes its own shade from its elevation. */
    --iso-side-dark: #586273;

    /* ─── Chart series ──────────────────────────────────────────────────────
       The per-gateway line/chip colours on the device signal panel, indexed by
       the gateway's position in the packet-count ordering. Slots 1-2 are the
       brand pair so the common two-gateway case reads as Patitur; 3-10 are
       ColorBrewer Set2 (qualitative, colour-blind-safe to 8 classes) plus one
       Set1 salmon. They lived as a hex tuple in constants/signal_metrics.py,
       which made the series palette invisible to the design system. Python now
       emits a slot NUMBER and these decide what it looks like. */
    --series-1: var(--color-brand-green-secondary);
    --series-2: var(--tier-rad);
    --series-3: #fc8d62;
    --series-4: #8da0cb;
    --series-5: #e78ac3;
    --series-6: #a6d854;
    --series-7: #ffd92f;
    --series-8: #e5c494;
    --series-9: #b3b3b3;
    --series-10: #fb9a99;

    /* ─── Terrain cartography ───────────────────────────────────────────────
       The isometric terrain map's two colour axes. They lived as bare hexes in
       flask_app/iso/render.py, which made them a second palette the design
       system could not see: every one is 9 dE or more from anything named here,
       so they are genuinely their own family rather than drift.

       Landcover — what the ground IS. Blue reads as water and green as growing
       land; the map's legend leans on that being consistent. */
    --landcover-water: #93b4dd;
    --landcover-forest: #5f8f63;
    --landcover-urban: #cf906f;
    --landcover-bare: #cdb98c;
    --landcover-rural: #a9c98c;

    /* Building use — what the covering building is FOR, painted only on urban
       cells. A warm→magenta→violet→neutral gamut, chosen to avoid blue and
       green so a built cell never reads as terrain. The six real uses are
       saturated; the two occupancy-unknown buckets are neutral greys (~96% of
       urban cells in real data), so the map reads calm and tagged cells pop. */
    --building-use-residential: #e0a93f;
    --building-use-commercial: #e0574b;
    --building-use-industrial: #7a5230;
    --building-use-utility: #c86fa6;
    --building-use-civic: #8168c6;
    --building-use-other: #b07a55;
    --building-use-unclassified: #b9b3ae;
    --building-use-unknown: #8a837c;
    /* Not a building use: the footprint fetch failed for this cell's disk.
       A rose-grey so "we could not tell" reads apart from "no building". */
    --building-use-unavailable: #b59a9a;

    /* ─── Palette gap, named 2026-08-24 ───────────────────────────────────
       Families the system genuinely did not have, so the code reached for
       whichever framework was nearest — Bootstrap's alert set, a Tailwind
       violet ramp, three oranges for a health ladder with no tokens. Naming
       them changes nothing on screen; it stops the next person inventing a
       fourth orange. Counts are from the audit at the time of naming. */

    /* Violet / indigo — the system had none */
    --violet-fg: #6366f1; /* 6×  glossary accents                 */
    --violet-deep-fg: #5b21b6; /* 2×  .cluster-floating-range, .geom-* */

    /* Flash messages — Bootstrap's alert set, kept because it is what the
       flash partial renders and re-toning it is a visual decision */
    --flash-danger-fg: #721c24; /* 3×  .alert-danger                    */
    --flash-danger-bg: #f8d7da; /* 3×  .alert-danger                    */
    --flash-warning-fg: #856404; /* 2×  .flash.warning                   */
    --flash-info-bg: #d1ecf1; /* 2×  .flash.info                      */
    --flash-success-bg: #cfe9d6; /* 3×  .flash.success, .dd-pp--land     */

    /* Network-health tier ladder — robust / mixed / fragile */
    --health-mixed-fg: #e8a20c; /* 4×  mostly_resilient                 */
    --health-fragile-fg: #f5810a; /* 4×  mostly_fragile                   */

    /* Policy comparison — the text tones matching the cell grounds above */
    --policy-stricter-fg: #15803d; /* 4×  .cell-stricter                   */
    --policy-looser-fg: #c2410c; /* 3×  .cell-looser                     */

    /* Warmer / softer steps the amber family lacked */
    --warning-soft-bg: #fef3c7; /* 5×  table headers, tiles             */
    --warning-softer-bg: #ffedd5; /* 4×  .alert-modal-quick-btn-ack:hover */
    --warning-mid: #fcd34d; /* 3×  partial-state tiles              */
    --sev-major-fg: #ea580c; /* 3×  .alert-icon.severity-major       */

    /* Blues and greens the ladder stopped short of */
    --info-darkest-fg: #0369a1; /* 3×  gateway icon, banner accents     */
    --method-radial-fg: #0ea5e9; /* 4×  radial method, map markers       */
    --success-mid: #16a34a; /* 3×  .status-connected                */
    --success-soft-bg: #a4f4cf; /* 3×  .device-status-badge-online      */

    /* Reds beyond the severity set */
    --danger-bright-fg: #dc3545; /* 6×  list items, mini statistics      */
    --danger-soft-fg: #f3b0b0; /* 3×  .pos-tier-conf-badge.is-low      */
    --danger-delete-fg: #e74c3c; /* 3×  .patitur-btn-delete              */

    /* Auth surface */
    --auth-btn-primary-hover: #5a6bc0; /* 3× .login-form .btn-primary:hover */
    --auth-btn-fg: #0a1a1f; /* 3× .patitur-btn, .status-badge    */

    /* Neutral */
    --fg-placeholder: #999999; /* 3×  textarea::placeholder            */

    /* ─── Semantic aliases, added 2026-08-24 ──────────────────────────────
       Names, not colours. Every value below already existed under a name from
       the map or chart domain, and the code kept reaching for the hex because
       the available name was wrong for the job: #991b1b paints compliance
       danger chips but was only called --hex-rssi-critical, so routing it there
       would couple the compliance matrix to the RSSI band ladder — re-tone one
       and the other moves silently.

       An alias breaks that coupling. Two names, one value, and each surface
       reaches for the one that describes what it is painting. Nothing here
       introduces a new colour. */

    /* Neutral text tones the --fg-N ladder does not cover */
    --fg-body-strong: #374151; /* 36×, 26 of them `color:` */
    --fg-heading: var(
        --gw-marker-border
    ); /* 15× headings, values, tooltip ground */

    /* Info — the blue family, previously only nameable as a gateway hex */
    --info-fg: var(--hex-gw-3); /* 10× .alert-item-low, severity maps */
    --info-border: var(--hex-gw-1); /* 15× banner + status-chip borders   */
    --info-deep-fg: var(--hex-gw-4); /* darkest step of the same family     */

    /* Danger / warning / success dots and deep tones */
    --danger-deep-fg: var(
        --hex-rssi-critical
    ); /* 11× .fw-chip-high, attack counts */
    --danger-dot: var(--hex-rssi-poor); /* 4×  severity maps, badges        */
    --warning-fg: var(--hex-rssi-fair); /* 6×  partial / fair states        */
    --warning-dot: var(--gw-marker-fill); /* 2×  .alert-item-medium           */
    --sev-major-dot: var(
        --hex-rssi-marginal
    ); /* 4×  .alert-item-high             */
    --success-dot: var(
        --hex-rssi-excellent
    ); /* 2×  badges                       */
    --success-bright: var(
        --chart-status-online
    ); /* online / connected pips        */

    /* ─── Named 2026-08-24 ────────────────────────────────────────────────
       Colours the product had been using for a long time with no name. Each
       is named for the JOB its selectors do, not its hue — the distinction
       that made --hex-rssi-critical the wrong name for a compliance danger
       chip. Usage counts are from the colour audit at the time of naming. */

    /* Coverage grading (compliance article + catalog legends) */
    --coverage-strong-fg: #065f46; /* 32× .fw-article-legend-chip-strong  */
    --coverage-strong-bg: #d1fae5; /* 10× coverage badge fill             */
    --coverage-partial-fg: #78350f; /* 22× .fw-article-legend-chip-partial */

    /* Danger, deeper than --sev-*-fg: banners, criticals, red-700 hovers */
    --danger-fg: #dc2626; /* 16× .alert-item-critical, --cp-red  */
    --danger-strong-fg: #b91c1c; /* 19× .landing-banner-cta             */
    --danger-darkest-fg: #7f1d1d; /* 8×  .fw-banner-attack               */

    /* On a dark surface a mid-tone accent goes muddy, so the feedback states
       lighten one step. Used by the toast icons under
       prefers-color-scheme: dark; no light-mode surface wants these. */
    --success-on-dark: #4ade80;
    --danger-on-dark: #f87171;

    /* Darkest step of each family, for text on a soft badge ground. The
       badges set these on a *-100-ish background, where the -600/-700 steps
       do not carry enough contrast. Nothing else in the palette was within
       dE 9 of either, so snapping would have been visible. */
    --warning-darkest-fg: #854d0e;
    --sev-major-darkest-fg: #9a3412;

    /* The focus ring on form controls and buttons. An alias, not a new value:
       the colour already existed, but only under a name about gateway hexes,
       so 88 sites in markup spelled out the shade instead of the role. */
    --focus-ring: var(--hex-gw-3);

    /* Info, the blue chip family */
    --info-bg: #dbeafe; /* 9×  .fw-status-scheduled            */
    --info-strong-fg: #1e40af; /* 16× .fw-article-chip-*              */

    /* Warning, deeper than --status-warning-* */
    --warning-strong-fg: #b45309; /* 13× .landing-tenants-*              */
    --banner-warning-bg: var(
        --status-warning-bg
    ); /* 13× .analytics-banner-warning       */
    --banner-warning-border: #fde68a; /* 9×  .analytics-banner-warning       */
    --banner-warning-fg: #d97706; /* 9×  .analytics-banner-* icon        */
    --pill-warning-fg: #92400e; /* 12× .fw-laf-pill                    */

    /* Policy comparison cells — stricter/looser than the inherited default */
    --policy-stricter-bg: #bbf7d0; /* 18× .cell-stricter                  */
    --policy-looser-bg: #fed7aa; /* 9×  .cell-looser                    */

    /* Status */
    --status-active-fg: #10b981; /* 8×  .collector-item-active, --cp-green */
    --status-resolved-bg: #f0fdf4; /* 10× .alert-resolved-card            */

    /* Chrome */
    --link-internal-fg: #0e9f6e; /* 13× .link-internal — the link green */
    --chart-axis-fg: #666666; /* 17× Chart.js title + ticks          */
    --nav-active-gradient-end: #58ff98; /* 15× #sidebar active nav gradient */
    --color-brand-teal: #00d4aa; /* 8×  .patitur-btn, chart gradients   */
    --auth-btn-primary: #7386d5; /* 7×  .login-form .btn-primary        */
}

/* ─── Semantic typography roles ─────────────────────────────────────────── */
/* Mirrors usage in the product: page titles are Ubuntu Sans Medium 30 in
   brand green; section titles are Ubuntu Sans 18; everything else is Inter. */

html {
    font-family: var(--font-base);
    color: var(--fg-2);
}

/* The single source of the app-wide font. This has to sit on `body`, not
   only on `html`: the Tailwind CDN injects its preflight `html` rule after
   this file, so an `html`-only declaration loses the cascade and the page
   would fall back to Tailwind's `ui-sans-serif` stack. A declaration on
   `body` beats that inherited value regardless of load order. */
body {
    font-family: var(--font-base);
}

/* ─── Heading scale ───────────────────────────────────────────────────────────
   The element selectors are written `body h1` rather than `h1`, and that is
   load-bearing.

   Tailwind's preflight emits `h1,h2,h3,h4,h5,h6 { font-size: inherit;
   font-weight: inherit }` at specificity 0,0,1, and the CDN injects its
   <style> at the END of <head> — after this file. A bare `h1` here is also
   0,0,1, so preflight won on source order and EVERY heading in the product
   rendered at 16px/400, the same as body text. Measured in a browser, not
   inferred: 56 headings carrying no size utility were rendering as body copy.

   `body h1` is 0,0,2, which beats preflight while still losing to any class —
   so a heading carrying `text-lg` or `.h2` is unaffected, and the scale only
   applies where nothing else has spoken.
   ─────────────────────────────────────────────────────────────────────────── */
body h1,
.h1,
.patitur-main-page-title {
    font-family: var(--font-display);
    font-weight: var(--fw-medium);
    font-size: var(--fs-2xl);
    line-height: var(--lh-snug); /* 39px. Was a bare 28px — a line box SMALLER
       than the 30px text, so a wrapping title overlapped its own next line.
       Matches the h2 rule's --lh-snug and what the four `leading-tight` call
       sites were reaching for; those never applied, because this stylesheet
       loads after Tailwind's CDN and won on source order. */
    /* Near-black, not brand-green: a large green heading reads as a link
       (link green #0e9f6e is a near-identical shade). Keeps the Ubuntu Sans
       type; drops the green. Matches .dd-hero-title (detail heroes). */
    color: var(--fg-1);
    margin: 0;
}

body h2,
.h2 {
    font-family: var(--font-display);
    font-weight: var(--fw-semibold);
    font-size: var(--fs-xl);
    line-height: var(--lh-snug);
    color: var(--fg-1);
}

body h3,
.h3,
.panel-title {
    font-family: var(--font-display);
    font-weight: var(--fw-medium);
    font-size: var(--fs-lg);
    line-height: 28px;
    color: var(--fg-1);
}

body h4,
.h4 {
    font-family: var(--font-base);
    font-weight: var(--fw-semibold);
    font-size: var(--fs-md);
    line-height: var(--lh-base);
    color: var(--fg-1);
}

p,
.body {
    font-family: var(--font-base);
    font-size: var(--fs-base);
    line-height: var(--lh-relaxed);
    color: var(--fg-2);
}

/* Carried over from the legacy demo stylesheet, which was the only rule
   setting a paragraph weight. Kept as-is to hold rendering identical; it
   is scoped to `p` (not `.body`) to match exactly what it replaces.
   Whether the product actually wants light paragraphs is a design call,
   tracked as DS-12. */
p {
    font-weight: var(--fw-light);
}

.body-sm {
    font-size: var(--fs-sm);
    line-height: var(--lh-base);
    color: var(--fg-3);
}

.eyebrow {
    /* Brand-green uppercase scope label used above the tenant banner title.
       Always paired with a 8px brand-green dot. */
    font-family: var(--font-base);
    font-size: var(--fs-sm);
    font-weight: var(--fw-semibold);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-brand-green);
}

/* .code-chip dropped from this group — it has a fuller, superset definition in
   design-system.css (loads later) that re-sets all of these. `code` / `.code` keep
   this base rule. */
code,
.code {
    font-family: var(--font-mono);
    font-size: var(--fs-xs);
    font-weight: var(--fw-semibold);
    color: var(--fg-3);
    background: var(--status-neutral-bg);
    padding: 2px 8px;
    border-radius: var(--radius-xs);
}
