/* ===========================================================================
   OpenImpact.Horizon — canonical Sealed Horizon layout engine.
   Load order contract: tokens.css, then base.css, then the app stylesheet.
   Distilled from kora-base.css plus the hand-written patterns in Selo,
   Suara and Aprende. Every value below is a canonical token reference —
   no hardcoded colours, radii, shadows or durations belong in this file.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   1. Reset, typography, container
   --------------------------------------------------------------------------- */

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

html, body {
    margin: 0;
    padding: 0;
}

body {
    font-family: var(--font-sans);
    background: var(--bg);
    color: var(--ink);
    line-height: var(--line-height);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

/* Links carry no underline by default — the browser's UA stylesheet adds one,
   and a bare `color` rule leaves it in place. Standalone links (nav items,
   cards, actions) read as links from context and position.

   .prose a deliberately opts back in: WCAG 1.4.1 wants >= 3:1 against the
   surrounding text when colour is the only cue for a link inside a block of
   text, and --accent-strong against the dark-mode --ink is only 2.90:1. In
   running prose the underline is doing real work, not decoration. */
a {
    color: var(--accent-strong);
    text-decoration: none;
}

h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-sans);
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1.15;
    color: var(--ink);
    margin: 0 0 var(--space-3);
}

h1 { font-size: var(--text-2xl); }
h2 { font-size: var(--text-xl); margin-top: var(--space-5); }
h3 { font-size: var(--text-lg); margin-top: var(--space-4); }
h4, h5, h6 { font-size: var(--text-base); margin-top: var(--space-3); }

h1:focus { outline: none; }

/* A centred content column with responsive padding. */
.container {
    width: 100%;
    max-width: 66rem;
    margin-inline: auto;
    padding-inline: var(--space-4);
    padding-block: var(--space-section);
}

@media (min-width: 768px) {
    .container { padding-inline: var(--space-5); }
}

@media (min-width: 1024px) {
    .container { padding-inline: var(--space-6); }
}

/* Comfortable reading width for prose-heavy content. */
.prose {
    max-width: var(--measure);
    font-size: var(--text-lg);
    line-height: var(--line-height);
}

.prose h1, .prose h2, .prose h3 {
    margin-top: var(--space-6);
}

.prose p {
    margin: 0 0 var(--space-4);
}

.prose a {
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-thickness: 1px;
}

/* ---- Blazor framework boilerplate (every app currently repeats this) ---- */

.valid.modified:not([type="checkbox"]) {
    outline: 1px solid var(--accent);
}

.invalid {
    outline: 1px solid var(--danger);
}

.validation-message {
    color: var(--danger);
    font-size: var(--text-sm);
}

.blazor-error-boundary {
    background: var(--danger);
    padding: var(--space-4) var(--space-5);
    color: #fff;
    border-radius: var(--radius-sm);
}

.blazor-error-boundary::after {
    content: "An error has occurred.";
}

#blazor-error-ui {
    display: none;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background: var(--surface);
    border-top: 1px solid var(--warn);
    color: var(--ink);
    padding: var(--space-3) var(--space-5);
    box-shadow: var(--shadow-float);
    z-index: 1000;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    float: right;
}

/* ---------------------------------------------------------------------------
   2. Buttons
   --------------------------------------------------------------------------- */

/* The pill controls (.btn, .status-pill, .page-tabs a) carry deliberately
   off-grid optical padding. These are not scale leaks — snapping them to
   --space-* would visibly resize every button in the system. Leave them. */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: 0.62rem 1.25rem;
    border: 1px solid transparent;
    border-radius: var(--radius-pill);
    font: inherit;
    font-weight: 600;
    text-decoration: none;
    text-align: center;
    cursor: pointer;
    transition: transform var(--dur-fast) var(--ease),
                box-shadow var(--dur-fast) ease,
                background var(--dur-fast) ease,
                border-color var(--dur-fast) ease,
                color var(--dur-fast) ease;
}

.btn:active {
    transform: scale(0.98);
}

.btn[disabled],
.btn.is-disabled {
    opacity: 0.5;
    pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
    .btn:hover {
        transform: translateY(-1px);
    }
}

@media (prefers-reduced-motion: reduce) {
    .btn:active {
        transform: none;
    }
}

.btn-primary {
    background: var(--accent);
    color: #fff;
}

.btn-primary:hover {
    background: var(--accent-strong);
}

.btn-secondary {
    background: var(--accent-soft);
    color: var(--accent-strong);
}

