/**
 * Datacenter's stylesheet: tokens, base, layout, components, header, footer,
 * the app shell. Marketing and the app share these tokens (docs/style.md).
 *
 * Light and warm by default. `:root` holds light. Dark is written twice: once
 * for the reader who never touches the toggle (prefers-color-scheme), once
 * for the one who does (`data-theme`, stamped by public/static/theme.js).
 *
 * Area styles live in their own files, linked after this one by the layout:
 * site-marketing.css, app-analytics.css, app-links.css, app-billing.css.
 * Use the tokens here; add no new colors without a contrast note.
 */

/* ---------------- tokens ----------------
   Light and warm by default (DECISIONS.md, 2026-10-21): warm paper ground,
   raised white cards, warm neutral lines and ink, one blue accent, green only
   on the call to action, red only for "missed" numbers.

   Dark is written twice, like light used to be: once for the reader who
   never touches the toggle (prefers-color-scheme), once for the one who does
   (`data-theme`, stamped by public/static/theme.js). Ratios are WCAG 2.1. */

:root {
  --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9.5 12 15.5 18 9.5'/%3E%3C/svg%3E");
  /* Warm paper. Cards sit on it in white; tinted bands alternate with it. */
  --bg: #f8f6f1;
  /* Panels and app cards: a breath warmer than white, so they sit on paper
     without going grey. --text-faint 5.5:1, --text-dim 6.9:1 on it. */
  --bg-panel: #fbfaf7;
  /* The tint band (alternate marketing sections, inset wells): one step down
     from paper. --text-dim 6.1:1, --text-faint 4.9:1 on it. */
  --bg-tint: #f0ede6;
  --bg-raised: #ffffff;
  --bg-input: #ffffff;
  --bg-hover: #f2efe8;
  --bg-active: #e9e5dc;
  /* Hairlines: 1.20:1 on --bg, enough on a flat warm ground. */
  --line: #e4dfd5;
  /* 1.41:1 on --bg: borders that must read (inputs, selected cards). */
  --line-strong: #cdc6b8;
  --line-control: #dcd5c8;
  /* The edge of a field, a switch track or a checkbox: what tells a person a
     box is there to type in (WCAG 1.4.11). 3.6:1 on --bg-panel, 3.2:1 on --bg-tint. */
  --line-input: #8a8377;
  /* On --bg: --text 15.6:1, --text-dim 6.6:1, --text-faint 5.3:1.
     On --bg-panel: --text-dim 6.1:1, --text-faint 4.9:1. */
  --text: #1f1d1a;
  --text-dim: #5c574f;
  --text-faint: #6b665d;
  /* The current blue family, one step deeper so it holds on the tint:
     5.8:1 on --bg, 5.3:1 on --bg-panel. White ink on it 6.2:1. */
  --accent: #1559d0;
  --accent-ink: #ffffff;
  --accent-hover: #124cb3;
  --accent-soft: rgba(21, 89, 208, 0.1);
  /* The soft blue band ("pick what you run", the promise). --text 14.5:1,
     --accent 5.4:1, --text-dim 6.2:1 on it. */
  --brand-band: #e9eefb;
  --overlay: rgba(236, 232, 224, 0.8);
  --scrim: rgba(40, 34, 26, 0.38);
  /* The logo's one green (brand/datacenter/README.md): the wordmark's slash
     and the main button, flat, the same in both themes. 3.05:1 on --bg and
     5.54:1 on the dark --bg, so it is for shapes, never for small text. */
  --brand-green: #16a34a;
  /* The call to action: the brand green with ink text, 5.1:1 in both themes
     (white on it is 3.3:1, which fails). The hover keeps the fill and draws
     an ink ring (ui.css .btn-primary), since a second green would be a second
     brand color. */
  --cta: var(--brand-green);
  --cta-hover: var(--brand-green);
  --cta-ink: #1f1d1a;
  --danger: #c4392b;
  --danger-hover: #ad3124;
  --danger-ink: #ffffff;
  /* Danger text and "lost" numbers: 6.1:1 on --bg. */
  --danger-fg: #b3261e;
  /* Loss and gain, nowhere else: missed numbers red, found numbers blue. */
  --lost: var(--danger-fg);
  --found: var(--accent);
  /* Semantic tones: -fg is text and icons, -bg the soft fill, -line its border.
     Every -fg is AA for small text on its own -bg and on --bg-panel:
     success 5.8:1, warning 6.1:1, danger 7.2:1, info 5.4:1. */
  --success: #1c7a45;
  --success-fg: #1d6b3f;
  --success-bg: #e9f5ed;
  --success-line: #b5dcc3;
  --warning: #b07d1c;
  --warning-fg: #7a5514;
  --warning-bg: #fbf3e1;
  --warning-line: #e6d3a2;
  --danger-bg: #fce9e5;
  --danger-line: #e2aca3;
  --danger-text: #8c2b26;
  --info: var(--accent);
  --info-fg: var(--accent);
  --info-bg: #e9eefb;
  --info-line: color-mix(in srgb, var(--accent) 32%, transparent);
  /* Dot texture: warm grey at low strength. */
  --site-dot: color-mix(in srgb, #bdb4a3 34%, transparent);
  --shadow-card: 0 1px 2px rgba(60, 45, 20, 0.05), 0 8px 24px rgba(60, 45, 20, 0.06);
  --shadow-menu: 0 10px 24px rgba(60, 45, 20, 0.12);
  --shadow-panel: 0 1px 2px rgba(60, 45, 20, 0.06), 0 18px 40px rgba(60, 45, 20, 0.1);
  --shadow-sheet: 0 24px 60px rgba(60, 45, 20, 0.2);
  --header-bg: rgba(248, 246, 241, 0.88);
  --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235c574f' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9.5 12 15.5 18 9.5'/%3E%3C/svg%3E");

  --site-max: 1160px;
  --gutter: 32px;
  /* ---- the system (docs/style.md, Design system) ----
     Spacing: one 4px scale. Use these for gaps, padding and margins. */
  --space-0: 0;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-16: 64px;

  /* Type: one scale. The named steps are what pages use; the numbers are
     there for the rare in-between (a chart axis, a big number). */
  --fs-11: 11px;
  --fs-12: 12px;
  --fs-13: 13px;
  --fs-14: 14px;
  --fs-15: 15px;
  --fs-16: 16px;
  --fs-17: 17px;                 /* reading size: guides, and the setup steps an owner follows */
  --fs-18: 18px;
  --fs-20: 20px;
  --fs-24: 24px;
  --fs-28: 28px;
  --fs-32: 32px;
  --fs-40: 40px;
  --fs-48: 48px;
  --type-display: var(--fs-28);  /* the page title */
  --type-title: var(--fs-20);    /* a section or a dialog */
  --type-heading: var(--fs-16);  /* a card */
  --type-body: var(--fs-15);
  --type-ui: var(--fs-14);       /* controls, table cells */
  --type-small: var(--fs-13);    /* hints, meta lines */
  --type-caption: var(--fs-12);  /* pills, axis labels */
  --type-label: var(--fs-11);    /* mono eyebrows and table heads */
  --lh-tight: 1.2;
  --lh-snug: 1.35;
  --lh-body: 1.55;
  --weight-medium: 500;
  --weight-strong: 600;
  --weight-title: 650;
  --track-label: 0.08em;
  --track-title: -0.015em;

  /* Controls: three heights. 32 for dense rows and toolbars, 36 for most
     buttons and fields in the app, 44 for the one main action and for every
     control on a phone (a finger, below). */
  --ctl-h-sm: 32px;
  --ctl-h-md: 36px;
  --ctl-h-lg: 44px;

  /* Radii: one set. Controls md, cards lg, dialogs and sheets xl. */
  --r-xs: 4px;
  --r-sm: 6px;
  --r-md: 8px;
  --r-lg: 12px;
  --r-xl: 16px;
  --r-pill: 999px;
  --radius: var(--r-lg);
  --radius-sm: var(--r-md);
  --radius-lg: var(--r-xl);

  /* Elevation: flat cards (0), a resting lift (1), cards that float (2),
     menus and popovers (3), dialogs and sheets (4). */
  --elev-0: none;
  --elev-1: 0 1px 2px rgba(60, 45, 20, 0.06);
  --elev-2: var(--shadow-card);
  --elev-3: var(--shadow-menu);
  --elev-4: var(--shadow-sheet);

  /* Focus: one ring, the same on every control. The solid inner line (with the
     field's own accent border, 2px of accent at 5.3:1 or better) is what meets
     WCAG 1.4.11; the soft outer glow is the look. */
  --focus-ring: 0 0 0 1px var(--accent), 0 0 0 4px color-mix(in srgb, var(--accent) 22%, transparent);

  /* Motion: short and calm. All of it drops to none under reduced motion. */
  --dur-1: 90ms;   /* hover, press */
  --dur-2: 160ms;  /* menus, toggles */
  --dur-3: 240ms;  /* dialogs, toasts */
  --dur-4: 400ms;  /* count-up, page */
  --ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);

  --header-h: 62px;
  --sans: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  /* Marketing h1 and h2 only. System serifs, no web font: New York on Apple,
     Iowan Old Style and Charter where Safari's ui-serif is missing, Georgia on
     Windows. Charter's free cut (Bitstream Charter) covers Linux. */
  --serif: ui-serif, 'New York', 'Iowan Old Style', Charter, 'Bitstream Charter', Georgia, serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Button and field sizes. Marketing keeps its roomier 40 and 48; the app
     and the sign-in pages map these to the control heights (ui.css). */
  --btn-h-sm: var(--ctl-h-sm);
  --btn-h-md: 40px;
  --btn-h-lg: 48px;
  --btn-fs-sm: var(--fs-13);
  --btn-fs-md: var(--fs-15);
  --btn-fs-lg: 15.5px;
  --btn-px-sm: 11px;
  --btn-px-md: 16px;
  --btn-px-lg: 22px;
  --btn-radius: var(--r-md);
  --field-h: 40px;
  --field-fs: var(--fs-15);
  --field-px: 10px;
  --field-radius: var(--r-md);

  /* Old names, kept so nothing breaks; new code uses the tones above. */
  --chip-ok-fg: var(--success-fg);
  --chip-ok-line: var(--success-line);
  --chip-ok-bg: var(--success-bg);
  --chip-warn-fg: var(--warning-fg);
  --chip-warn-line: var(--warning-line);
  --chip-warn-bg: var(--warning-bg);
  --error-bg: var(--danger-bg);
  --error-line: var(--danger-line);
  --error-text: var(--danger-text);
  color-scheme: light;
}

