/* ==========================================================
   DeltaVisor · marketing site core
   site/css/core.css

   Everything every marketing page needs, in ONE same-origin file, on top
   of cdn/css/v1/universal.css (the tokens, which every surface shares).

   WHY THIS EXISTS. The site used to load five stylesheets, three of them
   cross-origin from the CDN, and measured CSS coverage across all five
   pages put them at 18% used: 104 KiB of unused rules on every load.
   components.css alone was 62 KB at 2% used, because the site borrows
   four `app__` header rules and the pricing-card chassis out of a file
   built for the admin console. Those rules are copied in below rather
   than dragged in whole.

   THE LINE. Values live in universal.css because every surface has to
   agree on them. Components live with the surface that renders them,
   because the admin console and a marketing page have almost nothing in
   common past the tokens. If you find yourself wanting a colour here,
   it belongs in universal.css instead.

   The CDN files are untouched and still serve admin, the vanilla
   dashboard, and the region landing pages.

   Sections:
     1. reset, typography base, ambient glow, .eyebrow, .btn*
     2. inline text primitives, utilities, scrollbar, motion, print
     3. borrowed component atoms: the app header, the plan card
     4. the marketing vocabulary itself: nav, section rhythm, signals,
        the live-figure band, FAQ, prose, footer, scroll reveal
========================================================== */

/* ==========================================================
   1-2 · FROM THE SHARED DESIGN SYSTEM
   Copied, not linked. The site renders with these and with nothing else
   in that file, so linking it meant shipping 27 KB of form fields,
   selects, switches and chips to use a button.
========================================================== */

/* ==========================================================
   RESET + BASE
========================================================== */
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-padding-top: var(--s-7); }
html, body { height: 100%; }
body {
  font-family: var(--font-body);
  font-size: var(--t-base);
  line-height: 1.45;
  color: var(--ink-soft);
  background: var(--paper-0);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  letter-spacing: -0.003em;
  font-feature-settings: "ss01", "cv11", "cv09";
  overflow-x: clip;
  position: relative;
}

img, svg { display: block; max-width: 100%; }
/* Form-control reset. Font/color inheritance is wanted on every form
   control. The background/border wipe is scoped to <button> only, 
   inputs/selects/textareas get their chrome from the safety-net and
   `select` rules later in this file; a blanket reset here would
   wipe them out (and used to). */
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
input, textarea { cursor: text; }
textarea { resize: none; }
a { color: inherit; text-decoration: none; color: var(--accent);}
ul, ol { list-style: none; }
em { font-style: italic; }

/* ==========================================================
   AMBIENT GLOW
   Soft radial in the top-left, tinted by the accent. Anchors
   chrome to a "light source" without being decorative. Pinned
   to the viewport, sits behind everything.
========================================================== */
html::before {
  content: "";
  position: fixed;
  top: -12.5rem;
  left: -12.5rem;
  width: 37.5rem;
  height: 37.5rem;
  background: radial-gradient(circle, rgba(10, 132, 255, 0.08), transparent 70%);
  pointer-events: none;
  z-index: 0;
}

/* ==========================================================
   TYPOGRAPHY BASE
========================================================== */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1.1;
  color: var(--ink);
}
h1 { font-size: clamp(2.5rem, 6vw, var(--t-5xl)); }
h2 { font-size: clamp(2rem, 5vw, var(--t-4xl)); }
h3 { font-size: clamp(1.25rem, 2.4vw, var(--t-xl)); }

p { color: var(--ink-soft); }

.prose p + p { margin-top: var(--s-4); }
.prose p {
  font-size: clamp(1rem, 1.1vw, var(--t-md));
  line-height: 1.6;
  color: var(--ink-soft);
  max-width: 60ch;
}
.prose em {
  font-style: italic;
  color: var(--ink);
}
.prose strong { font-weight: 600; color: var(--ink); }
.prose h2 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-2xl);
  letter-spacing: -0.01em;
  line-height: 1.15;
  margin: var(--s-7) 0 var(--s-2);
  color: var(--ink);
}
.prose h3 {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--t-md);
  letter-spacing: 0;
  margin: var(--s-5) 0 var(--s-2);
  color: var(--ink);
}
.prose ul, .prose ol {
  margin: 0 0 var(--s-4);
  padding-left: 1.25rem;
  max-width: 60ch;
  color: var(--ink-soft);
  line-height: 1.6;
}
.prose li { margin: 0.25rem 0; }
.prose li > ul, .prose li > ol { margin-bottom: 0; }
.prose code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--paper-2);
  padding: 0.1em 0.35em;
  border-radius: var(--radius-sm);
  color: var(--ink-soft);
}
.prose pre {
  font-family: var(--font-mono);
  font-size: 0.85em;
  line-height: 1.55;
  background: var(--paper-2);
  border: 1px solid var(--rule-soft);
  border-radius: var(--radius-sm);
  padding: 0.9rem 1.1rem;
  margin: 0 0 var(--s-4);
  max-width: 60ch;
  overflow-x: auto;
  white-space: pre;
  color: var(--ink-soft);
}
.prose pre code {
  background: transparent;
  padding: 0;
  border-radius: 0;
  font-size: inherit;
}

