/* ==========================================================================
   Typography System - IBM Plex Sans + IBM Plex Mono
   ==========================================================================

   Font Weights:
   - 400 (Regular): Body text, paragraphs
   - 500 (Medium):  UI labels, navigation, captions
   - 600 (SemiBold): Buttons, subheadings (h3, h4), emphasis
   - 700 (Bold):    Main headings (h1, h2), strong emphasis

   Font Families:
   - IBM Plex Sans: Primary UI font (professional, technical)
   - IBM Plex Mono: Display numbers, code, monospace
   ========================================================================== */

/* ==========================================================================
   Design Tokens
   ==========================================================================
   The canonical palette and design-token declarations live in /css/tokens.css
   (loaded first in the cascade). All colour, shadow, radius, and spacing
   tokens are defined there; this file only consumes them via var(--name).
   ========================================================================== */

/* ==========================================================================
   Vue pre-mount cloak
   ==========================================================================
   `v-cloak` is a GLOBAL Vue concern, not a per-component one, so the rule that
   gives it meaning has to be in <head> — i.e. resolved before the browser can
   paint any Vue root's raw markup. It used to live in file_manager.css, which
   head.php does not link: that stylesheet is emitted by
   src/components/file_manager/_config.php via AppFrameSlots::setAfterFrame(),
   ~34 KB of markup AFTER `id="fileTransferApp"`. The browser therefore painted
   the uncompiled `{{ }}`/`v-if` template first and hid it only once the late
   <link> arrived — a visible flash of raw markup on every domain-page load
   (cortex-ymn5ip5). Keep this rule in a head-loaded stylesheet.

   `!important` is load-bearing, not decoration. When framed, the Vue root IS
   the app card: domain_app_frame.php renders
   `<div class="ev-card" id="fileTransferApp" v-cloak>`. `[v-cloak]` and
   `.ev-card` have identical (0,1,0) specificity, and evident.css `.ev-card`
   sets `display: flex`, so order alone decides. This bundle happens to load
   after Evident today, but per-module head includes load after it (head.php
   emits modules/<m>/includes/head.php last — and the development module's
   head_ui_components.php already links file_manager.css there). A cloak that
   any later equal-specificity rule can defeat is a cloak that silently stops
   working; the whole point is "must not be visible", so state it absolutely.
   ========================================================================== */

[v-cloak] { display: none !important; }

/* ==========================================================================
   THE BENCH — canvas tone + pinstripe + tooth + ambient swoop
   ==========================================================================
   Ported from the canonical Evident study v16 (study/index.html:1938-2039).
   The canvas is the ENVIRONMENT: the un-worked bench that the molded and
   machined processes both act upon. It is NOT a flat fill.

   Four layers, top first:
     1. ambient swoop  — body::after,  a fixed composited luminance sweep
     2. material tooth — body::before, a fixed ~180px irregular field
     3. ink pinstripe  — 1px on a 3px pitch, below
     4. lit companion  — half-pitch offset, so the pitch reads MILLED
   over the flat canvas tone (--color-bg).

   Values live in tokens.css; do not inline them here.
   ========================================================================== */

body {
    font-family: 'IBM Plex Sans', sans-serif;
    background:
        repeating-linear-gradient(90deg,
            var(--cc-canvas-stripe) 0px,
            var(--cc-canvas-stripe) 1px,
            transparent 1px,
            transparent 3px),
        repeating-linear-gradient(90deg,
            transparent 0px,
            transparent 1px,
            var(--cc-canvas-lite) 1px,
            var(--cc-canvas-lite) 2px,
            transparent 2px,
            transparent 3px),
        var(--color-bg);
    /* PERF, carried verbatim from the study (:1999-2011). This must NOT become
       `fixed`: a background-attachment:fixed layer on <body> forces the
       compositor to re-rasterise a full-viewport gradient on every scroll
       frame, and it is the one construct the study flags as a macOS Safari
       risk. The swoop still needs to be viewport-anchored — it is environment
       light, not page texture — so it lives on the already-fixed pseudo-element
       below, which composites once and costs nothing per frame. */
    background-attachment: scroll, scroll, scroll;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* The tooth: an inline feTurbulence field as a fixed full-viewport underlay,
   so its alpha is theme-controlled by --cc-canvas-tooth rather than baked into
   the data URI. baseFrequency 0.9 = fine tooth. The fractal is desaturated by
   feColorMatrix saturate 0, so every pixel it contributes has R = G = B and
   Invariant 7 survives a texture that would otherwise introduce chroma.

   ~180px and aperiodic against a 3px regular pitch — two orders of magnitude
   apart, so the two textures cannot form a beat pattern. That gap is the whole
   reason grain is legal on the bench and illegal on a carve floor.

   :not([style*="background-image"]) — NOT cosmetic. The cover-image feature
   below already owns body::before/::after, and a user with a cover image set
   would otherwise have BOTH rules match: the attribute selector wins the
   conflicting properties, but `opacity: var(--cc-canvas-tooth)` has no
   counterpart in that rule and would leak through, rendering their cover image
   at 3% opacity. Mutually exclusive selectors, not cascade order, is what makes
   this safe. A page with a cover image has no visible bench anyway. */
body:not([style*="background-image"])::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: -2;
    pointer-events: none;
    opacity: var(--cc-canvas-tooth);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
    background-size: 180px 180px;
}

/* The ambient swoop: the environment light. Pure luminance — the accent
   whisper the study carried in v4 was removed with the rest of the colour, so
   even the atmosphere is achromatic. Reuses --ev-swoop-angle, which the trunk
   already declares for molded faces; the study uses one angle for both.

   Negative z-index rather than the study's `z-index: 0` + `.chrome/.page
   { z-index: 1 }` contract: CC has no single guaranteed page wrapper to hang
   that on. A negative-z-index pseudo-element paints above its parent's
   background and below its parent's content, which is exactly this position,
   and needs no cooperation from any content selector. Both bench layers are
   position:fixed, so they need no positioned ancestor; body is static here
   (the position:relative rule below applies only to the cover-image case) and
   carries z-index:auto either way, so it creates no stacking context and the
   negative layers resolve against the root as intended. */
body:not([style*="background-image"])::after {
    content: '';
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background-image:
        linear-gradient(var(--ev-swoop-angle),
            var(--ev-amb-hi)   0%,
            transparent       58%,
            var(--ev-amb-lo) 100%);
}

/* A bare `.form-control:focus, .form-select:focus, .form-check-input:focus`
   block was here, painting `box-shadow: 0 0 0 0.25rem var(--color-focus-ring)`.
   It was pre-Evident intent ("brand primary instead of Bootstrap blue") that
   outlived the port: this file loads at head.php:124, AFTER
   evident-bootstrap.css at :113, at identical (0,2,0) specificity — so it beat
   the adapter's own focus rules outright. Because box-shadow is REPLACED and
   not extended, it erased the pocket's four-part carve stack the instant a
   field took focus and put back exactly the 0.25rem coloured halo Invariant L4
   forbids. The adapter already carves all three arms
   (evident-bootstrap.css:893 for control/select, :937 for check-input),
   stepping the pocket LIP up a rank with a thin --ev-accent-edge inset —
   an indicator on the lip, not a bloom. Deleted rather than overridden; the
   now-unreferenced --color-focus-ring alias went with it. (cortex-ovnfxcx) */

.accordion-body.bg-light {
    background-color: var(--surface) !important;
}

/* Background image styling - uses position:fixed pseudo-elements instead of
   background-attachment:fixed which is broken in Safari/iOS. */
body[style*="background-image"] {
    position: relative;
}

body[style*="background-image"]::before {
    content: '';
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    background-image: inherit;
    background-size: cover;
    background-position: center;
    pointer-events: none;
    z-index: -2;
}

body[style*="background-image"]::after {
    content: '';
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    /* Was the literal rgba(238, 238, 238, 0.35) — 238 is #eee, the OLD bench
       tone, hardcoded here and the only raw colour literal in this file
       (palette obligation cortex-nuq33jb). It would have gone visibly wrong
       the moment the bench moved to #c9c9c9. Tokenised while this pass is in
       these exact pseudo-elements anyway. */
    background-color: color-mix(in srgb, var(--color-bg) 35%, transparent);
    pointer-events: none;
    z-index: -1;
}
/* ==========================================================================
   Logged-out shell
   ==========================================================================
   Evident owns every material on this surface. This file only composes those
   materials into the standalone logged-out layout and retains brand/link
   behavior. The page canvas is .ev-pinstripe, the top housing is .ev-molded,
   and the login assembly is .ev-card with native pockets and keys. */

.login-body {
    position: relative;
    min-height: 100vh;
    overflow-x: hidden;
    color: var(--ev-ink);
}

/* The ornamental datum deliberately extends beyond the stage. Clip it at the
   page root as well as the body so it cannot widen the desktop scroll area. */
.cc-login-root {
    overflow-x: clip;
}

/* The login is a sparse marquee surface, so it gets one deliberate coloured
   light source. Material remains strictly achromatic: this layer is light
   falling across the page ground, never a coloured face. */
.login-body::before {
    position: fixed;
    inset: 5.625rem 0 0;
    z-index: 0;
    content: "";
    pointer-events: none;
    background:
        radial-gradient(
            circle at 68% 48%,
            rgba(var(--ev-accent-rgb), 0.14) 0,
            rgba(var(--ev-accent-rgb), 0.055) 20rem,
            transparent 42rem
        );
}

.login-navbar {
    position: relative;
    min-height: 5.625rem;
    padding-block: 0;
    z-index: 3;
    background: color-mix(in srgb, var(--ev-metal-hi) 82%, transparent);
    backdrop-filter: blur(18px) saturate(0.82);
}

.login-navbar__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ev-btn-pad-x-md);
}

.login-brand {
    display: inline-flex;
    align-items: center;
}

.login-brand__logo {
    display: block;
    width: auto;
}

.login-brand__logo--light {
    display: var(--login-brand-logo-light-display, block);
}

.login-brand__logo--dark {
    display: var(--login-brand-logo-dark-display, none);
}

.login-navbar__title {
    margin: 0;
    color: var(--ev-ink-dim);
    font: 500 0.875rem/1.3 var(--ev-font-sans);
    letter-spacing: 0.02em;
}

.login-title-action {
    color: var(--ev-ink);
}

.login-title-action::before {
    content: "\00b7";
    margin-inline: 0.45em;
    color: var(--ev-ink-faint);
    font-weight: 400;
}

.login-shell {
    position: relative;
    z-index: 1;
    display: grid;
    place-items: center;
    min-height: calc(100vh - 5.625rem);
    padding-block: clamp(3rem, 7vh, 6rem);
}

.login-stage {
    position: relative;
    display: grid;
    grid-template-columns: minmax(22rem, 1fr) minmax(26rem, 29rem);
    align-items: center;
    gap: clamp(4rem, 7vw, 7rem);
    width: min(100%, 70rem);
    isolation: isolate;
}

/* One large axial datum is scribed into the page ground behind the console.
   It is a single piece of ornament in the stock: no shadow, elevation, state,
   or category is implied by it. */
.login-stage::before {
    position: absolute;
    z-index: -1;
    content: "";
    pointer-events: none;
}

.login-stage::before {
    top: 50%;
    right: -12rem;
    width: clamp(38rem, 55vw, 56rem);
    aspect-ratio: 1;
    border: 1px solid var(--ev-rule-strong);
    border-radius: 50%;
    translate: 0 -50%;
    opacity: 0.58;
}

#signup-page {
    width: 100%;
}

.login-intro {
    position: relative;
    padding-left: clamp(1.5rem, 3vw, 2.75rem);
}

/* This accent line is a live indicator at indicator scale, not coloured
   material. It frames the complete welcome statement: heading and supporting
   copy, including when either wraps. */
.login-intro::before {
    position: absolute;
    top: 0.35rem;
    bottom: 0.2rem;
    left: 0;
    width: 2px;
    border-radius: var(--ev-radius-pill);
    content: "";
    background: var(--ev-accent);
    box-shadow: 0 0 18px rgba(var(--ev-accent-rgb), 0.55);
}

.login-heading {
    max-width: 15.5ch;
    margin: 0;
    font-size: clamp(3.25rem, 4.3vw, 4.35rem);
    line-height: 0.98;
    letter-spacing: -0.04em;
    text-wrap: balance;
}

.login-intro-copy {
    max-width: 31rem;
    margin: 1.4rem 0 0;
    color: var(--ev-ink-dim);
    font: 450 clamp(1rem, 1.2vw, 1.125rem)/1.55 var(--ev-font-sans);
    text-wrap: balance;
}

