/*
 * Banyan design tokens — UX-0006 §4 (design-system and auth UX contract).
 *
 * Every colour role below is a CSS custom property referenced by role
 * (`--bn-primary`, `--bn-surface`, ...), never a raw hex in a component.
 * The two brand primaries and the corrected state palette are the only hex
 * values in the theme; the rest of the panel derives from these tokens.
 *
 * Modes (§5) are token swaps, never CSS filters. The shape-first state glyphs
 * (hollow/filled dot, clock, triangle, padlock) carry state in every mode
 * because colour is a reinforcement, not the carrier (UX-0004 §6.2).
 */

:root,
:root[data-banyan-mode='light'] {
    --bn-primary: #2563eb;
    --bn-primary-hover: #1d4ed8;
    --bn-primary-fg: #ffffff;
    --bn-composed: #0f172a;
    --bn-text: #1e293b;
    --bn-text-muted: #6b7280;
    --bn-text-disabled: #9ca3af;
    --bn-surface: #ffffff;
    --bn-surface-2: #f9fafb;
    --bn-surface-3: #e5e7eb;
    --bn-border-subtle: #f1f5f9;
    --bn-border: #e2e8f0;
    --bn-border-strong: #cbd5e1;
    --bn-danger: #b91c1c;
    --bn-warning: #b45309;
    --bn-success: #15803d;

    --bn-state-draft: #6b7280;
    --bn-state-published: #059669;
    --bn-state-scheduled: #2563eb;
    --bn-state-expired: #b45309;
    --bn-state-locked: #78716c;

    --bn-focus-ring: #2563eb;
    --bn-focus-grabbed: #d97706;

    --bn-font-sans: 'Inter Variable', 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI',
        'Noto Sans', 'Noto Sans HK', 'Noto Sans TC', 'Noto Sans SC', sans-serif;
    --bn-font-mono: 'JetBrains Mono', ui-monospace, 'SFMono-Regular', 'Menlo', monospace;

    --bn-text-3xl: 30px;
    --bn-text-3xl-height: 1.2;
    --bn-text-2xl: 24px;
    --bn-text-2xl-height: 1.3;
    --bn-text-xl: 18px;
    --bn-text-xl-height: 1.4;
    --bn-text-lg: 15px;
    --bn-text-lg-height: 1.45;
    --bn-text-base: 14px;
    --bn-text-base-height: 1.6;
    --bn-text-sm: 12px;
    --bn-text-sm-height: 1.5;
    --bn-text-xs: 11px;
    --bn-text-xs-height: 1.4;

    /*
     * Spacing (§4.3): a 4px grid. The number in the token is the multiplier, so
     * --bn-space-6 is 6 x 4px = 24px and the ladder stays readable when a rule
     * mixes steps. Components use the 8px steps; the 4px step is for dense
     * inline metadata and icon-to-text gaps.
     */
    --bn-space-1: 4px;
    --bn-space-2: 8px;
    --bn-space-3: 12px;
    --bn-space-4: 16px;
    --bn-space-5: 20px;
    --bn-space-6: 24px;
    --bn-space-8: 32px;
    --bn-space-10: 40px;
    --bn-space-12: 48px;

    --bn-radius-input: 6px;
    --bn-radius-card: 6px;
    --bn-radius-dialog: 8px;

    --bn-density: compact;

    /*
     * Control sizing. --bn-control-height is the compact 32px control the dense
     * surfaces build to; --bn-target-min is the 28px hit area the shell owes
     * every icon-only target (UX-0006 §6, sidebar/tree/locale switcher).
     */
    --bn-control-height: 32px;
    --bn-target-min: 28px;

    --bn-elevation-card: 0 1px 2px 0 rgb(15 23 42 / 0.06);
    --bn-elevation-dropdown: 0 4px 6px -1px rgb(15 23 42 / 0.1);
    --bn-elevation-modal: 0 10px 15px -3px rgb(15 23 42 / 0.1);

    --bn-overlay: rgb(15 23 42 / 0.48);

    --bn-auth-hero-start: #0f172a;
    --bn-auth-hero-mid: #1e3a5f;
    --bn-auth-hero-end: #0f2744;
    --bn-auth-hero-text: #e2e8f0;
    --bn-auth-hero-accent: #93c5fd;
    --bn-auth-hero-on-surface: #f8fafc;
    --bn-auth-hero-muted: #94a3b8;
    --bn-auth-hero-mask: #000000;
    --bn-auth-preview-surface: #ffffff;
    --bn-auth-preview-chrome: #f8fafc;
    --bn-auth-preview-border: #e2e8f0;
    --bn-auth-preview-dot: #cbd5e1;
    --bn-auth-preview-text: #0f172a;
    --bn-auth-preview-muted: #64748b;
    --bn-auth-preview-soft: #475569;
    --bn-auth-preview-sky: #bfdbfe;
    --bn-auth-preview-sea: #1d4ed8;
    --bn-auth-preview-sun: #fbbf24;
    --bn-auth-preview-success: #15803d;
}

