/* ============================================================
   Lumohub — tokens.css
   THE design tokens and the base reset, shared by the application (app.css) and the public
   site (public.css). Extracted from app.css so the two sheets cannot drift: a colour, a
   duration or the 87.5% root lived in one file and was linked by one host, which is exactly
   how a marketing page ends up a shade off the product.
   Load order on both hosts: the family's fonts.css and base.css (AD.Ui), then tokens.css, then the sheet that
   uses them. The family's sheets hold what every product draws the same way — the type pair's faces, the reset,
   the one focus ring, the one reduced-motion rule, the layout primitives, the chip, the signature stroke, the
   skip link — and read the tokens below (AD.Ui.TokenContract), so Lumohub's colours, scale and root stay its own.
   ============================================================ */

/* ══════════════════════════════════════════════
   1. TOKENS — Light (default)
   ══════════════════════════════════════════════ */
:root {
    /* REFERENCED, never recopied: five names for the same green meant five lines to keep in sync,
       and forgetting one is exactly how the app ended up showing several greens. */
    --clr-present: var(--clr-accent);
    --clr-present-bg: var(--clr-accent-pale);
    --clr-future: oklch(0.53 0.008 70); /* neutral — forecast, uncertain */
    --clr-future-bg: oklch(0.935 0.010 85);
    --clr-future-border: oklch(0.875 0.010 90);

    /* The brand: CORAL, hue 40 — Sami's THEME.md (2026-10-07), the first colour of the coral ·
       petrol · cream trio. It acts (buttons, links, the active place, focus, logo) and NEVER judges
       a figure. Two lightnesses, and the reason matters: the coral people recognise is the FILL
       (.72 .15 38 = #F27F5C), too light to carry text itself (2.6:1 on white) but perfect under
       dark text — every large flat area takes it through --clr-control. --clr-accent is the same
       family at L .55 (5.2:1) and takes everything that is or carries text.
       Coral and the loss red (22) both live in the warm hues: what separates them is lightness and
       role — the red is darker and duller and only ever marks a figure, a status or a rule.
       Same hue in both themes, only the lightness moves. The sRGB copies (manifest, meta tags, e-mail
       shell, invoice default, icons) hold #F27F5C and are locked by BrandAlignmentTests.
       History: Billy.tech's pink #E75A6A (hue 16.6) on 2026-10-06, replaced by Sami's own file. */
    --clr-accent: oklch(0.55 0.18 40);
    --clr-accent-pale: oklch(0.965 0.025 40);
    --clr-accent-fill: oklch(0.72 0.15 38);
    --clr-control: var(--clr-accent-fill);
    --clr-text-on-control: oklch(0.22 0.05 38);
    /* Dimmed accent for decorative rules and bars. A real token rather than opacity, which drifts. */
    --clr-accent-track: oklch(0.82 0.09 40);
    --clr-accent-dark: oklch(0.42 0.13 40); /* accent as TEXT on a pale bg — dark in light mode */
    --clr-accent-border: oklch(0.88 0.055 40);

    /* Page ground — a very light warm neutral, the MD's --bg (#F9F8F3). The colour of the light
       theme comes from three colours that each weigh (THEME.md): this ground and the white cards,
       the PETROL rail (--clr-rail), the coral. The CREAM (#F5EEDC) is a band, never a ground: the
       top bar (--clr-band) and the insets that sit on a white card (--clr-bg-alt). */
    --clr-bg: oklch(0.978 0.006 90);
    --clr-bg-alt: oklch(0.95 0.025 90);
    --clr-band: var(--clr-bg-alt);

    /* Surfaces (cards, dialogs) */
    --clr-surface: #ffffff;
    --clr-surface-raised: #ffffff;

    /* Borders — always neutral, never coloured on a container. */
    --clr-border: oklch(0.905 0.006 100);
    --clr-border-strong: oklch(0.86 0.008 95);

    /* Ink — a warm near-black (the MD's --fg). Contrast is measured on the CREAM, the tightest surface
       text sits on: muted text at L .53 lands on 4.57:1 there (5.28 on white). */
    --clr-text-primary: oklch(0.24 0.009 55);
    --clr-text-secondary: oklch(0.42 0.009 60);
    --clr-text-muted: oklch(0.53 0.008 70);
    /* Text on a coloured fill that is not the accent's: the logo's L, a success pill. The accent's fill carries
       dark ink (--clr-text-on-accent, the family's contract, below). */
    --clr-text-on-color: #ffffff;

    /* The RAIL — PETROL, the structure colour of the trio (THEME.md). It paints the sidebar, on a
       phone the tab bar and the "More" sheet, and the public site's footer, in both themes; each
       carries `.on-frame`, which maps the text, border, fill and accent tokens onto these.
       Petrol and the gain green are neighbours (205 vs 156): the rail stays very dark and dull
       (L ≤ .31, C ≤ .05) and never touches a figure, a state or a chart, or it reads as a gain.
       The active entry is a pill on --clr-rail-active with its label in the LIGHT coral: 6.6:1 on
       the rail, 4.8:1 on the pill (the MD's L .78 would measure 4.4:1 there). */
    --clr-rail: oklch(0.31 0.05 205);
    /* Opaque: a menu that opens inside the rail (the phone sheet's language picker) sits on it. */
    --clr-rail-raised: oklch(0.36 0.05 205);
    --clr-rail-active: oklch(0.39 0.055 205);
    --clr-rail-text: oklch(0.94 0.01 205);
    --clr-rail-text-muted: oklch(0.72 0.025 205);
    --clr-rail-accent: oklch(0.80 0.12 40);
    /* The family's frame (AD.Ui .on-frame): Lumohub's rail. */
    --clr-frame: var(--clr-rail);
    --clr-frame-raised: var(--clr-rail-raised);
    --clr-frame-text: var(--clr-rail-text);
    --clr-frame-text-muted: var(--clr-rail-text-muted);
    --clr-highlight: var(--clr-rail-accent);

    /* Petrol OFF the rail (Sami, 2026-10-07: "a third colour, a bit more present"): page titles,
       section headers and the monthly revenue chart — the current month in --clr-petrol, the past
       ones in --clr-petrol-soft. Never a breakdown, a category, a state or a button, and always dull
       (chroma ≤ .055, PaletteHueTests): lighter or more saturated, petrol reads as the gain green. */
    --clr-petrol: oklch(0.31 0.05 205);
    --clr-petrol-soft: oklch(0.60 0.045 205);
    --clr-rail-line: oklch(1 0 0 / 0.10);
    --clr-rail-line-strong: oklch(1 0 0 / 0.22);
    --clr-rail-fill: oklch(1 0 0 / 0.10);

    /* Neutral fill: gauge tracks, empty avatar */
    --clr-fill: oklch(0.89 0.009 75);

    /* PRINTED MATTER — the invoice document and its on-screen preview. Deliberately NOT derived from
       the app palette and NOT theme-aware: an invoice is white paper with dark ink whether the user
       browses in light or dark, and it is a legal document a client has already received. Kept in the
       exact hex values it has always rendered with, so re-issuing an old invoice cannot shift its
       colours; they are tokens all the same, so the print branding stays one place to change.
       The accent is the user's own brand colour (SettingsBrandTab), falling back to --clr-paper-ink. */
    --clr-paper: #ffffff;
    --clr-paper-alt: #f8f9fc;
    --clr-paper-ink: #1a1a2e;
    --clr-paper-ink-soft: #444444;
    --clr-paper-ink-muted: #666666;
    --clr-paper-ink-faint: #888888;
    --clr-paper-rule: #e2e8f0;

    /* The paper type scale: the on-screen invoice preview mirrors the PDF's point sizes (DocumentFrame),
       a document scale of its own, smaller than the interface's. */
    --fs-paper-xs: 0.54rem;
    --fs-paper-sm: 0.68rem;
    --fs-paper-md: 0.79rem;
    --fs-paper-lg: 0.86rem;
    --fs-paper-xl: 1.07rem;
    --fs-paper-title: 1.71rem;

    /* Third-party brand colour, fixed by its owner — never derived from our accent. Exact hex, like
       the paper palette: an approximation would no longer be LinkedIn's blue. */
    --clr-linkedin: #0a66c2;

    /* Drop shadows — translucent, used as they are (never mixed again: a color-mix of a translucent
       colour multiplies its alpha). Four weights, or every new card invents its own rgba(0,0,0,…):
       soft for a resting panel, the base for a lifted control, strong for a menu, float for what
       sits above the page (dialog, tour card). Declared ONCE per theme — a second, opaque copy
       further down this block silently won and put black shadows back in dark. */
    --clr-shadow-soft: oklch(0 0 0 / 0.06);
    --clr-shadow: oklch(0 0 0 / 0.10);
    --clr-shadow-strong: oklch(0 0 0 / 0.14);
    --clr-shadow-float: oklch(0 0 0 / 0.25);

    /* DATA-VIZ — a VIVID categorical palette (Sami, 2026-10-07: "vivid colours, red, blue, green,
       mauve"), which replaced the cold band of the THEME.md of the same morning. Eight hues apart from
       each other, each ≥ 3:1 on its card; between themes only the lightness moves. A colour never
       sits on text: a swatch beside a neutral label. Locked by PaletteHueTests. */
    --clr-viz-other: oklch(0.75 0.006 70); /* "Other": a residue, neutral */

    /* Expense categories, clients and any other split. Beyond seven a chart groups the rest in
       "Other". */
    --clr-cat-1: oklch(0.56 0.19 255); /* blue */
    --clr-cat-2: oklch(0.57 0.21 25); /* red */
    --clr-cat-3: oklch(0.60 0.17 150); /* green */
    --clr-cat-4: oklch(0.55 0.21 310); /* mauve */
    --clr-cat-5: oklch(0.66 0.16 70); /* amber */
    --clr-cat-6: oklch(0.60 0.11 195); /* teal */
    --clr-cat-7: oklch(0.60 0.22 350); /* pink */
    --clr-cat-8: oklch(0.47 0.19 280); /* indigo */

    /* Where the revenue goes (the money card): the tax takes the red and the net the green, so the
       palette agrees with the roles (THEME.md §0: red = loss, green = gain). */
    --clr-flow-charges: var(--clr-cat-1);
    --clr-flow-tax: var(--clr-cat-2);
    --clr-flow-retained: var(--clr-cat-5);
    --clr-flow-net: var(--clr-cat-3);

    /* Semantic states — the colours that JUDGE. Green 156 = gain (a variation, a saved amount, a
       favourable status), gold 92 = advice with time ahead, red 22 = loss/critical. They are earned,
       never decorative, and now fully decoupled from the brand accent. */
    --clr-success: oklch(0.46 0.12 156);
    --clr-success-bg: oklch(0.955 0.03 156);
    --clr-success-border: oklch(0.86 0.06 156);
    /* L 0.54 minimum: below it 10–12 px text on the soft bg drops under 4.5:1. */
    --clr-warning: oklch(0.54 0.13 92);
    --clr-warning-bg: oklch(0.97 0.05 92);
    --clr-warning-border: oklch(0.88 0.085 92);
    /* Advice IS the gold role (a recommendation with time ahead) — one hue, referenced. */
    --clr-advice: var(--clr-warning);
    /* Ledger red: darker and duller than the coral on purpose — that lightness gap IS the rule
       that keeps loss and brand apart, since both live in the warm hues. */
    --clr-danger: oklch(0.41 0.17 22);
    --clr-danger-bg: oklch(0.955 0.028 22);
    --clr-danger-border: oklch(0.85 0.07 22);
    --clr-info: oklch(0.48 0.09 250);
    --clr-info-bg: oklch(0.955 0.02 250);

    /* Day types (timesheet, calendar) — a categorical palette: these hues tell kinds of day
       apart, they signal neither threshold nor alert. Vacation reuses the gold on purpose; the
       three others sit 45° apart inside the viz band, and none of them may approach the accent —
       a worked day IS the accent (--clr-present), so a sick day at hue 312 was the same square. */
    --clr-day-vacation: oklch(0.54 0.13 92);
    --clr-day-vacation-bg: oklch(0.97 0.05 92);
    --clr-day-sick: oklch(0.50 0.13 195);
    --clr-day-sick-bg: oklch(0.955 0.03 195);
    --clr-day-training: oklch(0.42 0.16 285);
    --clr-day-training-bg: oklch(0.955 0.03 285);
    --clr-day-other: oklch(0.40 0.14 240);
    --clr-day-other-bg: oklch(0.955 0.03 240);


    /* Compositing neutrals: modal scrim, toggle knob */
    --clr-overlay: oklch(0.12 0.004 50 / 0.58);
    --clr-knob: #ffffff;

    /* Layout */
    --sidebar-width: 18rem;
    --topbar-height: 3.71rem;
    --content-padding: 2rem;

    /* Type — two families, not one: sans for the interface, serif for amounts AND titles.
       The contrast of the two is what lets the eye find the figure without hunting for it.
       No monospace anywhere: it says "terminal", not "accounting". */
    --font-sans: 'Instrument Sans', system-ui, -apple-system, sans-serif;
    --font-serif: 'Source Serif 4', Georgia, 'Times New Roman', serif;

    /* Type scale (THEME.md §4). Twelve ad-hoc sizes between .75 and 1 rem is not a scale: nothing
       stands out because everything is almost the same. Nine steps, named by size; the .fs-*
       utilities of app.css apply the token of their own name. 2xs is the section label, xs the size the
       pages used most (the former 0.79rem step merged into it on 2026-10-07); both floor at 12 px, the smallest
       text a page shows (audit 2026-10-31: 10.5 and 11.5 px on a laptop, where the root is 14 px) — the px is the
       floor THEME §3b allows, the rem still follows a larger system font. base is the root itself (inputs, body
       copy). A literal font-size is debt (DesignSystemRatchetTests). */
    --fs-2xs: max(0.75rem, 12px);
    --fs-xs: max(0.82rem, 12px);
    --fs-sm: 0.86rem;
    --fs-md: 0.93rem;
    --fs-base: 1rem;
    --fs-lg: 1.07rem;
    --fs-xl: 1.29rem;
    --fs-2xl: 1.71rem;
    --fs-3xl: 2.29rem;

    /* Spacing — the rhythm the stylesheets already used, named: a 2px grid at the 14px desktop
       root, each step called by that px value (--space-8 = 8px = 0.57rem; 9.1px on a phone,
       where the root is 16px). Margins, paddings and gaps take a step; an odd value is debt
       (PxUsageRatchetTests). */
    --space-2: 0.14rem;
    --space-4: 0.29rem;
    --space-6: 0.43rem;
    --space-8: 0.57rem;
    --space-10: 0.71rem;
    --space-12: 0.86rem;
    --space-14: 1rem;
    --space-16: 1.14rem;
    --space-18: 1.29rem;
    --space-20: 1.43rem;
    --space-24: 1.71rem;
    --space-28: 2rem;
    --space-32: 2.29rem;
    --space-36: 2.57rem;
    --space-40: 2.86rem;

    /* Radius (THEME.md §6): xs a progress bar, sm a small control, md a control or a nav entry,
       lg a card, xl a panel, pill a chip or a state badge. */
    --radius-xs: 0.29rem;
    --radius-sm: 0.43rem;
    --radius-md: 0.57rem;
    --radius-lg: 0.86rem;
    --radius-xl: 1.14rem;
    --radius-pill: 62.5rem;

    /* The family's stroke (../AtlasDigital/common/DESIGN-SYSTEM.md §1): exactly 3 px at the 14 px root, as Atlas's
       0.1875rem at its 16 px root — not 0.21rem: a border is floored to whole pixels and 2.94 px drew 2. The focus
       ring's width and the signature stroke's are the same value. */
    --stroke-signature: 0.2143rem;

    /* Motion — three durations, three curves, nothing else anywhere in the sheet.
       A symmetric `ease` makes every interaction feel like it is floating: the standard for a UI
       that answers is a curve that leaves fast and brakes (--ease-out). --ease-spring overshoots
       slightly and belongs to pressed states only; --ease-in-out to a panel that travels. */
    --dur-1: 0.1s;   /* state flip: colour, opacity, pressed */
    --dur-2: 0.18s;  /* hover, chips, tabs, rows */
    --dur-3: 0.28s;  /* entrances: modal, card, drawer */
    --ease-out: cubic-bezier(.2, .8, .2, 1);
    --ease-spring: cubic-bezier(.34, 1.4, .64, 1);
    --ease-in-out: cubic-bezier(.65, 0, .35, 1);

    /* Transitions — composed from the tokens above; callers use these three. */
    --transition-fast: var(--dur-1) var(--ease-out);
    --transition-base: var(--dur-2) var(--ease-out);
    --transition-sidebar: var(--dur-3) var(--ease-in-out);

    /* Shadows */
    --shadow-sm: 0 1px 0.29rem rgba(0, 0, 0, .07), 0 1px 1px rgba(0, 0, 0, .05);
    --shadow-md: 0 0.29rem 1.14rem rgba(0, 0, 0, .09), 0 1px 0.29rem rgba(0, 0, 0, .06);
    --shadow-lg: 0 0.57rem 2.29rem rgba(0, 0, 0, .11), 0 0.14rem 0.57rem rgba(0, 0, 0, .07);

    /* Relief — in light mode depth comes from the shadows above; the top edge stays invisible.
       See the dark block for why it exists. */
    --clr-edge: transparent;
    --clr-edge-strong: transparent;
    --elev-1: var(--shadow-sm);
    --elev-2: var(--shadow-md);

    /* Gradients. Both are VEILS of pure white and black laid OVER whatever colour is underneath,
       never a second copy of a brand colour: a card keeps --clr-surface, a button keeps
       --clr-control, and the veil only bends the light across it. That is what lets one pair of
       tokens give relief to every surface and every accent in both themes.
       --grad-surface: relief for a panel. --grad-lift: the same plus a deeper foot, for something
       that should look pressable.
       The light theme needs the SHADOW half, not the highlight half, and that is easy to get wrong:
       a white veil over a white card is nothing at all, which is exactly what shipped first and why
       only the dark theme looked sculpted. So here the light end stays for the tinted surfaces
       (page ground, striped rows) and the visible work is done by a faint dark foot.
       The foot stays LIGHTER than the ground under the card: at .042 over the near-white ground of
       2026-10-06 the bottom of every card turned darker than the page — depth upside down, a
       greyish card. .015 keeps the bend and the card above its ground. */
    --grad-surface: linear-gradient(180deg, oklch(1 0 0 / .5) 0%, oklch(1 0 0 / 0) 30%,
    oklch(0 0 0 / .015) 100%);
    --grad-lift: linear-gradient(180deg, oklch(1 0 0 / .18) 0%, oklch(1 0 0 / 0) 52%,
    oklch(0 0 0 / .07) 100%);

    /* The top bar: a BREATH of brand, not a wash. The first version opened at 32% and Sami read it
       as a coloured band rather than a surface — the colour has to be felt, not seen. What separates
       the bar from the content is now --elev-bar (relief), not the gradient. */
    --grad-bar: linear-gradient(90deg, color-mix(in oklab, var(--clr-accent) 11%, transparent) 0%,
    color-mix(in oklab, var(--clr-accent) 4%, transparent) 26%, transparent 52%);

    /* The bar floats a hair above the page: a soft drop shadow in light. In dark a shadow is
       invisible, so the separation becomes a lit bottom edge instead — same token, both themes. */
    --elev-bar: 0 0.14rem 0.71rem var(--clr-shadow);

    /* Colour scheme for the browser's native elements */
    color-scheme: light;

    /* ── The family's token contract (AD.Ui.TokenContract): Lumohub's own values under the names the shared
       components read. An alias follows its source in both themes. ── */
    --clr-text: var(--clr-text-primary);
    /* A control's edge (a field, a chip, an outlined button, a switch's track) says "this answers": 3:1 on the card
       and on the ground (WCAG 1.4.11), where a card's hairline reads 1.5:1. */
    --clr-field-border: oklch(0.65 0.008 95);
    /* The coral carries dark ink (white on it read 2.6:1); its hover leans toward the accent's text value. */
    --clr-text-on-accent: var(--clr-text-on-control);
    --clr-accent-fill-hover: color-mix(in oklab, var(--clr-control) 85%, var(--clr-accent));
    --clr-surface-hover: var(--clr-surface-raised);
    --shadow-rest: var(--elev-1);
    --shadow-lift: var(--elev-2);
    --clr-focus: var(--clr-accent);
    --clr-signature: var(--clr-accent);
    --ring-width: var(--stroke-signature);
    --dur-pulse: 1.4s;
    --reading-max: 68ch;
    /* A dense desktop workspace; the touch layer below grows every target to 44 px. */
    --target: 2.29rem;

    /* ── Lumohub's own ideas, through the knobs the family's sheets read ── */
    --stack-gap: var(--space-12);
    --grid-min: 15rem;
    --grid-gap: var(--space-14);
    --icon-size: 1em;
    --card-shadow: var(--elev-1);
    --card-image: var(--grad-surface);
    --card-padding-phone: var(--space-14);
    --chip-font-size: var(--fs-sm);
    --chip-color: var(--clr-text-muted);
    --switch-knob: var(--clr-knob);
    /* The stroke stands upright, as tall as the line, the width of the focus ring. */
    --signature-width: var(--stroke-signature);
    --signature-height: 1.1em;
    --signature-gap: var(--space-12);
    /* Empty states sit inside cards: centred and flat. */
    --empty-align: center;
    --empty-text-align: center;
    --empty-background: transparent;
    --empty-border-color: transparent;
    --empty-shadow: none;
    --empty-padding: var(--space-40) var(--space-20);
    /* The field (AD.Ui Field) reads like the hand-written ones: .form-label's size and colour, .form-hint's size. */
    --field-label-size: var(--fs-md);
    --field-label-color: var(--clr-text-secondary);
    --field-hint-size: var(--fs-xs);
    /* The selection a shade stronger than the family's: the coral is lighter than other accents. */
    --selection-mix: 32%;
    /* The family's button (AD.Ui), at Lumohub's density: its padding and size, the press, the hover's shadow, a quiet
       action in the secondary ink, the danger's softer hairline. */
    --btn-padding-y: var(--space-8);
    --btn-padding-x: var(--space-16);
    --btn-font-size: var(--fs-md);
    /* The family's field (AD.Ui .input) at Lumohub's density. */
    --input-padding: 0.64rem var(--space-12);
    --input-font-size: var(--fs-md);
    /* The page's title in the petrol, its size kept on a phone; the figure tile's figure. */
    --page-title-color: var(--clr-petrol);
    --page-title-size-phone: var(--fs-2xl);
    --kpi-size: 1.86rem;
    --section-label-size: var(--fs-2xs);
    --btn-press: 0.97;
    --btn-primary-shadow-hover: var(--shadow-md);
    --btn-quiet-color: var(--clr-text-secondary);
    --btn-quiet-padding-x: var(--space-16);
    --btn-danger-border: var(--clr-danger-border);
    --btn-sm-padding-x: 0.79rem;
}