/* Dark, warm-tinted so it is the same room with the lights down. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --bg: #161513;
    --bg-panel: #1c1b18;
    /* The dark tint band: a step up from --bg. --text-faint 5.2:1 on it. */
    --bg-tint: #1f1d1a;
    --bg-raised: #23211e;
    --bg-input: #191816;
    --bg-hover: #2b2925;
    --bg-active: #33302b;
    /* 1.41:1 on --bg. */
    --line: #34312b;
    --line-strong: #45413a;
    --line-control: #3c3832;
    /* 3.3:1 on --bg-raised, 3.7:1 on --bg-input, 3.0:1 on --bg-hover. */
    --line-input: #777166;
    /* On --bg: --text 15.1:1, --text-dim 7.5:1, --text-faint 5.7:1 (5.0:1 on --bg-raised). */
    --text: #ede9e2;
    --text-dim: #aba59b;
    --text-faint: #958f85;
    /* 7.3:1 on --bg, 6.5:1 on --bg-raised. Ink on it is near black (7.6:1). */
    --accent: #57a8ff;
    --accent-ink: #08121f;
    --accent-hover: #7bbcff;
    --accent-soft: rgba(87, 168, 255, 0.16);
    /* --text-dim 6.6:1 on it. */
    --brand-band: #182133;
    --overlay: rgba(20, 19, 17, 0.74);
    --scrim: rgba(6, 5, 4, 0.66);
    /* The same green and the same ink as light: 5.1:1, and 5.2:1 against
       --bg-panel, so the button leads. */
    --cta: var(--brand-green);
    --cta-hover: var(--brand-green);
    --cta-ink: #1f1d1a;
    --danger: #d94a45;
    --danger-hover: #e85d58;
    --danger-ink: #1a0605;
    /* 9.0:1 on --bg. */
    --danger-fg: #ff9a95;
    --success: #3fb06a;
    --success-fg: #8ee0a1;
    --success-bg: #16271c;
    --success-line: #2d5b3c;
    --warning: #d9a53f;
    --warning-fg: #e6c77a;
    --warning-bg: #262013;
    --warning-line: #5c4c24;
    --danger-bg: #3a1a18;
    --danger-line: #8c4340;
    --danger-text: #ffd9d6;
    --info-bg: #182133;
    --site-dot: color-mix(in srgb, #c9bca6 12%, transparent);
    --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.3), 0 8px 24px rgba(0, 0, 0, 0.25);
  --elev-1: 0 1px 2px rgba(0, 0, 0, 0.3);
    --elev-1: 0 1px 2px rgba(0, 0, 0, 0.3);
    --shadow-menu: 0 12px 28px rgba(0, 0, 0, 0.45);
    --shadow-panel: 0 1px 2px rgba(0, 0, 0, 0.35), 0 18px 40px rgba(0, 0, 0, 0.42);
    --shadow-sheet: 0 26px 64px rgba(0, 0, 0, 0.6);
    --header-bg: rgba(22, 21, 19, 0.88);
    --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23aba59b' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9.5 12 15.5 18 9.5'/%3E%3C/svg%3E");
    color-scheme: dark;
  }
}

:root[data-theme='dark'] {
  --bg: #161513;
  --bg-panel: #1c1b18;
  --bg-tint: #1f1d1a;
  --bg-raised: #23211e;
  --bg-input: #191816;
  --bg-hover: #2b2925;
  --bg-active: #33302b;
  --line: #34312b;
  --line-strong: #45413a;
  --line-control: #3c3832;
  --line-input: #777166;
  --text: #ede9e2;
  --text-dim: #aba59b;
  --text-faint: #958f85;
  --accent: #57a8ff;
  --accent-ink: #08121f;
  --accent-hover: #7bbcff;
  --accent-soft: rgba(87, 168, 255, 0.16);
  --brand-band: #182133;
  --overlay: rgba(20, 19, 17, 0.74);
  --scrim: rgba(6, 5, 4, 0.66);
  --cta: var(--brand-green);
  --cta-hover: var(--brand-green);
  --cta-ink: #1f1d1a;
  --danger: #d94a45;
  --danger-hover: #e85d58;
  --danger-ink: #1a0605;
  --danger-fg: #ff9a95;
  --success: #3fb06a;
  --success-fg: #8ee0a1;
  --success-bg: #16271c;
  --success-line: #2d5b3c;
  --warning: #d9a53f;
  --warning-fg: #e6c77a;
  --warning-bg: #262013;
  --warning-line: #5c4c24;
  --danger-bg: #3a1a18;
  --danger-line: #8c4340;
  --danger-text: #ffd9d6;
  --info-bg: #182133;
  --site-dot: color-mix(in srgb, #c9bca6 12%, transparent);
  --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.3), 0 8px 24px rgba(0, 0, 0, 0.25);
  --shadow-menu: 0 12px 28px rgba(0, 0, 0, 0.45);
  --shadow-panel: 0 1px 2px rgba(0, 0, 0, 0.35), 0 18px 40px rgba(0, 0, 0, 0.42);
  --shadow-sheet: 0 26px 64px rgba(0, 0, 0, 0.6);
  --header-bg: rgba(22, 21, 19, 0.88);
  --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23aba59b' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9.5 12 15.5 18 9.5'/%3E%3C/svg%3E");
  color-scheme: dark;
}

