/* ============================================================================
   AtChurch.Online — Theme Token Contract
   ============================================================================

   This file is the single source of truth for the site's visual language.
   Every theme is nothing more than a different set of values for the `--ac-*`
   custom properties declared below. No theme adds selectors; no theme adds
   rules. A theme is DATA.

   Load order matters (see Pages/Shared/_Layout.cshtml):

       bootstrap.min.css      framework defaults
       theme-tokens.css       <-- THIS FILE: tokens + Bootstrap bridge
       site.css               legacy page styles
       components.css         shared component layer built on these tokens
       (per-church theme)     injected :root block that overrides --ac-* only

   RULES FOR CONTRIBUTORS
   ----------------------
   1. Never write a raw hex value in a page, a component, or site.css.
      Use a token. If no token fits, add one here first.
   2. Tokens are SEMANTIC, not literal. `--ac-border`, never `--ac-slate-200`.
      A theme is free to make "border" a 2px black line; naming it after a
      grey would make that theme a lie.
   3. A token added here must be given a value in EVERY theme file, or it
      will silently fall back to the Default value and break that theme's
      visual coherence.

   THE BOOTSTRAP LEVER
   -------------------
   Bootstrap 5.3 is itself CSS-variable driven. The bridge section near the
   bottom of this file maps `--bs-*` onto `--ac-*`, which means every
   .btn / .card / .table / .nav / .badge / .modal across all 185 pages picks
   up the active theme without a single page edit. That bridge is the reason
   this whole approach is affordable.
   ============================================================================ */


/* ============================================================================
   1. THEME: AtChurch Default (light)
   ============================================================================
   Derived from the values the codebase already converged on, not invented:
   #4f46e5 / #0891b2 / #1e293b / #64748b came from the --bible-* block that
   used to live in site.css; #e2e8f0 (the single most-used colour in the repo,
   59 occurrences) and #f8fafc / #f1f5f9 came from the newer page styles.
   ============================================================================ */