.login-console {
    position: relative;
    width: 100%;
}

.login-console::after {
    position: absolute;
    inset: -5rem;
    z-index: -2;
    content: "";
    pointer-events: none;
    background: radial-gradient(
        ellipse,
        rgba(var(--ev-accent-rgb), 0.09),
        transparent 66%
    );
}

/* Signup still shares the logged-out wrapper while its feature-gated form is
   migrated separately. Preserve its existing lead role without painting a
   second material language. */
.login-lead {
    color: var(--ev-ink);
}

.login-error-message {
    margin-bottom: 1rem;
}

/* Wrong credentials are ordinary retry state, not a service fault. Seat the
   unchanged non-leaky message in one quiet, achromatic Evident cut: the form
   remains the focal material and red stays reserved for genuine system/session
   failures. The welcome hero is deliberately untouched, matching success. */
.login-credential-notice {
    padding: 0.9rem 1rem;
    color: var(--ev-ink);
}

.login-credential-notice__message {
    font-weight: 550;
}

.login-credential-notice .login-error-help {
    color: var(--ev-ink-dim);
}

.login-card {
    width: 100%;
}

/* The swoop is a finish layer. Keep the real form content above that layer
   without changing the library component's paint. */
.login-card > * {
    position: relative;
    z-index: 1;
}

.login-card__footer {
    display: grid;
    gap: 0.75rem;
}

.login-field + .login-field {
    margin-top: 1.25rem;
}

.login-field .ev-caption {
    display: block;
    margin-bottom: 0.5rem;
}

.login-reason {
    margin: 0 0 1.25rem;
}

.login-submit,
.login-dev-key {
    width: 100%;
}

.login-recovery-link {
    margin: 0;
    text-align: center;
}

.login-service-rail {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    margin-top: 1.25rem;
    border-top: 1px solid var(--ev-rule);
}

.login-service-link {
    display: grid;
    gap: 0.2rem;
    min-width: 0;
    padding: 0.95rem 1rem;
    text-decoration: none;
}

.login-service-link + .login-service-link {
    border-left: 1px solid var(--ev-rule);
}

.login-service-prompt {
    margin: 0;
    color: var(--ev-ink-dim);
}

.login-service-action {
    color: var(--ev-accent-text);
    font: 600 0.9375rem/1.35 var(--ev-font-sans);
}

.login-service-link:hover .login-service-action,
.login-service-link:focus .login-service-action {
    color: var(--ev-accent);
}

.login-service-rail--single {
    grid-template-columns: minmax(0, 1fr);
}

.login-body a:not(.ev-key) {
    color: var(--ev-accent-text);
}

.login-body a:not(.ev-key):hover,
.login-body a:not(.ev-key):focus {
    color: var(--ev-accent);
}

.login-body .dev-only {
    margin-top: 1.25rem;
}

.login-webmail {
    margin-top: 1.25rem;
}

@media (max-width: 991.98px) {
    .login-stage {
        grid-template-columns: minmax(0, 1fr);
        gap: 2rem;
        width: min(100%, 36rem);
    }

    .login-stage::before {
        right: 50%;
        translate: 50% -44%;
    }

    .login-intro {
        padding-left: 1.5rem;
    }

    .login-heading {
        max-width: 13ch;
        font-size: clamp(2.75rem, 8vw, 4.5rem);
    }
}

@media (max-width: 575.98px) {
    .login-navbar {
        min-height: 4.75rem;
    }

    .login-navbar__title {
        font-size: 0.75rem;
    }

    .login-title-action {
        display: none;
    }

    .login-shell {
        min-height: calc(100vh - 4.75rem);
        padding-block: 2.5rem 4rem;
    }

    .login-stage {
        gap: 1.5rem;
    }

    .login-stage::before,
    .login-console::after {
        display: none;
    }

    .login-intro {
        padding-left: 0;
    }

    .login-intro::before {
        display: none;
    }

    .login-heading {
        font-size: clamp(2.35rem, 12vw, 3.2rem);
        line-height: 1;
    }

    .login-service-rail {
        grid-template-columns: minmax(0, 1fr);
    }

    .login-service-link + .login-service-link {
        border-top: 1px solid var(--ev-rule);
        border-left: 0;
    }
}
code, pre, kbd, samp {
    font-family: var(--bs-font-monospace), monospace;
}

/* Override Bootstrap's text-warning with darker, more readable color */
.text-warning {
    color: var(--color-warning) !important;
}

.container-fluid-height {
    display: flex;
    flex-direction: column;
}

.row-fluid-height {
    flex: 1;
}

p {
    font-size: 0.9rem;
    line-height: 1.66;
    color: var(--color-text);
}

.lead {
    font-size: 0.95em;
    color: var(--color-primary-dark);
}

h1 {
    font-size: 1.667em;
    font-weight: 700;
}

h2 {
    font-size: 1.5em;
    font-weight: 700;
}

h3 {
    font-size: 1.4em;
    font-weight: 600;
}

h4 {
    font-size: 1.125em;
    font-weight: 600;
    color: var(--color-primary-dark);
}

a {
    transition: var(--transition-fast);
}

a:hover {
    transition: none;
}

/* Remove underlines from links in headings and cards - cleaner UI */
h1 a, h2 a, h3 a, h4 a, h5 a, h6 a,
.card a {
    text-decoration: none;
}

h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover,
.card a:hover:not(.btn) {
    text-decoration: none;
    color: var(--color-primary);
}

small {
    color: var(--color-text-muted);
    font-weight: 500;
}

/* The navigation is LAND — un-cut stock at the highest elevation, the product
   housing rather than a part placed on the page. The content area beside it is
   the pocket that was milled out of the same billet. That reading is what makes
   the active item's scoop legal: subtractive is always legal into any face.

   It is dark stock in BOTH themes (achromatic, so Invariant 7 holds) and so
   draws from the --ev-dark-* scope rather than the theme-following ladder.
   --ev-dark-metal-hi, not --ev-metal: in dark the floors sit ABOVE --ev-metal,
   so a cut into --ev-metal would render brighter than its own parent. See the
   dark material scope note in tokens.css.

   Opaque, not glass: no backdrop-filter on a dense scrolling surface, and no
   gradient or wash to compensate. The rim carries the separation.

   Edges: top, left and bottom sit at the viewport boundary — no material was
   removed there, so there is no edge to draw. Only the RIGHT side is a real
   arris (the content pocket begins there), and it gets the fine lit burr.

   The nav housing also sits above the page-header bar in the assembly. Its
   higher stacking rank keeps the bar's cast falloff on the content side of the
   right arris, so the bar reads as seated beneath the housing instead of
   painted across its edge. */
#nav {
    max-width: 260px;
    padding: 0;
    background: var(--ev-dark-metal-hi);
    height: 100vh;
    /* Internal scrolling is intentional; JS bottom-alignment conflicts with
       the viewport-height max and this overflow boundary. */
    max-height: 100vh;
    overflow-y: auto;
    z-index: 110; /* Above .page-header-bar (100), below mobile #nav-small (200) */
    position: sticky;
    top: 0;
    align-self: flex-start;
    box-shadow: none;
    border-right: 1px solid var(--ev-dark-edge-glow);
}


#nav-icon {
    margin: 28px 20px 20px;
}

#nav-icon span {
    color: var(--ev-dark-ink);
    margin-left: 12px;
    font-size: 1.125em;
    line-height: 36px;
    font-weight: 500;
}

#nav-icon img {
    margin-top: -5px;
}

#nav ul {
    list-style: none;
    padding: 0;
}

#nav ul li a {
    padding: 8px 24px;
    display: flex;
    align-items: center;
    color: var(--ev-dark-ink-dim);
    font-weight: 500;
    text-decoration: none;
    line-height: 1.4;
    font-size: 0.875em;
}

#nav ul li a .icon {
    flex-shrink: 0;
}

/* Unread marker on a nav tab (today: unread feedback status changes,
   cortex-u5pp1cb). Geometry only — the chip is a shipped .ev-badge and supplies
   its own face, ink and shadow stack, so nothing here touches material. It rides
   the flex row's free space to the trailing edge, which is why the label can be
   any length without the count moving. */
#nav ul li a .nav-badge {
    margin-left: auto;
    flex-shrink: 0;
}

#nav ul li a:hover {
    color: var(--ev-dark-ink);
}

/* The active item is a rank-1 scoop milled into the nav's land, open at the
   left edge (no radius there) so it reads as a channel cut in from the side.
   Monotonic ceiling, checked against the ACTUAL parent and not the brightest
   token in the theme: floor #1e1e1e (30) is darker than the nav land #272727
   (39), so the cut is genuinely below the face it was cut into. Rank-1 shading
   because this is the outermost carve on this surface — nothing is nested
   inside it, so nothing finer is needed. Axial: zero x/y on all three layers. */
#nav ul .active a {
    color: var(--ev-dark-ink);
    background-color: var(--ev-dark-floor-n1);
    box-shadow: var(--ev-dark-r1-line),
                var(--ev-dark-r1-lip),
                var(--ev-dark-r1-wall);
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
    margin-right: 12px;
}

/* Prevent content from pushing the layout wider than viewport.
   min-width: 0 overrides flexbox default of min-width: auto which
   prevents flex items from shrinking below their content size. */
#content {
    min-width: 0;
    overflow-wrap: break-word;
}

#content-wrapper {
    margin-bottom: var(--space-lg);
    padding: 0 var(--space-3xl);
    max-width: 1800px;
}

.content-wrapper-inner {
    padding: 0 16.667%;
}

.content-wrapper-fw {
    background-color: var(--color-white);
    padding: 80px;
    border-radius: var(--radius-md);
}

#nav-small {
    position: fixed;
    top: 0;
    left: 0;
    width: 52px;
    height: 52px;
    z-index: 200; /* Above sticky .page-header-bar (z-index: 100) */
    display: flex;
    align-items: center;
    justify-content: center;
    transition: left 0.2s ease-in-out;
}

/* Sits on the header bar and must read as the same continuous face, so it takes
   the bar's material token rather than a matched-by-hand copy. Legal placement:
   a raised key on a raised face. The token is theme-following, which is why the
   dark-theme override this rule used to need is gone. */
#nav-small button {
    background: var(--ev-metal-hi);
    width: 52px;
    height: 52px;
    border-radius: 0;
    border: none;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0;
    padding: 0;
}

#nav-small button .hamburger-box {
    transform: scale(0.6);
}

.hamburger:hover, .hamburger.is-active:hover {
    opacity: 1;
}

#nav-small button .hamburger-inner, #nav-small button .hamburger-inner:before, #nav-small button .hamburger-inner:after {
    background-color: var(--color-grey-700);
}

/* The mobile full-screen menu is the same dark stock as the nav it replaces —
   one piece of housing, not a translucent scrim over the page. */
#main-menu {
    background: var(--ev-dark-metal-hi);
    position: fixed;
    overflow: hidden;
    top: 0;
    width: 100%;
    bottom: 0;
    z-index: 10;
}

/* All three sit on dark stock (#nav-small carries only a button, no anchor),
   so they take the scope's ink rather than the theme-following --color-white. */
#main-menu a, #nav-small a, #nav-icon a {
    text-decoration: none;
    color: var(--ev-dark-ink);
}

#main-menu .icon {
    font-size: 300%;
    margin-right: 0;
}

#user-bar > span, [id="back-to-bar"] > span {
    color: var(--color-text-muted);
    font-size: 0.8em;
    font-weight: 500;
}

#user-bar strong {
    color: var(--color-primary);
    font-weight: 700;
    text-decoration: underline;
}

#user-bar a, [id="back-to-bar"] a {
    color: var(--color-primary);
    border: 2px solid var(--color-primary);
    border-radius: var(--radius-pill);
    font-weight: 600;
    display: inline-block;
    padding: 8px 16px;
    text-decoration: none;
    margin-left: 12px;
    transition: var(--transition-fast);
}

#user-bar a:hover {
    color: var(--color-primary-dark);
    border-color: var(--color-primary-dark);
    transition: none;
}

.navbar-nav .nav-link.nav-loading::after {
    content: '';
    position: absolute;
    bottom: -1px;
    left: 0;
    right: 0;
    height: 2px;
    background: var(--color-primary);
    border-radius: 1px 1px 0 0;
}

.navbar-nav .nav-link.nav-loading::after {
    opacity: 0.35;
}
.rounded-light h3 {
    margin-bottom: 32px;
}

/* Headings on a carve were embossed with a two-part text-shadow. Invariant 7
   is explicit: purist flat text, no embossed, debossed or shadowed glyphs.
   Ink is ink; it has no material and casts nothing. (cortex-vnt3p6m) */
