/* Self-hosted (see public/fonts/ — pulled once from Google Fonts, latin
   subset only, served from this origin). No third-party font request on
   any page load, and no CSP loosening needed — consistent with this app's
   "no external service without a real decision" posture (see README). */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-400.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-500.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-600.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400 700; /* variable file — Google serves one instance for this range */
  font-display: swap;
  src: url('/fonts/ibm-plex-sans-var.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Serif';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/ibm-plex-serif-500.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Serif';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/fonts/ibm-plex-serif-600.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Serif';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/ibm-plex-serif-700.woff2') format('woff2');
}
/* Manrope — the brand typeface from hgc.design.md (a design system measured
   off Higher Ground Consulting's live site, civil/geotechnical/environmental
   engineering — the same field Dam-Sure's compliance data comes out of).
   Self-hosted the same way as the Plex family above, same reasoning. */
@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 400 800; /* variable file — one instance covers this range */
  font-display: swap;
  src: url('/fonts/manrope-var.woff2') format('woff2');
}

/*
  Design system, in brief. Rebased on hgc.design.md (measured tokens off
  Higher Ground Consulting's live site — a civil/geotechnical/environmental
  engineering consultancy, the same professional field that signs the
  reports Dam-Sure tracks) — colors, type, shadow and motion below trace to
  that file. Not a literal 1:1 copy: their `background`/`border` tokens are
  the same saturated blue as `primary`, which reads as a bold hero/CTA color
  on their marketing site, not a page-wide background for a data-dense
  claim/badge/table app — so it's used here as the brand color (header
  accents, primary buttons, the hero block) while body content keeps a
  light, legible paper surface. Their `surface` token (#94795d, a warm
  bronze) is used as the secondary accent instead of a card background for
  the same readability reason. Their 14-entry breakpoint list is a raw
  extraction (adjacent near-duplicates like 768/769, 1200/1201 are
  min/max-width pairs from the same rule, not distinct decisions) —
  curated down to the two this layout actually needs, snapped to the
  nearest values that *are* deliberate (576, 768).

  Two typographic voices:
  - Manrope (display 42/700, heading 27/700, body 14/400/1.65 — hgc.design.md's
    own scale): everything you read — headings, body copy, labels, nav.
  - Mono, uppercase, tracked (IBM Plex Mono — kept from the prior pass as
    the "utility face for captions/data" the brief leaves room for):
    primary buttons, status tags, dates, coordinates. The voice of a
    stamped form field, not a SaaS chip.
  A colored left-edge stripe on every card (.card) is the one repeating
  status device: at-a-glance compliance state, the way a case-file folder
  carries a colored tab. See hazardBadge()/eapBadge()/stripeClass() in
  app.js and dashboard.js for what sets it.
*/

:root {
  --ink: #333333;          /* hgc.design.md: text */
  --ink-soft: #6b6b6b;     /* muted tone derived from the above — theirs (#fff) assumes a dark hero, not body copy */
  --paper: #ecf1f7;        /* cool slate blue, replacing hgc.design.md's warm beige — echoes --brand below rather than the bronze/beige field their marketing site uses; lightened from #dfe8f2, kept a shade off pure white so --paper-raised cards still read as raised against it */
  --paper-raised: #ffffff;
  --paper-sunken: #dbe6ed;
  --line: #c3d4de;
  --line-strong: #9ab2c2;
  --brand: #005587;        /* hgc.design.md: primary */
  --brand-dark: #003b5f;
  --brand-tint: #e4edf3;
  --on-brand: #ffffff;     /* hgc.design.md: on-primary */
  --accent: #94795d;       /* hgc.design.md: surface/accent — bronze, used as the secondary color */
  --accent-dark: #7a6249;
  --danger: #9c3b2a;
  --danger-bg: #fbeee9;
  --ok-bg: #eaf3ee;
  --ok: #1f5f4f;
  --warn-bg: #fbf3e2;
  --warn: #8a5a15;

  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 14px;
  --shadow-card: 0 0 10px rgba(0, 0, 0, 0.28);    /* hgc.design.md: shadows.card, opacity trimmed for a light page (theirs sits on a dark hero) */
  --shadow-raised: 0 0 22px rgba(0, 0, 0, 0.32);  /* hgc.design.md: shadows.elevated */

  /* hgc.design.md: spacing (base 3px, scale 3/9/15/24/27/30/48/54/120/144) —
     applied at the structural joints (section/header/hero/card padding),
     not mechanically substituted into every micro-gap in this file. */
  --space-1: 3px; --space-2: 9px; --space-3: 15px; --space-4: 24px; --space-5: 27px;
  --space-6: 30px; --space-7: 48px; --space-8: 54px;

  /* hgc.design.md: motion */
  --duration-fast: 250ms;
  --duration-base: 400ms;
  --duration-slow: 1250ms;

  --font-display: 'Manrope', -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-body: 'Manrope', -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; font-size: 87.5%; } /* 14px base — hgc.design.md's body size; every rem in this file scales off it */

body {
  margin: 0;
  font-family: var(--font-body);
  background: var(--paper);
  color: var(--ink);
  line-height: 1.65; /* hgc.design.md: typography.body.lineHeight */
}

h1, h2, h3 { font-family: var(--font-display); font-weight: 700; } /* hgc.design.md: display/heading both weight 700 */

@media (prefers-reduced-motion: no-preference) {
  .claim-btn, .plan-btn, .card, .search-box button, .nav-toggle .bars,
  .nav-toggle .bars::before, .nav-toggle .bars::after, nav#nav,
  .checkpoint-row, .auth-submit { transition: background-color var(--duration-fast) ease, border-color var(--duration-fast) ease, color var(--duration-fast) ease, transform var(--duration-fast) ease, box-shadow var(--duration-fast) ease; }
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}

/* ---------- Header / nav ---------- */
header {
  padding: 18px 24px;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  flex-wrap: wrap;
  border-bottom: 1px solid var(--line);
  background: var(--paper-raised);
  position: relative;
}
header nav, header .nav-toggle { margin-left: auto; }
.logo-group { display: flex; align-items: center; gap: 10px; justify-content: flex-start; }
.logo {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.2rem;
  letter-spacing: -0.01em;
  text-decoration: none;
  color: var(--ink);
  display: flex;
  align-items: center;
  gap: 2px;
}
.logo-img {
  height: 42px;
  width: 42px;
  display: block;
}
.logo span { color: var(--brand); }
.logo .logo-text-dark { color: #003b5f; font-weight: 800; }
.logo .logo-text-light { color: #008cdb; font-weight: 800; }
.logo-eyebrow {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-soft);
  border-left: 1px solid var(--line-strong);
  padding-left: 10px;
}
@media (max-width: 576px) { .logo-eyebrow { display: none; } }

nav#nav { display: flex; align-items: center; }
/* Scoped to nav#nav specifically (not a bare `nav a`) — this styling is for
   the public site's top nav only. A bare `nav a, nav button.linklike`
   selector matches ANY anchor inside ANY <nav>, including the admin
   consoles' own bare <nav> (.admin-sidebar > nav in platform-admin.html,
   prospect-builder.html, engineer-dashboard.html): margin-left:24px leaked
   through onto platform-admin.html's "Prospects" <a class="admin-nav-item">
   (the only admin-sidebar nav item that's an <a> rather than a <button>) and
   knocked it out of alignment with its sibling buttons, because
   .admin-nav-item never sets its own margin-left to override it — every
   other property this rule sets IS already overridden by .admin-nav-item's
   higher specificity, which is why only the alignment broke. */
nav#nav a, nav#nav button.linklike {
  color: var(--ink-soft);
  text-decoration: none;
  font-size: 0.92rem;
  margin-left: 24px;
  background: none;
  border: none;
  cursor: pointer;
  font-family: inherit;
  padding: 0;
}
nav#nav a:hover, nav#nav button.linklike:hover { color: var(--ink); }
nav#nav a.primary {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background: var(--brand);
  color: #fff;
  padding: 9px 16px;
  border-radius: var(--radius-sm);
}
nav#nav a.primary:hover { background: var(--brand-dark); color: #fff; }

.nav-toggle {
  display: none;
  background: none;
  border: none;
  cursor: pointer;
  padding: 8px;
  margin-left: 12px;
}
.nav-toggle .bars {
  position: relative;
  display: block;
  width: 20px;
  height: 2px;
  background: var(--ink);
  border-radius: 2px;
}
.nav-toggle .bars::before, .nav-toggle .bars::after {
  content: '';
  position: absolute;
  left: 0;
  width: 20px;
  height: 2px;
  background: var(--ink);
  border-radius: 2px;
}
.nav-toggle .bars::before { top: -6px; }
.nav-toggle .bars::after { top: 6px; }
.nav-toggle.open .bars { background: transparent; }
.nav-toggle.open .bars::before { top: 0; transform: rotate(45deg); }
.nav-toggle.open .bars::after { top: 0; transform: rotate(-45deg); }

