/* ==========================================================================
   Property Data — v2 theme
   ==========================================================================
   A visual-redesign preview: a Mercury-style light dashboard, brand blue +
   violet accents, floating rounded panels on soft shadows, Inter, Lucide.

   Nothing here loads Blueprint or the current styles.css/theme-blueprint.css.
   No dependency beyond the two vendored asset folders (vendor/inter,
   vendor/lucide) — no npm install, no build step, no CDN at runtime.

   Structure of this file:
     1. Font face (self-hosted Inter)
     2. Design tokens (:root)
     3. Reset / base
     4. Motion helpers (reveal, stagger, skeleton shimmer, view transitions)
     5. Shell — sidebar, drawer, topbar, content
     6. Panel + panel header
     7. Big number / stat / trend chip
     8. Buttons
     9. Pills & status chips
     10. Segmented switch, tabs
     11. Inputs, selects, multi-select popover
     12. Filter bar
     13. Progress / meter rows
     14. Charts (donut, bars, sparkline) — container styling, SVG built by app.js
     15. List rows, headline cards
     16. Tooltip / hover preview
     17. Empty state
     18. Toast
     19. Modal / sheet
     20. Calendar month cell
     21. Lock screen
     22. Utilities
   ========================================================================== */

/* ---- 1. Font face --------------------------------------------------- */

@font-face {
  font-family: 'Inter Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url('../vendor/inter/inter-latin-wght-normal.woff2') format('woff2-variations');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}

/* ---- 2. Design tokens ------------------------------------------------ */

:root {
  /* Canvas & surfaces */
  --canvas: #f3f4f9;
  --canvas-2: #eceef5;
  --panel: #ffffff;
  --panel-2: #f8f9fc;
  --ink: #14151f;
  --ink-2: #52556a;
  --ink-3: #8d90a3;
  --ink-4: #b2b4c2;
  --line: rgba(20, 22, 40, 0.07);
  --line-strong: rgba(20, 22, 40, 0.13);

  /* Brand */
  --brand-sky: #2788d0;
  --brand-sky-dark: #1c6aa8;
  --brand-navy: #0d2f5a;
  --brand-violet: #7c5cff;
  --brand-violet-dark: #6a46ef;
  /* Solid, not gradient (Clem, v2 feedback round 1, G1: "I do not want to see
     a single gradient again across the whole thing"). The token names stay
     — every button/pill/chip below still reads var(--brand-gradient) — so
     this is the one place that decision lives, not a hunt through every
     consumer. */
  --brand-gradient: var(--brand-sky);
  --brand-gradient-hover: var(--brand-sky-dark);
  --brand-tint: rgba(39, 136, 208, 0.1);
  --violet-tint: rgba(124, 92, 255, 0.1);
  --focus-ring: #2788d0;

  /* Status — refined from styles.css card-status-* / pinColor(), Clem's palette call */
  --status-new: #189454;
  --status-new-tint: rgba(24, 148, 84, 0.12);
  --status-post: #b9790f;
  --status-post-tint: rgba(185, 121, 15, 0.13);
  --status-cancel: #d84343;
  --status-cancel-tint: rgba(216, 67, 67, 0.11);
  --status-sold3rd: #4a90d9;
  --status-sold3rd-tint: rgba(74, 144, 217, 0.13);
  --status-soldbank: #7c5cff;
  --status-soldbank-tint: rgba(124, 92, 255, 0.12);
  --status-probate-bid: #2788d0;
  --status-probate-bid-tint: rgba(39, 136, 208, 0.12);
  /* Bids with no property found (courtNoteClass()'s status-bids-noprop) —
     grey, matching the classic pages' #8f99a8, not the "court-lead" bucket's
     violet (R5). */
  --status-probate-noprop: #8f99a8;
  --status-probate-noprop-tint: rgba(143, 153, 168, 0.14);
  --status-approved: #c22762;
  --status-approved-tint: rgba(194, 39, 98, 0.12);
  /* The person who died, made obvious with a
     colour. A muted plum: not a sale status (green New,
     amber Postponed, red Cancelled, blue links, the bright Sold-To-Bank
     violet, the raspberry Approved). Text on its own tint is 6.2:1 (AA).
     .v2-deceased-tag below; the card's party row and Interested Parties
     row use the same pair (v2/card.css "parties"). */
  --deceased: #7b3f72;
  --deceased-tint: rgba(123, 63, 114, 0.12);

  /* Radii */
  --r-2xl: 20px;
  --r-xl: 16px;
  --r-lg: 12px;
  --r-md: 10px;
  --r-sm: 8px;
  --r-pill: 999px;

  /* Shadows — soft, layered, diffuse; no hard borders */
  --shadow-xs: 0 1px 2px rgba(16, 24, 40, 0.05);
  --shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.04), 0 6px 14px -6px rgba(16, 24, 40, 0.10);
  --shadow-panel: 0 1px 1px rgba(16, 24, 40, 0.03), 0 10px 24px -10px rgba(16, 24, 40, 0.14),
    0 28px 56px -24px rgba(16, 24, 40, 0.14);
  --shadow-panel-hover: 0 1px 1px rgba(16, 24, 40, 0.03), 0 18px 36px -12px rgba(16, 24, 40, 0.18),
    0 36px 72px -28px rgba(16, 24, 40, 0.18);
  --shadow-pop: 0 16px 40px -10px rgba(14, 16, 30, 0.28), 0 6px 16px -6px rgba(14, 16, 30, 0.16);

  /* Spacing scale */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-7: 32px;
  --sp-8: 40px;
  --sp-9: 48px;
  --sp-10: 64px;

  /* Type scale */
  --fs-display: 52px;
  --fs-h1: 26px;
  --fs-h2: 19px;
  --fs-h3: 15.5px;
  --fs-body: 14.5px;
  --fs-small: 13px;
  --fs-micro: 11.5px;
  --lh-tight: 1.08;
  --lh-snug: 1.3;
  --lh-normal: 1.55;

  /* Motion */
  --dur-fast: 120ms;
  --dur-base: 220ms;
  --dur-slow: 420ms;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --skel-min: 350ms;

  --sidebar-w: 252px;
  --topbar-h: 68px; /* the title row lines up with the sidebar logo */
  --content-max: 1360px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---- 3. Reset / base -------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font-family: 'Inter Variable', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: var(--fs-body);
  line-height: var(--lh-normal);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* clip, not hidden: `hidden` makes body a scroll container on iOS Safari,
     which un-sticks the topbar (Clem, 2026-09-24: header moved on scroll). */
  overflow-x: clip;
}
html { overflow-x: clip; }
h1, h2, h3, h4, p, figure { margin: 0; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }
img { max-width: 100%; display: block; }
ul { margin: 0; padding: 0; list-style: none; }
input, select, textarea { font: inherit; color: inherit; }
svg { display: block; }
:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
  border-radius: 4px;
}
::selection { background: var(--brand-tint); color: var(--brand-navy); }
/* Skip To Content (v2/app.js addSkipLink): the first Tab stop on every
   page, off-canvas until it has focus. Its target, <main id="content">, is
   focused programmatically (tabindex=-1) only to move the Tab start point —
   it is not a control, so it draws no ring of its own. */
.skip-link {
  position: fixed;
  top: 8px;
  left: 8px;
  z-index: 2000;
  padding: 10px 16px;
  border-radius: var(--r-md, 8px);
  background: var(--brand-navy);
  color: #fff;
  font-weight: 600;
  box-shadow: var(--shadow-pop);
  transform: translateY(-200%);
}
.skip-link:focus, .skip-link:focus-visible { transform: none; outline: 2px solid var(--focus-ring); outline-offset: 2px; }
#content[tabindex="-1"]:focus { outline: none; }
/* The Sales / Deals / Changes search pill turns its input's own outline off
   (sales.css, deals.css, changes.css); this is the ring that replaces it,
   drawn on the pill the way .search-pill:focus-within already does. */
.v2-search:has(input:focus-visible) { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* ---- 4. Motion helpers ------------------------------------------------- */

@keyframes fadeRise {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}
.fade-rise { animation: fadeRise var(--dur-slow) var(--ease-out) both; }

.stagger > * {
  opacity: 0;
  transform: translateY(8px);
  animation: fadeRise var(--dur-base) var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * 45ms);
}

@keyframes skelShimmer {
  0%, 100% { opacity: 0; }
  50% { opacity: 1; }
}
.skel {
  position: relative;
  overflow: hidden;
  background: #e7e9f1;
  border-radius: var(--r-md);
  display: block;
}
.skel::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(255, 255, 255, 0.55);
  opacity: 0;
  animation: skelShimmer 1.35s ease-in-out infinite;
}
.skel-text { height: 13px; border-radius: 4px; margin: 4px 0; }
.skel-title { height: 20px; width: 55%; border-radius: 5px; }
.skel-display { height: var(--fs-display); width: 45%; border-radius: 10px; }
.skel-circle { border-radius: 50%; }
.skel-icon { width: 36px; height: 36px; border-radius: var(--r-lg); }
.skel-row { display: flex; align-items: center; gap: var(--sp-3); }
.skel-chip { height: 24px; width: 70px; border-radius: var(--r-pill); }

