/* ── Site-wide text size bump ──
   FluentUI's own type ramp (--fontSizeBase*/--fontSizeHero* and their --lineHeight* pairs,
   consumed both by plain elements and inside every Fluent component's shadow DOM) drives most of
   the app's text — a root font-size change alone doesn't reach it, since these are fixed px custom
   properties, not em/rem. Shifted the whole ramp up by one of FluentUI's own steps (e.g. body text
   Base300 14px->16px, the old Base400) rather than picking new numbers, so proportions and
   line-heights stay as tuned. Hero900 has no usable next step (Hero1000 is 68px), so it's
   extrapolated at the same +8px/+12px cadence as the step below it.
   !important is load-bearing here, not decoration: these tokens aren't set by any rule in the
   package stylesheets but by a Constructable StyleSheet the Fluent JS bundle adds to
   document.adoptedStyleSheets at runtime. Adopted stylesheets cascade after every <link>/<style>
   in the document regardless of load order, so a plain :root rule here — even loaded last — still
   loses to it once specificity ties (:root vs :root). !important is the only lever that reaches
   over it from a static file. */
:root {
    --fontSizeBase100: 12px !important;
    --lineHeightBase100: 16px !important;
    --fontSizeBase200: 14px !important;
    --lineHeightBase200: 20px !important;
    --fontSizeBase300: 16px !important;
    --lineHeightBase300: 22px !important;
    --fontSizeBase400: 20px !important;
    --lineHeightBase400: 26px !important;
    --fontSizeBase500: 24px !important;
    --lineHeightBase500: 32px !important;
    --fontSizeBase600: 28px !important;
    --lineHeightBase600: 36px !important;
    --fontSizeHero700: 32px !important;
    --lineHeightHero700: 40px !important;
    --fontSizeHero800: 40px !important;
    --lineHeightHero800: 52px !important;
    --fontSizeHero900: 48px !important;
    --lineHeightHero900: 64px !important;
}

/* Our own CSS below is written in rem against this root size, not FluentUI's ramp above — bumped
   the same modest notch (16px -> 17px) so it scales in step with it. */
html {
    font-size: 17px;
}

/* A second bump, phones only: on top of the site-wide notch above, mobile gets one more step of
   both the root size (for our rem-based classes) and FluentUI's ramp (for everything else) —
   small screens are read at arm's length more than a desktop monitor is. */
@media (max-width: 768px) {
    html {
        font-size: 18px;
    }

    :root {
        --fontSizeBase100: 14px !important;
        --lineHeightBase100: 20px !important;
        --fontSizeBase200: 16px !important;
        --lineHeightBase200: 22px !important;
        --fontSizeBase300: 20px !important;
        --lineHeightBase300: 26px !important;
        --fontSizeBase400: 24px !important;
        --lineHeightBase400: 32px !important;
        --fontSizeBase500: 28px !important;
        --lineHeightBase500: 36px !important;
        --fontSizeBase600: 32px !important;
        --lineHeightBase600: 40px !important;
        --fontSizeHero700: 40px !important;
        --lineHeightHero700: 52px !important;
        --fontSizeHero800: 48px !important;
        --lineHeightHero800: 64px !important;
        --fontSizeHero900: 56px !important;
        --lineHeightHero900: 76px !important;
    }
}

html, body {
    margin: 0;
    font-family: var(--fontFamilyBase);
}

/* ── Undo FluentUI's global scroll lock ──
   The FluentUI JS bundle adopts its own runtime stylesheet (see the --fontSizeBase comment
   above for how these cascade after any plain stylesheet regardless of load order) that sets
   `body { height: 100dvh; overflow: hidden; }` unconditionally, from first load - not
   something toggled per dialog. It's meant for an app built on v5's FluentLayout, which owns
   its own internal scroll region; this app uses plain elements instead precisely so app.css's
   .content rules can own the page's scroll behavior (see MainLayout's comment), and nothing
   here ever un-locks FluentUI's own body rule. !important is required for the same reason the
   font-size override above needs it: a plain rule here loses the cascade tie to the adopted
   sheet regardless of specificity or source order.
   Desktop mouse-wheel and JS-driven scrolling both tolerate the locked body just fine (Chrome
   still scrolls the viewport/html), which is what made this easy to miss without a real touch
   device - but a real touch swipe respects the nearest scrollable ancestor's own overflow, and
   refuses to scroll AT ALL once body says it can't. That's what actually blocks scrolling and
   pull-to-refresh on a phone, on every page, regardless of any per-page .content rule below. */
body {
    height: auto !important;
    overflow: visible !important;
}

.body-content > .content {
    padding: 1rem;
}

/* ── Post-navigation heading focus ──
   Routes.razor's <FocusOnNavigate Selector="h1" /> moves focus to each page's <h1> after a
   client-side navigation, so screen readers announce the new page - SPA nav never reloads
   the document, so without this, focus silently stays put and assistive tech gets no cue
   anything changed. That's a tabindex="-1" + focus() call, not a real interactive element,
   so the browser's default focus ring reads as a stray box around plain text. Scoped to h1
   rather than a blanket *:focus rule, which would also strip the ring from buttons/links/
   inputs that genuinely need it (WCAG 2.4.7). */
