/* Shared structural design tokens — surfaces, text, borders, gridlines.
   Single source of truth so contrast fixes apply app-wide instead of being patched
   page-by-page. Every page's .viz-root wrapper picks these up; pages still define their
   own page-specific semantic accent vars (--series-1, --good, --bad, --warning, etc.)
   locally since those aren't part of the surface/text contrast problem this file fixes.

   Fixed 2026-07-17: --surface-1 and --page-plane used to be nearly the same shade
   (#fcfcfb vs #f9f9f7, ~1.03:1 contrast) and --border was only 10% opacity, so cards,
   inputs, and table rows all blended into the page background. Values below are chosen
   and verified so text meets WCAG AA (>=4.5:1) and borders meet the UI-component
   non-text contrast minimum (>=3:1) against both --surface-1 and --page-plane, in both
   themes — see the contrast check this was built against, kept in scratchpad, not
   committed here since it's a one-off verification script, not app code. */

/* A short page (few rows, little content) would otherwise be shorter than an open nav dropdown
   needs, clipping it with no scroll room to reach the rest -- force every page to be at least
   one full screen tall regardless of how little content it has. dvh (falls back to plain vh in
   browsers that don't support it) tracks the browser's actual visible area, not the address-bar-
   expanded one, which matters on mobile/tablet where that gap is exactly when this bites. */
html, body {
  min-height: 100vh;
  min-height: 100dvh;
}

.viz-root {
  color-scheme: light;
  /* Every page nests its actual content in <div class="viz-root"> one level inside <body> --
     each page's own `body { background: var(--page-plane) }` rule can't see these custom
     properties (they're scoped to .viz-root and its descendants, and body is an ANCESTOR of
     .viz-root, not a descendant), so it silently did nothing and body stayed browser-default
     white. Applying the real background/text color and a full-page min-height here instead --
     where the variables actually resolve -- is what makes dark mode cover the whole page rather
     than just the text inside it. */
  display: block;
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--page-plane);
  color: var(--text-primary);
  --surface-1:      #f7f7f4;
  --page-plane:     #e7e5df;
  --text-primary:   #0b0b0b;
  --text-secondary: #45443f;
  --text-muted:     #5f5d55;
  --gridline:       #d3d1c7;
  --row-alt:        #f4f3ee;
  --baseline:       #b0aea2;
  --border:         rgba(11,11,11,0.48);
}
:root[data-theme="dark"] .viz-root {
  color-scheme: dark;
  --surface-1:      #232322;
  --page-plane:     #0d0d0d;
  --text-primary:   #ffffff;
  --text-secondary: #cfcec8;
  --text-muted:     #9c9b93;
  --gridline:       #3c3c39;
  --row-alt:        #1c1c1b;
  --baseline:       #4a4943;
  --border:         rgba(255,255,255,0.36);
}
:root[data-theme="light"] .viz-root {
  color-scheme: light;
  --surface-1:      #f7f7f4;
  --page-plane:     #e7e5df;
  --text-primary:   #0b0b0b;
  --text-secondary: #45443f;
  --text-muted:     #5f5d55;
  --gridline:       #d3d1c7;
  --row-alt:        #f4f3ee;
  --baseline:       #b0aea2;
  --border:         rgba(11,11,11,0.48);
}

/* Zebra striping for any <table> under a .viz-root wrapper — applies uniformly without
   needing a per-page rule. Relies on the browser's implicit <tbody> when one isn't
   written explicitly, so this is safe even on markup that skips <tbody>. */
.viz-root table tbody tr:nth-child(even) {
  background: var(--row-alt);
}

/* Site header — every staff-facing page includes an empty
     <div class="site-header" id="site-header"></div>
   which site-nav.js populates at load: logo/Home (-> dashboard.html, added 2026-07-17 — the
   dashboard is where a staff member actually starts their day, not the index directory page),
   a Menu dropdown listing every section (so there's always a way to navigate regardless of
   which page you started on — the browser back button doesn't help when a page was opened
   directly, e.g. a bookmark or fresh tab), and an Owner-only "View as" dropdown for previewing
   the app as a non-Owner would see it. portal.html is the one exception — it keeps its own
   hardcoded logo+Home markup (pointing to /portal.html) and does NOT include site-nav.js, since
   a client should never get staff chrome (menu, view-as) at all. */
.site-header {
  display: flex;
  align-items: center;
  padding: 10px 16px;
  /* Reserves the header's real rendered height (buttons + padding) before site-nav.js has
     populated it -- it starts as an empty div and its content only appears after an async
     fetch (Cameron 2026-07-26: page loads "high" then visibly bumps down once the nav renders).
     Without this, the collapsed empty div is ~20px (just the padding) until content lands. */
  min-height: 52px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-1);
  position: relative;
  gap: 4px;
  /* On a narrow phone, Home + every nav item doesn't fit in one row -- rather than squish
     buttons illegibly or silently clip the rest off-screen (unreachable, since the page itself
     is overflow-x: hidden), let the header scroll horizontally on its own so every item stays
     full-size and reachable by a swipe. */
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.site-header > * {
  flex-shrink: 0;
}
.site-home-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  color: var(--text-secondary);
  font-size: 0.85rem;
  font-weight: 600;
}
.site-home-link:hover {
  color: var(--series-1);
}
.site-home-logo {
  height: 22px;
  width: auto;
  display: block;
}

