/* Panelhop design v3: the primitives (web/README.md, Design v3).
   Loaded after site.css on a page with design v3, and on any page whose render used one of these (render.mjs
   renderPage: the scope's `used`). Only class names site.css doesn't have, so on a page that doesn't use them nothing
   here applies; legacy classes are restyled in v3.css, on v3 pages only. The tokens (--card, --r-*, --head-gap …) are
   in site.css :root. */

/* ---------- the source tooltip (lib/ui.mjs fig; components.js initTips) ----------
   A figure (.fig) is the trigger: a number, a value or an exhibit title. Its note (.fig-note) stays in the DOM for text
   extractors, Site Inspector and the markdown twin, but is never shown in place: display:none at rest keeps it out of
   browse mode and of accessible names, while aria-describedby still reads it (a directly referenced hidden node
   counts). The note is either the trigger's last child (a value) or a <p> right after the heading the trigger sits in
   (an exhibit title); its brackets (.fig-p) are for readers without CSS. With JavaScript (html.has-tips) one floating
   tip (.fig-tip, on body) shows the note; without it a hovered or focused value shows its own note as a bubble fixed
   along the bottom of the screen, at every width, so no clipping section (the hero's overflow: hidden) cuts it and no
   figure at a card's right edge pushes it off screen (MR 7 review A11Y-1: a bubble under its figure ran up to 196px past
   the screen on the industry pages, and the hero cut its chips' notes): from the left edge on a wider screen, the full
   width on a phone. Both are flat: a 1px --ink-line-strong edge, no shadow. On a touch screen the trigger has the
   pointer cursor, which is also what makes iOS Safari send it the tap. */
.fig { cursor: help; text-decoration: none; }
@media (hover: none) {
  .fig { cursor: pointer; }
}
.fig-note { display: none; }
html:not(.has-tips) .fig:is(:hover, :focus-visible, :focus-within) > .fig-note { display: block; position: fixed; z-index: 30; left: 12px; right: auto; top: auto; bottom: calc(12px + env(safe-area-inset-bottom, 0px)); width: max-content; max-width: min(480px, calc(100vw - 24px)); padding: 10px 14px; border: 1px solid var(--ink-line-strong); border-radius: 12px; background: var(--ink); color: var(--on-ink); font: 500 .875rem/1.45 var(--f-brand); letter-spacing: 0; text-align: left; text-transform: none; white-space: normal; }
@media (max-width: 560px) {
  html:not(.has-tips) .fig:is(:hover, :focus-visible, :focus-within) > .fig-note { right: 12px; width: auto; max-width: none; }
}
html:not(.has-tips) .fig-note .fig-p { display: none; }
/* :focus-within above keeps a bubble open while its source link has focus, so Tab reaches the link */
.fig-note a { color: inherit; }

/* The floating tip (components.js): fixed on body, so no overflow:hidden ancestor clips it, placed above its trigger
   (below when there's no room) and kept between the header and the bottom of the screen; its words (.fig-tip-t)
   scroll when there are more than fit. Ink on any background, flat (no shadow: brand/guidelines/visual.md), its edge
   the ink theme's line, --ink-line-strong (as the nav dropdown's), which shows against ink. It stays open while the
   pointer is on it (WCAG 1.4.13): an invisible bridge (::before, placed by components.js: --bl, --bw, --bh) spans the
   gap to the trigger. Esc closes it. On a touch phone it is a line along the bottom of the screen, or along the top,
   under the header, when its trigger is down there (data-dock="top", at --tip-top). */
.fig-tip { position: fixed; z-index: 90; left: 0; top: 0; width: max-content; max-width: min(360px, calc(100vw - 32px)); padding: 11px 15px 12px; border: 1px solid var(--ink-line-strong); border-radius: 14px; background: var(--ink); color: var(--on-ink); font: 500 .875rem/1.45 var(--f-brand); letter-spacing: 0; text-align: left; text-wrap: pretty; }
.fig-tip[hidden] { display: none; }
.fig-tip-t { overflow-y: auto; overscroll-behavior: contain; }
/* the note's source link (components.js tipContent): the tip's own text colour, told apart by its underline (thicker
   on hover); keyboard focus (Tab from the trigger) rings it in lime, as on any charcoal ground */
.fig-tip a { color: inherit; text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; }
.fig-tip a:hover { text-decoration-thickness: 2px; }
.fig-tip :focus-visible { outline-color: var(--lime); outline-offset: 2px; border-radius: 2px; }
.fig-tip::before { content: ""; position: absolute; left: var(--bl, 0); width: var(--bw, 0); height: var(--bh, 0); }
.fig-tip[data-side="above"]::before { top: 100%; }
.fig-tip[data-side="below"]::before { bottom: 100%; }
@media (prefers-reduced-motion: no-preference) {
  .fig-tip { animation: fig-tip-in .14s ease-out; }
}
@keyframes fig-tip-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@media (max-width: 560px) and (hover: none) {
  .fig-tip { left: 12px !important; right: 12px; top: auto !important; bottom: calc(12px + env(safe-area-inset-bottom, 0px)); width: auto; max-width: none; padding: 14px 16px; font-size: .9375rem; }
  .fig-tip[data-dock="top"] { top: var(--tip-top, 84px) !important; bottom: auto; }
  .fig-tip-t { max-height: 40vh; }
  .fig-tip::before { content: none; }
}
@media (forced-colors: active) {
  .fig-tip, html:not(.has-tips) .fig:is(:hover, :focus-visible, :focus-within) > .fig-note { border-color: CanvasText; }
}

/* ---------- icons (lib/icons.mjs): 24-unit line icons in the text colour, sized by their width/height ---------- */
svg.ic { display: inline-block; flex: none; max-width: none; vertical-align: -0.2em; }

/* ---------- the section head (lib/ui.mjs sectionHead) ----------
   DOM order h2, label, lede (chunkers keep the label with its section); the grid shows the label first. Layouts:
   stack (label, title, lede in one column), split (label and title on the left, the lede beside them, aligned to the
   bottom) and side (the head in a column of its own beside the section's blocks, .section-body: the FAQ). The gap
   below the head is --head-gap. */
.section-head:is(.head-stack, .head-split, .head-side) { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0; max-width: none; margin-bottom: var(--head-gap); }
.section-head:is(.head-stack, .head-split, .head-side) > .eyebrow { order: -1; margin-bottom: 24px; }
.section-head:is(.head-stack, .head-split, .head-side) > .lede { margin-top: 24px; }
.section-head.head-stack { max-width: 900px; }
@media (min-width: 901px) {
  .section-head.head-split { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); column-gap: clamp(40px, 6vw, 96px); align-items: end; }
  .section-head.head-split > .eyebrow { grid-column: 1; grid-row: 1; }
  .section-head.head-split > h2 { grid-column: 1; grid-row: 2; }
  .section-head.head-split > .lede { grid-column: 2; grid-row: 1 / span 2; align-self: end; justify-self: end; max-width: 440px; margin-top: 0; }
  .section-head.head-split:not(:has(> .eyebrow)) > .lede { grid-row: 2; }
  .wrap:has(> .section-head.head-side) { display: grid; grid-template-columns: minmax(0, 380px) minmax(0, 760px); justify-content: space-between; column-gap: clamp(40px, 6vw, 100px); align-items: start; }
  .section-head.head-side { margin-bottom: 0; }
}
.section-body { min-width: 0; }
/* The head's link (headLink: home's "See services and deliverables"): after the lede, under it on a phone; from 901px
   at the head's right, level with the bottom of the title (stack, which then takes the row's width) or under the lede
   (split) */
.section-head > .head-link { margin: 24px 0 0; }
@media (min-width: 901px) {
  .section-head.head-stack.has-link { max-width: none; grid-template-columns: minmax(0, 900px) auto; justify-content: space-between; column-gap: 40px; align-items: end; }
  .section-head.head-stack.has-link > :not(.head-link) { grid-column: 1; }
  .section-head.head-stack.has-link > .head-link { grid-column: 2; grid-row: 1 / span 3; margin: 0; }
  .section-head.head-split > .head-link { grid-column: 2; justify-self: end; }
}

/* ---------- a disclosure's line beside a button row (components.mjs moreLink; group.besideButtons) ----------
   services.html: "See all 32 checks" with its chevron, 24px after the Book button, in the disclosure line's own type
   (.more-sum, below). The disclosure it opens, further down, is put away while it is closed once components.js's 'more'
   tool runs (is-live), so the line shows once; without the script both lines show and the link goes down to it. */
.more-link { display: inline-flex; align-items: center; gap: 8px; font-size: 1.0625rem; font-weight: 700; line-height: 1.3; color: inherit; text-decoration: none; }
.more-link:hover > span { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 4px; }
.more-link:focus-visible { border-radius: 4px; }
.more.is-far.is-live:not([open]) { display: none; }
.row:has(> .more-link) { column-gap: 24px; }

/* ---------- a button's icon before its label (render.mjs button: button.icon, e.g. play) ----------
   16px, and still on hover: site.css nudges a button's svg, which is right for the arrow after a label only. By its
   own class: an icon after a label (the tiles' More button's arrow, an .ic too) keeps site.css's 18px and its nudge */
.btn > .ic-lead { width: 16px; height: 16px; }
.btn:hover > .ic-lead { transform: none; }

/* ---------- tag variants (the chip sizes are v3.css's .tag; .tag-lime and .tag-warn are site.css's) ----------
   Written with .tag, so each beats v3.css's .tag and .ink .tag (one class more), which come later */
.tag.tag-line { background: transparent; border: 1px solid var(--line-strong); color: var(--text-2); }
.tag.tag-solid { background: var(--ink); color: var(--paper); }
.tag.tag-ink { background: var(--ink-3); color: var(--on-ink); }
.ink .tag.tag-line { background: transparent; border-color: var(--ink-line-2); color: var(--on-ink-2); }
.ink .tag.tag-solid { background: var(--lime); color: var(--ink); }

/* ---------- a chart's key under it (render.mjs keyRows, v3): the foot rows that aren't a source ---------- */
.exhibit-key { display: flex; flex-direction: column; gap: 4px; margin: 0; font-size: var(--t-small); line-height: 1.5; color: var(--text-2); }
.ink .exhibit-key { color: var(--on-ink-2); }

/* ---------- the video's duration chip (render.mjs video, v3): on the poster, ink-3 with a clock ---------- */
.video-dur { gap: 8px; }
.video-dur .ic { color: var(--on-ink-2); }

/* ======================================================================================================================
   The components (MR 4; lib/components.mjs, components.js TOOLS): one delimited block each, below the primitives.
   ====================================================================================================================== */

/* ---------- the range field (a tool's slider; components.js bindRange) ----------
   The label and its live value (<output>) on one line, the range under them, then an optional scale (.range-ticks,
   aria-hidden: each tick placed at its value's step, --at from 0 to 1). Styled only inside .range-field, so the legacy
   calculator's sliders (site.css input[type="range"]) don't change. A 4px track filled up to the thumb (--p, which
   the server writes for the default and components.js repaints) and a 24px thumb: ink ringed in the card colour on
   paper, lime ringed in ink on ink (--rf-* below). The server renders the input disabled; it looks the same. */
.range-field { --rf-fill: var(--ink); --rf-rest: var(--line); --rf-thumb: var(--ink); --rf-ring: var(--card); --rf-label: var(--text-2); --rf-tick: var(--muted); display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: end; column-gap: 16px; }
.ink .range-field { --rf-fill: var(--lime); --rf-rest: var(--ink-line-2); --rf-thumb: var(--lime); --rf-ring: var(--ink); --rf-label: var(--on-ink-2); --rf-tick: var(--on-ink-label); }
.range-field > label { padding-bottom: .3em; font-size: 1rem; font-weight: 600; line-height: 1.35; color: var(--rf-label); }
.range-field > output { font-size: 2.125rem; font-weight: 800; line-height: 1; letter-spacing: -0.04em; font-variant-numeric: tabular-nums; white-space: nowrap; }
.range-field > input[type="range"] { grid-column: 1 / -1; display: block; width: 100%; height: 24px; margin: 16px 0 0; background: transparent; cursor: pointer; }
.range-field > input[type="range"]:disabled { cursor: default; }
.range-field input[type="range"]::-webkit-slider-runnable-track { height: 4px; border-radius: 4px; background: linear-gradient(90deg, var(--rf-fill) var(--p, 50%), var(--rf-rest) var(--p, 50%)); }
.range-field input[type="range"]::-moz-range-track { height: 4px; border-radius: 4px; background: var(--rf-rest); }
.range-field input[type="range"]::-moz-range-progress { height: 4px; border-radius: 4px; background: var(--rf-fill); }
.range-field input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; box-sizing: border-box; width: 24px; height: 24px; margin-top: -10px; border: 4px solid var(--rf-ring); border-radius: 50%; background: var(--rf-thumb); }
.range-field input[type="range"]::-moz-range-thumb { box-sizing: border-box; width: 24px; height: 24px; border: 4px solid var(--rf-ring); border-radius: 50%; background: var(--rf-thumb); }
/* the focus ring goes round the thumb, where the eye is: lime-deep on paper, lime on ink (outside the thumb's ink ring,
   so it reads apart from the lime thumb). Forced colours drop box-shadow: there the input gets a Highlight outline */
.range-field input[type="range"]:focus-visible { outline: none; }
.range-field input[type="range"]:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 2px var(--lime-deep); }
.range-field input[type="range"]:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 2px var(--lime-deep); }
.ink .range-field input[type="range"]:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 2px var(--lime); }
.ink .range-field input[type="range"]:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 2px var(--lime); }
/* the scale: the first tick reads from the track's start, the last ends at its end, the rest are centred on their step */
.range-ticks { grid-column: 1 / -1; position: relative; height: 1.4em; margin-top: 10px; font-size: .8125rem; font-weight: 600; line-height: 1.4; color: var(--rf-tick); font-variant-numeric: tabular-nums; }
.range-ticks > span { position: absolute; top: 0; left: calc(12px + (100% - 24px) * var(--at, 0)); translate: -50% 0; white-space: nowrap; }
.range-ticks > span:first-child { left: 0; translate: none; }
.range-ticks > span:last-child { left: auto; right: 0; translate: none; }
@media (forced-colors: active) {
  .range-field input[type="range"]::-webkit-slider-runnable-track { background: CanvasText; }
  .range-field input[type="range"]::-webkit-slider-thumb { background: Highlight; border-color: Canvas; }
  .range-field input[type="range"]:focus-visible { outline: 2px solid Highlight; outline-offset: 2px; }
}
/* below 360px (320px is the reflow width) the scale's labels get smaller, so the first two never touch */
@media (max-width: 359px) {
  .range-ticks { font-size: .6875rem; }
}

/* ---------- toggle pills (a tool's filter chips: button.pill.pill-toggle[aria-pressed]) ----------
   Pressed: an ink fill on paper, lime on ink. v3.css gives every pressed .pill the same on v3 pages; these carry it to
   a v2 page that uses a tool. */
