/* Sponge & Stone theme bridge for the logged-in app.
   Maps Bootstrap 5.3 theme variables to the brand tokens from docs/design.md
   so stock components shift toward the brand before any screen is
   hand-restyled. The marketing pages consume the plum light values straight
   from :root (marketing.css keeps only its own tokens); dark values are
   plum-tinted, never gray.

   Two tiers. The primitives below are hsl() formulas: the neutrals are one
   palette rotated per accent theme, holding saturation and lightness exactly
   (that invariant is what keeps every contrast pair identical across
   themes), so only a hue moves. Each theme sets --hue once; the --hue-*
   pins record the small per-token drift the hand-rotated originals carry.
   A brand-new theme is one line, --hue, and every neutral follows; accents
   are hand-tuned per theme and mode, so themes state those as literals.
   The semantic layer is written once, in terms of the primitives, and dark
   mode redefines only primitives (plus its few true exceptions).

   The user's color from the profile page renders as data-sponge-theme on
   <body> (Turbo Drive replaces <body> but never touches <html> attributes),
   while data-bs-theme lives on <html>. Custom properties substitute var()
   where they are declared, so every block below must land on <html> for the
   formulas to see a theme's hue: theme blocks match through
   :root:has([data-sponge-theme]).

   The --bs-*-rgb comma triplets survive as literals because Bootstrap's
   compiled CSS reads them (a/a:hover, .navbar, .card, .table, .toast,
   .form-floating labels, and the text and bg utilities) and a comma triplet
   cannot be derived from a color in CSS. Our own stylesheets use
   color-mix() instead. */

:root,
[data-bs-theme="light"] {
  /* Plum, the default: the hue every formula below reads */
  --hue: 264;

  /* Primitives: the rotating neutrals, then the hand-tuned accent family */
  --paper: hsl(var(--hue) 26.32% 96.27%);
  --card: #FFFFFF;
  --ink: hsl(var(--hue-ink, var(--hue)) 30.19% 20.78%);
  --muted: hsl(var(--hue-muted, var(--hue)) 14.52% 47.25%);
  --line: hsl(var(--hue-line, var(--hue)) 31.15% 88.04%);
  --accent: hsl(var(--hue-accent, var(--hue)) 46.85% 56.47%);
  --accent-deep: hsl(var(--hue-accent-deep, var(--hue)) 38.26% 45.1%);
  --wash: hsl(var(--hue-wash, var(--hue)) 47.37% 92.55%);
  /* Where "deeper" leads: mixed into backdrops that intensify with depth */
  --depth-tint: hsl(var(--hue-depth-tint, var(--hue)) 53.85% 87.25%);

  /* The fixed families, clear of every accent hue: moss (success), rose
     (danger), sky (word), sea (info), gold (fact) */
  --moss: #2F7A57;
  --moss-wash: #E4F0E9;
  --rose: #A0344E;
  --rose-wash: #F7E3E7;
  --sky: #0D6EFD;
  --sky-wash: #E2EDFE;
  --sea: #2E5FA3;
  --sea-wash: #E4EBF5;
  --gold: #9A7009;
  --gold-wash: #F6EEDA;

  --display: ui-rounded, "SF Pro Rounded", "Hiragino Maru Gothic ProN", "Arial Rounded MT Bold", system-ui, sans-serif;

  /* Semantic layer: written once, resolved per theme through the primitives */
  --bs-body-bg: var(--paper);
  --bs-body-color: var(--ink);
  --bs-emphasis-color: hsl(var(--hue-emphasis, var(--hue)) 33.33% 14.12%);
  --bs-secondary-color: var(--muted);
  --bs-tertiary-color: hsl(var(--hue-muted, var(--hue)) 14.52% 47.25% / 0.75);
  --bs-secondary-bg: var(--wash);
  --bs-tertiary-bg: var(--paper);
  --bs-heading-color: var(--ink);

  --bs-primary: var(--accent);
  --bs-primary-text-emphasis: var(--accent-deep);
  --bs-primary-bg-subtle: var(--wash);
  --bs-primary-border-subtle: hsl(var(--hue-primary-border-subtle, var(--hue)) 48.28% 88.63%);
  --bs-success: var(--moss);
  --bs-success-text-emphasis: var(--moss);
  --bs-success-bg-subtle: var(--moss-wash);
  --bs-success-border-subtle: #C9E2D4;
  --bs-danger: var(--rose);
  --bs-danger-text-emphasis: var(--rose);
  --bs-danger-bg-subtle: var(--rose-wash);
  --bs-danger-border-subtle: #EFC9D2;
  --bs-info: var(--sea);
  --bs-info-text-emphasis: var(--sea);
  --bs-info-bg-subtle: var(--sea-wash);
  --bs-info-border-subtle: #C8D6EB;

  --bs-link-color: var(--accent-deep);
  --bs-link-hover-color: hsl(var(--hue-link-hover, var(--hue)) 38.14% 38.04%);

  --bs-border-color: var(--line);
  --bs-border-color-translucent: hsl(var(--hue-border-translucent, var(--hue)) 37.63% 36.47% / 0.14);
  --bs-border-radius: 0.875rem;
  --bs-border-radius-sm: 0.625rem;
  --bs-border-radius-lg: 1.25rem;
  --bs-border-radius-xl: 1.25rem;
  --bs-border-radius-pill: 999px;

  --bs-focus-ring-color: color-mix(in srgb, var(--accent) 20%, transparent);

  /* Bootstrap's compiled -rgb interface, stated per theme */
  --bs-body-bg-rgb: 245, 243, 248;
  --bs-body-color-rgb: 46, 37, 69;
  --bs-emphasis-color-rgb: 30, 24, 48;
  --bs-secondary-color-rgb: 111, 103, 138;
  --bs-tertiary-color-rgb: 111, 103, 138;
  --bs-secondary-bg-rgb: 232, 227, 245;
  --bs-tertiary-bg-rgb: 245, 243, 248;
  --bs-primary-rgb: 107, 92, 196;
  --bs-success-rgb: 47, 122, 87;
  --bs-danger-rgb: 160, 52, 78;
  --bs-info-rgb: 46, 95, 163;
  --bs-link-color-rgb: 85, 71, 159;
  --bs-link-hover-color-rgb: 71, 60, 134;
}