.btn-secondary:hover {
}

.btn-ghost {
    background: transparent;
    color: var(--ink);
    border-color: var(--line);
}

.btn-ghost:hover {
    background: var(--surface-sunk);
}

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

.btn-danger:hover {
    filter: brightness(0.92);
}

/* ---------------------------------------------------------------------------
   3. Forms
   --------------------------------------------------------------------------- */

.field {
    margin-bottom: var(--space-4);
}

.field > label,
label {
    display: block;
    margin-bottom: var(--space-2);
    font-weight: 600;
    font-size: var(--text-sm);
    color: var(--ink);
}

input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="submit"]):not([type="button"]):not([type="file"]),
select,
textarea {
    display: block;
    width: 100%;
    box-sizing: border-box;
    padding: var(--space-3);
    font: inherit;
    color: var(--ink);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    transition: border-color var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}

input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="submit"]):not([type="button"]):not([type="file"]):focus,
select:focus,
textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-glow);
}

input:disabled,
select:disabled,
textarea:disabled {
    background: var(--surface-sunk);
    color: var(--muted);
    cursor: not-allowed;
    opacity: 0.7;
}

textarea {
    min-height: 6rem;
    resize: vertical;
}

.help {
    display: block;
    margin-top: var(--space-1);
    font-size: var(--text-sm);
    color: var(--muted);
}

.help.is-danger {
    color: var(--danger);
}

/* ---------------------------------------------------------------------------
   4. Grid and spacing helpers
   --------------------------------------------------------------------------- */

.grid-cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
    gap: var(--space-4);
}

.stack {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.stack.gap-2 { gap: var(--space-2); }
.stack.gap-4 { gap: var(--space-4); }
.stack.gap-6 { gap: var(--space-6); }

.cluster {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
}

/* ---------------------------------------------------------------------------
   5. Structural patterns
   --------------------------------------------------------------------------- */

/* Card */

.card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    overflow: hidden;
}

.card-header {
    display: flex;
    align-items: stretch;
    border-bottom: 1px solid var(--line-subtle);
}

.card-header-title {
    display: flex;
    align-items: center;
    flex-grow: 1;
    padding: var(--space-4) var(--space-5);
    font-weight: 700;
    color: var(--ink);
}

.card-header-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4) var(--space-5);
    cursor: pointer;
}

.card-content {
    padding: var(--space-5);
}

.card-footer {
    display: flex;
    align-items: stretch;
    border-top: 1px solid var(--line);
}

.card-footer-item {
    display: flex;
    flex: 1 1 0;
    align-items: center;
    justify-content: center;
    padding: var(--space-3);
}

.card-footer-item:not(:last-child) {
    border-right: 1px solid var(--line);
}

/* Masthead: sticky glass bar. color-mix derives the translucent glass tint
   from --surface at request time, so it works for any surface colour a
   consumer's theme sets (including dark mode), not just white. */

.masthead {
    position: sticky;
    top: 0;
    z-index: 10;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-3) var(--space-5);
    background: color-mix(in srgb, var(--surface) 82%, transparent);
    backdrop-filter: saturate(160%) blur(16px);
    -webkit-backdrop-filter: saturate(160%) blur(16px);
    border-bottom: 1px solid var(--line-subtle);
}

/* Shell: sidebar-plus-content admin layout, collapsing to a horizontal
   scrolling top bar under 768px. */

.shell {
    display: flex;
    min-height: 100vh;
}

.shell-sidebar {
    flex: 0 0 15rem;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-5) var(--space-3);
    background: var(--surface);
    border-right: 1px solid var(--line-subtle);
}

.shell-main {
    flex: 1 1 auto;
    min-width: 0;
    padding: var(--space-6) var(--space-5);
}

@media (max-width: 768px) {
    .shell {
        flex-direction: column;
    }

    .shell-sidebar {
        flex: 0 0 auto;
        width: 100%;
        flex-direction: row;
        overflow-x: auto;
        position: sticky;
        top: 0;
        z-index: 6;
        border-right: 0;
        border-bottom: 1px solid var(--line-subtle);
        background: color-mix(in srgb, var(--surface) 82%, transparent);
        backdrop-filter: saturate(160%) blur(16px);
        -webkit-backdrop-filter: saturate(160%) blur(16px);
    }

    .shell-main {
        padding: var(--space-5) var(--space-4);
    }
}

/* Table */

