/* =========================================================================
   Docket Management System — Design System (v0.6.0 — unified light theme)
   ==========================================================================
   UI-only redesign. Every class name below that is referenced by JavaScript
   is preserved exactly (see the "JS-DEPENDENT" markers throughout) — only
   visual values changed. New class names introduced here are additive and
   touch no .js file. v0.6.0: one palette site-wide (see the removed
   dark-mode block below for what changed and why).
   ========================================================================= */

/* -------------------------------------------------------------------------
   1. Design tokens
   ------------------------------------------------------------------------- */
:root {
  /* Color — this is now the ONE Branch9 palette, used on every page.
     (Previously only home.html's cream/white workspace used these exact
     values, via a body.page-home override — see the removed dark-mode
     block below for that history.) */
  --ink:        #1A1508;   /* primary text */
  --ink-2:      #4A4030;   /* secondary text, labels */
  --ink-3:      #6B6152;   /* tertiary text, placeholders, muted */
  --brass:      #A9802E;   /* retained, currently unused — see --accent below */
  --brass-dark: #8C6A24;
  --accent:     #2C5282;   /* primary actions — buttons, links, active nav, focus rings */
  --accent-dark:#1E3A5F;
  --maroon:     #7A2E2E;   /* sparing signature accent only */
  --paper:      #FAF7EF;   /* page background */
  --card:       #FFFFFF;
  --line:       #E4DFCF;
  --line-strong:#C9C2AC;

  --green:    #2F6B4F; --green-bg: #E1EFE6;
  --amber:    #8A5A00; --amber-bg: #FBEBCF;
  --red:      #9C3B2E; --red-bg:   #F7E3DF;
  --blue:     #2C5282; --blue-bg:  #E3ECF7;
  --purple:   #6B4FA0; --purple-bg:#EEE8F7;
  --gray-bg:  #EEEDE7;

  /* Type scale */
  --text-xs:   11px;
  --text-sm:   12.5px;
  --text-base: 14px;
  --text-md:   16px;
  --text-lg:   19px;
  --text-xl:   24px;
  --text-display: 30px;

  /* Both point to the same modern sans-serif now — the old serif
     (Source Serif 4) is retired site-wide per the "clean modern
     sans-serif, avoid excessive serif styling" direction. Kept as two
     separate tokens (rather than collapsing to one) so hierarchy can
     still be tuned independently later without touching every call site. */
  --font-display: 'Inter', -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  --font-body: 'Inter', -apple-system, "Segoe UI", Roboto, Arial, sans-serif;

  /* Spacing (4px base) */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;

  /* Radius / shadow */
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
  --shadow-sm: 0 1px 2px rgba(22, 35, 58, 0.06);
  --shadow-md: 0 8px 24px rgba(22, 35, 58, 0.10);
  --shadow-lg: 0 20px 60px rgba(22, 35, 58, 0.30);

  --nav-height: 60px;
  --nav-width: 232px;
  --nav-bg: #16233A;         /* nav/structural chrome */
  --nav-accent: #7BAAE0;     /* brighter blue for icons/active-state/focus ON the navy nav — --accent itself is tuned for light backgrounds, so a lighter value is used here for contrast against --nav-bg */

  --zebra-tint: rgba(22, 35, 58, 0.02);
  --row-hover-tint: rgba(169, 128, 46, 0.06);

  /* Explicit: keep native form controls/scrollbars light even if the
     visitor's OS prefers dark. See "Dark mode" note below. */
  color-scheme: light;
}

/* ---------------------------------------------------------------------- */
/* Dark mode note (removed): this file used to auto-switch every token    */
/* above to a dark palette via @media (prefers-color-scheme: dark), plus  */
/* a body.page-home override that opted the Dashboard back out of it.     */
/* There was never an in-app toggle for this — it only ever fired based   */
/* on the visitor's OS/browser preference — so per explicit direction     */
/* ("if the existing dark theme is simply the old default styling rather  */
/* than an intentional user-selectable dark mode, replace it") it's been  */
/* removed outright rather than extended to every page. Branch9 now has   */
/* exactly one palette, defined once above, used everywhere. If a real    */
/* user-selectable dark mode is wanted later, this is the block to        */
/* reintroduce — ideally behind a toggle rather than automatic detection. */
/* ---------------------------------------------------------------------- */

/* -------------------------------------------------------------------------
   2. Reset / base
   ------------------------------------------------------------------------- */
* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { font-family: var(--font-display); font-weight: 600; margin: 0; color: var(--ink); }
a { color: var(--accent-dark); }

button, input, select, textarea { font-family: inherit; }

/* -------------------------------------------------------------------------
   3. Layout shells
   ------------------------------------------------------------------------- */
.wrap {
  max-width: 1080px;
  margin: 0 auto;
  padding: var(--space-8) var(--space-5) 60px;
}

.wrap-narrow { max-width: 440px; }
/* Was 1080px — far too narrow on desktop, leaving a large unused margin
   on the right of every page except the dashboard (which had its own,
   separate .wrap-dashboard override at 1440px). Consolidated: one class,
   one value, used by every page including the dashboard now — home.html
   no longer needs its own width override (see home.html's <main> class,
   changed from "wrap wrap-dashboard" to "wrap wrap-wide" to match).
   1600px still leaves ~90-100px of breathing room on a 1920px display
   rather than going fully edge-to-edge, while comfortably filling
   smaller desktop/laptop widths since this is a max-width cap, not a
   fixed width — .wrap has no fixed width, so it still shrinks naturally
   on narrower viewports and phones exactly as before. */
.wrap-wide { max-width: 1600px; }

/* Phase 3: replaces a one-off `style="padding-top: 0; padding-bottom: 0;"`
   previously duplicated inline on 404.html and login.html's <main> (both
   sit inside .login-shell, which centers them vertically itself, so the
   default .wrap top/bottom padding was redundant there). */
.wrap-flush-y { padding-top: 0; padding-bottom: 0; }

.header { margin-bottom: var(--space-6); }

.header .eyebrow {
  font-size: var(--text-xs);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 var(--space-2);
  font-weight: 600;
}

.header h1 {
  font-size: var(--text-display);
  margin: 0 0 var(--space-2);
}

.header .sub {
  font-size: var(--text-base);
  color: var(--ink-2);
  margin: 0;
  line-height: 1.55;
}

.header .sub a { color: var(--accent-dark); font-weight: 500; text-decoration: none; }
.header .sub a:hover { text-decoration: underline; }

.footnote {
  margin-top: var(--space-5);
  font-size: var(--text-xs);
  color: var(--ink-3);
  line-height: 1.5;
}

/* -------------------------------------------------------------------------
   4. Navigation
   ------------------------------------------------------------------------- */
/* Base rules below are shared by both tiers. Desktop (>1024px) lays these
   out as a fixed left sidebar (see the "Left sidebar" block further down,
   which sits right before the existing ≤1024px responsive rules). Tablet/
   phone (≤1024px) keep the original wrapping top-bar layout entirely
   unchanged — same rules, same breakpoints, same behavior as before. */
.app-nav {
  position: sticky;
  top: 0;
  z-index: 40;
  height: var(--nav-height);
  background: var(--nav-bg);
  display: flex;
  align-items: center;
  padding: 0 var(--space-6);
  gap: var(--space-8);
}

/* Signature detail: a slender navy-to-blue-to-maroon hairline under the nav bar */
.app-nav::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -3px;
  height: 3px;
  background: linear-gradient(90deg, var(--nav-bg) 0%, var(--nav-accent) 55%, var(--maroon) 100%);
}

.app-nav-brand {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  color: #fff;
  white-space: nowrap;
  min-width: 0;
  text-decoration: none;
}

.app-nav-brand-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-sm);
  background: #fff;
  flex-shrink: 0;
}

.app-nav-brand-icon svg { width: 19px; height: 19px; color: var(--nav-bg); }

.app-nav-brand-text {
  display: flex;
  flex-direction: column;
  justify-content: center;
  line-height: 1.3;
  min-width: 0;
}