@media (max-width: 900px) {
    :root {
        --target: 44px;
    }
}

/* ══════════════════════════════════════════════
   2. TOKENS — Dark (anthracite barely petrol)
   ══════════════════════════════════════════════ */
[data-theme="dark"] {
    --clr-present: var(--clr-accent);
    --clr-present-bg: var(--clr-accent-pale);
    /* "Future" = uncertain, hence neutral: any hue would pull it toward the accent. */
    --clr-future: oklch(0.68 0.008 70);
    --clr-future-bg: oklch(0.26 0.006 50);
    --clr-future-border: oklch(0.34 0.007 50);

    /* Same hue as light, lightness raised to L 0.76 so the coral reads on the dark ground. Below
       0.70 a large figure goes muddy; the fill keeps the SAME value, still with dark text. */
    --clr-accent: oklch(0.76 0.15 40);
    --clr-accent-fill: oklch(0.76 0.15 40);
    --clr-control: var(--clr-accent-fill);
    --clr-text-on-control: oklch(0.22 0.05 38);
    --clr-accent-pale: oklch(0.27 0.05 40);
    --clr-accent-track: oklch(0.50 0.09 40);
    --clr-accent-dark: oklch(0.80 0.13 40); /* accent as TEXT on a pale bg — light in dark mode */
    --clr-accent-border: oklch(0.38 0.07 40);

    /* Data-viz lifted for the dark ground — SAME hues, only the lightness moves. */
    --clr-viz-other: oklch(0.55 0.006 70);
    --clr-cat-1: oklch(0.70 0.16 255);
    --clr-cat-2: oklch(0.70 0.18 25);
    --clr-cat-3: oklch(0.76 0.17 150);
    --clr-cat-4: oklch(0.72 0.17 310);
    --clr-cat-5: oklch(0.80 0.15 70);
    --clr-cat-6: oklch(0.76 0.12 195);
    --clr-cat-7: oklch(0.74 0.17 350);
    --clr-cat-8: oklch(0.64 0.17 280);

    /* Ground — "anthracite barely petrol" (Sami's THEME.md, 2026-10-07), never #000: the saturated
       coral vibrates on pure black, and bg → surface needs two distinct steps to stack panels.
       Surfaces are a warm neutral (hue 50). History: a warm black (hue 17, L .165) from 2026-09-30. */
    --clr-bg: oklch(0.195 0.008 205);
    --clr-bg-alt: oklch(0.165 0.008 205);

    --clr-surface: oklch(0.238 0.006 50);
    --clr-surface-raised: oklch(0.275 0.007 50);
    /* The top bar keeps the card surface in the dark; the rail stays PETROL, the same hue as in
       light (its light text and light coral carry over from :root). */
    --clr-band: var(--clr-surface);
    --clr-rail: oklch(0.235 0.03 205);
    --clr-rail-raised: oklch(0.29 0.035 205);
    --clr-rail-active: oklch(0.31 0.04 205);
    --clr-rail-text-muted: oklch(0.70 0.02 205);
    --clr-petrol: oklch(0.78 0.045 205);
    --clr-petrol-soft: oklch(0.56 0.045 205);

    --clr-border: oklch(0.315 0.007 50);
    --clr-border-strong: oklch(0.385 0.008 50);
    --clr-field-border: oklch(0.53 0.008 50);

    --clr-text-primary: oklch(0.95 0.005 70);
    --clr-text-secondary: oklch(0.80 0.007 70);
    --clr-text-muted: oklch(0.68 0.008 70);
    /* The dark-mode solid fills are LIGHT (coral 0.76, red 0.645, green 0.78), so white on top
       would be unreadable. Text sitting on a solid fill turns very dark warm ink instead. */
    --clr-text-on-color: oklch(0.16 0.01 50);

    --clr-fill: oklch(0.335 0.007 50);

    --clr-success: oklch(0.78 0.14 156);
    --clr-success-bg: oklch(0.27 0.045 156);
    --clr-success-border: oklch(0.38 0.06 156);
    --clr-warning: oklch(0.84 0.14 92);
    --clr-warning-bg: oklch(0.28 0.055 92);
    --clr-warning-border: oklch(0.40 0.085 92);
    --clr-advice: var(--clr-warning);
    --clr-danger: oklch(0.645 0.16 22);
    --clr-danger-bg: oklch(0.26 0.055 22);
    --clr-danger-border: oklch(0.40 0.085 22);
    --clr-info: oklch(0.72 0.10 250);
    --clr-info-bg: oklch(0.28 0.04 250);

    --clr-day-vacation: oklch(0.84 0.14 92);
    --clr-day-vacation-bg: oklch(0.28 0.055 92);
    --clr-day-sick: oklch(0.78 0.12 195);
    --clr-day-sick-bg: oklch(0.28 0.05 195);
    --clr-day-training: oklch(0.80 0.12 285);
    --clr-day-training-bg: oklch(0.29 0.06 285);
    --clr-day-other: oklch(0.78 0.11 240);
    --clr-day-other-bg: oklch(0.28 0.05 240);


    --clr-overlay: oklch(0.03 0.002 50 / 0.72);
    --clr-knob: #ffffff;

    /* No shadows in dark — separation comes from the surface steps, not from glow. The shadow
       colours turn fully transparent, so a rule that composes one keeps its geometry and draws
       nothing. */
    --shadow-sm: none;
    --shadow-md: none;
    --shadow-lg: none;
    --clr-shadow-soft: oklch(0 0 0 / 0);
    --clr-shadow: oklch(0 0 0 / 0);
    --clr-shadow-strong: oklch(0 0 0 / 0);
    --clr-shadow-float: oklch(0 0 0 / 0);

    /* Relief in dark. With the shadows off, bg → surface is four points of lightness apart and a
       1px border: a card sits flat and nothing lifts on hover. A hairline of light along the TOP
       edge only reads as a surface catching the light from above — the standard way to give depth
       without a glow and without tinting the anthracite (it is pure white at 6%, chroma 0). */
    --clr-edge: oklch(1 0 0 / .06);
    --clr-edge-strong: oklch(1 0 0 / .1);
    --elev-1: inset 0 1px 0 var(--clr-edge);
    --elev-2: inset 0 1px 0 var(--clr-edge-strong);

    /* On black the relief is the other way round: a dark foot would vanish, so the highlight does
       the work — at a third of the light value, or every panel turns into a grey wash and the two
       surface steps stop reading. */
    --grad-surface: linear-gradient(180deg, oklch(1 0 0 / .05) 0%, oklch(1 0 0 / 0) 42%);
    --grad-lift: linear-gradient(180deg, oklch(1 0 0 / .13) 0%, oklch(1 0 0 / 0) 52%,
    oklch(0 0 0 / .14) 100%);

    --grad-bar: linear-gradient(90deg, color-mix(in oklab, var(--clr-accent) 15%, transparent) 0%,
    color-mix(in oklab, var(--clr-accent) 6%, transparent) 26%, transparent 52%);
    --elev-bar: 0 1px 0 var(--clr-edge-strong), 0 0.21rem 0.86rem oklch(0 0 0 / .38);

    /* Native elements (select, scrollbar, input) in dark mode */
    color-scheme: dark;
}

