/* ============================================================================
   theme.css — Obeikan AI design tokens (single source of truth)
   ----------------------------------------------------------------------------
   All themeable colors/fonts live here, not hardcoded in templates. Templates
   reference these CSS variables (var(--token)). The active theme is chosen by
   the data-theme attribute on <html> ("light" | "dark"), set by the theme
   bootstrap in base.html from the user's saved appearance preference.

   To add a new theme: copy a block below and change the values under a new
   [data-theme="<name>"] selector, then expose it in the Settings → Appearance
   picker (templates/settings.html).

   BESIDES THE TOKENS this file carries exactly two app-GLOBAL rules, both below
   the token blocks and both cross-referenced by the token comments: the one
   scrollbar treatment for every scroller (--scroll-thumb) and the house
   :focus-visible ring (--accent / --accent-weak). They stay here because the
   seven standalone heads that link theme.css WITHOUT extending base.html
   (login, 404, selfcheck, the invite and reset pages) need them and link
   nothing else. The app-global COMPONENTS that used to sit at the end of this
   file — the tooltip bubble, the compliance chips, the chat thinking feed —
   moved to static/shared_components.css on 2026-08-10, loaded immediately after
   this file in base.html. Add new components there, not here; a new TOKEN
   belongs here.
   ============================================================================ */