/*
 * Dark mode — reverse surfaces and text; the primaries stay. State badges in
 * dark mode carry a computed table owned by the theme spec (UX-0004 §11.1 open
 * question); the shapes carry the state until then.
 */
html.dark {
    --bn-composed: #f1f5f9;
    --bn-text: #e2e8f0;
    --bn-text-muted: #94a3b8;
    --bn-text-disabled: #64748b;
    --bn-surface: #0f172a;
    --bn-surface-2: #1e293b;
    --bn-surface-3: #334155;
    --bn-border-subtle: #1e293b;
    --bn-border: #334155;
    --bn-border-strong: #475569;
    --bn-overlay: rgb(2 6 23 / 0.6);
}

/*
 * High contrast — push text to full contrast, borders to the strong role.
 */
@media (prefers-contrast: more) {
    :root {
        --bn-text: #0f172a;
        --bn-text-muted: #1e293b;
        --bn-border-subtle: #e2e8f0;
        --bn-border: #cbd5e1;
        --bn-border-strong: #0f172a;
    }
}

/*
 * Monochrome (mourning period, ADR-9) — a token swap, never
 * filter: grayscale(1) (UX-0004 §7.2). Each grey is derived from the WCAG
 * luminance of the light role it replaces and retains >= 3:1 against the
 * surface; the state SHAPES carry the distinction (UX-0004 §6.2).
 */
:root[data-banyan-mode='monochrome'] {
    --bn-primary: #475569;
    --bn-primary-hover: #334155;
    --bn-primary-fg: #ffffff;
    --bn-composed: #0f172a;
    --bn-text: #334155;
    --bn-text-muted: #6b7280;
    --bn-text-disabled: #9ca3af;
    --bn-danger: #475569;
    --bn-warning: #57534e;
    --bn-success: #4b5563;
    --bn-state-draft: #6b7280;
    --bn-state-published: #4b5563;
    --bn-state-scheduled: #475569;
    --bn-state-expired: #57534e;
    --bn-state-locked: #6b7280;
    --bn-focus-ring: #0f172a;
    --bn-focus-grabbed: #0f172a;
}

/*
 * Reduced motion — every transition collapses to a <=100ms simple fade or a
 * static state; no transform animation (UX-0006 §7.5).
 */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/*
 * Reduced transparency — the modal overlay and any translucent surface render
 * as solid; no backdrop-blur (UX-0006 §7.5).
 */
@media (prefers-reduced-transparency: reduce) {
    .fi-modal-window,
    .fi-modal {
        backdrop-filter: none !important;
    }

    :root {
        --bn-overlay: rgb(15 23 42 / 1);
    }
}

/*
 * Forced colours (Windows High Contrast) — use CSS4 system colours, never a
 * hard-coded hue (UX-0004 §8.1).
 */