.table {
    width: 100%;
    border-collapse: collapse;
}

.table th,
.table td {
    padding: var(--space-3) var(--space-4);
    text-align: left;
    border-bottom: 1px solid var(--line-subtle);
}

.table th {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.table tbody tr:hover {
    background: var(--surface-sunk);
}

/* Modal scrim and slide-over scaffolding, geometry ported from Suara's
   SlideOver.razor.css. See "Flagged discrepancy for Phase 3" in
   docs/superpowers/plans/2026-07-05-horizon-phase-2-base-css.md before
   wiring the Blazor SlideOver component (Task 3.9) to these classes. */

.modal-scrim {
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, 0.42);
    z-index: 60;
}

.slide-over {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(30rem, 100%);
    background: var(--surface);
    border-left: 1px solid var(--line);
    z-index: 61;
    display: flex;
    flex-direction: column;
    outline: none;
}

.slide-over-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid var(--line);
    flex: 0 0 auto;
}

.slide-over-title {
    margin: 0;
    font-size: var(--text-lg);
}

.slide-over-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border: none;
    background: none;
    color: var(--muted);
    cursor: pointer;
    border-radius: var(--radius-sm);
}

.slide-over-close:hover {
    background: var(--surface-sunk);
    color: var(--ink);
}

.slide-over-body {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: var(--space-5);
}

.slide-over-foot {
    flex: 0 0 auto;
    padding: var(--space-4) var(--space-5);
    border-top: 1px solid var(--line);
    display: flex;
    gap: var(--space-3);
    justify-content: flex-end;
}

@media (prefers-reduced-motion: no-preference) {
    .slide-over {
        animation: horizon-slide-over-in var(--dur-slow) var(--ease);
    }

    .modal-scrim {
        animation: horizon-slide-over-fade var(--dur-slow) ease;
    }
}

@keyframes horizon-slide-over-in {
    from { transform: translateX(2rem); opacity: 0.6; }
    to { transform: translateX(0); opacity: 1; }
}

@keyframes horizon-slide-over-fade {
    from { opacity: 0; }
    to { opacity: 1; }
}

@media (max-width: 768px) {
    .slide-over {
        width: 100%;
        border-left: none;
    }
}

/* Status pill */

.status-pill {
    display: inline-block;
    padding: 0.2rem 0.65rem;
    border-radius: var(--radius-pill);
    background: var(--accent-soft);
    color: var(--accent-strong);
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

/* Empty state */

.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--space-3);
    padding: var(--space-8) var(--space-4);
    color: var(--muted);
}

.empty-state-icon {
    color: var(--line);
}

.empty-state-message {
    margin: 0;
    max-width: var(--measure);
}

.empty-state-action {
    margin-top: var(--space-2);
}

/* Progress bar */

.progress {
    height: var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--surface-sunk);
    overflow: hidden;
}

.progress-fill {
    height: 100%;
    background: var(--accent);
    border-radius: var(--radius-pill);
    transition: width var(--dur-slow) var(--ease);
}

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

/* Metric card and summary cards. auto-fit/11rem match Suara's own values
   exactly (this component is sourced from Suara specifically), which is
   deliberately different from the generic .grid-cards primitive above
   (auto-fill/16rem). */

.summary-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: var(--space-4);
}

.metric-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-4);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
}

.metric-label {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--muted);
}

.metric-value {
    font-size: var(--text-xl);
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--accent-strong);
    font-variant-numeric: tabular-nums;
}

.metric-detail {
    font-size: var(--text-sm);
    color: var(--muted);
}

/* Page header */

.page-header {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding-bottom: var(--space-2);
    margin-bottom: var(--space-section);
    border-bottom: 1px solid var(--line);
}

.page-breadcrumb {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    font-size: var(--text-sm);
    color: var(--muted);
}

.page-breadcrumb a {
    color: var(--muted);
}

.page-breadcrumb a:hover {
    color: var(--accent);
}

.page-header-row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
}

.page-header-titles {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
}

.page-title {
    margin: 0;
}

.page-header-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.page-tabs {
    display: flex;
    gap: var(--space-1);
    flex-wrap: wrap;
}

.page-tabs a {
    padding: 0.4rem 0.7rem;
    border-radius: var(--radius-pill);
    color: var(--muted);
    text-decoration: none;
    font-size: var(--text-sm);
}

.page-tabs a:hover {
    background: var(--surface-sunk);
    color: var(--ink);
}

