/*
 * The public site — homepage, pricing, contact, getting started, and the legal
 * pages. One stylesheet, no build step and no CDN: every public page is served
 * logged-out to somebody deciding whether to trust us, so it must render from
 * this origin alone.
 *
 * It lives under /static/ rather than in a <style> block so the service worker
 * (which caches /static/ and nothing else) can keep it, and so a legal page
 * added later inherits the look without copying a stylesheet.
 *
 * THE LOOK IS ADAPTED FROM THE AXION FLEET LANDING PAGE, which is the owner's
 * own and the reference he pointed at. What was taken: the dark hero with a
 * masked grid and blurred glows, the uppercase eyebrow tag, the gradient rail
 * across the top of a card, the tinted icon tile, the tilted product panel with
 * cards floating over it, and its 120px section rhythm. What was NOT taken: the
 * Inter webfont (see the font stack below), the purple/cyan/green accent
 * spread — three assistants read better in one accent with three tints than in
 * three unrelated hues — and the AOS scroll-reveal library, which is 14 KB of
 * third-party JavaScript to make text appear that is already there.
 *
 * EVERY CLASS THE TEMPLATES USE IS STILL HERE. The five public pages share one
 * small vocabulary — .hero .pill .btn .ghost .grid .card .plans .plan .panel
 * .steps — so the restyle lands on all of them without touching their markup.
 *
 * THE ORBIT IS THE ONE EXCEPTION and is the homepage's alone. Its .shot/.chip
 * predecessor was too, so nothing outside landing.html lost a class when the
 * hero's right-hand column was redrawn.
 */

/* --------------------------------------------------------------- tokens */
/* ONE BLOCK, so the palette can move without a search across the file. Every
   colour below was a literal repeated eight or ten times; changing the blue
   meant changing it in the header, the buttons, the pill, the plan border and
   the numbered steps, and missing one was how the site ended up with two
   blues. Names say the ROLE, not the colour — `--accent`, not `--blue` —
   because the next palette may not be blue. */
:root {
  --ink:        #0b1220;   /* headings */
  --body:       #475569;   /* running text */
  --muted:      #64748b;   /* asides, notes, captions */
  --faint:      #94a3b8;   /* the quietest legible grey */
  --line:       #e6ebf2;
  --line-soft:  #f1f5f9;
  --surface:    #fff;
  --tint:       #f7f9fc;   /* alternating section bands */

  --accent:     #2563eb;
  --accent-ink: #1d4ed8;
  --accent-lit: #3b82f6;   /* the lighter end, for rails and glows */
  --accent-pale:#eff6ff;
  --accent-line:#bfdbfe;

  /* THE DARK END, one colour used by the hero and the closing panel so the
     page opens and shuts on the same note rather than on two near-blacks. */
  --dark:       #070d18;
  --dark-2:     #0f1729;
  --on-dark:    #cbd5e1;
  --on-dark-dim:#94a3b8;

  /* Tinted with the ink rather than pure black — a neutral-black shadow over a
     slightly blue-grey page reads as dirt. */
  --shadow-sm:  0 1px 2px rgba(11, 18, 32, .05);
  --shadow-md:  0 2px 4px rgba(11, 18, 32, .04),
                0 12px 28px -12px rgba(11, 18, 32, .12);
  --shadow-lg:  0 24px 60px -20px rgba(11, 18, 32, .22);
  --shadow-accent: 0 1px 3px rgba(37, 99, 235, .28),
                   0 8px 20px -6px rgba(37, 99, 235, .30);

  --radius-sm:  8px;
  --radius:     14px;
  --radius-lg:  22px;

  --ease: .22s cubic-bezier(.4, 0, .2, 1);
}

* { box-sizing: border-box }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100% }
body {
  margin: 0; color: var(--body); line-height: 1.65; background: var(--surface);
  /* THE SYSTEM STACK, DELIBERATELY, and the one place this diverges from the
     reference — Axion loads Inter from Google Fonts. Every page here is served
     to somebody deciding whether to trust us and must render from this origin
     alone: a font from a CDN is a third party watching that decision, and a
     self-hosted one is 40-90 KB in front of the first paint. This stack
     resolves to SF Pro, Segoe UI Variable and Roboto — all of which are, in
     2026, better faces than the webfont they would be replacing. */
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI Variable Text",
               "Segoe UI", system-ui, Roboto, "Helvetica Neue", Arial, sans-serif;
  font-feature-settings: "kern" 1, "liga" 1;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
h1, h2, h3, h4 { color: var(--ink); font-weight: 700 }
a { color: var(--accent) }
img { max-width: 100% }

/* Everything that moves, moves at one speed — and not at all for somebody who
   asked their system to stop. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto }
  *, *::before, *::after { transition: none !important; animation: none !important }
}

.wrap { max-width: 1160px; margin: 0 auto; padding: 0 24px }
.narrow { max-width: 720px }

/* ---------------------------------------------------------------- header */
/* IT STAYS LIGHT AND SOLID over the dark hero, where the reference fades a
   transparent bar into a white one on scroll. That effect needs a scroll
   listener on every public page; these pages carry one script and it is the
   demo form. A solid bar is also the honest shape here — the hero is one
   section of a light site, not a full-screen dark landing. */
header {
  position: sticky; top: 0; z-index: 20; background: rgba(255, 255, 255, .88);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--line);
}
/* THE BAR IS THE HEIGHT OF THE MARK, and deliberately not more. min-height
   was 68px around a 36px logo, so growing the logo to 56px left a band of
   dead white above and below it — the owner's note was "reduce this margin to
   almost zero". 60px against a 56px mark is 2px either side: enough that the
   mark is not touching the border, and nothing else. Every other item in the
   row (the nav, the Sign in button) is shorter than the mark, so the mark is
   what sets the height and this number only has to keep up with it. */
header .wrap { display: flex; align-items: center; gap: 14px; min-height: 60px; flex-wrap: wrap }
/* The mark sits ON the text baseline rather than above it: inline-flex with
   centred items, so the logo and the word read as one lockup at any font size. */
.brand { display: inline-flex; align-items: center; gap: 9px;
  font-weight: 800; letter-spacing: -.02em; text-decoration: none; color: var(--ink) }
/* The whole square, at a size that reads. The mark is circular and sits
   centred in its canvas, so it needs no cropping — an earlier version cropped a
   1024px share asset in CSS because that file was mostly empty field, and the
   window had to be re-measured every time the asset moved. max-width overrides
   the global `img { max-width: 100% }` so the mark keeps its size in a flex row. */
.brand img { display: block; width: 56px; height: 56px; max-width: none; flex: 0 0 auto }
header nav { margin-left: auto; display: flex; gap: 24px; align-items: center;
  font-size: 14.5px; font-weight: 550 }
header nav a { color: var(--muted); text-decoration: none; transition: color var(--ease) }
header nav a:hover, header nav a[aria-current] { color: var(--ink) }
.nav-login {
  background: var(--accent); color: #fff !important; padding: 9px 20px;
  border-radius: var(--radius-sm); font-size: 14px; font-weight: 650;
  text-decoration: none; white-space: nowrap;
  box-shadow: var(--shadow-accent); transition: background var(--ease), transform var(--ease);
}
.nav-login:hover { background: var(--accent-ink); transform: translateY(-1px) }
/* TRY IT FREE, THE QUIETER OF THE TWO (2026-09-30). An outline in the accent
   so it reads as an action without competing with Sign in's fill; nav-try
   because .ghost is taken and is sized for a hero, not a header. */
.nav-try {
  border: 1px solid var(--accent); color: var(--accent); padding: 8px 16px;
  border-radius: var(--radius-sm); font-size: 14px; font-weight: 650;
  text-decoration: none; white-space: nowrap; transition: background var(--ease);
}
.nav-try:hover { background: var(--tint) }

/* --------------------------------------------------------------- buttons */
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--accent); color: #fff; padding: 14px 28px;
  border-radius: 10px; font: inherit; font-weight: 650; text-decoration: none;
  border: 0; cursor: pointer; font-size: 15px; line-height: 1.2;
  box-shadow: var(--shadow-accent);
  transition: background var(--ease), transform var(--ease), box-shadow var(--ease);
}
.btn:hover {
  background: var(--accent-ink); transform: translateY(-1px);
  box-shadow: 0 2px 6px rgba(37, 99, 235, .35), 0 12px 28px -8px rgba(37, 99, 235, .38);
}
.btn:active { transform: translateY(0) }
/* A DISABLED BUTTON STOPS ADVERTISING ITSELF (2026-09-28), the rule app.css
   gained the same day after a dead "Start a draft" looked live. The public
   forms disable their button while a request is in flight; without this it
   kept its glow and its hover lift, so a second press looked possible. Kept
   legible, not faded, for the reason app.css gives. .picker-go.is-off keeps
   its own fade: it is a link, and it needs pointer-events off as well. */
