/* ═══════════════════════════════════════════════════════════════════════
   WOOF — the dashboard style.
   Brand by Abtion, 2024. Student well-being platform.

   One design, two palettes. Structure, spacing and type live in the rules
   below and are shared; light and dark differ only in the token blocks.
   The dark palette is selected by data-theme="dark" on <html>, which app.py
   renders from the theme cookie (see theming.py) so it is correct on first
   paint with no flash.

   Adding a colour here means adding it to BOTH token blocks —
   tests/unit/test_theme_contract.py enforces that.
   ═══════════════════════════════════════════════════════════════════════ */
@import url('https://fonts.googleapis.com/css2?family=Hanken+Grotesk:ital,wght@0,400;0,500;0,600;0,700;0,800;1,400;1,700&family=Radio+Canada+Big:ital,wght@0,400;0,500;0,600;0,700;1,400;1,700&display=swap');

/* ═══════════════════════════════════════════════════════════════════════
   Brand foundations — the raw scales both palettes draw from.
   ═══════════════════════════════════════════════════════════════════════ */
:root {
  /* ---- Brand color roles ------------------------------------------ */
  /* Primary — periwinkle/indigo. The Woof "voice" color. */
  --primary-25:  #F2EFFF;
  --primary-50:  #E5DFFF;
  --primary-100: #CBC6FF;
  --primary-200: #B7B8FF;
  --primary-300: #9491FF;
  --primary-400: #716BFF;
  --primary-500: #5253FF;  /* core brand blue — buttons, links, focus */
  --primary-600: #4344D5;
  --primary-700: #3334AB;
  --primary-800: #2C2C96;  /* logo navy, headings on light */
  --primary-900: #1B1F72;  /* deepest — logo/illustration ink */

  /* Blue Hour — cool neutral scale (text, surfaces, borders) */
  --blue-hour-25:  #F7F9FF;
  --blue-hour-50:  #F0F4FC;  /* default page background */
  --blue-hour-75:  #E1E9F7;
  --blue-hour-100: #D6E2F9;
  --blue-hour-200: #A8BFEC;
  --blue-hour-300: #87A2D5;
  --blue-hour-400: #6783B8;
  --blue-hour-500: #4D699E;
  --blue-hour-600: #425985;  /* muted body / labels */
  --blue-hour-700: #364665;
  --blue-hour-800: #253553;
  --blue-hour-900: #0D1931;  /* near-black headings */

  /* Mood accents — used for well-being signals (the heart of Woof) */
  --lizard-300:    #A5EBC1;  /* positive / good mood — green */
  --lizard-400:    #84DAA6;
  --lizard-500:    #68CA8F;
  --sunflower-300: #FFEEA9;  /* neutral / steady — yellow */
  --sunflower-400: #FFE88F;
  --sunflower-500: #F9DD70;
  --cool-lava-300: #FFC6C6;  /* negative / needs attention — coral */
  --cool-lava-400: #FAB0A6;
  --cool-lava-500: #F59689;
  --cool-lava-600: #EB7D6E;

  /* Basics */
  --white: #FFFFFF;
  --black: #081124;
  --red:   #DC251C;  /* error / destructive */

  /* Semantic aliases deliberately live in the palette blocks below, not here.
     The scales above are palette-independent ingredients; anything that has a
     different value in light and dark belongs with the palette that sets it. */

  /* ---- Type families ---------------------------------------------- */
  --font-heading: "Radio Canada Big", "Hanken Grotesk", sans-serif;
  --font-body:    "Hanken Grotesk", "Noto Sans", system-ui, sans-serif;

  /* ---- Type scale -------------------------------------------------- */
  --text-xs:   12px;
  --text-sm:   14px;
  --text-base: 16px;
  --text-lg:   20px;
  --text-xl:   24px;
  --text-2xl:  32px;
  --text-3xl:  38px;
  --text-4xl:  48px;
  --text-5xl:  64px;
  --text-6xl:  96px;

  --leading-tight:  1.0;
  --leading-snug:   1.15;
  --leading-normal: 1.4;
  --leading-loose:  1.6;

  /* ---- Radii ------------------------------------------------------- */
  --radius-xs:   4px;
  --radius-sm:   8px;
  --radius-md:   12px;
  --radius-lg:   16px;
  --radius-xl:   24px;
  --radius-2xl:  32px;
  --radius-pill: 999px;

  /* ---- Spacing (4px base) ----------------------------------------- */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;
  --space-9: 96px;

  /* ---- Shadows (soft, cool-tinted) -------------------------------- */
  --shadow-xs: 0 1px 2px rgba(44,44,150,0.06);
  --shadow-sm: 0 2px 8px rgba(44,44,150,0.08);
  --shadow-md: 0 8px 24px rgba(44,44,150,0.12);
  --shadow-lg: 0 16px 48px rgba(44,44,150,0.18);
  --shadow-focus: 0 0 0 4px rgba(82,83,255,0.25);
}

