@tailwind base;
@tailwind components;
@tailwind utilities;

/* ===========================================================================
   THEME LAYER (Phase 29)
   ===========================================================================

   Every colour token the portal uses is a CSS custom property here, and
   tailwind.config.ts points the SAME token names (ink, panel, panel2, line,
   mute, ghost, paper, accent, accent2, good, warn, bad) at them. That is the
   whole trick: `bg-panel`, `text-mute`, `border-line` keep working unchanged
   across finance, HR, inventory, work and the group cockpit — only the values
   under them differ per theme. No component grew a conditional class.

   WHY CHANNEL TRIPLETS (`--c-panel: 20 17 28`) rather than hex:
   the codebase leans hard on Tailwind's alpha modifier (`bg-good/15`,
   `bg-ink/85`, `bg-bad/20` — roughly 200 call sites). A hex custom property
   cannot take `/15`. Triplets composed as `rgb(var(--c-x) / <alpha-value>)`
   can. The convenience `--x: rgb(var(--c-x))` forms exist for plain CSS and
   for inline `style={{}}` props; inline tints compose alpha the same way,
   e.g. `rgb(var(--c-good) / 0.14)`.

   CASCADE — three blocks, no source-order hazard:
     :root, :root[data-theme="dark"]   dark, the product default
     :root:not([data-theme])           OS preference, first visit only
     :root[data-theme="light"]         explicit opt-in
   The middle block only matches when NOTHING is stamped on <html>, so it can
   never fight either explicit theme regardless of order. The inline script in
   app/layout.tsx stamps data-theme before first paint, so in practice the
   media block is the no-JS fallback.

   DARK IS THE DEFAULT AND THE IDENTITY. Light is opt-in and is NOT an
   inversion: it is a violet-biased paper ground (#F4F2FA, not #FFF) with its
   own accent family, because #E6B450 gold on paper is a 1.7:1 smear.
   Every text/background pair below is >= 4.5:1 (body) or >= 3:1 (large/UI);
   test/theme-contrast.test.ts fails the build if that stops being true.
   =========================================================================== */