.app-nav-brand-title {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--text-md);
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.app-nav-brand-subtitle {
  font-family: var(--font-body);
  font-size: 10.5px;
  font-weight: 400;
  color: #A9B1C4;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Sidebar collapse toggle — lives in the nav itself (not a page-specific
   header) so it's available on every authenticated page, not just one.
   Hidden by default: the collapse behavior only exists for the desktop
   fixed-column sidebar (see "Left sidebar" below), so on the tablet/phone
   top-bar tier this control has nothing to do and stays out of the way. */
.app-nav-toggle { display: none; }

.app-nav-links {
  display: flex;
  gap: var(--space-2);
  flex: 1;
}

.app-nav-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: 36px;
  padding: 0 var(--space-4);
  border-radius: var(--radius-sm);
  color: #C4CAD6;
  font-size: var(--text-sm);
  font-weight: 500;
  text-decoration: none;
  transition: background 0.15s ease, color 0.15s ease;
}

.app-nav-link svg { width: 15px; height: 15px; }

.app-nav-link:hover { background: rgba(255, 255, 255, 0.08); color: #fff; }

.app-nav-link:focus-visible,
.app-nav-logout:focus-visible {
  outline: 2px solid var(--nav-accent);
  outline-offset: 2px;
}

.app-nav-link.active {
  background: rgba(123, 170, 224, 0.18);
  color: #fff;
}

.app-nav-user {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  white-space: nowrap;
}

.app-nav-email {
  font-size: var(--text-xs);
  color: #B9C2CF;
}

.app-nav-logout {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: 32px;
  padding: 0 var(--space-3);
  border-radius: var(--radius-sm);
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
  font-size: var(--text-xs);
  font-family: inherit;
  cursor: pointer;
  transition: background 0.15s ease;
}

.app-nav-logout svg { width: 14px; height: 14px; }
.app-nav-logout:hover { background: rgba(255, 255, 255, 0.14); }

/* ---------------------------------------------------------------------- */
/* Left sidebar (desktop, >1024px)                                        */
/*                                                                          */
/* Same markup, same classes as the tablet/phone top bar above — this is  */
/* a layout-only override. .app-nav becomes a fixed-position column       */
/* instead of a sticky row; .app-nav-links stacks vertically instead of   */
/* running inline; .app-nav-user moves to the bottom of the column via    */
/* margin-top: auto instead of sitting inline after the links. Nothing    */
/* here touches nav-auth.js's selectors (#userEmail, #logoutBtn,          */
/* .app-nav-links [data-permission]) or renames any class, so the JS that */
/* wires the nav is untouched. Content (.wrap) gets a matching left       */
/* margin so it no longer sits under the fixed column. Scoped with :has() */
/* so pages without a nav (login.html, 404.html) are unaffected.          */
/* ---------------------------------------------------------------------- */
@media (min-width: 1025px) {
  .app-nav {
    position: fixed;
    top: 0;
    left: 0;
    width: var(--nav-width);
    height: 100vh;
    overflow-y: auto;
    flex-direction: column;
    align-items: stretch;
    padding: var(--space-6) var(--space-4);
    gap: 0;
  }

  .app-nav::after {
    left: auto;
    top: 0;
    bottom: 0;
    right: -3px;
    width: 3px;
    height: auto;
    background: linear-gradient(180deg, var(--nav-bg) 0%, var(--nav-accent) 55%, var(--maroon) 100%);
  }

  .app-nav-brand {
    padding: var(--space-2) var(--space-2) var(--space-5);
    margin-bottom: var(--space-3);
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  }

  .app-nav-toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    height: 36px;
    padding: 0 var(--space-4);
    margin-bottom: var(--space-3);
    border: none;
    border-radius: var(--radius-sm);
    background: none;
    color: #C4CAD6;
    font-size: var(--text-sm);
    font-weight: 500;
    font-family: inherit;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
  }

  .app-nav-toggle svg { width: 15px; height: 15px; flex-shrink: 0; }
  .app-nav-toggle:hover { background: rgba(255, 255, 255, 0.08); color: #fff; }
  .app-nav-toggle:focus-visible { outline: 2px solid var(--nav-accent); outline-offset: 2px; }

  .app-nav-links {
    flex: 0 1 auto;
    flex-direction: column;
    gap: var(--space-1);
  }

  .app-nav-link { width: 100%; justify-content: flex-start; }

  .app-nav-user {
    margin-top: auto;
    padding-top: var(--space-4);
    border-top: 1px solid rgba(255, 255, 255, 0.1);
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-3);
  }

  .app-nav-email {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .app-nav-logout { width: 100%; justify-content: center; }

  body:has(.app-nav) .wrap {
    margin-left: var(--nav-width);
  }

  /* .data-table th's sticky offset (top: var(--nav-height)) exists to
     clear the sticky top bar on tablet/phone. There's no top bar taking
     up vertical space on desktop anymore — the nav is a fixed sidebar
     that doesn't push page content down — so the sticky header should
     stick to the very top of the scroll container here instead. */
  .data-table th {
    top: 0;
  }
}

/* ---------------------------------------------------------------------- */
/* Sidebar collapse — toggled app-wide by #sidebarToggleBtn (now part of  */
/* the shared nav markup, wired once in nav-auth.js) via                  */
/* body.sidebar-collapsed. Uses font-size:0 to hide the raw text nodes in */
/* nav links/toggle/logout without wrapping every page's shared nav       */
/* markup in <span> elements — every icon's size is set via explicit      */
/* width/height (see .app-nav-link svg etc. above), not font-size, so     */
/* icons stay visible while labels collapse to nothing. State is          */
/* persisted to localStorage (see nav-auth.js) so it stays consistent as  */
/* the user moves between pages instead of resetting on every navigation. */
/* ---------------------------------------------------------------------- */
@media (min-width: 1025px) {
  body.sidebar-collapsed .app-nav {
    width: 72px;
    padding-left: var(--space-2);
    padding-right: var(--space-2);
  }

  body.sidebar-collapsed .app-nav-link,
  body.sidebar-collapsed .app-nav-logout,
  body.sidebar-collapsed .app-nav-toggle {
    font-size: 0;
    justify-content: center;
    gap: 0;
    padding-left: 0;
    padding-right: 0;
  }

  /* .app-nav-brand-title/.app-nav-brand-subtitle set their own explicit
     font-size, so they don't inherit a font-size:0 from a collapsed
     ancestor the way plain text nodes do — hide the text column
     directly instead. */
  body.sidebar-collapsed .app-nav-brand-text { display: none; }
  body.sidebar-collapsed .app-nav-brand { justify-content: center; gap: 0; }

  body.sidebar-collapsed .app-nav-email { display: none; }

  /* Was scoped to .page-home only, from when the toggle existed on the
     dashboard alone. Now that every authenticated page can collapse the
     sidebar, every page's content needs to reclaim that space. */
  body.sidebar-collapsed .wrap {
    margin-left: 72px;
  }
}

/* -------------------------------------------------------------------------
   5. Cards
   ------------------------------------------------------------------------- */
.card {                                                        /* JS-DEPENDENT: class name emitted by hearings.js/calendar.js templates */
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  box-shadow: var(--shadow-sm);
}

.form-card { margin-bottom: var(--space-6); }                  /* JS-DEPENDENT */
.form-card h2 { font-size: var(--text-lg); margin: 0 0 var(--space-4); }

.cal-content-card { padding: var(--space-4); overflow-x: auto; } /* JS-DEPENDENT */

.card-flush { padding: 0; }

/* -------------------------------------------------------------------------
   6. Buttons
   ------------------------------------------------------------------------- */
.btn-primary, .btn-secondary, .btn-small {                      /* JS-DEPENDENT class names */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font-family: inherit;
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: background 0.12s ease, border-color 0.12s ease, opacity 0.12s ease;
}

.btn-primary svg, .btn-secondary svg, .btn-small svg { width: 15px; height: 15px; flex-shrink: 0; }

.btn-primary:focus-visible,
.btn-secondary:focus-visible,
.btn-small:focus-visible {
  outline: 2px solid var(--accent-dark);
  outline-offset: 2px;
}

.btn-primary {                                                  /* JS-DEPENDENT */
  width: 100%;
  height: 42px;
  border: none;
  background: var(--accent);
  color: #fff;
  font-size: var(--text-base);
  font-weight: 600;
}
.btn-primary:hover { background: var(--accent-dark); }
.btn-primary:disabled, .btn-secondary:disabled, .btn-small:disabled { opacity: 0.55; cursor: not-allowed; }

.btn-inline { width: auto; padding: 0 var(--space-5); }         /* JS-DEPENDENT */

.btn-secondary {                                                /* JS-DEPENDENT */
  height: 38px;
  padding: 0 var(--space-4);
  border: 1px solid var(--line-strong);
  background: var(--card);
  color: var(--ink);
  font-size: var(--text-base);
  font-weight: 500;
}
.btn-secondary:hover { border-color: var(--ink-3); background: var(--paper); }

.btn-small {                                                    /* JS-DEPENDENT */
  height: 30px;
  padding: 0 var(--space-3);
  border: 1px solid var(--line-strong);
  background: var(--card);
  color: var(--ink);
  font-size: var(--text-xs);
  font-weight: 500;
}
.btn-small:hover { border-color: var(--ink-3); background: var(--paper); }
.btn-small.btn-danger { color: var(--red); border-color: #E7C9C2; } /* JS-DEPENDENT */
.btn-small.btn-danger:hover { background: var(--red-bg); }

/* -------------------------------------------------------------------------
   7. Forms / inputs
   ------------------------------------------------------------------------- */
.field { margin-bottom: var(--space-4); display: flex; flex-direction: column; gap: var(--space-1); } /* JS-DEPENDENT */
.field-full { grid-column: 1 / -1; }                            /* JS-DEPENDENT */

.field label {
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--ink-2);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.field input, .field select, .field textarea {                  /* JS-DEPENDENT selectors */
  height: 40px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  padding: 0 var(--space-3);
  font-size: var(--text-base);
  font-family: inherit;
  color: var(--ink);
  background: var(--paper);
  width: 100%;
}

.field textarea { height: auto; min-height: 64px; padding: var(--space-2) var(--space-3); resize: vertical; }

/* Shared focus treatment for every text-style form control across the
   app (main form fields, search inputs, filter selects/dates, the Users
   role select) — consolidated from 6 identical copies into one rule;
   same selectors, same declarations, nothing visually changes. */
.field input:focus, .field select:focus, .field textarea:focus,
.hearings-search input:focus,
.activity-search input:focus,
.activity-filter select:focus,
.report-filter select:focus, .report-filter input[type="date"]:focus,
.role-select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(169, 128, 46, 0.15);
}

.required { color: var(--maroon); }                              /* JS-DEPENDENT */

.form-grid { display: grid; gap: var(--space-3) var(--space-5); margin-bottom: var(--space-2); } /* JS-DEPENDENT */
.form-grid-2 { grid-template-columns: 1fr 1fr; }                /* JS-DEPENDENT */
.form-grid-3 { grid-template-columns: 1.2fr 1fr 1fr; }          /* JS-DEPENDENT */

.form-error {                                                    /* JS-DEPENDENT */
  min-height: 18px;
  font-size: var(--text-sm);
  color: var(--red);
  margin: 0 0 var(--space-3);
}

/* Phase 3: modifier for a static, non-error informational notice reusing
   .form-error's box (role="alert", same spacing) with neutral instead of
   red styling — replaces a one-off `style="color: var(--ink); font-weight:
   600;"` previously duplicated inline on migration-dryrun.html and
   migration-execute.html's tool-disclosure paragraphs. Always combined
   with .form-error in markup, never used alone. */
.form-notice {
  color: var(--ink);
  font-weight: 600;
}

.form-actions {                                                  /* JS-DEPENDENT */
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}

.case-rows-section { border-top: 1px solid var(--line); margin-top: var(--space-4); padding-top: var(--space-4); } /* JS-DEPENDENT */
.case-rows-section h3 { font-size: var(--text-base); margin: 0 0 var(--space-3); font-family: var(--font-body); font-weight: 600; }

.case-row {                                                      /* JS-DEPENDENT — read by hearings.js querySelectorAll */
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  padding: var(--space-3);
  margin-bottom: var(--space-3);
  background: var(--paper);
}

.case-row-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--space-2); } /* JS-DEPENDENT */
.case-row-label { font-size: var(--text-xs); font-weight: 600; color: var(--ink-2); text-transform: uppercase; letter-spacing: .03em; } /* JS-DEPENDENT */