/* ═══════════════════════════════════════════════════════════════════════
   LIGHT — default palette
   ═══════════════════════════════════════════════════════════════════════ */
:root{
  color-scheme:light;
  --bg:#F0F4FC;--surface:#FFFFFF;--surface2:#F7F9FF;
  --border:#D6E2F9;--border-strong:#A8BFEC;
  --text:#0D1931;--text-muted:#425985;
  --accent:#5253FF;--accent-soft:#E5DFFF;
  --accent-hover:#4344D5;--accent-press:#3334AB;
  /* Roles that differ per palette. Component rules use these, never the raw
     brand scales above — a scale value is palette-independent and would keep
     its light reading on a dark page. */
  --brand-ink:#2C2C96;--brand-tint:#F2EFFF;--brand-soft:#E5DFFF;
  --logo-bg:#2C2C96;--tip-bg:#1B1F72;
  --fg-subtle:#87A2D5;--row-hover:#F7F9FF;--track-off:#D6E2F9;
  --pos:#68CA8F;--mid:#F9DD70;--neg:#EB7D6E;
  --radius:20px;--shadow:0 2px 8px rgba(44,44,150,.08);
  --shadow-lift:0 8px 24px rgba(44,44,150,.12);

  /* Chart tokens — read into JS by refreshChartTheme() in
     templates/js/globals.html; the Chart.js layer has no other colour source.
     Ramps run dark -> mid because the pale end vanishes on a white card. */
  --chart-grid:#D6E2F9;
  --chart-tick:#425985;
  --chart-fg:#0D1931;
  --chart-axis-title:#425985;
  --chart-tooltip-bg:#0D1931;
  --chart-tooltip-brd:#253553;
  --chart-tooltip-fg:#FFFFFF;
  --chart-zero-line:#0D1931;
  --chart-surface:#FFFFFF;
  --chart-accent:#5253FF;
  --chart-pos:#2C8C6A;
  --chart-neg:#C4564A;
  --chart-font:'Hanken Grotesk',system-ui,sans-serif;
  /* Individually addressable so a template can reference one deliberately
     (var(--chart-palette-3, #fallback)) as well as let JS cycle through them
     as a rotation — see refreshChartTheme() in templates/js/globals.html. */
  --chart-palette-1:#5253FF;   --chart-palette-2:#C4564A;
  --chart-palette-3:#2C8C6A;   --chart-palette-4:#D99A1F;
  --chart-palette-5:#2C2C96;   --chart-palette-6:#A855A8;
  --chart-palette-7:#1B7A96;   --chart-palette-8:#C2456F;
  --chart-palette-9:#425985;   --chart-palette-10:#4344D5;
  --chart-palette-11:#7D5A2E;  --chart-palette-12:#4F8F3F;
  --chart-palette-13:#B03A3A;  --chart-palette-14:#6A5ACD;
  --chart-palette-15:#2E8B8B;  --chart-palette-16:#8A6D3B;
  /* Slot 17 is not part of the JS auto-rotation (globals.html's
     DEFAULT_PALETTE stops at 16) -- it exists for templates that pin it
     deliberately, same as any other named chart-* token below. */
  --chart-palette-17:#A855F7;
  --chart-ramp-pos:#1F6B4E,#2C8C6A,#3FA37E,#68CA8F,#8FD9AC;
  --chart-ramp-neg:#8F2E2E,#B03A3A,#C4564A,#EB7D6E,#F09F92;

  /* Named accents that recurred as hand-typed literals across dashboards
     before this token existed -- see docs/adr for the decision to name
     these instead of leaving them as repeated literals. */
  --chart-warn:#F7971E;
  --chart-secondary:#6C63FF;
  --chart-info:#38BDF8;
  --chart-periwinkle:#87A2D5;

  /* Archetype quadrant identity colours -- read by theming.archetype_colors()
     instead of a second, hardcoded Python dict. Deliberately identical in
     both palettes below: these are identity colours (a user learns "quadrant
     I = this colour"), not series colours meant to re-tune per theme. */
  --chart-archetype-i:#2D6A9F;
  --chart-archetype-ii:#E05A5A;
  --chart-archetype-iii:#3BAD6E;
  --chart-archetype-iv:#D4A017;

  /* Data Maturity tier badges -- also identity colours, also identical in
     both palettes. --chart-tier-silver is a deliberate new value: the tier
     previously shared its literal with Emerging (#94A3B8) in both, a bug
     this token fixes by giving Silver its own value. */
  --chart-tier-emerging:#94A3B8;
  --chart-tier-bronze:#CD7F32;
  --chart-tier-silver:#C0C0C0;
  --chart-tier-gold:#EAB308;
  --chart-tier-platinum:#8B5CF6
}