:root,
:root[data-theme='dark'] {
  color-scheme: dark;

  /* Surfaces — obsidian */
  --c-ink: 10 9 16;         /* #0A0910 page */
  --c-panel: 20 17 28;      /* #14111C card */
  --c-panel2: 30 26 41;     /* #1E1A29 raised */
  --c-line: 46 41 64;       /* #2E2940 border */

  /* Text */
  --c-paper: 243 239 250;   /* #F3EFFA 16.5:1 on panel */
  --c-mute: 156 149 178;    /* #9C95B2  6.5:1 on panel */
  --c-ghost: 138 130 163;   /* #8A82A3  5.2:1 on panel — was #655D7C (3.0:1),
                               which failed AA on the dark ground per the
                               earlier design critique. Lifted here. */

  /* Accents + status */
  /* PHASE 42 — this is NO LONGER THE HOLDING'S BRAND COLOUR.
     Apostrophe's identity was decided on 2026-08-07: COLOR V2 of the option
     deck — indigo-violet #565CA2, pale blue, green, lime, terracotta, peach,
     near-black #1A1A1A, light grey. Gold appears nowhere in it. It was only
     ever here because the app began as the Gilgamesh command centre, and
     #E6B450 is Gilgamesh's Sunflower Gold #EBBD54 to within (5, 9, 4).
     V2's own primary cannot take this slot either: measured against the tokens
     around it, indigo-violet collides with the interaction indigo --c-wk on
     BOTH themes. Of V2's eight colours only the lime clears every collision,
     and lime is a companion swatch rather than the primary — so the holding now
     carries NO chrome accent at all. Its identity travels on the wordmark and
     the apostrophe glyph set, which is how V2 is actually built (a pale mark on
     a saturated ground, never an accent on a neutral one).
     WHAT THIS TOKEN STILL DOES: data emphasis, and only on the group deck —
     the budget "Actual" figure and Kpi tone="accent". That is the last
     conflation and it is redesign item 3, which needs a decision about what a
     neutral positive figure looks like rather than a rename. The value is
     UNCHANGED here on purpose: this phase moved usage, not hues. */
  --c-accent: 230 180 80;   /* #E6B450 */
  --c-accent2: 155 107 255; /* #9B6BFF violet */
  --c-good: 63 208 139;     /* #3FD08B */
  --c-warn: 245 158 11;     /* #F59E0B */
  --c-bad: 255 107 107;     /* #FF6B6B */

  /* Text/icon colour that sits ON a filled accent chip or button. In dark it
     IS the page ground, which is why 62 sites historically wrote `text-ink`.
     Separated so light can use white without those sites going invisible. */
  --c-onaccent: 10 9 16;    /* #0A0910 */

  /* Modal / sheet backdrop. On dark it IS the page ground, so nothing moves.
     It is a SEPARATE token because a scrim must stay dark on BOTH grounds — a
     light wash over a light page dims nothing, and the dialog it is supposed
     to lift stops reading as modal. */
  --c-scrim: 10 9 16;       /* #0A0910 */

  /* Work module identity (was hardcoded #818CF8 / #a5aeff / #93a0ff) */
  --c-wk: 129 140 248;      /* #818CF8 fills, active rules, dots */
  --c-wksoft: 165 174 255;  /* #a5aeff small text on panel (9.0:1) */
  --c-wkhover: 147 160 255; /* #93a0ff button hover */

  /* HR module — TARTEEB brand family on the portal ground */
  --c-hr-indigo: 69 67 114;        /* #454372 brand primary, fills */
  --c-hr-indigo-soft: 150 148 208; /* #9694D0 readable indigo (6.6:1). Lifted
                                      from #8B89C7 in Phase 29: the module's
                                      own `wash of itself` chip put it at
                                      4.2:1 inside its own tint on panel2. */
  --c-hr-yellow: 243 201 67;       /* #F3C943 brand accent (11.8:1) */

  /* Charts — validated against the card per CHARTS_SPEC_2026-07-31 s1.1 */
  --c-chart-s1: 187 138 43;  /* #BB8A2B gold snapped into the dark L band */
  --c-chart-s2: 155 107 255; /* #9B6BFF */
  /* s3-s6 were per-component hex literals until Phase 29.1. Every DARK value
     here is the byte-identical hue those components already shipped, so the
     dark theme does not move a pixel; only the light band is newly picked. */
  --c-chart-s3: 168 255 46;  /* #A8FF2E Sport City lime  (15.1:1) */
  --c-chart-s4: 0 230 195;   /* #00E6C3 Sport City aqua  (11.6:1) */
  --c-chart-s5: 45 212 191;  /* #2DD4BF Layout teal      (10.0:1) */
  --c-chart-s6: 56 189 248;  /* #38BDF8 sky, the aging 31-60 step and the
                                group donut's categorical extension (8.7:1) */
  --c-chart-track: 46 41 64; /* #2E2940 de-emphasis */

  /* ENTITY IDENTITY (Phase 34). These were raw hex in lib/entities/registry.ts
     and are used as CHART FILLS and status dots, not decoration — so they are
     graphical objects and owe 3:1 (WCAG 1.4.11). Four of the five dark values
     are byte-identical to the hex they replace, so dark does not move.
     TARTEEB is the exception and had to move: #454372 on the card measured
     2.07:1. Lifted along its own hue to #8A86D6 (5.2:1 on panel2). The brand
     indigo #454372 is unchanged everywhere it carries the TARTEEB brand — this
     token is the on-screen data colour, which is a different job. */
  /* PHASE 41 — the four real companies now wear their REAL brand hues, and the
     set is chosen AS A SET.

     Phase 34 tokenised these correctly and measured each one against the card.
     What a per-colour floor cannot see is whether two marks are the same colour
     AS EACH OTHER, and all four companies appear together in one bar chart, one
     treemap, one donut and one bubble map. Measured on the values Phase 34
     shipped:
       dark   ent-layout #2DD4BF vs --good #3FD08B = 1.06:1, 55 channel steps.
              A company's identity dot read as a "healthy" status colour.
       light  ent-gilgamesh #9A6B12 vs ent-sportcity #A64A08 = 1.24:1, 37 steps.
              Two indistinguishable bars on every group chart.
       light  ent-layout #299688 = 3.61:1 against onaccent, so the company name
              TreemapCell prints ON that cell was unreadable.
     Every one of those cleared its own 3:1 floor. They are PAIR failures.

     Three of the four hues were also not the company's. Mohammed supplied the
     brand guidelines on 2026-08-07 (TARTEEB 40pp, Gilgamesh 14pp, the Layout
     Interior collateral, an Apostrophe option deck), so they are now sourced
     rather than approximated. Saturation is held and only lightness moves —
     the same rule the chart series follow.

     SQUARE IS UNTOUCHED. Not incorporated, never summed, never a series
     (CFO-91). It is held fixed here and the other four are solved around it. */
  --c-ent-tarteeb: 117 115 173;   /* #7573AD  brand indigo #454372 lifted. Was
                                     #8A86D6 — same idea, but this also clears
                                     the pair checks below. */
  --c-ent-gilgamesh: 235 189 84;  /* #EBBD54  Sunflower Gold, the BRAND value.
                                     Was #E6B450, the portal's own chrome gold —
                                     which differs from the brand by (5, 9, 4)
                                     per channel, because this app began as the
                                     Gilgamesh command center and the holding
                                     rebrand changed strings, not the palette. */
  --c-ent-layout: 120 142 142;    /* #788E8E  the slate-sage line off Layout's
                                     own collateral, lifted. REPLACES #2DD4BF
                                     teal, which appears nowhere in their
                                     identity — and which their 45% partner has
                                     a login and has been seeing as their own
                                     company's colour. NOT their brass #D5B936:
                                     brass is the same hue family as Gilgamesh
                                     gold and the two are indistinguishable
                                     side by side. Brass stays the print seal. */
  --c-ent-sportcity: 249 115 22;  /* #F97316 unchanged — an SPV with no brand to
                                     encode, so there is nothing to correct */
  --c-ent-square: 148 163 184;    /* #94A3B8 unchanged */

  /* Composed decoration */
  --stage-glow-1: rgba(155, 107, 255, 0.1);
  --stage-glow-2: rgba(230, 180, 80, 0.07);
  --glass-top: rgba(30, 26, 41, 0.7);
  --glass-bottom: rgba(20, 17, 28, 0.7);
  --shadow-card: 0 1px 0 rgba(255, 255, 255, 0.03), 0 10px 30px -18px rgba(0, 0, 0, 0.8);
  --shadow-glow: 0 0 0 1px rgba(230, 180, 80, 0.15), 0 8px 40px -12px rgba(155, 107, 255, 0.35);
  --c-scroll-thumb: 46 41 64;
  --stripe: rgba(255, 255, 255, 0.018);
}

