/*
  System fonts only. A webfont from a CDN would send every visitor's IP address
  to a third party, which under TDDDG section 25 and the DSGVO turns a static
  page into something that needs a consent banner. Not worth it for a typeface.
*/

:root {
  --bg: #fbfaf8;
  --panel: #ffffff;
  --ink: #16181d;
  --ink-2: #4b5058;
  --ink-3: #7a8089;
  --rule: #e2e0dc;
  --rule-2: #efedea;
  --accent: #1c4fd8;
  --ok: #1f7a4d;
  --warn: #9a6100;
  --bad: #b3261e;
  --info: #5b3fb5;
  --add: #e8f4ec;
  --del: #fbeceb;

  /*
    Chart tones. Three, and they are an emphasis palette rather than a
    categorical one: the accent above carries the thing being counted, and the
    other two are neutrals for "the other side of the same count" and "we could
    not read this". No new hues -- --chart-lead IS --accent.

    Checked with the data-viz palette validator against the surface these
    actually render on (--panel), in both modes:

      light  lead 6.65:1  quiet 4.98:1  none 1.92:1
             worst pair chart-none/chart-quiet -- CVD dE 18.5, normal-vision 20.8
      dark   lead 6.82:1  quiet 3.43:1  none 1.70:1
             worst pair chart-quiet/chart-lead -- CVD dE 18.8, normal-vision 19.4

    --chart-none is deliberately below the 3:1 mark used for marks that must be
    read from colour alone. That is legal here and only here, because it never
    is read from colour alone: its count is printed in the legend beside it, it
    is named in the coverage line under every chart, and the companies in it are
    listed in the table that opens below. A tone that means "absence" should
    recede; a tone that means "absence" and cannot be resolved any other way
    would be a lie.
  */
  --chart-lead: var(--accent);
  --chart-quiet: #6b7079;
  --chart-none: #bebbb4;

  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --wrap: 74rem;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #14151a;
    --panel: #1b1d23;
    --ink: #e9e9ec;
    --ink-2: #b0b3ba;
    --ink-3: #7f838c;
    --rule: #2c2f37;
    --rule-2: #23262d;
    --accent: #7ea2ff;
    --ok: #56c98d;
    --warn: #e0a33c;
    --bad: #f08079;
    --info: #ab93f5;
    --add: #17301f;
    --del: #34191a;

    /* Selected for the dark surface, not flipped. See the note above. */
    --chart-quiet: #767a83;
    --chart-none: #40434a;
  }
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 400 16px/1.55 var(--sans);
  font-feature-settings: "tnum" 1;
}

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

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

h1, h2, h3 { line-height: 1.2; letter-spacing: -0.015em; }

.skip {
  position: absolute; left: -9999px; top: 0; background: var(--panel);
  padding: .6rem 1rem; z-index: 10;
}
.skip:focus { left: 0; }

/* ---------------------------------------------------------------- masthead */

.masthead {
  border-bottom: 1px solid var(--rule);
  background: var(--panel);
  padding: 2.5rem 0 1.75rem;
}
.masthead h1 { margin: 0 0 .6rem; font-size: clamp(1.6rem, 3.6vw, 2.35rem); font-weight: 620; }
.masthead h1 a { color: inherit; text-decoration: none; }

.standfirst {
  margin: 0 0 1.5rem;
  max-width: 56ch;
  color: var(--ink-2);
  font-size: 1.03rem;
}