.pill.pill-toggle { cursor: pointer; font: inherit; font-size: .9375rem; font-weight: 600; }
.pill.pill-toggle[aria-pressed="true"] { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.ink .pill.pill-toggle[aria-pressed="true"] { background: var(--lime); border-color: var(--lime); color: var(--ink); }

/* ---------- the founder card (components.mjs founderCard) ----------
   One person: a 132px round photo, the kicker, the name line and a sentence, then their experience chips and the
   LinkedIn link on the right. Below 900px the chips and the link go under the words; below 560px everything stacks.
   A card on paper and paper-2; ink-2 on ink. The photo is never a frog, so no disc. */
.founder { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; grid-template-areas: "photo text side"; align-items: center; column-gap: 32px; padding: 40px 44px; border: 1px solid var(--line); border-radius: var(--r-tool); background: var(--card); color: var(--text); }
.founder-photo { grid-area: photo; display: block; width: 132px; height: 132px; border-radius: 50%; object-fit: cover; background: var(--paper-3); }
.founder-text { grid-area: text; max-width: 560px; }
.founder-kicker { margin: 0; font-size: var(--t-small); font-weight: 700; line-height: 1.4; color: var(--lime-deep); }
.founder-text h3 { margin: 8px 0 0; font-size: clamp(1.625rem, 1.38rem + .75vw, 2rem); font-weight: 700; line-height: 1.15; letter-spacing: -0.02em; }
.founder-text > p:not(.founder-kicker) { margin: 12px 0 0; font-size: var(--t-body, 1.0625rem); line-height: 1.55; color: var(--text-2); }
.founder-side { grid-area: side; display: flex; flex-direction: column; align-items: flex-end; gap: 20px; margin-left: 16px; }
.founder-chips { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; margin: 0; padding: 0; list-style: none; }
.founder-chips > .tag { min-height: 34px; padding: 6px 14px; border-radius: var(--r-pill); font-family: var(--f-brand); font-size: .9375rem; font-weight: 600; line-height: 1.3; letter-spacing: 0; text-transform: none; }
.founder-link { margin: 0; }
.founder .link-arrow { gap: 10px; padding-bottom: 0; border-bottom: 0; font-size: 1.0625rem; font-weight: 700; color: inherit; white-space: nowrap; }
.founder .link-arrow .ic { transition: translate .2s ease; }
.founder .link-arrow:hover .ic { translate: 3px 0; }
.ink .founder { border-color: var(--ink-line); background: var(--ink-2); color: var(--on-ink); }
.ink .founder-kicker { color: var(--lime); }
.ink .founder-text > p:not(.founder-kicker) { color: var(--on-ink-2); }
@media (max-width: 900px) {
  .founder { grid-template-columns: auto minmax(0, 1fr); grid-template-areas: "photo text" ". side"; row-gap: 24px; padding: 32px; }
  .founder-side { align-items: flex-start; margin-left: 0; }
  .founder-chips { justify-content: flex-start; }
}
@media (max-width: 560px) {
  .founder { grid-template-columns: minmax(0, 1fr); grid-template-areas: "photo" "text" "side"; row-gap: 20px; padding: 26px 22px 28px; border-radius: 24px; }
  .founder-photo { width: 96px; height: 96px; }
}
@media (prefers-reduced-motion: reduce) {
  .founder .link-arrow .ic { transition: none; }
}

/* ---------- the deal-size slider (components.mjs acvSlider; components.js TOOLS.acv) ----------
   A tool card: the sliders on the left (.calc-in), the motion bands, the three numbers and the advice on the right
   (.calc-out, a shade darker). From 1100px the two sit side by side; below, the results go under the sliders; below
   560px it is one card, the bands three compact chips and the numbers rows (label left, number right). The current band is lime
   with ink text on both themes. The numbers never squeeze: each number keeps its width (a label wraps instead, its
   own width not counted: contain inline-size) and a number that doesn't fit beside the others goes to the next row. */
.calc { display: grid; grid-template-columns: minmax(0, 1fr); border: 1px solid var(--line); border-radius: var(--r-tool); background: var(--card); color: var(--text); overflow: hidden; }
.calc-in { display: flex; flex-direction: column; gap: 40px; padding: 52px 48px 56px; }
.calc-out { display: flex; flex-direction: column; padding: 52px 56px; background: var(--paper-2); }
.ink .calc { border-color: var(--ink-line); background: var(--ink-2); color: var(--on-ink); }
.ink .calc-out { background: var(--ink-3); }
@media (min-width: 1100px) {
  .calc { grid-template-columns: minmax(0, 500fr) minmax(0, 740fr); }
}
.calc-head { display: flex; flex-direction: column; gap: 8px; }
.calc-head h3 { margin: 0; }
.acv-calc .range-field.is-lead > output { font-size: clamp(2.75rem, 2.2rem + 1.6vw, 3.5rem); }
.acv-calc .range-field.is-lead + .range-field { margin-top: 8px; }
.motion-steps { display: grid; grid-template-columns: repeat(var(--n, 3), minmax(0, 1fr)); gap: 8px; margin: 0; padding: 0; list-style: none; }
.motion-steps > li { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding: 16px 18px; border: 1px solid var(--line-strong); border-radius: var(--r-tile); color: var(--text-2); }
.ms-name { font-size: 1.375rem; font-weight: 800; line-height: 1.25; letter-spacing: -0.01em; }
.ms-sub { font-size: .875rem; font-weight: 600; line-height: 1.4; }
/* a band's range never breaks at its dash, and the separator stays with the motion word (a no-break space after it) */
.ms-range { white-space: nowrap; }
.motion-steps > li.is-on { border-color: var(--lime); background: var(--lime); color: var(--ink); }
.ink .motion-steps > li { border-color: var(--ink-line-2); color: var(--on-ink-2); }
.ink .motion-steps > li.is-on { border-color: var(--lime); color: var(--ink); }
.motion-steps .fig:focus-visible { outline-color: currentColor; }
.calc-kpis { display: flex; flex-wrap: wrap; column-gap: 32px; row-gap: 28px; margin: 48px 0 0; }
.calc-kpis > div { display: flex; flex: 1 1 0; flex-direction: column-reverse; justify-content: flex-end; gap: 8px; min-width: max-content; }
.calc-kpis dt { contain: inline-size; font-size: .9375rem; font-weight: 500; line-height: 1.4; color: var(--text-2); }
.calc-kpis dd { margin: 0; font-size: clamp(2rem, 1.6rem + 1.1vw, 2.5rem); font-weight: 800; line-height: 1; letter-spacing: -0.04em; font-variant-numeric: tabular-nums; white-space: nowrap; }
.calc-kpis .is-key dd { color: var(--lime-deep); }
.ink .calc-kpis dt { color: var(--on-ink-2); }
.ink .calc-kpis .is-key dd { color: var(--lime); }
.calc.is-below .calc-kpis dd { color: var(--muted); }
.ink .calc.is-below .calc-kpis dd { color: var(--on-ink-2); }
.calc-advice { max-width: 560px; margin: 48px 0 0; padding-top: 28px; border-top: 1px solid var(--line); font-size: 1.125rem; line-height: 1.55; color: var(--text-2); }
.ink .calc-advice { border-top-color: var(--ink-line-2); color: var(--on-ink-2); }
/* forced colours drop the lime fill: the current band takes the system highlight instead */
@media (forced-colors: active) {
  .motion-steps > li.is-on { forced-color-adjust: none; border-color: Highlight; background: Highlight; color: HighlightText; }
}
.calc-advice strong { color: var(--text); }
.ink .calc-advice strong { color: var(--on-ink); }
@media (max-width: 1099px) {
  .calc-in { padding: 40px 40px 44px; }
  .calc-out { padding: 40px; }
}
@media (max-width: 560px) {
  .calc { border-radius: 24px; }
  .calc-in { gap: 32px; padding: 26px 22px 32px; }
  /* one card on a phone, as the mockup draws it: the results under the sliders on the same ground */
  .calc-out { padding: 0 22px 28px; background: transparent; }
  .ink .calc-out { background: transparent; }
  .range-field > label { font-size: .9375rem; }
  .range-field > output { font-size: 1.875rem; }
  .acv-calc .range-field.is-lead > output { font-size: 2.75rem; }
  .motion-steps > li { align-items: center; justify-content: center; gap: 0; padding: 9px 8px; border-radius: var(--r-pill); text-align: center; }
  .ms-name { font-size: 1rem; font-weight: 700; }
  .ms-sub { font-size: .75rem; }
  .ms-sep, .ms-motion { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
  .calc-kpis { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; margin-top: 28px; padding-top: 24px; border-top: 1px solid var(--line); }
  .ink .calc-kpis { border-top-color: var(--ink-line-2); }
  .calc-kpis > div { flex-direction: row; align-items: baseline; justify-content: space-between; gap: 16px; min-width: 0; }
  .calc-kpis dt { contain: none; font-size: .9375rem; }
  /* a row's label stands alone here (wider, it reads on from the number above it): sentence case */
  .calc-kpis dt::first-letter { text-transform: uppercase; }
  .calc-kpis dd { font-size: 1.875rem; }
  .calc-advice { margin-top: 28px; padding-top: 24px; font-size: 1rem; }
}

/* ---------- product UI mocks (components.mjs uiMock) ----------
   Example product UI, drawn in HTML: an alert, an account brief, a scorecard, a forecast, a funnel or a report. The
   first four are the product's own screen (.mock-screen: charcoal ink-2 with the ink line, on any ground, as the
   mockups draw them on paper too); a report is a printed page (a card, ink-2 on charcoal); a funnel takes the section's
   ground. The tag (.mock-tag) is the one sticker a v3 page keeps. A frog avatar sits on a paper square with a 2px lime
   border, never straight on charcoal. Lime highlights in an alert's headline are .mock-hl (site.css's .hl is lime-deep
   text, for paper). The actions are drawn, not controls. */
.mock { min-width: 0; margin: 0; }
.mock.mock-screen { padding: 36px 40px; border: 1px solid var(--ink-line-2); border-radius: var(--r-card); background: var(--ink-2); color: var(--on-ink); }
.mock-head { display: flex; align-items: center; justify-content: space-between; gap: 8px 12px; margin: 0; }
.mock-title { margin: 0; font-size: 1.25rem; font-weight: 800; line-height: 1.3; letter-spacing: -0.01em; }
.mock-head .mock-tag { flex: none; }
.mock-sub { margin: 6px 0 0; font-size: .9375rem; line-height: 1.45; color: var(--text-2); }
.ink .mock-sub { color: var(--on-ink-2); }
.mock-screen .mock-sub { color: var(--on-ink-label); }
.mock-hl { color: var(--lime); font-weight: 800; }

/* the alert: the avatar beside the message */
.mock-alert.mock-screen { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start; gap: 16px; padding: 28px 30px; }
.al-avatar { display: flex; align-items: center; justify-content: center; width: 48px; height: 48px; border: 2px solid var(--lime); border-radius: 12px; background: var(--paper); }
.al-avatar img { display: block; width: 34px; height: 34px; object-fit: contain; }
.al-body { min-width: 0; }
.al-top { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; margin: 0; line-height: 1.3; }
.al-app { font-size: 1.0625rem; font-weight: 800; }
.al-apptag { display: inline-flex; align-items: center; height: 22px; padding: 0 8px; border-radius: var(--r-pill); background: var(--ink-3); font-size: .75rem; font-weight: 600; color: var(--on-ink); }
.al-time { font-size: .875rem; color: var(--on-ink-label); }
.al-top .mock-tag { margin-left: auto; }
.al-text { margin: 10px 0 0; font-size: 1.125rem; line-height: 1.45; }
.al-text b { font-weight: 800; }
.al-signals { display: flex; flex-direction: column; gap: 12px; margin: 20px 0 0; padding: 18px 20px; border-radius: 14px; background: var(--ink-3); list-style: none; font-size: 1rem; line-height: 1.4; }
.al-signals li { display: flex; justify-content: space-between; gap: 16px; }
.al-signals b, .br-signals b { flex: none; color: var(--lime); font-weight: 800; font-variant-numeric: tabular-nums; }
.al-group { display: flex; align-items: flex-start; gap: 8px; margin: 16px 0 0; font-size: .9375rem; line-height: 1.4; color: var(--on-ink-2); }
.al-group .ic { margin-top: 2px; }
.al-acts { display: flex; flex-wrap: wrap; gap: 12px; margin: 24px 0 0; }
.mock-act { display: inline-flex; align-items: center; min-height: 44px; padding: 0 20px; border: 1.5px solid var(--ink-line-2); border-radius: var(--r-pill); font-size: .9375rem; font-weight: 700; color: var(--on-ink); }
.mock-act.is-primary { border-color: var(--lime); background: var(--lime); color: var(--ink); }

/* the account brief: the account and its score ring, why now, the buying group, the first touch, the foot */
.mock-brief.mock-screen { padding: 0; overflow: hidden; }
.br-top { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 26px 32px; border-bottom: 1px solid var(--ink-line-2); }
.br-tag { white-space: nowrap; }
.br-line { margin: 0; font-size: .8125rem; font-weight: 700; line-height: 1.4; color: var(--on-ink-label); }
.br-co { margin: 6px 0 0; font-size: 1.5rem; font-weight: 800; line-height: 1.2; letter-spacing: -0.01em; }
.br-sub { margin: 2px 0 0; font-size: .9375rem; line-height: 1.4; color: var(--on-ink-2); }
.br-score { display: flex; flex: none; flex-direction: column; align-items: center; justify-content: center; width: 88px; height: 88px; margin: 0; border: 3px solid var(--lime); border-radius: 50%; }
.br-score b { font-size: 2rem; font-weight: 800; line-height: 1; letter-spacing: -0.04em; font-variant-numeric: tabular-nums; }
.br-score span { margin-top: 2px; font-size: .6875rem; font-weight: 700; color: var(--on-ink-label); }
.br-body { padding: 26px 32px; }
.br-h { margin: 26px 0 0; font-size: .875rem; font-weight: 700; color: var(--on-ink-2); }
.br-h:first-child { margin-top: 0; }
.br-signals { display: flex; flex-direction: column; gap: 12px; margin: 12px 0 0; padding: 0; list-style: none; font-size: 1rem; line-height: 1.4; }
.br-signals li { display: flex; align-items: baseline; gap: 12px; }
.br-age { flex: none; min-width: 64px; color: var(--on-ink-label); white-space: nowrap; }
.br-what { flex: 1; min-width: 0; }
.br-roles { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0 0; padding: 0; list-style: none; }
.br-roles li { display: inline-flex; align-items: center; min-height: 30px; padding: 3px 12px; border: 1px solid var(--ink-line-2); border-radius: var(--r-pill); font-size: .875rem; font-weight: 600; color: var(--on-ink-2); }
.br-roles li.is-mapped { border-color: var(--lime); background: var(--lime); color: var(--ink); }
.br-touch { margin: 8px 0 0; padding: 16px 18px; border-radius: 12px; background: var(--ink-3); font-size: 1rem; line-height: 1.55; }
.br-end { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 6px 16px; margin: 0; padding: 18px 32px; background: var(--ink-3); font-size: .875rem; line-height: 1.4; color: var(--on-ink-2); }

/* the scorecard: an HTML track per area (--v, the score's share of 5), warn under the threshold */
.score-rows { display: flex; flex-direction: column; gap: 20px; margin: 32px 0 0; padding: 0; list-style: none; }
.score-rows li { display: grid; grid-template-columns: minmax(0, 170px) minmax(48px, 1fr) 2.25rem; align-items: center; gap: 16px; }
.score-area { font-size: .9375rem; font-weight: 600; line-height: 1.3; }
/* in an industry section an area that takes two lines takes two of about the same length, never one word alone */
.ind-section .score-area { text-wrap: balance; }
.score-track { display: block; height: 12px; border-radius: 12px; background: var(--ink-3); overflow: hidden; }
.score-track i { display: block; width: calc(var(--v, 0) * 100%); height: 100%; border-radius: 12px; background: var(--paper); }
.score-n { text-align: right; font-weight: 800; font-variant-numeric: tabular-nums; }
.score-rows li.is-low .score-track i { background: var(--warn-on-ink); }
.score-rows li.is-low .score-n { color: var(--warn-on-ink); }
.score-call { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin: 32px 0 0; padding-top: 24px; border-top: 1px solid var(--ink-line-2); font-size: .9375rem; line-height: 1.45; color: var(--on-ink-2); }
.score-call .tag.tag-lime { flex: none; background: var(--lime); color: var(--ink); }

/* the forecast: a real table, ticks lime and crosses warn, the evidence share right-aligned; the totals under it */
.mock-forecast.mock-screen { padding: 32px 34px; container-type: inline-size; }
.fc-wrap { margin: 20px 0 0; overflow-x: auto; }
/* while it scrolls it is in the tab order (components.js initScrollers): a lime ring on the charcoal screen */
.fc-wrap:focus-visible { outline: 2px solid var(--lime); outline-offset: 4px; border-radius: 4px; }
.fc-table { width: 100%; border-collapse: collapse; font-size: 1rem; line-height: 1.35; }
.fc-table thead th { padding: 0 10px 10px 0; font-size: .875rem; font-weight: 700; color: var(--on-ink-label); text-align: left; vertical-align: bottom; }
.fc-table tbody th, .fc-table tbody td { padding: 16px 10px 16px 0; border-top: 1px solid var(--ink-line); text-align: left; vertical-align: middle; }
.fc-table tbody th { font-weight: 700; }
.fc-table .fc-ev { padding-right: 0; text-align: right; }
.fc-table tbody .fc-ev { font-weight: 800; color: var(--lime); font-variant-numeric: tabular-nums; }
.fc-table tbody tr.is-warn .fc-ev { color: var(--warn-on-ink); }
.fc-yes { color: var(--lime); }
.fc-no { color: var(--warn-on-ink); }
.fc-yes .ic, .fc-no .ic { display: block; }
/* a narrow forecast (a phone, a narrow column): each deal's value under its name, the check heads hyphenated, tighter cells */
@container (max-width: 460px) {
  .fc-table { font-size: .9375rem; hyphens: auto; }
  .fc-table thead th { padding-right: 6px; font-size: .75rem; }
  .fc-table tbody th, .fc-table tbody td { padding: 14px 6px 14px 0; }
  .fc-deal { white-space: nowrap; }
  .fc-val { display: block; font-weight: 600; color: var(--on-ink-2); }
  .fc-sep { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
}
.fc-sum { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 6px 16px; margin: 16px 0 0; padding: 16px 18px; border-radius: 12px; background: var(--ink-3); font-size: .9375rem; line-height: 1.4; color: var(--on-ink-2); }
.fc-sum b { color: var(--on-ink); font-weight: 800; }
.fc-sum .is-key b { color: var(--lime); }

/* the funnel: a bar per step (--w, on a log scale), never narrower than its words; the accent step lime */
.mock-funnel > .mock-head { justify-content: flex-start; margin-bottom: 14px; }
.funnel-steps { display: flex; flex-direction: column; gap: 10px; margin: 0; padding: 0; list-style: none; }
.funnel-steps li { box-sizing: border-box; display: flex; align-items: center; justify-content: space-between; gap: 16px; width: var(--w, 100%); min-width: fit-content; max-width: 100%; min-height: 52px; padding: 8px 20px; border: 1px solid var(--line); border-radius: 12px; background: var(--card); font-size: .9375rem; line-height: 1.3; color: var(--text-2); }
.funnel-steps b { font-size: 1rem; font-weight: 800; color: var(--text); font-variant-numeric: tabular-nums; }
.ink .funnel-steps li { border-color: var(--ink-2); background: var(--ink-2); color: var(--on-ink-2); }
.ink .funnel-steps b { color: var(--on-ink); }
.funnel-steps li.is-accent, .ink .funnel-steps li.is-accent { border-color: var(--lime); background: var(--lime); font-weight: 700; color: var(--ink); }
.funnel-steps li.is-accent b { color: var(--ink); }
/* in an industry section a step takes the width components.mjs works out (funnelFit, --e: its share or its words' width,
   whichever is wider, never wider than the step above), its words wrapping when the step above leaves them less room */
.ind-section .funnel-steps li { width: var(--e, var(--w, 100%)); min-width: min-content; }

/* the report: a column per month, its stages stacked to the total (--h), the first stage lime in the last column */
.mock-report { padding: 36px 40px; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card); color: var(--text); }
.ink .mock-report { border-color: var(--ink-line); background: var(--ink-2); color: var(--on-ink); }
.mock-report { --ps-1: var(--ink); --ps-2: var(--text-2); --ps-3: var(--line-strong); --ps-4: var(--paper-3); --ps-5: var(--paper-2); }
/* on charcoal the stages run from paper to the ink ring. With four stages (the mockup's), each against the next and the
   last against the card (ink-2): 1.9:1, 1.6:1, 2.5:1 and 2.0:1 on a v3 page (where on-ink-3 is the label grey), and
   1.9:1, 1.8:1, 2.2:1 and 2.0:1 on a v2 page. A fifth stage (ink-3) is 1.7:1 from the fourth and 1.2:1 from the card,
   so on charcoal a report keeps to four (the Studio says so). The 1px separators in the card's colour part them too */
.ink .mock-report { --ps-sep: var(--ink-2); --ps-1: var(--on-ink); --ps-2: var(--on-ink-2); --ps-3: var(--on-ink-3); --ps-4: var(--ink-ring); --ps-5: var(--ink-3); }
.prog-cols { display: grid; grid-template-columns: repeat(var(--n, 5), minmax(0, 1fr)); gap: 18px; margin: 32px 0 0; padding: 0; list-style: none; }
.prog-col { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.prog-stack { display: flex; flex-direction: column; justify-content: flex-end; height: 240px; overflow: hidden; }
.prog-stack i { box-sizing: border-box; display: block; flex: none; height: var(--h, 0); }
.prog-stack i + i { border-top: 1px solid var(--ps-sep, var(--card)); }
.prog-m { font-size: .9375rem; font-weight: 600; line-height: 1.3; text-align: center; color: var(--muted); }
.ink .prog-m { color: var(--on-ink-2); }
/* the key: its items are words in a line that wraps in balanced lines (a half-width card at 1024px: two and two, not
   three and one); the last line's 8px under it is taken back */
.prog-key { margin: 24px 0 -8px; padding: 0; list-style: none; font-size: .9375rem; font-weight: 600; line-height: 1.4; color: var(--muted); text-wrap: balance; }
.prog-key li { display: inline-block; margin: 0 20px 8px 0; white-space: nowrap; }
.ink .prog-key { color: var(--on-ink-2); }
.prog-key i { display: inline-block; width: 12px; height: 12px; margin-right: 8px; border-radius: 3px; vertical-align: -1px; }
.prog-key i + i { margin-left: -4px; }
.ink .prog-key i { outline: 1px solid var(--ink-line-2); outline-offset: -1px; }
.prog-stack .ps-1, .prog-key .ps-1 { background: var(--ps-1); }
.prog-stack .ps-2, .prog-key .ps-2 { background: var(--ps-2); }
.prog-stack .ps-3, .prog-key .ps-3 { background: var(--ps-3); }
.prog-stack .ps-4, .prog-key .ps-4 { background: var(--ps-4); }
.prog-stack .ps-5, .prog-key .ps-5 { background: var(--ps-5); }
/* lime marks the newest month's first stage (Customer, M4): the key draws that stage's swatch and a lime one beside it */
.prog-col:last-child .ps-1, .prog-key .ps-now { background: var(--lime); }

/* the timeline (MR 8a; vendor-type.html's term window): a card (56px in, 28px round) whose tag sits in its corner; the
   ticks along the top with a line down each through the track; the track (44px, paper-2) at 96px with its bars (ink,
   their words in the widest stretch outside a window) and its windows (lime, 16px proud of the track, the chip 14px
   above); the marks 36px under the track in up to 2 rows (components.mjs timelineRows), each a 14px dot, the title and a
   line, 23% of the track wide, ending at its mark near the track's end. A narrow card (under 640px) keeps the ticks
   and the track, writes the bars' words and the end tick under the track, and lists the marks under them, each dot on
   the track too */
.mock-timeline { position: relative; container-type: inline-size; padding: 56px 56px 48px; border: 1px solid var(--line); border-radius: 28px; background: var(--card); color: var(--text); }
.ink .mock-timeline { border-color: var(--ink-line); background: var(--ink-2); color: var(--on-ink); }
.mock-timeline > .mock-head { position: absolute; top: 18px; right: 24px; }
.tl { --tl-track: 96px; position: relative; padding-top: 176px; }
.tl-ticks { position: absolute; inset: 0 0 auto; height: 178px; margin: 0; padding: 0; list-style: none; }
.tl-ticks li { position: absolute; top: 0; left: var(--at); font-size: .9375rem; font-weight: 700; line-height: 1.4; color: var(--muted); white-space: nowrap; }
.tl-ticks li::after { content: ''; position: absolute; left: 0; top: 28px; width: 1px; height: 150px; background: var(--line); }
.tl-ticks li.is-end { left: auto; right: 0; color: var(--text); }
.tl-ticks li.is-end::after { content: none; }
.tl-ticks li.tl-today { top: calc(var(--tl-track) - 26px); transform: translateX(-100%); padding-right: 8px; font-size: .8125rem; color: var(--text-2); }
.tl-ticks li.tl-today::after { left: auto; right: 0; top: 0; height: 70px; border-left: 1px dashed var(--text-2); width: 0; background: none; }
.ink .tl-ticks li { color: var(--on-ink-3); }
.ink .tl-ticks li.is-end, .ink .tl-ticks li.tl-today { color: var(--on-ink); }
.ink .tl-ticks li::after { background: var(--ink-line); }
/* a tick whose words would run into the next tick's on this card, or into the end tick's, keeps its line and drops its
   words (components.mjs timelineTicks: .is-mute-wide on a wide card, .is-mute-narrow on a narrow one) */
.tl-ticks li.is-mute-wide { visibility: hidden; }
.tl-ticks li.is-mute-wide::after, .tl-ticks li.is-mute-narrow::after { visibility: visible; }
/* Today's words in a row of their own, between the ticks' words and the chips, where over the track they would meet a
   window or its chip (components.mjs timelineModel todayRow): the track 24px lower, and the words on the card's ground,
   so a tick's line never runs through them */
.tl.has-today-row { --tl-track: 120px; padding-top: 200px; }
.has-today-row .tl-ticks { height: 202px; }
.has-today-row .tl-ticks li::after { height: 174px; }
.has-today-row .tl-ticks li.tl-today { top: 30px; background: var(--card); }
.has-today-row .tl-ticks li.tl-today::after { height: 134px; }
.ink .has-today-row .tl-ticks li.tl-today { background: var(--ink-2); }
.tl-track { position: absolute; left: 0; right: 0; top: var(--tl-track); height: 44px; border-radius: 12px; background: var(--paper-2); }
.ink .tl-track { background: var(--ink-3); }
.tl-seg { position: absolute; top: 0; bottom: 0; left: var(--from); width: calc(var(--to) - var(--from)); margin: 0; border-radius: 12px; background: var(--ink); color: var(--paper); }
.ink .tl-seg { background: var(--paper); color: var(--ink); }
.tl-seg-k { position: absolute; top: 0; bottom: 0; left: var(--l); width: var(--w); display: flex; align-items: center; padding: 0 20px; overflow: hidden; font-size: 1rem; font-weight: 700; line-height: 1.15; }
.tl-win { position: absolute; top: -16px; bottom: -16px; left: var(--from); width: calc(var(--to) - var(--from)); margin: 0; border-radius: 14px; background: var(--lime); }
.tl-win-k { position: absolute; left: 0; bottom: calc(100% + 14px); display: inline-flex; align-items: center; height: 30px; padding: 0 14px; border-radius: 999px; background: var(--ink); color: var(--lime); font-size: .8125rem; font-weight: 600; line-height: 1; white-space: nowrap; }
.ink .tl-win-k { background: var(--lime); color: var(--ink); }
.tl-dots { display: none; }
.tl-marks { display: grid; grid-template-columns: minmax(0, 1fr); row-gap: 24px; margin: 0; padding: 0; list-style: none; }
.tl-mark { grid-row: var(--r, 1); grid-column: 1; display: flex; flex-direction: column; align-items: flex-start; width: 23%; margin-left: var(--at); font-size: .9375rem; line-height: 1.4; color: var(--muted); }
.tl-mark::before { content: ''; flex: none; width: 14px; height: 14px; border-radius: 50%; background: var(--ink); }
.tl-mark b { margin-top: 8px; font-size: 1rem; font-weight: 700; line-height: 1.35; color: var(--text); }
.tl-mark.is-end { justify-self: end; align-items: flex-end; margin-left: 0; margin-right: calc(100% - var(--at)); text-align: right; }
.tl-mark.is-win::before { background: var(--lime-deep); }
.tl-mark.is-passed { opacity: .72; }
.tl-mark.is-passed::before { background: var(--line-strong); }
.ink .tl-mark { color: var(--on-ink-3); }
.ink .tl-mark b { color: var(--on-ink); }
.ink .tl-mark::before { background: var(--on-ink); }
.ink .tl-mark.is-win::before { background: var(--lime); }
@container (max-width: 639px) {
  /* the ticks' words on their own row, the window's chip between them and the track */
  .tl { --tl-track: 84px; padding-top: 182px; }
  .tl-ticks { height: 124px; }
  .tl-ticks li { font-size: .75rem; }
  .tl-ticks li::after { top: 22px; height: 100px; }
  .tl-ticks li.is-mute-wide { visibility: visible; }
  .tl-ticks li.is-mute-narrow { visibility: hidden; }
  /* the end tick and the bars' words under the track */
  .tl-ticks li.is-end { top: calc(var(--tl-track) + 50px); }
  .tl-ticks li.tl-today { top: calc(var(--tl-track) - 22px); font-size: .75rem; }
  .tl-ticks li.tl-today::after { height: 58px; }
  .tl-track { height: 36px; border-radius: 10px; }
  /* the bar's fill is its ::before here, so its words, under the track, sit on the card's ground and not inside a dark
     box (what a reader, and the contrast check, takes their ground from) */
  .tl-seg { border-radius: 10px; background: none; color: var(--text); }
  .tl-seg::before { content: ''; position: absolute; inset: 0; border-radius: inherit; background: var(--ink); }
  .ink .tl-seg { background: none; color: var(--on-ink); }
  .ink .tl-seg::before { background: var(--paper); }
  .tl-seg-k { top: calc(100% + 14px); bottom: auto; left: 0; width: max-content; max-width: 70cqi; padding: 0; overflow: visible; font-size: .8125rem; color: var(--text); }
  .ink .tl-seg-k { color: var(--on-ink); }
  .tl-seg-k::before { content: ''; display: inline-block; flex: none; width: 10px; height: 10px; margin-right: 8px; border-radius: 3px; background: var(--ink); }
  .ink .tl-seg-k::before { background: var(--paper); }
  .tl-win { top: -10px; bottom: -10px; border-radius: 12px; }
  .tl-win-k { bottom: calc(100% + 8px); height: 26px; padding: 0 10px; font-size: .75rem; }
  .tl-dots { display: block; position: absolute; inset: 0; pointer-events: none; }
  .tl-dots i { position: absolute; top: 50%; left: var(--at); width: 12px; height: 12px; margin: -6px 0 0 -6px; border: 2px solid var(--card); border-radius: 50%; background: var(--ink); }
  .tl-dots i.is-win { background: var(--lime-deep); }
  .tl-dots i.is-passed { background: var(--line-strong); }
  .ink .tl-dots i { border-color: var(--ink-3); background: var(--on-ink); }
  .tl-marks { row-gap: 16px; }
  .tl-mark { grid-row: auto; display: grid; grid-template-columns: 14px minmax(0, 1fr); column-gap: 12px; width: auto; margin: 0; }
  .tl-mark::before { grid-row: 1 / span 2; margin-top: 4px; }
  .tl-mark b { margin-top: 0; }
  /* a mark near the end lists as the others do: its dot beside its title, not its last line */
  .tl-mark.is-end { justify-self: stretch; align-items: flex-start; margin-right: 0; text-align: left; }
  /* Today's own row: the track 16px lower */
  .tl.has-today-row { --tl-track: 100px; padding-top: 198px; }
  .has-today-row .tl-ticks { height: 140px; }
  .has-today-row .tl-ticks li::after { height: 116px; }
  .has-today-row .tl-ticks li.tl-today { top: 24px; }
  .has-today-row .tl-ticks li.tl-today::after { height: 112px; }
}
@media (max-width: 560px) {
  .mock-timeline { padding: 48px 20px 28px; border-radius: 20px; }
  .mock-timeline > .mock-head { top: 14px; right: 16px; }
}

@media (max-width: 560px) {
  .mock.mock-screen, .mock-report { padding: 24px 20px; border-radius: 20px; }
  /* the avatar beside the app's line only; the message under both, full width (the body's parts join the grid) */
  .mock-alert.mock-screen { align-items: center; gap: 14px 12px; padding: 22px 20px; }
  .mock-alert .al-body { display: contents; }
  .mock-alert .al-body > :not(.al-top) { grid-column: 1 / -1; }
  .al-top .mock-tag { margin-left: 0; }
  .al-text { margin-top: 0; }
  .al-avatar { width: 40px; height: 40px; border-radius: 10px; }
  .al-avatar img { width: 28px; height: 28px; }
  .al-text { font-size: 1.0625rem; }
  .al-signals { padding: 14px 16px; font-size: .9375rem; }
  .al-acts .mock-act { flex: 1 1 auto; justify-content: center; }
  .mock-brief.mock-screen { padding: 0; }
  .br-top { padding: 20px; }
  .br-co { font-size: 1.25rem; }
  .br-score { width: 72px; height: 72px; }
  .br-score b { font-size: 1.625rem; }
  .br-body { padding: 20px; }
  .br-age { min-width: 56px; }
  .br-end { padding: 16px 20px; }
  .score-rows { gap: 16px; margin-top: 24px; }
  .score-rows li { grid-template-columns: minmax(0, 8.5rem) minmax(40px, 1fr) 2.25rem; gap: 12px; }
  .mock-forecast.mock-screen { padding: 22px 18px; }
  .fc-table { font-size: .9375rem; }
  .prog-cols { gap: 10px; }
  .prog-stack { height: 180px; }
  .prog-m { font-size: .875rem; }
}
/* forced colours drop the fills that draw the tracks, bars and stacks: outline them instead */
@media (forced-colors: active) {
  .score-track, .funnel-steps li { border: 1px solid CanvasText; }
  /* the report's stages keep apart in system colours: a pattern each, on the bars and in the key alike (the newest
     month's first stage in Highlight); the counts are in words for screen readers and in the twin */
  .prog-stack i, .prog-key i { forced-color-adjust: none; border: 1px solid CanvasText; background: Canvas; }
  .prog-stack .ps-1, .prog-key .ps-1 { background: CanvasText; }
  .prog-stack .ps-2, .prog-key .ps-2 { background: repeating-linear-gradient(45deg, CanvasText 0 2px, Canvas 2px 5px); }
  .prog-stack .ps-3, .prog-key .ps-3 { background: radial-gradient(circle, CanvasText 1px, Canvas 1.5px) 0 0 / 4px 4px; }
  .prog-stack .ps-4, .prog-key .ps-4 { background: Canvas; }
  .prog-stack .ps-5, .prog-key .ps-5 { background: repeating-linear-gradient(0deg, CanvasText 0 1px, Canvas 1px 4px); }
  .prog-col:last-child .ps-1, .prog-key .ps-now { background: Highlight; }
  .score-track i { forced-color-adjust: none; background: CanvasText; }
  .br-roles li.is-mapped { border-width: 2px; }
}

/* ---------- tabs: modules or stages (components.mjs moduleTabs; components.js TOOLS.tabs) ----------
   The list of tabs (in-page links until components.js makes them tabs) and the panels. Without JavaScript every panel
   shows, one after the other; components.js hides all but the open one (the hidden attribute, kept here: a panel is a
   grid). A tab is open when it is aria-selected (is-on, set with it). Two variants:
   - list (the Leak Fix picker): a column of modules beside the open one's card; the open module charcoal with an arrow.
     On a phone the list stacks over the card
   - rail (the home stage rail): a row of 56px pills with icons on a hairline, the open one lime; the panel under it,
     its words on the left and its mock (or, without one, its checklist) on the right. From 1001 to 1099px the pills
     are 18px wide inside, not 26px, so the 7 stages still fit in one row; where the row doesn't fit (up to 1000px) it
     scrolls sideways, edge to edge, each pill joined to the next by the hairline. On a phone the pills are
     home-m.html's chips: 40px, no icons and no hairline. Scrolling, the row fades out at the screen's edge */
.mods { min-width: 0; }
.mod-list { margin: 0; padding: 0; list-style: none; }
.mod-item { min-width: 0; }
.mod-link { display: flex; align-items: center; gap: 10px; text-decoration: none; color: inherit; cursor: pointer; }
.mod-link > span { min-width: 0; }
.mod-panel { min-width: 0; }
.mod-panel[hidden] { display: none; }
.mod-panel:focus-visible { outline-offset: 6px; border-radius: var(--r-ui); }
.mod-top { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px 16px; }
.mod-top h3 { margin: 0; }
.mod-dur { flex: none; }
.mod-text { margin: 20px 0 0; color: var(--text-2); }
.ink .mod-text { color: var(--on-ink-2); }
.mod-ba { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; margin-top: 40px; }
.mod-before, .mod-after { padding: 24px; border-radius: 18px; }
.mod-before { background: var(--paper-2); }
.mod-after { background: var(--lime-tint); color: var(--ink); }
.ink .mod-before { background: var(--ink-3); }
.mod-k { margin: 0; font-size: .9375rem; font-weight: 700; line-height: 1.4; }
.mod-after .mod-k { color: var(--lime-deep); }
.mod-bt { margin: 12px 0 0; font-size: var(--t-h4, 1.1875rem); font-weight: 700; line-height: 1.3; text-wrap: balance; }
.mod-bx { margin: 8px 0 0; font-size: .9375rem; line-height: 1.45; color: var(--muted); }
.mod-after .mod-bx { color: var(--text-2); }
.ink .mod-before .mod-bx { color: var(--on-ink-2); }
.mod-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 24px 32px; margin: 40px 0 0; padding-top: 28px; border-top: 1px solid var(--line); }
.ink .mod-facts { border-top-color: var(--ink-line); }
.mod-facts dt { font-size: .9375rem; font-weight: 700; line-height: 1.4; color: var(--muted); }
.ink .mod-facts dt { color: var(--on-ink-2); }
.mod-facts dd { margin: 8px 0 0; font-size: var(--t-h4, 1.1875rem); font-weight: 700; line-height: 1.3; text-wrap: balance; }
.mod-points { display: flex; flex-direction: column; gap: 16px; margin: 40px 0 0; padding: 0; list-style: none; font-size: 1.0625rem; font-weight: 600; line-height: 1.4; }
.mod-points li { display: flex; align-items: flex-start; gap: 12px; }
.mod-points .ic { flex: none; margin-top: 1px; color: var(--lime-deep); }
.ink .mod-points .ic { color: var(--lime); }

/* the list variant */
.mods-list { display: grid; grid-template-columns: minmax(0, 400px) minmax(0, 1fr); align-items: start; gap: 24px; }
.mods-list .mod-list { display: flex; flex-direction: column; gap: 8px; }
.mods-list .mod-link { justify-content: space-between; min-height: 60px; padding: 10px 22px; border: 1px solid var(--line); border-radius: var(--r-tile); font-weight: 600; line-height: 1.3; }
.mods-list .mod-link .ic { flex: none; opacity: 0; }
.mods-list .mod-link:hover { border-color: var(--line-strong); }
.mods-list .mod-link.is-on { border-color: var(--ink); background: var(--ink); color: var(--paper); font-weight: 700; }
.mods-list .mod-link.is-on .ic { opacity: 1; }
.mods-list .mod-link:focus-visible { border-radius: var(--r-tile); }
.ink .mods-list .mod-link { border-color: var(--ink-line-2); }
.ink .mods-list .mod-link.is-on { border-color: var(--lime); background: var(--lime); color: var(--ink); }
.mods-list .mod-panels { display: flex; flex-direction: column; gap: 24px; min-width: 0; }
.mods-list .mod-panel { padding: 44px 48px; border: 1px solid var(--line); border-radius: var(--r-tool); background: var(--card); }
.ink .mods-list .mod-panel { border-color: var(--ink-line); background: var(--ink-2); }
.mods-list .mod-top h3 { font-size: clamp(1.5rem, 1.3rem + .6vw, 1.875rem); letter-spacing: -0.02em; }
.mods-list .mod-mock { margin-top: 40px; }

/* the rail variant */
.mods-rail .mod-list { --rail-gap: 12px; position: relative; display: flex; justify-content: space-between; gap: var(--rail-gap); }
.mods-rail .mod-list::before { content: ""; position: absolute; left: 20px; right: 20px; top: 50%; height: 2px; margin-top: -1px; background: var(--line); }
.ink .mods-rail .mod-list::before { background: var(--ink-line-2); }
.mods-rail .mod-item { position: relative; flex: none; }
.mods-rail .mod-link { min-height: 56px; padding: 0 26px; border: 1px solid var(--line-strong); border-radius: var(--r-pill); background: var(--card); font-size: 1.0625rem; font-weight: 700; white-space: nowrap; }
.ink .mods-rail .mod-link { border-color: var(--ink-line-2); background: var(--ink-2); color: var(--on-ink); }
.mods-rail .mod-link.is-on, .ink .mods-rail .mod-link.is-on { border-color: var(--lime); background: var(--lime); color: var(--ink); }
.mods-rail .mod-link:focus-visible { border-radius: var(--r-pill); }
.mods-rail .mod-panels { display: flex; flex-direction: column; gap: 64px; margin-top: clamp(48px, 5vw, 80px); }
.mods-rail .mod-panel { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: start; gap: 48px clamp(40px, 6vw, 120px); }
.mods-rail .mod-panel.has-mock { grid-template-columns: minmax(0, 480px) minmax(0, 620px); justify-content: space-between; }
.mods-rail .mod-top h3 { font-size: clamp(1.75rem, 1.4rem + 1vw, 2.125rem); letter-spacing: -0.02em; }
.mods-rail .mod-text { font-size: clamp(1.0625rem, 1rem + .3vw, 1.25rem); line-height: 1.5; }
/* a stage without a mock: its words on the left, its checklist on the right (no empty column) */
.mods-rail .mod-panel:not(.has-mock) { grid-template-rows: auto 1fr; row-gap: 0; }
.mods-rail .mod-panel:not(.has-mock) .mod-main { display: contents; }
.mods-rail .mod-panel:not(.has-mock) .mod-main > :not(.mod-points) { grid-column: 1; }
.mods-rail .mod-panel:not(.has-mock) .mod-text { align-self: start; }
.mods-rail .mod-panel:not(.has-mock) .mod-points { grid-column: 2; grid-row: 1 / span 2; align-self: start; margin-top: 6px; }
/* 1001 to 1099px (a small laptop, an iPad on its side): the row stays whole on its hairline, its pills 18px wide inside */
@media (min-width: 1001px) and (max-width: 1099px) {
  .mods-rail .mod-link { padding: 0 18px; }
}
@media (max-width: 1000px) {
  /* the row scrolls sideways, from the screen's edge to its edge, and fades out over its last 40px, the cue that more
     stages follow (as the blog's chips do); 40px of blank at its end, so the last pill comes out of the fade */
  .mods-rail .mod-list { justify-content: flex-start; margin-inline: calc(-1 * var(--gutter, 16px)); padding: 4px 40px 4px var(--gutter, 16px); overflow-x: auto; scrollbar-width: none; overscroll-behavior-x: contain; -webkit-mask-image: linear-gradient(to left, transparent, #000 40px); mask-image: linear-gradient(to left, transparent, #000 40px); }
  .mods-rail .mod-list::-webkit-scrollbar { display: none; }
  /* the hairline is a join from each pill to the one before it, so it runs with the pills to the row's end (a line
     on the list would be only as wide as the screen) */
  .mods-rail .mod-list::before { content: none; }
  .mods-rail .mod-item + .mod-item::before { content: ""; position: absolute; right: 100%; top: 50%; width: var(--rail-gap); height: 2px; margin-top: -1px; background: var(--line); }
  .ink .mods-rail .mod-item + .mod-item::before { background: var(--ink-line-2); }
}
@media (max-width: 900px) {
  .mods-list { grid-template-columns: minmax(0, 1fr); }
  .mods-rail .mod-panel, .mods-rail .mod-panel.has-mock { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .mods-rail .mod-panel:not(.has-mock) { row-gap: 0; }
  .mods-rail .mod-panel:not(.has-mock) .mod-points { grid-column: 1; grid-row: auto; margin-top: 28px; }
}
@media (max-width: 560px) {
  .mods-list .mod-panel { padding: 28px 22px; border-radius: 24px; }
  .mod-ba { grid-template-columns: minmax(0, 1fr); margin-top: 28px; }
  .mod-before, .mod-after { padding: 20px; }
  .mod-facts { grid-template-columns: minmax(0, 1fr); gap: 18px; margin-top: 28px; padding-top: 22px; }
  /* home-m.html's chips: no icons, no hairline, 8px apart */
  .mods-rail .mod-list { --rail-gap: 8px; }
  .mods-rail .mod-item + .mod-item::before { content: none; }
  .mods-rail .mod-link { min-height: 40px; padding: 0 14px; font-size: .9375rem; }
  .mods-rail .mod-link > .ic { display: none; }
  .mod-points { margin-top: 28px; font-size: 1rem; }
}
@media (forced-colors: active) {
  .mod-link.is-on { forced-color-adjust: none; border-color: Highlight; background: Highlight; color: HighlightText; }
}

/* ---------- card grid variants (components.mjs CARD_VARIANTS; render.mjs cardGrid) ----------
   frogs: the services as cards, the frog on a baseline above the chip, the title (a link) and a line; 4 across, 2 from
   1024px, and on a phone a row that scrolls sideways (snapping, one card and a bit on screen). A frog on a card on
   charcoal sits on a paper disc, a circle at every width (170px, 128px on a phone). tiles: icon tiles, each one link
   (the title's, stretched over the tile), 5 across; highlight is the lime tile, with a charcoal icon box; on a phone
   the tiles it doesn't show (is-more) and the More button swap.
   principles: an icon box, a title and a line, 4 across. The icon box (.ico-box) is a 52px rounded square: paper-2
   with an ink icon on light, ink-3 with a lime one on charcoal. */
.ico-box { display: inline-flex; flex: none; align-items: center; justify-content: center; width: 52px; height: 52px; border-radius: var(--r-tile); background: var(--paper-2); color: var(--ink); }
.ink .ico-box { background: var(--ink-3); color: var(--lime); }

.cards-frogs { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 24px; }
.frog-card { display: flex; flex-direction: column; min-width: 0; padding: 32px 28px; }
.frog-pic { display: flex; align-items: flex-end; height: 170px; }
.frog-pic img { display: block; width: auto; height: auto; max-width: 100%; max-height: 160px; }
.frog-chip { margin: 24px 0 0; font-size: .9375rem; font-weight: 700; line-height: 1.4; color: var(--lime-deep); }
.frog-card h3 { margin: 8px 0 0; font-size: var(--t-h3, 1.5rem); line-height: 1.22; }
.frog-card h3 a { color: inherit; text-decoration: none; }
.frog-card h3 a:hover { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 4px; }
.frog-card p:not(.frog-chip) { margin: 12px 0 0; color: var(--text-2); }
.ink .frog-chip { color: var(--lime); }
.ink .frog-card p:not(.frog-chip) { color: var(--on-ink-2); }
.ink .frog-pic { flex: none; justify-content: center; align-items: center; width: 170px; height: 170px; border-radius: 50%; background: var(--paper); }
.ink .frog-pic img { max-width: 116px; max-height: 116px; }
@media (max-width: 1024px) {
  .cards-frogs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .cards-frogs { display: flex; gap: 12px; margin-inline: calc(-1 * var(--gutter, 16px)); padding: 0 var(--gutter, 16px) 4px; overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-inline: var(--gutter, 16px); scrollbar-width: none; overscroll-behavior-x: contain; }
  .cards-frogs::-webkit-scrollbar { display: none; }
  .frog-card { flex: none; width: min(270px, 78vw); padding: 26px 24px; scroll-snap-align: start; }
  .frog-pic { height: 128px; }
  .frog-pic img { max-height: 120px; }
  .ink .frog-pic { width: 128px; height: 128px; }
  .ink .frog-pic img { max-width: 88px; max-height: 88px; }
  .frog-chip { margin-top: 20px; }
}
/* the dots under the row on a phone (components.js initDots): a dot per card, the one at the row's start long, as
   home-m.html draws them; decorative, so they are no targets */
.frog-dots { display: none; }
@media (max-width: 560px) {
  .frog-dots { display: flex; align-items: center; gap: 8px; margin: 20px 0 0; } /* 24px under the cards, past the row's 4px */
  .frog-dots i { flex: none; width: 6px; height: 6px; border-radius: 6px; background: var(--line-strong); transition: width .2s ease; }
  .frog-dots i.is-on { width: 22px; background: var(--ink); }
  .ink .frog-dots i { background: var(--ink-ring); }
  .ink .frog-dots i.is-on { background: var(--on-ink); }
}
@media (prefers-reduced-motion: reduce) {
  .frog-dots i { transition: none; }
}

.tiles { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); grid-auto-rows: 1fr; gap: 16px; margin: 0; padding: 0; list-style: none; }
.tile { position: relative; display: flex; flex-direction: column; min-width: 0; padding: 24px; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card); color: var(--text); transition: border-color .2s ease; }
.tile-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.tile-top > .ic { color: var(--ink); transition: translate .2s ease; }
.tile h3 { margin: 20px 0 0; font-size: var(--t-h4, 1.1875rem); line-height: 1.3; text-wrap: balance; }
.tile h3 a { color: inherit; text-decoration: none; }
/* the title's link covers the tile: one target, named by the title; the focus ring goes round the tile */
.tile h3 a::after { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: inherit; }
.tile h3 a:focus-visible { outline: none; }
.tile h3 a:focus-visible::after { outline: 2px solid var(--lime-deep); outline-offset: 3px; border-radius: var(--r-card); }
.tiles .nowrap { white-space: nowrap; }
.tile p { margin: 8px 0 0; font-size: 1rem; line-height: 1.45; color: var(--text-2); text-wrap: balance; }
.tile:hover { border-color: var(--line-strong); }
.tile:hover .tile-top > .ic { translate: 3px 0; }
.tile.is-hl { border-color: var(--lime); background: var(--lime); color: var(--ink); }
.tile.is-hl p { color: var(--ink); }
.tile.is-hl .ico-box { background: var(--ink); color: var(--lime); }
.tile.is-hl h3 a:focus-visible::after { outline-color: var(--ink); }
.ink .tile { border-color: var(--ink-line); background: var(--ink-2); color: var(--on-ink); }
.ink .tile p { color: var(--on-ink-2); }
.ink .tile-top > .ic { color: var(--on-ink); }
.ink .tile h3 a:focus-visible::after { outline-color: var(--lime); }
.tiles-more { display: none; margin: 24px 0 0; }
@media (max-width: 1100px) {
  .tiles { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
  .tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* the last row never leaves a tile alone: a lone last tile takes the row's width, and 3 or 4 across (641 to 1100px) the
   last row's tiles share its free columns (10 tiles: 4, 4 and two 2 wide; 3, 3, 3 and one the row's width). Not on a
   phone, where the is-more tiles hide */
@media (min-width: 1101px) {
  .tile:last-child:nth-child(5n+1) { grid-column: 1 / -1; }
}
@media (min-width: 901px) and (max-width: 1100px) {
  .tile:last-child:nth-child(4n+1) { grid-column: 1 / -1; }
  .tile:nth-last-child(2):nth-child(4n+1), .tile:last-child:nth-child(4n+2), .tile:last-child:nth-child(4n+3) { grid-column: span 2; }
}
@media (min-width: 641px) and (max-width: 900px) {
  .tile:last-child:nth-child(3n+1) { grid-column: 1 / -1; }
  .tile:last-child:nth-child(3n+2) { grid-column: span 2; }
}
@media (min-width: 561px) and (max-width: 640px) {
  .tile:last-child:nth-child(2n+1) { grid-column: 1 / -1; }
}
@media (max-width: 640px) {
  .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .tile { padding: 18px; border-radius: 18px; }
  .tile .ico-box { width: 42px; height: 42px; }
  .tile h3 { margin-top: 12px; }
  .tile p { margin-top: 4px; font-size: .9375rem; }
}
@media (max-width: 560px) {
  .tile.is-more { display: none; }
  .tiles-more { display: block; }
  .tiles-more .btn { width: 100%; justify-content: center; }
}
@media (prefers-reduced-motion: reduce) {
  .tile, .tile-top > .ic { transition: none; }
}

.principles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 40px; }
.principle { min-width: 0; }
.principle h3 { margin: 24px 0 0; font-size: var(--t-h4, 1.1875rem); line-height: 1.3; }
.principle p { margin: 8px 0 0; color: var(--text-2); }
.ink .principle p { color: var(--on-ink-2); }
@media (max-width: 1024px) {
  .principles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .principles { grid-template-columns: minmax(0, 1fr); gap: 32px; }
}

/* ---------- stats variants (render.mjs stats; components.mjs STAT_VARIANTS) ----------
   hero: the big numbers three across, a line above them and between them (the home page's problem); on a phone each
   number beside its line, a line between the rows and one under the last, as home-m.html closes the list. compact: a
   strip of small numbers between two lines, three across (the services facts); on a phone one under the other, each
   over its line.
   Written with the row's element classes, so they beat v3.css's sizes, which come later. */
.stats.stats-hero { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.stats.stats-compact { grid-template-columns: repeat(3, minmax(0, 1fr)); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.stats.stats-compact > .stat { gap: 8px; padding: 22px 16px 22px 24px; }
.stats.stats-compact > .stat:first-child { padding-left: 0; }
.stats.stats-compact > .stat > .n.num { font-size: 2.375rem; }
/* In a split's column from 901 to 1099px a cell is 131-161px wide, too narrow for "6 hours" at 38px, so "About 6
   hours" broke into three lines with the 6 alone. There the number shrinks with the screen, 28px at 901 to 38px by
   1099, and takes two lines at most ("About / 6 hours"). */
@media (min-width: 901px) and (max-width: 1099px) {
  .split-even .stats.stats-compact > .stat > .n.num { font-size: clamp(1.75rem, 4.8vw - 15px, 2.375rem); }
}
.stats.stats-compact > .stat > p { max-width: none; font-size: .9375rem; line-height: 1.4; color: var(--muted); }
.ink .stats.stats-compact { border-color: var(--ink-line); }
.ink .stats.stats-compact > .stat > p { color: var(--on-ink-2); }
@media (max-width: 1000px) {
  .stats.stats-hero > .stat:nth-child(3), .stats.stats-compact > .stat:nth-child(3) { border-left: 1px solid var(--line); border-top: 0; }
  .stats.stats-hero > .stat:nth-child(3) { padding-left: 40px; }
  .ink .stats.stats-hero > .stat:nth-child(3), .ink .stats.stats-compact > .stat:nth-child(3) { border-left-color: var(--ink-line); }
}
@media (max-width: 560px) {
  .stats.stats-hero, .stats.stats-compact { grid-template-columns: minmax(0, 1fr); }
  .stats.stats-hero > .stat, .stats.stats-compact > .stat, .stats.stats-hero > .stat:nth-child(3), .stats.stats-compact > .stat:nth-child(3) { flex-direction: row; align-items: center; gap: 20px; padding: 20px 0; border-left: 0; border-top: 1px solid var(--line); }
  .stats.stats-hero > .stat:first-child, .stats.stats-compact > .stat:first-child { border-top: 0; }
  .stats.stats-hero > .stat:last-child { border-bottom: 1px solid var(--line); }
  .stats.stats-hero > .stat > .n.num { flex: none; width: 130px; font-size: 3.5rem; }
  /* a compact number keeps its label under it: their widths differ too much to share a column */
  .stats.stats-compact > .stat, .stats.stats-compact > .stat:nth-child(3) { flex-direction: column; align-items: flex-start; gap: 4px; padding: 16px 0; }
  .stats.stats-compact > .stat > .n.num { font-size: 1.875rem; }
  .ink .stats.stats-hero > .stat, .ink .stats.stats-compact > .stat { border-top-color: var(--ink-line); }
  .ink .stats.stats-hero > .stat:last-child { border-bottom-color: var(--ink-line); }
}

/* ---------- the steps strip (components.mjs stepStrip): numbered circles joined by a line, the first lime ----------
   A step after the first holds the line before it (80px, then its 16px margin and the step's 16px gap): its share
   starts at those 112px, so the line never comes out of its words and every step's words get the same width. The
   words wrap in balanced lines, never leaving one word alone. Up to 1000px the steps stack, one under the other: in
   a row there a step's second line ("within 2 business days") wrapped in two. */
.step-strip { display: flex; align-items: center; margin: 0; padding: 0; list-style: none; counter-reset: none; }
.step-strip > li { display: flex; flex: 1 1 0; align-items: center; gap: 16px; min-width: 0; }
.step-strip > li + li { flex-basis: 112px; }
.step-strip > li + li::before { content: ""; flex: none; width: 80px; height: 2px; margin-right: 16px; background: var(--line); }
.ss-t b, .ss-t span { text-wrap: balance; }
.ss-n { display: flex; flex: none; align-items: center; justify-content: center; width: 44px; height: 44px; border-radius: 50%; background: var(--paper-3); font-size: 1.375rem; font-weight: 800; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; color: var(--ink); }
.step-strip > li:first-child .ss-n { background: var(--lime); }
.ss-t { display: flex; flex-direction: column; min-width: 0; }
.ss-t b { font-size: 1.0625rem; font-weight: 700; line-height: 1.3; }
.ss-t span { font-size: .9375rem; line-height: 1.4; color: var(--muted); }
.ink .step-strip > li + li::before { background: var(--ink-line-2); }
.ink .ss-n { background: var(--ink-3); color: var(--on-ink); }
.ink .step-strip > li:first-child .ss-n { background: var(--lime); color: var(--ink); }
.ink .ss-t span { color: var(--on-ink-2); }
@media (max-width: 1000px) {
  .step-strip { flex-direction: column; align-items: stretch; gap: 0; }
  .step-strip > li, .step-strip > li + li { flex: none; }
  .step-strip > li + li::before { content: none; }
  .step-strip > li + li { margin-top: 20px; }
}

/* ---------- the disclosure (components.mjs disclosure; group layout disclosure): a line with a chevron that opens
   the blocks under it; the chevron turns when open ---------- */
.more { min-width: 0; }
.more-sum { display: inline-flex; align-items: center; gap: 8px; font-size: 1.0625rem; font-weight: 700; line-height: 1.3; cursor: pointer; list-style: none; }
.more-sum::-webkit-details-marker { display: none; }
.more-sum .ic { transition: rotate .2s ease; }
.more[open] > .more-sum .ic { rotate: 180deg; }
.more-sum:hover > span { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 4px; }
.more-sum:focus-visible { border-radius: 4px; }
.more-body { margin-top: 32px; }
@media (prefers-reduced-motion: reduce) {
  .more-sum .ic { transition: none; }
}

/* ---------- a package's flag (render.mjs packages): the lime chip on top, lime with charcoal text on the featured
   (charcoal) card ---------- */
.pkg-flag { align-self: flex-start; }
.pkg.feature .tag.pkg-flag { background: var(--lime); color: var(--ink); }

/* ---------- the home hero's drawing on v3 (components.mjs heroHop) ----------
   The mockup's 520 × 540 drawing, scaled with its column (a container: sizes in cqi): the dotted lime hop path and its
   nodes, the frog at its end on a paper disc with a 3px lime ring, three example cards (.hero-ui, ink-2 with the ink
   line) at the mockup's places in a stage of its proportions, and the tag under the stage. The places are in the
   stage's width (cqi; the mockup's % of its 540px height × 540 / 520), and the lowest card, the routing one, is in the
   flow: where the column is narrow (about 370px at 1001px) and its words wrap, the stage grows to hold it, and the
   tag stays under it rather than behind it. On a phone (560px and less) only the signal and the routing cards show,
   one under the other (the second set in a little), then the tag. */
.hero-hop { display: flex; flex-direction: column; align-items: flex-end; gap: 16px; width: 100%; max-width: 520px; margin: 0 0 0 auto; color: var(--on-ink); }
.hh-stage { position: relative; container-type: inline-size; width: 100%; aspect-ratio: 520 / 540; }
.hh-path { position: absolute; left: 0; top: 0; width: 100%; height: auto; overflow: visible; }
.hh-path path { fill: none; stroke: var(--lime); stroke-width: 3; stroke-dasharray: 1 12; stroke-linecap: round; }
.hh-path circle { fill: var(--ink); stroke: var(--paper); stroke-width: 2.5; }
.hh-path circle.is-on { stroke: var(--lime); }
.hh-frog { position: absolute; left: 80.4%; top: calc(1.5cqi * 540 / 520); display: flex; align-items: center; justify-content: center; width: 20%; aspect-ratio: 1; border: 3px solid var(--lime); border-radius: 50%; background: var(--paper); }
.hh-frog img { display: block; width: 77%; height: auto; }
.hero-ui { position: absolute; padding: 3.5cqi 3.85cqi; border: 1px solid var(--ink-line-2); border-radius: var(--r-ui); background: var(--ink-2); color: var(--on-ink); }
.hero-ui.hu-1 { left: 0; top: calc(7.4cqi * 540 / 520); width: 57.7%; }
.hero-ui.hu-2 { left: 48.1%; top: calc(46.3cqi * 540 / 520); width: 51.9%; }
.hero-ui.hu-3 { left: 25%; top: 74.1%; width: 55.8%; }
@media (min-width: 561px) {
  .hero-ui.hu-3 { position: relative; top: auto; margin-top: calc(74.1cqi * 540 / 520); }
}
.hu-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 0; }
.hu-k { display: inline-flex; align-items: center; gap: 8px; min-width: 0; font-size: clamp(.75rem, 2.5cqi, .8125rem); font-weight: 700; line-height: 1.3; color: var(--on-ink-2); }
.hu-1 .hu-k { color: var(--lime); }
.hu-k .ic { width: 16px; height: 16px; }
.hu-pill { display: inline-flex; flex: none; align-items: center; height: 26px; padding: 0 10px; border-radius: var(--r-pill); background: var(--lime); font-size: .8125rem; font-weight: 700; color: var(--ink); }
.hu-3 .hu-pill { background: var(--lime-tint); color: var(--lime-deep); }
.hu-t { margin: 10px 0 0; font-size: clamp(.9375rem, 3.27cqi, 1.0625rem); font-weight: 700; line-height: 1.35; }
.hu-d { margin: 4px 0 0; font-size: clamp(.8125rem, 2.7cqi, .875rem); line-height: 1.4; color: var(--on-ink-label); }
.hu-prog { display: flex; gap: 8px; margin-top: 12px; }
.hu-prog i { flex: 1; height: 6px; border-radius: 6px; background: var(--ink-line-2); }
.hu-prog i.is-on { background: var(--lime); }
.tag.hh-tag { flex: none; }
@media (max-width: 1000px) {
  .hero-hop { margin: 8px auto 0 0; }
}
@media (max-width: 560px) {
  .hero-hop { align-items: stretch; gap: 12px; max-width: none; margin-top: 0; }
  .hh-stage { display: flex; flex-direction: column; gap: 12px; aspect-ratio: auto; }
  .hh-path, .hh-frog, .hero-ui.hu-2 { display: none; }
  .hero-ui, .hero-ui.hu-1, .hero-ui.hu-3 { position: static; width: auto; padding: 16px 18px; }
  .hero-ui.hu-3 { margin-left: 28px; }
  .hu-t { font-size: 1rem; }
  .tag.hh-tag { align-self: flex-start; }
}
@media (forced-colors: active) {
  .hu-prog i { border: 1px solid CanvasText; }
  .hu-prog i.is-on { forced-color-adjust: none; background: CanvasText; }
}

/* ---------- the services hero on v3 (render.mjs pageHero: .ph-grid and .ph-band) ----------
   services.html: the text and the tiles side by side, centred on each other, then the pills in a band of their own
   along the hero's foot. The grid is in the wrap, so the tiles never sit over the text, whatever its length: from
   1001px they take min(500px, 40vw) beside it (the mockup's 500px from 1250px; 400px at 1001, where the text keeps
   its 465px, the width of the buttons and of "Four services." on one line at that size) with 56px between; below
   1001px they go under the text, up to 500px wide. site.css places a page hero's art over the hero (absolute); in the
   grid it is a cell. */
.ph-grid { display: grid; grid-template-columns: minmax(0, 1fr); }
.ph-grid > .stack { min-width: 0; }
.ph-grid > .hero-art { position: static; transform: none; width: auto; max-width: 500px; margin: clamp(36px, 8vw, 56px) 0 0; }
@media (min-width: 1001px) {
  .ph-grid { grid-template-columns: minmax(0, 1fr) min(500px, 40vw); column-gap: 56px; align-items: center; }
  .ph-grid > .hero-art { max-width: none; margin: 0; }
}
/* the pills' band: the ink line above it and 88px tall (services.html's sub-nav), the hero's bottom space above the
   line; the first pill lime, as the mockup draws it (the service to start with), its colours only (no state) */
.page-hero.has-band { padding-bottom: 0; }
.page-hero.has-band > .wrap { padding-bottom: clamp(48px, 6vw, 80px); }
.ph-band { border-top: 1px solid var(--ink-line); }
.ph-band .pill-row { gap: 12px; align-items: center; min-height: 88px; padding-block: 20px; }
.ph-band .pill.is-lead { border-color: var(--lime); background: var(--lime); color: var(--ink); }

/* ---------- the services hero's tiles on v3 (components.mjs heroServiceTiles; render.mjs HERO_ART.services) ----------
   services.html: a 2 × 2 of product cards (ink-2, the ink line, a 16px radius) in the loop's order, clockwise from the
   top left (Panel Check, Signal Desk, Leak Fix, Panel Ops), each joined to the next by lime dots across the gap between
   them; the first lime-edged, its icon lime and a lime "Start here" chip. Both rows are as tall as the taller one, as
   the mockup draws them, also where a line wraps in a narrow tile (a phone, 1001px to about 1190px); the dots stay
   put, as each card places its own. Placed by .ph-grid above; site.css's .page-hero .hero-art rule sizes every svg in
   it to its width, so the icons say their size here. */
.svc-grid { --gx: 28px; --gy: clamp(40px, 4.8vw, 68px); display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-rows: 1fr; column-gap: var(--gx); row-gap: var(--gy); margin: 0; padding: 0; list-style: none; }
.svc-card { position: relative; display: flex; flex-direction: column; min-width: 0; padding: 24px; border: 1px solid var(--ink-line-2); border-radius: var(--r-ui); background: var(--ink-2); color: var(--on-ink); }
.svc-card.is-first { border-color: var(--lime); }
.svc-card:nth-child(3) { grid-column: 2; grid-row: 2; }
.svc-card:nth-child(4) { grid-column: 1; grid-row: 2; }
.svc-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 24px; margin: 0; color: var(--on-ink-2); }
.svc-card.is-first .svc-top { color: var(--lime); }
.page-hero .hero-svc svg.ic { width: 22px; height: 22px; }
.svc-start { display: inline-flex; flex: none; align-items: center; height: 24px; padding: 0 9px; border-radius: var(--r-pill); background: var(--lime); font-size: .75rem; font-weight: 700; line-height: 1; color: var(--ink); white-space: nowrap; }
.svc-name { margin: 28px 0 0; font-size: 1.25rem; font-weight: 800; line-height: 1.4; letter-spacing: -0.01em; }
.svc-line { margin: 4px 0 0; font-size: .875rem; line-height: 1.5; color: var(--on-ink-label); }
.svc-line .nowrap { white-space: nowrap; }
/* the dots, from each tile to the next across the gap (none from a last tile with no next) */
.svc-card::after { content: ""; position: absolute; pointer-events: none; background: radial-gradient(circle, var(--lime) 1.3px, transparent 1.8px) center / 10px 10px; }
.svc-card:nth-child(odd)::after { top: 50%; width: var(--gx); height: 10px; translate: 0 -50%; background-repeat: repeat-x; }
.svc-card:nth-child(1)::after { left: 100%; }
.svc-card:nth-child(3)::after { right: 100%; }
.svc-card:nth-child(even)::after { left: 50%; width: 10px; height: var(--gy); translate: -50% 0; background-repeat: repeat-y; }
.svc-card:nth-child(2)::after { top: 100%; }
.svc-card:nth-child(4)::after { bottom: 100%; }
.svc-card:last-child:not(:nth-child(4))::after { content: none; }
/* From 561px (beside the text from 1001px; under it, as wide, at 768) a tile is services.html's, 168px tall where no
   line wraps: the icon row 33px with the 24px icon at its top and the chip centred in it (the mockup's icon is inline
   in a line of the body's 18px / 1.55), the name and the line at the body's 1.55. The dots across a row sit at the
   name's height, where the mockup's dotted loop crosses the gap: 24px padding, the 33px row, the name's 28px margin
   and half its line. A phone keeps the rule below. */
@media (min-width: 561px) {
  .svc-top { min-height: 33px; }
  .svc-top > svg.ic { align-self: flex-start; }
  .page-hero .hero-svc svg.ic { width: 24px; height: 24px; }
  .svc-name { line-height: 1.55; }
  .svc-line { line-height: 1.55; }
  .svc-card:nth-child(odd)::after { top: calc(85px + 1.25rem * 1.55 / 2); }
}
@media (max-width: 560px) {
  .svc-grid { --gx: 20px; --gy: 32px; }
  .svc-card { padding: 16px; }
  .svc-name { margin-top: 18px; font-size: 1.0625rem; }
}
@media (forced-colors: active) {
  .svc-card::after { forced-color-adjust: none; background-image: radial-gradient(circle, CanvasText 1.3px, transparent 1.8px); }
}

/* ---------- the signal cards (components.mjs signalCards; components.js TOOLS.signals) ----------
   The filter (toggle pills, All first; rendered hidden, shown by components.js) with its count line at the row's end,
   on the baseline of the pills' first row (so it stays level with that row when the pills wrap),
   then a card per signal: the kind as a lime tag, when to act with a clock (its figure's note a tooltip), the signal,
   and the play under a line. 3 across, 2 from 1024px, one column on a phone (TECH-PLAN 4c). Each card spans three of
   the grid's rows as a subgrid (head, signal, play), so a head whose timing wraps under the chip moves the whole row's
   signals down with it: the h3s and the plays of a row stay level, and every card is as tall as its row. The timing
   sits at the head's end when it fits and starts under the chip when it doesn't. A card the filter leaves out is
   hidden (the hidden attribute, kept here: the card is a grid). */
.signals { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; column-gap: 24px; }
.signal-filter { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 32px; }
.signal-filter[hidden] { display: none; }
.signal-filter, .signal-count { align-self: baseline; }
.signal-count { grid-column: 2; margin: 0 0 32px; font-size: var(--t-small); font-weight: 600; line-height: 1.4; color: var(--muted); white-space: nowrap; }
.signal-filter[hidden] + .signal-count { grid-column: 1 / -1; justify-self: start; }
.ink .signal-count { color: var(--on-ink-2); }
.signal-grid { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px; margin: 0; padding: 0; list-style: none; }
.signal-card { display: grid; grid-row: span 3; grid-template-rows: subgrid; row-gap: 0; align-items: start; min-width: 0; padding: 30px; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card); color: var(--text); }
.signal-card[hidden] { display: none; }
.signal-top { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; }
.tag.signal-kind { min-height: 34px; padding: 6px 14px; border-radius: var(--r-pill); background: var(--lime-tint); color: var(--lime-deep); font-family: var(--f-brand); font-size: .9375rem; font-weight: 600; line-height: 1.4; letter-spacing: 0; text-transform: none; }
.signal-when { display: inline-flex; align-items: center; gap: 8px; font-size: var(--t-small); font-weight: 600; line-height: 1.4; color: var(--muted); }
.signal-when .ic { flex: none; }
.signal-card h3 { margin: 24px 0 0; font-size: var(--t-h3, 1.5rem); line-height: 1.22; letter-spacing: -0.012em; text-wrap: balance; }
.signal-play { margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--line); }
.signal-play-k { margin: 0; font-size: var(--t-small); font-weight: 700; line-height: 1.4; color: var(--lime-deep); }
.signal-play-k + p { margin: 8px 0 0; font-size: var(--t-body, 1.0625rem); line-height: 1.55; color: var(--text-2); text-wrap: pretty; }
.ink .signal-card { border-color: var(--ink-line); background: var(--ink-2); color: var(--on-ink); }
.ink .tag.signal-kind { background: var(--ink-3); color: var(--lime); }
.ink .signal-when { color: var(--on-ink-2); }
.ink .signal-play { border-top-color: var(--ink-line); }
.ink .signal-play-k { color: var(--lime); }
.ink .signal-play-k + p { color: var(--on-ink-2); }
@media (max-width: 1024px) {
  .signal-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* exactly 3 signals (a vendor type's, SPEC v2 §6.1; MR 8a) fill their rows: 3 across down to 901px, as on the desktop
   and the mockup, then 2 with the third across the row; an industry page's 4 to 6 keep 2 across (a card the filter
   hides is still a child, so the count never changes with the filter) */
@media (min-width: 901px) and (max-width: 1024px) {
  .signal-grid:has(> :nth-child(3):last-child) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 641px) and (max-width: 900px) {
  .signal-grid:has(> :nth-child(3):last-child) > :last-child { grid-column: 1 / -1; }
}
@media (max-width: 640px) {
  .signals { grid-template-columns: minmax(0, 1fr); }
  .signal-filter { margin-bottom: 16px; }
  .signal-count { grid-column: 1; margin-bottom: 24px; }
  .signal-grid { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .signal-card { padding: 24px; }
  .signal-card h3 { margin-top: 20px; }
  .signal-play { margin-top: 20px; padding-top: 16px; }
}

/* ---------- the market sizer (components.mjs marketSizer; components.js TOOLS.sizer) ----------
   A tool card (.calc): the segments as checkbox rows and the two sliders on the left; on the right the named list, its
   tiers as a strip (each tier's share of the width, never narrower than its number) with their labels under it, then
   the accounts per rep on a card and those on the tiers worked by hand on lime. A ticked row (is-on) has an ink edge
   and an ink box with a lime tick; an unticked one is muted. The checkbox is the native input (restyled; the system's
   own in forced colours), disabled until components.js starts. Paper only (render.mjs INK_BLOCKS leaves it out). */
.sizer-rows { min-width: 0; margin: 0; padding: 0; border: 0; }
.sizer-rows > legend { float: left; width: 100%; margin: 0 0 20px; padding: 0; font-size: 1rem; font-weight: 700; line-height: 1.35; }
.sizer-row { clear: both; display: grid; grid-template-columns: 22px minmax(0, 1fr) auto; align-items: center; column-gap: 12px; min-height: 58px; padding: 14px 18px; border: 1px solid var(--line); border-radius: var(--r-tile); color: var(--muted); }
.sizer-row + .sizer-row { margin-top: 12px; }
.sizer-row.is-on { padding: 13.5px 17.5px; border: 1.5px solid var(--ink); color: var(--text); }
.sizer.is-live .sizer-row { cursor: pointer; }
.sizer-row > input { grid-area: 1 / 1; -webkit-appearance: none; appearance: none; width: 22px; height: 22px; margin: 0; border: 1.5px solid var(--line-strong); border-radius: 6px; background: var(--card); }
.sizer-row > input:checked { border-color: var(--ink); background: var(--ink); }
.sizer-row > input:focus-visible { outline: 2px solid var(--lime-deep); outline-offset: 3px; }
.sizer-tick { grid-area: 1 / 1; display: flex; align-items: center; justify-content: center; width: 22px; height: 22px; color: var(--lime); pointer-events: none; visibility: hidden; }
.sizer-row > input:checked + .sizer-tick { visibility: visible; }
.sizer-name { grid-column: 2; min-width: 0; font-weight: 600; line-height: 1.35; }
.sizer-n { font-weight: 700; font-variant-numeric: tabular-nums; }
.sizer-rows ~ .range-field { margin-top: 0; }
.sizer-k { margin: 0; font-size: 1rem; font-weight: 700; line-height: 1.35; color: var(--text-2); }
.sizer-total { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 16px; margin: 8px 0 0; font-size: 1.125rem; line-height: 1.3; color: var(--text-2); }
.sizer-big { font-weight: 800; letter-spacing: -0.04em; font-variant-numeric: tabular-nums; color: var(--text); }
.sizer-total .sizer-big { font-size: clamp(4rem, 2.6rem + 3vw, 6rem); line-height: .95; }
/* a big figure's focus ring hugs its line (an inline-block of the number's line height), not the font's taller box
   (1.2em against a .95em line), which at 96px reaches 12px above and below the line, onto the label over it ("Your
   named list") or the line under the result;
   and it clears the ends of the number, which its tight tracking and the € push past the box (the padding widens the
   ring only: the margin gives the width back, so nothing moves) */
.sizer-big .fig, .slip-total .fig { display: inline-block; padding-inline: .06em; margin-inline: -.06em; }
.tier-strip { display: flex; margin: 32px 0 0; padding: 0; list-style: none; }
.tier-strip > li { display: flex; flex: var(--w, 1) 1 0; flex-direction: column; gap: 12px; min-width: 4.25rem; }
.tier-strip b { display: flex; align-items: center; height: 64px; padding: 0 14px; font-size: 1.125rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.tier-strip > li:nth-child(1) b { background: var(--ink); color: var(--lime); }
.tier-strip > li:nth-child(2) b { background: var(--text-2); color: var(--paper); }
.tier-strip > li:nth-child(n+3) b { background: var(--paper-3); color: var(--text-2); }
.tier-strip > li:first-child b { border-radius: var(--r-tile) 0 0 var(--r-tile); }
.tier-strip > li:last-child b { border-radius: 0 var(--r-tile) var(--r-tile) 0; }
.tier-strip > li > span { padding-right: 8px; font-size: .875rem; font-weight: 600; line-height: 1.35; color: var(--text-2); }
.sizer-kpis { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; margin-top: 40px; }
.sizer-kpi { margin: 0; padding: 24px; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card); font-size: .9375rem; line-height: 1.45; color: var(--muted); }
.sizer-kpi > .sizer-big { display: block; margin-bottom: 8px; font-size: 2.75rem; line-height: 1; }
/* the judgement on a line of its own, under the words it follows (as the mockup breaks it) */
.sizer-say { display: block; }
.sizer-say:empty { display: none; }
.sizer-kpi.is-focus { border-color: var(--lime); background: var(--lime); font-weight: 600; color: var(--ink); }
.sizer-kpi.is-focus > .sizer-big { color: var(--ink); }
.sizer-kpi.is-focus .fig:focus-visible { outline-color: var(--ink); }
.ink .sizer-row { border-color: var(--ink-line-2); color: var(--on-ink-2); }
.ink .sizer-row.is-on { border-color: var(--on-ink); color: var(--on-ink); }
.ink .sizer-row > input { border-color: var(--ink-ring); background: var(--ink-2); }
.ink .sizer-row > input:checked { border-color: var(--lime); background: var(--lime); }
.ink .sizer-tick { color: var(--ink); }
.ink .sizer-k, .ink .sizer-total, .ink .tier-strip > li > span { color: var(--on-ink-2); }
.ink .sizer-big { color: var(--on-ink); }
.ink .tier-strip > li:nth-child(1) b { background: var(--lime); color: var(--ink); }
.ink .tier-strip > li:nth-child(2) b { background: var(--on-ink-2); color: var(--ink); }
.ink .tier-strip > li:nth-child(n+3) b { background: var(--ink-line-2); color: var(--on-ink); }
.ink .sizer-kpi { border-color: var(--ink-line); background: var(--ink-2); color: var(--on-ink-2); }
.ink .sizer-kpi.is-focus { border-color: var(--lime); background: var(--lime); color: var(--ink); }
@media (max-width: 560px) {
  .sizer-row { min-height: 52px; padding: 12px 14px; }
  .sizer-row.is-on { padding: 11.5px 13.5px; }
  .sizer-total .sizer-big { font-size: 4rem; }
  .tier-strip { margin-top: 24px; }
  .tier-strip b { height: 52px; padding: 0 10px; font-size: 1rem; }
  .sizer-kpis { grid-template-columns: minmax(0, 1fr); gap: 12px; margin-top: 28px; }
  .sizer-kpi { padding: 20px; }
  .sizer-kpi > .sizer-big { font-size: 2.25rem; }
}
@media (forced-colors: active) {
  .sizer-row > input { -webkit-appearance: auto; appearance: auto; }
  .sizer-tick { display: none; }
  .sizer-row.is-on { border-width: 2px; }
  .tier-strip b { border: 1px solid CanvasText; }
  .sizer-kpi.is-focus { border-width: 2px; }
}

/* ---------- the slip calculator (components.mjs slipCalculator; components.js TOOLS.slip) ----------
   A tool card (.calc): the three sliders on the left; on the right the bookings that slip into next year (lime on
   charcoal, lime-deep on paper, the model note its tooltip) and the line after it, then up to three stalls, each a row
   with a warn "Stall" tag, the stall, and on the right the fix with the service under it. The tag and the stall are one
   group (.slip-what, a subgrid of the row's first two columns, as the mockup groups them), centred on the row, and the
   tag sits on the stall's first line (its words on that line's baseline), so a stall that wraps keeps its tag level
   with its start. On a phone the result follows the sliders under a line (one card, as industry-telecom-m.html draws
   it) and a fix goes under its stall. A stall or fix that wraps is balanced, as the deal map's stalls are (site.css
   .dm-stall > dd): on the 9 industry pages at 390, 20 of the 54 stalls and fixes had left one word alone on a line of
   its own ("Budget owner named before / pilot"), 28 at 360. Both are blockified (a grid item of .slip-what, a flex item
   of .slip-fix), so the property takes.
   Drawn for charcoal, the ground the industry template gives it (render.mjs INK_BLOCKS), and for paper after an ink
   section. */
.slip-total { margin: 0; font-size: clamp(4rem, 2.4rem + 4vw, 6rem); font-weight: 800; line-height: .95; letter-spacing: -0.04em; font-variant-numeric: tabular-nums; color: var(--lime-deep); }
.slip-total output { display: inline; }
.slip-text { margin: 12px 0 0; font-size: 1.25rem; line-height: 1.45; color: var(--text-2); }
.slip-k { margin: 40px 0 0; font-size: .9375rem; font-weight: 700; line-height: 1.4; color: var(--text-2); }
.slip-stalls { display: flex; flex-direction: column; gap: 12px; margin: 12px 0 0; padding: 0; list-style: none; }
.slip-stalls > li { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 4px 12px; padding: 16px 18px; border-radius: var(--r-tile); background: var(--card); }
.slip-what { display: grid; grid-column: 1 / 3; grid-template-columns: subgrid; align-items: baseline; min-width: 0; }
.tag.slip-tag { flex: none; }
.slip-stall { font-size: 1rem; line-height: 1.4; text-wrap: balance; }
.slip-fix { display: flex; flex-direction: column; align-items: flex-end; text-align: right; }
.slip-fix > b { font-size: .9375rem; font-weight: 600; line-height: 1.4; color: var(--lime-deep); text-wrap: balance; }
.slip-svc { font-size: .8125rem; font-weight: 600; line-height: 1.4; color: var(--muted); }
.ink .slip-total { color: var(--lime); }
.ink .slip-text, .ink .slip-k { color: var(--on-ink-2); }
.ink .slip-stalls > li { background: var(--ink-2); }
.ink .slip-fix > b { color: var(--lime); }
.ink .slip-svc { color: var(--on-ink-label); }
.slip .fig:focus-visible { outline-color: currentColor; }
@media (max-width: 560px) {
  .slip .calc-out > .slip-total { padding-top: 24px; border-top: 1px solid var(--line); font-size: 3.5rem; }
  .ink .slip .calc-out > .slip-total { border-top-color: var(--ink-line-2); }
  .slip-text { font-size: 1rem; }
  .slip-k { margin-top: 28px; }
  /* the card is one ground on a phone (.calc-out is transparent there): the rows take the next shade */
  .slip-stalls > li { grid-template-columns: auto minmax(0, 1fr); padding: 14px 16px; background: var(--paper-2); }
  .ink .slip-stalls > li { background: var(--ink-3); }
  /* on-ink-label is for ink-2 fills (5.1:1); on ink-3 it is 4.3:1, so the service takes on-ink-2 there (6.9:1) */
  .ink .slip-svc { color: var(--on-ink-2); }
  .slip-fix { grid-column: 2; align-items: flex-start; text-align: left; }
}
@media (forced-colors: active) {
  .slip-stalls > li { border: 1px solid CanvasText; }
}

/* ---------- the seat ring (components.mjs seatRing; components.js TOOLS.seats) ----------
   The buying group as a ring (the mockup's 680 × 600 stage, scaled with its box: a container, sizes in cqi): the dashed
   ring and a spoke per seat (SVG), each seat's short label as a chip on its point, the group in an ink disc at the
   centre. A veto seat has a warn edge, the champion a lime-tint chip with a lime-deep edge, the rest a line; the key
   says so in words, and each card says it again. Without JavaScript every card shows in a grid under the ring (under
   the group's name and size below a 640px stage, where the ring goes).
   With it (is-live) the labels give way to the tablist's buttons in the same places, one card shows (its button ink
   with lime words, its spoke drawn darker), and from 1280px (a ring of 640px or more) the ring and the card sit side
   by side; when the section's
   head comes straight before the ring, the head moves into the card's column above the key (the mockup's layout: a
   subgrid of the section's own grid). Below a 640px stage (a container query) the ring goes and the buttons wrap as
   chips above the card, as industry-telecom-m.html draws them. No class holds "buying" (extractors drop "yin"). */
.seats { display: grid; grid-template-columns: minmax(0, 1fr); row-gap: 40px; }
.seat-stage { container-type: inline-size; justify-self: center; width: 100%; max-width: 680px; min-width: 0; }
.seat-map { position: relative; aspect-ratio: 680 / 600; }
.seat-svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.seat-orbit { fill: none; stroke: var(--line-strong); stroke-width: 1.5; stroke-dasharray: 2 8; stroke-linecap: round; }
.seat-spoke { stroke: var(--line); stroke-width: 1.5; }
.seat-spoke.is-on { stroke: var(--ink); stroke-width: 2.5; }
.seat-lbls { margin: 0; padding: 0; list-style: none; }
.seat-lbl, .seat-tab { position: absolute; left: var(--x); top: var(--y); translate: -50% -50%; display: flex; align-items: center; justify-content: center; box-sizing: border-box; width: 26.5cqi; min-height: 7.06cqi; margin: 0; padding: 4px 12px; border: 1px solid var(--line-strong); border-radius: var(--r-pill); background: var(--card); color: var(--ink); font: inherit; font-size: clamp(.8125rem, 2.35cqi, 1rem); font-weight: 600; line-height: 1.2; text-align: center; }
.seat-lbl.is-veto, .seat-tab.is-veto { border: 1.5px solid var(--warn); }
.seat-lbl.is-champion, .seat-tab.is-champion { border: 1.5px solid var(--lime-deep); background: var(--lime-tint); }
.seat-tab { cursor: pointer; }
.seat-tab:hover { border-color: var(--ink); }
.seat-tab.is-veto:hover { border-color: var(--warn); }
.seat-tab.is-on { border-color: var(--ink); background: var(--ink); color: var(--lime); }
.seat-tab.is-on.is-veto { border-color: var(--warn); }
.seat-tab.is-on.is-champion { border-color: var(--lime-deep); }
.seat-tab:focus-visible { outline: 2px solid var(--lime-deep); outline-offset: 3px; }
.seat-centre { position: absolute; left: 50%; top: 50%; translate: -50% -50%; display: flex; flex-direction: column; align-items: center; justify-content: center; box-sizing: border-box; width: 32.35%; aspect-ratio: 1; margin: 0; padding: 4cqi; border-radius: 50%; background: var(--ink); color: var(--paper); text-align: center; }
.seat-centre > b { font-size: clamp(1rem, 2.94cqi, 1.25rem); font-weight: 800; line-height: 1.2; }
.seat-centre > span { margin-top: 6px; font-size: clamp(.75rem, 2.06cqi, .875rem); line-height: 1.35; color: var(--on-ink-2); }
.seat-centre .fig:focus-visible { outline-color: var(--lime); }
.seat-tabs { position: absolute; inset: 0; pointer-events: none; }
.seat-tabs > .seat-tab { pointer-events: auto; }
.seat-tabs[hidden] { display: none; }
.seats.is-live .seat-lbls { display: none; }
.seat-side { min-width: 0; }
.seat-key { display: flex; flex-wrap: wrap; gap: 8px 20px; margin: 0 0 24px; padding: 0; list-style: none; font-size: var(--t-small); font-weight: 600; line-height: 1.4; color: var(--text-2); }
.seat-key > li { display: inline-flex; align-items: center; gap: 8px; }
.seat-key > li::before { content: ""; flex: none; box-sizing: border-box; width: 14px; height: 14px; border: 1.5px solid var(--line-strong); border-radius: 50%; }
.seat-key > li.is-veto::before { border: 2px solid var(--warn); }
.seat-key > li.is-champion::before { border: 2px solid var(--lime-deep); background: var(--lime-tint); }
.seat-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr)); gap: 16px; margin: 0; padding: 0; list-style: none; }
.seats.is-live .seat-cards { display: block; }
.seat-card { min-width: 0; padding: 30px 32px; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--card); color: var(--text); }
.seat-card[hidden] { display: none; }
.seat-card:focus-visible { outline: 2px solid var(--lime-deep); outline-offset: 4px; }
.seat-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px 12px; }
.seat-top h3 { margin: 0; font-size: var(--t-h3, 1.5rem); line-height: 1.22; text-wrap: balance; }
.seat-flags { display: flex; flex: none; flex-wrap: wrap; justify-content: flex-end; gap: 6px; margin: 0; }
.seat-flags > .tag { min-height: 34px; padding: 6px 14px; border-radius: var(--r-pill); font-family: var(--f-brand); font-size: .9375rem; font-weight: 600; line-height: 1.4; letter-spacing: 0; text-transform: none; }
.seat-titles { margin: 4px 0 0; font-size: var(--t-small); line-height: 1.45; color: var(--muted); }
.seat-dl { display: flex; flex-direction: column; gap: 16px; margin: 24px 0 0; font-size: 1.0625rem; line-height: 1.5; }
.seat-dl dt { font-weight: 700; }
.seat-dl dd { margin: 0; color: var(--text-2); }
.ink .seat-orbit { stroke: var(--ink-ring); }
.ink .seat-spoke { stroke: var(--ink-line); }
.ink .seat-spoke.is-on { stroke: var(--lime); }
.ink :is(.seat-lbl, .seat-tab) { border-color: var(--ink-line-2); background: var(--ink-2); color: var(--on-ink); }
.ink :is(.seat-lbl, .seat-tab).is-veto { border-color: var(--warn-on-ink); }
.ink .seat-tab.is-on { border-color: var(--lime); background: var(--lime); color: var(--ink); }
.ink .seat-centre { background: var(--ink-3); }
.ink .seat-key { color: var(--on-ink-2); }
.ink .seat-card { border-color: var(--ink-line); background: var(--ink-2); color: var(--on-ink); }
.ink :is(.seat-titles, .seat-dl dd) { color: var(--on-ink-2); }
@media (min-width: 1280px) {
  .seats.is-live { grid-template-columns: minmax(0, 680fr) minmax(0, 500fr); column-gap: clamp(40px, 5vw, 76px); align-items: center; }
}
/* stacked (below 1280px) the key and card keep the ring's 680px, centred, where the column is wide enough for that to
   read as a column (from 900px: 74px or more each side); narrower, they fill the column, level with the section's head */