/* Plum's drift pins, scoped to plum being active: hand-rotated tokens sit a
   few degrees off the theme hue, and the pins record that. They must not
   apply when another value of data-sponge-theme is in play, so that a theme
   the blocks below don't know (a trial hue, a future theme) gets the clean
   one-hue rotation from the formula fallbacks alone. */
:root:not(:has([data-sponge-theme])) {
  --hue-ink: 256.875;
  --hue-muted: 253.7143;
  --hue-line: 258.9474;
  --hue-emphasis: 255;
  --hue-border-translucent: 252;
  --hue-accent: 248.6538;
  --hue-accent-deep: 249.5455;
  --hue-wash: 256.6667;
  --hue-depth-tint: 258.8571;
  --hue-link-hover: 248.92;
  --hue-primary-border-subtle: 257.14;
}

[data-bs-theme="dark"]:not(:has([data-sponge-theme])) {
  --hue-paper-dark: 263.0769;
  --hue-card-dark: 259.0909;
  --hue-ink-dark: 258.4615;
  --hue-muted-dark: 256.2162;
  --hue-line-dark: 256.875;
  --hue-border-translucent-dark: 253.9535;
  --hue-wash-dark: 254.4828;
  --hue-depth-tint-dark: 261.8182;
  --hue-accent-dark: 250.3226;
  --hue-accent-deep-dark: 250.2632;
  --hue-accent-fill-hover: 249.6;
  --hue-link-hover-dark: 251;
  --hue-primary-border-subtle-dark: 255.79;
}