/* ==========================================================
   EYEBROW
   Quiet sans label, no mono-caps "instrument tag" treatment.
   Used as a small section context label.
========================================================== */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-body);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-mid);
}
.eyebrow__sigil { display: none; }  /* legacy § sigil retired */

/* ==========================================================
   BUTTONS
========================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4375rem;
  padding: 0.5rem 0.875rem;
  font-family: var(--font-body);
  font-size: var(--t-sm);
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
  background: rgba(255, 255, 255, 0.05);
  box-shadow: inset 0 0 0 1px var(--rule);
  border: 0;
  border-radius: var(--radius-md);
  cursor: pointer;
  position: relative;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform var(--dur-fast) var(--ease);
}
.btn:hover { background: rgba(255, 255, 255, 0.10); }
.btn:active { transform: scale(0.97); }
.btn__arrow {
  font-family: var(--font-body);
  font-size: 1em;
  transition: transform var(--dur) var(--ease);
}
.btn:hover .btn__arrow { transform: translateX(2px); }

.btn--primary {
  background: var(--accent);
  color: var(--ink);
  box-shadow: 0 0 0 1px rgba(10, 132, 255, 0.40), 0 0.375rem 1rem rgba(10, 132, 255, 0.28);
}
.btn--primary:hover {
  background: var(--accent-deep);
  color: var(--ink);
}

/* Secondary, translucent raised chip with a hairline inset ring. This is
   the everyday neutral; it's visually identical to a bare .btn (kept as the
   explicit semantic name, not a separate look). Pairs with .btn--primary. */
.btn--secondary {
  background: rgba(255, 255, 255, 0.05);
  color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--rule);
}
.btn--secondary:hover {
  background: rgba(255, 255, 255, 0.10);
  color: var(--ink);
}

/* Danger, neutral chip with error-colored label at rest (inherits the base
   ring); fills solid red on hover, ring following the fill so no grey
   hairline shows over the red. */
.btn--danger {
  background: rgba(255, 255, 255, 0.05);
  color: var(--status-error);
}
.btn--danger:hover {
  background: var(--status-error);
  color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--status-error);
}

.btn--small { padding: 0.375rem 0.6875rem; font-size: var(--t-xs); }

/* A row of buttons. Used on the watcher builder, the watcher page and the org home, and
   defined nowhere until now, so all three were relying on the whitespace between two
   inline-flex elements for their spacing. */
.btn-row { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.btn[disabled], .btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}

/* ==========================================================
   HONEYPOT (off-screen, accessible)
========================================================== */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ==========================================================
   INLINE TEXT PRIMITIVES
========================================================== */
.hint {
  font-family: var(--font-body);
  font-size: var(--t-xs);
  letter-spacing: 0;
  color: var(--ink-mid);
}
.hint--tight { letter-spacing: 0; }

.inline-code {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  background: var(--paper-1);
  padding: 2px 0.375rem;
  border-radius: var(--radius-sm);
  color: var(--ink-soft);
  letter-spacing: 0;
}

/* ==========================================================
   UTILITIES
========================================================== */
.mono         { font-family: var(--font-mono); }
.muted        { color: var(--ink-mid); }
.text-success { color: var(--status-success); }
.text-danger  { color: var(--status-error); }
.text-accent  { color: var(--accent); }

.text-3xs { font-size: var(--t-3xs); }
.text-2xs { font-size: var(--t-2xs); }
.text-xs  { font-size: var(--t-xs); }
.text-sm  { font-size: var(--t-sm); }
.text-md  { font-size: var(--t-md); }
.text-lg  { font-size: var(--t-lg); }
.text-xl  { font-size: var(--t-xl); }

.text-right { text-align: right; }
.nums-right { text-align: right; font-variant-numeric: tabular-nums; }