/* CSS-only "remove" icon on dynamically-rendered case-row remove buttons */
[data-remove-case]::before { content: ""; display: inline-block; width: 13px; height: 13px; margin-right: 4px; vertical-align: -2px;
  background-color: var(--red); -webkit-mask: var(--icon-x) center / contain no-repeat; mask: var(--icon-x) center / contain no-repeat; }

/* -------------------------------------------------------------------------
   8. Tables (productivity: sticky header, zebra, hover, tabular figures)
   ------------------------------------------------------------------------- */
.data-table {                                                    /* JS-DEPENDENT */
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}

.data-table th {
  position: sticky;
  top: var(--nav-height);
  z-index: 5;
  text-align: left;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink-2);
  font-weight: 600;
  padding: var(--space-3) var(--space-4);
  background: var(--paper);
  border-bottom: 2px solid var(--line-strong);
}

.data-table td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}

.data-table tbody tr:nth-child(even) { background: var(--zebra-tint); }
.data-table tbody tr:hover { background: var(--row-hover-tint); }
.data-table tbody tr[tabindex]:focus-visible {                    /* JS-DEPENDENT: rows made keyboard-focusable in hearings.js/archived.js */
  outline: 2px solid var(--accent-dark);
  outline-offset: -2px;
}
.data-table tr:last-child td { border-bottom: none; }

/* Round the table's own corners (rather than clipping the card with
   overflow:hidden, which would break the sticky <thead> above by
   confining its sticky positioning to the card instead of the viewport). */
.data-table thead th:first-child { border-top-left-radius: var(--radius-lg); }
.data-table thead th:last-child { border-top-right-radius: var(--radius-lg); }
.data-table tbody tr:last-child td:first-child { border-bottom-left-radius: var(--radius-lg); }
.data-table tbody tr:last-child td:last-child { border-bottom-right-radius: var(--radius-lg); }

/* Status column badge-ify. Coupled to column order in hearings.html's
   <thead> (Date, Time, Section, Status, ...) since hearings.js emits plain
   <td> text with no dedicated class — a deliberate CSS-only trade-off so
   no .js file needs editing. If the column order ever changes, update the
   nth-child index below. */
.data-table tbody td:nth-child(4) {
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--blue);
}
.data-table tbody td:nth-child(4)::before {
  content: "";
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--blue);
  margin-right: 6px;
}

.empty-row {                                                     /* JS-DEPENDENT */
  text-align: center;
  color: var(--ink-3);
}
/* Phase 3: was `padding: ... !important;` — the !important was only
   needed because `.empty-row` alone (0,1,0) loses specificity to
   `.data-table td` (0,1,1) above. Scoping the selector to `.data-table`
   wins on specificity instead, so !important is no longer needed. This
   was the CSS's only !important (Phase 2 audit §9/§22); removed rather
   than documented-and-kept, since the fix required no fragile selector
   escalation. */
.data-table .empty-row {
  padding: var(--space-8) var(--space-4);
}

.muted { color: var(--ink-3); font-style: italic; }              /* JS-DEPENDENT */

.row-actions { display: flex; gap: var(--space-2); white-space: nowrap; } /* JS-DEPENDENT */

[data-action="edit"]::before { content: ""; display: inline-block; width: 13px; height: 13px; margin-right: 4px; vertical-align: -2px;
  background-color: var(--ink-2); -webkit-mask: var(--icon-pencil) center / contain no-repeat; mask: var(--icon-pencil) center / contain no-repeat; }

/* -------------------------------------------------------------------------
   9. Toolbar (Hearings / Calendar / Activity Log / Reports)
   ------------------------------------------------------------------------- */