:root {

    /* ---- Brand -------------------------------------------------------- */
    --ac-brand: #4f46e5;
    --ac-brand-rgb: 79, 70, 229;
    --ac-brand-hover: #4338ca; /* darker — interactive states */
    --ac-brand-active: #3730a3; /* darker still — pressed */
    /* A genuinely LIGHTER tint, distinct from -hover. Decorative only: the
       far stop of a brand gradient and hover border colours. Not a text or
       fill colour, so it carries no contrast minimum — but it must stay
       lighter than --ac-brand or every brand gradient on the site inverts
       and goes muddy. */
    --ac-brand-light: #818cf8;
    --ac-brand-soft: #eef2ff; /* tinted background for selected/active states */
    --ac-brand-contrast: #ffffff; /* text that sits ON --ac-brand */

    /* ---- Accent — the theme's SECOND hue -------------------------------
       This is the slot that lets a page look distinct without going off-theme.

       A page that wants its own identity (the giving flow, the Bible reader)
       consumes --ac-accent-* instead of --ac-brand-*. Because the theme author
       picks brand and accent together, harmony is guaranteed by construction —
       which a page-local hardcoded colour can never promise. It also cannot
       COLLIDE: a fixed gold on the Give page would have become invisible under
       the Chapel theme, whose own brand is antique gold.

       AtChurch Default's accent is the gold the Give page used to hardcode, so
       that page is unchanged while now being fully themeable. Indigo + gold is
       also a deliberate complementary pairing rather than an accident.

       Five roles, same fill/ink split as the status colours below — gold is a
       light hue and CANNOT carry white text at any usable saturation, so the
       fill is bright and the ink is dark:

         --ac-accent           identity: borders, rules, focus outlines. 3:1 min.
         --ac-accent-fill      a solid accent surface. Bright.
         --ac-accent-on-fill   the ink for that surface. Dark, deliberately.
         --ac-accent-ink       accent-coloured TEXT on a light surface. 4.5:1 min.
         --ac-accent-soft      a wash for selected/active states. */
    --ac-accent: #a8790a;
    --ac-accent-rgb: 168, 121, 10;
    --ac-accent-fill: #daa520;
    --ac-accent-fill-hover: #c9931a;
    --ac-accent-on-fill: #1e293b;
    --ac-accent-ink: #996515;
    --ac-accent-soft: #fdf8e8;

    /* ---- Surfaces ----------------------------------------------------- */
    --ac-bg: #f8fafc; /* the page itself */
    --ac-surface: #ffffff; /* cards, panels, table bodies */
    --ac-surface-sunken: #f1f5f9; /* wells, table headers, filter bars */
    --ac-surface-raised: #ffffff; /* popovers, dropdowns, modals */
    --ac-surface-overlay: rgba(15, 23, 42, 0.5); /* modal/offcanvas backdrop */

    /* Scrims for text laid over a photograph. Deliberately NOT theme-tinted and
       NOT lightened in dark mode: the image underneath is arbitrary church
       content, so the only thing keeping the caption readable is a dark wash.
       A theme that tinted this to its brand would make white text fail over a
       bright photo. Themes may adjust the opacity, never invert it. */
    --ac-scrim: linear-gradient(180deg, rgba(0, 0, 0, 0.15) 0%, rgba(0, 0, 0, 0.55) 60%, rgba(0, 0, 0, 0.72) 100%);
    --ac-scrim-solid: rgba(0, 0, 0, 0.75); /* chips and pills over imagery */
    --ac-text-on-scrim: #ffffff;

    /* Deliberately translucent, and the only surface token that is. A
       backdrop-filter blur is invisible behind an opaque background, so glass
       panels need a surface that lets the page through — but --ac-surface
       itself must stay opaque, because everything else layered on it (text
       contrast, nested cards, sticky headers) depends on that.
       Themes with a glass personality raise the alpha here and set
       --ac-surface-blur; flat themes can leave both alone. */
    --ac-surface-glass: rgba(255, 255, 255, 0.95);

    /* A deliberately dark bar on a light page — the Give form header, and any
       future inverted strip. Distinct from --ac-text because that INVERTS in
       dark mode: deriving a dark bar from it would turn the bar white. */
    --ac-surface-inverse: #1e293b;
    --ac-text-on-inverse: #f8fafc;

    /* Themes with a glass or gradient personality override these two; flat
       themes leave them as-is and they cost nothing. */
    --ac-surface-blur: 0px;
    --ac-bg-image: none;

    /* ---- Gradients -----------------------------------------------------
       Gradients are WHOLE tokens rather than being composed in each rule, and
       that granularity is the point: a flat theme (Clarity, Monoline) sets each
       of these to a solid `var(--ac-*-fill)` and every gradient on the site
       flattens at once. Composing them inline would leave a flat theme unable
       to flatten anything — which is exactly the bug the Give page had, with two
       hardcoded linear-gradients no theme could reach. */
    /* Single-hue depth: the same colour going darker. For buttons and bars that
       need a little dimension without introducing a second hue. */
    --ac-gradient-brand: linear-gradient(135deg, var(--ac-brand) 0%, var(--ac-brand-active) 100%);
    --ac-gradient-accent: linear-gradient(135deg, var(--ac-accent-fill) 0%, var(--ac-accent-fill-hover) 100%);
    /* Two-hue and decorative — brand into the theme's accent. */
    --ac-gradient-brand-accent: linear-gradient(135deg, var(--ac-brand) 0%, var(--ac-accent) 100%);
    --ac-gradient-inverse: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);

    /* ---- Text --------------------------------------------------------- */
    /* muted and subtle are a shade darker than the slate-400/500 they came
       from: the originals measured 4.34:1 on --ac-surface-sunken and 2.56:1
       on --ac-surface respectively, both short of AA. */
    --ac-text: #1e293b;
    --ac-text-muted: #5b6a80;
    --ac-text-subtle: #7c8da4; /* placeholders, disabled, timestamps */
    --ac-text-on-brand: #ffffff;
    --ac-link: var(--ac-brand);
    --ac-link-hover: var(--ac-brand-hover);

    /* ---- Lines -------------------------------------------------------- */
    /* Two weights with different jobs, and different rules:
         --ac-border        decorative — card edges, table row dividers. No
                            contrast minimum (WCAG exempts purely decorative
                            boundaries), so it can stay light.
         --ac-border-strong identifies a UI component — input and select
                            outlines, the dropzone dash, outline-button edges.
                            WCAG 2.1 SC 1.4.11 requires 3:1 against the
                            adjacent surface, which the #cbd5e1 this replaces
                            missed badly at 1.48:1. Inputs also simply read
                            better for it. Chosen to clear 3:1 against ALL
                            THREE light surfaces an input can sit on —
                            surface (3.43), bg (3.28) and sunken (3.13) —
                            since sunken is the tightest and picking against
                            white alone leaves it failing there. */
    --ac-border: #e2e8f0;
    --ac-border-strong: #7d8c9e;
    --ac-border-width: 1px; /* Monoline-style themes raise this to 2px */
    --ac-focus-ring: 0 0 0 0.25rem rgba(var(--ac-brand-rgb), 0.25);

    /* ---- Status ------------------------------------------------------- */
    /* NOT THEMEABLE IN HUE. A theme may retune the -soft tints so they sit
       correctly on its surfaces, and dark mode does exactly that below — but red
       must stay red and green must stay green. Danger, success and warning are
       information, not decoration; a theme that recolours them to fit its palette
       has broken the interface, not restyled it. Expressive freedom belongs to
       --ac-brand and --ac-accent.

       Each status carries three values with three distinct jobs. Getting the
       job wrong is the single easiest way to ship an inaccessible page, so:

         --ac-{s}        THE FILL. A solid block of colour that carries white
                         text (black, for warning and info — those two are too
                         light for white at any usable saturation). Never use
                         this as a text colour on a light surface.
         --ac-{s}-soft   a tint, for badge and alert backgrounds.
         --ac-{s}-text   THE INK. Coloured text or icons, whether on -soft or
                         directly on a surface. This is the one dark mode
                         inverts to a light tint, which is why routing status
                         text through it works in both modes and using
                         --ac-{s} does not.

       Pages currently hand-roll all three, which is why "pending" is amber on
       one screen and yellow on the next across the six competing
       .status-badge definitions this replaces.

       success and danger are darker than the #10b981 / #ef4444 they were
       derived from. Those two measured 2.54:1 and 3.76:1 against the white
       text Bootstrap puts on .btn-success / .btn-danger — a contrast
       regression versus Bootstrap's own #198754 / #dc3545. */
    --ac-success: #088060;
    --ac-success-rgb: 8, 128, 96;
    --ac-success-soft: #d1fae5;
    --ac-success-text: #065f46;

    --ac-warning: #f59e0b; /* carries BLACK text — 9.78:1 */
    --ac-warning-rgb: 245, 158, 11;
    --ac-warning-soft: #fef3c7;
    --ac-warning-text: #92400e;

    --ac-danger: #d92626;
    --ac-danger-rgb: 217, 38, 38;
    --ac-danger-soft: #fee2e2;
    --ac-danger-text: #991b1b;

    --ac-info: #0ea5e9; /* carries BLACK text — 7.58:1 */
    --ac-info-rgb: 14, 165, 233;
    --ac-info-soft: #e0f2fe;
    --ac-info-text: #075985;

    --ac-neutral: #64748b;
    --ac-neutral-rgb: 100, 116, 139;
    --ac-neutral-soft: #f1f5f9;
    --ac-neutral-text: #475569;

    /* ---- Tooltip ------------------------------------------------------ */
    /* Deliberately inverted against the page — a tooltip is transient and
       should read as floating above the UI, not as another panel. */
    --ac-tooltip-bg: #1e293b;
    --ac-tooltip-text: #f8fafc;

    /* ---- Shape -------------------------------------------------------- */
    --ac-radius-xs: 4px;
    --ac-radius-sm: 8px;
    --ac-radius-md: 12px;
    --ac-radius-lg: 16px;
    --ac-radius-xl: 24px;
    --ac-radius-pill: 999px;

    /* ---- Depth -------------------------------------------------------- */
    /* Flat themes (Clarity, Monoline) set all four to `none`. Because every
       component references these rather than writing its own box-shadow,
       "make it flat" is a four-line theme change. */
    --ac-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
    --ac-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
    --ac-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
    --ac-shadow-glow: 0 0 20px rgba(var(--ac-brand-rgb), 0.15);
    --ac-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.05);

    /* ---- Type --------------------------------------------------------- */
    --ac-font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
                    "Helvetica Neue", Arial, sans-serif;
    --ac-font-heading: var(--ac-font-body);
    --ac-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    /* Scripture is deliberately NOT themeable to a sans stack — the Bible
       reader's serif setting is a readability decision, not a style one. */
    --ac-font-scripture: "Merriweather", Georgia, "Times New Roman", serif;

    --ac-weight-body: 400;
    --ac-weight-medium: 500;
    --ac-weight-semibold: 600;
    --ac-weight-heading: 700;

    --ac-text-xs: 0.75rem;
    --ac-text-sm: 0.875rem;
    --ac-text-base: 1rem;
    --ac-text-lg: 1.125rem;
    --ac-text-xl: 1.375rem;
    --ac-text-2xl: 1.75rem;
    --ac-text-3xl: 2.25rem;

    --ac-leading-tight: 1.25;
    --ac-leading-normal: 1.5;
    --ac-leading-relaxed: 1.75;

    /* Editorial themes (Sanctuary, Chapel) add letter-spacing / uppercase to
       headings via these two rather than by restyling every h1-h6. */
    --ac-heading-tracking: normal;
    --ac-heading-transform: none;
    --ac-label-tracking: 0.05em;
    --ac-label-transform: uppercase;

    /* ---- Density ------------------------------------------------------ */
    /* Harbor (dense/pro) shrinks these; Bloom (friendly) grows them. Every
       component's padding is a multiple of --ac-space, so one value retunes
       the whole site's breathing room. */
    --ac-space: 0.25rem;
    --ac-gap: 1rem;
    --ac-card-pad: 1.25rem;
    --ac-section-gap: 2rem;
    --ac-control-height: 2.5rem;
    --ac-table-row-pad: 0.75rem;

    /* ---- Motion ------------------------------------------------------- */
    --ac-transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    --ac-transition-fast: all 0.15s ease;
    --ac-lift: translateY(-4px); /* the standard card hover displacement */
}