/* ── Light (default) ─────────────────────────────────────────────────────── */
:root {
    --bg:             #FAF9F5;   /* warm paper canvas (one step lighter — Claude-exact) */
    --bg-raised:      #FFFFFF;   /* raised panels */
    --bg-secondary:   #F0EEE6;   /* list rows / secondary wells (KB doc lists) */
    --surface:        #FFFFFF;   /* cards / bubbles / composer */

    --sidebar-bg:     #F5F4EE;   /* light warm rail (theme-aware) */
    --sidebar-text:   #44413B;   /* re-derived against the lighter rail */
    --sidebar-strong: #1F1E1D;   /* logo / active item / titles */
    --sidebar-dim:    #6b6862;
    --sidebar-faint:  #6E6A62;   /* section labels, meta — raised from #9a968d to clear WCAG AA (2.68:1 → 4.88:1) */
    --sidebar-line:   rgba(31, 30, 29, 0.10);
    --sidebar-hover:  rgba(31, 30, 29, 0.05);
    --sidebar-active: rgba(31, 30, 29, 0.07);   /* neutral fill — terracotta-tinted active retired */
    /* Selected conversation fill — accent-derived, one dedicated token so the
       active row reads distinct from the neutral --sidebar-active nav fill and
       clears the barely-there --accent-weak step (audit C7). Resolves per-theme
       via var(--accent). */
    --sidebar-selected: color-mix(in srgb, var(--accent) 14%, transparent);
    --sidebar-well:   rgba(31, 30, 28, 0.04);
    --sidebar-chip:   #fbfaf7;
    --sidebar-accent: #c96442;

    --card:           #ffffff;
    --card-border:    rgba(31, 30, 28, 0.10);
    --border:         rgba(31, 30, 28, 0.10);
    --input-border:   rgba(31, 30, 28, 0.18);
    --input-focus:    #c96442;
    --scroll-thumb:   rgba(31, 30, 28, 0.28);   /* scrollbar thumbs (global rule
                         below the token blocks) — stronger than --border because
                         a 4px thumb needs presence to be grabbable, still quiet */

    --text:           #1F1E1D;
    --muted:          #6b6862;
    --subtle:         #9a968d;

    --accent:            #c96442;
    --accent-weak:       rgba(201, 100, 66, 0.10);
    --btn-primary-bg:    #c96442;
    --btn-primary-hover: #b5563a;
    --btn-primary-text:  #ffffff;
    /* Label colour for text/icons ON an accent-coloured fill (primary button,
       active feedback chip, submit). THEME-VARYING: white on the light clay, a
       near-black label on the lighter dark-mode terracotta (white on #d97757 is
       only 3.12:1; #2a1a12 on it is ~5.3:1 — the standard light-accent-on-dark
       treatment). The button colour itself never changes. */
    --on-accent:         #ffffff;
    /* ── Accent that has to be READ, not merely seen ──────────────────────────
       --accent is a ~3:1 colour: right for a fill, a border or a glyph, and
       UNDER the 4.5:1 WCAG 1.4.3 asks of text — while every accent LABEL in this
       app is 11-13px. Two tokens fix that at the SAME hue (15°) and saturation,
       moved on lightness alone, so the brand reads unchanged. Each range below
       is the WORST case measured across all five app surfaces (--bg, --surface,
       --card, --sidebar-bg, --bg-secondary), before → after:
         --on-accent-weak  text/glyphs ON an --accent-weak (or --sidebar-selected)
             tint — active filter chips and their counts, segmented controls, the
             author badge, the selected project row, running state chips.
             light 3.01-3.48 → 4.64-5.37 · dark 3.48-4.39 → 4.70-5.92.
         --link  accent text on a PLAIN surface — the "Change this" reopen link,
             the owner re-assign button, the dashed add-a-section chip on hover.
             light 3.36-3.90 → 4.73-6.02 · dark 4.24-5.33 → 4.69-5.90.
       NOT interchangeable: --link on a tint measures 4.24 light / 3.86 dark, so
       a tinted control takes --on-accent-weak and a plain one takes --link. */
    --on-accent-weak:    #9F4A2C;
    --link:              #A94E30;
    --user-bubble:       #EDEAE1;

    --success:  #3f7a4e;
    --warning:  #b5762a;
    --danger:   #b5443a;

    /* Semantic status tokens (light) — ok / warn / danger / info bg+text pairs */
    --ok-bg:     #E5EFE6;
    --ok-text:   #2E5C3A;
    --warn-bg:   #F6ECD9;
    --warn-text: #7A5A1E;
    --danger-bg: #F6E0DC;
    --danger-text: #8C3A30;
    --info-bg:   #E8E9F2;
    --info-text: #3E4470;

    --font-sans:  "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --font-serif: "Lora", "Source Serif 4", ui-serif, Georgia, "Times New Roman", serif;
    --font-arabic:"Noto Naskh Arabic", "Amiri", "Segoe UI", sans-serif;
    /* Prompt/composer input boxes only (owner 2026-07-11): Styrene B stand-in.
       Latin subsets only — Arabic input falls through to the system stack. */
    --font-input: "Archivo", "Inter", ui-sans-serif, system-ui, sans-serif;
    /* Code spans / pasted-text wells — one stack instead of per-rule retyping. */
    --font-mono: ui-monospace, "SF Mono", Menlo, monospace;

    /* ── Chat content typography (Feature B — Claude Code parity) ──────────────
       ONE shared body stack + scale so assistant replies, user messages and
       thinking-mode text read as a single system. NO serif in message bodies
       (the serif hero greeting is a separate surface). Arabic swaps the family
       for --font-arabic via the [dir="rtl"] rule in chat.html; the size /
       line-height / paragraph-gap vars are language-neutral. --chat-thinking-fg
       tracks --muted so it flips with the theme (quiet ~60%-weight foreground).
       Referenced vars resolve per-theme at use time, so these need no dark twin. */
    --chat-body-family: var(--font-sans);
    --chat-body-size:   15px;
    --chat-body-line:   1.65;
    --chat-para-gap:    0.7em;
    --chat-thinking-fg: var(--muted);

    --sidebar-width: 288px;
    --mobile-header-h: 56px;   /* sticky top bar shown < 1024px (off-canvas drawer trigger) — 52→56 for the 44px hamburger target */
    --radius-sm:  8px;
    --radius-md:  12px;
    --radius-lg:  16px;
    --radius-xl:  24px;

    /* ── Spacing scale (UI review — 4pt base) ─────────────────────────────────
       One 7-step ramp so gaps / padding / margins snap to a shared rhythm
       instead of ad-hoc pixels. Consume via var(--space-N). Adopted by the newer
       stylesheets (adaptation_review.css onward); the older ones still carry
       ad-hoc pixels and migrate rule by rule, never in a blind sweep. */
    --space-1: 4px;    /* hairline — icon↔label, chip inner padding */
    --space-2: 8px;    /* tight — control padding, small stacks */
    --space-3: 12px;   /* default inner padding / list-row gaps */
    --space-4: 16px;   /* standard block gap */
    --space-5: 24px;   /* section spacing */
    --space-6: 32px;   /* large section / page gutter */
    --space-7: 48px;   /* hero / major separation */

    /* ── Radius scale (UI review) — semantic aliases onto the existing ramp ───
       Named by ROLE. ctrl / card alias the existing --radius-sm / --radius-md so
       there stays ONE source of truth (no duplicate 8px / 12px); pill is new
       (fully-rounded chips, toggles, switches). The aliases resolve to the same
       pixels, so swapping a raw 8px for --radius-ctrl repaints nothing. */
    --radius-ctrl: var(--radius-sm);   /* 8px  — buttons, inputs, small controls */
    --radius-card: var(--radius-md);   /* 12px — cards, menus, dialogs */
    --radius-pill: 999px;              /* fully rounded — pills / chips / switches */

    /* ── Type scale (UI review) — the house sizes + the 13px secondary ────────
       11 caption · 13 secondary · 14 body · 16 heading · 20 title · 24 title-lg.
       13px was the single most-used font-size in the audit, so it earns a name.
       Chat bodies keep their own --chat-body-size (a separate surface with its
       own line-height and paragraph rhythm) and are deliberately not on this
       ramp. --fs-title-lg is the PAGE-HERO step: 24px was already the size of
       base.css's .page-header h2 and of the review page's h1, so it was a house
       size with no name — which is how a bare `font-size: 24px` keeps getting
       re-typed. A serif hero uses it; --fs-title stays the dialog/section step. */
    --fs-caption:   11px;   /* chips, meta, timestamps */
    --fs-secondary: 13px;   /* dense secondary text (most-used in the audit) */
    --fs-body:      14px;   /* default body copy */
    --fs-heading:   16px;   /* card / section headings */
    --fs-title:     20px;   /* dialog / section titles */
    --fs-title-lg:  24px;   /* page hero (the one <h1>/<h2> a page leads with) */

    /* ── Z-index ladder (UI review fix 3) ─────────────────────────────────────
       FIVE named tiers replace the z-index anarchy that produced the mobile
       ⋯-menu / context-toggle overlap. Everything that stacks app-GLOBALLY maps
       onto one of these; consume via var(--z-…). A sibling that must sit just
       above its tier uses a micro-offset — calc(var(--z-raised) + 1) — and the
       100-unit gaps between tiers leave room for that without reaching the next
       tier. --z-sticky is reserved for pinned chrome that stacks ABOVE the
       raised layer (a future sticky in-content header, say); NOTE the mobile top
       bar is deliberately NOT here — it must sit BELOW the drawer scrim + sidebar
       and so lives in the overlay subsystem (raw, documented) instead. That
       subsystem (mobile-header, the two scrims, the parked context panel, the
       reopen toggle) is a self-contained micro-ladder BELOW --z-raised: its five
       internal levels are finer than these app-global tiers, so it keeps its own
       documented raw values (drawer.css / context_panel.css) and the z-index
       guard test allowlists exactly those. */
    --z-raised:  100;   /* lifted off the page — sidebar rail, edge affordances */
    --z-sticky:  200;   /* pinned chrome stacking above --z-raised (reserved) */
    --z-popover: 300;   /* menus, dropdowns, floating popovers */
    --z-modal:   400;   /* dialog / modal overlays (above menus) */
    --z-toast:   500;   /* tooltips, toasts — always on top OF THE LADDER.
                           LATENT: the un-migrated template modal overlays
                           (settings/limits/invite/mem-import, 1000-1200 inline)
                           still sit ABOVE this tier — no tooltip fires inside
                           them today (zero data-tooltip there), but a future
                           data-tooltip inside one would hide behind it until
                           those modals migrate onto the ladder (Stage 3+). */

    /* ── Motion (app-wide) ────────────────────────────────────────────────────
       Shared open/close animation grammar so every panel, popover, menu, toast
       and dialog fades the same way — fast and noticeable, never sluggish. Open
       decelerates (ease-out), close accelerates (ease-in). Consume these instead
       of scattering magic durations. All motion that uses them is additionally
       gated behind `html.anim-ready` (added one frame after first paint, so the
       persisted collapsed state paints instantly) and wrapped in
       @media (prefers-reduced-motion: no-preference). */
    --anim-fast: 160ms;                            /* popovers · menus · toasts · fades */
    --anim-med:  200ms;                            /* panels · split-view (larger surfaces) */
    --anim-ease-out: cubic-bezier(0.16, 1, 0.3, 1);   /* open — decelerate into place */
    --anim-ease-in:  cubic-bezier(0.4, 0, 1, 1);      /* close — accelerate away */
}