.toolbar { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: var(--space-3); margin-bottom: var(--space-2); } /* JS-DEPENDENT */

.export-dropdown {
  position: relative;
}

.export-dropdown-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 30;
  background: var(--card);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: var(--space-3);
  width: 260px;
}

.export-dropdown-date-row {
  display: flex;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}

.export-dropdown-date-row input[type="date"] {
  flex: 1;
  min-width: 0;
  height: 32px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  padding: 0 var(--space-2);
  font-size: var(--text-xs);
  font-family: inherit;
  color: var(--ink);
  background: var(--paper);
}

.export-dropdown-divider {
  height: 1px;
  background: var(--line);
  margin: var(--space-2) 0;
}

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

.export-dropdown-item:hover {
  background: var(--paper);
}

.export-dropdown-item:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

#toolbarExportStatus {
  text-align: right;
  margin-bottom: var(--space-4);
}

/* -------------------------------------------------------------------------
   10. Status dots (diagnostics.html) — pure CSS, keyed to classes already
       toggled by the existing, untouched diagnostics.js
   ------------------------------------------------------------------------- */
.status-list { list-style: none; margin: 0; padding: 0; }        /* JS-DEPENDENT */

.status-item {                                                   /* JS-DEPENDENT */
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--line);
  font-size: var(--text-base);
}
.status-item:last-child { border-bottom: none; }

.dot {                                                            /* JS-DEPENDENT — classes toggled by diagnostics.js */
  width: 20px;
  height: 20px;
  border-radius: 50%;
  flex-shrink: 0;
  position: relative;
  background: var(--gray-bg);
  border: 2px solid var(--ink-3);
}
.dot.pending { background: var(--gray-bg); border-color: var(--ink-3); }
.dot.pass { background: var(--green); border-color: var(--green); }
.dot.fail { background: var(--red); border-color: var(--red); }

.dot.pass::after, .dot.fail::after {
  content: "";
  position: absolute; inset: 4px;
  background-color: #fff;
}
.dot.pass::after { -webkit-mask: var(--icon-check) center / contain no-repeat; mask: var(--icon-check) center / contain no-repeat; }
.dot.fail::after { -webkit-mask: var(--icon-x) center / contain no-repeat; mask: var(--icon-x) center / contain no-repeat; }

.label { flex: 1; font-weight: 500; }
.detail { font-size: var(--text-xs); color: var(--ink-2); }

.overall {                                                        /* JS-DEPENDENT */
  margin-top: var(--space-5);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  font-weight: 500;
  background: var(--gray-bg);
  color: var(--ink-2);
}
.overall.pass { background: var(--green-bg); color: var(--green); }
.overall.fail { background: var(--red-bg); color: var(--red); }

/* -------------------------------------------------------------------------
   11. Login-specific
   ------------------------------------------------------------------------- */
.login-shell { min-height: 100vh; display: flex; align-items: center; justify-content: center; }

.dashboard-welcome { font-size: var(--text-base); margin: 0 0 var(--space-4); }

/* -------------------------------------------------------------------------
   13. Calendar
   ------------------------------------------------------------------------- */
.cal-toolbar { display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; margin-bottom: var(--space-4); } /* JS-DEPENDENT */

.cal-view-toggle { display: flex; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); overflow: hidden; } /* JS-DEPENDENT */

.cal-view-btn {                                                   /* JS-DEPENDENT */
  height: 36px; padding: 0 var(--space-4); border: none; background: var(--card);
  color: var(--ink); font-size: var(--text-sm); font-family: inherit; cursor: pointer;
  border-right: 1px solid var(--line-strong);
}
.cal-view-btn:last-child { border-right: none; }
.cal-view-btn-active { background: var(--nav-bg); color: #fff; }    /* JS-DEPENDENT — applied via classList.toggle */

.cal-nav { display: flex; gap: var(--space-2); }                 /* JS-DEPENDENT */
.cal-label { font-size: var(--text-base); font-weight: 600; margin-left: auto; font-family: var(--font-display); } /* JS-DEPENDENT */

/* Month view */
.cal-month-grid {                                                 /* JS-DEPENDENT */
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px;
  background: var(--line); border: 1px solid var(--line); border-radius: var(--radius-md); overflow: hidden;
}
.cal-month-headcell { background: var(--paper); padding: var(--space-2); font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-2); text-align: center; font-weight: 600; } /* JS-DEPENDENT */
.cal-month-cell { background: var(--card); min-height: 108px; padding: var(--space-2); cursor: pointer; } /* JS-DEPENDENT */
.cal-month-cell:hover { background: var(--paper); }
.cal-month-cell[tabindex]:focus-visible {                          /* JS-DEPENDENT: cells made keyboard-focusable in calendar.js */
  outline: 2px solid var(--accent-dark);
  outline-offset: -2px;
}
.cal-month-cell-muted { opacity: 0.4; }                           /* JS-DEPENDENT */
.cal-month-cell-today .cal-month-daynum { background: var(--accent); color: #fff; border-radius: 50%; } /* JS-DEPENDENT */
.cal-month-daynum { font-size: var(--text-sm); font-weight: 600; width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; margin-bottom: var(--space-1); } /* JS-DEPENDENT */
.cal-month-entries { display: flex; flex-direction: column; gap: 3px; }  /* JS-DEPENDENT */
.cal-month-entry { font-size: var(--text-xs); background: var(--blue-bg); color: var(--blue); padding: 2px 6px; border-radius: var(--radius-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; } /* JS-DEPENDENT */
.cal-month-entry:hover { opacity: 0.85; }
.cal-month-more { font-size: var(--text-xs); color: var(--ink-3); }  /* JS-DEPENDENT */

/* Week view */
.cal-week-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--space-2); } /* JS-DEPENDENT */
.cal-week-col { border: 1px solid var(--line); border-radius: var(--radius-md); min-height: 210px; } /* JS-DEPENDENT */
.cal-week-colhead { text-align: center; font-size: var(--text-sm); font-weight: 600; padding: var(--space-2); border-bottom: 1px solid var(--line); background: var(--paper); border-radius: var(--radius-md) var(--radius-md) 0 0; } /* JS-DEPENDENT */
.cal-week-colhead-today { color: var(--accent-dark); }             /* JS-DEPENDENT */
.cal-week-entries { padding: var(--space-2); display: flex; flex-direction: column; gap: var(--space-2); } /* JS-DEPENDENT */
.cal-week-entry { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: var(--space-2) var(--space-3); font-size: var(--text-xs); cursor: pointer; } /* JS-DEPENDENT */
.cal-week-entry:hover { border-color: var(--ink-3); background: var(--paper); }
.cal-week-entry-time { font-weight: 600; }                        /* JS-DEPENDENT */
.cal-week-entry-section { color: var(--ink-2); }                  /* JS-DEPENDENT */
.cal-week-entry-status { color: var(--ink-2); font-style: italic; } /* JS-DEPENDENT */
.cal-week-entry-count { color: var(--ink-3); margin-top: 2px; display: inline-block; } /* JS-DEPENDENT */
.cal-week-empty { font-size: var(--text-xs); color: var(--ink-3); text-align: center; padding: var(--space-3) var(--space-1); } /* JS-DEPENDENT */

/* Day view */
.cal-day-list { display: flex; flex-direction: column; gap: var(--space-3); }  /* JS-DEPENDENT */
.cal-day-card { border: 1px solid var(--line); border-radius: var(--radius-md); padding: var(--space-4); background: var(--card); } /* JS-DEPENDENT */
.cal-day-card-main { display: flex; align-items: flex-start; gap: var(--space-4); }  /* JS-DEPENDENT */
.cal-day-card-time { width: 130px; flex-shrink: 0; font-weight: 600; font-size: var(--text-base); } /* JS-DEPENDENT */
.cal-day-card-body { flex: 1; min-width: 0; }                     /* JS-DEPENDENT */
.cal-day-card-title { margin: 0; font-size: var(--text-base); font-weight: 500; }  /* JS-DEPENDENT */
.cal-day-card-meta { margin: 3px 0 0; font-size: var(--text-sm); color: var(--ink-2); }  /* JS-DEPENDENT */
.cal-day-card-actions { display: flex; flex-direction: column; gap: var(--space-2); flex-shrink: 0; } /* JS-DEPENDENT */
.cal-details-link { text-align: center; text-decoration: none; display: inline-flex; align-items: center; justify-content: center; gap: 4px; } /* JS-DEPENDENT */
.cal-details-link::after { content: ""; width: 12px; height: 12px; background-color: currentColor; -webkit-mask: var(--icon-arrow-right) center / contain no-repeat; mask: var(--icon-arrow-right) center / contain no-repeat; }