[data-bs-theme="dark"] {
  color-scheme: dark;

  /* Dark primitives: same rotation, plum-tinted depths, never gray */
  --paper: hsl(var(--hue-paper-dark, var(--hue)) 26.53% 9.61%);
  --card: hsl(var(--hue-card-dark, var(--hue)) 28.95% 14.9%);
  --ink: hsl(var(--hue-ink-dark, var(--hue)) 41.94% 93.92%);
  --muted: hsl(var(--hue-muted-dark, var(--hue)) 23.27% 68.82%);
  --line: hsl(var(--hue-line-dark, var(--hue)) 25.81% 24.31%);
  --accent: hsl(var(--hue-accent-dark, var(--hue)) 54.39% 66.47%);
  --accent-deep: hsl(var(--hue-accent-deep-dark, var(--hue)) 62.3% 76.08%);
  /* Saturated fills for solid components: the lifted dark accent is too
     light behind white text, so fills keep the light-mode hue */
  --accent-fill: hsl(var(--hue-accent, var(--hue)) 46.85% 56.47%);
  --accent-fill-hover: hsl(var(--hue-accent-fill-hover, var(--hue)) 50.51% 61.18%);
  --wash: hsl(var(--hue-wash-dark, var(--hue)) 29.29% 19.41%);
  /* Dark theme deepens toward near-black plum rather than lightening */
  --depth-tint: hsl(var(--hue-depth-tint-dark, var(--hue)) 40.74% 5.29%);

  --moss: #5FAF87;
  --moss-wash: #1E3229;
  --rose: #E58BA1;
  --rose-wash: #3A1E27;
  --sky: #7FB2F0;
  --sky-wash: #1C2C4A;
  --sea: #5C8CCB;
  --sea-wash: #1B2840;
  --gold: #F2B34C;
  --gold-wash: #3A2E17;

  /* Dark's true semantic exceptions; everything else follows the primitives */
  --bs-emphasis-color: #FFFFFF;
  --bs-tertiary-color: hsl(var(--hue-muted-dark, var(--hue)) 23.27% 68.82% / 0.75);
  --bs-primary-border-subtle: hsl(var(--hue-primary-border-subtle-dark, var(--hue)) 27.14% 27.45%);
  --bs-success-text-emphasis: #7CC7A0;
  --bs-success-border-subtle: #2C4A3C;
  --bs-danger-border-subtle: #543040;
  --bs-info-text-emphasis: #8FB6E8;
  --bs-info-border-subtle: #2C3F63;
  --bs-link-hover-color: hsl(var(--hue-link-hover-dark, var(--hue)) 66.67% 82.35%);
  --bs-border-color-translucent: hsl(var(--hue-border-translucent-dark, var(--hue)) 36.75% 77.06% / 0.14);
  --bs-focus-ring-color: color-mix(in srgb, var(--accent) 25%, transparent);

  --bs-body-bg-rgb: 23, 18, 31;
  --bs-body-color-rgb: 237, 233, 246;
  --bs-emphasis-color-rgb: 255, 255, 255;
  --bs-secondary-color-rgb: 167, 157, 194;
  --bs-tertiary-color-rgb: 167, 157, 194;
  --bs-secondary-bg-rgb: 42, 35, 64;
  --bs-tertiary-bg-rgb: 23, 18, 31;
  --bs-primary-rgb: 139, 123, 216;
  --bs-success-rgb: 95, 175, 135;
  --bs-danger-rgb: 229, 139, 161;
  --bs-info-rgb: 92, 140, 203;
  --bs-link-color-rgb: 169, 156, 232;
  --bs-link-hover-color-rgb: 191, 180, 240;
}

/* ---------- accent themes ----------
   Each block pins its hues and states its hand-tuned accents; the formulas
   above do the rest. Blocks target <html> via :has() because that is where
   the formulas substitute. Tide sits brighter and colder than --sea (info),
   fern teal-leaning away from --moss (success), blossom magenta-leaning away
   from --rose (danger). No attribute means plum. */

:root:has([data-sponge-theme="tide"]) {
  --hue: 228;
  --hue-ink: 223.125;
  --hue-muted: 221.1429;
  --hue-line: 227.3684;
  --hue-border-translucent: 219.4286;
  --accent: #2B6FD3;
  --accent-deep: #1F55A8;
  --wash: #E1EBFA;
  --depth-tint: #C9DBF4;
  --bs-emphasis-color: #181F30;
  --bs-primary-border-subtle: #CFDFF6;
  --bs-link-hover-color: #17458C;
  --bs-body-bg-rgb: 243, 244, 248;
  --bs-body-color-rgb: 37, 46, 69;
  --bs-emphasis-color-rgb: 24, 31, 48;
  --bs-secondary-color-rgb: 103, 114, 138;
  --bs-tertiary-color-rgb: 103, 114, 138;
  --bs-secondary-bg-rgb: 225, 235, 250;
  --bs-tertiary-bg-rgb: 243, 244, 248;
  --bs-primary-rgb: 43, 111, 211;
  --bs-link-color-rgb: 31, 85, 168;
  --bs-link-hover-color-rgb: 23, 69, 140;
}