.btn:disabled, .btn[aria-disabled="true"]:not(.picker-go),
.btn:disabled:hover, .btn[aria-disabled="true"]:not(.picker-go):hover {
  background: #e2e8f0; color: #475569; box-shadow: none; transform: none;
  cursor: not-allowed;
}
.ghost {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 14px 24px; border-radius: 10px; font-weight: 650; font-size: 15px;
  text-decoration: none; border: 1px solid var(--line); color: var(--ink);
  background: var(--surface); transition: border-color var(--ease), background var(--ease);
}
.ghost:hover { border-color: var(--faint); background: var(--tint) }

/* ------------------------------------------------------------------ hero */
/* DARK, AND IT IS THE ONLY DARK SECTION ABOVE THE FOLD. The page was white
   from the header to the footer with a pale blue wash behind the headline, so
   nothing on it had any weight — a "hero" that was simply the first paragraph.
   The reference makes this section near-black and everything after it light,
   which gives the page somewhere to start.
   Shared by all five public pages, which is why the treatment lives on .hero
   and not on the homepage. */
.hero {
  position: relative; overflow: hidden; isolation: isolate;
  background: var(--dark); color: var(--on-dark);
  padding: 88px 0 96px;
}
/* THE GRID, MASKED. A flat grid across a dark panel looks like graph paper; the
   radial mask fades it out before it reaches any edge, so it reads as texture
   under the headline rather than as a pattern the text is sitting on. */
.hero::before {
  content: ""; position: absolute; inset: 0; z-index: -2; pointer-events: none;
  background-image:
    linear-gradient(rgba(59, 130, 246, .07) 1px, transparent 1px),
    linear-gradient(90deg, rgba(59, 130, 246, .07) 1px, transparent 1px);
  background-size: 64px 64px;
  -webkit-mask-image: radial-gradient(ellipse 75% 65% at 50% 35%, #000 25%, transparent 100%);
          mask-image: radial-gradient(ellipse 75% 65% at 50% 35%, #000 25%, transparent 100%);
}
/* TWO GLOWS, heavily blurred and low opacity. They are what stops the
   background being a flat rectangle — the eye reads depth behind the text. */
.hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(560px 420px at 12% -10%, rgba(37, 99, 235, .30), transparent 70%),
    radial-gradient(520px 400px at 92% 108%, rgba(56, 189, 248, .14), transparent 70%);
}
.hero-grid { display: grid; grid-template-columns: 1fr .92fr; gap: 56px; align-items: center }
.hero h1 {
  color: #fff; font-size: clamp(34px, 4.6vw, 54px); line-height: 1.07;
  letter-spacing: -.033em; font-weight: 800; margin: 0 0 18px; max-width: 17ch;
}
.hero p.sub {
  font-size: 17.5px; line-height: 1.72; color: var(--on-dark);
  max-width: 56ch; margin: 0 0 30px;
}
.cta { display: flex; gap: 14px; flex-wrap: wrap; align-items: center }
/* The secondary button is redrawn for the dark ground: a hairline of white
   rather than a grey border, which disappears entirely against near-black. */
.hero .ghost {
  background: transparent; color: #fff; border-color: rgba(255, 255, 255, .22);
}
.hero .ghost:hover { background: rgba(255, 255, 255, .07); border-color: rgba(255, 255, 255, .42) }
.pill {
  display: inline-flex; align-items: center; gap: 8px;
  background: rgba(59, 130, 246, .13); color: #bfdbfe;
  border: 1px solid rgba(59, 130, 246, .25);
  font-weight: 650; font-size: 12.5px; letter-spacing: .02em;
  padding: 7px 15px; border-radius: 100px; margin: 0 0 20px;
}
/* The live dot, ON THE HOMEPAGE ONLY. It is the one thing on the page that
   moves on its own, and it is 6px across — enough to say "this is running",
   not enough to pull the eye off the headline. Scoped to .hero-grid because
   the other four pages reuse .pill as a plain label, and a pulsing dot beside
   "Plans and prices" is an animation that means nothing. */
.hero-grid .pill::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: #60a5fa; box-shadow: 0 0 0 0 rgba(96, 165, 250, .7);
  animation: pill-dot 2.4s ease-out infinite;
}
@keyframes pill-dot {
  0%   { box-shadow: 0 0 0 0 rgba(96, 165, 250, .55) }
  70%  { box-shadow: 0 0 0 7px rgba(96, 165, 250, 0) }
  100% { box-shadow: 0 0 0 0 rgba(96, 165, 250, 0) }
}
.hero-note { margin: 26px 0 0; font-size: 13.5px; color: var(--on-dark-dim) }

/* ----------------------------------------------------- stacked quotes */
/* ONE UNDER THE OTHER, EACH A ROW (owner, 2026-09-16: "vertical … each of
   them have a lot of words"). The person sits in one column, the quote runs
   beside them at a comfortable measure, and the three cards share one width
   so the eye drops straight down the page. Rows alternate sides — person
   left, then right, then left — which is what stops three wide cards
   reading as a table. The slider this replaced is in git history (71c245e)
   for when there are five or more.

   THESE CARDS DO MOVE ON HOVER, unlike .card's rule further up (owner,
   2026-09-16, of the plain version: "looks very simple and minimal and does
   not have hover over effect"). A lift, a deeper shadow, the accent rail
   sliding in along the edge and the photograph's ring taking the accent.
   Nothing is clickable, so the pointer stays an arrow; the motion is there to
   give the section some life, and reduced motion switches it off. */
.quote-stack { display: grid; gap: 22px; max-width: 980px }
.quote-stack .quote {
  position: relative; overflow: hidden;
  display: grid; grid-template-columns: 210px 1fr; gap: 34px; align-items: start;
  padding: 30px 34px 30px 30px;
  background: linear-gradient(180deg, #fff 0%, #fbfcfe 100%);
  transition: transform .28s ease, box-shadow .28s ease, border-color .28s ease;
}
.quote-stack .quote:nth-child(even) { grid-template-columns: 1fr 210px; padding: 30px 30px 30px 34px }
.quote-stack .quote:nth-child(even) figcaption { order: 2 }
/* the accent rail: a 4px bar down the person's edge, scaled to nothing until hover */
.quote-stack .quote::after {
  content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 4px;
  background: linear-gradient(180deg, var(--accent-lit), var(--accent));
  transform: scaleY(0); transform-origin: top; transition: transform .32s ease;
}
.quote-stack .quote:nth-child(even)::after { left: auto; right: 0; transform-origin: bottom }
.quote-stack .quote:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg), 0 0 0 1px var(--accent-line);
  border-color: var(--accent-line);
}
.quote-stack .quote:hover::after { transform: scaleY(1) }
.quote-stack .quote figcaption {
  flex-direction: column; align-items: flex-start; gap: 16px;
  margin: 0; padding: 0 30px 0 0; border-bottom: 0; border-right: 1px solid var(--line);
  align-self: stretch;
}
.quote-stack .quote:nth-child(even) figcaption { padding: 0 0 0 30px; border-right: 0; border-left: 1px solid var(--line) }
.quote-stack .quote .face {
  width: 128px; height: 128px; flex-basis: 128px;
  transition: box-shadow .28s ease, transform .28s ease;
}
.quote-stack .quote:hover .face {
  transform: scale(1.03);
  box-shadow: 0 0 0 3px #fff, 0 0 0 5px var(--accent-lit), 0 10px 24px rgba(37, 99, 235, .18);
}
.quote-stack .quote .who { font-size: 16px }
/* THE CLINIC'S LINKEDIN POST, as a fourth card (landing.html). The circle
   takes the photographs' size and hover from .face and carries the clinic's
   own logo, which the owner supplied on 2026-09-17; it held their initials
   until then, while we had nothing else. The post keeps its own paragraphs,
   the hashtags stay quiet, and the link to the original closes the card where
   a reader who wants to check it will look. .quote .face.face-logo, not
   .face-logo alone: .quote .face further down sets the photographs' grey
   placeholder at the same specificity and would win on order. */
/* A LOGO IS NOT A FACE: contain and a white ground, because a mark drawn to
   its own edges would be cropped by the circle that suits a photograph, and
   `cover` would enlarge it until it was. The padding keeps it off the ring. */