[data-toggle-expand]::before { content: ""; display: inline-block; width: 13px; height: 13px; margin-right: 2px; vertical-align: -2px;
  background-color: var(--ink); -webkit-mask: var(--icon-chevron-down) center / contain no-repeat; mask: var(--icon-chevron-down) center / contain no-repeat; }

.cal-day-card-cases { border-top: 1px solid var(--line); margin-top: var(--space-3); padding-top: var(--space-3); } /* JS-DEPENDENT */
.cal-case-list { margin: 0; padding-left: 18px; font-size: var(--text-sm); }  /* JS-DEPENDENT */
.cal-case-list li { margin-bottom: var(--space-1); }
.cal-case-empty, .cal-case-loading { font-size: var(--text-sm); color: var(--ink-3); margin: 0; } /* JS-DEPENDENT */

/* -------------------------------------------------------------------------
   14. Firebase fatal-error overlay — class/id names are hardcoded inside
       auth-guard.js's JS (element.className / innerHTML strings), so they
       are preserved exactly here.
   ------------------------------------------------------------------------- */
.fatal-overlay {                                                  /* JS-DEPENDENT — set via el.className in auth-guard.js */
  position: fixed; inset: 0; background: rgba(22, 35, 58, 0.92);
  z-index: 1000; display: flex; align-items: center; justify-content: center; padding: var(--space-5);
}
.fatal-card {                                                     /* JS-DEPENDENT */
  background: var(--card); border-radius: var(--radius-lg); max-width: 440px; width: 100%;
  padding: var(--space-8) var(--space-6); box-shadow: var(--shadow-lg);
}
.fatal-card h2 { margin: 0 0 var(--space-3); font-size: var(--text-lg); color: var(--red); }
.fatal-card p { font-size: var(--text-base); color: var(--ink-2); margin: 0 0 var(--space-3); line-height: 1.55; }
.fatal-card p:last-child { margin-bottom: 0; }
.fatal-detail {                                                   /* JS-DEPENDENT */
  font-size: var(--text-xs); font-family: monospace; background: var(--paper);
  border: 1px solid var(--line); border-radius: var(--radius-sm); padding: var(--space-2) var(--space-3);
  color: var(--ink-3); word-break: break-word;
}

/* ---------------------------------------------------------------------- */
/* v0.7.1 — Hearing Quick View (read-only modal, hearings.html)            */
/* Same overlay/card visual language as .fatal-overlay above, new class    */
/* names (no JS depends on .fatal-* here — this is a separate concern).    */
/* ---------------------------------------------------------------------- */

[data-hearing-row] {
  cursor: pointer;
}

.preview-overlay {
  position: fixed;
  inset: 0;
  background: rgba(22, 35, 58, 0.55);
  z-index: 900;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: var(--space-8) var(--space-4);
  overflow-y: auto;
}

.preview-card {
  background: var(--card);
  border-radius: var(--radius-lg);
  max-width: 640px;
  width: 100%;
  padding: var(--space-6);
  position: relative;
  box-shadow: var(--shadow-lg);
}

.preview-close {
  position: absolute;
  top: var(--space-4);
  right: var(--space-4);
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--paper);
  color: var(--ink-2);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.preview-close:hover {
  border-color: var(--ink-3);
}

.preview-title {
  font-size: var(--text-lg);
  margin: var(--space-1) var(--space-8) var(--space-4) 0;
}

.preview-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3) var(--space-5);
  margin-bottom: var(--space-4);
}

.preview-field {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.preview-field-label {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--ink-3);
}

.preview-field-value {
  font-size: var(--text-base);
  color: var(--ink);
}

.preview-field-value.muted {
  color: var(--ink-3);
  font-style: italic;
}

.preview-notes {
  border-top: 1px solid var(--line);
  padding-top: var(--space-3);
  margin-bottom: var(--space-4);
}

.preview-cases {
  border-top: 1px solid var(--line);
  padding-top: var(--space-3);
}

.preview-cases h3 {
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: 600;
  margin: 0 0 var(--space-2);
}

.preview-case-item {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3);
  margin-bottom: var(--space-2);
}

.preview-case-no {
  font-weight: 600;
  font-size: var(--text-sm);
  margin: 0;
}

.preview-case-charge,
.preview-case-filed {
  font-size: var(--text-sm);
  color: var(--ink-2);
  margin: 2px 0 0;
}

.preview-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}


/* -------------------------------------------------------------------------
   15. CSS-only icon shapes (mask-image data URIs), used on elements whose
       markup is generated by hearings.js/calendar.js/diagnostics.js —
       lucide.createIcons() never runs against that dynamic content, so
       these icons are rendered purely in CSS instead, in Lucide's visual
       style (24x24, 2px stroke, rounded caps).
   ------------------------------------------------------------------------- */
:root {
  --icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
  --icon-x: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'/%3E%3Cline x1='6' y1='6' x2='18' y2='18'/%3E%3C/svg%3E");
  --icon-pencil: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z'/%3E%3C/svg%3E");
  --icon-chevron-down: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  --icon-arrow-right: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'/%3E%3Cpolyline points='12 5 19 12 12 19'/%3E%3C/svg%3E");
  --icon-lock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='11' width='18' height='11' rx='2'/%3E%3Cpath d='M7 11V7a5 5 0 0 1 10 0v4'/%3E%3C/svg%3E");
}

/* Login submit button icon. Kept as a ::before pseudo-element (not a real
   child element) specifically because login.js sets this button's
   .textContent directly during sign-in ("Signing in…" / "Log in") — a
   real child <i> element would be destroyed by that. Pseudo-elements are
   not part of the DOM .textContent touches, so this survives every state
   change untouched, with zero changes to login.js. */
#submitBtn::before {
  content: "";
  display: inline-block;
  width: 15px;
  height: 15px;
  margin-right: var(--space-2);
  vertical-align: -2px;
  background-color: #fff;
  -webkit-mask: var(--icon-lock) center / contain no-repeat;
  mask: var(--icon-lock) center / contain no-repeat;
}

/* ---------------------------------------------------------------------- */
/* v0.6.1 — Footer / creator credit                                        */
/* New, additive class only — doesn't touch anything JS depends on.        */
/* ---------------------------------------------------------------------- */

/* ---------------------------------------------------------------------- */
/* Dashboard greeting header (home.html only) — new, additive classes.     */
/* Does not touch .header, which every other page still uses as-is.        */
/* ---------------------------------------------------------------------- */

.dashboard-greeting-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-6);
  flex-wrap: wrap;
}

.dashboard-greeting-left {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
}

.dashboard-greeting h1 {
  font-size: var(--text-display);
  margin: 0 0 var(--space-1);
}

/* Dashboard headings/values are bolder than these elements' defaults
   elsewhere, for stronger hierarchy on this page specifically. The
   font-family switch this rule used to do is no longer needed —
   --font-display and --font-body are the same typeface everywhere now
   (see the design-tokens block at the top of this file). These 4
   classes are exclusively used by home.js/home.html (confirmed via
   grep), so this has no effect elsewhere. */
body.page-home .dashboard-greeting h1,
body.page-home .today-panel-title,
body.page-home .session-title,
body.page-home .summary-value,
body.page-home .dashboard-stat-value {
  font-weight: 700;
}

.dashboard-greeting .sub {
  font-size: var(--text-base);
  color: var(--ink-2);
  margin: 0;
}

.dashboard-date-badge {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  white-space: nowrap;
}

.dashboard-date-badge svg {
  width: 18px;
  height: 18px;
  color: var(--ink-3);
  flex-shrink: 0;
}