[data-bs-theme="dark"]:has([data-sponge-theme="tide"]) {
  --hue-paper-dark: 230.7692;
  --hue-card-dark: 226.3636;
  --hue-ink-dark: 226.1538;
  --hue-muted-dark: 223.7838;
  --hue-line-dark: 223.125;
  --hue-border-translucent-dark: 220.4651;
  --accent: #6FA5E8;
  --accent-deep: #93BDF0;
  --accent-fill: #2B6FD3;
  --accent-fill-hover: #3D7EDC;
  --wash: #1D2C46;
  --depth-tint: #070B14;
  --bs-emphasis-color: #FFFFFF;
  --bs-primary-border-subtle: #2C4266;
  --bs-link-hover-color: #B2CFF6;
  --bs-body-bg-rgb: 18, 20, 31;
  --bs-body-color-rgb: 233, 236, 246;
  --bs-emphasis-color-rgb: 255, 255, 255;
  --bs-secondary-color-rgb: 157, 167, 194;
  --bs-tertiary-color-rgb: 157, 167, 194;
  --bs-secondary-bg-rgb: 29, 44, 70;
  --bs-tertiary-bg-rgb: 18, 20, 31;
  --bs-primary-rgb: 111, 165, 232;
  --bs-link-color-rgb: 147, 189, 240;
  --bs-link-hover-color-rgb: 178, 207, 246;
}

:root:has([data-sponge-theme="fern"]) {
  --hue: 192;
  --hue-ink: 181.875;
  --hue-muted: 178.2857;
  --hue-line: 183.1579;
  --hue-border-translucent: 177.4286;
  --accent: #127D72;
  --accent-deep: #0C6159;
  --wash: #DDF0ED;
  --depth-tint: #C3E2DC;
  --bs-emphasis-color: #183030;
  --bs-primary-border-subtle: #C8E5E0;
  --bs-link-hover-color: #094F49;
  --bs-body-bg-rgb: 243, 247, 248;
  --bs-body-color-rgb: 37, 68, 69;
  --bs-emphasis-color-rgb: 24, 48, 48;
  --bs-secondary-color-rgb: 103, 138, 137;
  --bs-tertiary-color-rgb: 103, 138, 137;
  --bs-secondary-bg-rgb: 221, 240, 237;
  --bs-tertiary-bg-rgb: 243, 247, 248;
  --bs-primary-rgb: 18, 125, 114;
  --bs-link-color-rgb: 12, 97, 89;
  --bs-link-hover-color-rgb: 9, 79, 73;
}

[data-bs-theme="dark"]:has([data-sponge-theme="fern"]) {
  --hue-paper-dark: 189.2308;
  --hue-card-dark: 185.4545;
  --hue-ink-dark: 184.6154;
  --hue-muted-dark: 181.6216;
  --hue-line-dark: 181.875;
  --hue-border-translucent-dark: 178.6047;
  --accent: #4FB8AB;
  --accent-deep: #79CDC2;
  --accent-fill: #127D72;
  --accent-fill-hover: #179487;
  --wash: #17332F;
  --depth-tint: #05100E;
  --bs-emphasis-color: #FFFFFF;
  --bs-primary-border-subtle: #24504A;
  --bs-link-hover-color: #9BDBD2;
  --bs-body-bg-rgb: 18, 29, 31;
  --bs-body-color-rgb: 233, 245, 246;
  --bs-emphasis-color-rgb: 255, 255, 255;
  --bs-secondary-color-rgb: 157, 193, 194;
  --bs-tertiary-color-rgb: 157, 193, 194;
  --bs-secondary-bg-rgb: 23, 51, 47;
  --bs-tertiary-bg-rgb: 18, 29, 31;
  --bs-primary-rgb: 79, 184, 171;
  --bs-link-color-rgb: 121, 205, 194;
  --bs-link-hover-color-rgb: 155, 219, 210;
}

:root:has([data-sponge-theme="blossom"]) {
  --hue: 336;
  --hue-ink: 324.375;
  --hue-muted: 322.2857;
  --hue-line: 328.4211;
  --hue-border-translucent: 319.7143;
  --accent: #B33C92;
  --accent-deep: #8F2C74;
  --wash: #F8E2F1;
  --depth-tint: #F0CBE4;
  --bs-emphasis-color: #301827;
  --bs-primary-border-subtle: #F1CFE7;
  --bs-link-hover-color: #762260;
  --bs-body-bg-rgb: 248, 243, 245;
  --bs-body-color-rgb: 69, 37, 56;
  --bs-emphasis-color-rgb: 48, 24, 39;
  --bs-secondary-color-rgb: 138, 103, 125;
  --bs-tertiary-color-rgb: 138, 103, 125;
  --bs-secondary-bg-rgb: 248, 226, 241;
  --bs-tertiary-bg-rgb: 248, 243, 245;
  --bs-primary-rgb: 179, 60, 146;
  --bs-link-color-rgb: 143, 44, 116;
  --bs-link-hover-color-rgb: 118, 34, 96;
}