@media (forced-colors: active) {
    :root {
        --bn-primary: LinkText;
        --bn-primary-hover: LinkText;
        --bn-primary-fg: CanvasText;
        --bn-composed: CanvasText;
        --bn-text: CanvasText;
        --bn-text-muted: CanvasText;
        --bn-surface: Canvas;
        --bn-surface-2: Canvas;
        --bn-surface-3: Canvas;
        --bn-border-subtle: CanvasText;
        --bn-border: CanvasText;
        --bn-border-strong: CanvasText;
        --bn-danger: CanvasText;
        --bn-warning: CanvasText;
        --bn-success: CanvasText;
        --bn-focus-ring: Highlight;
        --bn-auth-hero-start: Canvas;
        --bn-auth-hero-mid: Canvas;
        --bn-auth-hero-end: Canvas;
        --bn-auth-hero-text: CanvasText;
        --bn-auth-hero-accent: LinkText;
        --bn-auth-hero-on-surface: CanvasText;
        --bn-auth-hero-muted: CanvasText;
        --bn-auth-hero-mask: CanvasText;
        --bn-auth-preview-surface: Canvas;
        --bn-auth-preview-chrome: Canvas;
        --bn-auth-preview-border: CanvasText;
        --bn-auth-preview-dot: CanvasText;
        --bn-auth-preview-text: CanvasText;
        --bn-auth-preview-muted: CanvasText;
        --bn-auth-preview-soft: CanvasText;
        --bn-auth-preview-sky: Canvas;
        --bn-auth-preview-sea: Canvas;
        --bn-auth-preview-sun: Canvas;
        --bn-auth-preview-success: Canvas;
    }
}

/* ── The panel and auth shell map the tokens onto Filament's surfaces ─────── */

.fi-body {
    background-color: var(--bn-surface-2);
    color: var(--bn-text);
    font-family: var(--bn-font-sans);
}

.fi-simple-layout {
    background-color: var(--bn-surface-2);
}

/*
 * Enterprise auth split (UX-0006 §7.1): form column left, trust hero right
 * from the md breakpoint; below md the form stacks above a compact hero.
 */
.fi-simple-layout:has(.bn-auth-hero) {
    display: flex;
    flex-direction: column;
    min-height: 100dvh;
    background: var(--bn-surface);
}

.fi-simple-layout:has(.bn-auth-hero) .fi-simple-main-ctn {
    flex: 1 1 auto;
    display: flex;
    align-items: stretch;
    justify-content: center;
    padding: clamp(1.5rem, 4vw, 3rem);
    background: var(--bn-surface);
}

.fi-simple-layout:has(.bn-auth-hero) .fi-simple-main {
    width: 100%;
    max-width: 28rem;
    margin-inline: auto;
    border-radius: 0;
    box-shadow: none;
    background: transparent;
}

.fi-simple-layout:has(.bn-auth-hero) .fi-simple-page {
    display: flex;
    flex-direction: column;
    min-height: 100%;
    width: 100%;
}

.fi-simple-layout:has(.bn-auth-hero) .fi-simple-page-content {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: var(--bn-space-5);
}

.fi-simple-layout:has(.bn-auth-hero) .fi-simple-header {
    text-align: start;
    margin: 0;
}

.fi-simple-layout:has(.bn-auth-hero) .fi-simple-header-heading {
    font-size: clamp(1.75rem, 2.5vw, 2rem);
    line-height: 1.2;
    font-weight: 600;
    letter-spacing: -0.02em;
}

.fi-simple-layout:has(.bn-auth-hero) .fi-simple-header-subheading {
    margin-top: var(--bn-space-2);
    font-size: var(--bn-text-base);
    line-height: var(--bn-text-base-height);
    color: var(--bn-text-muted);
}

.bn-auth-form__brand {
    margin-bottom: var(--bn-space-6);
}

.bn-auth-forgot {
    margin: calc(var(--bn-space-2) * -1) 0 var(--bn-space-2);
    text-align: end;
}

.bn-auth-forgot a {
    color: var(--bn-primary);
    font-size: var(--bn-text-sm);
    font-weight: 500;
    text-decoration: none;
}

.bn-auth-forgot a:hover {
    text-decoration: underline;
}