.dashboard-date-badge-day {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink);
  margin: 0;
}

.dashboard-date-badge-tz {
  font-size: var(--text-xs);
  color: var(--ink-3);
  margin: 0;
}

.dashboard-header-right {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  flex-wrap: wrap;
}

.dashboard-user-chip { position: relative; }

.dashboard-user-chip-trigger {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  background: none;
  border: none;
  padding: var(--space-1);
  border-radius: var(--radius-md);
  cursor: pointer;
  font-family: inherit;
  transition: background 0.12s ease;
}

.dashboard-user-chip-trigger:hover { background: var(--paper); }

.dashboard-user-chip-trigger:focus-visible {
  outline: 2px solid var(--accent-dark);
  outline-offset: 2px;
}

.dashboard-user-chip-trigger svg { width: 16px; height: 16px; color: var(--ink-3); flex-shrink: 0; }

.dashboard-user-avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--nav-bg);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-sm);
  flex-shrink: 0;
}

.dashboard-user-chip-text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 1.3;
}

.dashboard-user-chip-name { font-size: var(--text-sm); font-weight: 600; color: var(--ink); }
.dashboard-user-chip-role { font-size: var(--text-xs); color: var(--ink-3); }

.dashboard-user-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 160px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: var(--space-2);
  z-index: 30;
}

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

.dashboard-user-logout:hover { background: var(--paper); }
.dashboard-user-logout svg { width: 15px; height: 15px; color: var(--ink-3); flex-shrink: 0; }

/* ---------------------------------------------------------------------- */
/* v0.7.0 — Dashboard summary cards (home.html)                            */
/* Reuses existing tokens/typography only — no new colors or fonts.        */
/* ---------------------------------------------------------------------- */

.dashboard-stats-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-4);
  margin-bottom: var(--space-6);
}

.dashboard-stat-card {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  text-align: left;
}

.dashboard-stat-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: var(--radius-md);
  flex-shrink: 0;
}

.dashboard-stat-icon svg { width: 22px; height: 22px; }

.dashboard-stat-icon--blue   { background: var(--blue-bg);   color: var(--blue); }
.dashboard-stat-icon--green  { background: var(--green-bg);  color: var(--green); }
.dashboard-stat-icon--purple { background: var(--purple-bg); color: var(--purple); }

.dashboard-stat-value {
  font-family: var(--font-display);
  font-size: var(--text-display);
  font-weight: 600;
  color: var(--ink);
  margin: 0;
  line-height: 1.15;
}

.dashboard-stat-label {
  font-size: var(--text-xs);
  color: var(--ink-2);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin: 0 0 var(--space-1);
}

.dashboard-stat-sub {
  font-size: var(--text-xs);
  color: var(--ink-3);
  margin: 2px 0 0;
}

.today-panel-title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-lg);
  margin: 0 0 var(--space-4);
}

.today-panel-title svg {
  width: 18px;
  height: 18px;
  color: var(--accent-dark);
  flex-shrink: 0;
}

/* ---------------------------------------------------------------------- */
/* v0.8.1 — Dashboard UX Polish (home.html)                                */
/* Today's Hearings becomes the visual centerpiece: a wide main column     */
/* paired with a narrower sidebar (Now/Next/Summary/Quick Actions), each   */
/* card sized to its own content instead of stretching to match a         */
/* neighbor. Supersedes v0.8.0's .dashboard-live-row (equal-width side-by- */
/* side Session+Summary cards). Reuses existing tokens/status colors      */
/* only — no new colors introduced.                                       */
/* ---------------------------------------------------------------------- */

.dashboard-main-row {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: var(--space-4);
  margin-bottom: var(--space-6);
  align-items: start;
}

.dashboard-main-col {
  min-width: 0;
}

.dashboard-side-col {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  min-width: 0;
}

.dashboard-side-col .card {
  padding: var(--space-5);
}

.dashboard-timeline-card .today-panel-title {
  font-size: var(--text-xl);
}

.session-card,
.summary-card {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* Compact empty states (2/6): no active/next hearing shouldn't reserve
   the same vertical space as a card actually showing hearing details.
   v0.8.2: tightened a bit further as part of the general whitespace
   pass, and given a sibling for the Timeline card's own empty state. */
.session-card--compact {
  padding-top: var(--space-3);
  padding-bottom: var(--space-3);
}

/* v0.8.2: Today's Hearings itself also shrinks slightly when there's
   nothing to show, instead of always reserving full card padding. */
.dashboard-timeline-card--empty {
  padding-bottom: var(--space-4);
}

.session-label,
.summary-title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-xs);
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.09em;
  font-weight: 600;
  margin: 0 0 var(--space-2);
}

.session-label svg,
.summary-title svg {
  width: 14px;
  height: 14px;
  color: var(--ink-3);
  flex-shrink: 0;
}

.session-title {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  color: var(--ink);
  margin: 0;
}

.session-case {
  font-size: var(--text-base);
  color: var(--ink);
  margin: 0;
}

.session-stage {
  font-size: var(--text-sm);
  color: var(--ink-2);
  margin: var(--space-1) 0 0;
}

.session-time {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--accent-dark);
  margin: var(--space-2) 0 0;
}

.session-countdown {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--blue);
  margin: var(--space-2) 0 0;
}

.session-empty {
  font-size: var(--text-sm);
  color: var(--ink-3);
  font-style: italic;
  margin: 0;
}

/* Today's Summary (3): a compact horizontal row of columns instead of
   v0.8.0's stacked rows — reuses the same .summary-value/.summary-label
   typography, just laid out side by side. */
.summary-columns {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-2);
  text-align: center;
}

.summary-col {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-2) 0;
}

.summary-value {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 600;
  color: var(--ink);
}

.summary-label {
  font-size: var(--text-xs);
  color: var(--ink-2);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.quick-actions-card { margin-bottom: 0; }

.quick-actions-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.quick-actions-row .btn-secondary { width: auto; }

/* Dashboard stats-grid error (Phase 5): reuses .form-error's existing box
   model, just given room above the main row instead of its usual
   inside-a-form margin. Hidden by default via the [hidden] attribute set
   in the markup; home.js only un-hides it on a case-stats listener
   failure. */
.dashboard-stats-error { margin: calc(var(--space-4) * -1) 0 var(--space-6); }

/* Phase 5 — Upcoming Hearings panel + shared "panel header with a link"
   pattern. Reuses .today-panel-title/.card/.empty-row rather than
   introducing new typography. */
.dashboard-panel-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-1);
}

.dashboard-panel-header .today-panel-title { margin-bottom: 0; }

.panel-link {
  font-size: var(--text-xs);
  color: var(--accent-dark);
  font-weight: 600;
  white-space: nowrap;
  flex-shrink: 0;
}

.panel-link:hover,
.panel-link:focus-visible { text-decoration: underline; }

.upcoming-card { margin-bottom: 0; }

.upcoming-sub {
  font-size: var(--text-xs);
  color: var(--ink-3);
  margin: 0 0 var(--space-3);
}

.upcoming-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.upcoming-item {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: var(--space-2) var(--space-2);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.upcoming-item:hover { background: var(--paper); }

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

.upcoming-item:not(:last-child) { border-bottom: 1px solid var(--line); }

.upcoming-date {
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--accent-dark);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.upcoming-case {
  font-size: var(--text-sm);
  color: var(--ink);
}

.upcoming-stage {
  font-size: var(--text-xs);
  color: var(--ink-3);
}

/* Error notice's Retry button (Phase 5): sits inside the same
   .inline-notice box notify.js already renders, alongside its dismiss
   button — reuses .inline-notice's color tokens rather than introducing
   a new button style. */
.inline-notice-retry {
  flex-shrink: 0;
  background: none;
  border: 1px solid currentColor;
  border-radius: var(--radius-sm);
  color: inherit;
  font-size: var(--text-xs);
  font-weight: 600;
  padding: 2px var(--space-2);
  cursor: pointer;
}

.inline-notice-retry:hover { opacity: 0.85; }

/* Today's Hearings timeline (1/6): more breathing room per row so it
   reads as the dashboard's centerpiece, not a compact list. */
.timeline-header {
  font-size: var(--text-xs);
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.09em;
  font-weight: 600;
  margin: 0 0 var(--space-3);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--line-strong);
}

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