[data-bs-theme="dark"]:has([data-sponge-theme="blossom"]) {
  --hue-paper-dark: 332.3077;
  --hue-card-dark: 327.2727;
  --hue-ink-dark: 327.6923;
  --hue-muted-dark: 324.3243;
  --hue-line-dark: 324.375;
  --hue-border-translucent-dark: 322.3256;
  --accent: #E07EC4;
  --accent-deep: #EBA1D4;
  --accent-fill: #B33C92;
  --accent-fill-hover: #C14DA1;
  --wash: #3A2134;
  --depth-tint: #120711;
  --bs-emphasis-color: #FFFFFF;
  --bs-primary-border-subtle: #58324F;
  --bs-link-hover-color: #F2BCE1;
  --bs-body-bg-rgb: 31, 18, 24;
  --bs-body-color-rgb: 246, 233, 240;
  --bs-emphasis-color-rgb: 255, 255, 255;
  --bs-secondary-color-rgb: 194, 157, 179;
  --bs-tertiary-color-rgb: 194, 157, 179;
  --bs-secondary-bg-rgb: 58, 33, 52;
  --bs-tertiary-bg-rgb: 31, 18, 24;
  --bs-primary-rgb: 224, 126, 196;
  --bs-link-color-rgb: 235, 161, 212;
  --bs-link-hover-color-rgb: 242, 188, 225;
}

/* ---------- the maturity scale ----------
   From sponge to stone (README): anything wearing data-maturity reads the
   scale from these knobs instead of restating it. --maturity is the ink,
   --maturity-fill the surface behind it. */

[data-maturity="sponge"] {
  --maturity: var(--muted);
  --maturity-fill: color-mix(in srgb, var(--paper) 90%, transparent);
}

[data-maturity="curing"] {
  --maturity: var(--accent);
  --maturity-fill: color-mix(in srgb, var(--accent) 45%, transparent);
}

[data-maturity="stone"] {
  --maturity: var(--accent-deep);
  --maturity-fill: color-mix(in srgb, var(--accent-deep) 90%, transparent);
}

/* Swatches on the profile page. Each dot wears its own hue for the current
   mode, whatever theme is active. */
.theme-swatches {
  display: flex;
  gap: 1rem;
}

.theme-swatch {
  display: grid;
  justify-items: center;
  gap: 0.35rem;
  cursor: pointer;
  color: var(--muted);
  font-size: 0.85rem;
}

.theme-swatch-dot {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  background: var(--dot);
  box-shadow: inset 0 0 0 3px var(--card), 0 0 0 1px var(--line);
  transition: box-shadow 0.18s ease, transform 0.18s ease;
}

.theme-swatch:hover .theme-swatch-dot { transform: scale(1.07); }

.theme-swatch:has(input:checked) {
  color: var(--ink);
  font-weight: 600;
}

.theme-swatch:has(input:checked) .theme-swatch-dot,
.theme-swatch:has(input:focus-visible) .theme-swatch-dot {
  box-shadow: inset 0 0 0 3px var(--card), 0 0 0 3px var(--dot);
}

