/* Design tokens — OrchardRank, red on white.
 *
 * ONE PROBLEM WORTH NAMING, because getting it wrong is how red brands become unusable:
 * red already meant "danger" in this interface. Making it also mean "the main action" puts the
 * publish button and the delete button in the same colour, and a customer about to push work to
 * a live site should never have to read carefully to tell those apart.
 *
 * So the two are separated by DEPTH rather than hue, and never rely on colour alone:
 *   --brand   #e30721  bright, saturated  → primary actions, links, active navigation
 *   --bad     #7f1d1d  dark, desaturated  → destructive actions and errors, always with a word
 * A destructive control is additionally outlined rather than filled, so the difference survives
 * greyscale, projector washout, and the ~8% of men with red-green colour blindness (for whom
 * red vs green is the failing pair — red vs dark-red still reads as light vs dark).
 *
 * Contrast, MEASURED in the browser rather than estimated: white on #e30721 is 4.86:1 and white
 * on #7f1d1d is 10.02:1 — both clear WCAG AA for body text (4.5:1), not merely for large text.
 */
:root {
  --space-1: .5rem;  --space-2: 1rem;  --space-3: 1.5rem;  --space-4: 2.5rem;
  --radius: 12px;
  --font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  --bg: #fbf9f9;          /* white, warmed a half-step so the red never looks cold */
  --surface: #ffffff;
  --border: #ecdfe1;      /* the border carries a trace of the brand instead of neutral grey */
  --text: #1a1416;
  --text-muted: #6b5c5f;

  /* TWO reds, and the reason is measured, not aesthetic. The reference brand (City Bank,
   * #F20823) is a vivid red that scores 4.34:1 against white — under the 4.5 WCAG asks for
   * body text. City Bank themselves put DARK text on it, never white. Using it behind white
   * button labels would make the most-clicked text on the site the least legible.
   *
   * So the vivid red keeps its job as the identity — big fills, the masthead rule, hero
   * panels, large display type, where 4.34 is comfortably fine because the threshold for
   * large text is 3.0. And a hair-darker sibling carries small white text: #E30721 is the
   * closest shade to the reference that clears 4.5 (4.86:1). Side by side they read as the
   * same colour; the difference exists only where legibility is at stake. */
  --brand: #e30721;        /* interactive: buttons, links, anything with small white text */
  --brand-vivid: #f20823;  /* identity: large fills, rules, display type — the reference red */
  --accent: var(--brand);
  --accent-soft: #fff1f2;  /* the tint used for selected rows and quiet emphasis */

  /* A THIRD red, and the reason is the same arithmetic as the first two. #e30721 clears 4.5
   * against white, but the soft tint is not white — it is a pale pink, and on it the same red
   * measures 4.43. That is a fail by seven hundredths, which is exactly the kind of miss nobody
   * catches by eye: the count pills, the tags and the pillar chips all looked fine and all sat
   * just under the line. A shade darker restores the margin (5.05) while reading as the same
   * colour beside its siblings. */
  --brand-on-tint: #d2061e;
  --accent-contrast: #ffffff;
  --ok: #15803d;
  --bad: #7f1d1d;          /* destructive — DARK red, never the brand red */
  --warn: #b45309;
  --shadow: 0 1px 2px rgba(90,20,30,.06), 0 4px 16px rgba(90,20,30,.07);
  --shadow-lift: 0 2px 6px rgba(90,20,30,.10), 0 12px 28px rgba(90,20,30,.10);
}
@media (prefers-color-scheme: dark) {
  :root {
    /* Dark mode inverts the problem: #c8102e on a dark ground is muddy and hard to read, so the
       brand lightens. The danger colour lightens too, but stays a step behind, preserving the
       same light-vs-dark relationship the whole system depends on. */
    --bg: #14100f; --surface: #1d1718; --border: #35292b;
    --text: #f2e9ea; --text-muted: #a8989b;
    --brand: #ff5c6e; --brand-vivid: #ff7080; --accent: var(--brand);
    --accent-soft: #2a1a1d; --accent-contrast: #14100f;
    /* On a dark tint the correction runs the other way: lighter, not darker. */
    --brand-on-tint: #ff8592;
    --ok: #4ade80; --bad: #b34a4a; --warn: #f0a94a;
    --shadow: 0 1px 2px rgba(0,0,0,.5), 0 6px 24px rgba(0,0,0,.4);
    --shadow-lift: 0 2px 8px rgba(0,0,0,.55), 0 14px 32px rgba(0,0,0,.45);
  }
}

* { box-sizing: border-box; }
body {
  margin: 0; font-family: var(--font); color: var(--text); background: var(--bg);
  line-height: 1.55; -webkit-font-smoothing: antialiased;
}

/* ⭐ Form controls do NOT inherit the page font. Browsers give <input>, <select>, <textarea>
 * and <button> their own UA default — Arial here — and `font-family` on <body> does not reach
 * them, because the UA stylesheet sets it directly on the element and a direct rule always
 * beats inheritance.
 *
 * Eleven components had each remembered to write `font: inherit` themselves. Every control that
 * did NOT carry one of those classes rendered in Arial beside system-ui body text: the type
 * dropdowns in the marketplace filters, the niche and profit inputs, the "Show" button on the
 * legal pages. Measured across seventeen pages, five were shipping two typefaces.
 *
 * One base rule fixes all of them and every control written from here on, which is the point —
 * a convention that each new template has to remember is a convention that will be forgotten.
 * The per-component rules still layer their own size and weight on top. */
input, select, textarea, button { font: inherit; }

/* Links. There was no base rule for these at all, so every anchor without a class of its own
 * rendered in the browser's default #0000EE — bright blue, in a product whose whole identity is
 * red. "Forgot your password?", the contact address in the terms, the cross-links on Pricing:
 * all of them, on every page, looking like an unstyled document from 1996. It is the single
 * loudest signal that nobody finished the design.
 *
 * It hid because the default passes contrast on a light page (8.6:1) and only fails in dark
 * mode, where it measures 2.01 against the dark ground. A light-only check would call it clean.
 * Seven class rules had each re-declared `color: var(--accent)` to work around it one screen at
 * a time, which is what a missing base rule looks like from the inside.
 *
 * The underline stays. Colour alone must not be what tells somebody a word is a link — that is
 * the same rule the two-red palette exists to respect. */
a { color: var(--accent); text-underline-offset: .15em; }
a:hover { color: var(--brand-on-tint); }
a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }

.topbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--border);
  background: var(--surface);
}
.brand { font-weight: 700; letter-spacing: -.01em; }
.brand-sub {
  font-weight: 600; font-size: .7em; color: var(--accent);
  border: 1px solid var(--accent); border-radius: 6px; padding: .1em .4em; margin-inline-start: .3em;
  vertical-align: middle;
}
.phase-pill {
  font-size: .78rem; color: var(--text-muted);
  border: 1px solid var(--border); border-radius: 999px; padding: .25em .8em; background: var(--bg);
}

.topbar-right { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.quota { font-size: .82rem; color: var(--text-muted); }
.quota b { color: var(--text); font-variant-numeric: tabular-nums; }
.ws-name { font-size: .88rem; font-weight: 600; }
.ws-switch select {
  font: inherit; font-size: .88rem; padding: .25em .5em; border-radius: 8px;
  border: 1px solid var(--border); background: var(--bg); color: var(--text);
}
.role-chip {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--text-muted); border: 1px solid var(--border); border-radius: 999px;
  padding: .15em .6em;
}
.inline { display: inline; }
.btn-link {
  font: inherit; font-size: .85rem; background: none; border: none; padding: 0;
  color: var(--accent); cursor: pointer; text-decoration: underline;
}
.btn-link:hover { filter: brightness(1.1); }
.btn:disabled, .btn-primary:disabled { opacity: .5; cursor: not-allowed; }

.mainnav { display: flex; gap: var(--space-2); margin-inline-start: var(--space-3); flex: 1; }
.mainnav a {
  font-size: .9rem; font-weight: 600; color: var(--text-muted); text-decoration: none;
  padding: .3em .1em; border-bottom: 2px solid transparent;
}
.mainnav a:hover { color: var(--text); border-bottom-color: var(--accent); }

.page { max-width: 860px; margin: 0 auto; padding: var(--space-4) var(--space-3); }

/* The desktop STEP 3 status strip: one glance says whether the queue needs you. */
.queue-strip {
  display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
  padding: .55em .9em; border-radius: 10px; margin: 0 0 var(--space-3);
  background: var(--accent-soft); color: var(--text); font-size: .9rem;
  border: 1px solid var(--border);
}
.queue-strip b { letter-spacing: .06em; color: var(--brand-on-tint); }
.queue-strip.is-bad { border-color: var(--bad); }
.queue-strip.is-bad b { color: var(--bad); }
.queue-strip.is-live { border-color: var(--accent); }

/* Queue statuses in the job table: waiting is quiet, running is brand, failed is loud. */
.badge-queued { color: var(--text-muted); }
.badge-running { color: var(--brand-on-tint); font-weight: 600; }

/* The desktop's second tab row (SEO Plan | Keywords | Calendar), as a quiet strip. */
.subnav {
  display: flex; gap: var(--space-2); margin: 0 0 var(--space-3);
  border-bottom: 1px solid var(--border);
}
.subnav a {
  font-size: .88rem; font-weight: 600; color: var(--text-muted); text-decoration: none;
  padding: .35em .2em .5em; border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.subnav a:hover { color: var(--text); }
.subnav a[aria-current] { color: var(--brand-on-tint); border-bottom-color: var(--accent); }

/* --- dashboard --- */
.dash-head { margin-bottom: var(--space-3); }
.dash-head h1 { font-size: 1.7rem; letter-spacing: -.02em; margin: 0 0 .2rem; }

/* The three customer doors on Home: new site → Plan, volume → Bulk, old site → Upgrade.
   Each card names WHO it is for before what it does, so nobody has to guess their path. */
.journeys {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-2); margin-bottom: var(--space-3);
}
.journey {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: var(--space-3); text-decoration: none; color: inherit;
  display: flex; flex-direction: column; gap: .35rem; box-shadow: var(--shadow);
}
.journey:hover { border-color: var(--accent); }
.journey > b { font-size: 1.05rem; letter-spacing: -.01em; }
.journey-kicker {
  font-size: .78rem; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  color: var(--brand-on-tint);
}
.journey-desc { font-size: .88rem; color: var(--text-muted); line-height: 1.45; }