/* A finger, not a pointer: every control on a phone is at least 44 px. */
@media (max-width: 720px) {
  :root {
    --btn-h-sm: 44px;
    --btn-h-md: 46px;
    --btn-h-lg: 50px;
    --field-h: 46px;
    /* 16 px or iOS zooms the page when a field takes focus. */
    --field-fs: 16px;
    --gutter: 16px;
  }
}

@media (min-width: 721px) and (max-width: 1023px) {
  :root {
    --gutter: 24px;
  }
}

/* ---------------- base ---------------- */

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  /* The sticky header is 62px plus its 1px border. */
  scroll-padding-top: 63px;
  /* Room for the scrollbar is kept, so nothing shifts sideways as a page grows. */
  scrollbar-gutter: stable;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* A #link lands with a little room under the sticky header (scroll-padding-top
   above), not flush against it. Pages with a second sticky bar add its height. */
:target {
  scroll-margin-top: var(--space-4);
}

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

/* Sticky footer: the body is a column at least one screen tall and <main>
   takes what is left, so a short page pushes the footer to the bottom. */
body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--text);
  font: 15px/1.6 var(--sans);
  /* A word longer than its box (large text on a phone) breaks instead of
     running out of it. It changes nothing where words fit. */
  overflow-wrap: break-word;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a {
  color: var(--accent);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

/* Links drawn as controls (pills, buttons, chips, tiles) never underline: they change color or fill instead. */
a:is(.pill, .live-now, .hl-badge, .btn, .chip, .segment, .icon-button, .card, .nav-item):hover {
  text-decoration: none;
}

/* A link in running text is told apart by more than its color. */
main p a:not([class]),
main li a:not([class]),
main .prose a:not([class]) {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

p {
  margin: 0;
}

img,
svg {
  max-width: 100%;
}

code,
kbd,
pre {
  font-family: var(--mono);
  font-size: 0.92em;
}

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

::selection {
  background: var(--accent-soft);
}

[hidden] {
  display: none !important;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* The first stop for a keyboard: past the header, straight to the page. */
.skip-link {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 1000;
  padding: 8px 14px;
  border-radius: 8px;
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
  transform: translateY(-200%);
}

.skip-link:focus,
.skip-link:focus-visible {
  transform: none;
  outline: 2px solid var(--text);
  outline-offset: 2px;
  text-decoration: none;
}

main[tabindex='-1']:focus {
  outline: none;
}

/* ---------------- layout ---------------- */

.container {
  width: 100%;
  max-width: var(--site-max);
  margin: 0 auto;
  padding-inline: var(--gutter);
}

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

/* The last section takes the spare height, so its ground runs to the footer. */
.site-main > .section:last-child {
  flex: 1 0 auto;
}

.section {
  padding-block: 56px;
  border-top: 1px solid var(--line);
}

.section:first-child {
  border-top: none;
}

.section-tight {
  padding-block: 8px 72px;
  border-top: none;
}

/* A dotted panel: a 20px dot ground, faint enough that a paragraph over it
   still reads as print on paper. */
.section-alt,
.dots {
  background-color: var(--bg-panel);
  background-image: radial-gradient(var(--site-dot) 1px, transparent 1px);
  background-size: 20px 20px;
}

.band {
  background: var(--brand-band);
}

.section-head {
  max-width: 660px;
  margin-bottom: 30px;
}

.eyebrow,
.section-eyebrow {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 10px;
}

.section-title {
  font-size: 27px;
  font-weight: 700;
}

.section-sub {
  margin-top: 10px;
  color: var(--text-dim);
}

.lead {
  font-size: 17px;
  color: var(--text-dim);
  max-width: 34em;
}

.prose {
  max-width: 66ch;
}

.prose > * + * {
  margin-top: 1em;
}

.prose h2 {
  margin-top: 1.8em;
  font-size: 22px;
}

.prose h3 {
  margin-top: 1.5em;
  font-size: 17px;
}

.prose ul,
.prose ol {
  padding-left: 1.3em;
}

.muted {
  color: var(--text-dim);
}

.faint {
  color: var(--text-faint);
}

.mono {
  font-family: var(--mono);
}

.stack {
  display: grid;
  gap: var(--space-4);
}

.row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

.row-between {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.grid-2,
.grid-3 {
  display: grid;
  gap: 16px;
}

.grid-2 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.grid-3 {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

@media (max-width: 960px) {
  .grid-3 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 720px) {
  .grid-2,
  .grid-3 {
    grid-template-columns: minmax(0, 1fr);
  }
  .section {
    padding-block: 44px;
  }
  .section-title {
    font-size: 23px;
  }
}

/* ---------------- hero ---------------- */

.hero {
  padding-block: 56px 64px;
}

.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: 44px;
  align-items: center;
}

.hero h1 {
  font-size: 44px;
  font-weight: 700;
  letter-spacing: -0.025em;
}

.hero h1 .accent,
.accent-word {
  color: var(--accent);
}

.hero-lead {
  margin-top: 18px;
  font-size: 17px;
  color: var(--text-dim);
  max-width: 34em;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 26px;
}

.hero-facts {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
  margin: 26px 0 0;
  padding: 0;
  list-style: none;
  font-size: 13px;
  color: var(--text-faint);
}

@media (max-width: 960px) {
  .hero-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 32px;
  }
  .hero h1 {
    font-size: 36px;
  }
}

@media (max-width: 720px) {
  .hero {
    padding-block: 34px 44px;
  }
  .hero h1 {
    font-size: 30px;
  }
  .hero-lead {
    font-size: 15.5px;
  }
  .hero-actions .btn {
    flex: 1 1 160px;
  }
}


/* ---------------- wordmark ---------------- */

.wordmark {
  font-size: 17px;
  color: var(--text);
  user-select: none;
  text-decoration: none;
  white-space: nowrap;
}

.wordmark:hover {
  text-decoration: none;
}

/* The wordmark is the logo drawn inline (src/brand.ts), the letters inked from
   --text and the slash from --brand-green, so light and dark need no rules
   of their own. Sized from the link's font-size: the d is 1490 of the
   drawing's 2184 units, so a height of 1.466em makes the d exactly 1em tall
   and the font-size reads as the d height (brand/datacenter/README.md: 14px
   at the least). The box is centered on the middle of the x-height band, not
   on the ink, because the slash drops below the baseline: plain flex
   centering puts the letters, not the slash, on the row's center line. */
.wordmark-svg {
  display: block;
  height: 1.466em;
  width: auto;
  aspect-ratio: 10750 / 2184;
}
.wordmark-ink {
  fill: var(--text);
}
.wordmark-slash {
  fill: var(--brand-green);
}

/* ---------------- header ---------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--header-bg);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}

.site-header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: var(--header-h);
  padding-block: 8px;
}

.site-header .wordmark {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  margin-left: 2px;
  /* A 20px d: the wordmark runs 143px. */
  font-size: 20px;
  min-height: 44px;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: 2px;
  margin-left: 14px;
  flex: 1 1 auto;
  min-width: 0;
}

.nav-link {
  display: inline-flex;
  align-items: center;
  min-height: 38px;
  padding: 4px 11px;
  border-radius: 7px;
  color: var(--text-dim);
  font: inherit;
  font-weight: 500;
  text-decoration: none;
  background: transparent;
  border: none;
  cursor: pointer;
}

.nav-link:hover {
  color: var(--text);
  background: var(--bg-raised);
  text-decoration: none;
}

.nav-link[aria-current='page'] {
  color: var(--text);
}

/* A menu in the row: a <details> whose summary looks like the links beside
   it, with a chevron that turns over while its panel is open. */
.nav-group {
  position: relative;
}

.nav-group > summary {
  gap: 5px;
  list-style: none;
}

.nav-group > summary::-webkit-details-marker {
  display: none;
}

.nav-group[open] > summary {
  color: var(--text);
  background: var(--bg-raised);
}

.nav-chevron {
  flex: 0 0 auto;
  width: 12px;
  height: 12px;
  margin-top: 1px;
  opacity: 0.7;
  transition: transform 0.15s ease;
}

.nav-group[open] .nav-chevron {
  transform: rotate(180deg);
}

.nav-panel {
  position: absolute;
  top: calc(100% + 10px);
  left: 50%;
  z-index: 70;
  width: 340px;
  padding: 6px;
  transform: translateX(-50%);
  background: var(--bg-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-panel);
}

.nav-panel-list {
  display: grid;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 56px;
  padding: 8px 10px;
  border-radius: 9px;
  color: var(--text);
  text-decoration: none;
}

.nav-item:hover,
.nav-item:focus-visible {
  background: var(--bg-active);
  text-decoration: none;
}

.nav-item:focus-visible {
  outline-offset: -2px;
}

.nav-item-icon {
  display: grid;
  place-items: center;
  flex: 0 0 36px;
  width: 36px;
  height: 36px;
  border-radius: 9px;
  background: var(--accent-soft);
  color: var(--accent);
}

.nav-item-icon svg {
  width: 18px;
  height: 18px;
}

.nav-item-text {
  display: grid;
  gap: 1px;
  min-width: 0;
}

.nav-item-label {
  font-weight: 600;
  font-size: 14.5px;
  line-height: 1.3;
}

.nav-item-line {
  color: var(--text-dim);
  font-size: 13px;
  line-height: 1.35;
}

.nav-item[aria-current='page'] {
  background: var(--bg-active);
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 1 auto;
  min-width: 0;
}

/* With large text (a phone's text size, browser zoom) a button's words break
   onto two lines before the menu is pushed off the screen. At normal sizes
   the row fits, so nothing breaks. */
.header-actions .btn {
  flex-shrink: 1;
  min-width: 0;
}

.header-actions > :not(.btn) {
  flex: none;
}

/* The phone menu: a sheet under the header, behind a Menu button. Hidden on
   a desk, where the row carries the same links. */
.nav-menu {
  display: none;
  position: relative;
}

.nav-menu > summary {
  list-style: none;
}

.nav-menu > summary::-webkit-details-marker {
  display: none;
}

.menu-icon-close {
  display: none;
}

.nav-menu[open] .menu-icon-open {
  display: none;
}

.nav-menu[open] .menu-icon-close {
  display: inline;
}

.nav-sheet {
  position: absolute;
  top: calc(100% + 8px);
  right: -6px;
  z-index: 60;
  width: min(360px, calc(100vw - 24px));
  max-height: calc(100dvh - 84px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 6px 8px 8px;
  background: var(--bg-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sheet);
}

.nav-sheet-group + .nav-sheet-group {
  margin-top: 6px;
  padding-top: 4px;
  border-top: 1px solid var(--line);
}

.nav-sheet-heading {
  padding: 6px 10px 0;
  color: var(--text-faint);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  line-height: 16px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.nav-sheet-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 4px;
}

/* The call to action stays pinned to the bottom of the sheet while it scrolls. */
.nav-sheet-foot {
  position: sticky;
  bottom: -8px;
  z-index: 1;
  display: grid;
  gap: 6px;
  margin: 6px -8px -8px;
  padding: 10px 8px 12px;
  border-top: 1px solid var(--line);
  background: var(--bg-raised);
}

/* Sign in sits beside the call, always in reach at the foot of the menu. */
.nav-sheet-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
}

/* The account menu: avatar button, then a small list. */
.account-menu {
  position: relative;
}

.account-menu > summary {
  list-style: none;
}

.account-menu > summary::-webkit-details-marker {
  display: none;
}

.avatar-button {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 3px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 999px;
  cursor: pointer;
}

.avatar-button:hover,
.account-menu[open] > .avatar-button {
  border-color: var(--line-strong);
  background: var(--bg-raised);
}

.avatar {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  border: 1px solid var(--line-strong);
}

.menu-who {
  padding: 8px 10px 10px;
  margin-bottom: 5px;
  border-bottom: 1px solid var(--line);
}

.menu-who .who-email {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.menu-who .who-plan {
  margin-top: 2px;
  font-size: 12.5px;
  color: var(--text-dim);
}

/* Degrades in a set order as width shrinks: link padding, then Sign in, then
   the whole row gives way to the phone menu at 860px. */
@media (max-width: 1100px) {
  .site-nav {
    margin-left: 8px;
  }
  .site-nav .nav-link {
    padding: 4px 8px;
  }
}

/* The setup call button leaves the header first; the menu sheet keeps it. */
@media (max-width: 1180px) {
  .header-actions .hide-call {
    display: none;
  }
}

@media (max-width: 860px) {
  .site-nav {
    display: none;
  }
  .nav-menu {
    display: block;
  }
  .header-actions .hide-narrow {
    display: none;
  }
}

@media (max-width: 720px) {
  .site-header .wordmark {
    font-size: 19px;
  }
  .header-actions {
    gap: 2px;
  }
  .header-actions .hide-phone {
    display: none;
  }
}

@media (max-width: 380px) {
  .header-actions .btn {
    --btn-px: 12px;
  }
}

/* Under 360px (a small phone, or 400% zoom on a laptop) the row is tight:
   16px keeps the wordmark, Start tracking and the menu on one row at 320.
   The app header, with four 44px tools, and the site header when signed in
   (Dashboard, the account and the menu, as on a 404) take the wordmark down
   to 14px, the smallest the logo allows (brand/datacenter/README.md). */
@media (max-width: 359px) {
  .site-header .wordmark {
    font-size: 16px;
  }
  .app-header .wordmark,
  .site-header-inner:has(.account-menu) .wordmark {
    font-size: 14px;
  }
}

/* ---------------- footer ---------------- */

.site-footer {
  border-top: 1px solid var(--line);
  background: var(--bg-raised);
}

.footer-inner {
  padding-block: 36px 0;
}

.footer-grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  column-gap: 32px;
  row-gap: 28px;
  align-items: start;
}

.footer-brand {
  grid-column: span 2;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.site-footer .wordmark {
  display: inline-flex;
  align-items: center;
  /* An 18px d, a step under the header's. The drawing's box is 26.4px tall
     with air above the d and under the slash; the row stays 24px, as it was
     before the slash logo, and the 1.2px of air on each side overhangs it.
     The ink starts 1.6px inside the box, so nothing is cut. */
  height: 24px;
  font-size: 18px;
  align-self: flex-start;
}

.footer-tagline {
  margin-top: 10px;
  max-width: 30em;
  color: var(--text-dim);
  font-size: 13px;
  line-height: 1.5;
}

.footer-group {
  min-width: 0;
}

.footer-eyebrow {
  display: flex;
  align-items: center;
  height: 20px;
  margin: 0;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-faint);
}

/* Held open wider than a phone, where the summary is only the eyebrow. */
.footer-summary {
  display: block;
  list-style: none;
  cursor: default;
  pointer-events: none;
}

.footer-summary::-webkit-details-marker {
  display: none;
}

.footer-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 12px 0 0;
  padding: 0;
  list-style: none;
}

.footer-list a,
.footer-compare a {
  display: inline-block;
  padding: 1px 0;
  color: var(--text-dim);
  font-size: 13px;
  line-height: 1.4;
}

.footer-list a:hover,
.footer-compare a:hover,
.footer-meta a:hover {
  color: var(--text);
  text-decoration: none;
}

.footer-compare {
  margin-top: 28px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}

.footer-compare .footer-list {
  flex-direction: row;
  flex-wrap: wrap;
  gap: 6px 28px;
  margin-top: 10px;
}

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 4px 24px;
  margin-top: 18px;
  padding-block: 10px 14px;
  border-top: 1px solid var(--line);
  font-size: 12px;
  color: var(--text-faint);
}

