/* ==========================================================================
   Let's Get Fit — Design System
   Implements "Let's Get Fit SaaS UI/UX Guidelines":
   "Modern Minimalist with Luxury Accents" — stark black/white/gray punctuated
   by the brand's signature metallic gold, taken from the logo.

   Two themes: Light = "Studio Bright" (default), Dark = "Midnight Iron".
   Theme is selected by [data-theme] on <html>; with no explicit choice we
   follow the OS via prefers-color-scheme.

   The doc-specified variables below are the SOURCE OF TRUTH. The --color-*
   aliases further down exist so pre-existing markup picks up the new palette
   without being rewritten. Prefer the doc names in new code.
   ========================================================================== */
:root {
    /* ---- Light Mode: "Studio Bright" ---- */
    --bg-base:        #FAFAFA;
    --bg-surface:     #FFFFFF;
    --bg-elevated:    #FFFFFF;
    --bg-input:       #F4F4F5;
    --bg-secondary-action: #F4F4F5;

    --text-primary:   #111111;
    --text-secondary: #5E636E;
    --text-inverse:   #FFFFFF;

    --brand-gold:       #D4AF37;
    --brand-gold-hover: #B8962B;
    --brand-gold-soft:  rgba(212, 175, 55, 0.12);
    --brand-gold-ring:  rgba(212, 175, 55, 0.28);

    --action-primary:      #1A1A1A;
    --action-primary-text: #FFFFFF;

    /* Foreground for anything sitting on a GOLD fill. Gold is light in both themes,
       so this stays near-black in both — do not swap it for --action-primary-text,
       which is white in light mode and would fail contrast on gold. */
    --on-gold: #14110A;

    /* Foreground for anything sitting on a --status-* fill. Unlike gold, the status
       colours are dark in light mode and light in dark mode, so this one flips. */
    --on-status: #FFFFFF;

    /* Count badges hold one red across both themes: it is the darkest red that still
       reads as red on the dark surface while clearing 4.5:1 against white at 10px. */
    --badge-danger-bg: #C62828;

    /* Danger tints, so error surfaces don't hardcode rgba(255,82,82,...) */
    --danger-soft: rgba(198, 40, 40, 0.08);
    --danger-ring: rgba(198, 40, 40, 0.22);

    --border-subtle: #EBEBEB;
    --border-strong: #D1D1D1;

    --status-success: #2E7D32;
    --status-warning: #F57F17;
    --status-error:   #C62828;

    /* Mobile chrome offsets (web ↔ Android parity — MOBILE_UX_PARITY.md) */
    --mobile-nav-height: 0px;
    --sticky-cta-bottom: 12px;

    --shadow-sm: 0 1px 3px rgba(0,0,0,0.05), 0 1px 2px rgba(0,0,0,0.03);
    --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.05), 0 2px 4px -1px rgba(0,0,0,0.03);
    --shadow-lg: 0 10px 25px -5px rgba(0,0,0,0.1), 0 8px 10px -6px rgba(0,0,0,0.05);
    --shadow-hover: 0 8px 16px rgba(0,0,0,0.1);
    --card-border-width: 1px;

    --radius-sm: 4px;
    --radius-md: 8px;
    --radius-lg: 12px;

    /* Motion: quick start, elegant deceleration. 200-300ms only. */
    --ease-snappy: cubic-bezier(0.2, 0.8, 0.2, 1);
    --transition-snappy: 200ms cubic-bezier(0.2, 0.8, 0.2, 1);

    --font-ui: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-display: 'Playfair Display', Georgia, serif;

    /* ---------------------------------------------------------------
       Back-compat aliases. Older views were written against these.
       --------------------------------------------------------------- */
    --color-bg:             var(--bg-base);
    --color-surface:        var(--bg-surface);
    --color-surface-2:      var(--bg-secondary-action);
    --color-surface-hover:  var(--bg-secondary-action);
    --color-surface-active: var(--border-subtle);

    --color-primary:            var(--brand-gold);
    --color-primary-dark:       var(--brand-gold-hover);
    --color-primary-glow:       var(--brand-gold-soft);
    --color-primary-glow-strong:var(--brand-gold-ring);
    --color-accent:             var(--brand-gold-hover);

    --color-danger:       var(--status-error);
    --color-danger-hover: #A81E1E;
    --color-warning:      var(--status-warning);
    --color-info:         #0A5C8A;

    --color-text:       var(--text-primary);
    --color-text-muted: var(--text-secondary);
    --color-text-dim:   #7A7F89;
    --color-border:       var(--border-subtle);
    --color-border-hover: var(--border-strong);

    --focus-ring: 0 0 0 3px var(--brand-gold-ring);

    --spacing-xs: 4px;
    --spacing-sm: 8px;
    --spacing-md: 16px;
    --spacing-lg: 24px;
    --spacing-xl: 40px;
    --spacing-xxl: 64px;

    --radius-xs: 4px;
    --radius-xl: 16px;
    --radius-full: 9999px;

    --shadow-glow: 0 0 15px var(--brand-gold-ring);
    --font-family: var(--font-ui);
    --transition:      var(--transition-snappy);
    --transition-slow: 300ms var(--ease-snappy);
}

