/* Knightvision API workspace: the look of /app (templates/app.html).

   The :root block below is copied VERBATIM from the first :root block of
   templates/app.html, so this workspace follows the app's palette instead of
   drifting beside it (the convention of templates/reels.html). It carries both
   name sets: the prototype names (--bg, --surface, --accent, --text) are the
   source of truth, the app-wide names (--bg-card, --purple, --text-primary ...)
   are aliases onto them. tests/test_portal_theme.py compares the shared values
   with app.html. When the app's palette changes, re-copy the block; never edit
   a value here.

   Single theme, dark: there is no [data-theme] rule anywhere in this folder.
   Fonts: Manrope (--font-body) and Bricolage Grotesque (--font-display), loaded
   by templates/partner_portal.html from Google Fonts, the same two links as the
   app. Icons are Heroicons outline at stroke-width 1.8 (app.js, icons). */

:root {
    /* ── the dark system — the source of truth. Single theme: there is
         no light variant and no toggle, so :root IS the palette.

         Every value below is measured, not picked. The two that drive
         the rest:

         1. Surfaces cannot separate by VALUE here. --surface-flat on
            --bg is a contrast ratio of 1.07; even a much lighter card
            only reaches 1.16. In the light system a card could carry
            itself by being brighter than the ground — in the dark it
            cannot. --border is what makes a surface readable, so it is
            a real hairline (0.08 white), not decoration. Remove it and
            the whole screen collapses into one flat plane.

         2. The accent is a TEXT and LINE colour, and a fill only under
            dark text. #00A3FF against --bg is 7.19 (AAA). White on
            that same blue is 2.73 — below even the large-text floor —
            while --bg on it is 7.19. So the primary button is dark ink
            on neon, never white on neon.

         --accent-strong is BRIGHTER than --accent, not darker: in the
         dark, "more prominent" means closer to the light. That is the
         inversion of the light system, where hover went deeper.

         --green and --danger were #2E7D4F / #D64545 and scored 3.64 /
         4.19 on a card — both fail body text. These clear 10.54 and
         6.62. ── */
    --bg: #0B0B0F;
    --bg-rail: rgba(13, 13, 17, 0.82);
    --surface: linear-gradient(180deg, #17171D, #131319);
    --surface-flat: #141419;
    --surface-2: linear-gradient(180deg, #1C1C23, #17171D);
    --surface-3: #1C1C23;
    --border: rgba(255, 255, 255, 0.08);
    --border-strong: rgba(255, 255, 255, 0.16);
    --text: #F2F3F5;
    --text-dim: #A0A4AD;
    --text-faint: #828894;
    /* The accent is the old purple — the admin dashboard's --primary
       #8b5cf6 (violet-500) with violet-400 as the strong step, the pair
       the 404 page already uses. Tried against the blue on the compare
       server and chosen (David, 2026-09-20); this is the decision, not
       a test, so the blue is no longer carried here as a revert. */
    --accent: #8b5cf6;
    --accent-strong: #a78bfa;
    --accent-tint: rgba(139, 92, 246, 0.12);
    --accent-line: rgba(139, 92, 246, 0.35);
    /* Ink for anything sitting ON the accent. White on #00A3FF is 2.73
       — below even the large-text floor — so a filled accent button
       takes this, never #fff. */
    --on-accent: #0B0B0F;
    /* Native controls are not styled by us: select popups, checkbox
       and radio unchecked states, date pickers and the default
       scrollbar all render in light chrome on a black page without
       this. There was no color-scheme declaration anywhere in the app
       before. */
    color-scheme: dark;
    --green: #4ADE80;
    --danger: #FF6B6B;
    --radius: 16px;
    /* Shadows barely read on a dark ground — the border does the
       separating. These stay for depth on overlays, not for hierarchy. */
    --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.40), 0 8px 26px -14px rgba(0, 0, 0, 0.60);
    --shadow-pop: 0 18px 50px -12px rgba(0, 0, 0, 0.70);
    --font-display: 'Bricolage Grotesque', 'Manrope', system-ui, sans-serif;
    --font-body: 'Manrope', system-ui, sans-serif;

    /* ── app-wide names, aliased onto the above ── */
    --bg-warm: var(--bg);
    --bg-card: var(--surface-flat);
    --bg-card-hover: var(--surface-3);
    --bg-sidebar: var(--bg-rail);
    --border-subtle: var(--border);
    --border-input: var(--border-strong);
    --border-hover: var(--border-strong);

    /* Names the stylesheet ALREADY uses but nobody ever defined, so the
       fallback after the comma won every time — and those fallbacks
       were written for a light page: `#fff` inputs, `#f8fafc` panels,
       a `rgba(0,0,0,.08)` hairline that is invisible on a dark card.
       That is why parts of the app were still white. --red is worse
       than cosmetic: it has NO fallback, so every failure message
       styled `color: var(--red)` had no colour at all. */
    --bg-input: rgba(255, 255, 255, 0.04);
    --bg-subtle: var(--surface-3);
    --border-card: var(--border);
    --text-muted: var(--text-faint);
    --red: var(--danger);
    --red-light: rgba(255, 107, 107, 0.12);
    /* The AI Generator's own surface for a user bubble / active chat.
       It lived only inside the dead [data-theme="dark"] rule, so both
       users of it resolved to nothing and the highlight never showed. */
    --pg-user-bg: rgba(139, 92, 246, 0.10);
    --text-primary: var(--text);
    --text-secondary: var(--text-dim);
    --text-tertiary: var(--text-faint);
    /* The --purple-* names are historical and stay — they are read by
       1615 call sites, by account.html, and by static/js/editor_*.js
       and velocity.js via getComputedStyle. Renaming them would break
       canvas drawing silently. The value is the neon blue. */
    --purple: var(--accent);
    --purple-hover: var(--accent-strong);
    --purple-light: var(--accent-tint);
    --accent-green: rgba(74, 222, 128, 0.14);
    --accent-green-text: var(--green);
    --accent-green-border: rgba(74, 222, 128, 0.28);
    --sidebar-width: 270px;
    --sidebar-rail: 60px;
    --radius-sm: 10px;
    --radius-md: var(--radius);
    --radius-lg: 22px;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35);
    --shadow-md: var(--shadow-card);
    --shadow-lg: var(--shadow-pop);
    --glass-blur: 20px;
}