.mt-1 { margin-top: var(--s-1); }
.mt-2 { margin-top: var(--s-2); }
.mt-3 { margin-top: var(--s-3); }
.mt-4 { margin-top: var(--s-4); }
.mt-5 { margin-top: var(--s-5); }
.mt-6 { margin-top: var(--s-6); }
.mb-1 { margin-bottom: var(--s-1); }
.mb-2 { margin-bottom: var(--s-2); }
.mb-3 { margin-bottom: var(--s-3); }
.mb-4 { margin-bottom: var(--s-4); }
.mb-5 { margin-bottom: var(--s-5); }
.mb-6 { margin-bottom: var(--s-6); }

.hidden    { display: none !important; }
.is-hidden { display: none; }

/* ==========================================================
   SCROLLBAR, dark, neutral
========================================================== */
::-webkit-scrollbar { width: 0.625rem; height: 0.625rem; }
::-webkit-scrollbar-track {
  background: var(--paper-0);
  border-radius: var(--radius-sm);
}
::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.10);
  border-radius: var(--radius-sm);
  border: 2px solid var(--paper-0);
}
::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.20); }

/* ==========================================================
   REDUCED MOTION
========================================================== */
@media (prefers-reduced-motion: reduce) {
  **::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  [data-reveal] { opacity: 1; transform: none; }
}

/* ==========================================================
   PRINT
========================================================== */
@media print {
  html::before { display: none; }
  * { color: #000 !important; background: #fff !important; }
}


/* ==========================================================
   3 · BORROWED COMPONENT ATOMS
   The header chrome and the pricing-card chassis, lifted from
   cdn/css/v1/components.css so the marketing site and the app's plan
   picker keep rendering the same card. If either changes shape, both
   files have to move; that is the cost of not making a marketing page
   depend on the admin console's stylesheet.
========================================================== */

/* Toolbar, translucent material, sticks on scroll. */
.app__header {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-5);
  /* Lock a fixed bar height so every surface renders the same chrome
     regardless of what its app__header-end carries, dashboard/admin
     have btn--small clusters (~3.4rem natural), help/docs have plain-
     text link clusters (~2.8rem natural). Without this, the bar's
     height drifts per surface. */
  min-height: 3.5rem;
  padding: 0 1.5rem;
  background: var(--bar);
  backdrop-filter: saturate(180%) blur(1.375rem);
  -webkit-backdrop-filter: saturate(180%) blur(1.375rem);
  border-bottom: 1px solid var(--rule-soft);
}
.app__mark {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  font-family: var(--font-wordmark);
  /* Geist is variable and fonts.css loads 300..700, so 700 is a
     drawn weight, not a synthesised bold. Going past 700 would need
     the import range widened first. */
  font-size: var(--t-2xl);
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--ink);
  text-decoration: none;
  line-height: 1;
}
/* Logo mark sits to the left of the wordmark. Height is set here so
   the SVG scales to the bar, .app__mark's flex gap handles spacing. */