.stat-row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--space-2); margin-bottom: var(--space-4);
}
.stat {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: var(--space-2) var(--space-3); text-decoration: none; color: inherit;
  display: flex; flex-direction: column; gap: .1rem; box-shadow: var(--shadow);
}
.stat:hover { border-color: var(--accent); }
.stat-n { font-size: 1.6rem; font-weight: 700; letter-spacing: -.02em; }
.stat-l { font-size: .82rem; color: var(--text-muted); }

.panel {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: var(--space-3); margin-bottom: var(--space-3); box-shadow: var(--shadow);
}
.panel h2 { font-size: 1.05rem; margin: 0 0 var(--space-2); }
.panel-head { display: flex; justify-content: space-between; align-items: baseline; }
.panel-head h2 { margin-bottom: var(--space-2); }
.hint { font-size: .86rem; color: var(--text-muted); margin: var(--space-2) 0 0; }

/* A readable list of rules or facts, at body size rather than the muted small text the
   other lists use — these are terms somebody has to be able to read carefully. */
.plain-list {
  margin: var(--space-2) 0 0; padding-inline-start: 1.2rem; color: var(--text);
  line-height: 1.65;
}
.plain-list li + li { margin-top: .5rem; }

.warn-inline { color: #b45309; }
.warn-inline code {
  background: var(--bg); padding: .1em .35em; border-radius: 4px; font-size: .95em;
}

.row {
  display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-2);
  padding: .6em 0; border-bottom: 1px solid var(--border); flex-wrap: wrap;
}
.row:last-child { border-bottom: none; }
.row-title { font-weight: 600; color: var(--text); text-decoration: none; }
.row-title:hover { color: var(--accent); }
.row-meta { font-size: .8rem; color: var(--text-muted); }

/* --- tools --- */
.field textarea {
  font: inherit; font-size: .92rem; padding: .7em .8em; border-radius: 10px;
  border: 1px solid var(--border); background: var(--bg); color: var(--text); resize: vertical;
}
.field textarea:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--accent) 45%, transparent); outline-offset: 1px;
}
.verdict {
  font-size: .92rem; background: var(--bg); border-inline-start: 3px solid var(--accent);
  padding: .6em .8em; border-start-start-radius: 0; border-start-end-radius: 8px;
  border-end-end-radius: 8px; border-end-start-radius: 0; margin: 0 0 var(--space-2);
}
.metric-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: var(--space-2); margin: var(--space-2) 0;
}
.metric {
  background: var(--bg); border: 1px solid var(--border); border-radius: 10px;
  padding: .6em .7em; display: flex; flex-direction: column;
}
.metric b { font-size: 1.15rem; letter-spacing: -.01em; }
.metric span { font-size: .74rem; color: var(--text-muted); }
.sub { font-size: .92rem; margin: var(--space-3) 0 var(--space-1); }
.gate-list { display: flex; flex-direction: column; gap: .25rem; }
.gate-row { display: flex; align-items: center; gap: .5rem; font-size: .88rem; }
.gate-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.gate-dot.ok { background: var(--ok); }
.gate-dot.bad { background: var(--bad); }
.gate-name { flex: 1; text-transform: capitalize; }
/* The capitalize above suits one-word gate names ("readability"). Prose inside a gate row —
   the dashboards reuse the layout for full sentences — must NOT be title-cased, or "Ask them
   what stopped" renders as legalese. */
.gate-name small { display: block; text-transform: none; color: var(--text-muted); }
.gate-score { color: var(--text-muted); font-variant-numeric: tabular-nums; }
/* --- legal + pricing --- */
.legal { max-width: 700px; }
.legal h1 { font-size: 1.8rem; letter-spacing: -.02em; margin: 0 0 .3rem; }
.legal h2 { font-size: 1.08rem; margin: var(--space-4) 0 var(--space-1); }
.legal h3 { font-size: .95rem; margin: var(--space-3) 0 var(--space-1); }
.legal p, .legal li { font-size: .94rem; line-height: 1.65; }
.legal ul { padding-inline-start: 1.2rem; }
.legal li { margin: .35rem 0; }
.refund-table { border-collapse: collapse; width: 100%; margin: var(--space-2) 0; font-size: .9rem; }
.refund-table th, .refund-table td {
  text-align: start; padding: .5em .7em; border-bottom: 1px solid var(--border);
}
.refund-table th { color: var(--text-muted); font-weight: 600; font-size: .82rem; }
.refund-table td { font-variant-numeric: tabular-nums; }

/* 300px, not 210px: a package card now carries who it is for, what is in it, what is NOT, and
   the allowance — at 210px every one of those lines breaks two or three times and the ladder
   reads as noise. Three comfortable columns beats five cramped ones. */
.plan-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: var(--space-2); margin: var(--space-3) 0 var(--space-4);
}
.plan-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: var(--space-3); display: flex; flex-direction: column; box-shadow: var(--shadow);
}
.plan-card h2, .plan-card h3 { font-size: 1.05rem; margin: 0 0 .3rem; }

/* Three ladders of five or six packages each need room the 860px reading column does not have:
   at that width six cards wrap to 260px columns and every line inside them breaks twice. The
   pricing page opts into a wider container; nothing else does, because prose is easier to read
   narrow and only this page is a comparison table wearing cards. */
.page-wide { max-width: 1180px; }
.plan-card .hint { font-size: .8rem; margin: 0 0 var(--space-2); }
.plan-card .plan-list + .plan-list { border-top: 1px solid var(--border); padding-top: .4rem; }
.plan-card .badge-ok { align-self: flex-start; margin-bottom: .4rem; }
.plan-price { display: flex; align-items: baseline; gap: .35rem; margin-bottom: .5rem; }
.plan-price b { font-size: 1.9rem; letter-spacing: -.03em; }
.plan-price span { font-size: .78rem; color: var(--text-muted); }
.plan-blurb { font-size: .86rem; color: var(--text-muted); margin: 0 0 var(--space-2); }
.plan-list { list-style: none; padding: 0; margin: 0 0 var(--space-3); flex: 1; }
.plan-list li { font-size: .85rem; padding: .25em 0; border-bottom: 1px solid var(--border); }
.plan-list li:last-child { border-bottom: none; }

/* --- landing --- */
.lp-hero { text-align: center; padding: var(--space-4) 0 var(--space-3); }
.lp-hero h1 {
  font-size: 2.1rem; line-height: 1.15; letter-spacing: -.03em; margin: 0 auto var(--space-2);
  max-width: 18ch;
}
.lp-hero .lede { max-width: 60ch; margin: 0 auto var(--space-3); }
.lp-hero .btn, .lp-hero .btn-secondary { margin: 0 .3rem; }
.lp-audit { border: 1px solid var(--accent); }
.lp-result { margin-top: var(--space-3); padding-top: var(--space-3); border-top: 1px solid var(--border); }
.lp-cols {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-3); margin: var(--space-4) 0;
}
.lp-cols h3 { font-size: 1rem; margin: 0 0 .3rem; }
.lp-cols p { font-size: .9rem; color: var(--text-muted); margin: 0; }
.lp-cta { text-align: center; }
.lp-cta b { display: block; margin-bottom: .3rem; }
.foot a { color: var(--accent); }

.free-chip {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; color: var(--ok);
  border: 1px solid currentColor; border-radius: 999px; padding: .1em .6em; margin-inline-start: .4em;
  vertical-align: middle;
}
/* The counterpart to `.free-chip`: this tool spends. Brand red rather than green, because
   the difference between "free forever" and "costs you words" must survive a glance. */
.ai-chip {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--brand-on-tint);
  border: 1px solid currentColor; border-radius: 999px; padding: .1em .6em;
  margin-inline-start: .4em; vertical-align: middle;
}
.tool-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: var(--space-2);
}
/* A spending tool is marked in the grid too, so the choice is visible before the click. */
.tool-card.is-ai { border-inline-start: 3px solid var(--accent); }
.tool-card {
  display: flex; flex-direction: column; gap: .25rem; text-decoration: none; color: inherit;
  background: var(--bg); border: 1px solid var(--border); border-radius: 10px;
  padding: .7em .85em;
}
.tool-card:hover { border-color: var(--accent); }
.tool-card b { font-size: .92rem; }
.tool-card span { font-size: .78rem; color: var(--text-muted); }
.kv { display: grid; grid-template-columns: minmax(120px, auto) 1fr; gap: .4rem var(--space-2); margin: 0; }
.kv dt { font-size: .82rem; color: var(--text-muted); text-transform: capitalize; }
.kv dd { margin: 0; font-size: .9rem; word-break: break-word; }

.chips { display: flex; flex-wrap: wrap; gap: .3rem; }
.chip {
  font-size: .78rem; background: var(--bg); border: 1px solid var(--border);
  border-radius: 999px; padding: .2em .7em;
}

/* --- auth --- */
.auth { max-width: 380px; margin: var(--space-4) auto; }
.auth h1 { font-size: 1.5rem; margin: 0 0 var(--space-3); letter-spacing: -.02em; }
.auth-form { display: flex; flex-direction: column; gap: var(--space-2); }
.field { display: flex; flex-direction: column; gap: .3rem; font-size: .9rem; }
.field span { font-weight: 600; }
.field input {
  font: inherit; padding: .6em .8em; border-radius: 10px;
  border: 1px solid var(--border); background: var(--surface); color: var(--text);
}
.field input:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--accent) 45%, transparent); outline-offset: 1px;
}
.field small { color: var(--text-muted); font-size: .8rem; }
.auth-error {
  background: color-mix(in srgb, var(--bad) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--bad) 40%, transparent);
  color: var(--bad); padding: .6em .8em; border-radius: 8px; font-size: .88rem;
  margin: 0 0 var(--space-2);
}
.auth-alt { margin-top: var(--space-3); font-size: .88rem; color: var(--text-muted); }
.auth-alt a { color: var(--accent); }

