/*
 * EVOrbit design system — token layer (status 1F).
 *
 * ONE definition of the platform's visual language, owned by the Control Plane and consumed
 * unchanged by CMS and RMS. Products must not redefine these values; they add component styles on
 * top. A second definition is how a "consistent" design system stops being consistent.
 *
 * Two layers, deliberately:
 *
 *   PRIMITIVES (--cp-palette-*) are raw values. They never appear in component CSS, because a
 *   component that reaches for a raw colour cannot be re-themed — the dark theme would have to
 *   restate every rule instead of a handful of tokens.
 *
 *   SEMANTIC tokens (--cp-surface-*, --cp-text-*, ...) name a ROLE. Component CSS uses only these,
 *   and the dark theme is then a short list of reassignments at the bottom of this file rather than
 *   a parallel stylesheet.
 *
 * CSP: this file has no @import and no reference to another origin — the self-hosted @font-face
 * url()s below are same-origin, exactly what `style-src 'self'` / `font-src 'self'` already permit
 * without an exception.
 */

/*
 * Inter, self-hosted. Reviewed against the "somewhere near" reference the owner shared
 * (2026-09-04): its most transferable trait was the typeface, not its marketing-hero layout or
 * role-picker/stat-chip content, neither of which matches how this product actually authenticates.
 *
 * Self-hosted rather than linked from a public font host, for one reason that is not optional
 * here: this platform's Content-Security-Policy (status 1.23) is `style-src 'self'` / `font-src
 * 'self'` by default, and a third-party font host is exactly the kind of dependency CP-35 already
 * found and removed once. Five static weights (400/500/600/700/800) cover every weight this
 * stylesheet set uses — 120 KB total, cached once, no third-party request on every page load.
 *
 * font-display:swap so text renders immediately in the system fallback and swaps in once Inter has
 * loaded, rather than sitting invisible during the fetch.
 */
@font-face {
    font-family: "Inter";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("/fonts/inter/inter-400.woff2") format("woff2");
}
@font-face {
    font-family: "Inter";
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("/fonts/inter/inter-500.woff2") format("woff2");
}
@font-face {
    font-family: "Inter";
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url("/fonts/inter/inter-600.woff2") format("woff2");
}
@font-face {
    font-family: "Inter";
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("/fonts/inter/inter-700.woff2") format("woff2");
}
@font-face {
    font-family: "Inter";
    font-style: normal;
    font-weight: 800;
    font-display: swap;
    src: url("/fonts/inter/inter-800.woff2") format("woff2");
}

/*
 * Space Grotesk, self-hosted the same way, as a distinct DISPLAY face for headings — this was
 * already the app pages' evident intent (`font-family:'Space Grotesk'` on every h1/h2/h3 across
 * control-plane-layout.css and site.css) but, like DM Sans, it was never actually loaded, so every
 * heading in the app has always silently rendered in the system fallback. A geometric display face
 * over Inter for body text is a deliberate, common pairing (distinct character at large sizes,
 * shared x-height family so they sit together comfortably) — genuine richness, not a font-count
 * reduction to one typeface everywhere. Weights 500/600/700 cover every heading declaration; a
 * requested 800 falls back to the nearest available weight (700), which is graceful, not broken.
 */
@font-face {
    font-family: "Space Grotesk";
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("/fonts/space-grotesk/sg-500.woff2") format("woff2");
}
@font-face {
    font-family: "Space Grotesk";
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url("/fonts/space-grotesk/sg-600.woff2") format("woff2");
}
@font-face {
    font-family: "Space Grotesk";
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("/fonts/space-grotesk/sg-700.woff2") format("woff2");
}