.rounded-light h1,
.rounded-light h2,
.rounded-light h3,
.rounded-light h4 {
    text-shadow: none;
    color: var(--text-strong);
}

/* The profile hero carried a two-part debossed text-shadow — a -1px dark lift
   over a +1px light one, i.e. engraved glyphs. Invariant 7 is unconditional:
   purist flat text, no embossed, debossed or shadowed glyphs. Ink is ink; it
   has no material and casts nothing. The same treatment was already removed
   from carve headings by cortex-vnt3p6m; this was the surviving instance.
   Both offsets were also directional, breaching Invariant 6 on the way past.
   (cortex-mn5hkp8) */
.profile-hero h1,
.profile-hero h2,
.profile-hero h3,
.profile-hero p {
    text-shadow: none;
}

/* Buttons on a MOLDED (raised) face. A .rounded-white section is cast, not
   cut, so a button sitting on it is a raised key on raised material — legal
   under the nesting invariant, and the one place a key may sit.

   The depth shading is the study's outer molded pair: --ev-contact-N is the
   tight ring where the key meets the face, --ev-ambient-N the wide falloff.
   Both are zero-offset (Invariant 6); the four directional values that were
   here (0 2px 4px / 0 1px 2px, and their hover pair) are gone. They were the
   commonest offset shadow in the trunk and appeared TWICE in this file — see
   the duplicate block further down, which is now the single definition.

   Hover steps contact/ambient up one rank rather than translating the key:
   liveness is finish, and depth is rim — moving the element is neither.

   Active is a real press: the key goes DOWN into the material, so the outer
   depth shadow is dropped entirely and replaced with the rank-3 cut stack.
   The translateY(1px) it replaces was depicting a downward light direction
   on a surface lit axially. (cortex-mn5hkp8) */
.rounded-white .btn:not(.btn-link) {
    box-shadow:
        var(--ev-contact-1),
        var(--ev-ambient-1);
}

.rounded-white .btn:not(.btn-link):hover,
.rounded-white .btn:not(.btn-link).is-hover {
    box-shadow:
        var(--ev-contact-2),
        var(--ev-ambient-2);
}

.rounded-white .btn:not(.btn-link):active,
.rounded-white .btn:not(.btn-link).is-active {
    box-shadow:
        var(--ev-r3-line),
        var(--ev-r3-lip),
        var(--ev-r3-wall);
}

/* Buttons in btn-groups should not have individual shadows as they're on the
   same plane. The paired `backdrop-filter: none` reset is gone with the
   declaration it was resetting — a reset of nothing is dead weight. */
.rounded-white .btn-group .btn:not(.btn-link),
.rounded-white .btn-group .btn:not(.btn-link):hover,
.rounded-white .btn-group .btn:not(.btn-link):active {
    box-shadow: none;
}

.max-300 {
    max-width: 300px;
}

.max-700 {
    max-width: 700px;
}

.max-900 {
    max-width: 900px;
}

.max-1000 {
    max-width: 1000px;
}

/* Page header with optional actions aligned to baseline */
.page-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    margin-bottom: var(--space-lg);
    gap: var(--space-md);
}

.page-header h1 {
    margin-bottom: 0;
}

.page-header .lead {
    margin-bottom: 0;
    margin-top: var(--space-xs);
}

/* Bootstrap 5 removed form-group class - restore margin-bottom for legacy forms */
.form-group {
    margin-bottom: var(--space-md);
}

/* Search input with icon - always larger than standard inputs */
.search-input-wrapper {
    position: relative;
}

.search-input-wrapper .bi-search {
    position: absolute;
    left: 14px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--color-text-muted);
    pointer-events: none;
    font-size: 1.1em;
}

.search-input-wrapper input {
    padding: 0.75rem 1rem 0.75rem 42px;
    font-size: 1rem;
}

/* The domains view switch shares a toolbar with the deliberately-large search
   pocket above. Evident's largest segmented size is still one step shorter, so
   seat the switch in the same measured band without overriding its internals. */
.domains-toolbar .domains-view-selector {
    min-height: calc(1.4rem + 1.5rem);
}

.domains-toolbar .search-input-wrapper {
    min-width: 0;
}

/* Make form-selects next to search inputs the same height */
.search-input-wrapper ~ .form-select {
    padding: 0.75rem 2.25rem 0.75rem 1rem;
    font-size: 1rem;
}

/* The legacy copy-to-clipboard surface lived here: the pre-Evident value/field/
   truncate rules, the clipboard-button rule with its hover and copied states,
   and the floating "copied" tooltip. All deleted with their last consumer
   (cortex-9bfk1se). Evident ships the real component — see .ev-copyable and its
   __value / __copy / __feedback elements in evident.css.

   The retired class tokens are deliberately NOT spelled out here: a tombstone
   that names them keeps every future material census hitting this comment, and
   a census that cannot return zero stops being an invariant (cortex-q5hlxqc
   settled the same question by removing a token from a comment rather than
   teaching the scanner to skip comments). Run `git log -S` on this file to
   recover them. */

/* Buttons in floating containers (rounded-white) should float above the surface.
   The box-shadow declarations that were here duplicated the molded-key block
   earlier in this file verbatim, and being later they WON the cascade — so the
   ported stack above had no effect until they were removed. Only the stacking
   context is unique to this rule, so only that remains. (cortex-mn5hkp8) */
.rounded-white .btn:not(.btn-link) {
    position: relative;
    z-index: 1;
}

/* Clickable table rows */
.clickable-row {
    cursor: pointer;
}

/* Sortable table headers */
.sortable-header {
    user-select: none;
    transition: background-color var(--transition-fast);
}

.sortable-header:hover {
    background-color: var(--color-grey-200);
}

.sortable-header .sort-icon {
    font-size: 0.75em;
    vertical-align: middle;
}

.sortable-header.sort-asc .sort-icon,
.sortable-header.sort-desc .sort-icon {
    color: var(--color-primary);
}

/* Vertical alignment for all tables - ensures button cells align with text */
.table th,
.table td {
    vertical-align: middle;
}

table.rounded-white td, table.rounded-white th, table.rounded-white-each td {
    border-top: none;
}

table.rounded-white-each {
    border-collapse: separate;
    border-spacing: 0 10px;
}

table.rounded-white-each tr {
    background: var(--color-white);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    margin-bottom: 20px;
}

table.rounded-white-each td:first-child {
    border-radius: var(--radius-md) 0 0 var(--radius-md);
}

table.rounded-white-each td:last-child {
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
}
/* Gallery-only forced states mirror the vendored adapter's real pseudo states.
   Application markup must never use these aliases. */
.btn.is-hover {
    transition: none;
}

.btn.is-focus-visible {
    outline: 2px solid var(--ev-accent-edge);
    outline-offset: 2px;
}

.btn-group > .btn.is-focus-visible,
.btn-group-vertical > .btn.is-focus-visible {
    outline-offset: -2px;
    z-index: 4;
}

.btn-outline-primary.is-hover {
    background-color: var(--ev-accent);
    border-color: var(--ev-accent-edge);
    color: var(--ev-accent-ink);
}

/* THE NEUTRAL KEY IS THE ADAPTER'S, ENTIRELY. (cortex-ojqr4jy)

   Three local rules stood here — a rest face, a hover, and an `.active:hover`
   — and all three are deleted rather than retuned, because every one of them
   set `background-color` and `border` LITERALLY and so beat the adapter's
   `--bs-btn-*` remap at `evident-bootstrap.css` "THE NEUTRAL KEY".

   The rest rule was the founder-visible defect. It read

       border: 1px solid var(--bs-gray-400);
       background-color: rgba(0, 0, 0, 0.03);

   under a banner calling it a "subtle background tint", which is pre-Evident
   intent: Bootstrap's outline button has no face, so a 3% wash was how you
   hinted at one. Under Evident that is two breaches at once. A key is a RAISED
   CAST PART and a part you can see through is not a part — measured on
   /databases, "Skift databasekode" computed `rgba(0, 0, 0, 0.03)` while the
   adapter was correctly supplying an opaque `--bs-btn-bg: var(--ev-metal-hi)`
   (#ececec), so the page pinstripe read straight through the control. Pinstripe
   is page ground and chrome ONLY (cortex-yat5aad); it must never surface inside
   a control's face. And the 1px #ced4da ring is the signature defect by name —
   an edge drawn where no material was removed — which is exactly why the
   adapter sets `--bs-btn-border-width: 0` rather than a transparent border.

   The hover rule swapped the face to --bs-gray-100 and the rim to --bs-gray-500.
   A fill swap is the wrong CHANNEL: hover is FINISH (Invariant 4), and the
   adapter already carries it by stepping --ev-contact/--ev-ambient, the same
   way .btn-primary and .rounded-light .btn do. Nothing replaces this rule
   because nothing needs to.

   The `.active:hover` rule assumed a filled active state ("hover should darken,
   not lighten") that only existed while Bootstrap painted `.active` #6c757d.
   The adapter now resolves `--bs-btn-active-bg` to --ev-metal-hi, so the rule's
   premise is gone and all it did was turn a hovered selected key gray-700.

   The btn-group leg below loses `.btn-outline-secondary` for the same reason:
   `margin-left: -1px` exists to collapse two adjacent 1px borders, and the
   neutral key no longer has one, so on it the negative margin was pulling two
   borderless raised faces into a 1px overlap. .btn-outline-primary and
   .btn-outline-danger keep their 1px rim, so they keep the compensation. */

/* Fix double border in btn-group with outline buttons */
.btn-group > .btn-outline-primary:not(:first-child),
.btn-group > .btn-outline-danger:not(:first-child) {
    margin-left: -1px;
}

.btn-group > .btn-outline-secondary:hover,
.btn-group > .btn-outline-primary:hover,
.btn-group > .btn-outline-danger:hover {
    z-index: 1;
}

.btn-primary.is-hover {
    box-shadow:
        var(--ev-acc-shoulder-1),
        var(--ev-acc-shoulder-2),
        var(--ev-contact-2),
        var(--ev-ambient-1);
}

.btn-primary.is-active {
    box-shadow:
        var(--ev-r3-line),
        var(--ev-r3-lip),
        var(--ev-r3-wall);
}

/* Create/Add button style - consistent across the app */
.btn-create {
    position: relative;
}

.btn-create .bi-plus-lg {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5em;
    height: 1.5em;
    margin-left: -0.25rem;
    margin-right: 0.375rem;
    border-radius: 4px;
    background: rgba(255, 255, 255, 0.2);
    font-size: 0.9em;
}

.btn-create:hover .bi-plus-lg {
    background: rgba(255, 255, 255, 0.3);
}

#container.collapsing {
    height: 100%;
}

#container.collapse:not(.show) {
    display: flex;
}

@media only screen and (min-width: 960px) and (max-width: 1200px) {
    #nav {
        max-width: 220px;
    }

    #content-wrapper {
        padding: 0 40px;
    }
}

@media only screen and (max-width: 991px) {
    #nav {
        margin-left: 0;
        width: 260px;
        max-width: 260px;
        position: fixed;
        height: 100%;
        z-index: 150; /* Above sticky .page-header-bar (z-index: 100) */
        box-shadow: none;
        transform: translateX(-100%);
        /* Position is state, not decoration: it must change atomically with
           aria-expanded so a throttled transition cannot leave an announced
           open menu fully off-canvas. */
        transition: none;
    }

    #nav-icon span {
        font-size: 1em;
        line-height: 28px;
    }

    #nav-icon img {
        margin-top: -5px;
        width: 32px;
        height: 32px;
    }

    #container {
        height: 100%;
        margin-left: 0;
    }

    /* When menu is open, show the nav and shift content.
       Off-canvas is the one state where the nav genuinely IS a part floating
       over the page rather than land continuous with it, so an outer shadow is
       honest here. It uses the PAGE-theme ambient token, not the dark scope —
       the shadow falls on the page's material, not on the nav's. */
    #container.nav-open #nav {
        transform: translateX(0);
        box-shadow: var(--ev-ambient-2);
    }

    #container.nav-open #nav-small {
        left: 208px; /* 260px nav width - 52px button width */
    }

    #container.nav-open #nav-small button {
        background: transparent;
        border: none;
    }

    #container.nav-open #nav-small button .hamburger-inner,
    #container.nav-open #nav-small button .hamburger-inner:before,
    #container.nav-open #nav-small button .hamburger-inner:after {
        background-color: rgba(255, 255, 255, 0.7);
    }

    #content-wrapper {
        padding: 0 16px; /* Symmetric padding - hamburger overlays content */
    }

    .content-wrapper-fw {
        padding: 24px;
    }
}