/* ══════════════════════════════════════════════
   2a. MOTION — the global contract
   ══════════════════════════════════════════════ */
/* The one reduced-motion rule is the family's (AD.Ui base.css): a visitor who asked their system for less motion
   gets the end state immediately. Two blocks further down do MORE than remove motion (the confetti disappears,
   the indeterminate bar becomes a full static bar) and stay where they are. */

/* ══════════════════════════════════════════════
   2c. FOCUS — one ring for the whole app
   ══════════════════════════════════════════════ */
/* The ring is the family's (AD.Ui base.css: --clr-focus, --ring-width, outside the element). Lumohub's classes that
   set `outline: none` on themselves at a higher specificity than an element's ring take it back here, so a
   keyboard user never loses the focus. */
.chip:focus-visible,
.nav-item:focus-visible,
.icon-btn:focus-visible {
    outline: var(--ring-width) solid var(--clr-focus);
    outline-offset: 2px;
}

/* The overlay's own focus ring would trace the whole viewport, the content's (the skip link's target)
   the whole page; an onboarding step's title takes the focus to be read, not to be used. */
.dialog-scrim:focus-visible,
.app-shell:focus-visible,
.app-content:focus-visible,
.login-shell > main:focus-visible,
.ob-title:focus-visible {
    outline: none;
}