.hero h1 { font-size: 1.9rem; letter-spacing: -.02em; margin: 0 0 var(--space-1); }
.lede { color: var(--text-muted); margin: 0 0 var(--space-3); font-size: 1.05rem; }

.card-wrap {
  display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
  margin: var(--space-3) 0 var(--space-4);
}
.status-card {
  display: flex; gap: var(--space-2); align-items: flex-start;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: var(--space-2) var(--space-3); box-shadow: var(--shadow); min-width: 260px;
}
.dot { width: 12px; height: 12px; border-radius: 50%; margin-top: .45rem; flex: none; }
.dot-ok { background: var(--ok); box-shadow: 0 0 0 4px color-mix(in srgb, var(--ok) 20%, transparent); }
.dot-bad { background: var(--bad); box-shadow: 0 0 0 4px color-mix(in srgb, var(--bad) 20%, transparent); }
.status-line { font-size: .92rem; }
.status-key { display: inline-block; min-width: 96px; color: var(--text-muted); }
.status-muted { color: var(--text-muted); font-size: .82rem; margin-top: .3rem; }

.btn,
/* `.btn-primary` is the name nine templates already reach for — including the button that
   accepts AI data-sharing. It was never defined, so the single most important button in the
   product rendered as a grey browser default. Same rules rather than a rename: the name reads
   better at the call site, and renaming across nine files invites a missed one. */
.btn-primary {
  font: inherit; font-weight: 600; cursor: pointer;
  background: var(--accent); color: var(--accent-contrast); border: none;
  border-radius: 10px; padding: .6em 1.1em;
}
.btn:hover, .btn-primary:hover { filter: brightness(1.05); }
.btn:focus-visible, .btn-primary:focus-visible { outline: 3px solid color-mix(in srgb, var(--accent) 50%, transparent); outline-offset: 2px; }
/* Added by app.js the moment a POST form submits — the pressed button dims and stops
   answering, so a nervous second click cannot place a second order. */
.is-busy { opacity: .55; cursor: progress; pointer-events: none; }

/* The Google-result preview on a draft: deliberately NOT our brand — it imitates the search
   page it predicts, because that is the whole point of a preview. Colours are fixed, not
   themed: Google's result page does not follow our palette either. */
