/* Copyright 2026 Limelit. Licensed under the Apache License, Version 2.0.
   See the LICENSE file in the repository root for the full terms. */

/* Limelit Open. Tokens mirror the Limelit design system so the open core and
 * the hosted product look like one product. Every themed token is declared in
 * both places below: a token defined only in light renders as invisible text
 * in dark, which is worse than an unstyled page because it looks fine until
 * someone switches. */

:root {
  color-scheme: light;

  --brand: #5a5af0;
  --brand-strong: #3c3cc9;
  --brand-hover: #4a4ad9;
  --brand-soft: #eeeefb;
  --brand-deep: #1a1a46;

  --ink: #14141c;
  --ink-2: #43474f;
  --ink-3: #6b7280;
  --ink-4: #9ca3af;
  --on-ink: #ffffff;

  --bg: #ffffff;
  --bg-app: #f4f4f7;
  --bg-2: #f7f7f9;
  --surface: #ffffff;

  --rule: #e6e8ec;
  --rule-2: #d3d6dd;

  --pos-bg: #e9f9f0;
  --pos-fg: #0b7a43;
  --neg-bg: #fbe3d8;
  --neg-fg: #c2410c;
  --warn-bg: #fef3e2;
  --warn-fg: #b45309;
  --info-bg: #e6e8f8;
  --info-fg: #3c3cc9;

  /* The grid's heat ramp. One hue, six steps, intensity only.
   * Not red-to-green: that ramp asserts "bad" and "good", and 20% visibility
   * is excellent in one category and dire in another. It is also the ramp
   * that fails hardest for red-green colour blindness, which is about 8% of
   * men. Intensity says "more" without saying "good". */
  --cell-empty: transparent;
  --cell-0: #f1f2f6;
  --cell-1: #dfe0fa;
  --cell-2: #c3c5f6;
  --cell-3: #9c9ff0;
  /* #6e72e6 sat at relative luminance 0.2106, inside the band where neither
   * black nor white ink clears 4.5:1. This value lifts it clear and spaces
   * the top of the ramp more evenly. */
  --cell-4: #787ceb;
  --cell-5: #4a4ad9;

  /* Ink is paired with its step rather than chosen in Go, because the
   * readable colour flips at a different step in each theme and in the
   * opposite direction. */
  --cell-0-ink: var(--ink);
  --cell-1-ink: var(--ink);
  --cell-2-ink: var(--ink);
  --cell-3-ink: var(--ink);
  --cell-4-ink: var(--ink);
  --cell-5-ink: #ffffff;

  /* A measured zero is the finding on a new install, and the zero fill is
   * nearly invisible against the card, so it gets an edge. */
  --cell-ring: #d3d6dd;

  --mark-own: #fde68a;
  --mark-rival: #e9eaf2;

  /* Series colours for competitor charts. Eight hues chosen so the first four
   * stay furthest apart under protanopia and deuteranopia, tuned a step
   * quieter than the badges so the property's line is the loudest thing on
   * the page. They are assigned ALPHABETICALLY among the brands a chart
   * draws, never by rank, so within one page a brand is one colour on every
   * chart. Only the top six rivals get a hue; everyone else is drawn in
   * --chart-field, so a brand crossing that boundary changes from a hue to
   * grey and nothing else. The property never takes one of these. */
  --series-1: #c98a2e;
  --series-2: #2e9a8c;
  --series-3: #c0466f;
  --series-4: #7c5cc4;
  --series-5: #4a9a4e;
  --series-6: #2f86c2;
  --series-7: #8f7468;
  --series-8: #d9633b;

  /* Chart furniture. The property's line, the hairline grid, the baseline,
   * the field grey for unranked brands, the hover cursor, the shaded span
   * nobody measured, and the area under the property's line. */
  --chart-own: #5a5af0;
  --chart-grid: #eef0f4;
  --chart-base: #d3d6dd;
  --chart-field: #c2c6cf;
  --chart-cursor: #14141c;
  --plot-gap: #f6f6f9;
  --area-top: rgb(90 90 240 / 24%);
  --area-bottom: rgb(90 90 240 / 0%);
  --own-glow: transparent;
  --tip-bg: #ffffff;
  --tip-border: #e6e8ec;
  --tip-shadow: 0 6px 24px rgb(20 20 28 / 10%), 0 1px 3px rgb(20 20 28 / 6%);

  /* Citation source classes carry fixed colours on every surface, so a
   * social source is the same colour in the mix chart and on a badge. The
   * one exception is "other", which the mix chart draws in --chart-field so
   * its large grey block stays quiet behind the classes that mean
   * something. */
  --src-own: var(--brand);
  --src-competitor: #c2185b;
  --src-social: #e0851f;
  --src-informational: #2a9d8f;
  --src-other: #9ca3af;

  --radius: 10px;
  --radius-sm: 6px;
  --shadow: 0 1px 2px rgb(20 20 28 / 6%), 0 1px 3px rgb(20 20 28 / 4%);
  --sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Inter, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
}

