/* ==========================================================================
   FoundrySuite marketing site
   --------------------------------------------------------------------------
   Same palette discipline as the application (foundrysuite/webapp/assets/css/
   tokens.css): dark-first, system font stacks only, and every foreground /
   background pair chosen to clear WCAG AA rather than adjusted until it looks
   right. Colors were checked with tests/test_wcag_contrast.py's math.

   The page loads no third-party resource of any kind — no web font, no CDN,
   no analytics, no tracker, no image host. That is not an accident of the
   build; it is the first claim the site makes, and it is checkable in the
   network tab.
   ========================================================================== */

:root {
  /* Without this the browser renders its own widgets in the light scheme it
     assumes by default: a white scrollbar track against a near-black page, and
     a light flash behind the text before the stylesheet lands. One line, and it
     is the difference between a page that looks deliberate and one that looks
     like an unstyled document with a theme applied. */
  color-scheme: dark;

  /* --- type ------------------------------------------------------------- */
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
    Arial, "Noto Sans", "Liberation Sans", sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", "Roboto Mono", monospace;

  /* --- color: dark is the default -------------------------------------- */
  --bg-canvas: #08090c;
  --bg-subtle: #0b0d11;
  --bg-surface: #101319;
  --bg-raised: #161a21;
  --bg-inset: #0d1015;

  --text-primary: #e9ebf1;
  --text-secondary: #9ba3b2;
  --text-muted: #7b8291;

  --border-subtle: #1c2029;
  --border-default: #252a34;
  --border-strong: #343b48;
  /* The frame around a screenshot. Deliberately several steps lighter than
     --border-strong: the product's own dark interface sits against this page at
     a luminance almost identical to --bg-canvas, so the edge is the only
     cue that the picture has an edge. 3.38:1 against the canvas, 3.16:1 against
     --bg-surface, because a shot can land on either. */
  --border-figure: #5c6573;

  --accent: #8579ff;
  --accent-hover: #968cff;
  /* The label on the accent fill is dark, not white. This accent is bright
     enough that white on it measures 3.4:1 — it is a 16px semibold label, not
     large text, so the bar is 4.5:1 and white fails it. The application picks
     this label the same way, by measuring rather than by convention
     (theme-core.js bestLabelOn). */
  --accent-text: #101116;
  /* An accent that clears 4.5:1 against its own 10% wash, not only against
     the page. The wash is composited when the check is made; see the note in
     the application's tokens.css. */
  --accent-on-soft: #9489ff;
  --accent-soft: rgba(133, 121, 255, 0.12);
  --accent-border: rgba(133, 121, 255, 0.34);

  --success: #4ea86b;
  --success-soft: rgba(78, 168, 107, 0.12);
  --warn: #d9a441;
  --warn-soft: rgba(217, 164, 65, 0.12);
  --danger: #e06a5e;

  /* --- space ------------------------------------------------------------ */
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.25rem;
  --s-6: 1.5rem;
  --s-7: 1.75rem;
  --s-8: 2rem;
  --s-10: 2.5rem;
  --s-12: 3rem;
  --s-16: 4rem;
  --s-20: 5rem;
  --s-24: 6rem;

  --r-sm: 6px;
  --r-md: 10px;
  --r-lg: 14px;
  --r-xl: 20px;
  --r-full: 999px;

  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --t-fast: 120ms;

  --maxw: 1140px;
  --measure: 68ch;
  --header-h: 64px;
}

/* The light palette is designed, not inverted: the dark accent is far too
   light to sit as a link on white, and the dark background cannot simply be
   flipped without losing the hierarchy the dark theme gets from its surfaces. */
[data-theme="light"] {
  /* The native widgets follow the palette, not the OS. A dark scrollbar
     thumb on a white page is the same defect in the other direction. */
  color-scheme: light;

  --bg-canvas: #f7f8fa;
  --bg-subtle: #f1f3f6;
  --bg-surface: #ffffff;
  --bg-raised: #ffffff;
  --bg-inset: #f5f6f9;

  --text-primary: #16181d;
  --text-secondary: #4d5462;
  --text-muted: #5b6270;

  --border-subtle: #e7e9ee;
  --border-default: #dcdfe6;
  --border-strong: #b9bfcb;
  /* See the note on the dark theme's value. Here the screenshots are dark
     figures on a light page, so they read against the page on their own and
     this only has to mark the edge: 3.31:1 on the canvas, 3.52:1 on a surface. */
  --border-figure: #818999;

  --accent: #5a49e0;
  --accent-hover: #4c3dbc;
  --accent-text: #ffffff;
  --accent-on-soft: #5a49e0;
  --accent-soft: rgba(90, 73, 224, 0.09);
  --accent-border: rgba(90, 73, 224, 0.3);

  --success: #18723a;
  --warn: #8a5904;
  --danger: #b8332b;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + var(--s-6));
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg-canvas);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  line-height: 1.2;
  letter-spacing: -0.02em;
  font-weight: 640;
  text-wrap: balance;
}

