/* ============================================================
   ZED — "Graphite & Ember"
   A warm, calm reskin of the Untitled UI system.
   Warm paper surfaces · ink text · dark graphite chrome ·
   a single ember signal color · mono metadata.
   ============================================================ */

:root {
  /* ---------- EMBER (brand / signal) ---------- */
  --ember-25:  #FEF8F5;
  --ember-50:  #FCF1EC;
  /* OPAQUE twin of --ember-50 (the selected-row background). Used as the cutout
     ring around an avatar's presence dot on a selected row — --ember-50 itself
     is translucent in the dark sidebar, so a ring made from it lets the green
     dot bleed through ("full green" blob); this stays solid so the dot reads as
     a clean, separated indicator (Slack-style). */
  --ember-50-solid: #FCF1EC;
  --ember-100: #F8DDD1;
  --ember-200: #F0BBA4;
  --ember-300: #E69274;
  --ember-400: #D96E48;
  --ember-500: #C75233;   /* primary action */
  --ember-600: #AB4127;
  --ember-700: #8A331F;
  --ember-800: #6B281A;
  --ember-900: #4F1F15;

  /* FIXED action-button fill — BLUE, and theme-INdependent, the same stance as
     --link-fg, --data-fill, --saved- and --chip-. It was ember until
     2026-08-05; primary actions are blue now so every affordance in the app
     speaks with one voice. theme.ts remaps the whole --ember- ramp to the
     accent theme, and a gray/graphite accent turned a primary button into
     "looks disabled" (gray fill + white text) — theme.ts must never remap
     these either.

     LITERAL HEX, NOT var(--blue-600) — deliberately. This is a FILL under WHITE
     text, and theme.ts lifts --blue-600 to #3B8BE2 for dark mode, where white
     text scores 3.5:1 and fails. The fixed value below is 5.5:1 against white
     in both modes, and 3.2:1 against the dark canvas (a large filled shape, so
     3:1 is the bar it has to clear).

     NOTE: never write a "star-slash" glob (--saved-<star><slash>) in a CSS
     comment — it CLOSES the comment. That bug silently ate the --btn-pri
     declaration below for four days; see the 2026-08-05 changelog entry. */
  --btn-pri: #1E68C2;
  --btn-pri-hover: #1A50A0;

  /* THE BRAND COLOUR — the logo's orange (brand/brand.cjs), for the screens
     that ARE the brand: sign-in, register, forgot/reset, invite, download,
     the legal pages (Damir, 2026-10-02). FIXED and theme-independent like
     --btn-pri above, and for the same reason: nobody has a theme before they
     sign in, and theme.ts must never remap these.

     ⚠️ INSIDE THE APP, primary actions and links stay BLUE (--btn-pri,
     --link-fg). These are for the signed-out screens only.

     ⚠️ TWO SHADES ON PURPOSE. --brand is a FILL under white text at 14.5px
     semibold: 3.5:1 — below the 4.5:1 body-text bar, taken knowingly so the
     button is the logo's own colour. A text LINK in that colour on the paper
     canvas is 3.1:1 and reads thin, so links take --brand-link, the same hue
     a step darker (4.2:1 on paper, 4.7:1 on white). */
  --brand: #FF4000;
  --brand-hover: #E63900;
  --brand-link: #D93600;
  --brand-link-hover: #B82E00;

  /* Map brand-* tokens onto ember so kit components inherit it */
  --brand-25: var(--ember-25);   --brand-50: var(--ember-50);
  --brand-100: var(--ember-100); --brand-200: var(--ember-200);
  --brand-300: var(--ember-300); --brand-400: var(--ember-400);
  --brand-500: var(--ember-500); --brand-600: var(--ember-500);
  --brand-700: var(--ember-600); --brand-800: var(--ember-700);
  --brand-900: var(--ember-800); --brand-950: var(--ember-900);

  /* ---------- WARM PAPER NEUTRALS ---------- */
  /* The two BACKGROUND steps are one neutral near-white since 2026-10-02
     (Damir: every beige background is #FAFAFA — web, desktop, phone). They
     were #FBFAF6 / #F6F3ED. 100–300 are fills and borders drawn ON a
     background and keep the warm ramp, or a hover and a hairline would
     disappear into it. Mobile's copy: mobile/src/design/tokens.ts. */
  --paper-0:   #FFFFFF;
  --paper-25:  #FAFAFA;
  --paper-50:  #FAFAFA;
  --paper-100: #EFEBE2;
  --paper-200: #E4DED2;
  --paper-300: #D4CCBC;
  --ink-950:   #16140F;
  --ink-900:   #211E18;
  --ink-800:   #322E26;
  --ink-700:   #4A453B;
  --ink-600:   #635D50;
  --ink-500:   #807868;
  --ink-400:   #9C9384;
  --ink-300:   #BCB3A2;

  /* Gray-* tokens remapped to warm neutrals for kit components */
  --gray-25: var(--paper-25);   --gray-50: var(--paper-50);
  --gray-100: var(--paper-100); --gray-200: var(--paper-200);
  --gray-300: var(--paper-300); --gray-400: var(--ink-400);
  --gray-500: var(--ink-500);   --gray-600: var(--ink-600);
  --gray-700: var(--ink-700);   --gray-800: var(--ink-800);
  --gray-900: var(--ink-900);   --gray-950: var(--ink-950);

  /* ---------- GRAPHITE (dark chrome rails) ---------- */
  --graphite-900: #1B1814;
  --graphite-850: #221F1A;
  --graphite-800: #2A2620;
  --graphite-700: #353029;
  --graphite-600: #443E35;
  --graphite-500: #5A5347;
  /* ---------- TEXT ON CALL CHROME ----------
     A huddle's surfaces — the incoming-call modal, the call window, its round
     controls — are drawn on the FIXED `--graphite-*` scale, which no theme
     touches. Their text must be fixed too.

     ⚠️ THEY USED `--on-graphite*` AND THAT IS A DIFFERENT QUESTION (Damir,
     2026-09-21: "vidis kako su odvratna ova ljubicasta slova i ikonice ne vide
     se zbog teme"). `--on-graphite*` is text on the THEMED chrome — the rail
     and the sidebar headers — so `lib/theme` rewrites it from the theme's
     `content-inv-*` ramp and it even goes DARK in light mode, because it
     follows the sidebar's own colour. Read on a near-black modal that never
     changes, a purple theme turned the caller's name purple on black and the
     Decline label vanished entirely.

     The values are exactly what `--on-graphite*` is at `:root`, which is why
     the default theme always looked right and only a custom one broke.

     ⚠️ MUST STAY OUT OF `lib/theme`'s runtime `set()` list — that is the whole
     point, and `lib/designTokens/designTokens.test.ts` asserts it. An inline
     custom property on `:root` beats any stylesheet rule, so a token the theme
     engine writes could never be pinned from here.

     Not `--on-window*`: that family is right in spirit (a surface dark in every
     theme) but it exists ONLY when the theme engine has run — it has no `:root`
     default, so a fresh app would render call text as nothing at all. */
  --on-call:            #EFEAE0;
  --on-call-muted:      #A89F8F;
  --on-call-faint:      #756E61;

  --on-graphite:        #EFEAE0;
  --on-graphite-muted:  #A89F8F;
  --on-graphite-faint:  #756E61;

  /* Tooltip / shortcut popover surface. LIGHT-mode default: a floating white
     card with a crisp light edge and dark text — same family as menus/popovers,
     so it doesn't read as a dark blob on the light feed. Dark mode remaps these
     to an elevated neutral grey with light text (see theme.ts). --tooltip-fg is
     the text/caret-fill colour, flipped per mode alongside the bg. */
  --tooltip-bg: #ffffff;
  --tooltip-border: var(--border-secondary);
  --tooltip-fg: var(--ink-800);

  /* ---------- THEMEABLE NAV / ACCENT (overridden at runtime by theme.js) ---------- */
  --nav-bg: #1B1814;          /* workspace rail · top bar */
  --nav-bg-soft: #221F1A;     /* nav rail · sidebar widgets · container */
  --nav-border: #5A5347;      /* container + rail dividers */
  --nav-accent: #C75233;      /* selected-item accent on nav */
  --nav-accent-soft: rgba(199,82,51,0.16);
  --notif: #C75233;           /* notification / unread badges */
  --sidebar-bg: var(--paper-50);  /* channel sidebar — subtly theme-tinted */
  --sidebar-solid: var(--paper-50);  /* flat sidebar color — for avatar presence rings (never a gradient) */

  /* ---------- SEMANTIC ---------- */
  --success-25:#F4FBF6; --success-50:#E8F6ED; --success-100:#CDEBD8; --success-200:#A6DDBA;
  --success-300:#7CCF9C; --success-400:#46B877; --success-500:#2E9E5B;
  --success-600:#218049; --success-700:#1A6139;
  --warning-25:#FFFCF5; --warning-50:#FFF7E8; --warning-100:#FCE9C0; --warning-200:#F8DA94;
  --warning-300:#F3CB6E; --warning-400:#EDB13A; --warning-500:#E0921B;
  --warning-600:#BC7212; --warning-700:#915710;
  --error-25:#FFF8F7; --error-50:#FDEEEC; --error-100:#FAD6D2; --error-200:#F5B0A8;
  --error-300:#EF9B92; --error-400:#E56A5D; --error-500:#D6422F;
  --error-600:#B62F20; --error-700:#8F271B;
  --blue-50:#EEF5FC; --blue-100:#D2E6F8; --blue-300:#84BAEF;
  --blue-500:#2E84E0; --blue-600:#1E68C2; --blue-700:#1A50A0;

  /* Saved-for-later message highlight — FIXED blue, deliberately independent
     of the selected theme/accent (Slack-style). Light defaults here; dark mode
     remaps them in theme.ts (bg #1C2A33 / fg #1D9BD1). */
  --saved-bg: #E9F5FA;
  --saved-fg: #1364A3;

  /* Search filter chips (the `in:` scope + typed tokens in the search field) —
     FIXED blue, deliberately independent of the selected accent theme, the same
     stance as --saved-* above and for the same reason: a chip reads as a piece
     of query SYNTAX, not as branding, and Slack keeps it blue whatever the
     sidebar colour is. Light defaults here; theme.ts remaps them for dark. */
  --chip-bg: #E4EFFB;
  --chip-border: #B7D5F4;
  --chip-fg: #1A50A0;

  /* TEXT LINKS — "Show N earlier replies", "Forgot password?", a system
     message's inline action, an in-copy "Use an avatar instead". FIXED blue,
     deliberately independent of the accent theme, same stance as --saved-* and
     --chip-* above: a link is an affordance, not branding, and Slack keeps
     links blue whatever the sidebar colour is. These used to draw from
     --fg-brand / --ember-* / --nav-accent, all of which theme.ts remaps per
     accent — so a gray theme rendered every link gray-on-gray, i.e. as plain
     dead text. NO dark-mode remap is needed here (and none must be added):
     --blue-600/700 are themselves mode-aware semantic tokens that theme.ts
     lifts to bright hues for dark, and the indirection resolves at use time.
     Reserve these for LINKS — a decorative brand icon or a selected/checked
     state still follows the theme (see the --btn-pri note above). */
  --link-fg: var(--blue-600);
  --link-fg-hover: var(--blue-700);

  /* DATA MARKS — anything that ENCODES A VALUE: the admin dashboard's chart
     bars and its legend swatch, the top-senders share bars. FIXED blue for the
     same reason as the tokens above: a bar is a measurement, not branding, and
     these were drawn from --ember-*, which theme.ts remaps per accent — so a
     gray theme rendered every bar and progress fill in gray, i.e. as disabled
     chrome rather than data. -soft is the "latest bucket" highlight, -strong
     the hovered/emphasised one; the ordering works in BOTH modes because
     theme.ts lifts --blue-600 above --blue-500 for dark and leaves it below in
     light. Text/icon EMPHASIS (rank numbers, activity-feed badges) is not a
     data mark and still follows the theme. */
  --data-fill: var(--blue-500);
  --data-fill-strong: var(--blue-600);
  --data-fill-soft: var(--blue-300);

  /* The data blue when the mark has to sit UNDER WHITE TEXT — today the upload
     bar's pill, whose percentage is written inside it.

     A LITERAL HEX, for exactly the reason --btn-pri is one: neither of the
     tokens above can carry white text in both modes. theme.ts lifts
     --blue-600 to #3B8BE2 for dark, where white scores 3.5:1 and fails, and
     --data-fill (--blue-500, #2E84E0) is 3.8:1 in EITHER mode — it was never
     meant to have text on it, only to be looked at. This value is 5.5:1
     against white in both modes. Never remap it. */
  --data-fill-deep: #1E68C2;

  /* presence */
  --presence-online: var(--success-500);
  --presence-away:   var(--warning-500);
  --presence-dnd:    var(--error-500);
  --presence-offline:var(--ink-300);
  /* outline for the hollow offline dot — constant gray, legible on any theme */
  --presence-offline-ring:#9BA3AC;

  /* ---------- SEMANTIC ROLE TOKENS ---------- */
  --fg-primary:    var(--ink-900);
  --fg-secondary:  var(--ink-700);
  --fg-tertiary:   var(--ink-500);
  --fg-quaternary: var(--ink-400);

  /* ---------- A MESSAGE'S THREE TEXTS ----------
     The sender's name, the body and the timestamp beside the name. Here they
     are the ink steps a message always used, so light mode is unchanged.
     The composer's editor types in `--msg-body` too: a draft is a body.

     In DARK mode `lib/theme` sets them to Slack's own three (Damir,
     2026-10-02, a message in each app side by side: "jel tako da nisu
     iste?"): the body was #F2F4F7 — brighter and cooler than Slack's
     #D1D2D3, and the SAME tone as the name, so a message had no hierarchy —
     and the timestamp #838A94 against Slack's #ABABAD. Slack's name is the
     one bright thing in the row (#F8F8F8).

     Their own tokens rather than a new dark ink ramp: `--ink-900` is every
     heading, label and field in the app, and only a message was measured.

     The two `.sidebar-scope` blocks below re-declare them, because a custom
     property's `var()` is resolved where it is DECLARED: left to this one, a
     message drawn inside the sidebar would take the content's ink, not the
     chrome's. */
  --msg-name:      var(--ink-900);
  --msg-body:      var(--fg-primary);
  --msg-meta:      var(--fg-tertiary);
  --fg-disabled:   var(--ink-300);
  --fg-placeholder:var(--ink-400);
  --fg-on-brand:   #FFFFFF;
  --fg-brand:      var(--ember-600);
  --fg-error:      var(--error-600);
  --fg-success:    var(--success-600);
  --fg-warning:    var(--warning-600);

  --bg-primary:     var(--paper-0);
  --bg-secondary:   var(--paper-50);
  --bg-tertiary:    var(--paper-100);
  --bg-quaternary:  var(--paper-200);
  --bg-active:      var(--ember-50);
  --bg-disabled:    var(--paper-100);
  --bg-overlay:     rgba(22,20,15,0.55);
  --bg-brand:       var(--ember-500);
  --bg-brand-subtle:var(--ember-50);
  --bg-canvas:      var(--paper-50);

  --border-primary:   var(--paper-300);
  --border-secondary: var(--paper-200);
  --border-tertiary:  var(--paper-100);
  --border-disabled:  var(--paper-200);
  --border-brand:     var(--ember-300);
  --border-error:     var(--error-300);

  /* ---------- TYPE ---------- */
  --font-sans: 'Lato', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-display: 'Lato', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-text: 'Lato', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  /* NOT actually monospace — `--font-mono` / the `.mono` class mark METADATA
     (timestamps, counts, ids, captions), which this app sets in the same face
     as everything else, with the tighter tracking the class adds. Renamed
     nothing on purpose — 185 call sites use `--font-mono`/`.mono` as
     "metadata type", which is still exactly what it means.

     The face is LATO, everywhere, and the files ship with the bundle:
     src/fonts/appFont.css repeats these four stacks under `html:root` so a
     stale copy of this file cannot name a font the bundle does not carry. */
  --font-mono: 'Lato', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --fw-regular:400; --fw-medium:500; --fw-semibold:600; --fw-bold:700;

  --text-display-2xl-size:72px; --text-display-2xl-line:90px;
  --text-display-xl-size:60px;  --text-display-xl-line:72px;
  --text-display-lg-size:48px;  --text-display-lg-line:60px;
  --text-display-md-size:36px;  --text-display-md-line:44px;
  --text-display-sm-size:30px;  --text-display-sm-line:38px;
  --text-display-xs-size:24px;  --text-display-xs-line:32px;
  --text-xl-size:20px; --text-xl-line:30px;
  --text-lg-size:18px; --text-lg-line:28px;
  --text-md-size:16px; --text-md-line:24px;
  --text-sm-size:14px; --text-sm-line:20px;
  --text-xs-size:12px; --text-xs-line:18px;

  /* ---------- SPACING ---------- */
  --space-0:0; --space-0_5:2px; --space-1:4px; --space-1_5:6px; --space-2:8px;
  --space-3:12px; --space-4:16px; --space-5:20px; --space-6:24px; --space-8:32px;
  --space-10:40px; --space-12:48px; --space-16:64px; --space-20:80px;
  --space-24:96px; --space-32:128px;

  /* ---------- RADIUS ---------- */
  --radius-none:0; --radius-xxs:2px; --radius-xs:4px; --radius-sm:6px;
  --radius-md:8px; --radius-lg:10px; --radius-xl:12px; --radius-2xl:16px;
  --radius-3xl:20px; --radius-4xl:24px; --radius-full:9999px;

  /* ---------- SHADOWS (warm-tinted, restrained) ---------- */
  /* The top bar's SEARCH FIELD. Its own pair because the top bar is window
     chrome — dark in every theme (`--on-window` in theme.ts says so), so the
     field is a pale wash on a dark strip and neither the content nor the
     sidebar border tokens describe it.

     ⚠️ DEFAULT = the line, and `[data-mode="light"]` below swaps it for a
     shadow (Damir, 2026-09-18). Dark mode keeps the line: a black shadow on
     dark chrome draws nothing, which is the same reason the shell's panes use
     a line there.

     ⚠️ THE BORDER GOES `transparent`, IT IS NEVER DROPPED — a 1px border box
     still occupies its pixel, so the field does not resize by 2px when the
     surface flips. Same rule as `--pane-divider`. */
  --topbar-field-border: rgba(255,255,255,0.10);
  --topbar-field-shadow: none;

  --shadow-xs: 0 1px 2px 0 rgba(33,30,24,0.05);
  --shadow-sm: 0 1px 3px 0 rgba(33,30,24,0.10), 0 1px 2px 0 rgba(33,30,24,0.06);
  --shadow-md: 0 4px 8px -2px rgba(33,30,24,0.10), 0 2px 4px -2px rgba(33,30,24,0.06);
  --shadow-lg: 0 12px 16px -4px rgba(33,30,24,0.10), 0 4px 6px -2px rgba(33,30,24,0.04);
  --shadow-xl: 0 20px 24px -4px rgba(33,30,24,0.12), 0 8px 8px -4px rgba(33,30,24,0.04);
  --shadow-2xl:0 24px 48px -12px rgba(33,30,24,0.22);
  --shadow-3xl:0 32px 64px -12px rgba(33,30,24,0.18);
  /* Derive from the accent (--ember-500 is remapped per theme) so the focus
     glow matches the active theme instead of being hardcoded ember-orange. */
  --focus-ring: 0 0 0 4px color-mix(in srgb, var(--ember-500) 22%, transparent);
  --focus-ring-error: 0 0 0 4px rgba(214,66,47,0.22);
  --inset-skeu: inset 0 -2px 0 rgba(33,30,24,0.10), inset 0 1px 0 rgba(255,255,255,0.18);

  /* ---------- MOTION ---------- */
  --ease-out: cubic-bezier(0.16,1,0.3,1);
  --ease-in-out: cubic-bezier(0.4,0,0.2,1);
  --dur-fast:90ms; --dur-base:120ms; --dur-slow:180ms;
}