/* Explicit user choice wins in both directions. */
:root[data-theme="dark"] {
    --bg-base:        #0A0A0B;
    --bg-surface:     #18181A;
    --bg-elevated:    #222225;
    --bg-input:       #222225;
    --bg-secondary-action: #2A2A2E;

    --text-primary:   #F3F4F6;
    --text-secondary: #9CA3AF;
    --text-inverse:   #0A0A0B;

    --brand-gold:       #E3C258;
    --brand-gold-hover: #F0D679;
    --brand-gold-soft:  rgba(227, 194, 88, 0.14);
    --brand-gold-ring:  rgba(227, 194, 88, 0.32);

    --action-primary:      var(--brand-gold);
    --action-primary-text: #0A0A0B;

    --border-subtle: #2D2D30;
    --border-strong: #3F3F46;

    --status-success: #4CAF50;
    --status-warning: #FFB300;
    --status-error:   #EF5350;

    /* Status fills are light here, so white on them fails AA — flip to near-black. */
    --on-status: #0A0A0B;

    --danger-soft: rgba(239, 83, 80, 0.12);
    --danger-ring: rgba(239, 83, 80, 0.28);

    --shadow-sm: none;
    --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.3);
    --shadow-lg: 0 10px 25px -5px rgba(0,0,0,0.5);
    --shadow-hover: 0 0 15px rgba(227, 194, 88, 0.3);

    --color-text-dim:     #6B7280;
    --color-danger-hover: #FF6B6B;
    --color-info:         #40C4FF;
}

/* No explicit choice -> follow the OS. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]):not([data-theme="dark"]) {
        --bg-base:        #0A0A0B;
        --bg-surface:     #18181A;
        --bg-elevated:    #222225;
        --bg-input:       #222225;
        --bg-secondary-action: #2A2A2E;

        --text-primary:   #F3F4F6;
        --text-secondary: #9CA3AF;
        --text-inverse:   #0A0A0B;

        --brand-gold:       #E3C258;
        --brand-gold-hover: #F0D679;
        --brand-gold-soft:  rgba(227, 194, 88, 0.14);
        --brand-gold-ring:  rgba(227, 194, 88, 0.32);

        --action-primary:      var(--brand-gold);
        --action-primary-text: #0A0A0B;

        --border-subtle: #2D2D30;
        --border-strong: #3F3F46;

        --status-success: #4CAF50;
        --status-warning: #FFB300;
        --status-error:   #EF5350;

        --on-status: #0A0A0B;

        --danger-soft: rgba(239, 83, 80, 0.12);
        --danger-ring: rgba(239, 83, 80, 0.28);

        --shadow-sm: none;
        --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.3);
        --shadow-lg: 0 10px 25px -5px rgba(0,0,0,0.5);
        --shadow-hover: 0 0 15px rgba(227, 194, 88, 0.3);

        --color-text-dim:     #6B7280;
        --color-danger-hover: #FF6B6B;
        --color-info:         #40C4FF;
    }
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html {
    scroll-behavior: smooth;
    overflow-x: hidden;
}

body {
    background: var(--color-bg);
    color: var(--color-text);
    font-family: var(--font-family);
    font-size: 15px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    overflow-x: hidden;
}

/* ==========================================================================
   Typography — hierarchy per the design guidelines
   H1 32/40 Semi-Bold, tracking -1%   H2 24/32 Medium
   Body 15/24 Regular                 Micro 12/16 Medium, uppercase, +1.5px
   ========================================================================== */