.stats {
  display: grid; gap: 1px;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  margin: 0; background: var(--rule); border: 1px solid var(--rule);
  border-radius: 6px; overflow: hidden;
}
.stats div { background: var(--panel); padding: .7rem .9rem; }
.stats dt { font-size: .74rem; text-transform: uppercase; letter-spacing: .07em; color: var(--ink-3); }
.stats dd { margin: .15rem 0 0; font-size: 1.28rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.stats dd.small { font-size: .95rem; font-weight: 500; }

.crawl-banner {
  margin: 1rem 0 0; padding: .7rem .9rem; border-radius: 6px;
  border: 1px solid var(--warn); color: var(--warn);
  background: color-mix(in srgb, var(--warn) 8%, transparent);
  font-size: .9rem;
}

/* -------------------------------------------------------------------- tabs */

.tabs {
  display: flex; gap: .25rem; flex-wrap: wrap;
  border-bottom: 1px solid var(--rule); margin-bottom: 1.75rem;
  position: sticky; top: 0; background: var(--bg); z-index: 5;
  padding-top: .5rem;
}
.tabs a {
  padding: .55rem .85rem; text-decoration: none; color: var(--ink-2);
  border-bottom: 2px solid transparent; font-size: .95rem; font-weight: 500;
}
.tabs a:hover { color: var(--ink); }
.tabs a.on { color: var(--ink); border-bottom-color: var(--accent); }

/* ------------------------------------------------------------------- views */

main { padding-bottom: 3rem; min-height: 55vh; }

.view-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
h2 { font-size: 1.3rem; font-weight: 600; margin: 0 0 .35rem; }
h3 { font-size: 1rem; font-weight: 600; margin: 0 0 .4rem; }

.note { margin: .35rem 0 1.4rem; color: var(--ink-2); font-size: .92rem; max-width: 72ch; }

.filter { font-size: .87rem; color: var(--ink-3); display: inline-flex; align-items: center; gap: .4rem; }
.filter select {
  font: inherit; font-size: .87rem; padding: .3rem .45rem; color: var(--ink);
  background: var(--panel); border: 1px solid var(--rule); border-radius: 5px;
}

.loading, .empty { color: var(--ink-3); padding: 1.5rem 0; font-style: italic; }

/* -------------------------------------------------------------------- feed */

.feed { list-style: none; margin: 0; padding: 0; }
.feed li.change {
  background: var(--panel); border: 1px solid var(--rule);
  border-radius: 8px; padding: 1rem 1.1rem; margin-bottom: .8rem;
}
.change-head {
  display: flex; gap: .55rem; align-items: baseline; flex-wrap: wrap;
  margin-bottom: .5rem;
}
.change-head .co { font-weight: 620; }
.change-head .co a { color: inherit; text-decoration: none; }
.change-head .co a:hover { text-decoration: underline; }
.change-head time { color: var(--ink-3); font-size: .82rem; margin-left: auto; white-space: nowrap; }

.tag {
  font-size: .72rem; letter-spacing: .045em; text-transform: uppercase;
  padding: .16rem .42rem; border-radius: 4px; font-weight: 600;
  border: 1px solid var(--rule); color: var(--ink-2); background: var(--rule-2);
}
.tag.modified { color: var(--info); }
.tag.added    { color: var(--ok); }
.tag.removed  { color: var(--bad); }
.tag.oscillating { color: var(--warn); border-color: var(--warn); cursor: help; }
.tag.retracted { color: var(--bad); border-color: var(--bad); }

/* Deliberately the quietest tag on the page. It reports an absence -- nobody
   has looked again yet -- and an absence should not shout. */
.tag.once { color: var(--ink-3); border-style: dashed; background: none; cursor: help; }

/* A withdrawn claim is struck through rather than deleted: it was published,
   somebody may have read it, and the record of that is the point. */
.change.retracted .summary,
.change.retracted .diff { text-decoration: line-through; color: var(--ink-3); }
.change.retracted .why { text-decoration: none; color: var(--bad); font-size: .82rem; margin: .5rem 0 0; }


.summary { margin: 0 0 .6rem; font-size: .98rem; }

.diff { font-family: var(--mono); font-size: .82rem; line-height: 1.5; }
.diff p { margin: 0; padding: .38rem .55rem; border-radius: 4px; overflow-wrap: anywhere; }
.diff .was { background: var(--del); }
.diff .now { background: var(--add); margin-top: .2rem; }
.diff .marker { color: var(--ink-3); user-select: none; }

.magnitude {
  display: inline-block; height: 4px; border-radius: 2px; background: var(--accent);
  vertical-align: middle; min-width: 3px;
}

/* ------------------------------------------------------------------ tables */

.grid { width: 100%; border-collapse: collapse; font-size: .92rem; }
.grid th, .grid td {
  text-align: left; padding: .6rem .7rem; border-bottom: 1px solid var(--rule-2);
  vertical-align: top;
}
.grid thead th {
  font-size: .74rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-3); border-bottom: 1px solid var(--rule); font-weight: 600;
  position: sticky; top: 2.6rem; background: var(--bg);
}
.grid tbody tr:hover { background: var(--panel); }
.grid .num { text-align: right; font-variant-numeric: tabular-nums; }
.grid .co-name { font-weight: 560; }
.grid .co-name a { color: inherit; text-decoration: none; }
.grid .co-name a:hover { text-decoration: underline; }
.grid .seg { display: block; font-size: .76rem; color: var(--ink-3); }
.grid .quiet { color: var(--ink-3); }
.grid .mono { font-family: var(--mono); font-size: .82rem; }

/* ------------------------------------------------------------------ health */

.state { font-size: .8rem; font-weight: 600; white-space: nowrap; }
.state::before {
  content: ""; display: inline-block; width: .55rem; height: .55rem;
  border-radius: 50%; margin-right: .4rem; background: currentColor;
}
.state.ok { color: var(--ok); }
.state.degraded, .state.structure-changed, .state.origin-shift { color: var(--warn); }
.state.stale, .state.error { color: var(--bad); }
.state.blocked { color: var(--info); }
.state.pending { color: var(--ink-3); }

.legend { list-style: none; display: flex; flex-wrap: wrap; gap: 1.1rem; padding: 0; margin: 0 0 1.2rem; }
.legend li { font-size: .84rem; color: var(--ink-2); }

/* ------------------------------------------------------- the landing view */

/*
  A KPI row, not a chart. Four numbers whose job is to be read, not compared,
  and a one-bar bar chart of each would say less than the number does.

  Proportional figures on purpose: tabular-nums gives every digit the width of a
  zero, which makes a large standalone number look loose. Tabular figures are
  for columns that have to line up vertically, and there is a table below for
  that.
*/
.kpis {
  display: grid; gap: 1px; margin: 0 0 2.5rem;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  background: var(--rule); border: 1px solid var(--rule);
  border-radius: 6px; overflow: hidden;
}
.kpis div { background: var(--panel); padding: .85rem 1rem; }
.kpis dt { font-size: .74rem; text-transform: uppercase; letter-spacing: .07em; color: var(--ink-3); }
.kpis dd { margin: .1rem 0 0; font-size: 2rem; font-weight: 600; font-variant-numeric: proportional-nums; line-height: 1.1; }
.kpis p { margin: .15rem 0 0; font-size: .78rem; color: var(--ink-3); }

