/* ═══════════════════════════════════════════════════════════════════════════
   MYSCORE  +  M3 MATERIAL THEME BUILDER PALETTES  +  SIDEBAR PRE-PAINT STATE
   MyScore is the house default, taken from the MyScore AI design spec.
   Seed hues: Monet Green 145 · Sunset Amber 70 · Electric Cyan 190 · Rose Berry 345

   Themes are just CSS variables in a selector — no `@plugin "daisyui/theme"`,
   therefore NO BUILD STEP. Plain stylesheet, linked AFTER public/assets/daisyui.css.

   ── ONE SOURCE OF TRUTH: data-theme on <html> ──────────────────────────────
   Selectors are `:root[data-theme="X"]` — deliberately (0,2,0), not plain
   `[data-theme="X"]` at (0,1,0). The previous version relied on
   `:root:has(input.theme-controller[value=X]:checked)` at (0,4,1) to win the
   cascade, and that is the only reason the light palettes appeared to work.

   A `.theme-controller` CANNOT coexist with a light/dark axis: a checked
   controller always applies its own value at (0,4,1), so it would override any
   `<palette>-dark` set via data-theme. The controller is therefore gone, and the
   extra specificity above is what makes data-theme reliable — it must beat both
   @theme's `:root` (0,1,0) and daisyui.css, regardless of where the browser
   Tailwind runtime injects its generated stylesheet.

   ── THEME VALUE MAP (palette × mode), resolved in JS and pre-paint ─────────
     MyScore  + light  →  data-theme="myscore"
     MyScore  + dark   →  data-theme="dark"     (the legacy key, kept as-is so
                                                 the glass / 3D engine, which
                                                 matches it exactly, keeps applying)
     Palette  + light  →  data-theme="<palette>"
     Palette  + dark   →  data-theme="<palette>-dark"
     mode=system       →  resolved to light/dark before being applied
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Monet Green 145 · light ─────────────────────────────────────────────── */
:root[data-theme="monet-green"] {
    color-scheme: light;

    --m3-base-100: oklch(98.5% 0.01 145);
    --m3-base-200: oklch(96% 0.02 145);
    --m3-base-300: oklch(93% 0.03 145);
    --m3-base-content: oklch(25% 0.04 145);
    --m3-primary: oklch(55% 0.15 145);
    --m3-primary-content: oklch(98% 0.01 145);
    --m3-secondary: oklch(60% 0.12 145);
    --m3-secondary-content: oklch(98% 0.01 145);
    --m3-accent: oklch(65% 0.18 145);
    --m3-accent-content: oklch(15% 0.03 145);
    --m3-neutral: oklch(30% 0.03 145);
    --m3-neutral-content: oklch(95% 0.01 145);
    --m3-info: oklch(70% 0.15 220);
    --m3-info-content: oklch(15% 0.02 220);
    --m3-success: oklch(65% 0.20 145);
    --m3-success-content: oklch(15% 0.03 145);
    --m3-warning: oklch(80% 0.15 70);
    --m3-warning-content: oklch(20% 0.03 70);
    --m3-error: oklch(65% 0.25 25);
    --m3-error-content: oklch(15% 0.04 25);

    --m3-radius-selector: 0.75rem;
    --m3-radius-field: 0.625rem;
    --m3-radius-box: 1.25rem;
    --m3-size-selector: 0.25rem;
    --m3-size-field: 0.25rem;
    --m3-border: 1px;
    --m3-depth: 1;
    --m3-noise: 0;
}

/* ── Monet Green 145 · dark ──────────────────────────────────────────────── */
:root[data-theme="monet-green-dark"] {
    color-scheme: dark;

    --m3-base-100: oklch(18% 0.02 145);
    --m3-base-200: oklch(16% 0.02 145);
    --m3-base-300: oklch(14% 0.02 145);
    --m3-base-content: oklch(88% 0.01 145);
    --m3-primary: oklch(78% 0.12 145);
    --m3-primary-content: oklch(15% 0.03 145);
    --m3-secondary: oklch(72% 0.10 145);
    --m3-secondary-content: oklch(15% 0.03 145);
    --m3-accent: oklch(75% 0.15 145);
    --m3-accent-content: oklch(15% 0.03 145);
    --m3-neutral: oklch(28% 0.02 145);
    --m3-neutral-content: oklch(85% 0.01 145);
    --m3-info: oklch(72% 0.12 220);
    --m3-info-content: oklch(0% 0 0);
    --m3-success: oklch(78% 0.15 145);
    --m3-success-content: oklch(15% 0.03 145);
    --m3-warning: oklch(83% 0.12 70);
    --m3-warning-content: oklch(16% 0.02 70);
    --m3-error: oklch(72% 0.18 25);
    --m3-error-content: oklch(14% 0.03 25);

    --m3-radius-selector: 0.75rem;
    --m3-radius-field: 0.625rem;
    --m3-radius-box: 1.25rem;
    --m3-size-selector: 0.25rem;
    --m3-size-field: 0.25rem;
    --m3-border: 1px;
    --m3-depth: 1;
    --m3-noise: 0;
}