@media (min-width: 900px) and (max-width: 1279px) {
  .seats.is-live .seat-side { justify-self: center; width: 100%; max-width: 680px; }
}
@container (max-width: 639px) {
  .seat-map { aspect-ratio: auto; }
  .seat-svg, .seat-lbls { display: none; }
  .seat-centre { position: static; translate: none; display: block; width: auto; aspect-ratio: auto; margin: 0 0 16px; padding: 0; border-radius: 0; background: none; color: var(--text); text-align: left; }
  .seat-centre > b { display: block; font-size: 1.0625rem; }
  .seat-centre > span { display: block; margin-top: 2px; font-size: .9375rem; color: var(--muted); }
  .seat-centre .fig:focus-visible { outline-color: var(--lime-deep); }
  .seat-tabs { position: static; display: flex; flex-wrap: wrap; gap: 8px; pointer-events: auto; }
  .seat-tab { position: static; translate: none; width: auto; min-height: 40px; padding: 0 14px; font-size: .9375rem; }
  .ink .seat-centre { background: none; color: var(--on-ink); }
}
@media (max-width: 560px) {
  .seats { row-gap: 24px; }
  .seat-key { margin-bottom: 16px; }
  .seat-card { padding: 24px; border-radius: 20px; }
  .seat-dl { gap: 12px; margin-top: 16px; font-size: 1rem; }
}
@media (forced-colors: active) {
  .seat-lbl.is-veto, .seat-tab.is-veto, .seat-key > li.is-veto::before { border-style: double; border-width: 4px; }
  .seat-tab.is-on { forced-color-adjust: none; border-color: Highlight; background: Highlight; color: HighlightText; }
}
/* the ring beside the section's head (from 1280px, where the ring's column is 640px or more, with JavaScript): when
   the head comes straight before the ring in its section, the head moves into the card's column, above the key, and
   its title takes the smaller size (as the mockup draws the buying group); the ring spans both rows, centred. The
   seats become a subgrid of the section's grid, so the head and the card share one column; the head sits above the
   seats' box (z-index), which keeps its figures reachable. Without :has() or JavaScript the head stays above the ring */