.footer-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 18px;
}

.footer-meta a {
  color: var(--text-faint);
  font-size: 12px;
  white-space: nowrap;
}

/* The toggle keeps its box; pulling it out by its padding keeps the glyph on the edge. */
.footer-meta .icon-button {
  margin-right: -10px;
}

@media (max-width: 900px) {
  .footer-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
  .footer-brand {
    grid-column: 1 / -1;
  }
}

/* A phone: the brand, then the groups as rows between hairlines, each a
   full-width eyebrow with a chevron, closed until tapped. */
@media (max-width: 720px) {
  .footer-inner {
    padding-block: 28px 0;
  }
  .footer-grid {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 0;
  }
  .footer-brand {
    margin-bottom: 22px;
  }
  .footer-group {
    border-top: 1px solid var(--line);
  }
  .footer-compare {
    margin-top: 0;
    padding-top: 0;
  }
  .footer-summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    min-height: 48px;
    cursor: pointer;
    pointer-events: auto;
    -webkit-tap-highlight-color: transparent;
  }
  .footer-summary .footer-eyebrow {
    height: auto;
    font-size: 12px;
  }
  .footer-summary::after {
    content: '';
    flex: 0 0 auto;
    width: 14px;
    height: 14px;
    margin-right: 2px;
    background: var(--text-dim);
    -webkit-mask: var(--chevron) center / contain no-repeat;
    mask: var(--chevron) center / contain no-repeat;
    transition: transform 0.15s ease;
  }
  .footer-group[open] > .footer-summary::after {
    transform: rotate(180deg);
  }
  .footer-list,
  .footer-compare .footer-list {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0 16px;
    margin: 0 0 12px;
  }
  .footer-list a,
  .footer-compare a,
  .footer-meta a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    /* Large text: a long word breaks inside its column. */
    max-width: 100%;
    overflow-wrap: anywhere;
  }
  .footer-bottom {
    flex-direction: column-reverse;
    align-items: flex-start;
    margin-top: 0;
    padding-top: 6px;
  }
}