/* ── Sunset Amber 70 · light ─────────────────────────────────────────────── */
:root[data-theme="sunset-amber"] {
    color-scheme: light;

    --m3-base-100: oklch(98% 0.01 70);
    --m3-base-200: oklch(96% 0.02 70);
    --m3-base-300: oklch(93% 0.03 70);
    --m3-base-content: oklch(25% 0.04 70);
    --m3-primary: oklch(55% 0.18 70);
    --m3-primary-content: oklch(98% 0.01 70);
    --m3-secondary: oklch(60% 0.14 70);
    --m3-secondary-content: oklch(98% 0.01 70);
    --m3-accent: oklch(65% 0.20 70);
    --m3-accent-content: oklch(15% 0.03 70);
    --m3-neutral: oklch(30% 0.03 70);
    --m3-neutral-content: oklch(95% 0.01 70);
    --m3-info: oklch(70% 0.15 220);
    --m3-info-content: oklch(15% 0.02 220);
    --m3-success: oklch(65% 0.20 145);
    --m3-success-content: oklch(15% 0.03 145);
    --m3-warning: oklch(80% 0.18 70);
    --m3-warning-content: oklch(20% 0.03 70);
    --m3-error: oklch(65% 0.25 25);
    --m3-error-content: oklch(15% 0.04 25);

    --m3-radius-selector: 0.75rem;
    --m3-radius-field: 0.625rem;
    --m3-radius-box: 1.25rem;
    --m3-size-selector: 0.25rem;
    --m3-size-field: 0.25rem;
    --m3-border: 1px;
    --m3-depth: 1;
    --m3-noise: 0;
}

/* ── Sunset Amber 70 · dark ──────────────────────────────────────────────── */
:root[data-theme="sunset-amber-dark"] {
    color-scheme: dark;

    --m3-base-100: oklch(18% 0.02 70);
    --m3-base-200: oklch(16% 0.02 70);
    --m3-base-300: oklch(14% 0.02 70);
    --m3-base-content: oklch(88% 0.01 70);
    --m3-primary: oklch(78% 0.15 70);
    --m3-primary-content: oklch(15% 0.03 70);
    --m3-secondary: oklch(72% 0.12 70);
    --m3-secondary-content: oklch(15% 0.03 70);
    --m3-accent: oklch(75% 0.18 70);
    --m3-accent-content: oklch(15% 0.03 70);
    --m3-neutral: oklch(28% 0.02 70);
    --m3-neutral-content: oklch(85% 0.01 70);
    --m3-info: oklch(72% 0.12 220);
    --m3-info-content: oklch(0% 0 0);
    --m3-success: oklch(78% 0.15 145);
    --m3-success-content: oklch(15% 0.03 145);
    --m3-warning: oklch(83% 0.15 70);
    --m3-warning-content: oklch(16% 0.02 70);
    --m3-error: oklch(72% 0.18 25);
    --m3-error-content: oklch(14% 0.03 25);

    --m3-radius-selector: 0.75rem;
    --m3-radius-field: 0.625rem;
    --m3-radius-box: 1.25rem;
    --m3-size-selector: 0.25rem;
    --m3-size-field: 0.25rem;
    --m3-border: 1px;
    --m3-depth: 1;
    --m3-noise: 0;
}

/* ── Electric Cyan 190 · light ───────────────────────────────────────────── */
:root[data-theme="electric-cyan"] {
    color-scheme: light;

    --m3-base-100: oklch(98% 0.01 190);
    --m3-base-200: oklch(96% 0.02 190);
    --m3-base-300: oklch(93% 0.03 190);
    --m3-base-content: oklch(25% 0.04 190);
    --m3-primary: oklch(55% 0.18 190);
    --m3-primary-content: oklch(98% 0.01 190);
    --m3-secondary: oklch(60% 0.14 190);
    --m3-secondary-content: oklch(98% 0.01 190);
    --m3-accent: oklch(65% 0.22 190);
    --m3-accent-content: oklch(15% 0.03 190);
    --m3-neutral: oklch(30% 0.03 190);
    --m3-neutral-content: oklch(95% 0.01 190);
    --m3-info: oklch(70% 0.18 220);
    --m3-info-content: oklch(15% 0.02 220);
    --m3-success: oklch(65% 0.20 145);
    --m3-success-content: oklch(15% 0.03 145);
    --m3-warning: oklch(80% 0.15 70);
    --m3-warning-content: oklch(20% 0.03 70);
    --m3-error: oklch(65% 0.25 25);
    --m3-error-content: oklch(15% 0.04 25);

    --m3-radius-selector: 0.75rem;
    --m3-radius-field: 0.625rem;
    --m3-radius-box: 1.25rem;
    --m3-size-selector: 0.25rem;
    --m3-size-field: 0.25rem;
    --m3-border: 1px;
    --m3-depth: 1;
    --m3-noise: 0;
}