h1:focus {
    outline: none;
}

/* ── Input / list / accordion default width ──
   These web components ship with a fixed intrinsic width rather than stretching to fill their
   container: close enough in a wide desktop dialog, but an obvious gap on a narrow phone dialog
   (CaseEditDialog's Status select and accordion sections). fluent-field is the wrapper v5 puts
   around every labelled input, so it has to stretch too or the input inside can't. Not scoped
   to dialogs - the header's firm-switcher select (MainLayout.razor) has the same gap. */
fluent-field,
fluent-dropdown,
fluent-text-input,
fluent-textarea,
fluent-accordion,
fluent-accordion-item {
    width: 100%;
}

/* ── Nested FluentStack width inside an accordion item ──
   FluentStack's own default cross-axis alignment doesn't stretch its children to fill
   available width (each child sizes to its own content instead) - a top-level accordion
   section's stack still reads full-width because its several leaf fields' combined natural
   sizing happens to reach it, but a FluentStack NESTED one level deeper (CaseEditDialog's
   Client/Interested Party fields, each wrapping a combobox + "+ Create ..." button in their
   own vertical FluentStack) has nothing forcing it wide, so it - and the plain unstyled
   <div> around it - both shrink to the combobox's own width instead of the section's full
   width. `.fluent-stack-vertical` is the class FluentStack renders regardless of nesting depth, so
   this catches every level, not just the one currently narrow. CaseEditDialog's quick-intake
   view (`.intake-quick-fields`) renders the same Client-picker fragment outside any accordion
   item, so it needs the identical fix - narrow enough to miss on a wide desktop dialog, but
   obvious on mobile. `.intake-quick-fields` is itself the outer stack-vertical (the Class
   parameter adds it alongside FluentStack's own rendered class on the SAME element), so the
   "Client" div's parent plays both roles at once - a plain descendant-combinator match against
   `.fluent-stack-vertical` never fires for it, unlike the accordion case where the outer stack and the
   div's immediate parent are still two different elements. `.intake-quick-fields > div` covers
   that one directly. */
fluent-dialog-body .fluent-stack-vertical > div,
fluent-accordion-item .fluent-stack-vertical,
fluent-accordion-item .fluent-stack-vertical > div,
.intake-quick-fields .fluent-stack-vertical,
.intake-quick-fields .fluent-stack-vertical > div,
.intake-quick-fields > div {
    width: 100%;
}

/* ── Native date/datetime inputs inside an accordion item ──
   CaseEditDialog's Hearings/Appointments/Payment sections use plain <input type="date"> /
   <input type="datetime-local"> (not a FluentUI component - see the DateTimeOffset/Boise-
   wall-clock comment on the proxies in the code-behind), each in its own unstyled wrapper
   div. The rule above already stretches that wrapper div to full width; this stretches the
   input inside it too, so the field itself fills the row rather than sitting narrow under a
   now-full-width label. box-sizing: border-box keeps the native calendar-picker icon inside
   the same width instead of pushing it past the section's edge. */
fluent-accordion-item input[type="date"],
fluent-accordion-item input[type="datetime-local"] {
    width: 100%;
    box-sizing: border-box;
}

/* ── Unauthenticated landing (/app, signed out) ── */
.landing {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    text-align: center;
    padding: 4rem 1rem;
}

.landing h1 {
    margin: 0;
}

.landing p {
    color: var(--colorNeutralForeground2);
    margin: 0 0 0.5rem;
}

/* ── Shell (MainLayout) ── */
.app-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 3rem;
    padding: 0 1rem;
    background: var(--colorBrandBackground);
    color: var(--colorNeutralForegroundOnBrand);
}

.header-firm {
    margin-right: 1rem;
}

.main {
    display: flex;
    align-items: stretch;
}

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

/* ── Header ── */
.header-brand {
    font-weight: 700;
    font-size: 1.1rem;
    white-space: nowrap;
    color: inherit;
    text-decoration: none;
}

/* ── Account menu ── */
.account-menu-wrap {
    position: relative;
}

/* Full-width, left-aligned menu rows (Fluent buttons centre their content by default). */
.account-item {
    width: 100%;
    justify-content: flex-start;
}

.account-dropdown {
    position: absolute;
    right: 0;
    top: 100%;
    z-index: 1000;
    min-width: 200px;
    max-width: calc(100vw - 1rem);
    background: var(--colorNeutralBackground2);
    border: 1px solid var(--colorNeutralStroke2);
    border-radius: 0.375rem;
    padding: 0.5rem;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}

/* ── Sidebar – hidden on mobile, shown on desktop ── */
.sidebar-nav {
    display: block;
}

/* ── Bottom nav – hidden on desktop, shown on mobile ── */
.bottom-nav {
    display: none;
}

/* ── Record grid (clients, cases) – shown on desktop ── */
.record-grid {
    display: block;
}

/* ── Record cards (clients, cases) – hidden on desktop, shown on mobile ── */
.record-cards {
    display: none;
}

