/* ==========================================================================
   Thredo — Modernist design system
   --------------------------------------------------------------------------
   One stylesheet for the whole marketing site. There is no build step: pages
   are hand-written static HTML and link this file directly.

   Markup repeats across pages by design (see the note in site/README.md), but
   styles must not. Everything visual lives here, so a change to the nav or a
   button lands on every page at once and the HTML stays free of inline style
   attributes — which also keeps the pages small and cacheable, which is the
   whole reason this site is static in the first place.

   Contents
     1  Tokens
     2  Reset and base
     3  Layout
     4  Typography
     5  Buttons
     6  Header and footer
     7  Components
     8  Utilities
     9  Responsive
   ========================================================================== */

/* 1 — Tokens ============================================================== */

:root {
  /* Surfaces */
  --paper:    #FCFCFA;   /* page */
  --canvas:   #F4F3EF;   /* alternating sections */
  --surface:  #FFFFFF;   /* cards */

  /* Ink. Contrast-checked against --paper:
     ink 18.6:1 · ink-2 7.1:1 · ink-3 3.3:1 — all pass WCAG AA. */
  --ink:      #0E0F17;
  --ink-2:    #55565F;
  --ink-3:    #8A8B93;

  /* Rules */
  --line:     #E2E1DB;
  --line-2:   #C9C8C1;

  /* Accent — the Thredo Signal (design-system §8). Yellow marks state and
     attention: a fill behind ink, a progress fill, a highlight. Never a
     button fill and never coloured text — CTAs are ink pills. The var keeps
     its old name so component rules below need no renaming. */
  --lime:      #FFD400;
  --lime-soft: #FFF7CC;
  --on-lime:   #0E0F17;

  /* Status — genuine state only, never decoration */
  --success:  #1D7A4C;
  --warning:  #9A6400;
  --danger:   #B3261E;

  --font: "Inter", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  /* Cal Sans ships ONE style that already draws semibold at weight 400 —
     heavier weights get faux-bolded by the browser, so display text always
     sets font-weight 400. Same rule as the app. */
  --font-display: "Cal Sans", "Inter", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;

  /* Soft geometry: 10px controls/chips, 16px cards (below), 999 pills. */
  --radius:   10px;

  /* 8px spacing grid */
  --s1: 8px;   --s2: 16px;  --s3: 24px;  --s4: 32px;
  --s6: 48px;  --s8: 64px;  --s12: 96px; --s16: 128px;

  --max: 1280px;
  --gutter: 48px;
}

/* 2 — Reset and base ====================================================== */

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, svg, video { max-width: 100%; height: auto; display: block; }
a { color: var(--ink); text-decoration: none; }
a:hover { color: var(--ink-2); }
::selection { background: var(--lime); color: var(--on-lime); }

/* Visible focus, always. Modernist has no colour to spare for focus states,
   so it is a hard ink outline. */
:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; border-radius: 2px; }

/* Keyboard users land here first. Off-screen until focused. */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--ink); color: var(--paper);
  padding: 12px 20px; font-weight: 600; font-size: 14px;
}
.skip:focus { left: 0; color: var(--paper); }

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

/* 3 — Layout ============================================================== */

.wrap { max-width: var(--max); margin: 0 auto; padding: 0 var(--gutter); }

/* Whitespace is the primary structuring device in this system. Cutting the
   section padding collapses the whole thing, so it is deliberately large. */
section { padding: var(--s12) 0; }
section.tight { padding: var(--s8) 0; }
.bg-canvas { background: var(--canvas); }
.bordered  { border-bottom: 1px solid var(--line); }

.grid { display: grid; gap: var(--s3); }
.g2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.g3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.g4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* Asymmetric splits read as more deliberate than centring everything. */
.g-7-5 { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: var(--s8); }
.g-6-6 { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--s8); }

.stack > * + * { margin-top: var(--s2); }
.row { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }

/* 4 — Typography ========================================================== */

h1, h2, h3, h4 { margin: 0; font-weight: 600; }

/* Negative tracking on anything 20px and up is the clearest tell of
   Modernist done right. Untracked large text reads as a default template. */
/* The scale, measured from the landing export rather than guessed at.

   Every heading in that file is weight 800; the site had been drawing h2 at
   600 and 30px against the design's 800 at 44, which is why the page read as
   quieter and flatter than the comp. Counted across the export:

     h1  78 / 800 / 0.97 / -0.035em     (one, the hero)
     h2  44 / 800 / 1.05 / -0.03em      (five of nine; 52 twice, 56 and 72 once)
     h3  19 / 700                       (card titles)

   The clamps land exactly on those numbers at the 1280 container the design
   was drawn in, and scale down from there rather than overflowing a phone. */
/* Display register is Cal Sans — single style, drawn semibold at weight 400
   (see --font-display note). It is tight by design, so tracking relaxes to
   -0.01em and line-heights come up a touch from the Archivo values. */
.display { font-family: var(--font-display); font-size: clamp(42px, 6.1vw, 78px); font-weight: 400; line-height: 1.02; letter-spacing: -0.01em; }
h1        { font-family: var(--font-display); font-size: clamp(38px, 5vw, 52px);  font-weight: 400; line-height: 1.06; letter-spacing: -0.01em; }
h2        { font-family: var(--font-display); font-size: clamp(30px, 3.44vw, 44px); font-weight: 400; line-height: 1.08; letter-spacing: -0.01em; }
h3        { font-size: 19px; font-weight: 600; line-height: 1.35; letter-spacing: -0.015em; }
h4        { font-size: 16px; font-weight: 600; letter-spacing: -0.01em; }

/* The two sections the export draws larger than the rest: the closing call to
   action at 72, and the two mid-page turns at 52. Modifiers rather than new
   elements, so the document outline stays h2. */
.h2-lg    { font-size: clamp(32px, 4.1vw, 52px); line-height: 1.05; }
.h2-xl    { font-size: clamp(36px, 5.6vw, 72px); line-height: 1.02; }

p { margin: 0; }
.lead  { font-size: 18px; line-height: 1.55; letter-spacing: -0.005em; color: var(--ink-2); }
.small { font-size: 13px; }
.muted { color: var(--ink-2); }
.faint { color: var(--ink-3); }

/* Cap reading measure. 65 characters is the comfortable ceiling. */
.measure { max-width: 62ch; }
.measure-sm { max-width: 46ch; }

/* The one place uppercase is allowed: section eyebrows and table headers. */
.label {
  font-size: 11px; font-weight: 600; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--ink-3); line-height: 1.2;
}
.eyebrow { display: block; margin-bottom: var(--s2); }

/* Highlight sits on the soft signal tint — full yellow behind a whole phrase
   reads as decoration, which the signal is not for. */
.mark { background: var(--lime-soft); color: var(--on-lime); padding: 0 4px; }

/* 5 — Buttons ============================================================= */