@media (min-width: 1280px) {
  .wrap:has(> .section-head + .seats.is-live) { display: grid; grid-template-columns: minmax(0, 680fr) minmax(0, 500fr); grid-template-rows: auto auto; column-gap: clamp(40px, 5vw, 76px); row-gap: 24px; align-items: start; }
  .wrap:has(> .section-head + .seats.is-live) > .section-head { grid-column: 2; grid-row: 1; z-index: 1; grid-template-columns: minmax(0, 1fr); align-self: end; min-width: 0; }
  .wrap:has(> .section-head + .seats.is-live) > .section-head > * { grid-column: 1; grid-row: auto; justify-self: start; max-width: none; }
  .wrap:has(> .section-head + .seats.is-live) > .section-head > h2 { font-size: var(--t-h2-sm); }
  .wrap:has(> .section-head + .seats.is-live) > .seats { grid-column: 1 / -1; grid-row: 1 / span 2; grid-template-columns: subgrid; grid-template-rows: subgrid; }
  .wrap:has(> .section-head + .seats.is-live) > .seats > .seat-stage { grid-column: 1; grid-row: 1 / span 2; align-self: center; }
  .wrap:has(> .section-head + .seats.is-live) > .seats > .seat-side { grid-column: 2; grid-row: 2; }
}