h1, h2, h3, h4, h5, h6 { color: var(--text-primary); }

h1 {
    font-size: 32px;
    line-height: 40px;
    font-weight: 600;
    letter-spacing: -0.01em;
    margin-bottom: var(--spacing-md);
}
h2 {
    font-size: 24px;
    line-height: 32px;
    font-weight: 500;
    letter-spacing: -0.01em;
    margin-bottom: var(--spacing-md);
}
h3 { font-size: 19px; line-height: 28px; font-weight: 600; margin-bottom: var(--spacing-sm); }
h4 { font-size: 16px; line-height: 24px; font-weight: 600; margin-bottom: var(--spacing-sm); }
h5 { font-size: 15px; line-height: 22px; font-weight: 600; margin-bottom: var(--spacing-xs); }

p { color: var(--color-text-muted); font-size: 15px; line-height: 24px; }

/* Micro labels — status badges, small section headers, table column heads. */
.micro,
.stat-tile-label,
.nav-section-label {
    font-size: 12px;
    line-height: 16px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    color: var(--color-text-muted);
}

/* Display face. Used SPARINGLY — hero text and marketing moments only,
   never for dense UI or data, per the guidelines. */
.display {
    font-family: var(--font-display);
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1.1;
    color: var(--text-primary);
}
.display-gold { color: var(--brand-gold); }

a {
    color: var(--color-primary);
    text-decoration: none;
    transition: var(--transition);
}
a:hover { color: var(--color-accent); }

img { max-width: 100%; display: block; }

/* Utilities */
.hidden { display: none !important; }
.text-center { text-align: center; }
.text-right { text-align: right; }
.text-muted { color: var(--color-text-muted) !important; }
.text-primary { color: var(--color-primary) !important; }
.text-danger { color: var(--color-danger) !important; }
.text-white { color: var(--text-primary) !important; }
.text-sm { font-size: 13px; }
.text-xs { font-size: 11px; }
.font-bold { font-weight: 700; }
.font-semibold { font-weight: 600; }

.flex { display: flex; }
.flex-col { flex-direction: column; }
.flex-wrap { flex-wrap: wrap; }
.flex-1 { flex: 1; }
.flex-grow { flex-grow: 1; }
.items-center { align-items: center; }
.items-start { align-items: flex-start; }
.items-end { align-items: flex-end; }
.items-stretch { align-items: stretch; }
.justify-between { justify-content: space-between; }
.justify-center { justify-content: center; }
.justify-end { justify-content: flex-end; }
.gap-xs { gap: var(--spacing-xs); }
.gap-sm { gap: var(--spacing-sm); }
.gap-md { gap: var(--spacing-md); }
.gap-lg { gap: var(--spacing-lg); }