/* User info indicator in nav: logged-in email and role */
.nav-user-info {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  margin-left: 20px;
  padding-left: 16px;
  border-left: 1px solid var(--line);
}
.nav-user-email {
  font-size: 0.8rem;
  color: var(--ink-soft);
  word-break: break-all;
}
.nav-user-role {
  font-family: var(--font-mono);
  font-size: 0.65rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--brand);
}

/* Settings gear + its dropdown — account settings, role-appropriate links
   (report-template branding, team management), log out. Replaces what used
   to be a bare email/role readout with nothing to click. */
.settings-menu { position: relative; margin-left: 20px; padding-left: 16px; border-left: 1px solid var(--line); }
.settings-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  margin: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--ink-soft);
  cursor: pointer;
}
.settings-toggle:hover, .settings-toggle[aria-expanded="true"] { color: var(--brand); border-color: var(--line); background: var(--paper-raised); }
.settings-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 20;
  min-width: 220px;
  display: flex;
  flex-direction: column;
  background: var(--paper-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: 6px;
  transform-origin: top right; /* the gear icon it opens from — a fade/pop from nowhere reads as disconnected from what triggered it */
  opacity: 1;
  transform: scale(1) translateY(0);
}
.settings-dropdown[hidden] {
  display: none; /* author .settings-dropdown rule above would otherwise beat the UA [hidden] rule at equal specificity */
  opacity: 0;
  transform: scale(0.96) translateY(-4px);
}
@media (prefers-reduced-motion: no-preference) {
  .settings-dropdown {
    transition: opacity var(--duration-fast) ease, transform var(--duration-fast) ease, display var(--duration-fast) allow-discrete;
  }
  @starting-style {
    .settings-dropdown:not([hidden]) { opacity: 0; transform: scale(0.96) translateY(-4px); }
  }
}
.settings-dropdown-user {
  padding: 8px 10px 10px;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--line);
}
.settings-dropdown-user .nav-user-email { word-break: break-all; }
.settings-dropdown a, .settings-dropdown button.linklike {
  display: block;
  width: 100%;
  text-align: left;
  margin-left: 0;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  font-size: 0.85rem;
}
.settings-dropdown a:hover, .settings-dropdown button.linklike:hover { background: var(--paper-sunken); color: var(--ink); }

@media (max-width: 768px) {
  .nav-toggle { display: inline-flex; align-items: center; justify-content: center; }
  nav#nav {
    display: none;
    flex-direction: column;
    align-items: stretch;
    width: 100%;
    order: 3;
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--line);
    gap: 2px;
    opacity: 0;
    transform: translateY(-6px);
  }
  nav#nav.open { display: flex; opacity: 1; transform: translateY(0); }
  nav#nav a, nav#nav button.linklike { margin-left: 0; padding: 10px 2px; width: 100%; text-align: left; }
  nav#nav a.primary { width: fit-content; margin-top: 6px; }
  .nav-user-info {
    margin-left: 0;
    padding-left: 0;
    border-left: none;
    align-items: flex-start;
    padding: 10px 2px;
    width: 100%;
  }
  .settings-menu { margin-left: 0; padding-left: 0; border-left: none; width: 100%; }
  .settings-toggle { width: auto; height: auto; padding: 10px 2px; justify-content: flex-start; gap: 8px; }
  .settings-toggle::after { content: 'Account settings'; font-size: 0.92rem; }
  .settings-dropdown { position: static; box-shadow: none; margin-top: 4px; }
}

/* nav#nav.open's display swap animates via @starting-style (transition-behavior:
   allow-discrete) rather than JS-timed open/close classes — the element stays
   display:none/opacity:0 at rest so it never eats layout space when closed,
   but still gets a real enter/exit transition instead of the instant display
   cut every other .open toggle on this page used to be. */
@media (max-width: 768px) and (prefers-reduced-motion: no-preference) {
  nav#nav {
    transition: opacity var(--duration-fast) ease, transform var(--duration-fast) ease, display var(--duration-fast) allow-discrete;
  }
  @starting-style {
    nav#nav.open { opacity: 0; transform: translateY(-6px); }
  }
}

/* ---------- Hero ---------- */
.hero {
  position: relative;
  max-width: 760px;
  margin: 0 auto;
  padding: 64px 24px 360px;
  text-align: center;
  overflow: hidden;
}
/* Concentric contour lines — the shape of a reservoir's elevation survey,
   the one recurring image behind this product's whole reason to exist. */
.hero::before {
  content: '';
  position: absolute;
  top: -60px;
  right: -120px;
  width: 480px;
  height: 480px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 600 400'%3E%3Cg fill='none' stroke='%23005587' stroke-width='1.3'%3E%3Cpath d='M300 34 C 430 34,528 108,528 200 C 528 302,430 366,300 366 C 170 366,64 302,64 200 C 64 108,170 34,300 34 Z'/%3E%3Cpath d='M296 66 C 402 62,486 124,488 198 C 490 280,404 332,298 334 C 196 336,118 284,116 202 C 114 126,196 70,296 66 Z'/%3E%3Cpath d='M302 98 C 384 96,442 142,444 198 C 446 258,388 300,300 302 C 218 304,158 262,156 200 C 154 146,224 100,302 98 Z'/%3E%3Cpath d='M298 128 C 358 128,398 160,400 198 C 402 240,362 270,300 270 C 242 270,202 240,200 200 C 198 162,242 128,298 128 Z'/%3E%3Cpath d='M300 160 C 342 158,366 178,366 200 C 366 224,340 242,300 242 C 262 242,236 222,236 200 C 236 180,260 162,300 160 Z'/%3E%3C/g%3E%3C/svg%3E");
  background-repeat: no-repeat;
  opacity: 0.14;
  pointer-events: none;
}
@media (max-width: 576px) { .hero::before { width: 320px; height: 320px; top: -40px; right: -140px; } }
.hero.compact { padding-bottom: 8px; }

/* The top-of-page audience split (public/index.html's "Who's tracking the
   deadline?" through the two picker cards) gets a real photo instead of the
   line-art watermark below — a dam's actual reservoir, not an abstraction
   of one. This wraps the .hero (not = it) specifically so the photo runs
   full-bleed, edge to edge, while the text/cards inside keep the same
   centered 760px measure every other .hero uses — background-size:cover
   fills the full width at its own aspect ratio, cropping top/bottom rather
   than letterboxing or distorting it. A flat white wash over it (not a dark
   scrim) keeps the ink-on-paper reading of the rest of the page instead of
   forcing white text. */
.audience-hero {
  min-height: 500px;
  background:
    linear-gradient(rgba(255,255,255,0.65), rgba(255,255,255,0.65)),
    url('/images/hero-lake.jpg') center 38% / cover no-repeat;
}
.audience-hero .hero::before { display: none; } /* the photo already carries this section's texture */

.hero > * { position: relative; }
.hero h1, .hero h2 {
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 4.4vw, 2.7rem);
  font-weight: 700;
  line-height: 1.15;
  margin: 0 0 16px;
  letter-spacing: -0.01em;
}
.hero p {
  color: var(--ink-soft);
  font-size: 1.05rem;
  max-width: 560px;
  margin: 0 auto 32px;
}
.search-box {
  max-width: 640px;
  margin: 0 auto 8px;
  background: var(--paper-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 8px;
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  box-shadow: var(--shadow-card);
}
.search-box input[type="text"] {
  flex: 1;
  min-width: 160px;
  border: none;
  background: transparent;
  padding: 12px 14px;
  font-size: 1rem;
  font-family: inherit;
  outline: none;
  color: var(--ink);
}
.search-box select {
  border: none;
  background: transparent;
  padding: 12px 6px;
  font-size: 0.95rem;
  font-family: inherit;
  color: var(--ink-soft);
  outline: none;
}
.search-box button {
  font-family: var(--font-mono);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background: var(--brand);
  color: #fff;
  border: none;
  padding: 0 22px;
  border-radius: var(--radius-md);
  font-size: 0.85rem;
  cursor: pointer;
}
.search-box button:hover { background: var(--brand-dark); }
.hint {
  color: var(--ink-soft);
  font-size: 0.85rem;
  text-align: center;
  margin-bottom: 40px;
}
.state-links {
  color: var(--ink-soft);
  font-size: 0.85rem;
  text-align: center;
  margin: -24px 0 40px;
}
.state-links a { color: var(--ink-soft); text-decoration: underline; }

main {
  max-width: 780px;
  margin: 0 auto;
  padding: 0 24px 80px;
}

/* Wider variant for data-dense business pages (engineer-dashboard.html) —
   the default 780px above is sized for the narrow public/consumer pages
   (dam lookup, plain owner dashboard) and is too tight for a 6-column job
   board or the income chart, both of which want real horizontal room. */
main.dashboard-main { max-width: 1180px; }
@media (max-width: 900px) { main.dashboard-main { max-width: 780px; } }
#stats {
  text-align: center;
  color: var(--ink-soft);
  font-family: var(--font-mono);
  font-size: 0.82rem;
  margin-bottom: 24px;
}
#stats strong { color: var(--ink); font-weight: 600; }
.result-count {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.02em;
  color: var(--ink-soft);
  margin: 0 0 12px 4px;
}