/* Buttons are pills — the same capsule as the app's CTAs. Yellow is never a
   button fill (signal rule), so the primary action is ink for every flow. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-family: inherit; font-size: 14px; font-weight: 500; line-height: 1;
  padding: 14px 26px; border-radius: 999px;
  border: 1px solid transparent; cursor: pointer;
  transition: background .12s ease-out, border-color .12s ease-out, color .12s ease-out;
}
.btn-primary { background: var(--ink); color: var(--paper); }
.btn-primary:hover { background: #26282D; color: var(--paper); }

/* Legacy class from the lime era — kept so no page breaks, renders ink. */
.btn-lime { background: var(--ink); color: var(--paper); }
.btn-lime:hover { background: #26282D; color: var(--paper); }

.btn-ghost { background: transparent; color: var(--ink); border-color: var(--line-2); }
.btn-ghost:hover { border-color: var(--ink); color: var(--ink); }

.btn-sm { padding: 9px 16px; font-size: 13.5px; }

/* No box at all — for the third-priority action. */
.link-underline { border-bottom: 1px solid var(--ink); padding-bottom: 2px; font-weight: 600; }

/* 6 — Header and footer =================================================== */

/* Header — landing-v2 register: translucent paper with a blur, a quieter
   64px bar, and the one ink pill on the right. */
.site-header {
  position: sticky; top: 0; z-index: 20;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}
@supports not (background: color-mix(in srgb, red 50%, blue)) {
  .site-header { background: var(--paper); }
}
.site-header .wrap {
  height: 64px; display: flex; align-items: center; justify-content: space-between; gap: var(--s3);
}
.brand { display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: 17px; letter-spacing: -0.01em; }
.brand svg { flex-shrink: 0; }

.site-nav { display: flex; align-items: center; gap: 28px; font-size: 14px; font-weight: 500; }
.site-nav a { color: var(--ink-2); transition: color .12s ease-out; }
.site-nav a:hover, .site-nav a[aria-current="page"] { color: var(--ink); }
/* The pill keeps its own colours whatever the nav link rules say — this bar
   is where an inherited ink-on-ink once made the CTA unreadable. */
.site-nav .btn-primary, .site-nav .btn-primary:hover { color: var(--paper); }

/* Log in and the demo CTA are actions, not navigation. Sitting them a weight
   above the section links — and in full ink rather than muted — separates the
   two jobs without adding a second colour, which the system does not have to
   spare. */
.site-nav .nav-action { font-weight: 600; color: var(--ink); }
.nav-sep { width: 1px; height: 20px; background: var(--line); }

.nav-toggle { display: none; background: none; border: 0; padding: 8px; cursor: pointer; color: var(--ink); }

.site-footer { border-top: 1px solid var(--line); padding: var(--s8) 0 var(--s4); }
/* Footer column headings are labels, not display — back to the UI face. */
.site-footer h2 { font-family: var(--font); font-size: 11px; font-weight: 600; }
.footer-grid { display: grid; grid-template-columns: 2fr repeat(4, 1fr); gap: var(--s4); }
.footer-grid ul { list-style: none; margin: var(--s2) 0 0; padding: 0; }
.footer-grid li + li { margin-top: 10px; }
.footer-grid a { font-size: 14px; color: var(--ink-2); }
.footer-grid a:hover { color: var(--ink); }
.footer-legal {
  margin-top: var(--s6); padding-top: var(--s3); border-top: 1px solid var(--line);
  display: flex; justify-content: space-between; gap: var(--s3); flex-wrap: wrap;
  font-size: 13px; color: var(--ink-3);
}

/* 7 — Components ========================================================== */

/* No shadows anywhere. Elevation is a hairline plus the whitespace around it. */
.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 16px; padding: var(--s4);
}
.card-tight { padding: var(--s3); }

.stat-value { font-family: var(--font-display); font-size: 44px; font-weight: 400; letter-spacing: -0.01em; line-height: 1; }
.stat-label { margin-top: 10px; }

.pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12.5px; font-weight: 500; padding: 5px 11px;
  border: 1px solid var(--line); border-radius: 999px; color: var(--ink-2);
}
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
  padding: 4px 9px; border-radius: var(--radius);
  background: var(--canvas); color: var(--ink-2);
}
.badge-soon { background: transparent; border: 1px dashed var(--line-2); color: var(--ink-3); }

/* Chat proof. The whole pitch is that these are real conversations, so they
   get real structure rather than a decorative bubble graphic. */
.thread { border: 1px solid var(--line); border-radius: 16px; background: var(--surface); overflow: hidden; }
.thread-head {
  display: flex; justify-content: space-between; align-items: center; gap: var(--s2);
  padding: 14px 18px; border-bottom: 1px solid var(--line);
  font-size: 13px; font-weight: 600;
}
.thread-body { padding: 18px; display: flex; flex-direction: column; gap: 4px; }
.msg { max-width: 78%; padding: 11px 14px; border-radius: var(--radius); font-size: 14.5px; line-height: 1.45; }
.msg-in  { background: var(--canvas); align-self: flex-start; }
.msg-out { background: var(--ink); color: var(--paper); align-self: flex-end; }
.msg-meta { font-size: 11.5px; color: var(--ink-3); margin: 2px 0 8px; }
.msg-meta.out { align-self: flex-end; }
.thread-foot {
  padding: 12px 18px; border-top: 1px solid var(--line);
  display: flex; justify-content: space-between; gap: var(--s2);
  font-size: 12.5px; color: var(--ink-3); flex-wrap: wrap;
}
/* The thread film. Sized so the 2560px source lands at roughly 2x on a
   normal display — the type in it is small, and anything less looks soft.
   No shadow and a hairline border, so it reads as a panel in the page rather
   than a video player dropped on top of it. */
.film { margin: 0; }
.film-media {
  width: 100%; max-width: 1180px; aspect-ratio: 16 / 9;
  border: 1px solid var(--line); border-radius: 16px;
  background: var(--paper);
  /* object-fit matters: before the source loads, the poster is all there is,
     and a stretched poster is worse than no video at all. */
  object-fit: cover;
}
/* The still and the video occupy the same box, so swapping one for the other
   cannot shift the page. Same rule as .film-media above; declared together so
   they can never drift apart. */
.film-poster { display: block; }
.film-media[hidden], .film-poster[hidden] { display: none; }

.film-cap { font-size: 12.5px; color: var(--ink-3); margin-top: 10px; max-width: 62ch; }

/* Reduced motion never autoplays — but the reader can still choose to. The
   button is injected by JS, so it never appears for someone without it, where
   it would do nothing. */
.film-play {
  display: inline-flex; align-items: center; gap: 8px;
  margin-top: 12px; padding: 9px 14px;
  font-family: inherit; font-size: 13px; font-weight: 700; line-height: 1;
  color: var(--ink); background: var(--surface);
  border: 1px solid var(--ink); border-radius: var(--radius);
  cursor: pointer;
}
.film-play:hover { background: var(--canvas); }
.film-play[hidden] { display: none; }

.receipt { border: 1px solid var(--ink); border-radius: var(--radius); padding: 12px 14px; margin: 8px 0; align-self: flex-end; max-width: 78%; }

table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 12px 0; border-bottom: 1px solid var(--line); font-size: 14px; }
th { font-size: 11px; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-3); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }

/* FAQ. <details> means it works with JavaScript disabled, which matters for
   both crawlers and the FAQPage structured data. */