.app__mark-logo {
    display: block;
    height: 1.65rem;
    width: auto;
    margin-bottom: 0.15rem;
}
.app__mark-sigil { display: none; }
/* Small tag chip after the wordmark, used for "Admin", "Beta", etc. */
.app__mark-tag {
  margin-left: 0.25rem;
  padding: 2px 0.5rem;
  font-family: var(--font-body);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0;
  color: var(--ink-mid);
  background: var(--paper-1);
  border-radius: var(--radius-full);
}
.app__header-end {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  font-size: var(--t-sm);
  color: var(--ink-mid);
}
/* Cross-surface link clusters (help, docs) put plain text anchors in
   .app__header-end. The global `a { color: inherit; text-decoration:
   none }
.app__header-end a {
  color: var(--ink-mid);
  text-decoration: none;
  transition: color var(--dur) var(--ease);
}
.app__header-end a:hover { color: var(--ink); }
.app__header-start {
  display: inline-flex;
  align-items: center;
  gap: 1rem;
}
/* ==========================================================
   PLAN CARD · tier pricing card
   Single card shape used on the marketing pricing page and the
   dashboard plan picker. Slots: optional kicker + name, price
   block (currency · amount · per), optional billing/savings
   lines, full-width CTA, check-bulleted feature list. Featured
   variant adds an accent ring + glow; current variant tints the
   background. Both surfaces emit the same markup so a styling
   change ripples to both at once.
========================================================== */
.plan-card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: clamp(1rem, 1.5vw, 1.5rem);
  align-items: stretch;
}
/* Monthly/annual segmented toggle above the plan cards */
.plan-interval {
    display: inline-flex;
    gap: 0.25rem;
    margin: 0;
    padding: 0.25rem;
    background: var(--paper-2);
    border: 1px solid var(--rule);
    border-radius: var(--radius-full);
    align-self: center;
}
.plan-interval__opt {
  display: inline-flex; align-items: center; gap: 0.5rem;
  padding: 0.375rem 0.875rem; border: none; background: none; cursor: pointer;
  color: var(--ink-mid); font-family: inherit; font-size: var(--t-sm);
  border-radius: var(--radius-full);
  transition: background 160ms var(--ease-out), color 160ms var(--ease-out);
}
.plan-interval__opt.is-active { background: var(--accent); color: #fff; }
.plan-interval__save { font-size: var(--t-2xs); font-weight: 600; color: var(--status-success); }
.plan-interval__opt.is-active .plan-interval__save { color: #fff; }
.plan-card {
  position: relative;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: var(--radius-lg);
  padding: clamp(1.5rem, 2.5vw, 2rem);
  display: flex;
  flex-direction: column;
  gap: 1rem;
  transition: border-color 160ms var(--ease-out);
}
.plan-card:hover { border-color: rgba(255, 255, 255, 0.14); }
.plan-card--featured {
  background: var(--paper-1);
  border-color: rgba(10, 132, 255, 0.45);
  box-shadow: 0 0 0 1px rgba(10, 132, 255, 0.18), 0 1.5rem 3rem -1.25rem rgba(10, 132, 255, 0.32);
}
.plan-card--featured:hover { border-color: rgba(10, 132, 255, 0.70); }
.plan-card--current {
  background: var(--accent-tint);
  border-color: rgba(10, 132, 255, 0.30);
}
/* Enterprise contact-us card: no price, quieter, dashed edge */
.plan-card--contact { background: var(--paper-1); border-style: dashed; }
.plan-card__flag {
  position: absolute;
  top: 0;
  right: 1.5rem;
  transform: translateY(-50%);
  background: var(--accent);
  color: #fff;
  padding: 0.3125rem 0.6875rem;
  border-radius: var(--radius-full);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  box-shadow: 0 0.375rem 0.875rem rgba(10, 132, 255, 0.4);
}
.plan-card__top {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.plan-card__kicker {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-mid);
  font-variant-numeric: tabular-nums;
}
.plan-card__name {
  margin: 0;
  font-size: clamp(1.5rem, 2.2vw, 1.875rem);
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1.05;
  color: var(--ink);
}
.plan-card__price-block {
  border-top: 1px solid var(--rule);
  padding-top: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.plan-card__price {
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: 0.1em;
  line-height: 1;
  color: var(--ink);
}
.plan-card__currency {
  font-size: clamp(1.125rem, 1.6vw, 1.375rem);
  color: var(--ink-mid);
  font-weight: 500;
  letter-spacing: -0.01em;
}
.plan-card__amount {
  font-size: clamp(2.75rem, 5.5vw, 3.75rem);
  font-weight: 600;
  color: var(--ink);
  letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums;
}
/* A word rather than a figure ("Let's talk" on a contact tier), so it cannot carry
   the numeral's size. It MUST stay after .plan-card__amount: both are one class,
   so the cascade decides on order, and this rule sat 63 lines ABOVE its own base
   for long enough that every contact card in the site and the dashboard rendered
   "Let's talk" at the full 3.75rem numeral size. */
.plan-card__amount--sm { font-size: clamp(1.5rem, 2.2vw, 1.875rem); letter-spacing: -0.02em; }
.plan-card__per {
  font-size: var(--t-md);
  color: var(--ink-mid);
  font-weight: 500;
  letter-spacing: -0.005em;
}
.plan-card__billing {
  margin: 0;
  font-size: var(--t-xs);
  color: var(--ink-mid);
  font-weight: 400;
  font-variant-numeric: tabular-nums;
}
.plan-card__savings {
  margin: 0;
  font-size: var(--t-xs);
  color: var(--accent);
  font-weight: 500;
  line-height: 1.45;
}
.plan-card__savings strong {
  color: var(--accent);
  font-weight: 600;
}
.plan-card__savings:empty { display: none; }
.plan-card__cta {
  align-self: stretch;
  justify-content: center;
  margin-top: 0.25rem;
}
.plan-card__list {
  list-style: none;
  padding: 1rem 0 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  font-size: var(--t-sm);
  line-height: 1.5;
  color: var(--ink-soft);
  border-top: 1px solid var(--rule);
  font-weight: 400;
}
.plan-card__list li {
  position: relative;
  padding-left: calc(1rem + 0.625em);
}
/* Checkmark sits in the left padding, out of flow, so the bullet text is
   plain inline content (a bolded number flows inline instead of becoming a
   sibling flex item with a gap around it). Uses a CSS mask so the fill
   tracks --accent at runtime (an inline SVG data URI would hard-code the
   color and drift if the accent ever changes). */
.plan-card__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.15rem;
  width: 1rem;
  height: 1rem;
  background-color: var(--accent);
  -webkit-mask: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='3 8.5 6.5 12 13 4.5'/%3e%3c/svg%3e") no-repeat center / contain;
          mask: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='3 8.5 6.5 12 13 4.5'/%3e%3c/svg%3e") no-repeat center / contain;
}
.plan-card__list strong {
  color: var(--ink);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}


/* ==========================================================
   SITE NAV
   The outer chrome (`.app__header` + `.app__mark` + `.app__header-end`) is the
   canonical contract shared with admin / dashboard / app, defined in
   cdn/css/v1/components.css. This block defines the marketing-only pieces that
   sit INSIDE `.app__header-end`: the inline link cluster, the primary CTA pill,
   and the mobile hamburger panel.
========================================================== */

.site-nav {
  display: flex;
  align-items: center;
  gap: var(--s-5);
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--ink-mid);
}
.site-nav a {
  transition: color 160ms var(--ease-out);
}
.site-nav a:not(.site-nav__cta):hover { color: var(--ink); }
.site-nav a[aria-current="page"] { color: var(--ink); }

/* Primary CTA pill, an iOS-feel filled accent with a subtle glow. Mirrors the
   shared .btn--primary but inline-sized for the nav.

   `a.site-nav__cta` (element + class) ties the specificity of the canonical
   `.app__header-end a` rule in components.css so the cascade order picks this
   file and the white text wins on the blue pill. Without the element selector
   the class-only form loses on specificity and the pill turns grey. */
a.site-nav__cta {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.5rem 0.9375rem;
  background: var(--accent);
  color: #fff;
  border-radius: var(--radius-full);
  font-weight: 600;
  letter-spacing: -0.005em;
  box-shadow: 0 0 0 1px rgba(10, 132, 255, 0.40), 0 0.375rem 1rem rgba(10, 132, 255, 0.28);
  transition: background 160ms var(--ease-out), transform 80ms var(--ease-out);
}
a.site-nav__cta:hover { background: var(--accent-deep); color: #fff; }
a.site-nav__cta:active { transform: scale(0.97); }
.site-nav__cta-arrow {
  width: 0.75em;
  height: 0.75em;
  flex-shrink: 0;
}

.site-nav__toggle {
  display: none;
  align-items: center;
  justify-content: center;
  padding: 0.5rem 0.625rem;
  border: 1px solid var(--rule);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  border-radius: var(--radius-md);
  font: inherit;
  line-height: 1;
}
.site-nav__toggle:hover { background: var(--paper-1); }
.site-nav__toggle-icon { display: block; width: 1.125rem; height: 0.75rem; }
.site-nav__toggle-icon line { stroke: currentColor; stroke-width: 1.5; }
.site-nav__toggle[aria-expanded="true"] .site-nav__toggle-icon-bars { display: none; }
.site-nav__toggle-icon-x { display: none; }
.site-nav__toggle[aria-expanded="true"] .site-nav__toggle-icon-x { display: block; }

/* The nav gained two links (Product, Who it's for), so it collapses a little
   earlier than it used to or the cluster crowds the wordmark. */
@media (max-width: 68rem) {
  .site-nav__toggle { display: inline-flex; }
  .site-nav {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 40;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: var(--s-4) var(--gutter) var(--s-5);
    background: var(--paper-1);
    border-top: 1px solid var(--rule);
    border-bottom: 1px solid var(--rule);
  }
  .app__header[data-nav-open="true"] .site-nav { display: flex; }
  .site-nav a { padding: var(--s-3) 0; color: var(--ink); }
  .site-nav__cta { margin-top: var(--s-3); justify-content: center; }
}

/* ==========================================================
   SECTION RHYTHM
   Every marketing page is a stack of .hsec blocks sharing one content column
   and one left edge, so the eye never has to re-find the margin between
   sections. --home-max is the column; the page gutter is the shared token.
========================================================== */

:root {
  /* The marketing content column. Named --home-max because the home page
     introduced it and every page and stylesheet now references it. */
  --home-max: 78rem;

  /* ---------- RHYTHM ----------
     Named for the JOB each space does, not for a step on the --s-N scale, so
     the hierarchy is declared once here instead of being re-decided at every
     call site. Every margin, padding and gap on the marketing site comes from
     this block.

     The ratios are the point. Measured before this existed, the page ran
     72 / 32 / 24 / 16: section breaks only 2.25x the head gap, and a grid
     gutter NARROWER than the card padding beside it, which is what made a page
     of otherwise generous blocks read as crowded. Each level below drops hard
     against the one above, so proximity does the grouping and the reader can
     see the structure without reading it.

       section   80   HALF the break between two ideas: it is padding-block,
                      so two adjacent sections put ~160px between their content
                      and a tinted band still has its own internal air. Setting
                      this to the full intended break is the classic double-
                      padding bug, and it opened a 244px void under the hero
                      before this comment existed.
       head      46   a section's header block down to its content
       block     40   two blocks inside one section
       grid      24   between cards, always >= their own padding
       card      30   a card's interior
       group     12   lines within one tight group (set locally)             */
  --rhythm-section: clamp(3.25rem, 5.5vw, 5rem);
  --rhythm-head:    clamp(2.25rem, 3.2vw, 3.25rem);
  --rhythm-block:   clamp(1.75rem, 2.4vw, 2.5rem);
  --gap-grid:       clamp(1.25rem, 1.6vw, 1.5rem);
  --pad-card:       clamp(1.5rem, 2vw, 1.875rem);

  /* Line length. Measured rather than assumed: `ch` is the width of the "0"
     glyph, which in Geist is noticeably wider than its average character, so
     65ch rendered at roughly 78 characters and read long. These are tuned to
     land near 65 real characters for body copy and 58 for a lede, which takes
     a shorter line because it is set larger. */
  --measure:      56ch;
  --measure-lede: 50ch;
}

.hsec {
  padding-block: var(--rhythm-section);
  padding-inline: var(--gutter);
}
.hsec > * { max-width: var(--home-max); margin-inline: auto; }
.hsec--alt { background: var(--paper-1); }
/* A section that reads as one continuous idea with the one above it, so the
   pair does not get a double dose of vertical padding between them. */
.hsec--tight { padding-block-start: 0; }
/* The closing call to action carries more air than a content section, because
   it is the one place the page should feel like it has stopped. */
.hsec--cta { padding-block: clamp(4rem, 7vw, 6.5rem); }

/* Full-width like the grid below it, so header and content share a left edge.
   A max-width plus centering floats the header indented over its own cards. */
.hsec__head { display: flex; flex-direction: column; gap: var(--s-3); margin-bottom: var(--rhythm-head); }
/* Display type takes a SHORTER measure than body copy, not a longer one: a
   34ch heading at 34px ran most of the column and lost its shape.
   h1 is here because a page whose top heading IS a section head (pricing,
   contact) must not fall back to the UA's 2em bold. */
.hsec__head h1,
.hsec__head h2 { font-size: clamp(1.75rem, 3.6vw, var(--t-3xl)); max-width: 22ch; line-height: 1.12; letter-spacing: -0.025em; }
.hsec__lede { color: var(--ink-mid); font-size: clamp(1rem, 1.2vw, var(--t-md)); line-height: 1.6; max-width: var(--measure-lede); }

/* Keep the sticky header from hiding anchor targets. */
.hsec[id], .hero-live[id], section[id] { scroll-margin-top: 5rem; }

/* Closing call to action, centred. */
.hsec--cta { text-align: center; }
.cta-inner { display: flex; flex-direction: column; align-items: center; gap: var(--s-4); }
.cta-inner h2 { font-size: clamp(1.75rem, 4vw, var(--t-4xl)); }
.cta-inner .hsec__lede { text-align: center; max-width: 46ch; }

.hl-ctas { display: flex; gap: var(--s-3); flex-wrap: wrap; margin-top: var(--s-3); }
.hl-ctas--center { justify-content: center; }
.hl-ctas .btn { padding: 0.625rem 1.125rem; font-size: var(--t-base); }

/* ==========================================================
   SIGNAL VOCABULARY
   One dot, coloured from the shared --eg-* event-group tokens, so a signal
   named anywhere on the site carries the same colour it carries in the product,
   the landing pages, the digest email, and the map. The tokens are the single
   source; nothing here invents a colour.
========================================================== */

.hl-swatch {
  width: 0.5rem; height: 0.5rem; border-radius: var(--radius-full);
  display: inline-block; flex: none; background: var(--ink-mid);
  box-shadow: 0 0 0.375rem currentColor;
}
.hl-swatch[data-g="permits"]      { background: var(--eg-permits);      color: var(--eg-permits); }
.hl-swatch[data-g="demolitions"]  { background: var(--eg-demolitions);  color: var(--eg-demolitions); }
.hl-swatch[data-g="cofo"]         { background: var(--eg-cofo);         color: var(--eg-cofo); }
.hl-swatch[data-g="construction"] { background: var(--eg-construction); color: var(--eg-construction); }
.hl-swatch[data-g="sales"]        { background: var(--eg-sales);        color: var(--eg-sales); }
.hl-swatch[data-g="landuse"]      { background: var(--eg-landuse);      color: var(--eg-landuse); }
.hl-swatch[data-g="inspections"]  { background: var(--eg-inspections);  color: var(--eg-inspections); }
.hl-swatch[data-g="violations"]   { background: var(--eg-violations);   color: var(--eg-violations); }
.hl-swatch[data-g="tax"]          { background: var(--eg-tax);          color: var(--eg-tax); }
.hl-swatch[data-g="foreclosure"]  { background: var(--eg-foreclosure);  color: var(--eg-foreclosure); }
.hl-swatch[data-g="vacancy"]      { background: var(--eg-vacancy);      color: var(--eg-vacancy); }
.hl-swatch[data-g="condemnation"] { background: var(--eg-condemnation); color: var(--eg-condemnation); }
.hl-swatch[data-g="distress"]     { background: var(--eg-distress);     color: var(--eg-distress); }
/* The remainder chip, "Resolved & closed". It is one of the thirteen the product
   counts and colours, so it belongs here with the rest. */
.hl-swatch[data-g="other"]        { background: var(--eg-other);        color: var(--eg-other); }

/* The ring is a pseudo-element running transform + opacity, NOT an animated
   box-shadow. box-shadow cannot be composited, so the old version repainted
   every frame, forever, on every live dot on the page. Same look, off the main
   thread. `will-change` is deliberately absent: the compositor already promotes
   a transform/opacity animation, and declaring it permanently on an infinite
   animation just holds a layer for the life of the page. */
.hl-live-dot {
  position: relative;
  width: 0.5rem; height: 0.5rem; border-radius: var(--radius-full);
  background: var(--status-success); flex: none; display: inline-block;
}
.hl-live-dot::after {
  content: ""; position: absolute; inset: 0;
  border-radius: var(--radius-full);
  background: var(--status-success);
  animation: hl-pulse 2.6s var(--ease-out) infinite;
}
@keyframes hl-pulse {
  0%   { transform: scale(1);   opacity: 0.5; }
  70%  { transform: scale(3);   opacity: 0; }
  100% { transform: scale(3);   opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .hl-live-dot::after { animation: none; opacity: 0; } }

/* ==========================================================
   LIVE FIGURE BAND
   Every number in here is hydrated from GET /public/stats by stats.js; the
   markup carries the last known value as its no-JS fallback. Mono and tabular
   so a column of figures reads as evidence rather than as decoration.
========================================================== */

.stat-band { border-top: 1px solid var(--rule); padding-top: var(--rhythm-block); margin-top: var(--s-3); display: flex; flex-direction: column; gap: var(--s-4); }
.stat-band__lead { font-size: var(--t-2xs); letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-mid); }
.stat-band__row {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s-3) 2.75rem;
  font-size: var(--t-xs); color: var(--ink-mid);
  letter-spacing: 0.01em;
}
.stat-band__item { display: inline-flex; align-items: baseline; gap: 0.5rem; }
.stat-band__row b {
  color: var(--ink); font-weight: 600; font-size: clamp(1.375rem, 2.4vw, var(--t-2xl));
  letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
}

/* ==========================================================
   FAQ · native details/summary
   Shared, because the pricing page and the product page both answer questions
   and a second accordion would guarantee the two drift apart visually.
========================================================== */

.faq { max-width: 78ch; }
.faq__item { border-top: 1px solid var(--rule); }
.faq__item:last-child { border-bottom: 1px solid var(--rule); }
.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  cursor: pointer;
  list-style: none;
  padding: var(--s-5) 0;
  font-size: clamp(0.9375rem, 1.2vw, 1.0625rem);
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--ink);
  line-height: 1.35;
  transition: color 160ms var(--ease-out);
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q::marker { content: ""; }
.faq__q:hover { color: var(--accent); }