/* ══════════════════════════════════════════════
   2c1. SIGNATURE STROKE — the family's mark
   ══════════════════════════════════════════════ */
/* A short bar slanted like a rising arrow before the label that opens a section (../.claude/DESIGN-SYSTEM.md §1):
   the app's page title, the public site's eyebrows — never a KPI's section label, never every card title. The
   family's `.signature` (AD.Ui base.css) draws it in Lumohub's proportions (--signature-* above): upright, the
   accent's text value (--clr-signature), a non-text mark at 3:1 or more on the cream — not a flat area, which
   would take --clr-control. Inside .on-frame the stroke takes the rail's accent. */

/* The family's endorsement — "a product by Atlas Digital SRL" — links to the publisher's site: a link, so the
   accent (the rail's inside .on-frame). One class for the public footer and the app's foot. */
.publisher-link {
    color: var(--clr-accent);
}

@media (hover: hover) {
    .publisher-link:hover {
        text-decoration: underline;
    }
}

/* ══════════════════════════════════════════════
   2c2. TIER TAG — the plan a feature needs
   ══════════════════════════════════════════════ */
/* THEME.md §5: the plan's NAME as a neutral outlined word — never a crown, never gold, never a
   colour of its own (an offer is not a state). One class for the app and the public site. */
.tier-tag {
    display: inline-flex;
    align-items: center;
    padding: 0 var(--space-6);
    border: 1px solid var(--clr-border);
    border-radius: var(--radius-pill);
    font-size: var(--fs-2xs);
    font-weight: 600;
    line-height: 1.6;
    letter-spacing: 0.02em;
    color: var(--clr-text-secondary);
    white-space: nowrap;
    vertical-align: middle;
}