/* Respect the OS-level reduced-motion preference globally. Because every
   component uses --ac-transition/--ac-lift instead of its own values, this
   single block disables site-wide motion. */
@media (prefers-reduced-motion: reduce) {
    :root {
        --ac-transition: none;
        --ac-transition-fast: none;
        --ac-lift: none;
    }
}


/* ============================================================================
   2. THEME: AtChurch Default (dark)
   ============================================================================
   Dark mode is keyed off Bootstrap's own `data-bs-theme="dark"` attribute on
   <html> rather than a bespoke one, so a single attribute flips both our
   tokens AND every native Bootstrap component. Only the values that must
   change are re-declared; shape, type and density are inherited from above.
   ============================================================================ */

:root[data-bs-theme="dark"] {
    /* Interactive states go LIGHTER in dark mode, and -light goes lighter
       still, preserving the ordering the gradients rely on. */
    --ac-brand: #818cf8;
    --ac-brand-rgb: 129, 140, 248;
    --ac-brand-hover: #a5b4fc;
    --ac-brand-active: #c7d2fe;
    --ac-brand-light: #c7d2fe;
    --ac-brand-soft: #1e1b4b;
    --ac-brand-contrast: #1e1b4b;

    /* The bright-fill/dark-ink pairing carries over unchanged — an accent block
       reads correctly against a dark page too. What has to change is the accent
       used as TEXT: -ink lightens, because a deep gold on a dark surface is
       unreadable. */
    --ac-accent: #daa520;
    --ac-accent-rgb: 218, 165, 32;
    --ac-accent-fill: #daa520;
    --ac-accent-fill-hover: #e0b020;
    --ac-accent-on-fill: #1e1b0b;
    --ac-accent-ink: #e0b84a;
    --ac-accent-soft: #2a2312;

    --ac-bg: #0f172a;
    --ac-surface: #1e293b;
    --ac-surface-sunken: #172033;
    --ac-surface-raised: #263449;
    --ac-surface-overlay: rgba(0, 0, 0, 0.65);
    --ac-surface-glass: rgba(30, 41, 59, 0.85);
    --ac-surface-inverse: #263449;
    --ac-text-on-inverse: #f8fafc;
    --ac-gradient-inverse: linear-gradient(135deg, #263449 0%, #172033 100%);

    --ac-text: #e2e8f0;
    --ac-text-muted: #94a3b8;
    --ac-text-subtle: #6b7c93;
    --ac-text-on-brand: #1e1b4b;

    /* Same 3:1 rule as light mode — #475569 only reached 1.93:1 against the
       dark surface, leaving inputs with an effectively invisible outline. */
    --ac-border: #334155;
    --ac-border-strong: #677891;

    --ac-success-soft: #064e3b;
    --ac-success-text: #6ee7b7;
    --ac-warning-soft: #4a2c07;
    --ac-warning-text: #fcd34d;
    --ac-danger-soft: #4c1d1d;
    --ac-danger-text: #fca5a5;
    --ac-info-soft: #0c4a6e;
    --ac-info-text: #7dd3fc;
    --ac-neutral-soft: #263449;
    --ac-neutral-text: #cbd5e1;

    /* Lighter than the surface rather than darker — inverting to near-white
       here would glare against a dark page. */
    --ac-tooltip-bg: #4a5b73;
    --ac-tooltip-text: #f8fafc;

    /* Shadows read as noise on dark surfaces; depth comes from surface
       lightness instead. Kept non-zero but much softer. */
    --ac-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
    --ac-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.5);
    --ac-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.6);
    --ac-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.3);
}