/* ---------- Cards ---------- */
.card {
  background: var(--paper-raised);
  border: 1px solid var(--line);
  border-left: 4px solid var(--line-strong);
  border-radius: var(--radius-lg);
  padding: 16px 18px;
  margin-bottom: 10px;
  box-shadow: var(--shadow-card);
}
.card.stripe-ok { border-left-color: var(--ok); }
.card.stripe-warn { border-left-color: var(--warn); }
.card.stripe-danger { border-left-color: var(--danger); }
.card-top {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
}
.card h3 {
  font-family: var(--font-display);
  font-weight: 600;
  margin: 0 0 4px;
  font-size: 1.05rem;
}
.card .meta {
  color: var(--ink-soft);
  font-size: 0.86rem;
}
.card-title-link { color: inherit; text-decoration: none; }
.card-title-link:hover { color: var(--brand); text-decoration: underline; }

/* ---------- Programmatic state-info pages (public/states/*.html) ---------- */
.info-page { max-width: 720px; margin: 0 auto; padding: 40px 24px 80px; }
.info-page h1 { font-family: var(--font-display); font-size: 1.75rem; margin: 0 0 8px; }
.info-page .lede { color: var(--ink-soft); margin: 0 0 8px; }
/* h2 section headers (state pages' "Frequently asked questions" /
   "How to self-inspect a small dam") — gives these pages a real H1->H2->H3
   hierarchy instead of jumping straight from H1 to each card's own H3. */
.info-page h2 { font-family: var(--font-display); font-size: 1.2rem; margin: 32px 0 4px; }
.info-page h2:first-of-type { margin-top: 28px; }
.info-page .card { margin-top: 16px; }
.info-page .card:first-of-type { margin-top: 24px; }
.info-page .card p { font-size: 0.92rem; color: var(--ink-soft); }
/* The HowTo schema's own step list, rendered visibly rather than left only
   in JSON-LD — see the state pages' own comment on why (a structured-data/
   visible-content mismatch an SEO audit flagged). */
.howto-steps { margin: 10px 0 0; padding-left: 22px; }
.howto-steps li { margin-bottom: 8px; font-size: 0.92rem; color: var(--ink-soft); }
.howto-steps li strong { color: var(--ink); }
.info-page .source-note { margin-top: 28px; font-size: 0.85rem; color: var(--ink-soft); }
.info-page .state-crosslinks { margin-top: 12px; font-size: 0.85rem; color: var(--ink-soft); }

/* ---------- Single dam record page ---------- */
.dam-page { max-width: 780px; margin: 0 auto; padding: 40px 24px 80px; }
.dam-title { font-family: var(--font-display); font-size: 1.5rem; margin: 0 0 4px; }
.dam-nid { color: var(--ink-soft); font-family: var(--font-mono); font-size: 0.8rem; margin-top: 16px; }
.dam-footnote { color: var(--ink-soft); font-size: 0.82rem; margin-top: 20px; }
.badge-row { margin-top: 10px; display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }

/* Status tags read as stamped record data: mono, uppercase, tracked,
   square corners — distinct in shape from the pill-shaped "state" tag,
   so shape itself signals category vs. status. */
.badge {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 4px 9px;
  border-radius: var(--radius-sm);
  white-space: nowrap;
  border: 1px solid transparent;
}
.badge.state { background: var(--paper-sunken); color: var(--ink-soft); border-radius: 100px; }
.badge.hazard-high { background: var(--danger-bg); color: var(--danger); }
.badge.hazard-other { background: var(--paper-sunken); color: var(--ink-soft); }
.badge.eap-no { background: var(--danger-bg); color: var(--danger); }
.badge.eap-pending { background: var(--warn-bg); color: var(--warn); }
.badge.eap-yes { background: var(--ok-bg); color: var(--ok); }

/* An engineer's own field assessment on a dam (Inspection.overallConditionRating)
   — engineer-dashboard.js's conditionBadge(). Satisfactory/fair/poor/
   unsatisfactory is the actual state-inspection-report scale (see
   models/Inspection.js), not an invented one. */
.badge.condition-satisfactory { background: var(--ok-bg); color: var(--ok); }
.badge.condition-fair { background: var(--warn-bg); color: var(--warn); }
.badge.condition-poor { background: var(--danger-bg); color: var(--danger); }
.badge.condition-unsatisfactory { background: var(--danger-bg); color: var(--danger); }

/* Inspector worklist (public/inspector-app.js) — assignment priority and
   status, same stamped-tag voice as the badges above. */
.badge.priority-urgent { background: var(--danger-bg); color: var(--danger); }
.badge.priority-high { background: var(--warn-bg); color: var(--warn); }
.badge.priority-normal { background: var(--paper-sunken); color: var(--ink-soft); }
.badge.priority-low { background: var(--paper-sunken); color: var(--ink-soft); }
.badge.status-assigned { background: var(--warn-bg); color: var(--warn); }
.badge.status-in_progress { background: var(--brand-tint); color: var(--brand-dark); }
.badge.status-completed { background: var(--ok-bg); color: var(--ok); }

/* Offline/sync state banner — public/inspect.js and public/inspector-app.js
   (see public/sw.js's queued-write handling). Same three-state shape as the
   badges above (danger/warn/ok palette) rather than a new one. */
.sync-banner { display: none; margin: 0 0 14px; padding: 10px 14px; border-radius: var(--radius-md); font-size: 0.85rem; line-height: 1.45; border: 1px solid transparent; }
.sync-banner.offline { display: block; background: var(--warn-bg); color: var(--warn); border-color: var(--warn); }
.sync-banner.syncing { display: block; background: var(--brand-tint); color: var(--brand-dark); border-color: var(--brand); }
.sync-banner.success { display: block; background: var(--ok-bg); color: var(--ok); border-color: var(--ok); }

.empty, .loading {
  text-align: center;
  color: var(--ink-soft);
  padding: 56px 0 40px;
  font-size: 0.92rem;
  background-repeat: no-repeat;
  background-position: top center;
  background-size: 44px auto;
  padding-top: 68px;
}
.empty {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 32'%3E%3Cg fill='none' stroke='%234b5d66' stroke-width='1.6' stroke-linecap='round'%3E%3Cpath d='M2 22 Q 12 14 24 22 T 46 22'/%3E%3Cpath d='M2 28 Q 12 20 24 28 T 46 28'/%3E%3C/g%3E%3C/svg%3E");
  opacity: 0.9;
}
.loading { background-image: none; }

footer {
  text-align: center;
  color: var(--ink-soft);
  font-size: 0.78rem;
  padding: 24px;
  border-top: 1px solid var(--line);
}

.claim-btn {
  background: none;
  border: 1px solid var(--line);
  color: var(--ink-soft);
  font-family: var(--font-body);
  font-size: 0.82rem;
  font-weight: 600;
  padding: 6px 13px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  /* Also used on <a> download links (dashboard.js), not just <button>s. */
  text-decoration: none;
  display: inline-block;
}
.claim-btn:hover { border-color: var(--brand); color: var(--brand); }
.claim-btn:disabled, .claim-btn[aria-disabled="true"] { opacity: 0.6; cursor: default; }
.claim-btn:disabled:hover, .claim-btn[aria-disabled="true"]:hover { border-color: var(--line); color: var(--ink-soft); }
.claim-btn.claimed { background: var(--ok-bg); border-color: var(--ok-bg); color: var(--ok); }