/* ── Electric Cyan 190 · dark ────────────────────────────────────────────── */
:root[data-theme="electric-cyan-dark"] {
    color-scheme: dark;

    --m3-base-100: oklch(18% 0.03 190);
    --m3-base-200: oklch(16% 0.03 190);
    --m3-base-300: oklch(14% 0.03 190);
    --m3-base-content: oklch(88% 0.01 190);
    --m3-primary: oklch(78% 0.15 190);
    --m3-primary-content: oklch(15% 0.03 190);
    --m3-secondary: oklch(72% 0.12 190);
    --m3-secondary-content: oklch(15% 0.03 190);
    --m3-accent: oklch(75% 0.20 190);
    --m3-accent-content: oklch(15% 0.03 190);
    --m3-neutral: oklch(28% 0.02 190);
    --m3-neutral-content: oklch(85% 0.01 190);
    --m3-info: oklch(72% 0.15 220);
    --m3-info-content: oklch(0% 0 0);
    --m3-success: oklch(78% 0.15 145);
    --m3-success-content: oklch(15% 0.03 145);
    --m3-warning: oklch(83% 0.12 70);
    --m3-warning-content: oklch(16% 0.02 70);
    --m3-error: oklch(72% 0.18 25);
    --m3-error-content: oklch(14% 0.03 25);

    --m3-radius-selector: 0.75rem;
    --m3-radius-field: 0.625rem;
    --m3-radius-box: 1.25rem;
    --m3-size-selector: 0.25rem;
    --m3-size-field: 0.25rem;
    --m3-border: 1px;
    --m3-depth: 1;
    --m3-noise: 0;
}

/* ── Rose Berry 345 · light ──────────────────────────────────────────────── */
:root[data-theme="rose-berry"] {
    color-scheme: light;

    --m3-base-100: oklch(98% 0.01 345);
    --m3-base-200: oklch(96% 0.02 345);
    --m3-base-300: oklch(93% 0.03 345);
    --m3-base-content: oklch(25% 0.04 345);
    --m3-primary: oklch(55% 0.20 345);
    --m3-primary-content: oklch(98% 0.01 345);
    --m3-secondary: oklch(60% 0.16 345);
    --m3-secondary-content: oklch(98% 0.01 345);
    --m3-accent: oklch(65% 0.24 345);
    --m3-accent-content: oklch(15% 0.03 345);
    --m3-neutral: oklch(30% 0.03 345);
    --m3-neutral-content: oklch(95% 0.01 345);
    --m3-info: oklch(70% 0.15 220);
    --m3-info-content: oklch(15% 0.02 220);
    --m3-success: oklch(65% 0.20 145);
    --m3-success-content: oklch(15% 0.03 145);
    --m3-warning: oklch(80% 0.15 70);
    --m3-warning-content: oklch(20% 0.03 70);
    --m3-error: oklch(65% 0.25 25);
    --m3-error-content: oklch(15% 0.04 25);

    --m3-radius-selector: 0.75rem;
    --m3-radius-field: 0.625rem;
    --m3-radius-box: 1.25rem;
    --m3-size-selector: 0.25rem;
    --m3-size-field: 0.25rem;
    --m3-border: 1px;
    --m3-depth: 1;
    --m3-noise: 0;
}

/* ── Rose Berry 345 · dark ───────────────────────────────────────────────── */
:root[data-theme="rose-berry-dark"] {
    color-scheme: dark;

    --m3-base-100: oklch(18% 0.03 345);
    --m3-base-200: oklch(16% 0.03 345);
    --m3-base-300: oklch(14% 0.03 345);
    --m3-base-content: oklch(88% 0.01 345);
    --m3-primary: oklch(78% 0.18 345);
    --m3-primary-content: oklch(15% 0.03 345);
    --m3-secondary: oklch(72% 0.15 345);
    --m3-secondary-content: oklch(15% 0.03 345);
    --m3-accent: oklch(75% 0.22 345);
    --m3-accent-content: oklch(15% 0.03 345);
    --m3-neutral: oklch(28% 0.02 345);
    --m3-neutral-content: oklch(85% 0.01 345);
    --m3-info: oklch(72% 0.12 220);
    --m3-info-content: oklch(0% 0 0);
    --m3-success: oklch(78% 0.15 145);
    --m3-success-content: oklch(15% 0.03 145);
    --m3-warning: oklch(83% 0.12 70);
    --m3-warning-content: oklch(16% 0.02 70);
    --m3-error: oklch(72% 0.18 25);
    --m3-error-content: oklch(14% 0.03 25);

    --m3-radius-selector: 0.75rem;
    --m3-radius-field: 0.625rem;
    --m3-radius-box: 1.25rem;
    --m3-size-selector: 0.25rem;
    --m3-size-field: 0.25rem;
    --m3-border: 1px;
    --m3-depth: 1;
    --m3-noise: 0;
}