/* First visit, nothing stored, OS says light. Matches ONLY when <html> carries
   no data-theme, so it cannot override either explicit choice. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) {
    color-scheme: light;

    --c-ink: 244 242 250;
    --c-panel: 252 251 254;
    --c-panel2: 237 234 247;
    --c-line: 213 206 232;

    --c-paper: 23 19 31;
    --c-mute: 92 84 112;
    --c-ghost: 107 99 131;

    --c-accent: 116 84 17;
    --c-accent2: 100 47 206;
    --c-good: 10 95 53;
    --c-warn: 110 65 0;
    --c-bad: 168 30 30;

    --c-onaccent: 255 255 255;
    --c-scrim: 38 26 64;

    --c-wk: 84 76 208;
    --c-wksoft: 74 66 190;
    --c-wkhover: 71 65 184;

    --c-hr-indigo: 69 67 114;
    --c-hr-indigo-soft: 69 67 114;
    --c-hr-yellow: 107 83 0;

    --c-chart-s1: 154 107 18;
    --c-chart-s2: 109 59 214;
    --c-chart-s3: 90 150 5;
    --c-chart-s4: 7 151 129;
    --c-chart-s5: 41 150 136;
    --c-chart-s6: 17 143 199;
    --c-chart-track: 220 214 236;

    --c-ent-tarteeb: 69 67 114;
    --c-ent-gilgamesh: 46 31 18;
    --c-ent-layout: 103 122 122;
    --c-ent-sportcity: 197 84 5;
    --c-ent-square: 90 100 118;

    --stage-glow-1: rgba(109, 59, 214, 0.07);
    --stage-glow-2: rgba(138, 100, 20, 0.05);
    --glass-top: rgba(255, 255, 255, 0.85);
    --glass-bottom: rgba(245, 243, 251, 0.85);
    --shadow-card: 0 1px 0 rgba(255, 255, 255, 0.6), 0 10px 30px -20px rgba(38, 26, 64, 0.35);
    --shadow-glow: 0 0 0 1px rgba(138, 100, 20, 0.22), 0 8px 40px -14px rgba(109, 59, 214, 0.28);
    --c-scroll-thumb: 198 189 222;
    --stripe: rgba(23, 19, 31, 0.025);
  }
}

/* Explicit opt-in. Same values as the media block above; kept literal because
   plain CSS has no way to share a declaration list across two selectors that
   must not be merged (merging them would let the media block override an
   explicit choice). test/theme-tokens.test.ts asserts the two light blocks
   stay byte-identical, so drift fails the build. */