/* ============================================================================
   3. BACK-COMPAT: --bible-* aliases
   ============================================================================
   The Bible Reader shipped the first token set on this site, namespaced
   --bible-*, and roughly a dozen pages plus ~700 lines of site.css consume
   it. Rather than find-and-replace across all of them, the old names are
   aliased onto the new ones here.

   Net effect: every Bible Reader page became themeable with zero page edits.

   The original :root block was REMOVED from site.css when these aliases were
   added — if it were left in place it would load after this file and win on
   equal specificity, silently pinning the Bible pages to indigo forever.

   New code must use --ac-*. This block is a bridge, not an API.
   ============================================================================ */

:root {
    --bible-primary: var(--ac-brand);
    /* -light must map to --ac-brand-light, NOT --ac-brand-hover: eight rules in
       site.css use it as the far stop of `linear-gradient(brand, brand-light)`,
       and -hover is darker than brand, which would invert them. */
    --bible-primary-light: var(--ac-brand-light);
    --bible-primary-dark: var(--ac-brand-active);
    --bible-secondary: var(--ac-accent);
    --bible-accent: var(--ac-warning);
    --bible-success: var(--ac-success);
    --bible-warning: var(--ac-warning);
    --bible-danger: var(--ac-danger);
    /* --bible-surface was rgba(255,255,255,0.95), and .bible-glass pairs it
       with a backdrop-filter. Pointing it at the opaque --ac-surface would
       have silently flattened every glass panel in the Bible Reader, so it
       maps to the translucent token instead. --bible-surface-elevated was
       0.98 alpha and is used by cards that read better opaque. */
    --bible-surface: var(--ac-surface-glass);
    --bible-surface-elevated: var(--ac-surface-raised);
    --bible-text: var(--ac-text);
    --bible-text-muted: var(--ac-text-muted);
    --bible-border: var(--ac-border);
    --bible-shadow-sm: var(--ac-shadow-sm);
    --bible-shadow: var(--ac-shadow-md);
    --bible-shadow-lg: var(--ac-shadow-lg);
    --bible-shadow-glow: var(--ac-shadow-glow);
    --bible-radius: var(--ac-radius-lg);
    --bible-radius-sm: var(--ac-radius-sm);
    --bible-radius-lg: var(--ac-radius-xl);
    --bible-transition: var(--ac-transition);
}