/* ── Action column (e.g. the per-row Edit button on CaseFinancials) – narrow and centered so the
   button isn't left cramped against the row's edges. app.css is a plain global stylesheet (not a
   scoped *.razor.css), so this reaches the <td class="col-action"> FluentDataGrid renders our
   TemplateColumn content into directly, without needing ::deep. ── */
.col-action {
    display: flex;
    align-items: center;
    justify-content: center;
}

/* ── Click affordance ── */
.record-grid ::deep tr[role="row"] { cursor: pointer; }
.record-card { cursor: pointer; }

/* ── Filter bar row (search + add button) ── */
.record-filter-row {
    display: flex;
    gap: 0.5rem;
    align-items: center;
}

.record-filter-row input {
    flex: 1;
}

.add-record-btn {
    white-space: nowrap;
    flex-shrink: 0;
}

/* ── Filter bar — visible on both desktop and mobile ── */
.record-filter-bar {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
    margin-bottom: 0.5rem;
}

.record-filter-bar input {
    width: 100%;
    padding: 0.5rem 0.75rem;
    border-radius: 0.5rem;
    border: 1px solid var(--colorNeutralStroke2);
    background: var(--colorNeutralBackground2);
    color: var(--colorNeutralForeground1);
    font-size: 0.9rem;
    box-sizing: border-box;
}

.record-filter-buttons {
    display: flex;
}

.record-filter-buttons button {
    flex: 1;
    position: relative;
    padding: 0.3rem 0.5rem;
    border: 1px solid var(--colorNeutralStroke1);
    background: transparent;
    color: var(--colorNeutralForeground1);
    font-size: 0.75rem;
    font-weight: 500;
    cursor: pointer;
}

/* Joined split-button look (same technique as .intake-mode-toggle below): borders
   overlap via negative margin, rounding lives only on the group's outer corners
   instead of on every button, and the active segment's border comes to front. */
.record-filter-buttons button + button {
    margin-left: -1px;
}

.record-filter-buttons button:first-child {
    border-radius: 999px 0 0 999px;
}

.record-filter-buttons button:last-child {
    border-radius: 0 999px 999px 0;
}

.record-filter-buttons button.active-filter {
    background: var(--colorBrandBackground);
    color: var(--foreground-on-accent-rest);
    border-color: var(--colorBrandStroke1);
    z-index: 1;
}

/* ── Intake mode toggle (CaseEditDialog "New Case", ClientEditDialog "New Client") — a
   genuinely joined two-segment button group (Bootstrap's split-button look): borders
   overlap via negative margin and the active segment's border is brought to front with
   z-index, rather than each button being its own pill like .record-filter-buttons above. ── */
.intake-mode-toggle {
    display: flex;
}

.intake-mode-toggle button {
    flex: 0 0 auto;
    position: relative;
    padding: 0.4rem 0.75rem;
    border: 1px solid var(--colorNeutralStroke1);
    background: transparent;
    color: var(--colorNeutralForeground1);
    font-size: 0.85rem;
    font-weight: 500;
    white-space: nowrap;
    cursor: pointer;
}

.intake-mode-toggle button + button {
    margin-left: -1px;
}

.intake-mode-toggle button:first-child {
    border-radius: 0.5rem 0 0 0.5rem;
}

.intake-mode-toggle button:last-child {
    border-radius: 0 0.5rem 0.5rem 0;
}

.intake-mode-toggle button.active {
    background: var(--colorBrandBackground);
    color: var(--foreground-on-accent-rest);
    border-color: var(--colorBrandStroke1);
    z-index: 1;
}

/* ── Selects inside .record-filter-bar (Cases' county filter, Clients' sort) — styled to
   match the search box above them ── */
.county-filter-select,
.record-sort-select {
    width: 100%;
    padding: 0.5rem 0.75rem;
    border-radius: 0.5rem;
    border: 1px solid var(--colorNeutralStroke2);
    background: var(--colorNeutralBackground2);
    color: var(--colorNeutralForeground1);
    font-size: 0.9rem;
    box-sizing: border-box;
}

/* The sort select is mobile-only: the desktop grid already sorts via its clickable column
   headers, so it only appears once .record-cards takes over (768px media query below). */
.record-sort-select {
    display: none;
}

/* ── To-do highlighting (Cases) — mirrors the desktop's per-cell tint for a case carrying a
   pending attorney or client/assistant to-do (CaseSelection.Pane.cs's
   ManagedCasesGridView_CellFormatting: AttyColor / AsstColor). Colors are fixed hex rather
   than theme tokens, same approach as .status-badge above, so they read consistently in both
   themes. A left-edge stripe rather than a full background tint keeps the row's own status
   badge and text legible underneath. ── */
.record-grid tr.todo-atty td:first-child {
    box-shadow: inset 6px 0 0 #2e7d32;
}

.record-grid tr.todo-client td:first-child {
    box-shadow: inset 6px 0 0 #1565c0;
}

.record-grid tr.todo-atty.todo-client td:first-child {
    box-shadow: inset 6px 0 0 #2e7d32, inset 12px 0 0 #1565c0;
}