:root[data-theme='light'] {
  color-scheme: light;

  /* Surfaces — paper with a violet bias, never pure white. The page is the
     DARKEST of the three so cards lift off it, which is the inverse of the
     dark theme's ordering and the reason this is not an inversion. */
  --c-ink: 244 242 250;     /* #F4F2FA page */
  --c-panel: 252 251 254;   /* #FCFBFE card */
  --c-panel2: 237 234 247;  /* #EDEAF7 raised / inset */
  --c-line: 213 206 232;    /* #D5CEE8 border, 1.47:1 on the card — structure,
                               not noise; the dark theme's line reads 1.34:1 */

  /* Text */
  --c-paper: 23 19 31;      /* #17131F 17.7:1 on panel */
  --c-mute: 92 84 112;      /* #5C5470  6.9:1 on panel */
  --c-ghost: 107 99 131;    /* #6B6383  5.5:1 on panel */

  /* Accents + status. Gold cannot survive the trip to paper — #E6B450 is
     1.7:1 on #FCFBFE — so the light accent is the same hue driven down to a
     bronze that carries white text AND reads as text itself.
     These sit DARKER than the minimum a plain label needs, because the
     module-wide badge pattern is `bg-X/15 text-X`: the wash lifts the local
     background toward the text colour, and a token that only just clears AA
     on the bare card drops to ~3.5:1 inside its own chip. Every value below
     clears 4.5:1 against its own 5/10/15% wash on all three surfaces. */
  --c-accent: 116 84 17;    /* #745411 bronze, 6.8:1 text / 7.0:1 with white */
  --c-accent2: 100 47 206;  /* #642FCE deep violet, 7.2:1 */
  --c-good: 10 95 53;       /* #0A5F35 7.5:1 */
  --c-warn: 110 65 0;       /* #6E4100 8.4:1 — deliberately a full step darker
                               than good, so the two do not converge in
                               luminance the way a naive amber would */
  --c-bad: 168 30 30;       /* #A81E1E 7.1:1 */

  --c-onaccent: 255 255 255; /* white on every fill above, all >= 5.3:1 */
  --c-scrim: 38 26 64;       /* #261A40 — stays DARK on paper on purpose */

  --c-wk: 84 76 208;        /* #544CD0 fill (6.3:1 with white) */
  --c-wksoft: 74 66 190;    /* #4A42BE small text on panel (7.2:1) */
  --c-wkhover: 71 65 184;   /* #4741B8 hover DARKENS on paper, lightens on dark */

  --c-hr-indigo: 69 67 114;      /* #454372 unchanged: the TARTEEB brand primary
                                    is a fill on both grounds */
  --c-hr-indigo-soft: 69 67 114; /* the brand primary IS the readable step on
                                    paper (8.9:1); no lighter variant needed */
  --c-hr-yellow: 107 83 0;       /* #6B5300 TARTEEB yellow driven to 7.1:1 */

  /* Charts — the light band, re-picked rather than reused. #BB8A2B sits in the
     DARK lightness band and turns to mud on a #FCFBFE card. */
  --c-chart-s1: 154 107 18;  /* #9A6B12 4.5:1 on panel */
  --c-chart-s2: 109 59 214;  /* #6D3BD6 6.3:1 on panel */
  /* s3-s6: the SAME HUE as the dark value, driven down the lightness axis
     until it clears the 3:1 graphical floor with headroom. Hue and saturation
     are held; only L moves. Raw #A8FF2E is 1.20:1 on a #FCFBFE card — the
     worst mark in the portal — and #00E6C3 is 1.55:1, so these could not be
     reused across the ground any more than the gold could. */
  --c-chart-s3: 90 150 5;    /* #5A9605 lime  3.5:1 on panel */
  --c-chart-s4: 7 151 129;   /* #079781 aqua  3.5:1 on panel */
  --c-chart-s5: 41 150 136;  /* #299688 teal  3.5:1 on panel */
  --c-chart-s6: 17 143 199;  /* #118FC7 sky   3.5:1 on panel */
  --c-chart-track: 220 214 236; /* #DCD6EC de-emphasis, strictly below all */

  /* Entity identity on paper. Every value re-picked DOWN the lightness axis:
     the dark set is far too light on #FCFBFE (gold measures ~1.9:1 there).
     TARTEEB returns to the true brand indigo #454372, which on paper is
     14.9:1 and needs no lift. Each clears 3:1 on ink, panel and panel2. */
  --c-ent-tarteeb: 69 67 114;     /* #454372 the brand indigo itself */
  --c-ent-gilgamesh: 46 31 18;    /* #2E1F12 DARK COFFEE — a listed Gilgamesh
                                     brand primary, not a darkened gold. This is
                                     the one brand whose palette spans both
                                     lightness bands, so both themes get a real
                                     brand colour. It also breaks the collision
                                     the bronze-gold #9A6B12 had with Sport City
                                     (1.24:1, 37 steps): Dark Coffee separates by
                                     0.089 luminance with 9.8:1 of headroom. */
  --c-ent-layout: 103 122 122;    /* #677A7A slate-sage driven down. Was #299688,
                                     a darkened version of the invented teal, and
                                     3.61:1 against onaccent — the company name
                                     on its own treemap cell was unreadable. */
  --c-ent-sportcity: 197 84 5;    /* #C55405 — was #A64A08, which measured
                                     1.08:1 against --bad #A81E1E with 46 steps
                                     between them. An identity dot that reads as
                                     an error marker is worse than a dim one. */
  --c-ent-square: 90 100 118;     /* #5A6476 */

  --stage-glow-1: rgba(109, 59, 214, 0.07);
  --stage-glow-2: rgba(138, 100, 20, 0.05);
  --glass-top: rgba(255, 255, 255, 0.85);
  --glass-bottom: rgba(245, 243, 251, 0.85);
  --shadow-card: 0 1px 0 rgba(255, 255, 255, 0.6), 0 10px 30px -20px rgba(38, 26, 64, 0.35);
  --shadow-glow: 0 0 0 1px rgba(138, 100, 20, 0.22), 0 8px 40px -14px rgba(109, 59, 214, 0.28);
  --c-scroll-thumb: 198 189 222;
  --stripe: rgba(23, 19, 31, 0.025);
}