.quote .face.face-logo { object-fit: contain; background: #fff; padding: 10px }
.quote-post blockquote p { margin: 0 0 12px; max-width: none }
.quote-post blockquote p:last-child { margin-bottom: 0 }
.quote-post .quote-tags { color: var(--muted); font-size: 14px }
.quote-source { display: inline-block; margin-top: 16px; font-size: 14.5px; font-weight: 650;
  color: var(--accent); text-decoration: none }
.quote-source:hover, .quote-source:focus-visible { color: var(--accent-ink); text-decoration: underline }
/* THE QUOTATION MARK, drawn in the accent at low opacity above the words —
   a ::before, so the sentence the person said is still the only text in the
   blockquote and copying it picks up nothing extra. */
.quote-stack .quote blockquote {
  position: relative; padding-top: 30px;
  font-size: 16.5px; line-height: 1.75; max-width: 64ch; color: var(--body);
}
.quote-stack .quote blockquote::before {
  content: "\201C"; position: absolute; top: -14px; left: -6px;
  font: 800 92px/1 Georgia, "Times New Roman", serif; color: var(--accent);
  opacity: .16; pointer-events: none;
  transition: opacity .28s ease, transform .28s ease;
}
.quote-stack .quote:hover blockquote::before { opacity: .28; transform: translateY(-3px) }
/* On a phone the row folds back into the ordinary card: person on top, rule
   beneath, words below — and no side-swapping. */
@media (max-width: 640px) {
  .quote-stack .quote, .quote-stack .quote:nth-child(even) { grid-template-columns: 1fr; gap: 0; padding: 22px }
  .quote-stack .quote figcaption, .quote-stack .quote:nth-child(even) figcaption {
    order: 0; flex-direction: row; align-items: center; gap: 14px;
    margin-bottom: 16px; padding: 0 0 16px; border-left: 0; border-right: 0; border-bottom: 1px solid var(--line);
  }
  .quote-stack .quote blockquote { padding-top: 22px }
}
@media (prefers-reduced-motion: reduce) {
  .quote-stack .quote, .quote-stack .quote::after, .quote-stack .quote .face, .quote-stack .quote blockquote::before { transition: none }
  .quote-stack .quote:hover { transform: none }
  .quote-stack .quote:hover .face { transform: none }
}

/* ------------------------------------------------------- the hero film */
/* THE FOOTAGE BEHIND THE HOMEPAGE HEADLINE. Markup and reasoning live in
   app/templates/site/_hero_video.html; this is the whole treatment.

   THE HERO TAKES THE FILM'S SHAPE (owner, 2026-09-16: "not square cut …
   misses the corners of video"). aspect-ratio 2944/1248 on the section means
   the video is not cropped on a wide screen; the copy floats over it and the
   section is exactly as tall as the picture. min-height keeps the headline and
   buttons from overflowing on a short, wide window.

   ``width: 100%`` IS WHAT STOPS THAT min-height WIDENING THE PAGE. With width
   left auto, a min-height transfers through aspect-ratio into a minimum WIDTH:
   520 × 2944/1248 ≈ 1227px. So every window from 981px (where the rule below
   hands over) up to 1226px got a hero wider than the screen — the whole
   homepage scrolled sideways by up to 246px, and the film's pause button sat
   off to the right where nobody could see it. A definite width keeps the ratio
   from driving the width: in that band the hero holds 520px tall at the
   window's width, and the film covers and trims a little from each side
   instead. Wider than 1227px, the ratio wins and nothing is cropped.

   THE SCRIM, NOT THE GRID. The grid texture and the two glows that dress the
   other four heroes are switched off here — texture over a photograph is
   noise — and replaced by one left-to-right darkening, heaviest under the
   copy, lightest where the desk and the tablet are. */
.hero-film-hero { padding: 0; display: flex; align-items: center; width: 100%; aspect-ratio: 2944 / 1248; min-height: 520px }
.hero-film-hero::before, .hero-film-hero::after { content: none }
.hero-single { position: relative; width: 100% }
.herofilm {
  position: absolute; inset: 0; z-index: -3; width: 100%; height: 100%;
  object-fit: cover; object-position: center; display: block; background: var(--dark);
}
.hero-scrim {
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    linear-gradient(90deg, rgba(2, 6, 23, .80) 0%, rgba(2, 6, 23, .62) 38%, rgba(2, 6, 23, .22) 68%, rgba(2, 6, 23, .10) 100%),
    linear-gradient(180deg, rgba(2, 6, 23, .25) 0%, transparent 30%, transparent 70%, rgba(2, 6, 23, .35) 100%);
}
/* The film and the scrim are positioned against the section, not the .wrap,
   so they run edge to edge while the copy keeps the page gutter. */
.hero-film-hero .herofilm, .hero-film-hero .hero-scrim { position: absolute }
.hero-film-hero .hero-single { position: static }
.hero-film-hero .hero-copy { position: relative; z-index: 1; max-width: 640px; padding: 64px 0 }
.hero-film-hero p.sub { font-size: 19px; margin-bottom: 26px; max-width: 40ch }
/* THE THREE NAMES AS CHIPS, under the buttons: named, not explained. */
.hero-products { list-style: none; display: flex; flex-wrap: wrap; gap: 8px; margin: 22px 0 0; padding: 0 }
.hero-products li strong {
  display: inline-block; font-weight: 650; font-size: 12.5px; letter-spacing: .02em;
  color: #dbeafe; background: rgba(59, 130, 246, .16); border: 1px solid rgba(147, 197, 253, .28);
  padding: 6px 12px; border-radius: 100px;
}
.hero-film-hero .hero-note { margin-top: 18px }
/* The hero's third door, to the demo check-in (2026-09-30): a line of text
   under the buttons, on the dark film, so the filled "Get a demo" keeps the
   eye. hero-try because every short name in the hero is already somebody's. */
.hero-try { margin: 16px 0 0; font-size: 15px; color: var(--on-dark-dim) }
.hero-try a { color: #fff; font-weight: 650; text-underline-offset: 3px }
.hero-try span { display: block; margin-top: 2px; font-size: 13.5px }
/* THE PAUSE BUTTON (WCAG 2.2.2; why it exists and why it is served hidden are
   in site/_hero_video.html). Positioned against the section like the film, in
   the bottom-right corner: the copy sits left, so the headline, the buttons
   and the chips are never under it. Dressed like the visitor page's .playbtn
   — a dark translucent disc with a white glyph — at 44px, the size WCAG
   2.5.5 asks of a target, with a pale ring so the disc still has an edge over
   the darkest footage. The focus ring is white with a dark halo, because the
   site's blue ring (:focus-visible, below) disappears into the scrim; it is
   scoped to this button so the global rule's 4px radius does not square the
   disc off. [hidden] is spelled out because display:grid would beat the
   browser's own hidden rule. */
.filmtoggle {
  position: absolute; right: 20px; bottom: 20px; z-index: 2;
  width: 44px; height: 44px; padding: 0; border-radius: 50%; cursor: pointer;
  display: grid; place-items: center;
  background: rgba(15, 23, 42, .72); color: #fff; border: 1px solid rgba(255, 255, 255, .55);
}
.filmtoggle[hidden] { display: none }
.filmtoggle:hover { background: rgba(15, 23, 42, .9) }
.filmtoggle svg { fill: currentColor; display: block }
.filmtoggle .filmtoggle-play { display: none; margin-left: 2px }
.filmtoggle[data-paused="true"] .filmtoggle-pause { display: none }
.filmtoggle[data-paused="true"] .filmtoggle-play { display: block }
/* On the button itself, not under .hero-film-hero: the Canada page's hero is a
   different section with the same film and button, and the site's blue ring
   disappears against the dark overlay on either. */
.filmtoggle:focus-visible {
  outline: 3px solid #fff; outline-offset: 2px; border-radius: 50%;
  box-shadow: 0 0 0 7px rgba(2, 6, 23, .85);
}

/* -------------------------------------------------------------- the orbit */
/* THE DRAWN PRODUCT PANEL, SECOND VERSION. See landing.html for what it shows
   and where the shape came from. This is the whole illustration: eight labelled
   cards on a ring, a hub in the middle, spokes between them, and five
   animations. No script, no library, no image.

   ONE SQUARE THAT SCALES. The wires are an SVG on a 400x400 viewBox and the
   cards are placed with percentages of the same box, so the two layers stay
   registered at any width and the whole diagram is sized by its column alone.
   The three numbers that decide the composition are variables on .orbit
   because they only work as a set: pull the ring in without shrinking the
   cards and they collide.

   THE PADDING THE TABLET NEEDED IS GONE. That 48/52px was margin for two
   floating cards to hang off the corners; the orbit needs every pixel of the
   column it can get, and it fences itself with --gap instead. */
.hero-art { position: relative }

.orbit {
  --ring: 37%;   /* distance from centre to a card's centre */
  --card: 22%;   /* card width; --ring + --card/2 must stay under 50% */
  --hub:  30%;   /* hub diameter — the ring's inner clearance */

  /* EIGHT HUES, ONE PER SPOKE — the owner's call, and the reference's own
     scheme. This is the single place on the site where the accent spread the
     top of this file turned down is the right answer: a ring of eight cards in
     three tints of one blue reads as a texture, and the eye has nothing to
     count. Eight colours make it eight THINGS, which is the claim the diagram
     exists to make.

     IT IS FENCED TO THE ORBIT and goes no further. These are declared on
     .orbit, not on :root, so nothing else on the site can reach for a green or
     an amber — the rest of the page is still one accent, and the hero's own
     furniture (pill, buttons, glows) is untouched.

     THE 400 SHADES, NOT THE 500s the reference uses. Its palette was picked for
     white cards on a pale ground; at #10b981 or #6366f1 on near-black the
     darker half of the ring goes muddy and the icons stop reading. Each is one
     step lighter, which is what keeps all eight at a similar apparent
     brightness — the ring should not have a heavy side. */
  --t-calls:      #60a5fa;  /* blue    */
  --t-messages:   #34d399;  /* emerald */
  --t-checkin:    #a78bfa;  /* violet  */
  --t-receipts:   #fbbf24;  /* amber   */
  --t-documents:  #f87171;  /* coral   */
  --t-figures:    #2dd4bf;  /* teal    */
  --t-alerts:     #fb923c;  /* orange  */
  --t-scheduling: #818cf8;  /* indigo  */

  position: relative; width: 100%; aspect-ratio: 1;
  max-width: 520px; margin: 0 auto;
}

/* ---- the wires */
.orbit-wires { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible }

/* THE SPOKES DRAW THEMSELVES OUTWARD, staggered by --i. Each line is 40 units
   long by construction, so one dasharray covers all eight.

   40, BECAUSE A SPOKE ENDS WHERE ITS PACKET DOES. They first ran the whole way
   to the card's centre (r=148), on the reasoning that the card would cover the
   tail — but these cards are TRANSLUCENT, so the tail was not hidden by one, it
   showed through it and ran on under the icon and the label. Ending at r=100,
   level with the far end of the packet's travel, leaves each card a clean
   object with a wire arriving at it. */
.orbit-spokes line {
  stroke-width: 2.5; stroke-linecap: round; opacity: .38;
  stroke-dasharray: 40; stroke-dashoffset: 0;
  animation: orbit-draw 1.1s cubic-bezier(.4, 0, .2, 1) backwards;
  animation-delay: calc(.15s + var(--i) * .07s);
}
@keyframes orbit-draw { from { stroke-dashoffset: 40; opacity: 0 } }

.orbit-ring { stroke: rgba(186, 200, 255, .2); stroke-width: 2 }
/* One bright arc, a quarter of the circumference (2*pi*60 = 377), sweeping the
   ring on a slow loop. transform-box/origin because an SVG child rotates about
   the user-space origin otherwise, which throws it off the canvas. */
.orbit-arc { stroke-width: 3; stroke-linecap: round; stroke-dasharray: 94 283 }
.orbit-sweep {
  transform-box: view-box; transform-origin: 200px 200px;
  animation: orbit-sweep 20s linear infinite;
}
@keyframes orbit-sweep { to { transform: rotate(360deg) } }

/* THE PARTICLES, which are the one thing here that says the middle is shared
   rather than merely central: work leaves the hub, reaches a card, comes back.
   Each rides a <g> already rotated to its spoke, so the dot only ever moves
   along one axis and the 8 of them cost nothing. Durations are deliberately
   coprime-ish (6s + i*0.7s) so the eight never fall into step and start
   pulsing as one — which is what a single shared duration looked like. */
/* The circle is small and the bloom around it does the work — see the
   orbit-glow filter in landing.html. Drawn at .95 rather than full so the
   merged blurs stay the brightest part of the packet. */
.orbit-sparks .spark {
  opacity: 0;
  animation: orbit-spark 6s ease-in-out infinite;
  animation-duration: calc(6s + var(--i) * .7s);
  animation-delay: calc(1.2s + var(--i) * .3s);
}
/* 40 UNITS, WHICH IS NOW THE WHOLE SPOKE: the packet runs its wire end to end
   and stops there. THE TWO NUMBERS ARE ONE NUMBER — change this travel and the
   dasharray above must change with it, or the dot will overshoot its line. */
@keyframes orbit-spark {
  0%, 100% { transform: translateX(0);    opacity: 0 }
  18%      {                              opacity: .95 }
  50%      { transform: translateX(40px); opacity: .95 }
  82%      {                              opacity: 0 }
}

/* ---- the hub */
.orbit-hub {
  position: absolute; left: 50%; top: 50%;
  width: var(--hub); aspect-ratio: 1; transform: translate(-50%, -50%);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; text-align: center; border-radius: 50%;
  /* Not a white disc. A white circle on near-black is a hole punched in the
     hero; this is the dark ground lifted a little, with the same blue glow the
     section's own background uses so it belongs to the panel it sits on. */
  background:
    radial-gradient(circle at 50% 35%, rgba(59, 130, 246, .22), rgba(9, 15, 28, .92) 70%);
  box-shadow: inset 0 0 0 1px rgba(148, 197, 253, .14),
              0 0 60px -10px rgba(59, 130, 246, .55);
  animation: orbit-hub-in .8s cubic-bezier(.22, 1.4, .5, 1) backwards;
}
.orbit-hub-ico { display: block; color: #93c5fd; animation: orbit-pulse 3s ease-in-out infinite }
.orbit-hub-ico .ico { width: 30px; height: 30px }
.orbit-hub b     { color: #fff; font-size: 13.5px; font-weight: 750; letter-spacing: -.01em }
.orbit-hub small { color: var(--on-dark-dim); font-size: 11.5px; line-height: 1.3 }
@keyframes orbit-hub-in { from { transform: translate(-50%, -50%) scale(.2); opacity: 0 } }
/* The centre breathes and nothing else does; at 1.06 it is a change of weight
   rather than a thing bouncing next to the headline. */
@keyframes orbit-pulse { 50% { transform: scale(1.06) } }

/* ---- the eight cards */
/* Placed from the centre by the --x/--y the template computed, so adding or
   moving one is arithmetic in landing.html and never a new rule here. */
/* --hue, NOT --tint. Each node sets its own colour as a custom property that
   its icon tile and border read. The obvious name was --tint, which is what it
   was called first — and --tint is ALREADY A GLOBAL TOKEN on :root, the pale
   band behind alternating sections. Setting it here silently shadowed the
   global one for everything inside a node. Nothing in a node happens to use
   the band colour, so it broke nothing; it was a trap for whoever next put
   something tinted inside a card. */
.orbit-node {
  position: absolute;
  left: calc(50% + var(--x)); top: calc(50% + var(--y));
  width: var(--card);
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 10px 6px 11px; border-radius: 12px; text-align: center;
  /* NO backdrop-filter. It was here to frost the hero's grid behind a card, a
     thing nobody could see on a ground this dark — and it took the passing
     particle with it, blooming a bright thumbprint into whichever corner the
     dot happened to be nearest. A flat translucent white is the same card
     without the artefact, and without a compositor layer per card. */
  background: rgba(255, 255, 255, .06);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--hue) 26%, transparent),
              0 14px 30px -18px rgba(0, 0, 0, .9);
  /* The centring translate lives in the transform, so every keyframe and the
     hover below must restate it or the card jumps half its width sideways. */
  transform: translate(-50%, -50%);
  transition: transform .25s cubic-bezier(.4, 0, .2, 1), background .25s;
  animation: orbit-node-in .55s cubic-bezier(.22, 1.4, .5, 1) backwards;
  animation-delay: calc(.4s + var(--i) * .08s);
}
@keyframes orbit-node-in {
  from { transform: translate(-50%, -50%) scale(0); opacity: 0 }
}
.orbit-node:hover {
  background: rgba(255, 255, 255, .1);
  transform: translate(-50%, -50%) scale(1.06);
}
.orbit-ico {
  display: grid; place-items: center; width: 30px; height: 30px;
  border-radius: 9px; color: var(--hue);
  background: color-mix(in srgb, var(--hue) 20%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--hue) 30%, transparent);
}
.orbit-ico .ico { width: 16px; height: 16px }
.orbit-node b {
  color: #fff; font-size: 12.5px; font-weight: 700; letter-spacing: -.01em;
  line-height: 1.2;
}
.orbit-node small {
  color: var(--on-dark-dim); font-size: 10.5px; line-height: 1.28;
  /* Two lines at most. "Charts and graphs" wrapping to three made its card
     taller than its neighbours and tilted the whole ring. */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ------------------------------------------------------------- structure */
/* 96px, not the reference's 120px. These pages are denser than a fleet
   landing — the homepage carries four sections of real prose — and at 120px
   the reader spends a screen and a half on empty band. */
section { padding: 96px 0 }
section.tint { background: var(--tint) }
h2 { font-size: clamp(26px, 3vw, 38px); line-height: 1.18; letter-spacing: -.025em; margin: 0 0 10px }
h3 { font-size: 19px; letter-spacing: -.01em; margin: 14px 0 7px }
.lead { color: var(--muted); margin: 0 0 40px; font-size: 17.5px; line-height: 1.65; max-width: 62ch }
.note { color: var(--muted); font-size: 14px }

/* ------------------------------------------------------------------ cards */
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px }
.grid.two { grid-template-columns: 1fr 1fr }
.card {
  position: relative; overflow: hidden;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 28px;
  box-shadow: var(--shadow-sm);
  transition: transform var(--ease), box-shadow var(--ease), border-color var(--ease);
}
/* THE RAIL ACROSS THE TOP, taken from the reference and reduced to one hue.
   Axion gives each card its own gradient — purple, blue, green — which works
   for three unrelated features. These three cards are three assistants in one
   product line, so they get one accent at three intensities: related, not
   interchangeable. Always drawn rather than revealed on hover — it is what
   tells the eye the three are a set, and hover does not exist on a tablet. */
.card::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px;
  background: linear-gradient(90deg, var(--accent), var(--accent-lit));
  opacity: .9;
}
.card:nth-child(2)::before { background: linear-gradient(90deg, var(--accent-lit), #38bdf8) }
.card:nth-child(3)::before { background: linear-gradient(90deg, #38bdf8, #22d3ee) }
.card:hover {
  transform: translateY(-3px); border-color: var(--accent-line);
  box-shadow: var(--shadow-md);
}
/* The tinted tile. The emoji it replaced were a different picture on every
   platform — see site/_icons.html. */
.ico-wrap {
  display: grid; place-items: center; width: 48px; height: 48px;
  border-radius: 12px; background: var(--accent-pale); color: var(--accent);
  margin-bottom: 4px;
}
.ico { width: 24px; height: 24px; display: block }
.card p { margin: 0 0 10px; color: var(--body); font-size: 15px }
.card ul { margin: 10px 0 0; padding-left: 20px; color: var(--body); font-size: 15px }
.card ul li { margin-bottom: 6px }
/* The Visitor card's one "from" price (landing.html). Quiet on purpose: it
   answers "roughly what?" and points at the plans; it is not an offer. */
.card .card-price { margin: 4px 0 0; font-size: 14px; font-weight: 600 }
.card .card-price a { color: var(--accent-ink); text-decoration: none }
.card .card-price a:hover { text-decoration: underline }

/* ------------------------------------------------------------ the plans */
/* AS MANY COLUMNS AS THERE ARE PLANS, down to one on a phone. Fixed at two, the
   three assistant bundles wrapped 2 + 1 and the last one — all three, the offer
   we most want read — sat alone under a half-empty row looking like an
   afterthought. auto-fit keeps the usage plans on this page working unchanged
   whatever their count. */
.plans { display: grid; gap: 22px; align-items: start;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)) }
.plan {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 28px;
  transition: transform var(--ease), box-shadow var(--ease), border-color var(--ease);
}
.plan:hover { transform: translateY(-3px); box-shadow: var(--shadow-md) }
/* The one we most want read, marked by more than a slightly bluer border. */
.plan.feature {
  border-color: var(--accent-line); box-shadow: var(--shadow-md);
  background: linear-gradient(180deg, var(--accent-pale), var(--surface) 120px);
}
.plan h3 { font-size: 21px; margin: 0; letter-spacing: -.02em }
.plan .price { color: var(--muted); font-size: 15px; margin: 8px 0 18px }
/* The number is the thing somebody came to this page for. */
.plan .price strong { display: block; color: var(--ink); font-size: 38px; font-weight: 800;
  letter-spacing: -.03em; line-height: 1.1 }
.allow { width: 100%; border-collapse: collapse; font-size: 15px; margin-bottom: 20px }
.allow th, .allow td { text-align: left; padding: 10px 0; border-bottom: 1px solid var(--line-soft) }
.allow td.num { text-align: right; font-weight: 700; white-space: nowrap;
  font-variant-numeric: tabular-nums }
.allow th { font-weight: 600; color: var(--body) }

/* --------------------------------------------------------- numbered steps */
/* The top margin is load-bearing: on /getting-started the list follows the h2
   directly with no .lead between them, and h2's own 10px left the first step's
   number touching the heading. */
.steps { counter-reset: step; list-style: none; margin: 34px 0 0; padding: 0 }
.steps > li {
  counter-increment: step; position: relative; padding: 0 0 30px 52px; margin: 0;
  border-left: 2px solid var(--line); margin-left: 15px;
}
.steps > li:last-child { border-left-color: transparent; padding-bottom: 0 }
.steps > li::before {
  content: counter(step); position: absolute; left: -16px; top: -4px;
  width: 32px; height: 32px; border-radius: 999px; background: var(--accent); color: #fff;
  font-weight: 700; font-size: 15px; display: flex; align-items: center; justify-content: center;
  box-shadow: 0 0 0 4px var(--surface), var(--shadow-accent);
}
.steps h3 { margin: 0 0 4px }
.steps p { margin: 0 0 8px; color: var(--body) }

/* -------------------------------------------------------- the dark panel */
.panel {
  position: relative; overflow: hidden; isolation: isolate;
  background: var(--dark-2); color: #fff; border-radius: var(--radius-lg); padding: 48px;
  display: grid; grid-template-columns: 1fr 1fr; gap: 44px; align-items: start;
}
/* The same glow the hero uses, so the page shuts on the note it opened on. */
.panel::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: radial-gradient(600px 320px at 88% -20%, rgba(37, 99, 235, .35), transparent 70%);
}
.panel h2 { color: #fff }
.panel p { color: var(--on-dark) }
.panel a { color: #93c5fd }
.panel form { display: grid; gap: 12px }
.panel label, .panel legend { font-size: 13px; font-weight: 600; color: #e2e8f0 }
/* NOT THE TICK BOXES. `.panel input` matched every input, so the three
   "which would you like?" checkboxes were stretched to the full width of the
   form and given 13px of padding — three grey slabs floating to the right of
   their own labels. Selecting by type is the fix; a checkbox is not a field
   somebody types into and shares none of this. */
.panel input:not([type=checkbox]):not([type=radio]),
.panel textarea, .panel select {
  width: 100%; padding: 13px 14px; border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, .16);
  background: rgba(255, 255, 255, .05); color: #fff; font: inherit;
  transition: border-color var(--ease), background var(--ease), box-shadow var(--ease);
}
.panel input[type=checkbox], .panel input[type=radio] {
  width: 16px; height: 16px; margin: 0 8px 0 0; vertical-align: -2px;
  accent-color: var(--accent-lit); flex: 0 0 auto;
}
/* The label wraps the box, so it is the row — and the row is the tap target.
   A 16px square is below the 44px minimum on its own. */
.panel fieldset label { display: flex; align-items: flex-start; gap: 2px;
  padding: 7px 0; font-weight: 400; color: var(--on-dark); cursor: pointer }
.panel input:focus, .panel textarea:focus, .panel select:focus {
  outline: 0; border-color: var(--accent-lit); background: rgba(255, 255, 255, .09);
  box-shadow: 0 0 0 3px rgba(59, 130, 246, .22);
}
.panel input::placeholder, .panel textarea::placeholder { color: #8b9bb4 }
.panel .field { display: grid; gap: 5px }
.hp { position: absolute; left: -9999px }
.formMsg { font-size: 14px; margin-top: 6px; min-height: 20px }

/* A visible focus ring everywhere, on the page's own accent. Removing it is
   how a keyboard becomes unusable on a form somebody is trying to send us. */
:focus-visible { outline: 2px solid var(--accent-lit); outline-offset: 2px; border-radius: 4px }

/* ---------------------------------------------------------------- footer */
footer { border-top: 1px solid var(--line); padding: 40px 0 48px; color: var(--muted); font-size: 14px }
footer .cols { display: flex; gap: 30px; flex-wrap: wrap; align-items: baseline }
footer nav { display: flex; gap: 20px; flex-wrap: wrap; margin-left: auto }
footer a { color: var(--body); text-decoration: none }
footer a:hover { text-decoration: underline }
footer .legal { margin-top: 20px; color: var(--faint) }

/* ============================================================= responsive */
@media (max-width: 980px) {
  .hero-grid { grid-template-columns: 1fr; gap: 44px }
  /* THE FILM COVERS ON A NARROW SCREEN. Below this width the copy is taller
     than a 2.36:1 picture, so the section grows with the text and the picture
     crops at the sides. The script plays the portrait phone film here, not the
     wide one — see site/_hero_video.html for how it is framed. */
  .hero-film-hero { aspect-ratio: auto; min-height: 0 }
  .hero-film-hero .hero-copy { padding: 56px 0 }
  /* LIGHTER WHERE THE COPY IS LARGE, DARK WHERE IT IS SMALL. The phone now plays
     a film worth seeing, and the old .82/.70/.82 wash hid it. The headline and
     the solid buttons carry their own weight, so the middle of the frame can
     open up; the small grey note at the bottom cannot, so the bottom stays as
     dark as before. */
  .hero-scrim { background: linear-gradient(180deg, rgba(2, 6, 23, .66) 0%, rgba(2, 6, 23, .50) 40%, rgba(2, 6, 23, .62) 62%, rgba(2, 6, 23, .80) 82%, rgba(2, 6, 23, .84) 100%) }
  /* THIS 980px IS ALSO THE FILM'S. The script at the foot of landing.html
     matches "(max-width: 980px)" to choose the phone film over the wide one;
     change one, change the other. The pause button shows at this width now
     that phones play a film too, so the copy makes room under itself and the
     button never sits on the last line. */
  .hero-film-hero:has(.filmtoggle:not([hidden])) .hero-copy { padding-bottom: 92px }
  /* THE ORBIT STOPS BEING A COLUMN AND BECOMES A BLOCK. It gets wider here
     than it ever was beside the headline, which is the one width at which the
     eight subtitles are comfortable rather than clamped. */
  .orbit { max-width: 560px }
  .grid { grid-template-columns: 1fr 1fr }
  .panel { grid-template-columns: 1fr }
}

/* ------------------------------------------------------------ testimonials */
/* Built on the same surface/line/radius tokens as .card so the section reads as
   part of the page rather than a widget dropped into it — but deliberately NOT
   .card: a card is a thing you can click into, and these are not. No hover
   lift and no top rail for the same reason.

   The quote mark is drawn with ::before rather than typed into the markup, so
   the sentence a person actually said is the only text in the blockquote and
   copying it does not pick up decoration. .grid.two already collapses to one
   column at 820px, so these stack on a phone with no rule of their own. */
.quote {
  margin: 0; padding: 28px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow-sm);
  display: flex; flex-direction: column;
}
.quote blockquote {
  margin: 0; color: var(--body);
  font-size: 15.5px; line-height: 1.7;
}
/* THE PERSON COMES FIRST (owner, 2026-09-13: "larger on top, title in front
   of the picture"). The attribution used to sit at the bottom in a 52px row,
   with ``margin-top:auto`` lining two cards of different lengths up along
   their last line. At the top that problem disappears — cards align on their
   first line for free — so the auto margin goes with it and the photograph
   can be the size a face needs to be recognisable. */
.quote figcaption {
  display: flex; align-items: center; gap: 20px;
  margin-bottom: 18px; padding-bottom: 18px;
  border-bottom: 1px solid var(--line);
}
.quote figcaption > span { display: flex; flex-direction: column; gap: 3px; min-width: 0 }
/* Fixed size and aspect-ratio so the row does not reflow as the picture
   arrives, and object-fit so a photograph that is not square is filled rather
   than squashed — both faces are cropped to a circle, so a stretch would show.
   The 320px source is 4x this, which is what keeps it sharp on a retina
   screen. alt is empty on purpose: the name is right beside it in text, and a
   screen reader announcing it twice is noise. */
.quote .face {
  /* 144px, double the first cut (owner, 2026-09-13). The sources are 320px
     square, so this is still better than 2x on a retina screen — going
     larger would start to soften them, and one of the two photographs has
     no more pixels behind it than that. */
  width: 144px; height: 144px; flex: 0 0 144px; aspect-ratio: 1;
  border-radius: 50%; object-fit: cover;
  background: var(--line);
  /* A ring rather than a border: a border would eat into the 72px and shave
     a pixel off the face at the crop edge. */
  box-shadow: 0 0 0 1px var(--line), 0 2px 10px rgba(15, 23, 42, .07);
}
/* SMALLER ON A PHONE, and the desktop size is still double what it was. At
   390px the card is 354px wide: a 144px face plus its gap leaves 190px for
   the text, which wraps "Independent Insurance Coordinator" onto three
   lines. 104px gives the role two and keeps the face the first thing read. */
@media (max-width: 520px) {
  .quote .face { width: 104px; height: 104px; flex: 0 0 104px }
  .quote figcaption { gap: 14px }
}
.quote .who { font-weight: 600; color: var(--ink); font-size: 15px }
.quote .role { color: var(--muted); font-size: 13.5px }

@media (max-width: 820px) {
  section { padding: 64px 0 }
  .hero { padding: 52px 0 60px }
  .hero p.sub { font-size: 16.5px }
  .lead { font-size: 16.5px; margin-bottom: 30px }
  .grid, .grid.two, .plans { grid-template-columns: 1fr }
  .panel { padding: 30px }
  footer nav { margin-left: 0 }

  /* THE HEADER, WHICH WAS THE WORST OF IT.
     Five links and a button shared one flex row that was allowed to wrap, so on
     a phone "Getting started" and "Talk to us" each broke ACROSS TWO LINES and
     the bar grew to a quarter of the screen before any content appeared.
     Two rows now: brand and Sign in, then the links. Each link refuses to break
     mid-phrase, and the row scrolls sideways if a sixth is ever added rather
     than wrapping into a block again.

     NOT A HAMBURGER DRAWER, which is what the reference does at this width. A
     drawer needs a script, a scrim, a focus trap and an Escape handler to be
     usable, and this is five links — a scrolling row is the smaller thing that
     works, including with JavaScript switched off. */
  header .wrap { min-height: 0; padding-top: 10px; padding-bottom: 10px;
    row-gap: 8px; column-gap: 10px }
  .brand { font-size: 16px }
  .brand img { width: 44px; height: 44px }
  .nav-login { margin-left: auto; padding: 8px 16px; order: 2 }
  /* Beside Sign in on the first row, which then gives up its auto margin to
     it: the pair sits right, the brand left, the links on the row below.
     BOTH GO COMPACT HERE (2026-09-30): at full size the brand and two buttons
     measured 361px for a 284px row on a 320px phone, and Sign in wrapped onto
     a row of its own. */
  .nav-try { margin-left: auto; padding: 6px 9px; order: 2; font-size: 13px }
  .nav-try + .nav-login { margin-left: -2px; padding: 7px 11px; font-size: 13px }
  /* THE NAME MAY TAKE TWO LINES; SIGN IN MAY NOT TAKE A ROW (2026-10-01).
     Under DejaVu Sans, which is what system-ui is on the Linux browsers CI
     runs, "Digital Front Desk" is ~157px at 16px and the first row needed
     393px of a 354px row at 390 wide: Sign in wrapped onto a row of its own
     and the header measured 139px, failing every release that day. A zero
     basis lets the buttons claim their width first and the name wrap beside
     the mark, inside the 44px the mark already makes the row. On the faces
     most phones have it still fits on one line. */
  .brand { flex: 1 1 0; min-width: 0; line-height: 1.15 }
  header nav { order: 3; width: 100%; margin-left: 0; gap: 18px; font-size: 14px;
    overflow-x: auto; scrollbar-width: none }
  header nav::-webkit-scrollbar { display: none }
  header nav a { white-space: nowrap }

  /* THE CTA BUTTONS GO FULL WIDTH, because a 28px-padded button next to
     another one leaves a stub of a tap target at the end of a narrow row. */
  .cta { gap: 10px }
  .cta .btn, .cta .ghost { width: 100%; justify-content: center }

  /* THE SUBTITLES GO BEFORE THE LABELS DO. Under about 500px of orbit a card is
     ~110px wide and "Texts and replies" is clamped to two cramped lines; the
     noun on its own still carries the diagram, and the ring gets shorter cards
     to breathe with. The ring widens to use the space the shorter cards free. */
  .orbit { --ring: 39%; --card: 20% }
  .orbit-node { padding: 9px 5px 10px }
  .orbit-node small { display: none }
  .orbit-hub b { font-size: 12.5px }
  .orbit-hub small { font-size: 11px }
}

@media (max-width: 560px) {
  .wrap { padding: 0 18px }
  section { padding: 52px 0 }
  .hero { padding: 40px 0 48px }
  .plan .price strong { font-size: 32px }
  .card, .plan { padding: 22px }
  .panel { padding: 24px; border-radius: var(--radius) }
}

/* Under ~360px the brand, the menu button and the two status icons no longer
   share one row, and the icons wrapped onto a second line — a 115px-tall header
   on the smallest phone we support. The title tightens so the header stays
   one line tall. */
@media (max-width: 360px) {
  .brand { font-size: 15px; gap: 5px }
  .brand img { width: 38px; height: 38px }
}


/* ---------------------------------------------------------------------------
   THE PRICE PICKER. Markup and the argument for it live in
   app/templates/site/_price_picker.html.

   Two columns: what you are choosing on the left, what it costs on the right,
   and the right-hand one sticks to the top of its column so the number stays
   in view while somebody works down the list. One column on a narrow screen,
   with the total first, because on a phone the answer should not be below
   three fieldsets. */
.picker {
  display: grid; grid-template-columns: 1.25fr .75fr; gap: 28px;
  align-items: start; margin-top: 26px;
}
.picker-set { border: 0; padding: 0; margin: 0 0 22px }
.picker-set[hidden] { display: none }
.picker-group { margin-bottom: 10px }
.picker-group .picker-opt { margin-bottom: 0 }
/* THE LADDER, INDENTED UNDER THE PRODUCT IT PRICES, with a rule down the left
   so the eye reads "these belong to the box above" rather than "here is
   another list". */
.picker-sub {
  border: 0; border-left: 2px solid var(--accent-line); border-radius: 0;
  margin: 10px 0 0 21px; padding: 2px 0 2px 18px;
}
.picker-sub[hidden] { display: none }
.picker-sub legend { padding: 0; margin: 0 0 10px; font-size: 13.5px;
  font-weight: 650; color: var(--muted) }
.picker-sub .picker-opt { padding: 12px 15px; margin-bottom: 8px }
.picker-sub .picker-opt:last-child { margin-bottom: 0 }
.picker-sub .picker-opt-name { font-size: 14.5px }
.picker-sub .picker-opt-price { font-size: 14px }
.picker-sub .picker-opt-what { font-size: 13.5px }
.picker-set legend {
  padding: 0; margin: 0 0 12px; font-size: 14px; font-weight: 650;
  color: var(--muted); letter-spacing: .01em;
}
.picker-opt {
  display: flex; gap: 13px; align-items: flex-start; cursor: pointer;
  border: 1px solid var(--line); border-radius: 12px; background: var(--surface);
  padding: 15px 17px; margin-bottom: 10px;
  transition: border-color var(--ease), box-shadow var(--ease);
}
.picker-opt:hover { border-color: var(--accent-line) }
.picker-opt:has(input:checked) {
  border-color: var(--accent); box-shadow: var(--shadow-sm);
  background: var(--accent-pale);
}
.picker-opt:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px }
.picker-opt input { margin: 2px 0 0; width: 18px; height: 18px; accent-color: var(--accent); flex: none }
.picker-opt-body { display: grid; grid-template-columns: 1fr auto; gap: 2px 14px; flex: 1 }
.picker-opt-name { font-weight: 650; color: var(--ink); font-size: 15.5px }
.picker-opt-price { font-weight: 650; color: var(--accent); font-size: 15px; white-space: nowrap }
.picker-opt-what { grid-column: 1 / -1; color: var(--muted); font-size: 14px; line-height: 1.45 }

.picker-total {
  position: sticky; top: 92px;
  border: 1px solid var(--accent-line); border-radius: 14px;
  background: var(--surface); padding: 22px; box-shadow: var(--shadow-md);
}
.picker-total-label { margin: 0; font-size: 13px; color: var(--muted); font-weight: 650 }
.picker-amount { margin: 4px 0 0; font-size: 44px; font-weight: 800; color: var(--ink);
  letter-spacing: -.035em; line-height: 1 }
.picker-per { margin: 7px 0 0; font-size: 14px; color: var(--muted) }
.picker-annual { margin: 3px 0 0; font-size: 14px; color: var(--muted) }
.picker-annual b { color: var(--ink) }
.picker-lines { list-style: none; padding: 16px 0 0; margin: 16px 0 0;
  border-top: 1px solid var(--line); font-size: 14px; color: var(--body) }
.picker-lines li { display: flex; justify-content: space-between; gap: 14px; padding: 4px 0 }
.picker-lines b { color: var(--ink); white-space: nowrap }
.picker-empty { margin: 16px 0 0; font-size: 14px; color: var(--muted) }
.picker-go { display: block; text-align: center; margin-top: 18px }
.picker-go.is-off { opacity: .45; pointer-events: none }
.picker-foot { margin: 12px 0 0; font-size: 12.5px; color: var(--muted); line-height: 1.45 }
.picker-scope { margin-top: 20px }
.picker-hint { margin: 12px 0 0; font-size: 13.5px; color: var(--accent); font-weight: 600 }
/* THE TYPICAL AGENCY PRICE, STRUCK THROUGH IN RED (owner, 2026-09-24). Red
   is the line, not the figure, so the number under it stays readable; the
   label beside it on the page says whose price it is — see
   app/services/pricing.py for why that label is not optional. */
.price-market { color: var(--muted); font-weight: 500; text-decoration: line-through;
  text-decoration-color: #dc2626; text-decoration-thickness: 2px; margin-right: 4px }
.price-market-note { display: block; margin-top: 2px; color: #b91c1c; font-weight: 600; font-size: 13px }

/* ---------------------------------------------------------------------------
   PACKAGES, above the picker on /pricing. ``pkg-`` because .plan, .card and
   .panel are global in this stylesheet and a new page reusing one inherits a
   look it did not ask for. */
.pkgs { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; margin-top: 26px }
.pkg { position: relative; display: flex; flex-direction: column; border: 1px solid var(--line);
  border-radius: 14px; background: var(--surface); padding: 24px 22px 22px }
.pkg.is-featured { border: 2px solid var(--accent); box-shadow: var(--shadow-md) }
.pkg-flag { position: absolute; top: -12px; left: 22px; background: var(--accent); color: #fff;
  font-size: 12px; font-weight: 700; padding: 3px 10px; border-radius: 999px }
.pkg h3 { margin: 0 }
.pkg-who { margin: 6px 0 0; color: var(--muted); font-size: 14px; line-height: 1.45 }
.pkg-price { margin: 16px 0 0; font-size: 38px; font-weight: 800; color: var(--ink);
  letter-spacing: -.03em; line-height: 1 }
.pkg-price span { font-size: 14px; font-weight: 500; color: var(--muted); letter-spacing: 0 }
.pkg-annual { margin: 5px 0 0; font-size: 13.5px; color: var(--muted) }
.pkg-parts { list-style: none; padding: 14px 0 0; margin: 14px 0 0; border-top: 1px solid var(--line);
  font-size: 14px; color: var(--body); flex: 1 }
.pkg-parts li { display: flex; justify-content: space-between; gap: 12px; padding: 4px 0 }
.pkg-parts b { color: var(--ink); white-space: nowrap }
.pkg-parts li.is-free b { color: #15803d }
.pkg .btn { display: block; text-align: center; margin-top: 18px }
.pkg-basis { margin-top: 18px; font-size: 13px; color: var(--muted); line-height: 1.5 }
@media (max-width: 860px) {
  .pkgs { grid-template-columns: 1fr; gap: 22px }
}

@media (max-width: 860px) {
  .picker { grid-template-columns: 1fr; gap: 22px }
  .picker-choose { order: 2 }
  .picker-total { order: 1; position: static }
  .picker-amount { font-size: 38px }
}
/* On a phone the name and the price stop sharing a row: side by side, "Visitor
   Assistant" wrapped to two lines to make room for a figure that never wraps,
   which reads as a mistake rather than a layout. */
@media (max-width: 560px) {
  .picker-opt-body { grid-template-columns: 1fr; gap: 3px }
  .picker-opt-price { white-space: normal }
  .picker-sub { margin-left: 10px; padding-left: 12px }
}

/* ---------------------------------------------------------------------------
   "WHAT WILL IT COST?" WITHOUT NUMBERS, on the landing page while prices are
   hidden there (2026-09-25). The checkbox cards are the price picker's own
   .picker-opt so the two versions of the section look like one product. */
.cost-ask { margin-top: 22px }
.cost-ask-set { border: 0; padding: 0; margin: 0 0 18px;
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px }
.cost-ask-set .picker-opt { margin-bottom: 0 }
.cost-ask-set .picker-opt-body { grid-template-columns: 1fr }
@media (max-width: 640px) { .cost-ask-set { grid-template-columns: 1fr } }


/* ---------- blog (2026-09-27) ---------- */
/* THE READING MEASURE. Articles are long prose read on phones as often as on
   desktops: about 70 characters a line, a generous line height, and a body
   size that does not shrink below 17px on a small screen. The hero keeps the
   site's dark band so a guide looks like part of the same site; no image,
   because there is no picture that would say anything the title does not. */
.blog-measure { max-width: 780px }
/* Read by a screen reader, not drawn. */
.blog-sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0 }
.blog-hero { padding: 64px 0 52px }
.blog-hero h1 { font-size: clamp(30px, 4.2vw, 44px); line-height: 1.12; letter-spacing: -.025em;
  margin: 14px 0 12px; color: #fff }
.blog-hero .sub { max-width: 62ch }
.blog-crumbs { font-size: 14px; color: var(--on-dark-dim) }
.blog-crumbs a { color: var(--on-dark); text-decoration: none }
.blog-crumbs a:hover { text-decoration: underline }
.blog-byline { margin: 0; font-size: 15px; color: var(--on-dark-dim) }

.blog-article { padding: 40px 0 72px }
.blog-toc { border: 1px solid var(--line); border-radius: 12px; background: var(--surface);
  padding: 18px 22px; margin: 0 0 36px }
.blog-toc h2 { font-size: 13px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); margin: 0 0 8px }
.blog-toc ul { margin: 0; padding: 0; list-style: none }
.blog-toc li { margin: 5px 0; line-height: 1.45 }
.blog-toc a { color: var(--accent); text-decoration: none }
.blog-toc a:hover { text-decoration: underline }

.blog-body { font-size: 18px; line-height: 1.72; color: var(--body) }
.blog-body p, .blog-body li { max-width: 70ch }
.blog-body .blog-lede { font-size: 20px; line-height: 1.6; color: var(--ink) }
.blog-body h2 { font-size: 26px; line-height: 1.25; letter-spacing: -.015em;
  margin: 48px 0 12px; scroll-margin-top: 90px }
.blog-body h3 { font-size: 19px; line-height: 1.35; margin: 26px 0 6px }
.blog-body ul { padding-left: 22px }
.blog-body li { margin: 6px 0 }
.blog-body a { color: var(--accent); text-underline-offset: 3px }
.blog-body .blog-ask { border-left: 4px solid var(--accent); background: var(--accent-pale);
  border-radius: 0 10px 10px 0; padding: 12px 16px; font-size: 17px }
.blog-faq { border-top: 1px solid var(--line); margin-top: 8px }
.blog-faq h3 { margin-top: 28px }
.blog-disclaimer { margin-top: 40px; font-size: 15px; color: var(--muted) }

.blog-more { margin-top: 56px; padding-top: 24px; border-top: 1px solid var(--line) }
.blog-more h2 { font-size: 20px; margin: 0 0 10px }
.blog-more ul { padding-left: 20px; margin: 0 0 14px; font-size: 17px }
.blog-more a { color: var(--accent) }

.blog-list { padding: 44px 0 72px }
.blog-cards { list-style: none; margin: 0; padding: 0; display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px }
.blog-card { border: 1px solid var(--line); border-radius: 14px; background: var(--surface);
  padding: 24px 24px 22px; display: flex; flex-direction: column }
.blog-card h2 { font-size: 22px; line-height: 1.3; letter-spacing: -.01em; margin: 8px 0 10px }
.blog-card h2 a { color: var(--ink); text-decoration: none }
.blog-card h2 a:hover { color: var(--accent) }
.blog-card p { margin: 0 0 14px; color: var(--body); line-height: 1.6 }
.blog-card .blog-card-meta { font-size: 14px; color: var(--muted); margin: 0 }
.blog-region { display: inline-block; font-size: 12px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--accent); background: var(--accent-pale);
  border-radius: 999px; padding: 2px 9px; margin-right: 6px }
.blog-card-more { margin-top: auto; color: var(--accent); font-weight: 600; text-decoration: none }

@media (max-width: 760px) {
  .blog-hero { padding: 40px 0 34px }
  .blog-cards { grid-template-columns: 1fr }
  .blog-body { font-size: 17px; line-height: 1.68 }
  .blog-body .blog-lede { font-size: 18px }
  .blog-body h2 { font-size: 22px; margin-top: 38px }
  .blog-body h3 { font-size: 18px }
  .blog-toc { padding: 14px 16px }
}

/* FOUR MENU ITEMS ON A 320px PHONE (2026-09-27). "Blog" made the row 4px wider
   than the screen; the strip scrolls, but with its scrollbar hidden "Talk to
   us" simply looked cut off. A tighter gap fits all four. */
@media (max-width: 360px) {
  header nav { gap: 13px }
}
/* THE NARROWEST PHONES KEEP THE MARK AND LOSE THE WORDS (2026-09-30). With
   "Try it free" beside Sign in, the words "Digital Front Desk" are what no
   longer fit on a 320-389px first row, and a header that wraps its sign-in
   button onto a third line is worse than a logo on its own. font-size 0
   rather than display:none, so the words stay the link's accessible name. */
@media (max-width: 389px) {
  header .brand { font-size: 0; gap: 0 }
}


/* ------------------------------------------------------------------ */
/* /appointment-reminders (2026-09-27). rem- because .card, .panel and */
/* .plan are already global here and reusing one restyles this page.   */
.rem-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px }
.rem-card { border: 1px solid var(--line); border-radius: 14px; background: var(--surface);
  padding: 26px 26px 22px }
.rem-card h3, .rem-grid h3 { margin: 0 0 10px; font-size: 20px; line-height: 1.3 }
.rem-grid > div h3 + p { margin-bottom: 22px }
.rem-card ul { padding-left: 20px; margin: 0 0 18px; color: var(--body); line-height: 1.6 }
.rem-card li { margin: 6px 0 }
.rem-label { font-size: 12px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted); margin: 0 0 8px }
/* A text message, as a bubble: the reader should recognise it at a glance. */
.rem-sms { background: var(--accent-pale); border: 1px solid var(--accent-line);
  border-radius: 16px 16px 16px 4px; padding: 12px 16px; margin: 0; font-size: 15.5px;
  line-height: 1.5; color: var(--ink); overflow-wrap: anywhere }
.rem-grid a, .rem-faq a { color: var(--accent); text-underline-offset: 3px }
.rem-faq { max-width: 72ch }
.rem-faq h3 { font-size: 19px; line-height: 1.35; margin: 28px 0 6px }
.rem-faq h3:first-child { margin-top: 0 }
.rem-faq p { margin: 0; color: var(--body); line-height: 1.65 }
.rem-close { text-align: left }
.rem-link { color: var(--accent); font-weight: 600; text-decoration: none }
@media (max-width: 820px) { .rem-grid { grid-template-columns: 1fr } }

/* The hero: a phone receiving the reminder, two stills cross-faded. */
.rem-hero { position: relative; overflow: hidden; background: #f4efe8;
  min-height: min(620px, 56.3vw) }
.rem-hero-art, .rem-hero-art img { position: absolute; inset: 0; width: 100%; height: 100% }
.rem-hero-art img { object-fit: cover; object-position: 78% 50% }
/* Wall on the left, and a wash across it so the words stay readable on any
   crop the width produces. */
.rem-hero-art::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, rgba(248,244,238,.94) 0%, rgba(248,244,238,.82) 38%,
  rgba(248,244,238,0) 62%) }