.mt-xs { margin-top: var(--spacing-xs); }
.mt-sm { margin-top: var(--spacing-sm); }
.mt-md { margin-top: var(--spacing-md); }
.mt-lg { margin-top: var(--spacing-lg); }
.mt-xl { margin-top: var(--spacing-xl); }
.mb-xs { margin-bottom: var(--spacing-xs); }
.mb-sm { margin-bottom: var(--spacing-sm); }
.mb-md { margin-bottom: var(--spacing-md); }
.mb-lg { margin-bottom: var(--spacing-lg); }
.mb-xl { margin-bottom: var(--spacing-xl); }
.ml-auto { margin-left: auto; }
.cursor-pointer { cursor: pointer; }
.w-full { width: 100%; }
.overflow-hidden { overflow: hidden; }
.relative { position: relative; }
.absolute { position: absolute; }

/* Animations */
@keyframes fadeInUp {
    from { opacity: 0; transform: translateY(16px); }
    to { opacity: 1; transform: translateY(0); }
}
@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}
@keyframes spin {
    to { transform: rotate(360deg); }
}
@keyframes pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.4; }
}
@keyframes slideInRight {
    from { transform: translateX(100%); opacity: 0; }
    to { transform: translateX(0); opacity: 1; }
}
@keyframes slideInUp {
    from { transform: translateY(100%); opacity: 0; }
    to { transform: translateY(0); opacity: 1; }
}

.animate-in { animation: fadeInUp 0.4s ease forwards; }
.animate-fade { animation: fadeIn 0.3s ease forwards; }