/* ── Bridge: theme layer (--m3-*) → consumer layer (--color-*, --radius-*, …) ─
   Every theme block in this file sets --m3-*. daisyui.css, and the prebuilt
   utilities in public/assets/daisyui.css, all read --color-* / --radius-* /
   --size-* / --border / --depth / --noise. This :root rule maps one layer onto
   the other EXACTLY ONCE, instead of repeating 28 aliases inside each of the
   ten theme blocks.

   Why it must exist: the `@theme` block in partials/head.blade.php used to
   declare the --color-* values itself. It no longer owns any theme value, so
   without this bridge the --m3-* tokens would be written and never read, and
   every palette would silently stop having any effect.

   The eight NON-COLOUR tokens carry var() fallbacks deliberately. They are a net
   for the one selector that cannot know which palette it is standing in for —
   the @media block below. Every palette block now sets all eight explicitly,
   because radii are NOT uniform across this system: myscore's field radius is a
   6.25rem pill against the 0.625rem here. Without a fallback, an unset --m3-*
   would make the property invalid for that theme — which silently flattens every
   card, button and input rather than erroring anywhere visible.

   Cascade: material-themes.css is linked AFTER daisyui.css, so this also
   outranks daisyui.css's own :root for the same properties.                     */
:root {
    --color-base-100: var(--m3-base-100);
    --color-base-200: var(--m3-base-200);
    --color-base-300: var(--m3-base-300);
    --color-base-content: var(--m3-base-content);
    --color-primary: var(--m3-primary);
    --color-primary-content: var(--m3-primary-content);
    --color-secondary: var(--m3-secondary);
    --color-secondary-content: var(--m3-secondary-content);
    --color-accent: var(--m3-accent);
    --color-accent-content: var(--m3-accent-content);
    --color-neutral: var(--m3-neutral);
    --color-neutral-content: var(--m3-neutral-content);
    --color-info: var(--m3-info);
    --color-info-content: var(--m3-info-content);
    --color-success: var(--m3-success);
    --color-success-content: var(--m3-success-content);
    --color-warning: var(--m3-warning);
    --color-warning-content: var(--m3-warning-content);
    --color-error: var(--m3-error);
    --color-error-content: var(--m3-error-content);

    --radius-selector: var(--m3-radius-selector, 0.75rem);
    --radius-field: var(--m3-radius-field, 0.625rem);
    --radius-box: var(--m3-radius-box, 1.25rem);
    --size-selector: var(--m3-size-selector, 0.25rem);
    --size-field: var(--m3-size-field, 0.25rem);
    --border: var(--m3-border, 1px);
    --depth: var(--m3-depth, 1);
    --noise: var(--m3-noise, 1);
}

/* ── MyScore · light — the MyScore AI design spec ────────────────────────────
   The house default, and the fallback for any unrecognised or absent
   preference. It replaced the palette previously labelled "Winter", and it is
   the only theme here whose values come from an external spec rather than from
   an M3 seed hue.

   The spec's own variable names are deliberately NOT introduced alongside these.
   Nothing in the project reads them, so they would be a second, drifting source
   of truth. Each one maps onto the M3 role that actually consumes it:
     --paper → base-100 · --paper-step → base-200 · --stone → base-300
     --ink → base-content and primary-content · --lime → primary
     --navy → secondary and info · --ink-2 → neutral
     #D3D2CC (--stone) serves again as neutral-content, and as the dark accent
     #1FA64A / #E5A919 / #D93829 → success / warning / error
   The spec's `--tab-radius` has no DaisyUI 5 consumer (v5 tabs read
   --radius-field), so it was dropped rather than kept as a value nothing reads.

   Shape is where this palette differs most from the others: --rounded-btn is a
   100px pill, so --m3-radius-field is 6.25rem and every .btn in the app renders
   fully round. --rounded-badge (6px) lands on --radius-selector, which is the
   token DaisyUI 5 uses for badges.

   The palette id is `myscore`, not `default` — the switcher radio value, both JS
   resolvers and this selector have to agree on one spelling.                  */