.finding { margin: 0 0 3rem; max-width: 58rem; }
.finding h3 { font-size: 1.15rem; margin-bottom: .5rem; }
.finding h4 { font-size: .78rem; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-3); margin: 0 0 .5rem; font-weight: 600; }
.sub-chart-head { margin-top: 1.6rem !important; text-transform: none !important; letter-spacing: 0 !important; font-size: .86rem !important; color: var(--ink-2) !important; }

/* The sentence the section exists for. Set above the chart because a reader
   who stops after one line should still leave with the finding. */
.takeaway { margin: 0 0 1.1rem; font-size: 1.05rem; line-height: 1.5; max-width: 46em; }
.takeaway b { font-weight: 620; }

/* The n, and what was unreadable. Never optional, never a footnote in a
   different colour to the point where nobody reads it. */
.coverage {
  margin: .8rem 0 0; font-size: .82rem; color: var(--ink-2);
  border-left: 2px solid var(--rule); padding-left: .7rem; max-width: 52em;
}
.coverage b { font-variant-numeric: tabular-nums; }

.chart-pair { display: grid; gap: 1.6rem; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); margin-top: 1.6rem; }

/* --------------------------------------------------------- bar charts (svg) */

/*
  The SVG in each row has no viewBox, so one user unit is one CSS pixel at every
  width and nothing about the mark distorts or shrinks. The label and the value
  are HTML rather than SVG text for the same reason: they reflow, they respond
  to browser zoom and to a reader's minimum font size, and they can be selected
  and searched. See the header of src/charts.js.
*/
.bars-svg { list-style: none; padding: 0; margin: 0; }
.bar-row {
  display: grid; grid-template-columns: minmax(5.5rem, 9.5rem) 1fr 2.2rem;
  gap: .7rem; align-items: center; padding: .18rem 0;
}
.bar-label { font-size: .9rem; overflow-wrap: anywhere; }
.bar-track { display: block; overflow: visible; }
.bar-fill { fill: var(--chart-lead); }
.bar-fill.quiet { fill: var(--chart-quiet); }
.bar-value { font-size: .88rem; font-variant-numeric: tabular-nums; color: var(--ink-2); text-align: right; }

/* --------------------------------------------------- share bars (0-100%) */

/*
  The segment breakdown plots a rate, not a count, so the track is the whole
  denominator and the rail behind the mark is the visible 100%. The rail is
  --rule: chrome, the same substance as a grid line, not a fourth chart tone.
  It sits below 3:1 against the surface on purpose -- it encodes nothing, and
  every number the bar carries is printed as text in the same row.

  The value column is wider than the ranked charts' because it holds the count,
  its denominator and the percentage together. They are one string and they stay
  one string: a percentage on a cell of six companies, on its own, is the exact
  false precision this section exists to avoid.
*/
.share-row { grid-template-columns: minmax(6.5rem, 10.5rem) 1fr minmax(6.4rem, auto); }
.share-rail { fill: var(--rule); }
.bar-value b { font-weight: 620; color: var(--ink); }
.share-pct { color: var(--ink-3); }
.share-suppressed { font-size: .82rem; color: var(--ink-3); font-style: italic; align-self: center; }
.bar-row.muted .bar-label { color: var(--ink-2); }

.cut { margin: 0 0 .4rem; }
.cut-grid {
  display: grid; gap: 1.7rem 2.2rem; margin-top: .4rem;
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
}
.cut-note { margin: .5rem 0 0; font-size: .82rem; color: var(--ink-2); max-width: 46em; }

/* The list of questions this data cannot answer. Set like the coverage note,
   because it is one: it reports an absence and it is not a footnote. */
.withheld {
  list-style: none; margin: .6rem 0 0; padding: 0 0 0 .7rem;
  border-left: 2px solid var(--rule); max-width: 52em;
}
.withheld li { font-size: .84rem; color: var(--ink-2); margin-bottom: .5rem; }
.withheld b { color: var(--ink); font-weight: 620; }

/* --------------------------------------------------- part-to-whole (svg) */

.stack { display: block; margin: .2rem 0 .7rem; }
.seg.lead  { fill: var(--chart-lead); }
.seg.quiet { fill: var(--chart-quiet); }
.seg.none  { fill: var(--chart-none); }
/* Touching marks are separated by a gap in the surface colour, never by a
   border drawn round them. */
.seg-gap { fill: var(--panel); }

.chart-legend { list-style: none; display: flex; flex-wrap: wrap; gap: .4rem 1.3rem; padding: 0; margin: 0; }
.chart-legend li { font-size: .86rem; color: var(--ink-2); display: flex; align-items: baseline; gap: .4rem; flex-wrap: wrap; }
.chart-legend b { font-variant-numeric: tabular-nums; color: var(--ink); }
.chart-legend .legend-note { color: var(--ink-3); font-size: .8rem; }
.swatch { width: .7rem; height: .7rem; border-radius: 2px; display: inline-block; flex: none; align-self: center; }
.swatch.lead  { background: var(--chart-lead); }
.swatch.quiet { background: var(--chart-quiet); }
.swatch.none  { background: var(--chart-none); }

/* ------------------------------------------------- method and table views */

.finding details { margin-top: .9rem; }
.finding summary {
  cursor: pointer; font-size: .85rem; color: var(--accent);
  padding: .2rem 0; width: fit-content;
}
.finding summary:hover { text-decoration: underline; }
details.method p { margin: .5rem 0 0; font-size: .85rem; color: var(--ink-2); max-width: 60em; }
details.inspect { border-top: 1px solid var(--rule-2); padding-top: .5rem; }
details.inspect .grid { margin-top: .7rem; font-size: .85rem; }
details.inspect .grid td { vertical-align: top; }