/* ======================================================================================================================
   The industry template v2 (MR 6; SPEC v2 §4.1, industry-telecom.html): the hero's counter, the first 90 days' compact
   frog cards and the vendor types' hooks. New class names only; v1 industry pages never carry them.
   ====================================================================================================================== */

/* ---------- the hero's counter (components.mjs heroCounter): the market by name, on a charcoal panel beside the hero's
   text (the mockup's market counter: 470px, 36px in, 24px round), the total 84px with its words beside it, a row per
   segment with its count and a lime track drawn to its share of the largest row, then the chips as outlined pills.
   Every row shows at every width, a phone included (SPEC v2 §4.1); under 1001px the panel comes under the text ---------- */
.ind-counter { align-self: center; justify-self: end; width: 100%; max-width: 470px; padding: 36px 36px 34px; border: 1px solid var(--ink-line-2); border-radius: 24px; background: var(--ink-2); color: var(--on-ink); }
.ctr-k { margin: 0; font-size: .9375rem; font-weight: 700; line-height: 1.4; color: var(--on-ink-2); }
.ctr-total { display: flex; align-items: flex-end; flex-wrap: wrap; column-gap: 12px; row-gap: 4px; margin: 12px 0 0; }
.ctr-n { font-size: clamp(3.75rem, 2.6rem + 2.6vw, 5.25rem); font-weight: 800; line-height: 1; letter-spacing: -0.04em; font-variant-numeric: tabular-nums; }
.ctr-unit { max-width: 15ch; padding-bottom: 10px; font-size: 1.0625rem; line-height: 1.35; color: var(--on-ink-2); }
.ctr-rows { display: grid; gap: 16px; margin: 32px 0 0; padding: 0; list-style: none; }
.ctr-rows > li { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 12px; row-gap: 8px; align-items: baseline; font-size: .9375rem; line-height: 1.4; }
.ctr-c { font-weight: 700; font-variant-numeric: tabular-nums; }
.ctr-track { grid-column: 1 / -1; display: block; height: 8px; border-radius: 8px; background: var(--ink-3); overflow: hidden; }
.ctr-track > i { display: block; width: var(--w); height: 100%; border-radius: 8px; background: var(--lime); }
.ctr-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 32px 0 0; padding: 0; list-style: none; }
.ctr-chip { display: inline-flex; align-items: center; min-height: 34px; padding: 4px 14px; border: 1px solid var(--ink-line-2); border-radius: 999px; font-size: .9375rem; font-weight: 600; line-height: 1.3; color: var(--on-ink-2); }
.ind-counter .fig:focus-visible { outline: 2px solid var(--lime); outline-offset: 3px; border-radius: 4px; }
/* beside the counter, the hero's text takes the mockup's 660px column from 1240px (the counter's 470px and a 110px gap),
   so at 1440 its lede keeps to 2 lines; below 1240px the hero keeps its 1:1 grid (site.css .ind-hero-grid). The
   freshness line's rule takes that column too, so it ends where the lede does, not 100px short at site.css's 560px
   (below 1240px the column is 560px or narrower, and under 1001px the 560px rule sits over the 560px counter) */