/* Convenience hex-equivalent forms for plain CSS and inline style props.
   Declared once, outside the theme blocks, so they resolve against whichever
   triplet set won the cascade. */
:root {
  --ink: rgb(var(--c-ink));
  --panel: rgb(var(--c-panel));
  --panel2: rgb(var(--c-panel2));
  --line: rgb(var(--c-line));
  --paper: rgb(var(--c-paper));
  --mute: rgb(var(--c-mute));
  --ghost: rgb(var(--c-ghost));
  --accent: rgb(var(--c-accent));
  --accent2: rgb(var(--c-accent2));
  --good: rgb(var(--c-good));
  --warn: rgb(var(--c-warn));
  --bad: rgb(var(--c-bad));
  --onaccent: rgb(var(--c-onaccent));
  --scrim: rgb(var(--c-scrim));
  --wk: rgb(var(--c-wk));
  --wksoft: rgb(var(--c-wksoft));
  --wkhover: rgb(var(--c-wkhover));
  --hr-indigo: rgb(var(--c-hr-indigo));
  --hr-indigo-soft: rgb(var(--c-hr-indigo-soft));
  --hr-yellow: rgb(var(--c-hr-yellow));
  --chart-s1: rgb(var(--c-chart-s1));
  --chart-s2: rgb(var(--c-chart-s2));
  --chart-s3: rgb(var(--c-chart-s3));
  --chart-s4: rgb(var(--c-chart-s4));
  --chart-s5: rgb(var(--c-chart-s5));
  --chart-s6: rgb(var(--c-chart-s6));
  --chart-track: rgb(var(--c-chart-track));
  --ent-tarteeb: rgb(var(--c-ent-tarteeb));
  --ent-gilgamesh: rgb(var(--c-ent-gilgamesh));
  --ent-layout: rgb(var(--c-ent-layout));
  --ent-sportcity: rgb(var(--c-ent-sportcity));
  --ent-square: rgb(var(--c-ent-square));
  /* The 2px gap colour between touching chart segments is the card surface. */
  --chart-surface: rgb(var(--c-panel));
  --focus-ring: rgb(var(--c-wk) / 0.6);
}