/* site-nav.js: Menu + View As dropdowns. Redesigned 2026-07-22 away from the flat
   bordered-box look (Cameron: "very windows 95") -- no visible chrome at rest, just text; a
   soft tinted background is the only affordance, appearing on hover/open/current rather than
   permanently outlining every nav item. */
.site-nav-dropdown {
  position: relative;
  margin-left: 2px;
}
.site-nav-btn {
  cursor: pointer;
  padding: 7px 12px;
  border: none;
  border-radius: 7px;
  background: none;
  color: var(--text-secondary);
  font-size: 0.85rem;
  font-weight: 600;
  transition: background-color 0.12s ease, color 0.12s ease;
}
.site-nav-btn:hover {
  color: var(--series-1);
  background: var(--series-1-wash);
}
.site-nav-dropdown.open .site-nav-btn {
  color: var(--series-1);
  background: var(--series-1-wash);
}
/* Icon-only profile button (top right) -- no text label, so a bit more padding/size than the
   text dropdowns keeps it from looking like an empty/broken button next to them. */
.site-nav-profile-btn {
  padding: 6px 10px;
  font-size: 1.15rem;
  line-height: 1;
  position: relative;
}
.site-nav-bell-icon { width: 17px; height: 17px; display: block; vertical-align: middle; }
.site-nav-bell-badge {
  position: absolute; top: 2px; right: 2px;
  min-width: 15px; height: 15px; padding: 0 3px;
  border-radius: 999px; background: var(--critical, #d03b3b); color: #fff;
  font-family: var(--font-mono, ui-monospace, monospace); font-size: 0.6rem; font-weight: 700;
  line-height: 15px; text-align: center;
}
.site-nav-notifications-panel { width: 320px; }

.site-nav-getting-started-panel { width: 300px; }
.site-nav-getting-started-row {
  display: block; padding: 8px 10px; border-radius: 7px; text-decoration: none;
  color: var(--text-primary); border-bottom: 1px solid var(--gridline);
}
.site-nav-getting-started-row:last-child { border-bottom: none; }
.site-nav-getting-started-row:hover { background: var(--series-1-wash); }
.site-nav-getting-started-label { font-size: 0.87rem; font-weight: 600; }
.site-nav-getting-started-desc { font-size: 0.78rem; color: var(--text-muted); margin-top: 2px; }
.site-nav-getting-started-row.completed { opacity: 0.6; }
.site-nav-getting-started-row.completed .site-nav-getting-started-label { text-decoration: line-through; }

.site-nav-theme-row {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  padding: 8px 10px 12px; margin-bottom: 4px;
  border-bottom: 1px solid var(--gridline);
  font-size: 0.82rem; color: var(--text-secondary);
}
.site-nav-theme-switch {
  position: relative; width: 40px; height: 22px; flex-shrink: 0;
  border-radius: 999px; border: 1px solid var(--border); background: var(--page-plane);
  cursor: pointer; padding: 0;
  transition: background-color 0.2s ease, border-color 0.2s ease;
}
.site-nav-theme-switch[aria-checked="true"] { background: var(--series-1); border-color: var(--series-1); }
.site-nav-theme-switch:focus-visible { outline: 2px solid var(--series-1); outline-offset: 2px; }
.site-nav-theme-switch-thumb {
  position: absolute; top: 1px; left: 1px; width: 18px; height: 18px; border-radius: 50%;
  background: var(--surface-1); box-shadow: 0 1px 3px rgba(0,0,0,0.3);
  transition: transform 0.2s ease;
}
.site-nav-theme-switch[aria-checked="true"] .site-nav-theme-switch-thumb { transform: translateX(18px); }
.site-nav-notifications-list { max-height: 320px; overflow-y: auto; }
.site-nav-notification-row {
  display: block; width: 100%; padding: 8px 10px; border-radius: 7px; text-decoration: none;
  color: var(--text-primary); border: none; border-bottom: 1px solid var(--gridline);
  background: none; font: inherit; text-align: left; cursor: pointer;
}
.site-nav-notification-row:last-child { border-bottom: none; }
.site-nav-notification-row:hover { background: var(--series-1-wash); }
.site-nav-notification-row.unread { font-weight: 600; }
.site-nav-notification-msg { font-size: 0.85rem; margin-bottom: 2px; }
.site-nav-notification-time { font-size: 0.72rem; color: var(--text-muted); font-weight: 400; }
/* Standalone header links (Dashboard, Inbox) -- plain links like .site-home-link, not buttons:
   no border or fill at rest, just a soft hover tint for feedback. */
.site-nav-link-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 10px;
  border-radius: 7px;
  text-decoration: none;
  margin-left: 2px;
  color: var(--text-secondary);
  font-size: 0.85rem;
  font-weight: 600;
  transition: background-color 0.12s ease, color 0.12s ease;
}
.site-nav-link-btn:hover {
  color: var(--series-1);
  background: var(--series-1-wash);
}
.site-nav-link-btn.current {
  color: var(--series-1);
  background: var(--series-1-wash);
}
.site-nav-viewas-active {
  color: var(--series-1);
  background: var(--series-1-wash);
}
.site-nav-spacer {
  flex: 1;
}
.site-nav-panel {
  display: none;
  /* position: fixed (not absolute) + JS-computed top/left (see positionPanel in site-nav.js) --
     the header scrolls horizontally (see .site-header overflow-x above), which per the CSS spec
     forces its overflow-y to auto too, so an absolutely-positioned panel anchored to a dropdown
     inside it would get clipped the moment it extended past the header's own height. Fixed
     positioning escapes that clipping entirely since it's relative to the viewport, not any
     scrolling ancestor. */
  position: fixed;
  min-width: 200px;
  background: var(--surface-1);
  border: 1px solid var(--gridline);
  border-radius: 10px;
  padding: 6px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.12), 0 2px 8px rgba(0,0,0,0.06);
  z-index: 50;
  /* Each section is its own dropdown now (2026-07-22 -- "make the group headings the actual
     menus"), so every panel only ever holds one short, flat list -- no columns needed. Kept as
     a safety net only: a pathologically short viewport (phone in landscape) shouldn't be able to
     run the panel off-screen with no way to reach the rest of it. dvh (falls back to vh) so this
     cap matches the browser's real visible area on mobile/tablet, not the address-bar-expanded
     one -- otherwise the cap itself can be taller than what's actually on screen. */
  max-height: 95vh;
  max-height: 95dvh;
  overflow-y: auto;
}
.site-nav-panel-right {
  left: auto;
  right: 0;
  min-width: 260px;
}
.site-nav-dropdown.open .site-nav-panel {
  display: block;
}
.site-nav-section-label {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-muted);
  padding: 6px 10px 4px;
}
.site-nav-section-label:not(:first-child) {
  margin-top: 6px;
  border-top: 1px solid var(--gridline);
  padding-top: 10px;
}
.site-nav-link {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-radius: 7px;
  text-decoration: none;
  color: var(--text-primary);
  font-size: 0.85rem;
  transition: background-color 0.12s ease;
}
.site-nav-link:hover {
  background: var(--series-1-wash);
}
.site-nav-link.current {
  background: var(--series-1-wash);
  color: var(--series-1);
  font-weight: 600;
}
.site-nav-link-icon {
  font-size: 1rem;
}
.site-nav-owner-tag {
  margin-left: auto;
  font-size: 0.68rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
/* Lets a <button> (e.g. Log out) share .site-nav-link's icon+text layout and hover/current
   styling instead of duplicating it -- just resets the handful of button-specific defaults
   (border/background/width/cursor/font) that a plain <a> never needed resetting in the first
   place. */
.site-nav-link-button-reset {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  border: none;
  background: none;
  cursor: pointer;
  font: inherit;
  text-align: left;
}
.site-nav-viewas-option {
  display: block;
  width: 100%;
  text-align: left;
  padding: 8px 10px;
  border-radius: 7px;
  border: none;
  background: none;
  color: var(--text-primary);
  font-size: 0.85rem;
  cursor: pointer;
  transition: background-color 0.12s ease;
}
.site-nav-viewas-option:hover {
  background: var(--series-1-wash);
}
.site-nav-viewas-option.current {
  font-weight: 600;
  color: var(--series-1);
  background: var(--series-1-wash);
}
.site-nav-viewas-role {
  display: block;
  font-size: 0.74rem;
  font-weight: 400;
  color: var(--text-muted);
}
.site-nav-viewas-note {
  font-size: 0.74rem;
  color: var(--text-muted);
  padding: 8px 8px 4px;
  border-top: 1px solid var(--gridline);
  margin-top: 4px;
}
.site-nav-viewas-banner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 6px 16px;
  background: var(--warning, #fab219);
  color: #1a1400;
  font-size: 0.82rem;
  font-weight: 600;
}
.site-nav-viewas-revert {
  padding: 3px 10px;
  border-radius: 6px;
  border: 1px solid rgba(0,0,0,0.3);
  background: rgba(255,255,255,0.35);
  color: #1a1400;
  font-size: 0.78rem;
  font-weight: 600;
  cursor: pointer;
}
.site-nav-viewas-revert:hover {
  background: rgba(255,255,255,0.55);
}