/* Very small screens: reduce left padding since hamburger floats above content */
@media only screen and (max-width: 575px) {
    #content-wrapper {
        padding: 0 12px 0 12px;
    }

    .content-wrapper-fw {
        padding: 16px;
    }
}
/* ==========================================================================
   Component: Page Header Bar (top nav with breadcrumbs + user)
   ========================================================================== */

/* MOLDED HOUSING, not a card and not a carve. Resolved deliberately, because the
   bar hosts the user pill and a raised key may only sit on a raised face — a
   carved bar would make the pill illegal. It is also physically over the page:
   fixed, with content scrolling beneath it. So it is cast material at the
   highest elevation, and it gets the molded vocabulary: no cut edge, an outer
   axial shadow, opaque face.

   The border-bottom is deleted rather than restyled. A molded piece has no
   arris — it rolls over — and nothing was cut along that line, so a drawn edge
   there is the signature defect of this language. The contact + ambient falloff
   carries the separation instead, and it reads from every direction because
   both tokens are zero-offset.

   GEOMETRY BELOW IS MIRRORED IN default.js WITH NO ERROR PATH — min-height 52,
   the paddings, and the +#content-wrapper spacers are re-derived there each
   frame. Material only in this rule; do not touch a number. */
.page-header-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.75rem var(--space-3xl);
    background: var(--ev-metal-hi);
    box-shadow: var(--ev-contact-1), var(--ev-ambient-1);
    min-height: 52px;
    position: fixed;
    top: 0;
    left: 260px; /* Nav width */
    right: 0;
    z-index: 100;
}

/* Spacer to push content below fixed header */
.page-header-bar + #content-wrapper {
    padding-top: calc(var(--page-header-rendered-height, 52px) + var(--space-lg));
}

/* Expandable headers (single breadcrumb pages) start tall */
.page-header-bar.expandable {
    min-height: 140px;
    padding: 1.5rem var(--space-3xl);
}

.page-header-bar.expandable + #content-wrapper {
    padding-top: calc(var(--page-header-rendered-height, 140px) + var(--space-lg));
}

/* Collapsed state for expandable headers */
.page-header-bar.expandable.collapsed {
    min-height: 52px;
    padding: 0.75rem var(--space-3xl);
}

.page-header-breadcrumbs {
    flex: 1;
    min-width: 0;
}

/* Expanded title (h1) for expandable pages */
.page-header-title {
    font-size: 2rem;
    font-weight: 600;
    margin: 0;
    color: var(--color-primary-dark);
    line-height: 1.2;
}

/* Lead text in expanded header */
.page-header-lead {
    margin: 0.5rem 0 0;
    font-size: 0.95rem;
    color: var(--color-text-muted);
    line-height: 1.5;
}

/* Hide title and lead when collapsed, show breadcrumb */
.page-header-bar.expandable.collapsed .page-header-title,
.page-header-bar.expandable.collapsed .page-header-lead {
    display: none;
}

/* Hide breadcrumb in expanded state when title is shown */
.page-header-bar.expandable:not(.collapsed) .expanded-hidden {
    display: none;
}

.page-header-bar.expandable.collapsed .expanded-hidden {
    display: block;
}

.page-header-user {
    flex-shrink: 0;
    white-space: nowrap;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.875rem;
    color: var(--color-text-muted);
    margin-left: 1rem;
    transition: opacity 0.2s ease-out;
}

.page-header-user-icon {
    font-size: 1.25rem;
    opacity: 0.7;
}

.page-header-user-name {
    font-weight: 500;
    color: var(--color-text);
}

.page-header-logout {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    color: var(--color-text-muted);
    text-decoration: none;
    padding: 0.25rem 0.5rem;
    border-radius: var(--radius-sm);
    margin-left: 0.5rem;
    transition: background 0.15s, color 0.15s;
    background: none;
    border: none;
    font: inherit;
    cursor: pointer;
}

.page-header-logout:hover {
    color: var(--color-primary);
    background: var(--color-grey-100);
}

/* Expanded user profile (for pages with single breadcrumb) */
.page-header-user-expanded {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 0.75rem;
    flex-shrink: 0;
}

/* Hide expanded profile when collapsed, show compact version */
.page-header-bar.expandable:not(.collapsed) .collapsed-visible {
    display: none;
}

.page-header-bar.expandable.collapsed .page-header-user-expanded {
    display: none;
}

.page-header-bar.expandable.collapsed .collapsed-visible {
    display: flex;
}

@media (max-width: 1199px) {
    .page-header-bar {
        padding: 0.75rem 40px;
        left: 220px; /* Narrower nav */
    }

    .page-header-bar.expandable {
        padding: 1.5rem 40px;
    }

    .page-header-bar.expandable.collapsed {
        padding: 0.75rem 40px;
    }
}

@media (max-width: 991px) {
    .page-header-bar {
        padding: 0.75rem 16px 0.75rem 60px; /* Left padding for hamburger menu (52px + 8px gap) */
        left: 0; /* Nav is hidden/overlay on mobile */
    }

    .page-header-bar.expandable {
        align-items: flex-start;
        flex-wrap: wrap;
        gap: 0.75rem;
        padding: 1rem 16px 1rem 60px;
        min-height: 180px;
    }

    .page-header-bar.expandable .page-header-breadcrumbs {
        flex: 1 0 100%;
        width: 100%;
    }

    .page-header-bar.expandable .page-header-title,
    .page-header-bar.expandable .page-header-lead {
        overflow-wrap: normal;
        word-break: normal;
    }

    .page-header-bar.expandable .page-header-user-expanded {
        flex: 1 1 100%;
        min-width: 0;
        margin-left: 0;
    }

    .page-header-bar.expandable.collapsed {
        align-items: center;
        flex-wrap: nowrap;
        gap: 0;
        padding: 0.75rem 16px 0.75rem 60px;
        min-height: 52px;
    }

    .page-header-bar.expandable.collapsed .page-header-breadcrumbs {
        flex: 1 1 0;
        width: auto;
    }

    /* Adjust spacer for expandable mobile header */
    .page-header-bar.expandable + #content-wrapper {
        padding-top: calc(var(--page-header-rendered-height, 180px) + var(--space-lg));
    }
}

@media (max-width: 768px) {
    .page-header-user {
        font-size: 0.8rem;
    }
}

@media (max-width: 575px) {
    /*
     * A long entity breadcrumb and the account controls cannot reliably share
     * one 390px row. Stack only non-expandable phone app bars; the existing
     * ResizeObserver keeps #content-wrapper clear of the rendered height.
     */
    .page-header-bar:not(.expandable) {
        align-items: stretch;
        flex-direction: column;
        gap: 0.5rem;
    }

    .page-header-bar:not(.expandable) .page-header-user {
        align-self: flex-end;
        margin-left: 0;
    }
}

/* ===========================================================================
   Component: Blog Posts Grid
   ========================================================================== */

/* Blog posts grid - allow full width */
.blog-posts-grid {
    /* No max-width constraint - cards should span full container width */
}

/* ==========================================================================
   Component: Year Selector
   ========================================================================== */

/* These paint registers live on the theme carrier so the dark finish can
   cross an outer light scope without relying on a descendant selector. */
:root,
[data-bs-theme="light"] {
    --year-selector-track-background: var(--color-white);
    --year-selector-track-shadow:
        var(--ev-contact-1),
        var(--ev-ambient-1);
}

.year-selector {
    position: relative;
    display: inline-block;
    z-index: 10;
}

.year-selector-track {
    display: flex;
    align-items: center;
    background: var(--year-selector-track-background);
    border-radius: var(--radius-pill);
    box-shadow: var(--year-selector-track-shadow);
    padding: 4px;
    gap: 2px;
}

.year-nav {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    color: var(--color-text-muted);
    text-decoration: none;
    transition: background 0.15s, color 0.15s;
}

.year-nav:hover:not(.disabled) {
    background: var(--color-grey-100);
    color: var(--color-text);
    transition: none;
}

.year-nav.disabled {
    opacity: 0.3;
    cursor: default;
}

.year-display {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    background: transparent;
    border: none;
    border-radius: var(--radius-pill);
    cursor: pointer;
    transition: background 0.15s;
}

.year-display:hover {
    background: var(--color-grey-100);
    transition: none;
}

.year-value {
    font-size: 1.125rem;
    font-weight: 600;
    color: var(--color-text);
}


.year-dropdown {
    position: absolute;
    top: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%) scale(0.95);
    opacity: 0;
    visibility: hidden;
    background: var(--color-white);
    border-radius: var(--radius-lg);
    box-shadow:
        var(--ev-contact-2),
        var(--ev-ambient-2);
    padding: 8px;
    min-width: 120px;
    max-height: 240px;
    overflow-y: auto;
    z-index: 1050;
    transition: opacity 0.15s, transform 0.15s, visibility 0.15s;
}

.year-selector.open .year-dropdown {
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) scale(1);
}

.year-option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 12px;
    border-radius: var(--radius-md);
    color: var(--color-text);
    text-decoration: none;
    font-weight: 500;
    transition: background 0.1s;
}

.year-option:hover {
    background: var(--color-grey-100);
    transition: none;
}

.year-option.selected {
    background: var(--color-primary);
    color: var(--color-white);
}

.year-option.selected:hover {
    background: var(--color-primary-dark);
}

.year-current-badge {
    font-size: 0.625rem;
    font-family: 'IBM Plex Sans', sans-serif;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    opacity: 0.7;
}

.year-selector-label {
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--color-text-muted);
    padding: 0 0.5rem 0 0.875rem;
    white-space: nowrap;
}

/* ==========================================================================
   Component: Export Option Cards (data export page)
   ========================================================================== */

.export-option-card {
    display: block;
    cursor: pointer;
    background: var(--color-white);
    border: 2px solid var(--color-grey-200);
    border-radius: var(--radius-lg);
    padding: 1rem;
    height: 100%;
    /* Narrowed from `all`, which was implicitly animating the :hover
       box-shadow below — another repeated grid element re-rasterising on a
       pointer sweep (performance budget items 4 and 6). The shadow now
       switches instantly, as .domain-card's does. Do not widen this back to
       `all`. (cortex-2s3rlfk) */
    transition: border-color 0.2s ease, background-color 0.2s ease;
}

.export-option-card:hover {
    border-color: var(--color-grey-300);
    box-shadow:
        var(--ev-contact-1),
        var(--ev-ambient-1);
}

.export-option-card.is-selected {
    border-color: var(--color-primary);
    background: var(--color-primary-light);
}

.export-option-card input[type="checkbox"] {
    position: absolute;
    opacity: 0;
}

.export-option-content {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
}

.export-option-icon {
    font-size: 1.5rem;
    color: var(--color-grey-600);
    flex-shrink: 0;
    transition: color 0.2s ease;
}

.export-option-card.is-selected .export-option-icon {
    color: var(--color-primary);
}

.export-option-text {
    flex: 1;
    min-width: 0;
}

.export-option-text strong {
    display: block;
    font-size: 0.9375rem;
    color: var(--color-text);
    margin-bottom: 0.25rem;
}

.export-option-text span {
    display: block;
    font-size: 0.8125rem;
    color: var(--color-text-muted);
    line-height: 1.4;
}

.export-option-check {
    font-size: 1.25rem;
    color: var(--color-primary);
    opacity: 0;
    transform: scale(0.8);
    /* Narrowed from `all`: .is-selected changes opacity and transform only,
       both compositor-only. (cortex-2s3rlfk) */
    transition: opacity 0.2s ease, transform 0.2s ease;
    flex-shrink: 0;
}

.export-option-card.is-selected .export-option-check {
    opacity: 1;
    transform: scale(1);
}

/* ==========================================================================
   Component: List Action Row
   ========================================================================== */

/* Navigation and its sibling action must share the available inline space.
   Flex items otherwise keep their min-content width, which lets a long entity
   name push the whole row (including its action) beyond a mobile viewport. */
.list-action-row {
    width: 100%;
    min-width: 0;
}

.list-action-row__main {
    min-width: 0;
}

.list-action-row__main .ev-data-list__primary {
    flex-wrap: wrap;
    overflow-wrap: anywhere;
}

.list-action-row__main .ev-data-list__primary > * {
    min-width: 0;
    max-width: 100%;
}

/* ==========================================================================
   Component: Policy Box
   ========================================================================== */

/* Static policy information uses Evident's shallow machined plane for its
   face, cut edge and theme response. Variant colour is confined to the small
   semantic mark; it never repaints the material. These rules live outside the
   PHP template so the component is safe inside Vue-managed surfaces. */
.policy-box {
    padding: 1.25rem;
    margin: 1rem 0;
}