.page-tabs a.active {
    background: var(--accent-soft);
    color: var(--accent-strong);
    font-weight: 600;
}

/* ---------------------------------------------------------------------------
   6. Avatar
   --------------------------------------------------------------------------- */

.avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    border-radius: var(--radius-pill);
    color: #fff;
    font-weight: 700;
    letter-spacing: 0.01em;
    user-select: none;
    overflow: hidden;
}

.avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.avatar-sm { width: 1.75rem; height: 1.75rem; font-size: var(--text-xs); }
.avatar-md { width: 2.25rem; height: 2.25rem; font-size: var(--text-sm); }
.avatar-lg { width: 3.5rem; height: 3.5rem; font-size: var(--text-lg); }

/* A small, brand-neutral palette so avatars for different people are visually
   distinguishable (Avatar.razor picks one deterministically from a name
   hash). These are fixed implementation-detail hues, not a themeable
   surface, so they live here rather than in tokens.css. */
.avatar-hue-0 { background: #0F766E; }
.avatar-hue-1 { background: #7C3AED; }
.avatar-hue-2 { background: #C2410C; }
.avatar-hue-3 { background: #BE123C; }
.avatar-hue-4 { background: #0369A1; }
.avatar-hue-5 { background: #4D7C0F; }

/* ---------------------------------------------------------------------------
   7. Alert
   --------------------------------------------------------------------------- */

.alert {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-4) var(--space-5);
    border-radius: var(--radius-md);
    border: 1px solid transparent;
}

.alert-icon {
    display: flex;
    flex: 0 0 auto;
    margin-top: 0.15rem;
}

.alert-body {
    flex: 1 1 auto;
    min-width: 0;
}

.alert-title {
    margin: 0 0 var(--space-1);
    font-weight: 700;
}

.alert-message {
    margin: 0;
}

.alert-dismiss {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    cursor: pointer;
    padding: var(--space-1);
    border-radius: var(--radius-sm);
    color: inherit;
    opacity: 0.7;
}

.alert-dismiss:hover {
    opacity: 1;
    background: rgba(0, 0, 0, 0.06);
}

.alert-info {
    background: var(--surface-sunk);
    border-color: var(--line);
    color: var(--ink);
}

.alert-success {
    background: color-mix(in srgb, var(--ok) 8%, var(--surface));
    border-color: color-mix(in srgb, var(--ok) 25%, transparent);
    color: var(--ok);
}

.alert-warning {
    background: color-mix(in srgb, var(--warn) 8%, var(--surface));
    border-color: color-mix(in srgb, var(--warn) 25%, transparent);
    color: var(--warn);
}

.alert-danger {
    background: color-mix(in srgb, var(--danger) 8%, var(--surface));
    border-color: color-mix(in srgb, var(--danger) 25%, transparent);
    color: var(--danger);
}

/* ---------------------------------------------------------------------------
   8. Tooltip
   --------------------------------------------------------------------------- */

.tooltip-wrapper {
    position: relative;
    display: inline-flex;
}

.tooltip-bubble {
    position: absolute;
    z-index: 40;
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-sm);
    background: var(--ink);
    color: var(--surface);
    font-size: var(--text-xs);
    line-height: 1.4;
    white-space: nowrap;
    box-shadow: var(--shadow-float);
    pointer-events: none;
}

.tooltip-top {
    bottom: calc(100% + 0.4rem);
    left: 50%;
    transform: translateX(-50%);
}

.tooltip-bottom {
    top: calc(100% + 0.4rem);
    left: 50%;
    transform: translateX(-50%);
}

.tooltip-left {
    right: calc(100% + 0.4rem);
    top: 50%;
    transform: translateY(-50%);
}

.tooltip-right {
    left: calc(100% + 0.4rem);
    top: 50%;
    transform: translateY(-50%);
}

/* Section 9: Modal — centred dialog, sibling to slide-over above. Shares
   .modal-scrim as its backdrop; geometry here is new (slide-over is a
   side panel, modal is a centred card). */

.modal {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    max-height: calc(100vh - 4rem);
    background: var(--surface);
    border-radius: var(--radius-lg);
    z-index: 61;
    display: flex;
    flex-direction: column;
    outline: none;
}

.modal-sm { width: min(24rem, calc(100vw - 2rem)); }
.modal-md { width: min(32rem, calc(100vw - 2rem)); }
.modal-lg { width: min(48rem, calc(100vw - 2rem)); }

.modal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid var(--line);
    flex: 0 0 auto;
}

.modal-title {
    margin: 0;
    font-size: var(--text-lg);
}

.modal-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border: none;
    background: none;
    color: var(--muted);
    cursor: pointer;
    border-radius: var(--radius-sm);
}

.modal-close:hover {
    background: var(--surface-sunk);
    color: var(--ink);
}

.modal-body {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: var(--space-5);
}

.modal-foot {
    flex: 0 0 auto;
    padding: var(--space-4) var(--space-5);
    border-top: 1px solid var(--line);
    display: flex;
    gap: var(--space-3);
    justify-content: flex-end;
}

@media (prefers-reduced-motion: no-preference) {
    .modal {
        animation: horizon-modal-in var(--dur-slow) var(--ease);
    }
}

@keyframes horizon-modal-in {
    from { opacity: 0; transform: translate(-50%, -50%) scale(0.96); }
    to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

@media (max-width: 576px) {
    .modal-sm,
    .modal-md,
    .modal-lg {
        width: calc(100vw - 1.5rem);
    }

    .modal {
        max-height: calc(100vh - 3rem);
    }
}

/* Section 10: Toast — event-driven notification stack, rendered by
   ToastHost.razor. Fixed top-right stack; colour variants reuse the same
   solid-fill treatment as .badge rather than Alert's tinted-background
   treatment, since toasts sit on arbitrary page backgrounds. */

.toast-container {
    position: fixed;
    top: var(--space-4);
    right: var(--space-4);
    z-index: 70;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    max-width: 22rem;
}

.toast {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-float);
    background: var(--ink);
    color: var(--surface);
}

.toast-message {
    flex: 1 1 auto;
    font-size: var(--text-sm);
}

.toast-dismiss {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    cursor: pointer;
    padding: var(--space-1);
    color: inherit;
    opacity: 0.7;
}

.toast-dismiss:hover {
    opacity: 1;
}

.toast-success { background: var(--ok); }
.toast-warning { background: var(--warn); }
.toast-danger { background: var(--danger); }

@media (prefers-reduced-motion: no-preference) {
    .toast {
        animation: horizon-toast-in var(--dur-base) var(--ease);
    }
}

@keyframes horizon-toast-in {
    from { opacity: 0; transform: translateX(1rem); }
    to { opacity: 1; transform: translateX(0); }
}

@media (max-width: 576px) {
    .toast-container {
        left: var(--space-4);
        right: var(--space-4);
        max-width: none;
    }
}

/* Section 11: Tabs — underline-indicator style (not Kora's gradient-pill
   theming, which is decorative beyond Sealed Horizon's single-accent
   language). Tabs.razor cascades itself to TabItem children; each TabItem
   renders its own .tab-panel only when active. */

.tabs {
    display: flex;
    gap: var(--space-2);
    border-bottom: 1px solid var(--line);
}

.tab-btn {
    padding: var(--space-3) var(--space-4);
    border: none;
    border-bottom: 2px solid transparent;
    background: none;
    color: var(--muted);
    font-size: var(--text-sm);
    font-weight: 500;
    cursor: pointer;
    margin-bottom: -1px;
    transition: color var(--dur-base) var(--ease), border-color var(--dur-base) var(--ease);
}

.tab-btn:hover {
    color: var(--ink);
}

.tab-btn.active {
    color: var(--accent);
    border-bottom-color: var(--accent);
}

.tab-panel {
    padding-top: var(--space-5);
}

/* Section 12: Dropdown — reuses the scrim click-catcher idiom already used
   by .modal-scrim (Modal/SlideOver), but transparent and layered below
   those (z-index 55/56 vs 60/61/70), for a plain outside-click-to-close
   menu with no dimming. */

.dropdown-wrapper {
    position: relative;
    display: inline-block;
}

.dropdown-trigger {
    display: inline-flex;
    cursor: pointer;
}

.dropdown-scrim {
    position: fixed;
    inset: 0;
    z-index: 55;
    background: transparent;
}

.dropdown-menu {
    position: absolute;
    top: calc(100% + var(--space-2));
    min-width: 12rem;
    background: var(--surface);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-float);
    padding: var(--space-2);
    z-index: 56;
    outline: none;
}

.dropdown-left {
    left: 0;
}

.dropdown-right {
    right: 0;
}

.dropdown-item {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    padding: var(--space-2) var(--space-3);
    border: none;
    background: none;
    color: var(--ink);
    font-size: var(--text-sm);
    text-align: left;
    cursor: pointer;
    border-radius: var(--radius-sm);
}

.dropdown-item:hover {
    background: var(--surface-sunk);
}

@media (prefers-reduced-motion: no-preference) {
    .dropdown-menu {
        animation: horizon-dropdown-in var(--dur-base) var(--ease);
    }
}

@keyframes horizon-dropdown-in {
    from { opacity: 0; transform: translateY(-0.25rem); }
    to { opacity: 1; transform: translateY(0); }
}

/* Section 13: DataTable — sortable/searchable/paginated wrapper around the
   existing .table styling (Phase 2); this section adds only the toolbar,
   sort affordance and pagination footer, not the table's own cell styling. */

.data-table-wrapper {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.data-table-toolbar {
    display: flex;
    justify-content: flex-end;
}

.data-table-toolbar input {
    max-width: 20rem;
}

.table-container {
    overflow-x: auto;
}

.table th.sortable {
    cursor: pointer;
    user-select: none;
}

.table th.sortable:hover {
    color: var(--ink);
}

.sort-indicator {
    margin-left: var(--space-1);
    font-size: 0.7em;
}

.table tbody tr.clickable {
    cursor: pointer;
}

.data-table-pagination {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
}

.data-table-page-info {
    font-size: var(--text-sm);
    color: var(--muted);
}

/* Section 14: Select — custom single-select combobox. Trigger is styled to
   match the bare input/select styling from Task 2.3 (border, radius,
   padding, focus ring); the open menu reuses Dropdown's existing
   .dropdown-scrim for outside-click closing rather than a second scrim
   class, and its entrance animation reuses the horizon-dropdown-in
   keyframe already defined for Dropdown. */

.select-wrapper {
    position: relative;
}

.select-trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    width: 100%;
    box-sizing: border-box;
    padding: var(--space-3);
    font: inherit;
    color: var(--ink);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    cursor: pointer;
    text-align: left;
    transition: border-color var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}

.select-trigger:focus,
.select-trigger.is-open {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-glow);
}

