/* ============================================================================
   Universum theme bridge — makes the Dev Factory apps match the Universum
   design language (light app-shell, tokens, typography). Loaded after
   universum-ui.css on every page (nginx sub_filter). Uses Universum tokens.
   ============================================================================ */
:root{
  --surface:#ffffff; --stroke:var(--border-subtle,#e6e9f2);
  --ink:var(--text-strong,#1d2233); --ink-soft:var(--text-body,#2c3040); --ink-mute:var(--text-muted,#5b6473);
  --f-body:var(--font-text); --f-head:var(--font-display); --f-mono:var(--font-mono);
  --r-sm:6px; --r-md:10px; --r-lg:12px; --r-xl:14px; --r-pill:999px;
}
html,body{ font-family:var(--font-text)!important; color:var(--text-body,#2c3040); background:var(--surface-soft,#f6f7fb); }
h1,h2,h3,h4,.font-serif{ font-family:var(--font-display,var(--font-text))!important; }

/* ── App shell: LIGHT Universum sidebar (overrides the app's dark gradient) ── */
aside.console-sidebar{
  background:var(--surface-soft,#f6f7fb)!important; color:var(--text-muted,#5b6473)!important;
  border-right:1px solid var(--border-subtle,#e6e9f2)!important;
  padding:12px!important; display:flex!important; flex-direction:column!important; gap:2px!important;
}
.u-side-nav__brand{
  display:block; padding:14px 10px 12px; margin:0; text-decoration:none;
  font-size:16px; font-weight:800; letter-spacing:-.01em; color:var(--text-strong,#1d2233)!important;
}
.u-side-nav__scroll{ flex:1; overflow-y:auto; display:flex; flex-direction:column; gap:2px; }
.u-side-nav__footer{ margin-top:auto; padding-top:10px; border-top:1px solid var(--border-subtle,#e6e9f2); display:flex; flex-direction:column; gap:2px; }
.u-side-nav__user{ display:flex; align-items:center; gap:10px; padding:8px 10px; }
.u-side-nav__avatar{ width:32px;height:32px;border-radius:999px;background:var(--action,#2B3086);color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;flex:none; }
/* the app's nav <a> also carried Tailwind text-white etc.; force Universum item colors */
aside.console-sidebar .u-side-nav__item{ color:var(--text-muted,#5b6473)!important; text-decoration:none; }
aside.console-sidebar .u-side-nav__item--active{ color:var(--text-strong,#1d2233)!important; background:var(--surface-card,#fff)!important; box-shadow:var(--shadow-xs,0 1px 2px rgba(16,24,40,.06)); }
aside.console-sidebar .u-side-nav__item--active .u-side-nav__icon{ color:var(--accent,#D20A11)!important; }

/* ── Main area + top bar → Universum surfaces ──
   The content canvas is WHITE; cards lift off it with a hairline + soft shadow. ── */
.console-main{ background:var(--surface-card,#fff)!important; }

/* ── Page header standard (Universum u-page-header, adapted) ──
   The first row of the content is a PAGE TITLE, not a second toolbar: display
   font at fs-h3 scale, generous padding aligned with the 32px content gutter,
   page meta/actions on the right. Context that already lives in the top bar
   (project name, back links, brand icons) must NOT be repeated here. A subtle
   hairline stays because the content pane scrolls under this fixed row. ── */
.console-main > header{
  background:var(--surface-card,#fff)!important;
  border-bottom:1px solid var(--border-subtle,#e6e9f2)!important;
  padding:20px 32px!important;
}
.console-main > header h1{
  font-family:var(--font-display,var(--font-text))!important;
  font-size:22px!important; font-weight:700!important; letter-spacing:-.015em;
  color:var(--text-strong,#1d2233)!important;
}
/* On a white canvas, white cards need a clear edge to read as cards ("contrastar ou serem brancos"). */
.console-main .u-card,
.console-main [class*="rounded-2xl"].bg-white,
.console-main [class*="rounded-xl"].bg-white{
  box-shadow:0 1px 2px rgba(16,24,40,.06), 0 1px 3px rgba(16,24,40,.04)!important;
  border:1px solid var(--border-subtle,#e6e9f2)!important;
}

/* ============================================================================
   Universum APP-SHELL — full-width top bar (brand + global) + contextual side
   nav. The top bar spans edge-to-edge above the (fixed) sidebar; the left rail
   holds only context items (project items inside a project, platform items
   outside). Global things (brand, back-to-projects, user) live in the top bar.
   ============================================================================ */
.u-df-topbar{ position:fixed; top:0; left:0; right:0; z-index:60; }
.u-df-brand{
  font-family:var(--font-display,var(--font-text)); font-weight:800; font-size:16px;
  letter-spacing:-.01em; color:var(--brand-blue,#2B3086)!important; text-decoration:none; flex:none;
}
.u-df-topbar__link{
  display:inline-flex; align-items:center; gap:6px; padding:6px 10px; border-radius:8px;
  font-size:13px; font-weight:500; color:var(--text-muted,#5b6473)!important; text-decoration:none;
}
.u-df-topbar__link:hover{ background:rgba(0,0,0,.045); color:var(--text-strong,#1d2233)!important; }
.u-df-user{ display:flex; align-items:center; gap:9px; }
.u-df-user__meta{ min-width:0; line-height:1.15; }
.u-df-user__av{
  width:30px;height:30px;border-radius:999px;background:var(--action,#2B3086);color:#fff;
  display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;flex:none;
}
.u-df-user__name{ font-size:13px;font-weight:600;color:var(--text-strong,#1d2233);line-height:1.15;margin:0; }
.u-df-user__mail{ font-size:11px;color:var(--text-subtle,#8891a4);line-height:1.15;margin:0; }
.u-df-logout{
  width:32px;height:32px;display:inline-flex;align-items:center;justify-content:center;border:none;
  background:transparent;border-radius:8px;color:var(--text-muted,#5b6473);cursor:pointer;flex:none;
}
.u-df-logout:hover{ background:rgba(0,0,0,.045);color:var(--accent,#D20A11); }
/* ── Top-bar navigation (approved P3+P6+P4) ──
   The DS bar clips (overflow:hidden, legacy of the removed texture ornaments) —
   the account dropdown needs it visible. The switcher pills sit next to the
   brand (DS default pushes __nav right); breadcrumb gets the product divider. */
.u-df-topbar{ overflow:visible!important; }
.u-df-topbar .u-breadcrumb{ padding-left:14px; border-left:1px solid var(--border-subtle,#e6e9f2); }
.u-df-topbar .u-top-bar__nav{ margin-left:16px; }
.u-df-topbar a.u-top-bar__nav-item{ text-decoration:none; display:inline-flex; align-items:center; }
/* "You are here" accent is RED everywhere: the DS side-nav active icon is brand-red
   ("same family as the menu/tab accent"), so the switcher's active pill joins that
   family too — red wash + red label — instead of the blue --surface-sel. Blue stays
   the ACTION color (buttons, links); red marks the current location. */
.u-df-topbar .u-top-bar__nav-item--active{
  background:var(--surface-accent-wash,rgba(210,10,17,.08))!important;
  color:var(--accent,#D20A11)!important;
}
.u-df-account{ border:none;background:transparent;padding:0;cursor:pointer;display:inline-flex;border-radius:999px; }
.u-df-topbar .u-menu__panel{ top:calc(100% + 8px); min-width:230px; }
/* Space Needle signature (approved V4) — the needle-over-arc symbol, cropped from
   the official logo PNG, always visible in the top bar next to the bell. */
.u-df-sn-mark{
  display:inline-block; flex:none; width:27px; height:18px;
  background:url(/universum/assets/logos/spaceneedle.png) no-repeat;
  background-size:84px auto; background-position:-28px -7px;
}
/* push the fixed sidebar + scrolling main below the 52px top bar.
   Force position:fixed — the DS .u-side-nav{position:relative} was overriding the app's
   fixed rail, dropping it into flow so main's margin-left:260 became a 260px empty gap. */
aside.console-sidebar{ position:fixed!important; left:0!important; top:52px!important; height:calc(100vh - 52px)!important; min-height:0!important; overflow-y:auto!important; }
@media (min-width:769px){ .console-main{ margin-top:52px!important; height:calc(100vh - 52px)!important; } }
@media (max-width:768px){ .console-main{ margin-top:52px!important; } }
/* hide any leftover in-sidebar brand/back-link/user once moved to the top bar */
aside.console-sidebar .u-df-moved{ display:none!important; }

/* ── Legacy sidebars (admin / data-explorer / ai-playground) still use the old
   dark Tailwind markup — force the Universum light look + hide the ⚡ logo. ── */
aside.console-sidebar a{ color:var(--text-muted,#5b6473)!important; border-left-color:transparent!important; text-decoration:none; }
aside.console-sidebar a:hover{ background:rgba(0,0,0,.045)!important; color:var(--text-strong,#1d2233)!important; }
aside.console-sidebar a.border-accent,
aside.console-sidebar a.bg-white\/10{ background:var(--surface-card,#fff)!important; color:var(--text-strong,#1d2233)!important; border-left-color:var(--accent,#D20A11)!important; box-shadow:var(--shadow-xs,0 1px 2px rgba(16,24,40,.06)); }
aside.console-sidebar a.border-accent i, aside.console-sidebar a.bg-white\/10 i{ color:var(--accent,#D20A11)!important; }
aside.console-sidebar .text-white, aside.console-sidebar .font-serif, aside.console-sidebar .font-bold{ color:var(--text-strong,#1d2233)!important; }
aside.console-sidebar .text-accent-300{ color:var(--action,#2B3086)!important; }
aside.console-sidebar .text-indigo-200\/60, aside.console-sidebar .text-indigo-100\/75, aside.console-sidebar .text-indigo-200\/70{ color:var(--text-subtle,#8891a4)!important; }
aside.console-sidebar .from-primary-500{ display:none!important; }
aside.console-sidebar .bg-white\/5{ background:transparent!important; }

/* ============================================================================
   DARK MODE — the design system is the single owner of dark mode. Apps load
   /universum/theme.js (sets html.dark + html[data-theme] + color-scheme, see
   that file for the controller) and this stylesheet supplies every dark rule:
   token overrides, app-shell overrides, component literal-colour overrides,
   and a Tailwind-utility compatibility layer for the still-Tailwind-heavy
   app content areas (ported from the upstream per-app theme.js, adapted to
   the palette below). Apps must NOT ship their own dark CSS or theme script
   anymore — this file is it.

   ── Palette (dark) ──────────────────────────────────────────────────────
   Surfaces   --surface-page  #0f1117  page background (outside the shell)
              --surface-soft  #151823  sidebar / body canvas
              --surface-card  #1a1e2b  content canvas, cards
              --surface-raised#20253a  menus, popovers, hover fills
              --surface-deep  #12163a  deep/navy surface (top bar "deep" variant)
   Text       --text-strong   #f1f3f9  headings              (14.97:1 on card)
              --text-body     #d5d9e6  body copy              (11.78:1 on card)
              --text-muted    #9aa3b8  secondary                (6.57:1 on card)
              --text-subtle   #7c8496  tertiary/meta            (4.43:1 on card)
              --text-inverse  #0f1117  text drawn on a solid --action/--accent fill
   Borders    --border-subtle #262b3d  --border-strong #323853  --border-input #3a4160
   Brand      --brand-red UNCHANGED (#D20A11, fills only — logo, solid danger uses)
              --brand-blue UNCHANGED (#2B3086, fills only)
              --accent        #ff5a60  text/icons/"you are here" markers (5.44:1 on card)
              --brand-blue-600 / --action  #6b7cff  primary action fill  (4.71:1 on card)
   Shadows    every --shadow-* becomes a neutral rgba(0,0,0,.45) tint (marine-ink shadows
              read as mud once the surface itself is dark; black-based shadows keep the
              lift legible). Contrast ratios verified with .foreman/scratch/contrast.js
              (WCAG relative-luminance method): body/card 11.78:1, muted/card 6.57:1 — both
              clear the ≥4.5:1 / ≥3:1 bars. Status colours (success/warning/danger) keep
              their SATURATED tokens for fills (dots, solid buttons, badge borders) but get
              lighter TEXT-only overrides below (badges, hints, danger menu items, timeline)
              since the raw --status-danger (#DD344C) only reaches 3.69:1 as text on card.
   ============================================================================ */
html.dark, html[data-theme="dark"]{
  --surface-page:#0f1117; --surface-soft:#151823; --surface-card:#1a1e2b;
  --surface-raised:#20253a; --surface-deep:#12163a;
  --surface-sel:rgba(107,124,255,.18);
  --surface-accent-wash:rgba(210,10,17,.16);
  --surface-info-wash:rgba(107,124,255,.14);

  --text-strong:#f1f3f9; --text-body:#d5d9e6; --text-muted:#9aa3b8; --text-subtle:#7c8496;
  --text-inverse:#0f1117; --text-link:#8aa3ff; --text-link-hover:#ff5a60;

  --border-subtle:#262b3d; --border-strong:#323853; --border-input:#3a4160;
  --border-accent:rgba(255,90,96,.45); --border-info:rgba(107,124,255,.45);

  /* --brand-red / --brand-blue stay the literal brand hexes — solid fills (logo,
     solid buttons, dots) don't get lighter, or they'd stop being "the brand colour". */
  --accent:#ff5a60; --accent-2:#89A6FF;
  --action:#6b7cff; --brand-blue-600:#6b7cff; --action-hover:#7f8eff; --action-press:#5866e6;

  --status-success:#3BA55C; --status-warning:#ED7100; --status-danger:#DD344C; --status-info:#6b7cff;

  /* F1: --brand-red / --brand-blue stay the literal brand hexes above (fills
     only), but the three gradients built from that same navy→light-blue ramp
     (--grad-wordmark, --grad-rainbow, --grad-duo) are also used as TEXT
     (u-gradient-text/u-stat/u-kicker--gradient, background-clip:text) and as
     a fill under --text-inverse (u-btn--accent, u-switch). The navy end
     (#2B3086) measures 1.48:1 on --surface-card — invisible as text and,
     since --text-inverse flips to near-black in dark mode, invisible under
     that fill too. Re-anchored to the same light-vivid family already used
     for --action/--brand-blue-600 so every stop clears 4.5:1 on
     --surface-card (contrast.js: 4.71 / 6.93 / 8.33 / 10.10:1 — see .foreman
     scratch/contrast.js "F1 fixes"). Decorative-only consumers (card border,
     progress fill, switch track) are unaffected by the swap. */
  --grad-wordmark:linear-gradient(120deg,#6b7cff 15%,#8aa3ff 60%,#b9c8ff 95%);
  --grad-rainbow:linear-gradient(90deg,#6b7cff 0%,#8aa3ff 40%,#a5b4fc 70%,#c7d2fe 100%);
  --grad-duo:linear-gradient(135deg,#6b7cff 0%,#8aa3ff 60%,#b9c8ff 100%);

  /* Neutral scale — every component below that reaches for --gray-* directly
     (checkbox/radio borders, segmented control, stepper "todo" badge, chip
     hover, progress track/skeleton, pagination ellipsis, breadcrumb sep,
     status-dot "offline") inherits a dark-safe value with no per-component
     rule needed. */
  --gray-50:#151823; --gray-100:#1c2131; --gray-150:#20253a; --gray-200:#262b3d;
  --gray-300:#3a4160; --gray-400:#565f80; --gray-500:#7c8496; --gray-600:#9aa3b8;

  --focus-ring:0 0 0 3px rgba(107,124,255,.40);
  --selection:rgba(255,90,96,.28);

  --shadow-xs:0 2px 5px rgba(0,0,0,.38);
  --shadow-sm:0 4px 10px rgba(0,0,0,.40);
  --shadow:0 16px 40px -18px rgba(0,0,0,.55);
  --shadow-lg:0 26px 70px -24px rgba(0,0,0,.60);
  --shadow-accent:0 24px 70px -24px rgba(255,90,96,.35);
  --glow-page:radial-gradient(34% 28% at 16% 20%,rgba(107,124,255,.14),transparent 70%),radial-gradient(30% 26% at 84% 78%,rgba(255,90,96,.10),transparent 70%);

  color-scheme:dark;
}

/* ── App shell ──────────────────────────────────────────────────────────── */
html.dark, html.dark body{ background:var(--surface-soft); }
html.dark .console-main{ background:var(--surface-card)!important; }
html.dark .console-sidebar{ background:var(--surface-soft); }
html.dark .u-side-nav__item--active{ background:var(--surface-card); }
html.dark .u-df-topbar{ background:var(--surface-card); }
/* "Dev Factory" wordmark: .u-df-brand hard-codes color:var(--brand-blue,#2B3086)
   !important — --brand-blue stays the literal navy in dark mode (fills only,
   see palette note above), so on the dark top bar the wordmark measures
   1.48:1 (illegible). Use --brand-blue-600, which IS overridden for dark
   (#6b7cff, same value as --action) — 4.71:1 on --surface-card. */
html.dark .u-df-brand{ color:var(--brand-blue-600)!important; }
/* hard-coded hover tints in the shell above — the light value only works on a
   light canvas; dark needs the inverse (a faint white wash), not a darker one. */
html.dark .u-df-topbar__link:hover{ background:rgba(255,255,255,.06); }
html.dark .u-df-logout:hover{ background:rgba(255,255,255,.06); color:var(--accent); }
html.dark aside.console-sidebar a:hover{ background:rgba(255,255,255,.06)!important; }
/* card box-shadow in the "white cards need a clear edge" rule above is a fixed
   rgba(16,24,40,…) literal (marine-ink, tuned for a white canvas) — swap for a
   neutral black lift so cards still separate from the dark canvas. */
html.dark .console-main .u-card,
html.dark .console-main [class*="rounded-2xl"].bg-white,
html.dark .console-main [class*="rounded-xl"].bg-white{
  box-shadow:0 1px 2px rgba(0,0,0,.45), 0 1px 3px rgba(0,0,0,.35)!important;
}
/* Space Needle signature — navy-on-dark-navy measures ~1.5:1 (invisible); a
   1.8x brightness lift (kept two-tone, not inverted to grey) puts both the
   needle (navy→#4d56f1, ~3.1:1) and the arc (red→#ff121f, ~4.2:1) back above
   the 3:1 non-text minimum against the topbar's dark --surface-card. */
html.dark .u-df-sn-mark{ filter:brightness(1.8); }

/* ── Component literal-colour overrides ────────────────────────────────────
   Everything token-driven (the vast majority of universum-ui.css) already
   re-themes for free from the :root override above. These are the rules that
   hard-code a hex/rgb literal instead of a var(), found by grepping src/v1/css
   and src/bridge.css for #hex / rgb(/rgba( / white / black outside var(). ── */

/* u-data-table__th header band: literal #eef0f6, copied verbatim from the
   reference .jsx (see display.css comment) instead of a token. */
html.dark .u-data-table__th{ background:#232838; }

/* u-badge success/warning/danger: literal tint + literal hex text (not
   var(--status-*), so the :root override above doesn't reach them). Same
   translucent-tint-plus-light-text treatment as the ported Tailwind chips
   below, and the same text colours reused there for consistency. */
html.dark .u-badge--success{ background:rgba(34,197,94,.16); border-color:rgba(34,197,94,.38); color:#6ee7a0; }
html.dark .u-badge--warning{ background:rgba(251,191,36,.16); border-color:rgba(251,191,36,.38); color:#fcd34d; }
html.dark .u-badge--danger{ background:rgba(248,113,113,.16); border-color:rgba(248,113,113,.38); color:#fca5a5; }
/* u-badge--info/--accent: background+border are already token-driven
   (--surface-info-wash / --surface-accent-wash, dark-safe) but the TEXT is a
   literal color:var(--brand-blue)/var(--brand-red) — those tokens stay the
   saturated brand hex on purpose (fills only, see palette note above), so on
   a dark badge wash the text reads at 1.48:1 / 3.00:1 (wiki "0 recursos" /
   "115 arquivos" badges, Code Wiki repo-name badges). Same tint-bg-plus-
   light-text treatment as success/warning/danger above; colours reused from
   the existing info/accent text conventions elsewhere in this file (toast
   info icon, side-nav active icon). 6.93:1 / 5.44:1 on --surface-card. */
html.dark .u-badge--info{ color:#8aa3ff; }
html.dark .u-badge--accent{ color:var(--accent); }

/* u-btn--danger hover/active: literal darker reds (meant to darken a red
   button on a white page toward black). On a dark page "darker" reads as
   "disappearing" — lighten instead, the same direction every other hover
   state in the DS takes on dark. */
html.dark .u-btn--danger:hover:not(:disabled){ background:#e5495f; }
html.dark .u-btn--danger:active:not(:disabled){ background:#ef6478; }

/* Status colours used directly as TEXT/icon colour (not a fill) need the
   lighter badge-family tones — the raw tokens above stay saturated for fills
   (dots, solid buttons, avatar presence) and only reach 3.69:1 as text. */
html.dark .u-menu__item--danger{ color:#fca5a5; }
html.dark .u-menu__item--danger .u-menu__item-icon{ color:#fca5a5; }
html.dark .u-menu__item--danger:hover, html.dark .u-menu__item--danger.u-menu__item--active{ background:rgba(248,113,113,.14); }
html.dark .u-dialog--danger .u-dialog__title{ color:#fca5a5; }
html.dark .u-input-wrap__hint--error,
html.dark .u-field__hint--error{ color:#fca5a5; }
html.dark .u-timeline__tone--success{ color:#6ee7a0; }
html.dark .u-timeline__tone--danger{ color:#fca5a5; }
html.dark .u-code-block__copy--done,
html.dark .u-code-block__copy--done:hover{ color:#6ee7a0; }
html.dark .u-toast--success .u-toast__icon{ color:#6ee7a0; }
html.dark .u-toast--error .u-toast__icon{ color:#fca5a5; }
html.dark .u-toast--info .u-toast__icon{ color:#8aa3ff; }
html.dark .u-alert--success .u-alert__icon{ color:#6ee7a0; }
html.dark .u-alert--warning .u-alert__icon{ color:#fcd34d; }
html.dark .u-alert--danger .u-alert__icon{ color:#fca5a5; }

/* u-tooltip / .skip-link: both pair `--ink` (a literal, always-dark #1d2233,
   deliberately NOT in the :root override above) with `--text-inverse` for a
   "dark ink chip + white text" bubble. --text-inverse flips to near-black in
   dark mode (it means "text on a solid --action/--accent fill" there) — paired
   with the still-dark --ink that reads as near-black-on-navy, i.e. invisible.
   Give both a real dark-mode treatment: a raised chip lighter than the page,
   with light text, so they still pop above dark content. */
html.dark .u-tooltip__bubble{ background:var(--surface-raised); color:var(--text-strong); }
html.dark .skip-link{ background:var(--surface-raised); color:var(--text-strong); }

/* ============================================================================
   Tailwind-compat layer — the app content areas are still Tailwind-heavy
   (this is what upstream's per-app theme.js used to cover). Ported here so
   the design system is the single owner; colours adapted from upstream's
   literal hexes to this file's semantic tokens/palette wherever the meaning
   lines up 1:1, and to a proportionate literal otherwise (chip tints, the
   extended slate/gray/red/amber/rose/emerald/sky/indigo/violet/orange scale
   upstream didn't fully cover, ring-*, shadow-*).
   ============================================================================ */
html.dark body{ background:var(--surface-soft); }
html.dark .bg-\[\#f4f6fd\]{ background:var(--surface-soft); }
html.dark .bg-white{ background:var(--surface-card); }
html.dark .bg-slate-50, html.dark .bg-gray-50{ background:var(--surface-soft); }
html.dark .bg-slate-100, html.dark .bg-gray-100{ background:var(--surface-raised); }
html.dark .bg-slate-200, html.dark .bg-gray-200{ background:#2a3050; }
html.dark .bg-primary-50{ background:rgba(107,124,255,.12); }
html.dark .bg-primary-100{ background:rgba(107,124,255,.18); }
html.dark .bg-indigo-50{ background:rgba(107,124,255,.10); }
html.dark .bg-blue-50{ background:rgba(107,124,255,.10); }
html.dark .bg-blue-100{ background:rgba(107,124,255,.16); }
html.dark .bg-teal-100{ background:rgba(45,212,191,.16); }
html.dark .hover\:bg-slate-50:hover, html.dark .hover\:bg-gray-50:hover{ background:var(--surface-raised); }
html.dark .hover\:bg-slate-100:hover, html.dark .hover\:bg-gray-100:hover{ background:#2a3050; }

/* Opacity-modifier utilities are separate generated classes (.bg-slate-50\/70
   is not .bg-slate-50) — each one actually used in markup needs its own rule,
   or the surface stays light while text on it turns light (upstream's own
   note: "made the roles card on Membros unreadable"). */
html.dark .bg-slate-50\/60, html.dark .bg-slate-50\/70{ background:var(--surface-raised); }
html.dark .hover\:bg-slate-50\/60:hover, html.dark .hover\:bg-slate-50\/50:hover{ background:#2a3050; }
html.dark .bg-primary-50\/50{ background:rgba(107,124,255,.10); }
html.dark .bg-amber-50\/40, html.dark .bg-amber-50\/70{ background:rgba(251,191,36,.14); }
html.dark .bg-emerald-50\/60{ background:rgba(52,211,153,.14); }
html.dark .bg-rose-50\/40{ background:rgba(251,113,133,.14); }
html.dark .bg-white\/70, html.dark .bg-white\/50{ background:#232840; }
html.dark .bg-slate-50\/40{ background:#181c29; }

html.dark .text-slate-900, html.dark .text-gray-900{ color:var(--text-strong); }
html.dark .text-slate-800, html.dark .text-gray-800{ color:var(--text-strong); }
html.dark .text-slate-700, html.dark .text-gray-700{ color:var(--text-body); }
html.dark .text-slate-600, html.dark .text-gray-600{ color:var(--text-muted); }
html.dark .text-slate-500, html.dark .text-gray-500{ color:var(--text-muted); }
html.dark .text-slate-400, html.dark .text-gray-400{ color:var(--text-subtle); }

html.dark .text-primary, html.dark .text-primary-600, html.dark .text-primary-700, html.dark .text-primary\/70{ color:#8aa3ff; }
html.dark .text-primary-dark{ color:#b9c8ff; }
html.dark .text-accent-dark{ color:#5eeeec; }
html.dark .text-teal-700{ color:#5eead4; }
html.dark .hover\:text-primary:hover{ color:#8aa3ff; }
html.dark .group:hover .group-hover\:text-primary{ color:#8aa3ff; }
html.dark .hover\:border-primary:hover{ border-color:#6b7cff; }
html.dark .text-indigo-600{ color:#a5b4fc; }
html.dark .text-blue-600, html.dark .text-blue-700{ color:#93c5fd; }
html.dark .text-primary\/50, html.dark .text-primary\/40{ color:#8aa3ff; }

html.dark .border-slate-50, html.dark .border-gray-50{ border-color:var(--border-subtle); }
html.dark .border-slate-100, html.dark .border-gray-100{ border-color:var(--border-subtle); }
html.dark .border-slate-200, html.dark .border-slate-200\/60, html.dark .border-gray-200{ border-color:var(--border-strong); }
html.dark .border-slate-300, html.dark .border-gray-300{ border-color:var(--border-strong); }
html.dark .divide-slate-100 > :not([hidden]) ~ :not([hidden]){ border-color:var(--border-subtle); }
html.dark .divide-slate-200 > :not([hidden]) ~ :not([hidden]){ border-color:var(--border-strong); }

html.dark .bg-red-50{ background:rgba(221,52,76,.14); }
html.dark .bg-red-100{ background:rgba(221,52,76,.20); }
html.dark .border-red-100{ border-color:rgba(221,52,76,.30); }
html.dark .border-red-200, html.dark .border-red-300{ border-color:rgba(221,52,76,.42); }
html.dark .text-red-800, html.dark .text-red-700, html.dark .text-red-600, html.dark .text-red-500, html.dark .text-red-700\/80{ color:#fca5a5; }

html.dark .bg-amber-50{ background:rgba(251,191,36,.14); }
html.dark .bg-amber-100{ background:rgba(251,191,36,.20); }
html.dark .border-amber-100{ border-color:rgba(251,191,36,.30); }
html.dark .border-amber-200, html.dark .border-amber-300{ border-color:rgba(251,191,36,.42); }
html.dark .text-amber-800, html.dark .text-amber-700, html.dark .text-amber-600, html.dark .text-amber-700\/80, html.dark .text-amber-700\/90{ color:#fcd34d; }

html.dark .bg-rose-50{ background:rgba(251,113,133,.14); }
html.dark .bg-rose-100{ background:rgba(251,113,133,.20); }
html.dark .border-rose-200, html.dark .border-rose-300{ border-color:rgba(251,113,133,.42); }
html.dark .text-rose-800, html.dark .text-rose-700, html.dark .text-rose-600{ color:#fda4af; }

html.dark .bg-emerald-50{ background:rgba(52,211,153,.14); }
html.dark .bg-emerald-100{ background:rgba(52,211,153,.20); }
html.dark .border-emerald-100{ border-color:rgba(52,211,153,.30); }
html.dark .border-emerald-200{ border-color:rgba(52,211,153,.42); }
html.dark .text-emerald-800, html.dark .text-emerald-700, html.dark .text-emerald-600{ color:#6ee7b7; }

html.dark .bg-sky-50{ background:rgba(56,189,248,.14); }
html.dark .bg-sky-100{ background:rgba(56,189,248,.20); }
html.dark .border-sky-100{ border-color:rgba(56,189,248,.30); }
html.dark .border-sky-200{ border-color:rgba(56,189,248,.42); }
html.dark .text-sky-800, html.dark .text-sky-700, html.dark .text-sky-600, html.dark .text-sky-700\/80, html.dark .text-sky-600\/80{ color:#7dd3fc; }

html.dark .bg-indigo-100{ background:rgba(107,124,255,.20); }
html.dark .bg-violet-50{ background:rgba(167,139,250,.14); }
html.dark .bg-violet-100{ background:rgba(167,139,250,.20); }
html.dark .border-violet-200, html.dark .border-violet-300, html.dark .border-violet-500{ border-color:rgba(167,139,250,.42); }
html.dark .text-violet-900, html.dark .text-violet-800, html.dark .text-violet-700, html.dark .text-violet-600{ color:#c4b5fd; }

html.dark .bg-orange-50{ background:rgba(237,113,0,.14); }
html.dark .text-orange-700, html.dark .text-orange-600{ color:#fdba74; }

html.dark .admin-stat-card, html.dark .project-card{ background:var(--surface-card); border-color:var(--border-strong); }
html.dark .admin-table th{ color:var(--text-muted); border-bottom-color:var(--border-strong); }
html.dark .admin-table td{ color:var(--text-body); border-bottom-color:var(--border-subtle); }
html.dark .admin-table tbody tr:hover{ background:var(--surface-raised); }
html.dark .status-badge.deleting{ background:var(--surface-raised); color:var(--text-muted); }
html.dark .form-group label, html.dark .field label{ color:var(--text-body); }
html.dark .field .hint{ color:var(--text-subtle); }
html.dark input, html.dark textarea, html.dark select{ background:var(--surface-card); color:var(--text-strong); border-color:var(--border-input); }
html.dark ::placeholder{ color:var(--text-subtle); }
/* the native date/time picker glyph is a dark browser-drawn icon, invisible on
   a dark input — invert it instead of hiding it. */
html.dark input[type="date"]::-webkit-calendar-picker-indicator,
html.dark input[type="time"]::-webkit-calendar-picker-indicator,
html.dark input[type="datetime-local"]::-webkit-calendar-picker-indicator{ filter:invert(1) brightness(1.7); }
html.dark ::-webkit-scrollbar-track{ background:var(--surface-card); }
html.dark ::-webkit-scrollbar-thumb{ background:var(--border-input); }
/* selection uses --text-strong, not --text-inverse: --text-inverse flips to a
   near-black in dark mode (text drawn on a solid --action/--accent fill), which
   would read as invisible-on-invisible against a translucent selection tint. */
html.dark ::selection{ background:rgba(107,124,255,.35); color:var(--text-strong); }
html.dark ::-moz-selection{ background:rgba(107,124,255,.35); color:var(--text-strong); }

html.dark .bg-primary-light{ background:rgba(107,124,255,.14); }
html.dark .bg-accent-light{ background:rgba(255,90,96,.14); }

html.dark .badge-green{ background:rgba(34,197,94,.16); color:#6ee7a0; }
html.dark .badge-amber{ background:rgba(251,191,36,.16); color:#fcd34d; }
html.dark .badge-slate{ background:var(--surface-raised); color:var(--text-muted); }
html.dark .badge-blue{ background:rgba(107,124,255,.16); color:#8aa3ff; }

html.dark .border-primary-100, html.dark .border-primary-200{ border-color:rgba(107,124,255,.35); }

/* SVG uses fill, not color. */
html.dark .fill-slate-900{ fill:var(--text-strong); }
html.dark .fill-slate-400{ fill:var(--text-subtle); }

/* generic shadow/ring utilities — Tailwind's default palette shadow reads as
   a light-grey smudge on a dark canvas; ring-color similarly. */
html.dark .shadow, html.dark .shadow-sm{ box-shadow:0 1px 3px rgba(0,0,0,.45)!important; }
html.dark .shadow-md{ box-shadow:0 4px 10px rgba(0,0,0,.45)!important; }
html.dark .shadow-lg, html.dark .shadow-xl{ box-shadow:0 14px 34px rgba(0,0,0,.50)!important; }
html.dark .ring-slate-200, html.dark .ring-slate-300, html.dark .ring-gray-200, html.dark .ring-gray-300{ --tw-ring-color:var(--border-strong); }
html.dark .ring-primary{ --tw-ring-color:var(--action); }

/* Escape hatch (`.theme-light`) for a subtree that must render on paper
   regardless of the page's theme — e.g. an embedded doc/report that isn't
   itself themeable. Deliberately keeps LITERAL light values, not tokens. */
html.dark .theme-light{ background:#ffffff; color:#334155; }
html.dark .theme-light .bg-white{ background:#ffffff; }
html.dark .theme-light .bg-slate-50, html.dark .theme-light .bg-slate-100{ background:#f1f5f9; }
html.dark .theme-light .border-slate-100, html.dark .theme-light .border-slate-200{ border-color:#e2e8f0; }
html.dark .theme-light .text-slate-900{ color:#0f172a; }
html.dark .theme-light .text-slate-800{ color:#1e293b; }
html.dark .theme-light .text-slate-700{ color:#334155; }
html.dark .theme-light .text-slate-600{ color:#475569; }
html.dark .theme-light .text-slate-500, html.dark .theme-light .text-slate-400{ color:#64748b; }
html.dark .theme-light .text-primary{ color:#1f35c7; }

/* doc-render — a rendered-markdown/HTML panel that stays on paper by design
   even when the surrounding shell goes dark (same reasoning as .theme-light). */
html.dark .doc-render .bg-white{ background:#ffffff; }
html.dark .doc-render .border-slate-200{ border-color:#e2e8f0; }
html.dark .doc-render .bg-slate-100{ background:#eef2f9; }
html.dark .doc-render .bg-slate-200{ background:#e2e8f0; }

/* Redoc (API reference) paints its own DOM via emotion — no Tailwind override
   reaches it, its colours come from the theme object passed to Redoc.init.
   These cover only the chrome Redoc hardcodes regardless of its theme (menu,
   search) and deliberately don't touch text colour, or they'd flatten the
   HTTP-verb / schema colour coding the theme object gets right. */
html.dark #redoc, html.dark #redoc .redoc-wrap, html.dark #redoc .api-content{ background:var(--surface-card); }
html.dark #redoc .menu-content{ background:var(--surface-soft); border-right:1px solid var(--border-strong); }
html.dark #redoc .menu-content label, html.dark #redoc .menu-content input{ background:var(--surface-card); color:var(--text-strong); border-color:var(--border-input); }
html.dark #redoc .menu-content svg{ fill:var(--text-muted); }
html.dark #redoc table th, html.dark #redoc table td{ background:transparent; }

html.theme-anim *{ transition:background-color .25s ease,border-color .25s ease,color .25s ease!important; }