/* ============================================================================
   4. BOOTSTRAP BRIDGE
   ============================================================================
   Maps Bootstrap's variables onto ours. This is what re-skins the ~185 pages
   that use stock Bootstrap classes without touching them.

   Two things to know about Bootstrap 5.3 when editing this:

   a) Many components read a COMPONENT-scoped variable (--bs-btn-bg) that
      Bootstrap assigns from a literal, not from --bs-primary. So setting
      --bs-primary alone does not recolour buttons. The component overrides
      in 4b below are required, not redundant.

   b) Bootstrap needs "R, G, B" triplets (--bs-primary-rgb) for anything it
      composes with alpha. Hence the --ac-*-rgb tokens.
   ============================================================================ */

/* ---- 4a. Global ------------------------------------------------------- */
:root,
:root[data-bs-theme="dark"] {
    --bs-primary: var(--ac-brand);
    --bs-primary-rgb: var(--ac-brand-rgb);
    --bs-secondary: var(--ac-neutral);
    --bs-secondary-rgb: var(--ac-neutral-rgb);
    --bs-success: var(--ac-success);
    --bs-success-rgb: var(--ac-success-rgb);
    --bs-danger: var(--ac-danger);
    --bs-danger-rgb: var(--ac-danger-rgb);
    --bs-warning: var(--ac-warning);
    --bs-warning-rgb: var(--ac-warning-rgb);
    --bs-info: var(--ac-info);
    --bs-info-rgb: var(--ac-info-rgb);

    --bs-body-bg: var(--ac-bg);
    --bs-body-color: var(--ac-text);
    --bs-secondary-color: var(--ac-text-muted);
    --bs-tertiary-color: var(--ac-text-subtle);
    --bs-secondary-bg: var(--ac-surface-sunken);
    --bs-tertiary-bg: var(--ac-surface-sunken);
    --bs-emphasis-color: var(--ac-text);

    --bs-border-color: var(--ac-border);
    --bs-border-width: var(--ac-border-width);
    --bs-border-radius: var(--ac-radius-sm);
    --bs-border-radius-sm: var(--ac-radius-xs);
    --bs-border-radius-lg: var(--ac-radius-md);
    --bs-border-radius-xl: var(--ac-radius-lg);
    --bs-border-radius-xxl: var(--ac-radius-xl);
    --bs-border-radius-pill: var(--ac-radius-pill);

    --bs-link-color: var(--ac-link);
    --bs-link-color-rgb: var(--ac-brand-rgb);
    --bs-link-hover-color: var(--ac-link-hover);

    --bs-body-font-family: var(--ac-font-body);
    --bs-body-font-weight: var(--ac-weight-body);
    --bs-body-line-height: var(--ac-leading-normal);
    /* Left at Bootstrap's own default of `inherit` on purpose — see the h1-h6 rule
       further down. Pointing this at --ac-text also defeats inheritance, so a
       heading inside a coloured bar would go back to rendering in body colour. */
    --bs-heading-color: inherit;

    --bs-box-shadow-sm: var(--ac-shadow-sm);
    --bs-box-shadow: var(--ac-shadow-md);
    --bs-box-shadow-lg: var(--ac-shadow-lg);
}