.quotes { list-style: none; margin: 0; padding: 0; }
.quotes li { padding: .1rem 0; overflow-wrap: anywhere; }
.quotes a { text-decoration: none; font-weight: 560; }
.quotes a:hover { text-decoration: underline; }

/* ----------------------------------------------------------------- company */

.co-header { border-bottom: 1px solid var(--rule); padding-bottom: 1rem; margin-bottom: 1.5rem; }
.co-header h2 { font-size: 1.7rem; }
.co-meta { color: var(--ink-3); font-size: .88rem; margin: .3rem 0 0; }
.co-meta a { margin-right: .9rem; }

.signal-cards { display: grid; gap: .8rem; grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr)); margin-bottom: 2rem; }
.signal-card { background: var(--panel); border: 1px solid var(--rule); border-radius: 8px; padding: .85rem .95rem; }
.signal-card h4 { margin: 0 0 .3rem; font-size: .74rem; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-3); font-weight: 600; }
.signal-card .val { font-size: .95rem; overflow-wrap: anywhere; }
.signal-card .val.none { color: var(--ink-3); font-style: italic; }
.signal-card footer { margin-top: .45rem; font-size: .76rem; color: var(--ink-3); font-family: var(--mono); }
.signal-card.suspect { border-color: var(--warn); }
.signal-card .flag { color: var(--warn); font-weight: 600; }

.timeline { list-style: none; margin: 0; padding: 0 0 0 1.15rem; border-left: 2px solid var(--rule); }
.timeline li { position: relative; padding: 0 0 1.2rem .6rem; }
.timeline li::before {
  content: ""; position: absolute; left: -1.8rem; top: .42rem;
  width: .6rem; height: .6rem; border-radius: 50%;
  background: var(--bg); border: 2px solid var(--accent);
}
.timeline time { display: block; font-size: .78rem; color: var(--ink-3); }

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

footer { border-top: 1px solid var(--rule); padding-top: 2rem; padding-bottom: 3rem; color: var(--ink-2); font-size: .9rem; }
footer h2 { font-size: 1.05rem; margin-bottom: 1rem; }
.cols { display: grid; gap: 1.6rem; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); }
.cols p { margin: 0 0 .6rem; max-width: 44ch; }
.colophon { margin-top: 2rem; color: var(--ink-3); font-size: .84rem; }

@media (max-width: 40rem) {
  .grid thead { display: none; }
  .grid, .grid tbody, .grid tr, .grid td { display: block; width: 100%; }
  .grid tr { border-bottom: 1px solid var(--rule); padding: .6rem 0; }
  .grid td { border: 0; padding: .18rem 0; }
  .grid td::before { content: attr(data-label) ": "; color: var(--ink-3); font-size: .78rem; }
  .grid td.co-name::before { content: ""; }
  .grid .num { text-align: left; }
}

/*
  Narrow screens: the bar drops to its own line under the label rather than
  being squeezed into a column too small to read. The mark never disappears --
  it is the chart -- and the label never truncates.
*/
@media (max-width: 34rem) {
  .bar-row { grid-template-columns: 1fr auto; row-gap: .05rem; padding: .3rem 0; }
  .bar-label { grid-column: 1; grid-row: 1; }
  .bar-value { grid-column: 2; grid-row: 1; }
  .bar-track { grid-column: 1 / -1; grid-row: 2; }
  /* The suppressed row takes the track's place rather than being squeezed into
     a column beside the label, so "too few to say" is never truncated. */
  .share-suppressed { grid-column: 1 / -1; grid-row: 2; }
  .kpis dd { font-size: 1.7rem; }
  .takeaway { font-size: 1rem; }
}

/*
  Forced-colors (Windows high contrast) replaces the palette wholesale, so the
  fills would collapse into one colour. The stacked bars keep their boundaries
  because the 2px separators are drawn in the surface colour, which the mode
  maps to its own background; the counts are in the legend either way.
*/
@media (forced-colors: active) {
  .bar-fill, .seg.lead { fill: Highlight; }
  /* The rail is chrome, so it becomes an outline rather than a fill the mode
     would collapse into the same colour as the mark sitting on it. */
  .share-rail { fill: Canvas; stroke: GrayText; stroke-width: 1; }
  .seg.quiet { fill: GrayText; }
  .seg.none { fill: Canvas; stroke: GrayText; stroke-width: 1; }
  .seg-gap { fill: Canvas; }
  .swatch { border: 1px solid CanvasText; }
}