/* Dark follows the system setting. Nothing writes data-theme="dark" yet;
 * when a stored preference does, this block needs a twin under
 * :root[data-theme="dark"] with the same tokens, or the toggle will flip the
 * chrome and leave the charts on the light palette. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --brand-strong: #a3a3ff;
    --brand-soft: #232340;

    --cell-empty: transparent;
    --cell-0: #1c1d26;
    --cell-1: #23244a;
    --cell-2: #2f3170;
    --cell-3: #3f42a0;
    --cell-4: #5457cc;
    --cell-5: #7d80ef;

    --cell-0-ink: var(--ink);
    --cell-1-ink: var(--ink);
    --cell-2-ink: var(--ink);
    --cell-3-ink: var(--ink);
    --cell-4-ink: var(--ink);
    /* The flip goes the other way here: the brightest step needs dark ink. */
    --cell-5-ink: var(--on-ink);

    --cell-ring: #3f404d;

    --mark-own: #6b5a12;
    --mark-rival: #2a2c38;

    --series-1: #e0a054;
    --series-2: #56bfb0;
    --series-3: #e07298;
    --series-4: #ab98e8;
    --series-5: #7ec081;
    --series-6: #62b4e8;
    --series-7: #bfa89e;
    --series-8: #ef8a66;

    --chart-own: #9d9dff;
    --chart-grid: #1f1f28;
    --chart-base: #35353f;
    --chart-field: #4a4e5a;
    --chart-cursor: #f2f2f5;
    --plot-gap: #131319;
    --area-top: rgb(157 157 255 / 32%);
    --area-bottom: rgb(157 157 255 / 0%);
    --own-glow: rgb(157 157 255 / 38%);
    --tip-bg: #1f1f27;
    --tip-border: #35353f;
    --tip-shadow: 0 6px 24px rgb(0 0 0 / 50%), 0 1px 3px rgb(0 0 0 / 40%);

    --src-own: var(--brand-strong);
    --src-competitor: #f06292;
    --src-social: #f0a04b;
    --src-informational: #4fc3b0;
    --src-other: #6b7280;

    --ink: #f2f2f5;
    --ink-2: #c3c6cd;
    --ink-3: #9096a1;
    --ink-4: #7d8492;
    --on-ink: #0b0b0f;

    --bg: #0e0e12;
    --bg-app: #0b0b0f;
    --bg-2: #1f1f27;
    --surface: #17171d;

    --rule: #26262e;
    --rule-2: #35353f;

    --pos-bg: #0d2f1e;
    --pos-fg: #4ade80;
    --neg-bg: #3a1a10;
    --neg-fg: #fb923c;
    --warn-bg: #3a2a0c;
    --warn-fg: #fbbf24;
    --info-bg: #1e2040;
    --info-fg: #a3a3ff;

    --shadow: 0 1px 2px rgb(0 0 0 / 40%), 0 1px 3px rgb(0 0 0 / 30%);
  }
}

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

body {
  margin: 0;
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink-2);
  background: var(--bg-app);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { color: var(--ink); font-weight: 600; margin: 0; letter-spacing: -0.01em; }
h1 { font-size: 22px; }
h2 { font-size: 16px; }
h3 { font-size: 14px; }
p { margin: 0 0 12px; }
a { color: var(--brand-strong); text-decoration: none; }
a:hover { text-decoration: underline; }
code, .mono { font-family: var(--mono); font-size: 12.5px; }

/* Layout ------------------------------------------------------------------ */

.shell { display: grid; grid-template-columns: 232px 1fr; min-height: 100vh; }

.sidebar {
  background: var(--surface);
  border-right: 1px solid var(--rule);
  padding: 16px 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.brandmark { display: flex; align-items: center; gap: 9px; padding: 6px 8px 14px; }
/* The mark is the same file Limelit Cloud serves, so the open core and the
   hosted product are recognisably one product. It carries its own gradient
   rather than the theme tokens, which is why it does not invert in dark. */
.brandmark .tile { width: 26px; height: 26px; flex: none; display: block; }
.brandmark .name { color: var(--ink); font-weight: 600; font-size: 14px; }
.brandmark .sub { color: var(--ink-4); font-size: 11px; }

.navlink {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 7px 10px; border-radius: var(--radius-sm);
  color: var(--ink-2); font-size: 13.5px;
}
.navlink:hover { background: var(--bg-2); text-decoration: none; color: var(--ink); }
.navlink[aria-current="page"] { background: var(--brand-soft); color: var(--brand-strong); font-weight: 600; }
.navlink .count { color: var(--ink-4); font-size: 11.5px; font-variant-numeric: tabular-nums; }
.navsection { color: var(--ink-4); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; padding: 14px 10px 6px; }

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

.topbar {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 12px 24px; border-bottom: 1px solid var(--rule);
  background: var(--surface); position: sticky; top: 0; z-index: 5;
}
.topbar .who { display: flex; align-items: baseline; gap: 10px; min-width: 0; }
.topbar .who strong { color: var(--ink); font-size: 14px; }
.topbar .who span { color: var(--ink-4); font-size: 12.5px; }

.content { padding: 24px; max-width: 1180px; width: 100%; }
.page-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 4px; }
.lede { color: var(--ink-3); margin: 4px 0 20px; max-width: 62ch; }

/* Components -------------------------------------------------------------- */

.card {
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 18px 20px;
}
.card + .card { margin-top: 16px; }
.card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 12px; }

.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px; }
.grid-4 { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 16px; }

.stat .label { color: var(--ink-3); font-size: 12.5px; }
.stat .value { color: var(--ink); font-size: 28px; font-weight: 600; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; line-height: 1.2; margin-top: 2px; }
.stat .sub { color: var(--ink-4); font-size: 11.5px; margin-top: 2px; }

.btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 13px; border-radius: var(--radius-sm); border: 1px solid var(--rule-2);
  background: var(--surface); color: var(--ink); font: inherit; font-size: 13.5px; font-weight: 500;
  cursor: pointer;
}
.btn:hover { background: var(--bg-2); text-decoration: none; }
.btn-primary { background: var(--brand); border-color: var(--brand); color: #fff; }
.btn-primary:hover { background: var(--brand-hover); border-color: var(--brand-hover); color: #fff; }
.btn-ghost { border-color: transparent; background: transparent; color: var(--ink-3); }
.btn-ghost:hover { background: var(--bg-2); color: var(--ink); }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }
.btn-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

.badge {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 1px 7px; border-radius: 999px; font-size: 11px; font-weight: 600;
  background: var(--bg-2); color: var(--ink-3); border: 1px solid var(--rule);
  white-space: nowrap;
}
.badge-branded { background: var(--bg-2); color: var(--ink-3); }
.badge-own { background: var(--pos-bg); color: var(--pos-fg); border-color: transparent; }
.badge-competitor { background: var(--neg-bg); color: var(--neg-fg); border-color: transparent; }

table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
th { text-align: left; color: var(--ink-3); font-weight: 500; font-size: 12px; padding: 0 10px 8px; border-bottom: 1px solid var(--rule); }
td { padding: 9px 10px; border-bottom: 1px solid var(--rule); color: var(--ink-2); }
tr:last-child td { border-bottom: none; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
.table-wrap { overflow-x: auto; }

label { display: block; color: var(--ink); font-size: 13px; font-weight: 500; margin-bottom: 5px; }
.hint { color: var(--ink-4); font-size: 12px; font-weight: 400; margin-top: 4px; }
input[type="text"], input[type="password"], input[type="number"], select, textarea {
  width: 100%; padding: 8px 10px; font: inherit; font-size: 13.5px;
  color: var(--ink); background: var(--surface);
  border: 1px solid var(--rule-2); border-radius: var(--radius-sm);
}
input:focus, select:focus, textarea:focus { outline: 2px solid var(--brand); outline-offset: -1px; border-color: var(--brand); }
.field + .field { margin-top: 16px; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
fieldset { border: none; margin: 0; padding: 0; }

.notice { padding: 11px 14px; border-radius: var(--radius-sm); font-size: 13px; margin-bottom: 16px; }
.notice-info { background: var(--info-bg); color: var(--info-fg); }
.notice-warn { background: var(--warn-bg); color: var(--warn-fg); }
.notice-error { background: var(--neg-bg); color: var(--neg-fg); }
.notice-ok { background: var(--pos-bg); color: var(--pos-fg); }

.empty { text-align: center; padding: 44px 20px; }
.empty h2 { margin-bottom: 6px; }
.empty p { color: var(--ink-3); max-width: 46ch; margin: 0 auto 16px; }

/* Wizard ------------------------------------------------------------------ */

.wizard { min-height: 100vh; display: grid; place-items: start center; padding: 48px 20px 64px; }
.wizard-inner { width: 100%; max-width: 620px; }
.steps { display: flex; gap: 6px; margin: 20px 0 24px; }
.step { flex: 1; height: 3px; border-radius: 2px; background: var(--rule); }
.step.done { background: var(--brand-strong); }
.step.now { background: var(--brand); }
.step-label { color: var(--ink-4); font-size: 12px; margin-bottom: 6px; }

.prompt-row { display: flex; gap: 10px; align-items: flex-start; padding: 9px 0; border-bottom: 1px solid var(--rule); }
.prompt-row:last-child { border-bottom: none; }
.prompt-row input[type="checkbox"] { margin-top: 4px; flex: none; }
.prompt-row .text { flex: 1; min-width: 0; color: var(--ink); }
.prompt-row .meta { display: flex; gap: 6px; align-items: center; flex: none; }

.footnote { color: var(--ink-4); font-size: 12px; margin-top: 18px; }

/* Narrow screens ----------------------------------------------------------
 * A GTM user opens this on a laptop, but a 232px fixed sidebar squeezes the
 * content column to nothing on a phone and the top bar's two halves overlap.
 * Below 860px the sidebar becomes a scrollable strip across the top.
 * Verified in a browser at 375px: a template test cannot see this. */

@media (max-width: 860px) {
  .shell { grid-template-columns: 1fr; }

  .sidebar {
    flex-direction: row;
    align-items: center;
    gap: 2px;
    overflow-x: auto;
    border-right: none;
    border-bottom: 1px solid var(--rule);
    padding: 8px 12px;
    position: sticky;
    top: 0;
    z-index: 6;
  }
  .sidebar .brandmark { padding: 0 12px 0 0; flex: none; }
  .sidebar .brandmark .sub { display: none; }
  .navsection { display: none; }
  .navlink { flex: none; white-space: nowrap; padding: 6px 10px; }

  .topbar { flex-wrap: wrap; gap: 8px; padding: 10px 16px; position: static; }
  .topbar .who { flex: 1 1 auto; }

  .content { padding: 16px; }
  .field-row { grid-template-columns: 1fr; }
  .wizard { padding: 24px 14px 48px; }

  /* A prompt row is a checkbox, the text, and its badges. Side by side that
   * leaves about ten characters for the text, so the badges wrap under it. */
  .prompt-row { flex-wrap: wrap; }
  .prompt-row .text { flex: 1 1 100%; order: 2; }
  .prompt-row .meta { order: 3; }

  /* A card header is a title and an add form. Side by side on a phone the
   * form's inputs collapse to a few characters each. */
  .card-head { flex-direction: column; align-items: stretch; gap: 10px; }
  .card-head form input[type="text"] { width: 100% !important; }

  /* Tables scroll inside their wrapper rather than squeezing a prompt down
   * to one word per line. */
  table { min-width: 540px; }
}

/* Settings: click-select ---------------------------------------------------
 * A raw "engine:provider[:model][:online]" text box asks a user to learn a
 * grammar before they can track anything. The engine list below is the same
 * thing as buttons, with the string kept behind an Advanced disclosure for
 * whoever wants to pin a model. */

.engine-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 12px; }

.engine {
  border: 1px solid var(--rule); border-radius: var(--radius);
  padding: 13px 14px; background: var(--bg-2);
}
.engine-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.engine-head h3 { font-size: 13.5px; }

.chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--surface); border: 1px solid var(--rule-2);
  border-radius: 999px; padding: 3px 6px 3px 8px; font-size: 12px;
}
.chip code { font-size: 11.5px; color: var(--ink-2); }
.chip form { display: inline-flex; }
.chip-x {
  border: none; background: none; cursor: pointer; padding: 0 4px;
  color: var(--ink-4); font-size: 15px; line-height: 1;
}
.chip-x:hover { color: var(--neg-fg); }

.targets { display: flex; flex-direction: column; gap: 6px; margin-bottom: 10px; }
.target {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: var(--surface); border: 1px solid var(--rule-2);
  border-radius: var(--radius-sm); padding: 6px 6px 6px 10px; font-size: 12px;
}
.target-main { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; }
.target-main code { font-size: 11.5px; color: var(--ink-2); }
.target-health { margin-top: 0; }
.target-off { border-style: dashed; }
.target-off code { color: var(--ink-4); }
.target-actions { display: flex; align-items: center; gap: 2px; flex: none; }
.target-actions form { display: inline-flex; }
.btn-sm { font-size: 12px; padding: 3px 9px; }

.notice-inline { margin: 0 0 10px; }
.token {
  margin: 8px 0 0; padding: 8px 10px; border-radius: var(--radius-sm);
  background: var(--bg-2); color: var(--ink); font-size: 12px;
  white-space: pre-wrap; word-break: break-all; font-family: var(--mono);
}
.token code { font-size: inherit; }

.track-row { display: flex; flex-wrap: wrap; gap: 6px; }
.track-row .btn { font-size: 12.5px; padding: 5px 10px; }
.track-row .badge { margin-left: 5px; }