* { box-sizing: border-box; }

/* When the workspace rail is hidden (unified rail), the channel sidebar sits
   flush against the rounded container's left edge — drop its own left border so
   it doesn't double up with the container border. */
.flush-rail > div:first-child .sidebar-scope { border-left: none !important; }

/* ---------- SHELL PANE SEPARATION ----------
   How the window frame and the COMPACT shell's sidebar are told apart from what
   is beside them: a LINE on dark chrome, where a shadow reads as nothing, and a
   SHADOW on a light one. Slack's own split, and Damir's (2026-09-16): "slack na
   light temi nema bordere te".

   ⚠️ A LEFT PANE HAS TWO SEAMS AND THEY ARE NOT THE SAME (Damir, 2026-09-18).
   Rail side: a plain `--border-secondary` LINE in every theme, drawn by each
   pane itself — "umjesto ovog shadowa … dodaj border koji je isti kao na DMs".
   The `--pane-divider` / `--pane-shadow-right` pair no longer serves it; what
   still reads that pair is the window FRAME and the COMPACT shell
   (`CompactShellBody`), a drawer over the content rather than a column beside
   it. Content side: the `--pane-cast-divider` / `--pane-cast-right` pair below,
   which is the same three-case rule as everything else here — ramp on a light
   surface, LINE on a dark one.

   ⚠️ THAT SECOND PAIR IS WHY THE DARK SHELL LOST ITS RIGHT BORDER ONCE ALREADY.
   Its first cut (3a2e7d6 → 28bb0d4) declared one `--pane-cast-right` value on
   `:root` for every mode and DROPPED the `borderRight` from all five panes, so
   dark mode was left with a black inset ramp on near-black chrome — which draws
   nothing — and no line to fall back to (Damir, 2026-09-18: "radili smo
   promjene na light mode-u a ti si maknuo border s dark moda"). A token that
   replaces a line on light surfaces belongs in THESE blocks, never on `:root`,
   and its use site keeps the line as the fallback. The guard in
   `lib/designTokens/designTokens.test.ts` now counts both halves.

   Sampled off the light theme in his screenshot rather than guessed — no 1px
   line anywhere, and each pane's left neighbour darkens ~4% of black over
   ~14px toward the seam. `inset` puts that ramp on OUR sidebar, the element we
   own; the routed content beside it is a different component on every page.

   ⚠️ DECLARED HERE AND NOWHERE ELSE, AND EVERY USE SITE CARRIES ITS OWN DARK
   VALUE AS A `var()` FALLBACK — `var(--pane-divider, var(--border-secondary))`.
   The first cut declared these on `:root` as `var(--border-secondary)`, and a
   custom property's `var()` is substituted where the property is DECLARED: the
   sidebar's divider stopped reading the chrome border that
   `[data-sb-theme="dark"] .sidebar-scope` defines below and picked up the
   CONTENT one from `:root` instead — which `lib/theme` remaps per theme
   (MODE_KEYS), so every custom theme painted the shell's borders in its own
   colour (Damir: "sada su borderi u boji ovisnosti o custom temi"). A fallback
   at the use site resolves in the element's own scope, which is the whole
   point.

   ⚠️ THE BORDER GOES `transparent`, IT IS NEVER DROPPED. A 1px border box still
   occupies its pixel, so nothing shifts by 2px when the surface flips.

   ⚠️ Keyed on `data-sb-theme` — the SIDEBAR's own composited luminance — and,
   for a dark sidebar, on `data-mode` too. Three cases, each Slack's:
     - light sidebar (light mode): no line, a soft shadow (block below);
     - DARK sidebar in LIGHT mode ("Darker sidebars"): no line, and the SAME
       shadow ramp as a light sidebar, a little deeper — 5% black on dark
       chrome draws nothing. Without any shadow the sidebar and the rail beside
       it melted into one purple slab; at 18% it read as a heavy gutter (Damir,
       2026-09-17, both ways). 7% is his setting;
     - dark mode: the fallback line at each use site, as before — there chrome
       and content are both dark and the line does the work.

   ⚠️ These names must stay OUT of theme.ts's runtime `set()` list: an inline
   custom property on :root beats any stylesheet rule. */