.policy-box--compact {
    padding: 0.875rem 1rem;
    margin: 1rem;
}

.policy-box__layout {
    display: flex;
    gap: 1rem;
    align-items: center;
}

.policy-box__icon-wrapper {
    flex-shrink: 0;
    width: 2.25rem;
    height: 2.25rem;
    display: flex;
    align-items: center;
    justify-content: center;
}

.policy-box--compact .policy-box__layout {
    gap: 0.75rem;
}

.policy-box--compact .policy-box__icon-wrapper {
    width: 1.75rem;
    height: 1.75rem;
}

.policy-box__icon {
    font-size: 1rem;
}

.policy-box--policy .policy-box__icon {
    color: var(--ev-ink-dim);
}

.policy-box--good .policy-box__icon {
    color: var(--ev-success);
}

.policy-box__body {
    flex-grow: 1;
    min-width: 0;
}

.policy-box__title {
    color: var(--ev-ink);
    font-weight: 600;
    margin-bottom: 0.375rem;
    font-size: 0.8125rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.policy-box__content {
    color: var(--ev-ink-dim);
    font-size: 0.875rem;
    line-height: 1.65;
}

/* ==========================================================================
   Component: Progress Bar Colors
   ========================================================================== */

.progress-danger .progress-bar {
    background-color: var(--bs-danger);
}

.progress-warning .progress-bar {
    background-color: var(--bs-warning);
}

.progress-success .progress-bar {
    background-color: var(--bs-success);
}

.progress-secondary .progress-bar {
    background-color: var(--bs-secondary);
}

/* The readout cluster itself is Evident's public `.ev-readout-cluster`
   component. Its plate, cells, count-aware container queries, typography and
   responsive schedule live in the vendored library, not in this consumer.

   These two aliases exist only so `/development/ui_components` can photograph
   the component's transient hover/press states without pointer interaction.
   Production interaction continues to use Evident's :hover/:active selectors. */
.ev-readout-cluster__cell:where(a).is-hover {
    transition: none;
    box-shadow:
        var(--ev-r3-line),
        var(--ev-r3-lip),
        var(--ev-r3-wall),
        var(--ev-shoulder-lite),
        var(--ev-r1-rim);
}
.ev-readout-cluster__cell:where(a).is-hover .ev-readout-cluster__value {
    color: var(--ev-accent-text);
}
.ev-readout-cluster__cell:where(a).is-hover .ev-readout-cluster__label {
    color: var(--ev-ink);
}

.ev-readout-cluster__cell:where(a).is-active {
    transition: box-shadow var(--ev-press-in) var(--ev-press-in-ease),
                background-color var(--ev-press-in) var(--ev-press-in-ease);
    background-color: var(--ev-direct-carve-floor, var(--ev-floor-n1));
    box-shadow:
        var(--ev-r2-line),
        var(--ev-r2-lip),
        var(--ev-r2-wall),
        var(--ev-r3-rim);
}
/* ==========================================================================
   Component: Notices — the notice owns the ink of its whole subtree
   ==========================================================================

   Evident faces `.ev-notice` in a saturated semantic colour and sets the
   matching `--ev-<sem>-fg` ink on the container itself, relying on normal
   inheritance to carry that ink to the text inside.

   Control Center's global typography loads AFTER the Evident adapter by
   design (see Evident docs/controlcenter-cascade-conflicts.md — CC stays the
   final owner during migration), so its bare element rules punch straight
   through that inheritance:

       p     -> --color-text          (layout-chrome.css)
       small -> --color-text-muted    (layout-chrome.css)
       h4    -> --color-primary-dark  (layout-chrome.css)
       .lead -> --color-primary-dark  (layout-chrome.css)
       a     -> --bs-link-color       (Bootstrap, remapped by Evident)

   Measured on the real head.php cascade in light theme, every one of those
   fails WCAG AA against every semantic face — `p` at 1.86:1 on `--ev-info`,
   `small` at 1.41:1 on `--ev-success`. That is the whole alert-variant family,
   not one mis-paired variant: the founder saw it as body ink on the steel-blue
   VAT-number notice (cortex-cyvmbek).

   Restoring inheritance here is one rule instead of a `:not()` carve-out on
   each of the five offenders, and it states the actual design fact rather than
   restating the notice ink in a second place. Elements that carry their OWN
   face are excluded, because they own their ink exactly the way the notice
   does. Bootstrap's `.text-*` utilities keep winning; they are `!important`.

   Links additionally take an underline: on a saturated face an inherited-ink
   link has no hue left to distinguish it, and `.card a` removes the default
   underline, so without this a link inside a card-hosted notice would be
   invisible as a link. */
.cc-alert {
    margin-block-end: 1rem;
}

.ev-notice :where(p, small, a, code, kbd, samp, pre, li, ul, ol, dl, dt, dd,
              h1, h2, h3, h4, h5, h6, .lead, label, span, strong, em, div, i):not(
              :where(.btn, .ev-key, .badge, .ev-badge, .form-control, .form-select,
                     .form-check-input)) {
    color: inherit;
}

/* Bootstrap's colour utilities are !important, so the inheritance repair above
   cannot neutralise stale `text-muted` classes. Semantic notices own a paired
   face and foreground; keep muted prose on that foreground while leaving
   neutral notices and nested components with their own face untouched. */
.ev-notice:where(.ev-notice--danger, .ev-notice--success, .ev-notice--warning, .ev-notice--info)
    .text-muted:not(:where(.btn, .badge, .form-control, .form-select,
                           .form-check-input)) {
    color: var(--ev-notice-ink) !important;
}

/* The Control Center alert component owns the exception for nested faces. Keep
   that exception behind its constant `.cc-alert` boundary: raw semantic notices
   (including the troubleshooter's JavaScript-built notices) still receive the
   semantic ink above, while a face composed inside our alert restores its own
   inherited ink. Cover both a face that itself carries `text-muted` and muted
   prose nested inside that face. */
.cc-alert.ev-notice:where(.ev-notice--danger, .ev-notice--success, .ev-notice--warning, .ev-notice--info)
    :where(.ev-key, .ev-badge, .ev-well, .ev-machined, .ev-card).text-muted,
.cc-alert.ev-notice:where(.ev-notice--danger, .ev-notice--success, .ev-notice--warning, .ev-notice--info)
    :where(.ev-key, .ev-badge, .ev-well, .ev-machined, .ev-card) .text-muted {
    color: inherit !important;
}

.ev-notice :where(a):not(:where(.btn, .ev-key, .badge, .ev-badge)) {
    text-decoration: underline;
}

/* Multi-line notices start their indicator at the copy's first line instead of
   centring it against the full paragraph block. The opt-in modifier preserves
   Evident's compact, vertically centred default for one-line notices. */
.ev-notice.cc-notice--large {
    align-items: start;
}

@media (min-width: 768px) {
    .ev-notice.cc-notice--large > .ev-notice__indicator {
        font-size: 1.25rem;
        line-height: 1.25;
    }
}

/* ==========================================================================
   Component: Section band — the rail's channel, extended to seat the actions
   ==========================================================================

   FOUNDER REPORT (2026-08-04, /domains/expiry): "The buttons on the right seem
   like they are floating a bit... I would like these sections to look more like
   a coherent UI element." Measured, the header row was three materials and one
   of them was nothing: the rail brought a milled channel (floor --ev-floor-n1,
   inset cut stack), the keys brought raised cast bodies (--ev-metal-hi, outer
   contact + ambient), and the container between them contributed no surface at
   all — 298px of bare page canvas between two fabrication events sharing a
   line. "Floating" was literally accurate in Evident's model.

   THE FIX IS NOT A NEW BOX. The channel already existed; it was merely too
   short. This rule moves that ONE cut outward onto the element that actually
   spans both groups, and strips the paint from the nested `.ev-rail` in the
   same breath, so exactly one cut is drawn — page -> channel -> seat, the same
   three planes and the same three floors as before. Wrapping the rail in an
   outer tray was considered and REJECTED by the founder: it would stack
   page -> band -> channel -> seat, enclosing content that is already enclosed,
   which is a fabrication event that never happened (rule 1). The DOM keeps the
   shipped `[data-cc-subnav] > nav.ev-rail` contract that the PHP and e2e tests
   assert; only which element carries the material changes.

   NOT EVERY HEADER ROW GETS THIS. Callers explicitly choose this self-supporting
   channel or `.cc-section-caption`, whose declared plane immediately below owns
   the floor. The component never infers material from which slots happened to
   be passed. (cortex-jykjnai)

   EVERY LAND IS --ev-seat-inset (3px), the same number the rail's detent is
   inset by (rail.css: "surviving channel floor reads around it") and the same
   number boss.css seats its sockets in the keyplate by. Block axis: the band's
   min-height is one --ev-btn-height-sm key plus two lands, the action group
   carries that land as a margin so a taller action (the year selector) keeps
   it, and the rail's items stretch to the channel so the seat's own 3px margin
   measures off the channel wall — which keeps the derived seat radius
   calc(--ev-radius-sm - --ev-rail-seat-inset) = 3px honest. Inline axis: the
   rail seats at the left wall exactly as before; padding-inline-end gives the
   keys the matching land at the right. Radii, floors and accent placement are
   untouched by design (see cortex-ui1af1u).

   DELETION CONDITION: delete this block when Evident ships a rail variant that
   seats actions in the channel and Control Center adopts it. Until then it
   composes Evident's own tokens and invents no value. (cortex-ui1af1u) */
.cc-section-band {
    box-sizing: border-box;
    /* one key plus a land above and below it */
    min-height: calc(var(--ev-btn-height-sm) + 2 * var(--ev-seat-inset));
    padding-inline-end: var(--ev-seat-inset);
    /* The channel's material, consumed from the same tokens rail.css composes:
       rank-2 lip + wall + rim over the deepest carve floor. The light rim owns
       the rounded top edge with NO dark top arris, matching .ev-segmented's
       fix-by-removal precedent (cortex-gifqvxx). */
    background-color: var(--ev-direct-carve-floor, var(--ev-floor-n1));
    color: var(--ev-ink);
    border-radius: var(--ev-radius-sm);
    box-shadow:
        var(--ev-r2-lip),
        var(--ev-r2-wall),
        var(--ev-r2-rim);
}

/* The nested rail stops being a channel and becomes what it always was inside
   one: labels lying on the floor with a detent under the current one. Its cut
   moved outward, it did not gain a second one. Fix-by-removal. */
.cc-section-band .ev-rail {
    display: flex;
    background-color: transparent;
    border-radius: 0;
    box-shadow: none;
    clip-path: none;
}

.cc-section-band .ev-rail::after {
    content: none;
}

/* The scrolling view lane fills the channel so the items — and therefore the
   seat's own inset — measure off the channel wall rather than an intermediate
   box. It keeps `overflow-x-auto flex-grow-1` from the markup. */
.cc-section-band [data-cc-subnav] {
    display: flex;
    align-items: stretch;
    min-width: 0;
}

/* The feedback channel carries a wider raw action fragment than structured
   channel callers. On phones, give its status rail a complete first row and
   seat the Signals-first actions below it instead of covering the trailing All
   destination. The caller class keeps this exception local to that surface. */
@media (max-width: 575.98px) {
    .feedback-status-channel {
        flex-wrap: wrap;
    }

    .feedback-status-channel [data-cc-subnav] {
        flex-basis: 100%;
        max-width: 100%;
    }

    .feedback-status-channel [data-cc-section-actions] {
        justify-content: flex-end;
        width: 100%;
        margin-left: 0 !important;
    }

    .feedback-status-channel [data-cc-subnav] + [data-cc-section-actions]::before {
        content: none;
    }
}

/* Structured destinations lie on the channel floor using the shipped rail-item
   recipe. One promoted Evident groove separates navigation scope from the
   destination lane; it is a short milled detail, never a full-height rule. */
.cc-section-band [data-cc-section-actions] {
    position: relative;
}

.cc-section-band [data-cc-subnav] + [data-cc-section-actions]::before {
    content: "";
    position: absolute;
    left: 0;
    top: var(--ev-seg-groove-inset);
    bottom: var(--ev-seg-groove-inset);
    width: 2px;
    background: linear-gradient(
        90deg,
        var(--ev-seg-groove-ink) 0,
        var(--ev-seg-groove-ink) 1px,
        var(--ev-seg-groove-land) 1px,
        var(--ev-seg-groove-land) 2px);
    transform: translateX(-1px);
    pointer-events: none;
    z-index: 2;
}

/* When the live seat touches the lane boundary, its depth is already enough
   distinction. Keep only Evident's quarter-strength material trace. */
.cc-section-band .cc-section-subnav--selected-last
    + [data-cc-section-actions]::before {
    opacity: var(--ev-seg-groove-muted-opacity);
}

.cc-section-action--danger {
    color: var(--ev-ink-dim);
}

.cc-section-band .ev-rail__item.cc-section-action--danger:hover:not(.ev-rail__item--selected):not(:disabled),
.cc-section-band .ev-rail__item.cc-section-action--danger:focus-visible {
    color: var(--ev-danger-action-ink);
}

.cc-section-action__glyph {
    width: 1em;
    height: 1em;
}

/* A title/action channel has no rail seat to establish its lands, so the band
   supplies them directly. Material selection remains explicit; only the
   internal layout responds to the declared content slots. */
.cc-section-band--without-subnav {
    padding-block: var(--ev-seat-inset);
    padding-inline-start: calc(var(--ev-seat-inset) + 0.5rem);
}

/* A caption is intentionally material-free. Its keys and title borrow the
   floor of the immediately following `[data-cc-caption-plane]`; default.js
   checks that same-floor/tight-gap/flush-edge contract in development. */
.cc-section-caption {
    --cc-caption-tight-gap: 1rem;
    min-width: 0;
}

/* Card cap on `.card-header.bg-light`. Arrived from layout-theme.css, where it
   was a dark-only literal behind the nested-theme guard idiom that bead
   cortex-w8l9sqr removed. This one was genuinely load-bearing and could not
   just be deleted: `.bg-light` resolves through --bs-light-rgb, which is
   248,249,250 in BOTH theme blocks — Bootstrap's light utility is not
   theme-aware at all. So a dark-scoped card header nested in a light page was
   rendering a near-white cap on a dark card, the loudest leak the audit found.

   The scope-correct form needs no guard and no new token: --ev-ink is defined
   in both theme blocks, so a wash mixed from it follows the nearest scope in
   either nesting direction. Both live themes are visually unchanged — dark
   lands within 1/255 of the old rgba(255,255,255,.04), and light moves from
   rgb(248,249,250) to rgb(245,245,245), which also retires a chromatic grey
   (R≠G≠B) from the trunk in passing.

   The `!important` is required, not decorative: it beats `.bg-light`'s own
   `!important` on the strength of the extra class in the selector. */
.card-header.bg-light {
    background-color: color-mix(in srgb, var(--ev-ink) 4%, transparent) !important;
}
/* ==========================================================================
   Component: Domain Cards (thumbnail grid)
   ========================================================================== */

.domains-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 1rem;
}