@media not (prefers-reduced-motion: reduce) {
  @view-transition { navigation: auto; }
  @keyframes vtFadeIn {
    from { opacity: 0; transform: translateY(10px) scale(0.995); }
    to { opacity: 1; transform: translateY(0) scale(1); }
  }
  @keyframes vtFadeOut {
    to { opacity: 0; }
  }
  ::view-transition-old(root) { animation: vtFadeOut 0.18s var(--ease-out) both; }
  ::view-transition-new(root) { animation: vtFadeIn 0.32s var(--ease-out) both; }
}

/* ---- 5. Shell: sidebar, drawer, topbar, content ------------------------ */

.app-shell { display: flex; min-height: 100vh; align-items: stretch; }

/* Two layers on purpose: the outer <aside> stretches to match the page's
   real height (its flex sibling, .shell-main, is almost always taller than
   one screen) so its white background and right hairline run the full
   length of the page and never leave a grey gap below a shorter viewport's
   worth of nav — while the inner wrapper is what actually sticks to the
   viewport and scrolls its own overflow, so the nav stays reachable without
   the whole column needing to be exactly 100vh tall. */
.sidebar {
  width: var(--sidebar-w);
  flex: 0 0 auto;
  background: var(--panel);
  border-right: 1px solid var(--line);
  z-index: 30;
  /* N4 (Clem, round 3): the sidebar must never scroll horizontally at any
     width. Belt and suspenders with .sidebar-sticky below — .sidebar itself
     never scrolls (its sticky child does), but a fixed width with no
     overflow-x guard still lets an overlong child (a long nav label, the
     wordmark + badge row) push the box wider than --sidebar-w and show a
     scrollbar on whichever ancestor first clips it. clip, not hidden:
     hidden makes .sidebar a scroll container, and the sticky nav inside it
     then scrolled away with the page (Clem, 2026-09-24). */
  overflow-x: clip;
}
.sidebar-sticky {
  position: sticky;
  top: 0;
  max-height: 100vh;
  overflow-y: auto;
  /* Setting only overflow-y makes overflow-x compute to 'auto' too (CSS
     Overflow spec: a non-visible y with a visible x forces x to auto as
     well) — that stray auto is what let this element grow its own
     horizontal scrollbar independent of the page-level `body{overflow-x:
     hidden}` rule, which only stops the page from scrolling sideways, not a
     nested scroll container from doing the same. Pin it to hidden instead. */
  overflow-x: hidden;
  padding: calc(var(--sp-5) + env(safe-area-inset-top, 0px)) var(--sp-4) calc(var(--sp-6) + env(safe-area-inset-bottom, 0px));
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
  min-width: 0;
}
.sidebar-head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 0 var(--sp-2);
  min-height: 32px;
  min-width: 0;
}
.sidebar-logo { width: 30px; height: 18px; flex: 0 0 auto; }
.sidebar-word {
  font-weight: 650;
  font-size: 15.5px;
  letter-spacing: -0.01em;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.sidebar-badge {
  margin-left: auto;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--brand-violet-dark);
  background: var(--violet-tint);
  padding: 3px 7px;
  border-radius: var(--r-pill);
}
/* .btn-icon (below) also sets display, and shares this selector's
   specificity — .btn-icon.sidebar-close beats it regardless of source
   order, so the drawer-close "×" stays hidden outside the <=900px drawer
   even if .btn-icon moves around later (R1: it was showing beside the
   logo at desktop widths because plain .sidebar-close lost that tie). */
.btn-icon.sidebar-close {
  display: none;
}

.sidebar-nav { display: flex; flex-direction: column; gap: 2px; flex: 1 1 auto; }
.nav-item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 9px var(--sp-3);
  border-radius: var(--r-lg);
  color: var(--ink-2);
  font-size: 14px;
  font-weight: 560;
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.nav-item .icon { color: var(--ink-3); transition: color var(--dur-fast); }
.nav-item:hover { background: var(--canvas); color: var(--ink); }
.nav-item:hover .icon { color: var(--ink-2); }
.nav-item[aria-current="page"] {
  background: var(--brand-tint);
  color: var(--brand-navy);
  font-weight: 650;
}
.nav-item[aria-current="page"] .icon { color: var(--brand-sky); }
.nav-item-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Log Out (v2/app.js logOutHtml): a nav row that is a button, at the foot of
   the nav, set off from it by a hairline so it never reads as a page. */
.nav-logout {
  width: 100%; border: 0; background: none; font: inherit; font-size: 14px; font-weight: 560;
  text-align: left; cursor: pointer; min-height: 40px;
  margin-top: calc(-1 * var(--sp-4)); border-top: 1px solid var(--line);
  border-radius: 0 0 var(--r-lg) var(--r-lg);
}
.nav-logout:focus-visible { outline: 2px solid var(--brand-sky); outline-offset: 2px; }
.nav-logout:disabled { opacity: .6; cursor: progress; }
/* Unread count (setNavBadge(), v2/app.js — the Recent Changes feed's). */
.nav-badge {
  flex: 0 0 auto; min-width: 20px; height: 20px; padding: 0 6px; border-radius: var(--r-pill);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--brand-sky); color: #fff; font-size: 11px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.drawer-toggle[data-badge] { position: relative; }
.drawer-toggle[data-badge]::after {
  content: ""; position: absolute; top: 6px; right: 6px; width: 8px; height: 8px; border-radius: 50%;
  background: var(--brand-sky); box-shadow: 0 0 0 2px var(--panel);
}

.nav-group { display: flex; flex-direction: column; }
.nav-group-btn {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  border: 0;
  background: transparent;
  padding: 9px var(--sp-3);
  border-radius: var(--r-lg);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
  cursor: pointer;
  transition: background var(--dur-fast), color var(--dur-fast);
}
.nav-group-btn:hover { background: var(--canvas); color: var(--ink-2); }
.nav-group-btn .icon { color: inherit; }
.nav-group-label { flex: 1; text-align: left; }
.nav-caret { transition: transform var(--dur-base) var(--ease-out); color: var(--ink-4); }
.nav-group[data-open="false"] .nav-caret { transform: rotate(-90deg); }
.nav-subitems {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding-left: 30px;
  margin: 2px 0 4px;
  overflow: hidden;
  max-height: 400px;
  transition: max-height var(--dur-base) var(--ease-in-out), opacity var(--dur-base);
}
.nav-group[data-open="false"] .nav-subitems { max-height: 0; opacity: 0; margin: 0; }
.nav-subitems .nav-item { font-size: 13.5px; padding: 7px var(--sp-3); }

/* Press-and-hold menu reordering (bindNavReorder, v2/app.js). */
.sidebar-nav .nav-item, .nav-group-btn { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }
body.nav-reordering, body.nav-reordering * { cursor: grabbing !important; }
.nav-drag {
  position: relative; z-index: 2; background: var(--panel) !important;
  box-shadow: 0 8px 24px rgba(16, 24, 40, 0.16), 0 0 0 1px var(--brand-sky);
  border-radius: var(--r-md); transform: scale(1.02);
}
.nav-group.nav-drag { padding: 2px 0; }
.nav-order-hint { margin: var(--sp-4) var(--sp-3) 0; font-size: 11.5px; color: var(--ink-3); }
.nav-order-reset {
  display: inline-flex; align-items: center; min-height: 32px; margin: var(--sp-1) var(--sp-3) 0; padding: 0;
  border: 0; background: none; font: inherit; font-size: 12.5px; font-weight: 650; color: var(--brand-sky); cursor: pointer;
}
.nav-order-reset[hidden] { display: none; }

.drawer-toggle {
  display: none;
  border: 0;
  background: var(--panel);
  box-shadow: var(--shadow-xs);
  color: var(--ink-2);
  width: var(--btn-h);
  height: var(--btn-h);
  border-radius: var(--r-pill);
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex: 0 0 auto;
}
.drawer-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(10, 13, 26, 0.42);
  z-index: 40;
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease-out);
}