/* Light mode drops the search field's outline for a soft lift instead — see
   --topbar-field-* above. Keyed on the MODE, not on the sidebar's surface: the
   top bar is window chrome and does not follow the sidebar. */
[data-mode="light"] {
  --topbar-field-border: transparent;
  --topbar-field-shadow: 0 1px 2px rgba(0,0,0,0.20), 0 3px 8px -3px rgba(0,0,0,0.18);
}

/* ---------- THE ADMIN CONSOLE'S FILLS ARE NEUTRAL (light mode) ----------
   Damir, 2026-10-02, three screenshots of the console: a documentation
   table's header, the selected page in a list, a channel's icon tile — "ova
   bez/zlatna boja… pretvori je u #FAFAFA". Those are the warm fill steps,
   --paper-100 (#EFEBE2) and --paper-200 (#E4DED2), on the console's white
   page. In the console they are #FAFAFA.

   ⚠️ ON THE ROOT, NOT ON THE CONSOLE'S <main>. The console's modals and
   popovers are portalled to <body>, outside any wrapper, and would have kept
   the beige. `AdminConsole` sets `data-admin-console` on <html> while it is
   mounted, and this rule goes with it — so the rest of the app is untouched.

   ⚠️ SO THE BORDERS MUST BE RE-STATED. --border-secondary / -tertiary are
   declared on :root AS var(--paper-200) / var(--paper-100), and a custom
   property's var() resolves where it is declared: left alone they would
   follow these two to #FAFAFA and every card's outline would vanish on a
   white page. They keep the values they had.

   ⚠️ --fill-neutral IS FOR FILLS THAT MUST BE SEEN: a skeleton's bars, a
   progress bar's track. #FAFAFA on white is two units of grey — right for a
   header's quiet tint, and nothing at all for a placeholder whose whole job
   is to show that something is coming. Read as
   `var(--fill-neutral, var(--paper-100))`, so outside this block (dark mode,
   the app itself) those keep their old step. */