.theme-swatch-dot[data-swatch="plum"] { --dot: #6B5CC4; }
.theme-swatch-dot[data-swatch="tide"] { --dot: #2B6FD3; }
.theme-swatch-dot[data-swatch="fern"] { --dot: #127D72; }
.theme-swatch-dot[data-swatch="blossom"] { --dot: #B33C92; }

[data-bs-theme="dark"] .theme-swatch-dot[data-swatch="plum"] { --dot: #8B7BD8; }
[data-bs-theme="dark"] .theme-swatch-dot[data-swatch="tide"] { --dot: #6FA5E8; }
[data-bs-theme="dark"] .theme-swatch-dot[data-swatch="fern"] { --dot: #4FB8AB; }
[data-bs-theme="dark"] .theme-swatch-dot[data-swatch="blossom"] { --dot: #E07EC4; }

/* Spike: spin any hue and watch the whole app follow. The track sweeps the
   wheel at the accent's saturation and lightness; the thumb wears the live
   accent, so it always matches what the page just became. */
.theme-hue-slider {
  appearance: none;
  width: 100%;
  height: 0.65rem;
  border-radius: 999px;
  background: linear-gradient(90deg,
    hsl(0 46.85% 56.47%), hsl(60 46.85% 56.47%), hsl(120 46.85% 56.47%),
    hsl(180 46.85% 56.47%), hsl(240 46.85% 56.47%), hsl(300 46.85% 56.47%),
    hsl(360 46.85% 56.47%));

  &::-webkit-slider-thumb {
    appearance: none;
    width: 1.4rem;
    height: 1.4rem;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: inset 0 0 0 3px var(--card), 0 0 0 1px var(--line);
  }
}

/* ---------- type roles ---------- */

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
  font-family: var(--display);
  font-weight: 700;
}

.btn,
.badge,
.navbar-brand,
.form-label {
  font-family: var(--display);
}

.form-label {
  font-weight: 600;
}

/* ---------- buttons ---------- */

.btn {
  --bs-btn-border-radius: 999px;
  --bs-btn-font-weight: 600;
}

.btn-primary {
  --bs-btn-bg: var(--accent);
  --bs-btn-border-color: var(--accent);
  --bs-btn-hover-bg: var(--accent-deep);
  --bs-btn-hover-border-color: var(--accent-deep);
  --bs-btn-active-bg: var(--accent-deep);
  --bs-btn-active-border-color: var(--accent-deep);
  --bs-btn-disabled-bg: var(--accent);
  --bs-btn-disabled-border-color: var(--accent);
}

.btn-success {
  --bs-btn-bg: var(--moss);
  --bs-btn-border-color: var(--moss);
}

/* Dark accents are lifted for legibility as text, but too light behind white
   button labels; filled buttons keep the saturated light-mode fills. */
[data-bs-theme="dark"] .btn-primary {
  --bs-btn-bg: var(--accent-fill);
  --bs-btn-border-color: var(--accent-fill);
  --bs-btn-hover-bg: var(--accent-fill-hover);
  --bs-btn-hover-border-color: var(--accent-fill-hover);
  --bs-btn-active-bg: var(--accent-fill-hover);
  --bs-btn-active-border-color: var(--accent-fill-hover);
  --bs-btn-disabled-bg: var(--accent-fill);
  --bs-btn-disabled-border-color: var(--accent-fill);
}

[data-bs-theme="dark"] .btn-success {
  --bs-btn-bg: #2F7A57;
  --bs-btn-border-color: #2F7A57;
  --bs-btn-hover-bg: #3C8F68;
  --bs-btn-hover-border-color: #3C8F68;
}

/* Bootstrap compiles its blue into these components rather than reading
   --bs-primary at runtime, so each needs an explicit re-point at the accent. */
.btn-outline-primary {
  --bs-btn-color: var(--accent-deep);
  --bs-btn-border-color: var(--accent);
  --bs-btn-hover-bg: var(--accent);
  --bs-btn-hover-border-color: var(--accent);
  --bs-btn-active-bg: var(--accent-deep);
  --bs-btn-active-border-color: var(--accent-deep);
  --bs-btn-disabled-color: var(--accent);
  --bs-btn-disabled-border-color: var(--accent);
}

.btn-outline-success {
  --bs-btn-color: var(--moss);
  --bs-btn-border-color: var(--moss);
  --bs-btn-hover-bg: var(--moss);
  --bs-btn-hover-border-color: var(--moss);
  --bs-btn-active-bg: var(--moss);
  --bs-btn-active-border-color: var(--moss);
}

[data-bs-theme="dark"] .btn-outline-success {
  --bs-btn-hover-bg: #2F7A57;
  --bs-btn-hover-border-color: #2F7A57;
  --bs-btn-active-bg: #2F7A57;
  --bs-btn-active-border-color: #2F7A57;
}

.btn-outline-info {
  --bs-btn-color: var(--sea);
  --bs-btn-border-color: var(--sea);
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: var(--sea);
  --bs-btn-hover-border-color: var(--sea);
  --bs-btn-active-color: #fff;
  --bs-btn-active-bg: var(--sea);
  --bs-btn-active-border-color: var(--sea);
  --bs-btn-disabled-color: var(--sea);
  --bs-btn-disabled-border-color: var(--sea);
}

[data-bs-theme="dark"] .btn-outline-info {
  --bs-btn-hover-bg: #2E5FA3;
  --bs-btn-hover-border-color: #2E5FA3;
  --bs-btn-active-bg: #2E5FA3;
  --bs-btn-active-border-color: #2E5FA3;
}

/* Stock warning yellow glares in both themes; the rescue verb reads in the
   fact-gold family instead */
.btn-outline-warning {
  --bs-btn-color: var(--gold);
  --bs-btn-border-color: var(--gold);
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: var(--gold);
  --bs-btn-hover-border-color: var(--gold);
  --bs-btn-active-color: #fff;
  --bs-btn-active-bg: var(--gold);
  --bs-btn-active-border-color: var(--gold);
  --bs-btn-disabled-color: var(--gold);
  --bs-btn-disabled-border-color: var(--gold);
}

[data-bs-theme="dark"] .btn-outline-warning {
  --bs-btn-hover-bg: #9A7009;
  --bs-btn-hover-border-color: #9A7009;
  --bs-btn-active-bg: #9A7009;
  --bs-btn-active-border-color: #9A7009;
}

.btn-outline-danger {
  --bs-btn-color: var(--rose);
  --bs-btn-border-color: var(--rose);
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: var(--rose);
  --bs-btn-hover-border-color: var(--rose);
  --bs-btn-active-color: #fff;
  --bs-btn-active-bg: var(--rose);
  --bs-btn-active-border-color: var(--rose);
  --bs-btn-disabled-color: var(--rose);
  --bs-btn-disabled-border-color: var(--rose);
}

[data-bs-theme="dark"] .btn-outline-danger {
  --bs-btn-hover-bg: #A0344E;
  --bs-btn-hover-border-color: #A0344E;
  --bs-btn-active-bg: #A0344E;
  --bs-btn-active-border-color: #A0344E;
}

.pagination {
  --bs-pagination-active-bg: var(--accent);
  --bs-pagination-active-border-color: var(--accent);
  --bs-pagination-focus-box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 15%, transparent);
}

.progress {
  --bs-progress-bar-bg: var(--accent);
}

.nav-pills {
  --bs-nav-pills-link-active-bg: var(--accent);
}

/* Rows sit on card, not body, so lists read as surfaces rather than
   cutouts of the page ground. Hover is the grid-row treatment: a soft wash
   lift, keeping the body ink (stock hover punches a paper-colored hole and
   snaps the text to near-black). */
.list-group {
  --bs-list-group-bg: var(--card);
  --bs-list-group-action-hover-color: var(--bs-body-color);
  --bs-list-group-action-hover-bg: color-mix(in srgb, var(--wash) 42%, var(--card));
  --bs-list-group-action-active-color: var(--bs-body-color);
  --bs-list-group-action-active-bg: var(--wash);
  --bs-list-group-active-bg: var(--accent);
  --bs-list-group-active-border-color: var(--accent);
}

.list-group-item-action {
  transition: background-color 0.15s ease, color 0.15s ease;
}

.form-check-input:checked {
  background-color: var(--accent);
  border-color: var(--accent);
}

.form-check-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 15%, transparent);
}

/* Secondary actions get the ghost treatment: wash fill on hover, no gray */
.btn-outline-secondary {
  --bs-btn-color: var(--accent-deep);
  --bs-btn-border-color: var(--line);
  --bs-btn-hover-color: var(--accent-deep);
  --bs-btn-hover-bg: var(--wash);
  --bs-btn-hover-border-color: var(--line);
  --bs-btn-active-color: var(--accent-deep);
  --bs-btn-active-bg: var(--wash);
  --bs-btn-active-border-color: var(--line);
}

/* ---------- button groups ---------- */

/* Stock btn-group welds pills into a capsule with hard seams. Restyle as a
   segmented control: a wash track holding floating pill segments, the same
   language as the knowledge-grid tabs. Handles btn-check radios and
   button_to forms alike. */
.btn-group {
  position: relative;
  background-color: var(--wash);
  border-radius: 999px;
  padding: 3px;
  gap: 3px;
}

.btn-group > form {
  flex: 0 0 auto;
}

.btn-group > .btn,
.btn-group > form .btn {
  /* Bootstrap squares inner corners at higher specificity; win it back */
  border-radius: 999px !important;
  margin: 0 !important;
  border: 0;
}

/* The ghost's wash hover/active vanishes against the wash track; the chosen
   segment surfaces on card instead, like the active grid tab */
.btn-group .btn-outline-secondary {
  --bs-btn-hover-bg: color-mix(in srgb, var(--card) 55%, transparent);
  --bs-btn-active-bg: var(--card);
}

.btn-group .btn-check:checked + .btn {
  background-color: var(--card);
  box-shadow: 0 1px 3px color-mix(in srgb, var(--bs-emphasis-color) 14%, transparent);
}

/* Radio groups driven by the segmented-control controller share one thumb
   that slides between segments; the checked label goes bare and lets the
   thumb be its surface */
.segmented-thumb {
  position: absolute;
  left: 0;
  top: 3px;
  border-radius: 999px;
  background-color: var(--card);
  box-shadow: 0 1px 3px color-mix(in srgb, var(--bs-emphasis-color) 14%, transparent);
  pointer-events: none;
  opacity: 0;
  transition: transform 0.2s ease-out,
              width 0.2s ease-out,
              opacity 0.2s ease;
}

.segmented-thumb.is-visible {
  opacity: 1;
}

.btn-group:has(.segmented-thumb) .btn-check:checked + .btn {
  background-color: transparent;
  box-shadow: none;
}

@media (prefers-reduced-motion: reduce) {
  .segmented-thumb {
    transition: none;
  }
}

/* ---------- navbar ---------- */

.navbar {
  --bs-navbar-color: var(--muted);
  --bs-navbar-hover-color: var(--ink);
  --bs-navbar-active-color: var(--ink);
  --bs-navbar-brand-color: var(--ink);
  --bs-navbar-brand-hover-color: var(--ink);
}

.navbar-brand {
  font-weight: 700;
}

/* Brand mark: the maturity circles in eclipse, opacity waxing sponge → stone.
   A soft wave of brightness travels through the cluster; each state's resting
   opacity lives in --o so the shimmer can return to it. */
.navbar-brand .brand-mark {
  color: var(--accent);
  flex-shrink: 0;
}

.brand-mark .brand-shine {
  animation: brandShine 3.2s ease-in-out infinite;
}

.brand-mark .brand-shine.s2 { animation-delay: 0.4s; }
.brand-mark .brand-shine.s3 { animation-delay: 0.8s; }

@keyframes brandShine {
  0%, 32%, 100% { opacity: var(--o); }
  12% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .brand-mark .brand-shine { animation: none; }
}

.dropdown-menu {
  --bs-dropdown-border-color: var(--line);
  --bs-dropdown-border-radius: 0.875rem;
  --bs-dropdown-link-active-bg: var(--wash);
  --bs-dropdown-link-active-color: var(--accent-deep);
}

/* ---------- cards ---------- */

.card {
  --bs-card-border-radius: 1.25rem;
  --bs-card-inner-border-radius: calc(1.25rem - 1px);
  --bs-card-bg: var(--card);
  --bs-card-cap-bg: transparent;
}

/* ---------- flash ---------- */

.alert {
  --bs-alert-border-radius: 0.875rem;
}

/* The washes alone melt into the lilac paper; a deeper fill and a tinted
   border keep the flash legible against the page ground */
.alert-success {
  --bs-alert-bg: color-mix(in srgb, var(--moss) 10%, var(--moss-wash));
  --bs-alert-color: var(--moss);
  --bs-alert-border-color: color-mix(in srgb, var(--moss) 30%, transparent);
}

.alert-danger {
  --bs-alert-bg: color-mix(in srgb, var(--rose) 10%, var(--rose-wash));
  --bs-alert-color: var(--rose);
  --bs-alert-border-color: color-mix(in srgb, var(--rose) 30%, transparent);
}

/* ---------- forms ---------- */

/* Inputs ride on card like the prediction textarea, lifted off the paper
   ground in both themes */
.form-control,
.form-select,
.form-check-input {
  background-color: var(--card);
}

.form-control:focus,
.form-select:focus,
.ts-wrapper.focus {
  /* Bootstrap's :focus resets to body-bg; stay on card */
  background-color: var(--card);
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 15%, transparent);
}

/* ---------- focus visibility floor ---------- */

a:focus-visible,
button:focus-visible,
[tabindex]:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

/* Tom Select's control is a focusable div inside the bordered wrapper; the
   wrapper gets the form-control focus treatment above, so skip the generic
   outline and Tom Select's own Bootstrap-blue ring on the inner control */
.ts-control:focus-visible {
  outline: 0;
}

.ts-wrapper.focus .ts-control {
  box-shadow: none;
}

/* Arrowing through dropdown options: fill the active row like a menu
   selection instead of Bootstrap's faint tertiary tint */
.ts-dropdown .active,
.ts-dropdown .active.create {
  background-color: var(--accent);
  color: #fff;
}

/* Same saturated fill as .btn-primary — the lifted dark accent is too
   light behind white text */
[data-bs-theme="dark"] .ts-dropdown .active,
[data-bs-theme="dark"] .ts-dropdown .active.create {
  background-color: var(--accent-fill);
}
