/* BizsOn design tokens — the ONLY global stylesheet in the system.
   All module UI must read colors/spacing/typography from these vars.

   COLOUR SOURCE OF TRUTH: Metronic (task 317 / GitLab #166).
   The colour tokens below are DERIVED from the semantic tokens the compiled
   Metronic theme declares on :root and .dark (--background, --foreground,
   --card, --primary, --border, …). Metronic flips the `dark` class on <html>,
   which re-computes ITS tokens, which re-computes these — so the --bz-* layer
   needs no dark palette of its own, and the two palettes can no longer drift
   apart. The one dark override is of Metronic's OWN semantic tokens (the
   charcoal block below, task 343), so everything still flows from one place.
   The data-theme hook is kept for server-side/theme-state callers.

   A token Metronic has no equivalent for (a third elevation step, a status hue)
   is derived with color-mix against --foreground: that always pushes the colour
   AWAY from the current background, so ONE declaration reads correctly in both
   themes — darker on white, lighter on zinc-950.

   Per-tenant brand override is injected inline as --bz-brand-primary /
   --bz-brand-accent on <html> by the TenantBrandOverride component so
   we never toggle classes.

   See docs/dev/guides/design-system.md. */
:root {
  /* Palette — every value follows Metronic's own token for the active theme. */
  --bz-color-bg: var(--background);
  /* In light mode page and card are the same white, separated by --border plus a small shadow,
     shadcn-style. In dark mode the card is one charcoal step lighter than the page (the html.dark
     block below, task 343), so borderless panels separate too. */
  --bz-color-surface: var(--card);
  /* Floating surfaces — drop-downs, pop-overs, dialogs — one elevation step above a card in dark
     mode, exactly as Metronic's own .kt-dropdown / .kt-modal-content use --popover. White in light. */
  --bz-color-popover: var(--popover);
  --bz-color-surface-2: var(--secondary);
  /* A third elevation step: Metronic stops at two, so this is one step further
     from the page than surface-2, in whichever direction the theme runs. */
  --bz-color-surface-3: color-mix(in oklab, var(--secondary) 92%, var(--foreground));
  --bz-color-fg: var(--foreground);
  --bz-color-fg-muted: var(--muted-foreground);
  --bz-color-fg-subtle: color-mix(in oklab, var(--muted-foreground) 78%, var(--background));
  --bz-color-border: var(--border);
  --bz-color-border-strong: color-mix(in oklab, var(--border) 62%, var(--foreground));
  --bz-color-accent: var(--primary);
  --bz-color-accent-hover: color-mix(in oklab, var(--primary) 86%, var(--foreground));
  --bz-color-accent-fg: var(--primary-foreground);
  /* The accent used AS TEXT — links, link buttons, accent labels. Identical to the accent in light
     mode; html.dark lifts it towards the foreground (task 343), because the brand blue that fills a
     button at 5.2:1 under white text is only 2.8:1 as text on a charcoal card. Fills, badges and
     backgrounds keep --bz-color-accent. */
  --bz-color-accent-text: var(--bz-color-accent);
  /* Status hues. Metronic ships only --destructive; warn/ok come from the
     Tailwind palette it already defines, nudged for contrast the same way. */
  --bz-color-danger: color-mix(in oklab, var(--destructive) 88%, var(--foreground));
  --bz-color-warn: color-mix(in oklab, var(--color-yellow-600) 88%, var(--foreground));
  --bz-color-ok: color-mix(in oklab, var(--color-green-600) 88%, var(--foreground));
  --bz-color-info: var(--primary);
  /* Deliberately brand-tinted rather than Metronic's grey --ring: a grey ring on
     zinc-950 is barely visible, and a focus indicator that cannot be seen is a
     missing focus indicator. */
  --bz-color-focus-ring: color-mix(in srgb, var(--primary) 40%, transparent);

  /* Workspace layers: a quiet tinted canvas behind crisp business surfaces. */
  --bz-color-canvas: color-mix(in oklab, var(--background) 94%, var(--primary));
  --bz-color-wash: color-mix(in oklab, var(--card) 96%, var(--primary));
  --bz-color-grid-head: color-mix(in oklab, var(--secondary) 96%, var(--primary));
  --bz-color-hero: color-mix(in oklab, var(--primary) 24%, var(--color-zinc-950));
  --bz-color-hero-end: color-mix(in oklab, var(--primary) 48%, var(--color-zinc-950));
  --bz-color-hero-fg: var(--color-white);
  --bz-color-hero-muted: color-mix(in srgb, var(--color-white) 78%, transparent);
  --bz-color-hero-line: color-mix(in srgb, var(--color-white) 16%, transparent);

  /* Brand (overridable per tenant) */
  --bz-brand-primary: var(--bz-color-accent);
  --bz-brand-primary-hover: var(--bz-color-accent-hover);
  --bz-brand-accent: var(--bz-color-accent);
  /* Compatibility aliases — several pages/components reference these shorthand names.
     They indirect to the canonical --bz-color-* tokens, which in turn follow Metronic,
     so any code using them follows the theme with no duplication anywhere.
     Prefer the --bz-color-* names in new code. */
  --bz-text-1: var(--bz-color-fg);
  --bz-text-2: var(--bz-color-fg-muted);
  --bz-text-3: var(--bz-color-fg-subtle);
  --bz-text-muted: var(--bz-color-fg-muted);
  --bz-surface: var(--bz-color-surface);
  --bz-surface-2: var(--bz-color-surface-2);
  --bz-surface-3: var(--bz-color-surface-3);
  --bz-border: var(--bz-color-border);
  --bz-border-soft: var(--bz-color-border);
  --bz-primary: var(--bz-color-accent);
  --bz-primary-active: var(--bz-color-accent-hover);
  --bz-primary-600: var(--bz-color-accent);
  --bz-primary-50: color-mix(in srgb, var(--bz-color-accent) 14%, transparent);

  /* Radius */
  --bz-radius-sm: 6px;
  --bz-radius-md: 10px;
  --bz-radius-lg: 18px;
  --bz-radius-xl: 24px;
  --bz-radius-pill: 999px;

  /* Spacing scale */
  --bz-space-1: 4px;
  --bz-space-2: 8px;
  --bz-space-3: 12px;
  --bz-space-4: 16px;
  --bz-space-5: 24px;
  --bz-space-6: 32px;
  --bz-space-8: 48px;

  /* Type — Inter when available, otherwise fall back to the OS UI stack
     (Segoe UI Variable on Windows 11, San Francisco on macOS/iOS, Roboto
     on Android). Inter is NOT bundled; if a tenant wants to guarantee
     it, they can self-host the font and inject an @font-face via the
     TenantBrandOverride. Until then the fallback stack renders cleanly
     across all platforms. */
  --bz-font-sans: "Inter", "Segoe UI Variable", "Segoe UI", system-ui,
                  -apple-system, BlinkMacSystemFont, Roboto,
                  "Helvetica Neue", Arial, sans-serif;
  --bz-font-mono: ui-monospace, "Cascadia Mono", SFMono-Regular, Menlo,
                  Consolas, "Liberation Mono", monospace;
  --bz-fs-xs: 12px;
  --bz-fs-sm: 13px;
  --bz-fs-md: 14px;
  --bz-fs-lg: 16px;
  --bz-fs-xl: 20px;
  --bz-fs-2xl: 28px;
  --bz-fs-3xl: 34px;
  --bz-fw-regular: 400;
  --bz-fw-medium: 500;
  --bz-fw-semibold: 600;
  --bz-fw-bold: 700;
  --bz-lh: 1.5;
  --bz-lh-tight: 1.25;

  /* Motion — durations by element weight, easings by intent.
     ease-out is the default: it starts fast, so the UI reacts in the exact
     moment the user is watching. Never ease-in on an entrance or a hover —
     it delays the first frame and reads as sluggish at identical duration. */
  --bz-duration-press: 120ms;   /* button press feedback */
  --bz-duration-fast: 120ms;    /* hover, color, small state changes */
  --bz-duration-base: 180ms;    /* dropdowns, popovers, toasts */
  --bz-duration-slow: 280ms;    /* modals, panels, drawers */
  --bz-duration-reveal: 460ms; /* one-time route/card arrival */
  --bz-ease: cubic-bezier(0.23, 1, 0.32, 1);          /* strong ease-out — the default */
  --bz-ease-out: cubic-bezier(0.23, 1, 0.32, 1);      /* explicit alias for new code */
  --bz-ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);  /* movement across the screen */
  --bz-ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);   /* sheets/panels, iOS-like */

  /* Elevation — soft, layered shadows */
  --bz-shadow-sm: 0 1px 2px rgba(15, 23, 42, .06),
                  0 1px 1px rgba(15, 23, 42, .04);
  --bz-shadow-md: 0 4px 12px rgba(15, 23, 42, .08),
                  0 2px 4px rgba(15, 23, 42, .04);
  --bz-shadow-lg: 0 16px 40px rgba(15, 23, 42, .14),
                  0 4px 10px rgba(15, 23, 42, .06);

  /* Layout */
  --bz-nav-width: 260px;
  --bz-header-height: 56px;
  --bz-control-height: 32px;
  --bz-control-height-lg: 40px;
  --bz-workspace-bar-height: 68px;
  --bz-workspace-height: calc(100dvh - var(--bz-workspace-bar-height) - 2 * var(--bz-space-3) - 2 * var(--bz-space-5));
}