/* ---------------- 404 (src/content/notFound.ts) ---------------- */

.nf {
  width: 100%;
  max-width: 720px;
  margin-inline: auto;
  padding: 72px var(--gutter) 88px;
}

.nf-head h1 {
  margin-top: 6px;
  font-size: clamp(30px, 6vw, 44px);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
}

.nf-sub {
  margin-top: 10px;
  font-size: 17px;
  color: var(--text-dim);
}

.nf-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 24px;
}

.nf-places {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin: 40px 0 0;
  padding: 0;
  list-style: none;
}

.nf-place {
  display: grid;
  gap: 4px;
  height: 100%;
  padding: 16px 18px;
  color: var(--text);
  text-decoration: none;
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  transition: border-color 0.15s ease, background-color 0.15s ease;
}

.nf-place:hover {
  text-decoration: none;
  background: var(--bg-hover);
  border-color: var(--line-strong);
}

.nf-place:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.nf-title {
  font-weight: 600;
}

.nf-line {
  font-size: 14px;
  color: var(--text-dim);
}

@media (max-width: 520px) {
  .nf {
    padding-block: 48px 64px;
  }

  .nf-places {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (prefers-reduced-motion: reduce) {
  .nf-place {
    transition: none;
  }
}

/* ---------------- auth pages ---------------- */

.auth {
  display: grid;
  /* One column no wider than the screen, whatever the card holds (large text). */
  grid-template-columns: minmax(0, 1fr);
  place-items: start center;
  padding-block: 56px 72px;
  /* The card sits in no container, so it needs the gutter itself: 16px on phones, not edge to edge. */
  padding-inline: var(--gutter);
}

.auth-card {
  width: 100%;
  max-width: 420px;
  padding: 28px;
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-panel);
}

.auth-card h1 {
  font-size: 24px;
  font-weight: 700;
}

.auth-card .auth-sub {
  margin-top: 6px;
  color: var(--text-dim);
}

.auth-card .form {
  margin-top: 22px;
}

/* Scoped to the card so ui.css's later .form-actions (4px) cannot pull the buttons up against the line above. */
.auth-card .auth-actions {
  margin-top: 22px;
}

.auth-social {
  display: grid;
  gap: 10px;
  margin-top: 22px;
}

.auth-social svg {
  flex: none;
}

.auth-or {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 20px;
  font-size: 13px;
  color: var(--text-dim);
}

.auth-or::before,
.auth-or::after {
  content: '';
  flex: 1;
  border-top: 1px solid var(--line);
}

.auth-or + .form {
  margin-top: 16px;
}

.auth-alt {
  margin-top: 18px;
  font-size: 14px;
  color: var(--text-dim);
  text-align: center;
}
/* Each link wraps whole ("Forgot your password?" never splits across lines).
   Where the two do not fit on one line they stack, and the dot goes. */
.auth-alt a {
  white-space: nowrap;
}
.auth-dot {
  margin-inline: 6px;
  color: var(--text-faint);
}

@media (max-width: 480px) {
  .auth-alt:has(.auth-dot) {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    gap: var(--space-2);
  }
  /* Stacked, each link has its own line; only large text ever breaks one. */
  .auth-alt:has(.auth-dot) a {
    white-space: normal;
  }
  .auth-alt .auth-dot {
    display: none;
  }
}

@media (max-width: 480px) {
  .auth {
    padding-block: 24px 48px;
  }
  .auth-card {
    padding: 22px 18px;
  }
}

/* ---------------- app shell ---------------- */

.app-header .container {
  max-width: 1400px;
}

.app-notice {
  margin-bottom: 20px;
}

.app-notice.notice,
.app-notice > .notice {
  align-items: center;
}

.notice-action {
  margin: 0 0 0 auto;
}

@media (max-width: 480px) {
  .app-notice,
  .app-notice.notice,
  .app-notice > .notice {
    flex-direction: column;
    align-items: flex-start;
  }
  /* A notice's action drops under its words on a phone, its left edge on
     theirs (the icon keeps its own column), so the words keep the width.
     A notice with no icon (the confirm-your-email banner in src/layout.ts,
     the View as banner in src/viewAs.ts) has one column: with two, its words took the first and
     pushed the action off the right edge of the page. */
  .notice:has(> .notice-action) {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
  }
  .notice:has(> .notice-action):not(:has(> .notice-icon)) {
    grid-template-columns: minmax(0, 1fr);
  }
  .notice:has(> .notice-action) > .notice-action {
    grid-column: -2;
    justify-self: start;
    margin: 0;
  }
}

.app-frame {
  display: grid;
  grid-template-columns: 220px minmax(0, 1fr);
  flex: 1 0 auto;
  width: 100%;
  max-width: 1400px;
  margin: 0 auto;
  /* The sidebar's rule, drawn by the frame so it runs the full page height. */
  background: linear-gradient(var(--line), var(--line)) 219px 0 / 1px 100% no-repeat;
}

.app-nav {
  position: sticky;
  top: calc(var(--header-h) + 1px);
  align-self: start;
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* Only as tall as its links, never a full screen: a full-screen sidebar
     made every frame a screen tall, so the footer below it gave even a short
     page 56px to scroll, and the page and sidebar slid up under the header.
     In a window too short for its links it scrolls by itself. */
  max-height: calc(100dvh - var(--header-h) - 1px);
  overflow-y: auto;
  padding: 20px 12px 20px var(--gutter);
}

.app-nav-link {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 40px;
  padding: 6px 10px;
  border-radius: 8px;
  color: var(--text-dim);
  font-weight: 500;
}

.app-nav-link svg {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  color: var(--text-faint);
}

.app-nav-link:hover {
  color: var(--text);
  background: var(--bg-raised);
  text-decoration: none;
}

.app-nav-link[aria-current='page'] {
  color: var(--text);
  background: var(--bg-active);
}

.app-nav-link[aria-current='page'] svg {
  color: var(--accent);
}

.app-nav-sep {
  height: 1px;
  margin: 8px 10px;
  background: var(--line);
}

.app-main {
  min-width: 0;
  padding: 28px var(--gutter) 64px;
}

/* The space from a tab row (appTabs) to the page under it, as on a site's tabs. */
.app-tabbed,
.set-page {
  margin-top: 24px;
}

/* ---- Settings (src/routes/account.ts): the full frame width, like a site's
   pages. Cards sit two to a row and share the row's height; a card left
   alone on its row takes the whole width. One column under 960px. */
.set-notices {
  display: grid;
  gap: 12px;
  margin-bottom: 16px;
}

.set-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}