@media (min-width: 1240px) {
  .ind-hero-grid:has(> .ind-counter) { grid-template-columns: minmax(0, 1fr) minmax(0, 470px); column-gap: 110px; }
  .ind-hero-grid:has(> .ind-counter) .ind-fresh { max-width: none; }
}
@media (max-width: 1000px) {
  .ind-counter { justify-self: stretch; max-width: 560px; margin-top: 8px; }
}
/* on a phone the total's words drop under the number when they don't fit beside it, so they take the panel's width
   there and don't wrap after 15 characters beside empty space */
@media (max-width: 560px) {
  .ind-counter { padding: 24px 22px; border-radius: 20px; }
  .ctr-n { font-size: 3.75rem; }
  .ctr-unit { max-width: none; padding-bottom: 6px; font-size: .9375rem; }
  .ctr-rows { gap: 12px; margin-top: 20px; }
  .ctr-rows > li { font-size: .875rem; }
  .ctr-track { height: 6px; }
  .ctr-chips { margin-top: 20px; }
  .ctr-chip { min-height: 30px; font-size: .8125rem; }
}

/* ---------- the vendor-type hero (MR 8a; SPEC v2 §6.3, vendor-type.html): the chips under the lede (the counter's
   outlined pills, 32px under it), and the veto list on a charcoal panel beside the text (440px, 32px in, 24px round):
   its title and the computed count in a warn chip, then a row per seat (16px, 13px above and below, the ink line
   between), a veto seat's tag in warn and the champion's in lime. From 1240px the text takes the rest of the row beside
   the panel with the mockup's 120px gap (680 + 120 + 440); below that the hero keeps its 1:1 grid, and under 1001px the
   panel comes under the text ---------- */