/* Names this workspace uses that the app's block does not define. Kept OUT of
   the copied block above so that block stays re-copyable byte for byte. The
   status hues are the ones of templates/affiliate.html and account.html. */
:root {
    --mono: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace;
    --danger-tint: rgba(255, 107, 107, 0.12);
    --danger-line: rgba(255, 107, 107, 0.32);
    --amber: #fbbf24;
    --amber-tint: rgba(245, 158, 11, 0.15);
    --amber-line: rgba(245, 158, 11, 0.32);
    --blue: #60a5fa;
    --blue-tint: rgba(96, 165, 250, 0.14);
    --blue-line: rgba(96, 165, 250, 0.32);
    --card-radius: 18px;   /* the app's .card */
    --gutter: 48px;        /* the app's .main side padding */
}

/* ───────── Base ───────── */
*, *::before, *::after { box-sizing: border-box; }
/* `hidden` must beat every display rule below (.btn is inline-flex, ...). */
[hidden] { display: none !important; }
html {
    font-family: var(--font-body);
    font-size: 15px;
    color: var(--text);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
    scroll-behavior: smooth;
    scroll-padding-top: 24px;
}
body {
    margin: 0;
    min-height: 100vh;
    background-color: var(--bg);
    color: var(--text);
    font-size: 14px;
    line-height: 1.55;
}
/* The app's two washes: a cool haze from above, a faint violet lift below. */
body::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: -2;
    pointer-events: none;
    background:
        radial-gradient(1000px 520px at 55% -12%, rgba(64, 160, 224, 0.08), transparent 62%),
        radial-gradient(760px 520px at 6% 108%, rgba(139, 92, 246, 0.05), transparent 62%);
}
button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; }
button:disabled { opacity: 0.45; cursor: not-allowed; }
a { color: inherit; text-decoration: none; }
:focus-visible { outline: 2px solid var(--accent-line); outline-offset: 2px; }
svg { width: 18px; height: 18px; flex-shrink: 0; vertical-align: middle; }
h1, h2, h3, h4, p { margin: 0; }
h1 {
    font-family: var(--font-display);
    font-size: 34px;
    font-weight: 800;
    letter-spacing: -0.02em;
    line-height: 1.08;
}
h2 { font-size: 16px; font-weight: 700; line-height: 1.35; letter-spacing: -0.01em; }
h3 { font-size: 14px; font-weight: 700; line-height: 1.4; }
code, pre, .mono { font-family: var(--mono); }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.10); border-radius: 8px; border: 2px solid transparent; background-clip: padding-box; }
::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.18); background-clip: padding-box; }
::-webkit-scrollbar-track { background: transparent; }