.serp-preview {
  display: block; max-width: 600px; padding: var(--space-2);
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface);
}
.serp-preview .serp-url { display: block; font-size: .8rem; color: var(--text-muted); }
.serp-preview .serp-title {
  display: block; font-size: 1.15rem; line-height: 1.3; color: #1a0dab; margin: .15rem 0;
}
.serp-preview .serp-desc { display: block; font-size: .88rem; line-height: 1.45; color: var(--text-muted); }
@media (prefers-color-scheme: dark) {
  .serp-preview .serp-title { color: #8ab4f8; }
}

/* The Ctrl+K jump palette — built entirely by app.js, styled here. */
.palette-overlay {
  position: fixed; inset: 0; z-index: 100; background: rgba(0,0,0,.35);
  display: flex; align-items: flex-start; justify-content: center; padding-top: 12vh;
}
.palette {
  width: min(34rem, 92vw); background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: 0 12px 40px rgba(0,0,0,.25); overflow: hidden;
}
.palette input {
  width: 100%; border: 0; border-bottom: 1px solid var(--border); background: transparent;
  color: var(--text); padding: .8rem 1rem; font-size: 1rem; outline: none;
}
.palette ul { list-style: none; margin: 0; padding: .3rem; max-height: 50vh; overflow-y: auto; }
.palette li a {
  display: flex; justify-content: space-between; gap: 1rem; align-items: baseline;
  padding: .45rem .7rem; border-radius: calc(var(--radius) - 4px);
  color: var(--text); text-decoration: none;
}
.palette li.active a, .palette li a:hover { background: var(--surface); color: var(--accent); }
.palette .palette-path { font-size: .75rem; color: var(--text-muted); }
.foot-kbd { display: block; margin-top: .35rem; font-size: .8rem; color: var(--text-muted); }

/* ── the draft editor ── */
.edit-grid { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: flex-start; }
.edit-main { flex: 3 1 30rem; min-width: 0; }
.edit-side { flex: 1 1 18rem; min-width: 0; }
.edit-body {
  width: 100%; min-height: 26rem; resize: vertical;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .9rem; line-height: 1.6;
}

/* ── the term-coverage panel ── */
.terms { display: flex; flex-wrap: wrap; gap: .3rem; margin: .4rem 0; }
.term {
  display: inline-block; padding: .1rem .45rem; border-radius: 999px;
  font-size: .78rem; border: 1px solid var(--border); white-space: nowrap;
}
.term-missing {
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  background: color-mix(in srgb, var(--accent) 10%, transparent); color: var(--text);
}
.term-used { color: var(--text-muted); }

/* ── the content calendar's month grid ── */
.cal-nav { display: flex; gap: .8rem; align-items: baseline; }
/* flex-basis 100%: inside the panel's flex layout an auto-sized wrapper shrinks to the
   table's content width and the calendar renders as a squeezed column — seen live. */
.cal-scroll { overflow-x: auto; flex: 1 1 100%; width: 100%; }
.cal-grid {
  /* display:table explicitly — the responsive global turns tables into scrollable blocks,
     which collapses a fixed-layout grid to content width (cells measured 42px inside a
     688px table, live). The .cal-scroll wrapper already provides the small-screen scroll. */
  display: table;
  width: 100%; min-width: 40rem; border-collapse: collapse; table-layout: fixed;
}
.cal-grid th {
  text-align: left; font-size: .72rem; color: var(--text-muted); font-weight: 600;
  padding: .3rem .4rem; border-bottom: 1px solid var(--border);
}
.cal-grid td {
  vertical-align: top; height: 4.6rem; padding: .3rem .4rem;
  border: 1px solid var(--border); font-size: .78rem;
}
.cal-day { display: block; font-weight: 700; font-variant-numeric: tabular-nums; }
.cal-out { background: var(--surface); }
.cal-out .cal-day { color: var(--text-muted); font-weight: 400; }
.cal-today { box-shadow: inset 0 0 0 2px var(--accent); }
.cal-today .cal-day { color: var(--accent); }
.cal-item {
  display: block; margin-top: .15rem; padding: .05rem .3rem; border-radius: 4px;
  background: color-mix(in srgb, var(--accent) 12%, transparent); color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cal-more { display: block; margin-top: .15rem; color: var(--text-muted); font-size: .72rem; }
.sr-hide {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}

/* ── the chat bubble ── */
.chat-launcher {
  position: fixed; right: 1rem; bottom: 1rem; z-index: 90;
  background: var(--accent); color: var(--accent-contrast); text-decoration: none;
  padding: .55rem .9rem; border-radius: 2rem; font-weight: 700; font-size: .9rem;
  box-shadow: 0 4px 14px rgba(200,16,46,.35);
}
.chat-launcher:hover { filter: brightness(1.05); }
.chat-panel {
  position: fixed; right: 1rem; bottom: 3.6rem; z-index: 95;
  width: min(22rem, calc(100vw - 2rem)); max-height: min(30rem, 70vh);
  display: flex; flex-direction: column;
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 12px 40px rgba(0,0,0,.25); overflow: hidden;
}
.chat-panel[hidden] { display: none; }
.chat-head {
  display: flex; align-items: baseline; gap: .5rem; padding: .6rem .8rem;
  border-bottom: 1px solid var(--border); background: var(--surface);
}
.chat-head span { font-size: .75rem; color: var(--text-muted); flex: 1 1 auto; }
.chat-log { flex: 1 1 auto; overflow-y: auto; padding: .7rem; min-height: 6rem; }
.chat-bubble {
  max-width: 88%; padding: .45rem .7rem; margin: 0 0 .45rem; border-radius: .8rem;
  font-size: .88rem; line-height: 1.45; white-space: pre-line; overflow-wrap: break-word;
}
.chat-you { margin-inline-start: auto; background: var(--accent); color: var(--accent-contrast); }
.chat-bot { background: var(--surface); border: 1px solid var(--border); color: var(--text); }
.chat-send { display: flex; gap: .4rem; padding: .6rem; border-top: 1px solid var(--border); align-items: flex-end; }
.chat-ask {
  flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: .15rem;
  font-size: .72rem; color: var(--text-muted);
}
.chat-ask input { min-width: 0; }
.chat-foot {
  margin: 0; padding: .45rem .8rem .6rem; font-size: .75rem; color: var(--text-muted);
}

.generate { border-top: 1px solid var(--border); padding-top: var(--space-3); margin-bottom: var(--space-4); }
.generate h2 { font-size: 1.05rem; margin: 0 0 var(--space-1); }
.lede-sm { color: var(--text-muted); font-size: .92rem; margin: 0 0 var(--space-2); }
.gen-form { display: flex; gap: var(--space-1); flex-wrap: wrap; align-items: flex-end; }

/* Every control wears its name where a person can see it.
 *
 * The topical-map form shipped as a row of boxes reading "5" and "8" — the labels existed only
 * as aria-label and title, which is to say: for screen readers and for anyone patient enough to
 * hover and wait. A sighted user just saw two meaningless numbers, and a form that makes people
 * guess is a form that makes the whole product look abandoned.
 *
 * The label WRAPS the control, so the association is automatic (no for/id bookkeeping to rot)
 * and clicking the name focuses the field. Placeholders go back to being examples, which is the
 * only job they were ever fit for — they vanish the moment somebody types. */
.field-l {
  display: flex; flex-direction: column; gap: .28rem; min-width: 0;
  flex: 1 1 260px;   /* the wrapper inherits the sizing role the bare input used to play */
  font-size: .76rem; font-weight: 600; color: var(--text-muted);
}
/* Inside the wrapper the flex axis is VERTICAL, so the input's own `flex: 1 1 260px` would
   become a 260px HEIGHT. Neutralised — the wrapper does the sizing now. */
.field-l > .gen-input { font-weight: 400; font-size: .95rem; width: 100%; flex: 0 0 auto; }
/* The form aligns to the flex END so buttons sit level with the inputs, not the labels. */
.gen-input {
  flex: 1 1 260px; font: inherit; padding: .6em .8em;
  border: 1px solid var(--border); border-radius: 10px; background: var(--surface); color: var(--text);
}
.gen-input:focus-visible { outline: 3px solid color-mix(in srgb, var(--accent) 45%, transparent); outline-offset: 1px; }

.job {
  margin-top: var(--space-2); background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: var(--space-2) var(--space-3); box-shadow: var(--shadow);
}
.job-head { display: flex; justify-content: space-between; font-size: .9rem; margin-bottom: .5rem; }
.job-stage { font-weight: 600; }
.job-pct { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.job-track { height: 8px; background: var(--border); border-radius: 999px; overflow: hidden; }
.job-bar { height: 100%; width: 0; background: var(--accent); border-radius: 999px; transition: width .4s ease; }
.job-failed .job-bar { background: var(--bad); }
.job-failed .job-stage { color: var(--bad); }
.job-result { margin-top: var(--space-2); }
.job-result h3 { margin: 0 0 .2rem; font-size: 1.05rem; }
.job-meta { color: var(--text-muted); font-size: .82rem; margin: 0 0 .5rem; }
.job-notice {
  font-size: .84rem; margin: 0 0 .6rem; padding: .5em .7em; border-radius: 8px;
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
}
.badge {
  display: inline-block; padding: .05em .5em; border-radius: 999px;
  font-size: .78rem; font-weight: 600; border: 1px solid currentColor;
}
/* Badges are written as `badge-{{ status }}` in a dozen templates, so the class name comes from
   a database value rather than from a designer. Two consequences, both fixed here:

   Every status the product can emit is listed. The ones that were missing rendered as unstyled
   grey text, which reads as a layout bug on exactly the rows that matter most — a pending
   commission, a failed job.

   Every one carries the pill shape itself rather than relying on a separate `.badge`, because
   most of those call sites emit the status class alone. Half the badges in the product were
   pills and half were coloured text, from the same template loop. */
.badge-strong, .badge-good, .badge-ok, .badge-needs-work, .badge-weak,
.badge-pending, .badge-paid, .badge-reversed, .badge-open, .badge-answered, .badge-closed,
.badge-failed, .badge-planned, .badge-written, .badge-succeeded, .badge-blocked {
  display: inline-block; padding: .05em .5em; border-radius: 999px;
  font-size: .78rem; font-weight: 600; border: 1px solid currentColor;
}
.badge-strong, .badge-good, .badge-ok,
.badge-paid, .badge-answered, .badge-written, .badge-succeeded { color: var(--ok); }
.badge-needs-work, .badge-pending, .badge-open, .badge-planned { color: #b45309; }
.badge-weak, .badge-reversed, .badge-failed, .badge-blocked { color: var(--bad); }
.badge-closed { color: var(--text-muted); }
.findings {
  font-size: .86rem; margin: 0 0 .8rem; padding: .6em .8em;
  border-inline-start: 3px solid var(--border); background: var(--bg); border-start-start-radius: 0; border-start-end-radius: 8px;
  border-end-end-radius: 8px; border-end-start-radius: 0;
}
.findings ul { margin: .3rem 0 0; padding-inline-start: 1.1rem; color: var(--text-muted); }
/* Not a problem with the article — a limit of ours. Distinct from findings, which are things
   the writer should fix, so it must not read as another item on that list. */
.findings.unchecked { border-inline-start-color: var(--accent); }
.findings.unchecked .hint { margin: .35rem 0 0; font-size: .82rem; }
.job-body {
  margin-top: var(--space-2); padding-top: var(--space-2); border-top: 1px solid var(--border);
  max-height: 460px; overflow-y: auto;
}
.job-body h4 { font-size: 1rem; margin: 1.1em 0 .3em; }
.job-body h5 { font-size: .92rem; margin: 1em 0 .3em; }
.job-body p, .job-body li { font-size: .93rem; }

/* --- review + drafts --- */
.crumbs { font-size: .84rem; color: var(--text-muted); margin-bottom: var(--space-2); }
.crumbs a { color: var(--accent); text-decoration: none; }
.crumbs a:hover { text-decoration: underline; }

.btn-secondary {
  display: inline-block; font: inherit; font-size: .9rem; font-weight: 600; cursor: pointer;
  background: transparent; color: var(--accent); border: 1px solid var(--accent);
  border-radius: 10px; padding: .5em 1em; text-decoration: none;
}
.btn-secondary:hover { background: color-mix(in srgb, var(--accent) 10%, transparent); }
.btn-danger {
  font: inherit; font-weight: 600; cursor: pointer; background: transparent; color: var(--bad);
  border: 1px solid color-mix(in srgb, var(--bad) 50%, transparent);
  border-radius: 10px; padding: .5em 1em;
}
.btn-sm { font-size: .85rem; padding: .4em .9em; }

.empty {
  border: 1px dashed var(--border); border-radius: var(--radius);
  padding: var(--space-3); text-align: center; color: var(--text-muted);
}
.empty a { color: var(--accent); }

.review-list { margin-bottom: var(--space-4); }
.review-list h2 { font-size: 1.05rem; margin: 0 0 var(--space-2); }
.draft-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: var(--space-2) var(--space-3); margin-bottom: var(--space-2); box-shadow: var(--shadow);
}
.draft-card.is-blocked { border-inline-start: 3px solid var(--bad); }
.draft-card.is-approved { border-inline-start: 3px solid var(--ok); }
.draft-title { font-weight: 700; font-size: 1.02rem; color: var(--text); text-decoration: none; }
.draft-title:hover { color: var(--accent); }
.draft-meta { color: var(--text-muted); font-size: .82rem; margin-top: .2rem; }
.origin { color: var(--accent); font-weight: 600; }
.draft-actions { display: flex; gap: var(--space-1); flex-wrap: wrap; margin-top: var(--space-2); }
.readonly-note { color: var(--text-muted); font-size: .84rem; margin: var(--space-2) 0 0; }
.review-note {
  font-size: .88rem; background: var(--bg); border-inline-start: 3px solid var(--border);
  padding: .5em .8em; border-start-start-radius: 0; border-start-end-radius: 8px;
  border-end-end-radius: 8px; border-end-start-radius: 0;
}
/* (badge-blocked and badge-needs-work are coloured with the rest of the badges above.) */
.notice-ok {
  background: color-mix(in srgb, var(--ok) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--ok) 40%, transparent);
  color: var(--ok); padding: .6em .8em; border-radius: 8px; font-size: .88rem;
  margin: 0 0 var(--space-2);
}
.connect-box {
  border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-2);
  background: var(--surface);
}
.connect-box summary { cursor: pointer; font-weight: 600; font-size: .92rem; }
.connect-box .auth-form { margin-top: var(--space-2); max-width: 420px; }

.draft-full h1 { font-size: 1.6rem; letter-spacing: -.02em; margin: 0 0 .3rem; }
.draft-body {
  margin-top: var(--space-3); padding-top: var(--space-3); border-top: 1px solid var(--border);
  white-space: pre-wrap; font-size: .95rem; line-height: 1.7;
}

.seams { border-top: 1px solid var(--border); padding-top: var(--space-3); }
.seams h2 { font-size: 1.05rem; margin: 0 0 var(--space-1); }
.seams ul { margin: 0; padding-inline-start: 1.2rem; color: var(--text-muted); }
.seams li { margin: .25rem 0; }

.foot {
  max-width: 760px; margin: 0 auto; padding: var(--space-3);
  color: var(--text-muted); font-size: .82rem; border-top: 1px solid var(--border);
}

/* --- plain-language panel (bilingual legal + onboarding) ------------------------------------
   The reader's own language sits FIRST and larger, because it is the one they will actually
   read; the English follows in a quieter tone because it is the version that governs. Both are
   always present — a language toggle that hides one of them is how people end up agreeing to
   something they never saw. */
.plain-panel {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: var(--space-3); margin: 0 0 var(--space-4); box-shadow: var(--shadow);
}
.plain-head {
  display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center;
  justify-content: space-between; margin-bottom: var(--space-2);
}
.plain-head h2 { margin: 0; font-size: 1.15rem; letter-spacing: -.01em; }
.lang-form { display: flex; align-items: center; gap: .5rem; font-size: .82rem; }
.lang-form label { color: var(--text-muted); }
.lang-form select {
  font: inherit; font-size: .85rem; padding: .35em .5em; border-radius: 8px;
  border: 1px solid var(--border); background: var(--bg); color: var(--text);
}
.plain-note {
  margin: 0 0 var(--space-2); padding: .6em .8em; border-radius: 8px; font-size: .82rem;
  color: var(--text-muted);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 25%, transparent);
}
.plain-warn {
  margin: 0 0 var(--space-2); padding: .6em .8em; border-radius: 8px; font-size: .85rem;
  background: color-mix(in srgb, var(--bad) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--bad) 35%, transparent);
}
.plain-block {
  padding: var(--space-2) 0; border-top: 1px solid var(--border);
}
.plain-block:first-of-type { border-top: none; padding-top: 0; }
.plain-local {
  white-space: pre-line; font-size: 1rem; line-height: 1.75; margin-bottom: .5rem;
}
.plain-en {
  white-space: pre-line; font-size: .9rem; line-height: 1.65; color: var(--text-muted);
}
/* When there is no translation the English IS the plain version, so it must not look secondary. */
.plain-block > .plain-en:only-child { font-size: 1rem; color: var(--text); }
.plain-foot {
  margin: var(--space-2) 0 0; padding-top: var(--space-2); border-top: 1px solid var(--border);
  font-size: .82rem; color: var(--text-muted);
}

/* --- onboarding walkthrough ------------------------------------------------------------------
   The step track is a real navigation aid, not decoration: the owner asked for the navigation
   to be marked step by step, so every number is a link and the current one is unmistakable. */
.onboard { max-width: 720px; }
.onboard-actions {
  display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center;
  margin-top: var(--space-3);
}
.step-track {
  display: flex; flex-wrap: wrap; gap: .4rem; list-style: none; padding: 0;
  margin: 0 0 var(--space-2);
}
/* The circles are <a> where they navigate (wizard, walkthrough) and <span> where they only
   show state (deal milestones) — both must look identical or the tracker reads as broken. */