/* ---------- Auth + dashboard pages ---------- */
.auth-box {
  max-width: 380px;
  margin: 56px auto;
  background: var(--paper-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 32px;
  box-shadow: var(--shadow-card);
}
.auth-box h1 { font-size: 1.45rem; margin: 0 0 4px; text-align: center; }
.auth-box .sub { text-align: center; color: var(--ink-soft); font-size: 0.9rem; margin-bottom: 24px; }
.account-type-toggle { display: flex; gap: 8px; margin-bottom: 18px; }
.account-type-toggle[hidden] { display: none; } /* author rule above would otherwise beat the UA [hidden] rule at equal specificity — same fix as .field-row[hidden] below */
.account-type-btn {
  flex: 1;
  padding: 10px 8px;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--paper-raised);
  color: var(--ink-soft);
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
  text-align: center;
}
.account-type-btn.active { background: var(--brand); border-color: var(--brand); color: #fff; }
.account-type-btn:hover:not(.active) { border-color: var(--ink-soft); color: var(--ink); }
.field { margin-bottom: 14px; }
.field label {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
  margin-bottom: 6px;
  font-weight: 500;
}
.field input, .field select, .field textarea, .filing-form select, .filing-form input[type="date"] {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  font-size: 0.95rem;
  outline: none;
  font-family: var(--font-body);
  background: var(--paper-raised);
  color: var(--ink);
}
.field input:focus, .field select:focus { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-tint); }
.field-row { display: flex; gap: 10px; }
.field-row[hidden] { display: none; } /* author .field-row rule above would otherwise beat the UA [hidden] rule at equal specificity */
.field-row .field { flex: 1; }
.logo-upload { display: flex; align-items: center; gap: 12px; }
.logo-upload-preview {
  width: 72px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--paper-raised); overflow: hidden; flex-shrink: 0;
}
.logo-upload-preview img { max-width: 100%; max-height: 100%; object-fit: contain; }
.logo-upload-preview.empty { font-family: var(--font-mono); font-size: 0.62rem; color: var(--ink-soft); text-align: center; }
.logo-upload-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.logo-upload-hint { font-size: 0.8rem; color: var(--ink-soft); margin: 6px 0 0; }
.auth-submit, .btn-block {
  display: block;
  width: 100%;
  text-align: center;
  text-decoration: none;
  box-sizing: border-box;
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: var(--brand);
  color: #fff;
  border: none;
  padding: 12px;
  border-radius: var(--radius-md);
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
  margin-top: 6px;
}
.auth-submit:hover, .btn-block:hover { background: var(--brand-dark); color: #fff; }
.auth-submit:disabled { opacity: 0.65; cursor: default; }
.auth-toggle {
  text-align: center;
  margin-top: 18px;
  font-size: 0.88rem;
  color: var(--ink-soft);
}
.auth-toggle button {
  background: none; border: none; color: var(--brand); font-weight: 600;
  cursor: pointer; font-size: inherit; font-family: inherit; padding: 0;
}
.auth-error {
  background: var(--danger-bg);
  color: var(--danger);
  border-left: 3px solid var(--danger);
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  font-size: 0.87rem;
  margin-bottom: 14px;
  display: none;
}
.auth-success {
  text-align: center;
  color: var(--ink-soft);
  font-size: 0.9rem;
  display: none;
}
.auth-success a { color: var(--brand); font-weight: 600; }

.dash-header {
  max-width: 780px;
  margin: 0 auto;
  padding: 40px 24px 0;
}
.dash-header h1 { font-size: 1.65rem; margin: 0 0 6px; }
.dash-header p { color: var(--ink-soft); margin: 0 0 8px; }
.plan-status {
  font-family: var(--font-mono);
  font-size: 0.76rem;
  letter-spacing: 0.02em;
  color: var(--ink-soft);
  margin: 0 0 24px;
}
.plan-status a, .link-btn {
  color: var(--brand);
  text-decoration: underline;
  cursor: pointer;
  background: none;
  border: none;
  font: inherit;
  padding: 0;
}
.due-date {
  font-family: var(--font-mono);
  font-size: 0.76rem;
  color: var(--ink-soft);
  margin-top: 10px;
  line-height: 1.7;
}
.due-date strong { color: var(--ink); }
.due-date .at-risk { color: var(--danger); font-weight: 600; }
.due-date.verify-row { display: flex; align-items: center; gap: 8px; font-family: var(--font-body); }
/* Point-of-use liability caveat next to a rendered due date — the fuller
   "not a guarantee" language lives on terms.html, but that page is easy to
   never visit; this sits right where someone is actually trusting a date.
   See public/terms.html's "What Dam-Sure is — and isn't" card. */
.due-date-caveat { font-family: var(--font-body); font-size: 0.72rem; font-style: italic; color: var(--ink-soft); margin-top: 4px; }
.action-row { margin-top: 12px; display: flex; gap: 8px; flex-wrap: wrap; }

.verify-banner {
  background: var(--warn-bg);
  color: var(--warn);
  border-left: 3px solid var(--warn);
  border-radius: var(--radius-sm);
  padding: 12px 16px;
  margin-bottom: 20px;
  font-size: 0.88rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}
.verify-banner .claim-btn { border-color: var(--warn); color: var(--warn); flex-shrink: 0; }
.verify-banner[hidden] { display: none; } /* author .verify-banner rule above would otherwise beat the UA [hidden] rule at equal specificity — this is why demoBanner (also .verify-banner) showed as an empty box instead of staying hidden */

.demo-banner { background: var(--brand-tint); color: var(--brand-dark); border-left-color: var(--brand); }
.demo-banner .claim-btn { border-color: var(--brand); color: var(--brand-dark); }
.claim-btn.danger { border-color: var(--danger); color: var(--danger); }
.claim-btn.danger:hover { background: var(--danger); color: #fff; }

/* ---------- Plans / pricing ---------- */
.plans {
  max-width: 780px;
  margin: 40px auto;
  padding: 0 24px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}
@media (max-width: 640px) { .plans { grid-template-columns: 1fr; } }

/* A scannable feature-by-feature table alongside each .plans pair of cards
   — the cards stay as the primary visual pick, this exists for a quick
   side-by-side compare and gives search engines an actual <table> to lift
   into a comparison snippet, which an SEO audit flagged as missing. */
.compare-table-wrap { max-width: 780px; margin: 8px auto 40px; padding: 0 24px; overflow-x: auto; }
.compare-table { width: 100%; border-collapse: collapse; font-size: 0.88rem; background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius-lg); }
.compare-table th, .compare-table td { padding: 10px 14px; border-bottom: 1px solid var(--line); text-align: left; }
.compare-table th { font-family: var(--font-mono); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--ink-soft); font-weight: 600; }
.compare-table th:not(:first-child), .compare-table td:not(:first-child) { text-align: center; }
.compare-table tbody tr:last-child td { border-bottom: none; }
/* Visually hidden but still announced by a screen reader — used on table
   captions where the surrounding heading already gives sighted users the
   same context. */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }

.plan-card {
  position: relative;
  background: var(--paper-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 28px;
  box-shadow: var(--shadow-card);
}
.plan-card.featured { border-color: var(--brand); box-shadow: var(--shadow-raised); }
.plan-ribbon {
  position: absolute;
  top: -11px;
  left: 24px;
  background: var(--accent); /* bronze, distinct from the blue primary CTA below it */
  color: #fff;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 4px 10px;
  border-radius: var(--radius-sm);
}
.plan-name {
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 600;
  margin: 4px 0 4px;
}
.plan-price { font-family: var(--font-display); font-size: 2.1rem; font-weight: 700; margin: 8px 0 4px; }
.plan-price span { font-family: var(--font-body); font-size: 0.95rem; font-weight: 500; color: var(--ink-soft); }
.plan-features { list-style: none; padding: 0; margin: 20px 0; font-size: 0.9rem; }
.plan-features li { padding: 6px 0; color: var(--ink-soft); }
.plan-features li::before { content: "✓ "; color: var(--brand); font-weight: 700; }
.plan-btn {
  display: block; width: 100%; text-align: center; padding: 12px; border-radius: var(--radius-md);
  font-family: var(--font-mono); text-transform: uppercase; letter-spacing: 0.04em;
  font-weight: 600; font-size: 0.85rem; cursor: pointer; border: 1px solid var(--line);
  background: var(--paper-raised); color: var(--ink); text-decoration: none; box-sizing: border-box;
}
.plan-btn:hover { border-color: var(--ink-soft); }
.plan-btn.primary { background: var(--brand); color: #fff; border: none; }
.plan-btn.primary:hover { background: var(--brand-dark); }
.plan-note { text-align: center; color: var(--ink-soft); font-size: 0.85rem; max-width: 600px; margin: 0 auto 20px; }

/* ---------- Inspection checkpoints ---------- */
.checkpoint-card {
  background: var(--paper-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  margin-bottom: 10px;
  overflow: hidden;
}
.checkpoint-row {
  padding: 14px 16px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  cursor: pointer;
}
.checkpoint-row:hover { background: var(--paper-sunken); }
.checkpoint-name { font-weight: 600; font-size: 0.95rem; }
.checkpoint-count { font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.02em; color: var(--ink-soft); }
.checkpoint-panel { display: none; border-top: 1px solid var(--line); padding: 14px 16px; background: var(--paper-sunken); }
.checkpoint-panel.open { display: block; }
.checkpoint-readonly { color: var(--ink-soft); font-size: 0.85rem; }
.gps-status { font-size: 0.85rem; color: var(--ink-soft); text-align: center; margin: 10px 0; min-height: 18px; }
.gps-status.error { color: var(--danger); }
.coord-row {
  display: flex; justify-content: space-between; background: var(--paper-raised);
  border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 8px 12px;
  margin-bottom: 6px; font-family: var(--font-mono); font-size: 0.8rem;
}
textarea.notes, input.notes {
  width: 100%; padding: 10px; border: 1px solid var(--line); border-radius: var(--radius-md);
  font-family: var(--font-body); font-size: 0.9rem; margin-top: 8px; display: block;
}
textarea.notes { min-height: 60px; resize: vertical; }
.concern-check { display: flex; align-items: center; gap: 8px; margin-top: 8px; font-size: 0.87rem; }
.capture-btn-full {
  width: 100%; font-family: var(--font-mono); text-transform: uppercase; letter-spacing: 0.04em;
  background: var(--brand); color: #fff; border: none; border-radius: var(--radius-md);
  padding: 12px; font-size: 0.82rem; font-weight: 600; cursor: pointer; margin-top: 10px;
}
.capture-btn-full:hover { background: var(--brand-dark); }
.capture-btn-full:disabled { background: #a8a29e; }
.capture-btn-full.secondary { background: var(--paper-raised); color: var(--ink-soft); border: 1px solid var(--line); }
.obs-log { font-size: 0.82rem; color: var(--ink-soft); margin-top: 6px; }
.obs-log .obs-entry { margin-top: 6px; }
.obs-log .concern-flag { color: var(--danger); font-weight: 600; }
.photo-add-label { cursor: pointer; color: var(--brand); }
.file-input-hidden { display: none; }
.inspect-body { max-width: 780px; margin: 0 auto; padding: 0 24px 100px; }

/* Amend flow (public/inspect.js's renderAmendmentHistory/renderAmendObsForm)
   — a correction made after a completed inspection, kept visibly distinct
   from the ordinary capture/obs-log styling above rather than blending in. */
.amendment-history { max-width: 780px; margin: 0 auto; padding: 0 24px; }
.amendment-entry {
  font-size: 0.85rem; color: var(--ink-soft); background: var(--paper-raised);
  border: 1px solid var(--line); border-radius: var(--radius-md); padding: 10px 14px; margin-bottom: 8px;
}
.amendment-entry strong { color: var(--ink); }
.amendment-entry ul { margin: 4px 0 0; padding-left: 18px; }
.amend-obs-form {
  margin-top: 8px; padding: 10px; background: var(--paper-raised);
  border: 1px dashed var(--line); border-radius: var(--radius-md);
}
.complete-bar { max-width: 780px; margin: 24px auto 0; padding: 0 24px; }
.complete-bar.done { text-align: center; color: var(--ink-soft); }
.complete-bar.done strong.concerns { color: var(--danger); }
.status-banner { text-align: center; padding: 40px 24px; color: var(--ink-soft); }
.complete-bar h3 { font-family: var(--font-display); font-size: 1rem; margin: 18px 0 8px; }
.complete-bar h3:first-child { margin-top: 0; }

/* ---------- Per-state checklist items (models/ChecklistTemplate.js) ---------- */
.checklist-item { border-top: 1px solid var(--line); padding: 12px 0; }
.checklist-item:first-child { border-top: none; padding-top: 0; }
.checklist-item-label { font-weight: 600; font-size: 0.88rem; }
.item-help { display: block; font-weight: 400; font-size: 0.78rem; color: var(--ink-soft); margin-top: 2px; }
.response-yesnona { display: flex; gap: 14px; margin-top: 8px; font-size: 0.85rem; }
.response-yesnona label { display: flex; align-items: center; gap: 4px; cursor: pointer; }
.response-select {
  width: 100%; margin-top: 8px; padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--radius-md);
  font-family: var(--font-body); font-size: 0.88rem; background: #fff;
}
.response-measurement { display: flex; gap: 8px; align-items: center; margin-top: 8px; }
.response-measurement .response-value {
  flex: 1; padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--radius-md); font-size: 0.88rem;
}
.response-measurement .response-unit { color: var(--ink-soft); font-size: 0.82rem; }
.capture-btn-small {
  font-family: var(--font-mono); text-transform: uppercase; letter-spacing: 0.03em;
  background: var(--paper-raised); color: var(--ink-soft); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 6px 10px; font-size: 0.72rem; font-weight: 600; cursor: pointer;
}
.capture-btn-small:hover { border-color: var(--brand); color: var(--brand); }
.capture-btn-small:disabled { opacity: 0.5; cursor: default; }
.capture-btn-small:disabled:hover { border-color: var(--line); color: var(--ink-soft); }
.recommendation-row { display: flex; gap: 8px; align-items: center; margin-bottom: 8px; }
.recommendation-row .rec-text {
  flex: 1; padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--radius-md); font-size: 0.88rem;
}
.recommendation-row .rec-priority { padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--radius-md); font-size: 0.85rem; }