.bn-auth-footer {
    margin-top: auto;
    padding-top: var(--bn-space-6);
    text-align: center;
    font-size: var(--bn-text-sm);
    color: var(--bn-text-muted);
}

.bn-auth-footer a {
    color: var(--bn-primary);
    font-weight: 600;
    text-decoration: none;
}

.bn-auth-footer a:hover {
    text-decoration: underline;
}

.fi-simple-layout:has(.bn-auth-hero) main form {
    display: flex;
    flex-direction: column;
    gap: var(--bn-space-4);
    padding: 0;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    background: transparent;
}

.fi-simple-layout:has(.bn-auth-hero) .fi-input-wrp {
    border-radius: 0.5rem;
    transition:
        border-color 150ms ease,
        box-shadow 150ms ease;
}

.fi-simple-layout:has(.bn-auth-hero) .fi-input-wrp:focus-within {
    border-color: var(--bn-primary);
    box-shadow: 0 0 0 3px color-mix(in oklab, var(--bn-primary) 18%, transparent);
}

.fi-simple-layout:has(.bn-auth-hero) .fi-btn:not(.fi-outlined).fi-color-primary {
    min-height: 2.75rem;
    border-radius: 0.5rem;
    transition:
        background-color 150ms ease,
        box-shadow 150ms ease,
        transform 150ms ease;
}

.fi-simple-layout:has(.bn-auth-hero) .fi-btn:not(.fi-outlined).fi-color-primary:hover {
    transform: translateY(-1px);
}

.fi-simple-layout:has(.bn-auth-hero) .fi-btn:not(.fi-outlined).fi-color-primary:focus-visible {
    outline: 2px solid var(--bn-primary);
    outline-offset: 2px;
}

.fi-simple-layout:has(.bn-auth-hero) .fi-btn[wire\\:loading] {
    opacity: 0.88;
    pointer-events: none;
}

.bn-auth-hero {
    position: relative;
    overflow: hidden;
    isolation: isolate;
    display: none;
    min-height: 18rem;
    background:
        radial-gradient(40rem 30rem at 20% 0%,
            color-mix(in oklab, var(--bn-primary) 35%, transparent), transparent 60%),
        linear-gradient(165deg, var(--bn-auth-hero-start), var(--bn-auth-hero-mid) 55%, var(--bn-auth-hero-end));
    color: var(--bn-auth-hero-text);
}

.bn-auth-hero__mesh {
    position: absolute;
    inset: 0;
    opacity: 0.45;
    background-image:
        linear-gradient(color-mix(in oklab, var(--bn-auth-hero-on-surface) 8%, transparent) 1px, transparent 1px),
        linear-gradient(90deg, color-mix(in oklab, var(--bn-auth-hero-on-surface) 8%, transparent) 1px, transparent 1px);
    background-size: 2.5rem 2.5rem;
    mask-image: radial-gradient(circle at 50% 40%, var(--bn-auth-hero-mask) 15%, transparent 72%);
    pointer-events: none;
}

.bn-auth-hero__content {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--bn-space-6);
    min-height: inherit;
    padding: clamp(2rem, 5vw, 4rem);
    text-align: center;
}

.bn-auth-hero__tagline {
    margin: 0;
    max-width: 30rem;
    font-size: clamp(1.25rem, 2.4vw, 1.625rem);
    font-weight: 600;
    line-height: 1.35;
    letter-spacing: -0.015em;
    color: var(--bn-auth-hero-on-surface);
}

/* Product preview: a small editor window in the brand's own tokens. */
.bn-auth-hero__preview {
    width: min(100%, 30rem);
    transform: perspective(1400px) rotateX(4deg) rotateY(-6deg);
    filter: drop-shadow(0 30px 45px color-mix(in oklab, var(--bn-auth-hero-start) 70%, transparent));
}