.step-track li a,
.step-track li span {
  display: grid; place-items: center; width: 2rem; height: 2rem; border-radius: 50%;
  border: 1px solid var(--border); background: var(--surface); color: var(--text-muted);
  text-decoration: none; font-size: .8rem; font-variant-numeric: tabular-nums;
}
.step-track li.done a, .step-track li.done span { border-color: var(--ok); color: var(--ok); }
.step-track li.here a,
.step-track li.here span {
  background: var(--accent); border-color: var(--accent); color: var(--accent-contrast);
  font-weight: 700;
}
.step-nav {
  display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center;
  margin-top: var(--space-2); padding-top: var(--space-2); border-top: 1px solid var(--border);
}
.why { margin-top: var(--space-2); }
.why summary { cursor: pointer; font-size: .88rem; color: var(--text-muted); }
.survey-q {
  border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-2);
  margin: 0 0 var(--space-2);
}
.survey-q legend { font-weight: 600; font-size: .92rem; padding: 0 .4em; }
.choice { display: block; padding: .3rem 0; font-size: .92rem; cursor: pointer; }
.choice input { margin-inline-end: .5rem; }

/* --- review code --------------------------------------------------------------------------- */
.code-badge {
  /* A referral link is one unbreakable token, so it pushed this badge to 450px inside a 375px
     phone and took the whole page sideways with it. `anywhere` rather than `break-word`: a URL
     has no spaces to break at, so the softer property finds nowhere to wrap and gives up. */
  overflow-wrap: anywhere;
  max-width: 100%;
  display: inline-block; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 1.35rem; letter-spacing: .12em; padding: .5rem .9rem; border-radius: 10px;
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  user-select: all;   /* one click selects the whole code */
}
.pre-wrap { white-space: pre-wrap; }

/* --- classes the templates were already using with no rule behind them ----------------------
   Found by comparing every class in the templates against this file. They rendered as bare
   divs: not broken, but not designed either — and "looks slightly wrong" is what a customer
   reads as "unfinished". */
.draft-head {
  display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: baseline;
  justify-content: space-between; margin-bottom: var(--space-1);
}
.draft-head h1, .draft-head h2, .draft-head h3 { margin: 0; }
.row-actions { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.status-body { font-size: .92rem; line-height: 1.6; color: var(--text-muted); }

/* The unread marker on the Alerts link. A count nobody can see is a notification that did not
   happen — the reason to write one at all is that somebody notices. */
.nav-badge {
  display: inline-block; min-width: 1.15rem; padding: 0 .35em; margin-inline-start: .3em;
  border-radius: 999px; background: var(--bad); color: #fff;
  font-size: .72rem; font-weight: 700; line-height: 1.3rem; text-align: center;
  vertical-align: text-top;
}

/* --- settings: data-sharing + refusal history --- */
/* State on a chip. `.chip` alone stays neutral; these two say which way it went without
   relying on the wording alone, which matters when the page is skimmed. */
.chip.ok { background: color-mix(in srgb, var(--ok) 15%, transparent); color: var(--ok); }
.chip.warn { background: color-mix(in srgb, #b45309 15%, transparent); color: #b45309; }

/* A disclosure for the full legal wording: present for anyone who wants it, folded away for
   everyone else. Hiding it entirely would be the thing the consent notice exists to prevent. */
details.plain { margin: var(--space-2) 0; }
details.plain summary {
  cursor: pointer; font-size: .88rem; color: var(--accent); font-weight: 600;
}
details.plain .pre-wrap {
  margin-top: var(--space-2); font-size: .9rem; color: var(--text-muted);
  border-inline-start: 2px solid var(--border); padding-inline-start: var(--space-2);
}

/* ── brand polish ─────────────────────────────────────────────────────────────
 * Applied on top of the token change, because swapping a colour variable alone
 * gives you a purple layout wearing red — not a red product.
 */

/* The masthead carries the brand instead of merely sitting above it. */
.topbar {
  border-bottom: 3px solid var(--brand-vivid);
  box-shadow: 0 1px 0 rgba(200,16,46,.06);
}
.brand { color: var(--accent); font-size: 1.05rem; }
.brand-sub {
  background: var(--accent); color: var(--accent-contrast); border-color: var(--accent);
}

/* Active navigation is marked by an underline as well as colour — colour alone
   would be invisible to a customer who cannot distinguish red from the text. */
.topbar nav a, .nav a {
  position: relative; text-decoration: none; color: var(--text-muted);
  padding-bottom: .15em; transition: color .15s ease;
}
.topbar nav a:hover, .nav a:hover { color: var(--accent); }
.topbar nav a[aria-current], .nav a[aria-current] {
  color: var(--accent); font-weight: 600;
}
.topbar nav a[aria-current]::after, .nav a[aria-current]::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -.35em;
  height: 2px; background: var(--accent); border-radius: 2px;
}

/* Cards lift slightly on hover so a long list feels responsive rather than static. */
.panel, .card {
  border-radius: var(--radius);
  transition: box-shadow .18s ease, transform .18s ease;
}
.panel:hover { box-shadow: var(--shadow-lift); }

/* Primary action: the brand red, filled. */
.btn, .btn-primary {
  box-shadow: 0 1px 2px rgba(200,16,46,.2);
  transition: filter .15s ease, box-shadow .15s ease, transform .06s ease;
}
.btn:active, .btn-primary:active { transform: translateY(1px); }

/* Destructive action: OUTLINED and dark, never filled brand red. Shape carries the
   difference, so it survives greyscale and colour-blindness. */
.btn-danger {
  color: var(--bad); border: 1.5px solid var(--bad); background: transparent; font-weight: 600;
}
.btn-danger:hover { background: var(--bad); color: #fff; }

/* Quiet emphasis — selected rows, the current step, a highlighted stat. */
.row.is-selected, .step.is-current, .stat-card.is-primary {
  background: var(--accent-soft); border-color: var(--accent);
}

.stat-card b, .stat-value { color: var(--accent); font-variant-numeric: tabular-nums; }

/* Status colours stay semantic and each keeps a word beside it in the markup. */
.chip.ok   { background: color-mix(in srgb, var(--ok) 14%, transparent);   color: var(--ok); }
.chip.warn { background: color-mix(in srgb, var(--warn) 16%, transparent); color: var(--warn); }
.chip.bad  { background: color-mix(in srgb, var(--bad) 14%, transparent);  color: var(--bad); }

.warn-inline { color: var(--warn); }

/* Rank movement. The arrow and the word "up"/"down" carry the meaning; the colour only
   makes the good news findable at a glance, so a colour-blind reader loses nothing. */
.rank-up   { color: var(--ok);  font-weight: 600; white-space: nowrap; }
.rank-down { color: var(--bad); font-weight: 600; white-space: nowrap; }
.nav-badge { background: var(--accent); color: var(--accent-contrast); }

/* Focus is brand-coloured and thick enough to find by eye — keyboard users are
   customers too, and the default outline disappears against a red button. */
:where(a, button, input, select, textarea, summary):focus-visible {
  outline: 3px solid color-mix(in srgb, var(--accent) 55%, transparent);
  outline-offset: 2px; border-radius: 6px;
}

/* Touch ergonomics — two floors that desktop never needed, measured on every screen:
   1. iPhones ZOOM THE WHOLE PAGE when a focused control's font is under 16px, and the app's
      denser desktop type (14-15.2px controls) sat under that line on all 15 form screens.
      The !important is deliberate: this floor must beat every per-component size.
   2. `.btn-link` text buttons measured 21px tall — a miss-tap with a thumb. Padding grows
      the target to ~34px while the negative margin holds the visual layout exactly still. */
@media (pointer: coarse), (max-width: 700px) {
  input:not([type="hidden"]), select, textarea { font-size: 16px !important; }
  .btn-link { padding: .5em .3em; margin: -.4em -.15em; }
}

/* Vestibular-safe: someone who asked their OS for reduced motion gets state changes as
   instant swaps, not animations. The bars and buttons still work — they just don't move. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: .01ms !important;
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
  }
}

/* Tables read as data, not as boxes. */
table { border-collapse: collapse; width: 100%; }
th {
  text-align: start; font-size: .8rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--text-muted); border-bottom: 2px solid var(--border); padding: .5em .6em;
}
td { padding: .55em .6em; border-bottom: 1px solid var(--border); }
tbody tr:hover { background: var(--accent-soft); }

/* Long content must never push the page sideways on a phone. `overflow-x:auto` only creates a
   scroll container on a block box, so wide tables become their own block-level scroller (a
   `.table-scroll` wrapper does the same for anything that needs it). */
pre, .pre-wrap { max-width: 100%; overflow-x: auto; }
table { display: block; max-width: 100%; overflow-x: auto; }
.table-scroll { max-width: 100%; overflow-x: auto; }

/* Skip link: first thing in the tab order, hidden until focused, so keyboard and screen-reader
   users jump straight past the header to the content on every page. */
/* Parked off-screen by CLIPPING, not by a negative offset.
 *
 * `left: -9999px` hides an element in a left-to-right page and breaks a right-to-left one: the
 * scroll origin flips, so the same offset puts the link 9999px into the scrollable area instead
 * of outside it. Measured after Arabic was switched on — every signed-in page gained 9999px of
 * horizontal scroll, from a link nobody could see.
 *
 * The clip technique has no direction to get wrong, and unlike `display: none` or
 * `visibility: hidden` it leaves the link focusable, which is the entire point of a skip link. */
.skip-link {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
  background: var(--accent); color: var(--accent-contrast);
  font-weight: 600; text-decoration: none;
}
.skip-link:focus {
  width: auto; height: auto; overflow: visible; clip-path: none;
  inset-block-start: 0; inset-inline-start: 0; z-index: 100;
  padding: .5em .9em; border-end-end-radius: 8px;
}
main:focus { outline: none; }

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ── bulk runs ────────────────────────────────────────────────────────────── */
/* A run of a thousand takes hours. The bar exists so "working" never looks like
   "stuck" — the single most common reason somebody kills a job that was fine. */
.progress {
  height: 6px; background: var(--border); border-radius: 999px; overflow: hidden;
  margin-top: .45rem; max-width: 320px;
}
.progress > span {
  display: block; height: 100%; background: var(--accent); border-radius: 999px;
  transition: width .4s ease;
}
.check { display: flex; gap: .6rem; align-items: flex-start; margin: var(--space-2) 0; }
.check input { margin-top: .25rem; flex: none; }
.check span { font-size: .9rem; color: var(--text-muted); }
.check b { color: var(--text); }
.field { display: flex; flex-direction: column; gap: .3rem; margin-bottom: var(--space-2); }
.field > span { font-size: .88rem; font-weight: 600; }
.field small { font-weight: 400; color: var(--text-muted); }
.field input[type="text"], .field select {
  font: inherit; padding: .6em .7em; border-radius: 10px;
  border: 1px solid var(--border); background: var(--bg); color: var(--text);
}
.count {
  font-size: .78rem; font-weight: 600; color: var(--brand-on-tint);
  background: var(--accent-soft); border-radius: 999px; padding: .1em .55em;
  vertical-align: middle;
}

/* ── page header ──────────────────────────────────────────────────────────────
 * `.hero` is an ORDINARY page header: an h1 and a line of explanation, on the
 * page's own background. Publish and Review use it that way, and so does every
 * screen that follows them.
 *
 * It used to be a full-bleed red gradient, because the landing page's marketing
 * masthead borrowed the same class name. That dragged a 220px band of saturated
 * red into the middle of two signed-in app screens, and took their explanatory
 * line down with it: `.lede` sets `color: var(--text-muted)`, and a rule that
 * MATCHES an element always beats a colour the element merely inherits — so the
 * hero's `color:#fff` lost to it and the sentence rendered warm grey on red at
 * 1.3:1, where AA asks for 4.5. It was, measurably, invisible.
 *
 * The two jobs are now two classes. This one stays quiet; `.masthead` below does
 * the shouting.
 */
.hero { margin: 0 0 var(--space-3); }
.hero h1 {
  font-size: clamp(1.5rem, 3.6vw, 2rem); line-height: 1.15; letter-spacing: -.02em;
  margin: 0 0 var(--space-1); font-weight: 800;
}
.hero .lede { max-width: 46rem; margin: 0; }

/* ── landing masthead ─────────────────────────────────────────────────────────
 * White canvas, red accent — the same relationship every other screen has, which
 * is the point. A full-bleed red fill made the landing page look like a different
 * product from the app behind it, and forced every word inside it to fight the
 * background: the vivid red is 4.34:1 against white, under the 4.5 body text
 * needs, so the small print was failing even before the grey lede did.
 *
 * Red still leads — it opens the page as a rule, carries the eyebrow, fills the
 * primary action and marks the phrases that matter. It just is not the canvas.
 */
.masthead {
  /* A pale brand band, not a brand FLOOD. It gives the page three levels of depth — tinted
     masthead, warm-white page, white panels — so the eye can tell where one thing ends and the
     next begins. An all-white page reads as unfinished for the same reason an all-red one reads
     as unreadable: nothing has a shape. */
  background: var(--accent-soft);
  border-top: 4px solid var(--brand-vivid);
  border-bottom: 1px solid var(--border);
  padding: var(--space-4) var(--space-3) var(--space-4);
}
.masthead-inner { max-width: 860px; margin: 0 auto; }
/* Red text on the tint takes the on-tint shade. Plain --brand measures 4.43 here and would put
   the page's first line back under the line it was just lifted over. */
.eyebrow {
  text-transform: uppercase; letter-spacing: .12em; font-size: .74rem; font-weight: 700;
  color: var(--brand-on-tint); margin: 0 0 var(--space-2);
}
.masthead h1 {
  font-size: clamp(1.9rem, 5.2vw, 3.1rem); line-height: 1.12; letter-spacing: -.03em;
  margin: 0 0 var(--space-2); font-weight: 800; text-wrap: balance; color: var(--text);
}
.masthead .lede {
  font-size: clamp(1rem, 2.1vw, 1.14rem); max-width: 46rem; margin: 0 0 var(--space-3);
  color: var(--text-muted);
}
/* The claims worth reading twice, in the brand colour — on the tint that means the on-tint
   shade, 5.05:1, so the emphasis is legible rather than merely decorative. */
.masthead .lede b { font-weight: 700; color: var(--brand-on-tint); }
.hero-cta { display: flex; gap: var(--space-2); flex-wrap: wrap; align-items: center; }
.hero-note { font-size: .85rem; color: var(--text-muted); margin: var(--space-3) 0 0; }

.btn-lg { font-size: 1.02rem; padding: .78em 1.5em; border-radius: 12px; }
.btn-ghost {
  display: inline-block; font: inherit; font-weight: 600; text-decoration: none;
  color: var(--brand-on-tint); border: 1.5px solid var(--brand); border-radius: 12px;
  padding: .7em 1.3em;
  transition: background .15s ease, border-color .15s ease;
}
.btn-ghost:hover { background: var(--accent-soft); }

.section-title {
  font-size: 1.35rem; letter-spacing: -.02em; margin: var(--space-4) 0 var(--space-2);
}

.lp-cols {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--space-2); margin-bottom: var(--space-4);
}
.use-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: var(--space-3); box-shadow: var(--shadow);
  border-top: 3px solid var(--brand-vivid);
}
.use-card h3 { font-size: 1.02rem; margin: .5rem 0 .4rem; letter-spacing: -.01em; }
.use-card p { font-size: .9rem; color: var(--text-muted); margin: 0; }
/* "What you need to start", per journey. A visitor who recognises themselves in a card
   immediately asks what it will cost them to try — answering it inside the card beats making
   them hunt through pricing for a prerequisite that might rule them out. */