.timeline-item {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  padding: var(--space-4);
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: background 0.15s ease, box-shadow 0.15s ease;
}

.timeline-item:not(:last-child) {
  margin-bottom: var(--space-2);
}

.timeline-item:hover {
  background: var(--row-hover-tint);
}

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

.timeline-item--now {
  background: var(--green-bg);
  box-shadow: inset 3px 0 0 var(--green);
}

.timeline-item--now:hover {
  background: var(--green-bg);
}

.timeline-item--next {
  background: var(--blue-bg);
  box-shadow: inset 3px 0 0 var(--blue);
}

.timeline-item--next:hover {
  background: var(--blue-bg);
}

.timeline-rail {
  position: relative;
  width: 14px;
  flex-shrink: 0;
  display: flex;
  justify-content: center;
}

/* Connector line, drawn through every dot except before the first and
   after the last item in the list. v0.8.2: thicker and higher-contrast
   ("stronger connector line") — still the existing line tokens, no new
   color introduced. */
.timeline-rail::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  width: 2px;
  height: 100%;
  background: var(--line-strong);
  transform: translateX(-50%);
}

.timeline-item:first-child .timeline-rail::before { top: 8px; }
.timeline-item:last-child .timeline-rail::before { height: 8px; }

.timeline-dot {
  position: relative;
  z-index: 1;
  width: 11px;
  height: 11px;
  margin-top: 6px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--card);
  border: 2px solid var(--line-strong);
}

.timeline-item--now .timeline-dot { border-color: var(--green); width: 13px; height: 13px; margin-top: 5px; }
.timeline-item--next .timeline-dot { border-color: var(--blue); }

.timeline-content {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  flex: 1;
}

.timeline-time {
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--ink);
}

.timeline-case {
  font-size: var(--text-md);
  color: var(--ink);
}

.timeline-stage {
  font-size: var(--text-xs);
  color: var(--ink-2);
}

.timeline-badge {
  align-self: flex-start;
  margin-top: var(--space-1);
  font-size: var(--text-sm);
  font-weight: 600;
  padding: 3px var(--space-3);
  border-radius: var(--radius-sm);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.timeline-badge--now { background: var(--green-bg); color: var(--green); }
.timeline-badge--next { background: var(--blue-bg); color: var(--blue); }
.timeline-badge--completed { background: var(--gray-bg); color: var(--ink-3); }
.timeline-badge--upcoming { background: var(--amber-bg); color: var(--amber); }

/* Timeline empty state (4) — a more professional, court-oriented message
   with a pointer to the two ways to schedule a hearing, in place of
   v0.8.0's plain "Enjoy the quiet day." Deliberately its own class
   rather than reusing .empty-row (which other pages' JS depends on). */
.timeline-empty {
  text-align: center;
  padding: var(--space-6) var(--space-4);
}

.timeline-empty svg {
  width: 28px;
  height: 28px;
  color: var(--ink-3);
  margin-bottom: var(--space-3);
}

.timeline-empty-title {
  font-size: var(--text-base);
  color: var(--ink-2);
  margin: 0 0 var(--space-1);
}

.timeline-empty-sub {
  font-size: var(--text-sm);
  color: var(--ink-3);
  margin: 0;
}

/* ---------------------------------------------------------------------- */
/* v0.7.0 — Hearings global search (hearings.html)                         */
/* ---------------------------------------------------------------------- */

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

/* Generic page-level divider between two full-width sections on the same
   page (e.g. "Archived Hearings" / "Archived Cases" on archived.html) —
   not scoped to any one page, unlike .report-section-heading above, which
   sits inside a card. */
.section-heading {
  font-size: var(--text-lg);
  margin: var(--space-6) 0 var(--space-3);
}

.hearings-search input,
.activity-search input {
  width: 100%;
  height: 40px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  padding: 0 var(--space-3);
  font-size: var(--text-base);
  font-family: inherit;
  color: var(--ink);
  background: var(--card);
}

/* ---------------------------------------------------------------------- */

.app-footer {
  text-align: center;
  font-size: var(--text-xs);
  color: var(--ink-3);
  margin-top: var(--space-8);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}

/* ---------------------------------------------------------------------- */
/* v0.6.1 — Mobile nav responsiveness (≤768px)                             */
/*                                                                          */
/* CSS-only. No IDs/classes were renamed and no JS was touched — every     */
/* selector below targets classes that already existed. The approach is   */
/* flexbox shrink-and-truncate rather than fixed widths, so it holds up   */
/* across 320/375/414/768px without fragile magic numbers:                 */
/*   - .app-nav wraps onto two rows: (brand + user block) on row one,      */
/*     nav links pushed to their own full-width row below                  */
/*   - .app-nav-brand takes "whatever space is left" and truncates with    */
/*     an ellipsis rather than overflowing                                 */
/*   - .app-nav-user (email + logout) never shrinks — it reserves its own  */
/*     space first, and the email inside it truncates on its own if needed */
/* ---------------------------------------------------------------------- */

/* ---------------------------------------------------------------------- */
/* v0.8.2 — Tablet tier (Responsive Dashboard & Navigation, ≤1024px)       */
/* Nav wrap-safety (previously only kicking in at ≤768px) now starts      */
/* here so nothing overflows horizontally between 769–1024px either, and  */
/* Home's two-column dashboard collapses to one so Today's Hearings still */
/* reads clearly on a tablet, not just a phone. Desktop (>1024px) is      */
/* completely untouched — nothing in this block or the narrower one below */
/* it applies above 1024px.                                               */
/* ---------------------------------------------------------------------- */
@media (max-width: 1024px) {
  .app-nav {
    height: auto;
    min-height: var(--nav-height);
    flex-wrap: wrap;
    align-items: center;
    padding: var(--space-3) var(--space-5);
    gap: var(--space-2) var(--space-4);
  }

  .app-nav-brand {
    flex: 1 1 auto;
    min-width: 0;
  }

  .app-nav-user {
    flex-shrink: 0;
    gap: var(--space-3);
  }

  .app-nav-email {
    max-width: 30vw;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .app-nav-logout {
    flex-shrink: 0;
  }

  /* Links move to their own full-width row below brand/user, and wrap
     internally too if ever needed (e.g. a much longer future label). */
  .app-nav-links {
    order: 3;
    flex: 1 1 100%;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-1);
  }

  /* Give the sticky nav's signature hairline room to sit below the now
     taller (wrapped) header instead of overlapping page content. */
  .app-nav::after {
    bottom: -3px;
  }

  /* Today's Hearings stacks above the sidebar (Now/Next/Summary/Quick
     Actions) instead of sitting beside it — still first in DOM order,
     so it still renders first, as required. */
  .dashboard-main-row {
    grid-template-columns: 1fr;
  }
}

/* ---------------------------------------------------------------------- */
/* Phone tier (≤768px) — deltas on top of the tablet tier above: smaller  */
/* nav text/spacing, the sticky table header workaround, a 2x2 stat grid, */
/* and Quick Actions becoming a 2-column grid instead of a single row.    */
/* ---------------------------------------------------------------------- */
@media (max-width: 768px) {
  .app-nav {
    padding: var(--space-2) var(--space-4);
    gap: var(--space-2) var(--space-3);
  }

  .app-nav-brand-icon { width: 30px; height: 30px; }
  .app-nav-brand-icon svg { width: 16px; height: 16px; }
  .app-nav-brand-title { font-size: var(--text-sm); }
  .app-nav-brand-subtitle { display: none; }

  .app-nav-user {
    gap: var(--space-2);
  }

  .app-nav-email {
    max-width: 34vw;
  }

  .app-nav-logout {
    padding: 0 var(--space-2);
    font-size: var(--text-xs);
  }

  .app-nav-link {
    height: 32px;
    padding: 0 var(--space-3);
    font-size: var(--text-xs);
  }

  /* The sticky table header offset is tuned for the desktop nav's fixed
     height; on mobile the nav is taller (two rows), so this is no longer
     a reliable anchor — switch off sticky behavior below 768px rather
     than have it stick at the wrong offset or overlap wrapped nav rows. */
  .data-table th {
    position: static;
  }

  /* Dashboard: 3 cards side-by-side is too cramped on a phone; stack them. */
  .dashboard-stats-grid {
    grid-template-columns: 1fr;
  }

  .dashboard-greeting-row {
    flex-direction: column;
    gap: var(--space-2);
  }

  .dashboard-header-right {
    width: 100%;
    justify-content: space-between;
  }

  /* Hearing Quick View: single column on narrow screens. */
  .preview-grid {
    grid-template-columns: 1fr;
  }

  /* Calendar: a fixed 7-column grid becomes unusably cramped at phone
     widths. .cal-content-card already scrolls horizontally (see its
     base rule); it just never engaged because the grid's `fr` columns
     always shrank to fit instead of overflowing. Giving the grid a
     legible minimum width here makes that existing scroll actually
     kick in, instead of squeezing every cell/entry unreadably thin. */
  .cal-month-grid,
  .cal-week-grid {
    min-width: 620px;
  }

  .summary-columns {
    grid-template-columns: 1fr;
    text-align: left;
  }

  /* Quick Actions (5): a 2-column grid on phones instead of a single
     stacked column, so all three buttons read as a compact block rather
     than a tall list. Whichever button ends up last among the ones a
     role can actually see spans the full width so it doesn't sit alone
     in a half-empty row — home.js's updateQuickActionsLayout() computes
     that and applies .quick-action-last-visible, since v0.9.2's RBAC can
     hide one or two of these three buttons per role and a plain
     :last-child rule would still target whichever button is last in the
     DOM regardless of whether that one is actually visible. */
  .quick-actions-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-2);
  }

  .quick-actions-row .btn-secondary {
    width: 100%;
    height: auto;
    min-height: 38px;
    padding: var(--space-2) var(--space-3);
    white-space: normal;
    text-align: center;
  }

  .quick-actions-row .btn-secondary.quick-action-last-visible {
    grid-column: 1 / -1;
  }
}