/* The home page's to-do rows are .mini-cards, not .record-cards, so they're listed here rather
   than given their own colours — the green/blue pair is defined exactly once. They never carry
   both classes (a TodoItem has one owner), hence no combined rule for them below. */
.record-card.todo-atty,
.home-todo-row.todo-atty {
    box-shadow: inset 6px 0 0 #2e7d32;
}

.record-card.todo-client,
.home-todo-row.todo-client {
    box-shadow: inset 6px 0 0 #1565c0;
}

.record-card.todo-atty.todo-client {
    box-shadow: inset 6px 0 0 #2e7d32, inset 12px 0 0 #1565c0;
}

/* ── Status badges — available on both desktop and mobile ── */
.status-badge {
    display: inline-block;
    font-size: 0.65rem;
    font-weight: 600;
    padding: 0.1rem 0.4rem;
    border-radius: 999px;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.status-badge.active {
    background: #107c1033;
    color: #107c10;
}

.status-badge.inactive {
    background: var(--colorNeutralStroke2);
    color: var(--colorNeutralForeground2);
}

.status-badge.archived {
    background: #d83b0133;
    color: #d83b01;
}

/* Run history states (Automations page, case2courtdocs/projects/workflow-automation's Phase 3) */
.status-badge.running {
    background: #0078d433;
    color: #0078d4;
}

.status-badge.succeeded {
    background: #107c1033;
    color: #107c10;
}

.status-badge.failed {
    background: #c42b1c33;
    color: #c42b1c;
}

/* ── Mini card — a compact, always-visible summary row (e.g. the embedded case list on
   ClientDetail). Deliberately separate from .record-card: that class's visual styling
   (background/border/padding) only exists inside the mobile media query below, since its
   only prior consumer was the mobile card list, which is display:none on desktop anyway. */
.mini-card {
    display: block;
    background: var(--colorNeutralBackground2);
    border-radius: 0.5rem;
    padding: 0.625rem 0.75rem;
    border: 1px solid var(--colorNeutralStroke2);
    cursor: pointer;
    text-decoration: none;
    color: inherit;
}

.mini-card .mini-card-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.mini-card .mini-card-title {
    font-weight: 600;
    font-size: 1.15rem;
}

.mini-card .mini-card-detail {
    font-size: 1rem;
    color: var(--colorNeutralForeground2);
}

.mini-card .mini-card-meta {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.25rem;
    font-size: 0.9rem;
    color: var(--colorNeutralForeground2);
}

/* ── Circuit reconnect UI — global ──
   Styled entirely off our own classes (added by reconnect.js), never off the
   components-reconnect-* classes Blazor sets: the framework adds those the moment the
   socket drops, and the whole point here is to stay invisible through a reconnect that
   finishes in a few hundred milliseconds. Default is hidden; reconnect.js decides when
   the banner has waited long enough to be worth showing. */
#components-reconnect-modal {
    display: none;
}

#components-reconnect-modal.reconnect-visible {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    position: fixed;
    /* It's a popover (reconnect.js raises it above open dialogs); undo the browser's
       centred popover placement so the positions below apply. */
    inset: auto;
    margin: 0;
    top: 0.75rem;
    left: 50%;
    transform: translateX(-50%);
    padding: 0.5rem 1rem;
    border-radius: 999px;
    background: var(--colorNeutralBackground2);
    color: var(--colorNeutralForeground1);
    border: 1px solid var(--colorNeutralStroke2);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
    font-size: 0.85rem;
}

/* Escalation: the framework has given up retrying, so stop pretending the page is live
   and cover it rather than let clicks and keystrokes vanish into a dead circuit. */
#components-reconnect-modal.reconnect-blocking {
    top: 0;
    left: 0;
    transform: none;
    width: 100%;
    height: 100%;
    border: none;
    border-radius: 0;
    box-shadow: none;
    background: rgba(0, 0, 0, 0.55);
    color: #fff;
    font-size: 1rem;
}

/* Diagnostics, revealed by reconnect.js only once a reconnect is dragging. Users are on
   mobile browsers with no console, so this line is the only way a stalled reconnect can
   be reported back. */
.reconnect-detail {
    display: none;
    opacity: 0.7;
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

#components-reconnect-modal.reconnect-detailed .reconnect-detail {
    display: inline;
}

.reconnect-dot {
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    flex-shrink: 0;
    background: var(--colorBrandBackground);
    animation: reconnect-pulse 1.2s ease-in-out infinite;
}

#components-reconnect-modal.reconnect-blocking .reconnect-dot {
    background: #fff;
}

@keyframes reconnect-pulse {
    50% { opacity: 0.25; }
}

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

/* ── Blazor error UI — global ── */
#blazor-error-ui {
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
}

/* ── Financial summary groups (CaseFinancials) — the two account roll-up panels.
   Side by side where there's room, stacked below the breakpoint via the flex-wrap. ── */
.summary-groups {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    margin-top: 0.5rem;
}

.summary-group {
    flex: 1 1 18rem;
    background: var(--colorNeutralBackground2);
    border: 1px solid var(--colorNeutralStroke2);
    border-radius: 0.5rem;
    padding: 0.75rem 1rem;
}