/* ══════════════════════════════════════════════
   2d. ON RAIL — the petrol island
   ══════════════════════════════════════════════ */
/* The third colour (THEME.md §1b), shared by the app's sidebar and tab bar and the public footer.
   It re-maps the tokens its content reads, so labels, icons, the active pill, hairlines, the
   focus ring and the language and theme controls follow without a rule of their own. */
.on-frame {
    --clr-text-primary: var(--clr-rail-text);
    --clr-text-secondary: var(--clr-rail-text-muted);
    --clr-text-muted: var(--clr-rail-text-muted);
    --clr-border: var(--clr-rail-line);
    --clr-border-strong: var(--clr-rail-line-strong);
    --clr-fill: var(--clr-rail-fill);
    --clr-bg: var(--clr-rail);
    --clr-bg-alt: var(--clr-rail);
    --clr-surface: var(--clr-rail-raised);
    --clr-surface-raised: var(--clr-rail-raised);
    --clr-accent: var(--clr-rail-accent);
    --clr-accent-dark: var(--clr-rail-accent);
    --clr-accent-pale: var(--clr-rail-active);
    /* The family's aliases are computed where they are declared: re-declared here, they follow the rail. */
    --clr-text: var(--clr-text-primary);
    --chip-color: var(--clr-text-muted);
}