.use-need {
  margin-top: .6rem !important; padding-top: .6rem;
  border-top: 1px dashed var(--border);
  font-size: .82rem !important; color: var(--text) !important;
}
.use-tag {
  display: inline-block; font-size: .68rem; font-weight: 800; letter-spacing: .1em;
  text-transform: uppercase; color: var(--brand-on-tint); background: var(--accent-soft);
  border-radius: 999px; padding: .25em .8em;
}

.feature-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: var(--space-3) var(--space-2); margin-top: var(--space-2);
}
.feature b { display: block; font-size: .96rem; margin-bottom: .25rem; }
.feature b::before {
  content: "—"; color: var(--brand); font-weight: 800; margin-inline-end: .4em;
}
.feature p { font-size: .88rem; color: var(--text-muted); margin: 0; }

.cta-band { text-align: center; border-top: 3px solid var(--brand-vivid); }
.cta-band h2 { font-size: 1.3rem; letter-spacing: -.02em; }
.cta-band .lede-sm { margin-bottom: var(--space-3); }

.foot {
  text-align: center; font-size: .84rem; color: var(--text-muted);
  padding: var(--space-4) var(--space-3); border-top: 1px solid var(--border);
}
.foot a { color: var(--text-muted); }
.foot a:hover { color: var(--brand); }

/* The feature band is a wider panel with no hover lift — it is a reference list, not a
   clickable card, and lifting it would promise an interaction that is not there. */
.feature-band { border-top: 3px solid var(--brand-vivid); }
.feature-band:hover { box-shadow: var(--shadow); }

/* ── the "More" menu ──────────────────────────────────────────────────────────
 * <details> rather than a scripted dropdown: it opens with the keyboard, works
 * with JavaScript disabled, and holds its own state. The only CSS worth noting
 * is that the panel is absolutely positioned, so opening it never reflows the
 * page underneath — a nav that pushes the content down as you browse it is
 * how people lose their place.
 */
.navmenu { position: relative; display: inline-block; }
.navmenu > summary {
  list-style: none; cursor: pointer; font-size: .9rem; font-weight: 600;
  color: var(--text-muted); padding: .3em .1em; border-bottom: 2px solid transparent;
}
.navmenu > summary::-webkit-details-marker { display: none; }
.navmenu > summary:hover { color: var(--text); border-bottom-color: var(--accent); }
.navmenu[open] > summary { color: var(--accent); }
.navmenu-panel {
  position: absolute; top: 100%; inset-inline-start: 0; z-index: 40; min-width: 210px;
  margin-top: .5rem; padding: .5rem; display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-lift);
}
.navmenu-panel a {
  padding: .45em .6em; border-radius: 8px; font-size: .9rem; font-weight: 500;
  color: var(--text); text-decoration: none; border-bottom: none;
}
.navmenu-panel a:hover { background: var(--accent-soft); color: var(--brand-on-tint); }
/* A menu that hangs from the END of the bar opens toward the middle, or it runs off-screen. */
.navmenu-panel-end { inset-inline-start: auto; inset-inline-end: 0; }
.navmenu-item { padding: .45em .6em; }

/* The bell — a status glanced at, not a tab. The badge rides its top corner the way every
   notification icon does, so the number reads at a glance even before the icon is recognised. */
.bell {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 10px; color: var(--text-muted);
  text-decoration: none;  /* the base link rule underlines; an underlined icon reads as a glitch */
}
.bell:hover { color: var(--text); background: var(--accent-soft); }
.bell.is-here { color: var(--brand-on-tint); background: var(--accent-soft); }
.bell .nav-badge {
  position: absolute; top: -2px; inset-inline-end: -2px;
}

/* The account trigger reads as a person, not another nav word. */
.account-menu > summary {
  display: inline-flex; align-items: center; gap: .4em;
  border: 1px solid var(--border); border-radius: 999px; padding: .3em .8em .3em .5em;
  background: var(--bg);
}
.account-menu > summary:hover { border-color: var(--accent); }
.account-name {
  max-width: 11em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: .85rem; font-weight: 600; color: var(--text);
}