.select-value.is-placeholder {
    color: var(--muted);
}

.select-menu {
    position: absolute;
    top: calc(100% + var(--space-2));
    left: 0;
    right: 0;
    background: var(--surface);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-float);
    padding: var(--space-2);
    z-index: 56;
    outline: none;
}

.select-search {
    padding: var(--space-1) var(--space-1) var(--space-2);
}

.select-options {
    max-height: 16rem;
    overflow-y: auto;
}

.select-option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-size: var(--text-sm);
}

.select-option:hover,
.select-option.is-focused {
    background: var(--surface-sunk);
}

.select-option.is-selected {
    color: var(--accent);
    font-weight: 600;
}

@media (prefers-reduced-motion: no-preference) {
    .select-menu {
        animation: horizon-dropdown-in var(--dur-base) var(--ease);
    }
}

/* ===========================================================================
   Navigation: SideNav rail. Presentation-only chrome; all colours from tokens.
   Collapsed = icon-only 64px rail; expanded = 240px icon+label. The rail is
   position:fixed to the left edge (real app usage and gallery preview alike).
   =========================================================================== */

.side-nav {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    display: flex;
    flex-direction: column;
    background: var(--surface);
    border-right: 1px solid var(--line);
    z-index: 40;
    overflow: hidden;
    transition: width var(--dur-slow) var(--ease);
}