/* ── Dark ────────────────────────────────────────────────────────────────── */
[data-theme="dark"] {
    --bg:             #262624;
    --bg-raised:      #2E2D2B;
    --bg-secondary:   #2E2D2B;   /* list rows / secondary wells (KB doc lists) */
    --surface:        #30302E;

    --sidebar-bg:     #1F1E1D;
    --sidebar-text:   rgba(255, 255, 255, 0.70);
    --sidebar-strong: #ffffff;
    --sidebar-dim:    rgba(255, 255, 255, 0.60);
    --sidebar-faint:  rgba(255, 255, 255, 0.48);   /* raised from .34 to clear WCAG AA (3.10:1 → ~4.7:1) */
    --sidebar-line:   rgba(255, 255, 255, 0.08);
    --sidebar-hover:  rgba(255, 255, 255, 0.06);
    --sidebar-active: rgba(255, 255, 255, 0.09);
    --sidebar-well:   rgba(0, 0, 0, 0.20);
    --sidebar-chip:   rgba(255, 255, 255, 0.04);
    --sidebar-accent: #d97757;

    --card:           #2b2a27;
    --card-border:    rgba(255, 255, 255, 0.10);
    --border:         rgba(255, 255, 255, 0.10);
    --input-border:   rgba(255, 255, 255, 0.18);
    --input-focus:    #d97757;
    --scroll-thumb:   rgba(255, 255, 255, 0.22);   /* see the light-theme note */

    --text:           #FAF9F5;
    --muted:          #b3afa6;
    --subtle:         #85817a;

    --accent:            #d97757;
    --accent-weak:       rgba(217, 119, 87, 0.14);
    --btn-primary-bg:    #d97757;
    --btn-primary-hover: #e08a6c;
    --btn-primary-text:  #ffffff;
    --on-accent:         #2a1a12;   /* near-black label on the light dark-mode clay (~5.3:1) */
    /* The dark twins of the two readable-accent tokens — see the light block for
       what each one is for and for the measured ratios. Lightened rather than
       darkened here, same hue (15°) and saturation as --accent. */
    --on-accent-weak:    #E3987F;
    --link:              #DD8262;
    --user-bubble:       #393937;

    --success:  #5fa570;
    --warning:  #d9a24a;
    --danger:   #e0695f;

    /* Semantic status tokens (dark) — translucent tints over the dark canvas */
    --ok-bg:     rgba(95, 165, 112, 0.18);
    --ok-text:   #8FC79E;
    --warn-bg:   rgba(217, 162, 74, 0.16);
    --warn-text: #D9B577;
    --danger-bg: rgba(224, 105, 95, 0.16);
    --danger-text: #E59B93;
    --info-bg:   rgba(137, 146, 214, 0.18);
    --info-text: #AEB5E8;
}