.navmenu-group {
  font-size: .68rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: var(--text-muted); padding: .5em .6em .2em;
}
.navmenu-group:not(:first-child) {
  border-top: 1px solid var(--border); margin-top: .3rem;
}
/* On a phone the panel would run off the right edge, so it spans instead. */
@media (max-width: 640px) {
  .navmenu { position: static; }
  .navmenu-panel { left: var(--space-3); right: var(--space-3); min-width: 0; }

  /* The whole app scrolled sideways on a phone.

     Measured at 375px: the top bar wanted 584px and got 375, so every signed-in page overflowed
     by 209 pixels — you could swipe the entire interface off to one side. It was found while
     checking Arabic and is not an RTL fault at all; English measured identically. A six-item
     nav, a workspace switcher and a quota readout do not fit on one line at phone width, and
     nothing told them to stop trying.

     The nav takes its own row and scrolls within itself. A row that scrolls is a familiar
     pattern and keeps every destination reachable; pushing items into the overflow menu would
     have made the page fit by making half the product harder to find. */
  .topbar { flex-wrap: wrap; row-gap: var(--space-2); }
  .mainnav {
    order: 3;
    flex-basis: 100%;
    margin-inline-start: 0;
    overflow-x: auto;
    scrollbar-width: none;            /* the row is short; a bar under it is just noise */
    -webkit-overflow-scrolling: touch;
  }
  .mainnav::-webkit-scrollbar { display: none; }
  .mainnav a { white-space: nowrap; }

  /* A flex child refuses to shrink below its content unless told it may. Without this the nav
     pushes the bar wide again however the row is arranged. */
  .topbar > *, .topbar-right { min-width: 0; }
}

/* ── Help desk ────────────────────────────────────────────────────────────────────────── */
/* The answer block is visually separated from the question because people scan for it — a
   reply that looks like the rest of the page gets read twice before it is found. */
.answer {
  margin-top: var(--space-3); padding: var(--space-3);
  background: var(--accent-soft); border-radius: var(--radius);
  border: 1px solid var(--border);
}
.answer h3 { margin: 0 0 var(--space-2); font-size: 1rem; }
.answer p { margin: 0 0 .7rem; line-height: 1.65; }

/* One help article, collapsed. <details> so it works with no JavaScript and is keyboard
   operable for free. */
.help-item { border-bottom: 1px solid var(--border); padding: .7rem 0; }
.help-item:last-child { border-bottom: 0; }
.help-item > summary {
  cursor: pointer; font-weight: 600; padding: .3rem 0; list-style-position: inside;
}
.help-item > summary:hover { color: var(--brand-on-tint); }
.help-item p { margin: .5rem 0 0; color: var(--text-muted); line-height: 1.65; }

/* A turn in a conversation. The customer's own words are tinted so a thread can be read at
   a glance without reading the labels. */
.support-turn { align-items: flex-start; }
.support-turn p { margin: .4rem 0 0; line-height: 1.6; }
.support-customer { background: var(--bg); border-radius: var(--radius); }
.support-operator { border-inline-start: 3px solid var(--accent); padding-inline-start: .8rem; }

/* A plain vertical form: label, field, label, field. Used by the help desk. */
.stack { display: flex; flex-direction: column; gap: var(--space-2); }



/* The three-step explainer on the dashboard. Numbered, spaced, and readable at a glance —
   somebody who has to read a paragraph to learn what a product does has already left. */
.how-it-works .steps {
  margin: var(--space-2) 0 0; padding: 0; list-style: none; counter-reset: step;
  display: grid; gap: var(--space-2);
}
.how-it-works .steps li {
  counter-increment: step; position: relative; padding-inline-start: 2.4rem;
  line-height: 1.6; color: var(--text-muted);
}
.how-it-works .steps li b { color: var(--text); }
.how-it-works .steps li::before {
  content: counter(step); position: absolute; inset-inline-start: 0; top: .05rem;
  width: 1.6rem; height: 1.6rem; border-radius: 50%;
  background: var(--accent); color: #fff; font-weight: 700; font-size: .85rem;
  display: grid; place-items: center;
}
@media (min-width: 720px) {
  .how-it-works .steps { grid-template-columns: repeat(3, 1fr); gap: var(--space-3); }
}

/* ── The one footer ───────────────────────────────────────────────────────────────────── */
/* Grouped, not a single line of twelve links: a wall of links is a wall nobody reads, and
   the footer is exactly where somebody looks when the top of the page did not answer them. */
.foot-nav {
  display: grid; gap: var(--space-3); text-align: start;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  max-width: 60rem; margin: 0 auto var(--space-3);
}
.foot-group { display: flex; flex-direction: column; gap: .4rem; }
.foot-group b {
  color: var(--text); font-size: .8rem; text-transform: uppercase; letter-spacing: .06em;
  margin-bottom: .2rem;
}
.foot-group a { color: var(--text-muted); font-size: .9rem; }
.foot-group a:hover { color: var(--brand-on-tint); }
.foot-line { max-width: 44rem; margin: 0 auto; font-size: .85rem; }

/* The manual: a numbered contents list, then one entry per article. */
.doc-toc { margin: var(--space-2) 0 0; padding-inline-start: 1.3rem; line-height: 1.9; }
.doc-toc li { color: var(--text-muted); }
.doc-entry { padding: var(--space-2) 0; border-bottom: 1px solid var(--border); }
.doc-entry:last-child { border-bottom: 0; }
.doc-entry h3 { margin: 0 0 .4rem; font-size: 1.02rem; }
.doc-entry p { margin: 0 0 .6rem; color: var(--text-muted); line-height: 1.65; }

/* The taller step list used by How it works — same numbering, more room per step. */
.steps-tall li { padding-block: .3rem; }
@media (min-width: 720px) {
  .how-it-works .steps-tall { grid-template-columns: 1fr; gap: var(--space-2); }
}

/* The one sentence that says what the product IS, directly under the headline. Bigger than
   body text because a stranger reads exactly one thing before deciding to keep reading. */
.what-it-is {
  /* Space on BOTH sides. With a top margin only, this paragraph butted straight into the lede
     below it and the two read as one run-on block — visible the moment the text became legible
     enough to notice. Every other block in the masthead closes with space; so does this one. */
  font-size: 1.06rem; line-height: 1.6; margin: var(--space-3) 0 var(--space-2);
  max-width: 44rem; color: var(--text);
}
/* ⭐ This used to force white — correct while the masthead was a full-bleed red gradient, and
   invisible the moment the masthead became a pale tint. Measured on the rendered page at
   1.09:1 against #fff1f2, where body text needs 4.5. The lede was rescued from exactly this
   when the background changed; this line was missed and kept shipping.
   The base `.what-it-is` colour (--text) is already right on the tint, so the override is gone
   rather than re-tinted: an element whose own class states a readable colour does not need a
   second opinion from its container. */
.masthead .what-it-is b { color: var(--brand-on-tint); }

/* The signed-out header's plain links, beside the Start free button. */
.foot-cta { color: var(--text-muted); font-size: .92rem; white-space: nowrap; }
.foot-cta:hover { color: var(--brand-on-tint); }

/* ── review at scale ──────────────────────────────────────────────────────────
 * A product sold as "1,000 articles a month" showed the review queue as one
 * unfiltered list with a per-draft form. These three strips — filter, bulk bar,
 * pager — are what make the hundredth draft reachable and the fiftieth decision
 * one press instead of fifty. */
.filter-bar {
  display: flex; gap: var(--space-1); flex-wrap: wrap; align-items: flex-end;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: var(--space-2); margin-bottom: var(--space-2);
}
.filter-bar .btn, .filter-bar .btn-link { margin-bottom: .1rem; }

.bulk-bar {
  display: flex; gap: var(--space-1); flex-wrap: wrap; align-items: center;
  background: var(--accent-soft); border: 1px solid var(--border);
  border-radius: var(--radius); padding: var(--space-2); margin-bottom: var(--space-2);
}
/* The "everything matching" strip carries a sentence of explanation, so it wraps to its own
   line rather than squeezing the button. */
.bulk-wide { display: block; }
.bulk-wide .row-meta { display: block; margin-top: .5rem; max-width: 52rem; }
.bulk-all { display: flex; align-items: center; gap: .45rem; font-size: .9rem; }
.bulk-all input { width: 1rem; height: 1rem; }

/* The per-draft checkbox sits before the title, aligned with it rather than with the block. */
.draft-head > input[type="checkbox"] { width: 1rem; height: 1rem; margin-top: .3rem; }
.draft-head { align-items: flex-start; justify-content: flex-start; }
.draft-head > div { flex: 1 1 auto; }

.pager {
  display: flex; gap: var(--space-2); align-items: center; justify-content: center;
  margin: var(--space-3) 0;
}

/* ── charts ───────────────────────────────────────────────────────────────────
 * Server-drawn SVG, so there is no library to load and nothing for the CSP to
 * block. Colours come from the tokens above rather than being baked into the
 * markup, which is what lets the same chart work in dark mode. */
.chart { width: 100%; height: auto; display: block; margin: var(--space-1) 0 var(--space-2); }
.chart-axis { font-size: 11px; fill: var(--text-muted); font-family: var(--font); }
.chart-label { font-size: 13px; fill: var(--text); font-family: var(--font); font-weight: 600; }
.chart-value {
  font-size: 13px; fill: var(--text); font-family: var(--font); font-weight: 700;
}
.chart-donut { width: 190px; height: 190px; display: block; margin: 0 auto; }
.chart-centre {
  font-size: 34px; font-weight: 700; fill: var(--text); font-family: var(--font);
  letter-spacing: -.02em;
}

/* Picture on one side, the same numbers in words on the other — never one without the
   other, so nothing on this screen is carried by colour or by sight alone. */
.chart-split {
  display: grid; grid-template-columns: 1fr; gap: var(--space-2); align-items: center;
}
@media (min-width: 720px) {
  .chart-split { grid-template-columns: 240px 1fr; gap: var(--space-3); }
}
.chart-legend { margin: 0; }
.chart-legend .stat-l .dot { width: 9px; height: 9px; margin: 0 .2rem 0 0; display: inline-block; }
.dot-warn { background: var(--warn); box-shadow: 0 0 0 4px color-mix(in srgb, var(--warn) 20%, transparent); }
.gate-dot.bad { background: var(--bad); }
.gate-dot.ok { background: var(--ok); }

/* ── link-building marketplace ─────────────────────────────────────────────────
 * Trust before flair: a strip of guarantees under the headline, a timeline that
 * is the SAME six stages on the buyer's order and the publisher's worklist, and
 * status badges for the order lifecycle the generic set did not cover. */