/* Dark mode. Metronic's own tokens carry the whole palette (see the header), so
   only the values it has no equivalent for live here.

   Shadows are the one thing that cannot be derived: a shadow is always black,
   and on a near-black surface it needs more opacity to register at all.

   There is deliberately NO @media (prefers-color-scheme: dark) copy of this.
   Metronic switches on the `dark` CLASS only, so an OS-preference block would
   darken these tokens while Metronic stayed light — a half-dark page. The
   bootstrap script in App.razor already resolves a stored `system` preference
   into an explicit class before first paint, which is what actually honours the
   OS setting. */
html.dark,
html[data-theme="dark"] {
  --bz-shadow-sm: 0 1px 2px rgba(0,0,0,.45);
  --bz-shadow-md: 0 4px 12px rgba(0,0,0,.50);
  --bz-shadow-lg: 0 16px 40px rgba(0,0,0,.60);
}

/* Charcoal dark palette (task 343 — GitLab #227). Metronic's .dark ships zinc-950 (#09090b) for
   the page, the card AND the pop-over, so the app read as pitch black with nothing separating the
   layers. This re-declares Metronic's own semantic tokens — once, here, not in the vendor
   stylesheet — as a soft charcoal elevation ramp (GitLab dark mode was the reference), and every
   --bz-* token, the DevExpress bridge in shell.css and every Metronic component follow from them.
   Light mode is untouched: only html.dark matches.

     page       --background   #1f1f23   L .014   foreground 15.7:1, muted 6.4:1
     card       --card         #27272c   L .021   foreground 14.2:1, muted 5.8:1
     pop-over   --popover      #2f2f35   L .029   foreground 12.7:1, muted 5.2:1  (drop-downs, dialogs)
     hover      --muted/accent #36363d   L .038   foreground 11.5:1, muted 4.7:1
     surface-2  --secondary    #3a3a41   L .043   foreground 10.8:1, muted 4.4:1  (grid headers, read-only)
     border #3f3f46 (zinc-700), input border #4a4a52, focus ring zinc-500

   --muted-foreground moves zinc-500 -> zinc-400: zinc-500 is 3.1:1 on the lighter card and under
   3:1 on a pop-over, too faint for secondary text. The accent (--primary) and every tenant brand
   colour are deliberately NOT touched. zinc-700 is a literal because the compiled Metronic build
   tree-shakes the unused --color-zinc-700.

   `html.dark` (0,1,1) out-ranks Metronic's `.dark` (0,1,0) whatever the load order. */