/* ── Scrollbars — ONE treatment for EVERY scroller (owner report 2026-08-09) ──
   Before this rule exactly three containers had styled scrollbars (.sidebar,
   .conv-list, .ctxp-scroll — thin/dark, WebKit-only, three separate copies) and
   everything else — the chat thread itself, modals, drawers, code blocks — fell
   back to the raw browser bar, so the app's scrollbars visibly changed style
   from pane to pane. Defined ONCE here, on the universal selector, in both
   engines' dialects:
     * WebKit/Chromium/Safari: the ::-webkit-scrollbar pseudos (4px, hairline
       thumb, transparent track; `height` styles horizontal bars — code blocks).
     * Firefox: the standard properties, gated behind a Firefox-only @supports
       probe ON PURPOSE — Chromium ≥121 also understands scrollbar-width/color,
       and any non-auto scrollbar-color there DISABLES the ::-webkit-* styling
       above, silently replacing the 4px design with the browser's ~11px "thin".
   The per-container copies are gone; --scroll-thumb lives in both theme blocks. */
*::-webkit-scrollbar { width: 4px; height: 4px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: var(--scroll-thumb); border-radius: 2px; }
*::-webkit-scrollbar-corner { background: transparent; }
@supports (-moz-appearance: none) {
    * { scrollbar-width: thin; scrollbar-color: var(--scroll-thumb) transparent; }
}
/* ONE exception (owner report 2026-09-18): the sidebar's recents list scrolls
   with NO visible bar. Its 4px thumb read as "a thin line down the side menu"
   — a permanent hairline beside every title, on every page. Scrolling is
   untouched (wheel, trackpad, keyboard, drag); only the indicator goes. Stated
   HERE, beside the global rule, because this file is the one place scrollbars
   are styled (test_scrollbars_are_styled_once_globally forbids the pseudo in
   base.css). Both dialects again: `scrollbar-width: none` for Firefox and
   Chromium ≥121 / Safari ≥18.2, the pseudo for the WebKit engines before them. */