/* ---------- Engineer portal ---------- */
.filing-form { display: none; border-top: 1px solid var(--line); padding: 14px 0 4px; margin-top: 12px; }
.filing-form.open { display: block; }
.filing-form select, .filing-form input[type="date"] { margin-bottom: 8px; }
.filing-form .capture-btn-full { width: 100%; }
.filing-file-input { margin-top: 8px; }
.filing-item { font-family: var(--font-mono); font-size: 0.8rem; color: var(--ink-soft); padding: 8px 0; border-top: 1px solid var(--line); }
/* Only the first filing in a card's list — border-top doubles as the
   separator BETWEEN filings too, so this shouldn't repeat on every one of
   them, just push the whole filings block a little further from whatever
   sits above it (the action-row buttons) than that row's own margin alone
   left room for. */
.filing-item:first-child { margin-top: 10px; }
.filing-item strong { font-family: var(--font-body); color: var(--ink); }

/* ---------- Impersonation banner (auth-nav.js) ---------- */
.impersonation-banner {
  background: var(--warn);
  color: #fff;
  text-align: center;
  font-size: 0.85rem;
  padding: 9px 16px;
  display: flex;
  gap: 12px;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
}
.impersonation-banner strong { font-weight: 700; }
.impersonation-banner button {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 600;
  background: rgba(255,255,255,0.16);
  color: #fff;
  border: 1px solid rgba(255,255,255,0.5);
  border-radius: var(--radius-sm);
  padding: 5px 12px;
  cursor: pointer;
}
.impersonation-banner button:hover { background: rgba(255,255,255,0.28); }

/* ==========================================================================
   Platform admin console (public/platform-admin.html)
   A distinct app shell, not the public site chrome — no <header>/<nav>,
   its own sidebar-and-view layout. Same design tokens throughout (fonts,
   palette, radii) so it still reads as the same product, just staff-only.
   ========================================================================== */
.admin-shell {
  display: flex;
  min-height: 100vh;
  align-items: stretch;
}
/* engineer-dashboard.html keeps the site's own <header>/<footer> around this
   shell (unlike platform-admin.html, which drops them) — full 100vh on top
   of that chrome would force extra scroll for no reason, so it gets a
   shorter floor instead. */
#engineerShell.admin-shell {
  min-height: 60vh;
}
.admin-sidebar {
  width: 220px;
  flex-shrink: 0;
  background: var(--brand-dark);
  color: #d8ded9;
  display: flex;
  flex-direction: column;
  padding: 20px 14px;
  gap: 4px;
}
.admin-sidebar-logo {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.1rem;
  color: #fff;
  padding: 4px 10px 6px;
  margin-bottom: 10px;
}
.admin-sidebar-logo span.brand-mark { color: #7fb8a4; }
.admin-sidebar-logo .logo-eyebrow {
  display: block;
  color: #9fb3ab;
  border: none;
  padding: 2px 0 0;
  font-size: 0.62rem;
}
.admin-nav-item {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  color: #cdd9d3;
  font-family: var(--font-body);
  font-size: 0.87rem;
  font-weight: 500;
  padding: 9px 10px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  text-decoration: none;
}
.admin-nav-item:hover { background: rgba(255,255,255,0.08); color: #fff; }
.admin-nav-item.active { background: var(--brand); color: #fff; font-weight: 700; }
.admin-nav-item[hidden] { display: none; } /* author .admin-nav-item rule above would otherwise beat the UA [hidden] rule at equal specificity */
.admin-sidebar-foot { margin-top: auto; padding-top: 14px; border-top: 1px solid rgba(255,255,255,0.14); display: flex; flex-direction: column; gap: 2px; }

/* .admin-main never set its own max-width/margin, so it inherited the
   generic `main { max-width: 780px; margin: 0 auto; }` rule above (a
   narrow-page default meant for reading-oriented pages, not a data-dense
   console) — that rule's max-width/margin apply per-property regardless of
   .admin-main's higher specificity on padding alone. Overridden here so
   flex:1 above can actually stretch to fill the shell, the way it was
   clearly meant to — this constrained BOTH engineer-dashboard.html's job
   board (6 kanban columns needing ~1450px, previously capped at 780px) and
   platform-admin.html's tables to the same 780px regardless of window size. */
.admin-main { flex: 1; min-width: 0; max-width: none; margin: 0; padding: 28px 32px 60px; }
.admin-topbar { display: flex; justify-content: space-between; align-items: baseline; flex-wrap: wrap; gap: 8px; margin-bottom: 22px; }
.admin-topbar h1 { font-size: 1.5rem; margin: 0; }
.admin-who { font-family: var(--font-mono); font-size: 0.78rem; color: var(--ink-soft); }
.admin-view[hidden] { display: none; }

.admin-stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 14px; margin-bottom: 28px; }
.admin-stat {
  background: var(--paper-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 16px 18px;
  box-shadow: var(--shadow-card);
}
.admin-stat .n { font-family: var(--font-display); font-size: 1.7rem; font-weight: 700; line-height: 1.1; }
.admin-stat .n.danger { color: var(--danger); }
.admin-stat .n.warn { color: var(--warn); }
.admin-stat .label { font-family: var(--font-mono); font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-soft); margin-top: 4px; }
.admin-stat .sub { font-size: 0.78rem; color: var(--ink-soft); margin-top: 6px; }

.admin-section-title { font-family: var(--font-display); font-size: 1.1rem; margin: 28px 0 12px; }
.admin-section-title:first-child { margin-top: 0; }

.admin-toolbar { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-bottom: 14px; }
.admin-toolbar input[type="text"], .admin-toolbar input[type="date"], .admin-toolbar select {
  padding: 8px 11px; border: 1px solid var(--line); border-radius: var(--radius-sm);
  font-family: var(--font-body); font-size: 0.86rem; background: var(--paper-raised); color: var(--ink);
}
.admin-toolbar input[type="text"] { flex: 1; min-width: 180px; }
.admin-toolbar input[type="file"] { font-size: 0.8rem; color: var(--ink-soft); }
.admin-toolbar input[type="date"] { min-width: 0; }
.admin-toolbar .toolbar-date-range { display: flex; align-items: center; gap: 6px; }
.admin-toolbar .toolbar-date-range span { font-size: 0.8rem; color: var(--ink-soft); }

.admin-table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--paper-raised); box-shadow: var(--shadow-card); }
.admin-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.admin-table th {
  text-align: left; font-family: var(--font-mono); font-size: 0.66rem; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--ink-soft); padding: 10px 14px; border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.admin-table td { padding: 10px 14px; border-bottom: 1px solid var(--line); vertical-align: middle; }
