/* ============================================================
   Elioplus Design System - design tokens
   ============================================================

   Every global custom property the design system defines, and the only place a
   raw colour, size or radius is written down.

   Two layers, in this order:

     1. PRIMITIVES   raw values with no meaning attached (ramps, radii, shadows).
                     Nothing here names a role or a product concept.
     2. SEMANTICS    what a value is FOR (--ds-text-muted, --ds-border,
                     --ds-success). This is the layer a consuming application's
                     components should reach for; the primitives above exist so
                     these have somewhere to point.

   One neutral ramp. Tailwind gray and slate were both in use for the same roles
   in the application this came from, alongside five older Chakra-era greys.
   Every call site was classified by what it is FOR and moved onto the semantic
   layer, and the duplicate ramps are gone.

   Nothing in this file may name a product concept. A consuming application keeps
   its own brand values in its own stylesheet, linked after this one, where it may
   both add tokens and override any semantic defined here - see the load order in
   README.md.

   The MudBlazor theme a consumer builds has to agree with these values, because
   MudBlazor's theme is C# and cannot read CSS. Elioplus.DesignSystem.Theming
   .DesignTokens.FindDrift() reads this file back out of the assembly and reports
   any entry that has drifted.
   ============================================================ */
/* ── 1. Primitives ─────────────────────────────────────────── */

:root {
    /* Neutral - Tailwind "gray". The dominant ramp in the dashboard and admin. */
    --ds-gray-50:   #f9fafb;
    --ds-gray-100:  #f3f4f6;
    --ds-gray-200:  #e5e7eb;
    --ds-gray-300:  #d1d5db;
    --ds-gray-400:  #9ca3af;
    /* Off-ramp step. Tailwind has nothing between 400 and 500, and the boundary of an
       input needs 3:1 against both white and the alt surface; 400 manages 2.5 and 500 is
       heavy enough to read as filled. This is the lightest value that clears it (3.34). */
    --ds-gray-450:  #858d9b;
    --ds-gray-500:  #6b7280;
    --ds-gray-600:  #4b5563;
    --ds-gray-700:  #374151;
    --ds-gray-800:  #1f2937;
    --ds-gray-900:  #111827;

    --ds-white: #ffffff;

    /* White at partial opacity - text and fills sitting on a colour surface (the app
       bar, a filled button, a dark hero) rather than on --ds-surface. A five-step
       emphasis scale, closest to Material's own high/medium/disabled ladder: a90 for a
       heading or icon that reads as fully white, a75/a60 for body text one and two
       steps quieter, a40 for a faint fill, a12 for a hover/pressed tint. */
    --ds-white-a90: rgba(255, 255, 255, 0.9);
    --ds-white-a75: rgba(255, 255, 255, 0.75);
    --ds-white-a60: rgba(255, 255, 255, 0.6);
    --ds-white-a40: rgba(255, 255, 255, 0.4);
    --ds-white-a12: rgba(255, 255, 255, 0.12);

    /* Blue */
    --ds-blue-50:  #eff6ff;
    --ds-blue-100: #dbeafe;
    --ds-blue-200: #bfdbfe;
    --ds-blue-500: #3b82f6;
    --ds-blue-600: #2563eb;
    --ds-blue-700: #1d4ed8;
    --ds-blue-900: #1e3a8a;

    /* Indigo / violet */
    --ds-indigo-50:  #eef2ff;
    --ds-indigo-100: #e0e7ff;
    --ds-indigo-500: #6366f1;
    --ds-indigo-600: #4f46e5;
    --ds-indigo-700: #4338ca;

    /* Green */
    --ds-green-50:  #f0fdf4;
    --ds-green-100: #d1fae5;
    --ds-green-500: #10b981;
    --ds-green-600: #059669;
    --ds-green-700: #047857;
    --ds-green-800: #065f46;

    /* Amber */
    --ds-amber-100: #fef3c7;
    --ds-amber-500: #f59e0b;
    --ds-amber-600: #d97706;
    --ds-amber-800: #92400e;

    /* Amber, the light end - a warning strip's wash and edge. */
    --ds-amber-50:  #fffbeb;
    --ds-amber-300: #fcd34d;

    /* Red */
    --ds-red-50:  #fef2f2;
    --ds-red-100: #fee2e2;
    --ds-red-500: #ef4444;
    --ds-red-600: #dc2626;
    --ds-red-800: #991b1b;

    /* Slate 900 - the ink an overlay and a floating panel's shadow are mixed from.
       ElioplusTheme.BrandInk is the same value. */
    --ds-slate-900: #0f172a;

    /* Legacy Elioplus brand. The original elioplus.com blues, and the night and mist the
       startup loader paints with. Frozen values, not the system accent (that is
       --ds-primary): they are the skin of the split-screen login and of the startup
       loader, whose own --ds-login-* / --ds-loader-* tokens point here, and
       ElioplusTheme.BrandBar / BrandButton carry the two mid blues for the admin apps'
       dark palettes. */
    --ds-legacy-blue-50:  #f5fafd;
    --ds-legacy-blue-400: #3699ff;
    --ds-legacy-blue-600: #187de4;
    --ds-legacy-blue-800: #0d4fa8;
    --ds-legacy-steel:    #5e7388;
    --ds-legacy-night:    #1a1f2e;
    --ds-legacy-mist:     #9aa5b8;

    /* Type scale. The sizes in use, named once so the same size
       stops being written three ways - 12px, 0.75rem and .75rem were all the same
       thing, as were 14px/0.875rem and 13px/0.8125rem. Values are px because the rem
       values here were all authored against the 16px root and gain nothing from being
       relative. 13px is this system's body size; 14px is MudBlazor's. */
    --ds-text-10: 10px;
    --ds-text-11: 11px;
    --ds-text-12: 12px;
    --ds-text-13: 13px;
    --ds-text-14: 14px;
    --ds-text-15: 15px;
    --ds-text-16: 16px;
    --ds-text-18: 18px;
    --ds-text-20: 20px;
    --ds-text-22: 22px;
    --ds-text-24: 24px;
    --ds-text-28: 28px;
    --ds-text-32: 32px;

    /* Line height for a heading, which needs less than running text. */
    --ds-leading-tight: 1.3;
    --ds-leading-body: 1.5;

    /* Weights */
    --ds-weight-regular:  400;
    --ds-weight-medium:   500;
    --ds-weight-semibold: 600;
    --ds-weight-bold:     700;
    /* The wordmark's weight; nothing else is this heavy. */
    --ds-weight-heavy:    800;

    /* Radii - the sizes actually in use. */
    --ds-radius-sm:   6px;
    --ds-radius-md:   8px;
    --ds-radius-lg:   12px;
    /* A fully-rounded pill; used by DsStatusBadge. */
    --ds-radius-pill: 999px;

    /* The type family the system is designed against, and what html/body is set to.
       A consuming application overrides this in its own brand stylesheet. */
    --ds-font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;

    /* The face of the "Elioplus" wordmark. Nexa Heavy where the host loads it; the body
       family at a heavy weight everywhere else. */
    --ds-font-brand: 'Nexa Heavy', var(--ds-font-family);

    /* Code, keys, identifiers and anything read character by character (an API key, a
       one-time code, a log line). Use the ds-mono utility on markup. */
    --ds-font-mono: ui-monospace, 'SF Mono', Monaco, 'Cascadia Code', Consolas, monospace;

    /* Shadows. sm is the resting lift of a card on a page; md a raised panel; lg a card
       floating over a coloured backdrop (the auth card on its gradient). */
    --ds-shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.04);
    --ds-shadow-md: 0 4px 16px rgba(0, 0, 0, 0.07);
    --ds-shadow-lg: 0 20px 40px rgba(0, 0, 0, 0.15);
    /* A panel that slides in from the right edge (a drawer): the shadow falls to its left. */
    --ds-shadow-side: -8px 0 40px rgba(15, 23, 42, 0.12);
}