/* Utilities the views are written against. */
.muted { color: var(--text-dim); }
.small { font-size: 13px; }
.tiny { font-size: 11.5px; }
.violet { color: var(--accent-strong); }
.green { color: var(--green); }
.nowrap { white-space: nowrap; }
.grow { flex: 1; min-width: 0; }
.row { display: flex; align-items: center; gap: 12px; }
.between { justify-content: space-between; }
.wrap { flex-wrap: wrap; }
.stack { display: grid; gap: 20px; }
.gap8 { gap: 8px; }
.gap24 { gap: 24px; }
.divider { height: 1px; background: var(--border); margin: 22px 0; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
.skip-link { position: fixed; top: -60px; left: 20px; z-index: 300; padding: 10px 14px; border-radius: var(--radius-sm); background: var(--accent); color: var(--on-accent); font-weight: 700; }
.skip-link:focus { top: 12px; }
.boot { padding: 72px var(--gutter); color: var(--text-dim); }
.boot h1 { margin-bottom: 10px; }
.boot p { margin-bottom: 18px; }

/* ───────── Sidebar (app.html, .sidebar … .profile-row) ───────── */
.sidebar {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 100;
    width: var(--sidebar-width);
    height: 100vh;
    height: 100dvh;
    display: flex;
    flex-direction: column;
    padding: 28px 20px 20px;
    background: var(--bg-sidebar);
    backdrop-filter: blur(var(--glass-blur));
    -webkit-backdrop-filter: blur(var(--glass-blur));
    border-right: 1px solid var(--border-subtle);
    line-height: normal;
    /* ONE scroll container for the whole column; the footer is pinned inside
       it (below), exactly like the app. */
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, 0.12) transparent;
    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.sidebar::-webkit-scrollbar { width: 6px; }
.sidebar::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.12); border-radius: 3px; border: 0; }

.sidebar-logo {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 8px 28px;
    border-bottom: 1px solid var(--border-subtle);
    margin-bottom: 24px;
    color: var(--text);
    transition: opacity 0.2s;
}
.sidebar-logo:hover { opacity: 0.75; }
.sidebar-logo img {
    width: 36px;
    height: 36px;
    object-fit: contain;
    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.sidebar-logo:hover img { transform: rotate(-8deg) scale(1.08); }
.sidebar-logo-name { font-weight: 650; font-size: 17px; letter-spacing: -0.3px; }
/* The app's admin eyebrow under the wordmark, here naming the workspace. */
.sidebar-logo-admin {
    display: block;
    margin-top: 3px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-tertiary);
}

.sidebar-nav { display: flex; flex-direction: column; gap: 4px; }
.nav-sect {
    margin: 0 16px 8px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-tertiary);
}
.nav-sect--in { margin: 14px 16px 2px; }
.nav-sect--in:first-child { margin-top: 0; }
.nav-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    border-radius: var(--radius-sm);
    font-size: 14px;
    font-weight: 450;
    color: var(--text-secondary);
    transition: all 0.15s ease;
    user-select: none;
}
.nav-item:hover { background: rgba(255, 255, 255, 0.03); color: var(--text-primary); }
.nav-item.active { background: var(--purple-light); color: var(--purple); font-weight: 550; }
.nav-item svg { width: 18px; height: 18px; flex-shrink: 0; opacity: 0.7; }
.nav-item.active svg { opacity: 1; }
.nav-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-badge-new,
.nav-end {
    margin-left: auto;
    font-size: 9px;
    font-weight: 800;
    letter-spacing: 0.06em;
    padding: 2px 6px;
    border-radius: 4px;
    line-height: 1;
    text-transform: uppercase;
}
.nav-badge-new { color: var(--accent-green-text); background: var(--accent-green); border: 1px solid var(--accent-green-border); }
.nav-end { color: var(--accent-strong); background: var(--accent-tint); border: 1px solid var(--accent-line); }

.sidebar-footer {
    margin-top: auto;
    padding-top: 20px;
    border-top: 1px solid var(--border-subtle);
    display: flex;
    flex-direction: column;
    gap: 8px;
}
/* Credits, top-up and the account row stay on screen; the nav scrolls behind
   them. Opaque fill on purpose: the rail is translucent. Only with height for
   it, as in the app. */