h1 { font-size: clamp(2.1rem, 1.35rem + 3.2vw, 3.5rem); }
h2 { font-size: clamp(1.55rem, 1.15rem + 1.8vw, 2.3rem); }
h3 { font-size: 1.16rem; letter-spacing: -0.012em; }

p { margin: 0; text-wrap: pretty; }

a {
  color: var(--accent);
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
a:hover { color: var(--accent-hover); }

/* A visible band, not a 1px outline. Same reasoning as the application's
   focus ring: the band that is actually painted is what gets measured. */
:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--bg-canvas), 0 0 0 4.5px var(--accent);
  border-radius: var(--r-sm);
}

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

.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--s-6);
}

.skip-link {
  position: absolute;
  left: var(--s-4);
  top: -100px;
  z-index: 100;
  padding: var(--s-3) var(--s-5);
  background: var(--accent);
  color: var(--accent-text);
  border-radius: var(--r-sm);
  font-weight: 600;
  text-decoration: none;
  transition: top var(--t-fast) var(--ease-out);
}
.skip-link:focus {
  top: var(--s-4);
  color: var(--accent-text);
}

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

.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  height: var(--header-h);
  display: flex;
  align-items: center;
  background: color-mix(in srgb, var(--bg-canvas) 88%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border-subtle);
}

.site-header .wrap {
  display: flex;
  align-items: center;
  gap: var(--s-6);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  font-weight: 660;
  letter-spacing: -0.02em;
  font-size: 1.03rem;
  color: var(--text-primary);
  text-decoration: none;
  white-space: nowrap;
}
.brand:hover { color: var(--text-primary); }

.brand-mark {
  width: 26px;
  height: 26px;
  border-radius: 7px;
  display: grid;
  place-items: center;
  background: linear-gradient(135deg, var(--accent) 0%, var(--accent-hover) 100%);
  color: var(--accent-text);
  flex: none;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: var(--s-5);
  margin-left: auto;
  font-size: 0.9rem;
}

.site-nav a {
  color: var(--text-secondary);
  text-decoration: none;
  padding: var(--s-2) 0;
  border-bottom: 1.5px solid transparent;
  white-space: nowrap;
}
.site-nav a:hover { color: var(--text-primary); }
.site-nav a[aria-current="page"] {
  color: var(--text-primary);
  border-bottom-color: var(--accent);
}

.nav-toggle,
.theme-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  /* 44px is the smallest target a thumb reliably lands on first time. At 36px
     this control is the one thing on a phone that is easy to miss, and missing
     it means the menu does not open at all -- not a slow interaction but a
     dead one. The icon stays the same size; the button is just bigger. */
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--border-default);
  border-radius: var(--r-sm);
  background: var(--bg-surface);
  color: var(--text-secondary);
  cursor: pointer;
  /* Flexbox would otherwise resolve a crowded header row by shrinking these,
     and it shrinks them to whatever is left over -- measured at 26px wide on
     trial.html at 390px. That defeats the 44px target above on the one control
     whose failure means no navigation at all. */
  flex: none;
}
.nav-toggle:hover,
.theme-toggle:hover { color: var(--text-primary); border-color: var(--border-strong); }

.header-actions {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin-left: var(--s-2);
}

/* --- buttons ------------------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  padding: 0.6rem 1.05rem;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  font: inherit;
  font-size: 0.92rem;
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--t-fast) var(--ease-out),
    border-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
}

.btn-primary {
  background: var(--accent);
  color: var(--accent-text);
  border-color: var(--accent);
}
.btn-primary:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
  color: var(--accent-text);
}

.btn-secondary {
  background: var(--bg-surface);
  color: var(--text-primary);
  border-color: var(--border-default);
}
.btn-secondary:hover {
  border-color: var(--border-strong);
  color: var(--text-primary);
}

.btn-ghost {
  background: transparent;
  color: var(--text-secondary);
  border-color: transparent;
}
.btn-ghost:hover { color: var(--text-primary); background: var(--bg-surface); }

.btn-lg { padding: 0.8rem 1.4rem; font-size: 1rem; }

/* The header CTA is deliberately quieter than the hero CTA. A filled accent
   button appears on every page at a fixed position, and when it is the same
   filled accent as the page's primary action the eye has two equally-weighted
   targets and no reason to prefer one -- three design reviewers flagged this
   independently on nearly every page. Outlined here, filled in the hero: the
   strongest color on the screen is the action that page exists to prompt. */