/* ═══════════════════════════════════════════════════════════════════════
   DARK — same design on the brand's deep navy.
   Surfaces come from the Blue Hour scale rather than neutral grey, and the
   accents step lighter (primary-300, lizard-400) so they stay legible.
   ═══════════════════════════════════════════════════════════════════════ */
:root[data-theme="dark"]{
  color-scheme:dark;
  /* The original dashboard palette — neutral near-black rather than brand
     navy. Only colours change here; the Woof geometry and type above are
     shared, which is what test_dark_does_not_redeclare_shared_geometry pins. */
  --bg:#0f1117;--surface:#1a1d27;--surface2:#222636;
  --border:#253553;--border-strong:#3a4d6e;
  --text:#e8eaf0;--text-muted:#6783b8;
  --accent:#5253ff;--accent-soft:rgba(82,83,255,.16);
  --accent-hover:#6465ff;--accent-press:#4344d5;
  --brand-ink:#b7b8ff;--brand-tint:rgba(82,83,255,.12);--brand-soft:rgba(82,83,255,.20);
  --logo-bg:#5253ff;--tip-bg:#222636;
  --fg-subtle:#4d5f80;--row-hover:#222636;--track-off:#253553;
  --pos:#43e97b;--mid:#f7d774;--neg:#ff6584;
  --shadow:0 4px 24px rgba(0,0,0,.4);
  --shadow-lift:0 8px 32px rgba(0,0,0,.5);

  --chart-grid:#253553;
  --chart-tick:#6783b8;
  --chart-fg:#e8eaf0;
  --chart-axis-title:#8899bb;
  --chart-tooltip-bg:#1a1d27;
  --chart-tooltip-brd:#253553;
  --chart-tooltip-fg:#ffffff;
  --chart-zero-line:#000000;
  --chart-surface:#1a1d27;
  --chart-accent:#5253ff;
  --chart-pos:#43e97b;
  --chart-neg:#ff6584;
  --chart-palette-1:#5253ff;   --chart-palette-2:#ff52aa;
  --chart-palette-3:#fffe52;   --chart-palette-4:#52ffa7;
  --chart-palette-5:#fc6400;   --chart-palette-6:#00ccfc;
  --chart-palette-7:#fcc8b0;   --chart-palette-8:#587414;
  --chart-palette-9:#00fc00;   --chart-palette-10:#8470bc;
  --chart-palette-11:#fc0040;  --chart-palette-12:#b44844;
  --chart-palette-13:#08786c;  --chart-palette-14:#d49c30;
  --chart-palette-15:#b0f0d4;  --chart-palette-16:#846c4c;
  --chart-palette-17:#a855f7;
  --chart-ramp-pos:#43e97b,#34d399,#6ee7b7,#a7f3d0,#d1fae5;
  --chart-ramp-neg:#ff6584,#f87171,#fca5a5,#fecaca,#fee2e2;

  --chart-warn:#f7971e;
  --chart-secondary:#6c63ff;
  --chart-info:#38bdf8;
  --chart-periwinkle:#87a2d5;

  --chart-archetype-i:#2D6A9F;
  --chart-archetype-ii:#E05A5A;
  --chart-archetype-iii:#3BAD6E;
  --chart-archetype-iv:#D4A017;

  --chart-tier-emerging:#94a3b8;
  --chart-tier-bronze:#cd7f32;
  --chart-tier-silver:#c0c0c0;
  --chart-tier-gold:#eab308;
  --chart-tier-platinum:#8b5cf6
}

/* ═══════════════════════════════════════════════════════════════════════
   Shared structure — identical in both palettes
   ═══════════════════════════════════════════════════════════════════════ */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}

/* ── Base ─────────────────────────────────────────────────────────────── */
body{font-family:'Hanken Grotesk',system-ui,sans-serif;background:var(--bg);color:var(--text);min-height:100vh;-webkit-font-smoothing:antialiased}
h1,h2,h3{font-family:'Radio Canada Big','Hanken Grotesk',sans-serif}

/* ── Header ───────────────────────────────────────────────────────────── */
header{
  background:var(--surface);border-bottom:1px solid var(--border);
  padding:16px 32px;display:flex;align-items:center;gap:16px;
  position:sticky;top:0;z-index:100
}
.logo{
  width:40px;height:40px;background:var(--logo-bg);
  border-radius:14px;display:flex;align-items:center;justify-content:center;
  color:#fff;text-decoration:none;font-size:20px
}
.header-text h1{font-size:20px;font-weight:700;letter-spacing:-.2px;color:var(--brand-ink)}
.header-text span{font-size:13px;color:var(--text-muted)}
.header-nav{margin-left:auto;display:flex;align-items:center;gap:6px}
.header-nav a{
  font-size:14px;font-weight:500;color:var(--text-muted);text-decoration:none;
  padding:8px 14px;border-radius:999px;transition:all .18s ease-out
}
.header-nav a:hover{color:var(--accent);background:var(--brand-tint)}