.faq { border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary {
  display: flex; justify-content: space-between; align-items: center; gap: var(--s2);
  padding: 22px 0; font-size: 17px; font-weight: 600; letter-spacing: -0.01em;
  cursor: pointer; list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; font-size: 22px; font-weight: 400; color: var(--ink-3); line-height: 1; flex-shrink: 0; }
.faq details[open] summary::after { content: "\2212"; }
.faq .answer { padding: 0 0 22px; color: var(--ink-2); max-width: 68ch; }

.steps { counter-reset: step; list-style: none; margin: 0; padding-left: 0; }
.step { display: grid; grid-template-columns: 52px 1fr; gap: var(--s2); padding: var(--s3) 0; border-bottom: 1px solid var(--line); }
.step-num { font-size: 13px; font-weight: 600; color: var(--ink-3); font-variant-numeric: tabular-nums; }


/* FAQ questions are <h3> inside <summary>.
   <summary> is a disclosure control; it is not a heading, and neither an
   extractor nor an AI Overview reads it as one. Wrapping the text restores
   the outline without changing a pixel — the heading is inlined and inherits
   the summary's own type, so this is semantics only. */
.faq summary h3 { display: inline; font: inherit; margin: 0; }

/* The install snippet. Monospace is deliberate: this is a line the reader is
   meant to copy, and proportional type in a code sample invites a typo. */
.code-block {
  margin: 0; padding: 12px 14px; overflow-x: auto;
  background: var(--canvas); border: 1px solid var(--line); border-radius: var(--radius);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12.5px; line-height: 1.6; color: var(--ink);
  white-space: pre;
}
.code-block code { font: inherit; background: none; padding: 0; }
/* Inline <code> in running prose — smaller, tinted, never a block. */
p > code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.92em; background: var(--canvas);
  border: 1px solid var(--line); border-radius: 4px; padding: 1px 5px;
}

/* Term/value pairs that used to be a two-column table with no columns to
   compare. Styled to the same rhythm as `table` so the card is unchanged. */
.def-list { margin: 0; display: grid; grid-template-columns: 1fr auto; }
.def-list dt, .def-list dd {
  margin: 0; padding: 12px 0; border-bottom: 1px solid var(--line); font-size: 14px;
}
.def-list dd { text-align: right; font-variant-numeric: tabular-nums; }

/* Contents list. Numbered because the page has an order and reading it in
   that order works; the numerals are the browser's here rather than hand-set
   spans, because unlike .steps these are not a designed element. */
/* The ranked list is an <ol> of cards. The numeral is inside each card as
   part of the "1. Best for …" label, so the browser marker is removed — two
   numbers on one entry reads as a bug. */
.ranked { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s3); }
.ranked > li { margin: 0; }

.toc { margin: var(--s2) 0 0; padding-left: 1.3em; }
.toc li + li { margin-top: 6px; }
.toc a { font-size: 14px; color: var(--ink-2); }
.toc a:hover { color: var(--ink); }

.logo-row { display: flex; flex-wrap: wrap; gap: 10px; }
.logo-chip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 14px; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); font-size: 14px; font-weight: 500;
}

/* The chip's 8px gap was always there for a mark; the homepage just never had
   one. Smaller than .channel-icon (28px) because a chip is a label carrying a
   mark, not a card with an icon. flex: none so a chip whose text wraps does not
   squash its logo. The two chips with no mark need no special case — an
   inline-flex gap with nothing on one side of it collapses. */
.logo-chip-mark { width: 20px; height: 20px; flex: none; }

/* Channel icons.
   The four brand marks keep their own colours: an SMB scans the page for the
   logo it recognises, and flattening WhatsApp to ink throws that away. Web
   chat and email have no brand, so they are drawn in currentColor to match
   the surrounding text — a visibly different class of thing, which is honest. */
/* One icon rule, because there is now one kind of icon.
   The row used to mix four coloured brand marks with two ink line drawings —
   the only colour anywhere on the page, and two different drawing weights in
   one row. The design draws all six on a 24-unit grid at stroke 1.7, in ink.
   That also sidesteps Meta's brand guidelines, which govern how the WhatsApp,
   Messenger and Instagram marks may be shown; a generic line icon is not
   their mark and needs no permission. */
.channel-icon-ink { width: 32px; height: 32px; color: var(--ink); flex: none; }

/* Still used by integrations.html for partner marks — HubSpot, Salesforce,
   Google Calendar. Those SHOULD be their own colours: they are other
   companies' logos shown as "we connect to this", which is exactly what a
   brand mark is for. The channel row is different; there the six marks were
   the only colour on the page and two of them were not brands at all. */
.channel-icon { width: 28px; height: 28px; flex: none; }
.channel-card { display: flex; flex-direction: column; gap: var(--s2); }

/* A single row of short reassurance lines, spread across the full width.
   Used for the trust strip under the hero. */
.strip { display: flex; flex-wrap: wrap; gap: var(--s4); justify-content: space-between; }

/* Bulleted list that keeps the marker inside the reading measure. */
.bullets { padding-left: 1.1em; margin: 0; }
.bullets li + li { margin-top: var(--s2); }

/* Pricing ------------------------------------------------------------- */

/* align-items: stretch (the default) is load-bearing here. Four plans whose
   feature lists differ in length will size to their own content if you let
   them, and the result is four cards with four different bottoms and four
   buttons at four different heights — which reads as a broken page, not a
   design. The row is also the one place on the site where the eye scans
   ACROSS columns, so the cards must share a baseline and the buttons must
   sit on one line. Each tier is a flex column and its CTA (always the last
   child) takes margin-top: auto. */
.tiers { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s2); align-items: stretch; }
.tier { background: var(--surface); border: 1px solid var(--line); border-radius: 16px; padding: var(--s3);
        display: flex; flex-direction: column; }
/* padding-top, not margin-top — `auto` has already claimed the margin, and
   without this the button would butt against the last feature row. */
.tier > :last-child { margin-top: auto; padding-top: var(--s3); }
/* The featured tier is marked with weight, not colour — lime is already
   spent on the page's single CTA. */
.tier-featured { border-color: var(--ink); }
/* 1px like every other card, dark rather than heavy. A 2px border here read as
   a DOUBLE border: it sits 16px from the neighbouring card's 1px hairline, and
   two parallel lines of unequal weight group into one thick edge — the equal
   gaps elsewhere do not do this. It also broke the shared baseline this grid
   exists for, since box-sizing:border-box took the extra 1px off the content
   box and dropped the $79 one pixel below the other three prices.
   The badge carries the emphasis; the border only has to mark the card. */
.tier-price { font-family: var(--font-display); font-size: 38px; font-weight: 400; letter-spacing: -0.01em; line-height: 1; }
.tier-features { list-style: none; margin: var(--s3) 0 0; padding: 0; font-size: 14px; }
.tier-features li { padding: 8px 0; border-top: 1px solid var(--line); color: var(--ink-2); }

/* Billing toggle. A radio group, not buttons — it is a choice between two
   states, and radios give keyboard and screen-reader semantics for free. */
.toggle { display: inline-flex; border: 1px solid var(--line-2); border-radius: 999px; overflow: hidden; }
.toggle input { position: absolute; opacity: 0; pointer-events: none; }
.toggle label { padding: 9px 18px; font-size: 13.5px; font-weight: 600; cursor: pointer; color: var(--ink-2); }
.toggle input:checked + label { background: var(--ink); color: var(--paper); }
.toggle input:focus-visible + label { outline: 2px solid var(--ink); outline-offset: -2px; }

.compare th:first-child, .compare td:first-child { width: 34%; }
.compare td { color: var(--ink-2); }
.compare tbody th { text-transform: none; letter-spacing: 0; font-size: 14px; color: var(--ink); font-weight: 600; }

/* Usage meter ---------------------------------------------------------- */
.meter { height: 6px; background: var(--canvas); border: 1px solid var(--line); border-radius: 2px; overflow: hidden; }
.meter span { display: block; height: 100%; background: var(--ink); }
.meter-80 { width: 80%; }