.rem-hero-lit { animation: rem-text-arrives 9s ease-in-out infinite }
@keyframes rem-text-arrives {
  0%, 22% { opacity: 0 }       /* the phone, dark */
  30%, 84% { opacity: 1 }      /* the reminder, long enough to read */
  94%, 100% { opacity: 0 }
}
@media (prefers-reduced-motion: reduce) { .rem-hero-lit { animation: none; opacity: 1 } }
.rem-hero-copy { position: relative; z-index: 1; padding-top: 72px; padding-bottom: 72px }
.rem-hero-copy h1 { color: var(--ink); max-width: 16ch; font-size: clamp(34px, 4.2vw, 54px);
  line-height: 1.08; letter-spacing: -.02em; margin: 16px 0 18px }
.rem-hero-sub { color: var(--body); font-size: 18px; line-height: 1.6; max-width: 44ch; margin: 0 0 26px }
.rem-hero-pill { display: inline-block; font-size: 13px; font-weight: 700; letter-spacing: .04em;
  color: var(--accent-ink); background: var(--accent-pale); border: 1px solid var(--accent-line);
  border-radius: 999px; padding: 6px 12px }
.rem-hero-note { margin: 22px 0 0; font-size: 14px; color: var(--muted) }
/* NARROW: words first, then the picture as its own block, uncovered. */
@media (max-width: 820px) {
  .rem-hero { min-height: 0; display: flex; flex-direction: column-reverse }
  /* Cropped to 4:3 around the phone, which the full wide frame shrinks to
     a thumbnail at this width. */
  .rem-hero-art { position: relative; aspect-ratio: 4 / 3 }
  .rem-hero-art img { object-position: 76% 50% }
  .rem-hero-art::after { content: none }
  .rem-hero-copy { padding-top: 40px; padding-bottom: 28px }
}