.btn-nav-cta {
  background: var(--accent-soft);
  color: var(--accent);
  border-color: var(--accent-border);
}
.btn-nav-cta:hover {
  background: var(--accent);
  color: var(--accent-text);
  border-color: var(--accent);
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  align-items: center;
}

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

.hero {
  position: relative;
  overflow: hidden;
  padding: var(--s-20) 0 var(--s-16);
  border-bottom: 1px solid var(--border-subtle);
}

/* A quiet grid rather than an image: no network request, no layout shift, and
   it cannot be mistaken for a screenshot of the product. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right, var(--border-subtle) 1px, transparent 1px),
    linear-gradient(to bottom, var(--border-subtle) 1px, transparent 1px);
  background-size: 56px 56px;
  mask-image: radial-gradient(ellipse 80% 60% at 50% 0%, #000 20%, transparent 75%);
  opacity: 0.55;
  pointer-events: none;
}

.hero::after {
  content: "";
  position: absolute;
  inset: -20% 0 auto 0;
  height: 420px;
  background: radial-gradient(ellipse 60% 100% at 50% 0%, var(--accent-soft), transparent 70%);
  pointer-events: none;
}

.hero .wrap { position: relative; z-index: 1; }

.hero-inner { max-width: 780px; }

/* The narrow hero left roughly 600px of empty canvas to the right of the text
   on a 1440px screen. That whitespace is not neutral on a page whose job is to
   justify $2200: it is the space where the proof should be. A real screenshot
   of the running software sits there on every page that has one. */
.hero-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: var(--s-10);
  align-items: center;
}

.hero-split .hero-inner { max-width: none; }

.hero-shot {
  position: relative;
  /* Lift the top edge out of the hero's vertical padding so the picture reads
     as present rather than appended. */
  margin: 0;
  /* The screenshot is a 1440x900 dark dashboard: at full column width it is
     the highest-contrast object on the page and three design reviewers
     independently reported it pulling focus off the call to action. Framing
     it as a product shot on a surface -- a border, a shadow, slightly inset
     from the column edge -- makes it read as evidence being presented rather
     than as the page's headline, and keeps the hero's own heading and button
     as the two things the eye lands on. */
  padding: var(--s-3);
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-lg);
  box-shadow: 0 24px 60px -28px rgba(0, 0, 0, 0.5);
}

.hero-shot img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: calc(var(--r-lg) - 6px);
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-size: 0.78rem;
  font-weight: 620;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent-on-soft);
  background: var(--accent-soft);
  border: 1px solid var(--accent-border);
  padding: 0.32rem 0.7rem;
  border-radius: var(--r-full);
  margin-bottom: var(--s-5);
}

.lede {
  font-size: clamp(1.02rem, 0.98rem + 0.35vw, 1.2rem);
  color: var(--text-secondary);
  max-width: 62ch;
  margin-top: var(--s-5);
}

.hero .btn-row { margin-top: var(--s-8); }

.hero-note {
  margin-top: var(--s-5);
  font-size: 0.86rem;
  color: var(--text-muted);
}

/* --- hero pillars ------------------------------------------------------ */
/* The three claims under the hero buttons. A grid rather than
   three columns of prose: the icon, the bold lead and the
   explanation stay one unit at every width. */
.pillar-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr));
  gap: var(--s-4);
}
.pillar {
  display: flex;
  gap: var(--s-3);
  align-items: flex-start;
  padding: var(--s-4);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-md);
  background: var(--bg-surface);
}
.pillar p {
  margin: 0;
  font-size: 0.86rem;
  color: var(--text-secondary);
}
.pillar-icon {
  flex: none;
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  color: var(--accent);
}
.pillar-icon svg { width: 22px; height: 22px; }

/* --- sections ----------------------------------------------------------- */

.section { padding: var(--s-20) 0; }
.section-tight { padding: var(--s-12) 0; }
.section-alt { background: var(--bg-subtle); border-block: 1px solid var(--border-subtle); }

.section-head { max-width: 720px; margin-bottom: var(--s-10); }
.section-head p {
  margin-top: var(--s-4);
  color: var(--text-secondary);
  font-size: 1.02rem;
}

.lede-wide { max-width: var(--measure); }

/* --- screenshots --------------------------------------------------------- */