/* Forms ---------------------------------------------------------------- */

.field { display: block; margin-bottom: var(--s3); }
.field > span { display: block; font-size: 13px; font-weight: 600; margin-bottom: 6px; }
.input, .textarea, .select {
  width: 100%; font-family: inherit; font-size: 15px; color: var(--ink);
  background: var(--surface); border: 1px solid var(--line-2); border-radius: 999px;
  padding: 12px 18px;
}
/* A capsule can't hold multi-line text — the textarea rounds like a card. */
.textarea { border-radius: 16px; }
.input::placeholder, .textarea::placeholder { color: var(--ink-3); }
.input:focus, .textarea:focus, .select:focus { outline: none; border-color: var(--ink); box-shadow: 0 0 0 2px var(--ink); }
.textarea { min-height: 132px; resize: vertical; }

/* A single line of user input shown back — a pasted URL, an ID. Reads as a
   value rather than prose. */
.mono-line {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 14px; color: var(--ink);
  background: var(--canvas); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 10px 12px;
}

/* Code ----------------------------------------------------------------- */
.code {
  display: block; background: var(--ink); color: var(--paper);
  border-radius: var(--radius); padding: 16px 18px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px; line-height: 1.6; overflow-x: auto; white-space: pre;
}

@media (max-width: 900px) {
  .tiers { grid-template-columns: minmax(0, 1fr); }
  /* A four-column comparison cannot shrink honestly — let it scroll. */
  .compare-scroll { overflow-x: auto; }
  .compare { min-width: 640px; }
}

/* Legal pages ---------------------------------------------------------
   Policy text is long-form reading, not marketing. Narrower measure, more
   generous leading, and a sticky contents rail so a fourteen-section
   document stays navigable. Deliberately plain — a privacy policy that
   looks designed reads as though it is selling you something. */

.legal { display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: var(--s8); }
.legal-toc { position: sticky; top: 92px; align-self: start; font-size: 13px; }
.legal-toc ol { list-style: none; margin: var(--s2) 0 0; padding: 0; counter-reset: toc; }
.legal-toc li { padding: 5px 0; }
.legal-toc a { color: var(--ink-2); }
.legal-toc a:hover { color: var(--ink); }

.legal-body { max-width: 68ch; }
.legal-body h1 { margin-bottom: var(--s2); }
.legal-body h2 {
  font-size: 22px; margin: var(--s8) 0 var(--s2);
  scroll-margin-top: 92px; padding-top: var(--s2); border-top: 1px solid var(--line);
}
.legal-body h3 { font-size: 15px; margin: var(--s3) 0 var(--s1); }
.legal-body p { margin: 0 0 var(--s2); color: var(--ink-2); line-height: 1.7; }
.legal-body strong { color: var(--ink); }
.legal-body ul, .legal-body ol { margin: 0 0 var(--s2); padding-left: 1.3em; color: var(--ink-2); line-height: 1.7; }
.legal-body li { margin-bottom: 6px; }
.legal-body a { color: var(--ink); text-decoration: underline; text-underline-offset: 2px; }
.legal-body table { margin: var(--s2) 0 var(--s3); }
.legal-body td { color: var(--ink-2); vertical-align: top; }

@media (max-width: 900px) {
  .legal { grid-template-columns: minmax(0, 1fr); gap: var(--s4); }
  .legal-toc { position: static; }
}

/* 8 — Utilities =========================================================== */

.mt-1{margin-top:var(--s1)}   .mt-2{margin-top:var(--s2)}   .mt-3{margin-top:var(--s3)}
.mt-4{margin-top:var(--s4)}   .mt-6{margin-top:var(--s6)}   .mt-8{margin-top:var(--s8)}
.mb-2{margin-bottom:var(--s2)} .mb-3{margin-bottom:var(--s3)} .mb-4{margin-bottom:var(--s4)}
.mb-6{margin-bottom:var(--s6)}
.center { text-align: center; }
.divider { height: 1px; background: var(--line); border: 0; margin: var(--s6) 0; }

/* 9 — Responsive ========================================================== */

@media (max-width: 900px) {
  :root { --gutter: 24px; }
  section { padding: var(--s8) 0; }

  .nav-toggle { display: block; }
  .site-nav {
    display: none; position: absolute; left: 0; right: 0; top: 64px;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--paper); border-bottom: 1px solid var(--line); padding: var(--s2) var(--gutter) var(--s3);
  }
  .site-nav.open { display: flex; }
  .site-nav a { padding: 12px 0; border-bottom: 1px solid var(--line); font-size: 16px; }
  .site-nav .btn { margin-top: var(--s2); border-bottom: 0; }
  .nav-sep { display: none; }

  .g2, .g3, .g4, .g-7-5, .g-6-6 { grid-template-columns: minmax(0, 1fr); gap: var(--s3); }
  .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s4); }
  .display { font-size: clamp(34px, 8.6vw, 46px); }
  .msg { max-width: 88%; }
}

@media (max-width: 560px) {
  .footer-grid { grid-template-columns: minmax(0, 1fr); }
  .stat-value { font-size: 34px; }
}

/* 10 — Blog =============================================================
   The blog is the only part of the site with long-form prose, so it is the
   only part that needs a measured reading column and vertical rhythm between
   paragraphs. Everything else here is marketing layout, where the constraint
   is the grid rather than the line length.

   65 characters is the reading measure — the point past which the eye starts
   losing its place on the return sweep. `.measure` (used for marketing copy)
   is deliberately narrower; prose needs a little more room before it starts
   feeling like a column of poetry. */

.post-head { border-bottom: 1px solid var(--line); }
.post-meta { display: flex; flex-wrap: wrap; gap: var(--s2); align-items: baseline; }

.prose { max-width: 68ch; }

/* The default rhythm between blocks.
   28px, not 24, because it has to be at least one line-height (17px × 1.65 =
   28px) or a paragraph break reads as a line break and the column looks like
   one undifferentiated slab. This is the single value that decides whether
   long-form feels readable or tight. */
.prose > * + * { margin-top: 28px; }

/* Headings belong to what FOLLOWS them, and the spacing has to say so.
   The first version gave h3 32px above and 24px below — near-symmetric, so
   every heading floated between two blocks instead of attaching to its own
   paragraph, and the whole page read as cramped despite having margins.
   The fix is the ratio, not the amount: roughly 4:1 for h2, 6:1 for h3. */
/* Cal Sans is single-style: weight stays 400 or the browser faux-bolds it. */
.prose h2 { font-size: 25px; font-weight: 400; line-height: 1.3; letter-spacing: -0.01em; margin-top: var(--s8); }
.prose h3 { font-size: 18px; font-weight: 700; line-height: 1.45; letter-spacing: -0.01em; margin-top: var(--s6); }
.prose h2 + * { margin-top: var(--s2); }
.prose h3 + * { margin-top: var(--s1); }
/* An h3 straight after an h2 is a subsection opening, not a gap to fill. */
.prose h2 + h3 { margin-top: var(--s3); }

.prose p, .prose li { font-size: 17px; line-height: 1.65; }
.prose ul, .prose ol { padding-left: 1.25em; margin-bottom: 0; }
/* These bullets run to two and three lines, so they need more than the 8px
   that suits a list of short items or they merge into a paragraph. */
.prose li + li { margin-top: var(--s2); }
.prose a { text-decoration: underline; text-underline-offset: 2px; }
.prose strong { font-weight: 700; }