.admin-table tbody tr:last-child td { border-bottom: none; }
.admin-table tbody tr:hover { background: var(--paper-sunken); }
.admin-table tbody tr.is-clickable { cursor: pointer; }
.admin-table .mono { font-family: var(--font-mono); font-size: 0.8rem; }
.admin-table .muted { color: var(--ink-soft); }

.admin-pagination { display: flex; align-items: center; gap: 10px; margin-top: 12px; font-family: var(--font-mono); font-size: 0.76rem; color: var(--ink-soft); }
.admin-pagination button {
  font-family: var(--font-mono); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.03em;
  background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 5px 11px; cursor: pointer; color: var(--ink);
}
.admin-pagination button:disabled { opacity: 0.4; cursor: default; }
.admin-pagination button:not(:disabled):hover { border-color: var(--brand); color: var(--brand); }

.admin-empty { padding: 40px 20px; text-align: center; color: var(--ink-soft); font-size: 0.9rem; }
.admin-loading { padding: 40px 20px; text-align: center; color: var(--ink-soft); font-size: 0.9rem; }

/* Small inline action buttons inside table rows / detail panes */
.admin-action {
  font-family: var(--font-mono); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.03em;
  border: 1px solid var(--line); background: var(--paper-raised); color: var(--ink-soft);
  padding: 8px 12px; min-height: 36px; border-radius: var(--radius-sm); cursor: pointer; white-space: nowrap;
}
.admin-action:hover { border-color: var(--brand); color: var(--brand); }
.admin-action.danger:hover { border-color: var(--danger); color: var(--danger); }
.admin-action:disabled { opacity: 0.5; cursor: default; }

/* Role / plan / status chips — same tag voice as .badge, admin-scoped names
   so they can carry their own palette without touching the public one. */
.admin-chip {
  display: inline-block; font-family: var(--font-mono); font-size: 0.66rem; font-weight: 600;
  letter-spacing: 0.04em; text-transform: uppercase; padding: 3px 8px; border-radius: var(--radius-sm);
  background: var(--paper-sunken); color: var(--ink-soft);
}
.admin-chip.admin { background: var(--brand-tint); color: var(--brand-dark); }
.admin-chip.pro { background: var(--ok-bg); color: var(--ok); }
.admin-chip.locked { background: var(--danger-bg); color: var(--danger); }
.admin-chip.unverified { background: var(--warn-bg); color: var(--warn); }

/* ---------- Modal (user / dam detail) ---------- */
.admin-modal-backdrop {
  position: fixed; inset: 0; background: rgba(23,36,43,0.45); backdrop-filter: blur(3px); display: flex;
  align-items: flex-start; justify-content: center; padding: 40px 16px; overflow-y: auto; z-index: 50;
  opacity: 1;
}
.admin-modal-backdrop[hidden] { display: none; opacity: 0; }
.admin-modal-backdrop[hidden] .admin-modal { opacity: 0; transform: scale(0.96) translateY(8px); }
.admin-modal {
  background: var(--paper-raised); border-radius: var(--radius-lg); max-width: 640px; width: 100%;
  box-shadow: var(--shadow-raised); padding: 26px 28px 28px;
  opacity: 1; transform: scale(1) translateY(0);
}
@media (prefers-reduced-motion: no-preference) {
  .admin-modal-backdrop {
    transition: opacity var(--duration-fast) ease, display var(--duration-fast) allow-discrete;
  }
  .admin-modal {
    transition: opacity var(--duration-fast) ease, transform var(--duration-fast) ease;
  }
  @starting-style {
    .admin-modal-backdrop:not([hidden]) { opacity: 0; }
    .admin-modal-backdrop:not([hidden]) .admin-modal { opacity: 0; transform: scale(0.96) translateY(8px); }
  }
}
@media (prefers-reduced-transparency: reduce) {
  .admin-modal-backdrop { background: rgba(23,36,43,0.85); backdrop-filter: none; }
}
.admin-modal-head { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin-bottom: 4px; }
.admin-modal-head h2 { font-family: var(--font-display); font-size: 1.3rem; margin: 0; }
.admin-modal-close {
  background: none; border: none; font-size: 1.3rem; line-height: 1; color: var(--ink-soft); cursor: pointer;
  width: 40px; height: 40px; display: inline-flex; align-items: center; justify-content: center; border-radius: var(--radius-sm);
}
.admin-modal-close:hover { color: var(--ink); background: var(--paper-sunken); }
.admin-modal-sub { color: var(--ink-soft); font-size: 0.85rem; margin: 0 0 18px; }
.admin-modal-group { margin-bottom: 18px; }
.admin-modal-group h3 {
  font-family: var(--font-mono); font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--ink-soft); margin: 0 0 8px; font-weight: 600;
}
.admin-kv { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; font-size: 0.86rem; }
.admin-kv dt { color: var(--ink-soft); }
.admin-kv dd { margin: 0; }
.admin-modal-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 6px; }
.admin-mini-list { list-style: none; margin: 0; padding: 0; font-size: 0.85rem; }
.admin-mini-list li { padding: 6px 0; border-top: 1px solid var(--line); display: flex; justify-content: space-between; gap: 10px; align-items: center; }
.admin-mini-list li:first-child { border-top: none; }

/* Below 860px, the sidebar's vertical button list (which needs a real
   column to stack in) has no room next to the main content anymore, so
   .admin-shell drops to a single column and the sidebar becomes a top bar
   instead. A first version just let the sidebar's own children wrap in a
   row (flex-wrap: wrap on a row of block-level, full-width nav buttons) —
   the buttons kept their column sizing (width: 100%) with nothing to be
   100% of anymore, so they collapsed to a narrow, oddly-wrapped stack
   floating to the right of the logo instead of a usable menu. Fixed here by
   making the nav itself a single horizontally-scrolling row of pill-shaped
   tabs (a standard mobile tab-bar pattern) rather than trying to wrap a
   vertical menu into limited width — verified against a real phone
   viewport (390px) with Playwright; see the "-webkit-scrollbar" rule below
   for the swipe hint that makes the scrollability itself discoverable. */
@media (max-width: 860px) {
  .admin-shell { flex-direction: column; }
  .admin-sidebar { width: 100%; flex-direction: column; align-items: stretch; padding: 12px 0 0; gap: 8px; }
  .admin-sidebar-logo { margin: 0; padding: 2px 14px 4px; }

  .admin-sidebar > nav {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    gap: 4px;
    padding: 0 14px 10px;
  }
  .admin-sidebar > nav::-webkit-scrollbar { height: 4px; }
  .admin-sidebar > nav::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.28); border-radius: 2px; }
  .admin-sidebar .admin-nav-item { width: auto; flex: 0 0 auto; white-space: nowrap; }

  .admin-sidebar-foot {
    margin-top: 0; padding: 10px 14px; border-top: 1px solid rgba(255,255,255,0.14);
    flex-direction: row; gap: 6px;
  }
  .admin-sidebar-foot .admin-nav-item { width: auto; flex: 0 0 auto; }
  .admin-main { padding: 20px 16px 48px; }
}

/* A firm manages many clients, each holding one or more dams — portfolio
   groups sorted by their most urgent dam (see engineer-dashboard.js). */
.client-group { margin-bottom: 28px; }
.client-group-header {
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 600;
  margin: 0 0 10px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line-strong);
  display: flex;
  align-items: baseline;
  gap: 10px;
}
.client-dam-count {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--ink-soft);
}

/* ---------- Audience split (public/index.html, public/pricing.html) ----------
   Two different buyers with different jobs: a consultancy filing on behalf
   of many clients, and an owner filing for themselves. One product, but
   never presented as one undifferentiated page — consultancies get first
   billing (docs/CONSULTANCY-LEADS.md) and their own tier and section. */
.eyebrow {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--brand);
  margin-bottom: 10px;
}
.hero-lede { max-width: 600px; margin: 0 auto 32px; color: var(--ink-soft); font-size: 1rem; }