.shell-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  padding: 0 var(--sp-7);
  position: sticky;
  top: 0;
  /* Locked and solid: nothing scrolls visibly through it, and on a phone it
     reaches up under the status bar (viewport-fit=cover on every page) so
     the page never shows between the two. */
  height: calc(var(--topbar-h) + env(safe-area-inset-top, 0px));
  padding-top: env(safe-area-inset-top, 0px);
  background: var(--canvas);
  box-shadow: 0 1px 0 var(--line);
  z-index: 30;
}
.search-pill {
  flex: 1 1 auto;
  min-width: 0;
  max-width: 420px;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  background: var(--panel);
  border-radius: var(--r-pill);
  padding: 0 var(--sp-4);
  height: 40px;
  box-shadow: var(--shadow-xs);
  color: var(--ink-3);
  transition: box-shadow var(--dur-fast);
}
.search-pill:focus-within { box-shadow: var(--shadow-xs), 0 0 0 3px var(--brand-tint); color: var(--ink-2); }
.search-pill input {
  border: 0;
  outline: 0;
  background: none;
  flex: 1 1 auto;
  font: inherit;
  color: var(--ink);
  min-width: 0;
  width: 0;
}
.search-pill input::placeholder { color: var(--ink-4); }
.search-kbd {
  font-size: 11px;
  color: var(--ink-4);
  border: 1px solid var(--line-strong);
  border-radius: 5px;
  padding: 1px 5px;
  flex: 0 0 auto;
}
.topbar-title { display: none; font-weight: 650; font-size: 15px; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.topbar-heading { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; flex: 1 1 auto; }
.topbar-heading .page-title { font-size: 22px; line-height: 1.2; white-space: nowrap; }
/* A subtitle that doesn't fit beside the header buttons wraps to a second
   line at a word break (two fit the 68px bar) instead of being cut
   mid-word ("983 matched t…", "pulle…" at 1280). */
.topbar-heading .page-sub {
  margin-top: 0; min-width: 0; line-height: 1.35;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.topbar-actions { display: flex; align-items: center; gap: var(--sp-2); margin-left: auto; }
.topbar-v2-pill { cursor: pointer; white-space: nowrap; }
.topbar-v2-pill:hover { background: var(--canvas-2); color: var(--ink); }

/* Data As Of — the freshness pill (v2/app.js mountFreshness, Clem
   2026-10-27): one per topbar, left of the action icons. Hover / focus
   shows the per-feed times; a tap toggles them (data-open) for phones.
   Same height as the icon buttons so it never shrinks their row. */
.topbar-fresh { position: relative; flex: 0 0 auto; }
.topbar-fresh-btn {
  display: inline-flex; align-items: center; gap: 6px;
  height: var(--btn-h); padding: 0 12px;
  border: 0; border-radius: var(--r-pill);
  background: var(--panel); box-shadow: var(--shadow-xs);
  color: var(--ink-2); font: inherit; font-size: var(--fs-small); font-weight: 600; white-space: nowrap;
  cursor: default;
}
.topbar-fresh-btn:hover, .topbar-fresh[data-open="true"] .topbar-fresh-btn { background: var(--panel-2); color: var(--ink); }
.topbar-fresh-btn .icon { width: 14px; height: 14px; color: var(--ink-3); flex: 0 0 auto; }
.topbar-fresh-pop {
  position: absolute; top: calc(100% + 8px); right: 0;
  min-width: 240px; padding: var(--sp-3) var(--sp-4);
  background: var(--panel); border-radius: var(--r-xl); box-shadow: var(--shadow-pop);
  font-size: var(--fs-small); color: var(--ink-2); white-space: nowrap;
  opacity: 0; pointer-events: none; transform: translateY(4px);
  transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
  z-index: 80;
}
.topbar-fresh:hover .topbar-fresh-pop, .topbar-fresh:focus-within .topbar-fresh-pop, .topbar-fresh[data-open="true"] .topbar-fresh-pop { opacity: 1; transform: none; pointer-events: auto; }
.topbar-fresh-h { font-weight: 650; color: var(--ink); margin-bottom: var(--sp-2); }
.topbar-fresh-pop dl { margin: 0; display: grid; grid-template-columns: auto auto; gap: 4px var(--sp-4); }
.topbar-fresh-pop dl > div { display: contents; }
.topbar-fresh-pop dt { color: var(--ink-3); font-weight: 560; }
.topbar-fresh-pop dd { margin: 0; color: var(--ink); font-variant-numeric: tabular-nums; }
@media (max-width: 720px) {
  /* Icon only beside the title on a phone; the time stays in the popover
     and in the button's accessible name. */
  .topbar-fresh-btn { width: var(--btn-h); padding: 0; justify-content: center; }
  .topbar-fresh-t { display: none; }
}
@media (max-width: 440px) {
  /* A sixth icon beside five pushes "Recordings" / "Bankruptcies" out of
     the title at 390; the page title wins on a phone this narrow. */
  .topbar-fresh { display: none; }
}

/* Full width on every page, like the Foreclosure pages always were (Clem,
   2026-09-25) — only the side padding sets the margin; --content-max is no
   longer applied here. */
.content { flex: 1 1 auto; padding: var(--sp-2) var(--sp-7) var(--sp-7); max-width: none; width: 100%; margin: 0 auto; }
/* Titles stay, the space around them goes (Clem, 2026-09-24: less white
   space above the page; the title itself "was a little nice"). */
.page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-4); margin-bottom: var(--sp-4); flex-wrap: wrap; }
.page-title { font-size: var(--fs-h1); font-weight: 650; letter-spacing: -0.015em; }
.page-sub { color: var(--ink-3); font-size: var(--fs-small); margin-top: 4px; }

@media (max-width: 900px) {
  .app-shell { display: block; }
  .sidebar {
    position: fixed;
    top: 0;
    left: 0;
    height: 100%;
    transform: translateX(-100%);
    transition: transform var(--dur-slow) var(--ease-out);
    box-shadow: var(--shadow-pop);
    z-index: 50;
  }
  body[data-drawer-open="true"] .sidebar { transform: translateX(0); }
  body[data-drawer-open="true"] .drawer-backdrop { display: block; opacity: 1; }
  .drawer-toggle { display: inline-flex; }
  .btn-icon.sidebar-close { display: inline-flex; margin-left: auto; }
  .shell-main { width: 100%; }
  /* With the drawer toggle and up to six header buttons beside it, a long
     title ("Foreclosure Sales", "Bankruptcies") was cut mid-word at 820
     ("Foreclos"); wrap it to two lines at a word break instead. */
  .topbar-heading .page-title { font-size: 20px; white-space: normal; min-width: min-content; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow-wrap: normal; }
}

@media (max-width: 720px) {
  .content { padding: var(--sp-1, 4px) var(--sp-4) var(--sp-4); }
  /* Tighter gaps so the Search button (v2/app.js) fits beside Refresh and
     Help without clipping a page title on a 390px phone. */
  .topbar { padding-inline: var(--sp-4); gap: var(--sp-2); }
  .topbar-actions { gap: var(--sp-1); }
  .search-pill { max-width: none; }
  /* A title that doesn't fit beside the action buttons wraps to a second
     line rather than ending in "…" ("Sheriff Sal…" at 390). */
  /* Wraps between words only — break-word split "Bankruptcie / s" beside
     five icon buttons; a 390 phone gets a slightly smaller title instead. */
  .topbar-heading .page-title { font-size: 18px; line-height: 1.15; letter-spacing: -0.02em; white-space: normal; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow-wrap: normal; -webkit-hyphens: manual; hyphens: manual; }
  .topbar-heading .page-sub { display: none; }
  .topbar-actions .btn { display: none; } /* a header link moved up (Overview's Component Library) — no room on a phone */
  :root { --fs-display: 40px; }
}
@media (max-width: 440px) {
  .topbar { padding-inline: var(--sp-3); }
  .topbar-actions { gap: 2px; }
  .topbar-heading .page-title { font-size: 16px; }
}

/* ---- 6. Panel + panel header ------------------------------------------- */

.panel {
  background: var(--panel);
  border-radius: var(--r-2xl);
  box-shadow: var(--shadow-panel);
  padding: var(--sp-6);
  transition: box-shadow var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
}
.panel.lift:hover, a.panel:hover, button.panel:hover {
  box-shadow: var(--shadow-panel-hover);
  transform: translateY(-3px);
}
.panel-flush { padding: 0; overflow: hidden; }
.panel-flush .panel-head { padding: var(--sp-6) var(--sp-6) 0; }

.panel-head { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-5); flex-wrap: wrap; }
.panel-icon {
  width: 38px;
  height: 38px;
  border-radius: var(--r-lg);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--brand-tint);
  color: var(--brand-sky);
  flex: 0 0 auto;
}
.panel-icon .icon { width: 19px; height: 19px; }
.panel-icon.violet { background: var(--violet-tint); color: var(--brand-violet-dark); }
/* flex: 1 1 0% (not the default 0 1 auto) so this item's hypothetical main
   size is 0, not its unwrapped text width — otherwise a long title ("Postponed
   this week") makes the *whole* flex item too wide for the row and .panel-head's
   own flex-wrap drops it below the icon instead of wrapping the text within
   its own column beside the icon (R2).
   min-width was 0 — which let this item shrink all the way to nothing
   instead of ever triggering .panel-head's own flex-wrap: with a
   non-shrinking .panel-action (a dropdown, a Month/Week/Agenda switch, ...)
   next to it, the row always "fit" by squashing the title into a near-0
   column, wrapping its own text mid-word underneath the controls instead of
   moving them to their own row (tablet-with-sidebar widths, ~900-1200px —
   the iPad-landscape "Probate Calendar" defect). A real floor forces the row
   to wrap the way it was always meant to once the title can't share a row
   with its controls at their full width. */
.panel-head-text { min-width: 140px; flex: 1 1 0%; }
.panel-title { font-size: var(--fs-h2); font-weight: 640; letter-spacing: -0.01em; color: var(--ink); }
.panel-sub { font-size: var(--fs-small); color: var(--ink-3); margin-top: 2px; }
.panel-action { margin-left: auto; flex: 0 0 auto; display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.panel-menu-btn {
  width: 32px;
  height: 32px;
  border-radius: var(--r-pill);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--canvas);
  color: var(--ink-3);
  border: 0;
  cursor: pointer;
  transition: background var(--dur-fast), color var(--dur-fast);
}
.panel-menu-btn:hover { background: var(--canvas-2); color: var(--ink-2); }
.panel-dropdown-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: var(--r-pill);
  background: var(--canvas);
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--ink-2);
  border: 0;
  cursor: pointer;
}
.panel-dropdown-pill:hover { background: var(--canvas-2); }

