/* =====================================================================
 *  ChicaBate OS — the site-wide design language.
 *  Replaces design-skins.css, header-fx.css, theme-ambient.css and
 *  landing-fx.css. Extracted from the approved landing mockups.
 *
 *  ARCHITECTURE
 *  ------------
 *  Two settings drive everything:
 *
 *    html[data-theme]   palette   heat | plasma          (was: 21 palettes)
 *    html[data-page-bg] background static | ember | constellation
 *
 *  The palettes are structurally IDENTICAL and differ only by hue:
 *    heat   — chrome hue 350, accent ramp 70 -> 20 -> 340   (gold/red/magenta)
 *    plasma — chrome hue 300, accent ramp 300 -> 330 -> 285 (lilac/magenta/violet)
 *
 *  The 12-variable palette contract (--primary, --primary-rgb, --secondary,
 *  --accent, --gradient, ...) is UNCHANGED and still supplied by theme.js.
 *  That contract is used ~4,000 times across the 41 pages; keeping it means
 *  every existing component adopts the new palette for free. Do not break it.
 *
 *  Colours here are authored as oklch for the new surfaces (wider, more
 *  vivid ramp) but ALWAYS fall back through the hex/rgb contract so the
 *  pre-JS render and older engines stay correct.
 *
 *  --cb-h-chrome is the one knob that re-tints every neutral surface. It is
 *  set per palette below; every chrome rule reads it. Change it in one place
 *  and the whole UI re-tints coherently.
 * ===================================================================== */

/* ---- palette-driven hues -------------------------------------------- *
 * --cb-h-chrome tints every neutral surface.
 * --cb-hue-a/b/c are the ACCENT RAMP anchors, in ramp order (hot -> cold).
 * Anything that needs "a colour from this palette" — member cards, avatar
 * fallbacks, chart series — must derive from these and NEVER hardcode a
 * hue number. A literal hue here is how you end up with violet cards on a
 * red palette; it is a real bug that a render caught, not a nitpick.       */
html                      { --cb-h-chrome: 355; --cb-hue-a: 350; --cb-hue-b:   5; --cb-hue-c: 335; }
html[data-theme="heat"]   { --cb-h-chrome: 350; --cb-hue-a:  70; --cb-hue-b:  20; --cb-hue-c: 340; }
html[data-theme="plasma"] { --cb-h-chrome: 355; --cb-hue-a: 350; --cb-hue-b:   5; --cb-hue-c: 335; }

:root {
    /* Semantic colours — NOT themed. "Online" means online in every palette,
       so it must not drift with the accent ramp. */
    --cb-live:      #51E674;
    --cb-live-rgb:  81, 230, 116;

    /* Chrome surfaces, all derived from --cb-h-chrome */
    --cb-ink:       oklch(0.09 0.03 var(--cb-h-chrome));
    --cb-glass:     oklch(0.09 0.03 var(--cb-h-chrome) / .5);
    --cb-hairline:  oklch(0.90 0.05 var(--cb-h-chrome) / .08);
    --cb-rule:      oklch(0.90 0.05 var(--cb-h-chrome) / .14);
    --cb-text:      oklch(0.97 0.01 var(--cb-h-chrome));
    --cb-muted:     oklch(0.85 0.02 var(--cb-h-chrome) / .78);
    --cb-faint:     oklch(0.82 0.02 var(--cb-h-chrome) / .55);
    --cb-panel:     oklch(0.13 0.03 var(--cb-h-chrome) / .55);

    /* Type */
    /* BLOODY RED typography — vampiric: engraved Roman caps for display
     * (tombstone lettering), an art-deco poster sans for UI (legible at
     * dense sizes), an antique typewriter for data. Loaded on demand by
     * theme.js (EXPERIENCE_FONTS.os); every other design language overrides
     * these three tokens in experiences.css with its own faces. */
    --cb-display: 'Syne', 'Space Grotesk', system-ui, sans-serif;
    --cb-ui:      'Space Grotesk', system-ui, -apple-system, sans-serif;
    --cb-mono:    'Space Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

    /* Geometry — the mockup's radii, kept as tokens so panels agree */
    --cb-r-sm: 8px;
    --cb-r:    12px;
    --cb-r-lg: 18px;
    --cb-r-xl: 24px;
    /* The ONE radius for wide/RECTANGULAR buttons (full-width nav links, rail
     * items, dock/tab links) on every page. FULL CAPSULE on purpose: a mid
     * radius (14px) left flat segments between the corner arcs on taller
     * buttons — four arcs + four flats read as an OCTAGON (user screenshot,
     * 2026-07-25). At 999px the arcs join seamlessly, so every button end is
     * one continuous curve. Never give a wide nav item its own ad-hoc radius. */
    --cb-rect-r: 999px;

    /* The one page gutter. clamp() so it breathes without breakpoints. */
    --cb-gutter: clamp(20px, 5vw, 64px);
}

/* =====================================================================
 *  1. BASE
 * ===================================================================== */
body {
    font-family: var(--cb-ui);
    color: var(--cb-text);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;
}

/* Form controls do NOT inherit the body font — the UA stylesheet gives them
   its own (Arial here), so without this every button, input and select on the
   site silently renders in the wrong typeface. A render caught this; reading
   the CSS would not have. */
button, input, select, textarea, optgroup {
    font-family: inherit;
    font-size: 100%;
    line-height: inherit;
}

/* Native <select> dropdown popups, site-wide. The closed control is dark, but
   Chromium/Firefox draw the OPEN option list with the OS palette — and because
   our selects use a translucent background, that list came out white text on a
   white popup (only the highlighted row was legible). `color-scheme: dark` tells
   the engine to draw the popup dark; the explicit option colors are the fallback
   for engines that ignore it. Applies to every styled select that doesn't set
   its own option colors. */