/* When there are few domains, use fixed-width cards with consistent spacing */
.domains-grid-few {
    grid-template-columns: repeat(auto-fit, 200px);
    gap: 1.5rem;
}

.domain-card {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    text-decoration: none;
}

.domain-thumbnail-wrapper {
    aspect-ratio: 16/10;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    position: relative;
    /* This is thumbnail fallback content, not Evident's page/chrome pinstripe:
       the image aperture shows a quiet striped pending/empty field while no
       usable preview covers it. */
    background: repeating-linear-gradient(
        135deg,
        var(--surface-alt) 0,
        var(--surface-alt) 0.5rem,
        var(--border-strong) 0.5rem,
        var(--border-strong) 1rem
    );
}

.domain-thumbnail {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.2s ease;
}

.domain-card:hover .domain-thumbnail {
    transform: scale(1.05);
}

.domain-thumbnail-placeholder {
    font-size: 2rem;
}

/* The separating rule and the material come from the shipped .ev-card__footer
   this element also carries. Only geometry stays local: the footer's default
   inline padding is sized for a full-width card, and on a 180px grid tile it
   narrows the caption enough to wrap a domain name onto a second line. */
.domain-card-body {
    padding: 0.75rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 0.25rem;
    flex: 1;
}

.domain-name {
    font-size: 0.85rem;
    font-weight: 500;
    word-break: break-all;
    line-height: 1.3;
}