.set-grid > :last-child:nth-child(odd) {
  grid-column: 1 / -1;
}

/* Delete account (src/routes/accountDelete.ts): what goes, one line each. */
.del-list {
  display: grid;
  gap: 10px;
  margin: 0;
  padding-left: 20px;
  line-height: 1.5;
}

/* A stretched card keeps its own rhythm at the top instead of spreading out. */
.set-grid > .card {
  align-content: start;
}

/* Long lines stay readable on a whole-width card. */
.set-grid .muted,
.set-grid .field-hint {
  max-width: 72ch;
}

.set-line {
  gap: 12px;
}

/* ---- Settings, Partner (src/routes/partners.ts) and /partners: an uploaded
   agency logo, square and contained, the same on both. */
.pt-logo {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  object-fit: contain;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

/* The program card sits beside the tall form: it keeps its own height. */
.set-grid > .pt-about-card {
  align-self: start;
}

.pt-stats {
  display: grid;
  /* Three across on a wide card, wrapping on a phone so "$1,234.00" never squeezes. */
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: var(--space-4);
}

.pt-checks {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2) var(--space-4);
  margin-top: var(--space-1);
}

.pt-serves-field {
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}

.pt-logo-now,
.pt-mini {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-2);
}

.pt-mini {
  margin-top: 0;
}

@media (max-width: 520px) {
  .pt-checks {
    grid-template-columns: minmax(0, 1fr);
  }
}

.set-value {
  overflow-wrap: anywhere;
}

/* ---- Settings, Team (src/routes/team.ts): invite, then the people, one row
   each: picture, who, role, actions. On a phone the role and actions drop
   under the name, in its column. */
.tm-invite-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(130px, 168px);
  align-items: start;
  gap: var(--space-3);
}

.tm-invite-row .field {
  margin: 0;
}

.tm-roles {
  display: grid;
  gap: var(--space-1);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--type-small);
  line-height: 1.45;
  color: var(--text-dim);
}

.tm-roles strong {
  color: var(--text);
  font-weight: var(--weight-strong);
}

.tm-sites summary {
  display: inline-flex;
  align-items: center;
  min-height: var(--ctl-h-sm);
  font-size: var(--type-ui);
  font-weight: var(--weight-strong);
  color: var(--accent);
  cursor: pointer;
}

.tm-sites summary {
  list-style: none;
}

.tm-sites summary::-webkit-details-marker {
  display: none;
}

.tm-sites summary:hover {
  color: var(--accent-hover);
}

.tm-sites-pick {
  display: grid;
  gap: var(--space-2);
  max-height: 240px;
  margin: var(--space-2) 0 var(--space-2);
  padding: var(--space-3);
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg-panel);
}

/* Invite and People each take the whole row: a list of people reads best wide. */
.set-grid > .tm-invite,
.set-grid > .tm-people {
  grid-column: 1 / -1;
}

.tm-invite-form {
  max-width: 640px;
}

.tm-list {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}

.tm-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) 0;
  border-top: 1px solid var(--line);
}

.tm-row:first-child {
  border-top: 0;
  padding-top: var(--space-1);
}

.tm-avatar {
  width: 36px;
  height: 36px;
}

.tm-name {
  font-weight: var(--weight-strong);
  overflow-wrap: anywhere;
}

.tm-sub {
  font-size: var(--type-small);
  color: var(--text-faint);
  overflow-wrap: anywhere;
}

.tm-end,
.tm-status,
.tm-actions,
.tm-role {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.tm-actions {
  gap: var(--space-1);
}

.tm-role-select {
  width: auto;
  min-width: 112px;
  height: var(--ctl-h-sm);
  padding-block: 0;
  font-size: var(--type-ui);
}

/* The role saves as soon as it changes (site.js data-autosubmit); without script the button stays. */
.tm-role.is-auto .tm-role-save {
  display: none;
}

.tm-join-hint {
  margin-top: var(--space-3);
  text-align: center;
}

/* "Ask Dana to upgrade" on a plan gate, for a team member: words, not a button (src/paywall.ts). */
.notice-ask {
  font-size: var(--type-small);
  font-weight: var(--weight-strong);
  color: var(--text-dim);
  white-space: nowrap;
}

@media (max-width: 560px) {
  .tm-invite-row {
    grid-template-columns: minmax(0, 1fr);
  }
  .tm-row {
    grid-template-columns: auto minmax(0, 1fr);
    row-gap: var(--space-2);
  }
  .tm-end {
    grid-column: 2;
    flex-wrap: wrap;
  }
}

/* In a team, whose account this is, beside the wordmark (src/layout.ts teamChip). */
.team-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  max-width: 280px;
  min-height: var(--ctl-h-sm);
  margin-left: var(--space-3);
  margin-right: auto;
  padding: 0 var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--bg-raised);
  color: var(--text-dim);
  font-size: var(--type-small);
  font-weight: var(--weight-strong);
  text-decoration: none;
  transition: background var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out);
}