.shots .section-head { margin-bottom: var(--s-8); }

/* A figure, not a div: the caption is part of the content, and `margin: 0`
   because the user-agent gives figures one, whose left indent would knock the
   first column out of alignment with everything above it. */
.shot { margin: 0; }

.shot img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--r-lg);
  /* Not `--border-default`. That measures 1.38:1 in the dark theme, which is
     right for a hairline separating rows of text, and wrong here: a product
     screenshot is almost entirely dark fills, so on the dark page it has almost
     no luminance of its own and this border is the only thing telling a
     reader where the picture stops. That makes it the boundary of a graphical
     object, which SC 1.4.11 covers at 3:1. */
  border: 1px solid var(--border-figure);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), 0 10px 30px rgba(0, 0, 0, 0.16);
}

/* The lead shot is the one the eye should land on first. It is already the
   widest thing on the page by virtue of sitting outside the grid; this only
   lifts it off the surface a little further than the pair below. */
.shot-wide img {
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.22), 0 16px 44px rgba(0, 0, 0, 0.2);
}

.shot figcaption {
  margin-top: var(--s-4);
  font-size: 0.92rem;
  color: var(--text-secondary);
  max-width: var(--measure);
}
.shot figcaption strong { color: var(--text-primary); font-weight: 600; }

/* Two columns, always — and two specifically, rather than the `auto-fit` that
   `.grid-2` uses. `auto-fit` fills the width with as many 320px columns as fit,
   so at 1092px it made *three*, dropping the fourth figure onto a row of its
   own. That reads as a mistake rather than a layout. A screenshot pair is also
   the smallest a 1440px interface stays legible at, which `auto-fit` does not
   know and cannot be told.
   `minmax(min(100%, 420px), 1fr)` sets where the pair splits: two columns need
   420×2 plus the gap, so below about 860px of content width the figures stack
   instead. Stacking at that width is deliberate — two 350px screenshots of a
   1440px interface are too small to read, and one 700px one is not. On a phone
   `min(100%, …)` keeps it to a single full-width column.

   Written as `.grid.shot-row` rather than `.shot-row` because `.grid-2` is
   declared further down this file and both selectors have the same specificity,
   so the later rule won and the override silently did nothing. Two classes
   beats one on specificity, which makes this independent of where either rule
   ends up — the version with the single class was tested at 1280px, measured
   three columns, and looked correct in the stylesheet the whole time. */
.grid.shot-row {
  margin-top: var(--s-6);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr));
}

.shots-note {
  margin-top: var(--s-8);
  font-size: 0.92rem;
  max-width: var(--measure);
}

/* --- cards -------------------------------------------------------------- */

.grid { display: grid; gap: var(--s-5); }

/* A grid item defaults to `min-width: auto`, which means it refuses to shrink
   below its content. The table on the install page has a 620px floor and
   `overflow-x: auto` to scroll inside — but without this the column expanded to
   the table and pushed the whole page sideways instead. */
.grid > *,
.split > * { min-width: 0; }
/* The `min()` in the track floor is load-bearing. A bare `minmax(320px, 1fr)`
   is a *minimum*, so on a viewport narrower than the floor the track keeps its
   320px and pushes the page sideways -- measured at 320px, where the cards ran
   24px past the edge of the screen on the home and trial pages. */
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(min(272px, 100%), 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(min(232px, 100%), 1fr)); }

.card {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-lg);
  padding: var(--s-6);
}
.card h3 { margin-bottom: var(--s-3); }
.card p { color: var(--text-secondary); font-size: 0.94rem; }

/* --- detail cards ------------------------------------------------------- */
/* "The records, up close": a card whose whole job is one small
   table of the shape the product writes. The table is tighter
   than the page's tables (which are for wide comparison grids)
   and its figures are mono and right-aligned, so a debit and a
   credit read as the two things they are. Scoped to
   `.detail-table` rather than bare: a bare `td` rule would hit
   every table on the site. */
.detail-card { padding: var(--s-5); }
/* The generic `table` rule carries a 620px floor for the install
   page's wide table, which scrolls inside a `.table-wrap`. A detail
   table has no wrapper and is meant to fit its card, so the floor
   would push the card -- and on a phone the whole page -- sideways. */
.detail-table {
  width: 100%;
  min-width: 0;
  border-collapse: collapse;
  margin-top: var(--s-3);
  font-size: 0.88rem;
}
.detail-table td {
  padding: var(--s-2) 0;
  border-bottom: 1px solid var(--border-subtle);
  color: var(--text-secondary);
  vertical-align: baseline;
}
.detail-table tr:last-child td { border-bottom: 0; }
.detail-table .num { text-align: right; white-space: nowrap; }
.detail-table .strong { color: var(--text-primary); font-weight: 620; }