.bn-auth-hero__window {
    overflow: hidden;
    border: 1px solid color-mix(in oklab, var(--bn-auth-hero-on-surface) 18%, transparent);
    border-radius: 0.875rem;
    background: color-mix(in oklab, var(--bn-auth-hero-on-surface) 96%, var(--bn-auth-hero-start));
    color: var(--bn-auth-preview-text);
    text-align: start;
}

.bn-auth-hero__chrome {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.625rem 0.875rem;
    border-bottom: 1px solid var(--bn-auth-preview-border);
    background: var(--bn-auth-preview-chrome);
}

.bn-auth-hero__chrome > span {
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 999px;
    background: var(--bn-auth-preview-dot);
}

.bn-auth-hero__crumb {
    margin: 0 0 0 0.5rem;
    font-size: 0.6875rem;
    color: var(--bn-auth-preview-muted);
}

.bn-auth-hero__body {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 9.5rem;
    gap: 0.875rem;
    padding: 0.875rem;
}

.bn-auth-hero__langs {
    display: flex;
    gap: 0.25rem;
    margin-bottom: 0.625rem;
}

.bn-auth-hero__lang {
    padding: 0.0625rem 0.4375rem;
    border: 1px solid var(--bn-auth-preview-border);
    border-radius: 999px;
    font-size: 0.625rem;
    font-weight: 600;
    color: var(--bn-auth-preview-soft);
}

.bn-auth-hero__lang.is-on {
    border-color: var(--bn-primary);
    background: var(--bn-primary);
    color: var(--bn-auth-preview-surface);
}

.bn-auth-hero__title {
    margin: 0 0 0.625rem;
    font-size: 0.875rem;
    font-weight: 600;
    line-height: 1.3;
}

.bn-auth-hero__line {
    display: block;
    height: 0.375rem;
    margin-bottom: 0.4375rem;
    border-radius: 999px;
    background: var(--bn-auth-preview-border);
}

.bn-auth-hero__line.is-short {
    width: 60%;
}

.bn-auth-hero__image {
    height: 4.25rem;
    margin-top: 0.75rem;
    border-radius: 0.5rem;
    background:
        radial-gradient(1.25rem 1.25rem at 78% 30%, var(--bn-auth-preview-sun) 98%, transparent),
        linear-gradient(180deg, var(--bn-auth-preview-sky) 0 58%, var(--bn-auth-preview-sea) 58% 100%);
}

.bn-auth-hero__side {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 0.625rem;
    border: 1px solid var(--bn-auth-preview-border);
    border-radius: 0.625rem;
    background: var(--bn-auth-preview-surface);
}

.bn-auth-hero__side-label {
    margin: 0;
    font-size: 0.625rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--bn-auth-preview-muted);
}