.side-nav.is-collapsed { width: 64px; }
.side-nav.is-expanded { width: 240px; }

/* ===========================================================================
   App shell: the in-flow partner to the fixed .side-nav rail. .app-main clears
   the rail and tracks its collapse via :has(), with no JS and no binding.

   It deliberately owns NO padding and NO max-width — nest a .container inside
   for the reading column, or omit it for full-bleed. .container already owns
   padding-inline and the --space-section rhythm; a second padding owner here
   would double up.

   The 64px/240px literals mirror .side-nav.is-collapsed/.is-expanded above.
   They are structural constants, not a themeable surface, so they stay literal.
   =========================================================================== */
.app-shell {
    min-height: 100vh;
}

.app-main {
    margin-left: 64px;
    transition: margin-left var(--dur-slow) var(--ease);
}

.app-shell:has(.side-nav.is-expanded) .app-main {
    margin-left: 240px;
}

@media (max-width: 768px) {
    /* The rail hides and becomes an overlay drawer; content reclaims the width.

       Both selectors are required. A media query adds NO specificity, so a bare
       `.app-main` here would lose to the `:has()` rule above and the 240px rail
       offset would persist on mobile — which is the dead-space bug this whole
       primitive exists to remove. Repeating the `:has()` selector matches its
       specificity, and this block wins on source order. */
    .app-main,
    .app-shell:has(.side-nav.is-expanded) .app-main {
        margin-left: 0;
    }
}

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