.card-icon {
  width: 34px;
  height: 34px;
  border-radius: var(--r-sm);
  display: grid;
  place-items: center;
  background: var(--accent-soft);
  color: var(--accent-on-soft);
  margin-bottom: var(--s-4);
  flex: none;
}

/* --- feature list ------------------------------------------------------- */

.checklist { list-style: none; margin: 0; padding: 0; }
.checklist li {
  position: relative;
  padding-left: 1.75rem;
  margin-bottom: var(--s-3);
  color: var(--text-secondary);
}
.checklist li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  border: 1.5px solid var(--success);
  background:
    linear-gradient(var(--success), var(--success)) center/9px 2px no-repeat;
  opacity: 0.9;
}
.checklist strong { color: var(--text-primary); font-weight: 620; }

/* --- split -------------------------------------------------------------- */

.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s-12);
  align-items: start;
}

.split-tight { gap: var(--s-8); }

/* --- table -------------------------------------------------------------- */

.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-lg);
  background: var(--bg-surface);
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.93rem;
  min-width: 620px;
}

th, td {
  text-align: left;
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--border-subtle);
  vertical-align: top;
}
thead th {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-secondary);
  font-weight: 620;
  background: var(--bg-inset);
}
tbody tr:last-child td { border-bottom: 0; }
td:first-child { color: var(--text-primary); font-weight: 560; }
td { color: var(--text-secondary); }

.yes { color: var(--success); font-weight: 600; }
.no { color: var(--text-muted); }

/* --- stat row ----------------------------------------------------------- */

.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
  gap: 1px;
  background: var(--border-subtle);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.stat {
  background: var(--bg-surface);
  padding: var(--s-6);
}
.stat-value {
  font-size: 1.5rem;
  font-weight: 660;
  letter-spacing: -0.02em;
  color: var(--text-primary);
  display: block;
}
.stat-label {
  font-size: 0.85rem;
  color: var(--text-secondary);
  margin-top: var(--s-1);
  display: block;
}

/* --- callout ------------------------------------------------------------ */

.callout {
  border: 1px solid var(--accent-border);
  background: var(--accent-soft);
  border-radius: var(--r-lg);
  padding: var(--s-6);
}
.callout h3 { margin-bottom: var(--s-2); }
.callout p { color: var(--text-secondary); }
.callout p + p { margin-top: var(--s-3); }

.callout-quiet {
  border-color: var(--border-default);
  background: var(--bg-inset);
}

/* --- pull quote --------------------------------------------------------- */

.quote {
  border-left: 3px solid var(--accent);
  padding-left: var(--s-6);
  font-size: 1.14rem;
  line-height: 1.55;
  color: var(--text-primary);
  max-width: var(--measure);
}
.quote-attr {
  margin-top: var(--s-4);
  font-size: 0.88rem;
  color: var(--text-secondary);
}

/* --- FAQ ---------------------------------------------------------------- */

.faq { max-width: 780px; }
.faq details {
  border-bottom: 1px solid var(--border-subtle);
  padding: var(--s-5) 0;
}
.faq details:first-of-type { border-top: 1px solid var(--border-subtle); }
.faq summary {
  cursor: pointer;
  font-weight: 600;
  list-style: none;
  display: flex;
  justify-content: space-between;
  gap: var(--s-4);
  color: var(--text-primary);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+";
  color: var(--text-muted);
  font-weight: 400;
  font-size: 1.2rem;
  line-height: 1.2;
}
.faq details[open] summary::after { content: "\2212"; }
.faq details p {
  margin-top: var(--s-4);
  color: var(--text-secondary);
  max-width: var(--measure);
}

/* --- CTA band ----------------------------------------------------------- */

.cta-band {
  border: 1px solid var(--border-default);
  border-radius: var(--r-xl);
  background: linear-gradient(160deg, var(--accent-soft), transparent 60%), var(--bg-surface);
  padding: var(--s-12) var(--s-8);
  text-align: center;
}
.cta-band p {
  margin: var(--s-4) auto 0;
  color: var(--text-secondary);
  max-width: 60ch;
}
.cta-band .btn-row { justify-content: center; margin-top: var(--s-8); }

/* --- segment nav (hub page) -------------------------------------------- */

.segment-grid { display: grid; gap: var(--s-4); grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr)); }