[data-mode="light"][data-admin-console] {
  --paper-100: #FAFAFA;
  --paper-200: #FAFAFA;
  --border-secondary: #E4DED2;
  --border-tertiary: #EFEBE2;
  --fill-neutral: #F0F0F0;
}

[data-sb-theme="light"] {
  --window-frame-border: transparent;
  --window-frame-shadow: 0 1px 2px rgba(33,30,24,0.06), 0 6px 16px -6px rgba(33,30,24,0.16);
  --pane-divider: transparent;
  --pane-shadow-right: inset -8px 0 8px -4px rgba(33,30,24,0.05);
  --pane-cast-divider: transparent;
  --pane-cast-right: inset -10px 0 12px -8px rgba(33,30,24,0.20);
}

/* "Darker sidebars" in light mode — see SHELL PANE SEPARATION above. */
[data-mode="light"][data-sb-theme="dark"] {
  --window-frame-border: transparent;
  --window-frame-shadow: 0 1px 2px rgba(0,0,0,0.06), 0 6px 16px -6px rgba(0,0,0,0.14);
  --pane-divider: transparent;
  --pane-shadow-right: inset -8px 0 8px -4px rgba(0,0,0,0.07);
  --pane-cast-divider: transparent;
  /* ⚠️ The SAME warm value as a light sidebar above, not this block's usual
     pure black: both surfaces were painted by one `:root` declaration until
     2026-09-18, so splitting it in two is meant to change WHERE the ramp
     applies, never how either light surface looks. */
  --pane-cast-right: inset -10px 0 12px -8px rgba(33,30,24,0.20);
}