/* ---- 4b. Components that need explicit overrides --------------------- */
/* See note (a) above — these read literals in Bootstrap's own stylesheet. */

.btn-primary {
    --bs-btn-bg: var(--ac-brand);
    --bs-btn-border-color: var(--ac-brand);
    --bs-btn-color: var(--ac-brand-contrast);
    --bs-btn-hover-bg: var(--ac-brand-hover);
    --bs-btn-hover-border-color: var(--ac-brand-hover);
    --bs-btn-hover-color: var(--ac-brand-contrast);
    --bs-btn-active-bg: var(--ac-brand-active);
    --bs-btn-active-border-color: var(--ac-brand-active);
    --bs-btn-active-color: var(--ac-brand-contrast);
    --bs-btn-disabled-bg: var(--ac-brand);
    --bs-btn-disabled-border-color: var(--ac-brand);
    --bs-btn-disabled-color: var(--ac-brand-contrast);
}

.btn-outline-primary {
    --bs-btn-color: var(--ac-brand);
    --bs-btn-border-color: var(--ac-brand);
    --bs-btn-hover-bg: var(--ac-brand);
    --bs-btn-hover-border-color: var(--ac-brand);
    --bs-btn-hover-color: var(--ac-brand-contrast);
    --bs-btn-active-bg: var(--ac-brand);
    --bs-btn-active-border-color: var(--ac-brand);
    --bs-btn-active-color: var(--ac-brand-contrast);
    --bs-btn-disabled-color: var(--ac-brand);
    --bs-btn-disabled-border-color: var(--ac-brand);
}

.btn-secondary {
    --bs-btn-bg: var(--ac-neutral);
    --bs-btn-border-color: var(--ac-neutral);
    --bs-btn-hover-bg: var(--ac-neutral-text);
    --bs-btn-hover-border-color: var(--ac-neutral-text);
    --bs-btn-active-bg: var(--ac-neutral-text);
    --bs-btn-active-border-color: var(--ac-neutral-text);
}

.btn-success { --bs-btn-bg: var(--ac-success); --bs-btn-border-color: var(--ac-success); }
.btn-danger  { --bs-btn-bg: var(--ac-danger);  --bs-btn-border-color: var(--ac-danger); }
.btn-warning { --bs-btn-bg: var(--ac-warning); --bs-btn-border-color: var(--ac-warning); }
.btn-info    { --bs-btn-bg: var(--ac-info);    --bs-btn-border-color: var(--ac-info); }

/* An outline button's LABEL is ink on a surface, not a fill — so it takes the
   -text token, never the fill token. These three took the fill (--ac-neutral,
   --ac-success, --ac-danger), which is the exact fill-vs-ink confusion the token
   contract exists to prevent, and it broke the same way that mistake always
   breaks: the fill tokens are not inverted for dark mode, so on a dark surface
   .btn-outline-secondary rendered its label in #64748b at 4.01:1. Five buttons
   on the bulletin toolbar, and every other outline-secondary on the site.

   The -text tokens ARE inverted (#475569 light, #cbd5e1 dark), so the label now
   reads in both modes. Hover keeps the fill, where white ink is correct and
   already gated by SOLID_FILLS.

   .btn-outline-primary is deliberately not in this list: --ac-brand is both a
   fill and an ink by design, and 'brand ink on brand-soft' already gates it. */
.btn-outline-secondary { --bs-btn-color: var(--ac-neutral-text); --bs-btn-border-color: var(--ac-border-strong); --bs-btn-hover-bg: var(--ac-neutral); --bs-btn-hover-border-color: var(--ac-neutral); }
.btn-outline-success   { --bs-btn-color: var(--ac-success-text); --bs-btn-border-color: var(--ac-success); --bs-btn-hover-bg: var(--ac-success); }
.btn-outline-danger    { --bs-btn-color: var(--ac-danger-text);  --bs-btn-border-color: var(--ac-danger);  --bs-btn-hover-bg: var(--ac-danger); }

.card {
    --bs-card-bg: var(--ac-surface);
    --bs-card-color: var(--ac-text);
    --bs-card-border-color: var(--ac-border);
    --bs-card-border-width: var(--ac-border-width);
    --bs-card-border-radius: var(--ac-radius-md);
    --bs-card-inner-border-radius: calc(var(--ac-radius-md) - var(--ac-border-width));
    --bs-card-spacer-x: var(--ac-card-pad);
    --bs-card-spacer-y: var(--ac-card-pad);
    --bs-card-cap-bg: var(--ac-surface-sunken);
}