.ind-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 32px 0 0; padding: 0; list-style: none; }
.ind-veto { align-self: center; justify-self: end; width: 100%; max-width: 440px; padding: 32px; border: 1px solid var(--ink-line-2); border-radius: 24px; background: var(--ink-2); color: var(--on-ink); }
.veto-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px; }
.veto-k { margin: 0; font-size: 1.125rem; font-weight: 800; line-height: 1.3; }
.veto-n { margin: 0; }
.ind-veto .veto-n .tag { min-height: 28px; padding: 3px 12px; font-size: .8125rem; }
.veto-rows { margin: 20px 0 0; padding: 0; list-style: none; }
.veto-rows > li { display: flex; align-items: center; justify-content: space-between; gap: 6px 12px; padding: 13px 0; border-top: 1px solid var(--ink-line); font-size: 1rem; line-height: 1.35; }
.veto-role { min-width: 0; }
.veto-tags { flex: none; display: inline-flex; gap: 6px; }
.ind-veto .veto-rows .tag { min-height: 24px; padding: 2px 10px; font-size: .75rem; }
.ind-veto .fig:focus-visible { outline: 2px solid var(--lime); outline-offset: 3px; border-radius: 4px; }
@media (min-width: 1240px) {
  .ind-hero-grid:has(> .ind-veto) { grid-template-columns: minmax(0, 1fr) minmax(0, 440px); column-gap: 120px; }
  .ind-hero-grid:has(> .ind-veto) .ind-fresh { max-width: none; }
}
@media (max-width: 1000px) {
  .ind-veto { justify-self: stretch; max-width: 560px; margin-top: 8px; }
}
@media (max-width: 560px) {
  .ind-chips { margin-top: 24px; }
  .ind-veto { padding: 24px 22px; border-radius: 20px; }
  .veto-k { font-size: 1.0625rem; }
  .veto-rows { margin-top: 14px; }
  .veto-rows > li { padding: 11px 0; font-size: .9375rem; }
}