:root {
    /* ---------------------------------------------------------------- primitives */
    /* Blues carry structure and brand; greens carry "live"/charging, which is the domain's
       natural positive signal. Both scales run 50 (lightest) to 900 (darkest). */
    --cp-palette-blue-50: #f4f7fb;
    --cp-palette-blue-100: #edf1f6;
    --cp-palette-blue-200: #dbe6eb;
    --cp-palette-blue-300: #ccd5e1;
    --cp-palette-blue-400: #7b8799;
    --cp-palette-blue-500: #637087;
    --cp-palette-blue-600: #284252;
    --cp-palette-blue-700: #17394e;
    --cp-palette-blue-800: #12334a;
    --cp-palette-blue-900: #0b2b42;
    --cp-palette-blue-950: #081f34;
    --cp-palette-blue-1000: #061522;

    --cp-palette-accent-300: #74a7f5;
    --cp-palette-accent-400: #4a8cf0;
    --cp-palette-accent-500: #1768e5;
    --cp-palette-accent-600: #1355bc;

    --cp-palette-green-300: #38dfb8;
    --cp-palette-green-400: #19c59a;
    --cp-palette-green-500: #0d9b7c;
    --cp-palette-green-600: #087e68;
    --cp-palette-green-50: #edfffa;

    --cp-palette-amber-400: #e8a33d;
    --cp-palette-amber-500: #c47f17;
    --cp-palette-amber-50: #fff8ec;

    --cp-palette-red-300: #ff8a8a;
    --cp-palette-red-400: #ef6a6a;
    --cp-palette-red-500: #d33f3f;
    --cp-palette-red-600: #a92d2d;
    --cp-palette-red-50: #fff1f1;

    --cp-palette-neutral-0: #ffffff;
    --cp-palette-neutral-25: #f8fafc;
    --cp-palette-neutral-50: #f3f6f8;
    --cp-palette-neutral-600: #718592;

    /* ------------------------------------------------------------------ surfaces */
    --cp-surface-page: var(--cp-palette-neutral-25);
    --cp-surface-raised: var(--cp-palette-neutral-0);
    --cp-surface-sunken: var(--cp-palette-blue-100);
    --cp-surface-hover: var(--cp-palette-blue-50);
    --cp-surface-inverse: var(--cp-palette-blue-950);
    --cp-surface-overlay: rgba(8, 31, 52, 0.55);

    /* Navigation stays deliberately dark in both themes. These are semantic component roles,
       not a second palette: sidebar CSS must not reach into primitive colours directly. */
    --cp-nav-surface-start: var(--cp-palette-blue-950);
    --cp-nav-surface-end: var(--cp-palette-blue-1000);
    --cp-nav-text: var(--cp-palette-blue-300);
    --cp-nav-text-muted: var(--cp-palette-blue-400);
    --cp-nav-text-hover: var(--cp-palette-blue-100);
    --cp-nav-surface-hover: var(--cp-palette-blue-800);
    --cp-nav-active: var(--cp-palette-green-400);
    --cp-nav-active-text: var(--cp-palette-green-50);
    --cp-nav-active-soft-start: rgba(25, 197, 154, 0.18);
    --cp-nav-active-soft-end: rgba(25, 197, 154, 0.06);
    --cp-nav-shadow: 12px 0 30px rgba(7, 27, 46, 0.08);

    /* ---------------------------------------------------------------------- text */
    --cp-text-primary: var(--cp-palette-blue-900);
    --cp-text-secondary: var(--cp-palette-blue-600);
    --cp-text-muted: var(--cp-palette-blue-500);
    --cp-text-inverse: var(--cp-palette-neutral-0);
    --cp-text-accent: var(--cp-palette-accent-500);

    /* ------------------------------------------------------------------- borders */
    --cp-border-subtle: var(--cp-palette-blue-200);
    --cp-border-strong: var(--cp-palette-neutral-600);
    --cp-border-inverse: var(--cp-palette-blue-800);

    /* -------------------------------------------------------------------- intent */
    --cp-accent: var(--cp-palette-accent-500);
    --cp-accent-hover: var(--cp-palette-accent-600);
    --cp-accent-contrast: var(--cp-palette-neutral-0);
    --cp-accent-soft: var(--cp-palette-blue-50);

    --cp-success: var(--cp-palette-green-500);
    --cp-success-soft: var(--cp-palette-green-50);
    --cp-success-contrast: var(--cp-palette-blue-1000);
    --cp-success-border: rgba(13, 155, 124, 0.45);

    --cp-warning: var(--cp-palette-amber-500);
    --cp-warning-soft: var(--cp-palette-amber-50);
    --cp-warning-contrast: var(--cp-palette-blue-1000);

    --cp-danger: var(--cp-palette-red-500);
    --cp-danger-hover: var(--cp-palette-red-600);
    --cp-danger-soft: var(--cp-palette-red-50);
    --cp-danger-contrast: var(--cp-palette-neutral-0);
    --cp-danger-border: rgba(211, 63, 63, 0.45);

    --cp-control-disabled-surface: var(--cp-palette-neutral-50);
    --cp-control-disabled-border: var(--cp-palette-blue-100);
    --cp-control-disabled-text: var(--cp-palette-blue-400);

    /* --------------------------------------------------------------------- focus */
    /* One focus treatment everywhere. Never removed without a replacement: an outline that is
       merely invisible makes the product unusable by keyboard while looking fine in screenshots. */
    --cp-focus-ring: 0 0 0 2px rgba(23, 104, 229, 0.45);
    --cp-focus-outline: 2px solid var(--cp-accent);

    /* ----------------------------------------------------------------- elevation */
    --cp-shadow-sm: 0 1px 2px rgba(8, 31, 52, 0.06);
    --cp-shadow-md: 0 4px 12px rgba(8, 31, 52, 0.08);
    --cp-shadow-lg: 0 16px 40px rgba(8, 31, 52, 0.14);

    /* -------------------------------------------------------------------- shape */
    --cp-radius-sm: 6px;
    --cp-radius-md: 10px;
    --cp-radius-lg: 16px;
    --cp-radius-pill: 999px;

    /* ------------------------------------------------------------------ spacing */
    /* A 4px scale. Component CSS uses these rather than arbitrary pixel values, which is what
       keeps rhythm consistent between screens written months apart. */
    --cp-space-1: 4px;
    --cp-space-2: 8px;
    --cp-space-3: 12px;
    --cp-space-4: 16px;
    --cp-space-5: 24px;
    --cp-space-6: 32px;
    --cp-space-7: 48px;
    --cp-space-8: 64px;

    /* ---------------------------------------------------------------- typography
       Named --cp-font-size-*, NOT --cp-text-*: --cp-text-* is the colour namespace, and a size
       sharing that prefix makes 'the text tokens' ambiguous for anything reasoning over them.
       Caught by DesignTokenTests, which flagged three font sizes as colours missing dark values. */
    --cp-font-sans: "Inter", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
    --cp-font-display: "Space Grotesk", "Inter", "Segoe UI", system-ui, sans-serif;
    --cp-font-mono: "Cascadia Mono", Consolas, "SF Mono", Menlo, monospace;

    --cp-font-size-xs: 11px;
    --cp-font-size-sm: 12px;
    --cp-font-size-base: 14px;
    --cp-font-size-md: 16px;
    --cp-font-size-lg: 20px;
    --cp-font-size-xl: 26px;
    --cp-font-size-2xl: 34px;

    --cp-weight-regular: 400;
    --cp-weight-medium: 500;
    --cp-weight-semibold: 600;
    --cp-weight-bold: 700;

    --cp-leading-tight: 1.25;
    --cp-leading-normal: 1.5;

    /* ------------------------------------------------------------------- motion */
    /* The standard Material "ease-out" curve, not the browser's linear-ish default `ease`. It
       decelerates into its resting state rather than moving at a near-constant rate throughout,
       which is the difference between a hover/focus transition feeling considered and feeling like
       nothing was specified at all. Picked up from reviewing the reference site's own transitions. */
    --cp-transition-fast: 120ms cubic-bezier(0.4, 0, 0.2, 1);
    --cp-transition-base: 200ms cubic-bezier(0.4, 0, 0.2, 1);
}