.summary-group h2 {
    font-size: 0.95rem;
    margin: 0 0 0.5rem;
    color: var(--colorNeutralForeground2);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.summary-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    padding: 0.3rem 0;
}

.summary-row + .summary-row {
    border-top: 1px solid var(--colorNeutralStroke2);
}

.summary-row .summary-label {
    font-size: 0.9rem;
}

/* Tabular figures so the amounts align down the column rather than jittering by glyph width */
.summary-row .summary-amount {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.summary-row.emphasis {
    font-weight: 600;
}

.col-amount {
    font-variant-numeric: tabular-nums;
}

/* ── Home dashboard ──
   Layout is deliberately borrowed rather than invented: the agenda and to-do panels are
   .summary-groups/.summary-group (above), whose `flex: 1 1 18rem` inside a wrapping flex row
   gives side-by-side-then-stacked with no media query of its own, and every row inside them is
   a .mini-card, which is styled outside the mobile block and so works at both widths. The rules
   here only cover what those two don't: the search box and the dashboard's own spacing. */
.home-greeting {
    margin-bottom: 0.75rem;
}

.home-search {
    position: relative;
    margin-bottom: 1rem;
}

.home-search-input {
    width: 100%;
    box-sizing: border-box;
    padding: 0.6rem 0.75rem;
    font-size: 1.1rem;
    font-family: inherit;
    color: var(--colorNeutralForeground1);
    background: var(--colorNeutralBackground2);
    border: 1px solid var(--colorNeutralStroke1);
    border-radius: 0.5rem;
}

.home-search-input:focus {
    outline: none;
    border-color: var(--colorBrandStroke1);
}

/* Keyboard-shortcut badge, sitting inside the box's right edge. pointer-events:none so it never
   swallows a click meant for the input underneath it. */
.home-search-hint {
    position: absolute;
    top: 50%;
    right: 0.6rem;
    transform: translateY(-50%);
    pointer-events: none;
    padding: 0.1rem 0.4rem;
    border: 1px solid var(--colorNeutralStroke2);
    border-radius: 0.25rem;
    font-size: 0.7rem;
    color: var(--colorNeutralForeground2);
}

/* Absolutely positioned so the panels below don't jump down as results appear. z-index clears
   the .summary-group cards immediately underneath, which are in the same stacking context. */
.home-search-results {
    position: absolute;
    top: calc(100% + 0.25rem);
    left: 0;
    right: 0;
    z-index: 50;
    max-height: 24rem;
    overflow-y: auto;
    background: var(--colorNeutralBackground1);
    border: 1px solid var(--colorNeutralStroke1);
    border-radius: 0.5rem;
    box-shadow: 0 8px 24px #0006;
}

/* An <a>, not a div — middle-click and Ctrl-click open a result in a new tab, matching how every
   other result row in the app behaves. The link styling has to be reset back to body text. */
.home-search-result {
    display: flex;
    align-items: baseline;
    gap: 0.625rem;
    padding: 0.5rem 0.75rem;
    cursor: pointer;
    text-decoration: none;
    color: inherit;
}

/* Keyboard highlight and hover share .highlighted (see below); this keeps a real focus ring
   available if a row is ever reached by Tab. */
.home-search-result:focus-visible {
    outline: 2px solid var(--colorBrandForeground1);
    outline-offset: -2px;
}

.home-search-result + .home-search-result {
    border-top: 1px solid var(--colorNeutralStroke2);
}

/* Hover and keyboard selection share one class — Home.razor sets _highlighted on mouseenter too,
   so the pointer and the arrow keys can never disagree about which row Enter would open. */
.home-search-result.highlighted {
    background: var(--colorNeutralBackground3Hover);
}

.home-search-kind {
    flex-shrink: 0;
    min-width: 3.5rem;
    padding: 0.1rem 0.4rem;
    border-radius: 0.75rem;
    font-size: 0.7rem;
    text-align: center;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    background: var(--colorNeutralBackground3);
    color: var(--colorNeutralForeground2);
}

.home-search-kind.case {
    background: #0078d433;
    color: #4aa3e8;
}

.home-search-kind.client {
    background: #10893e33;
    color: #4cbb7a;
}

.home-search-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.home-search-title {
    font-weight: 600;
}

.home-search-subtitle,
.home-search-empty {
    font-size: 0.8rem;
    color: var(--colorNeutralForeground2);
}

.home-search-empty {
    padding: 0.75rem;
}

/* flex-start rather than the flex default of stretch: with one panel full and the other empty
   ("Nothing on the calendar this week"), stretch gives the empty one the full height of its
   neighbour, so the dashboard opens on a large blank rectangle. Scoped to .home-page so
   CaseFinancials' own equal-height summary panels keep the default. */
.home-page .summary-groups {
    align-items: flex-start;
}

/* Panels scroll internally rather than growing without bound — a firm with fifty to-dos should
   not push "Recently touched" off the bottom of a desktop screen. */
.home-panel {
    max-height: 26rem;
    overflow-y: auto;
}

/* The agenda section itself carries no card styling — each event is its own .mini-card below
   it, not a list nested inside a bigger card. */
.home-agenda-section h2 {
    font-size: 1.1rem;
    margin: 0 0 0.5rem;
    color: var(--colorNeutralForeground2);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

/* Wider left padding than a plain .mini-card, to clear the 6px to-do stripe with room to spare —
   the same allowance .record-card makes for the same stripe. */
.home-todo-row {
    padding-left: 1.125rem;
}

.home-panel .mini-card + .mini-card,
.home-agenda-section .mini-card + .mini-card,
.home-recent-list .mini-card + .mini-card {
    margin-top: 0.375rem;
}

.home-day-heading {
    margin: 0.75rem 0 0.375rem;
    font-size: 0.9rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--colorNeutralForeground2);
}

.home-day-heading:first-of-type {
    margin-top: 0;
}

.home-agenda-time {
    flex-shrink: 0;
    font-variant-numeric: tabular-nums;
    font-size: 0.95rem;
    color: var(--colorNeutralForeground2);
}

.agenda-kind {
    margin-left: auto;
    flex-shrink: 0;
    padding: 0.05rem 0.4rem;
    border-radius: 0.75rem;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.agenda-kind.hearing {
    background: #8764b833;
    color: #a98fd6;
}

.agenda-kind.appointment {
    background: #ca500033;
    color: #e08a4a;
}

/* Case-level context (charge/judge/opposing counsel/handling attorney) on an agenda card — one
   line per item rather than packed onto a shared row. */
.home-agenda-case-meta {
    margin-top: 0.25rem;
    font-size: 0.9rem;
    color: var(--colorNeutralForeground2);
}

/* An agenda card's body is three unlabeled subsections — who's involved, what the event/case is,
   and any to-dos — each a .home-agenda-group, separated by a rule line rather than a background
   tint: a tinted band (tried first) lightens the card's own background enough to drop the
   hint-grey field labels, and the existing to-do green/blue, below readable contrast. A divider
   keeps every child on the card's own background instead. Uses the stronger --colorNeutralStroke1
   so the rule stays visible against the card. */
.home-agenda-group {
    margin-top: 0.375rem;
}

.home-agenda-group + .home-agenda-group {
    border-top: 1px solid var(--colorNeutralStroke1);
    margin-top: 0.5rem;
    padding-top: 0.375rem;
}

/* Reuses the case list's own to-do colours (.todo-atty/.todo-client, defined above for
   .record-card) as text colour rather than the card-edge stripe those use elsewhere — an agenda
   card already has a kind badge occupying that visual slot. Clamped for the same reason
   .home-todo-row's detail line was: to-do text is free-form and can run long. */
.home-agenda-todo {
    margin-top: 0.25rem;
    font-size: 0.95rem;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.home-agenda-todo.todo-atty {
    color: #2e7d32;
}

.home-agenda-todo.todo-client {
    color: #1565c0;
}

/* The to-do rows reuse the case list's own tint classes (.todo-atty / .todo-client, defined
   above for .record-card), so a to-do is the same colour here as on the case list. */

.home-panel-heading {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.home-panel-heading h2 {
    margin: 0 0 0.5rem;
}

.todo-sort {
    display: flex;
    gap: 0.25rem;
    margin-bottom: 0.5rem;
}

.todo-sort-btn {
    border: 1px solid var(--colorNeutralStroke2);
    border-radius: 999px;
    background: transparent;
    color: var(--colorNeutralForeground2);
    font-size: 0.7rem;
    padding: 0.15rem 0.6rem;
    cursor: pointer;
}

.todo-sort-btn.active {
    border-color: var(--colorBrandStroke1);
    color: var(--colorBrandForeground1);
}

.home-todo-subheading {
    margin: 0.75rem 0 0.375rem;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--colorNeutralForeground2);
}

.home-todo-subheading:first-of-type {
    margin-top: 0;
}

.home-todo-row .mini-card-detail {
    /* To-do text is free-form and can be long; cap it at three lines rather than letting one
       verbose entry own the panel. */
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.home-recent {
    margin-top: 1rem;
}

.home-recent h2 {
    font-size: 0.95rem;
    margin: 0 0 0.5rem;
    color: var(--colorNeutralForeground2);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

/* auto-fill rather than auto-fit: with a handful of cards, auto-fit would stretch each one across
   the full width; auto-fill keeps them at a readable column width and leaves the row short. */
.home-recent-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: 0.5rem;
}

.home-empty {
    margin: 0.25rem 0;
    font-size: 1rem;
    color: var(--colorNeutralForeground2);
}

.home-more {
    display: inline-block;
    margin-top: 0.5rem;
    font-size: 0.8rem;
    color: var(--colorBrandForeground1);
    text-decoration: none;
}

/* ── Responsive breakpoint ── */
@media (max-width: 768px) {
    /* Stack header items; allow wrapping */
    .app-header {
        flex-wrap: wrap;
        gap: 0.25rem;
        padding: 0.5rem;
    }

    /* Hide sidebar */
    .sidebar-nav {
        display: none !important;
    }

    /* Push body content to full width; add bottom padding so
       the fixed bottom nav doesn't cover content */
    .body-content {
        width: 100% !important;
        padding-bottom: 4rem;
    }

    /* Reduce content padding on mobile, and set up flex layout
       so the virtualized card list fills remaining height. */
    .body-content > .content {
        padding: 0.5rem;
        display: flex;
        flex-direction: column;
        height: calc(100dvh - 3.5rem);
        overflow: hidden;
    }

    .body-content > .content h1 {
        margin: 0.25rem 0;
    }

    .body-content > .content .record-filter-bar {
        flex-shrink: 0;
    }

    .body-content > .content .record-cards {
        overflow-y: auto;
        height: calc(100dvh - 9.5rem);
        width: 100%;
    }

    /* CaseFinancials opts out of the layout above: that scroll-pane sizing was designed for
       Clients/Cases, a virtualized list under a fixed filter bar, where only the list itself
       should scroll under a pinned header. Financials instead has two summary panels above a
       short, non-virtualized transaction list - giving the cards their own fixed-height pane left
       only a sliver of the screen to scroll transactions in, squeezed below the summaries. Un-cap
       both the outer pane and the card list here so the whole page scrolls as one normal flow.
       :has() lets this reach .content, which CaseFinancials doesn't render itself (MainLayout
       does) - safe to rely on given the surrounding rules already require dvh support. */
    .body-content > .content:has(.financials-page) {
        height: auto;
        overflow: visible;
    }

    .financials-page .record-cards {
        height: auto;
        overflow-y: visible;
    }

    /* The home dashboard opts out for the same reason CaseFinancials does, and it is the same
       shape of page: a search box and three short panels, not one virtualized list under a
       pinned filter bar. Left capped, the panels would be squeezed into a sliver and
       "Recently touched" would be unreachable below them. */
    .body-content > .content:has(.home-page) {
        height: auto;
        overflow: visible;
    }

    /* CaseDetail is the same shape as the home dashboard: a handful of stacked sections,
       not a virtualized list under a pinned filter bar. Case History can grow to any
       length (free-flowing text, not a capped textarea), so without this the default
       .content height cap silently clips it under the fixed bottom nav with no way to
       scroll to the rest. */
    .body-content > .content:has(.case-detail-page) {
        height: auto;
        overflow: visible;
    }

    /* Automations is the same shape as CaseDetail: several stacked sections (jobs, schedules,
       history), not one virtualized list under a pinned filter bar. Without this, the default
       .content height cap silently clips the run history section under the fixed bottom nav. */
    .body-content > .content:has(.automations-page) {
        height: auto;
        overflow: visible;
    }

    /* ClientDetail is the same shape too: action buttons above a plain (non-virtualized) list
       of case cards, not a virtualized list under a pinned filter bar. Without this, a client
       with more than a screenful of cases is clipped under the fixed bottom nav with no way to
       scroll to the rest. */
    .body-content > .content:has(.client-detail-page) {
        height: auto;
        overflow: visible;
    }

    /* FeatureFlags reuses the same .record-cards mobile markup as Clients/Cases, but has no
       .record-filter-bar - instead it has a multi-line intro paragraph above the list, which is
       taller than the filter bar the .record-cards fixed-height calc() above was tuned around.
       Left capped, that extra height pushes the actual flag rows past the bottom of .content's
       own hard cap, clipping the list under the fixed bottom nav with no way to scroll to it -
       same failure shape as ClientDetail/CaseDetail/Automations/Home, just via a different path
       (a too-short internal scroll pane instead of no scroll pane at all). Only a handful of
       flags exist per firm, so there's no virtualization to protect here either. */
    .body-content > .content:has(.feature-flags-page) {
        height: auto;
        overflow: visible;
    }

    .feature-flags-page .record-cards {
        height: auto;
        overflow-y: visible;
    }

    .automations-page .record-cards {
        height: auto;
        overflow-y: visible;
    }

    /* On a phone the panels are stacked in one scrolling column, so their desktop internal
       scroll caps (.home-panel above) would make two nested scroll areas — the classic
       "wrong thing scrolls" trap. Let the page scroll as one flow instead. */
    .home-panel {
        max-height: none;
        overflow-y: visible;
    }

    .home-search-results {
        max-height: 60vh;
    }

    /* No Ctrl key on a phone, and the narrow box needs the width more than the hint. */
    .home-search-hint {
        display: none;
    }

    /* Show bottom navigation bar */
    .bottom-nav {
        display: flex;
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        z-index: 999;
        background: var(--colorNeutralBackground1);
        border-top: 1px solid var(--colorNeutralStroke2);
        justify-content: space-around;
        padding: 0.25rem 0;
        /* safe-area for phones with home indicator */
        padding-bottom: max(0.25rem, env(safe-area-inset-bottom));
    }

    /* Native links (not FluentAnchorButton): an icon over a label, which the shadow-DOM button
       would only lay out as a row. The icon inherits the link colour, so .active tints both. */
    .bottom-nav a {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 0.15rem;
        height: 3.25rem;
        padding: 0 1rem;
        font-size: 0.7rem;
        text-decoration: none;
        color: var(--colorNeutralForeground1);
    }

    .bottom-nav a.active {
        color: var(--colorBrandForeground1);
        font-weight: 600;
    }

    /* Hide grid, show cards */
    .record-grid {
        display: none !important;
    }

    .record-cards {
        display: flex;
        flex-direction: column;
        gap: 0.375rem;
    }

    .record-sort-select {
        display: block;
    }

    .record-card {
        background: var(--colorNeutralBackground2);
        border-radius: 0.5rem;
        /* Left padding is wider than the others: it has to clear the 12px inset to-do stripe
           (.todo-atty.todo-client below) with room to spare, or the text sits flush against it. */
        padding: 0.625rem 0.75rem 0.625rem 1.125rem;
        border: 1px solid var(--colorNeutralStroke2);
    }

    .record-card .record-card-header {
        display: flex;
        align-items: center;
        gap: 0.5rem;
    }

    .record-card .record-name {
        font-weight: 600;
        font-size: 1rem;
    }

    .record-card .record-detail {
        font-size: 0.85rem;
        color: var(--colorNeutralForeground2);
    }

    .record-card .record-detail-row {
        display: flex;
        gap: 0.5rem;
        flex-wrap: wrap;
        margin-top: 0.25rem;
    }

    .record-card .record-card-meta {
        display: flex;
        align-items: center;
        gap: 0.5rem;
        margin-top: 0.25rem;
        font-size: 0.75rem;
        color: var(--colorNeutralForeground2);
    }

        .record-card {
            flex-direction: row;
            display: flex;
        }

        .record-card-body {
            flex: 1;
            min-width: 0;
        }

        .record-card-rail {
            display: flex;
            flex-direction: column;
            flex-shrink: 0;
            margin-left: 0.375rem;
        }

        .record-action-btn {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            width: 2rem;
            flex: 1 1 0;
            min-height: 1.75rem;
            border: 1px solid var(--colorNeutralStroke2);
            border-bottom: none;
            color: var(--colorBrandForeground1);
            background: transparent;
            text-decoration: none;
        }

        .record-action-btn:first-child {
            border-radius: 0.375rem 0.375rem 0 0;
        }

        .record-action-btn:last-child {
            border-bottom: 1px solid var(--colorNeutralStroke2);
            border-radius: 0 0 0.375rem 0.375rem;
        }

        .record-action-btn:only-child {
            border-radius: 0.375rem;
            border-bottom: 1px solid var(--colorNeutralStroke2);
            height: 100%;
            min-height: 3rem;
        }
}

/* ── Record detail page (client, case) ── */
.back-link {
    display: inline-block;
    margin-bottom: 0.5rem;
    color: var(--colorBrandForeground1);
    text-decoration: none;
}

.record-landing-actions {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    max-width: 420px;
}

.record-landing-btn {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.75rem 1rem;
    border: 1px solid var(--colorNeutralStroke2);
    border-radius: 0.5rem;
    background: var(--colorNeutralBackground2);
    color: var(--colorNeutralForeground1);
    text-decoration: none;
    font-size: 1rem;
    font: inherit;
    cursor: pointer;
    width: 100%;
    box-sizing: border-box;
    text-align: left;
}

.record-landing-btn svg {
    flex-shrink: 0;
    color: var(--colorBrandForeground1);
}

.record-landing-btn.disabled {
    opacity: 0.4;
    pointer-events: none;
}

/* ── Login link ── A plain <a>, not FluentAnchorButton: /auth/login is a minimal-API
   endpoint, not a routable component, and FluentAnchorButton's real anchor is rendered
   inert (it drives navigation itself via JS instead of native anchor click semantics),
   so target="_top" on it never actually reaches the browser - every click gets replayed
   through Blazor's own router instead, which 404s. A plain anchor's target="_top" is what
   Blazor's click interception itself honors (see MainLayout's LoginHref comment), so this
   is styled by hand to keep the same primary-button look. */
.login-link-btn {
    display: inline-block;
    padding: 0.375rem 0.875rem;
    border-radius: 0.25rem;
    background: var(--colorBrandBackground);
    color: var(--colorNeutralForegroundOnBrand);
    text-decoration: none;
    font-weight: 600;
    font-size: 1rem;
}

/* First-class event slots in CaseEditDialog: each slot is a two-line button (when, purpose)
   that opens EventEditDialog. Fluent tokens so it follows the theme. */
.event-slot {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    width: 100%;
    padding: 6px 10px;
    text-align: left;
    font: inherit;
    color: var(--colorNeutralForeground1);
    background: var(--colorNeutralBackground1);
    border: 1px solid var(--colorNeutralStroke1);
    border-radius: var(--borderRadiusMedium);
    cursor: pointer;
}

.event-slot:hover:not(:disabled) {
    background: var(--colorNeutralBackground1Hover);
}

.event-slot:disabled {
    cursor: default;
    color: var(--colorNeutralForegroundDisabled);
}

.event-slot-purpose {
    min-height: 1lh;
    color: var(--colorNeutralForeground2);
}