html.dark {
  --background: #1f1f23;
  --card: #27272c;
  --popover: #2f2f35;
  --muted: #36363d;
  --accent: #36363d;
  --secondary: #3a3a41;
  --muted-foreground: var(--color-zinc-400);
  --border: #3f3f46;
  --input: #4a4a52;
  --ring: var(--color-zinc-500);
  /* 60% brand, 40% foreground in oklab keeps the hue: default blue-600 becomes #73a3ff —
     6.6:1 on the page, 6.0 on a card, 5.3 on a pop-over, 4.8 on hover, 4.5 on surface-2,
     7.1 on the sidebar. A tenant brand colour is lifted the same way. */
  --bz-color-accent-text: color-mix(in oklab, var(--primary) 60%, var(--foreground));
}

/* The sidebar (<aside class="dark">) re-declares Metronic's .dark tokens on itself, so the block
   above never reaches it — in light mode it stays exactly as it was. In dark mode it stays a step
   DARKER than the page, but charcoal rather than pitch black; hover (--accent) moves with it or a
   hovered item would be the sidebar's own colour. */
html.dark .dark {
  --background: var(--color-zinc-900);
  --card: var(--color-zinc-900);
  --popover: var(--color-zinc-900);
  --muted: var(--color-zinc-800);
  --accent: var(--color-zinc-800);
}

/* Reduced motion: movement and infinite loops stop; the opacity fades that
   carry meaning (a toast arriving, the activity bar) keep a short duration.
   Reduced motion means fewer and gentler animations, not zero — killing the
   fades too would make state changes jarring rather than calmer, so
   --bz-duration-base is deliberately left intact. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --bz-duration-press: 1ms;
    --bz-duration-fast: 1ms;
    --bz-duration-slow: var(--bz-duration-base);
  }

  .bz-ai-chat-panel { animation: none; }
  .bz-progress-fill--indeterminate { animation: none; width: 100%; opacity: .55; }
  .bz-spinner { animation-duration: 1.6s; }
}
