/* Copyright (c) 2026 Bc. Jan Krejčí. All rights reserved.                  */
/* Proprietary and confidential. See LICENSE in the project root.           */

/*
 * Krejci.Forge.UI.Components — canonical stylesheet
 *
 * Design-system styling surface. All components in this package emit
 * semantic BEM classes (forge-{component}, forge-{component}__{element},
 * forge-{component}--{modifier}) and all visual properties flow from
 * design tokens (var(--accent-*), --surface-*, --text-*, --spacing-*, etc.)
 * resolved at runtime by Krejci.Forge.UI.DesignTokens + UI.Themes.
 *
 * Driven by ADR 027 — never hardcode colors/spacing/motion; always use tokens.
 * To re-skin: override tokens in a consumer stylesheet loaded AFTER this one.
 *
 * Sections:
 *   1. Fallback tokens        — in case UI.DesignTokens is not loaded
 *   2. Base + reset           — forge-prose, focus ring, scrollbars
 *   3. Layout                 — shell, topbar, sidebar, content, page
 *   4. Navigation             — nav items, breadcrumbs, tabs
 *   5. Actions                — buttons, icon buttons
 *   6. Forms                  — field, input, textarea, select, checkbox
 *   7. Data display           — card, kpi card, avatar, table
 *   8. Feedback               — alert, spinner, empty state, loading
 *   9. Dialog / modal         — dialog, backdrop
 *   10. Search                — topbar search + mobile collapse
 *   11. Chart                 — svg chart container + primitives
 *   12. Auth surfaces         — shared layout for Identity pages
 *   13. Utility               — minimal set (forge-visually-hidden, forge-stack, forge-row)
 */