.main{padding:32px;max-width:1600px;margin:0 auto}

/* ── Filters ──────────────────────────────────────────────────────────── */
.filters{
  background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);
  padding:20px 24px;display:flex;flex-wrap:wrap;gap:18px;align-items:flex-start;
  margin-bottom:24px;box-shadow:var(--shadow)
}
.filter-group{display:flex;flex-direction:column;gap:6px}
.filter-group label{font-size:13px;font-weight:600;color:var(--text-muted);letter-spacing:0}
.filter-group input,.filter-select{
  background:var(--surface);border:1.5px solid var(--border);border-radius:12px;
  color:var(--text);font-family:inherit;font-size:14px;padding:10px 14px;outline:none;
  transition:border-color .18s,box-shadow .18s;min-width:170px
}
.filter-group input:focus,.filter-select:focus{border-color:var(--accent);box-shadow:0 0 0 4px rgba(82,83,255,.18)}
.filter-select{cursor:pointer}
.toggle-switch{display:flex;align-items:center;gap:10px;cursor:pointer;user-select:none;font-size:14px;padding-top:2px}
.toggle-switch input{display:none}
.toggle-track{width:44px;height:26px;background:var(--track-off);border:none;border-radius:999px;position:relative;transition:background .2s}
.toggle-switch input:checked + .toggle-track{background:var(--accent)}
.toggle-thumb{position:absolute;top:3px;left:3px;width:20px;height:20px;background:#fff;border-radius:50%;transition:left .2s;box-shadow:0 1px 3px rgba(13,25,49,.25)}
.toggle-switch input:checked + .toggle-track .toggle-thumb{left:21px}

/* ── Buttons — pill, 22px radius ──────────────────────────────────────── */
.btn{
  padding:11px 24px;border-radius:22px;font-size:14px;font-weight:600;
  font-family:inherit;cursor:pointer;border:2px solid transparent;
  background:var(--accent);color:#fff;transition:all .18s ease-out;white-space:nowrap
}
.btn:hover{background:var(--accent-hover)}
.btn:active{background:var(--accent-press);transform:scale(.98)}
.btn-sm{padding:7px 16px;font-size:13px;border-radius:999px}
.btn-ghost{background:transparent;border:2px solid var(--border-strong);color:var(--accent)}
.btn-ghost:hover{background:var(--brand-tint);border-color:var(--accent)}

#loading-bar{position:fixed;top:0;left:0;width:100%;height:3px;background:var(--accent);transform:scaleX(0);transform-origin:left;transition:transform .3s ease;z-index:9999;opacity:0}
#loading-bar.htmx-request{opacity:1;animation:loading-slide 1.2s ease-in-out infinite}
@keyframes loading-slide{0%{transform:scaleX(0)}50%{transform:scaleX(.7)}100%{transform:scaleX(1);opacity:0}}

/* ── KPI cards ────────────────────────────────────────────────────────── */
.kpi-row{display:flex;gap:16px;margin-bottom:24px;flex-wrap:wrap}
.kpi-card{
  flex:1;min-width:190px;background:var(--surface);border:1px solid var(--border);
  border-radius:var(--radius);padding:22px 24px;display:flex;align-items:center;gap:16px;
  box-shadow:var(--shadow);position:relative
}
/* Standalone glyph, deliberately untiled — the boxed version crowded the
   number it sits next to. */
.kpi-icon{font-size:34px;line-height:1;color:var(--accent);flex-shrink:0}
.kpi-icon svg{width:30px;height:30px}
.kpi-value{font-family:'Radio Canada Big',sans-serif;font-size:34px;font-weight:700;letter-spacing:-.8px;line-height:1.1}
.kpi-label{font-size:13px;font-weight:500;text-transform:none;letter-spacing:0;color:var(--text-muted);margin-top:2px}
.kpi-accent-bar{width:4px;height:44px;border-radius:999px;flex-shrink:0}
/* Out of flow, so a badged card keeps its icon/value on the same line as an
   unbadged one sitting beside it in the same .kpi-row. */
.kpi-badge{position:absolute;top:14px;right:14px}
.kpi-badge .dashboard-card-badge{margin-left:0}

.kpi-pill{
  flex:1;min-width:280px;max-width:460px;background:var(--surface);
  border:1px solid var(--border);border-radius:var(--radius);
  padding:24px 24px 18px;box-shadow:var(--shadow);text-align:center;position:relative
}
.kpi-pill-accent{width:48px;height:4px;border-radius:999px;margin:0 auto 14px}
/* Out of flow, so a badged pill keeps its number on the same line as an
   unbadged one sitting beside it in the same .kpi-row. */
.kpi-pill-badge{position:absolute;top:14px;right:14px}
.kpi-pill-badge .dashboard-card-badge{margin-left:0}
.kpi-pill-value{font-family:'Radio Canada Big',sans-serif;font-size:52px;font-weight:700;letter-spacing:-1.5px;line-height:1}
.kpi-pill-label{font-size:13px;font-weight:500;text-transform:none;letter-spacing:0;color:var(--text-muted);margin-top:4px}
.kpi-pill-sub{display:flex;border-top:1px solid var(--border);margin-top:20px;padding-top:16px}
.kpi-pill-sub-divider{width:1px;background:var(--border);flex-shrink:0}
.kpi-pill-item{flex:1;padding:0 6px;min-width:0}
.kpi-pill-item-value{font-family:'Radio Canada Big',sans-serif;font-size:22px;font-weight:700;letter-spacing:-.4px;line-height:1.1}
.kpi-pill-item-label{font-size:12px;font-weight:500;text-transform:none;letter-spacing:0;color:var(--text-muted);margin-top:2px}

.overview-tab{display:contents;cursor:pointer}
.overview-tab .kpi-pill{transition:box-shadow .18s,transform .18s}
.overview-tab:hover .kpi-pill{transform:translateY(-2px);box-shadow:var(--shadow-lift)}
.overview-tab.active .kpi-pill{box-shadow:0 0 0 2px var(--accent),var(--shadow)}
.overview-section-hd{display:flex;align-items:baseline;gap:10px;margin:8px 0 16px;padding-top:24px;border-top:1px solid var(--border)}
.overview-section-hd h2{font-size:22px;font-weight:600;margin:0}
.overview-section-hd span{font-size:13px;color:var(--text-muted)}

/* ── Tooltip ──────────────────────────────────────────────────────────── */
.info-tip{position:relative;display:inline-flex;vertical-align:middle;margin-left:5px;color:var(--fg-subtle);cursor:help;outline:none}
.info-tip:hover,.info-tip:focus{color:var(--accent)}

/* A tooltip belongs in front of everything, but its z-index only ranks it
   inside its own card: hovering a KPI pill applies a transform, and a transform
   creates a stacking context the bubble cannot escape. So lift the whole card
   while it is hovered or holds focus — otherwise the next card in DOM order
   paints straight over the bubble. */
.kpi-card:hover,.kpi-card:focus-within,
.kpi-pill:hover,.kpi-pill:focus-within,
.chart-card:hover,.chart-card:focus-within{z-index:60}

.info-tip-body{
  visibility:hidden;opacity:0;transition:opacity .15s;position:absolute;z-index:200;
  top:150%;left:50%;transform:translateX(-50%);width:240px;max-width:60vw;padding:11px 13px;
  background:var(--tip-bg);border:none;border-radius:12px;box-shadow:var(--shadow-lift);
  font-size:12.5px;font-weight:400;line-height:1.45;letter-spacing:normal;text-transform:none;
  text-align:left;color:#fff;white-space:normal
}
.info-tip:hover .info-tip-body,.info-tip:focus .info-tip-body,.info-tip:focus-within .info-tip-body{visibility:visible;opacity:1}

/* ── Charts ───────────────────────────────────────────────────────────── */
.charts-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(420px,1fr));gap:16px;margin-bottom:24px}
.chart-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:24px;box-shadow:var(--shadow);position:relative}
.chart-card-hd{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:18px}
.chart-title{font-family:'Radio Canada Big',sans-serif;font-size:18px;font-weight:600;margin-bottom:18px}
.chart-card-hd .chart-title{margin-bottom:0}
.chart-dl-btn{flex-shrink:0;display:inline-flex;align-items:center;gap:5px}
.chart-toggle-btn{flex-shrink:0}
.chart-toggle-btn.on{background:var(--accent);border-color:var(--accent);color:#fff}
canvas,svg.plot{max-width:100%}

/* ── Chart export menu (chart_dl_btn macro) ───────────────────────────────
   Same floating-panel pattern as .msel (compact multi-select filter): a
   closed trigger button, a panel that only exists once opened, one open
   panel at a time (see closeAllPopovers() in globals.html). */
.chart-export{position:relative;flex-shrink:0}
.chart-export-panel{display:none;position:absolute;top:calc(100% + 6px);right:0;z-index:30;min-width:190px;
  background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius);
  box-shadow:var(--shadow);padding:6px;flex-direction:column;gap:2px}