.audience-picker {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  max-width: 760px;
  margin: 0 auto;
  text-align: left;
}
@media (max-width: 640px) { .audience-picker { grid-template-columns: 1fr; } }
.audience-card {
  display: block;
  background: var(--paper-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 22px 22px 20px;
  text-decoration: none;
  color: var(--ink);
  box-shadow: var(--shadow-card);
}
.audience-card:hover { border-color: var(--brand); box-shadow: var(--shadow-raised); transform: translateY(-1px); }
.audience-card.priority { border-color: var(--brand); }
.audience-kicker {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.64rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: var(--brand);
  color: #fff;
  padding: 3px 9px;
  border-radius: 100px;
  margin-bottom: 10px;
}
.audience-card h2 { font-family: var(--font-display); font-size: 1.12rem; margin: 0 0 8px; }
.audience-card p { color: var(--ink-soft); font-size: 0.88rem; margin: 0 0 14px; }
.audience-card .audience-cta {
  font-family: var(--font-mono);
  font-size: 0.76rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--brand);
}

/* Section band on index.html for the consultancy pitch — the visual seam
   between the two audiences. Tinted so it doesn't read as more of the same
   free-lookup page that follows it. */
.audience-section { padding: 28px 24px; }
.audience-section.tinted { background: var(--brand-tint); }
.audience-section-inner { max-width: 900px; margin: 0 auto; }
.section-head { text-align: center; max-width: 620px; margin: 0 auto 32px; }
.section-head h2 { font-size: clamp(1.5rem, 3.2vw, 1.9rem); margin: 0 0 10px; }
.section-head p { color: var(--ink-soft); margin: 0; }

.feature-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 32px; max-width: 620px; margin: 0 auto 28px; }
@media (max-width: 640px) { .feature-grid { grid-template-columns: 1fr; } }
.feature-grid .plan-features { margin: 0; }

.callout-box {
  max-width: 620px;
  margin: 0 auto 28px;
  background: var(--paper-raised);
  border: 1px solid var(--line);
  border-left: 4px solid var(--accent);
  border-radius: var(--radius-md);
  padding: 16px 18px;
  font-size: 0.87rem;
  color: var(--ink-soft);
}
.callout-box strong { color: var(--ink); }

.cta-row { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }
.cta-btn {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 0.8rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  padding: 12px 22px;
  border-radius: var(--radius-md);
  text-decoration: none;
  border: 1px solid var(--line-strong);
  color: var(--ink);
  background: var(--paper-raised);
}
.cta-btn:hover { border-color: var(--ink-soft); }
.cta-btn.primary { background: var(--brand); border-color: var(--brand); color: #fff; }
.cta-btn.primary:hover { background: var(--brand-dark); border-color: var(--brand-dark); }

/* Anchor jump at the top of pricing.html — scrolls to the matching group
   rather than hiding one with JS, so both stay crawlable and linkable
   (index.html's consultancy CTA deep-links to #consultancies). */
.pricing-jump { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; margin: 4px 0 0; }
.pricing-jump a {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  padding: 9px 16px;
  border-radius: 100px;
  border: 1px solid var(--line-strong);
  color: var(--ink-soft);
  text-decoration: none;
}
.pricing-jump a:hover { border-color: var(--brand); color: var(--brand); }

.plan-group-head { text-align: center; max-width: 620px; margin: 48px auto 20px; }
.plan-group-head h2 { font-family: var(--font-display); font-size: 1.4rem; margin: 0 0 6px; }
.plan-group-head p { color: var(--ink-soft); font-size: 0.9rem; margin: 0; }
#consultancies .plan-group-head { margin-top: 32px; }

/* ── Jobs & billing (engineer-dashboard.html's #jobs section) ───────────
   Job status board (Kanban-style columns) + a hand-rolled inline-SVG
   income chart — no charting library dependency exists in this project
   (see docs/CONSULTANCY-BILLING-SPEC.md), so this stays plain markup/SVG
   the same way every other page here is vanilla HTML/CSS/JS. */
.badge.job-open           { background: var(--paper-sunken); color: var(--ink-soft); }
.badge.job-in_progress    { background: var(--brand-tint);   color: var(--brand-dark); }
.badge.job-ready_to_invoice { background: var(--warn-bg);    color: var(--warn); }
.badge.job-invoiced       { background: var(--brand-tint);   color: var(--brand-dark); }
.badge.job-paid           { background: var(--ok-bg);        color: var(--ok); }
.badge.job-canceled       { background: var(--danger-bg);    color: var(--danger); }

.job-board { display: flex; gap: 14px; overflow-x: auto; padding-bottom: 10px; }
/* Flexible (grow + shrink) rather than the fixed 230px this used to be —
   6 rigid 230px columns need ~1450px and forced a horizontal scroll on
   the kanban even after .admin-main's own width was fixed (see that rule's
   comment) on anything narrower than roughly a 1560px window. 160px floor
   matches .admin-stat-grid's own minmax(160px,1fr) minimum elsewhere on
   this page, so a typical laptop width (~1440px) fits all 6 columns with
   room to grow, rather than clipping to their minimum. overflow-x: auto
   above stays as the fallback for anything narrower than that floor. */
.job-column {
  flex: 1 1 160px; min-width: 160px; background: var(--paper-sunken); border-radius: var(--radius-lg); padding: 10px;
  border: 2px dashed transparent; /* reserved, not just added on .drag-over, so the highlight doesn't shift layout by adding a border where none existed */
}
/* A column a dragged card can actually be dropped on (public/engineer-dashboard.js
   only wires dragover/drop listeners onto these — see setupJobDragAndDrop) gets
   the highlight; [data-locked-column] (Invoiced/Paid) never receives the
   'drag-over' class at all, so it never lights up — the browser's own
   not-allowed cursor is the only feedback there, which is the point. */
.job-column.drag-over { border-color: var(--brand); background: var(--brand-tint); }
.job-column h3 {
  font-family: var(--font-mono); font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--ink-soft); margin: 2px 4px 10px;
}
/* Count + $ subtotal on their own line below the status label — on the same
   line (space-between, no wrap) "Ready to invoice" and a $ subtotal fight
   for the same ~210px column width; stacking keeps both readable. */
.job-column h3 span { display: block; margin-top: 2px; font-weight: 600; letter-spacing: 0; }
.job-card {
  background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius-md);
  padding: 10px 12px; margin-bottom: 8px; box-shadow: var(--shadow-card); cursor: pointer;
}
.job-card:hover { border-color: var(--brand); }
.job-card:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.job-card[data-draggable="true"] { cursor: grab; touch-action: none; } /* touch-action:none hands the gesture to our own pointermove tracking instead of letting the browser start a page-scroll on touch */
.job-card[data-draggable="true"]:active { cursor: grabbing; }
.job-card.dragging { opacity: 0.4; }
.job-card-locked { cursor: default; }
.job-card-locked:hover { border-color: var(--line); } /* no hover affordance to suggest this one can be picked up/moved */

/* The floating clone that tracks the pointer during a drag (see
   setupJobDragAndDrop in engineer-dashboard.js) — position:fixed with inline
   left/top set from getBoundingClientRect(), same coordinate space. */
.job-card-ghost {
  position: fixed;
  margin: 0;
  z-index: 100;
  pointer-events: none;
  cursor: grabbing;
  box-shadow: var(--shadow-raised);
}
.job-card .job-title { font-weight: 600; font-size: 0.88rem; margin-bottom: 2px; }
.job-card .job-dam { font-size: 0.78rem; color: var(--ink-soft); }
.job-card .job-amount { font-family: var(--font-mono); font-size: 0.9rem; font-weight: 700; margin-top: 6px; color: var(--ink); }
.job-column-empty { font-size: 0.78rem; color: var(--ink-soft); padding: 4px; }

/* ── Upcoming inspections (engineer-dashboard.html's #upcomingInspections) —
   a compact "what needs attention" digest, same urgency stripe language as
   .card.stripe-* below, sized for scanning rather than the full detail a
   dam card gives. ─────────────────────────────────────────────────────── */
.upcoming-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 8px; }
.upcoming-item {
  display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap;
  background: var(--paper-raised); border: 1px solid var(--line); border-left: 4px solid var(--line-strong);
  border-radius: var(--radius-md); padding: 10px 14px; text-decoration: none; color: inherit;
}
.upcoming-item:hover { border-color: var(--brand); }
.upcoming-item.stripe-ok { border-left-color: var(--ok); }
.upcoming-item.stripe-warn { border-left-color: var(--warn); }
.upcoming-item.stripe-danger { border-left-color: var(--danger); }
.upcoming-item-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.upcoming-item-main strong { font-size: 0.92rem; }
.upcoming-item-owner { font-size: 0.78rem; color: var(--ink-soft); }
.upcoming-item-due { font-family: var(--font-mono); font-size: 0.78rem; white-space: nowrap; color: var(--ink-soft); }
.upcoming-item.stripe-danger .upcoming-item-due { color: var(--danger); font-weight: 600; }
.upcoming-item.stripe-warn .upcoming-item-due { color: var(--warn); font-weight: 600; }
.upcoming-item-more { font-size: 0.78rem; color: var(--ink-soft); padding: 4px 2px; }