/* When the channel sidebar is dark (Darker sidebars on, or dark colour mode),
   re-map the neutral tokens *locally inside the sidebar* so text/controls
   read as light-on-dark. Reactive: the theme engine sets data-sb-theme. */
[data-sb-theme="dark"] .sidebar-scope {
  /* ⚠️ THE TEXT IS THE THEME'S, NOT WHITE (Damir, 2026-10-02, our sidebar
     beside Slack's on Aubergine: "boja slova nije ista kao na slacku").
     These were white at fixed alphas — a resting row drew #DCDCDE where
     Slack draws #BAAAC2, a lavender. Slack's row text is `content-inv-sec`
     (dark mode: the navigation ramp's step 90 at 0.8 — for Aubergine
     rgba(227,206,235,0.8), which over the sidebar is #BCA9C3, the sampled
     colour within a unit or two) and the strong text `content-inv-pry`. The
     theme engine already writes both, as `--on-graphite*`; the LIGHT sidebar
     scope below has read them all along and this one had not.
       strong (active, unread, headings)  --on-graphite        content-inv-pry
       resting row text                   --on-graphite-muted  content-inv-sec
       glyphs, sub-lines                  --on-graphite-faint  content-inv-ter
     The steps between are the same three at a lower alpha, in the ratios the
     white ladder had (0.74/0.86, 0.52/0.62, 0.5/0.66), so nothing changes
     its place in the hierarchy — only its hue. */
  --ink-950:var(--on-graphite); --ink-900:var(--on-graphite);
  --ink-800:color-mix(in srgb, var(--on-graphite) 92%, transparent);
  --ink-700:var(--on-graphite-muted);
  --ink-600:color-mix(in srgb, var(--on-graphite-muted) 86%, transparent);
  --ink-500:var(--on-graphite-faint);
  --ink-400:color-mix(in srgb, var(--on-graphite-faint) 84%, transparent);
  --fg-primary:var(--on-graphite); --fg-secondary:var(--on-graphite-muted);
  --fg-tertiary:var(--on-graphite-faint);
  --fg-quaternary:color-mix(in srgb, var(--on-graphite-faint) 76%, transparent);
  /* A message drawn on the chrome takes the chrome's text (see `--msg-name`). */
  --msg-name:var(--on-graphite); --msg-body:var(--on-graphite);
  --msg-meta:var(--on-graphite-faint);
  --paper-0:rgba(255,255,255,0.13); --paper-100:rgba(255,255,255,0.10);
  --paper-200:rgba(255,255,255,0.18); --paper-300:rgba(255,255,255,0.26);
  /* selected-row (-25) / hover (-50) washes for list panes on the themed
     sidebar surface (Activity feed, Saved list) */
  --paper-25:rgba(255,255,255,0.10); --paper-50:rgba(255,255,255,0.07);
  /* light-ramp -600 text tones are too dark for the dark sidebar — lift them
     (e.g. the Saved view's green "Due …" reminder label) */
  --success-600:#3FCA84;
  --avatar-ring:var(--sidebar-solid);
  --border-primary:rgba(255,255,255,0.20); --border-secondary:rgba(255,255,255,0.12);
  --border-tertiary:rgba(255,255,255,0.08);
  /* Selection accents route to the theme tokens: Slack's selected row is the
     SOLID base-hgl-1 pill with content-hgl-1 text (verified live), not a wash. */
  --ember-50:var(--nav-accent); --ember-200:var(--nav-accent);
  --ember-500:var(--nav-on-accent); --ember-600:var(--nav-on-accent);
  --ember-50-solid:var(--nav-accent);
  --ember-700:var(--nav-on-accent); --ember-800:var(--nav-on-accent);
  --warning-400:#FAD86B;
  /* Opaque surface for floating hover pills — the translucent --paper-0 above
     would let the row text bleed through. */
  --hover-pill:color-mix(in srgb, #ffffff 10%, var(--sidebar-solid));
  /* Big two-line list rows (DMs page). The SUBTITLE is the name's own ink,
     only lighter in weight — measured on Slack's dark DMs list 2026-10-02
     (name and last message both #F8F8F8); it was 60% white here, which read
     as a dimmed row beside Slack's. The timestamp stays at 55%. */
  --list-sub:var(--on-graphite);
  --list-meta:rgba(255,255,255,0.55);
  /* Toggle ON state: solid accent track + on-accent knob (the ember remaps
     above turn --ember-500 into pale TEXT colour — wrong as a fill). */
  --toggle-on:var(--nav-accent);
  --toggle-knob:var(--nav-on-accent);
}
[data-sb-theme="dark"] .sidebar-scope .zed-field {
  background: rgba(0,0,0,0.24);
  border-color: rgba(255,255,255,0.10);
  box-shadow: none;
}

/* Light sidebar (light colour mode, Darker sidebars off): Slack tints ALL
   sidebar text with the theme's nav family (row text = nav-100 @ 0.8, captured
   live) and still paints the selected row as the solid base-hgl-1 pill. The
   theme engine feeds --on-graphite* / --nav-accent* per theme. */
[data-sb-theme="light"] .sidebar-scope {
  --ink-950:var(--on-graphite); --ink-900:var(--on-graphite);
  --ink-800:color-mix(in srgb, var(--on-graphite) 92%, transparent);
  --ink-700:color-mix(in srgb, var(--on-graphite) 84%, transparent);
  --ink-600:color-mix(in srgb, var(--on-graphite) 72%, transparent);
  --ink-500:color-mix(in srgb, var(--on-graphite) 62%, transparent);
  --ink-400:color-mix(in srgb, var(--on-graphite) 52%, transparent);
  --fg-primary:var(--on-graphite); --fg-secondary:var(--on-graphite-muted);
  --fg-tertiary:var(--on-graphite-faint);
  --fg-quaternary:color-mix(in srgb, var(--on-graphite) 45%, transparent);
  /* A message drawn on the chrome takes the chrome's text (see `--msg-name`). */
  --msg-name:var(--on-graphite); --msg-body:var(--on-graphite);
  --msg-meta:var(--on-graphite-faint);
  /* hover / selected washes, theme-tinted like Slack's alpha overlays */
  --paper-100:color-mix(in srgb, var(--on-graphite) 8%, transparent);
  --paper-50:color-mix(in srgb, var(--on-graphite) 5%, transparent);
  --paper-25:color-mix(in srgb, var(--on-graphite) 7%, transparent);
  --avatar-ring:var(--sidebar-solid);
  --ember-50:var(--nav-accent); --ember-200:var(--nav-accent);
  --ember-500:var(--nav-on-accent); --ember-600:var(--nav-on-accent);
  --ember-50-solid:var(--nav-accent);
  --ember-700:var(--nav-on-accent); --ember-800:var(--nav-on-accent);
  /* Big two-line list rows: Slack light renders the subtitle at FULL ink
     strength (only the weight differs from the name) and timestamps at 0.8. */
  --list-sub:var(--on-graphite);
  --list-meta:var(--on-graphite-muted);
  /* Toggle ON state — see the dark-scope note. */
  --toggle-on:var(--nav-accent);
  --toggle-knob:var(--nav-on-accent);
  /* An empty-state picture's pale top is mixed towards white for a WHITE
     pane; a light sidebar is about that tone itself, so the top dissolved
     into it and only the dark walls were left (the Later list — Damir,
     2026-10-02). Here the top is lifted off the surface it lies on instead,
     and the ground shadow is deepened to be seen on it. */
  --empty-art-top:color-mix(in srgb, #ffffff 82%, var(--sidebar-solid));
  --empty-art-shadow-opacity:0.14;
}

html, body {
  margin: 0;
  font-family: var(--font-sans);
  color: var(--fg-primary);
  background: var(--bg-canvas);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-feature-settings: "cv05" 1, "ss01" 1;
}

.mono { font-family: var(--font-mono); font-feature-settings: "tnum" 1; }

.text-display-2xl{font-size:var(--text-display-2xl-size);line-height:var(--text-display-2xl-line);letter-spacing:-.022em;font-weight:600;}
.text-display-xl{font-size:var(--text-display-xl-size);line-height:var(--text-display-xl-line);letter-spacing:-.022em;font-weight:600;}
.text-display-lg{font-size:var(--text-display-lg-size);line-height:var(--text-display-lg-line);letter-spacing:-.022em;font-weight:600;}
.text-display-md{font-size:var(--text-display-md-size);line-height:var(--text-display-md-line);letter-spacing:-.021em;font-weight:600;}
.text-display-sm{font-size:var(--text-display-sm-size);line-height:var(--text-display-sm-line);letter-spacing:-.019em;font-weight:600;}
.text-display-xs{font-size:var(--text-display-xs-size);line-height:var(--text-display-xs-line);letter-spacing:-.014em;font-weight:600;}
.text-xl{font-size:var(--text-xl-size);line-height:var(--text-xl-line);}
.text-lg{font-size:var(--text-lg-size);line-height:var(--text-lg-line);}
.text-md{font-size:var(--text-md-size);line-height:var(--text-md-line);}
.text-sm{font-size:var(--text-sm-size);line-height:var(--text-sm-line);}
.text-xs{font-size:var(--text-xs-size);line-height:var(--text-xs-line);}
.fw-regular{font-weight:400;} .fw-medium{font-weight:500;}
.fw-semibold{font-weight:600;} .fw-bold{font-weight:700;}

/* ::selection is deliberately UNSTYLED — the browser's default blue highlight,
   independent of the accent theme (same stance as --saved-* / --chip-*: a text
   selection is a system affordance, not branding). It used to be
   var(--ember-100), which theme.ts remaps to the accent, so selecting text
   painted it in the theme colour. */

/* Scrollbars — quiet, warm.
   The thumb tints from currentColor (like .scroll-hover below), NOT a fixed
   ink: a hardcoded dark thumb disappears entirely on the dark theme — the
   Activity feed and message list shipped with invisible scrollbars that way. */
.scroll-thin::-webkit-scrollbar{width:10px;height:10px;}
.scroll-thin::-webkit-scrollbar-thumb{background:color-mix(in srgb, currentColor 22%, transparent);border-radius:9999px;border:3px solid transparent;background-clip:content-box;}
.scroll-thin::-webkit-scrollbar-thumb:hover{background:color-mix(in srgb, currentColor 36%, transparent);background-clip:content-box;}
.scroll-thin::-webkit-scrollbar-track{background:transparent;}
/* Firefox fallback (no ::-webkit pseudo-elements). */
.scroll-thin{scrollbar-color:color-mix(in srgb, currentColor 26%, transparent) transparent;}
.scroll-dark::-webkit-scrollbar{width:10px;}
.scroll-dark::-webkit-scrollbar-thumb{background:rgba(255,255,255,0.12);border-radius:9999px;border:3px solid transparent;background-clip:content-box;}
.scroll-dark::-webkit-scrollbar-track{background:transparent;}

/* Opt-in: reserves the scrollbar's width UNCONDITIONALLY, even while the
   container isn't currently overflowing — for containers using overflow-y:auto
   (a scrollbar only when content overflows) whose content genuinely toggles
   between "fits" and "overflows" during normal use (the message list: loading
   more history, a thread reply appearing, …), where that transition silently
   changed the content column's width and reflowed every row under it.

   NOT folded into .scroll-thin itself: most .scroll-thin consumers (the
   sidebar, menus, popovers, admin tables) either always overflow already (this
   changes nothing for them) or usually DON'T (this then reserves a permanent,
   pointless gutter — a short channel list gained a bare stripe of empty
   padding down its right edge that was never there before). Apply this only
   where the reflow was actually observed. */
.scroll-stable-gutter{scrollbar-gutter:stable;}

/* Scrollbar that only shows while you're over the container (Slack's sidebar).
   Opt-in — combine with .scroll-thin / .scroll-dark, which still supply the
   thumb's colour and size.

   The GUTTER is always reserved (::-webkit-scrollbar keeps its 10px width; only
   the THUMB goes transparent), so revealing it can't reflow the rows underneath.
   The thumb is tinted from the text colour of whatever it's scrolling, so it
   works on the themed sidebar and on a white panel without a second rule — a
   fixed dark thumb is invisible on a dark sidebar. */
.scroll-hover::-webkit-scrollbar-thumb{
  background:transparent;
  background-clip:content-box;
  transition:background 140ms ease;
}
.scroll-hover:hover::-webkit-scrollbar-thumb{
  background:color-mix(in srgb, currentColor 26%, transparent);
  background-clip:content-box;
}
.scroll-hover:hover::-webkit-scrollbar-thumb:hover{
  background:color-mix(in srgb, currentColor 42%, transparent);
  background-clip:content-box;
}
/* Firefox has no ::-webkit pseudo-elements — scrollbar-color is the only lever,
   and it takes no transition, so this snaps rather than fades. */
.scroll-hover{scrollbar-color:transparent transparent;}
.scroll-hover:hover{scrollbar-color:color-mix(in srgb, currentColor 30%, transparent) transparent;}

/* Clickable @-mention pill in rendered messages — Slack-style hover darken.
   Base pill is blue (mention of someone else); --self is the gold variant
   used when the viewer themself is mentioned. */
.mention-pill{transition:background 120ms ease;}
.mention-pill:hover{background:var(--blue-100) !important;text-decoration:underline;}
.mention-pill:focus-visible{outline:2px solid var(--blue-500);outline-offset:1px;}
.mention-pill--self:hover{background:var(--warning-200) !important;}
.mention-pill--self:focus-visible{outline:2px solid var(--warning-500);}

/* Tab-strip buttons (ChannelHeader Messages/Files/Pins). With Preflight off,
   the UA's default focus ring survives on bare <button>s — a white pill that
   ignores the theme. Replace it with a theme-accent outline (NOT box-shadow:
   the active tab's underline is an inline box-shadow that would override it),
   keyboard-focus only. */
.tab-btn{outline:none;}
.tab-btn:focus-visible{outline:2px solid var(--ember-400);outline-offset:-2px;border-radius:var(--radius-md);}

/* Empty-state pictures (components/kit/EmptyArt) — Slack's isometric style,
   the phone's exact tones (mobile components/empty/EmptyArt): every face is
   MIXED from the accent, towards white for the top and towards black for the
   far side, so the picture follows a picked theme in light and dark. Read at
   use time, so a theme switch repaints them. */
:root {
  --empty-art-top: color-mix(in srgb, var(--ember-500) 14%, #ffffff);
  --empty-art-left: color-mix(in srgb, var(--ember-500) 90%, #ffffff);
  --empty-art-right: color-mix(in srgb, var(--ember-500) 76%, #000000);
  --empty-art-accent: var(--ember-500);
  --empty-art-soft: color-mix(in srgb, var(--ember-500) 55%, #ffffff);
  --empty-art-fold: color-mix(in srgb, var(--ember-500) 38%, #ffffff);
  --empty-art-sparkle: color-mix(in srgb, var(--ember-500) 70%, #ffffff);
  --empty-art-raised-left: color-mix(in srgb, var(--ember-500) 84%, #000000);
  --empty-art-raised-right: color-mix(in srgb, var(--ember-500) 66%, #000000);
  --empty-art-shadow: var(--ink-900);
  --empty-art-shadow-opacity: 0.07;
}

/* The message feed's loading placeholder (lib/messageSkeleton): ONE grey for
   every shape, Slack's own in light mode. In dark it is the neutral surface
   step, which the theme engine sets on <html> — a custom property's var() is
   resolved where it is DECLARED, so this has to be declared there too. */
:root { --skeleton-fill: #E8E8E8; }

html[data-mode="dark"] { --skeleton-fill: var(--paper-100); }

html[data-mode="dark"] {
  --empty-art-top: color-mix(in srgb, var(--ember-500) 22%, #ffffff);
  --empty-art-shadow: #000000;
  --empty-art-shadow-opacity: 0.35;
}