/* ------------------------------------------------------------ page anatomy */
/*
  The strip is the view's whole argument: one row per company, blocks left to
  right in the order the sections appear. Colour carries the type, and so does
  the text inside every block -- a reader who cannot distinguish the hues still
  reads the sequence, because the label is the content and not a tooltip.
*/
.strips { list-style: none; margin: 1.5rem 0 0; padding: 0; }
.strip-row { padding: .75rem 0; border-top: 1px solid var(--rule, #e5e5e5); }
.strip-row[hidden] { display: none; }
.strip-head { display: flex; gap: .75rem; align-items: baseline; flex-wrap: wrap; }
.strip-meta { color: var(--muted, #666); font-size: .85rem; }
.strip-none { color: var(--muted, #666); font-size: .9rem; margin: .4rem 0 0; }

.strip { display: flex; gap: 2px; margin-top: .45rem; overflow-x: auto; padding-bottom: .2rem; }
.blk {
  flex: 0 0 auto; min-width: 4.5rem; padding: .3rem .5rem; border-radius: 3px;
  font-size: .72rem; line-height: 1.25; display: flex; flex-direction: column; gap: .1rem;
  border: 1px solid rgba(0,0,0,.12); background: #f2f2f2; color: #222;
}
.blk-n { font-variant-numeric: tabular-nums; opacity: .55; font-size: .65rem; }
.blk-t { white-space: nowrap; }

/* One hue per section type. Distinguishable in greyscale by lightness order,
   and never the only carrier of meaning -- the label is always present. */
.blk-hero         { background: #1f2933; color: #fff; border-color: #1f2933; }
.blk-logos        { background: #d9e2ec; }
.blk-proof        { background: #b3d4c4; }
.blk-testimonial  { background: #cfe0b8; }
.blk-pricing      { background: #f3d9a4; }
.blk-faq          { background: #e6d3ef; }
.blk-comparison   { background: #f7c9c0; }
.blk-integrations { background: #c9dcef; }
.blk-features     { background: #e4e7eb; }
.blk-cta          { background: #f9e0b0; }
.blk-media        { background: #ddd6f3; }
.blk-other        { background: #fff; border-style: dashed; color: #666; }

.pos-grid { display: grid; gap: 1.5rem; grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr)); }
.pos h3 { margin: 0 0 .4rem; font-size: 1rem; }

.filters { display: flex; gap: 1rem; align-items: center; flex-wrap: wrap; margin: 1rem 0 0; }
.filters label { display: flex; gap: .4rem; align-items: center; font-size: .9rem; }
.filter-count { color: var(--muted, #666); font-size: .85rem; }

.scales { width: 100%; border-collapse: collapse; margin-top: .75rem; }
.scales th, .scales td { text-align: right; padding: .35rem .5rem; border-bottom: 1px solid var(--rule, #e5e5e5); font-variant-numeric: tabular-nums; }
.scales th[scope="row"], .scales thead th:first-child { text-align: left; }

@media (max-width: 40rem) {
  .blk { min-width: 3.6rem; font-size: .66rem; }
}

/* -------------------------------------------------------- section wireframe */
/*
  The wireframe is a map of one page: a column of blocks in the order the
  sections appear, each one clickable, with the reading beside it in the panel.

  On colour. There are seventeen section types and no seventeen-hue palette is
  honest -- past about eight, categorical colour stops naming things and starts
  decorating them, and a reader has to consult a key to use it, which is a key
  they will not consult. So the palette here is gentle by construction: every
  fill is a pale tint of one of six families in light mode and a dim tint of the
  same six in dark, all within a narrow lightness band, and the type name is
  printed inside the block. The hue is a hint that two blocks are the same kind
  of thing when you scan a column; the word is what tells you which kind. Nobody
  has to learn that green means proof, because it says "Proof".

  The narrow band is also what makes the contrast tractable. One label ink per
  mode sits on all seventeen fills, and every pair is checked rather than
  assumed -- the computed ratio is beside each fill below. The worst pair is
  13.49:1 in light and 10.36:1 in dark, both far past the 4.5:1 the text needs,
  which is the payment for keeping the tints this quiet.

  State is carried by the block's edge and the weight of its label, never by
  hue: hover thickens the edge, focus dashes it, pinned makes it heavy and the
  label bold. That way the four states are told apart in greyscale, in forced
  colours, and by a reader who is not looking at the colour at all.

  Theming follows the file: tokens on :root, overridden under
  prefers-color-scheme: dark. No second mechanism.
*/

:root {
  /* Ratios are label-on-fill, computed against --wf-label (#16181d here). */
  --wf-label: var(--ink);
  --wf-edge: var(--ink-3);        /* 3.82:1 on --bg, 3.02:1 worst on a fill */
  --wf-edge-hover: var(--ink-2);  /* 7.78:1 on --bg, 6.16:1 worst on a fill */
  --wf-edge-strong: var(--ink);   /* 17.02:1 on --bg, 13.49:1 worst on fill */

  --wf-hero:         #dbe1e8;  /* 13.49:1 */
  --wf-logos:        #e3e7ec;  /* 14.30:1 */
  --wf-proof:        #d8e6dd;  /* 13.77:1 */
  --wf-testimonial:  #e0ead6;  /* 14.30:1 */
  --wf-pricing:      #f0e6cf;  /* 14.31:1 */
  --wf-faq:          #e7e0ef;  /* 13.79:1 */
  --wf-comparison:   #f3ddd6;  /* 13.64:1 */
  --wf-integrations: #dae5f1;  /* 13.92:1 */
  --wf-features:     #e6e6e3;  /* 14.20:1 */
  --wf-product:      #dbe8ea;  /* 14.16:1 */
  --wf-resources:    #eae5da;  /* 14.14:1 */
  --wf-awards:       #f0e4c9;  /* 14.08:1 */
  --wf-events:       #e4e0f0;  /* 13.72:1 */
  --wf-security:     #dae7e2;  /* 13.96:1 */
  --wf-cta:          #f4e0c2;  /* 13.77:1 */
  --wf-media:        #e5dff0;  /* 13.65:1 */
  --wf-other:        #f1f0ee;  /* 15.59:1 */
}

@media (prefers-color-scheme: dark) {
  :root {
    /* Chosen for the dark surface, not flipped: a flipped pale tint goes muddy
       and the lightness band drifts. Ratios are against --wf-label (#e9e9ec). */
    --wf-hero:         #2e343c;  /* 10.36:1 */
    --wf-logos:        #272c33;  /* 11.60:1 */
    --wf-proof:        #22312a;  /* 11.25:1 */
    --wf-testimonial:  #293227;  /* 10.97:1 */
    --wf-pricing:      #362f21;  /* 10.93:1 */
    --wf-faq:          #2f2a39;  /* 11.47:1 */
    --wf-comparison:   #3a2a26;  /* 11.26:1 */
    --wf-integrations: #232e3b;  /* 11.36:1 */
    --wf-features:     #2b2c2e;  /* 11.54:1 */
    --wf-product:      #243033;  /* 11.21:1 */
    --wf-resources:    #312c24;  /* 11.43:1 */
    --wf-awards:       #36301e;  /* 10.84:1 */
    --wf-events:       #2c2938;  /* 11.70:1 */
    --wf-security:     #22302c;  /* 11.35:1 */
    --wf-cta:          #3b3121;  /* 10.52:1 */
    --wf-media:        #2e2739;  /* 11.83:1 */
    --wf-other:        #212327;  /* 12.99:1 */

    /* --wf-edge resolves to --ink-3 #7f838c here: 4.80:1 on --bg, 3.30:1 worst
       on a fill. --wf-edge-hover 8.68:1 / 5.98:1, --wf-edge-strong 15.05:1 /
       10.36:1. Every edge stays at or above 3:1 wherever it is drawn. */
  }
}

/*
  Layout. Wireframe left, panel right once there is room for the diagram at its
  natural 320 units and a panel wide enough to read; stacked below that. figure
  carries a 40px default margin in every browser, which on a 375px screen is the
  one thing that would push the page sideways -- so it goes first.
*/
.wf-figure {
  margin: 1.5rem 0 2rem;
  display: grid;
  gap: 1.1rem;
  align-items: start;
}

@media (min-width: 52rem) {
  .wf-figure { grid-template-columns: minmax(0, 320px) minmax(0, 1fr); gap: 1.75rem; }
}

/*
  The SVG has a viewBox, so it scales. It is capped at its natural width so the
  11px labels render at 11px on any screen wide enough to hold it; narrower than
  that they shrink with the diagram, which is why they are a locator and not the
  text -- the panel below carries the reading, in HTML, at the reader's size.
*/
.wf {
  display: block;
  width: 100%;
  max-width: 320px;
  height: auto;
}

.wf-sec { cursor: pointer; }

.wf-sec rect {
  fill: var(--wf-other);
  stroke: var(--wf-edge);
  stroke-width: 1;
  transition: stroke 180ms ease-out, stroke-width 180ms ease-out, fill 180ms ease-out;
}

.wf-sec text {
  fill: var(--wf-label);
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 500;
  user-select: none;
  transition: font-weight 180ms ease-out;
}

.wf-t-hero         rect { fill: var(--wf-hero); }
.wf-t-logos        rect { fill: var(--wf-logos); }
.wf-t-proof        rect { fill: var(--wf-proof); }
.wf-t-testimonial  rect { fill: var(--wf-testimonial); }
.wf-t-pricing      rect { fill: var(--wf-pricing); }
.wf-t-faq          rect { fill: var(--wf-faq); }
.wf-t-comparison   rect { fill: var(--wf-comparison); }
.wf-t-integrations rect { fill: var(--wf-integrations); }
.wf-t-features     rect { fill: var(--wf-features); }
.wf-t-product      rect { fill: var(--wf-product); }
.wf-t-resources    rect { fill: var(--wf-resources); }
.wf-t-awards       rect { fill: var(--wf-awards); }
.wf-t-events       rect { fill: var(--wf-events); }
.wf-t-security     rect { fill: var(--wf-security); }
.wf-t-cta          rect { fill: var(--wf-cta); }
.wf-t-media        rect { fill: var(--wf-media); }

/* "Other" is the classifier shrugging. A dashed edge says so without a colour
   and without a label the block does not have room for. */
.wf-t-other rect { fill: var(--wf-other); stroke-dasharray: 3 2; }

/* Hover: the edge thickens and darkens. Nothing moves, because a block that
   grows under the pointer moves the block below it and the reader loses the
   row they were aiming at. */
.wf-sec:hover rect { stroke: var(--wf-edge-hover); stroke-width: 1.75; }
.wf-sec:hover text { font-weight: 600; }

/*
  Pinned: heavy solid edge and a bold label. Distinguishable from hover by
  weight rather than hue, and readable at a glance down a column of blocks
  because it is the only one whose label is bold when the pointer is elsewhere.
*/
.wf-sec[aria-pressed="true"] rect {
  stroke: var(--wf-edge-strong);
  stroke-width: 2.5;
  stroke-dasharray: none;
}
.wf-sec[aria-pressed="true"] text { font-weight: 700; }

/*
  Focus. outline on an SVG <g> is drawn by some browsers and quietly dropped by
  others, so the ring that has to be there is a stroke on the rect -- dashed, so
  it reads as focus and not as pinned, and in --wf-edge-strong, which is 13.49:1
  at worst against the seventeen fills in light and 10.36:1 in dark. The outline
  is kept as well, offset outside the block, where it is drawn: two rings where
  the browser cooperates, one guaranteed ring where it does not. Never removed.
*/
.wf-sec:focus-visible {
  outline: 2px solid var(--wf-edge-strong);
  outline-offset: 2px;
}
.wf-sec:focus-visible rect {
  stroke: var(--wf-edge-strong);
  stroke-width: 2.5;
  stroke-dasharray: 4 2.5;
}

/* A pinned block that also has focus keeps its bold label, so both states are
   still legible at once. */

/* ---------------------------------------------------------------- the panel */

.wf-panel {
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 8px;
  padding: .9rem 1rem;
  min-width: 0;
  min-height: 9rem;
}
.wf-panel:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* Scoped to the panel on purpose: src/anatomy-svg.js also emits class="wf-empty"
   on the SVG <text> of the no-sections drawing, and an unscoped font-size leaks
   into it. Two authors, one class name, found during integration. */
.wf-panel .wf-empty { margin: 0; color: var(--ink-2); font-size: .92rem; font-style: italic; }

/*
  Measured against judged. These are two different kinds of statement and the
  panel is the only place a reader can tell them apart, so the difference is
  structural rather than decorative: measured items are counted off a solid
  rule with a filled marker and set in the body ink; judged items come off a
  dashed rule with a hollow marker, one step back in the ink scale. The dashed
  rule is the same device the file already uses for an absence -- the classifier
  behind the judged list is right about half the time, and half a fact is closer
  to a missing one than to a counted one.
*/
.wf-measured,
.wf-judged {
  list-style: none;
  margin: 0;
  padding: 0 0 0 1.15rem;
  max-width: 52em;
}
.wf-measured { margin-top: .2rem; border-left: 2px solid var(--rule); }
.wf-judged   { margin-top: 1.1rem; border-left: 2px dashed var(--rule); }

.wf-measured li,
.wf-judged li {
  position: relative;
  margin-bottom: .45rem;
  padding-left: 1rem;
  font-size: .88rem;
  overflow-wrap: anywhere;
}
.wf-measured li {
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.wf-judged li {
  color: var(--ink-2);
}

.wf-measured li::before,
.wf-judged li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .48em;
  width: .45rem;
  height: .45rem;
}
.wf-measured li::before { background: var(--ink-2); border-radius: 1px; }
.wf-judged li::before   { border: 1px dashed var(--ink-3); border-radius: 50%; }

.wf-measured b { font-weight: 620; }
.wf-judged b { font-weight: 600; color: var(--ink); }

/* The warning about what the judged list is worth. Set like the coverage note
   -- a rule and the warn ink, 5.14:1 on --panel in light and 7.60:1 in dark --
   rather than a filled banner, because it is true of every panel on the page
   and a banner that is always there is a banner nobody reads. */
.wf-caveat {
  margin: 1.1rem 0 0;
  padding-left: .7rem;
  border-left: 2px solid var(--warn);
  color: var(--warn);
  font-size: .82rem;
  max-width: 52em;
}

@media (max-width: 34rem) {
  .wf-panel { padding: .8rem .85rem; }
  .wf-measured li, .wf-judged li { font-size: .86rem; }
}

/* Reduced motion: every transition added above, off. The state changes still
   happen, they just happen at once. */
@media (prefers-reduced-motion: reduce) {
  .wf-sec rect,
  .wf-sec text { transition: none; }
}

/*
  Forced colours replaces the seventeen fills with one, which is fine, because
  the type was never in the fill -- it is the word inside the block. What has to
  survive is the edge, so the four states are redrawn in system colours: the
  dash patterns and stroke widths already carry them.
*/
@media (forced-colors: active) {
  .wf-sec rect { fill: Canvas; stroke: CanvasText; }
  .wf-sec text { fill: CanvasText; }
  .wf-sec:hover rect { stroke: Highlight; }
  .wf-sec[aria-pressed="true"] rect { stroke: Highlight; stroke-width: 3; }
  .wf-sec:focus-visible rect { stroke: Highlight; }
  .wf-measured li::before { background: CanvasText; }
  .wf-judged li::before { border-color: GrayText; }
}

/* ---- section wireframe: the explorer's own chrome
   ------------------------------------------------------------------------
   The rules above style a figure containing exactly an <svg> and a .wf-panel,
   which is what the build used to emit. The explorer adds a caption and a
   page-level fact list to the same grid, so without placement they land in
   whichever cell auto-flow reaches next and the layout scrambles. These rules
   place the extra children and style the controls; nothing above is changed. */

#anatomy-explorer { margin-top: 2.5rem; }

.wf-controls {
  display: flex; flex-wrap: wrap; gap: .75rem 1rem; align-items: center;
  margin: 1.25rem 0 0; padding: .75rem .9rem;
  background: var(--panel); border: 1px solid var(--rule); border-radius: 8px;
}
.wf-controls label { display: flex; align-items: center; gap: .4rem; font-size: .9rem; color: var(--ink-2); }
.wf-controls input[type="search"], .wf-controls select {
  font: inherit; font-size: .9rem; padding: .35rem .5rem;
  border: 1px solid var(--rule); border-radius: 5px; background: var(--bg); color: var(--ink);
  min-height: 2.25rem;                 /* comfortable target without being a button */
}
.wf-controls input[type="search"] { min-width: 12rem; }
.wf-controls select { max-width: 18rem; }
.wf-controls button {
  font: inherit; min-width: 2.5rem; min-height: 2.25rem;   /* >=44px with the label box */
  border: 1px solid var(--rule); border-radius: 5px;
  background: var(--bg); color: var(--ink); cursor: pointer;
}
.wf-controls button:hover { border-color: var(--ink-3); }
.wf-count { margin-left: auto; font-size: .85rem; color: var(--ink-2); font-variant-numeric: tabular-nums; }

/* Visually hidden but available to a screen reader. */
.wf-sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* The caption names the company and spans the whole figure; the page-level
   facts sit under the panel, not beside the diagram. */
.wf-figure > .wf-cap { grid-column: 1 / -1; display: flex; gap: .6rem; align-items: baseline; flex-wrap: wrap; }
.wf-cap a { font-weight: 600; font-size: 1.05rem; }
.wf-cap-meta { color: var(--ink-2); font-size: .85rem; }

.wf-page {
  margin: 0; padding-left: 1.1rem; list-style: none;
  font-size: .9rem; color: var(--ink-2); line-height: 1.6;
}
.wf-page li { position: relative; }
.wf-page li::before {
  content: ""; position: absolute; left: -1.1rem; top: .55em;
  width: .4rem; height: .4rem; background: var(--ink-3);   /* measured: solid, like .wf-measured */
}
@media (min-width: 52rem) {
  .wf-figure > .wf-page { grid-column: 2; }
}

.wf-noscript { color: var(--ink-2); font-size: .92rem; }

/* ---- similarity map
   ------------------------------------------------------------------------
   A force layout of every readable page. The palette is deliberately almost
   monochrome: a dot's POSITION already carries the only claim being made, and
   colouring 180 dots by segment would invite reading cluster colour as a
   finding when the clusters are shapes, not markets. Selection is carried by
   size and ring, not hue, so it survives greyscale and forced-colors. */

.wf-map-wrap { display: grid; gap: 1.25rem; align-items: start; margin-top: 1.25rem; }
@media (min-width: 58rem) {
  .wf-map-wrap { grid-template-columns: minmax(0, 1fr) minmax(0, 20rem); gap: 1.75rem; }
}

.wf-map {
  display: block; width: 100%; height: auto;
  background: var(--panel); border: 1px solid var(--rule); border-radius: 8px;
}

.wf-map-link { stroke: var(--ink-3); stroke-opacity: .22; stroke-width: 1; }

.wf-map-node {
  fill: var(--ink-2);
  stroke: var(--panel);
  stroke-width: 1.5;
  cursor: pointer;
  transition: r 150ms ease-out, fill 150ms ease-out;
}
.wf-map-node:hover { fill: var(--ink); r: 7; }

/* Focus has to survive on top of a dot that may sit over a link line, so it is
   a ring drawn in the ink colour rather than a browser outline on an SVG node,
   which renders inconsistently. */
.wf-map-node:focus-visible {
  outline: none;
  fill: var(--ink);
  stroke: var(--accent);
  stroke-width: 3;
  r: 7.5;
}
/* Selected: bigger and ringed. Size and ring, never colour alone. */
.wf-map-node.on {
  fill: var(--ink);
  stroke: var(--ink);
  stroke-width: 3;
  r: 8;
}

@media (prefers-reduced-motion: reduce) {
  .wf-map-node { transition: none; }
}
@media (forced-colors: active) {
  .wf-map-node { fill: CanvasText; stroke: Canvas; }
  .wf-map-node.on, .wf-map-node:focus-visible { stroke: Highlight; }
  .wf-map-link { stroke: CanvasText; }
}

.wf-map-shape {
  margin: .2rem 0 .8rem; font-size: .85rem; color: var(--ink-2);
  overflow-wrap: anywhere;
}
#wf-map-panel .wf-judged li { display: flex; gap: .5rem; align-items: baseline; flex-wrap: wrap; }

/* ---- the archetype homepage
   ------------------------------------------------------------------------
   A composite page as a stack of bands. The fill length is prevalence, and it
   is doubled by the printed percentage so the meaning never rests on the bar
   alone. Bands are not coloured by type: this is one page, not a legend, and
   17 hues would invite reading colour as a finding. */

.arch { list-style: none; margin: 1.5rem 0 0; padding: 0; border: 1px solid var(--rule); border-radius: 10px; overflow: hidden; }
.arch-band { display: grid; grid-template-columns: 8px 1fr; border-top: 1px solid var(--rule); }
.arch-band:first-child { border-top: 0; }

/* The prevalence rail down the left edge: a spine for the page diagram. */
.arch-bar { background: var(--bg); position: relative; }
.arch-fill { position: absolute; left: 0; top: 0; bottom: 0; width: 0; background: var(--ink-3); }

.arch-body { padding: .85rem 1rem; min-width: 0; }
.arch-head { display: flex; gap: .75rem; align-items: baseline; flex-wrap: wrap; }
.arch-name { font-weight: 600; font-size: 1.05rem; }
.arch-share { color: var(--ink-2); font-size: .9rem; }
.arch-share b { color: var(--ink); font-variant-numeric: tabular-nums; }
.arch-meta { margin: .25rem 0 0; color: var(--ink-2); font-size: .85rem; }

/* A fuller band reads as a wider horizontal wash behind the label, so the eye
   gets prevalence from the row itself, not only the number. Kept subtle: the
   percentage is the source of truth. */
.arch-band { position: relative; }
.arch-body::before {
  content: ""; position: absolute; inset: 0 auto 0 8px; width: calc(var(--share) * 1%);
  background: var(--panel); z-index: 0; pointer-events: none;
}
.arch-body > * { position: relative; z-index: 1; }

.arch .inspect { margin-top: .5rem; }

@media (prefers-color-scheme: dark) {
  .arch-body::before { background: color-mix(in srgb, var(--panel) 60%, transparent); }
}