/* A pulled-out fact. One per post at most — it stops working the moment it
   becomes a way of formatting any sentence you happen to like. */
.prose .callout {
  border-left: 3px solid var(--ink);
  padding: var(--s1) 0 var(--s1) var(--s3);
  font-size: 17px;
  line-height: 1.6;
}
/* A pulled-out fact needs air on both sides to read as pulled out. The
   general rhythm only supplies space above, which left it touching the
   paragraph beneath. */
.prose .callout + * { margin-top: var(--s4); }
.prose > .callout { margin-top: var(--s4); }

/* Tables carry the rate and category comparisons these posts live on, so they
   have to stay readable on a phone rather than overflowing the viewport. */
.prose .table-wrap { overflow-x: auto; }
.prose .table-wrap + * { margin-top: var(--s4); }
.prose > .table-wrap { margin-top: var(--s4); }
.prose table { width: 100%; border-collapse: collapse; font-size: 15px; }
.prose th, .prose td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line); }
.prose th { font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); }
.prose td:not(:first-child), .prose th:not(:first-child) { white-space: nowrap; }

/* Index cards. A whole-card link rather than a "read more" — a bigger target,
   and one link per post instead of two pointing at the same place, which
   reads as duplicate anchors to a crawler. */
.post-list { display: grid; gap: var(--s3); }
.post-card { display: block; border: 1px solid var(--line); border-radius: 16px; background: var(--surface); padding: var(--s3); }
.post-card:hover { border-color: var(--ink-3); }
.post-card h2 { font-size: 19px; font-weight: 400; letter-spacing: -0.01em; }
.post-card p { margin-top: var(--s1); }
.post-card .label { margin-bottom: var(--s1); display: block; }

/* Updated-on matters more than published-on for the posts that track a moving
   Meta policy — a reader needs to know the rates are current, and answer
   engines weight recency. */
.post-updated { border-top: 1px solid var(--line); padding-top: var(--s3); }
.prose > .post-updated { margin-top: var(--s8); }

/* The FAQ block brings its own rules and 22px summary padding, so it needs
   separation from the prose above rather than more internal spacing. */
.prose > .faq { margin-top: var(--s4); }

/* The hero and the body each carry a full section's padding, which stacked to
   nearly 200px of nothing between the standfirst and the first line. */
.post-head + section { padding-top: var(--s8); }

/* ==========================================================================
   PRICING — structure and figures
   --------------------------------------------------------------------------
   The reference everyone points at for this page (Chatbase) has no
   illustrations on it at all. What makes it read as designed is a visible
   grid scaffold, a headline carrying real weight, and tiny flat marks. So
   almost everything below is structure, and there is exactly ONE drawn
   figure. A pricing page is a decision surface: the visitor is comparing
   numbers and hunting for the disqualifier, and decoration sitting between
   two plan cards makes that job harder.

   Everything here is line work in --line / --ink. Lime appears twice on the
   whole page — the Growth mark and the filled part of the usage bar — and is
   a FILL both times, never a stroke and never text.
   ========================================================================== */

/* Four hairlines the full height of the viewport: the container edges and
   the gutter insets. Fixed rather than absolute so they read as one
   continuous scaffold behind every section rather than restarting at each
   one, and z-index 2 keeps them under the sticky header (z-index 20).

   Hidden below 1360px. Not for taste — at narrower widths the outer pair
   would land inside the content and read as a mistake, and `left: calc(50% -
   640px)` on a 360px viewport is a negative offset that some engines resolve
   into a horizontal scrollbar. jsdom cannot see either failure. */

/* A section divider with ruler ticks every 64px and one taller tick at dead
   centre. Reads as measurement, which is the page's whole argument — you are
   being charged for a thing that gets counted. */
.tick-rule { position: relative; height: 12px; border-top: 1px solid var(--line); }
.tick-rule::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 6px;
  background-image: repeating-linear-gradient(to right, var(--line) 0 1px, transparent 1px 64px);
}
.tick-rule::after {
  content: ""; position: absolute; left: 50%; top: 0; width: 1px; height: 12px; background: var(--ink);
}

/* Eyebrow with a mark beside it. The mark is 16px and --ink-3, which is only
   ~3:1 on paper — fine for a hairline drawing, which is why the WORD beside
   it is --ink-2 and not the same colour. */
.eyebrow-row { display: flex; align-items: center; gap: 8px; margin-bottom: var(--s2); }
.eyebrow-row .label { color: var(--ink-2); letter-spacing: 0.08em; font-weight: 700; }
.eyebrow-mark { flex: none; width: 16px; height: 16px; fill: none; stroke: var(--ink-3); stroke-width: 1; stroke-linecap: round; }

/* Per-plan marks. Chatbase separates its five tiers by hue; there is one
   accent here, so these separate by FORM and only the recommended plan is
   allowed to carry lime. */