/*
 * Dark theme.
 *
 * Only SEMANTIC tokens are reassigned — the primitives keep their meaning, and no component rule
 * is duplicated. If a component needs its own dark-mode rule, that is a signal it reached past the
 * semantic layer for a raw value.
 *
 * Not a simple inversion: surfaces lift as they come forward (page darkest, raised lighter), which
 * is how depth reads in dark UI, and the accent is brightened because a mid-blue that has enough
 * contrast on white does not have enough on near-black.
 */
@media (prefers-color-scheme: dark) {
    :root:not([data-cp-theme="light"]) {
        --cp-surface-page: var(--cp-palette-blue-1000);
        --cp-surface-raised: var(--cp-palette-blue-950);
        --cp-surface-sunken: var(--cp-palette-blue-900);
        --cp-surface-hover: var(--cp-palette-blue-800);
        --cp-surface-inverse: var(--cp-palette-neutral-0);
        --cp-surface-overlay: rgba(0, 0, 0, 0.65);

        --cp-text-primary: var(--cp-palette-blue-100);
        --cp-text-secondary: var(--cp-palette-blue-300);
        --cp-text-muted: var(--cp-palette-blue-400);
        --cp-text-inverse: var(--cp-palette-blue-950);
        --cp-text-accent: var(--cp-palette-accent-400);

        --cp-border-subtle: var(--cp-palette-blue-800);
        --cp-border-strong: var(--cp-palette-blue-400);
        --cp-border-inverse: var(--cp-palette-blue-200);

        --cp-accent: var(--cp-palette-accent-400);
        --cp-accent-hover: var(--cp-palette-accent-300);
        --cp-accent-contrast: var(--cp-palette-blue-1000);
        --cp-accent-soft: var(--cp-palette-blue-900);

        --cp-success: var(--cp-palette-green-400);
        --cp-success-soft: var(--cp-palette-blue-900);
        --cp-success-contrast: var(--cp-palette-blue-1000);
        --cp-success-border: rgba(25, 197, 154, 0.65);

        --cp-warning: var(--cp-palette-amber-400);
        --cp-warning-soft: var(--cp-palette-blue-900);
        --cp-warning-contrast: var(--cp-palette-blue-1000);

        --cp-danger: var(--cp-palette-red-300);
        --cp-danger-hover: var(--cp-palette-red-400);
        --cp-danger-soft: var(--cp-palette-blue-900);
        --cp-danger-contrast: var(--cp-palette-blue-1000);
        --cp-danger-border: rgba(255, 138, 138, 0.65);

        --cp-control-disabled-surface: var(--cp-palette-blue-900);
        --cp-control-disabled-border: var(--cp-palette-blue-800);
        --cp-control-disabled-text: var(--cp-palette-blue-400);

        --cp-focus-ring: 0 0 0 2px rgba(74, 140, 240, 0.55);

        /* Shadows barely read on dark surfaces; borders carry elevation instead. */
        --cp-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
        --cp-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.45);
        --cp-shadow-lg: 0 16px 40px rgba(0, 0, 0, 0.55);
    }
}