.segment-card {
  display: block;
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-lg);
  padding: var(--s-6);
  text-decoration: none;
  color: inherit;
  transition: border-color var(--t-fast) var(--ease-out), transform var(--t-fast) var(--ease-out);
}
.segment-card:hover {
  border-color: var(--accent-border);
  transform: translateY(-2px);
  color: inherit;
}
.segment-card h3 { font-size: 1.05rem; margin-bottom: var(--s-2); }
.segment-card p { color: var(--text-secondary); font-size: 0.92rem; }
.segment-card .more {
  margin-top: var(--s-4);
  color: var(--accent);
  font-size: 0.88rem;
  font-weight: 600;
}

/* A vertical on the who-its-for page: one row whose left side
   argues and whose right side is the way in. `.split` already
   supplies the two columns; these rules give the right-hand
   panel a surface of its own so the page reads as four
   sections rather than four walls of prose. */
.segment-section {
  align-items: stretch;
  margin-bottom: var(--s-12);
}
.segment-section:last-child { margin-bottom: 0; }
.segment-cta {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r-lg);
  padding: var(--s-6);
  display: flex;
  flex-direction: column;
}
.segment-cta p { color: var(--text-secondary); font-size: 0.94rem; }
.segment-cta .btn-row { margin-top: auto; }

/* --- prose page --------------------------------------------------------- */

.prose { max-width: var(--measure); }
.prose h2 { margin-top: var(--s-12); margin-bottom: var(--s-4); }
.prose h3 { margin-top: var(--s-8); margin-bottom: var(--s-3); }
.prose p { color: var(--text-secondary); margin-bottom: var(--s-4); }
.prose ul { color: var(--text-secondary); padding-left: 1.25rem; margin-bottom: var(--s-4); }
.prose li { margin-bottom: var(--s-2); }
.prose strong { color: var(--text-primary); }
.prose code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  background: var(--bg-inset);
  border: 1px solid var(--border-subtle);
  border-radius: 4px;
  padding: 0.1em 0.35em;
}

/* A digest is 64 unbroken hex characters and a shell command is not prose, so
   both have to be allowed the full width of their container and to scroll
   rather than wrap mid-token. */
pre {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--bg-inset);
  border: 1px solid var(--border-subtle);
  border-radius: 6px;
  padding: var(--s-3) var(--s-4);
  overflow-x: auto;
  margin: 0 0 var(--s-4);
  line-height: 1.5;
}
pre code {
  background: none;
  border: 0;
  padding: 0;
  font-size: 1em;
}
code.digest {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.82em;
  background: var(--bg-inset);
  border: 1px solid var(--border-subtle);
  border-radius: 6px;
  padding: var(--s-3) var(--s-4);
  overflow-wrap: anywhere;
  line-height: 1.6;
}

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

.site-footer {
  border-top: 1px solid var(--border-subtle);
  padding: var(--s-16) 0 var(--s-10);
  font-size: 0.9rem;
}
.footer-grid {
  display: grid;
  grid-template-columns: 1.6fr repeat(auto-fit, minmax(min(140px, 100%), 1fr));
  gap: var(--s-8);
}
/* These are <h2>, not <h4>. A footer heading hanging off an <h2> three
   sections earlier reads to a screen reader as an orphaned child of whatever
   section it was last in, which is how a skip-level defect happens. The
   visual treatment stays small and uppercase so the footer still reads as
   furniture rather than as a section. */
.footer-grid h2 {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  font-weight: 620;
  margin-bottom: var(--s-4);
}
.footer-grid ul { list-style: none; margin: 0; padding: 0; }
.footer-grid li { margin-bottom: var(--s-2); }
.footer-grid a { color: var(--text-secondary); text-decoration: none; }
.footer-grid a:hover { color: var(--text-primary); text-decoration: underline; }
.footer-about p { color: var(--text-secondary); max-width: 34ch; margin-top: var(--s-3); }

.footer-base {
  margin-top: var(--s-10);
  padding-top: var(--s-6);
  border-top: 1px solid var(--border-subtle);
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-4);
  justify-content: space-between;
  color: var(--text-muted);
  font-size: 0.85rem;
}

/* --- utilities ---------------------------------------------------------- */

.mono { font-family: var(--font-mono); }
.center { text-align: center; }
.mx-auto { margin-inline: auto; }
.mt-4 { margin-top: var(--s-4); }
.mt-6 { margin-top: var(--s-6); }
.mt-8 { margin-top: var(--s-8); }
.mt-10 { margin-top: var(--s-10); }
.mt-12 { margin-top: var(--s-12); }
.muted { color: var(--text-secondary); }
.small { font-size: 0.88rem; }
.nowrap { white-space: nowrap; }