.panel-grid { display: grid; gap: var(--sp-5); grid-template-columns: repeat(4, 1fr); }
.panel-grid.cols-3 { grid-template-columns: repeat(3, 1fr); }
.panel-grid.cols-2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 1180px) { .panel-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) {
  .panel-grid.cols-3, .panel-grid.cols-2 { grid-template-columns: 1fr; }
  /* Big-number tiles stay two across on a phone — stacked four high they
     pushed the filters and the list off the first screen. */
  .panel-grid { grid-template-columns: repeat(2, 1fr); gap: var(--sp-3); }
  .panel-grid > .panel { padding: var(--sp-4); min-width: 0; }
  .panel-grid .panel-title { font-size: 15px; }
  /* A half-width tile keeps its title beside the icon (the 140px floor put
     it on a line of its own) and a tighter gap above the number. */
  .panel-grid > .panel > .panel-head { flex-wrap: nowrap; margin-bottom: var(--sp-3); }
  .panel-grid > .panel > .panel-head .panel-head-text { min-width: 0; }
}

/* align-items: stretch (the grid default — not set explicitly here, which
   used to mean "start" won by inheriting nothing… no: it was set to `start`
   before, which is what let two side-by-side panels sit at their own
   content height instead of matching the row — G7, v2 feedback round 1:
   "any two components in the same row are the same height"). */
.grid-2 { display: grid; grid-template-columns: 1.3fr 1fr; gap: var(--sp-5); }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-5); }
@media (max-width: 1100px) { .grid-2, .grid-3 { grid-template-columns: 1fr; } }

/* A 1fr grid track's automatic minimum size is content-based by default, so a
   panel holding something that resists shrinking (a horizontal-scroll strip,
   a wide tab row, an unbroken address) can force the whole grid wider than
   the viewport instead of scrolling inside itself. Every direct grid item
   across the three grids above gets min-width: 0 so the track wins and any
   internal overflow-x: auto / text-overflow: ellipsis the item declares does
   its job instead. */
.panel-grid > *, .grid-2 > *, .grid-3 > * { min-width: 0; }

/* ---- 7. Big number / stat / trend chip --------------------------------- */

.stat { display: flex; flex-direction: column; gap: var(--sp-2); }
.stat-value {
  font-size: var(--fs-display);
  font-weight: 630;
  letter-spacing: -0.02em;
  line-height: var(--lh-tight);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.stat-value small { font-size: 0.4em; font-weight: 600; color: var(--ink-3); margin-left: 4px; }
.stat-caption { font-size: var(--fs-small); color: var(--ink-3); }
.stat-foot { display: flex; align-items: center; gap: var(--sp-2); margin-top: 2px; flex-wrap: wrap; }

.trend-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 10px 3px 8px;
  border-radius: var(--r-pill);
  font-size: var(--fs-small);
  font-weight: 650;
  width: fit-content;
  font-variant-numeric: tabular-nums;
}
.trend-chip .icon { width: 12px; height: 12px; }
.trend-chip.is-up { background: var(--status-new-tint); color: var(--status-new); }
.trend-chip.is-down { background: var(--status-cancel-tint); color: var(--status-cancel); }
.trend-chip.is-flat { background: var(--canvas); color: var(--ink-3); }

/* ---- 8. Buttons --------------------------------------------------------- */

/* G3 (v2 feedback round 1): one button height, everywhere — Save, Add watch,
   Export and every icon button all measure the same, width follows the
   label instead. --btn-h is the single source of that height; .btn-sm/
   .btn-lg only change padding/font-size, never height, and .btn-icon reads
   the same token so an icon button lines up exactly beside a label button. */
:root { --btn-h: 38px; }
/* Phones: every button (label or icon) is a 40px tap target. */
@media (max-width: 720px) { :root { --btn-h: 40px; } }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: var(--btn-h);
  padding: 0 18px;
  border-radius: var(--r-pill);
  font-size: 14px;
  font-weight: 630;
  border: 0;
  cursor: pointer;
  white-space: nowrap;
  transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out),
    background var(--dur-fast) var(--ease-out), color var(--dur-fast);
}
.btn:active { transform: scale(0.965); }
.btn .icon { width: 16px; height: 16px; }
.btn-primary {
  background: var(--brand-gradient);
  color: #fff;
  box-shadow: 0 10px 24px -10px rgba(124, 92, 255, 0.55);
}
.btn-primary:hover { background: var(--brand-gradient-hover); box-shadow: 0 14px 28px -8px rgba(124, 92, 255, 0.6); }
.btn-secondary { background: var(--panel); color: var(--ink); box-shadow: var(--shadow-xs); border: 1px solid var(--line-strong); }
.btn-secondary:hover { background: var(--panel-2); }
.btn-ghost { background: transparent; color: var(--ink-2); }
.btn-ghost:hover { background: rgba(20, 21, 31, 0.05); color: var(--ink); }
/* Padding/font-size only — height stays --btn-h on every size (G3). */
.btn-sm { padding: 0 14px; font-size: 13px; }
.btn-lg { padding: 0 24px; font-size: 15px; }
.btn-block { width: 100%; }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; pointer-events: none; }

.btn-icon {
  width: var(--btn-h);
  height: var(--btn-h);
  padding: 0;
  border-radius: var(--r-pill);
  background: var(--panel);
  box-shadow: var(--shadow-xs);
  color: var(--ink-2);
  border: 0;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.btn-icon:hover { background: var(--panel-2); color: var(--ink); }
/* .sm no longer shrinks the button itself (G3: one height everywhere) — it
   only used to be for a visually lighter icon button in a dense row; use a
   smaller icon size instead (.btn-icon.sm .icon) if that's still wanted. */
.btn-icon.sm { width: var(--btn-h); height: var(--btn-h); }
.btn-icon.ghost { background: transparent; box-shadow: none; }
.btn-icon.ghost:hover { background: rgba(20, 21, 31, 0.06); }

/* ---- 9. Pills & status chips -------------------------------------------- */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  border-radius: var(--r-pill);
  font-size: var(--fs-small);
  font-weight: 640;
  white-space: nowrap;
}
.pill-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: 0 0 auto; }
.pill .icon { width: 13px; height: 13px; }

.pill-new { background: var(--status-new-tint); color: var(--status-new); }
.pill-post { background: var(--status-post-tint); color: var(--status-post); }
.pill-cancel { background: var(--status-cancel-tint); color: var(--status-cancel); }
.pill-sold3rd { background: var(--status-sold3rd-tint); color: var(--status-sold3rd); }
.pill-soldbank { background: var(--status-soldbank-tint); color: var(--brand-violet-dark); }
.pill-probate-bid { background: var(--status-probate-bid-tint); color: var(--brand-sky-dark); }
.pill-approved { background: var(--status-approved-tint); color: var(--status-approved); }
.pill-neutral { background: var(--canvas); color: var(--ink-2); }

/* Sale venue (venuePillHtml(), v2/app.js; the rule is shared.js's
   saleVenue()). Online = brand sky, Live = amber, Unconfirmed = neutral. */