.income-chart-wrap {
  background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: 16px 18px; box-shadow: var(--shadow-card); margin-bottom: 20px;
  position: relative; /* positioning context for .income-chart-tooltip below */
}
.income-chart-wrap h3 { font-family: var(--font-display); font-size: 0.95rem; margin: 0 0 10px; }
/* The horizontal scroll lives on this inner wrapper, not .income-chart-wrap
   itself — setting overflow-x there would force overflow-y to clip too (a
   CSS rule: one non-'visible' overflow axis forces the other non-'visible'),
   which could cut off the tooltip popping up above the tallest bar. */
.income-chart-scroll { overflow-x: auto; }
.income-chart-legend { display: flex; gap: 16px; font-size: 0.78rem; color: var(--ink-soft); margin-top: 8px; }
.income-chart-legend span { display: inline-flex; align-items: center; gap: 5px; }
.income-chart-legend i { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }

.income-bar { cursor: pointer; }
.income-bar:hover, .income-bar:focus-visible, .income-bar.active { stroke: var(--ink); stroke-width: 1.5; outline: none; }
.income-chart-tooltip {
  position: absolute; transform: translate(-50%, calc(-100% - 8px));
  background: var(--ink); color: #fff; font-family: var(--font-mono); font-size: 0.76rem;
  padding: 5px 9px; border-radius: var(--radius-sm); white-space: nowrap; pointer-events: none;
  box-shadow: var(--shadow-card); z-index: 5;
}

/* public/engineer-dashboard.js's Calendar tab — a 42-cell month grid, same
   "own small module, own classes" pattern as .job-board above it. Due-date
   markers reuse .badge's color language (--danger/--warn) via the cal-dot
   modifiers below rather than introducing a third palette. */
.calendar-toolbar { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; margin-bottom: 10px; }
.calendar-nav { display: flex; align-items: center; gap: 10px; }
.calendar-nav h2 { font-family: var(--font-display); font-size: 1.05rem; margin: 0; min-width: 150px; text-align: center; }
.calendar-legend { display: flex; gap: 16px; font-size: 0.78rem; color: var(--ink-soft); margin-bottom: 10px; flex-wrap: wrap; }
.calendar-legend span { display: inline-flex; align-items: center; gap: 5px; }

.cal-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.cal-dot-due { background: var(--warn); }
.cal-dot-due.cal-dot-overdue { background: var(--danger); }
.cal-dot-scheduled { background: var(--brand); }
.cal-dot-completed { background: var(--ok); }

.calendar-weekdays {
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px;
  font-family: var(--font-mono); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--ink-soft); text-align: center; padding: 0 2px 6px;
}
.calendar-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.calendar-cell {
  background: var(--paper-raised); border: 1px solid var(--line); border-radius: 10px;
  min-height: 64px; padding: 6px 8px; cursor: pointer; transition: border-color 0.15s;
}
.calendar-cell:hover { border-color: var(--brand); }
.calendar-cell-out { background: var(--paper-sunken); color: var(--ink-soft); }
.calendar-cell-today { border-color: var(--brand); border-width: 2px; }
.calendar-cell-date { font-family: var(--font-mono); font-size: 0.8rem; }
.calendar-cell-dots { display: flex; gap: 4px; margin-top: 8px; flex-wrap: wrap; }

@media (max-width: 720px) {
  .calendar-weekdays { font-size: 0.62rem; }
  .calendar-cell { min-height: 44px; padding: 4px 5px; }
  .calendar-nav h2 { min-width: 0; font-size: 0.92rem; }
}

/* Account-connection panels above the jobs stat grid (routes/qbo.js's
   QuickBooks connect panel, routes/firmStripe.js's Stripe connect panel) —
   root-only, same card shape as .income-chart-wrap so every "panel" on this
   page reads as one family rather than a one-off. Shared class (.qbo-panel
   is the older, now-generic name — kept rather than renamed everywhere it's
   used in engineer-dashboard.js). */
.qbo-panel {
  background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: 14px 18px; box-shadow: var(--shadow-card); margin-bottom: 20px;
  display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap;
}
.qbo-panel[hidden] { display: none; } /* author .qbo-panel rule above would otherwise beat the UA [hidden] rule at equal specificity */
.qbo-panel-status { display: flex; align-items: center; gap: 10px; font-size: 0.85rem; }
.qbo-panel-status .badge { flex-shrink: 0; }
.qbo-panel-meta { color: var(--ink-soft); font-size: 0.78rem; }
.qbo-panel-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.qbo-panel-actions input[type="text"], .qbo-panel-actions input[type="password"] { min-width: 220px; }

.job-detail-kv { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; font-size: 0.85rem; margin-bottom: 14px; }
.job-detail-kv dt { color: var(--ink-soft); }
.line-items-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; margin-bottom: 10px; }
.line-items-table th { text-align: left; font-family: var(--font-mono); font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-soft); padding: 6px 8px; border-bottom: 1px solid var(--line); }
.line-items-table td { padding: 6px 8px; border-bottom: 1px solid var(--line); vertical-align: middle; }
.line-items-table td.num { text-align: right; font-family: var(--font-mono); }
.line-items-table tfoot td { font-weight: 700; border-bottom: none; padding-top: 8px; }
.line-item-add-row { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 10px; margin-bottom: 14px; }
.line-item-add-row input[type="text"] { flex: 1; min-width: 160px; }
.line-item-add-row input[type="number"] { width: 90px; }
.line-item-add-row input, .job-detail-kv input, .job-detail-kv select {
  padding: 7px 10px; border: 1px solid var(--line); border-radius: var(--radius-sm); font-family: var(--font-body); font-size: 0.85rem;
}

/* ---------- FAQ / Help center (public/faq.html, public/help.html) ----------
   Shared shell for both: a plain-input search box (reuses .search-box's look
   without its select/button, since filtering here is instant, not a submit),
   a row of category filter chips, and a flat list of .card items with
   data-category + data-help-id — search and category filter both just
   toggle each card's [hidden], no server round trip (the content set is
   small and static, unlike the 20k+-dam search this would be overkill for). */
.help-search { max-width: 640px; margin: 0 auto 20px; background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 4px; box-shadow: var(--shadow-card); }
.help-search input[type="text"] { width: 100%; border: none; background: transparent; padding: 12px 14px; font-size: 1rem; font-family: inherit; outline: none; color: var(--ink); }
.help-categories { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-bottom: 28px; }
.help-category-chip {
  font-family: var(--font-mono); font-size: 0.72rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;
  background: var(--paper-raised); color: var(--ink-soft); border: 1px solid var(--line); border-radius: 100px;
  padding: 7px 16px; cursor: pointer;
}
.help-category-chip:hover { border-color: var(--ink-soft); }
.help-category-chip.active { background: var(--brand); border-color: var(--brand); color: #fff; }
.help-video-note { display: inline-flex; align-items: center; gap: 6px; margin-top: 10px; font-size: 0.78rem; color: var(--ink-soft); background: var(--paper-sunken); border-radius: var(--radius-sm); padding: 5px 10px; }
.help-empty { text-align: center; color: var(--ink-soft); padding: 32px 0; }
/* Section headers grouping .help-item cards by category — an H2 between
   faq.html's H1 and each card's own H3, so the page has a real heading
   hierarchy instead of jumping straight from H1 to H3. */
.help-category-heading { font-family: var(--font-display); font-size: 1.1rem; margin: 28px 0 10px; }
.help-category-heading:first-of-type { margin-top: 20px; }
.help-category-heading[hidden] { display: none; }

/* Instructional videos pulled from Cloudflare R2 (routes/help.js) — the
   #helpVideos section itself is hidden entirely via [hidden] until help.js
   confirms at least one video exists at all, so an unconfigured/empty
   bucket never shows a blank section header above the written guides.
   Once it's shown, it stays shown — a search/category filter that matches
   zero videos hides #helpVideosList and shows helpVideosEmpty instead, so
   the section doesn't look like it vanished. */
.help-videos { margin-bottom: 32px; }
.help-videos h2 { font-family: var(--font-display); font-size: 1.1rem; margin: 0 0 4px; }
.help-videos-intro { font-size: 0.82rem; color: var(--ink-soft); margin: 0 0 14px; }
.help-videos-empty { padding: 20px 0; }
.help-videos-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; }
.help-video-card {
  background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: 10px; box-shadow: var(--shadow-card); transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.help-video-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-card-hover, var(--shadow-card)); border-color: var(--line-strong); }
.help-video-thumb { position: relative; }
.help-video-card video { width: 100%; aspect-ratio: 16 / 9; object-fit: contain; border-radius: var(--radius-sm); display: block; background: #000; }
.help-video-duration {
  position: absolute; right: 6px; bottom: 6px; background: rgba(0, 0, 0, 0.72); color: #fff;
  font-family: var(--font-mono); font-size: 0.68rem; padding: 2px 6px; border-radius: 4px; pointer-events: none;
}
.help-video-meta { margin-top: 8px; }
.help-video-category-badge {
  display: inline-block; font-family: var(--font-mono); font-size: 0.65rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.04em; color: var(--brand); background: var(--paper-sunken); border-radius: 100px; padding: 3px 9px; margin-bottom: 5px;
}
.help-video-card .help-video-title { font-size: 0.85rem; font-weight: 600; margin: 0 2px; color: var(--ink); }