:root[data-theme="myscore"] {
    color-scheme: light;

    /* Every value below is oklch DERIVED FROM the spec's hex tokens, so each one
       round-trips back to the hex named beside it. Where the spec's own oklch
       triples disagreed with its hexes — 14 of 20 did — the hex won
       (dec-a8f0b79d51069c4a). Where the spec gave a hex for a role's fill but a
       different colour for the text on it, the CONTENT token is the one that
       moved; see success-content below.                                        */
    --m3-base-100: oklch(95.7528% 0.00673 97.353);  /* #F2F1EC --paper */
    --m3-base-200: oklch(92.0971% 0.01224 96.432);  /* #E7E5DC --paper-step */
    --m3-base-300: oklch(86.2869% 0.00824 98.897);  /* #D3D2CC --stone */
    --m3-base-content: oklch(15.0035% 0.00212 286.141); /* #0B0B0C --ink */
    --m3-primary: oklch(81.381% 0.18887 122.151);  /* #C8F031 --lime */
    --m3-primary-content: oklch(15.0035% 0.00212 286.141); /* ink on lime */
    --m3-secondary: oklch(33.5205% 0.09879 255.372); /* #0B3668 --navy */
    --m3-secondary-content: oklch(100% 0 0);        /* #FFFFFF */
    --m3-accent: oklch(15.0035% 0.00212 286.141);   /* --ink as the accent */
    --m3-accent-content: oklch(89.5631% 0.20366 121.544); /* lime on ink */
    --m3-neutral: oklch(20.1053% 0.00394 286.04);   /* #161618 --ink-2 */
    --m3-neutral-content: oklch(86.2869% 0.00824 98.897); /* #D3D2CC */
    --m3-info: oklch(33.5205% 0.09879 255.372);     /* navy */
    --m3-info-content: oklch(100% 0 0);
    --m3-success: oklch(63.6478% 0.17185 148.44);   /* #1FA64A */
    --m3-success-content: oklch(15.0035% 0.00212 286.141); /* ink: 5.9:1, white was 3.2:1 */
    --m3-warning: oklch(77.0967% 0.15413 81.954);   /* #E5A919 */
    --m3-warning-content: oklch(15.0035% 0.00212 286.141);
    --m3-error: oklch(58.5416% 0.1999 29.678);      /* #D93829 */
    --m3-error-content: oklch(100% 0 0);

    --m3-radius-selector: 0.375rem;                 /* --rounded-badge, 6px */
    --m3-radius-field: 6.25rem;                     /* --rounded-btn, 100px pill */
    --m3-radius-box: 1.125rem;                      /* --rounded-box, 18px */
    --m3-size-selector: 0.25rem;
    --m3-size-field: 0.25rem;
    --m3-border: 1px;
    --m3-depth: 1;
    --m3-noise: 1;
}

/* ── MyScore · dark — the spec's dark ramp, on the legacy dark key ───────────
   data-theme="dark" — the key is deliberately unchanged, so every existing
   [data-theme="dark"] rule in the glass / 3D engine in partials/head.blade.php
   keeps working untouched. The switcher writes this exact spelling for myscore +
   dark rather than "myscore-dark"; see themeValue() in public/js/theme-switcher.js.

   Unlike every other palette, this block used to inherit its eight non-colour
   tokens from the :root fallbacks above. It now states them, because they are no
   longer uniform across the palettes — myscore's field radius is a pill, so
   inheriting 0.625rem here would give dark mode square buttons and light mode
   round ones.

   Two fills are the spec's own oklch triples rather than derived hexes: success
   and error are the only roles the spec gives without a hex beside the numbers,
   so the numbers stand. error-CONTENT is ink rather than the white the spec
   lists there — white on that salmon measures 3.0:1, below AA, while ink
   measures 6.1:1, and ink is what the spec already puts on success and warning
   in this same block.                                                          */
:root[data-theme="dark"] {
    color-scheme: dark;

    --m3-base-100: oklch(15.0035% 0.00212 286.141); /* #0B0B0C pitch ink */
    --m3-base-200: oklch(20.1053% 0.00394 286.04);  /* #161618 ink-2 */
    --m3-base-300: oklch(29.9146% 0.00895 285.846); /* #2D2D32 dark stone */
    --m3-base-content: oklch(95.7528% 0.00673 97.353); /* #F2F1EC paper text */
    --m3-primary: oklch(89.5631% 0.20366 121.544);  /* #C8F031 lime, unchanged */
    --m3-primary-content: oklch(15.0035% 0.00212 286.141);
    --m3-secondary: oklch(51.4076% 0.10324 253.979); /* #3A69A1 brightened navy */
    --m3-secondary-content: oklch(100% 0 0);
    --m3-accent: oklch(86.2869% 0.00824 98.897);    /* #D3D2CC stone */
    --m3-accent-content: oklch(15.0035% 0.00212 286.141);
    --m3-neutral: oklch(20.1053% 0.00394 286.04);   /* #161618 */
    --m3-neutral-content: oklch(86.2869% 0.00824 98.897);
    --m3-info: oklch(51.4076% 0.10324 253.979);
    --m3-info-content: oklch(100% 0 0);
    --m3-success: oklch(68.5% 0.182 147.2);         /* spec triple, no hex given */
    --m3-success-content: oklch(15.0035% 0.00212 286.141); /* ink — 7.5:1 */
    --m3-warning: oklch(77.0967% 0.15413 81.954);   /* #E5A919 */
    --m3-warning-content: oklch(15.0035% 0.00212 286.141);
    --m3-error: oklch(68.2% 0.185 28.5);            /* spec triple, no hex given */
    --m3-error-content: oklch(15.0035% 0.00212 286.141); /* ink: 6.1:1, white was 3.0:1 */

    --m3-radius-selector: 0.375rem;
    --m3-radius-field: 6.25rem;
    --m3-radius-box: 1.125rem;
    --m3-size-selector: 0.25rem;
    --m3-size-field: 0.25rem;
    --m3-border: 1px;
    --m3-depth: 1;
    --m3-noise: 1;
}