.team-chip:hover {
  background: var(--bg-hover);
  color: var(--text);
}

.team-chip svg {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
}

.team-chip-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A phone's header has no room for it: the account menu names the account and the role. */
@media (max-width: 560px) {
  .team-chip {
    display: none;
  }
}

/* The account menu's switcher (src/layout.ts switcherRows): the account you are in, ticked. */
.menu-row[aria-current='true'] {
  font-weight: var(--weight-strong);
}

.menu-row-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.menu-row .menu-row-check {
  margin-left: auto;
  color: var(--accent);
}

@media (max-width: 960px) {
  .set-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

.app-footer {
  padding: 18px var(--gutter);
  border-top: 1px solid var(--line);
  font-size: 12px;
  color: var(--text-faint);
}

.app-footer .footer-meta {
  justify-content: space-between;
}

/* On a phone the sidebar becomes a row of tabs under the header. */
@media (max-width: 860px) {
  .app-frame {
    grid-template-columns: minmax(0, 1fr);
    /* Rows keep their own height; spare height stays under the page. */
    align-content: start;
    background: none;
  }
  .app-nav {
    position: sticky;
    top: calc(var(--header-h) + 1px);
    z-index: 40;
    flex-direction: row;
    height: auto;
    gap: 4px;
    padding: 6px var(--gutter);
    overflow-x: auto;
    background: var(--header-bg);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--line);
    scrollbar-width: none;
  }
  .app-nav::-webkit-scrollbar {
    display: none;
  }
  .app-nav-link {
    flex: 0 0 auto;
    min-height: 44px;
  }
  .app-nav-sep {
    display: none;
  }
  .app-main {
    padding-top: 20px;
  }
}

/* As a row of tabs the sections are words only: all seven fit a tablet,
   and four fit a 390px phone, the rest a swipe away under the fade. */
@media (max-width: 860px) {
  .app-nav-link svg {
    display: none;
  }
  .app-nav-link {
    padding-inline: 12px;
  }
}

/* ---------------- sites list ---------------- */

.site-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 14px;
}

/* A site card is a .card (ui.css): the dashboard's chrome. This lays it out. */
.site-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  transition: border-color var(--dur-1) ease;
}

.site-card:hover {
  border-color: var(--line-strong);
}

.site-card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-2) 10px;
  min-width: 0;
}

.site-card-name {
  font-size: var(--type-heading);
  font-weight: var(--weight-title);
  color: var(--text);
  overflow-wrap: anywhere;
}

.site-card-name:hover {
  color: var(--accent);
  text-decoration: none;
}

.site-card-domain {
  margin-top: 2px;
  font-family: var(--mono);
  font-size: var(--type-caption);
  color: var(--text-dim);
  overflow-wrap: anywhere;
}

.site-card-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  gap: var(--space-2);
  margin-top: auto;
  font-size: var(--type-small);
  color: var(--text-faint);
}

.favicon-dot {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  color: var(--accent);
  background: var(--accent-soft);
}

.site-card-id {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1 1 220px;
  min-width: 0;
}

.min-w-0 {
  min-width: 0;
}

.narrow {
  max-width: 680px;
}

.site-settings {
  margin-top: 24px;
}

/* A site's Goals, Integrations, Share and Settings tabs use the whole frame,
   like its dashboard: on a wide screen the cards flow into two columns, each
   card under the one above it, so short cards leave no holes. Anything that
   is not a card (a notice, a back link) spans both. A connector's own page
   stays one column. */
@media (min-width: 1100px) {
  .stack.site-settings:not(.cn-page) {
    display: block;
    max-width: none;
    column-count: 2;
    column-gap: var(--space-4);
  }
  .stack.site-settings:not(.cn-page) > * {
    break-inside: avoid;
    margin-bottom: var(--space-4);
  }
  .stack.site-settings:not(.cn-page) > :not(.card) {
    column-span: all;
  }
}

.archived-table {
  margin-top: var(--space-3);
}

/* Cloudflare Turnstile (src/turnstile.ts): the widget sizes itself; this only
   spaces it and keeps the reserved height steady while it loads. */
.turnstile {
  margin-block: 4px 12px;
  min-height: 65px;
}

/* No lone words. Headings split their lines evenly, so "story." never drops
   to a line of its own; body copy avoids a one-word last line. Browsers
   without text-wrap simply wrap as before. Lines a heading forces itself
   (.hero-line, white-space: nowrap) are unaffected. */
h1,
h2,
h3,
h4,
.section-title,
.page-title {
  text-wrap: balance;
}

p,
li,
dd,
figcaption {
  text-wrap: pretty;
}

/* The paper icon at the top of sign up, sign in and password pages. On the
   light card the paper tile is the card's own color, so a hairline on the
   icon's corner (22.5 percent) shows where the tile ends; on dark the tile
   stands out by itself and the line is the dark hairline. */
.auth-mark,
.offline-mark {
  display: block;
  width: 48px;
  height: 48px;
  margin-bottom: 16px;
  border-radius: 22.5%;
  box-shadow: 0 0 0 1px var(--line);
}
.offline-mark {
  width: 56px;
  height: 56px;
}

/* ---------------- two-step sign-in (src/routes/twoFactor.ts) ---------------- */

/* The lock after "Admin" in the menus while Admin needs two-step sign-in. */
.nav-lock {
  display: inline-flex;
  margin-left: auto;
  color: var(--text-faint);
}
.nav-lock svg,
.app-nav-link .nav-lock svg {
  width: 14px;
  height: 14px;
}

.tf-head {
  gap: 12px;
}