.bn-auth-hero__steps {
    display: grid;
    gap: 0.375rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.bn-auth-hero__steps li {
    position: relative;
    padding-inline-start: 1.125rem;
    font-size: 0.6875rem;
    color: var(--bn-auth-preview-muted);
}

.bn-auth-hero__steps li::before {
    content: "";
    position: absolute;
    inset-inline-start: 0;
    top: 0.1875rem;
    width: 0.5625rem;
    height: 0.5625rem;
    border: 1.5px solid var(--bn-auth-preview-dot);
    border-radius: 999px;
}

.bn-auth-hero__steps li.is-done {
    color: var(--bn-auth-preview-text);
}

.bn-auth-hero__steps li.is-done::before {
    border-color: var(--bn-auth-preview-success);
    background: var(--bn-auth-preview-success);
}

.bn-auth-hero__steps li.is-now {
    font-weight: 600;
    color: var(--bn-auth-preview-text);
}

.bn-auth-hero__steps li.is-now::before {
    border-color: var(--bn-primary);
    box-shadow: 0 0 0 3px color-mix(in oklab, var(--bn-primary) 25%, transparent);
}

.bn-auth-hero__button {
    margin-top: auto;
    padding: 0.3125rem 0.5rem;
    border-radius: 0.375rem;
    background: var(--bn-auth-preview-success);
    font-size: 0.6875rem;
    font-weight: 600;
    text-align: center;
    color: var(--bn-auth-preview-surface);
}

.bn-auth-hero__points {
    display: grid;
    gap: 0.625rem;
    max-width: 28rem;
    margin: 0;
    padding: 0;
    list-style: none;
    text-align: start;
}

.bn-auth-hero__points li {
    position: relative;
    padding-inline-start: 1.75rem;
    font-size: 0.9375rem;
    line-height: 1.5;
    color: var(--bn-auth-hero-text);
}

.bn-auth-hero__points li::before {
    content: "";
    position: absolute;
    inset-inline-start: 0;
    top: 0.3125rem;
    width: 1rem;
    height: 1rem;
    border-radius: 999px;
    background:
        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 8.5l2.5 2.5L12 5.5' fill='none' stroke='%230f172a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 0.75rem no-repeat,
        var(--bn-auth-hero-accent);
}

@media (prefers-reduced-motion: reduce) {
    .bn-auth-hero__preview {
        transform: none;
    }
}

@media (max-width: 47.99rem) {
    .bn-auth-hero__preview,
    .bn-auth-hero__points {
        display: none;
    }
}

@media (min-width: 48rem) {
    .fi-simple-layout:has(.bn-auth-hero) {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        grid-template-rows: 1fr;
    }

    .fi-simple-layout:has(.bn-auth-hero) .fi-simple-main-ctn {
        grid-column: 1;
        grid-row: 1;
        min-height: 100dvh;
        border-inline-end: 1px solid var(--bn-border);
    }

    .fi-simple-layout:has(.bn-auth-hero) .bn-auth-hero {
        display: block;
        grid-column: 2;
        grid-row: 1;
        min-height: 100dvh;
    }
}

@media (max-width: 47.99rem) {
    .fi-simple-layout:has(.bn-auth-hero) .bn-auth-hero {
        display: block;
        order: 2;
    }

    .fi-simple-layout:has(.bn-auth-hero) .fi-simple-main-ctn {
        order: 1;
    }
}

.fi-simple-main {
    border-radius: var(--bn-radius-card);
}

.fi-simple-header-heading,
.fi-simple-header-subheading {
    color: var(--bn-text);
}

/*
 * Buttons. Filament v5 drives a filled button from four custom-property pairs —
 * `--bg`/`--text` and their `--hover-*` / `--dark-*` / `--dark-hover-*` twins,
 * read by `.fi-btn:not(.fi-outlined).fi-color:not(label)` in the compiled
 * sheet. There is no `--btn-color` in Filament v5, which is why the previous
 * mapping was inert: the shades came from the palette Filament generates from
 * `#2563eb`, whose OKLCH 600 step is lighter and less saturated than the brand
 * primary, so its WCAG picker fell back to the pale 400 fill with navy text
 * that reads as washed out. Pin the roles to the frozen tokens instead.
 *
 * These rules are deliberately unlayered: Filament ships `.fi-bg-color-*` and
 * friends inside `@layer utilities`, and an unlayered declaration outranks any
 * layer regardless of specificity or source order.
 */
.fi-btn:not(.fi-outlined).fi-color-primary,
.fi-btn:not(.fi-outlined).fi-color-danger,
.fi-btn:not(.fi-outlined).fi-color-warning,
.fi-btn:not(.fi-outlined).fi-color-success {
    --text: var(--bn-primary-fg);
    --hover-text: var(--bn-primary-fg);
    --dark-text: var(--bn-primary-fg);
    --dark-hover-text: var(--bn-primary-fg);
}

.fi-btn:not(.fi-outlined).fi-color-primary {
    --bg: var(--bn-primary);
    --hover-bg: var(--bn-primary-hover);
    --dark-bg: var(--bn-primary);
    --dark-hover-bg: var(--bn-primary-hover);
}

/* Filament derives a pale primary badge text shade from the panel palette.
   Keep compact status chips on the Banyan primary role so labels remain AA
   readable on their light tint. */
.fi-badge.fi-color-primary {
    --text: var(--bn-primary);
    --dark-text: var(--bn-primary-fg);
}

/*
 * §4.1 freezes a hover value for the primary only, so the other semantic roles
 * derive theirs by darkening the role towards --bn-composed. A computed value,
 * never a new brand hex.
 */
.fi-btn:not(.fi-outlined).fi-color-danger {
    --bg: var(--bn-danger);
    --hover-bg: color-mix(in oklab, var(--bn-danger) 85%, var(--bn-composed));
    --dark-bg: var(--bn-danger);
    --dark-hover-bg: color-mix(in oklab, var(--bn-danger) 85%, var(--bn-composed));
}

.fi-btn:not(.fi-outlined).fi-color-warning {
    --bg: var(--bn-warning);
    --hover-bg: color-mix(in oklab, var(--bn-warning) 85%, var(--bn-composed));
    --dark-bg: var(--bn-warning);
    --dark-hover-bg: color-mix(in oklab, var(--bn-warning) 85%, var(--bn-composed));
}

.fi-btn:not(.fi-outlined).fi-color-success {
    --bg: var(--bn-success);
    --hover-bg: color-mix(in oklab, var(--bn-success) 85%, var(--bn-composed));
    --dark-bg: var(--bn-success);
    --dark-hover-bg: color-mix(in oklab, var(--bn-success) 85%, var(--bn-composed));
}

/*
 * Filament treats `gray` as a button's default and emits no colour classes for
 * it at all, so a secondary action renders white-on-white with no edge. Give it
 * the neutral surface and the 1px border tier the system asks for (§4.3,
 * borders over shadows). The transparent border on the coloured buttons keeps
 * every button the same height.
 */
.fi-btn:not(.fi-outlined) {
    border: 1px solid transparent;
}

.fi-btn:not(.fi-outlined):not(.fi-color) {
    background-color: var(--bn-surface);
    border-color: var(--bn-border-strong);
    color: var(--bn-text);
}

.fi-btn:not(.fi-outlined):not(.fi-color):not(.fi-disabled):not([disabled]):hover {
    background-color: var(--bn-surface-2);
}

.fi-btn:not(.fi-color) > .fi-icon {
    color: var(--bn-text-muted);
}

.fi-sidebar {
    background-color: var(--bn-surface-2);
}

.fi-topbar {
    background-color: var(--bn-surface);
    border-bottom: 1px solid var(--bn-border);
}

.fi-ta {
    --table-border-color: var(--bn-border);
}

.fi-input-wrp,
.fi-input {
    border-color: var(--bn-border);
    border-radius: var(--bn-radius-input);
}

.fi-card,
.fi-section {
    border-color: var(--bn-border);
    border-radius: var(--bn-radius-card);
    box-shadow: var(--bn-elevation-card);
}

.fi-modal-window {
    border-radius: var(--bn-radius-dialog);
    box-shadow: var(--bn-elevation-modal);
}

/*
 * Focus treatment (UX-0006 §7.5, frozen): every focusable element shows the
 * --bn-primary ring, identical in light and dark mode, never removed without a
 * replacement. Grabbed/move focus uses --bn-focus-grabbed (UX-0004 §6.4).
 */
:focus-visible {
    outline: 2px solid var(--bn-focus-ring);
    outline-offset: 2px;
}

:root[data-banyan-mode='monochrome'] :focus-visible {
    outline-color: var(--bn-focus-ring);
}

/*
 * Motion (UX-0006 §7.5, frozen): micro 100ms, panels 150ms, page 200ms, all
 * ease-out. Reduced-motion collapses every transition (see the media query
 * above), so a drag/drop stays interruptible and never blocks manipulation.
 */
.fi-btn,
.fi-link,
.fi-icon-btn,
.fi-input,
.fi-ta-row,
.fi-sidebar-item,
.fi-topbar-item {
    transition:
        color 100ms ease-out,
        background-color 100ms ease-out,
        border-color 100ms ease-out;
}

.fi-modal-window,
.fi-dropdown-panel {
    transition: opacity 150ms ease-out;
}

/*
 * Page title at --bn-text-2xl and body at --bn-text-base, per §4.2. Filament v5
 * names the page title `.fi-header-heading` — the `.fi-page-heading-title` this
 * rule used before is not in the compiled sheet, so the title kept Filament's
 * own 30px/700. The weight is capped at 600: §4.2 allowed 700 for the page
 * title, and the enterprise remediation pass drops it so no weight above 600
 * renders anywhere in the panel (docs/plans/2026-08-enterprise-admin-ux.md,
 * "Design targets").
 */
.fi-header-heading {
    font-size: var(--bn-text-2xl);
    line-height: var(--bn-text-2xl-height);
    font-weight: 600;
}

/*
 * ── Status chip ──────────────────────────────────────────────────────────────
 *
 * The 5-state workflow chip, built on the frozen --bn-state-* palette. One
 * component for every surface that shows a state: list tables, tree rows, the
 * edit-screen header and the workflow queues.
 *
 * The colour is a reinforcement, never the carrier: `.bn-chip__glyph` is the
 * shape slot (hollow dot / filled dot / clock / triangle / padlock, UX-0004
 * §6.2) and it is what survives monochrome, where the --bn-state-* tokens all
 * swap to near-identical greys. Monochrome therefore needs no rule of its own —
 * the chip reads the tokens, and the token swap is the mode.
 */
.bn-chip {
    --bn-chip-color: var(--bn-state-draft);

    display: inline-flex;
    align-items: center;
    gap: var(--bn-space-1);
    padding: 2px var(--bn-space-2);
    border: 1px solid var(--bn-chip-color);
    border-radius: 999px;
    background-color: color-mix(in oklab, var(--bn-chip-color) 10%, var(--bn-surface));
    /* Status colour stays on the border and glyph. The label uses the normal
       text role so every state remains readable on its tinted surface. */
    color: var(--bn-text);
    font-size: var(--bn-text-sm);
    line-height: var(--bn-text-sm-height);
    font-weight: 500;
    white-space: nowrap;
}

.bn-chip__glyph {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 12px;
    height: 12px;
    color: var(--bn-chip-color);
}

.bn-chip--draft {
    --bn-chip-color: var(--bn-state-draft);
}

.bn-chip--published {
    --bn-chip-color: var(--bn-state-published);
}

.bn-chip--scheduled {
    --bn-chip-color: var(--bn-state-scheduled);
}

.bn-chip--expired {
    --bn-chip-color: var(--bn-state-expired);
}

.bn-chip--locked {
    --bn-chip-color: var(--bn-state-locked);
}

/*
 * "Untranslated" is the amber the tri-state calls for (UX-0001 §3.2) and reuses
 * the frozen state palette rather than introducing a sixth hue for it: expired
 * and untranslated are both "this needs attention before it ships", and the
 * chip never appears on the same surface as an expiry.
 */
.bn-chip--untranslated {
    --bn-chip-color: var(--bn-state-expired);
}

/*
 * Dark mode: the state hexes are chosen for 3:1+ against white and are too dark
 * to carry 12px label text on --bn-surface. UX-0004 §11.1 leaves the dark-mode
 * state table open, so the label falls back to --bn-text rather than inventing
 * one; the border and the glyph keep the state hue (>=3:1 as a non-text object,
 * 1.4.11) and the shape keeps the meaning.
 */
html.dark .bn-chip {
    background-color: color-mix(in oklab, var(--bn-chip-color) 18%, var(--bn-surface));
    border-color: color-mix(in oklab, var(--bn-chip-color) 60%, var(--bn-surface));
    color: var(--bn-text);
}

/* Grace-period reminder for a role that requires two-factor authentication. */
.bn-mfa-banner {
    margin-bottom: 1rem;
    padding: 0.75rem 1rem;
    border-radius: 0.5rem;
    border: 1px solid var(--bn-warning);
    background: var(--bn-surface-2);
    color: var(--bn-text);
}

.bn-mfa-banner a {
    font-weight: 600;
    text-decoration: underline;
}