select { color-scheme: dark; }
select option,
select optgroup {
    background-color: var(--cb-ink, #140c22);
    color: var(--cb-text, #f2f2f7);
}

/* ═══════════════════════════════════════════════════════════════════════
   SITE-WIDE DROPDOWN STYLE  ·  Website Layout › Dropdown Style
   ═══════════════════════════════════════════════════════════════════════
   Ten presets, chosen by an admin, applied as html[data-dropdown="<key>"]
   by theme.js — the same shape as data-dashboard and data-experience.

   WHY THIS USES !important.
   Dropdown styling on this site lives overwhelmingly in each page's own
   <style> block — 273 rules across 39 pages when this was written — and a
   page <style> comes AFTER every external sheet, so at equal specificity
   the page always won. A preset that a page could silently override is
   not a site-wide style, so the properties a page typically sets are
   forced here. This is the same bargain the uniform button radius already
   makes further down this file, and it has the same escape hatch:

       <select class="cb-dd-keep">   ← opts a control out entirely

   WHAT A PRESET CAN AND CANNOT DO — be honest about this in the UI.
   The CLOSED control is fully ours: fill, border, radius, corner shape,
   glow, typography and the arrow (drawn with gradients, so it follows the
   preset's accent without shipping an image). The OPEN option list is
   drawn by the BROWSER; only its background and text colour can be set.
   Nothing here can round the popup's corners or animate it — that needs a
   JS listbox replacing every native select, which is a different feature
   and a far bigger risk to every form on the site.

   Each preset sets variables only; the rules that consume them are
   written once, below. Adding an eleventh preset means one variable block
   and one whitelist entry, nothing else. */

/* ── the variables every preset fills in ─────────────────────────────── */
/* Every selector below is paired with a [data-dd-preview] form so the
   Website Layout > Dropdown Style cards are rendered by THESE rules, not
   by a look-alike copy in the admin page. What is auditioned is what
   ships — the same rule the 18+ badge and the tour button follow. */
html[data-dropdown], [data-dd-preview] {
    --dd-bg:      rgba(255,255,255,.05);
    --dd-bd:      rgba(255,255,255,.14);
    --dd-bw:      1px;
    --dd-r:       10px;
    --dd-fg:      var(--cb-text, #f2f2f7);
    --dd-accent:  var(--primary, #C40E2E);
    --dd-shadow:  none;
    --dd-focus:   0 0 0 2px rgba(var(--primary-rgb, 196,14,46), .45);
    --dd-pad-y:   9px;
    --dd-pad-x:   14px;
    --dd-ls:      normal;
    --dd-tt:      none;
    --dd-fw:      inherit;
    --dd-opt-bg:  var(--cb-ink, #140c22);
    --dd-opt-fg:  var(--cb-text, #f2f2f7);
    --dd-arrow-w: 7px;
}

/* ── the closed control ──────────────────────────────────────────────── */
html[data-dropdown]:not([data-dropdown="default"]) select:not(.cb-dd-keep),
[data-dd-preview] select:not(.cb-dd-keep) {
    -webkit-appearance: none; -moz-appearance: none; appearance: none;
    background-color: var(--dd-bg) !important;
    color: var(--dd-fg) !important;
    border: var(--dd-bw) solid var(--dd-bd) !important;
    border-radius: var(--dd-r) !important;
    /* Room for the arrow on the right, whatever the page asked for. */
    padding: var(--dd-pad-y) calc(var(--dd-pad-x) + 18px) var(--dd-pad-y) var(--dd-pad-x) !important;
    letter-spacing: var(--dd-ls) !important;
    text-transform: var(--dd-tt) !important;
    font-weight: var(--dd-fw);
    box-shadow: var(--dd-shadow) !important;
    /* The arrow is TWO gradients forming a solid chevron. Drawing it this
       way (rather than an SVG data URI) means it takes the preset's accent
       colour straight from a variable — no per-preset image, and nothing
       to keep in step when a colour changes. */
    background-image:
        linear-gradient(45deg,  transparent 50%, var(--dd-accent) 50%),
        linear-gradient(135deg, var(--dd-accent) 50%, transparent 50%) !important;
    background-position:
        calc(100% - var(--dd-pad-x) - var(--dd-arrow-w)) center,
        calc(100% - var(--dd-pad-x)) center !important;
    background-size: var(--dd-arrow-w) var(--dd-arrow-w) !important;
    background-repeat: no-repeat !important;
    cursor: pointer;
    transition: border-color .16s, box-shadow .16s, background-color .16s;
}
html[data-dropdown]:not([data-dropdown="default"]) select:not(.cb-dd-keep):hover,
[data-dd-preview] select:not(.cb-dd-keep):hover {
    border-color: var(--dd-accent) !important;
}
html[data-dropdown]:not([data-dropdown="default"]) select:not(.cb-dd-keep):focus,
html[data-dropdown]:not([data-dropdown="default"]) select:not(.cb-dd-keep):focus-visible,
[data-dd-preview] select:not(.cb-dd-keep):focus {
    outline: none !important;
    border-color: var(--dd-accent) !important;
    box-shadow: var(--dd-focus) !important;
}
html[data-dropdown]:not([data-dropdown="default"]) select:not(.cb-dd-keep):disabled,
[data-dd-preview] select:not(.cb-dd-keep):disabled {
    opacity: .5; cursor: default;
}
/* The one part of the popup a browser lets us colour. */
html[data-dropdown]:not([data-dropdown="default"]) select:not(.cb-dd-keep) option,
html[data-dropdown]:not([data-dropdown="default"]) select:not(.cb-dd-keep) optgroup,
[data-dd-preview] select:not(.cb-dd-keep) option {
    background-color: var(--dd-opt-bg) !important;
    color: var(--dd-opt-fg) !important;
}

/* The header account menu is a dropdown too, so a site-wide style that
   skipped it would look half-finished. Geometry stays as cb-components.css
   sets it; only the surface follows the preset. */
html[data-dropdown]:not([data-dropdown="default"]) .avatar-dropdown {
    background: var(--dd-opt-bg) !important;
    border: var(--dd-bw) solid var(--dd-bd) !important;
    border-radius: var(--dd-r) !important;
    box-shadow: var(--dd-shadow), 0 18px 44px rgba(0,0,0,.5) !important;
}

/* ── the ten presets ─────────────────────────────────────────────────── */
/* 1 · Neon Grid — hard-edged terminal cyan on near-black. */
html[data-dropdown="neon"], [data-dd-preview="neon"] {
    --dd-bg: #05080d; --dd-bd: rgba(0,229,255,.42); --dd-r: 3px;
    --dd-accent: #00E5FF; --dd-fg: #d6fbff; --dd-ls: .04em;
    --dd-shadow: inset 0 0 14px rgba(0,229,255,.10);
    --dd-focus: 0 0 0 1px #00E5FF, 0 0 16px rgba(0,229,255,.55);
    --dd-opt-bg: #05080d; --dd-opt-fg: #d6fbff;
}
/* 2 · Holo Pane — frosted glass, no hard colour of its own. */
html[data-dropdown="holo"], [data-dd-preview="holo"] {
    --dd-bg: rgba(255,255,255,.10); --dd-bd: rgba(255,255,255,.30); --dd-r: 14px;
    --dd-accent: #ffffff; --dd-fg: #ffffff;
    --dd-shadow: inset 0 1px 0 rgba(255,255,255,.22);
    --dd-focus: 0 0 0 3px rgba(255,255,255,.22);
    --dd-opt-bg: #1b1b22; --dd-opt-fg: #ffffff;
}
/* 3 · Circuit — board-green traces, wide tracking, nearly square. */
html[data-dropdown="circuit"], [data-dd-preview="circuit"] {
    --dd-bg: #071009; --dd-bd: rgba(87,255,141,.38); --dd-r: 2px;
    --dd-accent: #57FF8D; --dd-fg: #c6ffd8;
    --dd-ls: .10em; --dd-tt: uppercase; --dd-fw: 600;
    --dd-pad-y: 8px;
    --dd-shadow: inset 0 0 0 1px rgba(87,255,141,.10);
    --dd-focus: 0 0 0 1px #57FF8D, 0 0 18px rgba(87,255,141,.40);
    --dd-opt-bg: #071009; --dd-opt-fg: #c6ffd8;
}
/* 4 · Plasma Core — magenta bloom, the loudest of the ten. */
html[data-dropdown="plasma"], [data-dd-preview="plasma"] {
    --dd-bg: #14030f; --dd-bd: rgba(255,64,196,.45); --dd-r: 12px;
    --dd-accent: #FF40C4; --dd-fg: #ffd9f3;
    --dd-shadow: 0 0 22px -6px rgba(255,64,196,.55), inset 0 0 18px rgba(255,64,196,.12);
    --dd-focus: 0 0 0 2px rgba(255,64,196,.6), 0 0 30px -4px rgba(255,64,196,.7);
    --dd-opt-bg: #14030f; --dd-opt-fg: #ffd9f3;
}
/* 5 · Vapor Drive — cyan and magenta, eighties-future. */
html[data-dropdown="vapor"], [data-dd-preview="vapor"] {
    --dd-bg: #180d2b; --dd-bd: rgba(0,229,255,.5); --dd-bw: 2px; --dd-r: 6px;
    --dd-accent: #FF6AD5; --dd-fg: #eae0ff; --dd-ls: .03em;
    --dd-shadow: 3px 3px 0 rgba(255,106,213,.35);
    --dd-focus: 3px 3px 0 rgba(255,106,213,.6), 0 0 0 2px rgba(0,229,255,.5);
    --dd-opt-bg: #180d2b; --dd-opt-fg: #eae0ff;
}
/* 6 · Command Deck — flat instrument slab, zero radius, amber legend. */
html[data-dropdown="deck"], [data-dd-preview="deck"] {
    --dd-bg: #101418; --dd-bd: rgba(255,176,32,.35); --dd-r: 0px;
    --dd-accent: #FFB020; --dd-fg: #e8eef4;
    --dd-ls: .14em; --dd-tt: uppercase; --dd-fw: 700; --dd-pad-y: 10px;
    --dd-shadow: inset 0 -2px 0 rgba(255,176,32,.30);
    --dd-focus: inset 0 -2px 0 #FFB020, 0 0 0 1px rgba(255,176,32,.45);
    --dd-opt-bg: #101418; --dd-opt-fg: #e8eef4;
}
/* 7 · Aurora Veil — soft, roundest, no hard edge anywhere. */
html[data-dropdown="aurora"], [data-dd-preview="aurora"] {
    --dd-bg: rgba(120,180,255,.12); --dd-bd: rgba(160,220,255,.24); --dd-r: 999px;
    --dd-accent: #8FD8FF; --dd-fg: #eaf6ff;
    --dd-pad-x: 18px;
    --dd-shadow: inset 0 0 22px rgba(140,200,255,.14);
    --dd-focus: 0 0 0 3px rgba(143,216,255,.30);
    --dd-opt-bg: #101a2a; --dd-opt-fg: #eaf6ff;
}
/* 8 · Obsidian — the restrained one. Pure black, hairline edge. */
html[data-dropdown="obsidian"], [data-dd-preview="obsidian"] {
    --dd-bg: #000000; --dd-bd: rgba(255,255,255,.22); --dd-r: 2px;
    --dd-accent: #ffffff; --dd-fg: #f4f4f6;
    --dd-shadow: none;
    --dd-focus: 0 0 0 1px #ffffff;
    --dd-opt-bg: #000000; --dd-opt-fg: #f4f4f6;
}
/* 9 · Reactor — warning-panel amber with a hazard double edge. */
html[data-dropdown="reactor"], [data-dd-preview="reactor"] {
    --dd-bg: #150c02; --dd-bd: rgba(255,138,0,.5); --dd-bw: 1px; --dd-r: 4px;
    --dd-accent: #FF8A00; --dd-fg: #ffe4c2; --dd-fw: 600;
    --dd-shadow: inset 0 0 0 2px rgba(255,138,0,.12), 0 0 18px -8px rgba(255,138,0,.7);
    --dd-focus: inset 0 0 0 2px rgba(255,138,0,.35), 0 0 0 2px rgba(255,138,0,.5);
    --dd-opt-bg: #150c02; --dd-opt-fg: #ffe4c2;
}
/* 10 · Singularity — violet event horizon, an inner ring rather than a border. */
html[data-dropdown="singularity"], [data-dd-preview="singularity"] {
    --dd-bg: #0b0614; --dd-bd: rgba(167,110,255,.30); --dd-r: 999px;
    --dd-accent: #A76EFF; --dd-fg: #e9dcff; --dd-pad-x: 18px;
    --dd-shadow: inset 0 0 0 1px rgba(167,110,255,.30),
                 inset 0 0 20px rgba(167,110,255,.22);
    --dd-focus: inset 0 0 0 1px rgba(167,110,255,.6),
                0 0 26px -6px rgba(167,110,255,.8);
    --dd-opt-bg: #0b0614; --dd-opt-fg: #e9dcff;
}

/* Motion is a preference. The transition is the only movement here, so
   this is short — but it still has to be honoured. */
@media (prefers-reduced-motion: reduce) {
    html[data-dropdown] select:not(.cb-dd-keep) { transition: none !important; }
}

/* The page floor. The animated layer (chicabate-bg.js) paints ON TOP of
   this, so a JS failure or reduced-motion still leaves a correct backdrop
   rather than a white flash. */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -10;
    pointer-events: none;
    background:
        radial-gradient(120% 120% at 50% 45%,
            oklch(0.20 0.09 var(--cb-h-chrome)) 0%,
            oklch(0.06 0.03 var(--cb-h-chrome)) 72%),
        var(--cb-ink);
}

::selection { background: rgba(var(--primary-rgb, 196, 14, 46), .45); color: #fff; }

a { color: var(--primary); text-decoration: none; transition: color .18s ease; }
a:hover { color: var(--primary-glow, var(--accent)); }
/* Anchors and labels that ARE buttons must never take the link hover colour:
 * `a:hover` (0,1,1) beats their single-class colour rules, so hovering a
 * gradient CTA faded its label to --primary-glow ON the red gradient
 * (~2:1 — unreadable; reported 2026-08-05). Every anchor-button on this
 * site wants white on hover — the immune ones (.notif-btn,
 * .create-account-btn) already re-declared exactly that. */
a[class*="btn"]:hover, a[class*="cta"]:hover, label[class*="btn"]:hover { color: #fff; }

/* Focus: visible on every palette, never removed. Keyboard users are not
   a special case. */
:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
    border-radius: 4px;
}

/* Scrollbar, tinted to the palette so the chrome doesn't break the mood */
* { scrollbar-color: rgba(var(--primary-rgb), .45) transparent; scrollbar-width: thin; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
    background: rgba(var(--primary-rgb), .35);
    border-radius: 99px;
    border: 2px solid transparent;
    background-clip: content-box;
}
*::-webkit-scrollbar-thumb:hover { background: rgba(var(--primary-rgb), .6); background-clip: content-box; }

/* ── Gradient repeat-seam fix ──────────────────────────────────────────
 * A linear-gradient background repeats by default; at a fractional pixel
 * width the tile wraps and shows a 1px vertical line of the START colour at
 * the edge — visible on gradient-filled buttons, nav items, tabs, and the
 * palette bars. Forcing the gradient to EXACTLY cover the box (100% 100%, no
 * repeat) leaves no tile to repeat, so the seam disappears. background-size is
 * a no-op on solid/transparent fills, and this list never matches <select>
 * (whose arrow SVG must keep its own size). Elements that set their own
 * background-size (e.g. animated 200% avatars) aren't matched here. */
/* !important is REQUIRED: the gradient rules above use the `background`
 * SHORTHAND, which implicitly sets background-size:auto, and many are
 * high-specificity (e.g. html[data-dashboard="draconium"] .dr-snav[aria-current]).
 * A normal background-size here would lose the cascade and the seam would
 * stay on exactly those buttons. !important beats the shorthand's implicit
 * (normal) auto. Safe: no element in this list sets its own background-size
 * (only <select> arrows and animated 200% avatars/heroes do, none matched). */
button, input[type="submit"], input[type="button"],
[class*="btn"], [class*="button"],
.tab, .category-tab, .dr-ttab, .dr-snav, .dr-navlink,
.cd-side a, .cd-tabbar a, .header-nav-links a,
.pe-grad-bar {
    background-repeat: no-repeat !important;
    background-size: 100% 100% !important;
}

/* ── Uniform button curvature ──────────────────────────────────────────
 * Every push button on every page shares ONE fully-curved capsule radius,
 * so adjacent buttons can never disagree about their corners (the mail
 * compose "A member" / "Admin / Support" pair was the visible offender —
 * pages had drifted across 8/9/10/12/14px and 999px). The capsule matches
 * the site's oval nav pills, the pill inputs and the Draconium rails.
 * !important is REQUIRED for the same cascade reason as the seam fix
 * above: per-page border-radius rules are class-specific and would beat a
 * bare element selector.
 * Shape-exempt (their geometry IS the design, they only read as cards or
 * rows, not buttons): the picker tiles in Website Theme (.pal-card,
 * .exp-card, .dash-card, .logo-card-btn), dropdown menu rows
 * (.status-menu-item, .logout-item), and anything given .cb-corner-keep —
 * the documented escape hatch for future tile-like buttons. */
button:not(.pal-card):not(.exp-card):not(.dash-card):not(.logo-card-btn):not(.status-menu-item):not(.logout-item):not(.cb-corner-keep),
input[type="submit"], input[type="button"], input[type="reset"],
a.btn:not(.cb-corner-keep) {
    border-radius: 999px !important;
}

/* ── Selected-state curvature for nav items that are NOT <button>s ─────
 * The capsule rule above covers <button>-based navs, but <a>/<div>-based
 * nav items kept per-page 6-9px corners — visible on their gradient
 * SELECTED state as boxy pills next to smooth ones. Two families, same
 * as everywhere else:
 *  - the main nav links (the top bar — which the Sidebar Panel layout
 *    turns into the site-wide SIDEBAR) take the rectangular smooth curve;
 *    the Tabbed Workspace layout is excluded because its links are
 *    already full 999px pills.
 *  - small tab chips that render as <button> capsules on some pages but
 *    <div>s on others (.mc-tab, .sub-tab) take the capsule, so the same
 *    tab never changes shape between pages. */
html:not([data-dashboard="tabs"]) .header-nav-links > a,
html:not([data-dashboard="tabs"]) .nav-links > a {
    border-radius: var(--cb-rect-r, 14px) !important;
}
.mc-tab, .sub-tab { border-radius: 999px !important; }

/* Sidebar rails + <a>/<div>-based push buttons, pinned to the capsule
 * explicitly (requested 2026-07-26): the unified admin rail links
 * (.dr-snav), the Draconium dashboard rail links (.dr-navlink), the
 * Website Theme picker rail (.tv-navbtn), and the content-type tabs
 * (.content-tab — a <div>, so it dodged the <button> capsule rule and
 * sat at 15px). Same 999px capsule as every push button, on every page.
 * 2026-08-05 (audit, "corners aren't curved anymore"): the same dodge
 * existed wherever a BUTTON CLASS sits on an <a> or <label> — the
 * dashboards' quick-action anchors, "Full list page", the pricing plan
 * CTAs, the landing hero .cb-btn pair, the header .notif-btn icons and
 * the modal link-buttons all rendered their authored 6–15px rectangles
 * next to capsule <button>s. Pinned here with the rest. */
.dr-snav, .dr-navlink, .tv-navbtn, .content-tab,
.action-btn:not(.cb-corner-keep), .plan-btn, .cb-btn:not(.cb-corner-keep),
.modal-btn, .notif-btn {
    border-radius: 999px !important;
}

/* Admin action buttons, one size down (audit 2026-08-05, "buttons are too
 * big"): 14 admin pages author .action-btn at 15px 25px / 16px — ≈56px
 * tall next to the design system's .cb-btn at 11px 20px / 14px. Normalized
 * here centrally; the per-page rules keep their colours and borders. */
.action-btn {
    padding: 10px 18px !important;
    font-size: 14px !important;
}

/* ── Mobile-engine corner artifacts (phone screenshots, 2026-07-26) ────
 * The capsule radius was correct, but three Android rendering quirks
 * still drew square corners on the SELECTED gradient pills:
 *  (a) gradient backgrounds can BLEED past a rounded corner as square
 *      specks on some mobile engines — clip the paint to the padding box
 *      so the curve is always clean;
 *  (b) the default grey -webkit-tap-highlight paints a RECTANGLE over a
 *      rounded button while it is tapped;
 *  (c) UA focus rings are square-cornered on Samsung Internet / WebViews —
 *      replaced with a radius-following box-shadow ring (kept on
 *      :focus-visible so keyboard users never lose the indicator). */
/* !important on the clip: the selected states set the `background:`
 * SHORTHAND (higher specificity), which silently resets background-clip
 * to border-box — putting the bleed right back on the gradient pills. */
button, a.btn, .dr-snav, .dr-navlink, .tv-navbtn, .content-tab,
.dr-ttab, .cat-tab, .category-tab, .tabs .tab, .hc-seg button,
.pe-btn, .view-mode-btn {
    background-clip: padding-box !important;
    -webkit-tap-highlight-color: transparent;
}
.dr-snav:focus, .dr-navlink:focus, .tv-navbtn:focus, .content-tab:focus,
.dr-ttab:focus, .pe-btn:focus, .hc-seg button:focus, .view-mode-btn:focus {
    outline: none;
}
.dr-snav:focus-visible, .dr-navlink:focus-visible, .tv-navbtn:focus-visible,
.content-tab:focus-visible, .dr-ttab:focus-visible, .pe-btn:focus-visible,
.hc-seg button:focus-visible, .view-mode-btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(var(--primary-rgb, 196, 14, 46), .45);
}

/* =====================================================================
 *  2. TYPE
 *  Syne for display (the mockup's wordmark + headlines), Space Grotesk for
 *  UI, Space Mono for anything that is DATA — counts, labels, timestamps.
 *  Mono on live data is deliberate: "12,480 online" should read as a fact,
 *  not as marketing.
 * ===================================================================== */
.cb-display, .cb-h1, .cb-h2 { font-family: var(--cb-display); font-weight: 800; letter-spacing: -.02em; line-height: .95; }
.cb-h1 { font-size: clamp(44px, 9vw, 128px); }
.cb-h2 { font-size: clamp(30px, 4.4vw, 58px); }
.cb-mono, .mono { font-family: var(--cb-mono); }
.cb-syne, .syne  { font-family: var(--cb-display); }

/* The gradient headline word. Kept as a class, not baked into h1, so only
   the ONE charged word carries it. */
.cb-hot {
    background: var(--gradient-glow, linear-gradient(120deg, var(--accent), var(--secondary)));
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent; color: transparent;
    /* background-clip:text clips the box, so an italic or descender glyph that
       overhangs (the trailing italic "e" in "Theme") gets its tail cut off.
       A hair of right/bottom room lets the last glyph paint in full. */
    padding: 0 .14em .06em 0;
}

/* Serif masthead titles ("Website <em>Theme</em>", "Kink <em>Manager</em>")
   are gradient-clipped by a .modal-header h2 rule; the italic <em> is the last
   word, so its overhang was being cut. Same fix, applied wherever .tm-title
   appears (admin-theme, admin-kinktest, admindashboard theme panel). */
.tm-title { padding-right: .16em; overflow: visible; }

/* Section label — "// 01 — LIVE SIGNALS" */
.cb-seclabel {
    font-family: var(--cb-mono);
    font-size: 11px;
    letter-spacing: .22em;
    text-transform: uppercase;
    color: var(--cb-faint);
    display: block;
    margin-bottom: 14px;
}
.cb-seclabel::before { content: "// "; color: var(--primary); }

/* =====================================================================
 *  3. TICKER — the live signal strip above the nav
 * ===================================================================== */
.cb-ticker {
    position: relative;
    overflow: hidden;
    background: oklch(0.06 0.02 var(--cb-h-chrome));
    border-bottom: 1px solid var(--cb-hairline);
    padding: 5px 0;
    z-index: 60;
}
.cb-ticker-track {
    display: flex;
    gap: 0;
    width: max-content;
    animation: cbTicker 40s linear infinite;
}
.cb-ticker-group {
    display: flex;
    gap: 38px;
    padding-right: 38px;
    font-family: var(--cb-mono);
    font-size: 11px;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--cb-faint);
    white-space: nowrap;
}
.cb-ticker-live  { color: var(--cb-live); }
.cb-ticker-spark { color: var(--secondary); }
.cb-ticker:hover .cb-ticker-track { animation-play-state: paused; }
@keyframes cbTicker { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* =====================================================================
 *  4. HEADER / NAV — glass bar
 *  NOTE: the header is NEVER masked and NEVER given overflow:hidden.
 *  Both clip the avatar dropdown, which is a real child of the header.
 *  This has bitten this codebase before. Do not "tidy" it.
 * ===================================================================== */
.cb-nav, header.cb-nav {
    position: sticky;
    top: 0;
    z-index: 50;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
    padding: 16px var(--cb-gutter);
    background: var(--cb-glass);
    -webkit-backdrop-filter: blur(18px) saturate(1.4);
            backdrop-filter: blur(18px) saturate(1.4);
    border-bottom: 1px solid var(--cb-hairline);
}
.cb-brand { display: flex; align-items: center; gap: 12px; color: #fff; }
.cb-logo-mark {
    width: 34px; height: 34px;
    border-radius: 11px;
    display: inline-block;
    flex: none;
    background: conic-gradient(from 210deg,
        var(--accent), var(--primary), var(--secondary), var(--accent));
    animation: cbLogoFlicker 2.4s ease-in-out infinite;
}
.cb-wordmark {
    font-family: var(--cb-display);
    font-weight: 800;
    font-size: 22px;
    letter-spacing: -.02em;
}
@keyframes cbLogoFlicker {
    0%, 100% { filter: drop-shadow(0 0 6px rgba(var(--primary-rgb), .9))  drop-shadow(0 0 18px rgba(var(--secondary-rgb), .6)); }
    45%      { filter: drop-shadow(0 0 10px rgba(var(--primary-rgb), 1))  drop-shadow(0 0 26px rgba(var(--secondary-rgb), .8)); }
    70%      { filter: drop-shadow(0 0 4px rgba(var(--primary-rgb), .7))  drop-shadow(0 0 12px rgba(var(--secondary-rgb), .4)); }
}

.cb-navlinks { display: flex; align-items: center; gap: 26px; }
.cb-navlink {
    font-family: var(--cb-mono);
    font-size: 12px;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--cb-muted);
    transition: color .18s ease;
}
.cb-navlink:hover, .cb-navlink[aria-current="page"] { color: #fff; }

/* =====================================================================
 *  5. BUTTONS
 * ===================================================================== */
.cb-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    font-family: var(--cb-ui);
    font-size: 14px;
    font-weight: 600;
    line-height: 1;
    padding: 11px 20px;
    border-radius: var(--cb-r);
    border: 1px solid transparent;
    cursor: pointer;
    transition: filter .18s ease, border-color .18s ease, background .18s ease, transform .18s ease;
}
.cb-btn:active { transform: translateY(1px); }

.cb-btn-primary {
    font-weight: 700;
    color: #fff;
    background: var(--gradient, linear-gradient(120deg, var(--primary-glow), var(--primary)));
    box-shadow: 0 8px 30px rgba(var(--primary-rgb), .45);
}
.cb-btn-primary:hover { filter: brightness(1.12); }

.cb-btn-ghost {
    color: #fff;
    background: transparent;
    border-color: oklch(0.90 0.05 var(--cb-h-chrome) / .18);
}
.cb-btn-ghost:hover {
    border-color: rgba(var(--primary-rgb), .6);
    background: rgba(var(--primary-rgb), .08);
}

/* =====================================================================
 *  6. SURFACES — panels, member cards, chips
 * ===================================================================== */
.cb-panel {
    background: var(--cb-panel);
    -webkit-backdrop-filter: blur(14px);
            backdrop-filter: blur(14px);
    border: 1px solid var(--cb-hairline);
    border-radius: var(--cb-r-lg);
}

/* Member card. Each card sits at its own point on the palette ramp: set
   --hue to one of --cb-hue-a/b/c, never to a literal number, or the card
   will not follow the palette. Defaults to the ramp's mid anchor. */
.cb-card {
    --hue: var(--cb-hue-b);
    position: relative;
    aspect-ratio: 3 / 4;
    border-radius: var(--cb-r-lg);
    overflow: hidden;                     /* safe: a card holds no dropdown */
    border: 1px solid var(--cb-hairline);
    background:
        linear-gradient(160deg,
            oklch(0.42 0.20 var(--hue)),
            oklch(0.16 0.08 var(--hue)));
    transition: transform .5s cubic-bezier(.16,1,.3,1), border-color .3s ease, box-shadow .5s ease;
}
.cb-card:hover {
    transform: translateY(-6px);
    border-color: rgba(var(--primary-rgb), .5);
    box-shadow: 0 24px 60px rgba(var(--primary-rgb), .28);
}
.cb-card-meta {
    position: absolute;
    left: 0; right: 0; bottom: 0;
    padding: 14px;
    background: linear-gradient(to top, rgba(0,0,0,.82), transparent);
}
.cb-card-name { font-family: var(--cb-display); font-weight: 700; font-size: 17px; }
.cb-card-city { font-family: var(--cb-mono); font-size: 11px; color: var(--cb-faint); }

/* Match chip — "94%" */
.cb-chip {
    position: absolute;
    top: 10px; right: 10px;
    font-family: var(--cb-mono);
    font-size: 10px;
    font-weight: 700;
    padding: 4px 7px;
    border-radius: var(--cb-r-sm);
    background: rgba(0,0,0,.55);
    -webkit-backdrop-filter: blur(6px);
            backdrop-filter: blur(6px);
    border: 1px solid var(--cb-hairline);
    color: var(--accent);
}

/* Live dot — semantic green, never themed */
.cb-live {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: var(--cb-mono);
    font-size: 10px;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--cb-live);
}
.cb-live::before {
    content: "";
    width: 6px; height: 6px;
    border-radius: 50%;
    background: var(--cb-live);
    box-shadow: 0 0 8px rgba(var(--cb-live-rgb), .9);
    animation: cbPulse 2s ease-in-out infinite;
}
@keyframes cbPulse { 0%,100% { opacity: .5; transform: scale(1); } 50% { opacity: 1; transform: scale(1.3); } }

/* =====================================================================
 *  7. FORMS + TABLES
 *  The mockup is a landing page — it shows no form, no table, no admin
 *  surface. These are authored to match its language (mono labels, glass
 *  panels, gradient focus) so the other 40 pages don't fall back to the
 *  old look the moment a user signs in.
 * ===================================================================== */
.cb-label {
    display: block;
    font-family: var(--cb-mono);
    font-size: 11px;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--cb-faint);
    margin-bottom: 7px;
}
.cb-input, .cb-select, .cb-textarea {
    width: 100%;
    font-family: var(--cb-ui);
    font-size: 14px;
    color: var(--cb-text);
    padding: 12px 14px;
    border-radius: var(--cb-r);
    background: oklch(0.14 0.02 var(--cb-h-chrome) / .6);
    border: 1px solid var(--cb-rule);
    transition: border-color .18s ease, box-shadow .18s ease, background .18s ease;
}
.cb-input::placeholder, .cb-textarea::placeholder { color: var(--cb-faint); }
.cb-input:focus, .cb-select:focus, .cb-textarea:focus {
    outline: none;
    border-color: var(--primary);
    background: oklch(0.16 0.03 var(--cb-h-chrome) / .75);
    box-shadow: 0 0 0 3px rgba(var(--primary-rgb), .22);
}
.cb-input[aria-invalid="true"] { border-color: #FF5A5A; box-shadow: 0 0 0 3px rgba(255,90,90,.2); }

.cb-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.cb-table th {
    font-family: var(--cb-mono);
    font-size: 11px;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--cb-faint);
    text-align: left;
    padding: 10px 12px;
    border-bottom: 1px solid var(--cb-rule);
}
.cb-table td { padding: 12px; border-bottom: 1px solid var(--cb-hairline); }
.cb-table tbody tr { transition: background .15s ease; }
.cb-table tbody tr:hover { background: rgba(var(--primary-rgb), .06); }
/* Numeric columns are data — mono + right-aligned so digits line up. */
.cb-table .num { font-family: var(--cb-mono); text-align: right; font-variant-numeric: tabular-nums; }

/* Wide tables must scroll in their OWN box; the page body must never
   scroll sideways. */
.cb-tablewrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* =====================================================================
 *  8. SCROLL REVEAL
 * ===================================================================== */
[data-reveal] {
    opacity: 0;
    transform: translateY(40px);
    transition: opacity 1s cubic-bezier(.16,1,.3,1), transform 1s cubic-bezier(.16,1,.3,1);
}
[data-reveal].in { opacity: 1; transform: none; }

/* =====================================================================
 *  9. LAYOUT
 * ===================================================================== */
.cb-wrap    { max-width: 1280px; margin: 0 auto; padding-inline: var(--cb-gutter); }
.cb-section { padding-block: clamp(64px, 9vw, 128px); position: relative; z-index: 1; }

/* =====================================================================
 *  10. REDUCED MOTION
 *  Honour the OS setting. The previous ambient system deliberately
 *  overrode it; that was a bug, not a feature. Anyone who asks for less
 *  motion gets less motion — the background falls back to Static in
 *  chicabate-bg.js, and the decorative loops stop here.
 * ===================================================================== */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
        scroll-behavior: auto !important;
    }
    [data-reveal] { opacity: 1; transform: none; }
    .cb-ticker-track { animation: none; }
}

/* =====================================================================
 *  11. MOBILE
 * ===================================================================== */
@media (max-width: 860px) {
    .cb-navlinks { display: none; }        /* nav-mobile.js owns the drawer */
    .cb-nav { padding: 12px var(--cb-gutter); }
    .cb-h1 { letter-spacing: -.01em; }
}

/* ── Fixed-header pages: stop the page title being clipped ────────────
 *  The content/dashboard pages pin <header> with `position: fixed` and
 *  offset <main> with a FIXED `margin-top: 80px` (both in each page's
 *  inline <style>). But the header's real height varies a lot with
 *  viewport width — the nav wraps to 2–3 rows in a wide band (~850–1150px
 *  it measures ~144px, far taller than 80px), so the title (e.g.
 *  "Messages & Chat") slid underneath the header. A fixed pixel offset
 *  can never track that.
 *
 *  This file loads AFTER those inline styles, so the rules below win: the
 *  header becomes `sticky` — it stays in normal flow, so content is pushed
 *  down by the header's ACTUAL height (never overlapped) at any width,
 *  while still pinning to the top on scroll — and the now-wrong fixed
 *  `main` offset is removed. Landing (index.html has no <header>) is
 *  unaffected; the header keeps its blur, shadow and z-index. */
header { position: sticky; top: 0; }
/* Uniform gap between the (sticky, in-flow) header and the page title on
 *  EVERY page. Pages previously set this inconsistently — some via
 *  `margin-top: 80px` + small padding (~28px gap), others (media, shop) via
 *  `padding-top: 100px` — so the header→title spacing differed page to page.
 *  Because the header now sits in normal flow, the gap is simply main's
 *  top padding; fixing it here (this file wins over the inline styles)
 *  makes it identical everywhere, matching the Public Media reference. */
main   { margin-top: 0; padding-top: 100px; }
@media (max-width: 860px) { main { padding-top: 90px; } }
/* maintenance.html's <main class="wrap"> is a flex-centred card with no
   fixed header above it — the global top padding de-centred it and
   pushed its buttons below the fold on phones. */
main.wrap { padding-top: 0; }

/* ── Click sonar: a glowing ripple blooms at the cursor on every click.
 *  Spawned as a fixed DOM element by chicabate-bg.js (works on every page,
 *  independent of the page-background canvas). Colour follows the palette /
 *  active experience via var(--primary). ───────────────────────────────── */
.cb-click-ripple {
    position: fixed; z-index: 9998; pointer-events: none;
    width: 16px; height: 16px; margin: -8px 0 0 -8px; border-radius: 50%;
    border: 2px solid var(--primary, #C40E2E);
    box-shadow: 0 0 16px 3px var(--primary, #C40E2E),
                inset 0 0 8px var(--primary, #C40E2E);
    animation: cb-sonar 650ms cubic-bezier(.16,.6,.28,1) forwards;
    will-change: transform, opacity;
}
@keyframes cb-sonar {
    0%   { transform: scale(.28); opacity: .95; }
    100% { transform: scale(6);   opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .cb-click-ripple { display: none; } }

/* =====================================================================
 *  MOUSE BEHAVIOUR (Website Theme › Mouse Behaviour)
 *  Three independent site-wide choices, applied by theme.js as attributes
 *  on <html>: data-mouse-cursor (painted here, pure CSS), data-mouse-click
 *  and data-mouse-move (spawned as DOM particles by chicabate-bg.js, styled
 *  here). Defaults = the original behaviour: system cursor, the sonar
 *  ripple above, no move effect — so pages that never load the new
 *  attributes look exactly as before.
 * ===================================================================== */

/* ── Cursor designs ── one arrow silhouette, five treatments. SVG data-URIs
 * can't read CSS variables, so each design commits to a fixed accent from
 * the site's palettes; every one carries a dark halo + light edge so it
 * reads on the near-black chrome AND on bright photos. Hotspot 2 1 = the
 * arrow tip. `, auto` keeps a working cursor if a browser rejects SVG. */
html[data-mouse-cursor="ember"], html[data-mouse-cursor="ember"] * {
    cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 28 28'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%23FFC24A'/%3E%3Cstop offset='1' stop-color='%23E23A4E'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cpath d='M2 1 L2 21.5 L7.9 16.9 L11.3 24.3 L15.1 22.5 L11.7 15.2 L19.2 14.6 Z' fill='none' stroke='rgba(10,7,16,0.55)' stroke-width='4' stroke-linejoin='round'/%3E%3Cpath d='M2 1 L2 21.5 L7.9 16.9 L11.3 24.3 L15.1 22.5 L11.7 15.2 L19.2 14.6 Z' fill='url(%23g)' stroke='%23FFF4E4' stroke-width='1.4' stroke-linejoin='round'/%3E%3C/svg%3E") 2 1, auto;
}
html[data-mouse-cursor="neon"], html[data-mouse-cursor="neon"] * {
    cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 28 28'%3E%3Cpath d='M2 1 L2 21.5 L7.9 16.9 L11.3 24.3 L15.1 22.5 L11.7 15.2 L19.2 14.6 Z' fill='none' stroke='%23F25DEA' stroke-opacity='0.35' stroke-width='4.5' stroke-linejoin='round'/%3E%3Cpath d='M2 1 L2 21.5 L7.9 16.9 L11.3 24.3 L15.1 22.5 L11.7 15.2 L19.2 14.6 Z' fill='%2317041F' stroke='%23F25DEA' stroke-width='1.6' stroke-linejoin='round'/%3E%3C/svg%3E") 2 1, auto;
}
html[data-mouse-cursor="nova"], html[data-mouse-cursor="nova"] * {
    cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 28 28'%3E%3Cpath d='M2 1 L2 21.5 L7.9 16.9 L11.3 24.3 L15.1 22.5 L11.7 15.2 L19.2 14.6 Z' fill='none' stroke='rgba(20,8,40,0.55)' stroke-width='4' stroke-linejoin='round'/%3E%3Cpath d='M2 1 L2 21.5 L7.9 16.9 L11.3 24.3 L15.1 22.5 L11.7 15.2 L19.2 14.6 Z' fill='%23FFFFFF' stroke='%237B53FF' stroke-width='1.5' stroke-linejoin='round'/%3E%3Cpath d='M22 2.2 l1 2.3 2.3 1 -2.3 1 -1 2.3 -1-2.3 -2.3-1 2.3-1 Z' fill='%237B53FF'/%3E%3C/svg%3E") 2 1, auto;
}
html[data-mouse-cursor="chrome"], html[data-mouse-cursor="chrome"] * {
    cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 28 28'%3E%3Cdefs%3E%3ClinearGradient id='m' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%23F4F6F8'/%3E%3Cstop offset='0.55' stop-color='%239AA3AD'/%3E%3Cstop offset='1' stop-color='%23E8ECF0'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cpath d='M2 1 L2 21.5 L7.9 16.9 L11.3 24.3 L15.1 22.5 L11.7 15.2 L19.2 14.6 Z' fill='none' stroke='rgba(0,0,0,0.5)' stroke-width='4' stroke-linejoin='round'/%3E%3Cpath d='M2 1 L2 21.5 L7.9 16.9 L11.3 24.3 L15.1 22.5 L11.7 15.2 L19.2 14.6 Z' fill='url(%23m)' stroke='%2323272E' stroke-width='1.2'/%3E%3C/svg%3E") 2 1, auto;
}
html[data-mouse-cursor="rose"], html[data-mouse-cursor="rose"] * {
    cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 28 28'%3E%3Cdefs%3E%3ClinearGradient id='r' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%23FF9BE8'/%3E%3Cstop offset='1' stop-color='%23E84D9E'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cpath d='M2 1 L2 21.5 L7.9 16.9 L11.3 24.3 L15.1 22.5 L11.7 15.2 L19.2 14.6 Z' fill='none' stroke='rgba(40,6,26,0.5)' stroke-width='4' stroke-linejoin='round'/%3E%3Cpath d='M2 1 L2 21.5 L7.9 16.9 L11.3 24.3 L15.1 22.5 L11.7 15.2 L19.2 14.6 Z' fill='url(%23r)' stroke='%23FFFFFF' stroke-width='1.4' stroke-linejoin='round'/%3E%3Cpath d='M22 4.4 c-0.9-1.7-3.2-1.2-3.2 0.7 0 1.4 1.7 2.3 3.2 3.6 1.5-1.3 3.2-2.2 3.2-3.6 0-1.9-2.3-2.4-3.2-0.7 Z' fill='%23FFFFFF'/%3E%3C/svg%3E") 2 1, auto;
}
/* Editable fields keep the I-beam under every cursor design — an arrow over
 * a text box hides where the caret will land. */
html[data-mouse-cursor] textarea,
html[data-mouse-cursor] [contenteditable="true"],
html[data-mouse-cursor] input[type="text"], html[data-mouse-cursor] input[type="search"],
html[data-mouse-cursor] input[type="email"], html[data-mouse-cursor] input[type="password"],
html[data-mouse-cursor] input[type="url"], html[data-mouse-cursor] input[type="tel"],
html[data-mouse-cursor] input[type="number"] { cursor: text; }

/* ── Click + move effects ── DOM particles spawned by chicabate-bg.js at the
 * pointer, coloured off the LIVE palette via var(--primary)/… so every design
 * language tints its own effects. All are pointer-events:none, self-remove
 * after their animation, and are capped/throttled in JS. */
.cbfx { position: fixed; z-index: 9998; pointer-events: none; will-change: transform, opacity; }

/* Starburst — spark rays shoot out of the click point. */
.cbfx-spark {
    width: 3px; height: 13px; margin: -6px 0 0 -1px; border-radius: 2px;
    background: linear-gradient(to top, transparent, var(--primary, #C40E2E));
    transform: rotate(var(--a)) translateY(-5px);
    animation: cbfx-shoot 520ms cubic-bezier(.14,.7,.3,1) forwards;
}
@keyframes cbfx-shoot {
    0%   { opacity: 1; }
    100% { transform: rotate(var(--a)) translateY(-30px) scaleY(.35); opacity: 0; }
}

/* Pulse — one soft bloom of light. */
.cbfx-pulse {
    width: 44px; height: 44px; margin: -22px 0 0 -22px; border-radius: 50%;
    background: radial-gradient(circle, rgba(var(--primary-rgb, 196,14,46), .55) 0%, rgba(var(--primary-rgb, 196,14,46), .18) 45%, transparent 70%);
    animation: cbfx-pulse 480ms ease-out forwards;
}
@keyframes cbfx-pulse {
    0%   { transform: scale(.25); opacity: 1; }
    100% { transform: scale(1.9); opacity: 0; }
}

/* Rings — three staggered ripples, a thinner echo of the sonar. */
.cbfx-ring {
    width: 14px; height: 14px; margin: -7px 0 0 -7px; border-radius: 50%;
    border: 1.5px solid var(--primary, #C40E2E);
    box-shadow: 0 0 10px 1px rgba(var(--primary-rgb, 196,14,46), .5);
    opacity: 0;
    animation: cbfx-ring 700ms cubic-bezier(.16,.6,.28,1) forwards;
    animation-delay: var(--d, 0ms);
}
@keyframes cbfx-ring {
    0%   { transform: scale(.3); opacity: .9; }
    100% { transform: scale(5);  opacity: 0; }
}

/* Shards — angular fragments burst outward and spin. */
.cbfx-shard {
    width: 7px; height: 7px; margin: -3px 0 0 -3px;
    background: var(--c, var(--primary, #C40E2E));
    clip-path: polygon(50% 0, 100% 100%, 0 78%);
    animation: cbfx-shard 560ms cubic-bezier(.16,.7,.3,1) forwards;
}
@keyframes cbfx-shard {
    0%   { transform: translate(0, 0) rotate(0) scale(1); opacity: 1; }
    100% { transform: translate(var(--dx), var(--dy)) rotate(300deg) scale(.4); opacity: 0; }
}

/* Confetti — a scatter of palette-coloured chips with a little gravity. */
.cbfx-conf {
    width: 6px; height: 9px; margin: -4px 0 0 -3px; border-radius: 2px;
    background: var(--c, var(--primary, #C40E2E));
    animation: cbfx-conf 640ms cubic-bezier(.2,.6,.35,1) forwards;
}
@keyframes cbfx-conf {
    0%   { transform: translate(0, 0) rotate(0); opacity: 1; }
    100% { transform: translate(var(--dx), var(--dy)) rotate(var(--r, 260deg)); opacity: 0; }
}

/* Comet — a fading dot trail behind the pointer. */
.cbfx-comet {
    width: 8px; height: 8px; margin: -4px 0 0 -4px; border-radius: 50%;
    background: radial-gradient(circle, var(--primary, #C40E2E) 0%, rgba(var(--primary-rgb, 196,14,46), .35) 55%, transparent 75%);
    animation: cbfx-comet 480ms ease-out forwards;
}
@keyframes cbfx-comet {
    0%   { transform: scale(1); opacity: .85; }
    100% { transform: scale(.15); opacity: 0; }
}

/* Stardust — tiny four-point stars twinkle where the pointer passed. */
.cbfx-star {
    width: 9px; height: 9px; margin: -4px 0 0 -4px;
    background: var(--c, var(--accent, #FFB3C0));
    clip-path: polygon(50% 0, 62% 38%, 100% 50%, 62% 62%, 50% 100%, 38% 62%, 0 50%, 38% 38%);
    animation: cbfx-star 680ms ease-out forwards;
}
@keyframes cbfx-star {
    0%   { transform: scale(.3) rotate(0);      opacity: 0; }
    30%  { transform: scale(1.1) rotate(40deg); opacity: 1; }
    100% { transform: scale(.2) rotate(90deg);  opacity: 0; }
}

/* Embers — warm motes drift up off the pointer's path. */
.cbfx-ember {
    width: 5px; height: 5px; margin: -2px 0 0 -2px; border-radius: 50%;
    background: var(--c, var(--primary, #C40E2E));
    box-shadow: 0 0 8px 1px rgba(var(--primary-rgb, 196,14,46), .55);
    animation: cbfx-ember 900ms ease-out forwards;
}
@keyframes cbfx-ember {
    0%   { transform: translate(0, 0) scale(1); opacity: .9; }
    100% { transform: translate(var(--dx, 6px), -30px) scale(.3); opacity: 0; }
}

/* Glow — one soft light that follows the pointer (a single persistent
 * element chicabate-bg.js moves; the transition gives it the lag). */
.cbfx-glow {
    width: 90px; height: 90px; margin: -45px 0 0 -45px; border-radius: 50%;
    background: radial-gradient(circle, rgba(var(--primary-rgb, 196,14,46), .18) 0%, rgba(var(--secondary-rgb, 138,16,36), .08) 50%, transparent 72%);
    mix-blend-mode: screen;
    transition: left 120ms linear, top 120ms linear;
}

/* Bubbles — tiny glass beads rise off the pointer's path. */
.cbfx-bub {
    /* --s is set per bubble at spawn (chicabate-bg.js): a random size
       band — tiny / semi-small / semi-medium — so the trail reads as a
       lively mixed stream rather than uniform beads. */
    width: var(--s, 9px); height: var(--s, 9px);
    margin: calc(var(--s, 9px) / -2) 0 0 calc(var(--s, 9px) / -2);
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, .65);
    background: radial-gradient(circle at 32% 30%, rgba(255,255,255,.7) 0 18%, rgba(var(--secondary-rgb, 138,16,36), .25) 55%, transparent 75%);
    animation: cbfx-bub 1000ms ease-out forwards;
}
@keyframes cbfx-bub {
    0%   { transform: translate(0, 0) scale(.6); opacity: .9; }
    80%  { opacity: .7; }
    100% { transform: translate(var(--dx, -5px), -34px) scale(1); opacity: 0; }
}

/* Reduced motion: every pointer effect disappears; the cursor design (a
 * static image) is unaffected. */
@media (prefers-reduced-motion: reduce) { .cbfx { display: none; } }

/* ── 18+ badge mount points (Website Brand › 18+ Logo) ──────────────────
   The badge itself is drawn by cb-brand.js from the saved config; these
   rules only decide where each mount sits. A mount with the badge switched
   off collapses to nothing, so no gap is left behind. */
/* The badge now sits INSIDE the compliance notice and the gate's warning
   box rather than on a line of its own, so those two become flex rows. A
   disabled badge is display:none, and `gap` leaves no orphan space behind it. */
.footer-warning {
    display: flex; align-items: center; justify-content: center;
    gap: 14px; flex-wrap: wrap; text-align: center;
}
.footer-warning-text { flex: 0 1 auto; }
/* A flex item shrinks below its width by default. The badge is a CIRCLE, so
   letting that happen would squash it into an ellipse on a narrow screen. */
.footer-warning > [data-cb-age18],
.warning-box > [data-cb-age18] { flex: 0 0 auto; }
.warning-box {
    display: flex; align-items: center; justify-content: center; gap: 14px;
}
.warning-box-text { flex: 0 1 auto; }
/* The DMCA page keeps its own mount beside the heading. */
.dmca-age18 { display: flex; justify-content: flex-start; margin: 0 0 14px; }
@media (max-width: 600px) {
    .dmca-age18 { justify-content: center; }
    .footer-warning, .warning-box { gap: 10px; }
}