.provider { border-top: 1px solid var(--rule); padding: 16px 0; }
.provider:first-of-type { border-top: none; padding-top: 0; }
.provider:last-of-type { padding-bottom: 0; }
.provider-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; margin-bottom: 10px; }
.provider-head h3 { font-size: 13.5px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.provider-head .btn { flex: none; }

.provider-form { display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; }
.cred { flex: 1 1 240px; min-width: 0; }
.cred label { font-size: 12px; color: var(--ink-3); font-family: var(--mono); }
.cred input[disabled] { background: var(--bg-2); color: var(--ink-4); }

details.card > summary { cursor: pointer; color: var(--ink); list-style: revert; }
details.card > summary:hover { color: var(--brand-strong); }

@media (max-width: 860px) {
  .engine-list { grid-template-columns: 1fr; }
  .provider-head { flex-direction: column; }
  .provider-form { flex-direction: column; align-items: stretch; }
}

/* ---------------------------------------------------------------------------
   The measurement screens.

   Two rules run through everything below.

   A number never appears without its denominator. A card holding only "71%"
   is meaningless the moment it is screenshotted or read aloud, so every KPI
   carries its own label and the sample it rests on.

   Numerals are tabular everywhere they can be compared. A column of figures
   that shifts width as digits change is the clearest signal that nobody
   looked at the screen.
   --------------------------------------------------------------------------- */

.pagehead {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin-bottom: 20px;
}
.pagehead h1 { margin: 0 0 4px; font-size: 22px; letter-spacing: -0.02em; }
.pagehead .lede { margin: 0; max-width: 62ch; }
.crumb { margin: 0 0 6px; font-size: 12px; }
.crumb a { color: var(--ink-3); }

/* The window switch. A segmented control rather than a dropdown: three
   options that fit are three options you can see. */
.segmented {
  display: inline-flex; background: var(--bg-2); border: 1px solid var(--rule);
  border-radius: var(--radius-sm); padding: 2px; gap: 2px; flex: none;
}
.segmented a {
  padding: 5px 11px; border-radius: 4px; font-size: 12px; font-weight: 500;
  color: var(--ink-3); text-decoration: none; transition: background 120ms ease, color 120ms ease;
}
.segmented a:hover { color: var(--ink); }
.segmented a[aria-current="true"] { background: var(--surface); color: var(--ink); box-shadow: var(--shadow); }

/* KPIs. The lead card is visually heavier because one number is the point of
   the page and four equal cards say nothing is. */
.kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 18px; }
/* The overview's four cards: the lead takes the double column. Other pages
   (citations by type) have no lead and any number of cards. */
.kpis-lead { grid-template-columns: 2fr 1fr 1fr 1fr; }
.kpi {
  background: var(--surface); border: 1px solid var(--rule); border-radius: var(--radius);
  padding: 14px 16px 12px; display: flex; flex-direction: column; gap: 6px; min-width: 0;
}
/* The lead card is wider and its number larger, and it carries the history
   under it. That is the hierarchy; it no longer needs a brand-coloured ring. */