@media (max-width: 575px) {
    .domains-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

/* ==========================================================================
   Hero Banner Component - Prominent full-width banner
   ========================================================================== */

.hero-banner {
    padding: 2.5rem 2rem;
    text-align: center;
    overflow: hidden;
}

.hero-banner-content {
    position: relative;
}

.hero-banner-icon {
    margin-bottom: 1rem;
}

/* Flat accent ink on the neutral machined plane. It carries no shadow because
   ink has no material and casts nothing (Evident L3 / Invariant 7). */
.hero-banner-icon i {
    display: inline-block;
    font-size: 3rem;
    color: var(--ev-accent-text);
    animation: hero-icon-float 3s ease-in-out infinite;
}

@keyframes hero-icon-float {
    0%, 100% {
        transform: translateY(0) rotate(-15deg);
    }
    50% {
        transform: translateY(-8px) rotate(-15deg);
    }
}

.hero-banner-title {
    color: var(--ev-ink);
    font-size: 1.75rem;
    font-weight: 700;
    margin: 0 0 0.5rem;
}

.hero-banner-subtitle {
    color: var(--ev-ink-dim);
    font-size: 1rem;
    margin: 0;
    max-width: 500px;
    margin-left: auto;
    margin-right: auto;
}

@media (max-width: 767px) {
    .hero-banner {
        padding: 2rem 1.5rem;
    }

    .hero-banner-title {
        font-size: 1.5rem;
    }

    .hero-banner-icon i {
        font-size: 2.5rem;
    }
}

/* ==========================================================================
   Component: Success Feedback Animation
   Shared by success_feedback.php, mini_survey.php, and other AJAX confirmations
   ========================================================================== */

@keyframes success-bounce {
    0% {
        transform: scale(0);
        opacity: 0;
    }
    50% {
        transform: scale(1.2);
        opacity: 1;
    }
    70% {
        transform: scale(0.9);
    }
    85% {
        transform: scale(1.05);
    }
    100% {
        transform: scale(1);
        opacity: 1;
    }
}

.success-feedback-icon {
    animation: success-bounce 0.5s ease-out forwards;
}

/* ==========================================================================
   Component: Mini Survey / Newsletter Box
   Accent styling to distinguish interactive info boxes from content sections
   ========================================================================== */

/* These boxes are .rounded-light carves. The 3px accent left-border they used
   to carry was an accent-coloured MATERIAL edge on one side of a cut, which
   breaks two rules at once: material is never coloured (Invariant 7), and an
   edge treatment on a single side contradicts symmetric axial light — a cut
   is cut equally on all four sides or it is not a cut.

   The stripe is simply removed rather than replaced. The distinguishing job
   it was doing is already carried by the carve itself — these boxes sit on
   the page canvas as pockets, which reads as "different kind of thing" more
   strongly than a 3px line ever did. Adding a compensating accent pip here
   would be a new layer to replace a deleted one; if the distinction turns
   out to be too weak in practice, the answer is a deeper carve rank, not a
   second channel. (cortex-vnt3p6m) */
.mini-survey-box,
.newsletter-box {
    border-left: 0;
}

/* ==========================================================================
   Component: Dismissing Animations (Mini Survey, Newsletter, etc.)
   ========================================================================== */

/* Narrowed from `all`: the dismissing state changes opacity and transform and
   nothing else, and both are compositor-only. `all` would silently pick up any
   property a later rule adds — including box-shadow. (cortex-2s3rlfk) */
.mini-survey-thanks,
.newsletter-thanks {
    transition: opacity 0.6s ease-out, transform 0.6s ease-out;
}

.mini-survey-dismissing,
.newsletter-dismissing {
    opacity: 0;
    transform: translateY(-20px) scale(0.95);
}

/* ==========================================================================
   Component: User Avatar
   ========================================================================== */

/* A raised key, nested on the header pill which is itself a raised key on the
   bar — raised on raised, legal all the way down. Both of its live instances
   ride the chrome, so it is held to the chrome's invariants.

   It previously carried an outer AND an inset shadow at once, which claims the
   part was cast and cut simultaneously, and both layers had a y-offset. Now
   molded only, and axial. */
.user-avatar {
    box-shadow: var(--ev-contact-1);
}

.user-avatar-icon {
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* The scale carries the affordance; the finish step below switches instantly.
   box-shadow is deliberately absent from the transition list (performance
   budget item 4 — never animate a shadow on hover). (cortex-2s3rlfk) */
.user-avatar-clickable {
    cursor: pointer;
    transition: transform 0.15s;
}

/* Hover steps the FINISH (crisper contact, lit crown), not the depth. */
.user-avatar-clickable:hover {
    transform: scale(1.05);
    box-shadow: var(--ev-contact-2), var(--ev-shoulder-lite);
}

/* ==========================================================================
   Component: Info Box
   ========================================================================== */

.info-box {
    transition: background-color 0.15s ease;
}

/* Was rgba(4, 45, 74, 0.08) — brand navy as a material wash. (cortex-mn5hkp8) */
.info-box:hover {
    background-color: var(--ev-wash);
}

.info-box [data-bs-toggle] {
    cursor: pointer;
}

.info-box-chevron {
    transition: transform 0.2s ease;
}

.info-box [aria-expanded="true"] .info-box-chevron {
    transform: rotate(180deg);
}

/* ==========================================================================
   Component: Delete Button (subtle variant)
   ========================================================================== */

.delete-btn-subtle {
    background: transparent;
    border: 1px solid color-mix(in srgb, var(--danger) 50%, transparent);
    color: var(--danger);
    /* Narrowed from `all` to exactly what :hover and :active change.
       (cortex-2s3rlfk) */
    transition: background-color 0.2s ease, border-color 0.2s ease,
                color 0.2s ease, transform 0.2s ease;
}

.delete-btn-subtle:hover {
    background: color-mix(in srgb, var(--danger) 15%, transparent);
    border-color: var(--danger);
    color: var(--danger);
    transform: translateY(-1px);
}

.delete-btn-subtle:active {
    transform: translateY(0);
}

/* Works better on dark backgrounds */
.navbar-dark .delete-btn-subtle,
.bg-dark .delete-btn-subtle {
    border-color: color-mix(in srgb, var(--danger) 70%, transparent);
    color: color-mix(in srgb, var(--danger) 35%, var(--accent-fg));
}

.navbar-dark .delete-btn-subtle:hover,
.bg-dark .delete-btn-subtle:hover {
    background: color-mix(in srgb, var(--danger) 30%, transparent);
    border-color: var(--danger);
    color: var(--accent-fg);
}

/* ==========================================================================
   Component: List Group Split Item
   Rows with a clickable main area and a separated action zone.
   Only the main area participates in hover; the actions sit apart.
   ========================================================================== */

.list-group-split-item {
    overflow: hidden;
}

.list-group-split-main {
    transition: background-color 0.15s;
}

.list-group-split-main:hover {
    background-color: var(--bs-list-group-action-hover-bg, rgba(0, 0, 0, 0.03));
}

/* Was `-2px 0 6px` — the only NEGATIVE-x shadow in the trunk, lighting the
   panel from the right. Light is axial (Invariant 6). The separation this was
   reaching for is already carried by the border-left, which is the honest
   channel for it: a seam is a line, not a cast shadow. (cortex-mn5hkp8) */
.list-group-split-actions {
    border-left: 1px solid var(--bs-border-color, rgba(0, 0, 0, 0.1));
    background: var(--bs-list-group-bg, var(--surface));
    flex-shrink: 0;
}
/* ==========================================================================
   Dark Mode
   ========================================================================== */

:is([data-bs-theme="dark"], [data-bs-theme="darker"], [data-bs-theme="very-dark"]) {
    /* Paired with the light carrier in tokens.css. Descendant logos consume
       these unconditionally, so the nearest nested theme always wins. */
    --login-brand-logo-light-display: none;
    --login-brand-logo-dark-display: block;

    /* Neutrals - inverted grey scale */
    --color-white: var(--bg);
    --color-grey-50: var(--surface);
    --color-grey-100: var(--surface-alt);
    --color-grey-200: var(--border-strong);
    --color-grey-300: var(--text-faint);
    --color-grey-600: var(--text-dim);
    --color-grey-700: var(--text);
    --color-grey-800: var(--text-strong);
    --color-grey-900: var(--text-strong);

    /* Text */
    --color-text: var(--text);
    --color-text-muted: var(--text-dim);
    --color-text-light: var(--text-faint);

    /* Primary adjustments for dark backgrounds */
    --color-primary-dark: color-mix(in srgb, var(--accent) 45%, var(--text-strong));
    --color-primary-light: var(--accent-muted);

    /* Background */
    --color-bg: var(--bg);
    /* --color-bg-dark is NOT restated here any more (cortex-dk1b528). It pointed at
       --accent-fg, which is the ink that goes ON the accent, not a face to paint —
       and because this :is() block has the same specificity as the per-theme blocks
       in tokens.css but loads after them, that override silently WON. The effect was
       that neutralising --color-bg-dark in tokens.css did nothing at all: the one
       thing it painted, .copy-tooltip (layout-surfaces.css), kept rendering the
       chromatic #0d0f10. Measured on the live DOM, not inferred from the cascade.
       Removing it lets each theme's own value apply, which is what tokens.css
       already declared.

       That tooltip has since been deleted with the legacy copy seam
       (cortex-9bfk1se), so --color-bg-dark now has zero consumers — the same state
       --color-bg-darker was already in, and left alone for the same reason: whether
       to retire a zero-consumer token is palette work, not a side effect of removing
       its last consumer. The reasoning above is kept because it is what stops the
       accent-fg mapping being reinstated if a consumer ever returns.

       --color-bg-darker keeps the accent-fg mapping: tokens.css declares it that
       way too, and it also has zero consumers, so there is nothing to correct. */
    --color-bg-darker: var(--accent-fg);

    /* Shadows - stronger on dark backgrounds.
       Symmetric axial light (Evident Invariant 6): zero x and y offset, blur +
       spread only. Alphas are lifted over the light-theme ramp AND over the
       old dark offsets, because zeroing the offset spreads the same ink across
       four sides — measured, the naive dark `0 0 8px /.20` lost 87% of its
       falloff area versus `0 3px 8px /.20`. Geometry is kept identical to the
       light tokens so depth reads the same in both themes; only alpha differs.
       Must stay in lockstep with tokens.css:117-119. (cortex-1r37qcl) */
    --shadow-sm: 0 0 12px 1px rgba(0, 0, 0, 0.28);
    --shadow-md: 0 0 18px 2px rgba(0, 0, 0, 0.38);
    --shadow-lg: 0 0 20px 2px rgba(0, 0, 0, 0.46);

    /* Theme-carrier paint avoids an asymmetric descendant override when this
       dark island is itself nested inside a light scope. */
    --year-selector-track-background: rgba(255, 255, 255, 0.06);
    --year-selector-track-shadow: 0 0 0 1px rgba(255, 255, 255, 0.1);

    color-scheme: dark;
}

/* --------------------------------------------------------------------------
   Bootstrap --bs-* dark-palette mirror for the WHOLE dark family.

   Bootstrap defines its dark palette ONLY under [data-bs-theme=dark]
   (bootstrap.css:128-182). Under data-bs-theme="darker"/"very-dark" every
   --bs-* var would otherwise fall back to the LIGHT :root defaults, producing
   bright stat cards, light card bodies, and illegible muted text. Mirror the
   full set here, sourced from each theme's own tokens and darkened to suit the
   near-black (#000 / #070707) backgrounds. (cortex-fhw3lez)

   [data-bs-theme="dark"] was deliberately left out of that fix, because it DOES
   receive Bootstrap's own dark palette and so nothing looked broken. But that
   palette is Bootstrap's, not Evident's, and Bootstrap's dark neutrals are blue
   by design. Measured on the live DOM before this change:

       --bs-border-color  #495057  R73 G80 B87   a 14-level spread, and the
                                                 default border for every
                                                 Bootstrap component that does
                                                 not override it
       --bs-body-bg       #212529  R33 G37 B41
       --bs-secondary-bg  #343a40  R52 G58 B64

   So the two DERIVED themes were more conformant than the theme they derive
   from, and the app's most-used dark theme was the one still painting blue
   greys. Adding "dark" to the selector puts all three on Evident's own neutral
   tokens and satisfies the epic's "zero chromatic material faces" criterion for
   the dark family. (cortex-mz7eidz)

   Specificity: :is() takes the specificity of its most specific argument, so
   this block is (0,1,0) — IDENTICAL to Bootstrap's own [data-bs-theme=dark].
   It therefore wins on source order alone, which holds because head.php loads
   bootstrap.min.css at :64 and layout-theme.css at :83. If that order is ever
   changed, dark silently reverts to Bootstrap's blue neutrals.

   Neutral families below are token references, never literals, so each theme
   resolves them from its own ladder and they cannot re-acquire a tint. The
   SEMANTIC families (primary / success / info / warning / danger) stay as tuned
   hex: those are indicators, and chroma is legal for them under Invariant 7.
   -------------------------------------------------------------------------- */
:is([data-bs-theme="dark"], [data-bs-theme="darker"], [data-bs-theme="very-dark"]) {
    /* `color-scheme: dark` is NOT restated here. It used to be, back when this
       block's selector was :is(darker, very-dark) and therefore distinct from
       the neutrals block at the top of this file. Widening the selector to the
       full dark family made the two selectors IDENTICAL, and both declared
       color-scheme — a duplicate selector with an overlapping property, which
       tests/php/Unit/CssDuplicateSelectorTest.php exists to catch. The
       declaration at the top of this file already covers all three themes, so
       this one was pure redundancy. (cortex-mz7eidz) */

    /* Body / secondary / tertiary surfaces + colors */
    --bs-body-color: var(--text);
    --bs-body-color-rgb: 237, 237, 238;
    --bs-body-bg: var(--bg);
    --bs-emphasis-color: var(--text-strong);
    --bs-emphasis-color-rgb: 255, 255, 255;
    --bs-secondary-color: rgba(237, 237, 238, 0.75);
    --bs-secondary-color-rgb: 237, 237, 238;
    --bs-secondary-bg: var(--surface-alt);
    --bs-tertiary-color: rgba(237, 237, 238, 0.5);
    --bs-tertiary-color-rgb: 237, 237, 238;
    --bs-tertiary-bg: var(--surface);

    /* Text-emphasis family (mirrors bootstrap.css:144-151). The `primary`
       member is ink, so it takes the brand accent rather than Bootstrap's
       stock #6ea8fe — see the links block below for why the alias is spelled
       --ev-accent and not deleted outright. (cortex-cf4v7nn) */
    --bs-primary-text-emphasis: var(--ev-accent);
    --bs-secondary-text-emphasis: var(--secondary-ink-on-dark);
    --bs-success-text-emphasis: var(--success-ink-on-dark);
    --bs-info-text-emphasis: var(--info-ink-on-dark);
    --bs-warning-text-emphasis: var(--warning-ink-on-dark);
    --bs-danger-text-emphasis: var(--danger-ink-on-dark);
    --bs-light-text-emphasis: var(--neutral-ink-on-dark);
    --bs-dark-text-emphasis: var(--neutral-ink-dim-on-dark);

    /* bg-subtle family. Semantic members stay tuned hex, darker than
       Bootstrap's for the near-black bg. The three NEUTRAL members were hex
       too, and were chromatic in all three dark themes — --bs-light-bg-subtle
       was #1c2026, a stale copy of darker's --surface-alt from before that
       token was neutralised. They now reference each theme's own faces, which
       both removes the tint and stops the value going stale a second time.
       Mapping keeps Bootstrap's own ordering (dark <= light). (cortex-mz7eidz) */
    --bs-primary-bg-subtle: var(--primary-face-on-dark);
    --bs-secondary-bg-subtle: var(--surface);
    --bs-success-bg-subtle: var(--success-face-on-dark);
    --bs-info-bg-subtle: var(--info-face-on-dark);
    --bs-warning-bg-subtle: var(--warning-face-on-dark);
    --bs-danger-bg-subtle: var(--danger-face-on-dark);
    --bs-light-bg-subtle: var(--surface-alt);
    --bs-dark-bg-subtle: var(--surface);

    /* border-subtle family — semantic members mirror bootstrap.css:160-167.
       The neutral trio was raw hex lifted from Bootstrap's dark palette and so
       stayed blue in ALL THREE dark themes, including very-dark where every
       other neutral was already perfect: --bs-light-border-subtle #495057 is
       R73 G80 B87, tied with --bs-border-color for the worst chroma measured in
       this file. Now on the theme's own border ladder. (cortex-mz7eidz) */
    --bs-primary-border-subtle: var(--primary-border-on-dark);
    --bs-secondary-border-subtle: var(--border-strong);
    --bs-success-border-subtle: var(--success-border-on-dark);
    --bs-info-border-subtle: var(--info-border-on-dark);
    --bs-warning-border-subtle: var(--warning-border-on-dark);
    --bs-danger-border-subtle: var(--danger-border-on-dark);
    --bs-light-border-subtle: var(--border-strong);
    --bs-dark-border-subtle: var(--border);

    /* Headings / links / code / highlight */
    /* `inherit` resolves from the OUTER scope when this theme carrier is a
       dark island inside light chrome. Point at the local material ink so the
       Bootstrap heading rule recomputes on either a root or nested carrier. */
    --bs-heading-color: var(--ev-ink);
    /* ONE canonical link ink, derived from the brand accent. (cortex-cf4v7nn)
       These were Bootstrap's stock dark blues (#6ea8fe / #8bb9fe) and the code
       ink was Bootstrap's pink #e685b5 — three hues that are neither the brand
       nor achromatic, so a dark page ran a link colour unrelated to every other
       accent on it. In LIGHT the Evident adapter already points this whole
       family at --ev-accent-text (#064466); dark's counterpart is the accent
       itself, which needs no luminance step to be legible on a dark ground
       (8.13:1 on --bg #0e0e0e, 8.49:1 on darker's #070707, 6.78:1 on --surface
       #212121 — all clear of the 4.5:1 text floor).

       WHY THIS IS AN ALIAS AND NOT A DELETION. Deleting these would let the
       surface fall through to evident-bootstrap.css, which is the correct move
       in general and how the rest of this port works — but the adapter's dark
       block is keyed `:is([data-ev-theme="dark"], [data-bs-theme="dark"])`,
       which does NOT match `darker` or `very-dark`. Under those two themes
       --ev-accent-text still resolves to the LIGHT #064466, i.e. 1.94:1 on
       darker's near-black ground. --ev-accent is not theme-scoped (measured
       #2bb3f3 in all four themes), so it is safe in this three-theme selector
       where --ev-accent-text is not. Delete this block once Evident's dark
       scope covers all three (cortex-efa3l5n); do not delete it before.

       Hover deliberately equals rest, matching the adapter, which stopped
       shifting link hue on hover. The -rgb triple is the member that actually
       paints: Bootstrap resolves `a { color: rgba(var(--bs-link-color-rgb),
       var(--bs-link-opacity, 1)) }`, so a hex-only remap leaves links stock. */
    --bs-link-color: var(--ev-accent);
    --bs-link-hover-color: var(--ev-accent);
    --bs-link-color-rgb: var(--ev-accent-rgb);
    --bs-link-hover-color-rgb: var(--ev-accent-rgb);
    --bs-code-color: var(--ev-accent);
    --bs-highlight-color: var(--text);
    --bs-highlight-bg: var(--highlight-face-on-dark);

    /* Borders */
    --bs-border-color: var(--border-strong);
    --bs-border-color-translucent: rgba(255, 255, 255, 0.15);

    /* Form validation. Bootstrap ships these equal to the success/danger
       emphasis inks, so they reference the SAME two tokens rather than minting
       a duplicate pair — if the severity ink moves, validation moves with it. */
    --bs-form-valid-color: var(--success-ink-on-dark);
    --bs-form-valid-border-color: var(--success-ink-on-dark);
    --bs-form-invalid-color: var(--danger-ink-on-dark);
    --bs-form-invalid-border-color: var(--danger-ink-on-dark);

    /* Card body follows body bg (Bootstrap default; make explicit) */
    --bs-card-bg: var(--bs-body-bg);
}

/* Background overlay for dark mode. The last dark DESCENDANT selector in this
   file, and the only one that keeps the nested-light guard.

   On this selector the guard is provably inert: `body`'s only ancestor is
   `html`, so the guard can only bite when `html` is light — and a light `html`
   already fails the `:is(dark)` prefix. The two conditions are never
   simultaneously satisfiable, so it cannot change a computed value either way.

   It stays for exactly that reason. DarkThemeSelectorTest ratchets every dark
   descendant selector to carry the guard, and that ratchet is still the right
   one to point at whoever writes the NEXT such selector — the guard is a
   stopgap, but a stopgap beats nothing, and the real answer (put the value in
   the token layer so no theme selector is needed at all) is spelled out in the
   audit block below. Dropping the guard from the one rule where it is harmless
   would have bought nothing and cost the ratchet. (cortex-w8l9sqr) */
:is([data-bs-theme="dark"], [data-bs-theme="darker"], [data-bs-theme="very-dark"]) body[style*="background-image"]:where(:not([data-bs-theme="light"] *))::after {
    /* Was the literal rgba(26, 29, 33, 0.6) — the OLD blue-tinted #1a1d21 dark
       bench, hardcoded. Stale the moment that bench was retoned to a neutral
       #0e0e0e, and chromatic besides (R26 G29 B33). Same fix as its light
       counterpart in layout-base.css; only the alpha differs. */
    background-color: color-mix(in srgb, var(--color-bg) 60%, transparent);
}

/* The sidebar is invariant dark raised stock (--ev-dark-metal-hi), while the
   header is seated beneath that housing in the chrome assembly. Dark mode made
   the two planes collapse because --ev-metal-hi resolves to that same raised
   stock. Step only the lower plane down to Evident's existing plain-land rung:
   no invented colour, no extra edge, and the light declaration remains the
   raised face authored in layout-components.css. */
[data-bs-theme="dark"] .page-header-bar {
    background: var(--ev-metal);
}

/* No sidebar-ink override here any more, and its removal is the point. Its
   comment was right — "always light since sidebar always has a dark background"
   — but it implemented that by pointing at --surface, a token that follows the
   PAGE theme. On a surface that deliberately does not follow the page theme,
   that resolved to #1e2127 ink on a #272727 face: 1.08:1, invisible. (#1e2127 was
   --surface's value at the time; cortex-dk1b528 has since neutralised it to
   #212121, so grepping that old hex now finds only this sentence.) Measured
   on the live DOM in dark mode; it does not show up in a diff, because the rule
   was never edited — the face beneath it was.

   The nav ink now comes from --ev-dark-ink / --ev-dark-ink-dim, which are
   theme-independent exactly like the face they sit on, so both themes are
   correct from one declaration. */

/* Mobile hamburger button: no background override needed — it consumes
   --ev-metal-hi, which the dark theme already redefines. The bar colour needs
   no override either: the base rule in layout-chrome.css is already
   `background-color: var(--color-grey-700)`, and the dark-scoped copy that
   used to sit here restated that declaration verbatim. A verbatim restatement
   cannot change a value — it can only add a scope leak, because the guard
   switched it off inside a dark subtree of a light page while the base rule
   kept following the nearest scope correctly. (cortex-w8l9sqr) */

/* Carved baseplate — no dark override needed any more. (cortex-vnt3p6m)
   The base .rounded-light rule is written entirely against --ev-* tokens,
   and tokens.css already remaps the whole material layer per theme, so the
   carve follows the theme without restating a single shadow here. The
   previous override hardcoded rgba(255,255,255,0.04) plus its own inset pair
   and would now fight the base rule rather than extend it. Deleting it is
   the fix; a dark-scoped copy of the same declarations would be the
   compensating layer this codebase is trying to shed.

   The h1-h4 text-shadow reset is likewise gone: the base rule sets
   `text-shadow: none` unconditionally, because shadowed glyphs are forbidden
   in both themes, not just dark. */

/* Notices deliberately have no dark-theme repaint here. Evident owns each
   semantic face and its paired ink; flattening `.ev-notice` at this layer
   destroys that family-wide distinction. */

/* Headings — h4, .lead and .page-header-title had a dark-scoped
   `color: var(--color-primary-dark)` each. All three base rules
   (layout-chrome.css:45 and :25, layout-components.css:86) already declare
   exactly that, against exactly that token, and --color-primary-dark is
   redefined in the dark block at the top of this file. Three verbatim
   restatements, three scope leaks, zero value changes. Gone.
   (cortex-w8l9sqr) */

/* ==========================================================================
   Nested-theme guard audit (cortex-w8l9sqr)

   Every rule that used the

       :is([data-bs-theme="dark"], …) <sel>:where(:not([data-bs-theme="light"] *))

   idiom has now been measured on a live page, in a synthetic
   `[data-bs-theme="dark"]` wrapper, with the page theme set to dark and then
   to light, and each has been resolved. Sixteen rules went in; one comes out —
   the body background overlay above, whose guard is provably inert and which
   is kept deliberately so DarkThemeSelectorTest's ratchet still has a subject.
   Every other dark descendant selector in this file is gone.

   THE IDIOM CANNOT BE FIXED AT THE SELECTOR LEVEL. It is not a guard that was
   written slightly wrong; it is a guard that has no correct form. Without it,
   `:is([data-bs-theme="dark"], …) <sel>` wrongly styles a LIGHT subtree nested
   in a dark page. With it, the rule wrongly switches OFF for a DARK subtree
   nested in a light page, because `:not([data-bs-theme="light"] *)` asks
   whether ANY light ancestor exists, not whether the NEAREST theme scope is
   light — which is the question that actually matters. CSS cannot express
   "nearest scope" in a selector.

   Custom properties can, because they inherit: a value declared in both the
   light and the dark token block resolves at whichever scope is nearest, in
   both nesting directions, with no selector guard at all. So the guard was
   never the defect — it was the symptom. The defect was a dark-only value
   living in a selector instead of in the token layer, and the fix in every
   case below is to put the value back where it can scope.

   The rules resolved here, and how:

     verbatim restatement of a base rule that already used the same
     theme-scoped token — deleted, no value changed in either theme:
       #nav-small .hamburger-inner   h4   .lead   .page-header-title
       .content-wrapper-fw   #user-bar a   #user-bar a:hover
       .list-group-split-actions (its `background` declaration)
       .year-dropdown (its `background` declaration)

     INERT — the declaration painted nothing, because the Evident adapter
     zeroes the border it was colouring. Measured border-*-width: 0px in both
     themes. Same class as the .btn-outline-secondary rim lines noted further
     down this file:
       .card-footer (border-top-color)   .form-control / .form-select
       (border-color)   .year-dropdown (border-color)

     a theme-scoped token already carried the right value, and it was the
     base rule's OWN channel — deleted, both scopes now agree on the token
     (the .list-group-item precedent, cortex-6e8bb2g, stated below):
       .list-group-split-actions (border-left-color, --bs-border-color)
       .breadcrumb-item + .breadcrumb-item::before
       (--bs-breadcrumb-divider-color)
       .year-display:hover (--color-grey-100)

     the surface's real owner already had the selector — deleted here and NOT
     re-homed locally, because evident-bootstrap.css already styles it and a
     Control Center copy would shadow the vendored adapter. The ink opinion it
     carried belongs upstream in cortex/evident; see the note in
     layout-surfaces.css:
       .rounded-light .table thead th

     LOAD-BEARING — deletion would have changed the dark rendering, and no
     token carried the value, so this one was rewritten as an unguarded rule
     against a theme-scoped token and moved to the file owning its surface:
       .card-header.bg-light -> layout-components.css

   Both live-page themes render identically to before.
   ========================================================================== */

/* List groups — no override. `--bs-list-group-border-color` already resolves to
   rgba(245, 245, 245, 0.09) on a dark ground, and it does so through the token
   layer, which means it is correct whether the dark scope is the page or a
   subtree nested inside a light page.

   The hardcoded rgba(255, 255, 255, 0.06) that used to sit here was both a raw
   literal in trunk and NOT scope-independent: its
   `:where(:not([data-bs-theme="light"] *))` guard switches the rule off
   whenever ANY light ancestor exists, even when a nearer dark scope should win.
   So a dark-scoped list rendered one border on a dark page and a different one
   inside a light page. Measured on redesign HEAD, before this bead's page
   existed: outer-dark rgba(255,255,255,0.06) vs outer-light
   rgba(245,245,245,0.09), while the token read rgba(245,245,245,0.09) in both.
   Deleting the override makes both cases take the token and agree.

   The sibling rules that used the same idiom have since been measured the same
   way and are all resolved; see the audit block above.
   (cortex-6e8bb2g, cortex-w8l9sqr) */

/* Negative-x shadow dropped here too — see the light-theme rule in
   layout-entities.css. The border-left carries the seam. (cortex-mn5hkp8)

   The dark-scoped .list-group-split-actions override that stood here is gone
   as well. Its `background` restated the base rule's own
   `var(--bs-list-group-bg, …)`, and its `border-left-color` replaced
   --bs-border-color — the very token the base `border-left` shorthand reads —
   with a literal, and only when the outer page happened to be dark. The token
   is scope-correct in both directions (#3f3f3f dark, rgba(28,28,28,.1) light),
   so both cases now agree on it. Exactly the .list-group-item finding above.
   (cortex-w8l9sqr) */

/* These dark-theme overrides are now REDUNDANT and are removed rather than
   ported. --ev-contact-* and --ev-ambient-* are already redefined inside the
   [data-bs-theme="dark"] scope in tokens.css — with much heavier ink, for the
   reason that file states: a dark floor has far less headroom to darken into.
   The molded pair in layout-surfaces.css therefore adapts by itself, and
   re-stating it here would only re-introduce the offsets. (cortex-mn5hkp8) */

/* The dark-theme .btn-outline-secondary override is gone too, and this one is
   worth stating because deleting the light rule is what EXPOSED it.
   (cortex-ojqr4jy)

   It was banner'd "boost contrast in dark mode", and against Bootstrap's own
   #6c757d outline that is what it did. Against the adapter it did the opposite:
   --bs-btn-color: var(--text-dim) is #a3a3a3, which on the dark neutral key
   face --ev-metal-hi #272727 measures ~5.9:1, where the --ev-ink #ebebeb the
   adapter already supplies measures ~11.6:1. The override was DIMMING the
   label it claimed to boost, and --ev-ink is theme-scoped in evident.css, so
   nothing here had to restate it.

   The two rim lines were inert either way — the adapter sets
   `--bs-btn-border-width: 0`, so a border COLOUR paints nothing.

   --bs-btn-hover-bg: var(--text-faint) is the one that mattered. It is a face
   swap on hover, the same channel error as the light rule, and it was masked
   only because layout-controls.css was setting a literal hover background that
   outranked it. Removing that mask without removing this would have traded a
   translucent key in light for a key that turns #909090 on hover in dark. Both
   go; hover is FINISH in both themes and the adapter's contact/ambient step
   already carries it. Same reasoning as the redundant-override note above. */

/* Year selector pills — both dark overrides removed. (cortex-w8l9sqr)

   .year-display:hover swapped the base rule's `var(--color-grey-100)` for a
   literal 8% white. --color-grey-100 is redefined in the dark block at the top
   of this file (#eee light, #313131 dark), so the base rule was already
   following the theme; the literal only ever added the scope leak.

   .year-dropdown restated `background: var(--color-white)` through the
   equivalent --bs-body-bg (both #0e0e0e in dark), and set a border-color on a
   plate the base rule gives no border at all — measured border-width 0px in
   both themes, so that declaration painted nothing. */

/* No .user-avatar override here any more. It used to add `0 0 0 1px` in white
   "for visibility against dark backgrounds" — an outer lit hairline drawn all
   the way around a RAISED key, which is the signature defect of this language:
   a burr belongs only where material was actually removed, and nothing is cut
   around an avatar. Visibility is now carried by --ev-contact-1, which the dark
   theme already redefines to a much heavier near-black falloff. */

/* ==========================================================================
   Print Styles
   ========================================================================== */

@media print {
    /* Hide navigation sidebar */
    #nav {
        display: none !important;
    }

    /* Convert fixed header to static for proper flow */
    .page-header-bar {
        position: static !important;
        left: auto !important;
        right: auto !important;
        /* backdrop-filter reset dropped — the bar no longer carries one.
           Paper is a different medium with no material language, so the printed
           rule keeps a plain hairline and drops the on-screen falloff. */
        box-shadow: none !important;
        background: transparent !important;
        border-bottom: 1px solid var(--border-strong) !important;
    }

    /* Remove the spacer padding since header is no longer fixed */
    .page-header-bar + #content-wrapper {
        padding-top: 0 !important;
    }

    .page-header-bar.expandable + #content-wrapper {
        padding-top: 0 !important;
    }

    /* Hide user profile/login area in print */
    .page-header-user,
    .page-header-user-expanded,
    .page-header-logout {
        display: none !important;
    }

    /* Adjust content wrapper for print (no nav offset) */
    #content-wrapper {
        margin-left: 0 !important;
        padding-left: 1cm !important;
        padding-right: 1cm !important;
    }

    /* Hide interactive elements that don't make sense in print */
    .btn,
    .dropdown-toggle,
    .collapse-toggle {
        display: none !important;
    }

    /* Show links with their URLs (optional, helpful for print) */
    a[href]:after {
        content: none; /* Don't show URLs by default, too cluttered */
    }

    /* Reset backgrounds for better print appearance */
    .rounded-white,
    .rounded-light,
    .card {
        background: var(--surface) !important;
        box-shadow: none !important;
        border: 1px solid var(--border) !important;
    }
}