.chart-export-panel.open{display:flex}
.chart-export-item{display:block;width:100%;text-align:left;background:transparent;border:none;
  color:var(--text);font-family:inherit;font-size:13px;padding:8px 10px;border-radius:8px;cursor:pointer}
.chart-export-item:hover{background:var(--brand-tint)}
.chart-export-item.is-disabled{color:var(--text-muted);cursor:not-allowed}
.chart-export-item.is-disabled:hover{background:transparent}
.chart-export-divider{height:1px;background:var(--border);margin:4px 2px}
.chart-export-setting{display:flex;align-items:center;justify-content:space-between;gap:8px;
  padding:6px 10px;font-size:12.5px;color:var(--text-muted)}
.chart-export-setting select{font-family:inherit;font-size:12.5px;background:var(--surface);
  color:var(--text);border:1px solid var(--border);border-radius:6px;padding:2px 4px}

/* ── Scorecard: defined-but-not-yet-measurable KPI cards ──────────────────
   Deliberately quieter than a real chart card — dashed border, muted body —
   so a planned metric never reads as a measured one at a glance. */
.sc-planned{border-style:dashed;box-shadow:none}
.sc-planned-summary{margin:0;font-size:14px;line-height:1.5;color:var(--text-muted)}
.sc-planned-list{margin:12px 0 0;padding-left:18px;font-size:13.5px;line-height:1.7;color:var(--text-muted)}
.sc-planned-blocked{margin:14px 0 0;padding-top:12px;border-top:1px solid var(--border);font-size:12.5px;line-height:1.5;color:var(--fg-subtle)}
.sc-provisional-value{font-family:'Radio Canada Big',sans-serif;font-size:42px;font-weight:700;letter-spacing:-1.2px;line-height:1}
.sc-provisional-label{font-size:13px;color:var(--text-muted);margin-top:4px}