/* ══════════════════════════════════════════════
   3. RESET & BASE — the reset and the native defaults are the family's (AD.Ui base.css)
   ══════════════════════════════════════════════ */
html {
    /* 87.5% = 14px at the browser's default size, but respects the user's font-size setting —
       that is what makes rem units genuinely accessible. */
    font-size: 87.5%;
}

/* Phones read at the platform size: iOS and Android both set body text at 16px, and every rem of
   the interface scales with it. Breakpoint in px: a rem inside a media query is the browser's 16px. */
@media (max-width: 640px) {
    html {
        font-size: 100%;
    }
}

html, body {
    height: 100%;
    font-family: var(--font-sans);
    line-height: 1.6;
    background-color: var(--clr-bg);
    color: var(--clr-text-primary);
    -webkit-font-smoothing: antialiased;
    transition: background-color var(--transition-base), color var(--transition-base);
}

a {
    color: inherit;
    text-decoration: none;
}

button {
    cursor: pointer;
}

/* ── Language + theme controls — ONE copy for both hosts ──────────────────── */
/* The app topbar, the login layout and the marketing header render the same controls; this sheet is
   the one both hosts load, so the controls cannot drift apart again (they used to be copied in
   app.css and public.css). */
/* Language (and, on the marketing site, country) menus are native <details>: the app sets open from
   Blazor state, the marketing pages give them one shared name so opening one closes the other. */