.faq__mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: var(--radius-full);
  background: var(--paper-1);
  border: 1px solid var(--rule);
  font-family: var(--font-mono);
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--ink-mid);
  transition: transform 220ms var(--ease-out), background 160ms, color 160ms;
  flex: 0 0 auto;
  line-height: 1;
}
.faq__item[open] .faq__mark {
  transform: rotate(45deg);
  background: var(--accent-tint);
  color: var(--accent);
}
.faq__q:hover .faq__mark { background: var(--paper-2); color: var(--ink); }

.faq__a {
  padding: 0 0 var(--s-6);
  font-size: var(--t-md);
  line-height: 1.6;
  color: var(--ink-soft);
  max-width: 68ch;
  font-weight: 400;
}
.faq__a p { margin: 0 0 var(--s-3); }
.faq__a p:last-child { margin-bottom: 0; }
.faq__a a { color: var(--accent); font-weight: 500; }
.faq__a a:hover { color: var(--accent-deep); }

/* ==========================================================
   PROSE PRIMITIVES · bullet lists, inline email, code chips
   Used by the contact and legal pages and by any long-form block.
========================================================== */

.bullets {
  margin: var(--s-3) 0;
  padding-left: var(--s-5);
  list-style: disc;
}
.bullets > li {
  margin-bottom: var(--s-2);
  color: var(--ink-soft);
  line-height: 1.55;
}
.bullets a,
.prose a {
  color: var(--accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}
.bullets a:hover,
.prose a:hover { color: var(--accent-deep); }

.email-link {
  font-family: var(--font-mono);
  color: var(--accent);
  margin-inline: 0.15em;
}
.email-link:hover { color: var(--accent-deep); }

.prose code,
.bullets code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  margin-inline: 0.15em;
  padding: 0.05em 0.3em;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 0.25rem;
  color: var(--ink);
}