.table {
    --bs-table-bg: transparent;
    --bs-table-color: var(--ac-text);
    --bs-table-border-color: var(--ac-border);
    --bs-table-striped-bg: var(--ac-surface-sunken);
    --bs-table-striped-color: var(--ac-text);
    --bs-table-hover-bg: var(--ac-brand-soft);
    --bs-table-hover-color: var(--ac-text);
    --bs-table-cell-padding-y: var(--ac-table-row-pad);
}

.form-control,
.form-select {
    background-color: var(--ac-surface);
    color: var(--ac-text);
    border-color: var(--ac-border-strong);
    border-width: var(--ac-border-width);
    border-radius: var(--ac-radius-sm);
}

.form-control::placeholder { color: var(--ac-text-subtle); }

.form-control:focus,
.form-select:focus {
    border-color: var(--ac-brand);
    box-shadow: var(--ac-focus-ring);
}

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

.nav-pills {
    --bs-nav-pills-link-active-bg: var(--ac-brand);
    --bs-nav-pills-link-active-color: var(--ac-brand-contrast);
    --bs-nav-pills-border-radius: var(--ac-radius-sm);
}

.nav-tabs {
    --bs-nav-tabs-border-color: var(--ac-border);
    --bs-nav-tabs-link-active-bg: var(--ac-surface);
    --bs-nav-tabs-link-active-color: var(--ac-brand);
    --bs-nav-tabs-link-active-border-color: var(--ac-border) var(--ac-border) var(--ac-surface);
}

.dropdown-menu {
    --bs-dropdown-bg: var(--ac-surface-raised);
    --bs-dropdown-color: var(--ac-text);
    --bs-dropdown-border-color: var(--ac-border);
    --bs-dropdown-border-radius: var(--ac-radius-md);
    --bs-dropdown-link-color: var(--ac-text);
    --bs-dropdown-link-hover-bg: var(--ac-brand-soft);
    --bs-dropdown-link-active-bg: var(--ac-brand);
    --bs-dropdown-link-active-color: var(--ac-brand-contrast);
    --bs-dropdown-box-shadow: var(--ac-shadow-lg);
}

.modal {
    --bs-modal-bg: var(--ac-surface-raised);
    --bs-modal-color: var(--ac-text);
    --bs-modal-border-color: var(--ac-border);
    --bs-modal-border-radius: var(--ac-radius-lg);
    --bs-modal-header-border-color: var(--ac-border);
    --bs-modal-footer-border-color: var(--ac-border);
    --bs-modal-box-shadow: var(--ac-shadow-lg);
}

.offcanvas,
.offcanvas-start,
.offcanvas-end,
.offcanvas-top,
.offcanvas-bottom {
    --bs-offcanvas-bg: var(--ac-surface-raised);
    --bs-offcanvas-color: var(--ac-text);
    --bs-offcanvas-border-color: var(--ac-border);
}

.list-group {
    --bs-list-group-bg: var(--ac-surface);
    --bs-list-group-color: var(--ac-text);
    --bs-list-group-border-color: var(--ac-border);
    --bs-list-group-border-radius: var(--ac-radius-md);
    --bs-list-group-action-hover-bg: var(--ac-surface-sunken);
    --bs-list-group-active-bg: var(--ac-brand);
    --bs-list-group-active-border-color: var(--ac-brand);
    --bs-list-group-active-color: var(--ac-brand-contrast);
}

.progress {
    --bs-progress-bg: var(--ac-surface-sunken);
    --bs-progress-bar-bg: var(--ac-brand);
    --bs-progress-border-radius: var(--ac-radius-pill);
}

.badge { --bs-badge-border-radius: var(--ac-radius-pill); }

/* Tooltips are Bootstrap's rather than hand-rolled on purpose. Popper appends
   them to <body>, so they can never be clipped by an ancestor's overflow —
   which a CSS-only tooltip inevitably is, because .ac-table-wrap uses
   `overflow-x: auto` and the spec forces the other axis to `auto` too. Row
   action buttons live inside exactly that container. */
.tooltip {
    --bs-tooltip-bg: var(--ac-tooltip-bg);
    --bs-tooltip-color: var(--ac-tooltip-text);
    --bs-tooltip-border-radius: var(--ac-radius-sm);
    --bs-tooltip-font-size: var(--ac-text-xs);
    --bs-tooltip-opacity: 1;
    --bs-tooltip-padding-x: 0.5rem;
    --bs-tooltip-padding-y: 0.3rem;
}