.pill-venue { gap: 4px; padding: 2px 9px; font-size: 11.5px; font-weight: 650; line-height: 1.5; vertical-align: middle; }
.pill-venue-sm { padding: 1px 7px; font-size: 10.5px; }
.pill-venue-online { background: var(--brand-tint, rgba(39, 136, 208, 0.12)); color: var(--brand-sky-dark); }
.pill-venue-live { background: var(--status-post-tint); color: var(--status-post); }
.pill-venue-unconfirmed { background: var(--canvas); color: var(--ink-2); box-shadow: inset 0 0 0 1px var(--line-strong, var(--line)); }
.pill-venue-check { font-weight: 800; }
/* Listed / Pending on a Sales / Deals row (listingPillHtml, v2/app.js). Flat tints. */
.pill-listing { padding: 2px 9px; font-size: 11.5px; font-weight: 650; line-height: 1.5; vertical-align: middle; }
.pill-listing-sm { padding: 1px 7px; font-size: 10.5px; }
.pill-listing-listed { background: var(--brand-tint, rgba(39, 136, 208, 0.12)); color: var(--brand-sky-dark); }
.v2-deceased-tag {
  display: inline-flex;
  align-items: center;
  height: 18px;
  margin-left: 6px;
  padding: 0 7px;
  border-radius: var(--r-pill);
  background: var(--deceased-tint);
  color: var(--deceased);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: 1;
  white-space: nowrap;
  vertical-align: middle;
}
/* A list row's name with the tag: the name shortens, the tag never does. */
.v2-deceased-row { display: flex; align-items: center; gap: 0; }
.v2-deceased-name { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.v2-deceased-row > .v2-deceased-tag { flex: none; }
.v2-deceased-row > :not(.v2-deceased-name):not(.v2-deceased-tag) { flex: none; margin-left: 6px; }
.pill-listing-pending { background: var(--violet-tint); color: var(--brand-violet-dark); } /* not the amber of a Postponed status pill beside it */

.chip-removable { background: var(--panel-2); color: var(--ink-2); border: 1px solid var(--line-strong); cursor: pointer; }
.chip-removable:hover { background: var(--canvas); color: var(--ink); }
.chip-removable .icon { width: 12px; height: 12px; }

/* ---- 10. Segmented switch, tabs ------------------------------------------ */

/* Frosted glass (Clem, 2026-09-24 — first on Bankruptcies' sort, then every
 * segmented bar): translucent white over a blur, a light hairline plus a
 * faint outer ring so it still reads on a white panel, a top highlight; the
 * selected segment is a brighter pane. Flat fills only (G1: no gradients).
 * Selected is aria-selected (tablists) or aria-pressed (toggle groups). A
 * button with data-dir="asc|desc" draws its sort direction. */
.segmented {
  display: inline-flex;
  background: rgba(255, 255, 255, 0.55);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  backdrop-filter: blur(14px) saturate(160%);
  border: 1px solid rgba(255, 255, 255, 0.85);
  box-shadow: 0 4px 16px rgba(16, 24, 40, 0.06), 0 0 0 1px rgba(20, 22, 40, 0.05), inset 0 1px 0 rgba(255, 255, 255, 0.9);
  border-radius: var(--r-pill);
  padding: 3px;
  gap: 2px;
}
.segmented button {
  border: 0;
  background: transparent;
  padding: 7px 16px;
  border-radius: var(--r-pill);
  font-size: 13px;
  font-weight: 640;
  color: var(--ink-3);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  transition: background var(--dur-base) var(--ease-out), color var(--dur-base), box-shadow var(--dur-base);
}
.segmented button[aria-selected="true"], .segmented button[aria-pressed="true"] {
  background: rgba(255, 255, 255, 0.92);
  color: var(--ink);
  box-shadow: 0 1px 3px rgba(16, 24, 40, 0.08), inset 0 0 0 1px rgba(20, 22, 40, 0.05);
}
.segmented button:hover:not([aria-selected="true"]):not([aria-pressed="true"]) { color: var(--ink-2); }
.segmented button[data-dir="asc"]::after { content: "↑"; font-size: 11px; color: var(--ink-3); }
.segmented button[data-dir="desc"]::after { content: "↓"; font-size: 11px; color: var(--ink-3); }
.segmented .icon { width: 14px; height: 14px; }

.tabs { display: flex; gap: var(--sp-5); border-bottom: 1px solid var(--line); overflow-x: auto; min-width: 0; max-width: 100%; }
.tabs button {
  border: 0;
  background: none;
  padding: 11px 1px;
  font-size: 14px;
  font-weight: 620;
  color: var(--ink-3);
  cursor: pointer;
  position: relative;
  white-space: nowrap;
  transition: color var(--dur-fast);
}
.tabs button:hover { color: var(--ink-2); }
.tabs button[aria-selected="true"] { color: var(--ink); }
.tabs button[aria-selected="true"]::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  border-radius: 2px;
  background: var(--brand-gradient);
}

/* ---- 11. Inputs, selects, multi-select popover --------------------------- */

.field { display: flex; flex-direction: column; gap: 6px; }
.field-label { font-size: 12.5px; font-weight: 650; color: var(--ink-2); }
.input, .select, .msel-trigger {
  height: 40px;
  padding: 0 var(--sp-4);
  border-radius: var(--r-lg);
  border: 1px solid var(--line-strong);
  background: var(--panel);
  font: inherit;
  color: var(--ink);
  width: 100%;
  transition: border-color var(--dur-fast), box-shadow var(--dur-fast);
}
.input:focus, .select:focus { border-color: var(--brand-sky); box-shadow: 0 0 0 3px var(--brand-tint); outline: 0; }
/* Keyboard focus also gets the site's outline ring back (the rule above
   cancels the global :focus-visible one). The border + glow *transition* in,
   so for their first frames a focused control looked unfocused —
   keyboard.test.mjs flagged research / deals / changes selects. An outline
   is instant. */
.input:focus-visible, .select:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.input::placeholder { color: var(--ink-4); }
/* G5, found in review (Clem, 2026-09-24): "All dates" on Sales (a plain
 * un-upgraded <select class="select">, `when`/`commercial` stay single-
 * select on purpose — CLAUDE.md) rendered with no chevron and a different
 * font size from "All statuses"/"All types" beside it, because this rule
 * only ever turned the native arrow off (`appearance: none`) without
 * drawing .msel-btn's own chevron in its place, and never matched its
 * 14px font-size. Every select-like control must look identical (G5) —
 * same height (var(--btn-h) via the shared .input/.select/.msel-trigger
 * block above), same chevron, same radius — so this now paints the exact
 * same chevron SVG at the exact same size/position/colour as .msel-btn's
 * own background-image, and sets the same font-size, rather than being a
 * second, slightly different "select" look. */
.select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 34px;
  font-size: 14px;
  background: var(--panel) url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="%238d90a3" stroke-width="3"><path d="M6 9l6 6 6-6"/></svg>') no-repeat right 14px center;
  background-size: 10px;
}

.msel-trigger {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  cursor: pointer;
  color: var(--ink-2);
}
.msel-trigger .icon { margin-left: auto; color: var(--ink-3); width: 16px; height: 16px; }
.msel-trigger[aria-expanded="true"] { border-color: var(--brand-sky); box-shadow: 0 0 0 3px var(--brand-tint); }

.popover {
  position: absolute;
  background: var(--panel);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-pop);
  padding: var(--sp-2);
  min-width: 230px;
  max-height: 320px;
  overflow-y: auto;
  z-index: 60;
  animation: fadeRise var(--dur-fast) var(--ease-out) both;
}
.popover-option {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 8px 10px;
  border-radius: var(--r-md);
  font-size: 14px;
  cursor: pointer;
  color: var(--ink-2);
}
.popover-option:hover { background: var(--canvas); color: var(--ink); }
.popover-check {
  width: 17px;
  height: 17px;
  border-radius: 5px;
  border: 1.5px solid var(--line-strong);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  color: #fff;
  transition: background var(--dur-fast), border-color var(--dur-fast);
}
.popover-option[aria-checked="true"] .popover-check { background: var(--brand-gradient); border-color: transparent; }
.popover-check .icon { width: 11px; height: 11px; }
.popover-count {
  margin-left: auto;
  font-size: var(--fs-micro);
  color: var(--ink-4);
  background: var(--canvas);
  border-radius: var(--r-pill);
  padding: 1px 6px;
}

/* G5 (v2 feedback round 1): one dropdown, everywhere. ui.js's own
 * upgradeFilterSelects() (the site's real multi-select — status, type,
 * zoning, property type, zip, liens, on every page that filters a list)
 * builds real DOM with its own class names (.msel/.msel-btn/.msel-menu/
 * .msel-opt, real <input type="checkbox"> options, not the
 * .msel-trigger/.popover/.popover-option markup above, which only ever
 * existed as this component page's own hand-built demo). Rather than run
 * two visually-matching-but-structurally-different popovers, this styles
 * ui.js's real markup to be pixel-for-pixel the demo's look — the same
 * trigger pill, the same floating panel, the same check treatment — so
 * "Property type" on the component page and "Property type" on Sales are
 * not just similar, they are the same CSS rules. Native <select>s ui.js
 * hasn't upgraded (When/Type on Sales) reuse .select directly instead of a
 * second look. */
.msel { position: relative; }
.msel-btn {
  height: 40px;
  padding: 0 34px 0 var(--sp-4);
  border-radius: var(--r-lg);
  border: 1px solid var(--line-strong);
  background: var(--panel) url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="%238d90a3" stroke-width="3"><path d="M6 9l6 6 6-6"/></svg>') no-repeat right 14px center;
  background-size: 10px;
  font: inherit;
  font-size: 14px;
  color: var(--ink);
  cursor: pointer;
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: left;
  transition: border-color var(--dur-fast), box-shadow var(--dur-fast);
}
.msel-btn:hover { background-color: var(--panel-2); }
.msel[data-open="true"] .msel-btn, .msel-btn[aria-expanded="true"] { border-color: var(--brand-sky); box-shadow: 0 0 0 3px var(--brand-tint); }
.msel-label { pointer-events: none; }
.msel-menu {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  min-width: 230px;
  max-height: 320px;
  overflow-y: auto;
  background: var(--panel);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-pop);
  padding: var(--sp-2);
  z-index: 60;
  animation: fadeRise var(--dur-fast) var(--ease-out) both;
}
.msel-opt {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 8px 10px;
  border-radius: var(--r-md);
  font-size: 14px;
  color: var(--ink-2);
  cursor: pointer;
}
.msel-opt:hover { background: var(--canvas); color: var(--ink); }
.msel-sep { height: 1px; background: var(--line-strong); margin: 4px 2px; }
/* The real checkbox, restyled to read exactly like .popover-check: a small
   rounded square that fills solid on check rather than the browser's native
   checkbox chrome (which nothing else on this page uses). */