/* ── Table ────────────────────────────────────────────────────────────── */
.table-card{overflow:hidden}
.table-wrapper{overflow-x:auto;max-height:480px;overflow-y:auto}
.data-table{width:100%;border-collapse:collapse;font-size:14px;min-width:900px}
.data-table thead th{
  background:var(--surface);color:var(--text-muted);font-size:13px;font-weight:600;
  text-transform:none;letter-spacing:0;padding:12px 14px;text-align:left;white-space:nowrap;
  position:sticky;top:0;z-index:1;border-bottom:1px solid var(--border)
}
.data-table tbody tr{border-bottom:1px solid var(--border);transition:background .15s}
.data-table tbody tr:hover{background:var(--row-hover)}
.data-table tbody td{padding:12px 14px;color:var(--text);white-space:nowrap}
.data-table .num{text-align:right;font-variant-numeric:tabular-nums}

/* ── Badges ───────────────────────────────────────────────────────────── */
.mood-pill{display:inline-block;padding:3px 12px;border-radius:999px;font-size:13px;font-weight:600}
.mood-hi{background:#A5EBC1;color:#12492C}
.mood-mid{background:#FFEEA9;color:#6B5308}
.mood-lo{background:#FFC6C6;color:#8A2C1E}
.factor-badge{display:inline-block;padding:3px 10px;border-radius:999px;font-size:12.5px;max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.factor-pos{background:#EAF9F0;color:#2F7A52;border:1px solid #A5EBC1}
.factor-neg{background:#FFF0EE;color:#B0503F;border:1px solid #FFC6C6}
/* The light chip colours above read fine on the light palette (dark ink on a
   pale tint) but are hardcoded hex, not tokens, so they never adapted to the
   dark palette -- the same pale-mint/pale-pink chip just sits unreadably on
   a near-black page. Override with the theme's own --pos/--neg (already
   tuned bright-on-dark) tinted into the card surface, matching the
   color-mix() pattern checkin_dashboard.html's .deleted-badge already uses. */
:root[data-theme="dark"] .factor-pos{background:color-mix(in srgb, var(--pos) 18%, transparent);color:var(--pos);border-color:color-mix(in srgb, var(--pos) 45%, transparent)}
:root[data-theme="dark"] .factor-neg{background:color-mix(in srgb, var(--neg) 18%, transparent);color:var(--neg);border-color:color-mix(in srgb, var(--neg) 45%, transparent)}
.plan-badge{display:inline-block;padding:3px 10px;border-radius:999px;font-size:12.5px;font-weight:600;background:var(--brand-soft);color:var(--brand-ink)}
.plan-badge.plan-inactive{opacity:.55}
.plan-end{margin-left:6px;font-size:11.5px;color:var(--text-muted)}

/* ── Landing ──────────────────────────────────────────────────────────── */
.landing-intro{margin-bottom:32px}
.landing-intro h2{font-family:'League Gothic','Radio Canada Big',sans-serif;font-size:44px;font-weight:400;text-transform:uppercase;letter-spacing:.5px;color:var(--brand-ink);margin-bottom:4px}
.landing-intro p{font-size:16px;color:var(--text-muted)}
.folder-section{margin-bottom:36px}
.folder-header{display:flex;align-items:center;gap:12px;margin-bottom:16px}
.folder-icon{width:36px;height:36px;border-radius:12px;display:flex;align-items:center;justify-content:center}
.folder-name{font-family:'Radio Canada Big',sans-serif;font-size:18px;font-weight:600}
.folder-desc{font-size:13px;color:var(--text-muted);margin-left:auto}

.dashboard-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px}
.dashboard-card{
  background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);
  padding:24px;text-decoration:none;color:var(--text);display:flex;flex-direction:column;gap:8px;
  transition:all .18s ease-out;box-shadow:var(--shadow);position:relative;overflow:hidden
}
.dashboard-card::before{content:'';position:absolute;top:0;left:0;right:0;height:4px;background:var(--card-accent,var(--accent))}
.dashboard-card:hover{border-color:var(--border-strong);transform:translateY(-2px);box-shadow:var(--shadow-lift)}
.dashboard-card--flagged{border:2px solid var(--neg)}
.dashboard-card--flagged:hover{border-color:var(--neg)}
.dashboard-card-badge{
  display:inline-block;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.4px;
  color:#8A2C1E;background:#FFC6C6;border:none;border-radius:999px;padding:3px 9px;margin-left:6px;vertical-align:middle
}
.dashboard-card--admin-only{border:2px solid var(--accent)}
.dashboard-card--admin-only:hover{border-color:var(--accent-hover)}
.dashboard-card-badge--admin-only{color:var(--brand-ink);background:var(--brand-soft)}
.dashboard-card-title{font-family:'Radio Canada Big',sans-serif;font-size:18px;font-weight:600;letter-spacing:-.2px}
.dashboard-card-desc{font-size:14px;color:var(--text-muted);line-height:1.5;text-wrap:pretty}
.dashboard-card-arrow{margin-top:auto;font-size:14px;font-weight:600;color:var(--accent);display:flex;align-items:center;gap:6px}

/* ── Admin bar / breadcrumb ───────────────────────────────────────────── */
.admin-bar{background:var(--brand-tint);border:1px solid var(--brand-soft);border-radius:var(--radius);padding:14px 20px;display:flex;align-items:center;gap:16px;margin-bottom:24px;font-size:14px}
.admin-bar span{color:var(--text-muted)}
#refresh-status{font-size:13px;color:var(--text-muted)}
#refresh-status.ok{color:#2F7A52}
#refresh-status.err{color:#B0503F}
.breadcrumb{display:flex;align-items:center;gap:8px;margin-bottom:20px;font-size:14px;color:var(--text-muted)}
.breadcrumb a{color:var(--accent);text-decoration:none}
.breadcrumb a:hover{text-decoration:underline}
.breadcrumb .sep{opacity:.5}

/* ── Catalog ──────────────────────────────────────────────────────────── */
.catalog-table-wrapper{overflow-x:auto;max-width:100%}
.catalog-table{min-width:1200px;table-layout:auto}
.catalog-table .col-name{min-width:220px;max-width:280px;white-space:normal;font-weight:600}
.catalog-table .col-step{min-width:160px;max-width:200px;vertical-align:top;padding:12px 10px}
.catalog-table .cell-grades{font-size:13px;color:var(--text-muted);white-space:normal;min-width:120px}
.step-name{font-size:12.5px;color:var(--text-muted);margin-bottom:6px}
.step-factors{display:flex;flex-wrap:wrap;gap:5px}
.factor-chip{font-size:12px;padding:3px 10px;border-radius:999px;background:var(--brand-tint);border:1px solid var(--brand-soft);color:var(--brand-ink);white-space:nowrap}
.step-empty{color:var(--text-muted);font-size:13px}
.badge-public{display:inline-block;font-size:11px;padding:3px 10px;border-radius:999px;background:#EAF9F0;border:1px solid #A5EBC1;color:#2F7A52;font-weight:600;text-transform:uppercase;letter-spacing:.4px}
.badge-private{display:inline-block;font-size:11px;padding:3px 10px;border-radius:999px;background:#FFF0EE;border:1px solid #FFC6C6;color:#B0503F;font-weight:600;text-transform:uppercase;letter-spacing:.4px}

.catalog-filters{display:flex;flex-wrap:wrap;align-items:flex-start;gap:16px}
.cat-filter-group{display:flex;flex-direction:column;gap:6px}
.cat-filter-label{font-size:13px;font-weight:600;color:var(--text-muted)}

.multiselect-wrap{position:relative;display:inline-block}
.ms-trigger{display:flex;align-items:center;gap:8px;background:var(--surface);border:1.5px solid var(--border);border-radius:12px;padding:9px 14px;cursor:pointer;font-size:14px;min-width:160px;user-select:none;transition:border-color .18s}
.ms-trigger:hover{border-color:var(--accent)}
.ms-arrow{font-size:10px;color:var(--text-muted);margin-left:auto}
.ms-dropdown{display:none;position:absolute;top:calc(100% + 6px);left:0;z-index:200;background:var(--surface);border:1px solid var(--border);border-radius:16px;min-width:180px;max-height:260px;overflow-y:auto;box-shadow:var(--shadow-lift);padding:6px}
.ms-dropdown.ms-open{display:block}
.ms-option{display:flex;align-items:center;gap:9px;padding:8px 12px;font-size:14px;cursor:pointer;border-radius:10px;transition:background .15s}
.ms-option:hover{background:var(--brand-tint)}
.ms-option input[type=checkbox]{accent-color:var(--accent);width:15px;height:15px}

/* ── Tag cloud ────────────────────────────────────────────────────────── */
.tc-search-wrap{display:flex;align-items:center;gap:10px;margin-bottom:16px}
.tc-search-input{background:var(--surface);border:1.5px solid var(--border);border-radius:12px;padding:9px 14px;font-size:14px;color:var(--text);outline:none;width:260px;transition:border-color .18s}
.tc-search-input:focus{border-color:var(--accent)}
.tag-cloud-container{display:flex;flex-wrap:wrap;gap:8px 12px;padding:8px 0;line-height:1.5}
.tc-tag{cursor:pointer;color:var(--text-muted);transition:color .18s,transform .15s;white-space:nowrap;border-radius:999px;padding:2px 8px}
.tc-tag:hover{color:var(--accent);background:var(--brand-tint)}
.tc-tag.tc-active{color:#fff;background:var(--accent)}
.tc-tag.tc-unavailable{outline:1.5px dashed var(--neg)}
.tc-tag.tc-unavailable.tc-active{outline:none}
.tc-count{font-size:10px;opacity:.65;margin-left:3px}

/* ── Checkbox filter ──────────────────────────────────────────────────── */
.cbx-wrap{display:flex;flex-direction:column;gap:6px;min-width:150px;max-width:260px;flex:0 0 auto}
.cbx-search{padding:7px 10px;background:var(--surface);border:1.5px solid var(--border);border-radius:10px;color:var(--text);font-size:13px;outline:none}
.cbx-search::placeholder{color:var(--fg-subtle)}
.cbx-search:focus{border-color:var(--accent)}
.cbx-actions{display:flex;gap:6px}
.cbx-btn{flex:1;padding:4px 8px;background:transparent;border:1.5px solid var(--border);border-radius:999px;color:var(--text-muted);font-size:12px;cursor:pointer;font-family:inherit}
.cbx-btn:hover{border-color:var(--accent);color:var(--accent)}
.cbx-list{max-height:148px;overflow-y:auto;border:1px solid var(--border);border-radius:12px;background:var(--surface);scrollbar-width:thin}
.cbx-item{display:flex;align-items:center;gap:9px;padding:7px 10px;cursor:pointer;user-select:none}
.cbx-item:hover{background:var(--row-hover)}
.cbx-item input[type=checkbox]{position:absolute;opacity:0;width:0;height:0}
.cbx-mark{width:16px;height:16px;border:1.5px solid var(--border-strong);border-radius:5px;background:#fff;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:10px;color:#fff}
.cbx-item input:checked+.cbx-mark{background:var(--accent);border-color:var(--accent)}
.cbx-item input:checked+.cbx-mark::after{content:'✓'}
.cbx-lbl{font-size:13.5px;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

.sel-pill{background:var(--brand-tint);color:var(--brand-ink);padding:3px 10px;border-radius:999px;font-size:12.5px;white-space:nowrap}
.sel-pill--grade{background:var(--brand-soft);color:var(--brand-ink)}
.sel-pill--factor{background:#EAF9F0;color:#2F7A52}

/* ── Compact multi-select (cbx_filter popover=True) ──────────────────────
   Closed footprint matches .filter-select; the cbx-list only appears in a
   floating panel on click, so a filter with many options (countries,
   grades) doesn't force the always-visible filter bar to wrap or grow. */
.msel{position:relative}
.msel-trigger{display:flex;align-items:center;justify-content:space-between;gap:10px;
  background:var(--surface);border:1.5px solid var(--border);border-radius:12px;color:var(--text);
  font-family:inherit;font-size:14px;padding:10px 14px;min-width:170px;max-width:200px;cursor:pointer;text-align:left}
.msel-trigger:hover{border-color:var(--accent)}
.msel-trigger-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.msel-caret{color:var(--text-muted);font-size:10px;flex-shrink:0}
.msel-panel{display:none;position:absolute;top:calc(100% + 6px);left:0;z-index:30;width:240px;
  background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius);
  box-shadow:var(--shadow);padding:10px;flex-direction:column;gap:8px}
.msel-panel.open{display:flex}
.msel-panel .cbx-list{max-height:220px}

@media(prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}
@media(max-width:640px){.charts-grid{grid-template-columns:1fr}.main{padding:16px}.kpi-row{flex-direction:column}.dashboard-grid{grid-template-columns:1fr}}