/* ------------------------------------------------------------------ */
/* /virtual-receptionist-canada (2026-09-28). vr- for the same reason  */
/* as rem- above; the FAQ, pill and close reuse the rem- rules on      */
/* purpose so the two feature pages read as a set.                     */
.vr-measure { max-width: 76ch }
.vr-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px }
.vr-grid h3 { margin: 0 0 8px; font-size: 20px; line-height: 1.3 }
.vr-grid p, .vr-note { color: var(--body); line-height: 1.65; margin: 0 }
.vr-note { margin-top: 24px; max-width: 76ch }
.vr-grid a, .vr-note a, .vr-measure a { color: var(--accent); text-underline-offset: 3px }
/* The comparison scrolls inside its own box on a phone, never the page. */
.vr-table-wrap { overflow-x: auto; margin-top: 8px }
.vr-table { width: 100%; min-width: 620px; border-collapse: collapse; font-size: 15.5px }
.vr-table th, .vr-table td { text-align: left; vertical-align: top; padding: 12px 14px;
  border-bottom: 1px solid var(--line); line-height: 1.5 }
.vr-table thead th { font-size: 13px; letter-spacing: .04em; text-transform: uppercase; color: var(--muted) }
.vr-table tbody th { font-weight: 600; color: var(--ink); white-space: nowrap }
.vr-table td:first-of-type { background: var(--accent-pale) }
@media (max-width: 820px) { .vr-grid { grid-template-columns: 1fr } }