.pagination {
    --bs-pagination-color: var(--ac-brand);
    --bs-pagination-bg: var(--ac-surface);
    --bs-pagination-border-color: var(--ac-border);
    --bs-pagination-hover-bg: var(--ac-surface-sunken);
    --bs-pagination-active-bg: var(--ac-brand);
    --bs-pagination-active-border-color: var(--ac-brand);
    --bs-pagination-active-color: var(--ac-brand-contrast);
    --bs-pagination-border-radius: var(--ac-radius-sm);
}

.alert-primary   { --bs-alert-bg: var(--ac-brand-soft);   --bs-alert-color: var(--ac-brand-active); --bs-alert-border-color: var(--ac-brand); }
.alert-success   { --bs-alert-bg: var(--ac-success-soft); --bs-alert-color: var(--ac-success-text); --bs-alert-border-color: var(--ac-success); }
.alert-danger    { --bs-alert-bg: var(--ac-danger-soft);  --bs-alert-color: var(--ac-danger-text);  --bs-alert-border-color: var(--ac-danger); }
.alert-warning   { --bs-alert-bg: var(--ac-warning-soft); --bs-alert-color: var(--ac-warning-text); --bs-alert-border-color: var(--ac-warning); }
.alert-info      { --bs-alert-bg: var(--ac-info-soft);    --bs-alert-color: var(--ac-info-text);    --bs-alert-border-color: var(--ac-info); }
.alert-secondary { --bs-alert-bg: var(--ac-neutral-soft); --bs-alert-color: var(--ac-neutral-text); --bs-alert-border-color: var(--ac-border-strong); }

/* Bootstrap's .bg-light / .bg-white are used as de-facto surface tokens all
   over the site (the fallback navbar is .bg-light). Remapping them keeps
   those pages coherent under dark and non-white-surface themes. */
.bg-light { background-color: var(--ac-surface-sunken) !important; }
.bg-white { background-color: var(--ac-surface) !important; }
.text-muted { color: var(--ac-text-muted) !important; }
.border-top { border-top: var(--ac-border-width) solid var(--ac-border) !important; }
.border-bottom { border-bottom: var(--ac-border-width) solid var(--ac-border) !important; }


/* ============================================================================
   5. BASE ELEMENTS
   ============================================================================
   Deliberately minimal. Anything that belongs to a named pattern lives in
   components.css; only genuine element-level defaults go here.
   ============================================================================ */

body {
    background-color: var(--ac-bg);
    background-image: var(--ac-bg-image);
    background-attachment: fixed;
    color: var(--ac-text);
    font-family: var(--ac-font-body);
}

/* NO `color` here, deliberately.
   A heading must INHERIT its colour. Setting it explicitly breaks every heading
   that sits inside a container with its own colour — `.text-white` on a brand bar,
   `.ac-callout--danger`, an inverted header — because a declaration on the element
   beats inheritance from its parent.
   That was a real bug: the team name on /Teams/Chat rendered in near-black on the
   brand-coloured header bar under every theme. The pages migrated so far only
   looked right because each of their stylesheets happened to re-set the colour.
   Body gives headings --ac-text already, which is all the default case needs. */
h1, h2, h3, h4, h5, h6 {
    font-family: var(--ac-font-heading);
    font-weight: var(--ac-weight-heading);
    letter-spacing: var(--ac-heading-tracking);
    text-transform: var(--ac-heading-transform);
    line-height: var(--ac-leading-tight);
}

a { color: var(--ac-link); }
a:hover { color: var(--ac-link-hover); }

hr {
    border-color: var(--ac-border);
    opacity: 1;
}

/* Selection sets the WASH ONLY — never the ink.
 *
 * `color: var(--ac-text)` used to be here, and it assumed every selectable thing
 * on the page sits on a theme surface. Plenty does not:
 *
 *   - TinyMCE's dialogs (Source Code, Insert Link) render in a portal on <body>
 *     with TinyMCE's own light skin — white background, dark text.
 *   - "Paper" surfaces we deliberately keep light in both modes, like
 *     .bulletin-readonly-view (see the exceptions list in CLAUDE.md).
 *
 * In dark mode --ac-text is near-white, so selecting anything in those places
 * painted near-white ink on an almost-white highlight — about 1.1:1, completely
 * unreadable. That was live in the bulletin builder's Source Code dialog.
 *
 * The wash is translucent, so it tints whatever is underneath without needing to
 * restate the ink. Letting the text keep its own colour is what makes this
 * correct on a themed surface, a third-party widget and paper alike. */
::selection {
    background: rgba(var(--ac-brand-rgb), 0.2);
}