.msel-opt input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 17px;
  height: 17px;
  min-width: 17px;
  border-radius: 5px;
  border: 1.5px solid var(--line-strong);
  background: var(--panel);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background var(--dur-fast), border-color var(--dur-fast);
}
.msel-opt input[type="checkbox"]:checked {
  background: var(--brand-gradient) no-repeat center;
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="%23fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>');
  border-color: transparent;
}
.msel-opt input[type="checkbox"]:focus-visible { outline: 2px solid var(--brand-sky); outline-offset: 2px; }

/* ---- 12. Filter bar ------------------------------------------------------ */

.filter-bar { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.filter-bar-more {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 14px;
  border-radius: var(--r-pill);
  background: var(--panel);
  border: 1px dashed var(--line-strong);
  color: var(--ink-2);
  font-size: 13.5px;
  font-weight: 620;
  cursor: pointer;
}
.filter-bar-more:hover { background: var(--panel-2); border-color: var(--ink-4); }
.filter-bar-more .icon { width: 15px; height: 15px; }
.filter-chip-clear {
  background: none;
  border: 0;
  color: inherit;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  min-width: 24px;
  min-height: 24px;
  margin: -4px -8px -4px -2px;
  border-radius: var(--r-pill);
}
.filter-chip-clear:hover { background: rgba(20, 21, 31, 0.08); }

/* Active filter chips — ui.js's initMoreFilters() renders these (CLAUDE.md:
   "shows every active filter as a removable chip") on every page that
   carries the sale filter bar (Sales, Deals, Recent Changes, Calendar,
   Map). Moved here from v2/sales.css (round 3 review, Clem via the
   coordinator): that file is not loaded on every one of those pages
   (v2/deals.html doesn't link it), so its chips rendered as unstyled boxes
   there. One definition, in the shared shell, so every page that runs
   initMoreFilters() gets it regardless of which page-specific stylesheet it
   also loads. */
.filter-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}
.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  padding: 0 8px 0 12px;
  border-radius: var(--r-pill);
  border: none;
  background: var(--panel);
  box-shadow: var(--shadow-xs);
  color: var(--ink);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}
.filter-chip span { opacity: 0.5; font-size: 14px; }
.filter-chip:hover { background: #fff; box-shadow: var(--shadow-sm); }
.filter-chip-all { color: var(--status-cancel); }
@media (max-width: 600px) {
  .filter-chips { padding: 0 2px; }
  /* A dropdown told to fill its row (width: 100%) really does — the 220px
     desktop cap left "Probate Likelihood" two-thirds wide on a row of its own. */
  .msel-btn { max-width: 100%; }
  /* A switch wider than the phone wraps onto a second line whose buttons
     share it evenly, instead of scrolling its last option out of sight
     ("Last 90 Day…" on Pre-Probate) or leaving a lone button on row two. */
  .segmented { flex-wrap: wrap; max-width: 100%; }
  .segmented:has(> button:nth-child(4)) { border-radius: var(--r-xl); }
  .segmented > button { flex: 1 1 auto; white-space: nowrap; }
  /* 40px tap targets. html:root lifts this over the per-page desktop
     minimums (".wl-filters .segmented button { min-height: 30px }" and
     friends) without touching each of those files. The property card is
     left out: it sizes its own phone controls to 44px (v2/card*.css). */
  .segmented { padding: 2px; }
  html:root .segmented > button:not(.v2c-sheet *) { min-height: 40px; }
}

/* ---- 13. Progress / meter rows -------------------------------------------- */

.meter-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) 0; }
.meter-icon {
  width: 32px;
  height: 32px;
  border-radius: var(--r-md);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}
.meter-icon .icon { width: 16px; height: 16px; }
.meter-main { flex: 1 1 auto; min-width: 0; }
.meter-label-row { display: flex; justify-content: space-between; gap: var(--sp-3); font-size: 13.5px; margin-bottom: 7px; }
.meter-label { color: var(--ink); font-weight: 600; }
.meter-count { color: var(--ink-3); }
.meter-track { height: 8px; border-radius: var(--r-pill); background: var(--canvas); overflow: hidden; }
.meter-fill { height: 100%; border-radius: var(--r-pill); transition: width var(--dur-slow) var(--ease-out); }
.meter-value {
  font-size: 13.5px;
  font-weight: 650;
  color: var(--ink-2);
  white-space: nowrap;
  margin-left: var(--sp-3);
  font-variant-numeric: tabular-nums;
  flex: 0 0 auto;
  min-width: 42px;
  text-align: right;
}

/* ---- 14. Charts (containers; SVG built in app.js) -------------------------- */

.chart-donut { position: relative; display: inline-flex; flex: 0 0 auto; }
.chart-donut-center {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  pointer-events: none;
}
.chart-donut-center .n { font-size: 27px; font-weight: 660; letter-spacing: -0.02em; color: var(--ink); font-variant-numeric: tabular-nums; }
.chart-donut-center .label { font-size: 10.5px; color: var(--ink-3); font-weight: 600; text-transform: uppercase; letter-spacing: 0.03em; }
.chart-donut-legend { display: flex; flex-direction: column; gap: var(--sp-2); flex: 1 1 auto; min-width: 0; }
.chart-legend-row { display: flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--ink-2); }
.chart-legend-row b { color: var(--ink); font-variant-numeric: tabular-nums; margin-left: auto; }
.chart-legend-dot { width: 9px; height: 9px; border-radius: 3px; flex: 0 0 auto; }

.chart-bars rect { transition: height var(--dur-slow) var(--ease-out), y var(--dur-slow) var(--ease-out); }
.chart-bars text { font-size: 10px; fill: var(--ink-3); font-family: inherit; }

.chart-spark path.spark-line { fill: none; stroke-width: 2.25; stroke-linecap: round; stroke-linejoin: round; }
.chart-spark path.spark-area { stroke: none; }

/* ---- 15. List rows, headline cards ----------------------------------------- */

.list-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-2);
  border-radius: var(--r-lg);
  transition: background var(--dur-fast);
}
a.list-row, button.list-row { width: 100%; text-align: left; border: 0; background: none; cursor: pointer; }
.list-row:hover { background: var(--canvas); }
.list-row + .list-row { margin-top: 1px; }
.list-row-lead { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; flex: 1 1 auto; }
.list-row-avatar {
  width: 36px;
  height: 36px;
  border-radius: var(--r-md);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  font-weight: 650;
  font-size: 13px;
}
.list-row-text { min-width: 0; }
.list-row-title { display: block; font-size: 14px; font-weight: 610; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.list-row-sub { display: block; font-size: 12.5px; color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.list-row-end { flex: 0 0 auto; display: flex; align-items: center; gap: var(--sp-3); }
.list-row-value { font-size: 14px; font-weight: 650; font-variant-numeric: tabular-nums; text-align: right; }
.list-row-value small { display: block; font-size: 11.5px; font-weight: 550; color: var(--ink-3); }

.headline-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-4) var(--sp-4) calc(var(--sp-4) + 6px);
  border-radius: var(--r-xl);
  background: var(--panel);
  box-shadow: var(--shadow-sm);
  transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
/* N6 (Clem, round 3, reinforced 2026-09-24 via the coordinator after a
 * screenshot of Foreclosure Sales showed no colour at all — "make sure you
 * have the border color on the left side of the cards on every single
 * property card"): ONE rule, here, for the ~4px LEFT-edge status stripe
 * every card-shaped, per-property/per-case control across v2 carries — a
 * headline card (Overview's Next-7-days/Best-deals/Probate-this-week
 * cards, Foreclosure Deals), a Foreclosure Sales card, a Sheriff card, a
 * Probate Court List card, a Bankruptcies/Recordings list row and a Recent
 * Changes row. No page may define its own ::before/border-left/border-top
 * stripe rule any more — add the class to this selector list instead. Each
 * page still picks the COLOUR (the `--edge` custom property, inline style
 * or a `.status-*` modifier class, set where that page already computes
 * its status/type colour) — only the drawing rule is shared, so nothing
 * can drift into a top bar again. `overflow: hidden` on the same selector
 * clips the ::before to each component's own corner radius for free — no
 * per-component radius math needed here. Falls back to brand blue (or, for
 * the two components that already keyed their colour off `--st` before
 * this pass existed, that token) rather than disappearing, so a card that
 * forgot to set either is still visibly a status card, just not
 * mis-coloured. */
.headline-card,
.v2-card,
.v2-deal-card,
.v2l-card,
.v2l-row,
.v2-cl-card,
.v2-change-row {
  position: relative;
  overflow: hidden;
}
.headline-card::before,
.v2-card::before,
.v2-deal-card::before,
.v2l-card::before,
.v2l-row::before,
.v2-cl-card::before,
.v2-change-row::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 4px;
  background: var(--edge, var(--st, var(--brand-sky)));
}
a.headline-card, button.headline-card { cursor: pointer; border: 0; background: var(--panel); width: 100%; text-align: left; font: inherit; color: inherit; }
.headline-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-panel); }
.headline-card-top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-2); }
.headline-card-addr { font-size: 14.5px; font-weight: 650; color: var(--ink); line-height: var(--lh-snug); }
.headline-card-city { font-size: 12.5px; color: var(--ink-3); margin-top: 2px; }
.headline-card-row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); font-size: 13px; }
.headline-card-row .k { color: var(--ink-3); }
.headline-card-row .v { font-weight: 650; color: var(--ink); font-variant-numeric: tabular-nums; }
.headline-card-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); margin-top: 2px; }