/* Setup: two numbered steps in one card, a hairline between them. */
.tf-setup {
  display: grid;
  gap: 0;
  padding: 0;
  overflow: hidden;
}
.tf-step {
  display: grid;
  gap: 8px;
  padding: 24px;
}
.tf-step + .tf-step {
  border-top: 1px solid var(--line);
}
.tf-step-label {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
}
.tf-qr-row {
  display: flex;
  align-items: center;
  gap: 24px;
  margin-top: 10px;
}
/* The code stays dark on white in both themes: phone cameras need the contrast. */
.tf-qr {
  flex: none;
  padding: 8px;
  line-height: 0;
  background: #ffffff;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
}
.tf-qr svg {
  display: block;
  width: 168px;
  height: 168px;
}
.tf-key {
  display: grid;
  justify-items: start;
  gap: 8px;
  min-width: 0;
}
.tf-key-text {
  display: block;
  max-width: 100%;
  padding: 10px 12px;
  font-family: var(--mono);
  font-size: 14px;
  letter-spacing: 0.06em;
  line-height: 1.5;
  word-break: break-all;
  color: var(--text);
  background: var(--bg-input);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.tf-step .field {
  max-width: 220px;
}
/* Six digits read best big, spaced and centered. */
input.field-input[autocomplete='one-time-code'][inputmode='numeric'] {
  font-family: var(--mono);
  font-size: 20px;
  letter-spacing: 0.18em;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.auth-card input.field-input[autocomplete='one-time-code'][inputmode='numeric'] {
  font-size: 22px;
}

.tf-manage .field {
  max-width: 320px;
}

/* Recovery codes: two columns of mono codes in an inset well. */
.tf-codes {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px 24px;
  margin: 0;
  padding: 18px 22px;
  list-style: none;
  counter-reset: tf;
  font-family: var(--mono);
  font-size: 15px;
  letter-spacing: 0.06em;
  font-variant-numeric: tabular-nums;
  background: var(--bg-tint);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.tf-codes li {
  counter-increment: tf;
  white-space: nowrap;
}
.tf-codes li::before {
  content: counter(tf, decimal-leading-zero);
  display: inline-block;
  width: 2.4em;
  font-size: 11px;
  color: var(--text-faint);
}

/* The Admin gate: one centered card, one action. */
.tf-gate {
  display: grid;
  justify-items: center;
  gap: 12px;
  max-width: 520px;
  margin: 48px auto 0;
  padding: 36px 32px;
  text-align: center;
  background: var(--bg-raised);
  box-shadow: var(--shadow-panel);
}
.tf-gate-icon {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  margin-bottom: 4px;
  color: var(--accent);
  background: var(--accent-soft);
  border-radius: 14px;
}
.tf-gate-icon svg {
  width: 26px;
  height: 26px;
}
.tf-gate-title {
  font-size: 22px;
  font-weight: 650;
  letter-spacing: -0.01em;
  line-height: 1.3;
}
.tf-gate .btn {
  margin-top: 8px;
}
.tf-gate-note {
  font-size: 13.5px;
  color: var(--text-faint);
}

@media (max-width: 720px) {
  .tf-qr-row {
    flex-direction: column;
    align-items: stretch;
  }
  .tf-qr {
    align-self: center;
  }
  .tf-step {
    padding: 20px 18px;
  }
  .tf-step .field {
    max-width: none;
  }
  .tf-gate {
    margin-top: 16px;
    padding: 28px 20px;
  }
}
@media (max-width: 400px) {
  .tf-codes {
    gap: 8px 12px;
    padding: 14px 14px;
    font-size: 14px;
  }
  .tf-codes li::before {
    width: 2em;
  }
}

/* ---------------- home-screen app (public/static/pwa.js, src/routes/pwa.ts) ---------------- */

/* The add-to-home-screen hint: once, on a phone, above the home indicator. */
.a2hs {
  position: fixed;
  z-index: 90;
  right: max(12px, env(safe-area-inset-right));
  bottom: max(12px, env(safe-area-inset-bottom));
  left: max(12px, env(safe-area-inset-left));
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr);
  gap: 4px 12px;
  align-items: center;
  max-width: 480px;
  margin: 0 auto;
  padding: 14px 16px;
  background: var(--bg-raised);
  color: var(--text);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sheet);
  animation: a2hs-in 0.24s ease-out;
}

/* Out of the way while the Assistant is open: its field and Send button sit at the bottom too. */
body.as-on .a2hs {
  display: none;
}

@keyframes a2hs-in {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
}

.a2hs-icon {
  /* The icon's own corner, 22.5 percent of 40px, with the auth mark's hairline. */
  border-radius: 9px;
  box-shadow: 0 0 0 1px var(--line);
}

.a2hs-title {
  margin: 0;
  font-weight: 600;
}

.a2hs-line {
  margin: 2px 0 0;
  color: var(--text-dim);
  font-size: 14px;
  line-height: 1.45;
}

.a2hs-actions {
  display: flex;
  grid-column: 1 / -1;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 8px;
}

@media (prefers-reduced-motion: reduce) {
  .a2hs {
    animation: none;
  }
}

/* The offline page: one calm card, centered, inside the safe area. */
.offline-body {
  min-height: 100vh;
  min-height: 100dvh;
}

.offline {
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 12px;
  min-height: 100vh;
  min-height: 100dvh;
  padding: max(24px, env(safe-area-inset-top)) max(16px, env(safe-area-inset-right)) max(24px, env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
  text-align: center;
}

.offline h1 {
  margin: 8px 0 0;
  font-size: 24px;
}

.offline p {
  max-width: 30ch;
  margin: 0 0 8px;
  color: var(--text-dim);
}

/* ---------------- phone polish: the main app pages ----------------
   Sites, the dashboard in view mode, Messages and Reports on a touch screen.
   Every control is at least 44px to tap (Apple's guidelines, WCAG 2.5.5).
   Where a bigger box would change the look (pills, a tile's menu, tab chips),
   an invisible ::after grows the tap area instead. `.app` (and `.has-dash`, the
   dashboard on /demo and share pages) outranks the area
   files that load after this one. Phone width counts too: a phone is always touch. */
@media (pointer: coarse), (max-width: 720px) {
  :is(.app, .has-dash) .field-check {
    min-height: 44px;
  }
  :is(.app, .has-dash) .as-open,
  :is(.app, .has-dash) .chip,
  :is(.app, .has-dash) .dash-board-btn,
  :is(.app, .has-dash) .dash-live-btn {
    min-height: 44px;
  }
  :is(.app, .has-dash) .dash-tool:not(.dw-menu-btn) {
    width: 44px;
    height: 44px;
  }
  :is(.app, .has-dash) .dash-row {
    min-height: 44px;
  }
  :is(.app, .has-dash) .site-card-foot > a:not(.btn) {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
  :is(.app, .has-dash) .site-card-name,
  :is(.app, .has-dash) .scs-action,
  :is(.app, .has-dash) .dash-sub .pill,
  :is(.app, .has-dash) .site-card-pills a.pill,
  :is(.app, .has-dash) .dw-menu-btn,
  :is(.app, .has-dash) .dw-tabs button {
    position: relative;
  }
  :is(.app, .has-dash) .site-card-name::after,
  :is(.app, .has-dash) .scs-action::after,
  :is(.app, .has-dash) .dash-sub .pill::after,
  :is(.app, .has-dash) .site-card-pills a.pill::after,
  :is(.app, .has-dash) .dw-menu-btn::after,
  :is(.app, .has-dash) .dw-tabs button::after {
    content: '';
    position: absolute;
    inset: -12px -4px;
  }
  :is(.app, .has-dash) .dw-menu-btn::after {
    inset: -7px;
  }
  :is(.app, .has-dash) .dw-tabs button::after {
    inset: -7px -2px;
  }
  :is(.app, .has-dash) .dw-tabs button {
    min-width: 44px;
  }
}

/* Clear of the notch and the home indicator, in Safari and the Home Screen app
   (the viewport is viewport-fit=cover). The gutter grows only where an inset is wider. */
.app {
  --gutter: max(32px, env(safe-area-inset-left), env(safe-area-inset-right));
}
@media (max-width: 720px) {
  .app {
    --gutter: max(16px, env(safe-area-inset-left), env(safe-area-inset-right));
  }
}
@media (min-width: 721px) and (max-width: 1023px) {
  .app {
    --gutter: max(24px, env(safe-area-inset-left), env(safe-area-inset-right));
  }
}
.app .app-footer {
  padding-bottom: max(18px, env(safe-area-inset-bottom));
}

/* Inside an app's built-in browser the other sign-ins follow the email form (src/routes/social.ts socialAfter). */
.auth-social-after {
  margin-top: 16px;
}

.auth-social-after .field-hint {
  margin: 0;
  text-align: center;
}