.page-head {
  padding: var(--s-16) 0 var(--s-12);
  border-bottom: 1px solid var(--border-subtle);
}
.page-head .lede { margin-top: var(--s-4); }

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

.no-js-note { display: none; }

/* --- responsive --------------------------------------------------------- */

@media (max-width: 900px) {
  .split { grid-template-columns: 1fr; gap: var(--s-8); }
  .hero-split { grid-template-columns: 1fr; gap: var(--s-8); }
  .hero { padding: var(--s-16) 0 var(--s-12); }
  .section { padding: var(--s-16) 0; }
}

@media (max-width: 820px) {
  .nav-toggle { display: inline-flex; }
  .theme-toggle { display: inline-flex; }

  .site-nav {
    position: absolute;
    top: var(--header-h);
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: var(--s-3) var(--s-6) var(--s-5);
    background: var(--bg-canvas);
    border-bottom: 1px solid var(--border-default);
    margin-left: 0;
    font-size: 0.95rem;
  }
  /* Hidden by CSS rather than by a `hidden` attribute. The attribute would
     have to be set before the stylesheet loads, and on a slow connection the
     navigation would be visible and overlapping the hero for a moment. */
  .site-nav { display: none; }
  .site-nav.is-open { display: flex; }
  .site-nav a {
    padding: var(--s-3) 0;
    border-bottom: 1px solid var(--border-subtle);
  }
  .site-nav a[aria-current="page"] { border-bottom-color: var(--accent); }
  .header-actions { margin-left: var(--s-2); }
}

/* A button whose label is longer than its card cannot shrink, because the
   label is nowrap. Below this width the labels wrap instead — measured, after
   "Download it free to try" pushed a card 5px wider than its column at 375px. */
@media (max-width: 560px) {
  .btn { white-space: normal; max-width: 100%; }
  .btn-row .btn { flex: 1 1 12rem; }
}

/* At 390px the header asks for the brand, a call-to-action button and two 44px
   toggles -- more than fits. The toggles are now unshrinkable, so the shortfall
   has to come out of the padding and gaps instead; left alone the row ran 2px
   past the viewport and gave trial.html a horizontal scrollbar. */
@media (max-width: 480px) {
  .site-header .wrap { gap: var(--s-4); }
  .site-header .wrap { padding: 0 var(--s-4); }
  .header-actions { gap: var(--s-1); margin-left: var(--s-1); }
  .btn-nav-cta { padding: 0.45rem 0.7rem; font-size: 0.82rem; }
}

/* At 320px the brand, the call-to-action and two 44px toggles do not fit on one
   line, and hiding the call-to-action is not available: eight pages carry no
   other button near the top, so on pricing.html it is the only buy path on the
   page. The header takes two rows instead. --header-h is raised to match, which
   the mobile menu and the anchor scroll-padding both read, so they follow. */
@media (max-width: 360px) {
  :root { --header-h: 100px; }
  .site-header .wrap {
    flex-wrap: wrap;
    align-content: center;
    row-gap: var(--s-2);
  }
  .site-header .wrap .brand { flex: 1 1 100%; }
  .header-actions { margin-left: auto; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
/* --- pricing tiers ------------------------------------------------------- */

/* Three equal cards so the middle one being "featured" cannot read as "the
   other two are worse". The flag above the featured card is a label, not a
   different price: all three buy the identical software, and the page says so
   in a box directly beneath.

   Every card carries a flag row -- the featured one filled, the other two
   quiet -- so the flag reserves the same vertical space on all three and the
   tier names, the prices and the buy buttons line up horizontally across the
   columns rather than sitting at three different heights. */
.tiers {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(288px, 100%), 1fr));
  gap: var(--s-5);
  /* stretch (the grid default) is what makes the three cards equal
     height; `align-items: start` here used to size each card to its
     own content, so the middle card's flag pushed its price down a
     row and the three prices never lined up. */
  align-items: stretch;
}

.tier {
  display: flex;
  flex-direction: column;
  /* Equal-height cards whose buy buttons align: the auto margin on
     .tier-cta below absorbs the leftover space, which pins the CTA
     (and the total beneath it) to the bottom of every card however
     long the copy above it is. `space-between` is set as well -- the
     auto margin wins the free space first, so it changes nothing about
     the layout, but the intent ("distribute the card's content
     between top and bottom") is stated where the next reader looks. */
  justify-content: space-between;
  /* 2rem on every side, so no text and no button touches the card's
     left or right border. This used to read a custom property that was
     never defined, which invalidated the declaration and rendered the
     cards with no padding at all; see
     tests/test_site_pricing_typography.py. */
  padding: var(--s-8);
}