.conv-list { scrollbar-width: none; }
.conv-list::-webkit-scrollbar { display: none; }

/* ── Focus-visible ring (P3, a11y-hardened 2026-08) ───────────────────────────
   One house keyboard-focus ring for EVERY interactive element, defined once here
   rather than copied per component. A REAL ring: a 2px solid --accent outline set
   2px off the box, so a canvas gap separates the ring from the control and it
   reads on ANY surface, WITH OR WITHOUT a border — the previous indicator was a
   3px --accent-weak halo that measured ~1.1:1 on the ~29 borderless controls that
   have no border for the border-color half to tint (it was effectively invisible;
   WCAG 2.4.7/2.4.11). The outline follows the element's own border-radius and adds
   no layout box, so nothing shifts. The border tint + the faint --accent-weak halo
   are retained underneath (harmless on borderless controls, a nice inner glow on
   bordered ones). :focus-visible keeps it keyboard-only — mouse clicks stay quiet.
   The broad element/attribute selector list is the "strategy" (no 30 per-widget
   copies); the per-component restatements now add the SAME outline so the ring is
   uniform even where a control overrode the box-shadow for a local radius tweak. */
a:focus-visible,
button:focus-visible,
summary:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:not([tabindex="-1"]):focus-visible,
[role="button"]:focus-visible,
[role="tab"]:focus-visible,
[role="option"]:focus-visible,
[role="radio"]:focus-visible,
[role="checkbox"]:focus-visible,
[role="menuitem"]:focus-visible {
    outline: 2px solid var(--accent); outline-offset: 2px;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-weak);
}