/* Skeleton loaders */
.skeleton {
    background: linear-gradient(90deg, var(--color-surface) 25%, var(--color-surface-hover) 50%, var(--color-surface) 75%);
    background-size: 200% 100%;
    animation: skeleton-shimmer 1.5s infinite;
    border-radius: var(--radius-sm);
}
@keyframes skeleton-shimmer {
    0% { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

/* Toast Notifications */
.toast-container {
    position: fixed;
    bottom: 24px;
    right: 24px;
    z-index: 9999;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 10px;
    pointer-events: none;
}
.toast {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 14px 16px 14px 20px;
    border-radius: var(--radius-md);
    font-size: 14px;
    font-weight: 600;
    min-width: 280px;
    max-width: 420px;
    pointer-events: all;
    animation: slideInRight 0.3s var(--ease-snappy, cubic-bezier(0.2, 0.8, 0.2, 1));
    box-shadow: var(--shadow-lg);
}
.toast-icon { flex-shrink: 0; margin-top: 1px; }
.toast-body { flex: 1; min-width: 0; }
.toast-title {
    font-weight: 700;
    font-size: 13px;
    letter-spacing: 0.01em;
}
.toast-msg {
    font-size: 13px;
    font-weight: 500;
    line-height: 1.4;
    margin-top: 2px;
    /* Server messages can carry unbroken tokens (ids, urls) — never let them
       push the fill past the viewport. */
    overflow-wrap: anywhere;
}
.toast-close {
    flex-shrink: 0;
    width: 24px;
    height: 24px;
    margin: -2px -4px 0 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
    background: none;
    border-radius: var(--radius-sm);
    color: inherit;
    opacity: 0.7;
    cursor: pointer;
    transition: opacity var(--transition-snappy), background var(--transition-snappy);
}
.toast-close:hover { opacity: 1; background: rgba(127, 127, 127, 0.25); }
.toast-close:focus-visible { outline: 2px solid currentColor; outline-offset: 1px; opacity: 1; }
.toast.is-leaving {
    opacity: 0;
    transform: translateX(20px);
    transition: opacity 0.3s ease, transform 0.3s ease;
}
@media (max-width: 768px) {
    .toast-container {
        left: 16px;
        right: 16px;
        bottom: calc(var(--mobile-nav-height, 64px) + env(safe-area-inset-bottom, 0px) + 12px);
        align-items: stretch;
    }
    /* Auth pages pull in layout.css (so --mobile-nav-height is 64px) but render no
       bottom nav, which left toasts hovering above empty space. */
    body:not(:has(.mobile-bottom-nav)) .toast-container {
        bottom: calc(env(safe-area-inset-bottom, 0px) + 16px);
    }
    .toast {
        min-width: 0;
        max-width: none;
        width: 100%;
        animation: slideInUp 0.3s var(--ease-snappy, cubic-bezier(0.2, 0.8, 0.2, 1));
    }
    .toast.is-leaving { transform: translateY(12px); }
}
/* Solid semantic fills, no accent stripe — restrained per the design guidelines.
   --on-status flips white/near-black per theme because the fills invert too;
   hardcoded white failed AA on the lighter dark-mode fills. */
.toast-success { background: var(--status-success); color: var(--on-status); }
.toast-error   { background: var(--status-error);   color: var(--on-status); }
/* Warning is a light fill in BOTH themes, so it takes the same near-black
   foreground gold uses rather than the flipping one. */
.toast-warning { background: var(--status-warning); color: var(--on-gold); }
.toast-info    { background: var(--color-info);     color: var(--on-status); }

/* Loader */
.spinner {
    width: 24px;
    height: 24px;
    border: 2px solid rgba(255,255,255,0.15);
    border-top-color: var(--color-primary);
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
    display: inline-block;
}
.fullscreen-loader {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.6);
    backdrop-filter: blur(4px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 9998;
}

/* Slide Over / Modal — panel (default) + sheet (mobile short flows) */
.slide-over-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.6);
    backdrop-filter: blur(4px);
    z-index: 900;
    display: flex;
    align-items: stretch;
    justify-content: flex-end;
}
.slide-over-overlay.variant-sheet {
    align-items: flex-end;
    justify-content: stretch;
}
.slide-over {
    width: 100%;
    max-width: 520px;
    background: var(--color-surface);
    border-left: 1px solid var(--color-border);
    display: flex;
    flex-direction: column;
    animation: slideInRight 0.3s var(--ease-snappy, cubic-bezier(0.2, 0.8, 0.2, 1));
    overflow: hidden;
}
.slide-over.is-fullscreen {
    max-width: 100%;
    height: 100%;
    max-height: 100%;
    border-left: none;
    padding-top: env(safe-area-inset-top, 0px);
}
.slide-over.is-sheet {
    max-width: 100%;
    max-height: min(90dvh, 90vh);
    height: auto;
    border-left: none;
    border-radius: 16px 16px 0 0;
    animation: slideInUp 0.28s var(--ease-snappy, cubic-bezier(0.2, 0.8, 0.2, 1));
    padding-bottom: env(safe-area-inset-bottom, 0px);
}
.slide-over.is-sheet::before {
    content: '';
    display: block;
    width: 36px;
    height: 4px;
    border-radius: 2px;
    background: var(--border-strong);
    margin: 10px auto 0;
    flex-shrink: 0;
}
.slide-over-header {
    padding: 20px 24px;
    border-bottom: 1px solid var(--color-border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-shrink: 0;
    gap: 12px;
}
.slide-over.is-sheet .slide-over-header {
    padding: 12px 20px 16px;
}
.slide-over-header h3 {
    margin: 0;
    font-size: 18px;
}
.slide-over-body {
    flex: 1;
    overflow-y: auto;
    padding: 24px;
    -webkit-overflow-scrolling: touch;
}
.slide-over.is-sheet .slide-over-body {
    padding: 16px 20px 24px;
}
.mobile-search-results {
    margin-top: 12px;
    max-height: 50vh;
    overflow-y: auto;
}
.mobile-search-results a {
    display: block;
    padding: 12px 4px;
    text-decoration: none;
    border-bottom: 1px solid var(--color-border);
}
/* Floating surface shared by the topbar notification bell and global search.
   Both are absolutely positioned over page content, so without an opaque fill
   the content behind them shows straight through. */
.dropdown-panel {
    background: var(--bg-elevated);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    overflow: hidden;
}

.dropdown-panel.notification-panel {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 1000;
    padding: 0;
    /* The panel is anchored to the bell, not the viewport, so its own width has
       to fit in the space to the LEFT of the bell or it hangs off-screen. */
    width: min(340px, calc(100vw - 24px));
    max-height: min(70vh, 440px);
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
}

.notification-panel-header {
    position: sticky;
    top: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 16px;
    background: var(--bg-elevated);
    border-bottom: 1px solid var(--color-border);
    font-size: 14px;
    font-weight: 600;
}
.notification-panel-header .btn {
    padding: 0;
    font-size: 12px;
    min-height: 0;
}

@media (max-width: 768px) {
    /* Anchoring to the bell puts a 340px panel off the left edge on a 390px
       screen, so on mobile it detaches and spans the viewport instead. */
    .dropdown-panel.notification-panel {
        position: fixed;
        top: calc(56px + env(safe-area-inset-top, 0px) + 6px);
        left: 12px;
        right: 12px;
        width: auto;
        max-height: calc(100dvh - 56px - env(safe-area-inset-top, 0px) - var(--mobile-nav-height, 64px) - env(safe-area-inset-bottom, 0px) - 24px);
    }
}

/* Badges */
.badge {
    display: inline-flex;
    align-items: center;
    padding: 3px 10px;
    border-radius: var(--radius-full);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.4px;
    text-transform: uppercase;
}
/* Count pill used for unread chat/notification totals. Sized from its own line-box
   so a 1-digit and a 2-digit count both stay circular-ish rather than collapsing. */
.badge-pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: var(--radius-full);
    font-size: 10px;
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.bg-danger { background: var(--badge-danger-bg); color: #FFFFFF; }

/* Anchored to the top-right corner of an icon button. */
.badge-count {
    position: absolute;
    top: 2px;
    right: 2px;
    /* Lifts the pill off the icon strokes it overlaps. */
    box-shadow: 0 0 0 2px var(--bg-base);
}

.badge-primary { background: var(--color-primary-glow); color: var(--color-primary); }
.badge-secondary { background: rgba(255,255,255,0.06); color: var(--color-text-muted); }
.badge-danger { background: rgba(255,82,82,0.15); color: var(--color-danger); }
.badge-warning { background: rgba(255,171,64,0.15); color: var(--color-warning); }
.badge-info { background: rgba(64,196,255,0.15); color: var(--color-info); }

/* Avatar */
.avatar {
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
    border: 2px solid var(--color-border);
}
.avatar-sm { width: 28px; height: 28px; }
.avatar-md { width: 36px; height: 36px; }
.avatar-lg { width: 48px; height: 48px; }
.avatar-xl { width: 80px; height: 80px; }

/* Section divider */
.divider {
    height: 1px;
    background: var(--color-border);
    margin: var(--spacing-lg) 0;
}

/* Stat tiles */
.stat-tile {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--spacing-lg);
}
.stat-tile-value {
    font-size: 36px;
    font-weight: 800;
    color: var(--text-primary);
    line-height: 1;
}
.stat-tile-label {
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.8px;
    color: var(--color-text-muted);
    margin-top: 4px;
}

/* Empty state */
.empty-state {
    text-align: center;
    padding: 60px 24px;
    color: var(--color-text-muted);
}
.empty-state svg { opacity: 0.3; margin: 0 auto 16px; }
.empty-state h3 { color: var(--color-text-muted); font-size: 18px; }

/* ==========================================================================
   Accessibility baseline
   ========================================================================== */

/* Visible keyboard focus everywhere. Mouse users don't see it (:focus-visible),
   keyboard users always do. Nothing may remove this without a replacement. */
:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
    border-radius: var(--radius-xs);
}
a:focus-visible,
button:focus-visible,
[role="button"]:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: var(--focus-ring);
}

/* Skip-link target / screen-reader-only text */
.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* Respect the OS "reduce motion" setting app-wide. */
@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
    .spinner { animation-duration: 0.7s !important; }
}
