/* Space Grotesk is loaded via <link rel="stylesheet"> in base.html
   (with preconnect hints) instead of @import here. <link> is faster
   and more reliable than CSS-side @import — the latter sometimes
   doesn't load on corporate networks that proxy/filter CSS requests
   differently from HTML requests. */

/* NorthRock asset-management dashboard.
   Visual language matched to mktsvy.com admin: tight info-dense rows,
   pill-style tab nav, color-coded badges, property-grouped section
   cards with light-blue summary headers. Brand color is the navy from
   the NorthRock logo. Accent blue matches mktsvy's #2563eb. */

:root {
  --brand-navy: #1B4F76;
  --brand-navy-dark: #143958;
  --brand-navy-light: #2A6FA0;
  --accent: #2563eb;            /* mktsvy primary accent blue */
  --accent-soft: #DBEAFE;       /* selected-row tint */
  --brand-accent: #C9A85C;
  --mktsvy-teal: #14b8a6;       /* teal used on the MKTSVY AI pill */

  --bg: #F4F6F9;
  --surface: #FFFFFF;
  --surface-alt: #F8FAFC;
  --surface-hover: #EEF3F8;
  --border: #E1E5EC;
  --border-strong: #C7CDD7;

  --text: #1A2233;
  --text-soft: #45556C;
  --text-muted: #7A8699;

  --success: #2E7D5B;
  --success-bg: #E6F2EC;
  --warning: #C77900;
  --warning-bg: #FCEDD3;
  --danger:  #C0392B;
  --danger-bg: #FCE7E3;
  --info-bg: #E3EEF7;

  --radius: 5px;
  --radius-lg: 8px;
  --radius-pill: 999px;
  --shadow-sm: 0 1px 2px rgba(20, 57, 88, 0.06);
  --shadow:    0 2px 8px rgba(20, 57, 88, 0.08);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  font-family: 'Space Grotesk', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
  /* 14px base — matches mktsvy table-cell legibility. All other sizes
     are rem-relative so they scale proportionally. */
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ---- DARK MODE ----
   Activated by adding data-theme="dark" to the <html> or <body> element.
   Tokens are redeclared inside the [data-theme="dark"] selector so the
   rest of the stylesheet keeps using var(--name) and just inherits the
   themed values. Persistence is handled by a tiny script in base.html
   that reads/writes localStorage on a sun/moon button click. */
[data-theme="dark"] {
  --bg: #0F172A;
  --surface: #1E293B;
  --surface-alt: #182238;
  --surface-hover: #243248;
  --border: #2A3852;
  --border-strong: #3D4F6E;

  --text: #E5EAF1;
  --text-soft: #B4BFD0;
  --text-muted: #7F8BA3;

  --info-bg: #1E3252;
  --accent-soft: #1E3A8A;

  --success-bg: #163528;
  --warning-bg: #3A2A0E;
  --danger-bg: #3B1818;
}

a { color: var(--brand-navy); text-decoration: none; }
a:hover { color: var(--brand-navy-light); text-decoration: underline; }
button { font-family: inherit; }

/* ---- TOP BAR ---- mktsvy puts logo + actions all in one tight row. */
.topbar {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  padding: 0.35rem 1rem;
  display: flex;
  align-items: center;
  gap: 1rem;
  min-height: 44px;
  /* Sticky header — stays glued to the top of the viewport while
     the user scrolls so the nav tabs + AM filter + MKTSVY pill
     are always reachable. z-index sits above page chrome but
     below modals (which use z-index 90/100 on the admin modal,
     100/101 on the legacy dashboard modal). */
  position: sticky;
  top: 0;
  z-index: 50;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.02);
}
.topbar .brand-logo img {
  height: 22px;
  width: auto;
  max-width: 160px;
  display: block;
  object-fit: contain;
}
.topbar .brand-sub {
  color: var(--text-muted);
  font-size: 0.66rem;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  font-weight: 600;
}

/* mktsvy tab nav: pill chips with active highlighted in accent blue. */
.tabnav {
  display: flex;
  gap: 0.15rem;
  margin-left: 0.75rem;
}
.tabnav a {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.32rem 0.7rem;
  border-radius: var(--radius);
  color: var(--text-soft);
  font-weight: 600;
  font-size: 0.74rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  text-decoration: none;
  transition: background 120ms ease, color 120ms ease;
}
.tabnav a:hover {
  background: var(--surface-hover);
  color: var(--brand-navy);
  text-decoration: none;
}
.tabnav a.active {
  background: var(--accent);
  color: #fff;
}
/* Global Asset Manager dropdown — sits in the tab nav rail, just after
   the Admin link. Same compact pill style so it visually pairs with the
   tab buttons. */
.tabnav .am-filter-global {
  margin-left: 0.4rem;
  font-family: inherit;
  font-size: 0.74rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.28rem 0.6rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text-soft);
  cursor: pointer;
  max-width: 220px;
}
.tabnav .am-filter-global:hover {
  border-color: var(--accent);
  color: var(--brand-navy);
}

/* Property-filter button — opens the multi-select modal. Same compact
   pill geometry as the AM select so the two filters read as a paired
   group in the topbar. The count chip on the right turns the button
   into a single glance state-display (e.g. "Properties · All (19)"). */