/* ---------- the first 90 days (components.mjs CARD_VARIANTS 'frogs-compact'; MR 4b's follow-up 1/F7): 3 cards across,
   each the frog (84px) and its weeks as a pill on one line, then the title and a line; one column from 860px down. On
   charcoal the frog sits on a paper disc, never straight on ink ---------- */
.plan-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px; margin: 0; padding: 0; list-style: none; }
.plan-card { display: flex; flex-direction: column; min-width: 0; padding: 34px; }
.plan-top { order: -1; display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.plan-pic { flex: none; display: flex; align-items: center; }
.plan-pic img { display: block; width: auto; height: 84px; max-width: 140px; object-fit: contain; }
.plan-chip { display: inline-flex; align-items: center; min-height: 34px; padding: 4px 14px; border-radius: 999px; background: var(--paper-3); color: var(--ink); font-size: .9375rem; font-weight: 600; line-height: 1.3; white-space: nowrap; }
.plan-card h3 { margin: 24px 0 0; font-size: var(--t-h3, 1.5rem); line-height: 1.22; }
.plan-card p { margin: 12px 0 0; color: var(--text-2); }
.ink .plan-pic { justify-content: center; width: 96px; height: 96px; border-radius: 50%; background: var(--paper); }
.ink .plan-pic img { height: 64px; max-width: 72px; }
.ink .plan-chip { background: var(--ink-3); color: var(--on-ink); }
.ink .plan-card p { color: var(--on-ink-2); }
/* the measures' chips 40px under the cards, as the mockup (the stack's gap is the head's) */
.stack-lg > .plan-cards + .ind-measures { margin-top: calc(40px - var(--head-gap, 64px)); }
@media (max-width: 860px) {
  .plan-cards { grid-template-columns: minmax(0, 1fr); gap: 16px; }
}
@media (max-width: 560px) {
  .plan-card { padding: 26px 24px; }
  .plan-pic img { height: 64px; }
  .plan-card h3 { margin-top: 20px; }
}

/* ---------- vendor types as hooks (render.mjs typeGrid on v3: the short name, the hook as the title; SPEC v2 §5.8):
   the mockup's 5 across from 1200px, each card 230px tall at least with "Read" at its foot ---------- */
@media (min-width: 1200px) {
  /* :has() matches site.css's count rules' weight (.tg:has(> :nth-child(5):last-child)), whatever the count */
  .tg.tg-hooks:has(> :last-child:nth-child(n)) { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 16px; }
  /* 4 or 3 hooks (a vendor type's other playbooks, MR 8a; an industry with 4 types: banking, insurance, healthcare,
     manufacturing, MR 7) fill the row, as vendor-type.html draws its 4 across, rather than leave empty columns of a
     5-column grid */
  .tg.tg-hooks:has(> :nth-child(4):last-child) { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .tg.tg-hooks:has(> :nth-child(3):last-child) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.tg-hooks .tg-card { min-height: 230px; gap: 0; padding: 24px; }
.tg-hooks .tg-k { font-size: .9375rem; font-weight: 700; line-height: 1.4; color: var(--muted); }
.ink .tg-hooks .tg-k { color: var(--on-ink-2); }
.tg-hooks .tg-card h3 { margin-top: 12px; font-size: 1.25rem; line-height: 1.3; letter-spacing: -0.005em; }
.tg-hooks .tg-cta { margin-top: auto; padding-top: 24px; font-size: 1.0625rem; }
@media (max-width: 640px) {
  .tg-hooks .tg-card { min-height: 0; }
  .tg-hooks .tg-cta { padding-top: 20px; }
}
/* 5 hooks below 1200px fill their rows (site.css draws 2 or 3 across, which left an empty cell): two to a row with the
   fifth across the row where site.css draws 2 (640 to 699px), then 3 + 2 on a 6-column grid. 3 hooks (a vendor type's
   other playbooks in an industry of 4 types, MR 8a) take the third across the row there too; site.css draws them 3
   across from 700px */
@media (min-width: 640px) and (max-width: 699px) {
  .tg.tg-hooks:has(> :nth-child(5):last-child) > :last-child, .tg.tg-hooks:has(> :nth-child(3):last-child) > :last-child { grid-column: 1 / -1; }
}
@media (min-width: 700px) and (max-width: 1199px) {
  .tg.tg-hooks:has(> :nth-child(5):last-child) { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .tg.tg-hooks:has(> :nth-child(5):last-child) > :nth-child(-n + 3) { grid-column: span 2; }
  .tg.tg-hooks:has(> :nth-child(5):last-child) > :nth-child(n + 4) { grid-column: span 3; }
}
/* ---------- a vendor-type tool beside its head (MR 8a; vendor-type.html's forecast: the words 480px, the mock 640px,
   centred on each other; the head's h2 the smaller size and its lede 20px) from 1101px; from 901 to 1100px the head over
   the mock, as on a phone (the side head's grid in one column; the wrap's row gap, --head-gap, is the gap under the
   head, so the head keeps its margin of 0) ---------- */
.ind-section.ind-beside .section-head h2 { font-size: var(--t-h2-sm); }
@media (min-width: 901px) and (max-width: 1100px) {
  .ind-beside > .wrap:has(> .section-head.head-side) { grid-template-columns: minmax(0, 1fr); }
}
@media (min-width: 1101px) {
  .ind-beside > .wrap:has(> .section-head.head-side) { grid-template-columns: minmax(0, 480px) minmax(0, 640px); align-items: center; }
  .ind-beside .section-head.head-side > .lede { font-size: 1.25rem; }
}

/* the section's count line ("5 vendor types in telecom"), the head's lede: small and level with the title's foot, the
   title taking the rest of the row */
.ind-types .section-head .lede { font-size: .9375rem; font-weight: 600; line-height: 1.45; color: var(--muted); }
.ind-types .section-head h2 { max-width: none; }
@media (min-width: 901px) {
  .ind-types .section-head.head-split { grid-template-columns: minmax(0, 1fr) auto; }
}