/* ── Auto: follow the OS when no explicit choice has been made ───────────────
   Fires only when data-theme is absent, which now means storage is unavailable —
   both writers otherwise always set it. It therefore has to mirror the myscore
   dark values AND its radii, since those are no longer the :root fallbacks.
   Keep in step with data-theme="dark" above.                                   */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme]) {
        color-scheme: dark;

        --m3-base-100: oklch(15.0035% 0.00212 286.141);
        --m3-base-200: oklch(20.1053% 0.00394 286.04);
        --m3-base-300: oklch(29.9146% 0.00895 285.846);
        --m3-base-content: oklch(95.7528% 0.00673 97.353);
        --m3-primary: oklch(89.5631% 0.20366 121.544);
        --m3-primary-content: oklch(15.0035% 0.00212 286.141);
        --m3-secondary: oklch(51.4076% 0.10324 253.979);
        --m3-secondary-content: oklch(100% 0 0);
        --m3-accent: oklch(86.2869% 0.00824 98.897);
        --m3-accent-content: oklch(15.0035% 0.00212 286.141);
        --m3-neutral: oklch(20.1053% 0.00394 286.04);
        --m3-neutral-content: oklch(86.2869% 0.00824 98.897);
        --m3-info: oklch(51.4076% 0.10324 253.979);
        --m3-info-content: oklch(100% 0 0);
        --m3-success: oklch(68.5% 0.182 147.2);
        --m3-success-content: oklch(15.0035% 0.00212 286.141);
        --m3-warning: oklch(77.0967% 0.15413 81.954);
        --m3-warning-content: oklch(15.0035% 0.00212 286.141);
        --m3-error: oklch(68.2% 0.185 28.5);
        --m3-error-content: oklch(15.0035% 0.00212 286.141);

        --m3-radius-selector: 0.375rem;
        --m3-radius-field: 6.25rem;
        --m3-radius-box: 1.125rem;
        --m3-size-selector: 0.25rem;
        --m3-size-field: 0.25rem;
        --m3-border: 1px;
        --m3-depth: 1;
        --m3-noise: 1;
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   SIDEBAR COLLAPSE STATE — ONE SOURCE OF TRUTH
   ═══════════════════════════════════════════════════════════════════════════
   EVERY collapsed-state rule lives here, keyed on html[data-sidebar="collapsed"],
   and nowhere else.

   It used to be split in two: these pre-paint rules, plus a hand-maintained
   `.sidebar-menu-wrapper.is-collapsed` mirror in an inline <style> in
   sidebar.blade.php that Alpine applied at runtime. Two files, two selectors,
   two specificities, kept in sync by hand — and the mirror kept drifting. It was
   the origin of the collapsed-label bug, the empty-pop-out bug, and the
   duplicated tooltip rules. The attribute is now authoritative and the mirror is
   deleted.

   Why the attribute can replace Alpine's class outright: the min-width guard
   below is exactly what Alpine's `effectivelyCollapsed` computed
   (isCollapsed && !isMobile). A "collapsed" flag on a phone is a no-op either
   way, because mobile uses the off-canvas drawer instead of a rail — and keeping
   these rules UNSCOPED is what used to blank the labels in the mobile drawer for
   anyone who had collapsed the rail on desktop.

   The attribute is repainted from localStorage BEFORE first paint (the inline
   resolver in sidebar.blade.php) and again on every wire:navigate (its
   MutationObserver), so it is never stale. Alpine's toggleCollapse() writes it
   too, so the two can never disagree.

   The #app-sidebar id is deliberate: it outranks the .w-72 utility outright, so
   the attribute always wins without needing !important.
   ═══════════════════════════════════════════════════════════════════════════ */

@media (min-width: 1024px) {
    html[data-sidebar="collapsed"] #app-sidebar {
        width: 5rem; /* w-20 */
    }

    /* The nav must stop clipping so the theme flyout and the hover labels can
       escape it. When expanded it keeps the static overflow-y-auto it needs in
       order to scroll a long menu. */
    html[data-sidebar="collapsed"] #app-sidebar nav,
    html[data-sidebar="collapsed"] .sidebar-menu-wrapper,
    html[data-sidebar="collapsed"] .sidebar-menu-wrapper .menu,
    html[data-sidebar="collapsed"] .sidebar-menu-wrapper .menu li {
        overflow: visible !important;
    }

    html[data-sidebar="collapsed"] .sidebar-menu-wrapper .menu-title,
    html[data-sidebar="collapsed"] .sidebar-menu-wrapper .mary-hideable {
        display: none !important;
    }

    /* Icon-only rows: drop the label's inline padding and centre what is left. */
    html[data-sidebar="collapsed"] .sidebar-menu-wrapper .menu li > a {
        justify-content: center;
        padding-left: 0;
        padding-right: 0;
        position: relative;
        overflow: visible !important;
    }

    html[data-sidebar="collapsed"] .sidebar-menu-wrapper .menu li > a svg,
    html[data-sidebar="collapsed"] .sidebar-menu-wrapper .menu li > a i {
        margin: 0 !important;
    }

    /* ── Hover labels (tooltip emulation) ────────────────────────────────────
       The label is hidden at rest by the rule above and re-shown as a floating
       chip on hover. DaisyUI's own .tooltip would need duplicated markup; the
       label is already in the DOM, so it is reused. The `li > *` is the
       positioning context (`position: relative`, above).                      */
    html[data-sidebar="collapsed"] .sidebar-menu-wrapper .menu li > *:hover .mary-hideable {
        display: block !important;
        opacity: 1 !important;
        visibility: visible !important;
        position: absolute;
        left: calc(100% + 0.75rem);
        top: 50%;
        transform: translateY(-50%);
        background-color: var(--fallback-n, oklch(var(--n) / 1));
        color: var(--fallback-nc, oklch(var(--nc) / 1));
        padding: 0.4rem 0.75rem;
        border-radius: 0.375rem;
        font-size: 0.8125rem;
        font-weight: 500;
        z-index: 99999;
        white-space: nowrap;
        box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
        pointer-events: none;
    }
    html[data-sidebar="collapsed"] .sidebar-menu-wrapper .menu li > *:hover .mary-hideable::before {
        content: "";
        position: absolute;
        top: 50%;
        right: 100%;
        transform: translateY(-50%);
        border-width: 6px;
        border-style: solid;
        border-color: transparent var(--fallback-n, oklch(var(--n) / 1)) transparent transparent;
    }

    /* ── User profile box: avatar only ───────────────────────────────────────
       These three replace what Alpine's :class used to apply (scale-90, flex,
       justify-center) plus the two rules that hid the name/email.             */
    html[data-sidebar="collapsed"] .sidebar-user-wrapper {
        transform: scale(0.9);
        transform-origin: bottom;
        display: flex;
        justify-content: center;
    }
    html[data-sidebar="collapsed"] .sidebar-user-wrapper details summary > div > div:nth-child(2) {
        display: none !important;
    }
    html[data-sidebar="collapsed"] .sidebar-user-wrapper details summary > div {
        gap: 0 !important;
        justify-content: center;
        padding: 0 !important;
    }

    /* Logo row centres itself once the rail is narrow. */
    html[data-sidebar="collapsed"] .sidebar-logo-row {
        justify-content: center;
        padding-inline: 0;
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   THEME SWITCHER PANEL
   ═══════════════════════════════════════════════════════════════════════════
   Ends the sidebar's <nav> body — its own <ul class="menu">, as a two-level
   <li><details><summary><ul> item, sitting AFTER .sidebar-menu-wrapper and
   ABOVE the footer, which now holds only the user profile box.

   After the wrapper rather than inside it is deliberate and is the fix for the
   collapsed-state failure: it sidesteps the collapsed .mary-hideable rules
   entirely. Previously the item sat inside the wrapper, so the collapsed rules
   blanked the summary label AND the panel body, leaving an empty pop-out.      */

.theme-menu-item,
.theme-menu-item > details {
    position: relative;
}

@media (min-width: 1024px) {
    /* Collapsed rail: drop the summary text, keep the icon.
       <summary> is a child of <details>, not of the <li> — the old
       `.theme-menu-item > summary` selector never matched, so the label stayed visible. */
    html[data-sidebar="collapsed"] .theme-menu-item > details > summary .mary-hideable {
        display: none !important;
    }

    /* DaisyUI ships `.menu details { interpolate-size: allow-keywords;
       overflow: hidden }`. That `overflow: hidden` CLIPS THE FLYOUT AWAY: the
       panel sits at x = 5rem, entirely outside the ~4rem <details>, so it is
       erased rather than merely misplaced. Outranks `.menu details` here at
       (0,3,2) vs (0,1,1) — no !important needed.

       This is precisely what switching `fixed` → `absolute` exposed, and it is
       the one thing the earlier reasoning missed: overflow only clips an
       absolutely-positioned descendant when the clipping box is that element's
       CONTAINING BLOCK. Under `fixed` the containing block was the aside
       (overflow: visible), so <details> could not clip it; under `absolute` the
       containing block IS <details>, so the rule bites.

       Measured with the panel open, before this override: rect x 81..305,
       opacity 1, visibility visible, z-index 100001 — yet
       document.elementFromPoint() at its centre returned a <main> descendant,
       i.e. the popup was laid out correctly and completely invisible. */
    html[data-sidebar="collapsed"] .theme-menu-item > details {
        overflow: visible;
    }

    /* ── The flyout ──────────────────────────────────────────────────────────
       position:ABSOLUTE, anchored to .theme-menu-item — which is position:
       relative, set just above. It used to be `fixed; left: 5rem; bottom: 5rem`,
       and that `bottom` was hand-tuned to "footer padding + profile box": it only
       lined up because the trigger sat IN the footer, a fixed distance from the
       viewport bottom. The switcher now ends the <nav> BODY, above the footer, so
       its distance from the viewport bottom varies with the menu length and any
       hardcoded offset would drift. Anchoring to the trigger deletes the constant
       — and with it the "adjust this value if the profile box changes height"
       coupling that made the panel fragile.

       Two ancestors could clip this; both are handled. <nav> is one — it is
       released by `html[data-sidebar="collapsed"] #app-sidebar nav` in the
       SIDEBAR COLLAPSE STATE block above. That rule is now the ONLY thing
       stopping the nav's static overflow-y-auto from clipping this panel, since
       the release is no longer applied by Alpine. <details> is the other, and it
       needed the explicit override above. The aside is not a third: it computes
       overflow: visible.

       Geometry — HORIZONTAL IS A CONSTANT, DELIBERATELY NOT A PERCENTAGE.
       `.menu` is `width: fit-content` in DaisyUI (verified in
       public/assets/daisyui.css), so <details> is only as wide as its CONTENT.
       In the collapsed rail the summary is icon-only — the .mary-hideable label
       is display:none — so <details> measures ~3.5rem, NOT the 4rem of the
       rail's content box. `left: 100%` would therefore land the panel's left
       edge at ~4.5rem, i.e. INSIDE the 5rem rail, covering its right border
       instead of sitting beside it. (The <ul> now carries `w-full`, matching the
       sibling menu partial, so in practice <details> IS the rail width — but the
       offset is still written as a constant, so it cannot silently start
       depending on that class staying there.)

       What IS stable is <details>'s LEFT edge: the nav's px-2 (0.5rem) plus the
       ul's p-0, with no padding or border on the li or <details> itself (DaisyUI
       pads `li > *`, i.e. the summary, not the li). So the offset is the rail
       width MINUS that 0.5rem, and it holds whatever width the trigger happens
       to have. This reproduces the old `left: 5rem` exactly — that value was
       measured from the aside, which is why it never depended on the trigger.

       bottom:0 aligns the panel's bottom edge with the trigger's and grows it
       upward, which is what an item this low needs.

       It must NOT be laid out as a DaisyUI nested <ul>. The .menu rules add
       margin-inline-start and a ::before border to nested lists, which is what
       produced the shifted panel with a stray rule line. Everything below
       (margin/padding/border reset plus the ::before kill) cancels that.         */
    html[data-sidebar="collapsed"] .theme-menu-item > details[open] > ul {
        position: absolute;
        /* rail width (5rem) − the nav's px-2. NOT a percentage — see above. */
        left: calc(5rem - 0.5rem);
        bottom: 0;                 /* bottom-aligned with its trigger */
        top: auto;
        right: auto;

        /* Reset DaisyUI .menu nested-<ul> treatment */
        margin: 0;
        padding: 0.375rem;

        min-width: 14rem;
        width: max-content;
        max-width: 18rem;
        max-height: 70vh;
        overflow-x: visible;
        overflow-y: auto;

        background-color: var(--m3-base-100);
        border: 1px solid var(--m3-base-300);
        border-radius: var(--m3-radius-box, 1rem);
        box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.18), 0 4px 6px -4px rgb(0 0 0 / 0.18);
        z-index: 100001;
    }

    /* Kill the nested-menu connector line/indent decoration on the flyout. */
    html[data-sidebar="collapsed"] .theme-menu-item > details[open] > ul::before,
    html[data-sidebar="collapsed"] .theme-menu-item > details[open] > ul::after {
        content: none !important;
        display: none !important;
        border: 0 !important;
    }

    /* Every label inside the flyout must stay legible — the collapsed
       .mary-hideable rules would otherwise blank the whole menu. */
    html[data-sidebar="collapsed"] .theme-menu-item > details > ul .mary-hideable,
    html[data-sidebar="collapsed"] .theme-menu-item > details > ul .menu-title {
        display: block !important;
    }
}