.badge-accepted, .badge-content_review, .badge-published {
  display: inline-block; padding: .05em .5em; border-radius: 999px;
  font-size: .78rem; font-weight: 600; border: 1px solid currentColor; color: var(--accent);
}
.badge-verified, .badge-completed {
  display: inline-block; padding: .05em .5em; border-radius: 999px;
  font-size: .78rem; font-weight: 600; border: 1px solid currentColor; color: var(--ok);
}

.trust-strip {
  display: flex; flex-wrap: wrap; gap: var(--space-2); margin: 0 0 var(--space-3);
  padding: var(--space-2); background: var(--accent-soft); border-radius: var(--radius);
  font-size: .88rem; font-weight: 600; color: var(--brand-on-tint);
}
.trust-strip span { white-space: nowrap; }

.price-list { list-style: none; margin: .4rem 0 var(--space-2); padding: 0; font-size: .9rem; }
.price-list li { padding: .15rem 0; color: var(--text-muted); }
.price-list b { color: var(--text); }

/* The order timeline: six stages, the reached ones filled, the current one ringed. */
.order-timeline {
  display: flex; flex-wrap: wrap; gap: .3rem; list-style: none; margin: var(--space-2) 0;
  padding: 0; counter-reset: stage;
}
.order-timeline li {
  flex: 1 1 auto; text-align: center; font-size: .72rem; color: var(--text-muted);
  padding: .3rem .2rem; border-radius: 6px; border: 1px solid var(--border); position: relative;
}
.order-timeline li.done { background: var(--accent-soft); color: var(--brand-on-tint);
  border-color: transparent; }
.order-timeline li.now { background: var(--accent); color: #fff; border-color: transparent;
  font-weight: 700; }

/* Visible only to a screen reader. The (i) and the mode picker both carry labels that
   would be noise on screen and are the only description a non-sighted reader gets. */
.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;
}

/* ── the workflow panel: the three role-based dashboards ───────────────────────────────────── */
.workflow .panel-head { flex-wrap: wrap; gap: .5rem; }
.workflow-steps { list-style: none; margin: .75rem 0 0; padding: 0; }
.workflow-steps li {
  padding: .6rem 0; border-top: 1px solid var(--line);
  display: grid; grid-template-columns: 1fr auto; gap: .25rem .5rem; align-items: baseline;
}
.workflow-steps li:first-child { border-top: 0; }
.step-go { font-weight: 600; }
.step-tip { grid-column: 1 / -1; margin: 0; font-size: .9rem; color: var(--muted); }
/* The (i). A <details> rather than a title= tooltip: a tooltip is unreachable on a phone and
   invisible to a screen reader, and this text is the explanation a beginner needs most. */
.step-what { justify-self: end; }
.step-what > summary {
  list-style: none; cursor: pointer; width: 1.35rem; height: 1.35rem; border-radius: 50%;
  border: 1px solid var(--line); display: grid; place-items: center;
  font: 600 .8rem/1 serif; color: var(--muted);
}
.step-what > summary::-webkit-details-marker { display: none; }
.step-what > summary:hover, .step-what > summary:focus-visible { color: var(--ink); border-color: var(--ink); }
.step-what[open] > p {
  grid-column: 1 / -1; margin: .4rem 0 0; font-size: .9rem; color: var(--ink);
  background: var(--surface-2); padding: .5rem .6rem; border-radius: .4rem; max-width: 46ch;
}
.mode-switch { display: flex; gap: .4rem; align-items: center; }
@media (max-width: 640px) { .mode-switch { width: 100%; } .mode-switch select { flex: 1; } }
.nav-showall { display: inline; }
.linkish {
  background: none; border: 0; padding: 0; font: inherit; color: var(--muted);
  cursor: pointer; text-decoration: underline dotted;
}
.linkish:hover, .linkish:focus-visible { color: var(--ink); }

/* ── the run log inside a job card ─────────────────────────────────────────────────────────── */
.job-log {
  list-style: none; margin: .6rem 0 0; padding: .5rem .6rem; max-height: 12rem; overflow-y: auto;
  background: var(--surface-2); border-radius: .4rem;
  font: .82rem/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
  /* A long unbroken error string must wrap, not push the card sideways. */
  overflow-wrap: anywhere;
}
.job-log li { padding: .1rem 0; color: var(--muted); }
.job-log .log-warn { color: var(--warn); }
.job-log .log-error { color: var(--bad); font-weight: 600; }
.fault-detail > summary { cursor: pointer; color: var(--muted); font-size: .85rem; }
.fault-detail pre {
  margin: .3rem 0 0; padding: .4rem .5rem; background: var(--surface-2); border-radius: .3rem;
  font-size: .8rem; white-space: pre-wrap; overflow-wrap: anywhere; max-height: 10rem;
  overflow-y: auto;
}
.inline-form { display: flex; gap: .3rem; align-items: center; }
.fault-table { width: 100%; border-collapse: collapse; font-size: .92rem; }
.fault-table th, .fault-table td {
  text-align: left; padding: .5rem .6rem; border-bottom: 1px solid var(--line);
  vertical-align: top;
}
.fault-table th { font-weight: 600; color: var(--muted); font-size: .85rem; }

/* ── the marketplace boards: what you're selling, what you're buying ───────────────────────── */
.board { list-style: none; margin: .5rem 0 0; padding: 0; }
.board li {
  padding: .55rem 0; border-top: 1px solid var(--line);
  display: flex; flex-wrap: wrap; gap: .25rem .6rem; align-items: baseline;
}
.board li:first-child { border-top: 0; }
.board li > a { font-weight: 600; }
/* Waiting on you. A left edge rather than a background: it survives dark mode without a second
   colour, and it reads down the list as a column of things to answer. */
.board-hot { border-left: 3px solid var(--warn); padding-left: .5rem; margin-left: -.5rem; }
.board-need { color: var(--warn); font-size: .88rem; font-weight: 600; }

/* ── case studies ──────────────────────────────────────────────────────────────────────────── */
/* Generous spacing between stories: they are read, not scanned, and three of them running
   together looks like one long complaint. */
.case-study h3 {
  margin: 1rem 0 .25rem; font-size: .95rem; color: var(--muted); font-weight: 600;
}
.case-study p { max-width: 68ch; }
.notice-bad {
  padding: .6rem .8rem; border-radius: .4rem; border-left: 3px solid var(--bad);
  background: var(--surface-2);
}
/* The unfinished parts, named. Warning-coloured rather than error-coloured: nothing has gone
   wrong, there is just more to write. */
.problems { margin: .5rem 0; padding-left: 1.1rem; color: var(--warn); font-size: .92rem; }
.field-check { display: flex; gap: .5rem; align-items: flex-start; margin: .75rem 0; }
.field-check input { margin-top: .2rem; }

/* ── knowledge base ────────────────────────────────────────────────────────────────────────── */
.kb-search { display: flex; gap: .5rem; margin-top: .75rem; max-width: 32rem; }
.kb-search input { flex: 1; }
.kb-hits { margin: .5rem 0 0; padding-left: 1.1rem; }
.kb-item { border-top: 1px solid var(--line); padding: .5rem 0; }
.kb-item:first-of-type { border-top: 0; }
.kb-item > summary { cursor: pointer; font-weight: 600; }
/* An anchored article opens itself — a link from support must land ON the answer, not above
   a collapsed row the reader then has to find and click. */
.kb-item:target { background: var(--surface-2); border-radius: .4rem; padding: .5rem .6rem; }
.kb-body { margin-top: .4rem; max-width: 68ch; }
.kb-body p { margin: .5rem 0; }

/* ── language picker and the switch offer ──────────────────────────────────────────────────── */
.lang-picker { display: flex; gap: .4rem; align-items: center; font-size: .85rem; }
.lang-picker a, .lang-here { padding: .1rem .35rem; border-radius: .25rem; }
.lang-here { background: var(--surface-2); font-weight: 600; }
.lang-offer {
  display: flex; flex-wrap: wrap; gap: .5rem; align-items: center;
  padding: .6rem .8rem; margin: .5rem 0; border-radius: .4rem;
  background: var(--surface-2); border-left: 3px solid var(--brand, var(--ink));
  font-size: .92rem;
}

/* ── the blog ────────────────────────────────────────────────────────────────────────────────
   Three classes, because a reading surface needs exactly three things the app screens do not:
   a comfortable measure, breathing room between paragraphs, and headings that separate rather
   than shout. Everything else reuses the house classes. */
.post-list { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--space-2); }
.post-list li { display: grid; gap: .15rem; }
.post { max-width: 42rem; margin: 0 auto; }
.post-body { line-height: 1.7; }
.post-body p { margin: 0 0 var(--space-3); }
.post-body h2 { margin: var(--space-4) 0 var(--space-2); font-size: 1.25rem; }
.post-body h3 { margin: var(--space-3) 0 var(--space-2); font-size: 1.08rem; }
.post-body ul { margin: 0 0 var(--space-3) 1.1rem; }
.post-body li { margin-bottom: .35rem; }
.notice {
  background: var(--accent-soft); border-radius: var(--radius);
  padding: var(--space-2) var(--space-3); margin: 0 0 var(--space-3); font-size: .9rem;
}

/* The advisor: a numbered list where each item is a decision, and the AI's written plan.
   Both live here rather than inline because this page uses the app shell. */
.advice-list { counter-reset: advice; }
.advice-list > li {
  counter-increment: advice;
  border-left: 3px solid var(--line);
  padding-left: 1rem;
  margin-bottom: 1.4rem;
}
.advice-list > li:first-child { border-left-color: var(--accent); }
.advice-list h3 { margin: 0 0 .2rem; font-size: 1.05rem; }
.advice-list p { margin: .25rem 0; }

/* The written plan. Quoted, so it reads as something produced rather than as product copy —
   a reader should always be able to tell which sentences we stand behind. */
.ai-note {
  margin: .75rem 0;
  padding: .9rem 1.1rem;
  border-left: 3px solid var(--line);
  background: var(--surface-2, transparent);
  white-space: pre-wrap;
}