.prose strong,
.bullets strong,
.prose em,
.bullets em { margin-inline: 0.04em; }

/* ==========================================================
   FOOTER · [popular regions] ── [brand + tagline | nav columns]
========================================================== */

.site-foot { border-top: 1px solid var(--rule); padding: var(--rhythm-block) var(--gutter) var(--s-7); }
.site-foot__metros { max-width: var(--home-max); margin-inline: auto; margin-bottom: var(--rhythm-block); }
.site-foot__metros-h { display: block; color: var(--ink-mid); font-size: var(--t-2xs); text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: var(--s-3); }
.site-foot__metros nav { display: flex; flex-wrap: wrap; gap: var(--s-3) var(--s-4); }
.site-foot__metros a { color: var(--ink-soft); font-size: var(--t-sm); }
.site-foot__metros a:hover { color: var(--ink); }

.site-foot__inner {
  max-width: var(--home-max); margin-inline: auto;
  border-top: 1px solid var(--rule); padding-top: var(--rhythm-block);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.7fr);
  gap: var(--s-6) var(--s-7);
  align-items: start;
}
@media (max-width: 51.25rem) { .site-foot__inner { grid-template-columns: 1fr; } }

.site-foot__brand { display: flex; flex-direction: column; gap: var(--s-2); }
.site-foot__fine { color: var(--ink-ghost); font-size: var(--t-xs); max-width: 34ch; }
.site-foot__copy { color: var(--ink-ghost); font-size: var(--t-xs); margin-top: var(--s-2); }

