/* =============================================================================
   SEMANTIC TOKENS — the roles every stylesheet reads.
   =============================================================================

   SSOT: this is the single owner of every design ROLE in Chippie — colour,
   spacing, radius, elevation, motion duration and motion easing.

   Flow is one direction and never reverses:

       tokens/palette.css  ->  tokens/semantic.css  ->  everything else
                                                    ->  tokens/bootstrap-bridge.css

   Rules:
   * No colour literal may appear in this file. Colours come from --c-* in
     palette.css. Spacing, radius, duration and easing have no palette
     equivalent and are written here directly — this file owns them outright.
   * Themes (themes/skin.css, dark.css, rustic.css, beach.css, bushland.css,
     whitewash.css) override the roles below and may override palette ramp
     entries. They may not introduce a bare literal.
   * Component stylesheets read these names. They must never reach past this
     file into --c-*. If a component needs a colour that has no role here, the
     role is missing — add it, do not inline a ramp entry.

   These names are not new. They are the exact set themes/base.css shipped,
   moved here and re-expressed against the palette, so nothing that consumes
   them needs to change.
   ========================================================================== */

:root {
    /* ── Brand / action ────────────────────────────────────────────────── */
    --primary-color: var(--c-brand-700);
    --primary-rgb: var(--c-brand-700-rgb);
    --primary-hover: var(--c-brand-800);
    --primary-light: var(--c-brand-100);
    --primary-dark: var(--c-brand-900);

    --secondary-color: var(--c-neutral-600);
    --secondary-hover: var(--c-neutral-650);
    --secondary-light: var(--c-neutral-050);
    --secondary-dark: var(--c-neutral-700);

    --accent-color: var(--c-green-500);
    --accent-hover: var(--c-green-700);
    --warning-color: var(--c-amber-500);
    --warning-hover: var(--c-amber-600);
    --danger-color: var(--c-red-500);
    --danger-hover: var(--c-red-600);

    /* ── Surface canvas — the theme factory's single knob ───────────────
       A palette sets ONE token (--canvas) and the whole app's non-blue
       background flips. Every surface below derives from it, so white
       (Whitewash) vs sandstone (Beach) is a one-line change in the palette
       file. Granular per-area control: a palette can override a derived token
       (e.g. --surface-header) without touching --canvas. The other primary,
       the blue, lives in --primary-color / --nav-* above. */
    --canvas: var(--c-neutral-000);   /* baseline = Whitewash; Beach overrides to sandstone */
    --bg-canvas: var(--canvas);       /* page body */
    --surface: var(--canvas);         /* cards, sections, tables, list rows */
    --surface-header: var(--surface); /* granular hook: section/form headers */
    --bg-primary: var(--c-neutral-000);  /* raised surfaces (segmented pill, menus, modals) */
    --bg-secondary: var(--c-neutral-050);
    --bg-tertiary: var(--c-neutral-200);
    --bg-dark: var(--c-neutral-800);
    --bg-light: var(--c-neutral-000);

    /* ── Text ──────────────────────────────────────────────────────────── */
    --text-primary: var(--c-neutral-900);
    --text-secondary: var(--c-neutral-600);
    --text-muted: var(--c-neutral-600);
    --text-light: var(--c-neutral-000);
    --text-dark: var(--c-neutral-1000);

    /* ── Border ────────────────────────────────────────────────────────── */
    --border-color: var(--c-neutral-300);
    --border-light: var(--c-neutral-200);
    --border-dark: var(--c-neutral-500);

    /* ── Navigation ────────────────────────────────────────────────────────
       Flat solid colours: the navbar/banner has no gradient. Account mode is
       the brand blue; agent/store/admin go flat solid for consistency. */
    --nav-bg: var(--c-brand-700);
    --nav-text: var(--c-neutral-000);
    --nav-hover: rgba(var(--c-ink-white), 0.1);
    --nav-active: rgba(var(--c-ink-white), 0.2);

    /* The solid colour the native shells paint their status-bar scrim and
       bottom tab bar with. Native chrome takes a single colour, so a theme
       whose --nav-bg is a gradient must name its solid stand-in here; every
       other theme resolves this to its own --nav-bg through the cascade.
       Read by bridge/theme_controller.js, never by a stylesheet. */
    --nav-bg-native: var(--nav-bg);

    /* Navbar mode colours — one per session['mode']. Consumed by
       .navbar[data-nav-mode="..."] in themes/base.css. The navbar template
       emits only the mode; colour resolves from these tokens. */
    --nav-bg-account: var(--c-brand-700);
    --nav-bg-agent: var(--c-green-600);
    --nav-bg-store: var(--c-orange-500);
    --nav-bg-admin: var(--c-purple-500);
    --nav-shadow: none;

    /* ── Cards ─────────────────────────────────────────────────────────── */
    --card-bg: var(--surface);
    --card-border: var(--c-neutral-300);
    --card-shadow: 0 0.125rem 0.25rem rgba(var(--c-ink-black), 0.075);
    --card-hover-shadow: 0 0.5rem 1rem rgba(var(--c-ink-black), 0.15);

    /* ── Forms ─────────────────────────────────────────────────────────── */
    --input-bg: var(--c-neutral-000);
    --input-border: var(--c-neutral-350);
    --input-focus: var(--c-brand-200);
    --input-text: var(--c-neutral-700);

    /* ── Buttons ───────────────────────────────────────────────────────── */
    --btn-border-radius: 0.375rem;
    --btn-padding: 0.375rem 0.75rem;
    --btn-font-weight: 400;
    --btn-primary-hover-bg: var(--c-brand-800);
    --btn-primary-hover-border: var(--c-brand-800);
    /* Banner action button — a lighter blue than the flat-blue banner band
       (--primary-color) so the button edge reads against the banner. Hover
       lifts lighter still for clear feedback. */
    --banner-btn-bg: var(--c-brand-600);
    --banner-btn-border: var(--c-brand-500);
    --banner-btn-hover-bg: var(--c-brand-400);
    --banner-btn-hover-border: var(--c-brand-300);

    /* ── Typography ────────────────────────────────────────────────────────
       System stack by default. The active font trial overrides these tokens in
       themes/skin.css, which only the app shell loads — the public shell
       (public_base.html) must NOT pick up trial fonts (a trial serif token here
       would visibly fall back to system Times on public pages). Weight
       strategy: body/small text/buttons stay 400+ — never Light below ~1.1rem,
       since users read phones outdoors and thin small text is a legibility
       regression, not a style choice. --btn-font-weight above stays the owner
       for button weight.

       Brand fonts are NOT settled; docs/BRANDING.md is the SSOT. Do not add
       --font-* roles here beyond the ones that already existed. */
    --font-family-base: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --font-family-heading: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --font-size-base: 1rem;
    --line-height-base: 1.5;
    --font-weight-normal: 400;
    --font-weight-bold: 700;

    /* ── Spacing ───────────────────────────────────────────────────────────
       Two vocabularies, deliberately. --spacing-* is the pre-existing t-shirt
       scale that ~90 stylesheets already consume and it is not being churned.
       --space-N is the 4px numeric scale for new work, where a designer needs
       to say "three steps" rather than "medium". They agree at the overlap:
       --spacing-sm == --space-2, --spacing-md == --space-4. */
    --spacing-xs: 0.25rem;
    --spacing-sm: 0.5rem;
    --spacing-md: 1rem;
    --spacing-lg: 1.5rem;
    --spacing-xl: 3rem;

    --space-scale: 0.25rem;
    --space-1: var(--space-scale);
    --space-2: calc(var(--space-scale) * 2);
    --space-3: calc(var(--space-scale) * 3);
    --space-4: calc(var(--space-scale) * 4);
    --space-5: calc(var(--space-scale) * 5);
    --space-6: calc(var(--space-scale) * 6);
    --space-8: calc(var(--space-scale) * 8);
    --space-10: calc(var(--space-scale) * 10);
    --space-12: calc(var(--space-scale) * 12);
    --space-16: calc(var(--space-scale) * 16);

    /* ── Radius ────────────────────────────────────────────────────────────
       Softened base/lg for a modern rhythm (brings the default theme in line
       with dark/rustic's scale). --radius-pill is for fully-rounded affordances
       (the sheet grab handle, chips) where the value must not scale with the
       others. */
    --border-radius-sm: 0.375rem;
    --border-radius-base: 0.5rem;
    --border-radius-lg: 0.75rem;
    --border-radius-xl: 1rem;
    --radius-pill: 9999px;

    /* ── Elevation ─────────────────────────────────────────────────────────
       Layered (ambient + key light) so elevation reads as depth rather than the
       flat single-layer drop that signals "stock Bootstrap". --shadow-* is the
       established name; there is deliberately no parallel --elevation-* set. */
    --shadow-sm: 0 1px 2px rgba(var(--c-ink-shadow), 0.04),
                 0 1px 3px rgba(var(--c-ink-shadow), 0.08);
    --shadow-base: 0 2px 4px rgba(var(--c-ink-shadow), 0.04),
                   0 4px 12px rgba(var(--c-ink-shadow), 0.10);
    --shadow-lg: 0 4px 8px rgba(var(--c-ink-shadow), 0.04),
                 0 12px 28px rgba(var(--c-ink-shadow), 0.14);

    /* ── Motion ────────────────────────────────────────────────────────────
       The single owner of every duration and easing in the app. static/css/
       motion.css owns view-transition RULES and navigation KEYFRAMES; it reads
       its VALUES from here, so timing cannot drift between the nav transition,
       a row FLIP and a sheet drag.

       Three easings cover everything:
         standard  — the workhorse. UI that starts and stops on screen.
         emphasis  — screen-level motion that should feel weighted and settle
                     late (page push/pop, sheet present, shared-element morph).
         decel     — something arriving or being released; fast in, soft stop.
       --ease-overshoot is separate because its >1 endpoint is a deliberate
       bounce, not a variant of decel. Do not flatten it into one. */
    --dur-instant: 0ms;
    --dur-fast: 120ms;
    --dur-base: 200ms;
    --dur-slow: 280ms;
    /* Theme/colour crossfade. Deliberately off the interaction scale: swapping
       theme should read as a wash, not a UI response. Owned here so the global
       `*` transition in themes/base.css carries no literal. */
    --dur-theme-swap: 300ms;

    --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
    --ease-emphasis: cubic-bezier(0.32, 0.72, 0, 1);
    --ease-decel: cubic-bezier(0.22, 0.61, 0.36, 1);
    /* A harder stop than --ease-decel, for something released from a finger:
       it must arrive decisively rather than glide. Used by the swipe settle and
       the sheet snap-back. Two decel curves is deliberate, not drift. */
    --ease-settle: cubic-bezier(0.22, 1, 0.36, 1);
    --ease-overshoot: cubic-bezier(0.18, 0.89, 0.32, 1.28);

    /* Pre-existing transition shorthands, now expressed through the tokens so
       they cannot drift from the rest of the motion system. The durations are
       deliberately NOT the --dur-* scale: these are the slow colour/theme
       crossfades, a different job from interaction motion. */
    --transition-base: all 0.3s ease;
    --transition-fast: all 0.15s ease;
    --transition-slow: all 0.5s ease;

    /* ── Scrollbars ────────────────────────────────────────────────────── */
    --scrollbar-track: var(--c-neutral-100);
    --scrollbar-thumb: var(--c-neutral-400);
    --scrollbar-thumb-hover: var(--c-neutral-450);

    /* ── Alerts (soft background / border / text per severity) ─────────── */
    --alert-success-bg: var(--c-tint-success-bg);
    --alert-success-border: var(--c-tint-success-border);
    --alert-success-text: var(--c-tint-success-text);
    --alert-info-bg: var(--c-tint-info-bg);
    --alert-info-border: var(--c-tint-info-border);
    --alert-info-text: var(--c-tint-info-text);
    --alert-warning-bg: var(--c-tint-warning-bg);
    --alert-warning-border: var(--c-tint-warning-border);
    --alert-warning-text: var(--c-tint-warning-text);
    --alert-danger-bg: var(--c-tint-danger-bg);
    --alert-danger-border: var(--c-tint-danger-border);
    --alert-danger-text: var(--c-tint-danger-text);

    /* ── Dashboard banner band ─────────────────────────────────────────────
       Single source of truth for the blue header strip. .dashboard-header gets
       --banner-height as a fixed min-height so EVERY page's banner (dashboard,
       quotes, jobs, invoices, clients) and every skeleton is the SAME height,
       no matter how much heading / subtitle / button content it carries.
       Content is flex-centred within. Redefined per-breakpoint below — change
       here to resize every banner + skeleton in one move. --banner-pad-y is
       only a safety gutter for the rare case content exceeds --banner-height. */
    --banner-height: 8.5rem;
    --banner-pad-y: 1rem;
    --banner-margin-bottom: 1.5rem;

    /* ── Safe-area insets ──────────────────────────────────────────────────
       Single source of truth for the status bar (top) and home indicator
       (bottom). Non-zero ONLY in the native shell: base.html ships
       viewport-fit=cover so the WKWebView runs edge-to-edge, which is what lets
       .dashboard-header's colour extend up behind the clock. The browser,
       desktop, and the installed PWA all resolve these to 0, so every consumer
       is unchanged there and none need gating on html[data-hotwire-native].

       In-flow content running under the status bar while it scrolls is the
       intended design. Fixed OVERLAYS are not: their controls end up drawn
       behind the clock and battery and cannot be tapped. The overlay layer in
       themes/skin.css consumes these once, for every Bootstrap modal at once.
       New fixed overlays should consume the tokens rather than re-deriving
       env() at their own call site — that duplication is why the photo
       lightbox, the app lock and the bannerless page header each had to be
       fixed separately. */
    --safe-top: env(safe-area-inset-top, 0px);
    --safe-bottom: env(safe-area-inset-bottom, 0px);
}

/* Banner band — compact sizing on phones. Overrides the tokens above so every
   .dashboard-header (real + skeleton) resizes together. Taller than desktop
   because banner content stacks vertically on narrow screens. */
@media (max-width: 576px) {
    :root {
        --banner-height: 12.5rem;
        --banner-pad-y: 0.75rem;
        --banner-margin-bottom: 1rem;
    }
}

/* Reduced motion — the single gate for TRANSITION timing.
   Zeroing a duration stops a transition, but it does NOT stop a running
   @keyframes animation, which keeps its own animation-duration. Rules that
   drive keyframes (the view transitions in static/css/motion.css, the skeleton
   shimmer in themes/base.css) null their animation-name in their own
   prefers-reduced-motion block. Both gates are required; neither is redundant. */
@media (prefers-reduced-motion: reduce) {
    :root {
        --dur-fast: 0ms;
        --dur-base: 0ms;
        --dur-slow: 0ms;
        --dur-theme-swap: 0ms;
        --transition-base: none;
        --transition-fast: none;
        --transition-slow: none;
    }
}