.tier h2 .label { display: inline-flex; align-items: center; gap: 8px; }
.tier-mark { flex: none; width: 20px; height: 20px; fill: none; stroke: var(--ink); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.tier-mark .fill-lime { fill: var(--lime); }

/* The usage figure. One drawn thing on the page, and it draws the thing
   being sold: replies counted against an allowance. */
/* Sits inside an existing .card, so it brings no border of its own — a card
   inside a card is the tell that a figure was pasted rather than placed. */
.usage-figure { }
.usage-figure svg { display: block; width: 100%; height: auto; }
.usage-bar { fill: none; stroke: var(--ink); stroke-width: 1; }
.usage-fill { fill: var(--lime); }
.usage-cells { stroke: var(--line); stroke-width: 1; }
.usage-tick { stroke: var(--ink-3); stroke-width: 1; }
.usage-axis { font-family: var(--font); font-size: 14px; font-weight: 500; fill: var(--ink-2); }

/* SVG text scales with the viewBox, so at 360px the axis labels rendered at
   about 3px — present, invisible, and the kind of thing a screenshot at
   desktop width will never show you. Everything except the bar itself goes.
   The bar alone still says the thing, and the sentence beneath it says the
   number. */
@media (max-width: 640px) {
  .usage-cells, .usage-axis, .usage-tick { display: none; }
}

@media print {
  .site-header, .site-footer, .btn { display: none; }
  body { background: #fff; }
}

/* 10 — Motion ==============================================================
   One system, four primitives, applied consistently. The temptation with
   motion is to reach for a different effect per section; that is what makes a
   page read as a template. Everything below shares one easing curve and one
   distance, so the page feels like a single object being revealed rather than
   a series of unrelated tricks.

   THE RULE THAT MATTERS: nothing here hides content unless JavaScript is
   running. `.js-motion` is added to <html> by thredo.js before first paint,
   and every hidden state is scoped under it. Without JS — and for any crawler
   that does not execute it — the page renders exactly as it did before. This
   site's whole premise is that the crawler and the customer see the same HTML,
   and a `opacity: 0` in the base stylesheet would quietly end that.

   The hero h1 and lead are deliberately NOT revealed. They are the LCP
   candidate; animating them in delays the largest paint to make the page feel
   faster, which is precisely backwards. */

:root { --ease-out: cubic-bezier(0.22, 0.68, 0.24, 1); --rise: 14px; }

/* 1 — Reveal on scroll. The workhorse: everything below the fold arrives the
   same way, so the eye learns the grammar in the first section and stops
   noticing it — which is the goal. */
.js-motion [data-reveal] { opacity: 0; transform: translateY(var(--rise)); }
.js-motion [data-reveal].is-in {
  opacity: 1; transform: none;
  transition: opacity 0.5s var(--ease-out), transform 0.5s var(--ease-out);
}

/* 2 — Stagger inside a grid. Children arrive left to right rather than as a
   slab. Delays are nth-child in CSS rather than inline styles set by JS: the
   stylesheet stays the only place that knows about appearance, and the HTML
   stays free of style attributes. */
.js-motion [data-reveal-group].is-in > * { animation: rise 0.5s var(--ease-out) both; }
.js-motion [data-reveal-group].is-in > *:nth-child(1) { animation-delay: 0ms; }
.js-motion [data-reveal-group].is-in > *:nth-child(2) { animation-delay: 70ms; }
.js-motion [data-reveal-group].is-in > *:nth-child(3) { animation-delay: 140ms; }
.js-motion [data-reveal-group].is-in > *:nth-child(4) { animation-delay: 210ms; }
.js-motion [data-reveal-group].is-in > *:nth-child(5) { animation-delay: 280ms; }
.js-motion [data-reveal-group].is-in > *:nth-child(6) { animation-delay: 350ms; }
.js-motion [data-reveal-group]:not(.is-in) > * { opacity: 0; }
@keyframes rise { from { opacity: 0; transform: translateY(var(--rise)); } to { opacity: 1; transform: none; } }

/* 3 — The thread, typed. The one showpiece, and it earns its place because it
   is the argument: the page claims the agent answers in four seconds, and this
   is the only element that can show it rather than assert it. Messages arrive
   in sequence with the outbound ones a beat behind, the way a real reply lands.
   It runs once, on entry, and never loops — a looping conversation is a
   screensaver. */
.js-motion .thread-body > * { opacity: 0; }
.js-motion .thread.is-in .thread-body > * { animation: msg-in 0.42s var(--ease-out) both; }
.js-motion .thread.is-in .thread-body > *:nth-child(1) { animation-delay: 0.10s; }
.js-motion .thread.is-in .thread-body > *:nth-child(2) { animation-delay: 0.22s; }
.js-motion .thread.is-in .thread-body > *:nth-child(3) { animation-delay: 0.70s; }
.js-motion .thread.is-in .thread-body > *:nth-child(4) { animation-delay: 0.82s; }
.js-motion .thread.is-in .thread-body > *:nth-child(5) { animation-delay: 1.25s; }
.js-motion .thread.is-in .thread-body > *:nth-child(6) { animation-delay: 1.37s; }
.js-motion .thread.is-in .thread-body > *:nth-child(7) { animation-delay: 1.80s; }
.js-motion .thread.is-in .thread-body > *:nth-child(8) { animation-delay: 1.92s; }
.js-motion .thread.is-in .thread-body > *:nth-child(9) { animation-delay: 2.35s; }
@keyframes msg-in {
  from { opacity: 0; transform: translateY(8px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}

/* 4 — Hover. Cards lift a hair and their rule darkens; that is the whole
   effect. A shadow would be the wrong language for a system built on 1px
   rules and flat surfaces. */
.card { transition: transform 0.18s var(--ease-out), border-color 0.18s var(--ease-out); }
.card:hover { transform: translateY(-2px); border-color: var(--line-2); }
.logo-chip { transition: transform 0.18s var(--ease-out), border-color 0.18s var(--ease-out); }
.logo-chip:hover { transform: translateY(-2px); border-color: var(--ink-3); }
.step { transition: background 0.18s var(--ease-out); }
.step:hover { background: var(--surface); }

/* The underline draws from the left instead of appearing. Cheap, and it is
   the one place a link can feel like a control rather than blue text. */
.link-underline { background-image: linear-gradient(var(--ink), var(--ink));
  background-size: 0% 1px; background-repeat: no-repeat; background-position: 0 100%;
  transition: background-size 0.25s var(--ease-out); }
.link-underline:hover { background-size: 100% 1px; }

/* Buttons get a press. 1px is enough — the point is that it acknowledges the
   click, not that it moves. */
.btn { transition: background .12s ease-out, border-color .12s ease-out, color .12s ease-out, transform .12s ease-out; }
.btn:active { transform: translateY(1px); }

/* ── Reduced motion ──────────────────────────────────────────────────────
   The global rule at the top of this file collapses durations to 0.01ms,
   which stops the movement — but an element left at opacity 0 with no
   animation to run would stay invisible. So every hidden state is explicitly
   released here. "Reduce motion" means do not move things at me; it does not
   mean hide the page. */
@media (prefers-reduced-motion: reduce) {
  .js-motion [data-reveal],
  .js-motion [data-reveal-group]:not(.is-in) > *,
  .js-motion .thread-body > * { opacity: 1 !important; transform: none !important; }
  .card:hover, .logo-chip:hover, .btn:active { transform: none; }
}

/* 11 — Landing v2 =========================================================
   The composition designed 2026-09-07 (cal.com-inspired grammar, see the
   thredo-website sandbox): a centred compact hero with an announce chip and
   ONE ink pill, the product conversation floating directly beneath it, every
   section a rounded card on the paper board with one bento pair, and a dark
   full-bleed close. Applied to index.html only; inner pages keep the shared
   section grammar. */

.hero2 { text-align: center; padding: var(--s8) 0 var(--s6); }
.hero2 .display { max-width: 20ch; margin: var(--s3) auto 0; }
.hero2-lead { max-width: 62ch; margin: var(--s3) auto 0; }
.hero2-ctas { margin-top: var(--s4); display: flex; justify-content: center; gap: var(--s2); flex-wrap: wrap; }

.announce {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 13px; font-weight: 500; color: var(--ink-2);
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface); padding: 7px 14px;
}
/* The one yellow element above the fold — the signal, not decoration. */
.announce-dot { width: 8px; height: 8px; border-radius: 999px; background: var(--lime); flex: none; }

/* The conversation floats under the hero as a product surface. It reuses the
   .thread component untouched, so the typed-message animation still runs. */
.band-card { text-align: left; width: 100%; max-width: 1040px; margin: var(--s6) auto 0; border-radius: 20px; }

.tools-note { margin-top: var(--s3); font-size: 14px; color: var(--ink-2); }
.tools-note b { color: var(--ink); font-weight: 600; }

.hero2-stats { display: flex; justify-content: center; gap: clamp(28px, 6vw, 96px); margin-top: var(--s6); flex-wrap: wrap; }
.hero2-stats > div { max-width: 200px; }

/* The board: sections become rounded cards on paper. Their inner .wrap keeps
   the markup shared with other pages but gives up its own width and gutter. */
.board2 {
  max-width: var(--max); margin: 0 auto;
  padding: var(--s2) var(--gutter) var(--s8);
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 20px;
}
.board2 > section {
  grid-column: 1 / -1; margin: 0;
  background: var(--surface); border: 1px solid var(--line); border-radius: 24px;
  padding: clamp(24px, 3.2vw, 44px);
}
.board2 > section.bg-canvas { background: var(--surface); }
.board2 section .wrap { padding: 0; max-width: none; }
/* The bento pairs — the v2 signature. Adjacent in source order on purpose:
   Act+Understand, Handoff+Integrations. */
@media (min-width: 1000px) {
  .board2 > #does         { grid-column: span 7; }
  .board2 > #understand   { grid-column: span 5; }
  .board2 > #handoff      { grid-column: span 7; }
  .board2 > #integrations { grid-column: span 5; }
}

/* The dark close — the one dark band, bookending the paper page. */
.close2 { background: var(--ink); color: var(--paper); text-align: center; padding: var(--s12) 0; }
.close2 h2 { color: inherit; }
.close2 .lead { color: #B9BCC0; margin-left: auto; margin-right: auto; }
.close2 .muted { color: #B9BCC0; }
.close2 .faint { color: #8B8E93; }
.close2 .measure, .close2 .measure-sm { margin-left: auto; margin-right: auto; }
.close2-mark { display: inline-block; }

.btn-on-dark { background: var(--paper); color: var(--ink); }
.btn-on-dark:hover { background: #E8E8E4; color: var(--ink); }

/* 12 — Landing v2, draft parity ==========================================
   The remaining grammar from the 2026-09-07 draft: the yellow full stop,
   dropdown navigation, the static journey line, the Understand intent chip,
   solution verticals, and compact integration rows. */

/* The yellow full stop — the one sanctioned yellow "text": a single period
   closing a display sentence. */
.stop { color: var(--lime); }

/* Nav dropdowns. CSS-only: hover or focus-within opens the panel. */
.nav-dd { position: relative; display: flex; align-items: center; height: 64px; }
.nav-dd-btn {
  background: none; border: 0; padding: 0; font: inherit; cursor: pointer;
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 14px; font-weight: 500; color: var(--ink-2);
}
.nav-dd:hover .nav-dd-btn, .nav-dd:focus-within .nav-dd-btn { color: var(--ink); }
.nav-dd-caret { width: 10px; height: 10px; flex: none; }
.nav-dd-panel {
  display: none; position: absolute; top: 100%; left: -12px; margin-top: -8px;
  min-width: 216px; padding: 8px; z-index: 30;
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: 0 12px 32px rgba(10, 11, 13, 0.08);
}
.nav-dd:hover .nav-dd-panel, .nav-dd:focus-within .nav-dd-panel { display: block; }
.nav-dd-panel a { display: block; padding: 9px 12px; border-radius: 8px; font-size: 14px; color: var(--ink-2); }
.nav-dd-panel a:hover { background: var(--paper); color: var(--ink); }
@media (max-width: 900px) {
  /* In the sheet the groups flatten to plain link lists. */
  .nav-dd { height: auto; display: block; }
  .nav-dd-btn { display: none; }
  .nav-dd-panel { display: block; position: static; margin: 0; padding: 0; min-width: 0; border: 0; box-shadow: none; background: none; }
  .nav-dd-panel a { padding: 12px 0; border-bottom: 1px solid var(--line); border-radius: 0; font-size: 16px; }
}

/* Understand — the intent chip, resolved. */
.intent2 {
  display: inline-flex; align-items: center; gap: 9px; align-self: flex-start;
  background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 14px; font-size: 13.5px;
}
.understand2 { display: flex; flex-direction: column; gap: var(--s2); }
.understand2-msg { max-width: 420px; }
.measure-center { margin-left: auto; margin-right: auto; }
.dot2 { width: 8px; height: 8px; border-radius: 999px; background: var(--ink); flex: none; display: inline-block; }

/* The journey line, static. Yellow marks the moment happening now. */
.jl2 { position: relative; margin-top: var(--s6); }
.jl2-line { position: absolute; top: 6px; left: 12.5%; right: 12.5%; height: 2px; background: var(--ink); }
.jl2-cols { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s1); text-align: center; }
.jl2-node { position: relative; z-index: 1; display: block; width: 14px; height: 14px; border-radius: 999px; background: var(--ink); margin: 0 auto 12px; }
.jl2-node.active { background: var(--lime); border: 2px solid var(--ink); }
.jl2-node.hollow { background: var(--surface); border: 2px solid var(--ink); }
.jl2-cols b { display: block; font-size: 14.5px; font-weight: 600; }
.jl2-cols small { display: block; font-size: 12.5px; color: var(--ink-2); margin-top: 2px; }

/* Solutions — three verticals with a miniature resolved conversation. */
.verticals2 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s2); }
.vertical2 { background: var(--surface); border: 1px solid var(--line); border-radius: 16px; padding: var(--s3); display: flex; flex-direction: column; gap: var(--s2); }
.vertical2 .uses { font-size: 13px; color: var(--ink-2); margin-top: 4px; }
.vertical2 .mini { display: flex; flex-direction: column; gap: 8px; margin-top: auto; }
.vertical2 .mini .q { background: var(--canvas); border-radius: 10px; padding: 8px 12px; font-size: 13.5px; align-self: flex-start; }
.vertical2 .mini .a { display: flex; align-items: baseline; gap: 8px; font-size: 13px; color: var(--ink-2); padding-left: 2px; }
.vertical2 .mini .r { font-size: 13.5px; font-weight: 600; align-self: flex-end; background: var(--surface); border: 1px solid var(--line); border-radius: 10px; padding: 8px 12px; }
@media (max-width: 900px) { .verticals2 { grid-template-columns: minmax(0, 1fr); } }

/* Integrations — compact tool rows for the bento card. */
.integrations2 { display: flex; flex-direction: column; margin-top: var(--s3); }
.integration2 { padding: 14px 0; border-top: 1px solid var(--line); font-size: 14px; }
.integration2 .tool { font-weight: 600; display: block; }
.integration2 .does { color: var(--ink-2); }

/* 13 — Draft parity, second pass ==========================================
   The Understand moment, the Channels inbox, and the footer, matched to the
   sandbox draft (marketing2). */

/* Understand — a customer message and the resolved intent chip. */
.msg2 { background: var(--canvas); border-radius: 12px; padding: 10px 14px; max-width: 72%; align-self: flex-start; font-size: 14px; line-height: 1.5; }
.msg2 .byline { display: block; font-size: 11.5px; color: var(--ink-3); margin-bottom: 3px; font-weight: 500; }
.intent2 {
  display: inline-flex; align-items: center; gap: 9px; align-self: flex-start;
  background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 14px; font-size: 13.5px;
}
.understand2 { display: flex; flex-direction: column; gap: var(--s2); max-width: 560px; }

/* Channels — the one inbox every channel lands in (the story's resolved
   frame). Working dots are the Signal: activity happening now. */
.inbox2 { border: 1px solid var(--line); border-radius: 16px; background: var(--surface); overflow: hidden; max-width: 620px; margin: var(--s6) auto 0; }
.inbox2-row { display: flex; align-items: center; gap: 10px; padding: 13px 16px; font-size: 13.5px; }
.inbox2-row + .inbox2-row { border-top: 1px solid var(--line); }
.dot2-work { width: 8px; height: 8px; border-radius: 999px; background: var(--lime); flex: none; display: inline-block; }
.av2 {
  width: 26px; height: 26px; border-radius: 999px; flex: none;
  background: var(--canvas); color: var(--ink); font-size: 12px; font-weight: 600;
  display: inline-flex; align-items: center; justify-content: center;
}
.inbox2 .who { font-weight: 600; flex: none; }
.inbox2 .snip { color: var(--ink-2); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.inbox2 .meta { font-size: 12px; color: var(--ink-3); flex: none; }

/* Handoff — centre the film in the bento's leftover height instead of
   leaving the slack under the caption. */
.board2 > #handoff .wrap { display: flex; flex-direction: column; height: 100%; }
.board2 > #handoff .transcript2 { margin-top: auto; margin-bottom: auto; }

/* Footer — the draft's five columns on a brand column, quiet links, one
   legal row. Sentence-case headings, not the old uppercase labels. */
.footer2 { border-top: 1px solid var(--line); padding: 44px 0 36px; background: var(--paper); }
.footer2-cols { display: grid; grid-template-columns: 1.6fr repeat(5, 1fr); gap: 24px; }
.footer2-brand { display: flex; flex-direction: column; gap: 10px; padding-right: 16px; }
.footer2-brand .brand { font-size: 17px; }
.footer2-brand p { font-size: 13px; color: var(--ink-2); max-width: 24ch; }
.footer2-col { display: flex; flex-direction: column; gap: 2px; }
.footer2-h { font-size: 13px; font-weight: 600; margin: 0 0 6px; }
.footer2-col a { font-size: 13.5px; color: var(--ink-2); padding: 4px 0; }
.footer2-col a:hover { color: var(--ink); }
.footer2-legal {
  display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  margin-top: 36px; padding-top: 18px; border-top: 1px solid var(--line);
  font-size: 13px; color: var(--ink-3);
}
.footer2-legal nav { display: flex; gap: 18px; }
.footer2-legal a { font-size: 13px; color: var(--ink-2); }
.footer2-legal a:hover { color: var(--ink); }
@media (max-width: 1000px) { .footer2-cols { grid-template-columns: repeat(3, 1fr); } .footer2-brand { grid-column: span 3; } }
@media (max-width: 560px) { .footer2-cols { grid-template-columns: repeat(2, 1fr); } .footer2-brand { grid-column: span 2; } }

/* Channels stage — the draft's ChannelsStory frame, resolved mid-story:
   messages float in from four channels while the one inbox collects them. */
.chstage2 { position: relative; margin-top: var(--s6); padding: clamp(20px, 3vw, 32px); background: var(--paper); border: 1px solid var(--line); border-radius: 16px; min-height: 420px; }
.chbub2 { position: absolute; max-width: 240px; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 10px 14px; font-size: 13.5px; }
.chbub2 .cw { display: block; font-size: 11.5px; color: var(--ink-3); margin-top: 4px; }
/* Positions from the draft's CHANNEL_SETS — one bubble per corner. */
.chbub2:nth-of-type(1) { left: 4%; top: 6%; }
.chbub2:nth-of-type(2) { right: 5%; top: 10%; }
.chbub2:nth-of-type(3) { left: 6%; bottom: 16%; }
.chbub2:nth-of-type(4) { right: 4%; bottom: 20%; }
.chstage2 .inbox2 { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: min(420px, 86%); margin: 0; }
.chnote2 { position: absolute; left: 0; right: 0; bottom: 18px; text-align: center; font-size: 16px; font-weight: 600; }
@media (max-width: 720px) {
  .chstage2 { min-height: 0; display: flex; flex-direction: column; gap: var(--s2); align-items: center; padding-bottom: 56px; }
  .chbub2 { position: static; }
  .chstage2 .inbox2 { position: static; transform: none; width: 100%; }
}

/* Handoff transcript — the draft's HandoffStory as a resolved DOM scene
   (replaces the film: the draft renders this as real markup, and so do we). */
.transcript2 {
  border: 1px solid var(--line); border-radius: 16px; background: var(--paper);
  padding: clamp(18px, 2.4vw, 28px); display: flex; flex-direction: column; gap: 14px;
}
.tmsg { max-width: 72%; padding: 10px 14px; border-radius: 12px; font-size: 14px; line-height: 1.5; }
.tmsg .by { font-size: 11.5px; color: var(--ink-3); margin-bottom: 3px; display: flex; align-items: center; gap: 6px; font-weight: 500; }
.tmsg-cust { background: var(--canvas); align-self: flex-start; }
.tmsg-us { background: var(--surface); border: 1px solid var(--line); align-self: flex-end; }
.sysline2 { align-self: center; display: flex; align-items: center; gap: 7px; text-align: center; font-size: 12.5px; color: var(--ink-2); }
.seam2 { align-self: stretch; display: flex; align-items: center; gap: 12px; padding: 4px 0; }
.seam2-line { flex: 1; height: 2px; background: var(--ink); border-radius: 2px; opacity: .85; }
.seam2-line.after { opacity: .25; }
.seam2-who { display: flex; align-items: center; gap: 9px; font-size: 12.5px; color: var(--ink-2); flex: none; }
.seam2-av { width: 26px; height: 26px; border-radius: 999px; background: var(--ink); color: #FFFFFF; font-size: 11px; font-weight: 600; display: flex; align-items: center; justify-content: center; }
.seam2-who b { color: var(--ink); font-weight: 600; }

/* Channels stage motion — the draft's ChannelsStory as a timed DOM loop.
   Every hidden state is scoped under .js-motion AND .anim (added by the
   driver in thredo.js), so without JS — or for any crawler — the stage
   renders as the full resolved frame. Reduced motion never enters .anim. */
.js-motion .chstage2.anim { transition: opacity .4s var(--ease-out); }
.js-motion .chstage2.anim.fading { opacity: 0; }
.js-motion .chstage2.anim .chbub2 { transition: opacity .45s var(--ease-out), transform .45s var(--ease-out); }
.js-motion .chstage2.anim .chbub2.w { opacity: 0; transform: translateY(12px); }
.js-motion .chstage2.anim .chbub2.d { opacity: 0; transform: translateY(28px) scale(.92); }
.js-motion .chstage2.anim .inbox2-row { transition: opacity .4s var(--ease-out); }
.js-motion .chstage2.anim .inbox2-row.w { opacity: 0; }
.js-motion .chstage2.anim .chnote2 { transition: opacity .4s var(--ease-out); }
.js-motion .chstage2.anim .chnote2.w { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .js-motion .chstage2.anim .chbub2,
  .js-motion .chstage2.anim .inbox2-row,
  .js-motion .chstage2.anim .chnote2 { opacity: 1 !important; transform: none !important; }
}

/* Handoff transcript motion — the draft's HandoffStory beats. Same contract
   as the channels stage: hidden states live under .js-motion + .anim only,
   so no-JS and reduced-motion readers get the resolved scene. */
.js-motion .transcript2.anim { transition: opacity .4s var(--ease-out); }
.js-motion .transcript2.anim.fading { opacity: 0; }
.js-motion .transcript2.anim .tmsg,
.js-motion .transcript2.anim .sysline2,
.js-motion .transcript2.anim .seam2-who { transition: opacity .45s var(--ease-out), transform .45s var(--ease-out); }
.js-motion .transcript2.anim .tmsg.w,
.js-motion .transcript2.anim .sysline2.w,
.js-motion .transcript2.anim .seam2-who.w { opacity: 0; transform: translateY(10px); }
.js-motion .transcript2.anim .seam2-line { transform-origin: left; transition: transform .6s var(--ease-out); }
.js-motion .transcript2.anim .seam2-line.after { transform-origin: right; }
.js-motion .transcript2.anim .seam2-line.w { transform: scaleX(0); }
@media (prefers-reduced-motion: reduce) {
  .js-motion .transcript2.anim .tmsg,
  .js-motion .transcript2.anim .sysline2,
  .js-motion .transcript2.anim .seam2-who,
  .js-motion .transcript2.anim .seam2-line { opacity: 1 !important; transform: none !important; }
}