/* Columned footer nav. The flat link row it replaced made eight destinations
   read as one undifferentiated list; grouping them says what kind of thing each
   link is before the reader has to parse the label. */
.site-foot__cols { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-5); }
@media (max-width: 34rem) { .site-foot__cols { grid-template-columns: 1fr 1fr; } }
.site-foot__col { display: flex; flex-direction: column; gap: var(--s-2); }
.site-foot__col-h {
  font-size: var(--t-2xs); font-weight: 500; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--ink-ghost); margin-bottom: var(--s-1);
}
.site-foot__col a { color: var(--ink-mid); font-size: var(--t-sm); line-height: 1.5; }
.site-foot__col a:hover { color: var(--ink); }

/* Kept for the contact and legal pages, which carry the simple flat link row. */
.site-foot__links { display: flex; flex-wrap: wrap; gap: var(--s-3) var(--s-4); }
.site-foot__links a { color: var(--ink-mid); font-size: var(--t-sm); }
.site-foot__links a:hover { color: var(--ink); }

/* ==========================================================
   SCROLL REVEAL
   script.js adds .is-in as each block enters the viewport, and adds it to
   everything at once where IntersectionObserver is missing. The hidden state is
   gated on .js (set inline in <head>) so a no-JS reader gets the content
   immediately rather than a blank page.
========================================================== */

.js [data-reveal] { opacity: 0; transform: translateY(12px); transition: opacity var(--dur-3) var(--ease), transform var(--dur-3) var(--ease); }
.js [data-reveal].is-in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .js [data-reveal] { opacity: 1; transform: none; transition: none; }
}