.lt-controls {
    display: flex;
    align-items: center;
    gap: var(--space-8);
}

.lt-dd {
    position: relative;
}

.lt-dd-toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--space-4);
    height: 2.43rem;
    padding: 0 var(--space-10);
    border: 1px solid var(--clr-border);
    border-radius: var(--radius-md);
    background: var(--clr-bg-alt);
    color: var(--clr-text-secondary);
    font-size: var(--fs-sm);
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    list-style: none;
    transition: all var(--transition-fast);
}

.lt-dd-toggle::-webkit-details-marker {
    display: none;
}

@media (hover: hover) {
    .lt-dd-toggle:hover {
        background: var(--clr-surface);
        border-color: var(--clr-accent);
        color: var(--clr-text-primary);
    }
}

.lt-caret {
    font-size: 0.64rem;
    opacity: .7;
}

.lt-dd-menu {
    display: none;
    position: absolute;
    right: 0;
    top: calc(100% + 0.29rem);
    min-width: 9.5rem;
    background: var(--clr-bg);
    border: 1px solid var(--clr-border);
    border-radius: var(--radius-md);
    box-shadow: 0 0.57rem 1.71rem var(--clr-shadow-strong);
    padding: var(--space-4);
    z-index: 30;
}

details.lt-dd[open] > .lt-dd-menu {
    display: block;
}