/* The twelve-month tier is the one most people take, and the site says so in
   the flag. A 1px ring does not carry that: the card still reads as one of
   three equal options, which is what three reviewers independently said they
   saw. The distinction has to be legible at a glance -- a tinted surface, a
   real elevation and a filled flag -- while the other two tiers keep the same
   content and the same prominence they have always had. Nothing is hidden or
   reordered; the choice stays entirely the buyer's. */
.tier-featured {
  border-color: var(--accent-border);
  background: var(--accent-soft);
  box-shadow: 0 0 0 1px var(--accent-border), 0 12px 32px -18px rgba(0, 0, 0, 0.35);
}

.tier-featured .tier-flag {
  display: inline-block;
  align-self: flex-start;
  background: var(--accent);
  color: var(--accent-text);
  border-radius: 999px;
  padding: 0.2rem 0.65rem;
  font-weight: 650;
}

.tier p.tier-flag {
  font-size: 0.74rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent-on-soft);
  margin-bottom: var(--s-3);
}

/* The two quiet flags. Same size, same tracking, same reserved height as
   the featured one -- only the fill is missing -- so the row above the
   tier name is spent identically on all three cards. */
.tier p.tier-flag-quiet {
  color: var(--text-muted);
  font-weight: 500;
}

.tier-name {
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin-bottom: var(--s-4);
}

/* Scoped under `.tier p` rather than left as a bare `.tier-amount`.

   `.card p` is `0,1,1`; a bare class selector is `0,1,0` and loses. Every
   tier paragraph is a `<p>` inside a `.card`, so the price, the flag above it
   and the cadence line beneath it were all rendering at `.card p`'s 0.94rem in
   the secondary color -- the headline price of the pricing page set in body
   copy grey. `tests/test_site_pricing_typography.py` fails if these go back
   to bare class selectors, and checks the computed size in a browser. */
.tier p.tier-amount {
  /* The headline price: text-4xl at the narrowest viewport, growing to
     text-5xl as the column widens, bold, in the page's primary (white,
     in the dark scheme the site ships in). */
  font-size: clamp(2.25rem, 2rem + 1.5vw, 3rem);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--text-primary);
  margin: 0;
}

/* The "/mo" unit: a fixed text-lg, so it reads as the unit of the price
   rather than as a smaller price, in the secondary grey -- the slate of
   the page's muted text. */
.tier-unit {
  font-size: 1.125rem;
  font-weight: 500;
  letter-spacing: 0;
  color: var(--text-secondary);
  margin-left: 0.3em;
}

.tier-cadence { margin-top: var(--s-2); }

/* The button sits at the bottom of every card regardless of how long the
   copy above it is, so the three prices line up horizontally and can be
   compared without reading. The auto margin is what pins it there on an
   equal-height card. */
.tier-cta {
  margin-top: auto;
  padding-top: var(--s-6);
}
.tier-cta .btn { width: 100%; }

/* --- tour walkthrough ---------------------------------------------------- */

/* One step of the walkthrough: a number in the margin, the prose beside it.
   The number is decorative and hidden from assistive technology, because it
   carries no information the heading does not already carry -- reading "step 1
   of 6" aloud before every section is noise. The list is an ordered one in the
   markup so the sequence is in the document, not only in the picture. */
.walk-step {
  display: grid;
  grid-template-columns: 56px 1fr;
  gap: var(--s-6);
  padding-block: var(--s-8);
  border-top: 1px solid var(--border-subtle);
}

.walk-step:first-of-type {
  border-top: 0;
  padding-top: 0;
}

.walk-num {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--accent-text);
  background: var(--accent);
  border-radius: var(--r-full);
}

.walk-body h3 {
  font-size: 1.35rem;
  margin-bottom: var(--s-4);
}

.walk-body > p {
  color: var(--text-secondary);
  max-width: var(--measure);
  margin-bottom: var(--s-4);
}

.walk-body .shot-wide { margin-top: var(--s-6); }

/* The number sits in the left column, so on a phone it would either squeeze the
   prose to nothing or push it off screen. Stacked instead: the number above the
   heading, full width, which reads as a step marker rather than a gutter. */
@media (max-width: 640px) {
  .walk-step {
    grid-template-columns: 1fr;
    gap: var(--s-4);
  }
  .walk-num {
    width: 36px;
    height: 36px;
    font-size: 1rem;
  }
}