/* -------------------------------------------------------------------------
   13. Activity Log (v0.9.0)
   ------------------------------------------------------------------------- */
/* Input styling is shared with .hearings-search input above (see that
   rule's selector list) — only the wrapper here differs, since this one
   sits inside .toolbar's flex row (as a growing item) rather than as a
   standalone full-width block above it. */
.activity-search {
  flex: 1 1 260px;
  min-width: 200px;
}


.activity-filter {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: 0 0 auto;
}

.activity-filter-label {
  font-size: var(--text-sm);
  color: var(--ink-2);
}

.activity-filter select,
.report-filter select,
.report-filter input[type="date"],
.role-select {
  height: 40px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  padding: 0 var(--space-3);
  font-size: var(--text-base);
  font-family: inherit;
  color: var(--ink);
  background: var(--card);
}

/* -------------------------------------------------------------------------
   14. Reports & Statistics (v0.9.1)
   ------------------------------------------------------------------------- */
.report-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-4);
}

.report-filter {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.report-filter label {
  font-size: var(--text-sm);
  color: var(--ink-2);
}

.report-filter-checkbox {
  justify-content: flex-end;
}

.report-filter-checkbox label {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  height: 40px;
  font-size: var(--text-sm);
  color: var(--ink-2);
  cursor: pointer;
}

.report-filter-checkbox input[type="checkbox"] {
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
  cursor: pointer;
}

.report-export-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.report-section-heading {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: var(--space-4) var(--space-4) 0;
}

.report-section-heading h2 {
  font-size: var(--text-lg);
}

.report-day-divider {
  font-weight: 600;
  background: var(--paper);
  color: var(--ink-2);
}

.report-breakdowns {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-6);
  margin-top: var(--space-6);
}

@media (max-width: 768px) {
  .report-breakdowns {
    grid-template-columns: 1fr;
  }
}

/* -------------------------------------------------------------------------
   15. Role-Based Access Control / Users (v0.9.2)
   ------------------------------------------------------------------------- */
.role-select:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

/* -------------------------------------------------------------------------
   Backup & Restore (v0.9.4) — additive only, reuses existing tokens.
   ------------------------------------------------------------------------- */
.backup-panel { margin-bottom: var(--space-6); }              /* JS-DEPENDENT */
.backup-panel h2 { font-size: var(--text-lg); margin: 0 0 var(--space-2); }
.backup-panel > p.muted { margin: 0 0 var(--space-4); }

#restoreFileInput {                                            /* JS-DEPENDENT */
  display: block;
  margin-bottom: var(--space-4);
  font-family: inherit;
  font-size: var(--text-base);
  color: var(--ink);
}

.backup-status { margin-top: var(--space-3); font-size: var(--text-sm); } /* JS-DEPENDENT */
.backup-status-success { color: var(--green); }
.backup-status-error { color: var(--red); }

.backup-validation {                                            /* JS-DEPENDENT */
  margin: var(--space-4) 0;
  padding: var(--space-4);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
}
.backup-validation p { margin: 0 0 var(--space-2); }
.backup-validation ul { margin: 0; padding-left: var(--space-5); }
.backup-validation-ok { background: var(--green-bg); color: var(--ink); border: 1px solid var(--green); }
.backup-validation-error { background: var(--red-bg); color: var(--ink); border: 1px solid var(--red); }

.backup-progress-wrap { margin-top: var(--space-4); }           /* JS-DEPENDENT */
.backup-progress-track {
  width: 100%;
  height: 10px;
  background: var(--gray-bg);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.backup-progress-bar {                                          /* JS-DEPENDENT: width set by backup.js */
  height: 100%;
  width: 0%;
  background: var(--accent);
  transition: width 0.15s ease;
}
.backup-progress-label { margin-top: var(--space-2); font-size: var(--text-sm); color: var(--ink-2); }

/* -------------------------------------------------------------------------
   16. Utilities (Phase 3)
   ------------------------------------------------------------------------- */
/* Phase 3: replaces a one-off `style="display:none;"` previously inline on
   backup.html's #restoreProgressWrap. backup.js still sets
   `progressWrap.style.display = "block"` directly to reveal it — an
   inline style set via JS always wins over a class, so this class only
   needed to supply the *initial* hidden state; no .js change required. */
.is-hidden { display: none; }

/* -------------------------------------------------------------------------
   17. Inline Notifications (Phase 3)
   ------------------------------------------------------------------------- */
/* Reusable dismissible inline notice, rendered by js/notify.js's
   showNotice(). Replaces the app's 3 native alert() call sites (Phase 2
   audit, Error Handling: hearings.js "Could not archive", archived.js
   "Could not restore", cases.js "Could not archive") with something
   styled consistently with the rest of the app's inline feedback
   (.form-error, .backup-validation) instead of a blocking browser dialog.
   Color pairs reuse the same semantic tokens as .backup-validation-ok/
   -error and the badge system elsewhere in this file — no new colors
   introduced. */
.page-notice:empty { display: none; }

.inline-notice {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  line-height: 1.5;
}

.inline-notice-message { flex: 1 1 auto; }

.inline-notice-close {
  flex: 0 0 auto;
  border: none;
  background: none;
  padding: 0;
  margin: -2px -2px 0 0;
  font-size: var(--text-lg);
  line-height: 1;
  color: inherit;
  opacity: 0.6;
  cursor: pointer;
}
.inline-notice-close:hover { opacity: 1; }
.inline-notice-close:focus-visible {
  outline: 2px solid var(--accent-dark);
  outline-offset: 2px;
  opacity: 1;
}

.inline-notice-error   { background: var(--red-bg);   color: var(--ink); border: 1px solid var(--red); }
.inline-notice-success { background: var(--green-bg); color: var(--ink); border: 1px solid var(--green); }
.inline-notice-warning { background: var(--amber-bg); color: var(--ink); border: 1px solid var(--amber); }
.inline-notice-info    { background: var(--blue-bg);  color: var(--ink); border: 1px solid var(--blue); }