.side-nav-brand {
    display: flex;
    align-items: center;
    min-height: 64px;
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--line-subtle);
    overflow: hidden;
    white-space: nowrap;
}

.side-nav-body {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-3) var(--space-2);
    overflow-y: auto;
    overflow-x: hidden;
}

.side-nav-footer {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-2);
    border-top: 1px solid var(--line-subtle);
}

/* Rail item: a grid so the icon column is fixed and the label fills the rest. */
.nav-item {
    display: grid;
    grid-template-columns: 40px 1fr auto;
    align-items: center;
    gap: var(--space-2);
    height: 44px;
    padding: 0 var(--space-2);
    border-radius: var(--radius-sm);
    color: var(--ink);
    text-decoration: none;
    position: relative;
    transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}

.nav-item:hover { background: var(--surface-sunk); }

.nav-item-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    color: var(--muted);
}

.nav-item-label {
    font-size: var(--text-sm);
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.nav-item-badge {
    justify-self: end;
    min-width: 1.25rem;
    padding: 0 var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--accent-soft);
    color: var(--accent-strong);
    font-size: var(--text-xs);
    font-weight: 700;
    text-align: center;
}

/* Active: accent left-bar + soft fill + accent icon. Tokenised equivalent of
   Kora's teal accent, so it themes with the app automatically. */
.nav-item.is-active {
    background: var(--accent-soft);
    color: var(--accent-strong);
}

.nav-item.is-active .nav-item-icon { color: var(--accent-strong); }

.nav-item.is-active::before {
    content: "";
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 3px;
    height: 60%;
    border-radius: 0 var(--radius-xs) var(--radius-xs) 0;
    background: var(--accent);
}

.nav-item:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
}

/* Group heading */
.nav-group { display: contents; }

.nav-group-label {
    padding: var(--space-3) var(--space-2) var(--space-1);
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--muted);
    white-space: nowrap;
    overflow: hidden;
}

/* Toggle button shares the rail-item shape. */
.side-nav-toggle {
    display: grid;
    grid-template-columns: 40px 1fr;
    align-items: center;
    gap: var(--space-2);
    height: 44px;
    margin: var(--space-2);
    padding: 0 var(--space-2);
    border: none;
    background: none;
    color: var(--muted);
    border-radius: var(--radius-sm);
    cursor: pointer;
    text-align: left;
}

.side-nav-toggle:hover { background: var(--surface-sunk); color: var(--ink); }

/* Collapsed rail: hide every text label, keep only icons. */
.side-nav.is-collapsed .nav-item-label,
.side-nav.is-collapsed .nav-item-badge,
.side-nav.is-collapsed .nav-item-trailing,
.side-nav.is-collapsed .side-nav-toggle > .nav-item-label,
.side-nav.is-collapsed .side-nav-brand > * {
    display: none;
}

/* Collapsed group label becomes a divider rule instead of text. */
.side-nav.is-collapsed .nav-group-label {
    height: 1px;
    padding: 0;
    margin: var(--space-2) var(--space-2);
    background: var(--line);
    color: transparent;
    overflow: hidden;
}

/* SideNav mobile drawer: below 768px the rail hides; when open it slides in
   above the reused .modal-scrim (scrim z-index 60, so the drawer sits above). */
@media (max-width: 768px) {
    .side-nav {
        transform: translateX(-100%);
        transition: transform var(--dur-slow) var(--ease);
        z-index: 61;
    }

    /* On mobile the drawer always shows the expanded (icon+label) form. */
    .side-nav.is-drawer-open {
        transform: translateX(0);
        width: 240px;
    }

    .side-nav.is-drawer-open .nav-item-label,
    .side-nav.is-drawer-open .nav-item-badge,
    .side-nav.is-drawer-open .nav-group-label,
    .side-nav.is-drawer-open .side-nav-brand > * {
        display: revert;
    }

    /* The collapse toggle is meaningless in the drawer: hide it on mobile. */
    .side-nav-toggle { display: none; }
}