/* ---------------------------------------------------------------- */
/* 1. Fallback tokens (inert defaults if UI.DesignTokens is absent) */
/* ---------------------------------------------------------------- */
:root {
    /* ----- Component vocabulary mapped onto Forge Dashboard tokens ----- */
    /*
     * The component-level vocabulary (--surface-sN, --text-tN, --border-bN,
     * --accent-base, --semantic-*) targets the Forge Dashboard tokens emitted
     * by forge-dashboard.css under [data-theme="dark"|"light"]. The fallback
     * after the comma is used when forge-dashboard.css is NOT loaded (e.g. an
     * extracted component preview in Storybook or a one-off integration); the
     * dashboard tokens flip per data-theme so this single mapping handles
     * both light and dark without per-theme overrides on the component side.
     *
     * Without this var(--bg-N) bridge, forge-page / forge-card / forge-button
     * remained light even under data-theme="dark" because the explicit
     * literal hex values below shadowed the dashboard tokens.
     */
    --surface-s0: var(--bg-1, #f7f8fa);
    --surface-s1: var(--bg-2, #ffffff);
    --surface-s2: var(--bg-2, #f1f3f8);
    --surface-s3: var(--bg-3, #e9ecf2);
    --surface-s4: var(--bg-4, #dfe3eb);
    --surface-s5: var(--bg-4, #c8cfdb);
    --text-t1:    var(--fg-1, #1e2840);
    --text-t2:    var(--fg-2, #5a6780);
    --text-t3:    var(--fg-3, #667085);
    --text-t4:    var(--fg-4, #8a94a8);
    --border-b0:  var(--line, rgba(0, 0, 0, 0.04));
    --border-b1:  var(--line, rgba(0, 0, 0, 0.08));
    --border-b2:  var(--line-strong, rgba(0, 0, 0, 0.13));
    --border-b3:  var(--line-accent, rgba(0, 0, 0, 0.22));
    --semantic-success: var(--ok, #16a34a);
    --semantic-warning: var(--warn, #d88708);
    --semantic-danger:  var(--bad, #dc2626);
    --semantic-info:    var(--info, #0284c7);
    /* Accent token chain — hover/dim are DERIVED from base via color-mix
       so every accent (any colour the consumer sets) automatically gets a
       coherent hover shade and a soft tint. The legacy hardcoded blue
       fallbacks (#4a9eff / #3d8ce8) caused every non-themed Forge button
       to flash blue on hover regardless of the customer's accent —
       fixed in commit "fix(ui): derive accent-hover/dim from accent-base
       so hover stays on-brand". */
    --accent-base:  var(--accent, oklch(0.55 0.16 240));
    --accent-hover: color-mix(in oklch, var(--accent-base), black 10%);
    --accent-dim:   color-mix(in srgb, var(--accent-base), transparent 88%);
    --accent-on:    #ffffff;

    /* Base tokens */
    --typography-fontSansFamily: 'Outfit', ui-sans-serif, system-ui, sans-serif;
    --typography-fontMonoFamily: 'JetBrains Mono', ui-monospace, Menlo, monospace;
    --typography-baseSize:    14px;
    --typography-lineHeight:  1.5;
    --typography-scale-xs:    11px;
    --typography-scale-sm:    12.5px;
    --typography-scale-base:  14px;
    --typography-scale-lg:    16px;
    --typography-scale-xl:    18px;
    --typography-scale-2xl:   22px;
    --typography-scale-3xl:   28px;
    --typography-weights-normal:   400;
    --typography-weights-medium:   500;
    --typography-weights-semibold: 600;
    --typography-weights-bold:     700;

    --spacing-0:  0px;
    --spacing-1:  4px;
    --spacing-2:  8px;
    --spacing-3:  12px;
    --spacing-4:  16px;
    --spacing-5:  20px;
    --spacing-6:  24px;
    --spacing-8:  32px;
    --spacing-10: 40px;
    --spacing-12: 48px;
    --spacing-16: 64px;

    --radius-none: 0px;
    --radius-sm:   4px;
    --radius-md:   8px;
    --radius-lg:   12px;
    --radius-xl:   16px;
    --radius-full: 9999px;

    --motion-durationFast: 150ms;
    --motion-durationBase: 200ms;
    --motion-durationSlow: 350ms;
    --motion-easing:       cubic-bezier(.4, 0, .2, 1);

    --controls-heightSm:   30px;
    --controls-heightBase: 36px;
    --controls-heightLg:   42px;

    --shadow-sm: 0 4px 12px rgba(30, 40, 64, .08);
    --shadow-md: 0 8px 24px rgba(30, 40, 64, .10);
    --shadow-lg: 0 24px 60px rgba(30, 40, 64, .15);
}

:root[data-theme="dark"] {
    --shadow-sm: 0 4px 14px rgba(0, 0, 0, .3);
    --shadow-md: 0 8px 32px rgba(0, 0, 0, .5);
    --shadow-lg: 0 24px 80px rgba(0, 0, 0, .6);
}

/* ------------------------------------ */
/* 2. Base + reset (shell-level)        */
/* ------------------------------------ */
.forge-prose {
    font-family: var(--typography-fontSansFamily);
    font-size:   var(--typography-baseSize);
    line-height: var(--typography-lineHeight);
    color:       var(--text-t1);
    background:  var(--surface-s0);
    -webkit-font-smoothing: antialiased;
}

.forge-prose :where(h1, h2, h3, h4, h5, h6) {
    margin: 0 0 var(--spacing-3) 0;
    color: var(--text-t1);
    font-weight: var(--typography-weights-semibold);
    line-height: 1.25;
}
.forge-prose h1 { font-size: var(--typography-scale-3xl); }
.forge-prose h2 { font-size: var(--typography-scale-2xl); }
.forge-prose h3 { font-size: var(--typography-scale-xl); }
.forge-prose h4 { font-size: var(--typography-scale-lg); }
.forge-prose p  { margin: 0 0 var(--spacing-3) 0; color: var(--text-t2); }

.forge-prose :focus-visible {
    outline: 2px solid var(--accent-base);
    outline-offset: 2px;
}

/* ------------------------------------ */
/* 3. Layout — shell / topbar / sidebar */
/* ------------------------------------ */
.forge-shell {
    display: grid;
    grid-template-columns: 260px 1fr;
    grid-template-rows: 56px 1fr;
    grid-template-areas:
        "sidebar topbar"
        "sidebar content";
    min-height: 100dvh;
    background: var(--surface-s0);
    color: var(--text-t1);
    font-family: var(--typography-fontSansFamily);
    font-size: var(--typography-baseSize);
}

.forge-shell__topbar  { grid-area: topbar; }
.forge-shell__sidebar { grid-area: sidebar; }
.forge-shell__content {
    grid-area: content;
    overflow: auto;
    padding: var(--spacing-6);
}

.forge-shell.is-sidebar-collapsed { grid-template-columns: 72px 1fr; }

@media (max-width: 768px) {
    .forge-shell {
        grid-template-columns: 1fr;
        grid-template-rows: 56px 1fr;
        grid-template-areas: "topbar" "content";
    }
    .forge-shell__sidebar {
        position: fixed; inset: 56px 0 0 0;
        transform: translateX(-100%);
        transition: transform var(--motion-durationBase) var(--motion-easing);
        z-index: 40;
    }
    .forge-shell.is-drawer-open .forge-shell__sidebar { transform: translateX(0); }
    .forge-shell__content { padding: var(--spacing-4); }
}

.forge-topbar {
    display: flex;
    align-items: center;
    gap: var(--spacing-4);
    height: 100%;
    padding: 0 var(--spacing-4);
    background: var(--surface-s1);
    border-bottom: 1px solid var(--border-b1);
}
.forge-topbar__brand    { display: flex; align-items: center; gap: var(--spacing-2); font-weight: var(--typography-weights-semibold); }
.forge-topbar__center   { flex: 1; min-width: 0; display: flex; justify-content: center; }
.forge-topbar__actions  { display: flex; align-items: center; gap: var(--spacing-1); }
.forge-topbar__divider  { width: 1px; height: 24px; background: var(--border-b1); margin: 0 var(--spacing-1); }
.forge-topbar__drawer-toggle { display: none; }
@media (max-width: 768px) {
    .forge-topbar__drawer-toggle { display: inline-flex; }
    .forge-topbar__center { justify-content: flex-start; }
}

.forge-sidebar {
    display: flex;
    flex-direction: column;
    min-height: 100%;
    background: var(--surface-s1);
    border-right: 1px solid var(--border-b1);
    overflow-y: auto;
}
.forge-sidebar__header  { padding: var(--spacing-4); border-bottom: 1px solid var(--border-b0); }
.forge-sidebar__items   { padding: var(--spacing-2); display: flex; flex-direction: column; gap: var(--spacing-1); flex: 1; }
.forge-sidebar__group-label {
    padding: var(--spacing-3) var(--spacing-3) var(--spacing-1);
    font-size: var(--typography-scale-xs);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-t3);
}
.forge-sidebar__footer  { padding: var(--spacing-3); border-top: 1px solid var(--border-b0); }

/* ----- Content page wrapper — visually unified with dashboard `.grid` -----
 * Older pages still emit `<div class="forge-page">…<header class="forge-page__header">…`
 * markup. This block makes those wrappers render IDENTICALLY to the dashboard
 * `.page-header` + `.grid` pattern on Home.razor, so the entire app shares one
 * look without rewriting every Razor page. New pages should prefer
 * `.page-header` / `.grid` / `.module col-N` directly (see Home.razor and the
 * Account flow). The migration path: the BEM and dashboard markups produce the
 * same visual today; per-page rewrites can land independently. */
.forge-page {
    display: flex; flex-direction: column;
    gap: var(--s-6, 24px);
    padding: 0;
}
.forge-page__header {
    display: flex; align-items: flex-end; justify-content: space-between;
    gap: var(--s-6, 24px);
    margin-bottom: var(--s-2, 8px);
}

/* When `.forge-page__header` lives OUTSIDE a `.forge-page` flex wrapper (the
   Account / Manage pages render breadcrumb + header at the layout root,
   without the BEM container), the parent's flex `gap: 24px` doesn't apply,
   so the header sits 8 px above the content — visibly tighter than the
   other top-level pages. Matching margin keeps the rhythm consistent.
   Total spacing on regular pages: 24 px gap + 8 px margin = 32 px;
   stand-alone pages get 32 px directly via this rule. */
:not(.forge-page) > .forge-page__header {
    margin-bottom: var(--s-8, 32px);
}
.forge-page__title {
    margin: 0 0 4px;
    font-family: var(--font-display, "Outfit", system-ui, sans-serif);
    font-size: 28px;
    font-weight: 600;
    letter-spacing: -0.025em;
    color: var(--fg-1, var(--text-t1));
}
.forge-page__subtitle {
    margin: 0;
    color: var(--fg-3, var(--text-t3));
    font-size: 13px;
}
.forge-page__actions { display: flex; gap: var(--s-2, 8px); flex-wrap: wrap; align-items: center; }

/* Small viewports — when the title + action buttons combined would overflow
   the page width, drop the right-aligned actions onto their own row instead
   of squashing the title text or pushing buttons offscreen. The Tabs (Cards
   / Table) + primary CTA stay horizontally clustered on the second row.
   ForgeApp /todo and /onboarding both relied on this implicit re-flow that
   never materialized — visible cause: the parent `.forge-page__header`
   stayed `flex-direction: row` at every viewport size. */
@media (max-width: 720px) {
    .forge-page__header {
        flex-direction: column;
        align-items: stretch;
    }
    .forge-page__header > div:first-child {
        min-width: 0;
    }
    .forge-page__actions {
        justify-content: flex-start;
    }
}
.forge-page__shell { padding: var(--s-6, 24px) 0; }

/* ------------------------------------ */
/* 4. Navigation                        */
/* ------------------------------------ */
.forge-nav-item {
    display: flex;
    align-items: center;
    gap: var(--spacing-3);
    padding: var(--spacing-2) var(--spacing-3);
    border-radius: var(--radius-md);
    color: var(--text-t2);
    font-size: var(--typography-scale-base);
    text-decoration: none;
    transition: background var(--motion-durationFast) var(--motion-easing),
                color var(--motion-durationFast) var(--motion-easing);
}
.forge-nav-item:hover { background: var(--surface-s2); color: var(--text-t1); }
.forge-nav-item.is-active {
    background: var(--accent-dim);
    color: var(--accent-base);
    font-weight: var(--typography-weights-medium);
}
.forge-nav-item__icon  { flex: 0 0 18px; display: inline-flex; }
.forge-nav-item__label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.forge-nav-item__badge {
    font-size: var(--typography-scale-xs);
    padding: 2px 8px;
    border-radius: var(--radius-full);
    background: var(--surface-s3);
    color: var(--text-t2);
}

.forge-breadcrumb {
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-1);
    color: var(--text-t3); font-size: var(--typography-scale-sm);
}
.forge-breadcrumb__item { display: inline-flex; align-items: center; gap: var(--spacing-1); }
.forge-breadcrumb__link { color: var(--text-t3); text-decoration: none; }
.forge-breadcrumb__link:hover { color: var(--text-t1); }
.forge-breadcrumb__current { color: var(--text-t1); font-weight: var(--typography-weights-medium); }
.forge-breadcrumb__separator { color: var(--text-t4); }

/* Pill-segmented switcher — neutral surface tones, no accent flood and no
   underline rule. Replaces the previous underline-tab design that left a
   visible thin line above adjacent toolbar buttons (the "tenká čára nad
   Cards / Table" the design feedback called out). Single canonical visual
   for any radio-style row of choices. */
.forge-tabs {
    display: inline-flex;
    gap: 2px;
    padding: 3px;
    background: var(--surface-s2, oklch(0.22 0.012 280));
    border: 1px solid var(--border-b1, oklch(1 0 0 / 0.07));
    border-radius: var(--radii-md, 8px);
}
.forge-tab {
    padding: 7px 14px;
    background: transparent;
    border: 0;
    border-radius: var(--radii-sm, 6px);
    cursor: pointer;
    font-family: inherit;
    font-size: var(--typography-scale-sm, 12.5px);
    font-weight: 600;
    color: var(--text-t3, oklch(0.7 0.01 280));
    white-space: nowrap;
    transition: background var(--motion-durationFast) var(--motion-easing),
                color var(--motion-durationFast) var(--motion-easing);
}
.forge-tab:hover { color: var(--text-t1, oklch(0.95 0.005 280)); }
.forge-tab.is-active {
    background: var(--surface-s3, oklch(0.32 0.012 280));
    color: var(--text-t1, oklch(0.97 0.005 280));
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25),
                inset 0 0 0 1px oklch(1 0 0 / 0.06);
}

/* ------------------------------------ */
/* 5. Actions (buttons)                 */
/* ------------------------------------ */
.forge-button {
    display: inline-flex; align-items: center; justify-content: center;
    gap: var(--spacing-2);
    height: var(--controls-heightBase);
    padding: 0 var(--spacing-4);
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    font-family: inherit;
    font-size: var(--typography-scale-base);
    font-weight: var(--typography-weights-medium);
    line-height: 1;
    cursor: pointer;
    white-space: nowrap;
    text-decoration: none;
    transition: background var(--motion-durationFast) var(--motion-easing),
                color var(--motion-durationFast) var(--motion-easing),
                border-color var(--motion-durationFast) var(--motion-easing),
                transform var(--motion-durationFast) var(--motion-easing);
}
.forge-button:active:not(:disabled) { transform: translateY(1px); }
.forge-button:disabled { opacity: 0.5; cursor: not-allowed; }
.forge-button:focus-visible {
    outline: 2px solid var(--accent-base);
    outline-offset: 2px;
}

.forge-button--primary   { background: var(--accent-base); color: var(--accent-on); }
.forge-button--primary:hover:not(:disabled) { background: var(--accent-hover); }
.forge-button--secondary { background: var(--surface-s2); color: var(--text-t1); border-color: var(--border-b1); }
.forge-button--secondary:hover:not(:disabled) { background: var(--surface-s3); }
.forge-button--ghost     { background: transparent; color: var(--text-t2); }
.forge-button--ghost:hover:not(:disabled) { background: var(--surface-s2); color: var(--text-t1); }
.forge-button--danger    { background: var(--semantic-danger); color: #ffffff; }
.forge-button--danger:hover:not(:disabled) { filter: brightness(1.1); }

.forge-button--sm { height: var(--controls-heightSm); padding: 0 var(--spacing-3); font-size: var(--typography-scale-sm); }
.forge-button--lg { height: var(--controls-heightLg); padding: 0 var(--spacing-5); font-size: var(--typography-scale-lg); }
.forge-button--block { width: 100%; }

.forge-button__spinner {
    width: 14px; height: 14px;
    border: 2px solid currentColor; border-top-color: transparent;
    border-radius: 50%;
    animation: forge-spin var(--motion-durationSlow) linear infinite;
}

/* ForgeBusyButton — async-aware action button (ADR 050 + Project1 UX request)
   Designed by a UX-designer-with-20-years-of-practice mindset:
   - Cancel button is theme-aware (uses semantic --text-t2 / --surface-s2 tokens
     so it inverts cleanly between light + dark + every accent palette).
   - Spinner + Cancel link fade in via opacity (no jumpy layout shift; the
     wrapper's height stays constant because both elements are inline).
   - The 200 ms debounce + 300 ms minimum-duration is enforced in the C# logic;
     CSS transitions polish the *appearance* once the visual decides to show. */
.forge-busy-button {
    display: inline-flex; align-items: center; gap: var(--spacing-2);
    flex-wrap: wrap;
    /* The wrapper has no explicit transition — children animate independently. */
}
.forge-busy-button--busy {
    /* During work, the wrapper signals "in progress" with cursor:wait so even
       the area around the button (e.g. dialog footer padding) signals state. */
    cursor: wait;
}
.forge-busy-button--busy .forge-button {
    /* Underlying ForgeButton receives Loading=true (renders the spinner) and
       Disabled=true. We add a subtle pointer-events:none so accidental
       click-throughs during busy state are suppressed. */
    pointer-events: none;
}

.forge-busy-button__cancel {
    appearance: none;
    background: transparent;
    border: 1px solid transparent;
    padding: 4px 10px;
    height: var(--controls-heightBase, 32px);
    box-sizing: border-box;
    display: inline-flex; align-items: center;
    color: var(--text-t2);
    font-size: var(--typography-scale-sm);
    font-weight: 500;
    line-height: 1;
    cursor: pointer;
    border-radius: var(--radius-md);
    /* Fade-in from the moment the parent flips to .forge-busy-button--busy.
       Duration matches motion-durationFast so it pairs with ForgeButton's
       own spinner appearance. */
    opacity: 0;
    animation: forge-busy-cancel-in var(--motion-durationBase, 200ms) var(--motion-easing, ease-out) forwards;
    transition: color var(--motion-durationFast, 120ms) var(--motion-easing, ease-out),
                background var(--motion-durationFast, 120ms) var(--motion-easing, ease-out),
                border-color var(--motion-durationFast, 120ms) var(--motion-easing, ease-out);
}
.forge-busy-button__cancel:hover {
    color: var(--text-t1);
    background: var(--surface-s2);
    border-color: var(--border-b1, var(--surface-s3));
}
.forge-busy-button__cancel:active {
    background: var(--surface-s3);
}
.forge-busy-button__cancel:focus-visible {
    outline: 2px solid var(--accent-base);
    outline-offset: 2px;
}

@keyframes forge-busy-cancel-in {
    from { opacity: 0; transform: translateX(-4px); }
    to   { opacity: 1; transform: translateX(0); }
}

.forge-busy-button__error {
    flex-basis: 100%;
    color: var(--status-danger, #ef4444);
    font-size: var(--typography-scale-sm);
    margin-top: var(--spacing-1);
    /* Fade-in so the error doesn't jump onto the page abruptly. */
    animation: forge-busy-error-in var(--motion-durationBase, 200ms) var(--motion-easing, ease-out);
}
@keyframes forge-busy-error-in {
    from { opacity: 0; transform: translateY(-2px); }
    to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .forge-busy-button__cancel,
    .forge-busy-button__error {
        animation: none;
        opacity: 1;
        transform: none;
    }
}

.forge-icon-button {
    /* `position: relative` is the anchor for the absolute-positioned
       `.forge-icon-button__badge` indicator. Without it the badge climbs
       the DOM looking for the nearest positioned ancestor and ends up
       attached to the topbar (user-reported "badge appears next to
       search bar instead of next to the filter icon"). */
    position: relative;
    display: inline-flex; align-items: center; justify-content: center;
    width: var(--controls-heightBase); height: var(--controls-heightBase);
    border: 0; background: transparent; border-radius: var(--radius-md);
    color: var(--text-t2); cursor: pointer;
    transition: background var(--motion-durationFast) var(--motion-easing),
                color var(--motion-durationFast) var(--motion-easing);
}
.forge-icon-button:hover { background: var(--surface-s2); color: var(--text-t1); }
.forge-icon-button:disabled { opacity: 0.5; cursor: not-allowed; }
.forge-icon-button--sm { width: var(--controls-heightSm); height: var(--controls-heightSm); }
.forge-icon-button--lg { width: var(--controls-heightLg); height: var(--controls-heightLg); }

/* Chip variant — used by the inline "Clear filters" affordance in table /
   cards toolbars. Auto-widens to fit "<icon> <label>" instead of being a
   fixed-square hit target. Accent-tinted so it reads as an "active action"
   distinct from the neutral toolbar icons next to it. */
.forge-icon-button--chip {
    width: auto;
    padding: 0 var(--spacing-2);
    gap: var(--spacing-1);
    background: color-mix(in oklab, var(--accent) 14%, transparent);
    color: var(--accent);
    font-size: var(--typography-scale-sm);
    font-weight: 500;
    white-space: nowrap;
}
.forge-icon-button--chip:hover {
    background: color-mix(in oklab, var(--accent) 22%, transparent);
    color: var(--accent);
}
.forge-icon-button__label {
    /* `min-width: 0` + truncation keeps the chip from blowing the toolbar
       width on narrow viewports — label collapses to "Clear…" if needed. */
    min-width: 0;
    max-width: 14ch;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Sub-tablet: drop the visible label so only the filter-x icon remains.
   Still accessible via aria-label + tooltip. */
@media (max-width: 559.98px) {
    .forge-icon-button--chip .forge-icon-button__label { display: none; }
    .forge-icon-button--chip { width: var(--controls-heightBase); padding: 0; }
}

/* Inline clear-filters affordance inside the card-grid filter strip
   (legacy placement; the chip in the toolbar is the primary surface).
   Sits as a flexbox child at the end of the strip; same accent treatment. */
.forge-card-grid__filter-clear {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-1);
    padding: var(--spacing-1) var(--spacing-2);
    border: 1px solid color-mix(in oklab, var(--accent) 35%, transparent);
    border-radius: var(--radius-pill);
    background: color-mix(in oklab, var(--accent) 10%, transparent);
    color: var(--accent);
    font-size: var(--typography-scale-sm);
    font-weight: 500;
    cursor: pointer;
    align-self: flex-end;
    transition: background var(--motion-durationFast) var(--motion-easing);
}
.forge-card-grid__filter-clear:hover {
    background: color-mix(in oklab, var(--accent) 18%, transparent);
}

/* ------------------------------------ */
/* 6. Forms                             */
/* ------------------------------------ */
.forge-field { display: flex; flex-direction: column; gap: var(--spacing-1); }
.forge-field__label {
    font-size: var(--typography-scale-sm);
    color: var(--text-t2);
    font-weight: var(--typography-weights-medium);
}
.forge-field__help { font-size: var(--typography-scale-xs); color: var(--text-t3); }
.forge-field__error { font-size: var(--typography-scale-xs); color: var(--semantic-danger); }
.forge-field__required-marker { color: var(--semantic-danger); margin-left: 2px; }
.forge-field--flex { flex: 1; }
.forge-field.has-error .forge-input,
.forge-field.has-error .forge-textarea,
.forge-field.has-error .forge-select { border-color: var(--semantic-danger); }
.forge-field.has-error .forge-input:focus,
.forge-field.has-error .forge-textarea:focus,
.forge-field.has-error .forge-select:focus {
    outline-color: var(--semantic-danger);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--semantic-danger) 20%, transparent);
}

/* All form inputs share the same token surface (--input-* in
 * forge-dashboard.css). Override --input-radius, --input-bg, etc. in
 * wwwroot/forge-tokens.css to reshape every input across the app at once. */
.forge-input,
.forge-textarea,
.forge-select {
    width: 100%;
    padding: var(--input-padding-y) var(--input-padding-x);
    height: var(--input-height);
    font-family: inherit; font-size: var(--typography-scale-base);
    color: var(--input-text);
    background: var(--input-bg);
    border: var(--input-border-width) solid var(--input-border);
    border-radius: var(--input-radius);
    /* color-scheme propagates to the browser's native dropdown list (the
       <option> elements rendered by the OS / engine, NOT the <select>
       chrome we style ourselves). Without this, the dropdown options
       appear in default light styling on dark sites — the user sees
       white panel with light text, which is unreadable. The root <html>
       sets color-scheme via [data-theme="dark"] in forge-tokens.css;
       this declaration ensures the property cascades to every input. */
    color-scheme: inherit;
    transition: border-color var(--t-fast, 140ms) var(--ease-out, ease-out),
                box-shadow var(--t-fast, 140ms) var(--ease-out, ease-out),
                background var(--t-fast, 140ms) var(--ease-out, ease-out);
}
.forge-textarea {
    height: auto;
    min-height: calc(var(--input-height) * 2);
    padding: var(--spacing-2, 8px) var(--input-padding-x);
    resize: vertical;
    line-height: var(--typography-lineHeight);
}

/* `<textarea class="forge-input">` consumers — same height + padding +
   vertical resize as `.forge-textarea` so both authoring patterns get
   the Forge style. Without this, raw `<textarea>` defaulted to its native
   ~2em line height with no vertical padding and the browser's grey
   diagonal-hatch corner resizer. */
textarea.forge-input,
.forge-input--textarea {
    height: auto;
    min-height: calc(var(--input-height) * 2);
    padding: var(--spacing-2, 8px) var(--input-padding-x);
    resize: vertical;
    line-height: var(--typography-lineHeight);
}

/* Forge-styled resize affordance — the browser-default ::-webkit-resizer
   draws a tiny diagonal hatch in pure grey that ignores theme tokens. We
   replace it with a refined accent-tinted dot-triangle handle that
   inherits the active accent + adapts to light / dark / motion-reduced
   modes via CSS variables. Firefox keeps its native neutral handle (no
   equivalent pseudo-element exists) — acceptable; it's still neutral.

   Visual: three faint dots in a triangular cluster at the bottom-right
   corner — Linear / Notion / Apple "drag handle" idiom. Replaces the
   previous three-stripe gradient (user flagged as too prominent and not
   in the Forge visual vocabulary). The handle is sized at 16 × 16 px
   with the dots tucked into the inner 10 × 10 zone so it sits subtly
   inside the textarea's rounded corner without overlapping the border.

   Applied via three selectors so both authoring patterns get the styled
   handle: `.forge-textarea` (the Forge-built textarea component),
   `textarea.forge-input` (raw `<textarea>` with the input class),
   and `.forge-input--textarea` (modifier-class authored pattern). */
.forge-textarea::-webkit-resizer,
textarea.forge-input::-webkit-resizer,
.forge-input--textarea::-webkit-resizer {
    background-color: transparent;
    background-image:
        radial-gradient(circle at calc(100% - 5px) calc(100% - 5px),
            var(--accent-base) 1.4px, transparent 1.6px),
        radial-gradient(circle at calc(100% - 10px) calc(100% - 5px),
            var(--accent-base) 1.4px, transparent 1.6px),
        radial-gradient(circle at calc(100% - 5px) calc(100% - 10px),
            var(--accent-base) 1.4px, transparent 1.6px);
    background-repeat: no-repeat;
    opacity: 0.55;
    border-bottom-right-radius: var(--input-radius, var(--radius-1));
    transition: opacity 160ms var(--motion-easing, ease-out);
}
/* Brighten the handle on focus / hover so the affordance is obvious
   when the user is interacting with the textarea — stays subtle when
   the field is idle. */
.forge-textarea:hover::-webkit-resizer,
.forge-textarea:focus::-webkit-resizer,
textarea.forge-input:hover::-webkit-resizer,
textarea.forge-input:focus::-webkit-resizer,
.forge-input--textarea:hover::-webkit-resizer,
.forge-input--textarea:focus::-webkit-resizer {
    opacity: 0.85;
}
/* Effects-minimal mode flattens decoration — show a faint static handle
   with no hover transition. */
:root[data-effects="minimal"] .forge-textarea::-webkit-resizer,
:root[data-effects="minimal"] textarea.forge-input::-webkit-resizer,
:root[data-effects="minimal"] .forge-input--textarea::-webkit-resizer {
    opacity: 0.4;
    transition: none;
}
.forge-input:focus,
.forge-textarea:focus,
.forge-select:focus {
    outline: none;
    border-color: var(--input-border-focus);
    background: var(--input-bg-focus);
    box-shadow: var(--input-shadow-focus);
}
.forge-input::placeholder, .forge-textarea::placeholder { color: var(--input-placeholder); }
.forge-input:disabled, .forge-textarea:disabled, .forge-select:disabled {
    background: var(--input-disabled-bg);
    color: var(--input-disabled-text);
    cursor: not-allowed;
}

/* Password input — theme-aware browser-native reveal button.
   Edge / Chromium ship a built-in eye icon (::-ms-reveal in legacy Edge,
   modern Chromium uses an internal pseudo). Default styling is black-on-
   light which becomes invisible on dark themes, and the icon vanishes on
   focus loss. We:
     1. Filter the legacy Edge ::-ms-reveal so it inverts on dark themes.
     2. Force the modern Chromium reveal to stay visible permanently with
        a custom background-image fallback when the browser hides it.
   The legacy Edge selector first; modern browsers ignore it harmlessly. */
.forge-input[type="password"]::-ms-reveal,
.forge-input[type="password"]::-ms-clear {
    /* Light theme: leave the native black icon as-is (high contrast on
       white). Dark theme: invert so the icon is white on dark surface. */
    filter: var(--password-reveal-filter, none);
    cursor: pointer;
}
[data-theme="dark"] .forge-input[type="password"]::-ms-reveal,
[data-theme="dark"] .forge-input[type="password"]::-ms-clear {
    filter: invert(1);
}

/* Disable the native reveal so we can ship our own theme-aware toggle
   that stays visible and works across all browsers. Set this on the
   parent `.forge-password-field` wrapper to opt in. */
.forge-password-field .forge-input[type="password"]::-ms-reveal,
.forge-password-field .forge-input[type="password"]::-ms-clear {
    display: none !important;
}

/* ForgePasswordInput — own theme-aware toggle.
   Wrapper renders the input + an absolutely-positioned button overlapping
   the input's right edge. The button uses semantic --text-t2 / --surface-s2
   tokens so it inverts cleanly between light + dark + every accent palette. */
.forge-password-field {
    position: relative;
    display: block;
}
.forge-password-field .forge-input {
    /* Reserve room for the toggle button (40px = button width + small gap). */
    padding-right: 44px;
}
.forge-password-field__toggle {
    appearance: none;
    position: absolute;
    top: 50%;
    right: 6px;
    transform: translateY(-50%);
    width: 32px; height: 32px;
    display: inline-flex; align-items: center; justify-content: center;
    background: transparent;
    border: 0;
    border-radius: var(--radius-sm, 4px);
    color: var(--text-t2);
    cursor: pointer;
    transition: color var(--motion-durationFast, 120ms) var(--motion-easing, ease-out),
                background var(--motion-durationFast, 120ms) var(--motion-easing, ease-out);
}
.forge-password-field__toggle:hover {
    color: var(--text-t1);
    background: var(--surface-s2);
}
.forge-password-field__toggle:focus-visible {
    outline: 2px solid var(--accent-base);
    outline-offset: 2px;
}
.forge-password-field__toggle svg {
    width: 16px; height: 16px;
    pointer-events: none;
}

/* Icon-swap on toggle: BOTH eye + eye-off are rendered up front; CSS
   shows exactly one based on the wrapper's `data-revealed` attribute,
   which the inline-onclick JS flips. This keeps the toggle working
   under static SSR (Login.razor) — no Blazor circuit required. */
.forge-password-field__icon { display: none; }
.forge-password-field[data-revealed="false"] .forge-password-field__icon--show { display: inline-block; }
.forge-password-field[data-revealed="true"]  .forge-password-field__icon--hide { display: inline-block; }

/* ----- Floating label variant ------------------------------------------
 * Wrap a field in `<div class="forge-field forge-field--floating">` and
 * the label drops INTO the input when empty + floats up + scales down on
 * focus / fill. Mirrors the Material / iOS pattern. The label uses a
 * `:placeholder-shown` selector so it works with plain HTML inputs;
 * <InputText> components from Forge participate as long as the
 * placeholder is non-empty (use `placeholder=" "` if you don't want a
 * visible placeholder).
 *
 * To opt the entire app into floating labels: set
 * `--input-label-style: floating;` in forge-tokens.css and replace
 * `.forge-field` with `.forge-field--floating` in your auth/admin pages.
 * ----------------------------------------------------------------------- */
.forge-field--floating {
    position: relative;
}
.forge-field--floating .forge-field__label {
    position: absolute;
    left: calc(var(--input-padding-x) - 4px);
    top: 50%;
    transform: translateY(-50%);
    padding: 0 4px;
    font-size: var(--typography-scale-base);
    color: var(--input-placeholder);
    background: var(--bg-1, transparent);
    pointer-events: none;
    transition: top var(--t-fast, 140ms) var(--ease-out, ease-out),
                transform var(--t-fast, 140ms) var(--ease-out, ease-out),
                color var(--t-fast, 140ms) var(--ease-out, ease-out),
                font-size var(--t-fast, 140ms) var(--ease-out, ease-out);
}
.forge-field--floating .forge-input,
.forge-field--floating .forge-textarea,
.forge-field--floating .forge-select {
    /* Reserve top half-height of the input for the floated label so text
       does not collide with it on focus. */
    padding-top: calc(var(--input-padding-y) + 6px);
}
.forge-field--floating .forge-input:focus ~ .forge-field__label,
.forge-field--floating .forge-textarea:focus ~ .forge-field__label,
.forge-field--floating .forge-select:focus ~ .forge-field__label,
.forge-field--floating .forge-input:not(:placeholder-shown) ~ .forge-field__label,
.forge-field--floating .forge-textarea:not(:placeholder-shown) ~ .forge-field__label,
.forge-field--floating .forge-select:not([value=""]) ~ .forge-field__label {
    top: 0;
    transform: translateY(-50%) scale(0.85);
    color: var(--input-border-focus);
    font-weight: var(--typography-weights-medium);
}

/* Checkbox / radio (legacy class — used as a label wrapper around a
   native <input type="checkbox"> by older pages. New code should prefer
   the ForgeCheckbox component, which draws its own token-aware square +
   check glyph below.) */
.forge-checkbox, .forge-radio {
    display: inline-flex; align-items: center; gap: var(--spacing-2);
    cursor: pointer; user-select: none;
    font-size: var(--typography-scale-base); color: var(--text-t1);
}
.forge-checkbox__input, .forge-radio__input {
    width: 18px; height: 18px;
    accent-color: var(--accent-base);
    cursor: pointer;
}

/* ────────────────────────────────────────────────────────────────────────
   ForgeCheckbox — token-aware checkbox that re-skins with theme + accent.
   The native browser checkbox respects only `accent-color` (recent UA
   feature) so dark/light flips and our 5-accent palette never propagate
   correctly. ForgeCheckbox draws its own square + check glyph using the
   Forge token vocabulary, so theme/accent switches re-paint it for free.

   Structure (mirrors the .razor):
     <label.forge-checkbox>
       <input.forge-checkbox__native> ← visually hidden, source of truth
       <span.forge-checkbox__box>     ← painted square
         <svg.forge-checkbox__glyph>  ← check / minus path
       <span.forge-checkbox__label>   ← optional text after the box
     </label>
   The label carries [data-checked="true|false"] driven by Razor so the
   CSS doesn't need to read the native input's :checked pseudoclass (which
   doesn't propagate well up the parent chain in older Edge / WebKit).
   ─────────────────────────────────────────────────────────────────────── */

.forge-checkbox {
    /* Override the legacy compound rule above for the BEM-extended variant
       that ForgeCheckbox.razor renders. The legacy variant (no __native +
       __box) keeps the older selector untouched. */
    align-items: center;
    gap: var(--spacing-2, 8px);
}

.forge-checkbox .forge-checkbox__native {
    /* Visually hidden but still focusable + tab-reachable. clip-path keeps
       the input rendered (so the browser supplies focus + form semantics)
       without visual area. */
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    pointer-events: none;
}

.forge-checkbox__box {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border: 1.5px solid var(--line-strong, var(--border-b1, var(--text-t3)));
    border-radius: var(--radius-sm, 4px);
    background: var(--surface-s1, var(--bg-1));
    transition:
        background var(--motion-durationFast, 160ms) var(--motion-easing, ease),
        border-color var(--motion-durationFast, 160ms) var(--motion-easing, ease),
        box-shadow var(--motion-durationFast, 160ms) var(--motion-easing, ease);
}

.forge-checkbox__glyph {
    width: 14px;
    height: 14px;
    fill: none;
    stroke: var(--accent-on, white);
    stroke-width: 2.5;
    stroke-linecap: round;
    stroke-linejoin: round;
    /* Glyph hides by default — appears only when [data-checked="true"]. The
       stroke-dashoffset roll-back gives the path a hand-drawn quality. Token-
       driven duration so motion=reduced suppresses the draw-in per
       META-PRAVIDLO "Component motion + effects respect". */
    stroke-dasharray: 22;
    stroke-dashoffset: 22;
    transition: stroke-dashoffset var(--motion-durationBase, 220ms) var(--motion-easing, cubic-bezier(0.16, 1, 0.3, 1)) calc(var(--motion-durationFast, 160ms) / 4);
}

.forge-checkbox[data-checked="true"] .forge-checkbox__box,
.forge-checkbox.is-indeterminate .forge-checkbox__box {
    background: var(--accent-base, var(--accent));
    border-color: var(--accent-base, var(--accent));
}

.forge-checkbox[data-checked="true"] .forge-checkbox__glyph,
.forge-checkbox.is-indeterminate .forge-checkbox__glyph {
    /* "Draw" the path on transition by rolling the dash offset back to 0. */
    stroke-dashoffset: 0;
}

/* Hover — subtle border tint (keeps the box visible against the surface). */
.forge-checkbox:hover .forge-checkbox__box {
    border-color: var(--accent-base, var(--accent));
}
.forge-checkbox[data-checked="true"]:hover .forge-checkbox__box {
    /* When already checked, hover deepens slightly so the affordance is clear. */
    background: color-mix(in oklab, var(--accent-base, var(--accent)) 88%, black);
    border-color: color-mix(in oklab, var(--accent-base, var(--accent)) 88%, black);
}

/* Keyboard focus ring — only when keyboard navigation lands on the
   native input. :focus-visible avoids the ring on mouse clicks. */
.forge-checkbox .forge-checkbox__native:focus-visible + .forge-checkbox__box {
    box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent-base, var(--accent)) 30%, transparent);
    outline: none;
}

/* Indeterminate — used by tri-state pickers. The glyph SVG renders a
   horizontal stroke instead of a check; box uses the same accent fill so
   the pattern reads "partially checked". */
.forge-checkbox.is-indeterminate .forge-checkbox__box {
    background: var(--accent-base, var(--accent));
    border-color: var(--accent-base, var(--accent));
}

/* Disabled — muted box + muted label, but the box stays VISIBLE so users
   can still see whether the disabled item is checked or unchecked. The
   previous opacity: 0.55 + surface-s2 background made the unchecked-disabled
   box almost invisible against a similarly-coloured surrounding card
   (user-reported regression: "checkbox disabled nejde videt unchecked").
   Now: full opacity on the box itself, dashed-style border at full strength,
   only the label dims; both dark + light mode legible. */
.forge-checkbox.is-disabled {
    cursor: not-allowed;
}
.forge-checkbox.is-disabled .forge-checkbox__label {
    opacity: 0.55;
}
.forge-checkbox.is-disabled .forge-checkbox__box,
.forge-checkbox.is-disabled:hover .forge-checkbox__box {
    /* Box background still tints toward surface-s2 (so it reads "disabled"),
       but border uses --line-strong + a 1px outline glow so the rectangle
       has unmistakable edges even on a same-coloured card. */
    background: var(--surface-s2, var(--bg-2));
    border-color: var(--line-strong, var(--fg-3, currentColor));
    border-style: dashed;
    /* No inset shadow needed when border is dashed — that pattern alone
       is what disabled checkboxes look like in OS native controls. */
}
.forge-checkbox.is-disabled[data-checked="true"] .forge-checkbox__box {
    /* Checked-disabled: keep the accent tint so checkedness reads at a glance,
       but desaturate slightly to signal disabled-ness. Border returns to
       solid because the fill is informative on its own. */
    background: color-mix(in oklab, var(--accent-base, var(--accent)) 50%, var(--surface-s2));
    border-color: color-mix(in oklab, var(--accent-base, var(--accent)) 50%, var(--surface-s2));
    border-style: solid;
}
.forge-checkbox.is-disabled.is-indeterminate .forge-checkbox__box {
    /* Indeterminate-disabled mirrors checked-disabled tint so users see the
       mixed state, not an empty box. */
    background: color-mix(in oklab, var(--accent-base, var(--accent)) 50%, var(--surface-s2));
    border-color: color-mix(in oklab, var(--accent-base, var(--accent)) 50%, var(--surface-s2));
    border-style: solid;
}

.forge-checkbox__label {
    color: var(--fg-1, var(--text-t1));
    line-height: 1.4;
    font-size: var(--typography-scale-base, 14px);
}

/* Reduced motion — no glyph stroke animation. */
@media (prefers-reduced-motion: reduce) {
    .forge-checkbox__box,
    .forge-checkbox__glyph {
        transition: none;
    }
}

/* ---- ForgeSwitch — accent-driven on/off pill ---- */
.forge-switch {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    cursor: pointer;
    user-select: none;
    position: relative;
}

.forge-switch__native {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.forge-switch__track {
    flex-shrink: 0;
    position: relative;
    width: 44px;
    height: 24px;
    border-radius: 999px;
    background: var(--surface-s2, var(--bg-2));
    border: 1px solid var(--line-strong, var(--fg-3, currentColor));
    transition: background var(--motion-durationBase, 200ms) var(--motion-easing, ease),
                border-color var(--motion-durationBase, 200ms) var(--motion-easing, ease),
                box-shadow var(--motion-durationFast, 120ms) var(--motion-easing, ease);
}

.forge-switch__thumb {
    position: absolute;
    top: 2px;
    left: 2px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--surface-elevated, var(--bg-1));
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18), 0 0 0 1px rgba(0, 0, 0, 0.04);
    transition: transform var(--motion-durationBase, 200ms) var(--motion-easing, ease),
                background var(--motion-durationBase, 200ms) var(--motion-easing, ease);
}

.forge-switch[data-checked="true"] .forge-switch__track {
    background: var(--accent-base, var(--accent));
    border-color: var(--accent-base, var(--accent));
}

.forge-switch[data-checked="true"] .forge-switch__thumb {
    transform: translateX(20px);
    background: var(--surface-elevated, #fff);
}

/* Keyboard focus-visible — accent ring on the track so the user knows which
   switch keyboard input affects. */
.forge-switch__native:focus-visible + .forge-switch__track {
    outline: 2px solid var(--accent-base, var(--accent));
    outline-offset: 2px;
}

/* Hover — slight lift on the thumb. */
.forge-switch:not(.is-disabled):hover .forge-switch__thumb {
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.22), 0 0 0 1px rgba(0, 0, 0, 0.05);
}

.forge-switch.is-disabled {
    cursor: not-allowed;
}
.forge-switch.is-disabled .forge-switch__label {
    opacity: 0.55;
}
.forge-switch.is-disabled .forge-switch__track {
    opacity: 0.55;
    border-style: dashed;
}

.forge-switch__label {
    color: var(--fg-1, var(--text-t1));
    line-height: 1.4;
    font-size: var(--typography-scale-base, 14px);
}

/* Reduced motion — kill thumb slide; the [data-checked] flip is instant
   and the user still sees on/off through colour. */
@media (prefers-reduced-motion: reduce) {
    .forge-switch__track,
    .forge-switch__thumb {
        transition: none;
    }
}
:root[data-motion="reduced"] .forge-switch__track,
:root[data-motion="reduced"] .forge-switch__thumb {
    transition: none;
}

/* ---- ForgeRadioGroup + ForgeRadio — exclusive choice ---- */
.forge-radio-group {
    display: flex;
    gap: var(--gap-3, 12px);
}
.forge-radio-group.is-vertical {
    flex-direction: column;
}
.forge-radio-group.is-horizontal {
    flex-direction: row;
    flex-wrap: wrap;
}

.forge-radio {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    user-select: none;
    position: relative;
}

.forge-radio__native {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.forge-radio__disc {
    flex-shrink: 0;
    position: relative;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--surface-elevated, var(--bg-1));
    border: 2px solid var(--line-strong, var(--fg-3, currentColor));
    box-sizing: border-box;
    transition: border-color var(--motion-durationBase, 200ms) var(--motion-easing, ease),
                background var(--motion-durationBase, 200ms) var(--motion-easing, ease);
}

.forge-radio__dot {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--accent-base, var(--accent));
    transform: translate(-50%, -50%) scale(0);
    transition: transform var(--motion-durationFast, 120ms) var(--motion-easing, ease);
}

.forge-radio.is-selected .forge-radio__disc,
.forge-radio[data-checked="true"] .forge-radio__disc {
    border-color: var(--accent-base, var(--accent));
}
.forge-radio.is-selected .forge-radio__dot,
.forge-radio[data-checked="true"] .forge-radio__dot {
    transform: translate(-50%, -50%) scale(1);
}

.forge-radio__native:focus-visible + .forge-radio__disc {
    outline: 2px solid var(--accent-base, var(--accent));
    outline-offset: 2px;
}

.forge-radio:not(.is-disabled):hover .forge-radio__disc {
    border-color: var(--accent-base, var(--accent));
}

.forge-radio.is-disabled {
    cursor: not-allowed;
}
.forge-radio.is-disabled .forge-radio__disc {
    opacity: 0.55;
    border-style: dashed;
}
.forge-radio.is-disabled .forge-radio__label {
    opacity: 0.55;
}

.forge-radio__label {
    color: var(--fg-1, var(--text-t1));
    line-height: 1.4;
    font-size: var(--typography-scale-base, 14px);
}

.forge-radio-group.is-disabled .forge-radio {
    cursor: not-allowed;
}

/* Reduced motion — kill dot scale-in; selection is communicated through
   border-colour change which is OK to keep instant. */
@media (prefers-reduced-motion: reduce) {
    .forge-radio__dot,
    .forge-radio__disc {
        transition: none;
    }
}
:root[data-motion="reduced"] .forge-radio__dot,
:root[data-motion="reduced"] .forge-radio__disc {
    transition: none;
}

/* ------------------------------------ */
/* 7. Data display                      */
/* ------------------------------------ */
/* `.forge-card` is rendered to look identical to dashboard `.module` so older
 * pages that still emit `<ForgeCard>` markup integrate visually with the
 * `.module col-N` grid pattern on Home.razor. The same hover lift, ambient
 * accent glow (via ::before), border, and rise entrance animation apply. */
.forge-card {
    position: relative;
    display: flex; flex-direction: column;
    background: var(--surface-elevated, var(--surface-s1));
    border: 1px solid var(--line, var(--border-b1));
    border-radius: var(--r-lg, var(--radius-lg));
    padding: var(--s-5, 20px);
    /* Was `overflow: hidden` — clipped popups (ForgeSelect listbox,
       ForgeDropdown menu, ForgeLanguageMenu flyout, ForgeDateInput
       calendar) when they were absolutely-positioned inside a card.
       Switched to `isolation: isolate` which keeps the ::before glow
       inside its own stacking context without clipping descendants.
       Component Authoring Rules §9.1 — popups must escape overflow:hidden. */
    isolation: isolate;
    transition:
        transform var(--t-med, 240ms) var(--ease-out, ease-out),
        box-shadow var(--t-med, 240ms) var(--ease-out, ease-out),
        border-color var(--t-fast, 140ms);
    /* No default `animation: rise` — that re-fired every time the
       `.forge-list-item--inserted` marker class was removed (animation
       property changed → fresh playback), producing a visible bounce
       AFTER the proper insert choreography finished. Cards now stay
       visually static unless explicitly marked for a transition. */
}
.forge-card::before {
    content: "";
    position: absolute; inset: 0;
    border-radius: inherit;
    pointer-events: none;
    background:
        linear-gradient(180deg, oklch(1 0 0 / 0.04) 0%, transparent 30%),
        radial-gradient(120% 80% at 50% -20%, oklch(var(--accent-l) var(--accent-c) var(--accent-h) / 0.06), transparent 60%);
    opacity: var(--glass, 0.6);
}
[data-theme="light"] .forge-card::before {
    background:
        linear-gradient(180deg, oklch(1 0 0 / 0.6) 0%, transparent 30%),
        radial-gradient(120% 80% at 50% -20%, oklch(var(--accent-l) var(--accent-c) var(--accent-h) / 0.04), transparent 60%);
}
.forge-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
    border-color: var(--line-strong, var(--border-b2));
}
.forge-card:focus-within {
    border-color: var(--line-accent);
    box-shadow: var(--shadow-glow, 0 0 0 1px var(--accent));
}
.forge-card__header  {
    padding: 0 0 var(--s-3, 12px);
    margin-bottom: var(--s-3, 12px);
    border-bottom: 1px solid var(--line, var(--border-b0));
    position: relative; z-index: 2;
}
.forge-card__title   {
    margin: 0;
    font-size: 13px;
    font-family: var(--font-mono, inherit);
    color: var(--fg-3, var(--text-t3));
    letter-spacing: 0.04em;
    text-transform: uppercase;
    font-weight: 500;
    /* Q.14 (2026-06-05) — long titles caused uneven card heights when
       rendered in a ForgeCardGrid (user-reported regression — pieces like
       "134 1641A5 SDA SD41" wrapped over multiple lines, breaking the
       grid's visual rhythm). Clamp to 2 lines with ellipsis + native
       browser tooltip (title attribute carries the full text); cards
       stay rectangular and predictable. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
    overflow-wrap: anywhere;
    /* Stable line-height so 2 clamped lines reserve consistent vertical
       space regardless of accent / theme font scaling. */
    line-height: 1.35;
    max-height: calc(2 * 1.35em);
}
.forge-card__subtitle {
    margin: 4px 0 0;
    font-size: var(--typography-scale-sm);
    color: var(--fg-3, var(--text-t3));
    font-family: var(--font-sans, inherit);
    text-transform: none;
    letter-spacing: 0;
}
.forge-card__body    { padding: 0; flex: 1; position: relative; z-index: 2; }
.forge-card__footer  {
    padding: var(--s-3, 12px) 0 0;
    margin-top: var(--s-3, 12px);
    border-top: 1px solid var(--line, var(--border-b0));
    background: transparent;
    position: relative; z-index: 2;
}
.forge-card--interactive { cursor: pointer; }
.forge-card--interactive:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
}

.forge-kpi { padding: var(--spacing-5); }
.forge-kpi__label  { font-size: var(--typography-scale-sm); color: var(--text-t3); margin-bottom: var(--spacing-2); }
.forge-kpi__value  { font-size: var(--typography-scale-3xl); font-weight: var(--typography-weights-semibold); color: var(--text-t1); line-height: 1; }
.forge-kpi__delta  {
    display: inline-flex; align-items: center; gap: var(--spacing-1);
    margin-top: var(--spacing-2);
    font-size: var(--typography-scale-sm);
}
.forge-kpi__delta--up   { color: var(--semantic-success); }
.forge-kpi__delta--down { color: var(--semantic-danger); }
.forge-kpi__delta--flat { color: var(--text-t3); }
.forge-kpi__progress { margin-top: var(--spacing-3); height: 4px; background: var(--surface-s3); border-radius: var(--radius-full); overflow: hidden; }
.forge-kpi__progress-fill { height: 100%; background: var(--accent-base); transition: width var(--motion-durationBase) var(--motion-easing); }

.forge-avatar {
    display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px;
    background: var(--accent-dim); color: var(--accent-base);
    border-radius: var(--radius-full);
    font-weight: var(--typography-weights-semibold);
    font-size: var(--typography-scale-sm);
    user-select: none;
    overflow: hidden;
}
.forge-avatar img { width: 100%; height: 100%; object-fit: cover; }
.forge-avatar--sm { width: 28px; height: 28px; font-size: var(--typography-scale-xs); }
.forge-avatar--lg { width: 48px; height: 48px; font-size: var(--typography-scale-lg); }

/* ------------------------------------ */
/* Data table v2 — sortable, filterable, virtualized, mobile-responsive,  */
/* exportable. ADR 026 + ADR 027 (semantic classes + design tokens).      */
/* ------------------------------------ */

.forge-table-shell {
    display: flex; flex-direction: column;
    background: var(--surface-s1);
    border: 1px solid var(--border-b1);
    border-radius: var(--radius-lg);
    /* IMPORTANT: overflow stays visible so the toolbar's column-picker /
       filter / export / sort dropdowns can escape the shell's rounded
       boundary. The previous `overflow: hidden` value clipped those
       popups to the shell — visible in the user audit screenshot
       (column-picker bleeding outside the card). Rounded-corner clipping
       for the table body now lives on `.forge-table-wrap` (overflow: auto
       + matching border-radius), so the bottom corners still hug the
       shell border. The toolbar at the top already has straight bottom
       edges so no extra rounding needed there. */
    overflow: visible;
    /* Establishes a stacking context — dropdowns inside use z-index 30,
       and we don't want them competing with z-index from outer page
       chrome (modals, navbar dropdowns, etc.). */
    isolation: isolate;
}

.forge-table-wrap {
    /* Round the bottom corners to follow the shell. Top corners stay
       square because the toolbar sits above and provides its own border-
       bottom seam. */
    border-bottom-left-radius: calc(var(--radius-lg) - 1px);
    border-bottom-right-radius: calc(var(--radius-lg) - 1px);
}

.forge-table-toolbar {
    display: flex; align-items: center; gap: var(--spacing-3);
    padding: var(--spacing-3) var(--spacing-4);
    background: var(--surface-s2);
    border-bottom: 1px solid var(--border-b1);
    flex-wrap: wrap;
}
.forge-table-toolbar__title { display: flex; align-items: center; gap: var(--spacing-2); flex: 1 0 auto; }
.forge-table-toolbar__heading {
    margin: 0;
    font-size: var(--typography-scale-base);
    font-weight: var(--typography-weights-semibold);
    color: var(--text-t1);
}
.forge-table-toolbar__count {
    background: var(--surface-s3);
    color: var(--text-t2);
    font-size: var(--typography-scale-xs);
    padding: 2px 8px;
    border-radius: var(--radius-sm);
    font-variant-numeric: tabular-nums;
}
.forge-table-toolbar__search {
    position: relative;
    flex: 1 1 240px;
    max-width: 360px;
    display: flex; align-items: center;
}
.forge-table-toolbar__search > svg {
    position: absolute;
    left: 10px;
    /* Vertically centre the icon — without an explicit `top` the absolute
       svg defaults to top:0, leaving the input's placeholder + caret
       visually BELOW it. (Same fix as .forge-search__icon — both surfaces
       use the same icon-overlay-on-input pattern.) */
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    color: var(--text-t3);
    pointer-events: none;
}
.forge-table-toolbar__search > input {
    width: 100%;
    /* Reserve space on the left so placeholder + caret sit AFTER the icon,
       not on top of it. 32 px = 10 px svg-left + 16 px svg-width + 6 px
       breathing room. Mirror the global ForgeSearch input padding so both
       surfaces feel identical to type into. */
    padding-inline-start: 32px;
}
.forge-table-toolbar__actions { display: flex; align-items: center; gap: var(--spacing-1); flex: 0 0 auto; }
.forge-table-toolbar__menu { position: relative; }
.forge-table-toolbar__dropdown {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 30;
    min-width: 220px;
    /* Clamp width so a narrow viewport can't push the dropdown off-screen
       to the left when right: 0 anchors it under the toolbar icon. */
    max-width: min(320px, calc(100vw - 16px));
    margin: 0; padding: var(--spacing-1);
    list-style: none;
    background: var(--surface-s1);
    border: 1px solid var(--border-b1);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    animation: forge-dropdown-in var(--motion-durationFast) cubic-bezier(0.16, 1, 0.3, 1);
}
/* Narrow viewports: dropdown opens full-width below the toolbar.
   We need three things on mobile:
   1. `.forge-table-shell` to NOT clip overflow (its desktop `overflow: hidden`
      crops dropdowns that extend below the toolbar). The internal table
      keeps its own horizontal scroll via `.forge-table-wrap { overflow: auto }`.
   2. Dropdown positioned full-width to the viewport edges (8 px margin)
      instead of anchored to the toolbar button's right edge, which would
      push it off-screen when the button is in the right half of the toolbar.
   3. `.forge-table-toolbar__menu` reset to `position: static` so the
      dropdown's anchors are resolved against the toolbar (which we make
      `position: relative`), not the menu wrapper. */
@media (max-width: 640px) {
    .forge-table-shell {
        overflow: visible;
    }
    .forge-table-wrap {
        overflow-x: auto;
    }
    .forge-table-toolbar {
        position: relative;
    }
    .forge-table-toolbar__menu {
        position: static;
    }
    .forge-table-toolbar__dropdown {
        position: absolute;
        top: calc(100% + 6px);
        right: 8px;
        left: 8px;
        max-width: none;
        min-width: 0;
        width: auto;
        /* z-index above adjacent rows + sticky cells. */
        z-index: 50;
    }
}
@keyframes forge-dropdown-in {
    from { opacity: 0; transform: translateY(-4px); }
    to { opacity: 1; transform: translateY(0); }
}
/* Each <li> inside the toolbar dropdown gets a small vertical rhythm
   so column-picker checkboxes don't visually mash together — the user
   reported "u karet nejsou vubec mezi checkboxy vertikalni rozestupy"
   (no vertical spacing between checkbox rows) and asked for the same
   rhythm as the table dropdown. Same rule for both grid types. */
.forge-table-toolbar__dropdown li {
    padding: 0;
    margin: 2px 0;
}
.forge-table-toolbar__dropdown li:first-child { margin-top: 0; }
.forge-table-toolbar__dropdown li:last-child  { margin-bottom: 0; }

.forge-table-toolbar__check {
    display: flex; align-items: center; gap: var(--spacing-2);
    padding: var(--spacing-2) var(--spacing-3);
    color: var(--text-t1);
    font-size: var(--typography-scale-sm);
    cursor: pointer;
    border-radius: var(--radius-sm);
    width: 100%;             /* fills the dropdown li so hover surface matches the row */
    box-sizing: border-box;
}
.forge-table-toolbar__check:hover { background: var(--surface-s2); }
.forge-table-toolbar__separator {
    height: 1px; background: var(--border-b0);
    margin: var(--spacing-1) 0;
    list-style: none;
}
.forge-table-toolbar__action,
.forge-table-toolbar__reset {
    display: flex; align-items: center; gap: var(--spacing-2);
    width: 100%;
    padding: var(--spacing-2) var(--spacing-3);
    background: transparent;
    border: 0;
    color: var(--text-t1);
    font-size: var(--typography-scale-sm);
    text-align: left;
    cursor: pointer;
    border-radius: var(--radius-sm);
}
.forge-table-toolbar__action:hover,
.forge-table-toolbar__reset:hover { background: var(--surface-s2); }
.forge-table-toolbar__reset { color: var(--semantic-danger); }

.forge-icon-button__badge {
    position: absolute; top: 4px; right: 4px;
    width: 8px; height: 8px;
    background: var(--accent-base);
    border-radius: 50%;
    box-shadow: 0 0 0 2px var(--surface-s2);
}

.forge-table-wrap { overflow: auto; max-height: 100%; }
.forge-table { width: 100%; border-collapse: collapse; font-size: var(--typography-scale-base); }
.forge-table thead th {
    text-align: left;
    padding: var(--spacing-3) var(--spacing-4);
    background: var(--surface-s2);
    border-bottom: 1px solid var(--border-b1);
    font-weight: var(--typography-weights-semibold);
    color: var(--text-t2);
    font-size: var(--typography-scale-sm);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    position: sticky; top: 0; z-index: 5;
    white-space: nowrap;
}
.forge-table thead th.is-right { text-align: right; }
.forge-table thead th.is-center { text-align: center; }
.forge-table thead th.is-sticky {
    position: sticky; left: 0; z-index: 6;
    background: var(--surface-s2);
    box-shadow: 1px 0 0 var(--border-b1);
}
.forge-table thead th.is-sortable .forge-table__sort-btn {
    display: inline-flex; align-items: center; gap: var(--spacing-1);
    background: transparent;
    border: 0; padding: 0;
    color: inherit;
    font: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
    cursor: pointer;
    transition: color var(--motion-durationFast) ease;
}
.forge-table thead th.is-sortable .forge-table__sort-btn:hover { color: var(--text-t1); }
.forge-table thead th.is-sorted { color: var(--accent-base); }
.forge-table thead th.is-sorted .forge-table__sort-btn { color: var(--accent-base); }
.forge-table__sort-icon {
    display: inline-flex; align-items: center;
    color: var(--text-t4);
    transition: color var(--motion-durationFast) var(--motion-easing), transform var(--motion-durationFast) var(--motion-easing);
}
.forge-table thead th.is-sorted .forge-table__sort-icon { color: var(--accent-base); }
.forge-table__sort-rank {
    margin-left: 4px;
    font-size: 9px;
    color: var(--text-t3);
    font-weight: var(--typography-weights-semibold);
}

.forge-table__filter-row th {
    padding: var(--spacing-1) var(--spacing-2);
    background: var(--surface-s1);
    text-transform: none;
    font-weight: normal;
    letter-spacing: 0;
    border-bottom: 1px solid var(--border-b0);
    position: static;
    z-index: auto;
}
.forge-table__filter-range {
    display: flex; gap: 4px;
    /* When ForgeDateInput (and other Forge form wrappers) live inside a
       filter range, vertically center them against the surrounding row. */
    align-items: center;
}
.forge-table__filter-range > input,
.forge-table__filter-range > .forge-date-input { min-width: 0; flex: 1; }

/* ForgeSelect used as a Boolean/Enum column filter (replaces the old native
   <select>). Compact it to the filter-row scale + fill the header cell. */
.forge-table__filter-select { width: 100%; }
.forge-table__filter-select .forge-select-v2__trigger {
    min-height: 0;
    padding: 3px 8px;
    font-size: var(--typography-scale-xs, 0.75rem);
}

.forge-table tbody td {
    padding: var(--spacing-3) var(--spacing-4);
    border-bottom: 1px solid var(--border-b0);
    color: var(--text-t1);
    vertical-align: middle;
}
.forge-table tbody td.is-right { text-align: right; font-variant-numeric: tabular-nums; }
.forge-table tbody td.is-center { text-align: center; }
.forge-table tbody td.is-sticky {
    position: sticky; left: 0;
    background: var(--surface-s1);
    box-shadow: 1px 0 0 var(--border-b0);
}
.forge-table tbody tr:hover { background: var(--surface-s2); }
.forge-table tbody tr:hover td.is-sticky { background: var(--surface-s2); }

/* During row insert/update/delete animations, the row-level ::after sweep
   passes UNDER each cell but the sticky cell's opaque background
   (var(--surface-s1)) occludes it. Drop the sticky cell's background to
   transparent for the duration of the animation so the sweep is visible
   on the sticky column too. The row-level keyframe pulses the parent
   <tr> background; the sticky cell inherits visually because it's
   transparent during the animation window.

   Specificity tower: animation classes on <tr> won't reach cells unless we
   chain >. We chain explicitly on `tr.forge-list-item--*` to outrank the
   base `.forge-table tbody td.is-sticky` rule (0,3,1 vs ours 0,3,2). */
.forge-table tbody tr.forge-list-item--inserted > td.is-sticky,
.forge-table tbody tr.forge-list-item--updated > td.is-sticky,
.forge-table tbody tr.forge-list-item--deleting > td.is-sticky {
    background: transparent;
}
.forge-table tbody tr:last-child td { border-bottom: none; }

.forge-table__sentinel td {
    text-align: center;
    color: var(--text-t3);
    padding: var(--spacing-4);
    border-bottom: none;
}
.forge-table__loader {
    display: inline-flex; align-items: center; gap: var(--spacing-2);
    color: var(--text-t3);
    font-size: var(--typography-scale-sm);
}

/* Establish an inline-size container so the responsive rules below fire on
   the table's actual container (the showcase mobile stage at 375 px, the
   main page at any width) rather than the viewport. Component-internal
   responsiveness MUST react to its container, not the viewport — see
   Component Authoring Rules §8. */
.forge-table-shell {
    container-type: inline-size;
    container-name: forge-table;
}

/* Mobile responsive — table container <= 640px collapses each row into a card.
   @container fires inside the showcase mobile preview (stage = 375 px wide)
   AND in production when the page-level container is narrow. */
@container forge-table (max-width: 640px) {
    .forge-table-shell { border-radius: var(--radius-md); }
    .forge-table thead { display: none; }

    /* Reveal the filter row even on mobile when the user explicitly opens
       it with the Filters toolbar button. Without this, `display: none`
       on <thead> swallowed the filter row entirely so tapping Filters
       did nothing visible — a user-reported bug.
       The filter row uses a single-column layout on mobile (one filter
       per column wraps onto its own row) to stay readable on small
       viewports. */
    .forge-table[data-filters-open="true"] thead { display: table-header-group; }
    .forge-table[data-filters-open="true"] thead tr:not(.forge-table__filter-row) {
        display: none;
    }
    .forge-table[data-filters-open="true"] .forge-table__filter-row {
        display: grid;
        grid-template-columns: 1fr;
        gap: var(--spacing-2);
        padding: var(--spacing-2);
        background: var(--surface-s1);
    }
    .forge-table[data-filters-open="true"] .forge-table__filter-row th {
        display: block;
        padding: 0;
    }
    .forge-table[data-filters-open="true"] .forge-table__filter-row th::before {
        content: attr(data-label);
        display: block;
        color: var(--text-t3);
        font-size: var(--typography-scale-xs);
        font-weight: var(--typography-weights-medium);
        text-transform: uppercase;
        letter-spacing: 0.04em;
        margin-bottom: 4px;
    }

    .forge-table tr {
        display: grid;
        grid-template-columns: minmax(40%, auto) 1fr;
        column-gap: var(--spacing-3);
        padding: var(--spacing-3);
        border-bottom: 1px solid var(--border-b0);
        background: var(--surface-s1);
    }
    /* Filter row is grid-driven via its own override above; the generic
       grid template above would break it otherwise. */
    .forge-table[data-filters-open="true"] thead .forge-table__filter-row {
        grid-template-columns: 1fr;
    }
    .forge-table tr:hover { background: var(--surface-s2); }
    .forge-table td {
        display: contents;
        border: 0;
        padding: 0;
    }
    .forge-table td::before {
        content: attr(data-label);
        color: var(--text-t3);
        font-size: var(--typography-scale-xs);
        font-weight: var(--typography-weights-medium);
        text-transform: uppercase;
        letter-spacing: 0.04em;
        align-self: center;
    }
    .forge-table td.is-hidden-mobile { display: none; }
    .forge-table td.is-hidden-mobile::before { display: none; }
    .forge-table thead th.is-hidden-mobile { display: none; }
    .forge-table__sentinel td::before { display: none; }
    .forge-table__sentinel td { display: block; }
}

/* The branded letterhead (title + generated timestamp) is injected by
   forge-data-table.js `printTable(...)` ONLY for the duration of a Print
   export. Keep it out of the on-screen render — it exists purely for paper. */
.forge-print-doc { display: none; }

/* ════════════════════════════════════════════════════════════════════════
   PRINT — branded, theme-independent, black-&-white-safe document output.

   ForgeDataTable / ForgeCardGrid's "Print" export calls forge-data-table.js
   `printTable(tableId, opts)`, which:
     (a) flags <body> with `is-printing-forge-table-{id}`,
     (b) tags the target shell with `.forge-print-target`, and
     (c) injects a `.forge-print-doc` letterhead (title + timestamp) at the
         top of the target — mirroring the PDF export's header band.
   The rules below then:
     • blank the app chrome (sidebar / top-bar / nav) so ONLY the table prints,
     • FORCE a light palette regardless of the active theme — a dark theme must
       never bleed dark ink (or solid black backgrounds) onto paper,
     • restyle the grid as a report: light header fill + accent underline +
       whisper-light zebra that stays legible on a mono / greyscale printer,
     • drop every interactive affordance (toolbar, action buttons, sort icons,
       infinite-scroll sentinels).
   A plain Ctrl+P sets no body flag, so the full page still prints; the same
   table-beautify rules just tidy the grid in that path too.

   Colours mirror Pdf/TodoSummaryReportTemplate.cs so the Print and PDF exports
   read as one document family: accent #4C6BC9, ink #1A1F36, header fill
   #E7ECF5, zebra #F7F8FA, hairline #E5E7EB. */
@media print {
    /* Comfortable page box; the browser adds its own date + page-n/N header /
       footer, which the user toggles in the print dialog. */
    @page { margin: 14mm; }

    /* ── isolation: print ONLY the flagged table / card-grid ── */
    body[class*="is-printing-forge-table"] * { visibility: hidden !important; }
    body[class*="is-printing-forge-table"] .forge-print-target,
    body[class*="is-printing-forge-table"] .forge-print-target * { visibility: visible !important; }
    body[class*="is-printing-forge-table"] .forge-print-target {
        position: absolute;
        inset: 0 auto auto 0;
        width: 100%;
        margin: 0;
        padding: 0;
        border: none !important;
        box-shadow: none !important;
        background: #ffffff !important;
    }

    /* ── branded letterhead (JS-injected) — mirrors the PDF header band ── */
    body[class*="is-printing-forge-table"] .forge-print-target .forge-print-doc {
        display: block;
        margin: 0 0 14px;
    }
    .forge-print-doc__title {
        margin: 0;
        font-size: 19pt;
        font-weight: 600;
        letter-spacing: -0.01em;
        color: #1A1F36;
    }
    .forge-print-doc__meta {
        margin-top: 3px;
        font-size: 9pt;
        color: #6B7280;
    }
    .forge-print-doc__rule {
        height: 0;
        margin: 7px 0 0;
        border: 0;
        border-top: 1.5pt solid #4C6BC9;
    }

    /* ── strip interactive chrome from the printed target ── */
    .forge-table-toolbar,
    .forge-table__sentinel,
    .forge-table__sort-icon,
    .forge-card-grid__sentinel { display: none !important; }
    .forge-print-target button,
    .forge-print-target .forge-button,
    .forge-print-target .forge-icon-button,
    .forge-print-target a.forge-button,
    .forge-print-target .forge-no-print { display: none !important; }

    /* ── the table itself: light, structured, B&W-safe ── */
    .forge-table-shell,
    .forge-card-grid-shell { border: none !important; box-shadow: none !important; background: #ffffff !important; }
    .forge-table-wrap { overflow: visible !important; max-height: none !important; }
    .forge-table {
        width: 100%;
        border-collapse: collapse;
        font-size: 10pt;
        color: #1A1F36;
    }
    .forge-table thead th {
        padding: 7px 9px;
        font-weight: 600;
        text-align: left;
        color: #1A1F36 !important;
        background: #E7ECF5 !important;
        border-bottom: 1.5pt solid #4C6BC9 !important;
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }
    .forge-table thead th.is-right { text-align: right; }
    .forge-table thead th.is-center { text-align: center; }
    .forge-table tbody td {
        padding: 6px 9px;
        vertical-align: top;
        word-break: break-word;
        color: #1A1F36 !important;
        border-bottom: 0.5pt solid #E5E7EB !important;
    }
    .forge-table tbody tr { background: #ffffff !important; }
    .forge-table tbody tr:nth-child(even) td {
        background: #F7F8FA !important;
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }
    .forge-table tbody tr:hover td { background: inherit !important; }

    /* ── card grid on paper: two-up, never split a card across a page ── */
    .forge-card-grid { grid-template-columns: 1fr 1fr !important; gap: 10px !important; }
    .forge-card-grid__card {
        break-inside: avoid;
        background: #ffffff !important;
        box-shadow: none !important;
        border: 0.75pt solid #D1D5DB !important;
    }
}

.forge-input--xs {
    padding: 4px 8px;
    font-size: var(--typography-scale-xs);
    height: auto;
}
.forge-input--search { padding-left: 32px; }

/* ────────────────────────────────────────────────────────────────────────
   Native date / datetime / time inputs — make them theme-aware.
   The browser's native calendar-picker indicator (the little icon on the
   right edge of a <input type="date">) is rendered in the user-agent's
   black ink by default. On Forge's dark theme it disappears against the
   dark input surface — the user reported they "can't see the calendar
   icon in dark mode". Two complementary fixes:

   1. `color-scheme: dark light` on the input lets the browser draw a
      themed version of the picker (Chromium / WebKit honour this).
   2. The picker indicator pseudo-element gets `filter: invert(...)`
      under `[data-theme="dark"]` so the icon reads as white-on-dark.

   Works on .forge-input, .forge-input--xs, and the standalone variants
   we use inside the table filter strip. Firefox doesn't expose
   ::-webkit-calendar-picker-indicator but its own date picker already
   honours color-scheme, so the same dark-mode tint applies.            */
.forge-input[type="date"],
.forge-input[type="datetime-local"],
.forge-input[type="time"],
.forge-input[type="month"],
.forge-input[type="week"] {
    color-scheme: light dark;
}

[data-theme="dark"] .forge-input[type="date"]::-webkit-calendar-picker-indicator,
[data-theme="dark"] .forge-input[type="datetime-local"]::-webkit-calendar-picker-indicator,
[data-theme="dark"] .forge-input[type="time"]::-webkit-calendar-picker-indicator,
[data-theme="dark"] .forge-input[type="month"]::-webkit-calendar-picker-indicator,
[data-theme="dark"] .forge-input[type="week"]::-webkit-calendar-picker-indicator {
    /* invert(0.85) lifts the icon to near-white; the small contrast hint
       keeps it from blowing out against the input background. */
    filter: invert(0.85) hue-rotate(180deg);
    cursor: pointer;
    /* Slight padding push so the icon doesn't sit flush with the border. */
    padding-inline-end: 2px;
}

/* Light-theme picker indicator gets a subtle accent tint so it doesn't
   read as plain black on a white input. */
.forge-input[type="date"]::-webkit-calendar-picker-indicator,
.forge-input[type="datetime-local"]::-webkit-calendar-picker-indicator,
.forge-input[type="time"]::-webkit-calendar-picker-indicator,
.forge-input[type="month"]::-webkit-calendar-picker-indicator,
.forge-input[type="week"]::-webkit-calendar-picker-indicator {
    opacity: 0.72;
    cursor: pointer;
    transition: opacity var(--motion-durationFast) ease;
}
.forge-input[type="date"]:hover::-webkit-calendar-picker-indicator,
.forge-input[type="datetime-local"]:hover::-webkit-calendar-picker-indicator,
.forge-input[type="time"]:hover::-webkit-calendar-picker-indicator,
.forge-input[type="month"]:hover::-webkit-calendar-picker-indicator,
.forge-input[type="week"]:hover::-webkit-calendar-picker-indicator {
    opacity: 1;
}

/* ────────────────────────────────────────────────────────────────────────
   ForgeDateInput — Forge-skinned date / datetime / time picker.

   The native calendar-picker indicator is unstylable on Chromium and
   pitch-black on dark themes. We replace it with our own Forge trigger
   button that calls showPicker() (or focuses the input as a fallback),
   so the surrounding skin is fully theme-aware while we keep the
   native picker for mobile keyboards + iOS sheets + accessibility.

   Layout:

     ┌────────────────────────────────────┐
     │ Label                              │   ← __label (stacked, optional *)
     │ ┌────────────────────┬───────┐     │
     │ │ 12. 05. 2026       │  📅   │ ←── │   ← __field = native + trigger
     │ └────────────────────┴───────┘     │
     │ Help text below                    │   ← __help
     └────────────────────────────────────┘

   Visual states (transitions clamped via prefers-reduced-motion):
     · rest        : line-strong border, surface-s1 fill
     · hover       : accent-soft tint on trigger, icon lifts to accent
     · focus-within: accent border + 3-px accent-soft halo
     · has-error   : danger border + danger halo
     · disabled    : surface-s2 fill, fg-4 text, no pointer
                                                                          */
.forge-date-input {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1, 4px);
    /* Internal layout knobs — override per call-site or globally in
       forge-tokens.css to retune trigger size / icon scale.            */
    --forge-date-trigger-size: 32px;
    --forge-date-trigger-icon: 18px;
    --forge-date-trigger-gap: 4px;
}

.forge-date-input__label {
    font-size: var(--typography-scale-sm);
    color: var(--text-t2);
    font-weight: var(--typography-weights-medium);
    /* Tiny letter-spacing nudge to match other Forge field labels. */
    letter-spacing: 0.01em;
}

.forge-date-input__required {
    color: var(--semantic-danger);
    margin-inline-start: 2px;
    font-weight: var(--typography-weights-bold);
    user-select: none;
}

/* ── Field wrapper = composite border that hosts native input + trigger.
   Using a wrapper (instead of border on the native input) lets us style
   focus-within across both the input and the trigger button, so the ring
   travels with focus whichever child has it.                            */
.forge-date-input__field {
    position: relative;
    display: flex;
    align-items: stretch;
    width: 100%;
    height: var(--input-height);
    background: var(--input-bg);
    color: var(--input-text);
    border: var(--input-border-width) solid var(--input-border);
    border-radius: var(--input-radius);
    /* Clip native focus flash to the field's rounded corners. Without
       `overflow: hidden` the browser draws a square focus ring on the
       inner <input> that pokes outside the field's radius — user-flagged
       as "modré probliknutí které nerespektuje zaoblení". */
    overflow: hidden;
    transition: border-color var(--t-fast, 140ms) var(--ease-out, ease-out),
                box-shadow var(--t-fast, 140ms) var(--ease-out, ease-out),
                background var(--t-fast, 140ms) var(--ease-out, ease-out);
    /* Subtle inset shadow at rest gives the field its skeuomorphic
       depth. Disappears on focus when the halo takes over.            */
    box-shadow: inset 0 1px 0 0 oklch(from var(--surface-s2) l c h / 0.4);
}
.forge-date-input__field:hover {
    border-color: color-mix(in srgb, var(--input-border-focus) 50%, var(--input-border));
}
.forge-date-input__field:focus-within {
    border-color: var(--input-border-focus);
    background: var(--input-bg-focus);
    box-shadow: var(--input-shadow-focus);
}
.forge-date-input__field.has-error {
    border-color: var(--semantic-danger);
}
.forge-date-input__field.has-error:focus-within {
    border-color: var(--semantic-danger);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--semantic-danger) 22%, transparent);
}

/* ── Native input — strip the OS chrome so the wrapper carries the
   visual border. The calendar-picker pseudo-element is hidden via
   `appearance: none` + `opacity: 0` on the indicator (Chromium) and
   `color: transparent` on text overlap (Safari).                       */
.forge-date-input__native {
    flex: 1 1 auto;
    min-width: 0;
    /* Match other Forge inputs vertically. */
    padding: var(--input-padding-y, 0) var(--input-padding-x);
    /* Mobile Safari likes to add 1px of internal padding — nuke it. */
    margin: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font-family: inherit;
    font-size: var(--typography-scale-base);
    line-height: var(--input-height);
    /* color-scheme lets Chromium/WebKit pick a dark/light internal
       picker without us having to invert anything else. */
    color-scheme: light dark;
}
.forge-date-input__native:focus {
    outline: none;
}
/* Hide the native picker indicator — our trigger button replaces it.
   Chromium / Edge / modern Safari: ::-webkit-calendar-picker-indicator. */
.forge-date-input__native::-webkit-calendar-picker-indicator {
    display: none;
    -webkit-appearance: none;
    appearance: none;
}
/* Webkit / Chromium spin buttons on type="time" + the inner field
   wrappers also get killed so our trigger is the sole click target.    */
.forge-date-input__native::-webkit-inner-spin-button,
.forge-date-input__native::-webkit-clear-button {
    display: none;
    -webkit-appearance: none;
    appearance: none;
}
.forge-date-input__native::-webkit-datetime-edit {
    /* The editable parts (day / month / year etc.) inherit our font
       directly so they match the surrounding Forge typography.        */
    padding: 0;
}
.forge-date-input__native::placeholder {
    color: var(--input-placeholder);
}

/* ── Trigger button — square icon button glued to the input's right
   edge. Hover/focus get accent treatment; icon rotates a tiny bit
   for tactile feedback.                                                */
.forge-date-input__trigger {
    appearance: none;
    flex: 0 0 auto;
    align-self: center;
    width: var(--forge-date-trigger-size);
    height: var(--forge-date-trigger-size);
    margin-inline-end: var(--forge-date-trigger-gap);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 0;
    border-radius: var(--r-sm, 6px);
    color: var(--text-t2);
    cursor: pointer;
    transition: color var(--t-fast, 140ms) var(--ease-out, ease-out),
                background var(--t-fast, 140ms) var(--ease-out, ease-out),
                transform var(--t-fast, 140ms) var(--ease-out, ease-out);
}
.forge-date-input__trigger svg {
    width: var(--forge-date-trigger-icon);
    height: var(--forge-date-trigger-icon);
    pointer-events: none;
    transition: transform var(--t-fast, 140ms) var(--ease-out, ease-out);
}
.forge-date-input__trigger:hover {
    color: var(--accent-base, var(--accent));
    background: var(--accent-soft);
}
.forge-date-input__trigger:hover svg {
    /* Tiny rotation gives the calendar a playful "open me" tilt.
       Override per call-site with `--forge-date-trigger-tilt: 0deg`
       if you want it dead-still.                                     */
    transform: rotate(var(--forge-date-trigger-tilt, -6deg));
}
.forge-date-input__trigger:active {
    transform: scale(0.94);
}
.forge-date-input__trigger:focus-visible {
    outline: 2px solid var(--accent-base, var(--accent));
    outline-offset: 2px;
}

/* ── Disabled / readonly states ──────────────────────────────────── */
.forge-date-input.is-disabled .forge-date-input__field,
.forge-date-input__field:has(.forge-date-input__native:disabled) {
    background: var(--input-disabled-bg);
    color: var(--input-disabled-text);
    cursor: not-allowed;
}
.forge-date-input.is-disabled .forge-date-input__label,
.forge-date-input.is-disabled .forge-date-input__help {
    opacity: 0.55;
}
.forge-date-input.is-disabled .forge-date-input__trigger,
.forge-date-input__field:has(.forge-date-input__native:disabled) .forge-date-input__trigger {
    color: var(--input-disabled-text);
    cursor: not-allowed;
    pointer-events: none;
}
.forge-date-input__native:disabled {
    cursor: not-allowed;
    color: var(--input-disabled-text);
}
.forge-date-input__native:read-only {
    cursor: default;
}

/* ── Help text under the field. */
.forge-date-input__help {
    font-size: var(--typography-scale-xs);
    color: var(--text-t3);
    line-height: 1.4;
}

/* ── Compact / xs variant — matches .forge-input--xs density used in
   ForgeDataTable filter strip + ForgeCardGrid filter chips.             */
.forge-date-input--xs .forge-date-input__field {
    height: auto;
}
.forge-date-input--xs .forge-date-input__native {
    padding: 4px 8px;
    font-size: var(--typography-scale-xs);
    line-height: 1.2;
}
.forge-date-input--xs {
    --forge-date-trigger-size: 24px;
    --forge-date-trigger-icon: 14px;
    --forge-date-trigger-gap: 2px;
}

/* ── Reduced motion: kill the icon tilt + transform so motion-sensitive
   users get a steady control.                                          */
@media (prefers-reduced-motion: reduce) {
    .forge-date-input__field,
    .forge-date-input__trigger,
    .forge-date-input__trigger svg {
        transition: none;
    }
    .forge-date-input__trigger:hover svg,
    .forge-date-input__trigger:active {
        transform: none;
    }
}

/* ── ForgeDateInput popup (full Forge-native calendar / time picker) ─────
   Replaces the browser's native picker chrome with a Forge-skinned popover
   on desktop and a full-screen sheet on mobile (≤ 600 px). The popup is
   positioned by `forge-date-picker.js` using `position: fixed; top/left`
   so it can flip up + clamp horizontally without DOM-tree dependencies.

   Three layouts share the same chrome:
     · Date     → calendar only
     · Time     → time-grid only
     · DateTime → calendar (left) + time-grid (right), stack on mobile
*/
.forge-date-input.is-open .forge-date-input__field {
    border-color: var(--input-border-focus);
    box-shadow: var(--input-shadow-focus);
}

.forge-date-input__display {
    flex: 1 1 auto;
    min-width: 0;
    padding: var(--input-padding-y, 0) var(--input-padding-x);
    margin: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font-family: inherit;
    font-size: var(--typography-scale-base);
    line-height: var(--input-height);
    cursor: pointer;
    user-select: none;
}
.forge-date-input__display:focus { outline: none; }
.forge-date-input__display::placeholder { color: var(--input-placeholder); }

.forge-date-input__backdrop {
    position: fixed;
    inset: 0;
    background: oklch(from var(--surface-s0) l c h / 0);
    z-index: 9998;
    pointer-events: auto;
}

.forge-date-input__popup {
    /* `position: fixed` from the start so the popup is out-of-flow and
       cannot expand its parent container. Earlier behaviour: the popup
       was static until forge-date-picker.js's first frame promoted it
       to fixed — between mount and JS exec the popup briefly stretched
       the .forge-date-input wrapper, which on a filter-strip with
       multiple ForgeDateInputs side-by-side caused the whole toolbar
       row to balloon (user-reported regression: "klik na input rozhodi
       layout filtru"). Initial top/left is off-screen so we don't flash
       at (0,0) before JS positions the popup; the JS then immediately
       overrides with the right anchor. */
    position: fixed;
    top: -10000px;
    left: -10000px;
    z-index: 9999;
    display: flex;
    flex-direction: column;
    min-width: 296px;
    /* DateTime kind: calendar + time side-by-side needs ~580 px to be
       comfortable on desktop. Date / Time alone are content-sized
       around 296-340 px. */
    max-width: min(640px, calc(100vw - 16px));
    padding: 12px;
    background: var(--surface-s1);
    color: var(--text-t1);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-md, 10px);
    box-shadow:
        0 14px 32px -8px oklch(0 0 0 / 0.32),
        0 2px 4px oklch(0 0 0 / 0.08);
    animation: forge-date-popup-in var(--motion-durationBase) var(--ease-out-expo, cubic-bezier(0.16, 1, 0.3, 1));
    transform-origin: top center;
}

[data-forge-date-kind="datetime"] .forge-date-input__popup {
    /* DateTime layout: calendar above, time-grid below — separated by
       a divider. Earlier `flex-direction: row` put them side-by-side
       which made the popup ~580 px wide, harder to anchor under the
       trigger on narrower viewports. Stacking vertically also makes
       the layout the same as the mobile sheet, so users see a single
       consistent shape across breakpoints. */
    flex-direction: column;
    gap: 8px;
    align-items: stretch;
}

.forge-date-input__popup[data-forge-date-mode="sheet"] {
    position: fixed !important;
    inset: auto 0 0 0 !important;
    top: auto !important;
    left: 0 !important;
    right: 0 !important;
    border-radius: var(--r-lg, 16px) var(--r-lg, 16px) 0 0;
    max-width: 100vw !important;
    width: 100%;
    padding: 16px 16px calc(16px + env(safe-area-inset-bottom, 0));
    /* Cap the sheet's height so the calendar + time + footer all fit
       without the page behind it stretching. The internal columns get
       their own scroll (overflow-y on .forge-date-input__time-scroll)
       so navigation stays inside the sheet. */
    max-height: 88vh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    /* Make the footer sticky inside the sheet so the Today / OK buttons
       are always reachable even after a scroll. */
    transform: translateY(0);
    animation: forge-date-sheet-in 220ms var(--ease-out-expo, cubic-bezier(0.16, 1, 0.3, 1));
}

[data-forge-date-kind="datetime"] .forge-date-input__popup[data-forge-date-mode="sheet"] {
    flex-direction: column;
    gap: 12px;
}

.forge-date-input__popup[data-forge-date-mode="sheet"] ~ .forge-date-input__backdrop,
.forge-date-input__popup[data-forge-date-mode="sheet"] + .forge-date-input__backdrop {
    background: oklch(from var(--surface-s0) l c h / 0.5);
}
.forge-date-input.is-open .forge-date-input__backdrop {
    background: oklch(from var(--surface-s0) l c h / 0.0);
}
/* Mobile sheet variant gets a real dimmed backdrop. */
@media (max-width: 600px) {
    .forge-date-input.is-open .forge-date-input__backdrop {
        background: oklch(from var(--surface-s0) l c h / 0.45);
    }
}

@keyframes forge-date-popup-in {
    from { opacity: 0; transform: translateY(-6px) scale(0.96); }
    to { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes forge-date-sheet-in {
    from { opacity: 0; transform: translateY(24px); }
    to { opacity: 1; transform: translateY(0); }
}

/* Calendar pane ────────────────────────────────────────────────────────── */
.forge-date-input__calendar {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 272px;
}

.forge-date-input__nav {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: 4px;
}

.forge-date-input__nav-btn {
    appearance: none;
    width: 28px; height: 28px;
    display: inline-flex; align-items: center; justify-content: center;
    background: transparent;
    border: 0;
    border-radius: var(--r-sm, 6px);
    color: var(--text-t2);
    cursor: pointer;
    transition: background var(--t-fast, 140ms) var(--ease-out, ease-out),
                color var(--t-fast, 140ms) var(--ease-out, ease-out);
}
.forge-date-input__nav-btn:hover {
    background: var(--accent-soft);
    color: var(--accent-base, var(--accent));
}
.forge-date-input__nav-btn:focus-visible {
    outline: 2px solid var(--accent-base, var(--accent));
    outline-offset: 2px;
}

.forge-date-input__nav-title {
    appearance: none;
    background: transparent;
    border: 0;
    color: var(--text-t1);
    font-size: var(--typography-scale-base);
    font-weight: var(--typography-weights-semibold, 600);
    padding: 4px 10px;
    border-radius: var(--r-sm, 6px);
    cursor: pointer;
    text-transform: capitalize;
    transition: background var(--t-fast, 140ms) var(--ease-out, ease-out);
}
.forge-date-input__nav-title:hover {
    background: var(--accent-soft);
}

.forge-date-input__weekday-row {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
    margin-top: 2px;
}
.forge-date-input__weekday {
    font-size: var(--typography-scale-xs);
    text-transform: lowercase;
    color: var(--text-t3);
    text-align: center;
    padding: 4px 0;
    font-weight: var(--typography-weights-medium);
}

.forge-date-input__day-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
}
.forge-date-input__day {
    appearance: none;
    height: 36px;
    display: inline-flex; align-items: center; justify-content: center;
    background: transparent;
    border: 0;
    color: var(--text-t1);
    border-radius: var(--r-sm, 6px);
    font-size: var(--typography-scale-sm);
    font-variant-numeric: tabular-nums;
    cursor: pointer;
    transition: background var(--t-fast, 140ms) var(--ease-out, ease-out),
                color var(--t-fast, 140ms) var(--ease-out, ease-out),
                transform var(--t-fast, 140ms) var(--ease-out, ease-out);
}
.forge-date-input__day:hover:not(:disabled):not(.is-selected) {
    background: var(--accent-soft);
    color: var(--accent-base, var(--accent));
}
.forge-date-input__day.is-outside {
    color: var(--text-t4, var(--fg-4));
    opacity: 0.55;
}
.forge-date-input__day.is-today {
    box-shadow: inset 0 0 0 1px var(--accent-base, var(--accent));
    font-weight: var(--typography-weights-semibold, 600);
}
.forge-date-input__day.is-selected {
    background: var(--accent-base, var(--accent));
    color: var(--accent-on-base, #fff);
    font-weight: var(--typography-weights-semibold, 600);
}
.forge-date-input__day.is-disabled,
.forge-date-input__day:disabled {
    color: var(--text-t4, var(--fg-4));
    opacity: 0.35;
    cursor: not-allowed;
}
.forge-date-input__day:focus-visible {
    outline: 2px solid var(--accent-base, var(--accent));
    outline-offset: 2px;
}
.forge-date-input__day:active:not(:disabled) {
    transform: scale(0.94);
}

/* Year selector grid (shown when user clicks month/year title) ─────────── */
.forge-date-input__year-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 6px;
    min-height: 252px;
    padding: 8px 0;
}
.forge-date-input__year {
    appearance: none;
    padding: 12px 6px;
    background: transparent;
    border: 0;
    color: var(--text-t1);
    border-radius: var(--r-sm, 6px);
    font-size: var(--typography-scale-sm);
    font-variant-numeric: tabular-nums;
    cursor: pointer;
    transition: background var(--t-fast, 140ms) var(--ease-out, ease-out),
                color var(--t-fast, 140ms) var(--ease-out, ease-out);
}
.forge-date-input__year:hover {
    background: var(--accent-soft);
    color: var(--accent-base, var(--accent));
}
.forge-date-input__year.is-current {
    background: var(--accent-base, var(--accent));
    color: var(--accent-on-base, #fff);
    font-weight: var(--typography-weights-semibold, 600);
}

/* Time pane (for Time / DateTime kinds) ────────────────────────────────── */
.forge-date-input__time {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding-top: 8px;
    border-top: 1px solid var(--line-soft, var(--border-b0));
}
[data-forge-date-kind="time"] .forge-date-input__time {
    padding-top: 0;
    border-top: 0;
}

.forge-date-input__time-header {
    font-size: var(--typography-scale-sm);
    color: var(--text-t2);
    font-weight: var(--typography-weights-semibold, 600);
}

/* Two-column grid (hours + minutes) by default. Auto-fit so a third
   "seconds" column slots in cleanly when ShowSeconds=true. */
.forge-date-input__time-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(80px, 1fr));
    gap: 6px;
}
.forge-date-input__time-column {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-height: 0;
}
.forge-date-input__time-label {
    font-size: var(--typography-scale-xs);
    color: var(--text-t3);
    text-align: center;
    text-transform: lowercase;
}
.forge-date-input__time-scroll {
    display: flex;
    flex-direction: column;
    gap: 2px;
    max-height: 248px;
    overflow-y: auto;
    padding: 2px;
    /* Custom scrollbar (thin, accent on hover) — fits popup chrome. */
    scrollbar-width: thin;
    scrollbar-color: var(--text-t4, var(--fg-4)) transparent;
}
.forge-date-input__time-scroll::-webkit-scrollbar {
    width: 6px;
}
.forge-date-input__time-scroll::-webkit-scrollbar-thumb {
    background: var(--text-t4, var(--fg-4));
    border-radius: 3px;
}
.forge-date-input__time-cell {
    appearance: none;
    padding: 8px 6px;
    background: transparent;
    border: 0;
    color: var(--text-t1);
    border-radius: var(--r-sm, 6px);
    font-size: var(--typography-scale-sm);
    font-variant-numeric: tabular-nums;
    cursor: pointer;
    transition: background var(--t-fast, 140ms) var(--ease-out, ease-out),
                color var(--t-fast, 140ms) var(--ease-out, ease-out);
    text-align: center;
}
.forge-date-input__time-cell:hover:not(.is-selected) {
    background: var(--accent-soft);
    color: var(--accent-base, var(--accent));
}
.forge-date-input__time-cell.is-selected {
    background: var(--accent-base, var(--accent));
    color: var(--accent-on-base, #fff);
    font-weight: var(--typography-weights-semibold, 600);
}
.forge-date-input__time-cell:focus-visible {
    outline: 2px solid var(--accent-base, var(--accent));
    outline-offset: 2px;
}

/* Footer (Clear / Today / OK) ──────────────────────────────────────────
   Three-button row that spans the FULL width of the popup at every
   screen size (desktop popover + mobile sheet). The three actions are
   evenly distributed: Clear at the left edge, Today centred, OK at the
   right edge. Single layout = single muscle memory across breakpoints.
   ✓ Clear → removes the value + closes the popup
   ✓ Today → jumps view to today; commits a "today" value (Date kind
             closes the popup; DateTime / Time keep open so user can
             tweak the time)
   ✓ OK    → closes the popup, keeping the current selection
*/
.forge-date-input__footer {
    /* Two-column layout matching the actual DOM (Clear on left, then a
       .forge-date-input__footer-end group with Today + OK on the right).
       The previous 3-column grid expected three direct children but the
       DOM has only two, so it left a phantom column gap and the buttons
       didn't span the full width — visible as Today + OK bunched in the
       middle instead of pushed to the right edge.
       Using grid auto-1fr puts Clear flush left and the footer-end group
       flush right, with the footer-end's own flex layout handling Today
       + OK distribution. Buttons inside both columns stretch to full
       cell width via the per-button rules below. */
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 8px;
    align-items: stretch;
    margin-top: 4px;
    padding-top: 10px;
    border-top: 1px solid var(--line-soft, var(--border-b0));
    /* Sticky footer at the bottom on tall popups so the buttons stay
       visible even when the time grid scrolls long. */
    position: sticky;
    bottom: 0;
    background: var(--surface-s1);
    z-index: 2;
}

.forge-date-input__footer-end {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
}
.forge-date-input__footer-end > .forge-date-input__today,
.forge-date-input__footer-end > .forge-date-input__ok {
    flex: 1 1 0;
}
.forge-date-input__clear,
.forge-date-input__today,
.forge-date-input__ok {
    appearance: none;
    padding: 8px 12px;
    background: transparent;
    border: 0;
    color: var(--accent-base, var(--accent));
    border-radius: var(--r-sm, 6px);
    font-size: var(--typography-scale-sm);
    font-weight: var(--typography-weights-medium);
    cursor: pointer;
    text-align: center;
    transition: background var(--t-fast, 140ms) var(--ease-out, ease-out),
                color var(--t-fast, 140ms) var(--ease-out, ease-out);
}
.forge-date-input__today { text-align: center; }
.forge-date-input__clear { text-align: left; padding-left: 4px; }
.forge-date-input__ok    { text-align: right; padding-right: 4px; }
.forge-date-input__clear:hover,
.forge-date-input__today:hover {
    background: var(--accent-soft);
}
/* OK is the primary commit action — accent fill anchors the right side
   of the footer and signals "this is the commit button". */
.forge-date-input__ok {
    background: var(--accent-base, var(--accent));
    color: var(--accent-on-base, #fff);
    text-align: center;
    padding-right: 12px;
}
.forge-date-input__ok:hover {
    background: color-mix(in srgb, var(--accent-base, var(--accent)) 80%, white);
}
.forge-date-input__clear:focus-visible,
.forge-date-input__today:focus-visible,
.forge-date-input__ok:focus-visible {
    outline: 2px solid var(--accent-base, var(--accent));
    outline-offset: 2px;
}

/* Reduced motion ──────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
    .forge-date-input__popup,
    .forge-date-input__popup[data-forge-date-mode="sheet"] {
        animation: none;
    }
    .forge-date-input__day,
    .forge-date-input__year,
    .forge-date-input__time-cell,
    .forge-date-input__nav-btn,
    .forge-date-input__nav-title,
    .forge-date-input__clear,
    .forge-date-input__today {
        transition: none;
    }
    .forge-date-input__day:active:not(:disabled) {
        transform: none;
    }
}

/* ------------------------------------ */
/* Card grid (ForgeCardGrid)             */
/* ------------------------------------ */
/* Shell is purely structural — no border, no background, no rounded
   corners, no overflow clipping. The toolbar above and the cards
   below render directly on the page surface so each card's own
   border/shadow is the ONLY frame the user sees. The previous variant
   wrapped both layers in an outer rounded container, which combined
   with each card's own frame produced a "double box" the user
   correctly flagged as visually overcooked. */
.forge-card-grid-shell {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-4);
    background: transparent;
    border: none;
    border-radius: 0;
    overflow: visible;
}

/* The toolbar keeps its own subtle surface treatment so the search /
   sort / filter / column / export controls cluster as one block ABOVE
   the cards — the user explicitly asked for "horní panel s filtry atd
   jako u tabulky" (top panel with filters etc. like the table) right
   above the cards on the page background. */
.forge-card-grid-shell > .forge-table-toolbar {
    background: var(--surface-s1, var(--bg-1));
    border: 1px solid var(--border-b1, var(--line));
    border-radius: var(--radius-md);
}

/* Wrap = the area where the cards live. No padding so cards align
   flush with the toolbar's left/right edges; vertical gap from the
   shell handles spacing between toolbar and cards. */
.forge-card-grid-wrap { padding: 0; }

/* Filter strip — collapsible row of per-column filter inputs above the
   card grid. Mirrors the table's filter row but inline (no <td> grid),
   so each filter wears its own label. Wraps on narrow viewports.
   Rounded corners match the rest of Forge surfaces — sharp corners read
   as "raw HTML" and broke the visual cohesion the user flagged. */
.forge-card-grid__filterstrip {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-3);
    padding: var(--spacing-3) var(--spacing-4);
    border: 1px solid var(--line, var(--border-b1));
    border-radius: var(--radius-md);
    background: var(--surface-s1, var(--bg-2));
}
.forge-card-grid__filter {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 160px;
    flex: 1 1 200px;
}
.forge-card-grid__filterlabel {
    font-size: var(--typography-scale-xs, 11px);
    font-weight: var(--typography-weights-medium, 500);
    color: var(--fg-3, var(--text-t3));
    letter-spacing: 0.02em;
}
.forge-card-grid {
    display: grid;
    gap: var(--spacing-4);
}

/* The .forge-card-grid__card wrapper exists so Blazor has a DOM node to
   attach @key="..." onto for stable diffing. It MUST NOT carry its own
   visual frame — the user's CardTemplate already renders a ForgeCard with
   its own border + radius + hover lift, and a second outer frame
   produced visible "double-box" rendering the user explicitly flagged.
   `display: contents` lets the wrapper's children participate directly
   in the parent grid as if the wrapper weren't there visually, while
   keeping the DOM node so @key still works. */
.forge-card-grid__card {
    display: contents;
}
.forge-card-grid__sentinel {
    grid-column: 1 / -1;
    text-align: center;
    padding: var(--spacing-4);
    color: var(--text-t3);
}
@media (max-width: 640px) {
    .forge-card-grid-wrap { padding: var(--spacing-3); }
    .forge-card-grid { gap: var(--spacing-3); }
    .forge-card-grid__card { padding: var(--spacing-3); }
}
/* Card-grid print rules live in the unified PRINT block above (the branded,
   B&W-safe @media print near the table styles) so the table + card-grid Print
   exports share one document language. */

/* ------------------------------------ */
/* 8. Feedback                          */
/* ------------------------------------ */
.forge-alert {
    display: flex; align-items: flex-start; gap: var(--spacing-3);
    padding: var(--spacing-3) var(--spacing-4);
    border-radius: var(--radius-md);
    font-size: var(--typography-scale-base);
    border: 1px solid transparent;
}
.forge-alert__icon { flex: 0 0 18px; margin-top: 2px; }
.forge-alert__body { flex: 1; }
.forge-alert__title { font-weight: var(--typography-weights-semibold); margin-bottom: var(--spacing-1); }
.forge-alert--info    { background: color-mix(in srgb, var(--semantic-info) 12%, transparent);    color: var(--semantic-info);    border-color: color-mix(in srgb, var(--semantic-info) 28%, transparent); }
.forge-alert--success { background: color-mix(in srgb, var(--semantic-success) 12%, transparent); color: var(--semantic-success); border-color: color-mix(in srgb, var(--semantic-success) 28%, transparent); }
.forge-alert--warning { background: color-mix(in srgb, var(--semantic-warning) 12%, transparent); color: var(--semantic-warning); border-color: color-mix(in srgb, var(--semantic-warning) 28%, transparent); }
.forge-alert--danger  { background: color-mix(in srgb, var(--semantic-danger) 12%, transparent);  color: var(--semantic-danger);  border-color: color-mix(in srgb, var(--semantic-danger) 28%, transparent); }

.forge-spinner {
    display: inline-block;
    width: 18px; height: 18px;
    border: 2px solid var(--border-b2);
    border-top-color: var(--accent-base);
    border-radius: 50%;
    animation: forge-spin var(--motion-durationSlow) linear infinite;
}
.forge-spinner--sm { width: 14px; height: 14px; border-width: 2px; }
.forge-spinner--lg { width: 32px; height: 32px; border-width: 3px; }
@keyframes forge-spin { to { transform: rotate(360deg); } }

.forge-empty {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: var(--spacing-3);
    padding: var(--spacing-12) var(--spacing-6);
    color: var(--text-t3);
    text-align: center;
}
.forge-empty__icon { color: var(--text-t4); }
.forge-empty__title { font-size: var(--typography-scale-lg); color: var(--text-t1); font-weight: var(--typography-weights-medium); }
.forge-empty__description { font-size: var(--typography-scale-sm); color: var(--text-t3); max-width: 40ch; }

.forge-error-boundary {
    padding: var(--spacing-4);
    background: color-mix(in srgb, var(--semantic-danger) 8%, transparent);
    border: 1px solid color-mix(in srgb, var(--semantic-danger) 30%, transparent);
    border-radius: var(--radius-md);
    color: var(--semantic-danger);
}

/* ------------------------------------ */
/* 9. Dialog / modal                    */
/* ------------------------------------ */
.forge-backdrop {
    position: fixed; inset: 0;
    background: rgba(12, 15, 24, 0.48);
    backdrop-filter: blur(2px);
    display: flex; align-items: center; justify-content: center;
    padding: var(--spacing-4);
    z-index: 50;
    animation: forge-fade-in var(--motion-durationBase) var(--motion-easing);
}
.forge-dialog {
    background: var(--surface-s1);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    max-width: 520px;
    width: 100%;
    max-height: calc(100vh - var(--spacing-8));
    overflow: hidden;
    display: flex; flex-direction: column;
    animation: forge-dialog-in var(--motion-durationBase) var(--motion-easing);
}
.forge-dialog__header  { padding: var(--spacing-4) var(--spacing-5); border-bottom: 1px solid var(--border-b1); display: flex; align-items: center; justify-content: space-between; }
.forge-dialog__title   { margin: 0; font-size: var(--typography-scale-lg); font-weight: var(--typography-weights-semibold); }
.forge-dialog__body    { padding: var(--spacing-5); overflow-y: auto; }
.forge-dialog__footer  { padding: var(--spacing-3) var(--spacing-5); border-top: 1px solid var(--border-b1); background: var(--surface-s0); display: flex; justify-content: flex-end; gap: var(--spacing-2); }
.forge-dialog--lg { max-width: 780px; }
.forge-dialog--xl { max-width: 1040px; }

@keyframes forge-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes forge-dialog-in {
    from { opacity: 0; transform: translateY(8px) scale(0.98); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* ------------------------------------ */
/* 10. Search (topbar-optimized)        */
/* ------------------------------------ */
.forge-search {
    position: relative; display: flex; align-items: center;
    width: 100%; max-width: 420px;
}
.forge-search__icon {
    position: absolute; left: var(--spacing-3);
    /* Vertically centre the icon inside the input. Without an explicit `top`
       + transform the absolute span sits at the TOP of the .forge-search box,
       which leaves the input text + cursor visually BELOW the icon (because
       the input's text baseline is centred at the row's mid-line). */
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    color: var(--text-t3); pointer-events: none;
}
.forge-search__input {
    width: 100%;
    height: var(--controls-heightBase);
    padding: 0 var(--spacing-3) 0 calc(var(--spacing-3) * 2 + 18px);
    background: var(--surface-s2);
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    color: var(--text-t1);
    font-size: var(--typography-scale-base);
    transition: background var(--motion-durationFast) var(--motion-easing),
                border-color var(--motion-durationFast) var(--motion-easing);
}
.forge-search__input::placeholder { color: var(--text-t3); }
.forge-search__input:focus {
    outline: none;
    background: var(--surface-s1);
    border-color: var(--accent-base);
    box-shadow: 0 0 0 3px var(--accent-dim);
}
.forge-search__kbd {
    position: absolute; right: var(--spacing-2);
    padding: 2px 6px;
    background: var(--surface-s3);
    color: var(--text-t3);
    font-size: var(--typography-scale-xs);
    font-family: var(--typography-fontMonoFamily);
    border-radius: var(--radius-sm);
    pointer-events: none;
}
@media (max-width: 640px) {
    .forge-search__kbd { display: none; }
    .forge-search { max-width: none; }
}

/* ------------------------------------ */
/* 10c. Language menu (globe dropdown)  */
/* ------------------------------------ */
/* Spotlight-style culture picker. The trigger blends with the topbar's icon
   buttons; the menu drops below with a subtle slide-fade so it lands as a
   native overlay rather than a popping rectangle. */
.forge-langmenu {
    position: relative;
    display: inline-flex;
}
.forge-langmenu__trigger {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 36px;
    padding: 0 10px;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--text-t2);
    cursor: pointer;
    font: inherit;
    font-size: var(--typography-scale-sm);
    transition:
        background var(--motion-durationFast) var(--motion-easing),
        border-color var(--motion-durationFast) var(--motion-easing),
        color var(--motion-durationFast) var(--motion-easing);
}
.forge-langmenu__trigger:hover { background: var(--surface-s2); color: var(--text-t1); }
.forge-langmenu.is-open .forge-langmenu__trigger {
    background: var(--surface-s2);
    border-color: var(--border-b1);
    color: var(--text-t1);
}
.forge-langmenu__current {
    font-family: var(--typography-fontMonoFamily);
    font-weight: var(--typography-weights-semibold);
    letter-spacing: 0.04em;
}
.forge-langmenu__caret {
    transition: transform var(--motion-durationBase) var(--motion-easing);
}
.forge-langmenu.is-open .forge-langmenu__caret { transform: rotate(180deg); }

.forge-langmenu__backdrop {
    position: fixed;
    inset: 0;
    z-index: 60;
    background: transparent;
    cursor: default;
}

.forge-langmenu__menu {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 70;
    min-width: 220px;
    padding: 6px;
    background: var(--surface-elevated, var(--surface-s1));
    border: 1px solid var(--border-b1);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    display: flex;
    flex-direction: column;
    gap: 2px;
    /* Same fade-slide arc as ForgeDialog so the picker lands native to the
       Forge overlay vocabulary. transform-origin top-right anchors the
       expansion under the trigger. */
    transform-origin: top right;
    animation: forge-langmenu-in var(--motion-durationBase) var(--motion-easing);
}
@keyframes forge-langmenu-in {
    from { opacity: 0; transform: translateY(-6px) scale(0.97); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

.forge-langmenu__item {
    display: flex;
    align-items: center;
    gap: var(--spacing-3);
    width: 100%;
    padding: 8px 10px;
    background: transparent;
    color: var(--text-t1);
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font: inherit;
    font-size: var(--typography-scale-sm);
    text-align: left;
    transition: background var(--motion-durationFast) var(--motion-easing);
}
.forge-langmenu__item:hover,
.forge-langmenu__item:focus-visible {
    background: var(--surface-s2);
    outline: none;
}
.forge-langmenu__item.is-active {
    background: var(--accent-dim);
    color: var(--text-t1);
}
.forge-langmenu__item.is-active:hover { background: color-mix(in srgb, var(--accent-base) 18%, transparent); }
.forge-langmenu__flag { font-size: 16px; line-height: 1; flex-shrink: 0; }
.forge-langmenu__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.forge-langmenu__code {
    font-family: var(--typography-fontMonoFamily);
    font-size: var(--typography-scale-xs);
    color: var(--text-t3);
    letter-spacing: 0.04em;
}
.forge-langmenu__check { color: var(--accent-base); flex-shrink: 0; }

@media (max-width: 640px) {
    /* Mobile: anchor menu to right edge with a small inset, full readable width. */
    .forge-langmenu__menu {
        right: -8px;
        min-width: 240px;
    }
    /* Hide the current-code chip on mobile — the globe icon is enough,
       the open-state chevron + listbox tells users what they're picking. */
    .forge-langmenu__current { display: none; }
}

/* Trigger variant — looks like the input but is a <button> so the placeholder
   gets ellipsis instead of being clipped at "Se…" inside a 90 px field. */
.forge-search--trigger {
    cursor: pointer;
    background: transparent;
    border: none;
    padding: 0;
    text-align: left;
    font: inherit;
}
.forge-search__input--trigger {
    display: flex;
    align-items: center;
    color: var(--text-t3);
    font-weight: var(--typography-weights-regular);
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    /* Behaves like the real input: same height, padding, hover/focus chrome. */
    cursor: pointer;
}
.forge-search--trigger:hover .forge-search__input--trigger { color: var(--text-t2); }
.forge-search--trigger:focus-visible {
    outline: none;
}
.forge-search--trigger:focus-visible .forge-search__input--trigger {
    background: var(--surface-s1);
    border-color: var(--accent-base);
    box-shadow: 0 0 0 3px var(--accent-dim);
}

/* ------------------------------------ */
/* 10b. Search palette (Cmd+K modal)    */
/* ------------------------------------ */
/* Top-anchored modal on desktop (Spotlight / VS Code Quick Open pattern),
   fullscreen sheet on mobile. Tokens come from the same vocabulary as
   ForgeDialog so the palette inherits theme/accent flips for free. */
.forge-search-palette__backdrop {
    align-items: flex-start;
    padding-top: 15vh;
}
.forge-search-palette {
    background: var(--surface-s1);
    border: 1px solid var(--border-b1);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    width: 100%;
    max-width: 640px;
    max-height: min(70vh, 720px);
    display: flex; flex-direction: column;
    overflow: hidden;
    animation: forge-dialog-in var(--motion-durationBase) var(--motion-easing);
}

.forge-search-palette__inputrow {
    position: relative;
    display: flex; align-items: center;
    gap: var(--spacing-3);
    padding: var(--spacing-3) var(--spacing-4);
    border-bottom: 1px solid var(--border-b1);
    background: var(--surface-s1);
}
.forge-search-palette__icon {
    color: var(--text-t3);
    display: inline-flex;
    flex-shrink: 0;
}
.forge-search-palette__input {
    flex: 1; min-width: 0;
    background: transparent;
    border: none;
    color: var(--text-t1);
    font-size: var(--typography-scale-lg);
    height: 32px;
    outline: none;
}
.forge-search-palette__input::placeholder { color: var(--text-t3); }

.forge-search-palette__close {
    background: transparent;
    border: 1px solid var(--border-b1);
    color: var(--text-t3);
    border-radius: var(--radius-sm);
    padding: 2px 6px;
    font-family: var(--typography-fontMonoFamily);
    font-size: var(--typography-scale-xs);
    cursor: pointer;
    transition: background var(--motion-durationFast) var(--motion-easing);
}
.forge-search-palette__close:hover { background: var(--surface-s2); color: var(--text-t1); }
.forge-search-palette__close kbd { font: inherit; }

.forge-search-palette__body {
    overflow-y: auto;
    flex: 1;
    padding: var(--spacing-2) 0;
}
.forge-search-palette__section {
    padding: var(--spacing-2) var(--spacing-2);
}
.forge-search-palette__sectionhead {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--spacing-2) var(--spacing-3);
    color: var(--text-t3);
    font-size: var(--typography-scale-xs);
    font-weight: var(--typography-weights-semibold);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.forge-search-palette__clear {
    background: transparent;
    border: none;
    color: var(--text-t3);
    font-size: var(--typography-scale-xs);
    cursor: pointer;
    padding: 2px 4px;
    border-radius: var(--radius-sm);
    text-transform: none;
    letter-spacing: 0;
}
.forge-search-palette__clear:hover { color: var(--text-t1); background: var(--surface-s2); }

.forge-search-palette__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex; flex-direction: column;
    gap: 2px;
}
.forge-search-palette__row {
    display: flex; align-items: center;
    gap: var(--spacing-3);
    width: 100%;
    padding: var(--spacing-2) var(--spacing-3);
    background: transparent;
    color: var(--text-t1);
    border: none;
    border-radius: var(--radius-sm);
    text-align: left;
    cursor: pointer;
    text-decoration: none;
    font: inherit;
    transition: background var(--motion-durationFast) var(--motion-easing);
}
.forge-search-palette__row:hover,
.forge-search-palette__row:focus-visible {
    background: var(--surface-s2);
    outline: none;
}
.forge-search-palette__rowicon {
    color: var(--text-t3);
    flex-shrink: 0;
}
.forge-search-palette__rowtext {
    flex: 1; min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.forge-search-palette__rowhint {
    color: var(--text-t4, var(--text-t3));
    opacity: 0.6;
    flex-shrink: 0;
}

.forge-search-palette__empty {
    margin: 0;
    padding: var(--spacing-6) var(--spacing-4);
    color: var(--text-t3);
    text-align: center;
    font-size: var(--typography-scale-sm);
}

.forge-search-palette__footer {
    display: flex;
    justify-content: flex-end;
    gap: var(--spacing-3);
    padding: var(--spacing-2) var(--spacing-4);
    border-top: 1px solid var(--border-b1);
    background: var(--surface-s0);
    color: var(--text-t3);
    font-size: var(--typography-scale-xs);
}
.forge-search-palette__hint { display: inline-flex; align-items: center; gap: 4px; }
.forge-search-palette__hint kbd {
    background: var(--surface-s2);
    border: 1px solid var(--border-b1);
    border-radius: 3px;
    padding: 0 5px;
    font: 11px var(--typography-fontMonoFamily);
}

/* Mobile: fullscreen sheet. Drops the 15vh top offset, fills the viewport,
   pins the input row at the top. The footer hint legend is hidden — keyboard
   chips have no meaning on touch. */
@media (max-width: 640px) {
    .forge-search-palette__backdrop {
        padding: 0;
        padding-top: 0;
        align-items: stretch;
        background: var(--surface-s0);
        backdrop-filter: none;
    }
    .forge-search-palette {
        max-width: none;
        max-height: 100vh;
        height: 100vh;
        border-radius: 0;
        border: none;
        box-shadow: none;
        animation: forge-fade-in var(--motion-durationBase) var(--motion-easing);
    }
    .forge-search-palette__inputrow {
        padding: env(safe-area-inset-top, 12px) var(--spacing-4) var(--spacing-3);
    }
    .forge-search-palette__footer { display: none; }
}

/* ------------------------------------ */
/* 11. Chart (SVG containers)           */
/* ------------------------------------ */
.forge-chart { width: 100%; color: var(--text-t2); }
.forge-chart__axis line,
.forge-chart__axis path { stroke: var(--border-b1); }
.forge-chart__axis text { fill: var(--text-t3); font-size: var(--typography-scale-xs); font-family: var(--typography-fontSansFamily); }
.forge-chart__bar   { fill: var(--accent-base); transition: fill var(--motion-durationFast) var(--motion-easing); }
.forge-chart__bar:hover { fill: var(--accent-hover); }
.forge-chart__line  { fill: none; stroke: var(--accent-base); stroke-width: 2; }
.forge-chart__area  { fill: var(--accent-dim); }
.forge-chart__dot   { fill: var(--accent-base); }
.forge-chart__grid line { stroke: var(--border-b0); stroke-dasharray: 2 3; }

/* ForgeSparklineChart wrapper — inline-by-default `<span>` collapsed to its
   SVG content's intrinsic size (effectively zero), so the inner
   `style="width:100%;height:100%"` SVG had nothing to fill. Switch the
   wrapper to a block-level element so it owns the available width AND
   forwards whatever height the caller sets on the parent (KPI tile sets
   `height: 40px;` on `.kpi-spark`; the showcase hero uses `height: 64px;`
   on its container). The internal SVG then expands edge-to-edge. */
.forge-sparkline {
    display: block;
    width: 100%;
    height: 100%;
    min-height: 24px;  /* covers callers who forget to set a height on the parent */
    color: var(--accent-base);  /* SVG strokes inherit currentColor */
}
/* Effects-minimal mode (Appearance → Effects → "Minimal flat") strips
   decorative blurs / glows everywhere. The sparkline's ambient halo
   path is decorative, so we hide it — the crisp top stroke + area
   fill remain so the data is still legible without the glow. */
:root[data-effects="minimal"] .forge-sparkline__glow {
    display: none;
}

/* ------------------------------------ */
/* 12. Auth surfaces (Identity pages)   */
/* ------------------------------------ */
.forge-auth-shell {
    display: flex; align-items: center; justify-content: center;
    min-height: 100dvh;
    padding: var(--spacing-6);
    background: var(--surface-s0);
    font-family: var(--typography-fontSansFamily);
    color: var(--text-t1);
}
.forge-auth-container {
    width: 100%; max-width: 420px;
    background: var(--surface-s1);
    border: 1px solid var(--border-b1);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    padding: var(--spacing-8);
    display: flex; flex-direction: column; gap: var(--spacing-5);
}
.forge-auth-container h1 { margin: 0; font-size: var(--typography-scale-2xl); }
.forge-auth-container h2 { margin: 0; font-size: var(--typography-scale-xl); }
.forge-auth-container p  { color: var(--text-t3); margin: 0; font-size: var(--typography-scale-sm); }

.forge-auth-form { display: flex; flex-direction: column; gap: var(--spacing-4); }
.forge-auth-links { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--spacing-2); }
.forge-auth-links a {
    font-size: var(--typography-scale-sm);
    color: var(--accent-base); text-decoration: none;
}
.forge-auth-links a:hover { text-decoration: underline; }

/* Form-field alias used by Identity templates. Same layout as .forge-field, with
   descendant selectors so bare <InputText> inside it picks up input styling without
   requiring class="forge-input" on every form element. */
.forge-form-field { display: flex; flex-direction: column; gap: var(--spacing-1); margin-bottom: var(--spacing-3); }
.forge-form-field > label {
    font-size: var(--typography-scale-sm);
    color: var(--text-t2);
    font-weight: var(--typography-weights-medium);
}
.forge-form-field > input,
.forge-form-field > textarea,
.forge-form-field > select,
.forge-auth-container input:not([type="checkbox"]):not([type="radio"]),
.forge-auth-container textarea,
.forge-auth-container select {
    width: 100%;
    padding: 0 var(--spacing-3);
    height: var(--controls-heightBase);
    font-family: inherit; font-size: var(--typography-scale-base);
    color: var(--text-t1);
    background: var(--surface-s1);
    border: 1px solid var(--border-b2);
    border-radius: var(--radius-md);
    transition: border-color var(--motion-durationFast) var(--motion-easing),
                box-shadow var(--motion-durationFast) var(--motion-easing);
}
.forge-form-field > textarea,
.forge-auth-container textarea {
    height: auto; min-height: calc(var(--controls-heightBase) * 2);
    padding: var(--spacing-2) var(--spacing-3);
    resize: vertical; line-height: var(--typography-lineHeight);
}
.forge-form-field > input:focus,
.forge-form-field > textarea:focus,
.forge-form-field > select:focus,
.forge-auth-container input:not([type="checkbox"]):not([type="radio"]):focus,
.forge-auth-container textarea:focus,
.forge-auth-container select:focus {
    outline: none;
    border-color: var(--accent-base);
    box-shadow: 0 0 0 3px var(--accent-dim);
}
.forge-form-field .validation-message,
.forge-auth-container .validation-message {
    color: var(--semantic-danger);
    font-size: var(--typography-scale-xs);
}

/* Legacy Bootstrap-style button aliases so existing templates still render correctly. */
.btn { /* delegates to forge-button base */
    display: inline-flex; align-items: center; justify-content: center;
    gap: var(--spacing-2);
    height: var(--controls-heightBase); padding: 0 var(--spacing-4);
    border: 1px solid transparent; border-radius: var(--radius-md);
    font-family: inherit; font-size: var(--typography-scale-base);
    font-weight: var(--typography-weights-medium); cursor: pointer;
    transition: background var(--motion-durationFast) var(--motion-easing);
}
.btn-primary   { background: var(--accent-base); color: var(--accent-on); border-color: var(--accent-base); }
.btn-primary:hover:not(:disabled) { background: var(--accent-hover); }
.btn-secondary { background: var(--surface-s2); color: var(--text-t1); border-color: var(--border-b1); }
.btn-secondary:hover:not(:disabled) { background: var(--surface-s3); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* ------------------------------------ */
/* 12b. Dropdown / select + filter bar  */
/* ------------------------------------ */
.forge-select {
    appearance: none;
    padding-right: calc(var(--spacing-3) * 2 + 12px);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><path d='m6 9 6 6 6-6'/></svg>");
    background-repeat: no-repeat;
    background-position: right var(--spacing-3) center;
}

.forge-filter-bar {
    display: flex; flex-wrap: wrap; gap: var(--spacing-2);
    padding: var(--spacing-3) var(--spacing-4);
    background: var(--surface-s1);
    border: 1px solid var(--border-b1);
    border-radius: var(--radius-md);
    align-items: center;
}
.forge-filter-bar > .forge-search { flex: 1 1 260px; min-width: 200px; }
.forge-filter-bar > .forge-select,
.forge-filter-bar > .forge-input { flex: 0 0 auto; min-width: 160px; }

/* ------------------------------------ */
/* 12c. Rich list row (ForgeListItem)   */
/* ------------------------------------ */
.forge-list {
    display: flex; flex-direction: column;
    background: var(--surface-s1);
    border: 1px solid var(--border-b1);
    border-radius: var(--radius-md);
    overflow: hidden;
}
.forge-list-item {
    display: flex; align-items: center; gap: var(--spacing-3);
    padding: var(--spacing-3) var(--spacing-4);
    border: 0; background: transparent;
    border-bottom: 1px solid var(--border-b0);
    cursor: pointer;
    transition: background var(--motion-durationFast) var(--motion-easing);
    text-align: left;
}
.forge-list-item:last-child { border-bottom: none; }
.forge-list-item:hover  { background: var(--surface-s2); }
.forge-list-item.is-selected {
    background: var(--accent-dim);
    box-shadow: inset 3px 0 0 0 var(--accent-base);
}
.forge-list-item__leading {
    flex: 0 0 40px;
    width: 40px; height: 40px;
    border-radius: var(--radius-md);
    overflow: hidden;
    display: flex; align-items: center; justify-content: center;
    background: var(--surface-s2);
    color: var(--text-t3);
}
.forge-list-item__leading img { width: 100%; height: 100%; object-fit: cover; }
.forge-list-item__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.forge-list-item__title {
    font-size: var(--typography-scale-base);
    color: var(--text-t1);
    font-weight: var(--typography-weights-medium);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.forge-list-item__subtitle {
    font-size: var(--typography-scale-sm);
    color: var(--text-t3);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.forge-list-item__trailing {
    flex: 0 0 auto;
    display: flex; align-items: center; gap: var(--spacing-1);
    color: var(--text-t3);
}

/* ------------------------------------ */
/* 12d. Calendar (ForgeCalendar)        */
/* ------------------------------------ */
.forge-calendar {
    background: var(--surface-s1);
    border: 1px solid var(--border-b1);
    border-radius: var(--radius-lg);
    overflow: hidden;
}
.forge-calendar__header {
    display: flex; align-items: center; justify-content: space-between;
    padding: var(--spacing-3) var(--spacing-4);
    border-bottom: 1px solid var(--border-b1);
}
.forge-calendar__title { margin: 0; font-size: var(--typography-scale-lg); font-weight: var(--typography-weights-semibold); }
.forge-calendar__grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 1px;
    background: var(--border-b0);
}
.forge-calendar__weekday {
    padding: var(--spacing-2) var(--spacing-3);
    background: var(--surface-s2);
    color: var(--text-t3);
    font-size: var(--typography-scale-xs);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    text-align: center;
}
.forge-calendar__cell {
    position: relative;
    display: flex; flex-direction: column;
    gap: var(--spacing-1);
    min-height: 92px;
    padding: var(--spacing-2);
    background: var(--surface-s1);
    border: 0;
    color: var(--text-t1);
    font-family: inherit;
    font-size: var(--typography-scale-sm);
    text-align: left;
    cursor: pointer;
    transition: background var(--motion-durationFast) var(--motion-easing);
}
.forge-calendar__cell:hover       { background: var(--surface-s2); }
.forge-calendar__cell.is-today    { background: var(--surface-s2); }
.forge-calendar__cell.is-today .forge-calendar__day-number {
    background: var(--accent-base);
    color: var(--accent-on);
    border-radius: var(--radius-full);
    width: 22px; height: 22px;
    display: inline-flex; align-items: center; justify-content: center;
}
.forge-calendar__cell.is-selected {
    outline: 2px solid var(--accent-base); outline-offset: -2px;
}
.forge-calendar__cell--empty  { cursor: default; background: var(--surface-s0); }
.forge-calendar__cell--empty:hover { background: var(--surface-s0); }
.forge-calendar__day-number   {
    font-size: var(--typography-scale-sm);
    font-weight: var(--typography-weights-medium);
    color: var(--text-t2);
}
.forge-calendar__events { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.forge-calendar__event {
    display: block;
    padding: 2px var(--spacing-2);
    border-radius: var(--radius-sm);
    font-size: var(--typography-scale-xs);
    color: #ffffff;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.forge-calendar__event--info    { background: var(--semantic-info);    }
.forge-calendar__event--success { background: var(--semantic-success); }
.forge-calendar__event--warning { background: var(--semantic-warning); color: var(--surface-s0); }
.forge-calendar__event--danger  { background: var(--semantic-danger);  }
.forge-calendar__event--accent  { background: var(--accent-base); color: var(--accent-on); }
.forge-calendar__event-more     { color: var(--text-t3); font-size: var(--typography-scale-xs); }

/* ------------------------------------ */
/* 13. Utility (deliberately minimal)   */
/* ------------------------------------ */
.forge-visually-hidden {
    position: absolute !important;
    width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.forge-stack { display: flex; flex-direction: column; gap: var(--s-3, var(--spacing-3)); }
.forge-row   { display: flex; gap: var(--s-3, var(--spacing-3)); align-items: center; }
/* Auto-fit KPI grid for older pages. New pages should use the dashboard
 * `.grid` + `.module col-N` pattern (12-column layout) instead. */
.forge-grid-kpi {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--s-4, var(--spacing-4));
}

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
    .forge-button, .forge-nav-item, .forge-input, .forge-textarea, .forge-select,
    .forge-search__input, .forge-card--interactive, .forge-backdrop, .forge-dialog {
        transition: none !important; animation: none !important;
    }
}

/* ─────────────────────────────────────────────────────────────
   ForgeTweaksPanel — runtime UI customisation overlay
   Spec: docs/design/ui-theming-architecture-v2.md
   Translated from Anthropic Forge Dashboard handoff (tweaks-panel.jsx).
   ───────────────────────────────────────────────────────────── */
/*  World-class Tweaks panel — Apple/Adobe/Microsoft/Google-grade design.
    Frosted glass, accent-tinted highlights, generous breathing room, spring-
    feel hover states, accessible focus rings. Token-aware so theme + accent
    re-skin automatically. Mounted bottom-right on desktop, slide-up sheet
    on mobile (handled by the responsive block lower down). */
.forge-tweaks-panel {
    position: fixed;
    right: 24px;
    bottom: 24px;
    z-index: 2147483646;
    width: 360px;
    max-width: calc(100vw - 32px);
    max-height: calc(100vh - 48px);
    display: flex;
    flex-direction: column;
    color: var(--fg-1, #29261b);
    /* Solid (98% opaque) background — the panel itself must stay readable
       regardless of the user's effects tier setting. Earlier versions used
       88% + heavy blur which made the dialog see-through enough that text
       inside started blending with whatever was behind on the page (user
       reported: "ty vizualni efekty meni celkem dost pruhlednost toho
       dialogu to nevypada moc dobre"). The dialog stays glass-y on
       [data-effects="full"] via the override below; everything else
       collapses to opaque so the controls are crisp. */
    background: var(--surface-elevated, var(--bg-1));
    border: 1px solid var(--line, rgba(0, 0, 0, 0.1));
    border-radius: 18px;
    box-shadow:
        0 1px 1px color-mix(in oklab, black 10%, transparent),
        0 24px 56px -16px color-mix(in oklab, black 38%, transparent),
        0 12px 24px -12px color-mix(in oklab, black 24%, transparent),
        0 0 0 1px color-mix(in oklab, var(--accent) 8%, transparent);
    font-family: var(--font-sans, ui-sans-serif, system-ui, -apple-system, sans-serif);
    font-size: 13px;
    line-height: 1.45;
    overflow: hidden;
    animation: forge-tweaks-panel-in var(--motion-durationSlow) cubic-bezier(0.16, 1, 0.3, 1) both;
}

/* Glass treatment ONLY when the user opted into full visual effects.
   Auto / balanced / minimal keep the panel opaque per the rationale above. */
:root[data-effects="full"] .forge-tweaks-panel {
    background: color-mix(in oklab, var(--surface-elevated, var(--bg-1)) 92%, transparent);
    -webkit-backdrop-filter: blur(24px) saturate(160%);
    backdrop-filter: blur(24px) saturate(160%);
    border-color: color-mix(in oklab, var(--line, rgba(0, 0, 0, 0.1)) 80%, transparent);
}

@keyframes forge-tweaks-panel-in {
    from { opacity: 0; transform: translateY(16px) scale(0.96); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

.forge-tweaks-panel__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 14px 14px 20px;
    border-bottom: 1px solid color-mix(in oklab, var(--line) 50%, transparent);
    user-select: none;
}

.forge-tweaks-panel__header strong {
    font-size: 15px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--fg-1);
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.forge-tweaks-panel__header strong::before {
    content: "";
    width: 8px;
    height: 8px;
    border-radius: 999px;
    background: var(--accent);
    box-shadow: 0 0 0 4px color-mix(in oklab, var(--accent) 22%, transparent);
}

.forge-tweaks-panel__close {
    all: unset;
    width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 8px;
    cursor: pointer;
    color: var(--fg-3, rgba(41, 38, 27, 0.55));
    font-size: 18px;
    line-height: 1;
    transition:
        background-color 160ms cubic-bezier(0.4, 0, 0.2, 1),
        color 160ms cubic-bezier(0.4, 0, 0.2, 1),
        transform 160ms cubic-bezier(0.4, 0, 0.2, 1);
}

.forge-tweaks-panel__close:hover {
    background: color-mix(in oklab, var(--fg-1) 8%, transparent);
    color: var(--fg-1);
    transform: scale(1.05);
}

.forge-tweaks-panel__close:focus-visible {
    outline: 2px solid color-mix(in oklab, var(--accent) 60%, transparent);
    outline-offset: 2px;
}

.forge-tweaks-panel__body {
    padding: 8px 20px 20px;
    display: flex;
    flex-direction: column;
    gap: 14px;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: color-mix(in oklab, var(--fg-3) 30%, transparent) transparent;
}

.forge-tweaks-panel__body::-webkit-scrollbar {
    width: 6px;
}
.forge-tweaks-panel__body::-webkit-scrollbar-thumb {
    background: color-mix(in oklab, var(--fg-3) 30%, transparent);
    border-radius: 999px;
}

.forge-tweaks-panel__section {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--fg-3, rgba(41, 38, 27, 0.45));
    padding: 12px 0 4px;
    display: flex;
    align-items: center;
    gap: 8px;
}

.forge-tweaks-panel__section::after {
    content: "";
    flex: 1;
    height: 1px;
    background: linear-gradient(90deg,
        color-mix(in oklab, var(--line) 80%, transparent),
        transparent);
}

.forge-tweaks-panel__section:first-child {
    padding-top: 4px;
}

.forge-tweaks-panel__field {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.forge-tweaks-panel__label {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
    font-size: 13px;
    font-weight: 500;
    color: var(--fg-2, rgba(41, 38, 27, 0.78));
}

.forge-tweaks-panel__value {
    color: var(--accent-strong, var(--accent));
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    font-size: 12px;
    padding: 2px 8px;
    border-radius: 999px;
    background: color-mix(in oklab, var(--accent) 12%, transparent);
}

.forge-tweaks-panel__select {
    appearance: none;
    width: 100%;
    height: 36px;
    padding: 0 36px 0 12px;
    border: 1px solid color-mix(in oklab, var(--line, rgba(0, 0, 0, 0.1)) 90%, transparent);
    border-radius: 10px;
    background: var(--surface-s1, var(--bg-1));
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='14' height='14' fill='none' stroke='%23888' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 14px;
    color: inherit;
    font: inherit;
    font-size: 13px;
    outline: none;
    cursor: pointer;
    transition: border-color var(--motion-durationFast) var(--motion-easing),
                box-shadow var(--motion-durationFast) var(--motion-easing);
}

.forge-tweaks-panel__select:hover {
    border-color: color-mix(in oklab, var(--accent) 35%, var(--line));
}

.forge-tweaks-panel__select:focus-visible {
    border-color: color-mix(in oklab, var(--accent) 60%, var(--line));
    box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 18%, transparent);
}

.forge-tweaks-panel__slider {
    appearance: none;
    -webkit-appearance: none;
    width: 100%;
    height: 6px;
    margin: 10px 0;
    border-radius: 999px;
    background: linear-gradient(90deg,
        color-mix(in oklab, var(--accent) 60%, transparent),
        color-mix(in oklab, var(--accent) 12%, transparent));
    outline: none;
    cursor: pointer;
}

.forge-tweaks-panel__slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--surface-s1, #fff);
    border: 2px solid var(--accent);
    box-shadow:
        0 2px 8px color-mix(in oklab, var(--accent) 30%, transparent),
        0 0 0 0 color-mix(in oklab, var(--accent) 24%, transparent);
    cursor: grab;
    transition:
        transform 160ms cubic-bezier(0.4, 0, 0.2, 1),
        box-shadow 160ms cubic-bezier(0.4, 0, 0.2, 1);
}

.forge-tweaks-panel__slider::-webkit-slider-thumb:hover {
    transform: scale(1.12);
    box-shadow:
        0 4px 12px color-mix(in oklab, var(--accent) 40%, transparent),
        0 0 0 6px color-mix(in oklab, var(--accent) 18%, transparent);
}

.forge-tweaks-panel__slider:active::-webkit-slider-thumb {
    cursor: grabbing;
    transform: scale(1.04);
}

.forge-tweaks-panel__slider::-moz-range-thumb {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--surface-s1, #fff);
    border: 2px solid var(--accent);
    box-shadow:
        0 2px 8px color-mix(in oklab, var(--accent) 30%, transparent);
    cursor: grab;
}

.forge-tweaks-panel__preset {
    appearance: none;
    height: 36px;
    padding: 0 14px;
    border: 1px solid color-mix(in oklab, var(--line) 70%, transparent);
    border-radius: 10px;
    background: var(--surface-s1, var(--bg-1));
    color: var(--fg-1);
    font: inherit;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    text-align: left;
    display: flex;
    align-items: center;
    gap: 10px;
    /* Only animate hover effects (transform + box-shadow). DO NOT
       transition background-color / border-color — those flip instantly
       on theme switch (light↔dark) and accent change. A 200ms transition
       on them produces a visible ugly mid-tone "flash" during the swap
       because the token swap is synchronous but CSS transitions animate.
       Reported as a flicker bug on the accent preset chips in the Tweaks
       panel; the fix preserves the hover lift animation but removes the
       theme-switch artefact. Phase N.2 (2026-05-26). */
    transition:
        transform var(--motion-durationFast, 200ms) var(--motion-easing, cubic-bezier(0.4, 0, 0.2, 1)),
        box-shadow var(--motion-durationFast, 200ms) var(--motion-easing, cubic-bezier(0.4, 0, 0.2, 1));
}

.forge-tweaks-panel__preset::before {
    content: "";
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--accent), color-mix(in oklab, var(--accent) 70%, var(--fg-1)));
    box-shadow: inset 0 0 0 2px color-mix(in oklab, var(--surface-s1) 90%, transparent);
    flex-shrink: 0;
}

.forge-tweaks-panel__preset:hover {
    background: color-mix(in oklab, var(--accent) 8%, var(--surface-s1));
    border-color: color-mix(in oklab, var(--accent) 30%, var(--line));
    transform: translateY(-1px);
    box-shadow: 0 4px 12px -4px color-mix(in oklab, var(--accent) 24%, transparent);
}

.forge-tweaks-panel__preset:active {
    transform: translateY(0);
}

.forge-tweaks-panel__preset:focus-visible {
    outline: 2px solid color-mix(in oklab, var(--accent) 60%, transparent);
    outline-offset: 2px;
}

@media (max-width: 640px) {
    .forge-tweaks-panel {
        right: 12px;
        left: 12px;
        bottom: 12px;
        width: auto;
        max-width: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .forge-tweaks-panel,
    .forge-tweaks-panel__close,
    .forge-tweaks-panel__select,
    .forge-tweaks-panel__slider::-webkit-slider-thumb,
    .forge-tweaks-panel__preset {
        animation: none;
        transition: none;
    }
}

/* ────────────────────────────────────────────────────────────────────────
   Forge tooltip — JS-driven floating bubble.

   Trigger contract:
     data-tooltip="<text>"           required, the body of the tooltip
     data-tooltip-pos="<placement>"  optional, default "top"
       Placements: top, bottom, left, right,
                   top-start, top-end, bottom-start, bottom-end.

   The actual rendering, positioning, hover delay, viewport-clamping and
   auto-flip all live in `forge-tooltip.js` (loaded by the consumer's
   App.razor). The script renders ONE shared `<div class="forge-tooltip-bubble">`
   appended to `<body>` with `position: fixed`, so it escapes every
   ancestor's stacking context, overflow, transform, and isolation.

   We keep nothing pseudo-element-based. Earlier CSS-only `::after` work
   was unfixable in three structural ways:
     (a) `position: absolute` pseudo-elements inherit the parent's stacking
         context — they could never paint above a sibling with `z-index`.
     (b) Every ancestor with `overflow: hidden` (or `auto`, which the spec
         coerces to clip the orthogonal axis too) clips the bubble.
     (c) Pure CSS can't measure trigger-vs-viewport positions for clamping,
         so a tooltip near the right edge always overflowed.

   Native `title` attribute is intentionally NOT used — it produces the
   browser's default tooltip which clashes with our design system.
   ──────────────────────────────────────────────────────────────────── */
.forge-tooltip-bubble {
    /* `position: fixed` makes the bubble's containing block the viewport,
       not its DOM parent — escapes every overflow + stacking context. */
    position: fixed;
    z-index: 99999;
    pointer-events: none;
    padding: 6px 10px;
    background: var(--surface-s3, oklch(0.275 0.015 280));
    color: var(--text-t1, oklch(0.97 0.005 280));
    border: 1px solid var(--border-b1, oklch(1 0 0 / 0.08));
    border-radius: var(--radii-sm, 6px);
    font-family: var(--typography-fontSansFamily, 'Inter', sans-serif);
    font-size: 12px;
    font-weight: 500;
    line-height: 1.3;
    white-space: nowrap;
    box-shadow: 0 4px 14px rgb(0 0 0 / 0.4);
    /* Hidden until JS adds .is-visible. Off-screen left/top defaults so a
       FOUT-style flash doesn't appear before the script positions it. */
    opacity: 0;
    transform: translateY(2px);
    transition:
        opacity var(--motion-durationFast, 140ms) var(--motion-easing, ease-out),
        transform var(--motion-durationFast, 140ms) var(--motion-easing, ease-out);
}
.forge-tooltip-bubble.is-visible {
    opacity: 1;
    transform: translateY(0);
}

/* ────────────────────────────────────────────────────────────────────
   ForgeFileUpload — themed drag-and-drop drop zone.
   The wrapper is a <label>, so the entire visual area is the input's
   hit target. The actual <InputFile> is positioned off-screen but
   accessible via keyboard + screen reader. Drag-over state is mirrored
   from the C# `_isDragging` flag onto `.is-dragging`; selected state
   from `_selected != null` onto `.is-selected`.

   Theming: uses the semantic vocabulary (--bg-2 / --line / --accent /
   --accent-soft) so the same component renders correctly on light,
   dark, and every accent palette without a per-theme override.
   ──────────────────────────────────────────────────────────────────── */
.forge-file-upload {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--s-3, 12px);
    width: 100%;
    padding: var(--s-5, 20px) var(--s-4, 16px);
    background: var(--bg-2);
    border: 1.5px dashed var(--line-strong, var(--line));
    border-radius: var(--r-md, 10px);
    color: var(--fg-2);
    cursor: pointer;
    text-align: left;
    transition:
        border-color var(--t-fast, 140ms) var(--ease-out, ease-out),
        background var(--t-fast, 140ms) var(--ease-out, ease-out),
        color var(--t-fast, 140ms) var(--ease-out, ease-out),
        transform var(--t-fast, 140ms) var(--ease-out, ease-out);
}

.forge-file-upload:hover {
    border-color: var(--accent);
    color: var(--fg-1);
    background: var(--bg-3);
}

.forge-file-upload.is-dragging {
    border-style: solid;
    border-color: var(--accent);
    background: var(--accent-soft, var(--bg-3));
    color: var(--fg-1);
    transform: translateY(-1px);
    box-shadow: 0 0 0 4px var(--accent-soft, oklch(var(--accent-l) var(--accent-c) var(--accent-h) / 0.18));
}

.forge-file-upload.is-selected {
    border-style: solid;
    border-color: var(--ok, var(--line-accent, var(--accent)));
    background: var(--bg-2);
}

/* Visually-hide the input but keep it focusable for keyboard + AT users.
   Don't use display:none — that drops the element from the AT tree. */
.forge-file-upload__input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
    z-index: 1;
}

/* Bring the focus ring onto the wrapper when the hidden input is focused. */
.forge-file-upload:has(.forge-file-upload__input:focus-visible) {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.forge-file-upload__icon {
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    display: grid;
    place-items: center;
    border-radius: 999px;
    background: var(--accent-soft, var(--bg-3));
    color: var(--accent);
    transition: background var(--t-fast, 140ms) var(--ease-out, ease-out);
}

.forge-file-upload__icon svg {
    width: 22px;
    height: 22px;
}

.forge-file-upload.is-dragging .forge-file-upload__icon,
.forge-file-upload.is-selected .forge-file-upload__icon {
    background: var(--accent);
    color: white;
}

.forge-file-upload__body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex: 1;
}

.forge-file-upload__title {
    font-size: 14px;
    font-weight: 500;
    color: inherit;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.forge-file-upload__hint {
    font-size: 12px;
    color: var(--fg-3);
    font-family: var(--font-mono);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
    .forge-file-upload { transition: none; }
    .forge-file-upload.is-dragging { transform: none; }
}

/* ────────────────────────────────────────────────────────────────────
   Forge Motion — list-item lifecycle choreography.

   Three lifecycle classes, all theme-aware (every accent / glow / sweep
   reads `--accent`, so colour flips with the user's chosen preset and
   custom hue). Each is CSS-only — no JS layout engine, zero runtime
   cost, identical behaviour across Blazor WASM / Server / MAUI.

   ┌─────────────────────────────┬──────────────────────────────────────┐
   │ .forge-list-item--inserted  │ Newly-added row / card               │
   │ .forge-list-item--updated   │ Row / card whose data just changed   │
   │ .forge-list-item--deleting  │ Row / card mid-removal (fade + slide)│
   └─────────────────────────────┴──────────────────────────────────────┘

   ── INSERT layers ────────────────────────────────────────────────────
     1. rise            translateY(8px) → 0 + opacity 0 → 1.
                        NO max-height animation: that produced a brief
                        page scrollbar during the height grow + caused a
                        visible flicker as content overflow pushed the
                        viewport edge. Layout-shift now happens instantly
                        when the new row hits the DOM (browsers are very
                        good at this); the rise + sweep + accent bar still
                        read as "this row is new, look here."
     2. content-rise    children fade in from translateY(6px) + blur(2px),
                        delayed 120 ms (focus pull on the contents).
     3. accent-pulse    vertical accent bar on leading edge (::before)
                        scales 0 → 1 → fade. Plain rows only — cards
                        keep their ambient ::before glow.
     4. highlight-sweep 90° accent gradient slides across once, mix-
                        blend-mode: plus-lighter, delayed 200 ms.
     5. ring-fade       inset accent ring + drop-glow box-shadow decay
                        over 1.4 s. NO background-color animation: the
                        previous fill faded toward `transparent` and
                        snapped back to the surface colour when the
                        marker class dropped, producing a visible flash.
                        The ring alone is plenty visual without painting
                        the card body.

   ── UPDATE layer (single, fast, calm) ────────────────────────────────
     Soft accent ring pulses once over ~900 ms. No transform, no sweep —
     the user already initiated the change, so the animation just
     confirms "this is the row you touched" without yanking the eye.

   ── DELETE layer ─────────────────────────────────────────────────────
     Slide left + fade + scale down to 0.96, then collapse height to 0
     and zero out vertical padding/margin so the row's gap is reclaimed
     smoothly. Pointer events disabled so a doubled click can't fire
     during the exit animation. Consumer page calls the actual data
     removal AFTER the animation finishes (~380 ms).

   prefers-reduced-motion users get no animation at all. Marker classes
   are removed by the consumer page after the longest layer so the DOM
   stays clean.
   ──────────────────────────────────────────────────────────────────── */

/* Pure opacity entrance. Earlier versions added `translateY(8px → 0)`
   on the row + `translateY(6px) blur(2px) → 0 blur(0)` on children;
   both produced subpixel rendering shifts that the user perceived as
   "the row jumps a pixel at the end" + table cells appeared briefly
   misaligned during the keyframe. Holding to opacity-only keeps the
   row's geometry rock-solid for the duration of the animation while
   the accent bar / sweep / ring layers carry the visual interest. */
@keyframes forge-insert-rise {
    0%   { opacity: 0; }
    100% { opacity: 1; }
}

@keyframes forge-insert-content-rise {
    0%   { opacity: 0; }
    100% { opacity: 1; }
}

@keyframes forge-insert-highlight-sweep {
    /* Animate `background-position` (NOT `transform: translateX`) so the
       gradient sweeps INSIDE the pseudo-element's bounds. The previous
       transform variant pushed the element 120 % to the right, which on
       a wide table row extended past the row's right edge and triggered
       a horizontal scrollbar on the table body for the duration of the
       animation. background-position keeps the element static — the
       gradient itself is the only thing that moves. */
    0%   { opacity: 0; background-position: -25% 0; }
    20%  { opacity: 1; }
    100% { opacity: 0; background-position: 125% 0; }
}

@keyframes forge-insert-ring-fade {
    0% {
        box-shadow:
            inset 0 0 0 1px var(--accent, currentColor),
            0 0 24px -4px color-mix(in oklab, var(--accent, currentColor) 45%, transparent);
    }
    100% {
        box-shadow:
            inset 0 0 0 1px transparent,
            0 0 0 0 transparent;
    }
}

.forge-list-item--inserted {
    position: relative;
    /* `contain: layout` keeps the row's box-shadow + accent ring + sweep
       from contributing to ancestor layout calculations (the table
       briefly widened a few pixels during the animation as the inset
       ring's outer glow + ::before accent bar painted near the edges).
       Layout containment is the surgical fix — paint stays inside, but
       the row's natural overflow + sub-pixel positioning of children
       are unaffected. */
    contain: layout paint;
    animation:
        forge-insert-rise 420ms cubic-bezier(0.22, 1, 0.36, 1) both,
        forge-insert-ring-fade 1100ms cubic-bezier(0.4, 0, 0.2, 1) both;
    will-change: transform, opacity, box-shadow;
}

.forge-list-item--inserted > * {
    animation: forge-insert-content-rise 420ms cubic-bezier(0.22, 1, 0.36, 1) 80ms both;
}

/* Accent bar layer was previously a `::before` pseudo-element with
   `position: absolute`. Worked on cards, but on `<tr>` / `<table>`-row
   rendering (some grid layouts in the wild produce table-row layout
   semantics) the pseudo-element took a slot in the row's column flow
   and shifted the data cells until the animation cleared. The user
   reproduced this on /todo when the new row briefly mis-aligned its
   columns. The simplest fix is to drop the bar entirely — the row's
   `box-shadow` accent ring (inside `forge-insert-ring-fade`) already
   carries the "this row is new" signal on the leading edge as part
   of its inset 1 px ring. The freed pseudo-element can be reused by
   future card / row variants without conflict. */

/* Highlight sweep — a 90° accent gradient that slides across once. Uses
   ::after on PLAIN list items. Card override below provides its own
   ::after that respects the card's border-radius.

   Implementation note: the gradient's playback is driven by
   `background-position` (see @keyframes forge-insert-highlight-sweep
   above). Sizing the background-image to 250 % of its container and
   sliding it from -25 % to 125 % gives the same visual sweep without
   ever extending the element itself past the row — no horizontal
   scrollbar trigger on wide tables. */
.forge-list-item--inserted::after {
    content: "";
    position: absolute;
    inset: 0;
    /* Higher accent saturation on the gradient stops so the sweep is
       legible on every theme + accent. Was 22 % / 18 % at peaks; now
       40 % / 36 % gives the highlight enough visual weight to read
       past the row's own background without dominating it. */
    background-image: linear-gradient(
        90deg,
        transparent 0%,
        color-mix(in oklab, var(--accent, currentColor) 40%, transparent) 45%,
        color-mix(in oklab, var(--accent, currentColor) 36%, transparent) 55%,
        transparent 100%
    );
    background-size: 250% 100%;
    background-repeat: no-repeat;
    /* Default blend mode targets the dark theme — additive lighten
       brightens the row beneath the gradient, reading as an accent
       sweep on a dark surface. The light-theme override below swaps
       to `multiply` so the gradient DARKENS instead, which is how
       you make a highlight read against a near-white surface (additive
       blends with white produce white = invisible). */
    mix-blend-mode: plus-lighter;
    pointer-events: none;
    animation: forge-insert-highlight-sweep 900ms cubic-bezier(0.4, 0, 0.2, 1) both;
    z-index: 1;
}

[data-theme="light"] .forge-list-item--inserted::after {
    mix-blend-mode: multiply;
}

/* ── Card-specific override — sweep follows rounded corners ─────────── */
.forge-card.forge-list-item--inserted::after {
    border-radius: inherit;
}

/* ── Table-row CRUD lifecycle — outline ring + accent sweep, NOT per-cell
       background fill. Modern browsers (Chrome 76+ / Firefox 87+ / Safari 14+)
       allow `position: relative` on a <tr>, so the ::after pseudo-element +
       row-level box-shadow paint correctly across the whole row. We drop
       the legacy "fill every td" approach the user flagged as ugly: it
       coloured the entire row background which read as "the row itself
       turned green" instead of "this row was just added". The card variant
       (above) and the table variant share the same vocabulary now —
       outline ring + 90° accent sweep + optional content rise. ── */
tr.forge-list-item--inserted,
tr.forge-list-item--updated,
tr.forge-list-item--deleting {
    position: relative;
    contain: none;          /* layout containment is meaningless on a tr; paint is fine */
}
tr.forge-list-item--inserted > td,
tr.forge-list-item--updated > td,
tr.forge-list-item--deleting > td {
    /* No per-cell background flash — that produced the "row goes green"
       effect the user disliked. The ring + sweep above paint over every
       cell synchronously. */
    background-color: transparent;
    /* Suppress the generic .forge-list-item--inserted > * content-rise
       animation on table cells. Sticky cells (td.is-sticky) establish their
       own stacking context via z-index, so the same content-rise keyframe
       runs in a SEPARATE animation track for them — visible as a divided
       first-column animation the user flagged. With the animation
       suppressed on every td, the row-level ring + sweep paint together
       across the entire row and the sticky column doesn't lag behind. */
    animation: none !important;
}

/* Deleting row — same fade as cards (opacity + slight slide left). */
tr.forge-list-item--deleting {
    animation: forge-delete-row-fade 380ms cubic-bezier(0.4, 0, 0.6, 1) forwards;
}
@keyframes forge-delete-row-fade {
    0%   { opacity: 1; transform: translateX(0); }
    100% { opacity: 0; transform: translateX(-12px); }
}

/* Ghost rows / cards — DOM-only artifacts injected by forge-onboarding.js
   during a demo tour to simulate a CRUD lifecycle without touching the
   database. They carry the same shape + classes as real cards / table
   rows so they integrate visually; a faint accent left-strip + tint
   marks them as "demo-only" without screaming "fake!". */
[data-forge-ghost] {
    box-shadow: inset 4px 0 0 var(--accent, currentColor);
}

/* Force the ghost article card to the FIRST grid position visually even
   though it's appended at the END of the DOM. Inserting at the end keeps
   Blazor's positional diff happy (foreign nodes after the last expected
   child don't get scrubbed); `order: -1` makes the grid render it first
   so the user sees "Add → row appears at the top" — same way a real
   manual add would feel. */
article.forge-row-ghost.forge-card {
    order: -1;
    background: color-mix(in oklab, var(--accent, currentColor) 4%, var(--surface-elevated));
    border-color: color-mix(in oklab, var(--accent, currentColor) 35%, var(--line));
}

tr.forge-row-ghost > td {
    /* Subtle accent tint on each cell so the row reads as "demo content"
       even after the inserted-flash keyframe finishes. */
    background-color: color-mix(in oklab, var(--accent, currentColor) 6%, transparent);
}

/* ── UPDATE — single accent ring pulse, no transform ──────────────────── */

@keyframes forge-update-pulse {
    0% {
        box-shadow:
            inset 0 0 0 0 transparent,
            0 0 0 0 transparent;
    }
    35% {
        box-shadow:
            inset 0 0 0 2px var(--accent, currentColor),
            0 0 16px -2px color-mix(in oklab, var(--accent, currentColor) 40%, transparent);
    }
    100% {
        box-shadow:
            inset 0 0 0 0 transparent,
            0 0 0 0 transparent;
    }
}

.forge-list-item--updated {
    position: relative;
    animation: forge-update-pulse 900ms cubic-bezier(0.4, 0, 0.2, 1) both;
    will-change: box-shadow;
}

/* ── DELETE — slide left + fade + scale + height collapse ─────────────── */

/* Delete animation in two parallel keyframe streams so the visual exit
   (fade + slight slide) and the layout collapse (height shrink) play
   smoothly across the SAME duration without the "shrink → snap to
   zero → disappear" jolt the user reported. The earlier single-track
   version had max-height collapsing on a stiff cubic-bezier that
   front-loaded the size reduction, then the very last frame collapsed
   padding/margin/border in one step — that final frame read as a jump.

   Now both streams use cubic-bezier(0.4, 0, 0.2, 1) ("standard ease"
   — Material default, perceptually linear collapse) and run in lock-
   step over 360 ms. Padding / margin / border zero from 0% (start)
   so the layout collapse is gradual, not abrupt at the end. */

@keyframes forge-delete-fade {
    0%   { opacity: 1; transform: translateX(0)    scale(1); }
    100% { opacity: 0; transform: translateX(-24px) scale(0.97); }
}

@keyframes forge-delete-shrink {
    0% {
        max-height: 240px;
        padding-top: var(--forge-row-pad-y, 10px);
        padding-bottom: var(--forge-row-pad-y, 10px);
        margin-top: 0;
        margin-bottom: 0;
        border-top-width: 1px;
        border-bottom-width: 1px;
    }
    100% {
        max-height: 0;
        padding-top: 0;
        padding-bottom: 0;
        margin-top: 0;
        margin-bottom: 0;
        border-top-width: 0;
        border-bottom-width: 0;
    }
}

.forge-list-item--deleting {
    animation:
        forge-delete-fade   360ms cubic-bezier(0.4, 0, 0.2, 1) both,
        forge-delete-shrink 360ms cubic-bezier(0.4, 0, 0.2, 1) both;
    overflow: hidden;
    pointer-events: none;
    will-change: transform, opacity, max-height, padding, border-width;
}

@media (prefers-reduced-motion: reduce) {
    .forge-list-item--inserted,
    .forge-list-item--inserted > *,
    .forge-list-item--inserted::before,
    .forge-list-item--inserted::after,
    .forge-list-item--updated,
    .forge-list-item--deleting {
        animation: none !important;
    }
}

/* ============================================================== */
/* ForgeAccordion + ForgeAccordionItem (Phase I.E batch 1, ADR 059) */
/* ============================================================== */
.forge-accordion {
    display: flex;
    flex-direction: column;
    gap: var(--gap-2, 0.25rem);
}

.forge-accordion__item {
    /* Theme-aware tokens (match ForgeCard). The earlier `--surface-1` /
       `--radius-md` names with white/light hardcoded fallbacks are NOT
       defined in the token layer, so in dark mode they resolved to the
       literal `hsl(0 0% 100%)` → white boxes. The canonical Forge tokens
       (`--surface-s1`, `--border-b1`) carry per-theme values. */
    border: 1px solid var(--line, var(--border-b1));
    border-radius: var(--r-md, 0.5rem);
    background: var(--surface-elevated, var(--surface-s1));
    overflow: hidden;
}

.forge-accordion__header {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--gap-3, 0.5rem);
    padding: var(--gap-4, 0.75rem) var(--gap-5, 1rem);
    background: transparent;
    border: 0;
    color: inherit;
    text-align: start;
    font: inherit;
    cursor: pointer;
    transition: background-color var(--motion-durationFast) var(--motion-easing);
}

.forge-accordion__header:hover {
    background: var(--surface-s2);
}

.forge-accordion__header:focus-visible {
    outline: 2px solid var(--accent-base, hsl(220 90% 56%));
    outline-offset: -2px;
}

.forge-accordion__chevron {
    transition: transform var(--motion-durationBase) cubic-bezier(0.16, 1, 0.3, 1);
    display: inline-block;
    font-size: 1.2em;
    line-height: 1;
}

.forge-accordion__item.is-open .forge-accordion__chevron {
    transform: rotate(90deg);
}

.forge-accordion__panel {
    padding: var(--gap-4, 0.75rem) var(--gap-5, 1rem);
    border-top: 1px solid var(--border-b0, var(--border-b1));
}

@media (prefers-reduced-motion: reduce) {
    .forge-accordion__header,
    .forge-accordion__chevron {
        transition: none;
    }
}

/* ============================================================== */
/* ForgeVirtualList (Phase I.E batch 1, ADR 059)                   */
/* ============================================================== */
.forge-virtual-list {
    height: 100%;
    overflow-y: auto;
    contain: strict;
}

.forge-virtual-list__item {
    border-bottom: 1px solid var(--line-soft, hsl(0 0% 94%));
}

.forge-virtual-list__placeholder {
    padding: var(--gap-3, 0.5rem) var(--gap-5, 1rem);
    color: var(--text-t3, hsl(0 0% 50%));
    font-style: italic;
}

@container (max-width: 640px) {
    .forge-virtual-list__item {
        padding: var(--gap-3, 0.5rem) var(--gap-4, 0.75rem);
    }
}


/* ============================================================== */
/* Phase I.E batch 2 (ADR 059 Pillar 3) — Badge / Tag / Progress / */
/* Skeleton / Stat / Toast / Divider                              */
/* ============================================================== */

.forge-badge,
.forge-tag {
    display: inline-flex;
    align-items: center;
    gap: var(--gap-2, 0.25rem);
    border-radius: 9999px;
    font-weight: 600;
    line-height: 1;
    vertical-align: middle;
    transition: background-color var(--motion-durationFast, 150ms) var(--motion-easing, ease),
                color var(--motion-durationFast, 150ms) var(--motion-easing, ease);
    /* Subtle bordered look so badges read on every theme — not pure
       background-tint which can wash out on light theme + pastel accent. */
    border: 1px solid transparent;
}

.forge-badge--small,
.forge-tag--small { padding: 0.125rem 0.5rem; font-size: var(--typography-scale-xs, 0.75rem); }
.forge-badge--medium,
.forge-tag--medium { padding: 0.25rem 0.75rem; font-size: var(--typography-scale-sm, 0.875rem); }

/* Token-driven badge variants — every variant re-skins per theme +
   accent palette via color-mix on semantic tokens. No hardcoded HSL.
   Pattern: 14% mix into surface for background (soft tint), full token
   for text + border. Auto-readable on dark + light + every accent. */
.forge-badge--neutral, .forge-tag--neutral {
    background: var(--surface-s2, var(--surface-2));
    color: var(--text-t1, var(--fg-1));
    border-color: var(--line-strong, var(--fg-3));
}
.forge-badge--info, .forge-tag--info {
    background: color-mix(in oklab, var(--info, #3b82f6) 14%, var(--surface-elevated, transparent));
    color: var(--info, #3b82f6);
    border-color: color-mix(in oklab, var(--info, #3b82f6) 30%, transparent);
}
.forge-badge--success, .forge-tag--success {
    background: color-mix(in oklab, var(--ok, #10b981) 14%, var(--surface-elevated, transparent));
    color: var(--ok, #10b981);
    border-color: color-mix(in oklab, var(--ok, #10b981) 30%, transparent);
}
.forge-badge--warning, .forge-tag--warning {
    background: color-mix(in oklab, var(--warn, #f59e0b) 14%, var(--surface-elevated, transparent));
    color: var(--warn, #f59e0b);
    border-color: color-mix(in oklab, var(--warn, #f59e0b) 30%, transparent);
}
.forge-badge--danger, .forge-tag--danger {
    background: color-mix(in oklab, var(--bad, #ef4444) 14%, var(--surface-elevated, transparent));
    color: var(--bad, #ef4444);
    border-color: color-mix(in oklab, var(--bad, #ef4444) 30%, transparent);
}

.forge-tag__remove {
    background: transparent;
    border: 0;
    cursor: pointer;
    color: inherit;
    font: inherit;
    line-height: 1;
    padding: 0 0 0 0.25rem;
    opacity: 0.7;
    transition: opacity var(--motion-durationFast, 120ms) var(--motion-easing, ease);
    border-radius: 4px;
}
.forge-tag__remove:hover { opacity: 1; }
.forge-tag__remove:focus-visible {
    outline: 2px solid currentColor;
    outline-offset: 1px;
    opacity: 1;
}

:root[data-motion="reduced"] .forge-badge,
:root[data-motion="reduced"] .forge-tag,
:root[data-motion="reduced"] .forge-tag__remove {
    transition: none;
}

.forge-progress {
    display: flex;
    flex-direction: column;
    gap: var(--gap-2, 0.25rem);
}

.forge-progress__label {
    display: flex;
    justify-content: space-between;
    font-size: 0.875rem;
    color: var(--text-t2, hsl(0 0% 40%));
}

.forge-progress__bar {
    width: 100%;
    height: 0.5rem;
    border: 0;
    border-radius: 9999px;
    background: var(--surface-2, hsl(0 0% 92%));
    overflow: hidden;
}
.forge-progress__bar::-webkit-progress-bar { background: var(--surface-2, hsl(0 0% 92%)); border-radius: 9999px; }
.forge-progress__bar::-webkit-progress-value { background: var(--accent, hsl(220 90% 56%)); border-radius: 9999px; transition: width 200ms ease; }
.forge-progress__bar::-moz-progress-bar { background: var(--accent, hsl(220 90% 56%)); border-radius: 9999px; }

.forge-progress--success .forge-progress__bar::-webkit-progress-value { background: hsl(140 60% 45%); }
.forge-progress--warning .forge-progress__bar::-webkit-progress-value { background: hsl(40 90% 50%); }
.forge-progress--danger  .forge-progress__bar::-webkit-progress-value { background: hsl(0 80% 55%); }

.forge-progress--indeterminate .forge-progress__bar {
    background-image: linear-gradient(90deg, transparent 0%, var(--accent, hsl(220 90% 56%)) 50%, transparent 100%);
    background-size: 50% 100%;
    background-repeat: no-repeat;
    animation: forge-progress-indeterminate 1.4s ease-in-out infinite;
}

@keyframes forge-progress-indeterminate {
    0%   { background-position: -50% 0%; }
    100% { background-position: 150% 0%; }
}

@media (prefers-reduced-motion: reduce) {
    .forge-progress--indeterminate .forge-progress__bar { animation: none; }
}

/* ForgeSkeleton — themed shimmer placeholder.
   - Base surface picks up dark + light theme via tokens.
   - Highlight band derived from accent at low alpha so the skeleton
     subtly hints at the brand identity (NEXT-GEN UI restylability per
     Component Authoring Rules §0.2 — change accent, skeleton reskins). */
.forge-skeleton {
    display: inline-block;
    position: relative;
    overflow: hidden;
    background: var(--surface-s2, var(--surface-2));
    border-radius: var(--radius-2, 0.5rem);
    /* Subtle scale-pulse so the placeholder reads as "loading" even
       before the shimmer band passes — better feedback on slow devices. */
    animation: forge-skeleton-pulse 1.8s ease-in-out infinite;
}

.forge-skeleton::after {
    content: "";
    position: absolute;
    inset: 0;
    /* Shimmer band — accent-tinted at 12% so it re-skins per palette
       AND visibly differs from surface on dark theme (where surface-s3
       and surface-s2 are very close in luminance). */
    background: linear-gradient(90deg,
        transparent 0%,
        color-mix(in oklab, var(--accent-base, var(--accent, #6366f1)) 12%, transparent) 50%,
        transparent 100%);
    background-size: 200% 100%;
    animation: forge-skeleton-shimmer 1.6s ease-in-out infinite;
    pointer-events: none;
}

.forge-skeleton--text   { width: 100%; height: 1em; border-radius: var(--radius-1, 0.25rem); }
.forge-skeleton--rect   { width: 80px; height: 80px; }
.forge-skeleton--circle { width: 40px; height: 40px; border-radius: 50%; }

@keyframes forge-skeleton-shimmer {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

@keyframes forge-skeleton-pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.86; }
}

@media (prefers-reduced-motion: reduce) {
    .forge-skeleton,
    .forge-skeleton::after { animation: none; }
    .forge-skeleton::after { background: none; }
}
:root[data-motion="reduced"] .forge-skeleton,
:root[data-motion="reduced"] .forge-skeleton::after {
    animation: none;
}
:root[data-motion="reduced"] .forge-skeleton::after {
    background: none;
}

/* ForgeStat selectors live in the dedicated component block below (line ~5920).
   Earlier draft had a competing `.forge-stat` rule here with card-like padding
   that fought with the bare-markup intent (see Pillar 3 commit 59b16b4). Removed. */

.forge-divider {
    background: var(--line, var(--line-strong, hsl(0 0% 88%)));
    border: 0;
}

.forge-divider--horizontal { width: 100%; height: 1px; margin: var(--gap-5, 1rem) 0; }
.forge-divider--vertical   { width: 1px; height: auto; align-self: stretch; margin: 0 var(--gap-3, 0.5rem); }

.forge-divider--labeled.forge-divider--horizontal {
    display: flex;
    align-items: center;
    background: transparent;
    height: auto;
    color: var(--text-t3, hsl(0 0% 50%));
    font-size: 0.875rem;
}
.forge-divider--labeled.forge-divider--horizontal::before,
.forge-divider--labeled.forge-divider--horizontal::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--line, hsl(0 0% 88%));
}
.forge-divider__label { padding: 0 var(--gap-4, 0.75rem); }

.forge-toast-container {
    position: fixed;
    z-index: 1000;
    display: flex;
    flex-direction: column;
    gap: var(--gap-3, 0.5rem);
    pointer-events: none;
    max-width: 24rem;
}

.forge-toast-container--topleft     { top:    var(--gap-5, 1rem); left:   var(--gap-5, 1rem); }
.forge-toast-container--topcenter   { top:    var(--gap-5, 1rem); left:   50%; transform: translateX(-50%); }
.forge-toast-container--topright    { top:    var(--gap-5, 1rem); right:  var(--gap-5, 1rem); }
.forge-toast-container--bottomleft  { bottom: var(--gap-5, 1rem); left:   var(--gap-5, 1rem); }
.forge-toast-container--bottomcenter{ bottom: var(--gap-5, 1rem); left:   50%; transform: translateX(-50%); }
.forge-toast-container--bottomright { bottom: var(--gap-5, 1rem); right:  var(--gap-5, 1rem); }

.forge-toast {
    display: flex;
    align-items: flex-start;
    gap: var(--gap-3, 0.5rem);
    padding: var(--gap-3, 0.5rem) var(--gap-4, 0.75rem);
    /* Token-aware surface (previously hard-fallback white made toasts white-
       on-dark in dark mode). Falls through to --bg-1 if a theme doesn't
       define --surface-elevated separately. */
    background: var(--surface-elevated, var(--bg-1, hsl(0 0% 100%)));
    color: var(--fg-1, hsl(0 0% 20%));
    border: 1px solid var(--line, hsl(0 0% 88%));
    border-left-width: 3px;
    border-radius: var(--radius-md, 0.5rem);
    box-shadow: 0 4px 12px color-mix(in oklab, var(--shadow-color, black) 14%, transparent);
    pointer-events: auto;
    animation: forge-toast-in 200ms cubic-bezier(0.16, 1, 0.3, 1);
}

.forge-toast--info    { border-left-color: hsl(220 90% 56%); }
.forge-toast--success { border-left-color: hsl(140 60% 45%); }
.forge-toast--warning { border-left-color: hsl(40 90% 50%); }
.forge-toast--danger  { border-left-color: hsl(0 80% 55%); }

.forge-toast__icon { flex-shrink: 0; padding-top: 0.125rem; }
.forge-toast__body { flex: 1; min-width: 0; }
.forge-toast__title { font-weight: 600; margin-bottom: 0.125rem; }
.forge-toast__message { font-size: 0.875rem; color: var(--text-t2, hsl(0 0% 40%)); }
.forge-toast__dismiss {
    background: transparent; border: 0; cursor: pointer;
    color: var(--text-t3, hsl(0 0% 50%));
    font: inherit; font-size: 1.25rem; line-height: 1;
    padding: 0 0.25rem;
}
.forge-toast__dismiss:hover { color: var(--text-t1, hsl(0 0% 20%)); }

@keyframes forge-toast-in {
    from { transform: translateY(0.5rem); opacity: 0; }
    to   { transform: translateY(0); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .forge-toast { animation: none; }
}


/* ============================================================== */
/* Phase I.E batch 3 (ADR 059 Pillar 3) — Drawer / Popover / Menu */
/* DatePicker / Confirm / FormSection / ValidationSummary /       */
/* ShortcutsHelp                                                   */
/* ============================================================== */

.forge-drawer__backdrop,
.forge-confirm__backdrop,
.forge-shortcuts-help__backdrop,
.forge-popover__backdrop {
    position: fixed;
    inset: 0;
    background: hsl(0 0% 0% / 0.4);
    z-index: 900;
    animation: forge-overlay-fade 150ms ease;
}
.forge-popover__backdrop { background: transparent; z-index: 990; }

@keyframes forge-overlay-fade { from { opacity: 0; } to { opacity: 1; } }

.forge-drawer {
    position: fixed;
    /* Token-aware surface — `--surface-elevated` is the canonical floating-
       surface token in the Forge vocabulary, falling back to `--bg-1` when
       a theme doesn't define elevated separately. Previously this used the
       undefined `--surface-1` which fell back to hard-coded white, leaving
       the drawer white-on-dark in dark mode (visible regression). */
    background: var(--surface-elevated, var(--bg-1, hsl(0 0% 100%)));
    color: var(--fg-1, hsl(0 0% 20%));
    box-shadow: 0 8px 32px color-mix(in oklab, var(--shadow-color, black) 28%, transparent);
    z-index: 950;
    display: none;
    flex-direction: column;
    transition: transform var(--motion-durationBase) cubic-bezier(0.16, 1, 0.3, 1);
}
.forge-drawer.is-open { display: flex; }

.forge-drawer--right  { top: 0; right: 0; bottom: 0; width: min(28rem, 90vw); transform: translateX(100%); }
.forge-drawer--left   { top: 0; left:  0; bottom: 0; width: min(28rem, 90vw); transform: translateX(-100%); }
.forge-drawer--top    { top: 0; left:  0; right: 0; max-height: 60vh; transform: translateY(-100%); }
.forge-drawer--bottom { left: 0; right: 0; bottom: 0; max-height: 60vh; transform: translateY(100%); }
.forge-drawer.is-open { transform: translate(0); }

.forge-drawer__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--gap-4, 0.75rem) var(--gap-5, 1rem);
    border-bottom: 1px solid var(--line, hsl(0 0% 88%));
}
.forge-drawer__title { margin: 0; font-size: 1.125rem; font-weight: 600; }
.forge-drawer__close,
.forge-shortcuts-help__close {
    background: transparent; border: 0; cursor: pointer;
    color: var(--text-t2, hsl(0 0% 40%));
    font: inherit; font-size: 1.25rem; line-height: 1;
    padding: 0.25rem 0.5rem;
}
.forge-drawer__close:hover,
.forge-shortcuts-help__close:hover { color: var(--text-t1, hsl(0 0% 20%)); }

.forge-drawer__body { flex: 1; overflow-y: auto; padding: var(--gap-5, 1rem); }
.forge-drawer__footer {
    padding: var(--gap-4, 0.75rem) var(--gap-5, 1rem);
    border-top: 1px solid var(--line, hsl(0 0% 88%));
    display: flex; justify-content: flex-end; gap: var(--gap-3, 0.5rem);
}

@media (prefers-reduced-motion: reduce) {
    .forge-drawer { transition: none; }
}

.forge-popover {
    position: relative;
    display: inline-block;
}
.forge-popover__trigger {
    background: transparent;
    border: 1px solid var(--line, hsl(0 0% 88%));
    border-radius: var(--radius-md, 0.5rem);
    padding: var(--gap-2, 0.25rem) var(--gap-4, 0.75rem);
    cursor: pointer;
    font: inherit;
    color: inherit;
}
.forge-popover__panel {
    /* Anchor below the trigger button by default. data-placement="top" flips
       to anchor above; forge-popover.js writes the attribute on open after
       measuring viewport room (see ForgePopover.razor remarks). Consumers
       using ForgePopover inside an `overflow: hidden` parent must remove
       that overflow (or wrap the popover with `isolation: isolate;
       overflow: visible`) so the panel isn't clipped at the parent
       boundary. ForgeDataTable handles this via .forge-table-shell {
       overflow: visible } since commit 5cbedaa.

       --forge-popover-shift-x is a horizontal-overflow shift the JS sets
       when the panel would push past the viewport's right edge. Defaults
       to 0 so static (CSS-only) positioning is unchanged. */
    position: absolute;
    top: calc(100% + var(--spacing-1, 0.25rem));
    left: 0;
    transform: translateX(var(--forge-popover-shift-x, 0));
    z-index: 1000;
    min-width: 12rem;
    background: var(--surface-s1, var(--surface-1, hsl(0 0% 100%)));
    border: 1px solid var(--line, hsl(0 0% 88%));
    border-radius: var(--radius-md, 0.5rem);
    box-shadow: var(--shadow-md, 0 8px 24px color-mix(in oklab, var(--shadow-color, black) 12%, transparent));
    padding: var(--spacing-2, 0.25rem);
    /* Token-driven animation: --motion-duration* zeros under data-motion=
       reduced (or @media prefers-reduced-motion when auto), suppressing
       the slide-in entirely per META-PRAVIDLO Component motion + effects
       respect (forge-dashboard.css global gate). */
    animation: forge-popover-in var(--motion-durationFast, 150ms) var(--motion-easing, cubic-bezier(0.16, 1, 0.3, 1));
}

/* Right-edge alignment — popovers whose trigger sits in the topbar's right
   toolbar (bell, language menu, avatar, tweaks) anchor at the panel's
   right edge instead of the default left. Without this, a panel `min-width:
   12rem` positioned `left: 0` from a right-edge trigger extends 12rem to
   the right, overflowing the viewport.
   This rule applies inside:
     • `.header-right`  — the standard topbar right toolbar (ForgeTopBar)
     • `.forge-popover--align-end` — explicit opt-in for any popover not
       in the topbar (e.g. table-row action menus near the right column)
   Animation keyframes use --forge-popover-shift-x which stays 0 for these,
   so the slide-down animation is unchanged. */
.header-right .forge-popover__panel,
.forge-popover--align-end .forge-popover__panel {
    left: auto;
    right: 0;
}

/* Flip-up: anchor the panel ABOVE the trigger instead of below. Triggered
   by forge-popover.js writing data-placement="top" when there isn't room
   below the trigger. Animation direction inverts so the panel slides
   upward from the trigger origin (motion-respect: same token vars). */
.forge-popover__panel[data-placement="top"] {
    top: auto;
    bottom: calc(100% + var(--spacing-1, 0.25rem));
    animation: forge-popover-in-up var(--motion-durationFast, 150ms) var(--motion-easing, cubic-bezier(0.16, 1, 0.3, 1));
}

@keyframes forge-popover-in {
    from { opacity: 0; transform: translate(var(--forge-popover-shift-x, 0), -4px); }
    to   { opacity: 1; transform: translate(var(--forge-popover-shift-x, 0), 0); }
}

@keyframes forge-popover-in-up {
    from { opacity: 0; transform: translate(var(--forge-popover-shift-x, 0), 4px); }
    to   { opacity: 1; transform: translate(var(--forge-popover-shift-x, 0), 0); }
}

.forge-menu {
    list-style: none;
    margin: 0;
    padding: var(--gap-2, 0.25rem);
}
.forge-menu__item { display: block; }
.forge-menu__link {
    display: flex;
    align-items: center;
    gap: var(--gap-3, 0.5rem);
    width: 100%;
    padding: var(--gap-2, 0.25rem) var(--gap-3, 0.5rem);
    background: transparent;
    border: 0;
    border-radius: var(--radius-sm, 0.25rem);
    color: inherit;
    text-align: start;
    text-decoration: none;
    font: inherit;
    cursor: pointer;
    transition: background-color var(--motion-durationFast) var(--motion-easing);
}
.forge-menu__link:hover { background: var(--surface-2, hsl(0 0% 96%)); }
.forge-menu__link:focus-visible {
    outline: 2px solid var(--accent, hsl(220 90% 56%));
    outline-offset: -2px;
}
.forge-menu__icon { display: inline-flex; flex-shrink: 0; }
.forge-menu__label { flex: 1; }
.forge-menu__trailing { color: var(--text-t3, hsl(0 0% 50%)); font-size: 0.875rem; }
.forge-menu__item.is-disabled .forge-menu__link { opacity: 0.5; cursor: not-allowed; pointer-events: none; }

.forge-date-picker {
    display: flex;
    flex-direction: column;
    gap: var(--gap-2, 0.25rem);
}
.forge-date-picker__label { font-size: 0.875rem; color: var(--text-t2, hsl(0 0% 40%)); }
.forge-date-picker__input {
    padding: var(--gap-2, 0.25rem) var(--gap-3, 0.5rem);
    border: 1px solid var(--line, hsl(0 0% 88%));
    border-radius: var(--radius-md, 0.5rem);
    background: var(--surface-1, hsl(0 0% 100%));
    font: inherit;
}
.forge-date-picker__input:focus {
    outline: 2px solid var(--accent, hsl(220 90% 56%));
    outline-offset: -1px;
    border-color: var(--accent, hsl(220 90% 56%));
}

.forge-confirm,
.forge-shortcuts-help {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 1000;
    background: var(--surface-1, hsl(0 0% 100%));
    border-radius: var(--radius-lg, 0.75rem);
    box-shadow: 0 16px 48px hsl(0 0% 0% / 0.2);
    padding: var(--gap-5, 1rem);
    max-width: min(28rem, 90vw);
}
.forge-shortcuts-help { max-width: min(40rem, 90vw); max-height: 80vh; overflow-y: auto; }

.forge-confirm__title,
.forge-shortcuts-help__title { margin: 0 0 var(--gap-3, 0.5rem); font-size: 1.125rem; font-weight: 600; }
.forge-confirm__message {
    margin-bottom: var(--gap-5, 1rem);
    color: var(--text-t2, hsl(0 0% 40%));
    font-size: 0.9375rem;
}
.forge-confirm__actions {
    display: flex; justify-content: flex-end; gap: var(--gap-3, 0.5rem);
}
.forge-confirm__cancel {
    padding: var(--gap-2, 0.25rem) var(--gap-5, 1rem);
    background: transparent;
    border: 1px solid var(--line, hsl(0 0% 88%));
    border-radius: var(--radius-md, 0.5rem);
    cursor: pointer;
    color: inherit;
    font: inherit;
}
.forge-confirm__confirm {
    padding: var(--gap-2, 0.25rem) var(--gap-5, 1rem);
    border: 0;
    border-radius: var(--radius-md, 0.5rem);
    color: white;
    font: inherit;
    cursor: pointer;
    background: var(--accent, hsl(220 90% 56%));
}
.forge-confirm__confirm--danger  { background: hsl(0 80% 55%); }
.forge-confirm__confirm--warning { background: hsl(40 90% 50%); color: hsl(40 100% 12%); }
.forge-confirm__confirm--success { background: hsl(140 60% 45%); }

.forge-shortcuts-help__header {
    display: flex; justify-content: space-between; align-items: center;
    margin-bottom: var(--gap-3, 0.5rem);
}
.forge-shortcuts-help__group {
    margin: var(--gap-5, 1rem) 0 var(--gap-2, 0.25rem);
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-t3, hsl(0 0% 50%));
    font-weight: 600;
}
.forge-shortcuts-help__list { display: grid; gap: var(--gap-2, 0.25rem); margin: 0; }
.forge-shortcuts-help__row {
    display: grid;
    grid-template-columns: minmax(8rem, auto) 1fr;
    gap: var(--gap-4, 0.75rem);
    align-items: center;
}
.forge-shortcuts-help__keys { display: inline-flex; flex-wrap: wrap; gap: var(--gap-2, 0.25rem); }
.forge-shortcuts-help__kbd {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.5rem;
    height: 1.5rem;
    padding: 0 0.375rem;
    border: 1px solid var(--line, hsl(0 0% 80%));
    border-bottom-width: 2px;
    border-radius: var(--radius-sm, 0.25rem);
    background: var(--surface-2, hsl(0 0% 96%));
    font-family: ui-monospace, SFMono-Regular, "SF Mono", monospace;
    font-size: 0.75rem;
}
.forge-shortcuts-help__description { color: var(--text-t2, hsl(0 0% 40%)); }

.forge-form-section {
    border: 0;
    padding: 0;
    margin: 0 0 var(--gap-6, 1.5rem);
}
.forge-form-section__legend {
    margin: 0 0 var(--gap-3, 0.5rem);
    padding: 0;
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
}
.forge-form-section__title { font-size: 1rem; font-weight: 600; }
.forge-form-section__description { font-size: 0.875rem; color: var(--text-t2, hsl(0 0% 40%)); }
.forge-form-section__body {
    display: flex;
    flex-direction: column;
    gap: var(--gap-4, 0.75rem);
}

.forge-validation-summary {
    border: 1px solid hsl(0 70% 80%);
    background: hsl(0 80% 96%);
    color: hsl(0 70% 28%);
    border-radius: var(--radius-md, 0.5rem);
    padding: var(--gap-3, 0.5rem) var(--gap-4, 0.75rem);
}
.forge-validation-summary__title { font-weight: 600; margin-bottom: var(--gap-2, 0.25rem); }
.forge-validation-summary__list { margin: 0; padding-left: 1.25rem; }
.forge-validation-summary__item { margin-bottom: 0.125rem; }

/* ============================================================================
   ForgeTimeline — vertical / horizontal / alternating event timeline
   ----------------------------------------------------------------------------
   Layout primer:

   - All three orientations share the marker (dot) + body (card) per item.
   - The AXIS is rendered via a `::before` pseudo-element on the parent <ol>,
     positioned absolutely so it doesn't shift item layout.
   - Vertical: items are flex-row with the marker left, axis on left.
   - Horizontal: <ol> uses flex-row, items stack icon-on-top / body-below,
     axis is a horizontal line across the top of the marker row.
   - Alternating: items zig-zag via :nth-child even/odd. Falls back to
     Vertical at ≤ 720 px.

   Motion respect: all transitions use --motion-duration* tokens. The active-
   item pulse uses a token-driven keyframe; data-motion="reduced" suppresses
   it via the global gate in forge-dashboard.css (animation: none !important).
   ============================================================================ */

.forge-timeline {
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative;
}

/* ── Vertical (default) ──────────────────────────────────────────────── */
.forge-timeline--vertical {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-4, 16px);
}

.forge-timeline--vertical::before {
  content: "";
  position: absolute;
  top: 14px;
  bottom: 14px;
  left: 11px;
  width: 2px;
  background: var(--border-b1, var(--line));
  border-radius: 1px;
}

.forge-timeline--vertical .forge-timeline__item {
  display: grid;
  grid-template-columns: 28px 1fr;
  align-items: start;
  gap: var(--spacing-3, 12px);
  position: relative;
}

.forge-timeline--vertical .forge-timeline__marker {
  grid-column: 1;
  margin-top: 2px;
}

.forge-timeline--vertical .forge-timeline__body {
  grid-column: 2;
}

/* ── Horizontal ──────────────────────────────────────────────────────── */
.forge-timeline--horizontal {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: var(--spacing-4, 16px);
  overflow-x: auto;
  padding-bottom: var(--spacing-2, 8px);
}

.forge-timeline--horizontal::before {
  content: "";
  position: absolute;
  top: 13px;
  left: 14px;
  right: 14px;
  height: 2px;
  background: var(--border-b1, var(--line));
  border-radius: 1px;
}

.forge-timeline--horizontal .forge-timeline__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-2, 8px);
  flex: 1 1 0;
  min-width: 120px;
  position: relative;
  text-align: center;
}

.forge-timeline--horizontal .forge-timeline__marker {
  position: relative;
  z-index: 1;
}

.forge-timeline--horizontal .forge-timeline__body {
  font-size: var(--typography-scale-sm, 0.875rem);
}

/* ── Alternating (vertical with zig-zag) ─────────────────────────────── */
.forge-timeline--alternating {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-5, 20px);
}

.forge-timeline--alternating::before {
  content: "";
  position: absolute;
  top: 14px;
  bottom: 14px;
  left: 50%;
  transform: translateX(-50%);
  width: 2px;
  background: var(--border-b1, var(--line));
  border-radius: 1px;
}

.forge-timeline--alternating .forge-timeline__item {
  display: grid;
  grid-template-columns: 1fr 28px 1fr;
  align-items: center;
  gap: var(--spacing-3, 12px);
  position: relative;
}

.forge-timeline--alternating .forge-timeline__marker {
  grid-column: 2;
}

/* Odd items: body on the LEFT (column 1), marker centre, column 3 empty. */
.forge-timeline--alternating .forge-timeline__item:nth-child(odd) .forge-timeline__body {
  grid-column: 1;
  text-align: right;
  padding-right: var(--spacing-2, 8px);
}

/* Even items: body on the RIGHT (column 3), marker centre, column 1 empty. */
.forge-timeline--alternating .forge-timeline__item:nth-child(even) .forge-timeline__body {
  grid-column: 3;
  text-align: left;
  padding-left: var(--spacing-2, 8px);
}

/* Mobile fallback for alternating → vertical layout. */
@media (max-width: 720px) {
  .forge-timeline--alternating::before {
    left: 11px;
    transform: none;
  }
  .forge-timeline--alternating .forge-timeline__item {
    grid-template-columns: 28px 1fr;
  }
  .forge-timeline--alternating .forge-timeline__marker {
    grid-column: 1;
  }
  .forge-timeline--alternating .forge-timeline__item:nth-child(odd) .forge-timeline__body,
  .forge-timeline--alternating .forge-timeline__item:nth-child(even) .forge-timeline__body {
    grid-column: 2;
    text-align: left;
    padding-left: 0;
    padding-right: 0;
  }
}

/* ── Marker dot — variants ───────────────────────────────────────────── */
.forge-timeline__marker {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-s2, var(--bg-2));
  border: 2px solid var(--line, var(--border-b1));
  color: var(--text-t2, var(--fg-2));
  z-index: 1;
  transition:
    background var(--motion-durationFast, 160ms) var(--motion-easing, ease),
    border-color var(--motion-durationFast, 160ms) var(--motion-easing, ease),
    box-shadow var(--motion-durationFast, 160ms) var(--motion-easing, ease);
}

.forge-timeline__marker--primary {
  background: var(--accent-base, var(--accent));
  border-color: var(--accent-base, var(--accent));
  color: var(--accent-on, white);
}

.forge-timeline__marker--success {
  background: var(--surface-success, color-mix(in oklab, green 25%, var(--surface-s2)));
  border-color: var(--text-success, green);
  color: var(--text-success, green);
}

.forge-timeline__marker--warning {
  background: var(--surface-warning, color-mix(in oklab, orange 25%, var(--surface-s2)));
  border-color: var(--text-warning, orange);
  color: var(--text-warning, orange);
}

.forge-timeline__marker--danger {
  background: var(--surface-danger, color-mix(in oklab, red 25%, var(--surface-s2)));
  border-color: var(--text-danger, red);
  color: var(--text-danger, red);
}

.forge-timeline__marker--info {
  background: var(--surface-info, color-mix(in oklab, dodgerblue 25%, var(--surface-s2)));
  border-color: var(--text-info, dodgerblue);
  color: var(--text-info, dodgerblue);
}

.forge-timeline__marker--neutral {
  background: var(--surface-s3, var(--bg-3));
  border-color: var(--line-strong, var(--text-t3));
  color: var(--text-t3, var(--fg-3));
}

/* ── Active step — pulsing ring (motion-gated) ───────────────────────── */
.forge-timeline__item.is-active .forge-timeline__marker {
  box-shadow: 0 0 0 4px color-mix(in oklab, var(--accent-base, var(--accent)) 24%, transparent);
  animation: forge-timeline-pulse 1800ms var(--motion-easing, ease-in-out) infinite;
}

@keyframes forge-timeline-pulse {
  0%, 100% { box-shadow: 0 0 0 4px color-mix(in oklab, var(--accent-base, var(--accent)) 24%, transparent); }
  50%       { box-shadow: 0 0 0 8px color-mix(in oklab, var(--accent-base, var(--accent)) 14%, transparent); }
}

/* ── Body card ───────────────────────────────────────────────────────── */
.forge-timeline__body {
  min-width: 0;
}

.forge-timeline__title {
  margin: 0 0 var(--spacing-1, 4px) 0;
  font-size: var(--typography-scale-base, 1rem);
  font-weight: var(--typography-weights-semibold, 600);
  color: var(--text-t1, var(--fg-1));
  line-height: 1.4;
}

.forge-timeline__time {
  display: block;
  font-size: var(--typography-scale-xs, 0.75rem);
  color: var(--text-t3, var(--fg-3));
  margin-bottom: var(--spacing-1, 4px);
}

.forge-timeline__description {
  margin: 0;
  font-size: var(--typography-scale-sm, 0.875rem);
  color: var(--text-t2, var(--fg-2));
  line-height: 1.55;
}

/* =========================================================================
   ForgeSelect (v2) — Forge-styled single-select with optional autocomplete
   ========================================================================= */

.forge-select-v2 {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1, 4px);
    min-width: 0;
}

/* DON'T add `z-index` to .forge-select-v2 — that CREATES a stacking
   context boundary at the select-wrapper level that TRAPS the popup
   inside it, and the popup's own z-index:9999 only applies WITHIN that
   trapped context (so any sibling .forge-card painting AFTER the
   select's wrapper wins by document order regardless of how high the
   popup's z-index is). Phase Q.1 lesson — N.3's first attempt fell for
   exactly this trap; the inline z-index:99999999 the user reported was
   never going to escape it.

   Correct fix: raise the CLOSEST .forge-card ANCESTOR of the open
   select so the card-level paint order beats sibling cards. The popup
   then inherits the card's stacking context and z-index:9999 wins
   against any normal-flow sibling. Uses :has() — Chrome 105+ /
   Firefox 121+ / Safari 15.4+ / WebView2 (all Forge-target browsers).

   Phase Q.2 (2026-05-27) — third iteration of this fix; the previous
   two (N.3 + Q.1) addressed overflow clipping + naive z-index raise
   but missed the stacking-context-on-the-select trap. This one is
   tested against the /qr-codes split-layout case the user reported. */
.forge-card:has(.forge-select-v2.is-open) {
    position: relative;
    z-index: 50;
}

.forge-select-v2.is-disabled {
    opacity: 0.55;
    pointer-events: none;
}

.forge-select-v2__label {
    font-size: var(--typography-scale-sm, 0.875rem);
    font-weight: 500;
    color: var(--text-t1, var(--fg-1));
    display: flex;
    align-items: center;
    gap: var(--spacing-1, 4px);
}

.forge-select-v2__required {
    color: var(--semantic-danger, oklch(0.6 0.18 25));
    font-weight: 600;
}

.forge-select-v2__trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-2, 8px);
    width: 100%;
    min-height: 36px;
    padding: 6px 10px;
    background: var(--surface-elevated, var(--bg-1, transparent));
    color: var(--text-t1, var(--fg-1));
    border: 1px solid var(--line-strong, var(--fg-3));
    border-radius: var(--r-sm, 8px);
    font: inherit;
    font-size: var(--typography-scale-sm, 0.875rem);
    cursor: pointer;
    text-align: start;
    transition: border-color var(--motion-durationFast, 120ms) var(--motion-easing, ease),
                box-shadow var(--motion-durationFast, 120ms) var(--motion-easing, ease);
}

.forge-select-v2__trigger:hover {
    border-color: var(--accent-base, var(--line-stronger, var(--fg-2)));
}

.forge-select-v2__trigger:focus-visible {
    outline: 2px solid var(--accent-base, currentColor);
    outline-offset: 2px;
    border-color: var(--accent-base, var(--line-stronger));
}

.forge-select-v2__trigger.has-error {
    border-color: var(--semantic-danger, oklch(0.6 0.18 25));
}

.forge-select-v2.is-open .forge-select-v2__trigger {
    border-color: var(--accent-base, var(--line-stronger));
    box-shadow: 0 0 0 2px color-mix(in oklab, var(--accent-base, currentColor) 18%, transparent);
}

/* Combo (autocomplete) trigger — the field IS the input. The wrapper reuses the
   .forge-select-v2__trigger box (border / height / padding); the input fills it
   borderless, the chevron is a secondary toggle button. */
.forge-select-v2__trigger--combo {
    cursor: text;
}

.forge-select-v2__trigger--combo:focus-within {
    border-color: var(--accent-base, var(--line-stronger));
    box-shadow: 0 0 0 2px color-mix(in oklab, var(--accent-base, currentColor) 18%, transparent);
}

.forge-select-v2__trigger--combo.is-disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

.forge-select-v2__field {
    flex: 1 1 auto;
    min-width: 0;
    border: none;
    background: transparent;
    color: var(--text-t1, var(--fg-1));
    font: inherit;
    font-size: var(--typography-scale-sm, 0.875rem);
    padding: 0;
    outline: none;
    text-overflow: ellipsis;
}

.forge-select-v2__field::placeholder {
    color: var(--text-t3, var(--fg-3));
}

.forge-select-v2__field:disabled {
    cursor: not-allowed;
}

.forge-select-v2__toggle {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    background: transparent;
    color: var(--text-t2, var(--fg-2));
    cursor: pointer;
    padding: 0;
    margin: 0;
}

.forge-select-v2__toggle:disabled {
    cursor: not-allowed;
}

.forge-select-v2__value {
    flex: 1 1 0;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.forge-select-v2__value.is-placeholder {
    color: var(--text-t3, var(--fg-3));
}

.forge-select-v2__chevron {
    flex-shrink: 0;
    color: var(--text-t2, var(--fg-2));
    transition: transform var(--motion-durationBase, 180ms) var(--motion-easing, ease);
}

.forge-select-v2.is-open .forge-select-v2__chevron {
    transform: rotate(180deg);
}

.forge-select-v2__help {
    font-size: var(--typography-scale-xs, 0.75rem);
    color: var(--text-t3, var(--fg-3));
}

.forge-select-v2__error {
    font-size: var(--typography-scale-xs, 0.75rem);
    color: var(--semantic-danger, oklch(0.6 0.18 25));
}

.forge-select-v2__optionsource {
    display: none !important;
}

.forge-select-v2__popup {
    /* Phase O.3 (2026-05-26): reverted N.3 `position: fixed` after user
       reported "vůbec neotevírá" — the position-fixed variant had an
       initial-paint flash at wrong viewport coords before JS positioned
       it, and the visible state wasn't always reachable from the user's
       click. Back to the original `position: absolute` + high z-index
       which is the well-tested combo. The /qr-codes "dropdown clipped
       by preview card" symptom is fixed at the consumer level — the
       SETTINGS card grants `overflow: visible` so the dropdown can
       extend beyond it (.forge-card.is-overflow-visible utility). */
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 9999;
    display: flex;
    flex-direction: column;
    margin-top: 4px;
    min-width: 100%;
    max-height: min(320px, 50vh);
    overflow: hidden;
    background: var(--surface-elevated, var(--bg-1, white));
    color: var(--text-t1, var(--fg-1));
    border: 1px solid var(--line-strong, var(--fg-3));
    border-radius: var(--r-md, 10px);
    box-shadow:
        0 12px 28px -8px oklch(0 0 0 / 0.28),
        0 2px 4px oklch(0 0 0 / 0.06);
    animation: forge-select-popup-in var(--motion-durationBase, 180ms) var(--motion-easing, cubic-bezier(0.16, 1, 0.3, 1));
    transform-origin: top center;
}

/* O.3 utility: lets a consumer card opt out of the default overflow clipping
   when it contains a popup-style overlay (ForgeSelect dropdown, datepicker,
   tooltip). Apply via `<ForgeCard Class="is-overflow-visible">` on the card
   that hosts the select. The card's border-radius is unaffected because the
   ForgeCard inner body retains its own clipping for non-overlay content. */
.forge-card.is-overflow-visible,
.forge-card.is-overflow-visible .forge-card__body {
    overflow: visible;
}

@keyframes forge-select-popup-in {
    from { opacity: 0; transform: translateY(-4px) scale(0.98); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

:root[data-motion="reduced"] .forge-select-v2__popup,
:root:not([data-motion="full"]) .forge-select-v2__popup {
    animation: none;
}
@media (prefers-reduced-motion: reduce) {
    :root:not([data-motion="full"]) .forge-select-v2__popup {
        animation: none;
    }
}

.forge-select-v2__list {
    list-style: none;
    margin: 0;
    padding: 4px;
    overflow-y: auto;
    flex: 1 1 auto;
}

.forge-select-v2__option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-2, 8px);
    padding: 7px 10px;
    border-radius: var(--r-sm, 6px);
    cursor: pointer;
    font-size: var(--typography-scale-sm, 0.875rem);
    color: var(--text-t1, var(--fg-1));
    transition: background-color var(--motion-durationFast, 120ms) var(--motion-easing, ease);
}

.forge-select-v2__option:hover,
.forge-select-v2__option.is-highlighted {
    background: color-mix(in oklab, var(--accent-base, currentColor) 14%, transparent);
}

.forge-select-v2__option.is-selected {
    background: color-mix(in oklab, var(--accent-base, currentColor) 22%, transparent);
    color: var(--accent-on-soft, var(--text-t1));
    font-weight: 500;
}

.forge-select-v2__option-text {
    flex: 1 1 0;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.forge-select-v2__option-check {
    flex-shrink: 0;
    color: var(--accent-base, currentColor);
}

.forge-select-v2__empty {
    padding: 12px 10px;
    text-align: center;
    color: var(--text-t3, var(--fg-3));
    font-size: var(--typography-scale-sm, 0.875rem);
}

/* Compact variant — used inside table filter rows + tight toolbars. */
.forge-select-v2--xs .forge-select-v2__trigger {
    min-height: 28px;
    padding: 4px 8px;
    font-size: var(--typography-scale-xs, 0.75rem);
}

/* =========================================================================
   ForgeSlider — accent-driven range with a CSS-painted thumb + fill on top
   of a hidden native <input type="range"> (kept for screen-readers, voice
   control, keyboard a11y). The visible track + fill + thumb honour
   --accent-base from the cascaded theme tokens.
   ========================================================================= */

.forge-slider {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1, 4px);
}

.forge-slider.is-disabled {
    opacity: 0.55;
    pointer-events: none;
}

.forge-slider__header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--spacing-2, 8px);
}

.forge-slider__label {
    font-size: var(--typography-scale-sm, 0.875rem);
    font-weight: 500;
    color: var(--text-t1, var(--fg-1));
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-1, 4px);
}

.forge-slider__required {
    color: var(--semantic-danger, oklch(0.6 0.18 25));
    font-weight: 600;
}

.forge-slider__value {
    font-size: var(--typography-scale-xs, 0.75rem);
    color: var(--text-t2, var(--fg-2));
    font-variant-numeric: tabular-nums;
}

.forge-slider__track-wrap {
    position: relative;
    height: 24px;
    display: flex;
    align-items: center;
}

/* The native input is the accessibility primitive. Stays in flow so the
   browser still handles keyboard nav + touch focus + voice control, but
   the visible track / fill / thumb below are what the user sees. */
.forge-slider__native {
    appearance: none;
    -webkit-appearance: none;
    width: 100%;
    height: 24px;
    margin: 0;
    background: transparent;
    cursor: pointer;
    z-index: 2;
    /* Make the actual input invisible — clicks still register and the
       focus ring still draws (via the styled .forge-slider__thumb below). */
    opacity: 0;
}

.forge-slider__native:disabled {
    cursor: not-allowed;
}

.forge-slider__track {
    position: absolute;
    top: 50%;
    left: 0;
    right: 0;
    height: 6px;
    transform: translateY(-50%);
    border-radius: 999px;
    background: color-mix(in oklab, var(--accent-base, currentColor) 14%, transparent);
    z-index: 0;
    pointer-events: none;
}

.forge-slider__fill {
    position: absolute;
    inset: 0 auto 0 0;
    width: var(--forge-slider-fill, 0%);
    background: linear-gradient(90deg,
        color-mix(in oklab, var(--accent-base, currentColor) 80%, transparent),
        color-mix(in oklab, var(--accent-base, currentColor) 100%, transparent));
    border-radius: 999px;
}

.forge-slider__thumb {
    position: absolute;
    top: 50%;
    /* Drive thumb position from the same CSS variable that paints the fill.
       JS pointer drag mutates --forge-slider-fill on the root element via
       forge-slider.js#paint; Razor's initial value comes from CssVariables
       on the wrapper. WITHOUT this rule, the thumb's `left` would have to
       come from an inline style attribute (Razor render-time), and the JS
       module wouldn't be able to move it smoothly during drag — the thumb
       would stay frozen at the start position until pointerup triggered
       a .NET round-trip + re-render. */
    left: var(--forge-slider-fill, 0%);
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--surface-elevated, var(--bg-1, #fff));
    border: 2px solid var(--accent-base, currentColor);
    box-shadow: 0 2px 8px color-mix(in oklab, var(--accent-base, currentColor) 30%, transparent);
    transform: translate(-50%, -50%);
    transition: transform var(--motion-durationFast, 120ms) var(--motion-easing, ease),
                box-shadow var(--motion-durationFast, 120ms) var(--motion-easing, ease);
    pointer-events: none;
    z-index: 1;
}

.forge-slider__native:hover + .forge-slider__track .forge-slider__thumb {
    transform: translate(-50%, -50%) scale(1.12);
    box-shadow:
        0 4px 12px color-mix(in oklab, var(--accent-base, currentColor) 40%, transparent),
        0 0 0 6px color-mix(in oklab, var(--accent-base, currentColor) 18%, transparent);
}

.forge-slider__native:focus-visible + .forge-slider__track .forge-slider__thumb {
    box-shadow:
        0 0 0 4px color-mix(in oklab, var(--accent-base, currentColor) 26%, transparent),
        0 2px 8px color-mix(in oklab, var(--accent-base, currentColor) 30%, transparent);
}

.forge-slider__native:active + .forge-slider__track .forge-slider__thumb {
    transform: translate(-50%, -50%) scale(1.04);
}

.forge-slider__help {
    font-size: var(--typography-scale-xs, 0.75rem);
    color: var(--text-t3, var(--fg-3));
}

:root[data-motion="reduced"] .forge-slider__thumb,
:root:not([data-motion="full"]) .forge-slider__thumb {
    transition: none;
}
@media (prefers-reduced-motion: reduce) {
    :root:not([data-motion="full"]) .forge-slider__thumb {
        transition: none;
    }
}

/* =========================================================================
   ForgeQrCode — inline QR display + optional download buttons. SVG inside
   the canvas auto-scales to whatever container width the consumer gives.
   ========================================================================= */

.forge-qrcode {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: var(--spacing-2, 8px);
    padding: var(--spacing-3, 12px);
    background: var(--surface-elevated, var(--bg-1, transparent));
    border: 1px solid var(--line, var(--line-strong));
    border-radius: var(--r-md, 10px);
    color: var(--text-t1, var(--fg-1));
}

.forge-qrcode__label {
    font-size: var(--typography-scale-sm, 0.875rem);
    font-weight: 500;
    color: var(--text-t2, var(--fg-2));
    letter-spacing: 0.02em;
    text-align: center;
}

.forge-qrcode__canvas {
    /* Visible canvas size scales with PixelsPerModule so the slider has
       perceptible effect. `--qr-px` is set inline on .forge-qrcode by the
       Razor template (default 14 if absent for backward compat). Each
       PixelsPerModule unit maps to ~14 CSS pixels of canvas width,
       clamped to a sensible visible range (96–512 px) so the slider
       doesn't degenerate into a postage-stamp at PixelsPerModule=4 or
       overflow the card at PixelsPerModule=32. Phase N.4 (2026-05-26). */
    width: 100%;
    max-width: clamp(96px, calc(var(--qr-px, 14) * 14px), 512px);
    aspect-ratio: 1 / 1;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--surface-s1, white);
    border-radius: var(--r-sm, 6px);
    padding: var(--spacing-2, 8px);
    /* Smooth size transition makes the slider feel responsive instead of
       jumping in discrete steps. */
    transition: max-width var(--motion-durationFast, 120ms) var(--motion-easing, ease);
}

.forge-qrcode__canvas svg {
    width: 100%;
    height: 100%;
    display: block;
}

.forge-qrcode__placeholder,
.forge-qrcode__error {
    color: var(--text-t3, var(--fg-3));
    font-size: var(--typography-scale-sm, 0.875rem);
    text-align: center;
    padding: var(--spacing-3, 12px);
}

.forge-qrcode__error {
    color: var(--semantic-danger, oklch(0.6 0.18 25));
}

.forge-qrcode.is-loading .forge-qrcode__canvas {
    opacity: 0.55;
}

.forge-qrcode__actions {
    display: flex;
    flex-direction: row;
    gap: var(--spacing-2, 8px);
    flex-wrap: wrap;
    justify-content: center;
}

/* Compact variant for table-row inline rendering. */
.forge-qrcode--xs .forge-qrcode__canvas {
    max-width: 96px;
    padding: var(--spacing-1, 4px);
}
.forge-qrcode--xs .forge-qrcode__label {
    font-size: var(--typography-scale-xs, 0.75rem);
}

/* =========================================================================
   ForgeKanbanBoard — drag-drop column board. Horizontal scroll on narrow
   viewports, snap-to-column for touch devices.
   ========================================================================= */

.forge-kanban-board {
    display: flex;
    flex-direction: column;
    min-height: 200px;
}

.forge-kanban-board__columnsource {
    display: none !important;
}

.forge-kanban-board__columns {
    display: flex;
    flex-direction: row;
    gap: var(--spacing-3, 12px);
    align-items: flex-start;
    overflow-x: auto;
    overflow-y: hidden;
    /* overflow-y:hidden makes overflow-x clip vertically too, so the top inset
       must clear the first card's ~12px upward hover shadow + 4px focus outline
       in a column that isn't itself scrolling. (4px was too tight → clipped.) */
    padding: var(--spacing-3, 12px) var(--spacing-1, 4px) var(--spacing-3, 12px);
    /* CSS scroll-snap so finger swipes on touch align to one column. */
    scroll-snap-type: x proximity;
}

.forge-kanban-column {
    flex: 0 0 auto;
    width: 320px;
    max-width: 90vw;
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2, 8px);
    padding: var(--spacing-3, 12px);
    background: var(--surface-s1, var(--bg-1, transparent));
    border: 1px solid var(--line, var(--line-soft));
    border-radius: var(--r-md, 10px);
    scroll-snap-align: start;
    transition: border-color var(--motion-durationFast, 120ms) var(--motion-easing, ease),
                background-color var(--motion-durationFast, 120ms) var(--motion-easing, ease);
}

.forge-kanban-column.is-drag-over {
    border-color: var(--accent-base, currentColor);
    background: color-mix(in oklab, var(--accent-base, currentColor) 8%, var(--surface-s1, var(--bg-1)));
}

.forge-kanban-column.is-over-limit {
    border-color: var(--semantic-danger, oklch(0.6 0.18 25));
}

.forge-kanban-column__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-2, 8px);
    padding-bottom: var(--spacing-2, 8px);
    border-bottom: 1px solid var(--line-soft, var(--line));
}

.forge-kanban-column__title {
    font-size: var(--typography-scale-sm, 0.875rem);
    font-weight: 600;
    color: var(--text-t1, var(--fg-1));
    letter-spacing: 0.02em;
}

.forge-kanban-column__count {
    padding: 2px 8px;
    border-radius: 999px;
    font-size: var(--typography-scale-xs, 0.75rem);
    font-weight: 500;
    color: var(--text-t2, var(--fg-2));
    background: color-mix(in oklab, var(--text-t3, var(--fg-3)) 18%, transparent);
    font-variant-numeric: tabular-nums;
}

.forge-kanban-column__count--info {
    background: color-mix(in oklab, var(--semantic-info, var(--accent-base, oklch(0.7 0.15 240))) 22%, transparent);
    color: var(--semantic-info, var(--accent-base, oklch(0.45 0.18 240)));
}
.forge-kanban-column__count--success {
    background: color-mix(in oklab, var(--semantic-success, oklch(0.7 0.18 140)) 22%, transparent);
    color: var(--semantic-success, oklch(0.45 0.2 140));
}
.forge-kanban-column__count--warning {
    background: color-mix(in oklab, var(--semantic-warning, oklch(0.78 0.16 80)) 28%, transparent);
    color: var(--semantic-warning, oklch(0.45 0.18 60));
}
.forge-kanban-column__count--danger {
    background: color-mix(in oklab, var(--semantic-danger, oklch(0.6 0.18 25)) 22%, transparent);
    color: var(--semantic-danger, oklch(0.5 0.2 25));
}

.forge-kanban-column__body {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2, 8px);
    min-height: 80px;
    /* Vertical scroll inside the column when the list is taller than the
       viewport; horizontal scroll lives on the parent .forge-kanban-board__columns. */
    overflow-y: auto;
    max-height: calc(100vh - 240px);
    /* overflow-y:auto clips BOTH axes against the padding box (CSS spec: a
       non-visible value on one axis computes the other to auto, never visible),
       which sliced the FIRST card's upward hover shadow + focus outline at the
       top edge. Pad the scroll box for clearance; negate left/right/bottom with
       margin so card width/position is unchanged (the clip box only grows into
       the column's own padding). The 8px top keeps a breathing gap that also
       clears the ~12px upward hover-shadow reach. */
    padding: var(--spacing-2, 8px);
    margin: 0 calc(var(--spacing-2, 8px) * -1) calc(var(--spacing-2, 8px) * -1);
}

.forge-kanban-column__empty {
    margin: 0;
    padding: var(--spacing-4, 16px) var(--spacing-2, 8px);
    text-align: center;
    color: var(--text-t3, var(--fg-3));
    font-size: var(--typography-scale-xs, 0.75rem);
    border: 1px dashed var(--line-soft, var(--line));
    border-radius: var(--r-sm, 6px);
    background: transparent;
}

.forge-kanban-card {
    padding: var(--spacing-3, 12px);
    background: var(--surface-elevated, var(--bg-1, var(--surface-s2)));
    border: 1px solid var(--line, var(--line-strong));
    border-radius: var(--r-sm, 8px);
    cursor: grab;
    color: var(--text-t1, var(--fg-1));
    box-shadow: 0 1px 2px color-mix(in oklab, black 6%, transparent);
    transition: transform var(--motion-durationFast, 120ms) var(--motion-easing, ease),
                box-shadow var(--motion-durationFast, 120ms) var(--motion-easing, ease),
                border-color var(--motion-durationFast, 120ms) var(--motion-easing, ease);
}

.forge-kanban-card:hover {
    border-color: var(--accent-base, var(--line-stronger));
    box-shadow: 0 4px 12px -4px color-mix(in oklab, var(--accent-base, currentColor) 24%, transparent);
    transform: translateY(-1px);
}

.forge-kanban-card:focus-visible {
    outline: 2px solid var(--accent-base, currentColor);
    outline-offset: 2px;
}

.forge-kanban-card:active {
    cursor: grabbing;
}

.forge-kanban-card.is-dragging {
    opacity: 0.45;
    box-shadow: none;
}

.forge-kanban-card__title {
    margin: 0 0 var(--spacing-1, 4px);
    font-size: var(--typography-scale-sm, 0.875rem);
    font-weight: 600;
    color: var(--text-t1, var(--fg-1));
    line-height: 1.4;
}

.forge-kanban-card__subtitle {
    margin: 0;
    font-size: var(--typography-scale-xs, 0.75rem);
    color: var(--text-t2, var(--fg-2));
    line-height: 1.5;
}

:root[data-motion="reduced"] .forge-kanban-card,
:root:not([data-motion="full"]) .forge-kanban-card {
    transition: none;
}
@media (prefers-reduced-motion: reduce) {
    :root:not([data-motion="full"]) .forge-kanban-card {
        transition: none;
    }
}

/* ---- ForgeLineChart — multi-series line chart tooltip + legend ---- */
.forge-line-chart {
    position: relative;
    width: 100%;
}

.forge-line-chart__tooltip {
    /* layout values are inlined via style="" — this rule covers anything not
       expressible in inline style (line-height, list-style, etc.) */
    line-height: 1.5;
}

.forge-line-chart__tooltip-x {
    color: var(--text-t3, var(--fg-3));
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 4px;
}

.forge-line-chart__tooltip-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 2px 0;
}

.forge-line-chart__tooltip-swatch {
    flex-shrink: 0;
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 2px;
}

.forge-line-chart__tooltip-name {
    color: var(--text-t2, var(--fg-2));
    margin-right: auto;
}

.forge-line-chart__tooltip-value {
    color: var(--text-t1, var(--fg-1));
    font-weight: 600;
}

.forge-line-chart__legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--gap-3, 12px);
    margin: 8px 0 0;
    padding: 0;
    list-style: none;
}

.forge-line-chart__legend-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 11px;
    color: var(--text-t2, var(--fg-2));
    font-family: var(--font-mono, ui-monospace, monospace);
}

.forge-line-chart__legend-swatch {
    display: inline-block;
    width: 14px;
    height: 3px;
    border-radius: 2px;
}

.forge-line-chart__legend-swatch.is-dashed {
    background: repeating-linear-gradient(to right,
        currentColor 0,
        currentColor 4px,
        transparent 4px,
        transparent 8px) !important;
}

/* ---- ForgeActivityFeed — realtime "who did what when" stream ---- */
.forge-activity-feed {
    display: flex;
    flex-direction: column;
    gap: var(--gap-3, 12px);
    min-width: 0;
}

.forge-activity-feed__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--gap-2, 8px);
}

.forge-activity-feed__title {
    margin: 0;
    font-size: var(--typography-scale-base, 14px);
    font-weight: 600;
    color: var(--text-t1, var(--fg-1));
    letter-spacing: 0.01em;
}

.forge-activity-feed__mute {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border: 1px solid transparent;
    background: transparent;
    color: var(--text-t3, var(--fg-3));
    border-radius: var(--radius-1, 6px);
    cursor: pointer;
    transition: background var(--motion-durationFast, 120ms) var(--motion-easing, ease),
                color var(--motion-durationFast, 120ms) var(--motion-easing, ease),
                border-color var(--motion-durationFast, 120ms) var(--motion-easing, ease);
}
.forge-activity-feed__mute:hover {
    background: var(--surface-s2, var(--bg-2));
    color: var(--text-t1, var(--fg-1));
}
.forge-activity-feed__mute:focus-visible {
    outline: 2px solid var(--accent-base, var(--accent));
    outline-offset: 2px;
}
.forge-activity-feed__mute.is-muted {
    color: var(--warn, #f59e0b);
    border-color: color-mix(in oklab, var(--warn, #f59e0b) 30%, transparent);
    background: color-mix(in oklab, var(--warn, #f59e0b) 10%, transparent);
}

.forge-activity-feed__empty {
    padding: var(--gap-4, 16px) var(--gap-3, 12px);
    text-align: center;
    color: var(--text-t3, var(--fg-3));
    font-size: var(--typography-scale-sm, 13px);
    border: 1px dashed var(--line, var(--fg-3, currentColor));
    border-radius: var(--radius-2, 8px);
}

.forge-activity-feed__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--gap-3, 12px);
    position: relative;
}

.forge-activity-feed__entry {
    display: grid;
    grid-template-columns: 12px 1fr;
    gap: var(--gap-3, 12px);
    align-items: start;
    padding: var(--gap-2, 8px);
    margin: 0;
    border-radius: var(--radius-2, 8px);
    transition: background var(--motion-durationBase, 200ms) var(--motion-easing, ease);
    background: transparent;
}

/* Just-arrived highlight — token-tinted to the entry's variant. */
.forge-activity-feed__entry.is-new {
    background: color-mix(in oklab, var(--accent-base, var(--accent)) 8%, transparent);
    animation: forge-activity-pop-in var(--motion-durationBase, 200ms) var(--motion-easing, ease);
}

@keyframes forge-activity-pop-in {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0); }
}

.forge-activity-feed__marker {
    width: 10px;
    height: 10px;
    border-radius: 999px;
    margin-top: 6px;
    background: var(--text-t3, var(--fg-3));
    box-shadow: 0 0 0 3px color-mix(in oklab, currentColor 18%, transparent);
}

.forge-activity-feed__entry--info .forge-activity-feed__marker {
    background: var(--info, #3b82f6);
}
.forge-activity-feed__entry--success .forge-activity-feed__marker {
    background: var(--ok, #10b981);
}
.forge-activity-feed__entry--warning .forge-activity-feed__marker {
    background: var(--warn, #f59e0b);
}
.forge-activity-feed__entry--danger .forge-activity-feed__marker {
    background: var(--bad, #ef4444);
}
.forge-activity-feed__entry--neutral .forge-activity-feed__marker {
    background: var(--text-t3, var(--fg-3));
}

.forge-activity-feed__body {
    min-width: 0;
}

.forge-activity-feed__row {
    display: flex;
    gap: var(--gap-3, 12px);
    align-items: flex-start;
    min-width: 0;
}

.forge-activity-feed__main {
    flex: 1 1 auto;
    min-width: 0;
}

.forge-activity-feed__title-row {
    display: inline-flex;
    align-items: center;
    gap: var(--gap-2, 8px);
    color: var(--text-t1, var(--fg-1));
    text-decoration: none;
    line-height: 1.4;
}
.forge-activity-feed__link:hover {
    color: var(--accent-base, var(--accent));
    text-decoration: underline;
    text-underline-offset: 3px;
}

.forge-activity-feed__entry-title {
    font-weight: 600;
    font-size: var(--typography-scale-sm, 13px);
    word-break: break-word;
}

.forge-activity-feed__meta {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 2px;
    font-size: var(--typography-scale-xs, 11px);
    color: var(--text-t3, var(--fg-3));
}
.forge-activity-feed__sep {
    opacity: 0.6;
}
.forge-activity-feed__actor {
    font-weight: 500;
}

.forge-activity-feed__description {
    margin: 4px 0 0;
    color: var(--text-t2, var(--fg-2));
    font-size: var(--typography-scale-sm, 13px);
    line-height: 1.5;
    word-break: break-word;
}

@media (prefers-reduced-motion: reduce) {
    .forge-activity-feed__entry.is-new {
        animation: none;
    }
}
:root[data-motion="reduced"] .forge-activity-feed__entry.is-new,
:root:not([data-motion="full"]) .forge-activity-feed__entry.is-new {
    animation: none;
}
:root[data-effects="minimal"] .forge-activity-feed__marker {
    box-shadow: none;
}

/* ---- ForgeRecursiveForm — universal nested authoring ---- */
.forge-recursive-form {
    display: flex;
    flex-direction: column;
    gap: 2px;
    font-size: var(--typography-scale-sm, 13px);
}

.forge-recursive-form__empty {
    padding: var(--gap-4, 16px);
    text-align: center;
    color: var(--text-t3, var(--fg-3));
    border: 1px dashed var(--line, currentColor);
    border-radius: var(--radius-2, 8px);
}

.forge-recursive-form__row {
    display: grid;
    grid-template-columns: 24px 1fr auto;
    align-items: center;
    gap: var(--gap-2, 8px);
    padding: 4px var(--gap-2, 8px);
    border-radius: var(--radius-1, 6px);
    background: transparent;
    transition: background var(--motion-durationFast, 120ms) var(--motion-easing, ease);
}
.forge-recursive-form__row:hover {
    background: color-mix(in oklab, var(--accent-base, var(--accent)) 6%, transparent);
}
.forge-recursive-form__row.is-selected {
    background: color-mix(in oklab, var(--accent-base, var(--accent)) 10%, transparent);
}

.forge-recursive-form__toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border: 0;
    background: transparent;
    color: var(--text-t3, var(--fg-3));
    cursor: pointer;
    border-radius: var(--radius-1, 4px);
}
.forge-recursive-form__toggle:hover {
    background: var(--surface-s2, var(--bg-2));
    color: var(--text-t1, var(--fg-1));
}
.forge-recursive-form__toggle--spacer {
    cursor: default;
}

.forge-recursive-form__name {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--gap-3, 12px);
    background: transparent;
    border: 0;
    padding: 6px 8px;
    color: var(--text-t1, var(--fg-1));
    cursor: pointer;
    text-align: left;
    border-radius: var(--radius-1, 4px);
    min-width: 0;
    font: inherit;
}
.forge-recursive-form__label {
    font-weight: 500;
    word-break: break-word;
}
.forge-recursive-form__hint {
    color: var(--text-t3, var(--fg-3));
    font-variant-numeric: tabular-nums;
    font-size: var(--typography-scale-xs, 11px);
}

.forge-recursive-form__actions {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    opacity: 0;
    transition: opacity var(--motion-durationFast, 120ms) var(--motion-easing, ease);
}
.forge-recursive-form__row:hover .forge-recursive-form__actions,
.forge-recursive-form__row.is-selected .forge-recursive-form__actions,
.forge-recursive-form__row:focus-within .forge-recursive-form__actions {
    opacity: 1;
}

.forge-recursive-form__action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border: 0;
    background: transparent;
    color: var(--text-t3, var(--fg-3));
    cursor: pointer;
    border-radius: var(--radius-1, 4px);
    transition: background var(--motion-durationFast, 120ms) var(--motion-easing, ease),
                color var(--motion-durationFast, 120ms) var(--motion-easing, ease);
}
.forge-recursive-form__action:hover {
    background: var(--surface-s2, var(--bg-2));
    color: var(--text-t1, var(--fg-1));
}
.forge-recursive-form__action--danger:hover {
    color: var(--bad, #ef4444);
    background: color-mix(in oklab, var(--bad, #ef4444) 12%, transparent);
}

.forge-recursive-form__editor {
    padding: var(--gap-3, 12px);
    margin: 2px 0 var(--gap-2, 8px);
    background: var(--surface-s2, var(--bg-2));
    border-radius: var(--radius-2, 8px);
    border: 1px solid var(--line, currentColor);
}

.forge-recursive-form__children {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.forge-recursive-form__reorder {
    display: flex;
    gap: 2px;
    margin-top: 2px;
}

.forge-recursive-form__reorder-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 16px;
    border: 0;
    background: transparent;
    color: var(--text-t3, var(--fg-3));
    cursor: pointer;
    border-radius: 3px;
}
.forge-recursive-form__reorder-btn:hover:not(:disabled) {
    background: var(--surface-s2, var(--bg-2));
    color: var(--text-t1, var(--fg-1));
}
.forge-recursive-form__reorder-btn:disabled {
    opacity: 0.3;
    cursor: not-allowed;
}

@media (prefers-reduced-motion: reduce) {
    .forge-recursive-form__row,
    .forge-recursive-form__actions,
    .forge-recursive-form__action {
        transition: none;
    }
}

/* ---- ForgeVariantPicker — inline pick-one-of-N ---- */
.forge-variant-picker {
    display: flex;
    flex-direction: column;
    gap: var(--gap-2, 8px);
}

.forge-variant-picker__label {
    font-size: var(--typography-scale-xs, 11px);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-t3, var(--fg-3));
    font-weight: 600;
}

.forge-variant-picker__options {
    display: flex;
    gap: var(--gap-2, 8px);
}
.forge-variant-picker--horizontal .forge-variant-picker__options {
    flex-direction: row;
    flex-wrap: wrap;
}
.forge-variant-picker--vertical .forge-variant-picker__options {
    flex-direction: column;
}

.forge-variant-picker__option {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: var(--gap-2, 8px);
    padding: 8px 12px;
    border: 1px solid var(--line, var(--line-strong, currentColor));
    border-radius: var(--radius-2, 8px);
    background: var(--surface-elevated, var(--bg-1));
    cursor: pointer;
    transition: border-color var(--motion-durationFast, 150ms) var(--motion-easing, ease),
                background var(--motion-durationFast, 150ms) var(--motion-easing, ease),
                box-shadow var(--motion-durationFast, 150ms) var(--motion-easing, ease);
    min-width: 0;
}
.forge-variant-picker--vertical .forge-variant-picker__option {
    width: 100%;
}

.forge-variant-picker__option:hover:not(.is-disabled) {
    border-color: var(--accent-base, var(--accent));
}
.forge-variant-picker__option.is-selected {
    border-color: var(--accent-base, var(--accent));
    background: color-mix(in oklab, var(--accent-base, var(--accent)) 10%, var(--surface-elevated, transparent));
    box-shadow: 0 0 0 1px var(--accent-base, var(--accent));
}
.forge-variant-picker__option.is-disabled {
    opacity: 0.55;
    cursor: not-allowed;
    border-style: dashed;
}

.forge-variant-picker__native {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}
.forge-variant-picker__native:focus-visible + .forge-variant-picker__swatch,
.forge-variant-picker__native:focus-visible + .forge-variant-picker__icon,
.forge-variant-picker__native:focus-visible ~ .forge-variant-picker__option-body {
    outline: 2px solid var(--accent-base, var(--accent));
    outline-offset: 2px;
}

.forge-variant-picker__swatch {
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    border: 1px solid var(--line, currentColor);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, currentColor 10%, transparent);
}

.forge-variant-picker__icon {
    flex-shrink: 0;
    display: inline-flex;
    color: var(--text-t2, var(--fg-2));
}

.forge-variant-picker__option-body {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}

.forge-variant-picker__option-label {
    font-weight: 600;
    color: var(--text-t1, var(--fg-1));
    word-break: break-word;
}

.forge-variant-picker__option-description {
    font-size: var(--typography-scale-xs, 11px);
    color: var(--text-t3, var(--fg-3));
}

.forge-variant-picker__option-check {
    display: inline-flex;
    margin-left: auto;
    color: var(--accent-base, var(--accent));
}

@media (prefers-reduced-motion: reduce) {
    .forge-variant-picker__option {
        transition: none;
    }
}
:root[data-effects="minimal"] .forge-variant-picker__option.is-selected {
    box-shadow: none;
}

/* ---- ForgeStat: MOVED to DataDisplay/ForgeStat.razor.css ---- *
 * Canonical CSS isolation pilot — see docs/ai/bundle-size-and-tree-shaking.md
 * Strategy B. Consumer's bundle only ships .forge-stat selectors when
 * ForgeStat is referenced from a page. Apply the same migration playbook
 * to other component-private selectors as they're touched for any reason
 * (visual bug, theme respect, responsive fix). After 6 months this file
 * shrinks organically to the genuinely-global vocabulary (form field row
 * layout, table grid layout, page chrome). */

/* ---- ForgeSnackbar — viewport-anchored transient status overlay ---- */
.forge-snackbar {
    position: fixed;
    z-index: 1100;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px 12px 16px;
    min-width: 280px;
    max-width: min(560px, calc(100vw - 32px));
    background: var(--surface-elevated, var(--bg-1));
    color: var(--text-t1, var(--fg-1));
    border: 1px solid var(--line-strong, var(--fg-3, currentColor));
    border-left-width: 4px;
    border-radius: 10px;
    box-shadow: var(--shadow-lg, 0 10px 30px rgba(0, 0, 0, 0.16));
    animation: forge-snackbar-in var(--motion-durationBase, 200ms) var(--motion-easing, ease) forwards;
}

/* Entrance for edge-anchored variants (bottom-right / top-right): slide + fade. */
@keyframes forge-snackbar-in {
    from { opacity: 0; transform: translateY(8px) scale(0.98); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* Entrance for the horizontally-CENTERED variants. The keyframe MUST carry the
   `translateX(-50%)` centering in BOTH states — an animation with `forwards`
   overrides the position class's static `transform`, so a keyframe without
   translateX would clobber the centering and shove the snackbar off to the
   right (where the showcase stage's container-type clip then hides it — which
   is why the TopCenter demo appeared to "show nothing"). */
@keyframes forge-snackbar-in-center {
    from { opacity: 0; transform: translateX(-50%) translateY(8px) scale(0.98); }
    to   { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
}

:root[data-motion="reduced"] .forge-snackbar,
:root:not([data-motion="full"]) .forge-snackbar {
    animation: none;
}
@media (prefers-reduced-motion: reduce) {
    :root:not([data-motion="full"]) .forge-snackbar {
        animation: none;
    }
}

.forge-snackbar--bottom-center {
    bottom: 24px;
    left: 50%;
    transform: translateX(-50%);
}
.forge-snackbar--bottom-right {
    bottom: 24px;
    right: 24px;
}
.forge-snackbar--top-center {
    top: 24px;
    left: 50%;
    transform: translateX(-50%);
}
.forge-snackbar--top-right {
    top: 24px;
    right: 24px;
}

/* Centered variants animate with the centering-preserving keyframe so the
   animation's `forwards` final state keeps translateX(-50%) (see note above). */
.forge-snackbar--bottom-center,
.forge-snackbar--top-center {
    animation-name: forge-snackbar-in-center;
}

.forge-snackbar__body {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 1 1 auto;
    min-width: 0;
}

.forge-snackbar__message {
    flex: 1 1 auto;
    min-width: 0;
    line-height: 1.4;
    word-break: break-word;
}

.forge-snackbar__actions {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
}

.forge-snackbar__close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border: 0;
    background: transparent;
    color: var(--text-t3, var(--fg-3));
    cursor: pointer;
    border-radius: 6px;
    padding: 0;
}
.forge-snackbar__close:hover {
    background: var(--surface-s2, var(--bg-2));
    color: var(--text-t1, var(--fg-1));
}
.forge-snackbar__close:focus-visible {
    outline: 2px solid var(--accent-base, var(--accent));
    outline-offset: 2px;
}

/* Severity colour bars — left border + icon colour. */
.forge-snackbar--success {
    border-left-color: var(--ok, #10b981);
}
.forge-snackbar--success .forge-snackbar__body > svg,
.forge-snackbar--success .forge-snackbar__body i {
    color: var(--ok, #10b981);
}
.forge-snackbar--warning {
    border-left-color: var(--warn, #f59e0b);
}
.forge-snackbar--danger {
    border-left-color: var(--bad, #ef4444);
}
.forge-snackbar--info {
    border-left-color: var(--info, #3b82f6);
}
.forge-snackbar--neutral {
    border-left-color: var(--line-strong, var(--fg-3, currentColor));
}