/* The explicit choice, set by theme-boot.js from the user's stored preference. Duplicated rather
   than shared with the media query above because the two must win in both directions: a user on a
   light OS who chooses dark, and a user on a dark OS who chooses light. */
:root[data-cp-theme="dark"] {
    --cp-surface-page: var(--cp-palette-blue-1000);
    --cp-surface-raised: var(--cp-palette-blue-950);
    --cp-surface-sunken: var(--cp-palette-blue-900);
    --cp-surface-hover: var(--cp-palette-blue-800);
    --cp-surface-inverse: var(--cp-palette-neutral-0);
    --cp-surface-overlay: rgba(0, 0, 0, 0.65);

    --cp-text-primary: var(--cp-palette-blue-100);
    --cp-text-secondary: var(--cp-palette-blue-300);
    --cp-text-muted: var(--cp-palette-blue-400);
    --cp-text-inverse: var(--cp-palette-blue-950);
    --cp-text-accent: var(--cp-palette-accent-400);

    --cp-border-subtle: var(--cp-palette-blue-800);
    --cp-border-strong: var(--cp-palette-blue-400);
    --cp-border-inverse: var(--cp-palette-blue-200);

    --cp-accent: var(--cp-palette-accent-400);
    --cp-accent-hover: var(--cp-palette-accent-300);
    --cp-accent-contrast: var(--cp-palette-blue-1000);
    --cp-accent-soft: var(--cp-palette-blue-900);

    --cp-success: var(--cp-palette-green-400);
    --cp-success-soft: var(--cp-palette-blue-900);
    --cp-success-contrast: var(--cp-palette-blue-1000);
    --cp-success-border: rgba(25, 197, 154, 0.65);

    --cp-warning: var(--cp-palette-amber-400);
    --cp-warning-soft: var(--cp-palette-blue-900);
    --cp-warning-contrast: var(--cp-palette-blue-1000);

    --cp-danger: var(--cp-palette-red-300);
    --cp-danger-hover: var(--cp-palette-red-400);
    --cp-danger-soft: var(--cp-palette-blue-900);
    --cp-danger-contrast: var(--cp-palette-blue-1000);
    --cp-danger-border: rgba(255, 138, 138, 0.65);

    --cp-control-disabled-surface: var(--cp-palette-blue-900);
    --cp-control-disabled-border: var(--cp-palette-blue-800);
    --cp-control-disabled-text: var(--cp-palette-blue-400);

    --cp-focus-ring: 0 0 0 2px rgba(74, 140, 240, 0.55);
    --cp-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
    --cp-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.45);
    --cp-shadow-lg: 0 16px 40px rgba(0, 0, 0, 0.55);
}

/* Universal border-box. The stylesheets were written ASSUMING this (padding + explicit sizes
   everywhere) but it was never declared, so every padded element with a width/height/min-height was
   oversized under the default content-box — e.g. login inputs rendering 64px tall against a 40px
   min-height. This is the standard modern baseline; it belongs in the token layer because every
   product loads it first. */
*, *::before, *::after {
    box-sizing: border-box;
}

/* Honour a reduced-motion preference across every product. Stated once, here, so no component has
   to remember it. */
@media (prefers-reduced-motion: reduce) {
    :root {
        --cp-transition-fast: 0ms;
        --cp-transition-base: 0ms;
    }
}

/* Focus visibility is a token-level guarantee, not a per-component decision. */
:focus-visible {
    outline: var(--cp-focus-outline);
    outline-offset: 2px;
}

/* Depth indentation for the permission tree. Replaces a per-element inline
   `style="--permission-depth:N"`, which a strict `style-src` blocks outright. */
.cp-depth-0 { --permission-depth: 0; }
.cp-depth-1 { --permission-depth: 1; }
.cp-depth-2 { --permission-depth: 2; }