/* ── 2. Semantics ──────────────────────────────────────────── */

:root {
    /* Text. --ds-text-primary is the strong heading colour; --ds-text-body is the
       everyday paragraph colour. Both are in heavy use and are not the same value. */
    --ds-text-primary:   var(--ds-gray-900);
    --ds-text-body:      var(--ds-gray-700);
    --ds-text-secondary: var(--ds-gray-500);
    /* Muted is text a user still has to read - timestamps, counts, helper lines - so it
       has to clear 4.5:1. It used to be gray-400 at 2.5:1. Three *readable* grey levels
       cannot all pass on white and still look distinct, so the third level moved to a
       different job: --ds-text-disabled below, for content that is switched off or
       purely decorative, which WCAG exempts. */
    --ds-text-muted:     var(--ds-gray-500);
    --ds-text-disabled:  var(--ds-gray-400);
    --ds-text-inverse:   var(--ds-white);

    /* Surfaces */
    --ds-surface:        var(--ds-white);
    --ds-surface-alt:    var(--ds-gray-50);
    --ds-surface-sunken: var(--ds-gray-100);
    /* A neutral chip, count badge or overflow tag sits one step above sunken, so that it
       reads as a token placed ON a card rather than as a recess in it. */
    --ds-surface-chip:   var(--ds-gray-200);

    /* The dimmed backdrop behind a modal panel (a drawer's overlay). */
    --ds-scrim: rgba(15, 23, 42, 0.25);

    /* Lines. Four jobs, not one:
         --ds-border          the edge of a card or panel. Decorative: the surface is
                              identifiable without it, so it is not held to 3:1.
         --ds-divider         the hairline between rows in a list or table.
         --ds-border-emphasis a heavier edge - outlined buttons, hover and drop states.
         --ds-border-input    the boundary of a text field, which IS the affordance a
                              user has to see, so this one clears 3:1 (3.34 on white).
         --ds-border-hover    what an outlined control's edge darkens to on hover. It is
                              a transient state on an already-visible boundary, so it is
                              not held to 3:1 on its own. */
    --ds-border:          var(--ds-gray-200);
    --ds-divider:         var(--ds-gray-100);
    --ds-border-emphasis: var(--ds-gray-300);
    --ds-border-input:    var(--ds-gray-450);
    --ds-border-hover:    var(--ds-gray-400);

    /* The keyboard focus ring (base.css draws it on every link and button for
       :focus-visible; Ds* components use it for theirs). The accent, so the ring reads as
       "you are here" on the white and alt surfaces controls sit on. A coloured or dark band
       (a hero, a footer, an app bar) redefines it for its subtree to its own ink, usually
       --ds-text-inverse, so the ring stays visible there. */
    --ds-focus-ring:      var(--ds-primary);

    /* Accent. These are the system's default brand values, not a law: an application
       with its own palette redefines them in its brand stylesheet, which is linked
       after this file, and everything pointing at them follows.

       Whatever a consumer settles on, its MudBlazor theme has to carry the same
       values, or a Color.Primary control and a CSS rule render two different blues.
       DesignTokens.FindDrift() exists to catch exactly that. */
    --ds-primary:          #2f6fe4;
    --ds-primary-hover:    #2460cc;
    --ds-primary-strong:   var(--ds-blue-700);
    --ds-primary-surface:  var(--ds-blue-100);
    --ds-primary-subtle:   var(--ds-blue-50);
    --ds-secondary:        #596dd9;
    --ds-tertiary:         var(--ds-indigo-600);
    /* The tint and ink a tertiary icon tile or badge is painted with, matching the
       status pairs below. */
    --ds-tertiary-surface: var(--ds-indigo-100);
    --ds-tertiary-text:    var(--ds-indigo-700);

    /* The fill behind a brand mark (the icon disc on an auth card). A solid colour by
       default; an application may set a gradient here in its brand stylesheet, since
       the value is used as a background, never as a colour. */
    --ds-brand-fill:       var(--ds-primary);

    /* A hyperlink in body copy, not a button or a nav item - distinct from --ds-primary
       because a link sitting inside a paragraph of --ds-text-body needs to read as text
       first, at a value slightly darker/more saturated than the brand blue. */
    --ds-link:             #006bb7;
    --ds-link-hover:       #00588f;

    /* Status, each with the surface and on-surface text used by its badge.
       The base colours are the ones a filled button or chip is painted with, so each
       has to carry its own label legibly. Success, error and info sit one ramp step
       darker than the mid-tone for that reason - white on green-500 is 2.5:1, on
       green-700 it is 5.5:1. Amber is the exception: no amber that passes with white
       is still amber, so warning keeps its hue and takes dark ink instead. */
    --ds-success:         var(--ds-green-700);
    --ds-success-surface: var(--ds-green-100);
    --ds-success-text:    var(--ds-green-800);

    --ds-warning:          var(--ds-amber-500);
    --ds-warning-surface:  var(--ds-amber-100);
    --ds-warning-text:     var(--ds-amber-800);
    /* The ink a filled warning surface carries: white on amber-500 is 2.2:1. */
    --ds-warning-contrast: var(--ds-gray-900);
    /* A quieter warning strip than the badge surface: a pale wash with a visible edge. */
    --ds-warning-subtle:   var(--ds-amber-50);
    --ds-warning-border:   var(--ds-amber-300);

    --ds-error:           var(--ds-red-600);
    --ds-error-surface:   var(--ds-red-100);
    --ds-error-text:      var(--ds-red-800);

    --ds-info:            var(--ds-blue-600);
    --ds-info-surface:    var(--ds-blue-100);
    --ds-info-text:       var(--ds-blue-700);

    /* Blazor form validation and the error boundary. These are the framework
       template's own colours, kept at their original values and named here so an
       application can restyle them without overriding the rules in base.css. */
    --ds-valid:          #26b050;
    --ds-invalid:        #e50000;
    --ds-error-boundary: #b32121;
    /* The unhandled-error bar (#blazor-error-ui): the template's lightyellow strip and its
       upward shadow. */
    --ds-error-ui:        #ffffe0;
    --ds-error-ui-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
}