@media (max-width: 768px) and (prefers-reduced-motion: reduce) {
    .side-nav { transition: none; }
}

/* ===========================================================================
   Navigation: TopNav app bar. Sticky, translucent surface, hairline underline.
   =========================================================================== */

.top-nav {
    position: sticky;
    top: 0;
    display: flex;
    align-items: center;
    gap: var(--space-4);
    height: 56px;
    padding: 0 var(--space-4);
    background: var(--surface);
    border-bottom: 1px solid var(--line);
    z-index: 30;
}

.top-nav-brand {
    display: flex;
    align-items: center;
    font-weight: 700;
    white-space: nowrap;
}

.top-nav-links {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    flex: 1 1 auto;
    overflow-x: auto;
}

.top-nav-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-left: auto;
}

.top-nav-item {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    height: 36px;
    padding: 0 var(--space-3);
    border-radius: var(--radius-sm);
    color: var(--muted);
    text-decoration: none;
    font-size: var(--text-sm);
    font-weight: 500;
    white-space: nowrap;
    transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}

.top-nav-item:hover { background: var(--surface-sunk); color: var(--ink); }

.top-nav-item.is-active {
    color: var(--accent-strong);
    background: var(--accent-soft);
}

.top-nav-item:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
}

.top-nav-menu {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border: none;
    background: none;
    color: var(--ink);
    border-radius: var(--radius-sm);
    cursor: pointer;
}

.top-nav-menu:hover { background: var(--surface-sunk); }

/* ===========================================================================
   BottomSheet: bottom-anchored overlay. Stays docked to the bottom edge at
   every viewport width; only its width and horizontal centring change.
   Shares .modal-scrim as its backdrop (Section 9's convention). Top corners
   only are rounded; the bottom edge is always flush with the viewport.
   =========================================================================== */

.bottom-sheet {
    position: fixed;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    width: min(80%, 75rem);
    max-height: var(--sheet-max-height, 85vh);
    display: flex;
    flex-direction: column;
    background: var(--surface);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    z-index: 61;
    outline: none;
}

/* Tablet: wider, same 75rem cap as desktop. */
@media (max-width: 1024px) {
    .bottom-sheet {
        width: min(90%, 75rem);
    }
}

/* Mobile: full width, edge-to-edge, no horizontal centring transform. */
@media (max-width: 768px) {
    .bottom-sheet {
        left: 0;
        width: 100%;
        transform: none;
    }
}

.bottom-sheet-handle {
    width: 2.25rem;
    height: 0.25rem;
    flex-shrink: 0;
    margin: var(--space-3) auto 0;
    background: var(--line);
    border-radius: var(--radius-pill);
}

.bottom-sheet-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid var(--line);
    flex: 0 0 auto;
}

.bottom-sheet-title {
    margin: 0;
    font-size: var(--text-lg);
}

.bottom-sheet-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border: none;
    background: none;
    color: var(--muted);
    cursor: pointer;
    border-radius: var(--radius-sm);
}

.bottom-sheet-close:hover {
    background: var(--surface-sunk);
    color: var(--ink);
}

.bottom-sheet-body {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: var(--space-5);
    padding-bottom: calc(var(--space-5) + env(safe-area-inset-bottom, 0px));
}

.bottom-sheet-foot {
    flex: 0 0 auto;
    padding: var(--space-4) var(--space-5);
    padding-bottom: calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
    border-top: 1px solid var(--line);
    display: flex;
    gap: var(--space-3);
    justify-content: flex-end;
}

/* Entrance: slide up from the bottom. Desktop/tablet combine the slide with
   the horizontal centring transform; mobile has no centring transform to
   preserve, so it gets its own keyframe. */
@media (prefers-reduced-motion: no-preference) {
    .bottom-sheet {
        animation: horizon-bottom-sheet-in var(--dur-slow) var(--ease);
    }
}

@keyframes horizon-bottom-sheet-in {
    from { opacity: 0; transform: translateX(-50%) translateY(100%); }
    to { opacity: 1; transform: translateX(-50%) translateY(0); }
}

@media (max-width: 768px) and (prefers-reduced-motion: no-preference) {
    .bottom-sheet {
        animation-name: horizon-bottom-sheet-in-mobile;
    }
}

@keyframes horizon-bottom-sheet-in-mobile {
    from { opacity: 0; transform: translateY(100%); }
    to { opacity: 1; transform: translateY(0); }
}