.kpi-lead { border-color: var(--rule); box-shadow: var(--shadow); }
.kpi-label {
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--ink-3); display: flex; align-items: center; gap: 5px;
  /* Two lines reserved so a wrapping title cannot push its number out of line
     with the others. */
  min-height: 2.2em;
}
.kpi-value { display: flex; align-items: baseline; gap: 2px; }
.kpi-value .num {
  font-size: 34px; font-weight: 650; letter-spacing: -0.03em; line-height: 1.05;
  font-variant-numeric: tabular-nums; color: var(--ink);
}
.kpi-lead .kpi-value .num { font-size: 44px; letter-spacing: -0.035em; }
.kpi-value .unit { font-size: 17px; font-weight: 600; color: var(--ink-3); }
.kpi-foot { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.denom { font-size: 11.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.delta { font-size: 11.5px; font-weight: 600; font-variant-numeric: tabular-nums; }
.delta-up { color: var(--pos-fg); }
.delta-down { color: var(--neg-fg); }
.delta-flat { color: var(--ink-4); }
.kpi-range { margin-left: auto; font-size: 11px; color: var(--ink-4); font-variant-numeric: tabular-nums; }
.kpi-spark { display: block; width: 100%; height: 44px; margin-top: 6px; }
.kpi-spark .spark-area { fill: url(#ll-area-own); }
.kpi-spark .spark-line { fill: none; stroke: var(--chart-own); stroke-width: 1.75; stroke-linejoin: round; stroke-linecap: round; }
.kpi-spark .spark-line.bridge { stroke-dasharray: 3 5; opacity: 0.6; }

/* The formula, on hover and on keyboard focus. The thing no competitor shows
   and the thing that makes a number checkable. */
.help {
  width: 14px; height: 14px; border-radius: 50%; background: var(--bg-2);
  color: var(--ink-4); font-size: 9px; font-weight: 700; display: inline-grid;
  place-items: center; cursor: help; position: relative; flex: none;
}
.help:hover, .help:focus-visible { background: var(--brand-soft); color: var(--brand-strong); }
.help-pop {
  position: absolute; bottom: calc(100% + 8px); left: -8px; width: 250px;
  background: var(--ink); color: var(--bg); padding: 9px 11px; border-radius: var(--radius-sm);
  font-size: 11.5px; font-weight: 400; line-height: 1.45; text-transform: none;
  letter-spacing: 0; opacity: 0; pointer-events: none; transition: opacity 120ms ease;
  z-index: 20; box-shadow: 0 6px 18px rgb(0 0 0 / 18%);
}
.help:hover .help-pop, .help:focus-visible .help-pop { opacity: 1; }

.caption { font-size: 12px; color: var(--ink-3); margin: -6px 0 18px; }

.split { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 14px; }
.split-wide { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); align-items: start; }
.rail { display: flex; flex-direction: column; gap: 14px; }
.more { font-size: 12px; font-weight: 500; }

/* Standings. The own row stays visible at zero, because "you are not in this
   conversation" is the most useful thing this tool can say. */
table.standings { width: 100%; border-collapse: collapse; font-size: 13px; }
table.standings th {
  text-align: left; font-size: 10.5px; font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--ink-4); padding: 0 8px 7px; border-bottom: 1px solid var(--rule);
}
table.standings td { padding: 9px 8px; border-bottom: 1px solid var(--rule); vertical-align: middle; }
table.standings tr:last-child td { border-bottom: 0; }
table.standings .num, .num { text-align: right; font-variant-numeric: tabular-nums; }
.rank { color: var(--ink-4); font-variant-numeric: tabular-nums; width: 22px; }
.brand { display: block; font-weight: 550; color: var(--ink); }
.sub { display: block; font-size: 11px; color: var(--ink-4); }
tr.own .brand { color: var(--brand-strong); }
tr.own { background: var(--brand-soft); }
tr.absent .brand { color: var(--ink-3); }
.tag {
  font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
  background: var(--brand); color: #fff; padding: 1px 5px; border-radius: 3px; vertical-align: 1px;
}
.muted { color: var(--ink-4); }

.barcell { display: block; height: 4px; background: var(--bg-2); border-radius: 3px; overflow: hidden; margin: 5px 0 0; }
.bar { display: block; height: 100%; background: var(--brand); border-radius: 3px; }
tr.own .bar { background: var(--brand-strong); }
.barwide { width: 110px; }

/* The prompt by engine grid: one glance answers which engine is losing you
   which question, without changing a filter and scrolling from memory. */
table.grid { width: 100%; border-collapse: separate; border-spacing: 3px; font-size: 12.5px; }
.grid-prompt { max-width: 320px; min-width: 220px; }
.grid-prompt .prompt-text {
  display: block; color: var(--ink); font-weight: 500; line-height: 1.35;
  overflow: hidden; text-overflow: ellipsis; display: -webkit-box;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
th.grid-col {
  text-align: center; font-size: 10.5px; font-weight: 600; color: var(--ink-3);
  padding-bottom: 6px; white-space: nowrap;
}
th.grid-col span { display: block; }
th.grid-col .badge { margin-top: 3px; }
.grid-cell { width: 74px; }
.cell {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  height: 46px; border-radius: var(--radius-sm); text-decoration: none;
  font-variant-numeric: tabular-nums; transition: transform 120ms ease, box-shadow 120ms ease;
}
a.cell:hover { transform: translateY(-1px); box-shadow: var(--tip-shadow); }
.cell-value { font-size: 13px; font-weight: 650; }
.cell-sub { font-size: 9.5px; opacity: 0.75; font-weight: 500; }
/* An empty cell is a prompt that was never asked of that engine, not a zero.
   It reads as absence: dotted, unfilled, unclickable. */
.cell-empty { border: 1px dashed var(--rule-2); color: var(--ink-4); background: transparent; }

.catlist, .sourcelist, .queries, .chips, .sources, .answers { list-style: none; margin: 0; padding: 0; }
.catlist li, .sourcelist li { padding: 9px 0; border-bottom: 1px solid var(--rule); }
.catlist li:last-child, .sourcelist li:last-child { border-bottom: 0; }
.catlist-head, .sourcelist-head { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.catlist .cat { font-weight: 550; text-transform: capitalize; flex: 1; }
.catlist .num, .sourcelist .num { margin-left: auto; font-weight: 600; }
.sourcelist .site { font-weight: 550; word-break: break-all; }

/* Answers: the evidence list. */
.answers li { border-bottom: 1px solid var(--rule); }
.answers li:last-child { border-bottom: 0; }
.answer-link { display: block; padding: 14px 2px; text-decoration: none; color: inherit; border-radius: var(--radius-sm); }
.answer-link:hover { background: var(--bg-2); }
.answer-top { display: flex; align-items: flex-start; gap: 10px; justify-content: space-between; }
.answer-prompt { font-weight: 550; color: var(--ink); font-size: 14px; }
.answer-meta { display: flex; gap: 4px; flex: none; }
.answer-preview {
  margin: 5px 0 7px; color: var(--ink-3); font-size: 12.5px; line-height: 1.5;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.answer-foot { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.answer-foot .sub { display: inline; }

.chip {
  display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 600;
  padding: 2px 8px; border-radius: 20px; background: var(--bg-2); color: var(--ink-2);
}
.chip-own { background: var(--brand-soft); color: var(--brand-strong); }
.chip-miss { background: var(--bg-2); color: var(--ink-3); }
.chip-rival { background: var(--bg-2); color: var(--ink-2); }
.chip-rank { font-variant-numeric: tabular-nums; opacity: 0.7; }
.chips { display: flex; flex-wrap: wrap; gap: 6px; }

/* One answer in full. The brand is marked in the text, using the same offsets
   that produced the count, so the highlight and the number cannot disagree. */
.answer-title { font-size: 19px; line-height: 1.3; max-width: 60ch; }
.prose { font-size: 14px; line-height: 1.65; color: var(--ink-2); max-width: 72ch; }
.prose p { margin: 0 0 0.9em; }
.prose p:last-child { margin-bottom: 0; }
mark.mark-own { background: var(--mark-own); color: var(--ink); padding: 0 2px; border-radius: 2px; font-weight: 600; }
mark.mark-rival { background: var(--mark-rival); color: var(--ink-2); padding: 0 2px; border-radius: 2px; }

.queries li { padding: 6px 0; border-bottom: 1px solid var(--rule); font-size: 12px; }
.queries li:last-child { border-bottom: 0; }
.sources { counter-reset: src; }
.sources li { padding: 8px 0; border-bottom: 1px solid var(--rule); font-size: 12.5px; }
.sources li:last-child { border-bottom: 0; }
.sources a { font-weight: 500; }

/* First run. The empty state teaches instead of apologising, and it never
   shows fake data: every number on the overview comes from a real answer. */
.empty { text-align: left; }
.empty h2 { margin: 0 0 6px; }
.empty p { margin: 0 0 16px; }
.empty-steps { display: flex; flex-direction: column; gap: 2px; margin: 16px 0 14px; }
.step-row {
  display: flex; align-items: center; gap: 12px; padding: 11px 12px;
  border: 1px solid var(--rule); border-radius: var(--radius-sm); background: var(--bg-2);
}
.step-row div { flex: 1; }
.step-row strong { display: block; font-size: 13px; }
.step-mark {
  width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center;
  background: var(--rule); color: var(--ink-3); font-size: 11px; font-weight: 700; flex: none;
}
.step-row.done .step-mark { background: var(--brand); color: #fff; }

/* Charts. Inline SVG, so they inherit the page's tokens and follow the theme
   without a second palette. */
.chart { width: 100%; height: auto; display: block; }
.chart text { font-variant-numeric: tabular-nums; }
.chart .grid { stroke: var(--chart-grid); stroke-width: 1; shape-rendering: crispEdges; }
.chart .grid-base { stroke: var(--chart-base); }
.chart .line { fill: none; stroke: var(--brand); stroke-width: 2.5; stroke-linejoin: round; stroke-linecap: round; }
.chart .area { fill: var(--brand); opacity: 0.1; stroke: none; }
.chart .dot { fill: var(--brand); stroke: var(--surface); stroke-width: 2; }
.chart .axis { fill: var(--ink-4); font-size: 10px; font-family: var(--sans); }
.spark { width: 68px; height: 20px; stroke: var(--brand); stroke-width: 1.5; }

.badge-own { background: var(--brand-soft); color: var(--brand-strong); }
.badge-competitor { background: var(--neg-bg); color: var(--neg-fg); }
.badge-social { background: var(--bg-2); color: var(--ink-2); }
.badge-informational { background: var(--info-bg); color: var(--info-fg); }
.badge-other { background: var(--bg-2); color: var(--ink-3); }
.badge-warn { background: var(--warn-bg); color: var(--warn-fg); }

@media (max-width: 1080px) {
  .kpis { grid-template-columns: repeat(2, 1fr); }
  .kpi-lead { grid-column: 1 / -1; }
  .split, .split-wide { grid-template-columns: 1fr; }
}
@media (max-width: 860px) {
  .kpis { grid-template-columns: repeat(2, 1fr); }
  .pagehead { flex-direction: column; }
}

/* Answer prose. Engines write Markdown, so the small subset they use is
   rendered rather than shown as syntax. */
.prose h3 { font-size: 14px; font-weight: 650; color: var(--ink); margin: 1.1em 0 0.4em; }
.prose h3:first-child { margin-top: 0; }
.prose ul { margin: 0 0 0.9em; padding-left: 1.1em; }
.prose li { margin: 0 0 0.35em; }
.prose code {
  font-family: var(--mono); font-size: 0.88em; background: var(--bg-2);
  padding: 1px 4px; border-radius: 3px;
}
.prose a { word-break: break-word; }
.prose strong { color: var(--ink); font-weight: 600; }
.li-rank { font-variant-numeric: tabular-nums; color: var(--ink-4); font-weight: 600; }
.chip-times { font-size: 10px; opacity: 0.65; font-weight: 500; }

/* ---------------------------------------------------------------------------
   The grid, revised.

   Cells carry a fraction, not a percentage. On a new install "0/1" is a
   complete census of one answer the reader can open, while "0%" is an
   estimate of a rate from a single draw, and it is the form that reads as a
   broken widget.

   Two kinds of nothing, drawn differently on purpose. A measured zero is
   filled, ringed, full-strength and clickable, because it is the finding. A
   cell nobody has run is dashed, transparent and inert, because an unasked
   prompt is not one the engine ignored.
   --------------------------------------------------------------------------- */

.hm-none {
  background: var(--cell-empty); color: var(--ink-4);
  border: 1px dashed var(--rule-2); cursor: default;
  box-shadow: inset 0 0 0 1px var(--chart-grid);
}
.hm-0 { background: var(--cell-0); color: var(--cell-0-ink); box-shadow: inset 0 0 0 1px var(--cell-ring); }
.hm-1 { background: var(--cell-1); color: var(--cell-1-ink); }
.hm-2 { background: var(--cell-2); color: var(--cell-2-ink); }
.hm-3 { background: var(--cell-3); color: var(--cell-3-ink); }
.hm-4 { background: var(--cell-4); color: var(--cell-4-ink); }
.hm-5 { background: var(--cell-5); color: var(--cell-5-ink); }


.col-name { display: block; }
.grid-total {
  text-align: center; font-variant-numeric: tabular-nums; font-size: 11.5px;
  color: var(--ink-3); font-weight: 600; padding: 0 6px;
}
table.grid tfoot .grid-total { color: var(--ink-2); border-top: 1px solid var(--rule); padding-top: 7px; }
table.grid tfoot th.grid-prompt {
  font-size: 11px; font-weight: 600; color: var(--ink-3); text-transform: uppercase;
  letter-spacing: 0.05em; border-top: 1px solid var(--rule); padding-top: 7px;
}
table.grid th.grid-prompt { font-weight: 400; text-align: left; }
a.prompt-text { color: var(--ink); text-decoration: none; }
a.prompt-text:hover { text-decoration: underline; }
tr.row-branded { opacity: 0.72; }
.tag-quiet { background: var(--bg-2); color: var(--ink-3); font-weight: 600; }
.legend { max-width: 76ch; margin-top: 10px; }

/* The count-led headline, used below a useful sample. */
.kpi-count { gap: 7px; align-items: baseline; }
.kpi-count .of { font-size: 15px; color: var(--ink-3); font-weight: 500; }
.kpi-count .total { color: var(--ink-2); text-decoration: underline; text-underline-offset: 4px; }
.kpi-count a.total:hover { color: var(--brand-strong); }
.delta-none { color: var(--ink-4); font-weight: 500; }

.spark-line { stroke: var(--brand); stroke-width: 1.5; fill: none; stroke-linejoin: round; stroke-linecap: round; }
.spark-dot { fill: var(--brand); }
.chart-trend { max-height: 190px; }

/* ---------------------------------------------------------------------------
   The rich charts. Series colours come from the tokens above; the classes
   below bind them to --c so one brand is one colour across the race, the
   donut and the engine strips. Everything animated is entry motion only,
   gated on prefers-reduced-motion, and never changes a value.
   --------------------------------------------------------------------------- */
.s-own { --c: var(--chart-own); }
.s-1 { --c: var(--series-1); }
.s-2 { --c: var(--series-2); }
.s-3 { --c: var(--series-3); }
.s-4 { --c: var(--series-4); }
.s-5 { --c: var(--series-5); }
.s-6 { --c: var(--series-6); }
.s-7 { --c: var(--series-7); }
.s-8 { --c: var(--series-8); }
.s-rest, .s-field { --c: var(--chart-field); }

/* The gradient the areas fill with. The defs SVG is kept in flow but
   sized to nothing; display:none is the path where gradient resolution gets
   flaky. */
.chart-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
.chart-defs .stop-a { stop-color: var(--area-top); }
.chart-defs .stop-b { stop-color: var(--area-bottom); }

/* The race. */
.chart-wrap { position: relative; }
.chart-race .gap-band { fill: var(--plot-gap); }
.chart-race .tick { stroke: var(--chart-base); stroke-width: 1; }
.chart-race .axis-y, .chart-race .axis-x, .chart-race .axis-strip { font-size: 10.5px; fill: var(--ink-4); }
.chart-race .axis-strip { font-size: 9.5px; }
.chart-race .n-bar { fill: var(--chart-field); opacity: 0.55; }
.chart-race .n-bar.n-low { fill: var(--warn-fg); opacity: 0.55; }
.chart-race .series.line { fill: none; stroke: var(--c); stroke-width: 1.25; opacity: 0.45; stroke-linejoin: round; stroke-linecap: round; transition: opacity 160ms ease, stroke-width 160ms ease; }
.chart-race .rival-lead .series.line { stroke-width: 1.5; opacity: 0.7; }
.chart-race .series-own.line { stroke-width: 2.25; opacity: 1; filter: drop-shadow(0 0 6px var(--own-glow)); }
.chart-race .series.line.bridge { stroke-dasharray: 3 5; opacity: 0.4; filter: none; }
.chart-race .series-own.line.bridge { opacity: 0.7; }
.chart-race .area-own { fill: url(#ll-area-own); stroke: none; }
.chart-race .rivals .dot { fill: var(--c); stroke: var(--surface); stroke-width: 1.5; opacity: 0; transition: opacity 120ms ease; }
.chart-race .rivals .dot.is-on { opacity: 1; }
.chart-race .own .dot { fill: var(--c); stroke: var(--surface); stroke-width: 2; }
.chart-race .own .dot.dot-thin { fill: var(--surface); stroke: var(--c); stroke-width: 1.5; }
.chart-race .rivals .dot.dot-thin { fill: var(--surface); stroke: var(--c); }
.chart-race .halo { fill: var(--chart-own); opacity: 0.18; }
.chart-race .lead { stroke: var(--c); stroke-width: 1; opacity: 0.5; }
.chart-race .end { font-size: 11.5px; fill: var(--c); font-weight: 600; }
.chart-race .end .end-name { fill: var(--ink-2); font-weight: 500; }
.chart-race .end-own { font-weight: 700; }
.chart-race .end-own .end-name { fill: var(--ink); font-weight: 650; }
.chart-race .cursor { stroke: var(--chart-cursor); stroke-width: 1; opacity: 0; stroke-dasharray: 2 3; }
.chart-race.is-hover .cursor { opacity: 0.55; }
.chart-race.is-hover .series.line:not(.series-own) { opacity: 0.3; }

/* The hover card. Built by charts.js from values Go wrote onto the dots. */
.tip {
  position: absolute; z-index: 5; pointer-events: none; min-width: 180px; max-width: 260px;
  background: var(--tip-bg); border: 1px solid var(--tip-border); border-radius: var(--radius-sm);
  box-shadow: var(--tip-shadow); padding: 8px 10px; font-size: 12px; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.tip-head { display: flex; justify-content: space-between; gap: 10px; margin-bottom: 6px; padding-bottom: 6px; border-bottom: 1px solid var(--rule); }
.tip-day { font-weight: 650; }
.tip-n { color: var(--ink-3); font-size: 11px; }
.tip-n.tip-thin { color: var(--warn-fg); }
.tip-row { display: flex; align-items: center; gap: 7px; padding: 1.5px 0; color: var(--ink-2); }
.tip-row .swatch { width: 8px; height: 8px; border-radius: 2px; background: var(--c); flex: none; }
.tip-row .tip-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tip-row .tip-val { font-weight: 600; color: var(--ink); }
.tip-row.own { color: var(--ink); font-weight: 600; }

/* The legend under the race is for screen readers and phones; on a wide
   screen the end labels carry it. */
.legend-row { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: 12px; }
@media (min-width: 761px) { .chart-wrap[data-chart="race"] + .legend-row { display: none; } }
.legend-row li, .legend-col li { display: flex; align-items: center; gap: 7px; color: var(--ink-2); }
.legend-row .num, .legend-col .num { font-variant-numeric: tabular-nums; color: var(--ink); font-weight: 600; }
.legend-row li.own, .legend-col li.own { color: var(--ink); font-weight: 600; }
.swatch { width: 10px; height: 10px; border-radius: 3px; background: var(--c); flex: none; }
.legend-col { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; font-size: 12px; min-width: 0; }
.legend-col .legend-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.legend-more { width: 100%; }
.legend-more summary { display: flex; align-items: center; gap: 7px; cursor: pointer; list-style: none; }
.legend-more summary::-webkit-details-marker { display: none; }
.legend-more summary .legend-name { flex: 1; }
.legend-more summary::after { content: "+"; color: var(--ink-4); font-weight: 600; margin-left: 4px; }
.legend-more[open] summary::after { content: "\2013"; }
.legend-tail { margin: 6px 0 0 17px; gap: 4px; font-size: 11.5px; color: var(--ink-3); }

/* The donut. */
.donut-wrap { display: flex; align-items: center; gap: 18px; }
.chart-donut { width: 180px; height: 180px; flex: none; }
.donut-track { stroke: var(--bg-2); }
.chart-donut .arc { stroke: var(--c); stroke-linecap: butt; transition: stroke-width 140ms ease, opacity 140ms ease; }
.chart-donut .arc.series-own { stroke-width: 20; }
.chart-donut:hover .arc { opacity: 0.5; }
.chart-donut .arc:hover { opacity: 1; stroke-width: 22; }
.donut-value { font-size: 32px; font-weight: 650; fill: var(--ink); letter-spacing: -0.03em; }
.donut-label { font-size: 10.5px; fill: var(--ink-3); text-transform: uppercase; letter-spacing: 0.08em; }
.donut-denom { font-size: 11px; fill: var(--ink-4); }

/* The engine strips. */
.chart-engines .grid { stroke-width: 1; }
.chart-engines .track { stroke: var(--chart-base); stroke-width: 1; }
.chart-engines .axis { font-size: 10px; }
.chart-engines .eng { font-size: 12.5px; font-weight: 550; fill: var(--ink); }
.chart-engines .eng-sub { font-size: 10.5px; fill: var(--ink-4); }
.chart-engines .eng-sub .thin { fill: var(--warn-fg); }
.chart-engines .pt { fill: var(--c); stroke: var(--surface); stroke-width: 1.5; transition: opacity 120ms ease; }
.chart-engines .pt-field { fill: var(--chart-field); stroke-width: 1; }
.chart-engines .pt-own { stroke-width: 2; }
.chart-engines .pt-zero { fill: var(--surface); stroke: var(--c); stroke-width: 1.5; }
.chart-engines .pt-own.pt-zero { stroke-dasharray: 2 2; stroke-width: 2; }
.chart-engines .pt-field.pt-zero { stroke: var(--chart-field); }
.chart-engines .row-thin .pt { opacity: 0.6; }
.chart-engines .val { font-size: 13px; font-weight: 650; fill: var(--chart-own); }
.chart-engines .val-zero { fill: var(--ink-4); }
.chart-engines .val-sub { font-size: 10.5px; fill: var(--ink-4); }
.chart-engines .lead-val { font-size: 10.5px; font-weight: 600; fill: var(--c); paint-order: stroke; stroke: var(--surface); stroke-width: 3px; stroke-linejoin: round; }
.chart-engines .ptlabel { font-size: 11px; font-weight: 600; fill: var(--ink); paint-order: stroke; stroke: var(--surface); stroke-width: 3px; stroke-linejoin: round; opacity: 0; pointer-events: none; }
.chart-engines.has-focus .pt { opacity: 0.18; }
.chart-engines.has-focus .pt.is-on { opacity: 1; }
.chart-engines.has-focus .ptlabel { opacity: 1; }

/* The citation mix: fixed colour per source class on every surface. */
.mix-wrap { display: flex; flex-direction: column; gap: 10px; }
.chart-mix { width: 100%; min-width: 0; }
.mix-wrap .legend-col { flex-direction: row; flex-wrap: wrap; gap: 6px 16px; }
.mix-wrap .legend-col .legend-name { flex: none; }
.chart-mix .mix { stroke: var(--surface); stroke-width: 1; }
.chart-mix .col { transition: opacity 140ms ease; }
.chart-mix:hover .col:not(:hover) { opacity: 0.5; }
.chart-mix .mix-val { font-size: 10px; font-weight: 650; fill: var(--chart-own); }
.chart-mix .axis-sub { font-size: 9px; }
.mix-own { fill: var(--src-own); }
.mix-competitor { fill: var(--src-competitor); }
.mix-social { fill: var(--src-social); }
.mix-informational { fill: var(--src-informational); }
.mix-other { fill: var(--chart-field); }
.mix-legend-own { --c: var(--src-own); }
.mix-legend-competitor { --c: var(--src-competitor); }
.mix-legend-social { --c: var(--src-social); }
.mix-legend-informational { --c: var(--src-informational); }
.mix-legend-other { --c: var(--chart-field); }
.legend-col li[class^="mix-legend"] .legend-name { text-transform: capitalize; }

/* Entry motion. Nothing here changes a value, only when it appears. Under
   reduced motion everything is static at its final state. pathLength="1"
   on the drawn paths keeps the dash arithmetic unit-free. */
@media (prefers-reduced-motion: no-preference) {
  .chart-race .series-own.line:not(.bridge) { stroke-dasharray: 1; stroke-dashoffset: 1; animation: chart-draw 1100ms cubic-bezier(.2,.7,.2,1) 80ms forwards; }
  .chart-race .area-own { opacity: 0; animation: chart-in 700ms ease 520ms forwards; }
  .chart-race .rivals, .chart-race .ends, .chart-race .own .dot, .chart-race .own .bridge, .chart-race .n-strip { opacity: 0; animation: chart-in 600ms ease 760ms forwards; }
  .chart-race .halo { transform-box: fill-box; transform-origin: center; animation: chart-halo 2600ms ease-out 1500ms infinite; }
  .kpi-spark .spark-area { opacity: 0; animation: chart-in 600ms ease 400ms forwards; }
  .chart-donut .arc { stroke-dasharray: 1; stroke-dashoffset: 1; animation: chart-draw calc(var(--t, 1) * 700ms) linear calc(var(--d, 0) * 700ms) forwards; }
  .chart-engines .pt-own { transform-box: fill-box; transform-origin: center; animation: chart-pop 320ms cubic-bezier(.22,1,.36,1) both; animation-delay: calc(var(--k, 0) * 60ms + 200ms); }
}
@keyframes chart-draw { to { stroke-dashoffset: 0; } }
@keyframes chart-in { to { opacity: 1; } }
@keyframes chart-halo { 0% { transform: scale(.6); opacity: .32; } 70%, 100% { transform: scale(1.7); opacity: 0; } }
@keyframes chart-pop { from { transform: scale(.4); opacity: 0; } to { transform: scale(1); opacity: 1; } }

.bar-own { background: var(--src-own); }
.bar-competitor { background: var(--src-competitor); }
.bar-social { background: var(--src-social); }
.bar-informational { background: var(--src-informational); }
.bar-other { background: var(--src-other); }

/* The word cloud. Frequency is encoded once, as size. */
.cloud { margin: 4px 0 0; line-height: 1.9; color: var(--ink-2); word-spacing: 0.35em; }
.cloud span { display: inline-block; padding: 0 2px; color: var(--ink); cursor: default; transition: color 120ms ease; }
.cloud span:hover { color: var(--brand-strong); }

.split-3 { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1.85fr); }
.span-2 { min-width: 0; }
@media (max-width: 1080px) { .split-3 { grid-template-columns: 1fr; } .donut-wrap { flex-wrap: wrap; } }

/* Demo banner. It names the exact commit the demo runs, so the demo is
   checkable against the repository rather than trusted. */
.demo-banner {
  display: flex; align-items: center; gap: 10px; padding: 8px 16px;
  background: var(--brand-deep); color: #fff; font-size: 12.5px;
  position: sticky; top: 0; z-index: 30;
}
.demo-banner a { color: #fff; }
.demo-banner code { font-family: var(--mono); font-size: 11.5px; background: rgb(255 255 255 / 14%); padding: 1px 5px; border-radius: 3px; }
.demo-dot { width: 8px; height: 8px; border-radius: 50%; background: #4ade80; box-shadow: 0 0 0 3px rgb(74 222 128 / 25%); flex: none; }
.demo-cta { margin-left: auto; font-weight: 600; white-space: nowrap; text-decoration: none; padding: 4px 10px; border: 1px solid rgb(255 255 255 / 30%); border-radius: var(--radius-sm); }
.demo-cta:hover { background: rgb(255 255 255 / 10%); }
.shell-demo .sidebar { top: 34px; }