.lt-dd-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 0.5rem var(--space-10);
    border: none;
    background: transparent;
    color: var(--clr-text-secondary);
    font-size: var(--fs-md);
    border-radius: calc(var(--radius-md) - 0.14rem);
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
    transition: all var(--transition-fast);
}

@media (hover: hover) {
    .lt-dd-item:hover {
        background: var(--clr-surface);
        color: var(--clr-text-primary);
    }
}

/* The current language or country: the state assistive technology reads is the state drawn. */
.lt-dd-item[aria-current="true"] {
    color: var(--clr-accent);
    font-weight: 600;
}

.lt-flag {
    display: inline-flex;
    align-items: center;
    line-height: 1;
}

/* Theme toggle — ONE button (role="switch", on = dark): a click flips the mode, light by default.
   The sun and the moon sit at both ends of the track and stay visible; the knob — a raised disc
   overlapping the track edge the way a physical switch does — slides under the current mode's
   icon, which wears the accent. "On" also tints the track, so the state reads at a glance.
   The state comes from <html data-theme> alone, written by the synchronous head script before
   the first paint: never briefly wrong, and the same CSS serves the Blazor app and the static
   marketing pages, which cannot know the stored mode at render time. */
.lt-switch {
    position: relative;
    display: inline-flex;
    align-items: center;
    height: 1.86rem;
    padding: 0;
    border: 1px solid var(--clr-border);
    border-radius: var(--radius-pill);
    background: var(--clr-bg-alt);
    color: inherit;
    font: inherit;
    cursor: pointer;
    transition: border-color var(--transition-base), background-color var(--transition-base);
}

@media (hover: hover) {
    .lt-switch:hover {
        border-color: var(--clr-border-strong);
    }
}

:root[data-theme="dark"] .lt-switch {
    background: var(--clr-accent-pale);
    border-color: var(--clr-accent-border);
}

.lt-switch-icon {
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.86rem;
    height: 1.86rem;
    color: var(--clr-text-muted);
    pointer-events: none;
    transition: color var(--transition-base);
}

.lt-switch-icon svg {
    display: block;
    width: 0.93rem;
    height: 0.93rem;
}

/* Surface, not accent — an accent disc under an accent icon is the same colour twice. Flush with
   the inner edge so it lines up with the icon it sits under. */
.lt-switch-knob {
    position: absolute;
    top: 50%;
    left: 0;
    width: 1.86rem;
    height: 1.86rem;
    margin-top: -0.93rem;
    border: 1px solid var(--clr-border-strong);
    border-radius: 50%;
    background: var(--clr-surface);
    background-image: var(--grad-surface);
    box-shadow: 0 0.14rem 0.43rem var(--clr-shadow-float);
    pointer-events: none;
    transition: translate var(--dur-2) var(--ease-spring);
}

:root[data-theme="dark"] .lt-switch-knob {
    translate: 1.86rem 0;
}

:root[data-theme="light"] .lt-switch-icon[data-mode="light"],
:root[data-theme="dark"] .lt-switch-icon[data-mode="dark"] {
    color: var(--clr-accent);
}

/* ── Buttons: the family's (AD.Ui base.css), a pill as DESIGN-SYSTEM §6 draws it (Sami, 2026-10-27); Lumohub's
   size, its quiet action's colour and its danger's hairline are knobs, set with the contract below. ── */

/* The skip link is the family's (AD.Ui base.css): the first tab stop of the app and of the public site. Without
   it a keyboard user crosses the whole sidebar (or the site's twelve-stop header) on every page. */