@media (min-height: 600px) {
    .sidebar { padding-bottom: 0; }
    .sidebar-footer {
        position: sticky;
        bottom: 0;
        z-index: 2;
        padding-bottom: 20px;
        background: linear-gradient(var(--bg-sidebar), var(--bg-sidebar)), var(--bg);
    }
}
.sidebar-footer-card {
    background: var(--bg-card);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    padding: 8px 12px;
    transition: border-color 0.15s ease, background 0.15s ease;
}
.sidebar-footer-card:hover { border-color: var(--border-hover); background: var(--bg-card-hover); }
.credits-badge {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    font-weight: 500;
    color: var(--purple);
}
.credits-badge svg { width: 16px; height: 16px; }
.credits-badge .credits-count { font-weight: 700; margin-left: auto; font-variant-numeric: tabular-nums; }
/* utils/rank.py tiers, the app's pill colours (app.html .rank-pill). */
.rank-pill {
    --rank-fg: var(--accent-strong);
    --rank-bg: var(--accent-tint);
    --rank-line: var(--accent-line);
    display: inline-flex;
    align-items: center;
    flex-shrink: 0;
    font-size: 9px;
    font-weight: 800;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    padding: 2px 6px;
    border-radius: 4px;
    line-height: 1.4;
    color: var(--rank-fg);
    background: var(--rank-bg);
    border: 1px solid var(--rank-line);
}
.rank-bronze { --rank-fg: #c98f62; --rank-bg: rgba(201, 143, 98, 0.14); --rank-line: rgba(201, 143, 98, 0.4); }
.rank-silver { --rank-fg: #c9ced8; --rank-bg: rgba(201, 206, 216, 0.14); --rank-line: rgba(201, 206, 216, 0.4); }
.rank-gold { --rank-fg: #e9bd4f; --rank-bg: rgba(233, 189, 79, 0.16); --rank-line: rgba(233, 189, 79, 0.45); }

.sidebar-footer-btn {
    display: block;
    width: 100%;
    padding: 7px 12px;
    background: var(--bg-card);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    font-size: 13px;
    font-weight: 600;
    text-align: center;
    color: var(--text-primary);
    transition: border-color 0.15s ease, background 0.15s ease;
}
.sidebar-footer-btn:hover { border-color: var(--border-hover); background: var(--bg-card-hover); }
/* "Buy Credits" of the app: the conic gradient runs round the border. */
.sidebar-footer-btn.snake { position: relative; overflow: hidden; }
.sidebar-footer-btn.snake::before {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 200%;
    height: 200%;
    margin-top: -100%;
    margin-left: -100%;
    background: conic-gradient(from 0deg, transparent 70%, var(--purple) 85%, transparent 100%);
    animation: border-snake 6s linear infinite;
}
.sidebar-footer-btn.snake::after {
    content: '';
    position: absolute;
    inset: 1px;
    background: var(--bg-card);
    border-radius: calc(var(--radius-sm) - 1px);
    transition: background 0.15s;
}
.sidebar-footer-btn.snake:hover::after { background: var(--bg-card-hover); }
.sidebar-footer-btn.snake span { position: relative; z-index: 1; }
@keyframes border-snake { to { transform: rotate(360deg); } }
.sidebar-footer-row { display: flex; gap: 6px; }
.sidebar-footer-row > .sidebar-footer-btn {
    flex: 1 1 0;
    min-width: 0;
    padding: 7px 2px;
    font-size: 12px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.profile-row {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 6px 10px 6px 8px;
    background: var(--bg-card);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    color: var(--text);
    transition: border-color 0.15s ease, background 0.15s ease;
}
.profile-row:hover { border-color: var(--border-hover); background: var(--bg-card-hover); }
.profile-row.active { border-color: var(--accent-line); background: var(--accent-tint); }
.profile-avatar {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: var(--surface-3);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    font-size: 10px;
    font-weight: 600;
    color: var(--text-secondary);
}
.profile-info { flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; }
.profile-name { flex: 1; min-width: 0; font-size: 13px; font-weight: 550; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.profile-action { display: inline-flex; align-items: center; gap: 4px; flex-shrink: 0; font-size: 11px; color: var(--text-tertiary); }
.profile-action svg { width: 13px; height: 13px; }

/* Short screens (a laptop browser is ~740-900 px tall): the eleven entries and
   the footer still fit without scrolling. Same rules as the app above that. */
@media (max-height: 900px) {
    .sidebar { padding-top: 22px; }
    .sidebar-logo { padding-bottom: 20px; margin-bottom: 16px; }
    .nav-item { padding-top: 9px; padding-bottom: 9px; }
}
@media (max-height: 790px) {
    .sidebar-logo { padding-bottom: 16px; margin-bottom: 12px; }
    .sidebar-nav { gap: 2px; }
    .nav-sect--in { margin-top: 10px; }
    .nav-item { padding-top: 6px; padding-bottom: 6px; }
    .sidebar-footer { padding-top: 12px; gap: 6px; }
}
@media (max-height: 790px) and (min-height: 600px) {
    .sidebar-footer { padding-bottom: 14px; }
}

/* ───────── Main column ───────── */
.shell { margin-left: var(--sidebar-width); min-width: 0; min-height: 100vh; display: flex; flex-direction: column; }
/* The app has no top bar. This one is a quiet row above the page heading:
   the breadcrumb, the reference links and docs search, no fill, no border. */
.topbar {
    width: 100%;
    max-width: calc(1600px + 2 * var(--gutter));
    margin: 0 auto;
    padding: 22px var(--gutter) 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
}
.topbar-left { display: flex; align-items: center; gap: 12px; min-width: 0; }
.breadcrumb { display: flex; align-items: center; gap: 8px; font-size: 12.5px; font-weight: 500; color: var(--text-faint); min-width: 0; }
.breadcrumb svg { width: 13px; height: 13px; }
.breadcrumb span:last-child { color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.top-actions { display: flex; align-items: center; gap: 18px; }
.top-actions > a { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600; color: var(--text-dim); transition: color 0.15s; }
.top-actions > a:hover { color: var(--text); }
.top-actions > a svg { width: 15px; height: 15px; }
/* Beats .icon-btn's inline-flex: the drawer button exists only under 860px. */
.topbar .menu-toggle { display: none; }
.mobile-scrim { display: none; }
.main {
    flex: 1;
    width: 100%;
    max-width: calc(1600px + 2 * var(--gutter));
    margin: 0 auto;
    padding: 30px var(--gutter) 40px;
}
.main:focus { outline: none; }
.site-footer {
    display: flex;
    justify-content: space-between;
    gap: 12px 24px;
    flex-wrap: wrap;
    margin-top: 44px;
    padding-top: 22px;
    border-top: 1px solid var(--border);
    font-size: 12px;
    color: var(--text-faint);
}
.site-footer-links { display: flex; gap: 18px; flex-wrap: wrap; }
.site-footer a:hover { color: var(--text-dim); }

/* ───────── Page heading (app.html .page-header) ───────── */
.page-heading { display: flex; align-items: flex-end; justify-content: space-between; gap: 20px; margin-bottom: 32px; }
.page-heading h1 { margin-bottom: 6px; }
.page-heading p { font-size: 15px; color: var(--text-secondary); }
.eyebrow {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-faint);
    margin-bottom: 8px;
}
/* An in-page section title is the app's .card-title: an eyebrow with a
   hairline running to the controls on its right. */
.section-row { display: flex; align-items: center; gap: 16px; margin: 36px 0 16px; }
.section-row h2 {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 12px;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--text-faint);
}
.section-row h2::after { content: ''; flex: 1; height: 1px; background: var(--border); }

/* ───────── Buttons (app.html .btn / .btn-generate) ───────── */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    padding: 10px 16px;
    font-size: 13px;
    font-weight: 600;
    line-height: 1.3;
    white-space: nowrap;
    color: var(--text-primary);
    background: var(--bg-card);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    transition: all 0.15s;
}
.btn:hover:not(:disabled) { border-color: var(--border-hover); background: var(--bg-card-hover); }
.btn svg { width: 16px; height: 16px; }
/* THE action of a view: the app's pill. Dark ink on the accent, never white
   (app.html --on-accent). */
.btn.primary {
    padding: 11px 22px;
    border: 1px solid transparent;
    border-radius: 980px;
    background: var(--accent);
    color: var(--on-accent);
    font-weight: 700;
    letter-spacing: -0.1px;
    box-shadow: 0 8px 24px -8px rgba(139, 92, 246, 0.45);
}
.btn.primary:hover:not(:disabled) { background: var(--accent-strong); border-color: transparent; transform: translateY(-1px); box-shadow: 0 12px 30px -8px rgba(139, 92, 246, 0.55); }
.btn.primary:active { transform: none; }
.btn.primary:disabled { background: var(--surface-3); color: var(--text-faint); box-shadow: none; opacity: 1; }
.btn.subtle { background: transparent; }
.btn.danger { color: var(--danger); background: var(--danger-tint); border-color: var(--danger-line); }
.btn.danger:hover:not(:disabled) { background: rgba(255, 107, 107, 0.18); border-color: var(--danger); }
.btn.small { padding: 7px 12px; font-size: 12px; }
.btn.small svg { width: 14px; height: 14px; }
.btn.primary.small { padding: 8px 16px; }
.btn.full { width: 100%; }
.text-link { display: inline-flex; align-items: center; gap: 5px; font-size: 13px; font-weight: 600; color: var(--accent-strong); }
.text-link svg { width: 14px; height: 14px; transition: transform 0.15s; }
.text-link:hover svg { transform: translateX(2px); }
.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    flex-shrink: 0;
    padding: 0;
    border-radius: 9px;
    border: 1px solid var(--border-subtle);
    background: rgba(255, 255, 255, 0.04);
    color: var(--text-secondary);
    transition: color 0.15s, border-color 0.15s;
}
.icon-btn:hover:not(:disabled) { color: var(--text-primary); border-color: var(--border-strong); }
.icon-btn svg { width: 17px; height: 17px; }

/* ───────── Pills / status badges (account.html .status-badge) ───────── */
.pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px;
    border-radius: 6px;
    font-size: 11px;
    font-weight: 600;
    line-height: 1.5;
    white-space: nowrap;
    color: var(--text-secondary);
    background: rgba(255, 255, 255, 0.06);
}
.pill svg { width: 12px; height: 12px; }
.pill.purple { color: var(--accent-strong); background: var(--accent-tint); }
.pill.green { color: var(--green); background: var(--accent-green); }
.pill.red { color: var(--danger); background: var(--danger-tint); }
.pill.amber { color: var(--amber); background: var(--amber-tint); }
.pill.blue { color: var(--blue); background: var(--blue-tint); }
.pill.bronze { color: #c98f62; background: rgba(201, 143, 98, 0.14); }
.pill.silver { color: #c9ced8; background: rgba(201, 206, 216, 0.14); }
.pill.gold { color: #e9bd4f; background: rgba(233, 189, 79, 0.16); }
.dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex-shrink: 0; }
.dot.green { background: var(--green); }
.status-dot { display: inline-flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 600; color: var(--green); }

/* ───────── Cards (app.html .card) ───────── */
.panel {
    min-width: 0;
    overflow: hidden;
    background: var(--surface-flat);
    border: 1px solid var(--border);
    border-radius: var(--card-radius);
    box-shadow: var(--shadow-card);
}
.padded { padding: 26px; }
.panel > h2, .padded > h2 { margin-bottom: 4px; }
.panel-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 22px 26px 18px; }
.panel-head h2 { margin: 0; }
.panel-head p { margin-top: 4px; font-size: 12.5px; color: var(--text-faint); }
.panel-head > svg { color: var(--text-faint); }
.panel-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 13px 26px;
    border-top: 1px solid var(--border);
    font-size: 12.5px;
    color: var(--text-faint);
}
.grid { display: grid; gap: 20px; min-width: 0; }
.grid.two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid.three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid.four { grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* Stat tile (templates/affiliate.html .aff-stat): label, tinted icon, a
   display-face number. */
.stat {
    padding: 20px 22px;
    background: var(--surface);
}
.stat-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.stat-label { padding-top: 7px; font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-faint); }
.stat-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border-radius: 10px;
    background: var(--accent-tint);
    color: var(--accent-strong);
}
.stat-icon svg { width: 18px; height: 18px; }
.stat-icon.green { background: var(--accent-green); color: var(--green); }
.stat-icon.amber { background: var(--amber-tint); color: var(--amber); }
.stat-icon.blue { background: var(--blue-tint); color: var(--blue); }
.stat-icon.red { background: var(--danger-tint); color: var(--danger); }
.stat strong {
    display: block;
    margin: 8px 0 4px;
    font-family: var(--font-display);
    font-size: 30px;
    font-weight: 800;
    letter-spacing: -0.01em;
    line-height: 1.15;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.stat small { display: block; font-size: 12.5px; color: var(--text-secondary); }

/* ───────── Notices (affiliate.html .aff-notice) ───────── */
.notice {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 14px 16px;
    border: 1px solid var(--accent-line);
    border-radius: var(--radius-sm);
    background: var(--accent-tint);
    color: var(--text-secondary);
    font-size: 13px;
    line-height: 1.55;
}
.notice > svg { width: 18px; height: 18px; margin-top: 1px; color: var(--accent-strong); }
.notice strong { color: var(--text); font-weight: 700; }
.notice a { color: var(--accent-strong); font-weight: 600; }
.notice.neutral { background: rgba(255, 255, 255, 0.03); border-color: var(--border); }
.notice.neutral > svg { color: var(--text-faint); }
.notice.warning { background: var(--amber-tint); border-color: var(--amber-line); color: #f3d79b; }
.notice.warning > svg { color: var(--amber); }
.notice.bad { background: var(--danger-tint); border-color: var(--danger-line); color: #ffb3b3; }
.notice.bad > svg { color: var(--danger); }
.notice .btn { margin-top: 10px; }

/* ───────── Forms (app.html inputs) ───────── */
/* :where() keeps these at zero specificity, so any class rule (.search-box
   input, .aff-link-input ...) refines them without a fight. */
:where(input:not([type=checkbox]):not([type=radio]), select, textarea) {
    max-width: 100%;
    padding: 11px 14px;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    background: var(--surface-flat);
    color: var(--text);
    font-size: 14px;
    font-weight: 450;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
:where(input:not([type=checkbox]):not([type=radio]), select, textarea):focus { outline: none; border-color: var(--accent-line); box-shadow: 0 0 0 3px var(--accent-tint); }
:where(input, textarea)::placeholder { color: var(--text-tertiary); }
input[type=search]::-webkit-search-cancel-button { filter: invert(0.7); }
:where(textarea) { resize: vertical; min-height: 110px; line-height: 1.6; }
/* The app's select: no native chrome, a drawn caret. */
:where(select) {
    appearance: none;
    -webkit-appearance: none;
    min-height: 42px;
    padding-right: 38px;
    cursor: pointer;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23828894' stroke-width='1.8'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='m19.5 8.25-7.5 7.5-7.5-7.5'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 13px center;
    background-size: 15px 15px;
}
.field { display: grid; gap: 7px; margin-bottom: 18px; }
.field label { font-size: 11.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-faint); }
.field small { font-size: 12px; color: var(--text-faint); }
.toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 18px; }
.search-box { position: relative; flex: 1; min-width: 180px; }
.search-box > svg { position: absolute; top: 50%; left: 13px; width: 16px; height: 16px; transform: translateY(-50%); color: var(--text-tertiary); pointer-events: none; }
.search-box input { width: 100%; padding-left: 38px; }
/* The app's switch (.kv-switch): the checkbox stays in the DOM, invisible. */
.toggle { position: relative; display: inline-block; width: 34px; height: 20px; flex-shrink: 0; }
.toggle input { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; margin: 0; padding: 0; opacity: 0; cursor: pointer; }
.toggle .track { position: absolute; inset: 0; border-radius: 10px; background: var(--border-input); transition: background 0.18s; }
.toggle .track::before {
    content: '';
    position: absolute;
    top: 2px;
    left: 2px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
    transition: transform 0.18s;
}
.toggle input:checked + .track { background: var(--purple); }
.toggle input:checked + .track::before { transform: translateX(14px); }
.toggle input:focus-visible + .track { box-shadow: 0 0 0 3px var(--accent-tint); outline: 2px solid var(--accent-line); outline-offset: 2px; }
.toggle input:disabled { cursor: not-allowed; }
.toggle input:disabled + .track { opacity: 0.35; }

/* ───────── Tables (account.html .acc-table) ───────── */
.table-wrap { max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
table { width: 100%; border-collapse: collapse; text-align: left; font-size: 13px; white-space: nowrap; }
th {
    padding: 12px 20px;
    border-bottom: 1px solid var(--border);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--text-tertiary);
}
td { padding: 14px 20px; border-bottom: 1px solid var(--border); color: var(--text-secondary); vertical-align: middle; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr { transition: background 0.15s; }
tbody tr:hover { background: rgba(255, 255, 255, 0.02); }
td strong { color: var(--text); font-weight: 600; }
td small { display: block; margin-top: 3px; font-size: 11.5px; color: var(--text-tertiary); }
th.num, td.num { text-align: right; }
.table-wrap .btn { padding: 6px 11px; font-size: 12px; }
.table-actions { display: flex; gap: 7px; }

/* ───────── Tabs, segmented controls (affiliate.html .aff-tab, app .toggle-group) ───────── */
.tabs {
    display: flex;
    gap: 4px;
    margin-bottom: 24px;
    border-bottom: 1px solid var(--border);
    overflow-x: auto;
    scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tabs > button,
.tabs > a {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin-bottom: -1px;
    padding: 12px 14px;
    border: 0;
    border-bottom: 2px solid transparent;
    background: none;
    color: var(--text-secondary);
    font-size: 14px;
    font-weight: 600;
    white-space: nowrap;
    transition: color 0.15s, border-color 0.15s;
}
.tabs > button:hover, .tabs > a:hover { color: var(--text-primary); }
.tabs > .active { color: var(--accent-strong); border-bottom-color: var(--accent); }
.tabs svg { width: 18px; height: 18px; }
.segmented { display: inline-flex; gap: 3px; padding: 3px; border-radius: 11px; background: var(--surface-3); }
.segmented button {
    padding: 7px 14px;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: var(--text-dim);
    font-size: 13px;
    font-weight: 500;
    white-space: nowrap;
    transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.segmented button:hover:not(.active) { color: var(--text-primary); }
.segmented button.active { background: rgba(255, 255, 255, 0.11); color: var(--text); box-shadow: var(--shadow-sm); font-weight: 600; }
.page-count { display: flex; align-items: center; gap: 10px; font-variant-numeric: tabular-nums; }

/* ───────── Empty states, key strip, detail lists ───────── */
.empty { padding: 52px 24px; text-align: center; color: var(--text-faint); }
.empty > svg { display: block; width: 38px; height: 38px; margin: 0 auto 12px; color: var(--text-faint); opacity: 0.7; }
.empty h3 { margin-bottom: 6px; font-size: 14px; font-weight: 600; color: var(--text-secondary); }
.empty p { margin-bottom: 16px; font-size: 13px; }
.key-base {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
    margin-bottom: 24px;
    padding: 12px 14px 12px 18px;
    background: var(--surface-flat);
    border: 1px solid var(--border);
    border-radius: 14px;
}
.key-base > span { font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-faint); white-space: nowrap; }
.key-base code { flex: 1; min-width: 0; overflow: auto; font-size: 13px; color: var(--text-dim); white-space: nowrap; }
.task-detail { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin: 18px 0; }
.task-detail div { padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: rgba(255, 255, 255, 0.02); font-size: 13px; overflow-wrap: anywhere; }
.task-detail dt { margin-bottom: 4px; font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-faint); }
.task-detail dd { margin: 0; color: var(--text); }
.code-preview {
    overflow: auto;
    padding: 16px 18px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 12px;
    color: var(--text-dim);
    font: 12.5px/1.7 var(--mono);
    white-space: pre;
}

/* details / summary: the app's disclosure, chevron drawn in CSS. */
details { padding: 15px 0; border-bottom: 1px solid var(--border); font-size: 13.5px; }
details:last-child { border-bottom: 0; }
summary { display: flex; align-items: center; justify-content: space-between; gap: 12px; list-style: none; cursor: pointer; font-weight: 600; color: var(--text); }
summary::-webkit-details-marker { display: none; }
summary::after {
    content: '';
    width: 7px;
    height: 7px;
    flex-shrink: 0;
    margin-right: 4px;
    border-right: 1.8px solid var(--text-faint);
    border-bottom: 1.8px solid var(--text-faint);
    transform: rotate(-45deg);
    transition: transform 0.15s;
}
details[open] summary::after { transform: rotate(45deg); }
details p { margin-top: 10px; font-size: 13px; line-height: 1.65; color: var(--text-secondary); }

/* ───────── Dialog + toast (affiliate.html .aff-modal-card / .aff-toast) ───────── */
dialog {
    width: min(540px, calc(100% - 32px));
    max-height: 88vh;
    padding: 24px;
    color: var(--text);
    background: var(--surface-flat);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-pop);
}
dialog::backdrop { background: rgba(0, 0, 0, 0.6); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }
.modal-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 20px; }
.modal-head h2 { font-family: var(--font-display); font-size: 22px; font-weight: 800; letter-spacing: -0.01em; line-height: 1.2; }
.modal-head p { margin-top: 6px; font-size: 13px; color: var(--text-dim); overflow-wrap: anywhere; }
.modal-actions { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: 10px; margin-top: 22px; }
.modal-text { font-size: 13.5px; line-height: 1.7; color: var(--text-secondary); }
dialog h3 { margin: 18px 0 8px; }
dialog .notice { margin-top: 4px; }
#toast {
    position: fixed;
    bottom: 24px;
    left: calc(50% + var(--sidebar-width) / 2);
    z-index: 400;
    max-width: calc(100vw - 32px);
    padding: 12px 18px;
    border-radius: 12px;
    border: 1px solid var(--border-strong);
    background: var(--surface-3);
    box-shadow: var(--shadow-pop);
    color: var(--text);
    font-size: 13.5px;
    font-weight: 600;
    opacity: 0;
    pointer-events: none;
    transform: translate(-50%, 12px);
    transition: opacity 0.2s, transform 0.2s;
}
#toast.visible { opacity: 1; transform: translate(-50%, 0); }