html,
body {
  background: var(--ink);
  color: var(--paper);
  -webkit-font-smoothing: antialiased;
}

/* Ambient backdrop for the command center. Cinematic on obsidian, a faint
   violet/gold wash on paper — the same two light sources, dialled down so
   they read as atmosphere rather than as stains on a light ground. */
.bg-stage {
  background:
    radial-gradient(900px 500px at 80% -10%, var(--stage-glow-1), transparent 60%),
    radial-gradient(800px 500px at 0% 0%, var(--stage-glow-2), transparent 55%),
    var(--ink);
}

/* Thin scrollbars to match the theme */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: rgb(var(--c-scroll-thumb)); border-radius: 8px; }
::-webkit-scrollbar-track { background: transparent; }

@layer components {
  .card {
    @apply bg-panel border border-line rounded-xl p-5;
  }
  .card-glass {
    @apply rounded-xl border border-line p-5;
    background: linear-gradient(180deg, var(--glass-top), var(--glass-bottom));
    backdrop-filter: blur(6px);
  }
  .kpi-label {
    @apply text-mute text-[11px] uppercase tracking-wider;
  }
  .kpi-value {
    @apply text-paper text-2xl font-semibold mt-1 tabular-nums;
  }
  .chip {
    @apply inline-flex items-center gap-1.5 text-[11px] px-2.5 py-1 rounded-full border border-line;
  }
  .tab-btn {
    @apply text-sm px-3.5 py-2 rounded-lg whitespace-nowrap transition border border-transparent;
  }
  .tab-btn-active {
    @apply bg-panel2 border-line text-paper;
  }
  .tab-btn-idle {
    @apply text-mute hover:text-paper hover:bg-panel;
  }
  /* Used by ported entity modules (Sport City). */
  .pill {
    @apply inline-flex items-center gap-1 text-[10px] font-semibold uppercase tracking-wider px-2 py-0.5 rounded-full;
  }
}

/* Projects module (Phase 14, W-12): visible keyboard focus on every
   interactive element inside the work shell — the module has real keyboard
   features (N, Cmd+K, arrows); invisible focus undermines them. */
[data-work] :is(button, a, input, select, textarea, summary):focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--focus-ring);
}

/* Projects module (W-14a): the task side-peek slides in; the backdrop fades. */
@keyframes work-peek-in {
  from { transform: translateX(100%); }
  to { transform: translateX(0); }
}
@keyframes work-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
/* Phase 21: the mobile "More" nav sheet rises from the bottom edge. */
@keyframes work-sheet-in {
  from { transform: translateY(100%); }
  to { transform: translateY(0); }
}

/* Subtle field stripes (Sport City). */
.pitch-stripes {
  background-image: repeating-linear-gradient(
    90deg,
    var(--stripe) 0px,
    var(--stripe) 64px,
    transparent 64px,
    transparent 128px
  );
}

/* Live pulse on the "live" indicator */
@keyframes pulse-dot {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}
.live-dot { animation: pulse-dot 1.8s ease-in-out infinite; }

input[type='range'] {
  -webkit-appearance: none;
  appearance: none;
  height: 4px;
  border-radius: 999px;
  background: var(--line);
  outline: none;
}
input[type='range']::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--accent);
  cursor: pointer;
  box-shadow: 0 0 0 4px rgb(var(--c-accent) / 0.18);
}
input[type='range']::-moz-range-thumb {
  width: 18px;
  height: 18px;
  border: none;
  border-radius: 50%;
  background: var(--accent);
  cursor: pointer;
}