.tabnav .property-filter-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin-left: 0.4rem;
  font-family: inherit;
  font-size: 0.74rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.28rem 0.6rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text-soft);
  cursor: pointer;
  line-height: 1.2;
}
.tabnav .property-filter-btn:hover {
  border-color: var(--accent);
  color: var(--brand-navy);
}
.tabnav .property-filter-btn__count {
  display: inline-block;
  background: var(--surface-2, #f3f4f6);
  color: var(--brand-navy, #1B4F76);
  padding: 0.05rem 0.45rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  min-width: 1.4rem;
  text-align: center;
}
[data-theme="dark"] .tabnav .property-filter-btn__count {
  background: rgba(255,255,255,0.08);
  color: #cbd5e1;
}

/* Property-filter modal. Same visual family as the dashboard-settings
   modal: full-viewport scrim, card with header / scroll-body / footer,
   subtle slate-100 ghost while interacting. */
.property-filter-modal {
  position: fixed; inset: 0;
  background: rgba(15, 23, 42, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}
.property-filter-modal[hidden] { display: none; }
.property-filter-card {
  background: white;
  border-radius: 10px;
  width: min(720px, 92vw);
  max-height: min(82vh, 720px);
  display: flex;
  flex-direction: column;
  box-shadow: 0 20px 60px rgba(0,0,0,0.25);
}
.property-filter-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.85rem 1.1rem;
  border-bottom: 1px solid var(--border, #e5e7eb);
}
.property-filter-header h2 {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--brand-navy, #1B4F76);
}
.property-filter-close {
  background: transparent;
  border: none;
  cursor: pointer;
  font-size: 1.4rem;
  line-height: 1;
  color: var(--text-soft);
}
.property-filter-controls {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.55rem 1.1rem;
  border-bottom: 1px solid var(--border, #e5e7eb);
  font-size: 0.78rem;
}
.property-filter-link {
  background: transparent;
  border: none;
  color: var(--accent, #2563eb);
  cursor: pointer;
  padding: 0;
  font-size: inherit;
  font-weight: 600;
}
.property-filter-link:hover { text-decoration: underline; }
.property-filter-count-summary {
  margin-left: auto;
  color: var(--text-soft);
  font-size: 0.75rem;
}
.property-filter-body {
  overflow-y: auto;
  padding: 0.4rem 0.7rem 0.7rem;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.25rem 0.6rem;
}
@media (max-width: 640px) {
  .property-filter-body { grid-template-columns: 1fr; }
}
.property-filter-row {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.45rem 0.55rem;
  border-radius: 6px;
  font-size: 0.85rem;
  cursor: pointer;
}
.property-filter-row:hover { background: rgba(0,0,0,0.04); }
.property-filter-row input { margin: 0; }
.property-filter-row__name { flex: 1; }
.property-filter-row__pms {
  display: inline-block;
  padding: 0.08rem 0.5rem;
  border-radius: 4px;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
/* PMS chip colors mirror the bulk-download legend's hue family so the
   user reads them as the same data class across surfaces. */
.property-filter-row__pms.pms-realpage    { background: #dbeafe; color: #1e40af; }
.property-filter-row__pms.pms-yardi       { background: #ffedd5; color: #9a3412; }
.property-filter-row__pms.pms-rentmanager { background: #dcfce7; color: #166534; }
.property-filter-footer {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  padding: 0.7rem 1.1rem;
  border-top: 1px solid var(--border, #e5e7eb);
}
[data-theme="dark"] .property-filter-card {
  background: #1e293b;
  color: #e2e8f0;
}
[data-theme="dark"] .property-filter-header,
[data-theme="dark"] .property-filter-controls,
[data-theme="dark"] .property-filter-footer {
  border-color: rgba(255,255,255,0.08);
}
[data-theme="dark"] .property-filter-row:hover {
  background: rgba(255,255,255,0.06);
}

/* External text-only link (e.g. NORTHROCKCO.COM) — sits in the
   tabnav next to the MKTSVY pill. Inherits font-size / weight /
   letter-spacing / padding from the .tabnav a base so it reads
   at the same visual scale as OPERATIONS / FINANCIALS / DATA /
   ADMIN. Only the color is dialed down (muted text-soft) so it
   doesn't compete with the primary tab buttons or the brand
   mark on the left. */
.tabnav .external-text-link {
  margin-left: 0.4rem;
  color: var(--text-soft);
}
.tabnav .external-text-link:hover {
  background: var(--surface-hover);
  color: var(--brand-navy);
  text-decoration: none;
}
[data-theme="dark"] .tabnav .external-text-link:hover {
  color: #ffffff;
}

/* ---- MKTSVY AI pill ----
   Cross-product link to mktsvy.com. Ports the canonical brand mark
   verbatim from the mktsvy app: textured gradient ring + chart-bar
   icon + a comet sweep that flashes around the ring on a 5.5s cycle
   ("the scrape moment"). Wordmark + AI badge follow the same color
   tokens mktsvy uses so the chip reads identically across apps.

   Tuned for NorthRock's tighter topbar (~30px row): mark is 20×20
   instead of the canonical 30×30, padding is leaner, but the SVG
   geometry + animation are byte-for-byte the mktsvy original. */
.tabnav .mktsvy-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.34rem;
  margin-left: 0.45rem;
  padding: 0.18rem 0.55rem 0.18rem 0.35rem;
  border: 1px solid var(--border-strong);
  border-radius: 9999px;
  background: var(--surface);
  text-decoration: none;
  line-height: 1;
  font-family: 'Inter', -apple-system, BlinkMacSystemFont,
               'Segoe UI', system-ui, sans-serif;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.tabnav .mktsvy-pill:hover {
  border-color: #4a9eff;
  box-shadow: 0 0 0 2px rgba(74, 158, 255, 0.12);
}

.mktsvy-pill__mark {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  overflow: visible;    /* let comet glow extend past the bbox */
}
.mktsvy-pill__bar--dim    { fill: #6b7280; }   /* slate-500 — readable on both light + dark */
.mktsvy-pill__bar--accent { fill: #2563eb; }   /* mktsvy primary blue */

/* Comet sweep — quick flash, then ~4.5s dwell. Circumference for
   r=15 ≈ 94. Matches mktsvy's logo-comet-flash keyframe exactly. */
@keyframes nr-mktsvy-comet {
  0%   { stroke-dashoffset:  94; opacity: 0; }
  6%   { stroke-dashoffset:  94; opacity: 0; }
  10%  { opacity: 1; }
  32%  { stroke-dashoffset:   0; opacity: 1; }
  40%  { stroke-dashoffset: -12; opacity: 0; }
  100% { stroke-dashoffset: -12; opacity: 0; }
}
.mktsvy-pill__comet-head {
  stroke-dasharray: 7 87;
  stroke-dashoffset: 94;
  transform-origin: 50% 50%;
  transform: rotate(-90deg);     /* sweep starts at 12 o'clock */
  animation: nr-mktsvy-comet 5.5s ease-in-out infinite;
  filter: drop-shadow(0 0 1.5px #ffffff)
          drop-shadow(0 0 3px   #93c5fd)
          drop-shadow(0 0 5px   #60a5fa);
}
.mktsvy-pill__comet-trail {
  stroke-dasharray: 18 76;
  stroke-dashoffset: 94;
  transform-origin: 50% 50%;
  transform: rotate(-90deg);
  animation: nr-mktsvy-comet 5.5s ease-in-out infinite;
  opacity: 0.55;
  filter: drop-shadow(0 0 2px #bfdbfe);
}
@media (prefers-reduced-motion: reduce) {
  .mktsvy-pill__comet-head,
  .mktsvy-pill__comet-trail {
    animation: none;
    opacity: 0;
  }
}

/* Wordmark — MKT in deep navy, SVY in mktsvy blue. */
.mktsvy-pill__wordmark {
  display: inline-flex;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1;
}
.mktsvy-pill__mkt { color: var(--brand-navy); }
.mktsvy-pill__svy { color: #1a6ed8; }

/* AI badge — canonical pill with the gradient dot. */
.mktsvy-pill__ai {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  padding: 1px 6px;
  border-radius: 9999px;
  background: linear-gradient(135deg,
              rgba(37,99,235,0.08) 0%,
              rgba(124,58,237,0.08) 100%);
  color: #4f46e5;
  border: 1px solid rgba(124,58,237,0.22);
  line-height: 1.4;
}
.mktsvy-pill__ai::before {
  content: '';
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: linear-gradient(135deg, #2563eb 0%, #7c3aed 100%);
  flex-shrink: 0;
}

/* Dark-mode adjustments — same palette swaps the mktsvy app uses. */
[data-theme="dark"] .tabnav .mktsvy-pill {
  background: transparent;
}
[data-theme="dark"] .mktsvy-pill__mkt { color: #ffffff; }
[data-theme="dark"] .mktsvy-pill__svy { color: #4a9eff; }
[data-theme="dark"] .mktsvy-pill__bar--dim    { fill: #ffffff; }
[data-theme="dark"] .mktsvy-pill__bar--accent { fill: #6b7280; }
[data-theme="dark"] .mktsvy-pill__ai {
  background: linear-gradient(135deg,
              rgba(96,165,250,0.18) 0%,
              rgba(167,139,250,0.18) 100%);
  color: #ffffff;
  border-color: rgba(167,139,250,0.40);
}
[data-theme="dark"] .mktsvy-pill__comet-head {
  stroke: #4a9eff;
  filter: drop-shadow(0 0 1.5px #93c5fd)
          drop-shadow(0 0 3px   #4a9eff)
          drop-shadow(0 0 5px   #1e40af);
}

.topbar-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.65rem;
  color: var(--text-muted);
  font-size: 0.75rem;
}
.topbar-right .stat {
  color: var(--text-soft);
  font-weight: 600;
}
.topbar-right a {
  color: var(--accent);
  font-weight: 600;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.theme-toggle {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-soft);
  width: 26px;
  height: 26px;
  border-radius: var(--radius);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.95rem;
  line-height: 1;
  padding: 0;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.theme-toggle:hover {
  background: var(--surface-hover);
  color: var(--brand-navy);
  border-color: var(--brand-navy-light);
}

/* ---- ACTION TOOLBAR (under topbar, page-specific actions) ---- */
.toolbar {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  padding: 0.5rem 1rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.45rem;
}
.toolbar .toolbar-divider {
  width: 1px;
  height: 22px;
  background: var(--border);
  margin: 0 0.25rem;
}
.toolbar .toolbar-label {
  color: var(--text-muted);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-weight: 600;
  margin-right: 0.25rem;
}
.toolbar .toolbar-spacer { flex: 1; }
.toolbar .toolbar-meta {
  color: var(--text-muted);
  font-size: 0.78rem;
  margin-left: 0.5rem;
}

/* ---- BUTTONS (pill style) ---- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.4rem 0.85rem;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text-soft);
  border-radius: var(--radius);
  font-size: 0.8rem;
  font-weight: 600;
  line-height: 1.2;
  /* Native <button> elements ship with extra UA padding + a slightly
     different baseline than <a>, so a side-by-side .btn + .btn anchor
     (e.g. Settings + Refresh on /operations) renders at slightly
     different heights. Reset the UA appearance + force box-sizing so
     both element types size identically. */
  appearance: none;
  -webkit-appearance: none;
  box-sizing: border-box;
  font-family: inherit;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.btn:hover {
  background: var(--surface-hover);
  color: var(--brand-navy);
  border-color: var(--brand-navy-light);
  text-decoration: none;
}
.btn:active { background: var(--border); }
.btn-primary {
  background: var(--brand-navy);
  color: #fff;
  border-color: var(--brand-navy);
}
.btn-primary:hover {
  background: var(--brand-navy-dark);
  color: #fff;
  border-color: var(--brand-navy-dark);
}
.btn-sm { padding: 0.25rem 0.6rem; font-size: 0.75rem; }
.btn .icon { font-size: 0.85rem; }

/* ---- FILTER PILL ROW (e.g. property selector) ---- */
.filter-row {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  padding: 0.6rem 1rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.45rem;
}
.filter-row .filter-label {
  color: var(--text-muted);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-weight: 600;
  margin-right: 0.5rem;
}
.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.3rem 0.75rem;
  border: 1px solid var(--border);
  background: var(--surface-alt);
  color: var(--text-soft);
  border-radius: var(--radius-pill);
  font-size: 0.78rem;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: all 120ms ease;
}
.pill:hover {
  background: var(--surface-hover);
  color: var(--brand-navy);
  border-color: var(--brand-navy-light);
  text-decoration: none;
}
.pill.active {
  background: var(--brand-navy);
  color: #fff;
  border-color: var(--brand-navy);
}

/* ---- MAIN ---- */
main {
  padding: 1rem 1rem 3rem;
}

h1, h2, h3, h4 { color: var(--text); margin: 0; }
h1 { font-size: 1.35rem; font-weight: 600; }
h2 { font-size: 1rem; font-weight: 600; }
h3 { font-size: 0.9rem; font-weight: 600; }

/* ---- SECTION (property group card / chart group) ---- */
.section {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  margin-bottom: 1rem;
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  padding: 0.55rem 0.9rem;
  background: var(--info-bg);
  border-bottom: 1px solid var(--border-strong);
  gap: 0.5rem;
}
.section-header h2 {
  color: var(--brand-navy);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 0.78rem;
  white-space: nowrap;
}
.section-header .section-meta {
  color: var(--text-muted);
  font-size: 0.74rem;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.4rem;
}
/* AM filter dropdown placed inline in the section header, between the
   h2 title and the meta pipe. */
.section-header .am-filter {
  font-family: inherit;
  font-size: 0.78rem;
  padding: 0.15rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
}
.section-header .am-filter:hover {
  border-color: var(--accent);
}
.section-body { padding: 0.85rem 1rem; }
.section-body.flush { padding: 0; }

/* Collapsible sections on /tools — uses native <details>/<summary>.
   The summary doubles as the section header band; clicking it
   toggles disclosure. Default-closed: only the header shows on
   load, body slides in on click. */
.section-collapsible { padding: 0; }
.section-summary {
  cursor: pointer;
  list-style: none; /* hide the default browser disclosure triangle */
  position: relative;
  padding-right: 2.4rem; /* room for the custom chevron at the right */
  user-select: none;
}
.section-summary::-webkit-details-marker { display: none; }
.section-summary::after {
  content: "›";
  position: absolute;
  right: 1rem;
  top: 50%;
  transform: translateY(-50%) rotate(90deg);
  color: var(--brand-navy);
  font-size: 1.1rem;
  font-weight: 700;
  transition: transform 0.2s ease;
  line-height: 1;
}
details[open] > .section-summary::after {
  transform: translateY(-50%) rotate(-90deg);
}
.section-summary:hover { background: var(--info-bg-hover, var(--info-bg)); }

/* ---- STAT TILES (KPI cards) ---- */
.tile-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 0.6rem;
}
.tile {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.7rem 0.85rem;
}
.tile h3 {
  margin: 0 0 0.2rem 0;
  font-size: 0.65rem;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.07em;
}
.tile .tile-value {
  font-size: 1.3rem;
  font-weight: 600;
  color: var(--brand-navy);
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
.tile .tile-sub {
  color: var(--text-muted);
  font-size: 0.72rem;
  margin-top: 0.15rem;
}

/* ---- TABLES ----
   Density + typography copied from mktsvy.com admin tables: tight row
   padding, small tracked-out caps headers, tabular-nums for figures so
   columns of $$ + % line up cleanly. */
.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
}
.data-table thead th {
  background: var(--surface-alt);
  color: var(--text-muted);
  font-weight: 500;
  font-size: 0.64rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: 0.45rem 0.7rem;
  text-align: left;
  border-bottom: 1px solid var(--border-strong);
  white-space: nowrap;
}
.data-table thead th.num { text-align: right; }
.data-table thead th.center { text-align: center; }
.data-table tbody td {
  padding: 0.4rem 0.7rem;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.data-table tbody td.num { text-align: right; }
.data-table tbody td.center { text-align: center; }
.data-table tbody tr:last-child td { border-bottom: none; }
/* Subtle alternating zebra — light on light, mktsvy uses something
   similarly subtle to avoid the table reading as bold gridlines. */
.data-table tbody tr:nth-child(even) td { background: var(--surface-alt); }
.data-table tbody tr:hover td { background: var(--surface-hover); }
.data-table tbody tr.clickable { cursor: pointer; }
.data-table tbody tr.subtotal td,
.data-table tbody tr.subtotal:nth-child(even) td {
  background: var(--brand-navy);
  color: #fff;
  font-weight: 600;
  border-top: 2px solid var(--brand-navy-dark);
}
.data-table tbody tr.subtotal td .muted { color: rgba(255, 255, 255, 0.7); }
.data-table tbody tr.subtotal td .badge { background: rgba(255, 255, 255, 0.15); color: #fff; }

/* ---- ADMIN LAYOUT ----
   Two-column: a thin property picker on the left, the editor form on
   the right. Picker hides on narrow viewports (would-be mobile). */
.admin-layout {
  display: grid;
  grid-template-columns: 280px 1fr;
  gap: 1rem;
  align-items: start;
}
.admin-list .section { margin-bottom: 0; }
.admin-prop-list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 70vh;
  overflow-y: auto;
}
.admin-prop-list li {
  border-bottom: 1px solid var(--border);
}
.admin-prop-list li:last-child { border-bottom: none; }
.admin-prop-list li a {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.45rem 0.75rem;
  text-decoration: none;
  color: var(--text);
  gap: 0.5rem;
}
.admin-prop-list li a:hover {
  background: var(--surface-hover);
  text-decoration: none;
}
.admin-prop-list li.selected a {
  background: var(--accent-soft);
  font-weight: 600;
}
.admin-prop-list li a .name {
  font-size: 0.82rem;
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.admin-prop-list li a .meta {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}

.admin-form { display: flex; flex-direction: column; gap: 0.6rem; }
.admin-form .form-group-heading {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--brand-navy);
  font-weight: 700;
  margin: 0.5rem 0 0 0;
  padding-top: 0.4rem;
  border-top: 1px solid var(--border);
}
.admin-form .form-group-heading:first-child { border-top: none; padding-top: 0; }
.admin-form .form-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.5rem 0.75rem;
}
.admin-form label {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  font-size: 0.72rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 600;
}
.admin-form label.full { grid-column: 1 / -1; }
.admin-form input,
.admin-form textarea {
  font-family: inherit;
  font-size: 0.85rem;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
}
.admin-form input:focus,
.admin-form textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-soft);
}
.admin-form textarea { resize: vertical; min-height: 90px; }
.admin-form .form-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--border);
  margin-top: 0.5rem;
}

.admin-form select {
  font: inherit;
  font-size: 0.78rem;
  padding: 0.32rem 0.45rem;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface);
  color: var(--text);
}
.admin-form select:focus {
  outline: none;
  border-color: var(--brand-navy);
  box-shadow: 0 0 0 2px var(--brand-navy-light);
}

/* ---- ADMIN: Add Property + Manage AMs action row ----
   Sits above the property list. Compact, two-button cluster. */
.admin-actions {
  display: flex;
  gap: 0.4rem;
  padding: 0.5rem 0.6rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.4rem;
}

/* ---- DANGER BUTTON (delete actions) ----
   Used for destructive ops: Delete Property, Delete AM. Quiet by
   default (outlined red), saturated red on hover so the user knows
   they're about to do something irreversible. */
.btn-danger {
  color: var(--danger, #d05050);
  border-color: var(--danger, #d05050);
  background: transparent;
}
.btn-danger:hover {
  background: var(--danger, #d05050);
  color: #fff;
  border-color: var(--danger, #d05050);
}
.btn-danger:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  background: transparent;
  color: var(--danger, #d05050);
}

/* ---- ADMIN MODALS (Add Property, Manage AMs) ----
   Self-contained modals on the Admin page. Distinct from the
   shared #modal element in base.html so they can coexist without
   selector collisions. */
.admin-modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.45);
  z-index: 90;
  display: none;
}
.admin-modal-backdrop.open { display: block; }
.admin-modal {
  position: fixed;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  width: min(540px, 92vw);
  max-height: 85vh;
  /* No overflow on the wrapper — the modal-header is sticky at the
     top of the modal, and the modal-body scrolls independently below
     it (see flex-column rules in .admin-modal.open). This keeps the
     title visible while the user pages through a long table inside
     the modal body. */
  z-index: 100;
  box-shadow: 0 12px 36px rgba(0,0,0,0.25);
  display: none;
}
.admin-modal.open {
  display: flex;
  flex-direction: column;
}
.admin-modal .modal-header {
  background: var(--brand-navy);
  color: #fff;
  padding: 0.7rem 1rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-shrink: 0;  /* keep the title bar fixed at the top of the modal */
}
.admin-modal .modal-header h2 {
  color: #fff;
  font-size: 1rem;
  margin: 0;
}
.admin-modal .modal-close {
  background: transparent;
  border: 0;
  color: #fff;
  font-size: 1.2rem;
  cursor: pointer;
}
.admin-modal .modal-body {
  padding: 1rem 1.25rem;
  /* Body takes the remaining vertical space inside the modal and
     scrolls on its own. Vertical scroll only at body level — wide
     tables get an inner <div style="overflow-x:auto"> wrapper that
     handles horizontal scroll inside the table region so the modal
     header + footer action row stay fully visible. */
  flex: 1 1 auto;
  overflow-y: auto;
  overflow-x: hidden;
  min-height: 0;  /* lets flex children shrink properly in older Firefox */
}

/* ---- Threshold-settings modal — input color coding ----
   Tint each input cell with the color zone it represents so the
   user can see at a glance which input affects which threshold
   band. Subtle backgrounds — enough contrast to identify the zone
   without overwhelming the modal's overall layout. */
input.thresh-input[data-edge^="green"] {
  background: #ecf6f1;  /* very light green */
  border-color: #2E7D5B33;
}
input.thresh-input[data-edge^="yellow"] {
  background: #fdf3e0;  /* very light yellow */
  border-color: #C7790033;
}
input.thresh-input:focus {
  outline: 2px solid var(--brand-navy);
  outline-offset: -1px;
}

/* ---- AM list (inside Manage AMs modal) ---- */
.am-list {
  list-style: none;
  padding: 0;
  margin: 0.5rem 0 0;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.am-list li {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.45rem 0.7rem;
  border-bottom: 1px solid var(--border);
  font-size: 0.82rem;
}
.am-list li:last-child { border-bottom: none; }
.am-list .am-name {
  font-weight: 500;
  color: var(--text);
}

/* ---- DRILL-DOWN FACT STRIP ----
   Inline list of acquisition / loan facts shown above the KPI tiles in
   the per-property modal. Each chip is label-on-top, value-below. */
.fact-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.1rem;
  padding: 0.55rem 0.75rem;
  margin-bottom: 0.75rem;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 0.78rem;
}
.fact-strip .fact {
  display: inline-flex;
  flex-direction: column;
  gap: 0.05rem;
  line-height: 1.2;
}
.fact-strip .fact-wide { min-width: 260px; }
.fact-strip .fact-label {
  font-size: 0.62rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-weight: 600;
}
.fact-strip .fact-value {
  font-weight: 600;
  color: var(--text);
}

/* ---- DRILL-DOWN TREND CHART GRID ----
   Three stacked panes (occupancy / availability / in-place rent) just
   above the daily snapshot history in the property drill-down modal.
   maintainAspectRatio:false on the Chart.js side lets each canvas
   fill its pane height; we pin the pane height here so the modal
   doesn't unspool to an unreasonable length on big screens. */
.trend-chart-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.6rem;
  margin: 0.5rem 0 0.75rem;
}
.trend-chart-pane {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.5rem 0.75rem 0.4rem;
}
.trend-chart-pane canvas {
  width: 100% !important;
  height: 160px !important;
  display: block;
}
.trend-chart-title {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 0.2rem;
}

/* Expense-breakdown variant — same pane styling as the 3-pane
   top-of-modal grid but tiled into a 3-column small-multiples grid
   like the example xlsx the analyst supplied (5 rows × 3 cols for
   15 categories). The canvas is shorter than the top-of-modal
   charts since each pane is a sparkline rather than a full chart. */
.trend-chart-grid--breakdown {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.5rem;
}
.trend-chart-grid--breakdown .trend-chart-pane {
  padding: 0.4rem 0.55rem 0.3rem;
}
.trend-chart-grid--breakdown .trend-chart-pane canvas {
  height: 110px !important;
}
.trend-chart-grid--breakdown .trend-chart-title {
  font-size: 0.65rem;
  margin-bottom: 0.1rem;
}
/* Empty-state pane — when a category has no data in the window
   (e.g. RentManager properties' Recreational Amenities). Renders
   a centered em-dash inside the canvas area. */
.trend-chart-pane--empty canvas {
  visibility: hidden;
}
.trend-chart-pane--empty {
  position: relative;
}
.trend-chart-pane--empty::after {
  content: "—";
  position: absolute;
  inset: 1.4rem 0 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.4rem;
  color: var(--text-muted);
  pointer-events: none;
}

/* Shared toggle pill used by the Financials drill-down modal:
 *   .fin-trend-toggle      → $ / Per-Unit on Revenue/Expenses/NOI panes
 *   .fin-breakdown-toggle  → $ / % on the 15-pane expense breakdown
 * Same visual treatment so the two toggles read as a consistent
 * control family. Disabled button is dimmed and ignores hover.
 */
.fin-breakdown-toggle,
.fin-trend-toggle {
  display: inline-flex;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  overflow: hidden;
}
.fin-breakdown-toggle button,
.fin-trend-toggle button {
  background: var(--surface);
  border: 0;
  padding: 0.2rem 0.55rem;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-soft);
  cursor: pointer;
  font-family: inherit;
}
.fin-breakdown-toggle button:hover,
.fin-trend-toggle button:hover {
  background: var(--surface-hover);
  color: var(--brand-navy);
}
.fin-breakdown-toggle button.active,
.fin-trend-toggle button.active {
  background: var(--brand-navy);
  color: #fff;
}
.fin-breakdown-toggle button + button,
.fin-trend-toggle button + button {
  border-left: 1px solid var(--border-strong);
}
.fin-trend-toggle button:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.fin-trend-toggle button:disabled:hover {
  background: var(--surface);
  color: var(--text-soft);
}

/* Mobile-only: collapse the 3-col breakdown grid to a single column
   so each chart stays readable on a phone. The desktop rule above
   stays untouched outside the @media block. */
@media (max-width: 768px) {
  .trend-chart-grid--breakdown {
    grid-template-columns: 1fr;
  }
}

/* Drilldown control bar — date-range selector that sits flush-right
   at the top of the leasing modal body. Sticky-ish: pinned to the
   top of the scroll container so the user can change the range
   without scrolling back up. */
.drilldown-control-bar {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  margin: 0.4rem 0 0.6rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--border);
}
.drilldown-range-form {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
}
.drilldown-range-label {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.drilldown-range-label select {
  font: inherit;
  font-size: 0.78rem;
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
  color: var(--text);
  padding: 0.26rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  background: var(--surface);
  cursor: pointer;
}
.drilldown-range-custom {
  align-items: center;
  gap: 0.35rem;
  font-size: 0.78rem;
}
.drilldown-range-custom input[type="date"] {
  font: inherit;
  font-size: 0.78rem;
  padding: 0.2rem 0.4rem;
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  background: var(--surface);
  color: var(--text);
}

/* Lease-expiration chart inside the Leasing drill-down. Dual-axis
   bar+line; sized taller than the trend panes since it now has 30
   month labels on the x-axis (12 past + 18 future) which need extra
   vertical room for the rotated tick labels. */
.expiration-chart-wrap {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.6rem 0.75rem 0.4rem;
  margin: 0.4rem 0 0.5rem;
}
.expiration-chart-wrap canvas {
  width: 100% !important;
  height: 320px !important;
  display: block;
}

/* ---- SORTABLE COLUMNS ----
   Active column gets accent-blue ▲/▼ indicator; idle columns show a
   muted ⇅. Click handler lives in operations.html. */
.data-table.sortable thead th.sortable {
  cursor: pointer;
  user-select: none;
  position: relative;
  padding-right: 1.25rem;
}
.data-table.sortable thead th.sortable::after {
  content: '⇅';
  position: absolute;
  right: 0.45rem;
  top: 50%;
  transform: translateY(-50%);
  font-size: 0.7em;
  opacity: 0.35;
}
.data-table.sortable thead th.sortable.sort-asc::after {
  content: '▲';
  opacity: 1;
  color: var(--accent);
}
.data-table.sortable thead th.sortable.sort-desc::after {
  content: '▼';
  opacity: 1;
  color: var(--accent);
}
.data-table.sortable thead th.sortable:hover {
  background: var(--surface-hover);
  color: var(--text);
}

/* ---- OCCUPANCY TABLE WIDTH CONSTRAINTS ----
   16 columns. Order:
     1 Property | 2 Units | 3 Occupied | 4 Avail | 5 Occ %
     | 6 Avail %  (center)
     | 7 +30d %  (center) | 8 +30d movement
     | 9 +60d %  (center) | 10 +60d movement
     | 11 +90d % (center) | 12 +90d movement
     | 13 Avg Rent | 14 Recent | 15 PMS | 16 As Of
   The projection columns are split into pairs: a percentage-badge
   cell (center-aligned, header-labelled) plus an unlabeled movement
   cell carrying the "−<NTV> +<pre-leased>" hint. Splitting them
   fixes the staggered alignment problem caused by the inline hint
   pushing badges around in the old single-cell layout. */
/* Operations occupancy table — switched from table-layout:fixed +
   nth-child widths to table-layout:auto + per-column min/max widths
   keyed on the data-col attribute. nth-child broke for two reasons:
   (1) the gear-icon picker reorders columns, so position no longer
   identifies the logical column; (2) newer columns (city, state,
   T-12 metrics, etc.) had no width hint and ended up wasting or
   starving horizontal space. data-col selectors follow the column
   regardless of position and apply to ALL 37 registry keys. */
.occupancy-table {
  table-layout: auto;
  width: auto;
  min-width: 100%;
}
/* Scroll wrapper for the Operations occupancy table — content can
   exceed viewport width when many extended columns are enabled, so
   wrap with overflow-x:auto rather than wrapping cells. Mirrors the
   .dash-occ-snapshot-scroll pattern. */
.occupancy-scroll {
  overflow-x: auto;
  max-width: 100%;
}

/* ---- Projection / Avail % column alignment ----
   Class-based selectors so we don't have to chase nth-child indices
   every time the column order shifts. Right-align matches the
   financial-report convention every multifamily analyst is trained
   on: the units digit lines up vertically (91.6% vs 100.0%) which
   makes magnitudes easier to compare at a glance. The movement hint
   sits in its own cell to the immediate right, left-aligned so the
   "−N +M" reads naturally as a continuation of the badge. */
.occupancy-table .proj-pct {
  text-align: right;
  font-variant-numeric: tabular-nums;
  padding-left: 0.15rem;
  padding-right: 0.4rem;
}
.occupancy-table .proj-mov {
  text-align: left;
  padding-left: 0.2rem;
  padding-right: 0.45rem;
  font-size: 0.68rem;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.occupancy-table th.proj-mov { /* unlabeled header still needs to render */
  border-bottom: 1px solid var(--border);
}
/* Close Date column hidden from the table — still drives the
   default sort server-side (oldest acquisition first). Acquired
   date remains visible in the drill-down fact strip. */
/* Floor-plan group divider rows inside the drill-down lease tables.
 * Light info-blue background with dark text in light mode, dark-blue
 * background with light text in dark mode — both pulled from
 * --info-bg + --text which already flip on theme switch. Previous
 * styling used a hard navy fill + white text that was too heavy for
 * a per-floor-plan grouping. */
.data-table tbody tr.section-divider td {
  background: var(--info-bg);
  color: var(--text);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 0.66rem;
  font-weight: 700;
  padding-top: 0.4rem;
  padding-bottom: 0.4rem;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.data-table tbody tr.property-summary td {
  background: var(--info-bg);
  font-weight: 600;
}

/* Keep older class name working for existing routes that still use it */
.property-table-wrapper {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.property-table { width: 100%; border-collapse: collapse; font-size: 0.82rem; }
.property-table thead th {
  background: var(--surface-alt);
  color: var(--text-soft);
  font-weight: 600; font-size: 0.66rem; text-transform: uppercase;
  letter-spacing: 0.06em; padding: 0.55rem 0.75rem; text-align: left;
  border-bottom: 1px solid var(--border-strong); white-space: nowrap;
}
.property-table tbody td {
  padding: 0.5rem 0.75rem; border-bottom: 1px solid var(--border);
}
.property-table tbody tr:hover { background: var(--surface-hover); }

/* ---- BADGES + TAGS ---- */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.15rem 0.55rem;
  border-radius: var(--radius-pill);
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
}
.badge-count {
  background: var(--success-bg);
  color: var(--success);
  font-variant-numeric: tabular-nums;
}
.badge-count::before { content: "✓ "; }
.badge-pct-good    { background: var(--success-bg); color: var(--success); }
.badge-pct-warn    { background: var(--warning-bg); color: var(--warning); }
.badge-pct-danger  { background: var(--danger-bg);  color: var(--danger); }

/* PMS source tags */
.tag {
  display: inline-block;
  padding: 0.13rem 0.5rem;
  border-radius: var(--radius);
  font-size: 0.66rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  white-space: nowrap;
}
.tag-realpage   { background: var(--info-bg);    color: var(--brand-navy); }
.tag-yardi      { background: #F3E8E0;           color: #8A5A2C; }
.tag-rentmanager{ background: var(--success-bg); color: var(--success); }

/* ---- ROW-END ACTION ICONS ---- */
.row-actions {
  display: inline-flex;
  gap: 0.2rem;
  align-items: center;
}
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px; height: 24px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-soft);
  border-radius: var(--radius);
  cursor: pointer;
  font-size: 0.8rem;
  text-decoration: none;
}
.icon-btn:hover {
  background: var(--surface-hover);
  color: var(--brand-navy);
  border-color: var(--brand-navy-light);
  text-decoration: none;
}
.icon-btn-danger:hover {
  background: var(--danger-bg);
  color: var(--danger);
  border-color: var(--danger);
}

/* ---- SPARKLINE / MINI-HISTORY ---- */
.sparkline {
  display: inline-flex;
  gap: 0.3rem;
  align-items: center;
  font-variant-numeric: tabular-nums;
  font-size: 0.78rem;
  color: var(--text-soft);
}
.sparkline .spark-val { color: var(--text-soft); }
.sparkline .spark-val.spark-current { color: var(--brand-navy); font-weight: 600; }

/* ---- CHARTS ---- */
.chart-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.65rem 0.85rem;
  position: relative;
}
.chart-card .chart-title {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-soft);
  margin-bottom: 0.4rem;
  text-align: center;
}
.chart-card canvas {
  display: block;
  width: 100% !important;
  max-height: 200px;
}
.chart-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 0.75rem;
}
.chart-grid--tight {
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 0.6rem;
}

/* ---- MODAL ---- */
#modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(20, 57, 88, 0.55);
  z-index: 100; display: none;
}
#modal-backdrop.open { display: block; }
#modal {
  position: fixed;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  background: var(--surface);
  border-radius: var(--radius-lg);
  width: min(95vw, 1100px);
  max-height: 88vh;
  /* Flex column so the dark header stays pinned to the top while
     ONLY the body scrolls. The previous `overflow: auto` on the
     whole modal made the header scroll out of view as the user
     paged through long drill-down content. */
  display: none;
  flex-direction: column;
  overflow: hidden;     /* clip rounded corners against the body scroll */
  z-index: 101;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.25);
}
/* `.open` flips to flex (not block) so the column layout activates */
#modal.open { display: flex; }
.modal-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0.85rem 1.25rem;
  background: var(--brand-navy);
  color: #fff;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
.modal-header h2 { color: #fff; }
.modal-close {
  background: transparent; border: none;
  color: #fff; font-size: 1.5rem; cursor: pointer; line-height: 1;
}
.modal-body { padding: 1.25rem 1.5rem; }

/* Drilldown-modal-only flex layout. Admin modals (.admin-modal) share
   the .modal-header / .modal-body class names but use a block-flow
   container; we scope these flex rules to #modal's direct children
   so admin modals' single-scroll behavior is untouched. */
#modal > .modal-header {
  flex: 0 0 auto;       /* fixed height — never shrinks under scroll */
}
#modal > .modal-body {
  /* Scroll surface lives INSIDE the body, below the header.
     `min-height: 0` is critical — without it, flex children
     refuse to shrink past their natural content height and
     overflow: auto becomes overflow: visible in practice. */
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
}

/* ---- UTILITIES ---- */
.muted { color: var(--text-muted); }
.soft  { color: var(--text-soft); }
.right { text-align: right; }
.center { text-align: center; }
.nowrap { white-space: nowrap; }
.placeholder {
  padding: 3rem 1.5rem;
  text-align: center;
  color: var(--text-muted);
  background: var(--surface-alt);
  border-radius: var(--radius);
  border: 1px dashed var(--border-strong);
}
.text-success { color: var(--success); }
.text-warning { color: var(--warning); }
.text-danger  { color: var(--danger); }


/* =======================================================================
   AUTH PAGES
   Centered card pattern borrowed from mktsvy's /app login screen.
   Lives in its own template chain (auth/layout.html) so the regular
   topbar / sidebar chrome doesn't bleed into the login experience.
   ======================================================================= */
.auth-body {
  background: var(--bg);
  min-height: 100vh;
  margin: 0;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Space Grotesk', system-ui, -apple-system, sans-serif;
}
.auth-shell {
  width: min(480px, 92vw);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.25rem;
  padding: 2rem 0;
}
.auth-brand {
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
}
.auth-brand__logo img {
  /* Match the topbar logo sizing pattern — the eyebrow below it
     scales to span roughly the full image width (chevron +
     wordmark). */
  height: 48px;
  width: auto;
  max-width: 320px;
  display: block;
}
.auth-brand__eyebrow {
  /* "ASSET MANAGEMENT" — sized + letter-spaced so the line width
     matches the NorthRock logo above (chevron + wordmark combined,
     ~320px). mktsvy uses the same trick (MARKET INTELLIGENCE
     under MKTSVY). Iterated up from 0.78 → 1.05 → 1.3rem; this
     is the third pass at sizing per user feedback. */
  font-size: 1.3rem;
  font-weight: 500;
  letter-spacing: 0.5em;
  text-indent: 0.5em;     /* counter the trailing tracking */
  color: var(--text-muted);
  text-transform: uppercase;
}

.auth-card {
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1.75rem 1.75rem 1.5rem;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.04);
}
.auth-card__title {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--text);
  margin: 0 0 0.4rem;
}
.auth-card__subtitle {
  font-size: 0.85rem;
  color: var(--text-soft);
  margin: 0 0 1rem;
  line-height: 1.5;
}

.auth-flash {
  padding: 0.55rem 0.75rem;
  border-radius: 6px;
  font-size: 0.78rem;
  margin-bottom: 0.9rem;
  line-height: 1.4;
}
.auth-flash--info {
  background: var(--accent-soft);
  color: var(--brand-navy);
  border: 1px solid rgba(37, 99, 235, 0.15);
}
.auth-flash--success {
  background: #ecfdf5;
  color: #047857;
  border: 1px solid #a7f3d0;
}
.auth-flash--error {
  background: #fef2f2;
  color: #b91c1c;
  border: 1px solid #fecaca;
}

.auth-form {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}
.auth-form--wide { gap: 0.7rem; }
.auth-form__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.7rem;
}
.auth-form__field {
  display: flex;
  flex-direction: column;
  gap: 0.32rem;
}
.auth-form__label {
  font-size: 0.65rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  color: var(--text-muted);
  text-transform: uppercase;
}
.auth-form__label .req { color: var(--danger); margin-left: 0.15em; }
.auth-form__field input,
.auth-form__field select {
  font: inherit;
  font-size: 0.82rem;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--border-strong);
  border-radius: 5px;
  background: var(--surface);
  color: var(--text);
  width: 100%;
}
.auth-form__field input:focus,
.auth-form__field select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
/* Show/Hide password toggle — sits flush against the right edge of
   the password input. Reserves room on the input via padding-right
   so typed characters don't crash into the button. */
.password-field {
  position: relative;
  display: flex;
  align-items: stretch;
}
.password-field input {
  padding-right: 3.6rem;   /* leave room for "Hide" (worst-case width) */
}
.password-field .password-toggle {
  position: absolute;
  right: 0.35rem;
  top: 50%;
  transform: translateY(-50%);
  font: inherit;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 0.32rem 0.55rem;
  background: transparent;
  border: 0;
  border-radius: 4px;
  color: var(--text-soft);
  cursor: pointer;
  transition: color 100ms ease, background 100ms ease;
}
.password-field .password-toggle:hover {
  color: var(--brand-navy);
  background: var(--surface-hover);
}
.password-field .password-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.auth-form__turnstile {
  /* Cloudflare's widget renders an iframe; we just leave margin so
     it doesn't crash into the surrounding fields. */
  margin: 0.3rem 0 0.2rem;
  min-height: 65px;
}
.auth-form__submit {
  font: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  padding: 0.6rem 1.1rem;
  border: 1px solid var(--accent);
  border-radius: 5px;
  background: var(--accent);
  color: #fff;
  cursor: pointer;
  letter-spacing: 0.02em;
  transition: background 120ms ease, border-color 120ms ease;
  margin-top: 0.4rem;
}
.auth-form__submit:hover {
  background: var(--brand-navy);
  border-color: var(--brand-navy);
}
.auth-form__cancel {
  font: inherit;
  font-size: 0.82rem;
  padding: 0.6rem 1.1rem;
  border: 1px solid var(--border-strong);
  border-radius: 5px;
  background: var(--surface);
  color: var(--text-soft);
  cursor: pointer;
  text-decoration: none;
  margin-top: 0.4rem;
  text-align: center;
}
.auth-form__cancel:hover {
  color: var(--brand-navy);
  border-color: var(--brand-navy-light);
}
.auth-form__actions {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.5rem;
  justify-content: flex-end;
}
.auth-form__links {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.78rem;
  margin-top: 0.4rem;
}
.auth-form__links a {
  color: var(--accent);
  text-decoration: none;
  font-weight: 600;
}
.auth-form__links a:hover { text-decoration: underline; }
.auth-form__sep { color: var(--border-strong); }
.auth-form__legalese {
  margin: 1rem 0 0;
  font-size: 0.7rem;
  color: var(--text-muted);
  text-align: center;
  line-height: 1.4;
}

.auth-footer {
  text-align: center;
  color: var(--text-muted);
  font-size: 0.72rem;
}
.auth-footer a {
  color: var(--accent);
  text-decoration: none;
  font-weight: 600;
  margin-left: 0.5rem;
}
.auth-footer a:hover { text-decoration: underline; }

/* Topbar: current user pill — sits to the left of Sign out. */
.topbar-user {
  color: var(--text-soft);
  font-size: 0.72rem;
  font-weight: 600;
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Admin users page: per-row action cluster. */
.admin-user-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
}
.admin-users-wrapper {
  padding: 1rem;
}

/* Floating scroll-to-top button. Sits fixed in the bottom-right.
 * Brand-navy fill (NOT mktsvy pink) to match the rest of the report
 * UI. Hidden by default via the `hidden` attribute; JS toggles it
 * once the user scrolls past ~60% of the viewport height. */
.scroll-top {
  position: fixed;
  right: 1.5rem;
  bottom: 1.5rem;
  z-index: 60;            /* above sticky topbar (z-index 50) */
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  border: 1px solid var(--brand-navy-dark);
  background: var(--brand-navy);
  color: #ffffff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: var(--shadow);
  transition: transform 0.15s ease, background-color 0.15s ease,
              box-shadow 0.15s ease, opacity 0.15s ease;
  opacity: 0.92;
}
.scroll-top:hover {
  background: var(--brand-navy-dark);
  transform: translateY(-2px);
  box-shadow: 0 4px 14px rgba(20, 57, 88, 0.20);
  opacity: 1;
}
.scroll-top:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.scroll-top[hidden] {
  display: none;
}

/* ============================================================
 * MOBILE OVERRIDES — viewports ≤ 768px (phones + small tablets).
 *
 * Everything in this block is guarded by `@media (max-width: 768px)`,
 * so above the breakpoint NOT A SINGLE RULE applies and the desktop
 * cascade is byte-identical to what it was before this block was
 * added. The viewport meta tag in base.html
 * (`width=device-width, initial-scale=1`) is what enables these
 * rules to actually fire — without it iOS would render at 980px
 * regardless.
 *
 * Sections:
 *   1. Topbar (sticky header — wraps + scrolls horizontally)
 *   2. Page chrome (padding + headings tightened)
 *   3. Data tables (let wide tables scroll horizontally inside
 *      their `.section` cards — they're too information-dense to
 *      reflow into stacked cards without hiding columns the
 *      analyst needs to compare across properties)
 *   4. Modals (fill the screen instead of floating in the middle)
 *   5. Forms (full-width inputs, larger tap targets)
 *   6. Misc affordances (scroll-top button, KPI strip)
 * ============================================================ */
@media (max-width: 768px) {
  /* --- 1. Topbar --- */
  /* The desktop topbar is a single flex row with logo + tab nav +
     right-side actions. On a 375px phone that overflows; we let
     the row WRAP into 2-3 lines and tighten the padding so the
     header doesn't eat half the screen. */
  .topbar {
    flex-wrap: wrap;
    padding: 0.4rem 0.6rem;
    gap: 0.5rem;
    row-gap: 0.4rem;
    min-height: 0;
  }
  .topbar .brand-logo img {
    height: 20px;
    max-width: 130px;
  }
  /* Hide the "ASSET MANAGEMENT" sub-label — the logo + nav tabs
     already establish context, and at this width every horizontal
     pixel counts. */
  .topbar .brand-sub {
    display: none;
  }
  /* Tab nav becomes a horizontally-scrollable strip so OPERATIONS /
     FINANCIALS / TOOLS / ADMIN + the AM filter all stay reachable
     without forcing the page itself to widen. Hide the scrollbar
     to keep the strip looking like a pill rail. */
  .tabnav {
    margin-left: 0;
    flex: 1 1 100%;
    overflow-x: auto;
    overflow-y: hidden;
    flex-wrap: nowrap;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding-bottom: 0.15rem;
  }
  .tabnav::-webkit-scrollbar { display: none; }
  .tabnav a,
  .tabnav .am-filter-global,
  .tabnav .external-text-link,
  .tabnav .mktsvy-pill {
    flex: 0 0 auto;
    white-space: nowrap;
  }
  /* AM dropdown sometimes carries long firm names — let it shrink
     to its content rather than reserving a 220px lane. */
  .tabnav .am-filter-global {
    max-width: 180px;
  }
  /* Right-side stats / sign-out / theme toggle — drop "stat"
     labels we have room for on desktop but not on a phone. */
  .topbar-right {
    margin-left: auto;
    gap: 0.4rem;
    font-size: 0.7rem;
  }
  .topbar-right .stat {
    display: none;
  }

  /* --- 2. Main page chrome --- */
  main {
    padding: 0.6rem 0.55rem 2rem;
  }
  h1 { font-size: 1.1rem; }
  h2 { font-size: 0.9rem; }
  h3 { font-size: 0.82rem; }
  .section {
    margin-bottom: 0.7rem;
    border-radius: 8px;
  }
  .section-header {
    padding: 0.55rem 0.7rem;
  }

  /* --- 3. Data tables --- */
  /* The Financials / Operations / Tools tables have 10-15 columns;
     reflowing them into stacked cards would hide cross-column
     comparisons that ARE the point of these tables. Instead we
     let each table's parent .section scroll horizontally on the
     touch-x axis. Header is still sticky vertically (existing
     desktop rules), so the property column lane scrolls in
     sync with the data lanes — analyst keeps context. */
  .section {
    /* Override the desktop `overflow: hidden` (which would clip a
       table wider than the screen). Vertical overflow stays inside
       the section so its rounded corners + shadow still read
       cleanly. */
    overflow-x: auto;
    overflow-y: visible;
    -webkit-overflow-scrolling: touch;
  }
  .data-table {
    /* min-width keeps each column readable; the section scrolls. */
    min-width: 720px;
    font-size: 0.78rem;
  }
  .data-table thead th,
  .data-table tbody td {
    padding: 0.45rem 0.55rem;
  }

  /* --- 4. Modals --- */
  /* Two modal patterns exist (admin + legacy dashboard / drill-down).
     Both float in the middle of the screen on desktop with a backdrop.
     On mobile we want full-screen — gives back every available pixel
     to the data and avoids tap-target landmines around the chrome.
     Selectors target whatever container pattern is in use without
     relying on a specific class name. */
  .modal,
  .modal-container,
  .modal-dialog,
  #modal,
  #drilldown-modal {
    width: 100vw !important;
    max-width: 100vw !important;
    max-height: 100vh !important;
    left: 0 !important;
    top: 0 !important;
    right: 0 !important;
    bottom: 0 !important;
    border-radius: 0 !important;
    margin: 0 !important;
  }
  .modal-body,
  #modal-body {
    padding: 0.6rem !important;
  }

  /* --- 5. Forms (Tools page upload widgets, Admin user form) --- */
  /* Stack form rows vertically so 360-380px phones don't need to
     side-scroll a form, and bump tap-target sizes on inputs +
     buttons to the iOS 44px guideline. */
  input[type="text"],
  input[type="email"],
  input[type="password"],
  input[type="date"],
  input[type="number"],
  input[type="file"],
  select,
  textarea {
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
    font-size: 16px; /* iOS skips the auto-zoom-on-focus when ≥16px */
    min-height: 40px;
  }
  .btn {
    min-height: 40px;
    padding: 0.55rem 0.85rem;
  }
  /* Layouts that put form rows side-by-side on desktop — stack
     them on phones. These class names are the ones in tools.html
     + admin.html + auth/layout.html. */
  .form-row,
  .form-grid,
  .form-group-inline,
  .tools-row,
  .filters-row {
    flex-direction: column !important;
    align-items: stretch !important;
    gap: 0.45rem !important;
  }

  /* --- 6. Misc --- */
  /* Scroll-to-top button — shrink so it doesn't cover the bottom
     of a table cell the user is trying to read. */
  .scroll-top {
    width: 36px;
    height: 36px;
    bottom: 1rem;
    right: 1rem;
  }
  /* KPI tiles (used on Operations summary block) — single column
     instead of the 3-4 across desktop grid. */
  .kpi-strip,
  .kpi-row {
    grid-template-columns: 1fr !important;
    flex-direction: column !important;
    gap: 0.45rem !important;
  }
  .kpi-card {
    width: 100% !important;
    min-width: 0 !important;
  }
}

/* ---- Admin Data Management: per-cell scrape buttons + spinners ----
   The button sits inline with the freshness label; subtle by default
   (low-contrast, hover-revealed) so it doesn't visually fight with
   the dot+date that's the cell's primary content. */
.manual-scrape-btn {
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-3, #6b7280);
  cursor: pointer;
  padding: 0 0.3rem;
  border-radius: 4px;
  font-size: 0.9rem;
  line-height: 1.1;
  font-family: inherit;
  opacity: 0.45;
  transition: opacity 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.freshness-cell:hover .manual-scrape-btn { opacity: 1; }
.manual-scrape-btn:hover {
  color: var(--text-1, #1f2937);
  background: var(--bg-2, #f3f4f6);
  border-color: var(--border-color, #e5e7eb);
}
.manual-scrape-btn:active { transform: translateY(1px); }
.manual-scrape-btn:focus-visible { outline: 2px solid #4b8be0; outline-offset: 1px; }

.manual-scrape-spinner {
  display: inline-block;
  font-size: 0.95rem;
  color: #4b8be0;
  animation: nr-spin 1s linear infinite;
  cursor: progress;
}
@keyframes nr-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

.manual-scrape-ok {
  color: #2E7D5B;
  font-weight: 600;
  font-size: 0.9rem;
}
.manual-scrape-fail {
  color: #C0392B;
  font-weight: 600;
  font-size: 0.9rem;
  cursor: help;
}

/* ---- Server resources meter (mirrors mktsvy admin layout) ----
   2-column grid on wide screens, stacks to 1 col on narrow. Each meter
   = label, used/total/percent text on the right, a thin progress bar
   underneath colored by the same green/yellow/red usage tiers we use
   for freshness coloring. */
.srv-meter-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.75rem 1.5rem;
}
@media (max-width: 720px) {
  .srv-meter-grid { grid-template-columns: 1fr; }
}
.srv-meter {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.srv-meter-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 0.75rem;
}
.srv-meter-label {
  color: var(--text-2, #4b5563);
  font-weight: 500;
  letter-spacing: 0.02em;
}
.srv-meter-usage {
  color: var(--text-2, #4b5563);
  font-variant-numeric: tabular-nums;
  font-size: 0.72rem;
}
.srv-meter-bar {
  background: var(--bg-2, #f3f4f6);
  border-radius: 3px;
  height: 6px;
  overflow: hidden;
}
.srv-meter-fill {
  height: 100%;
  border-radius: 3px;
  transition: width 0.6s ease, background 0.3s ease;
}

/* ============================================================
   Landing dashboard at `/` — 3x2 tile grid roll-up of the
   portfolio's current state. Each tile is wrapped in an anchor
   that links to the relevant deep-dive tab.
   ============================================================ */
/* Grid-mode classes (per-user preference, set in Dashboard Settings):
   - .grid-mode-fixed  (default, also the bare-.dash-grid behavior):
     3 equal columns regardless of tile count. Responsive breakpoints
     below collapse this to 2-col @ ≤1080px and 1-col @ ≤720px so the
     layout stays readable on smaller screens.
   - .grid-mode-flex:
     Auto-fit columns with a 280px per-tile minimum. With N visible
     tiles, the row width is split evenly among the tiles that fit on
     it (1 tile = full width, 2 = 1/2 each, 3 = 1/3, 4 = 1/4 …). At
     viewport widths below ~280px-per-tile-times-N, tiles wrap to the
     next row organically — no separate media queries needed.
   The responsive media queries below only apply to fixed mode so they
   don't override flex mode's auto-fit behavior at the same breakpoints. */
.dash-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1rem;
  /* No top padding — the parent <main> already provides 1rem above,
     so adding another 1rem here would make the gap above the first
     row TWICE the gap between rows (the 1rem `gap` above). User-
     visible result: header/first-row spacing now matches inter-row
     spacing on the dashboard. */
  padding: 0 1.25rem 1rem;
}
.dash-grid.grid-mode-flex {
  /* Flex mode is flexbox — NOT auto-fit grid. We need per-tile sizing
     (the .tile-w-* classes below) which CSS Grid auto-fit can't honor
     because it forces equal-width columns. Flexbox with explicit
     `flex-basis` per tile + flex-wrap handles the layout naturally:
     - Tiles with .tile-w-full / -half / -third / -quarter / -fifth get
       a rigid flex-basis (no grow/shrink past that fraction)
     - Tiles with .tile-w-auto get `flex: 1 1 280px` — they grow to
       absorb whatever row width is left over by the explicit-width
       tiles on their row. So a row with one "1/4" + three "auto"
       tiles ends up as 25% + 25% + 25% + 25%; a row with two "1/2"
       tiles is 50%+50% and the next auto tile wraps to row 2 as
       full-width (or shares with whatever other tiles wrap with it).
     - Wide tiles (catalog-flagged via .dash-tile-wide) keep a hard
       `flex: 0 0 100%` so a wide-bodied tile never shrinks below the
       row width even if the user picks a narrow width pref. */
  display: flex;
  flex-wrap: wrap;
  /* gap is inherited from the base .dash-grid rule above (1rem) so
     the calc(...) subtractions below stay in sync. */
}
/* Per-tile width classes (only apply in flex mode — fixed mode is
   pure 3-col grid and ignores these). The calc subtracts each tile's
   fractional share of the inter-tile gap so N tiles at 1/N still fit
   exactly one row width even with the gap accounted for. */
.dash-grid.grid-mode-flex > .dash-tile.tile-w-auto {
  /* flex: <grow> <shrink> <basis> — grow=1 absorbs leftover row width;
     basis=280px sets the natural wrap threshold so auto tiles wrap to
     the next row when there isn't room for a readable tile. */
  flex: 1 1 280px;
  min-width: 280px;
}
.dash-grid.grid-mode-flex > .dash-tile.tile-w-full {
  flex: 0 0 100%;
}
.dash-grid.grid-mode-flex > .dash-tile.tile-w-half {
  flex: 0 0 calc(50% - 0.5rem);
  min-width: 0;
}
.dash-grid.grid-mode-flex > .dash-tile.tile-w-third {
  flex: 0 0 calc(33.3333% - 0.6667rem);
  min-width: 0;
}
.dash-grid.grid-mode-flex > .dash-tile.tile-w-quarter {
  flex: 0 0 calc(25% - 0.75rem);
  min-width: 0;
}
.dash-grid.grid-mode-flex > .dash-tile.tile-w-fifth {
  flex: 0 0 calc(20% - 0.8rem);
  min-width: 0;
}
/* Wide tiles (catalog-flagged) always span the full row regardless of
   the user's saved width pref. The selector specificity matches the
   per-tile width rules above so it doesn't lose the cascade. */
.dash-grid.grid-mode-flex > .dash-tile.dash-tile-wide {
  flex: 0 0 100%;
}
@media (max-width: 1080px) {
  /* Only collapse fixed mode — flex mode is already responsive via
     flex-wrap + the auto tiles' 280px basis floor. */
  .dash-grid:not(.grid-mode-flex) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* Mobile / phone-sized override: at viewports ≤820px every tile renders
   full width regardless of saved grid_mode + per-tile width prefs. Covers
   phones in any orientation (incl. Pro Max in landscape ~896px → no, that
   falls back to desktop layout — but the typical phone in landscape is
   ≤820px) AND iPad in portrait (~768-820px). The user's saved preferences
   stay intact in the DB; this is purely a render-time override so they
   come back when the device viewport widens. */
@media (max-width: 820px) {
  .dash-grid:not(.grid-mode-flex) { grid-template-columns: 1fr; }
  .dash-grid.grid-mode-flex > .dash-tile { flex: 0 0 100%; min-width: 0; }
}
/* Tablet-in-portrait override: touch-first devices (pointer: coarse)
   held vertically often have viewport widths >820px (iPad Pro portrait
   is ~1024px) but the multi-column dashboard feels cramped + each tile
   chart becomes hard to read. Force full-width tiles in this case too
   without changing the saved prefs. Landscape tablets / desktops with
   a touch screen are NOT affected — they keep the user's chosen layout. */
@media (pointer: coarse) and (orientation: portrait) {
  .dash-grid:not(.grid-mode-flex) { grid-template-columns: 1fr; }
  .dash-grid.grid-mode-flex > .dash-tile { flex: 0 0 100%; min-width: 0; }
}
/* Wide-tile modifier — spans the full row of the dash grid. Used by
   tiles whose body is a wide multi-column table that won't fit a
   single 1/3-width slot (e.g. Occupancy Snapshot's 9-column table). */
.dash-tile.dash-tile-wide { grid-column: 1 / -1; }
/* The drilldown link wraps the tile body + chart ONLY — the header
   stays outside so the dropdown menu can be interacted with without
   navigating. The link still fills the remaining vertical space
   inside the tile (flex:1) so the click target is generous. */
.dash-tile-link {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}
.dash-tile-link:hover { text-decoration: none; }
.dash-tile {
  background: white;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  padding: 0.85rem 1rem 0.95rem;
  display: flex;
  flex-direction: column;
  min-height: 380px;
  position: relative;  /* anchor for .dash-tile-close absolute positioning */
  transition: border-color 0.15s ease, box-shadow 0.15s ease,
              transform 0.15s ease;
}
/* Per-tile hide button. Floats in the upper-right corner of the tile,
   above the header but outside the drilldown anchor. Hidden until the
   user hovers the tile so it doesn't compete with the content visually.
   Click handler removes the tile (same as unchecking it in the
   Settings modal). */
.dash-tile-close {
  position: absolute;
  top: 0.4rem;
  right: 0.45rem;
  width: 1.35rem;
  height: 1.35rem;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: #94a3b8;          /* slate-400 — quiet until hovered */
  font-size: 1.05rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.15s ease, background 0.15s ease, color 0.15s ease;
  z-index: 2;              /* sit above the .dash-tile-link anchor */
}
.dash-tile:hover .dash-tile-close,
.dash-tile-close:focus-visible {
  opacity: 1;
}
.dash-tile-close:hover {
  background: #fee2e2;     /* red-100 */
  color: #b91c1c;          /* red-700 */
}
/* Hover on the LINK area (body + chart) is the primary affordance —
   lift the parent tile so the user gets visual feedback that the
   region is clickable. Hovering the header alone (where the dropdown
   lives) does NOT trigger the lift, matching the click semantics. */
.dash-tile:has(.dash-tile-link:hover) {
  border-color: var(--brand-navy-light, #2A6FA0);
  box-shadow: 0 4px 12px rgba(27, 79, 118, 0.10);
  transform: translateY(-1px);
}
.dash-tile-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Pull the band out through the tile's own padding so it spans the
     full tile width — mirrors the Operations / Financials section-
     header band (light bluish-grey on light, deep navy on dark) and
     visually labels the area as the drag-handle region (NOT the
     drilldown click target, which lives below). */
  margin: -0.85rem -1rem 0.65rem -1rem;
  padding: 0.55rem 1rem;
  background: var(--info-bg);
  border-bottom: 1px solid var(--border-strong);
  border-top-left-radius: 8px;
  border-top-right-radius: 8px;
  cursor: grab;        /* SortableJS handle — grab anywhere on the header */
  user-select: none;   /* prevent the title turning into a selection mid-drag */
}
.dash-tile-header:active { cursor: grabbing; }
.dash-tile-header h2 {
  margin: 0;
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--brand-navy, #1B4F76);
}
.dash-tile-controls {
  display: flex;
  gap: 0.25rem;
  /* Controls keep the default arrow / pointer cursor so users know
     these stay clickable even though the surrounding header is draggable. */
  cursor: default;
  /* Reserve clearance for the absolute-positioned × close button on the
     right edge of the tile. Without this, the X (which has z-index: 2
     and fades in on tile hover) sits directly on top of the dropdown's
     chevron — clicks the user thinks are landing on the dropdown
     actually hit the close button and hide the tile. */
  margin-right: 1.6rem;
}
/* Live-drag feedback on the dashboard grid: ghost = the placeholder
   where the tile will land; chosen = the picked-up tile; drag = the
   floating clone under the cursor. Mirrors mktsvy-ish visual. */
.dash-tile-ghost {
  opacity: 0.35;
  background: rgba(27, 79, 118, 0.06);
}
.dash-tile-chosen { cursor: grabbing; }
.dash-tile-drag {
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
  transform: rotate(-0.5deg);
}
.dash-tile-dropdown {
  font-size: 0.75rem;
  padding: 0.15rem 0.35rem;
  border: 1px solid #d1d5db;
  border-radius: 4px;
  background: white;
  cursor: pointer;
  color: #1f2937;
}
.dash-tile-dropdown:hover { border-color: var(--brand-navy-light, #2A6FA0); }

.dash-tile-body {
  font-size: 0.8rem;
  /* Don't let the body steal vertical space from the chart — it
     should size to its content so the chart can flex-grow to fill
     whatever's left in the tile. */
  flex: 0 0 auto;
}
.dash-tile-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.78rem;
}
.dash-tile-table th, .dash-tile-table td {
  padding: 0.22rem 0.3rem;
  text-align: left;
  border: none;
}
.dash-tile-table thead th {
  font-weight: 500;
  font-size: 0.7rem;
  color: #6b7280;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  border-bottom: 1px solid #e5e7eb;
  padding-bottom: 0.2rem;
}
.dash-tile-table tbody th {
  font-weight: 500;
  color: #374151;
}
.dash-tile-table td.num, .dash-tile-table th.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.dash-tile-table td.muted { color: #9ca3af; }
.dash-tile-table td.delta-positive { color: #16a34a; font-weight: 500; }
.dash-tile-table td.delta-negative { color: #dc2626; font-weight: 500; }
.dash-tile-table td.delta-neutral { color: #6b7280; }
/* Period caption shown above the BS Changes and Expense Comparison
   tile tables — "May 2026 vs Apr 2026" reading. Same hierarchy as
   the tile sub-headers: muted color, slightly smaller, modest margin
   so it doesn't crowd the table below. */
.dash-tile-period {
  font-size: 0.85em;
  color: var(--text-muted, #6b7280);
  margin: 0 0 6px 0;
  letter-spacing: 0.01em;
}
.dash-tile-period .muted { color: #9ca3af; }
/* Sub-header row that splits a multi-section table (e.g. "Current Month"
   vs "YTD" in T-12 Financials). Reads as a section divider, not a data
   row, so the same Actual/Budget/Var headers can serve both blocks. */
.dash-tile-table tr.dash-tile-subhead th {
  font-size: 0.66rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--brand-navy, #1B4F76);
  background: rgba(27, 79, 118, 0.05);
  padding-top: 0.45rem;
  padding-bottom: 0.2rem;
}

/* Occupancy Snapshot table — uses chip badges in numeric cells, so
   the default text-align:right via .num isn't enough (badges need
   center-align for the colored pill to read cleanly). Portfolio row
   gets a top border + subtle background to read as a totals band,
   matching the Operations page convention. */
.dash-occ-snapshot-table tbody td.num,
.dash-occ-snapshot-table thead th.num { text-align: center; }
.dash-occ-snapshot-table tbody td:first-child,
.dash-occ-snapshot-table thead th:first-child { text-align: left; }
.dash-occ-snapshot-table tbody tr.dash-tile-subtotal td {
  border-top: 1px solid var(--brand-navy, #1B4F76);
  background: rgba(27, 79, 118, 0.04);
  padding-top: 0.32rem;
  padding-bottom: 0.32rem;
}
[data-theme="dark"] .dash-occ-snapshot-table tbody tr.dash-tile-subtotal td {
  background: rgba(255, 255, 255, 0.04);
}
/* Snapshot scroll wrapper — lets the 9-column table live inside a
   1/3-width tile by scrolling horizontally when content overflows.
   table-layout:auto + nowrap on cells keeps each column at its
   natural width rather than letting the browser shrink Property
   names to fit. The scrollbar appears only when needed. */
.dash-occ-snapshot-scroll {
  overflow-x: auto;
  max-width: 100%;
}
.dash-occ-snapshot-table {
  table-layout: auto;
}
.dash-occ-snapshot-table th,
.dash-occ-snapshot-table td { white-space: nowrap; }

/* ----------------------------------------------------------------
   Per-column widths for the shared OCC_COLUMN_REGISTRY. Applies to
   BOTH the Operations Occupancy Trend table (.occupancy-table) and
   the Dashboard Occupancy Snapshot tile (.dash-occ-snapshot-table)
   so a user resizing one stays consistent with the other. Keyed on
   the data-col attribute, NOT positional nth-child, so the gear-
   icon picker's reorder + hide operations keep widths attached to
   the logical column rather than the slot.

   Sizing target: every column claims enough horizontal space for
   its widest realistic value WITHOUT stealing from neighbors. Text
   columns nowrap + ellipsis past max-width; numeric columns are
   sized to "100.0%" / "$12,345,678" / "2026-06-30" etc.
   ---------------------------------------------------------------- */
.occupancy-table th[data-col="name"],
.occupancy-table td[data-col="name"],
.dash-occ-snapshot-table th[data-col="name"],
.dash-occ-snapshot-table td[data-col="name"] {
  min-width: 170px;
  max-width: 220px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.occupancy-table th[data-col="units"],
.occupancy-table td[data-col="units"],
.dash-occ-snapshot-table th[data-col="units"],
.dash-occ-snapshot-table td[data-col="units"]            { min-width: 56px; white-space: nowrap; }
.occupancy-table th[data-col="occupied"],
.occupancy-table td[data-col="occupied"],
.dash-occ-snapshot-table th[data-col="occupied"],
.dash-occ-snapshot-table td[data-col="occupied"]         { min-width: 72px; white-space: nowrap; }
.occupancy-table th[data-col="available"],
.occupancy-table td[data-col="available"],
.dash-occ-snapshot-table th[data-col="available"],
.dash-occ-snapshot-table td[data-col="available"]        { min-width: 56px; white-space: nowrap; }
.occupancy-table th[data-col="occ_pct"],
.occupancy-table td[data-col="occ_pct"],
.dash-occ-snapshot-table th[data-col="occ_pct"],
.dash-occ-snapshot-table td[data-col="occ_pct"]          { min-width: 66px; white-space: nowrap; }
.occupancy-table th[data-col="avail_pct"],
.occupancy-table td[data-col="avail_pct"],
.dash-occ-snapshot-table th[data-col="avail_pct"],
.dash-occ-snapshot-table td[data-col="avail_pct"]        { min-width: 66px; white-space: nowrap; }
/* Projection % + movement chips — narrow because they pair up. */
.occupancy-table th[data-col^="proj_"][data-col$="0"],
.occupancy-table td[data-col^="proj_"][data-col$="0"],
.dash-occ-snapshot-table th[data-col^="proj_"][data-col$="0"],
.dash-occ-snapshot-table td[data-col^="proj_"][data-col$="0"] { min-width: 60px; white-space: nowrap; }
.occupancy-table th[data-col$="_mov"],
.occupancy-table td[data-col$="_mov"],
.dash-occ-snapshot-table th[data-col$="_mov"],
.dash-occ-snapshot-table td[data-col$="_mov"]            { min-width: 48px; white-space: nowrap; }
.occupancy-table th[data-col="avg_rent"],
.occupancy-table td[data-col="avg_rent"],
.dash-occ-snapshot-table th[data-col="avg_rent"],
.dash-occ-snapshot-table td[data-col="avg_rent"]         { min-width: 76px; white-space: nowrap; }
/* Subsidy count + percentage are 1-2 digit values; keep them tight. */
.occupancy-table th[data-col="sub_count"],
.occupancy-table td[data-col="sub_count"],
.dash-occ-snapshot-table th[data-col="sub_count"],
.dash-occ-snapshot-table td[data-col="sub_count"]        { min-width: 44px; white-space: nowrap; }
.occupancy-table th[data-col="sub_pct"],
.occupancy-table td[data-col="sub_pct"],
.dash-occ-snapshot-table th[data-col="sub_pct"],
.dash-occ-snapshot-table td[data-col="sub_pct"]          { min-width: 56px; white-space: nowrap; }
.occupancy-table th[data-col="recent"],
.occupancy-table td[data-col="recent"],
.dash-occ-snapshot-table th[data-col="recent"],
.dash-occ-snapshot-table td[data-col="recent"]           { min-width: 64px; }
.occupancy-table th[data-col="pms"],
.occupancy-table td[data-col="pms"],
.dash-occ-snapshot-table th[data-col="pms"],
.dash-occ-snapshot-table td[data-col="pms"]              { min-width: 74px; white-space: nowrap; }
.occupancy-table th[data-col="as_of"],
.occupancy-table td[data-col="as_of"],
.dash-occ-snapshot-table th[data-col="as_of"],
.dash-occ-snapshot-table td[data-col="as_of"]            { min-width: 92px; white-space: nowrap; }

/* ---- Extended (default-hidden) columns ---- */
.occupancy-table th[data-col="street_address"],
.occupancy-table td[data-col="street_address"],
.dash-occ-snapshot-table th[data-col="street_address"],
.dash-occ-snapshot-table td[data-col="street_address"] {
  min-width: 180px; max-width: 240px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.occupancy-table th[data-col="city"],
.occupancy-table td[data-col="city"],
.dash-occ-snapshot-table th[data-col="city"],
.dash-occ-snapshot-table td[data-col="city"] {
  /* Longest commonly-seen city: "North Chesterfield", "Virginia Beach". */
  min-width: 120px; white-space: nowrap;
}
.occupancy-table th[data-col="state"],
.occupancy-table td[data-col="state"],
.dash-occ-snapshot-table th[data-col="state"],
.dash-occ-snapshot-table td[data-col="state"]            { min-width: 44px; white-space: nowrap; }
.occupancy-table th[data-col="asset_manager"],
.occupancy-table td[data-col="asset_manager"],
.dash-occ-snapshot-table th[data-col="asset_manager"],
.dash-occ-snapshot-table td[data-col="asset_manager"] {
  min-width: 130px; max-width: 180px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.occupancy-table th[data-col="mgmt_company"],
.occupancy-table td[data-col="mgmt_company"],
.dash-occ-snapshot-table th[data-col="mgmt_company"],
.dash-occ-snapshot-table td[data-col="mgmt_company"] {
  min-width: 150px; max-width: 220px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.occupancy-table th[data-col="year_built"],
.occupancy-table td[data-col="year_built"],
.dash-occ-snapshot-table th[data-col="year_built"],
.dash-occ-snapshot-table td[data-col="year_built"]       { min-width: 60px; white-space: nowrap; }
.occupancy-table th[data-col="close_date"],
.occupancy-table td[data-col="close_date"],
.dash-occ-snapshot-table th[data-col="close_date"],
.dash-occ-snapshot-table td[data-col="close_date"]       { min-width: 92px; white-space: nowrap; }
/* Big-dollar columns — fit "$12,345,678" + a little breathing room. */
.occupancy-table th[data-col="purchase_price"],
.occupancy-table td[data-col="purchase_price"],
.occupancy-table th[data-col="all_in_cost"],
.occupancy-table td[data-col="all_in_cost"],
.occupancy-table th[data-col="equity"],
.occupancy-table td[data-col="equity"],
.occupancy-table th[data-col="initial_debt"],
.occupancy-table td[data-col="initial_debt"],
.occupancy-table th[data-col="current_debt"],
.occupancy-table td[data-col="current_debt"],
.occupancy-table th[data-col="t12_noi"],
.occupancy-table td[data-col="t12_noi"],
.dash-occ-snapshot-table th[data-col="purchase_price"],
.dash-occ-snapshot-table td[data-col="purchase_price"],
.dash-occ-snapshot-table th[data-col="all_in_cost"],
.dash-occ-snapshot-table td[data-col="all_in_cost"],
.dash-occ-snapshot-table th[data-col="equity"],
.dash-occ-snapshot-table td[data-col="equity"],
.dash-occ-snapshot-table th[data-col="initial_debt"],
.dash-occ-snapshot-table td[data-col="initial_debt"],
.dash-occ-snapshot-table th[data-col="current_debt"],
.dash-occ-snapshot-table td[data-col="current_debt"],
.dash-occ-snapshot-table th[data-col="t12_noi"],
.dash-occ-snapshot-table td[data-col="t12_noi"]          { min-width: 108px; white-space: nowrap; }
.occupancy-table th[data-col="interest_rate"],
.occupancy-table td[data-col="interest_rate"],
.dash-occ-snapshot-table th[data-col="interest_rate"],
.dash-occ-snapshot-table td[data-col="interest_rate"]    { min-width: 80px; white-space: nowrap; }
.occupancy-table th[data-col="maturity_date"],
.occupancy-table td[data-col="maturity_date"],
.dash-occ-snapshot-table th[data-col="maturity_date"],
.dash-occ-snapshot-table td[data-col="maturity_date"]    { min-width: 92px; white-space: nowrap; }
.occupancy-table th[data-col="lender"],
.occupancy-table td[data-col="lender"],
.dash-occ-snapshot-table th[data-col="lender"],
.dash-occ-snapshot-table td[data-col="lender"] {
  min-width: 130px; max-width: 200px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.occupancy-table th[data-col="loan_type"],
.occupancy-table td[data-col="loan_type"],
.dash-occ-snapshot-table th[data-col="loan_type"],
.dash-occ-snapshot-table td[data-col="loan_type"]        { min-width: 100px; white-space: nowrap; }
.occupancy-table th[data-col="econ_occ"],
.occupancy-table td[data-col="econ_occ"],
.dash-occ-snapshot-table th[data-col="econ_occ"],
.dash-occ-snapshot-table td[data-col="econ_occ"]         { min-width: 70px; white-space: nowrap; }
.occupancy-table th[data-col="t12_as_of"],
.occupancy-table td[data-col="t12_as_of"],
.dash-occ-snapshot-table th[data-col="t12_as_of"],
.dash-occ-snapshot-table td[data-col="t12_as_of"]        { min-width: 92px; white-space: nowrap; }

/* Management Company tile — small wrapped grey footnote listing
   the properties under each PM firm. The hover tooltip carries the
   full list verbatim too (we duplicate it on the parent <td> via the
   `title` attribute) so the reader can scan in either mode. */
.dash-mgmt-co-table td .dash-pm-properties {
  font-size: 0.66rem;
  font-weight: 400;
  color: #6b7280;
  line-height: 1.3;
  margin-top: 0.15rem;
  /* Allow the property list to wrap inside the cell; without this
     the nowrap from .dash-occ-snapshot-table-style would flow it
     into one very wide line. */
  white-space: normal;
  max-width: 18rem;
}
[data-theme="dark"] .dash-mgmt-co-table td .dash-pm-properties { color: #9ca3af; }

/* Thin divider between each PM-company row (mirrors the AM tile's
   row separator on the dashboard). First body row has no top
   border so it sits flush under the header line. The grand-total
   row already has a stronger navy border via .dash-tile-subtotal,
   which wins specificity here. */
.dash-mgmt-co-table tbody tr + tr td {
  border-top: 1px solid #f3f4f6;
}
[data-theme="dark"] .dash-mgmt-co-table tbody tr + tr td {
  border-top-color: rgba(255, 255, 255, 0.07);
}

/* Sortable header indicators — mirror the .data-table.sortable
   styling on the Operations page so click-to-sort affordances read
   the same on both surfaces (subtle ⇅ at rest, ▲/▼ tinted when
   active, pointer cursor on hover). Scoped to .dash-tile-table so
   the headers in the regular AM / Financials kv-tables stay plain. */
.dash-tile-table.sortable thead th.sortable {
  cursor: pointer;
  user-select: none;
  position: relative;
  padding-right: 0.9rem;
}
.dash-tile-table.sortable thead th.sortable::after {
  content: '⇅';
  position: absolute;
  right: 0.2rem;
  top: 50%;
  transform: translateY(-50%);
  font-size: 0.7em;
  opacity: 0.35;
}
.dash-tile-table.sortable thead th.sortable.sort-asc::after {
  content: '▲';
  opacity: 1;
  color: var(--brand-navy, #1B4F76);
}
.dash-tile-table.sortable thead th.sortable.sort-desc::after {
  content: '▼';
  opacity: 1;
  color: var(--brand-navy, #1B4F76);
}
.dash-tile-table.sortable thead th.sortable:hover {
  color: var(--brand-navy, #1B4F76);
}
[data-theme="dark"] .dash-tile-table tr.dash-tile-subhead th {
  color: #cbd5e1;
  background: rgba(255, 255, 255, 0.05);
}

/* Occupancy Snapshot row click → property focus.
   Each row carries data-property-code. Hover gets a subtle background
   tint + cursor:pointer to signal clickability. The currently focused
   row (server-rendered with .dash-row-focused) gets a stronger tint
   plus a 3px navy left edge so the user can see at a glance which
   property is driving the rest of the dashboard. The PORTFOLIO TOTAL
   row keeps its existing subtotal styling but inherits the cursor
   pointer + tooltip so the "click to clear" affordance is discoverable. */
.dash-occ-snapshot-table tbody tr[data-property-code] {
  cursor: pointer;
  transition: background-color 0.12s ease;
}
.dash-occ-snapshot-table tbody tr[data-property-code]:hover {
  background: rgba(27, 79, 118, 0.05);
}
.dash-occ-snapshot-table tbody tr.dash-row-focused {
  background: rgba(27, 79, 118, 0.10);
}
.dash-occ-snapshot-table tbody tr.dash-row-focused td:first-child {
  /* 3px navy edge in lieu of a noisy box-shadow / outline. inset-box-
     shadow keeps the border off the layout box so column widths stay
     locked across focused / unfocused state — important because the
     other tiles' widths cascade from the snapshot table's column
     sizing on the same row. */
  box-shadow: inset 3px 0 0 0 var(--brand-navy, #1B4F76);
}
.dash-occ-snapshot-table tbody tr.dash-row-focused:hover {
  background: rgba(27, 79, 118, 0.14);
}
[data-theme="dark"] .dash-occ-snapshot-table tbody tr[data-property-code]:hover {
  background: rgba(255, 255, 255, 0.04);
}
[data-theme="dark"] .dash-occ-snapshot-table tbody tr.dash-row-focused {
  background: rgba(111, 168, 214, 0.10);
}
[data-theme="dark"] .dash-occ-snapshot-table tbody tr.dash-row-focused td:first-child {
  box-shadow: inset 3px 0 0 0 var(--brand-navy-light, #6FA8D6);
}

.dash-tile-chart {
  margin-top: 0.6rem;
  /* Flex-grow to fill any remaining tile height — so when an
     adjacent tile (e.g. Lease Expirations) is taller, the chart in
     this tile stretches to match instead of leaving white space at
     the bottom. min-height guards small-tile aesthetics. */
  flex: 1 1 auto;
  min-height: 145px;
  position: relative;
}
.dash-tile-chart canvas {
  position: absolute; top: 0; left: 0; width: 100% !important; height: 100% !important;
}
.dash-empty {
  font-size: 0.78rem;
  color: #9ca3af;
  font-style: italic;
  padding: 1rem 0;
}

/* Tile 3 has a 3-up sub-grid */
.dash-tile-grid-3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.5rem;
}

/* Tile 6 — Asset Management single-header table layout.
   One header at the top (Actual / Budget / Δ $ / Δ %), then sections:
   ALL ASSET MANAGERS first (brand-navy emphasis), then individual AMs
   below as compact 2-line blocks. Name rows visually distinct from
   metric rows so the eye can group them at a glance. */
.dash-am-table {
  font-size: 0.76rem;
}
.dash-am-name-row th {
  padding-top: 0.55rem !important;
  padding-bottom: 0.15rem !important;
  font-weight: 600;
  font-size: 0.74rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: #374151;
  border-top: 1px solid #f3f4f6;
  text-align: left;
}
.dash-am-table tbody tr:first-child .dash-am-name-row th,
.dash-am-table tbody tr:first-child th {
  border-top: none;
  padding-top: 0.1rem !important;
}
.dash-am-name-row .muted {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  font-size: 0.7rem;
  color: #9ca3af;
}
.dash-am-total-label {
  color: var(--brand-navy, #1B4F76) !important;
  font-weight: 700 !important;
}
.dash-am-metric-label {
  padding-left: 0.7rem !important;
  font-weight: 400;
  color: #4b5563;
}

/* ============================================================
   Logo swap — show black wordmark in light mode, white in dark.
   Both <img> tags are emitted in base.html and toggled here.
   Selectors mirror the depth of `.topbar .brand-logo img` higher
   up in the file so they win the specificity match — otherwise
   the generic .brand-logo img display rule keeps both visible.
   ============================================================ */
.topbar .brand-logo img.brand-logo-dark { display: none; }
[data-theme="dark"] .topbar .brand-logo img.brand-logo-light { display: none; }
[data-theme="dark"] .topbar .brand-logo img.brand-logo-dark { display: block; }

/* ============================================================
   Dark-mode adjustments for the landing dashboard tiles.
   The base [data-theme="dark"] block defines surface / text /
   border tokens; this block redresses the dash-* components
   so they pick up the dark palette instead of staying white.
   ============================================================ */
[data-theme="dark"] .dash-tile {
  background: var(--surface, #1E293B);
  border-color: var(--border, #2A3852);
  color: var(--text, #E5EAF1);
}
[data-theme="dark"] .dash-tile-header {
  border-bottom-color: var(--border, #2A3852);
}
[data-theme="dark"] .dash-tile-header h2 {
  /* Use the soft brand-navy on a dark background it still pops
     well, mirroring the section-title color used elsewhere. */
  color: #6FA8D6;
}
[data-theme="dark"] .dash-tile-body { color: var(--text, #E5EAF1); }
[data-theme="dark"] .dash-tile-table thead th {
  color: var(--text-muted, #7F8BA3);
  border-bottom-color: var(--border, #2A3852);
}
[data-theme="dark"] .dash-tile-table tbody th {
  color: var(--text-soft, #B4BFD0);
}
[data-theme="dark"] .dash-tile-table td { color: var(--text, #E5EAF1); }
[data-theme="dark"] .dash-tile-table td.muted { color: var(--text-muted, #7F8BA3); }
[data-theme="dark"] .dash-tile-table td.delta-neutral { color: var(--text-muted, #7F8BA3); }
[data-theme="dark"] .dash-empty { color: var(--text-muted, #7F8BA3); }
[data-theme="dark"] .dash-tile-dropdown {
  background: var(--surface-alt, #182238);
  border-color: var(--border, #2A3852);
  color: var(--text, #E5EAF1);
}
[data-theme="dark"] .dash-tile-dropdown:hover {
  border-color: var(--border-strong, #3D4F6E);
}
/* AM tile section dividers + per-AM labels */
[data-theme="dark"] .dash-am-name-row th {
  color: var(--text-soft, #B4BFD0);
  border-top-color: var(--border, #2A3852);
}
[data-theme="dark"] .dash-am-name-row .muted {
  color: var(--text-muted, #7F8BA3);
}
[data-theme="dark"] .dash-am-total-label { color: #6FA8D6 !important; }
[data-theme="dark"] .dash-am-metric-label { color: var(--text-soft, #B4BFD0); }
/* Settings modal — same palette + dark card */
[data-theme="dark"] .dash-settings-card {
  background: var(--surface, #1E293B);
  color: var(--text, #E5EAF1);
}
[data-theme="dark"] .dash-settings-header {
  border-bottom-color: var(--border, #2A3852);
}
[data-theme="dark"] .dash-settings-header h2 { color: #6FA8D6; }
[data-theme="dark"] .dash-settings-close { color: var(--text-muted, #7F8BA3); }
[data-theme="dark"] .dash-settings-close:hover { color: var(--text, #E5EAF1); }
[data-theme="dark"] .dash-settings-hint { color: var(--text-muted, #7F8BA3); }
[data-theme="dark"] .dash-settings-row {
  background: var(--surface-alt, #182238);
  border-color: var(--border, #2A3852);
}
[data-theme="dark"] .dash-settings-row:hover {
  border-color: var(--border-strong, #3D4F6E);
}
[data-theme="dark"] .dash-settings-handle { color: var(--text-muted, #7F8BA3); }
[data-theme="dark"] .dash-settings-label { color: var(--text, #E5EAF1); }
[data-theme="dark"] .dash-settings-ghost {
  background: var(--surface-hover, #243248);
}
[data-theme="dark"] .dash-settings-footer {
  border-top-color: var(--border, #2A3852);
}
[data-theme="dark"] .dash-settings-reset {
  background: var(--surface-alt, #182238);
  border-color: var(--border, #2A3852);
  color: var(--text-soft, #B4BFD0);
}
[data-theme="dark"] .dash-settings-reset:hover {
  border-color: var(--border-strong, #3D4F6E);
}
[data-theme="dark"] .dash-settings-modal {
  background: rgba(0, 0, 0, 0.65);
}

/* ============================================================
   Dashboard Settings modal — gear-icon-triggered overlay that
   lets the user show/hide tiles and reorder them via drag.
   Plays nicely with SortableJS handle classes.
   ============================================================ */
.dash-settings-modal {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}
.dash-settings-modal[hidden] { display: none; }
.dash-settings-card {
  background: white;
  border-radius: 8px;
  width: min(420px, 92vw);
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.25);
}
.dash-settings-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid #e5e7eb;
}
.dash-settings-header h2 {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--brand-navy, #1B4F76);
  letter-spacing: 0.02em;
}
.dash-settings-close {
  background: none;
  border: none;
  font-size: 1.4rem;
  color: #6b7280;
  cursor: pointer;
  padding: 0 0.25rem;
  line-height: 1;
}
.dash-settings-close:hover { color: #111827; }
.dash-settings-body {
  padding: 0.85rem 1rem;
  overflow-y: auto;
  flex: 1 1 auto;
}
.dash-settings-hint {
  margin: 0 0 0.6rem;
  font-size: 0.78rem;
  color: #6b7280;
}
.dash-settings-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.dash-settings-row {
  display: flex;
  align-items: center;
  padding: 0.5rem 0.6rem;
  border: 1px solid #e5e7eb;
  border-radius: 6px;
  margin-bottom: 0.4rem;
  background: white;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.dash-settings-row:hover {
  border-color: var(--brand-navy-light, #2A6FA0);
}
.dash-settings-handle {
  cursor: grab;
  color: #9ca3af;
  font-size: 1.1rem;
  letter-spacing: -3px;
  margin-right: 0.6rem;
  user-select: none;
  font-weight: 700;
}
.dash-settings-handle:active { cursor: grabbing; }
.dash-settings-label {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
  font-size: 0.85rem;
}
.dash-settings-label input[type=checkbox] {
  accent-color: var(--brand-navy, #1B4F76);
  width: 1rem;
  height: 1rem;
  cursor: pointer;
}
/* Per-tile width dropdown in the Settings modal. Sits at the right
   edge of each row. Greyed via .is-muted when the user has Fixed grid
   mode selected (the saved value persists but has no visible effect
   until they switch back to Flexible). Wide-locked tiles get the
   native :disabled state since their full-width is structural, not a
   user-pref. */
.dash-settings-width {
  flex: 0 0 auto;
  margin-left: 0.5rem;
  padding: 0.18rem 0.4rem;
  font-size: 0.78rem;
  border: 1px solid #d1d5db;
  border-radius: 4px;
  background: white;
  color: #374151;
  cursor: pointer;
  min-width: 4.5rem;
}
.dash-settings-width:hover { border-color: #9ca3af; }
.dash-settings-width:focus {
  outline: 2px solid var(--brand-navy, #1B4F76);
  outline-offset: 1px;
}
.dash-settings-width.is-muted {
  opacity: 0.55;
  cursor: not-allowed;
}
.dash-settings-width:disabled {
  background: #f3f4f6;
  color: #9ca3af;
  cursor: not-allowed;
}
[data-theme="dark"] .dash-settings-width {
  background: var(--surface-alt, #182238);
  border-color: var(--border, #2A3852);
  color: var(--text, #E5EAF1);
}
[data-theme="dark"] .dash-settings-width:disabled {
  background: rgba(255,255,255,0.04);
  color: var(--text-muted, #7F8BA3);
}
.dash-settings-ghost {
  opacity: 0.35;
  background: #f3f4f6;
}
/* Tile-width / grid-mode toggle. Sits below the draggable tile list
   inside the same Settings modal body. Visually a fieldset with two
   stacked radio options; pattern mirrors .dash-settings-row spacing so
   the modal reads as one cohesive list. */
.dash-settings-gridmode {
  margin: 0.9rem 0 0.2rem;
  padding: 0.55rem 0.7rem 0.65rem;
  border: 1px solid #e5e7eb;
  border-radius: 6px;
  background: white;
}
.dash-settings-gridmode legend {
  padding: 0 0.35rem;
  font-size: 0.78rem;
  font-weight: 600;
  color: #374151;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.dash-settings-gridmode-opt {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.1rem;
  font-size: 0.85rem;
  cursor: pointer;
}
.dash-settings-gridmode-opt input[type=radio] {
  accent-color: var(--brand-navy, #1B4F76);
  width: 1rem;
  height: 1rem;
  cursor: pointer;
  margin: 0;
}
.dash-settings-gridmode-opt .muted {
  color: #6b7280;
  font-weight: 400;
}
[data-theme="dark"] .dash-settings-gridmode {
  background: var(--surface-alt, #182238);
  border-color: var(--border, #2A3852);
}
[data-theme="dark"] .dash-settings-gridmode legend { color: var(--text, #E5EAF1); }
[data-theme="dark"] .dash-settings-gridmode-opt .muted { color: var(--text-muted, #7F8BA3); }

/* Behavior toggles fieldset — checkbox sibling to dash-settings-gridmode.
   Visually identical card so the modal reads as one cohesive list of
   user-level configuration sections (Grid Mode / Behavior / …). */
.dash-settings-behavior {
  margin: 0.6rem 0 0.2rem;
  padding: 0.55rem 0.7rem 0.65rem;
  border: 1px solid #e5e7eb;
  border-radius: 6px;
  background: white;
}
.dash-settings-behavior legend {
  padding: 0 0.35rem;
  font-size: 0.78rem;
  font-weight: 600;
  color: #374151;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.dash-settings-behavior-opt {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  padding: 0.35rem 0.1rem;
  font-size: 0.85rem;
  cursor: pointer;
}
.dash-settings-behavior-opt input[type=checkbox] {
  accent-color: var(--brand-navy, #1B4F76);
  width: 1rem;
  height: 1rem;
  cursor: pointer;
  margin: 0.15rem 0 0 0;  /* nudge to align with first text line */
}
.dash-settings-behavior-opt .muted {
  color: #6b7280;
  font-weight: 400;
}
[data-theme="dark"] .dash-settings-behavior {
  background: var(--surface-alt, #182238);
  border-color: var(--border, #2A3852);
}
[data-theme="dark"] .dash-settings-behavior legend { color: var(--text, #E5EAF1); }
[data-theme="dark"] .dash-settings-behavior-opt .muted { color: var(--text-muted, #7F8BA3); }

/* ============================================================
   Lease Expirations drill-down modal — opens when the user clicks
   a bar in the Lease Expirations tile. Lists every resident whose
   lease ends in that month, segmented by Renewed / Unknown / NTV /
   Eviction. Modeled on dash-settings-modal so the two overlay
   surfaces feel like a matched pair.
   ============================================================ */
.dash-drill-modal {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}
.dash-drill-modal[hidden] { display: none; }
.dash-drill-card {
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 20px 60px rgba(15, 23, 42, 0.35);
  width: min(95vw, 1100px);
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.dash-drill-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  padding: 1rem 1.25rem 0.5rem;
  border-bottom: 1px solid #e5e7eb;
}
.dash-drill-header h2 {
  margin: 0;
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #1B4F76;
}
.dash-drill-subtitle {
  font-size: 0.95rem;
  color: #6b7280;
  margin-top: 0.15rem;
  font-weight: 500;
}
.dash-drill-close {
  background: none;
  border: 0;
  font-size: 1.4rem;
  cursor: pointer;
  color: #6b7280;
  padding: 0 0.25rem;
  line-height: 1;
}
.dash-drill-close:hover { color: #111827; }
.dash-drill-totals {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding: 0.75rem 1.25rem;
  border-bottom: 1px solid #f3f4f6;
  background: #fafbfc;
}
.expir-drill-total-chip {
  display: inline-flex;
  flex-direction: column;
  padding: 0.35rem 0.75rem 0.35rem 0.6rem;
  background: #fff;
  border: 1px solid #e5e7eb;
  border-radius: 6px;
  min-width: 80px;
  font-variant-numeric: tabular-nums;
}
.expir-drill-total-chip strong {
  font-size: 1.1rem;
  font-weight: 700;
  color: #111827;
}
.expir-drill-total-chip .muted {
  font-size: 0.7rem;
  color: #6b7280;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 600;
}
.expir-drill-total-chip.expir-drill-total-all {
  border-left: 3px solid #1B4F76;
}
.dash-drill-body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 0.75rem 1.25rem 1.25rem;
}
.dash-drill-loading, .dash-drill-empty, .dash-drill-error {
  text-align: center;
  color: #6b7280;
  padding: 2rem 1rem;
  font-size: 0.9rem;
}
.dash-drill-error { color: #b91c1c; }

.expir-drill-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}
.expir-drill-table th {
  text-align: left;
  padding: 0.5rem 0.6rem;
  font-size: 0.7rem;
  font-weight: 600;
  color: #4b5563;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: #f9fafb;
  border-bottom: 1px solid #e5e7eb;
  position: sticky;
  top: 0;
}
.expir-drill-table th.num,
.expir-drill-table td.num { text-align: right; }
.expir-drill-table tbody td {
  padding: 0.45rem 0.6rem;
  border-bottom: 1px solid #f3f4f6;
  color: #1f2937;
}
.expir-drill-table tbody tr:hover { background: #f9fafb; }
.expir-drill-seg-chip {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  border-radius: 10px;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

[data-theme="dark"] .dash-drill-card { background: #1E293B; color: #E5EAF1; }
[data-theme="dark"] .dash-drill-header { border-bottom-color: #2A3852; }
[data-theme="dark"] .dash-drill-header h2 { color: #6FA8D6; }
[data-theme="dark"] .dash-drill-subtitle { color: #7F8BA3; }
[data-theme="dark"] .dash-drill-close { color: #7F8BA3; }
[data-theme="dark"] .dash-drill-close:hover { color: #E5EAF1; }
[data-theme="dark"] .dash-drill-totals { background: #182238; border-bottom-color: #2A3852; }
[data-theme="dark"] .expir-drill-total-chip {
  background: #1E293B; border-color: #2A3852;
}
[data-theme="dark"] .expir-drill-total-chip strong { color: #E5EAF1; }
[data-theme="dark"] .expir-drill-total-chip .muted { color: #7F8BA3; }
[data-theme="dark"] .expir-drill-table th {
  background: #182238; color: #B9C2D2; border-bottom-color: #2A3852;
}
[data-theme="dark"] .expir-drill-table tbody td {
  color: #E5EAF1; border-bottom-color: #2A3852;
}
[data-theme="dark"] .expir-drill-table tbody tr:hover { background: #182238; }

.dash-settings-footer {
  display: flex;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.75rem 1rem;
  border-top: 1px solid #e5e7eb;
}
.dash-settings-reset,
.dash-settings-save {
  font-size: 0.82rem;
  padding: 0.4rem 0.8rem;
  border-radius: 5px;
  border: 1px solid #d1d5db;
  background: white;
  cursor: pointer;
  color: #374151;
}
.dash-settings-reset:hover { border-color: #9ca3af; }
.dash-settings-save {
  background: var(--brand-navy, #1B4F76);
  border-color: var(--brand-navy, #1B4F76);
  color: white;
  font-weight: 500;
}
.dash-settings-save:hover {
  background: var(--brand-navy-dark, #143958);
  border-color: var(--brand-navy-dark, #143958);
}

/* ──────── /help page ────────
   Renders the markdown-converted system-overview doc. Constrains
   line length for readable prose, gives headings clear hierarchy,
   styles tables to match the rest of the app. */
.help-page {
  max-width: 920px;
  margin: 1rem auto 4rem;
  padding: 0 1.2rem;
}
.help-header h1 {
  font-size: 1.4rem;
  font-weight: 700;
  color: var(--brand-navy, #1B4F76);
  margin: 0.5rem 0 0.25rem;
  letter-spacing: 0.01em;
}
.help-header p {
  margin: 0 0 1rem;
  font-size: 0.85rem;
}
.help-body {
  font-size: 0.92rem;
  line-height: 1.65;
  color: #1F2937;
}
.help-body h1 { display: none; }  /* doc's own H1 is the page header */
.help-body h2 {
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--brand-navy, #1B4F76);
  border-bottom: 1px solid #E5E7EB;
  padding-bottom: 0.3rem;
  margin: 2.2rem 0 0.9rem;
  scroll-margin-top: 70px;     /* offset for sticky topbar on anchor jump */
}
.help-body h3 {
  font-size: 1rem;
  font-weight: 600;
  color: var(--brand-navy, #1B4F76);
  margin: 1.4rem 0 0.55rem;
  scroll-margin-top: 70px;
}
.help-body h4 {
  font-size: 0.92rem;
  font-weight: 600;
  margin: 1rem 0 0.45rem;
  color: #374151;
}
.help-body p { margin: 0.55rem 0; }
.help-body ul, .help-body ol { padding-left: 1.4rem; }
.help-body li { margin: 0.25rem 0; }
.help-body code {
  background: #F3F4F6;
  border-radius: 3px;
  padding: 0.05rem 0.35rem;
  font-size: 0.85em;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  color: #B91C1C;
}
.help-body pre {
  background: #F8FAFC;
  border: 1px solid #E5E7EB;
  border-radius: 6px;
  padding: 0.7rem 0.9rem;
  overflow-x: auto;
  font-size: 0.82rem;
  line-height: 1.5;
}
.help-body pre code {
  background: transparent;
  padding: 0;
  color: #1F2937;
}
.help-body blockquote {
  margin: 0.6rem 0;
  padding: 0.4rem 0.9rem;
  border-left: 3px solid var(--brand-navy, #1B4F76);
  background: rgba(27, 79, 118, 0.04);
  color: #374151;
  font-style: italic;
}
.help-body table {
  border-collapse: collapse;
  width: 100%;
  margin: 0.9rem 0;
  font-size: 0.85rem;
}
.help-body th, .help-body td {
  border-bottom: 1px solid #E5E7EB;
  padding: 0.45rem 0.65rem;
  text-align: left;
  vertical-align: top;
}
.help-body th {
  background: var(--info-bg, #E3EEF7);
  font-weight: 600;
  color: var(--brand-navy, #1B4F76);
}
.help-body hr {
  border: none;
  border-top: 1px solid #E5E7EB;
  margin: 2rem 0;
}
.help-body a {
  color: var(--accent, #2563EB);
  text-decoration: none;
  border-bottom: 1px dotted currentColor;
}
.help-body a:hover { border-bottom-style: solid; }

/* Dark-mode variant for /help. */
[data-theme="dark"] .help-body { color: #E2E8F0; }
[data-theme="dark"] .help-body h2,
[data-theme="dark"] .help-body h3 {
  color: #6FA8D6;
  border-color: rgba(255,255,255,0.08);
}
[data-theme="dark"] .help-body code {
  background: rgba(255,255,255,0.06);
  color: #FCA5A5;
}
[data-theme="dark"] .help-body pre {
  background: rgba(255,255,255,0.04);
  border-color: rgba(255,255,255,0.08);
}
[data-theme="dark"] .help-body pre code { color: #E2E8F0; }
[data-theme="dark"] .help-body blockquote {
  background: rgba(255,255,255,0.04);
  color: #CBD5E1;
}
[data-theme="dark"] .help-body th {
  background: #1E3252;
  color: #CBD5E1;
}
[data-theme="dark"] .help-body th,
[data-theme="dark"] .help-body td,
[data-theme="dark"] .help-body hr {
  border-color: rgba(255,255,255,0.08);
}
