/* =============================================================================
   V4 THEME - Light, Modern, Warm
   Loaded AFTER base.css to override the old styles.
   Schibsted Grotesk (UI + body) + Fraunces (page titles) + JetBrains Mono (values).
   Warm off-white + terminal green accent.
   ============================================================================= */

/* 2026-09-27 (UX pass 2, DESIGN.md "one product voice"): the app now shares
   the narvy.io type pair. Fraunces = page titles only (--font-title),
   Schibsted Grotesk = every heading, label, button and body line,
   JetBrains Mono = measured values. Outfit / Source Sans 3 retired. */
@import url('https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,500..700&family=Schibsted+Grotesk:wght@400..800&family=JetBrains+Mono:wght@400;500;600;700&display=swap');

:root {
    /* Core palette */
    --primary-color: #00d972;
    --secondary-color: #00d972;
    --background-color: #fafaf8;
    --text-color: #0c0c0d;
    --border-color: #e8e6e1;
    /* 2026-08-14: success IS resolved. They were two greens for one idea --
       #00d972 for "it worked" and #00d972 for "it's fixed" -- which is the
       same duplication that produced the neon-vs-brand split. Merged on
       Wajdi's call, and it fixes a real bug on the way: #00d972 as text on
       the light ground was 2.43:1 and already failed AA. This is the
       readable form of the brand green at 4.95:1; the raw fill lives in
       --success below. */
    --success-color: #007e40;
    --warning-color: #f59e0b;
    --error-color: #ef4444;
    --info-color: #00d972;
    --highlight-color: #00d972;

    /* V4 tokens */
    --bg-primary: #fafaf8;
    --bg-secondary: #f5f4f0;
    --bg-card: #ffffff;
    --bg-input: #ffffff;
    --border-subtle: #e8e6e1;
    --border-strong: #d5d3ce;
    --text-primary: #0c0c0d;
    --text-secondary: #5c5a55;
    --text-muted: #6b6966;
    --accent: #00d972;
    --accent-text: #007e40;  /* WCAG AA: was #008a47 = 4.44:1 (fails), now 4.9:1 on white */
    --accent-bright: #00d972;
    --accent-dim: rgba(0, 217, 114, 0.08);
    --accent-medium: rgba(0, 217, 114, 0.15);
    --font-display: 'Schibsted Grotesk', 'Segoe UI', Roboto, Arial, sans-serif;
    --font-title: 'Fraunces', 'Iowan Old Style', Georgia, serif;
    --font-body: 'Schibsted Grotesk', 'Segoe UI', Roboto, Arial, sans-serif;
    --font-mono: 'JetBrains Mono', 'Fira Code', monospace;
    --font-sans: 'Schibsted Grotesk', 'Segoe UI', Roboto, Arial, sans-serif;
    --surface: #ffffff;
    --surface-light: #ffffff;
    --surface-elevated: #ffffff;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
    --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.06);
    --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.08);
    --radius-sm: 8px;
    --radius-md: 12px;
    --radius-lg: 16px;

    /* Skeleton loaders */
    --skeleton-strong: rgba(0, 0, 0, 0.06);
    --skeleton-light: rgba(0, 0, 0, 0.04);

    /* Override animations.css dark variables */
    --background: #fafaf8;
    --danger: #ef4444;
    --success: #00d972;   /* fill form of the same green; text form above */
    --warning: #f59e0b;

    /* Override old variables */
    --primary-dark: #00b85e;
    --primary-light: #00d972;
    --accent-cyan: #00d972;
    --accent-purple: #00d972;
    --gradient-primary: linear-gradient(135deg, #00d972 0%, #25e88b 100%);
    --gradient-secondary: linear-gradient(135deg, #00d972 0%, #25e88b 100%);
    --gradient-success: linear-gradient(135deg, #00d972 0%, #25e88b 100%);
    --gradient-tertiary: linear-gradient(135deg, #00d972 0%, #25e88b 100%);
    --gradient-dark: linear-gradient(135deg, #fafaf8, #f5f4f0);
    --wizard-primary: #00d972;
}

/* =============================================================================
   GLOBAL OVERRIDES
   ============================================================================= */
body {
    font-family: var(--font-body) !important;
    background-color: var(--bg-primary) !important;
    color: var(--text-primary);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-display);
    letter-spacing: -0.02em;
    color: var(--text-primary);
}

/* Rounded corners - V4 = soft edges */
.btn { border-radius: var(--radius-sm) !important; }
.card, .alert, .modal-content { border-radius: var(--radius-md) !important; }
/* 2026-08-14: badges were 6px, a value that appears nowhere in the radius
   scale (2 / 8 / 12 / 16 / pill) yet was the single most-used radius in this
   file. Moved onto the sm step so the scale is the scale. */
/* .nav-badge deliberately NOT in this line: it is a rectilinear chip at the
   2px hairline radius, set with the rest of its component below. Adding it
   back here reintroduces the two-shapes-in-one-sidebar bug. */
.badge { border-radius: var(--radius-sm) !important; }
input, select, textarea { border-radius: var(--radius-sm) !important; }

/* =============================================================================
   NAVBAR
   ============================================================================= */
.navbar {
    background: rgba(255, 255, 255, 0.92) !important;
    border-bottom: 1px solid var(--border-subtle) !important;
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
}

.logo {
    font-family: var(--font-display) !important;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text-primary) !important;
}

/* Persistent New Scan navbar CTA (2026-08-11): icon-only under 600px so it
   doesn't crowd the language/theme/mode/notification/user cluster next to it
   on phones -- same collapse pattern already used for other navbar-end items. */
@media (max-width: 600px) {
    .navbar-new-scan-btn span {
        display: none;
    }
    .navbar-new-scan-btn {
        padding: 0.45rem 0.6rem !important;
    }
}

/* New Scan dropdown (2026-08-11 addendum). The panel carries BOTH this
   class and .user-dropdown-menu (background/border-radius/box-shadow +
   light/dark theming inherited verbatim from that shared class - see rules
   above and the [data-theme="dark"] overrides further down this file).
   Everything below is !important because notifications.css's own
   .user-dropdown-menu rule (width/right/opacity/pointer-events/transform,
   toggled via its own .user-dropdown-open class this dropdown doesn't use)
   loads AFTER this file and would otherwise win the cascade on those exact
   properties - this dropdown is shown/hidden by new_scan_menu.js via a
   plain style.display toggle instead, so opacity/pointer-events must be
   pinned to their "visible" values unconditionally. */
.new-scan-menu-container {
    position: relative;
}
.navbar-new-scan-arrow {
    font-size: 0.78rem; /* DESIGN.md "label" type step */
    margin-left: 0.15rem;
    transition: transform 0.2s ease;
}
.new-scan-menu-open .navbar-new-scan-arrow {
    transform: rotate(180deg);
}
.new-scan-dropdown-menu {
    position: absolute !important;
    top: calc(100% + 10px) !important;
    left: 0 !important;
    right: auto !important;
    width: auto !important;
    min-width: 220px;
    max-width: 260px;
    z-index: 1000;
    padding: 0.4rem 0;
    opacity: 1 !important;
    pointer-events: auto !important;
    transform: none !important;
}
.new-scan-dropdown-menu .user-dropdown-item.feature-locked {
    opacity: 0.6;
}
.navscan-lock {
    margin-left: auto;
    font-size: 0.78rem; /* DESIGN.md "label" type step, matches the plan-badge lock icon size elsewhere */
    color: var(--text-tertiary, #98a69f);
}
@media (max-width: 600px) {
    .new-scan-dropdown-menu {
        left: auto;
        right: 0;
    }
}

.navbar-end .lang-switcher .lang-btn {
    font-family: var(--font-mono);
    color: var(--text-secondary);
    font-size: 0.8rem;
}

.navbar-end .lang-switcher .lang-btn:hover {
    color: var(--accent-text);
}
/* Active state sits on the solid green pill. White / light-green text on
   #00d972 fails WCAG 1.4.3 (3:1 to 1.8:1). Black gives 9.3:1. Fix
   Wajdi 2026-05-11: "blanc sur fond vert illisible, noir sur vert mieux". */
.navbar-end .lang-switcher .lang-btn.active {
    color: #0a0a14;
    font-weight: 700;
}

/* User menu - A04 flagged white-on-accent as failing in both themes.
   Switch text to black/near-black: #0a0a14 on #00d972 = 10.5:1, WCAG AAA. */
.user-avatar-modern,
.user-avatar-large {
    background: var(--accent) !important;
    color: #0a0a14 !important;
    border-radius: var(--radius-sm) !important;
    font-weight: 700;
}

/* Plan-tier badge (DESIGN.md plan-badge component): solid resolved-green
   fill with dark ink text, full pill radius. Same treatment for every plan
   name, this is the current user's own plan (community/starter/titan/
   business/enterprise), not a lock/upsell hint, so it gets the one literal
   plan-badge spec, not the amber lock-badge treatment below. Solid fill on
   dark ink passes contrast in both themes, so no per-theme override needed. */
.user-plan-badge,
.plan-badge-large {
    font-family: var(--font-mono);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    background: var(--accent) !important;
    color: #03170d !important;
    border: none !important;
    font-weight: 700;
    border-radius: 9999px !important;
    /* 2026-08-14: the pill had NO padding in any of the three files that
       define it, so the green fill hugged the glyphs and read as a
       highlight rather than a badge. Padding is DESIGN.md's plan-badge
       spec (6px 16px). inline-block is required for the vertical padding
       to occupy space on an inline <span>; inside .user-info, a flex
       container, it blockifies to `block` and still shrinks to content.
       Sized in em so browser text zoom scales the pill with the text
       instead of crushing the glyphs against the edge.
       font-size was 0.65rem (10.4px) here while notifications.css quietly
       overrode it to 0.75rem, so the documented spec never applied and the
       rendered size was 12px. That duplicate is now deleted and this is
       the only definition: 0.75rem keeps the size users already see and
       clears DESIGN.md's own 11px floor for functional text. */
    font-size: 0.75rem;
    display: inline-block;
    padding: 0.5em 1.33em;  /* = 6px 16px at 12px, DESIGN.md plan-badge */
    line-height: 1.35;
}

.user-menu-button {
    color: var(--text-primary) !important;
}

.user-name {
    color: var(--text-primary) !important;
}

.user-menu-arrow {
    color: var(--text-muted) !important;
}

.user-dropdown-menu {
    /* DESIGN.md No Double Edge Rule: a dropdown leaves the page plane, so the
       shadow alone is the elevation signal (DESIGN.md explicitly names
       dropdowns as legitimate shadow users) -- the hairline border on top of
       it was redundant, removed 2026-08-23. */
    background: #ffffff !important;
    border-radius: var(--radius-md) !important;
    box-shadow: var(--shadow-lg) !important;
}

.user-dropdown-header {
    border-bottom: 1px solid var(--border-subtle);
}

.user-dropdown-header h4 {
    color: var(--text-primary) !important;
}

.user-dropdown-header p {
    color: var(--text-secondary) !important;
}

.user-dropdown-item {
    color: var(--text-primary) !important;
}

.user-dropdown-item:hover {
    background: var(--accent-dim) !important;
    color: var(--accent-text) !important;
}

.user-dropdown-item i {
    color: var(--text-muted);
}

.user-dropdown-item:hover i {
    color: var(--accent-text) !important;
}

.user-dropdown-divider {
    background: var(--border-subtle) !important;
}

.user-dropdown-item.logout-item:hover {
    background: rgba(239, 68, 68, 0.06) !important;
    color: var(--error-color) !important;
}

.notification-dropdown {
    /* No Double Edge Rule, same reasoning as .user-dropdown-menu above. */
    background: #ffffff !important;
    border-radius: var(--radius-md) !important;
    box-shadow: var(--shadow-lg) !important;
}

.notification-badge {
    background: var(--error-color) !important;
    color: #fff !important;
    border-radius: 8px !important;
    font-weight: 700 !important;
}

.notification-bell {
    color: var(--text-secondary) !important;
}

.notification-bell:hover {
    color: var(--text-primary) !important;
}

/* =============================================================================
   SIDEBAR
   ============================================================================= */
.sidebar {
    background: #ffffff !important;
    border-right: 1px solid var(--border-subtle) !important;
    overflow: hidden;
    bottom: 42px !important;
    z-index: 101;
}

/* 2026-08-01 responsive audit: the plain `z-index: 101` above has no
   !important and this file loads LAST (base.html loads v4-theme.css after
   base.css/layout.css), so at <=768px it silently beat base.css's
   `@media(max-width:768px) .sidebar{z-index:1001}` (same specificity, later
   in cascade wins regardless of which rule sits inside a media query). Net
   effect: the open mobile sidebar (z-index:101) rendered UNDER
   .sidebar-overlay (z-index:1000, pointer-events:auto while open) -- every
   tap on what looked like a nav link actually hit the overlay first and just
   closed the menu instead of navigating. Real candidate for "hamburger menu
   broken on phone" / "very uncomfortable on mobile" reports. Re-assert above
   the overlay, scoped to mobile only so desktop stacking (sidebar always
   z-index:101 relative to on-page content) is untouched. */
@media (max-width: 768px) {
    .sidebar {
        z-index: 1002 !important;
    }
}

.sidebar-nav {
    flex: 1 !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 0.5rem !important;
}

.sidebar-footer {
    flex-shrink: 0 !important;
    padding-bottom: env(safe-area-inset-bottom, 0px);
    border-top: 1px solid var(--border-subtle) !important;
}

.sidebar-nav .nav-item {
    font-family: var(--font-body);
    transition: all 0.2s ease;
    color: var(--text-secondary);
    border-radius: 0 !important;
}

.sidebar-nav .nav-item:hover {
    background: var(--accent-dim) !important;
    color: var(--accent-text) !important;
    border-left-color: var(--accent);
}

.sidebar-nav .nav-item.active {
    /* 2026-08-14: the 3px green left stripe is gone. "Active" was encoded four
       times over -- tinted ground, accent text, accent icon, heavier weight --
       and the stripe was the fourth. It is also the single most recognisable
       tell of a generated UI, and DESIGN.md's nav-item-active spec is a tonal
       step plus accent text, no rail. The three remaining signals are plenty. */
    background: var(--accent-medium) !important;
    color: var(--accent-text) !important;
    font-weight: 600;
}

.sidebar-nav .nav-item.active i,
.sidebar-nav .nav-item.active .nav-icon-wrapper i {
    color: var(--accent-text) !important;
}

/* Bug fix 2026-07-31: base.css paints the active icon chip with a solid
   green gradient + a soft green box-shadow glow, while the rule above
   forces the glyph itself to the same accent green. Green-on-green with
   a blurred glow around it reads as a fuzzy/out-of-focus icon instead of
   a crisp one. Flatten the chip to the same light accent tint used on
   hover (no gradient, no shadow - app UI stays flat per DESIGN.md) so the
   bright glyph actually has contrast against it. */
.sidebar-nav .nav-item.active .nav-icon-wrapper {
    background: var(--accent-medium) !important;
    box-shadow: none !important;
}

.sidebar-nav .nav-item:hover i {
    color: var(--accent-text) !important;
}

.sidebar-nav .nav-item i {
    color: var(--text-muted);
}

.nav-item-glow {
    display: none !important;
}

/* Simple mode sidebar (2026-08-11, Wajdi round2 audit): "j'ai l'impression
   que le navbar a gauche est vide". A 4-item nav in the same 280px rail
   built for Expert's ~15 items read as unfinished, not a deliberate
   minimal surface. Narrower rail + larger touch targets + a one-line
   helper subtext per row (nav-item-text/nav-item-hint, set in base.html)
   so Simple mode reads as its own calmer, intentional treatment instead
   of "Expert with rows deleted". Scoped to body[data-ui-mode="simple"] so
   Expert's dense nav (base.css .sidebar/.page-wrapper widths) is
   untouched. */
body[data-ui-mode="simple"] .sidebar {
    width: 240px;
}

body[data-ui-mode="simple"] .page-wrapper.with-sidebar {
    padding-left: 240px;
}

@media (max-width: 768px) {
    /* Mobile sidebar overlays the page rather than pushing it (base.css
       .page-wrapper.with-sidebar { padding-left: 0 }), so the narrower rail
       width only matters off-canvas; no separate override needed. */
    body[data-ui-mode="simple"] .page-wrapper.with-sidebar {
        padding-left: 0;
    }
}

.nav-item-simple {
    padding: 1.1rem 1.25rem !important;
    gap: 0.85rem !important;
}

.nav-item-simple .nav-icon-wrapper {
    width: 38px;
    height: 38px;
    flex-shrink: 0;
}

.nav-item-simple .nav-icon-wrapper i {
    font-size: 1rem;
}

/* .simple-state-{attention,mid,clean} lived here with a 3px severity stripe
   each. Deleted 2026-08-14: the classes appear in no template, no JS and no
   view -- the dashboard's per-app state is carried by .aoc-dot, a real severity
   dot, which is the pattern DESIGN.md actually sanctions. They were dead CSS
   from an approach that got replaced, and the only thing they still did was
   put three more side-stripes in the file. */

.nav-item-text {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}

.nav-item-hint {
    font-family: var(--font-body);
    font-size: 0.72rem;
    font-weight: 400;
    letter-spacing: normal;
    text-transform: none;
    color: var(--text-muted);
    line-height: 1.3;
}

.sidebar-nav .nav-item.active .nav-item-hint {
    color: var(--accent-text) !important;
    opacity: 0.75;
}

.nav-section-title {
    font-family: var(--font-display);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    /* 2026-08-14: raised to the 11px floor DESIGN.md sets for functional UI
       text (nav, labels, buttons, badges). Was 0.65rem = 10.4px. */
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--text-muted);
}

.nav-section-line {
    background: var(--border-subtle) !important;
}

/* Sidebar badges */
/* NAV BADGES -- one shape, colour carries the meaning.
   2026-08-14 (Wajdi: "les badges ne sont pas tous pareils... et c'est pas
   beau"). He was right, and it was worse than it looked. Two complete badge
   systems were live at once: base.css set five different hues, v4-theme.css
   overrode them with !important into a THIRD arrangement where TITAN+ was a
   solid green pill at weight 700 and BETA was an outlined rounded square at
   weight 600. Two shapes, two weights, in the same 15-row sidebar.

   Worse than the inconsistency: TITAN+ wore the resolved green. That colour
   means "handled" everywhere else in the product (DESIGN.md, The One Green
   Rule), and the pill shape is reserved for the plan badge that says which
   plan you HAVE. Dressing "you must buy this" in the badge that means "you
   own this" is the opposite message in the same clothes.

   So: every nav badge is now the same rectilinear chip -- same face, size,
   weight, padding, 2px hairline radius (the pill stays reserved). Only the
   colour changes, and it encodes one thing: can you use this or not.
     NEW      accent tint, filled   -> available now
     BETA     accent, outline only  -> available, early
     TITAN+   amber                 -> locked behind a plan
     SOON     neutral outline       -> not built yet
   Green is spent only on what you can actually use. */
.nav-badge {
    font-family: var(--font-mono) !important;
    /* 2026-08-14: raised to the 11px floor DESIGN.md sets for functional UI
       text (nav, labels, buttons, badges). Was 0.55rem = 8.8px. */
    font-size: 0.7rem !important;
    font-weight: 600 !important;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    border-radius: 2px !important;
    padding: 0.15em 0.45em !important;
    line-height: 1.45 !important;
    border: 1px solid transparent !important;
    /* base.css floats these to the rail edge with margin-left:auto, which
       leaves a ragged column of chips detached from the labels they belong
       to -- only 5 of 15 rows carry one. A badge is an attribute of its
       label, so it sits next to it. */
    margin-left: 0.5rem !important;
    align-self: center;
    flex: 0 0 auto;
}

/* Available now. */
.nav-badge-new {
    background: var(--accent-dim) !important;
    color: var(--accent-text) !important;
    border-color: rgba(0, 217, 114, 0.25) !important;
}

/* Available, early. Same family as NEW, one step quieter: outline only. */
.nav-badge-beta {
    background: transparent !important;
    color: var(--accent-text) !important;
    border-color: rgba(0, 217, 114, 0.35) !important;
}

/* Locked behind a plan (TITAN+ / BUSINESS+).
   The previous note here argued this should wear the same resolved-green
   pill as the user's own plan badge, on the grounds that "gating a feature
   behind a plan is the same plan semantic". It is not. One says you have
   this, the other says you cannot use this. Amber is DESIGN.md's UI-state
   warning, which is exactly what a lock is, and it keeps the green honest. */
/* 2026-09-27 (UX pass 2): amber #f59e0b sat next to the High severity
   orange and read as a severity. A lock is stated by its text ("PRO+"), so
   the chip is a neutral outline now (DESIGN.md Navigation). */
.nav-badge-pro,
.nav-badge-team {
    background: transparent !important;
    /* Amber needs a different value per ground, measured not guessed: the
       bright #f59e0b is 6.60:1 on the dark tint but only 1.93:1 on the light
       one, so light gets the darkened hue at 4.53:1. */
    color: var(--text-secondary) !important;
    border: 1px solid var(--border-strong) !important;
}

[data-theme="dark"] .nav-badge-pro,
[data-theme="dark"] .nav-badge-team {
    color: #b5c2bb !important;
}

/* Not built yet: the quietest chip on the rail. */
.nav-badge-soon {
    background: transparent !important;
    color: var(--text-muted) !important;
    border: 1px solid var(--border-subtle) !important;
}

/* Plan indicator in sidebar footer */
.plan-indicator {
    background: var(--accent-dim) !important;
    border: 1px solid var(--border-subtle) !important;
    border-radius: var(--radius-sm) !important;
}

.plan-icon i {
    color: var(--accent-text) !important;
}

/* =============================================================================
   MAIN CONTENT
   ============================================================================= */
.main-content {
    background: var(--bg-primary);
}

/* =============================================================================
   CARDS
   ============================================================================= */
.card,
.stat-card,
.glass-card,
.analysis-card,
.info-card,
.settings-card,
.feature-card,
.pricing-card,
.balance-card,
.plan-card,
.project-card,
.integration-card,
.vuln-card,
.notification-card,
.session-card,
/* 2026-09-27 (UX pass 2, "card soup"): this list used to end with the
   substring selector [class*="-card"], which boxed EVERY element whose class
   merely contained "-card": card headers (.mon-card__head), grids of cards
   (.category-cards), even Font Awesome glyphs (.fa-credit-card, .fa-id-card
   got a background, border and shadow). Replaced by the classes that really
   are cards, found by rendering every page (tools: soup_audit, regression
   screenshots in docs/UX_PASS2_2026-09-27.md). A new card opts in here. */
.vuln-card-modern,
.auth-card,
.register-card,
.reset-card,
.upgrade-required-card,
.error-card,
.app-overview-card,
.app-card,
.mon-card,
.category-card {
    background: #ffffff !important;
    border: 1px solid var(--border-subtle) !important;
    border-radius: var(--radius-md) !important;
    box-shadow: var(--shadow-sm) !important;
    transition: all 0.2s ease;
}

/* (the substring hover rule that lifted every "-card" by 1px is gone:
   DESIGN.md, no translation on hover, depth by tonal step.) */

/* Glass card overrides */
.glass-card,
.glass-card::before {
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    background: #ffffff !important;
}

/* =============================================================================
   BUTTONS
   ============================================================================= */
.btn,
button.btn,
a.btn {
    font-family: var(--font-body) !important;
    font-weight: 600;
    letter-spacing: 0.01em;
    border-radius: var(--radius-sm) !important;
    transition: all 0.2s ease;
    font-size: 0.9rem;
}

.btn-primary,
.btn-success {
    background: var(--accent) !important;
    color: #0a0a14 !important;
    border: none !important;
    box-shadow: 0 2px 8px rgba(0, 217, 114, 0.25);
    font-weight: 600;
}

.btn-primary:hover,
.btn-success:hover {
    background: #00b85e !important;
    color: #0a0a14 !important;
    box-shadow: 0 4px 14px rgba(0, 217, 114, 0.35);
    transform: translateY(-1px);
}

.btn-secondary,
.btn-outline {
    background: transparent !important;
    color: var(--text-primary) !important;
    border: 1.5px solid var(--border-strong) !important;
}

.btn-secondary:hover,
.btn-outline:hover {
    background: var(--bg-secondary) !important;
    border-color: var(--text-primary) !important;
    color: var(--text-primary) !important;
}

.btn-danger {
    background: var(--error-color) !important;
    color: #fff !important;
}

.btn-danger:hover {
    background: #dc2626 !important;
}

/* =============================================================================
   GRADIENT BUTTON SYSTEM (Global theme, WCAG AA verified)
   - Default green: light gradient -> requires DARK text (#0a1a14)
   - Purple/pink/indigo variants: dark enough -> can use WHITE text
   - Orange variant: light -> requires DARK text (#1a1a0a)
   Replaces the inline `style="background: linear-gradient(...); color: white"`
   anti-pattern that was violating contrast on green/orange gradients.
   ============================================================================= */
.btn-gradient {
    background: linear-gradient(135deg, var(--accent, #00d972) 0%, var(--accent-bright, #00d972) 100%);
    color: #0a1a14 !important;
    padding: 0.875rem 1.75rem;
    border-radius: 12px;
    text-decoration: none;
    font-weight: 700;
    border: none;
    cursor: pointer;
    box-shadow: 0 4px 12px rgba(0, 217, 114, 0.25);
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
    font-size: 1rem; /* DESIGN.md Body step, was 0.95rem -- size wasn't part of the WCAG-contrast reasoning above */
    line-height: 1.2;
}
.btn-gradient:hover {
    transform: translateY(-1px);
    box-shadow: 0 6px 16px rgba(0, 217, 114, 0.35);
    color: #0a1a14 !important;
    text-decoration: none;
}
.btn-gradient:focus-visible {
    outline: 2px solid var(--accent, #00d972);
    outline-offset: 2px;
}

/* Purple gradient -- dark enough for white text (WCAG AA passes ~6:1) */
.btn-gradient.btn-gradient-purple {
    background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
    color: #ffffff !important;
    box-shadow: 0 4px 12px rgba(124, 58, 237, 0.35);
}
.btn-gradient.btn-gradient-purple:hover {
    box-shadow: 0 6px 16px rgba(124, 58, 237, 0.45);
    color: #ffffff !important;
}

/* Indigo gradient (667eea/764ba2) -- dark enough for white text */
.btn-gradient.btn-gradient-indigo {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: #ffffff !important;
    box-shadow: 0 4px 12px rgba(102, 126, 234, 0.35);
}
.btn-gradient.btn-gradient-indigo:hover {
    box-shadow: 0 6px 16px rgba(102, 126, 234, 0.45);
    color: #ffffff !important;
}

/* Pink/violet gradient (8b5cf6 -> ec4899) -- dark enough for white text */
.btn-gradient.btn-gradient-pink {
    background: linear-gradient(135deg, #8b5cf6 0%, #ec4899 100%);
    color: #ffffff !important;
    box-shadow: 0 4px 12px rgba(139, 92, 246, 0.35);
}
.btn-gradient.btn-gradient-pink:hover {
    box-shadow: 0 6px 16px rgba(236, 72, 153, 0.45);
    color: #ffffff !important;
}

/* Orange gradient -- too light for white text, force dark text */
.btn-gradient.btn-gradient-orange {
    background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
    color: #1a1a0a !important;
    box-shadow: 0 4px 12px rgba(217, 119, 6, 0.35);
}
.btn-gradient.btn-gradient-orange:hover {
    box-shadow: 0 6px 16px rgba(217, 119, 6, 0.45);
    color: #1a1a0a !important;
}

/* Small badge variant (for inline "BETA", "Coming Soon", "NEW" labels) */
.btn-gradient.btn-gradient-badge {
    padding: 0.25rem 0.6rem;
    /* 2026-08-14: raised to the 11px floor DESIGN.md sets for functional UI
       text (nav, labels, buttons, badges). Was 0.65rem = 10.4px. */
    font-size: 0.7rem;
    border-radius: 8px;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    font-weight: 700;
    box-shadow: none;
    display: inline-block;
}
.btn-gradient.btn-gradient-badge:hover {
    transform: none;
    box-shadow: none;
}

/* =============================================================================
   FORMS & INPUTS
   ============================================================================= */
input[type="text"],
input[type="email"],
input[type="password"],
input[type="url"],
input[type="number"],
input[type="search"],
textarea,
select,
.form-control,
.form-input {
    font-family: var(--font-body) !important;
    background: #ffffff !important;
    color: var(--text-primary) !important;
    border: 1.5px solid var(--border-subtle) !important;
    border-radius: var(--radius-sm) !important;
    outline: none;
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

input:focus,
textarea:focus,
select:focus,
.form-control:focus,
.form-input:focus {
    border-color: var(--accent) !important;
    box-shadow: 0 0 0 3px rgba(0, 217, 114, 0.12) !important;
}

::placeholder {
    color: var(--text-muted) !important;
}

label {
    font-family: var(--font-body);
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-secondary);
}

/* 2026-08-14: alert banners carried a 3px coloured left stripe over a tint.
   The tint alone already says which state this is, so the stripe was a second
   encoding of the same fact and the classic generated-UI rail. Replaced by a
   full 1px hairline in the state colour, which reads as a bounded object
   instead of a tab and matches DESIGN.md's hairline language. */
/* =============================================================================
   ALERTS & FLASH MESSAGES
   ============================================================================= */
.alert {
    background: #ffffff !important;
    border: 1px solid var(--border-subtle) !important;
    border-radius: var(--radius-sm) !important;
    font-family: var(--font-body);
    color: var(--text-primary) !important;
}

.alert-success {
    border: 1px solid var(--success-color) !important;
    background: rgba(0, 217, 114, 0.05) !important;
}

.alert-error,
.alert-danger {
    border: 1px solid var(--error-color) !important;
    background: rgba(239, 68, 68, 0.05) !important;
}

.alert-warning {
    border: 1px solid var(--warning-color) !important;
    background: rgba(245, 158, 11, 0.05) !important;
}

.alert-info {
    border: 1px solid var(--accent) !important;
    background: var(--accent-dim) !important;
}

.alert-content span,
.alert-content {
    color: var(--text-primary) !important;
}

.alert-close {
    color: var(--text-muted) !important;
}

/* =============================================================================
   TABLES
   ============================================================================= */
table {
    border-collapse: collapse;
}

table th {
    font-family: var(--font-display);
    text-transform: uppercase;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    border-bottom: 1px solid var(--border-subtle);
}

table td {
    border-bottom: 1px solid var(--border-subtle);
    color: var(--text-primary);
}

table tr:hover td {
    background: var(--accent-dim);
}

/* =============================================================================
   BADGES & TAGS
   ============================================================================= */
/* `[class*="badge"]` is a substring match, so at (0,2,0) it outranks the
   single-class plan-tier badge rules below and was clobbering their pill
   radius back down to 6px. Exclude the plan-tier badges here, same idiom as
   the button exclusion on the link rules above, so their own full-pill
   radius wins. */
.badge,
.tag,
.status-badge,
.severity-badge,
[class*="badge"]:not(.notification-badge):not(.user-plan-badge):not(.plan-badge-large):not(.nav-badge):not(.nav-badge-pro):not(.nav-badge-team) {
    font-family: var(--font-mono) !important;
    /* 2026-08-14: raised to the 11px floor DESIGN.md sets for functional UI
       text (nav, labels, buttons, badges). Was 0.65rem = 10.4px. */
    font-size: 0.7rem !important;
    font-weight: 600;
    letter-spacing: 0.03em;
    border-radius: 8px !important;
}

/* Severity colors.
   2026-08-14: these were the Tailwind 500/600 ramp (#ef4444, #f97316, #eab308,
   #3b82f6), a SECOND severity family running alongside the product's real one
   (#e5484d, #f0983a, #e8c33d, #4c8df6 -- see DESIGN.md). "Critical" was one red
   here and a different red in the Simple-mode state cards. Unified on the
   product colours. The text variants are the product hue darkened until it
   clears 4.5:1 on white, computed rather than picked: crit 4.54:1, high 4.54:1,
   med 4.62:1, low 4.58:1. */
.badge-critical,
.severity-critical {
    background: rgba(229, 72, 77, 0.08) !important;
    color: #e12d33 !important;
    border: 1px solid rgba(229, 72, 77, 0.2) !important;
}

.badge-high,
.severity-high {
    background: rgba(240, 152, 58, 0.08) !important;
    color: #b1620e !important;
    border: 1px solid rgba(240, 152, 58, 0.2) !important;
}

.badge-medium,
.severity-medium {
    background: rgba(232, 195, 61, 0.08) !important;
    color: #8d7211 !important;
    border: 1px solid rgba(232, 195, 61, 0.2) !important;
}

.badge-low,
.severity-low {
    background: rgba(76, 141, 246, 0.08) !important;
    color: #1b6ef4 !important;
    border: 1px solid rgba(76, 141, 246, 0.2) !important;
}

/* =============================================================================
   TABS & NAVIGATION
   ============================================================================= */
.tab,
.tab-btn,
[class*="tab-"] {
    font-family: var(--font-body);
    font-weight: 600;
    border-radius: var(--radius-sm) !important;
}

.tab-btn.active,
.tab.active,
[class*="tab-"].active {
    color: var(--accent-text) !important;
    border-color: var(--accent) !important;
    background: var(--accent-dim) !important;
}

/* =============================================================================
   PROGRESS BARS
   ============================================================================= */
.progress-bar,
progress,
[class*="progress"] {
    border-radius: var(--radius-sm) !important;
    background: var(--bg-secondary);
}

.progress-bar-fill,
progress::-webkit-progress-value {
    background: var(--accent) !important;
    border-radius: var(--radius-sm) !important;
}

/* =============================================================================
   MODALS
   ============================================================================= */
.modal-content,
.modal-dialog {
    /* No Double Edge Rule: DESIGN.md names dialogs explicitly as a legitimate
       shadow user (leaves the page plane); the hairline border was redundant. */
    background: #ffffff !important;
    border-radius: var(--radius-lg) !important;
    box-shadow: var(--shadow-lg) !important;
}

.modal-overlay,
.modal-backdrop {
    background: rgba(12, 12, 13, 0.4) !important;
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
}

/* =============================================================================
   SCROLLBARS - Thin, subtle
   ============================================================================= */
::-webkit-scrollbar {
    width: 6px;
    height: 6px;
}

::-webkit-scrollbar-track {
    background: var(--bg-secondary);
}

::-webkit-scrollbar-thumb {
    background: var(--border-strong);
    border-radius: 3px;
}

::-webkit-scrollbar-thumb:hover {
    background: var(--accent);
}

/* =============================================================================
   FOOTER
   ============================================================================= */
.site-footer {
    background: #ffffff !important;
    border-top: 1px solid var(--border-subtle) !important;
}

.site-footer a {
    font-family: var(--font-body);
    font-size: 0.8rem;
    color: var(--text-muted) !important;
}

.site-footer a:hover {
    color: var(--accent-text) !important;
}

.footer-copyright {
    color: var(--text-muted) !important;
}

.footer-separator {
    color: var(--border-subtle) !important;
}

/* Cookie notice */
.cookie-notice {
    background: #ffffff !important;
    border-top: 1px solid var(--border-subtle) !important;
    border-radius: 0 !important;
    box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.06);
}

.cookie-notice p {
    color: var(--text-secondary) !important;
}

.cookie-btn {
    background: var(--accent) !important;
    color: #0a0a14 !important; /* axe: white on the accent fails (1.88:1); #0a0a14 on #00d972 = 10.5:1 AA */
    border-radius: var(--radius-sm) !important;
    font-family: var(--font-body) !important;
    font-weight: 700;
}

/* =============================================================================
   AUTH PAGES (login, register, forgot-password)
   ============================================================================= */
/* 2026-09-27: .auth-container dropped from this list: the wrapper AND the
   card inside it were both boxed (a double border on /login). */
.auth-card,
.login-card,
.register-card {
    /* No Double Edge Rule: an in-page auth card doesn't leave the plane like a
       dropdown/dialog/toast does -- per DESIGN.md's elevation model this is a
       tonal-step card, so the border is the correct signal and the shadow was
       the redundant one (opposite fix direction from the dropdown/modal
       blocks above, which keep their shadow and lose the border). */
    background: #ffffff !important;
    border: 1px solid var(--border-subtle) !important;
    border-radius: var(--radius-lg) !important;
}

.auth-form h2,
.auth-card h2,
.register-card h2 {
    color: var(--text-primary) !important;
}

.auth-form p,
.auth-card p,
.register-card p {
    color: var(--text-secondary) !important;
}

/* Register page - override dark-theme hardcoded colors in register.css */
.register-card label,
.register-card .form-group label {
    color: var(--text-primary) !important;
}

.register-card input[type="text"],
.register-card input[type="email"],
.register-card input[type="password"],
.register-card select {
    background: var(--bg-input, #ffffff) !important;
    border-color: var(--border-strong, #d5d3ce) !important;
    color: var(--text-primary) !important;
}

.register-card .password-strength,
.register-card .requirement,
.register-card .login-link,
.register-card .terms-text {
    color: var(--text-secondary) !important;
}

.register-card .subtitle,
.register-card .form-hint {
    color: var(--text-muted) !important;
}

/* Google OAuth button */
.google-btn,
.oauth-btn {
    background: #ffffff !important;
    color: var(--text-primary) !important;
    border-radius: var(--radius-sm) !important;
    font-family: var(--font-body) !important;
    border: 1.5px solid var(--border-subtle) !important;
    box-shadow: var(--shadow-sm) !important;
}

.google-btn:hover,
.oauth-btn:hover {
    background: var(--bg-secondary) !important;
    box-shadow: var(--shadow-md) !important;
}

/* =============================================================================
   LEGAL PAGES
   ============================================================================= */
.legal-page,
.legal-content {
    font-family: var(--font-body);
    color: var(--text-primary);
}

.legal-content h1,
.legal-content h2,
.legal-content h3 {
    font-family: var(--font-display);
    color: var(--text-primary);
}

/* =============================================================================
   ANALYSIS STATUS / RESULTS
   ============================================================================= */
.status-running,
.status-processing {
    color: var(--accent-text) !important;
}

.status-completed,
.status-success {
    color: var(--success-color) !important;
}

.status-failed,
.status-error {
    color: var(--error-color) !important;
}

/* 2026-09-27: the global [class*="score"] rule (every class containing
   "score" went mono, including labels like "Security score" and "Not
   tested") is gone. DESIGN.md Instrument Rule: mono for real values only,
   set on the value itself (.big-score / .cat-score numbers below, .ts-mono). */
.big-score:not(.insufficient),
.cat-score:not(.insufficient) {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
}

/* Defensive: force Font Awesome family on every FA icon, with !important,
   so future [class*="..."] rules cannot tofu the glyph. Weight 900 = solid,
   400 = regular, brands family overrides for .fab below. */
i.fas, i.fa-solid,
.fas, .fa-solid {
    font-family: "Font Awesome 6 Free" !important;
    font-weight: 900 !important;
}
i.far, i.fa-regular,
.far, .fa-regular {
    font-family: "Font Awesome 6 Free" !important;
    font-weight: 400 !important;
}
i.fab, i.fa-brands,
.fab, .fa-brands {
    font-family: "Font Awesome 6 Brands" !important;
    font-weight: 400 !important;
}

/* =============================================================================
   EMPTY STATES
   ============================================================================= */
.empty-state,
.no-data,
[class*="empty"] {
    color: var(--text-muted);
}

.empty-state i,
.no-data i {
    color: var(--border-strong);
}

/* =============================================================================
   INTEGRATIONS PAGE
   ============================================================================= */
.integration-card .integration-icon {
    border-radius: var(--radius-sm) !important;
}

/* =============================================================================
   SELECTION & HIGHLIGHT
   ============================================================================= */
::selection {
    background: rgba(0, 217, 114, 0.3); /* real accent, was a near-duplicate green */
    color: #03170d; /* Earned Ink Rule: resolved-ink on an accent-tinted ground */
    /* Headings inherit -webkit-text-fill-color:transparent from the global
       gradient h1 rule (animations.css). Without resetting it here, selected
       heading glyphs stay transparent and look amputated (the "P" loses its
       stem). Reset the fill so selected text always paints solid. */
    -webkit-text-fill-color: #03170d;
}

/* =============================================================================
   LINKS
   ============================================================================= */
/* Same scoping fix as the dark-theme rule below: bare `a` (element only,
   still (0,0,1) but with no competing class-scoped rule it wins on source
   order) was painting every sidebar `.nav-item` link the accent colour too.
   Scope to where real content links live, `.main-content` plus `.nav-links`
   (the logged-out navbar Login link). A link styled as a button still keeps
   the button's own text colour, not the accent link colour. */
.main-content a:not([class*="btn"]):not([class*="button"]),
.nav-links a:not([class*="btn"]):not([class*="button"]) {
    color: var(--accent-text);
}

.main-content a:not([class*="btn"]):not([class*="button"]):hover,
.nav-links a:not([class*="btn"]):not([class*="button"]):hover {
    color: #00b85e;
}

/* =============================================================================
   CODE BLOCKS
   ============================================================================= */
code,
pre,
.code-block {
    font-family: var(--font-mono) !important;
    background: var(--bg-secondary) !important;
    border: 1px solid var(--border-subtle) !important;
    border-radius: var(--radius-sm) !important;
    color: var(--text-primary) !important;
}

/* =============================================================================
   COLOR OVERRIDE - Kill all old hardcoded blue/purple/dark values
   ============================================================================= */

:root {
    --primary-color: #00d972 !important;
    --primary-dark: #00b85e !important;
    --primary-light: #00d972 !important;
    --accent-cyan: #00d972 !important;
    --accent-purple: #00d972 !important;
    --gradient-primary: linear-gradient(135deg, #00d972 0%, #25e88b 100%) !important;
    --gradient-secondary: linear-gradient(135deg, #00d972 0%, #25e88b 100%) !important;
    --gradient-success: linear-gradient(135deg, #00d972 0%, #25e88b 100%) !important;
    --gradient-tertiary: linear-gradient(135deg, #00d972 0%, #25e88b 100%) !important;
    --gradient-dark: linear-gradient(135deg, #fafaf8, #f5f4f0) !important;
    --wizard-primary: #00d972 !important;
}

/* Sidebar active */
.sidebar-nav .nav-item:hover,
.nav-item.active {
    background: var(--accent-dim) !important;
    color: var(--accent-text) !important;
}

.sidebar-nav .nav-item.active {
    background: var(--accent-medium) !important;
    color: var(--accent-text) !important;
}

.sidebar-nav .nav-item.active i,
.sidebar-nav .nav-item:hover i {
    color: var(--accent-text) !important;
}

/* Toggle switch */
.toggle-switch input:checked + .toggle-slider,
.toggle-input:checked + .toggle-slider {
    background: var(--accent) !important;
}

/* Breadcrumb */
.breadcrumb-item.active,
.breadcrumb-item a:hover {
    color: var(--accent-text) !important;
}

.breadcrumb-item {
    color: var(--text-muted) !important;
}

/* Section headers / page titles */
.section-title-modern,
.page-title,
.page-title-text,
.section-header h2,
.dashboard-title {
    background: none !important;
    -webkit-background-clip: unset !important;
    -webkit-text-fill-color: var(--text-primary) !important;
    background-clip: unset !important;
    color: var(--text-primary) !important;
}

/* Stat cards */
.stat-card .stat-icon,
.summary-card .stat-icon,
.stat-icon-wrapper {
    background: var(--accent-dim) !important;
    color: var(--accent-text) !important;
    border-radius: var(--radius-sm) !important;
}

.stat-card .stat-icon i,
.summary-card .stat-icon i,
.stat-icon-wrapper i {
    color: var(--accent-text) !important;
}

/* Step indicators / wizard */
.step-number,
.step-indicator.active .step-number,
.wizard-step.active .step-number,
.step.active .step-number {
    background: var(--accent) !important;
    color: #fff !important;
    border-radius: 50% !important;
}

.step-indicator.completed .step-number,
.wizard-step.completed .step-number,
.step.completed .step-number {
    background: var(--accent) !important;
    color: #fff !important;
}

.step-connector.active,
.step-line.active {
    background: var(--accent) !important;
}

/* Gradient text → accent color */
.gradient-text,
.text-gradient,
[class*="gradient-text"] {
    background: none !important;
    -webkit-background-clip: unset !important;
    -webkit-text-fill-color: var(--accent-text) !important;
    background-clip: unset !important;
    color: var(--accent-text) !important;
}

/* Feature icons */
.feature-icon,
.info-icon,
.accent-icon,
[class*="feature-icon"] {
    background: var(--accent-dim) !important;
    color: var(--accent-text) !important;
    border-radius: var(--radius-sm) !important;
}

.feature-icon i,
.info-icon i {
    color: var(--accent-text) !important;
}

/* Scan type badges */
.scan-type-badge,
.analysis-type-badge,
[class*="type-badge"] {
    background: var(--accent-dim) !important;
    color: var(--accent-text) !important;
    border: 1px solid rgba(0, 217, 114, 0.2) !important;
    border-radius: 8px !important;
}

/* Progress shimmer */
.progress-bar-shimmer,
.progress-shimmer,
.shimmer-bar {
    background: linear-gradient(90deg, var(--accent) 0%, #00d972 50%, var(--accent) 100%) !important;
}

/* Alert modal */
.alert-modal.info .alert-icon,
.alert-icon.info {
    color: var(--accent-text) !important;
}

/* File input focus */
.file-input:focus,
.upload-card:focus-within {
    border-color: var(--accent) !important;
    box-shadow: 0 0 0 3px rgba(0, 217, 114, 0.12) !important;
}

/* Card hover - soft shadow, NOT glow */
.card:hover,
.glass-card:hover {
    box-shadow: var(--shadow-md) !important;
}

/* Icon gradient */
.icon-gradient,
[class*="icon-gradient"] {
    background: linear-gradient(135deg, #00d972, #25e88b) !important;
}

/* Auth form inputs */
.auth-form input:focus,
.register-form input:focus,
.login-form input:focus {
    border-color: var(--accent) !important;
    box-shadow: 0 0 0 3px rgba(0, 217, 114, 0.12) !important;
}

.auth-form .form-link,
.register-form .form-link,
.login-form .form-link,
.auth-link {
    color: var(--accent-text) !important;
}

.auth-form .btn-primary,
.register-form .btn-primary,
.login-form .btn-primary,
.auth-submit-btn {
    background: var(--accent) !important;
    color: #fff !important;
}

.auth-form .btn-primary:hover,
.register-form .btn-primary:hover,
.login-form .btn-primary:hover,
.auth-submit-btn:hover {
    background: #00b85e !important;
    color: #fff !important;
}

/* Password strength */
.password-strength-bar,
.strength-meter-fill {
    background: var(--accent) !important;
    border-radius: 2px !important; /* DESIGN.md hairline step, was 4px */
}

.password-strength-text,
.strength-label {
    color: var(--accent-text) !important;
}

/* Checkbox */
.custom-checkbox:checked,
.form-check-input:checked {
    background-color: var(--accent) !important;
    border-color: var(--accent) !important;
}

/* Notifications */
.notification-icon.info,
.notif-icon-info {
    color: var(--accent-text) !important;
}

.notification-icon.update,
.notif-icon-update {
    color: var(--accent-text) !important;
}

.notification-badge-header,
.mark-all-read {
    background: var(--accent) !important;
    color: #fff !important;
}

.notification-header,
.notification-modal-header {
    background: var(--accent) !important;
    color: #fff !important;
    border-radius: var(--radius-md) var(--radius-md) 0 0 !important;
}

.notification-dropdown-header h3 {
    color: var(--text-primary) !important;
}

.notification-dropdown-footer {
    border-top: 1px solid var(--border-subtle);
}

.view-all-link {
    color: var(--accent-text) !important;
}

/* Wizard */
.wizard-btn-primary,
.wizard-next-btn,
.wizard-submit-btn {
    background: var(--accent) !important;
    color: #fff !important;
    box-shadow: 0 2px 8px rgba(0, 217, 114, 0.25) !important;
}

.wizard-btn-primary:hover,
.wizard-next-btn:hover,
.wizard-submit-btn:hover {
    background: #00b85e !important;
    color: #fff !important;
    box-shadow: 0 4px 14px rgba(0, 217, 114, 0.35) !important;
}

.wizard-step-indicator.active,
.wizard-progress-fill {
    background: var(--accent) !important;
}

.wizard-badge,
.scan-badge {
    background: var(--accent) !important;
    color: #fff !important;
    border-radius: 8px !important;
}

/* Survey */
.survey-submit-btn,
.survey-btn-primary {
    background: var(--accent) !important;
    color: #fff !important;
}

.survey-option:hover,
.survey-option.selected {
    border-color: var(--accent) !important;
}

.survey-option.selected {
    background: var(--accent-dim) !important;
}

.survey-star.active,
.rating-star.active {
    color: var(--warning-color) !important;
}

.survey-header,
.survey-modal-header {
    background: var(--accent) !important;
    color: #fff !important;
}

/* Upgrade prompts */
.upgrade-card,
.upgrade-prompt,
[class*="upgrade-"]:not(.upgrade-banner):not(.upgrade-btn):not(.upgrade-cta-btn):not(.upgrade-primary-btn):not(.upgrade-icon):not(.upgrade-badge):not(.upgrade-feature-icon):not(.upgrade-progress-fill):not(.upgrade-title):not(.upgrade-subtitle) {
    /* No Double Edge Rule: in-page promo card, same reasoning as the auth-card
       block -- border is the elevation signal, shadow was redundant. */
    background: #ffffff !important;
    border: 1px solid var(--border-subtle) !important;
}

.upgrade-card:hover,
.upgrade-prompt:hover {
    border-color: var(--accent) !important;
    box-shadow: var(--shadow-md) !important;
}

.upgrade-btn,
.upgrade-cta-btn,
.upgrade-primary-btn {
    background: var(--accent) !important;
    color: #fff !important;
}

.upgrade-btn:hover,
.upgrade-cta-btn:hover,
.upgrade-primary-btn:hover {
    background: #00b85e !important;
    color: #fff !important;
}

.upgrade-icon,
.upgrade-badge {
    background: var(--accent) !important;
    color: #fff !important;
    border-radius: var(--radius-sm) !important;
}

.upgrade-feature-icon {
    color: var(--accent-text) !important;
}

.upgrade-progress-fill,
.usage-progress-fill {
    background: var(--accent) !important;
}

.upgrade-banner {
    background: #ffffff !important;
    border: 1px solid var(--border-subtle) !important;
    border-radius: var(--radius-md) !important;
}

.upgrade-banner h3 {
    color: var(--text-primary) !important;
}

.upgrade-banner p {
    color: var(--text-secondary) !important;
}

/* Waitlist */
.waitlist-btn,
.waitlist-submit-btn {
    background: var(--accent) !important;
    color: #fff !important;
}

.waitlist-feature-icon,
.waitlist-feature-icon.shield,
.waitlist-feature-icon.cloud,
.waitlist-feature-icon.teams,
.waitlist-feature-icon.enterprise {
    background: var(--accent) !important;
    color: #fff !important;
    border-radius: var(--radius-sm) !important;
}

.waitlist-input:focus {
    border-color: var(--accent) !important;
}

.waitlist-check-icon {
    background: var(--accent) !important;
    color: #fff !important;
}

/* Dashboard stat cards */
.dashboard-stat-card,
.stat-card-gradient {
    background: var(--accent-dim) !important;
}

/* Quota bar */
.quota-bar-fill,
.quota-progress-fill,
.usage-bar-fill {
    background: var(--accent) !important;
}

.quota-header,
.quota-icon {
    color: var(--accent-text) !important;
}

/* Pulse animation - V4 version */
.pulse-dot,
.status-dot.active,
.live-indicator {
    background: var(--accent) !important;
    box-shadow: 0 0 0 0 rgba(0, 217, 114, 0.4) !important;
    animation: v4-pulse 2s infinite !important;
}

@keyframes v4-pulse {
    0% { box-shadow: 0 0 0 0 rgba(0, 217, 114, 0.4); }
    70% { box-shadow: 0 0 0 8px rgba(0, 217, 114, 0); }
    100% { box-shadow: 0 0 0 0 rgba(0, 217, 114, 0); }
}

/* Settings */
.settings-section-title,
.settings-tab.active,
.settings-nav-item.active {
    color: var(--accent-text) !important;
    border-color: var(--accent) !important;
}

.settings-tab.active,
.settings-nav-item.active {
    background: var(--accent-dim) !important;
}

/* Light theme: accent-text on accent-dim drops to 4.44; bump to AA (5.18) */
[data-theme="light"] .settings-tab.active,
[data-theme="light"] .settings-nav-item.active {
    color: #006837 !important;
}

/* Page header */
.page-header,
.content-header {
    background: var(--bg-primary) !important;
    border-bottom: 1px solid var(--border-subtle) !important;
}

/* Catch-all gradient overrides */
.accent-gradient,
.bg-gradient,
[style*="linear-gradient"][style*="667eea"],
[style*="linear-gradient"][style*="4f46e5"],
[style*="linear-gradient"][style*="764ba2"] {
    background: linear-gradient(135deg, #00d972 0%, #25e88b 100%) !important;
}

/* =============================================================================
   SEVERITY BADGE COLORS - Visible on light backgrounds
   ============================================================================= */
/* Same unification as the block above. The 3px left border is the one place a
   coloured stripe is data rather than decoration, so it carries the flat
   product severity colour while the text carries its WCAG-safe companion. */
.severity-critical { background: rgba(229, 72, 77, 0.08) !important; color: #e12d33 !important; }
.severity-high { background: rgba(240, 152, 58, 0.08) !important; color: #b1620e !important; }
.severity-medium { background: rgba(232, 195, 61, 0.08) !important; color: #8d7211 !important; }
.severity-low { background: rgba(76, 141, 246, 0.08) !important; color: #1b6ef4 !important; }
.severity-info { background: rgba(107, 114, 128, 0.08) !important; color: #6b7280 !important; }

/* AA contrast: white-on-red-500/orange-500/blue-500 was 3.76/2.8/4.39.
   Darkening to *-600/700 gets all four pills above 4.5:1. */
.severity-indicator { font-weight: 600 !important; }
/* 2026-08-14: this was a THIRD severity palette (Tailwind 700/600/500), on top
   of the two already unified above. Solid fills carrying white text need the
   product hue darkened until white clears 4.5:1, so these are the computed
   variants: crit 4.51:1, high 4.57:1, low 4.53:1. Medium keeps the flat
   product yellow because near-black on it is already 10.33:1. */
.severity-indicator.critical { background: #e12f35 !important; color: #ffffff !important; border-radius: 8px !important; }
.severity-indicator.high { background: #b0620d !important; color: #ffffff !important; border-radius: 8px !important; }
.severity-indicator.medium { background: #e8c33d !important; color: #1a1a00 !important; border-radius: 8px !important; }
.severity-indicator.low { background: #1d6ff4 !important; color: #ffffff !important; border-radius: 8px !important; }

/* =============================================================================
   /analysis/<id> report buttons - AA contrast overrides (Apr 2026)
   The template hard-codes inline `style="color: …"` values that fail AA on
   white. We override via class selectors with !important to win the cascade
   without rewriting the (huge) template.
   ============================================================================= */
.download-btn.sarif { color: #1d4ed8 !important; border-color: #2563eb !important; }
.download-btn.html { color: #15803d !important; border-color: #16a34a !important; }
.download-btn.unified { color: #7e22ce !important; border-color: #a855f7 !important; }
.download-btn.locked { color: #4b5563 !important; }
.download-btn.locked > span:last-child { color: #006837 !important; }
[data-theme="dark"] .download-btn.sarif { color: #93c5fd !important; }
[data-theme="dark"] .download-btn.html { color: #6ee7b7 !important; }
[data-theme="dark"] .download-btn.unified { color: #d8b4fe !important; }
[data-theme="dark"] .download-btn.locked { color: #cbd5e1 !important; }
[data-theme="dark"] .download-btn.locked > span:last-child { color: #6ee7b7 !important; }

#regenerateReportBtn { color: #4338ca !important; border-color: #6366f1 !important; }
[data-theme="dark"] #regenerateReportBtn { color: #a5b4fc !important; }

/* "Rescan" status pill - theme-aware AA on its 15%-grey bg. */
.status-pill-rescan { color: #4b5563; }
[data-theme="dark"] .status-pill-rescan { color: #d1d5db; }

/* "Starter+" upgrade pill on locked report buttons. AA on the green-tinted bg. */
.plan-pill-starter {
    /* Colors left as-is -- explicit AA-contrast reasoning in the comment
       above this block, not drift. Radius only: DESIGN.md hairline step. */
    font-size: 0.7rem;
    font-weight: 700;
    padding: 0.1rem 0.4rem;
    background: rgba(0, 138, 71, 0.15);
    color: #006837;
    border-radius: 2px;
    margin-left: 0.2rem;
}
[data-theme="dark"] .plan-pill-starter {
    color: #6ee7b7;
}

/* =============================================================================
   Z-INDEX FIX
   ============================================================================= */
.status-dropdown-menu { z-index: 200 !important; }
#rescanModal { z-index: 1050 !important; }

/* =============================================================================
   DASHBOARD-SPECIFIC - Fix inline styles that hardcode dark colors
   ============================================================================= */
.dashboard-container {
    background: var(--bg-primary) !important;
}

.security-overview-grid {
    min-height: 220px;
}

/* Metric cards text */
.metric-value {
    color: var(--text-primary) !important;
}

.metric-card h3 {
    color: var(--text-secondary) !important;
}

/* Recent scans cards */
.scan-card,
.recent-scan-item {
    background: #ffffff !important;
    border: 1px solid var(--border-subtle) !important;
}

.scan-card:hover,
.recent-scan-item:hover {
    border-color: var(--accent) !important;
}

/* History page cards */
.analysis-list-item,
.history-card {
    background: #ffffff !important;
    border: 1px solid var(--border-subtle) !important;
}

/* Skeleton loading states - light theme */
.skeleton-loading {
    background: var(--bg-secondary) !important;
}

/* =============================================================================
   INLINE STYLE OVERRIDES - For templates with hardcoded dark colors
   ============================================================================= */
.btn-new-analysis {
    background: var(--accent) !important;
    color: #fff !important;
    border-radius: var(--radius-sm) !important;
    box-shadow: 0 2px 8px rgba(0, 217, 114, 0.25) !important;
}

.btn-new-analysis:hover {
    background: #00b85e !important;
    transform: translateY(-1px);
}

/* Fix hardcoded rgba(255,255,255,0.05) borders on light bg */
[style*="rgba(255, 255, 255, 0.05)"] {
    border-color: var(--border-subtle) !important;
}

/* Plan card override */
.plan-card .plan-header {
    color: var(--text-primary);
}

/* Fix chart backgrounds */
#mainSecurityGauge,
#vulnerabilityTrendChart,
#projectsSparkline,
#issuesSparkline,
#scansSparkline {
    background: transparent !important;
}

/* =============================================================================
   RETRY OPTIONS (analysis_status.html)
   ============================================================================= */
.retry-options {
    padding: 12px;
    border-radius: 8px;
}
.retry-options__title {
    margin: 0 0 8px;
    font-weight: 600;
}
.retry-options__desc {
    margin: 0 0 12px;
}
.retry-options--warning {
    border: 1px solid #f59e0b;
    background: rgba(245, 158, 11, 0.08);
}
.retry-options--warning .retry-options__title { color: var(--warning-color, #f59e0b); }
.retry-options--warning .retry-options__desc { color: var(--text-secondary); }

.retry-options--info {
    /* 2026-08-14: Tailwind blue-500 as a title colour is 3.68:1 on the light
       ground and fails AA. Moved onto the product's low-severity hue darkened
       to 4.58:1, with the flat hue kept for the border where contrast is not
       a text requirement. */
    border: 1px solid #4c8df6;
    background: rgba(76, 141, 246, 0.08);
}
.retry-options--info .retry-options__title { color: #1b6ef4; }
.retry-options--info .retry-options__desc { color: var(--text-secondary); }

.retry-options--purple {
    border: 1px solid #8b5cf6;
    background: rgba(139, 92, 246, 0.08);
}
.retry-options--purple .retry-options__title { color: #8b5cf6; }
.retry-options--purple .retry-options__desc { color: var(--text-secondary); }

/* =============================================================================
   DARK MODE - [data-theme="dark"]
   Warm charcoal, not pure black. Same accent green but brighter.
   Proper WCAG AA contrast on all text.
   ============================================================================= */
[data-theme="dark"] {
    --primary-color: #00d972;
    --secondary-color: #00d972;
    --background-color: #0f1311;
    --text-color: #f2f6f3;
    --border-color: #29332c;
    --success-color: #00d972;  /* 10.25:1 on the dark ground, up from 10.03 */
    --warning-color: #fbbf24;
    --error-color: #f87171;
    --info-color: #00d972;
    --highlight-color: #00d972;

    --bg-primary: #0f1311;
    --bg-secondary: #141a16;
    --bg-card: #182019;
    --bg-input: #182019;
    --border-subtle: #29332c;
    --border-strong: #3a463e;
    --text-primary: #f2f6f3;
    --text-secondary: #b5c2bb;
    --text-muted: #98a69f;
    /* 2026-08-14: this block used to set --accent: #00ff88, a neon green
       that existed nowhere else. Because the app defaults to dark, that
       made #00ff88 the green users actually saw, while the landing page,
       DESIGN.md and the plan-badge spec all said #00d972. Two brand
       greens, and the documented one was the one nobody saw. Unified on
       #00d972 (Wajdi, 2026-08-14). Contrast re-measured, not assumed:
       #00d972 on #0f1311 = 10.25:1, near-black on #00d972 = 10.5:1,
       both AAA. White on the accent still fails (1.88:1), which is why
       every accent-filled control below sets a near-black text colour. */
    --accent: #00d972;
    --accent-text: #00d972;  /* 10.25:1 on the dark ground, AAA */
    --accent-bright: #25e88b;
    --accent-dim: rgba(0, 217, 114, 0.08);
    --accent-medium: rgba(0, 217, 114, 0.15);
    --surface: #182019;
    --surface-light: #182019;
    --surface-elevated: #1f2922;
    --background: #0f1311;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.2);
    --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.3);
    --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.4);

    /* Skeleton loaders */
    --skeleton-strong: rgba(255, 255, 255, 0.06);
    --skeleton-light: rgba(255, 255, 255, 0.04);

    /* Override old variable names */
    --primary-dark: #00d972;
    --primary-light: #25e88b;
    --accent-cyan: #00d972;
    --accent-purple: #00d972;
    --gradient-primary: linear-gradient(135deg, #25e88b 0%, #00d972 100%);
    --gradient-secondary: linear-gradient(135deg, #25e88b 0%, #00d972 100%);
    --gradient-success: linear-gradient(135deg, #25e88b 0%, #00d972 100%);
    --gradient-tertiary: linear-gradient(135deg, #25e88b 0%, #00d972 100%);
    --gradient-dark: linear-gradient(135deg, #0f1311, #141a16);
    --wizard-primary: #00d972;

    color-scheme: dark;
}

/* --- Dark mode body --- */
[data-theme="dark"] body {
    background-color: #0f1311 !important;
    color: #f2f6f3;
}

/* --- Dark mode navbar --- */
[data-theme="dark"] .navbar {
    background: rgba(14, 14, 17, 0.92) !important;
    border-bottom-color: #29332c !important;
}

[data-theme="dark"] .logo {
    color: #f2f6f3 !important;
}

[data-theme="dark"] .user-menu-button,
[data-theme="dark"] .user-name {
    color: #f2f6f3 !important;
}

[data-theme="dark"] .user-menu-arrow,
[data-theme="dark"] .notification-bell {
    color: #98a69f !important;
}

[data-theme="dark"] .notification-bell:hover {
    color: #f2f6f3 !important;
}

[data-theme="dark"] .user-dropdown-menu {
    background: #182019 !important;
    border-color: #29332c !important;
}

[data-theme="dark"] .user-dropdown-item {
    color: #f2f6f3 !important;
}

[data-theme="dark"] .user-dropdown-item:hover {
    background: rgba(0, 217, 114, 0.08) !important;
    color: #00d972 !important;
}

[data-theme="dark"] .user-dropdown-divider {
    background: #29332c !important;
}

[data-theme="dark"] .notification-dropdown {
    background: #182019 !important;
    border-color: #29332c !important;
}

[data-theme="dark"] .notification-dropdown-header h3 {
    color: #f2f6f3 !important;
}

/* --- Dark mode sidebar --- */
[data-theme="dark"] .sidebar {
    background: #141a16 !important;
    border-right-color: #29332c !important;
}

[data-theme="dark"] .sidebar-nav .nav-item {
    color: #b5c2bb;
}

[data-theme="dark"] .sidebar-nav .nav-item i {
    color: #98a69f;
}

[data-theme="dark"] .sidebar-nav .nav-item:hover {
    color: #00d972 !important;
    background: rgba(0, 217, 114, 0.08) !important;
}

[data-theme="dark"] .sidebar-nav .nav-item.active {
    color: #00d972 !important;
    background: rgba(0, 217, 114, 0.16) !important;
}

[data-theme="dark"] .sidebar-nav .nav-item:hover i,
[data-theme="dark"] .sidebar-nav .nav-item.active i {
    color: #00d972 !important;
}

[data-theme="dark"] .sidebar-footer {
    border-top-color: #29332c !important;
}

/* --- Dark mode main content --- */
[data-theme="dark"] .main-content {
    background: #0f1311;
}

/* --- Dark mode cards --- */
[data-theme="dark"] .card,
[data-theme="dark"] .stat-card,
[data-theme="dark"] .glass-card,
[data-theme="dark"] .analysis-card,
[data-theme="dark"] .info-card,
[data-theme="dark"] .settings-card,
[data-theme="dark"] .feature-card,
[data-theme="dark"] .pricing-card,
[data-theme="dark"] .plan-card,
[data-theme="dark"] .project-card,
[data-theme="dark"] .integration-card,
[data-theme="dark"] .vuln-card,
[data-theme="dark"] .notification-card,
[data-theme="dark"] .session-card,
[data-theme="dark"] .vuln-card-modern,
[data-theme="dark"] .auth-card,
[data-theme="dark"] .register-card,
[data-theme="dark"] .reset-card,
[data-theme="dark"] .upgrade-required-card,
[data-theme="dark"] .error-card,
[data-theme="dark"] .app-overview-card,
[data-theme="dark"] .app-card,
[data-theme="dark"] .mon-card,
[data-theme="dark"] .category-card {
    background: #182019 !important;
    border-color: #29332c !important;
}

[data-theme="dark"] .glass-card,
[data-theme="dark"] .glass-card::before {
    background: #182019 !important;
}

/* --- Dark mode buttons --- */
[data-theme="dark"] .btn-primary,
[data-theme="dark"] .btn-success {
    background: #00d972 !important;
    color: #0f1311 !important;
}

[data-theme="dark"] .btn-primary:hover,
[data-theme="dark"] .btn-success:hover {
    background: #25e88b !important;
    color: #0f1311 !important;
}

[data-theme="dark"] .btn-secondary,
[data-theme="dark"] .btn-outline {
    color: #f2f6f3 !important;
    border-color: #3a463e !important;
}

[data-theme="dark"] .btn-secondary:hover,
[data-theme="dark"] .btn-outline:hover {
    background: #1f2922 !important;
    border-color: #f2f6f3 !important;
}

/* --- Dark mode forms --- */
[data-theme="dark"] input[type="text"],
[data-theme="dark"] input[type="email"],
[data-theme="dark"] input[type="password"],
[data-theme="dark"] input[type="url"],
[data-theme="dark"] input[type="number"],
[data-theme="dark"] input[type="search"],
[data-theme="dark"] textarea,
[data-theme="dark"] select,
[data-theme="dark"] .form-control,
[data-theme="dark"] .form-input {
    background: #182019 !important;
    color: #f2f6f3 !important;
    border-color: #29332c !important;
}

[data-theme="dark"] input:focus,
[data-theme="dark"] textarea:focus,
[data-theme="dark"] select:focus {
    border-color: #00d972 !important;
    box-shadow: 0 0 0 3px rgba(0, 217, 114, 0.15) !important;
}

[data-theme="dark"] ::placeholder {
    color: #98a69f !important;
}

[data-theme="dark"] label {
    color: #b5c2bb;
}

/* --- Dark mode alerts --- */
[data-theme="dark"] .alert {
    background: #182019 !important;
    border-color: #29332c !important;
    color: #f2f6f3 !important;
}

[data-theme="dark"] .alert-content span,
[data-theme="dark"] .alert-content {
    color: #f2f6f3 !important;
}

[data-theme="dark"] .alert-success { background: rgba(0, 217, 114, 0.08) !important; } /* real accent -- "success is resolved" (DESIGN.md), was Tailwind emerald */
[data-theme="dark"] .alert-error,
[data-theme="dark"] .alert-danger { background: rgba(248, 113, 113, 0.08) !important; }
[data-theme="dark"] .alert-warning { background: rgba(251, 191, 36, 0.08) !important; }
[data-theme="dark"] .alert-info { background: rgba(0, 217, 114, 0.08) !important; }

/* --- Dark mode tables --- */
[data-theme="dark"] table th {
    color: #98a69f;
    border-bottom-color: #29332c;
}

[data-theme="dark"] table td {
    border-bottom-color: #29332c;
    color: #f2f6f3;
}

[data-theme="dark"] table tr:hover td {
    background: rgba(0, 217, 114, 0.05);
}

/* --- Dark mode severity badges --- */
/* Dark ground uses DESIGN.md's severity TEXT companions, which exist because
   the flat severity colour fails 4.5:1 as small text on this ground. The tint
   behind them is the flat colour at 15%. The left border set above is not
   overridden here: it stays the flat product colour in both grounds. */
[data-theme="dark"] .severity-critical { background: rgba(229, 72, 77, 0.15) !important; color: #f87171 !important; }
[data-theme="dark"] .severity-high { background: rgba(240, 152, 58, 0.15) !important; color: #ffc98f !important; }
[data-theme="dark"] .severity-medium { background: rgba(232, 195, 61, 0.15) !important; color: #f5dd8a !important; }
[data-theme="dark"] .severity-low { background: rgba(76, 141, 246, 0.15) !important; color: #93c5fd !important; }
[data-theme="dark"] .severity-info { background: rgba(148, 163, 184, 0.15) !important; color: #94a3b8 !important; }

/* --- Dark mode modals --- */
[data-theme="dark"] .modal-content,
[data-theme="dark"] .modal-dialog {
    background: #182019 !important;
    border-color: #29332c !important;
}

[data-theme="dark"] .modal-overlay,
[data-theme="dark"] .modal-backdrop {
    background: rgba(0, 0, 0, 0.6) !important;
}

/* --- Dark mode scrollbars --- */
[data-theme="dark"] ::-webkit-scrollbar-track {
    background: #0f1311;
}

[data-theme="dark"] ::-webkit-scrollbar-thumb {
    background: #3a463e;
}

/* --- Dark mode footer --- */
[data-theme="dark"] .site-footer {
    background: #0f1311 !important;
    border-top-color: #29332c !important;
}

[data-theme="dark"] .site-footer a {
    color: #98a69f !important;
}

[data-theme="dark"] .footer-copyright {
    color: #98a69f !important;
}

/* --- Dark mode cookie notice --- */
[data-theme="dark"] .cookie-notice {
    background: #182019 !important;
    border-top-color: #29332c !important;
}

[data-theme="dark"] .cookie-notice p {
    color: #b5c2bb !important;
}

/* --- Dark mode auth pages --- */
[data-theme="dark"] .auth-card,
[data-theme="dark"] .login-card,
[data-theme="dark"] .register-card {
    background: #182019 !important;
    border-color: #29332c !important;
}

[data-theme="dark"] .auth-form h2,
[data-theme="dark"] .auth-card h2 {
    color: #f2f6f3 !important;
}

[data-theme="dark"] .auth-form p,
[data-theme="dark"] .auth-card p {
    color: #b5c2bb !important;
}

[data-theme="dark"] .google-btn,
[data-theme="dark"] .oauth-btn {
    background: #1f2922 !important;
    color: #f2f6f3 !important;
    border-color: #3a463e !important;
}

/* --- Dark mode code blocks --- */
[data-theme="dark"] code,
[data-theme="dark"] pre,
[data-theme="dark"] .code-block {
    background: #141a16 !important;
    border-color: #29332c !important;
    color: #f2f6f3 !important;
}

/* --- Dark mode links --- */
/* Accent colour for real content links only.
   `[data-theme="dark"] a` (attribute + element) outranked EVERYTHING, including
   `.sidebar-nav .nav-item` -- every sidebar item is a real, non-button link, so
   every sidebar item rendered green at once instead of just the active one.
   It also outranked links STYLED AS A BUTTON: the Report link in Continuous
   Monitoring rendered accent-coloured text on an accent background, contrast 1.00,
   literally invisible.
   Fix by scoping the SELECTOR to where real content links live (`.main-content`,
   plus `.nav-links` for the logged-out navbar Login link, the one navbar link
   with no dedicated colour rule of its own) instead of piling on another
   one-off `:not()` exclusion for chrome. The sidebar sits outside
   `.main-content` as a structural sibling (see base.html), so it is naturally
   out of scope now, no exclusion needed. Keep the button exclusion, still
   needed inside `.main-content` for button-styled links, and the two prior
   tab exclusions as harmless safety nets. */
[data-theme="dark"] .main-content a:not([class*="btn"]):not([class*="button"]):not(.mon-tab):not(.ha-tab),
[data-theme="dark"] .nav-links a:not([class*="btn"]):not([class*="button"]) {
    color: #00d972;
}

[data-theme="dark"] .main-content a:not([class*="btn"]):not([class*="button"]):not(.mon-tab):not(.ha-tab):hover,
[data-theme="dark"] .nav-links a:not([class*="btn"]):not([class*="button"]):hover {
    color: #25e88b;
}

/* --- Dark mode section headers --- */
[data-theme="dark"] .section-title-modern,
[data-theme="dark"] .page-title,
[data-theme="dark"] .page-title-text,
[data-theme="dark"] .section-header h2,
[data-theme="dark"] .dashboard-title {
    -webkit-text-fill-color: #f2f6f3 !important;
    color: #f2f6f3 !important;
}

/* --- Dark mode gradient text --- */
[data-theme="dark"] .gradient-text,
[data-theme="dark"] .text-gradient,
[data-theme="dark"] [class*="gradient-text"] {
    -webkit-text-fill-color: #00d972 !important;
    color: #00d972 !important;
}

/* --- Dark mode page header --- */
[data-theme="dark"] .page-header,
[data-theme="dark"] .content-header {
    background: #0f1311 !important;
    border-bottom-color: #29332c !important;
}

/* --- Dark mode upgrade prompts --- */
[data-theme="dark"] .upgrade-card,
[data-theme="dark"] .upgrade-prompt,
[data-theme="dark"] .upgrade-banner,
[data-theme="dark"] [class*="upgrade-"]:not(.upgrade-btn):not(.upgrade-cta-btn):not(.upgrade-primary-btn):not(.upgrade-icon):not(.upgrade-badge):not(.upgrade-feature-icon):not(.upgrade-progress-fill):not(.upgrade-title):not(.upgrade-subtitle) {
    background: #182019 !important;
    border-color: #29332c !important;
}

[data-theme="dark"] .upgrade-banner h3 {
    color: #f2f6f3 !important;
}

[data-theme="dark"] .upgrade-banner p {
    color: #b5c2bb !important;
}

/* --- Dark mode skeleton loaders --- */
[data-theme="dark"] .skeleton-loading {
    background: #141a16 !important;
}

/* --- Dark mode ::selection --- */
[data-theme="dark"] ::selection {
    background: rgba(0, 217, 114, 0.25);
    color: #f2f6f3;
    /* Same amputated-glyph fix as the base ::selection rule: reset the
       gradient headings' transparent text-fill so selected letters stay whole. */
    -webkit-text-fill-color: #f2f6f3;
}

/* --- Dark mode survey modal --- */
[data-theme="dark"] .survey-header,
[data-theme="dark"] .survey-modal-header {
    background: #00d972 !important;
    color: #0f1311 !important;
}

/* --- Dark mode notification header --- */
[data-theme="dark"] .notification-header,
[data-theme="dark"] .notification-modal-header {
    background: #00d972 !important;
    color: #0f1311 !important;
}

/* --- Dark mode settings --- */
[data-theme="dark"] .settings-section-title,
[data-theme="dark"] .settings-tab.active,
[data-theme="dark"] .settings-nav-item.active {
    color: #00d972 !important;
}

/* =============================================================================
   SIMPLE / EXPERT MODE TOGGLE (2026-08-11)
   Quick-access segmented control in the navbar. No new accent color --
   reuses --accent, the same green already driving plan-badge.
   (Theme toggle removed 2026-09-03: the site ships a single dark theme.)
   ============================================================================= */
/* Leading "View" label (2026-09-09): makes the segmented control read as a
   deliberate control users can act on, not decoration, so it gets noticed. */
.mode-toggle-label {
    font-size: 0.66rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-tertiary, #8a8f98);
    margin-right: 2px;
    user-select: none;
}

.mode-toggle-group {
    display: flex;
    align-items: center;
    border: 1.5px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    padding: 3px;
    gap: 2px;
    /* FIX (2026-09-09): was a borderless pill that blended into the header.
       Filled track + a faint brand-green halo (single accent, no 2nd green)
       so the eye catches it. */
    background: var(--bg-secondary);
    box-shadow: 0 0 0 3px rgba(0, 217, 114, 0.10);
}

.mode-toggle-btn {
    background: none;
    border: none;
    cursor: pointer;
    padding: 0.4rem 0.8rem;
    min-height: 34px;
    border-radius: calc(var(--radius-sm) - 2px);
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--text-secondary);
    transition: all 0.18s ease;
}

.mode-toggle-btn:hover:not(.active) {
    color: var(--accent-text);
    background: rgba(0, 217, 114, 0.08);
}

.mode-toggle-btn.active {
    background: var(--accent);
    /* WCAG 1.4.3 AA: near-black on #00d972 (10.5:1), same fix already
       applied to .user-avatar-modern above. */
    color: #0a0a14;
    box-shadow: 0 1px 6px rgba(0, 217, 114, 0.35);
}

.mode-toggle-btn:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

@media (max-width: 900px) {
    /* Header toggle collapses under 900px; the sidebar copy takes over. */
    .navbar-end .mode-toggle-group,
    .navbar-end .mode-toggle-label { display: none; }
}

/* Mobile Simple/Expert toggle inside the sidebar (2026-09-24 responsive sweep).
   Hidden on desktop (>900px), where the header toggle is the control; shown
   under 900px, re-enabling the group/label that the rule above would otherwise
   hide. Sits in the pinned sidebar footer so it never scrolls out of reach. */
.sidebar-mode-toggle-wrap {
    display: none;
    align-items: center;
    gap: 8px;
    padding: 0.85rem 1.25rem calc(0.85rem + env(safe-area-inset-bottom, 0px));
}
@media (max-width: 900px) {
    .sidebar-mode-toggle-wrap { display: flex; }
    .sidebar-mode-toggle-wrap .mode-toggle-group { display: flex; }
    .sidebar-mode-toggle-wrap .mode-toggle-label { display: inline; }
}

/* Stronger active state in the burger/off-canvas sidebar (2026-09-24): the
   tonal accent-medium tint is legible on desktop but too faint to read as
   "you are here" on a phone. Add a clear left accent bar + firmer tint, scoped
   to <=768px so the desktop rail (per DESIGN.md, no rail) is untouched. */
@media (max-width: 768px) {
    .sidebar-nav .nav-item.active {
        box-shadow: inset 3px 0 0 0 var(--accent) !important;
        background: rgba(0, 217, 114, 0.16) !important;
    }
}

/* Notification bell was easy to miss on the crowded mobile navbar (2026-09-24):
   its resting color is --text-secondary. Lift it to primary under 640px so the
   bell reads clearly, and make the unread badge pop a touch more. Desktop keeps
   the quieter resting state. */
@media (max-width: 640px) {
    .navbar-end .notification-bell {
        color: var(--text-primary) !important;
        font-size: 1.15rem;
    }
    .navbar-end .notification-badge {
        box-shadow: 0 0 0 2px #0f172a;
    }
}

/* Simple/Expert per-surface view filter (2026-08-11). Used on dashboard.html,
   analysis_vulnerabilities.html, vulnerability_lifecycle.html, new_analysis.html.
   !important beats any inline style JS later sets on the same element (eg.
   dashboard.js flipping #vulnerabilityHeatmap to display:grid once it has
   data) -- elements stay in the DOM in both modes so existing JS never hits
   a null querySelector, only their visibility changes. */
body[data-ui-mode="expert"] .simple-only { display: none !important; }
body[data-ui-mode="simple"] .expert-only { display: none !important; }

/* =============================================================================
   UNIFIED BUTTON SYSTEM (v4)
   Replaces scattered inline styles and conflicting .btn definitions.
   Hierarchy: ts-btn-primary > ts-btn-secondary > ts-btn-ghost > ts-btn-danger
   ============================================================================= */

/* Base button reset */
.ts-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.625rem 1rem;
    border-radius: 8px;
    font-family: var(--font-body);
    font-size: 0.875rem;
    font-weight: 700; /* 2026-09-27: narvy.io .btn weight, one button across site and app */
    line-height: 1.4;
    border: none;
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
    -webkit-font-smoothing: antialiased;
}
.ts-btn:focus-visible {
    outline: 2px solid var(--accent, #00d972);
    outline-offset: 2px;
}

.ts-btn:disabled,
.ts-btn.disabled {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}

/* ---- PRIMARY: Main CTA on each page ---- */
/* Dark text on bright green -- high contrast, not the old white-on-green */
.ts-btn-primary {
    background: var(--accent, #00d972);
    color: #0c0c0d;
    box-shadow: none;
}

.ts-btn-primary:hover {
    background: #25e88b; /* DESIGN.md's documented hover step, was a 3rd undocumented green */
    color: #0c0c0d;
}

/* Large variant for main wizard CTAs */
.ts-btn-primary.ts-btn-lg {
    padding: 0.875rem 2rem;
    font-size: 1rem;
    border-radius: 8px; /* DESIGN.md buttons step, was 10px */
}

/* ---- SECONDARY: Back, Cancel, Filter ---- */
.ts-btn-secondary {
    background: var(--bg-secondary, #f5f4f0);
    color: var(--text-primary, #0c0c0d);
    border: 1px solid var(--border-subtle, #e8e6e1);
}

.ts-btn-secondary:hover {
    background: var(--border-subtle, #e8e6e1);
    border-color: var(--border-strong, #d5d3ce);
}

/* ---- GHOST: Tertiary links-as-buttons ---- */
.ts-btn-ghost {
    background: transparent;
    color: var(--accent-text, #007e40); /* DESIGN.md Resolved on Paper, fallback was a near-duplicate */
    border: none;
    padding: 0.5rem 0.75rem;
}

.ts-btn-ghost:hover {
    background: var(--accent-dim, rgba(0, 217, 114, 0.08));
}

/* ---- DANGER: Delete, Remove ---- */
.ts-btn-danger {
    /* 2026-08-14: was #ef4444, which is 3.76:1 against its own white label and
       fails WCAG AA. Darkened to the product crit hue at 4.51:1. A destructive
       button is the last place an unreadable label is acceptable. */
    background: #e12f35;
    color: #ffffff;
}

.ts-btn-danger:hover {
    background: #c92a30;
}

/* ---- ACCENT: was an indigo gradient (a second brand colour). 2026-09-27:
   it renders as the secondary outline button, DESIGN.md has no indigo. ---- */
.ts-btn-accent {
    background: transparent;
    color: var(--text-primary);
    border: 1px solid var(--border-strong);
}

.ts-btn-accent:hover {
    background: var(--surface-elevated);
}

/* ---- Dark theme overrides ---- */
[data-theme="dark"] .ts-btn-primary {
    background: var(--accent, #00d972);
    color: #03170d; /* Earned Ink Rule: resolved-ink, was a near-duplicate */
}

[data-theme="dark"] .ts-btn-primary:hover {
    background: #25e88b; /* DESIGN.md's documented hover step, was a 4th undocumented green */
    color: #03170d;
}

/* Secondary = narvy.io .btn-ghost: transparent with a hairline, ink text. */
[data-theme="dark"] .ts-btn-secondary {
    background: transparent;
    color: var(--text-primary, #f2f6f3);
    border: 1px solid var(--border-strong, #3a463e);
}

[data-theme="dark"] .ts-btn-secondary:hover {
    background: var(--surface-elevated, #1f2922);
    border-color: var(--text-secondary, #b5c2bb);
}

/* ---- Wizard step circle (active) override ---- */
/* Replace white-on-#00d972 circles with dark-on-accent */
.step-circle.active,
.wizard-step-circle-active {
    background: var(--accent, #00d972) !important;
    color: #0c0c0d !important;
    border-color: var(--accent, #00d972) !important;
}

/* ---- Inline #00d972 button override ----
   Catches buttons that still use inline background: #00d972; color: white
   by targeting common patterns. These should be migrated to .ts-btn-primary. */
button[style*="background: #00d972"][style*="color: white"],
button[style*="background:#00d972"][style*="color: white"],
button[style*="background:#00d972"][style*="color:white"] {
    background: var(--accent, #00d972) !important;
    color: #0c0c0d !important;
}

/* =============================================================================
   SHARED APP-OVERVIEW GRID ("which apps need attention")
   Moved here from vulnerabilities.html (2026-08-11, Fable product review):
   dashboard.html's per-app cards and vulnerabilities.html's #simpleAppOverview
   / #expertAppOverview grid now render the SAME data (both fetch
   /api/vulnerabilities/overview, backed by the single
   get_per_app_vulnerability_overview() in website/vulnerability_processor.py
   -- see its docstring for the critical/attention/clean threshold decision).
   Sharing the CSS classes here, not just the data, is what guarantees zero
   visual drift between the two pages' color coding.

   Bare class selectors (not container-scoped) on purpose: both consuming
   pages define --surface/--border-subtle/--text-primary/--text-secondary/
   --text-tertiary/--accent/--accent-text/--border-strong with identical
   values on their own page-root wrapper (.vuln-mgmt-container,
   .dashboard-container), so these rules render identically on both without
   needing a shared wrapper class. Status dot colors are the product's real
   severity/resolved tokens only, never invented: red = has a critical
   finding, orange = has an open finding but no critical, green = no open
   findings.
   ============================================================================= */
.app-overview-heading {
  color: var(--text-primary); font-size: 1rem; font-weight: 700; margin: 0 0 0.75rem;
}
.app-overview-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 0.65rem;
  margin-bottom: 1.5rem;
}
.app-overview-grid.compact { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 0.5rem; }
.app-overview-card {
  display: flex; flex-direction: column; gap: 0.55rem;
  background: var(--surface); border: 1px solid var(--border-subtle); border-radius: 2px;
  padding: 0.85rem 1rem; cursor: pointer; text-align: left;
  font-family: inherit; color: inherit; width: 100%;
  /* This class was authored for a <button> (vulnerabilities.html) and is also
     used on an <a> (dashboard.html "Your apps"). No stylesheet loaded on the
     dashboard resets anchor decoration, so the whole tile, app name, severity
     counts and the open-findings line, rendered underlined. */
  text-decoration: none;
  transition: border-color 0.15s ease;
}
.app-overview-grid.compact .app-overview-card { padding: 0.6rem 0.75rem; gap: 0.35rem; }
.app-overview-card:hover { border-color: var(--border-strong); }
.app-overview-card:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.aoc-top { display: flex; align-items: center; gap: 0.5rem; min-width: 0; }
.aoc-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.aoc-dot.critical { background: #e5484d; box-shadow: 0 0 0 3px rgba(229,72,77,0.18); }
.aoc-dot.attention { background: #f0983a; box-shadow: 0 0 0 3px rgba(240,152,58,0.18); }
.aoc-dot.clean { background: #00d972; box-shadow: 0 0 0 3px rgba(0,217,114,0.18); }
.aoc-name {
  font-weight: 700; font-size: 0.92rem; color: var(--text-primary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0;
}
.aoc-platform { font-size: 0.78rem; color: var(--text-tertiary); text-transform: uppercase; letter-spacing: 0.04em; flex-shrink: 0; }
.aoc-counts { display: flex; gap: 0.75rem; flex-wrap: wrap; font-size: 0.8rem; color: var(--text-secondary); }
.aoc-counts .n { font-family: var(--font-mono); font-weight: 700; margin-right: 0.25rem; }
.aoc-counts .n.crit { color: #f87171; }
.aoc-counts .n.high { color: #ffc98f; }
.aoc-counts .n.med { color: #f5dd8a; }
.aoc-counts .n.low { color: #93c5fd; }
.aoc-total { font-size: 0.8rem; color: var(--text-secondary); }
.aoc-total.clean { color: var(--accent-text); display: flex; align-items: center; gap: 0.35rem; }

/* dashboard.html-only: "View all N apps" link below the capped grid, and the
   one contextual "see what needs fixing" / consultation-CTA footer that
   replaced the old per-card repeated CTA (2026-08-11). */
.app-overview-viewall {
  display: block; margin: -0.5rem 0 1.25rem; font-size: 0.85rem;
  color: var(--accent-text); text-decoration: none; font-weight: 600;
}
.app-overview-viewall:hover { text-decoration: underline; }
.app-overview-footer {
  background: var(--surface); border-radius: 2px; padding: 1.25rem 1.5rem;
  margin-bottom: 1.5rem; border: 1px solid var(--border-subtle);
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
}
.app-overview-footer .aof-consult {
  color: var(--text-secondary); font-size: 0.9rem; margin: 0;
}
.app-overview-footer .aof-consult strong { color: var(--text-primary); }

/* =============================================================================
   REDUCED MOTION
   2026-08-14. This stylesheet had zero prefers-reduced-motion handling across
   2657 lines, so a user with the OS setting on still got everything.

   Deliberately NOT the blanket `* { animation-duration: 0.01ms }` kill. This
   file uses motion for exactly one piece of meaning: `.status-dot.active` and
   `.live-indicator` pulse to say "live". Killing that outright would delete
   the signal, not calm it, so the ring stops moving and becomes a static halo
   instead. State survives; the movement does not.

   Transitions are collapsed rather than removed: a hover or focus change still
   lands instantly and stays visible, it just no longer travels. The two
   transform transitions in this file (the New Scan chevron, the icon button)
   are neutralised at the transform itself so nothing slides, even instantly.
   ============================================================================= */
@media (prefers-reduced-motion: reduce) {
    .status-dot.active,
    .live-indicator {
        animation: none !important;
        box-shadow: 0 0 0 4px rgba(0, 217, 114, 0.22) !important;
    }

    *,
    *::before,
    *::after {
        transition-duration: 0.001ms !important;
        transition-delay: 0ms !important;
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
    }

    html {
        scroll-behavior: auto !important;
    }

    .navbar-new-scan-arrow,
    .navbar-new-scan-btn:hover .navbar-new-scan-arrow {
        transform: none !important;
    }
}