/* ───────── Responsive ───────── */
@media (max-width: 1150px) {
    :root { --gutter: 32px; }
    .grid.four { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* Under 860px the sidebar is the app's off-canvas drawer. */
@media (max-width: 860px) {
    :root { --gutter: 16px; }
    .sidebar { transform: translateX(calc(-1 * var(--sidebar-width) - 1px)); }
    .sidebar.open { transform: translateX(0); box-shadow: 0 8px 40px rgba(0, 0, 0, 0.5); }
    .shell { margin-left: 0; }
    .mobile-scrim.open { display: block; position: fixed; inset: 0; z-index: 90; border: 0; background: rgba(0, 0, 0, 0.55); }
    .topbar .menu-toggle { display: inline-flex; }
    .topbar { padding-top: 14px; }
    .top-actions { gap: 10px; }
    .top-actions > a { display: none; }
    .main { padding-top: 22px; padding-bottom: 32px; }
    .page-heading { flex-direction: column; align-items: flex-start; gap: 14px; margin-bottom: 26px; }
    .page-heading h1 { font-size: 27px; }
    .page-heading p { font-size: 14px; }
    .grid.two, .grid.three { grid-template-columns: minmax(0, 1fr); }
    .padded { padding: 20px; }
    .panel-head { padding: 18px 20px 14px; }
    .panel-footer { padding: 12px 20px; flex-wrap: wrap; }
    th { padding: 11px 16px; }
    td { padding: 12px 16px; }
    #toast { left: 50%; }
    .task-detail { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 560px) {
    .page-heading h1 { font-size: 24px; }
    .grid.four { gap: 12px; }
    .stat { padding: 16px; }
    .stat-label { font-size: 10.5px; letter-spacing: 0.04em; }
    .stat-icon { width: 30px; height: 30px; }
    .stat strong { font-size: 22px; }
    .section-row { flex-wrap: wrap; }
    .toolbar .search-box { flex-basis: 100%; }
    .toolbar select { flex: 1; min-width: 120px; }
    .site-footer { flex-direction: column; }
    dialog { padding: 20px 16px; }
    .modal-actions .btn { white-space: normal; }
    .key-base { flex-wrap: wrap; }
    .key-base code { flex-basis: 100%; order: 3; }
}
@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after { transition: none !important; animation: none !important; }
}