/* ---- 16. Tooltip / hover preview -------------------------------------------- */

[data-tooltip] { position: relative; }
.tooltip {
  position: absolute;
  left: 50%;
  bottom: calc(100% + 8px);
  transform: translateX(-50%) translateY(4px);
  background: var(--ink);
  color: #fff;
  padding: 6px 10px;
  border-radius: 8px;
  font-size: 12px;
  font-weight: 560;
  white-space: nowrap;
  box-shadow: var(--shadow-pop);
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
  z-index: 80;
}
[data-tooltip]:hover .tooltip, [data-tooltip]:focus-visible .tooltip { opacity: 1; transform: translateX(-50%) translateY(0); }

.hover-preview {
  position: absolute;
  width: 260px;
  background: var(--panel);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-pop);
  padding: var(--sp-4);
  opacity: 0;
  transform: translateY(6px);
  pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
  z-index: 80;
}
.hover-target:hover .hover-preview, .hover-target:focus-within .hover-preview {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

/* ---- 17. Empty state ---------------------------------------------------------- */

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--sp-3);
  padding: var(--sp-9) var(--sp-5);
  color: var(--ink-3);
}
.empty-state-icon {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--canvas);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-3);
}
.empty-state-icon .icon { width: 26px; height: 26px; }
.empty-state-title { font-size: 15px; font-weight: 640; color: var(--ink-2); }
.empty-state-sub { font-size: 13.5px; max-width: 34ch; }

/* ---- 18. Toast ------------------------------------------------------------------ */

.toast-stack {
  position: fixed;
  bottom: var(--sp-6);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  z-index: 300;
  align-items: center;
}
.toast {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--ink);
  color: #fff;
  padding: 12px 18px;
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-pop);
  font-size: 13.5px;
  font-weight: 560;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
}
.toast.is-visible { opacity: 1; transform: translateY(0); }
.toast .icon { width: 16px; height: 16px; color: var(--status-new); flex: 0 0 auto; }
.toast.is-warn .icon { color: var(--status-post); }

/* ---- 19. Modal / sheet ------------------------------------------------------------ */

.modal-backdrop, .sheet-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(10, 13, 26, 0.45);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-base) var(--ease-out);
  z-index: 120;
}
.modal-backdrop.is-open, .sheet-backdrop.is-open { opacity: 1; pointer-events: auto; }

.modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -46%) scale(0.98);
  width: min(460px, calc(100vw - 32px));
  background: var(--panel);
  border-radius: var(--r-2xl);
  box-shadow: var(--shadow-pop);
  padding: var(--sp-6);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
  z-index: 121;
}
.modal.is-open { opacity: 1; transform: translate(-50%, -50%) scale(1); pointer-events: auto; }
.modal-head { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-4); }
.modal-title { font-size: var(--fs-h2); font-weight: 650; }
.modal-close { margin-left: auto; }
.modal-actions { display: flex; justify-content: flex-end; gap: var(--sp-3); margin-top: var(--sp-6); }

/* The keyboard shortcut sheet (v2/keys.js, "?"): the modal above with a
   two-column key list. */
.v2-keys-sheet { width: min(420px, calc(100vw - 32px)); }
.v2-keys-list { margin: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.v2-keys-row { display: flex; align-items: center; gap: var(--sp-4); }
.v2-keys-row dt { flex: 0 0 150px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.v2-keys-row dd { margin: 0; color: var(--ink-2); font-size: var(--fs-small); }
.v2-keys-or { font-size: 11px; color: var(--ink-4); }
.v2-keys-sheet kbd {
  display: inline-block; min-width: 22px; text-align: center;
  padding: 2px 7px; border: 1px solid var(--line-strong); border-bottom-width: 2px; border-radius: 6px;
  background: var(--canvas); color: var(--ink); font: inherit; font-size: 12px; font-weight: 600; line-height: 1.4;
}
.v2-keys-note { margin: var(--sp-4) 0 0; font-size: var(--fs-small); color: var(--ink-3); }

.v2-sheet {
  position: fixed;
  top: 0;
  right: 0;
  height: 100%;
  width: min(440px, 100vw);
  background: var(--panel);
  box-shadow: var(--shadow-pop);
  transform: translateX(100%);
  transition: transform var(--dur-slow) var(--ease-out);
  z-index: 121;
  padding: var(--sp-6);
  overflow-y: auto;
}
.v2-sheet.is-open { transform: translateX(0); }

/* ---- 20. Calendar month cell (Google-style) --------------------------------------- */

.cal-month-head { display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px; margin-bottom: var(--sp-2); }
.cal-month-head span { text-align: center; font-size: 11.5px; font-weight: 650; color: var(--ink-3); text-transform: uppercase; letter-spacing: 0.03em; padding-bottom: 4px; }
.cal-month {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 1px;
  background: var(--line);
  border-radius: var(--r-xl);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}
.cal-cell {
  background: var(--panel);
  min-height: 104px;
  padding: 7px;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.cal-cell.is-out { background: var(--panel-2); }
.cal-cell.is-out .cal-date-n { color: var(--ink-4); }
.cal-date-n {
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-size: 12.5px;
  font-weight: 650;
  color: var(--ink-2);
}
.cal-cell.is-today .cal-date-n { background: var(--brand-sky); color: #fff; }
.cal-event-pill {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 2px 7px;
  border-radius: var(--r-pill);
  font-size: 10.8px;
  font-weight: 620;
  background: var(--panel);
  border: 1px solid var(--line-strong);
  color: var(--ink-2);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.cal-event-dot { width: 6px; height: 6px; border-radius: 50%; flex: 0 0 auto; }
.cal-event-time { color: var(--ink-3); font-weight: 560; flex: 0 0 auto; }
.cal-more-pill { font-size: 10.8px; font-weight: 650; color: var(--ink-3); padding: 1px 6px; }


/* ---- 22b. Next-7-days strip (Overview widget e) --------------------------------------- */

/* Equal-width columns that all fit the panel at once — one per non-empty
   weekday, up to 5 (--strip-cols, set inline by index.v2.js from the actual
   count). Only at <=900px does it become a horizontal snap-scroller instead
   of squeezing columns down further. */
.strip-row { display: grid; grid-template-columns: repeat(var(--strip-cols, 5), minmax(0, 1fr)); gap: var(--sp-3); }
.strip-day {
  min-width: 0;
  background: var(--panel-2);
  border-radius: var(--r-lg);
  padding: var(--sp-3);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
@media (max-width: 900px) {
  .strip-row { display: flex; overflow-x: auto; scroll-snap-type: x mandatory; padding-bottom: 6px; }
  .strip-day { flex: 0 0 208px; scroll-snap-align: start; }
}
.strip-day.is-today { background: var(--brand-tint); }
.strip-day-head { font-size: 12.5px; font-weight: 650; color: var(--ink-2); }
.strip-day.is-today .strip-day-head { color: var(--brand-sky-dark); }
.strip-day-chips { display: flex; flex-direction: column; gap: 6px; }
.strip-chip {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 9px;
  border-radius: var(--r-md);
  background: var(--panel);
  font-size: 12px;
  font-weight: 610;
  color: var(--ink-2);
  box-shadow: var(--shadow-xs);
  cursor: pointer;
  border: 0;
  width: 100%;
  min-width: 0;
  text-align: left;
}
.strip-chip:hover { background: var(--panel-2); }
.strip-chip .pill-dot { width: 6px; height: 6px; flex: 0 0 auto; }
.strip-chip-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---- 22. Utilities -------------------------------------------------------------------- */

/* An element toggled via the `hidden` IDL property can also carry a class
   that sets `display` (a grid/flex row, a popover, a view pane, …) — a class
   selector and the UA's `[hidden]` rule are equal specificity, so without
   this the later, more specific rule wins and a "hidden" element still
   renders, empty but laid out. Found independently by three of the four v2
   page workers (calendar.js's Month/Week/Agenda switch, sales.js's filter
   panel, the card's tab panes); folded into the shared theme once so every
   v2 page gets it instead of redeclaring it. */
[hidden] { display: none !important; }

/* ui.js's initFilterCollapse() self-installs a "Filters" toggle button
   (#filters-toggle) on any page with a #filters form, styled by styles.css
   on v1 pages — which v2 does not load. It still needs to exist in the DOM
   for ui.js's own state, so it is hidden here rather than fought or forked. */
#filters-toggle { display: none; }

/* G4 (v2 feedback round 1): icons optically centred in icon buttons both
   ways — .icon is itself a centred flex box (not just sized), so a glyph
   whose own bounding box isn't perfectly square (×, star, the eye) still
   sits centred in its button rather than drifting toward whichever edge its
   path data is denser on. */
.icon { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; color: inherit; flex: 0 0 auto; }
.icon svg { width: 100%; height: 100%; display: block; }
.hairline-top { border-top: 1px solid var(--line); }
.hairline-bottom { border-bottom: 1px solid var(--line); }
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.text-muted { color: var(--ink-3); }
.text-sm { font-size: var(--fs-small); }
.mono-num { font-variant-numeric: tabular-nums; }
.sticky-index {
  position: sticky;
  top: var(--sp-4);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  background: rgba(243, 244, 249, 0.9);
  backdrop-filter: blur(8px);
  padding: var(--sp-3);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-xs);
  z-index: 15;
  margin-bottom: var(--sp-7);
}
.sticky-index a {
  padding: 6px 12px;
  border-radius: var(--r-pill);
  font-size: 13px;
  font-weight: 610;
  color: var(--ink-2);
}
.sticky-index a:hover { background: var(--panel); color: var(--ink); box-shadow: var(--shadow-xs); }
.section-h { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); margin: var(--sp-9) 0 var(--sp-5); }
.section-h:first-child { margin-top: 0; }
.section-h h2 { font-size: var(--fs-h1); font-weight: 650; letter-spacing: -0.01em; }
.section-h p { color: var(--ink-3); font-size: var(--fs-small); }

/* A hub's tab strip (Auctions): the glass .segmented bar with links for
   tabs, full width, above the page head. */
/* Compact and left-aligned, the same size and place as Probate's tab strip
   (Clem, 2026-09-24: the two hubs should look the same). */
.v2-hub-tabs { display: inline-flex; width: auto; max-width: 100%; align-self: flex-start; justify-self: start; margin: 0 0 var(--sp-4); overflow-x: auto; scrollbar-width: none; }
.v2-hub-tabs::-webkit-scrollbar { display: none; }
.v2-hub-tabs a {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  min-height: 34px; padding: 8px 16px; border-radius: var(--r-pill); white-space: nowrap;
  font-size: 13px; font-weight: 640; color: var(--ink-3); text-decoration: none;
  transition: background var(--dur-base) var(--ease-out), color var(--dur-base), box-shadow var(--dur-base);
}
.v2-hub-tabs a[aria-current="page"] {
  background: rgba(255, 255, 255, 0.92); color: var(--ink);
  box-shadow: 0 1px 3px rgba(16, 24, 40, 0.08), inset 0 0 0 1px rgba(20, 22, 40, 0.05);
}
.v2-hub-tabs a:hover:not([aria-current="page"]) { color: var(--ink-2); }
/* The way back to a hub's dashboard from one of its pages (v2/app.js
   crumbHtml(), Option A, Clem 2026-10-19). */
.v2-crumb {
  display: inline-flex; align-items: center; gap: 4px; margin: 0 var(--sp-3) var(--sp-3) 0; min-height: 32px;
  font-size: 13px; font-weight: 700; color: var(--brand-sky); text-decoration: none;
}
.v2-crumb:hover { text-decoration: underline; }
/* Probate's strip is buttons (in-page tabs) rather than links; same look. */
.v2-hub-tabs button { flex: 0 0 auto; min-height: 34px; padding: 8px 16px; white-space: nowrap; font-size: 13px; font-weight: 640; }
.v2-hub-tabs a:focus-visible { outline: 2px solid var(--brand-sky); outline-offset: 2px; }
/* A phone wraps the strip instead of scrolling it, so the last tab is never
   cut off ("Pa…" on Probate's six). */
@media (max-width: 600px) {
  .v2-hub-tabs { display: flex; flex-wrap: wrap; width: 100%; overflow: visible; border-radius: 18px; row-gap: 2px; }
  .v2-hub-tabs a, .v2-hub-tabs button { flex: 1 1 auto; padding: 7px 12px; min-height: 40px; }
  .v2-crumb { min-height: 40px; }
}

/* ---- Page & feature permissions (docs/permissions.md, the navigation
   lock). v2/app.js's applyPerms() sets html.lock-<feature> for each locked
   feature; anything marked .perm-<feature> hides under it. A locked page
   shows #v2-noaccess in place of its content (a hub's tab strip stays). */
html.lock-export .perm-export,
html.lock-valuations .perm-valuations,
html.lock-contacts .perm-contacts { display: none !important; }

body.v2-noaccess #content > :not(#v2-noaccess):not(.v2-hub-tabs) { display: none !important; }
#v2-noaccess { display: flex; justify-content: center; padding: var(--sp-8) 0; }
.v2-noaccess-card {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-3); text-align: center;
  width: 100%; max-width: 440px; padding: 32px 28px; border-left: 4px solid var(--status-post);
}
.v2-noaccess-icon {
  display: inline-flex; align-items: center; justify-content: center; width: 48px; height: 48px;
  border-radius: 50%; background: var(--status-post-tint); color: var(--status-post);
}
.v2-noaccess-title { margin: 0; font-size: 22px; font-weight: 700; letter-spacing: -0.01em; color: var(--ink); }
.v2-noaccess-text { margin: 0 0 var(--sp-2); font-size: 14.5px; line-height: 1.55; color: var(--ink-2); }
/* A short note where a locked feature used to be (Research). */
.v2-locked-note {
  display: flex; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-3); padding: 8px 14px;
  border-radius: var(--r-lg); background: var(--panel); box-shadow: var(--shadow-xs);
  border-left: 3px solid var(--status-post); font-size: 13.5px; line-height: 1.5; color: var(--ink-2);
}
.v2-locked-note[hidden] { display: none; }
.v2-locked-note strong { color: var(--ink); }

/* dragSort() (v2/app.js), the Dashboard Editors: the lifted tile follows the
   pointer, and the dashed slot is where it will land. */
.dnd-lift {
  position: fixed !important; z-index: 70; margin: 0 !important; box-sizing: border-box;
  pointer-events: none; will-change: transform; opacity: .97;
  box-shadow: 0 18px 44px rgba(20, 22, 40, .24);
}
.dnd-ph {
  box-sizing: border-box; min-width: 0; border-radius: var(--r-xl);
  border: 2px dashed var(--brand-sky); background: color-mix(in srgb, var(--brand-sky) 8%, transparent);
}
body.dnd-dragging, body.dnd-dragging * { cursor: grabbing !important; user-select: none; -webkit-user-select: none; }

/* ---- 23. Density: Compact (Clem, 2026-10-27) -------------------------------------------- */
/* Comfortable is every rule above, untouched. Compact is this block plus a
   matching block at the end of v2/list.css and each list page's own file,
   all under `:root[data-density="compact"]` (set by v2/app.js at load from
   the topbar's Density menu, kept in localStorage). Same markup, same
   classes, same tokens: smaller paddings and type, one-line secondary text
   (the full value is a title on hover — app.js bindClipTitles()), shorter
   stat tiles and panels. Interactive targets keep their 24px floor
   (tests/density.test.mjs runs the hit-target audit in this mode). */
.v2-density { position: relative; }
/* Phones have no room for a sixth topbar button beside the page title
   (tests/phone-sweep, saved-views-watchlist: "title squeezed" at 360/390),
   and Compact is a desktop affordance: the switch is hidden at ≤720px. A
   choice made on a wider window still applies (the CSS below keeps its
   phone rules). */
@media (max-width: 720px) { .v2-density { display: none; } }
.v2-density-menu {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  min-width: 168px;
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--panel);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-pop);
  z-index: 60;
}
.v2-density-menu button {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  min-height: 36px;
  padding: 0 12px;
  border: 0;
  background: none;
  border-radius: var(--r-md);
  font: inherit;
  font-size: 13px;
  font-weight: 620;
  color: var(--ink-2);
  text-align: left;
  cursor: pointer;
}
.v2-density-menu button:hover { background: var(--canvas); }
.v2-density-menu button[aria-checked="true"] { color: var(--brand-sky-dark); }
.v2-density-menu button:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }

:root[data-density="compact"] {
  --fs-display: 30px;
  --fs-small: 12.5px;
}
:root[data-density="compact"] .content { padding-top: var(--sp-1); }
:root[data-density="compact"] .panel { padding: var(--sp-4); border-radius: var(--r-xl); }
:root[data-density="compact"] .panel-flush { padding: 0; }
:root[data-density="compact"] .panel-flush .panel-head { padding: var(--sp-4) var(--sp-4) 0; }
:root[data-density="compact"] .panel-head { margin-bottom: var(--sp-3); }
:root[data-density="compact"] .panel-icon { width: 30px; height: 30px; border-radius: var(--r-md); }
:root[data-density="compact"] .panel-icon .icon { width: 15px; height: 15px; }
:root[data-density="compact"] .panel-grid { gap: var(--sp-3); }
:root[data-density="compact"] .stat { gap: 2px; }
:root[data-density="compact"] .page-head { margin-bottom: var(--sp-3); }
:root[data-density="compact"] .v2-hub-tabs { margin-bottom: var(--sp-3); }
:root[data-density="compact"] .list-row { padding: var(--sp-1) var(--sp-2); }
:root[data-density="compact"] .list-row-title { font-size: 13px; }
:root[data-density="compact"] .list-row-sub { font-size: 11.5px; }
:root[data-density="compact"] .list-row-avatar { width: 28px; height: 28px; font-size: 11.5px; }
/* The Watch star beside a row or card (v2/workspace.css): smaller, still
   over the 24px target floor. */
:root[data-density="compact"] .v2ws-star { width: 28px; height: 28px; }
:root[data-density="compact"] .v2ws-star .icon, :root[data-density="compact"] .v2ws-star svg { width: 15px; height: 15px; }
