/* /for-marketing styles. Layers on top of base.css, which holds the
   shared design system (palette, type, container, buttons, header,
   footer, accent rule, centered close).

   The page is built from the homepage concept's pieces (DESIGN.md, "The
   homepage concept's pieces"): full-bleed bands, white plates, one dot
   per account, the teal read line. It must not look like a different
   site to someone who arrives from the homepage's "For marketing" link.

   The first part sets the frames: hero, bands, the copy-beside-picture
   rows, the plate every picture sits on, the dark band, and the close.
   Then one labelled section per picture, in page order, holding what is
   drawn inside its plate, every selector scoped to [data-vis="<id>"].
   Section order matches src/views/for-marketing.ejs. */

/* ── Header, on a phone ─────────────────────────────────────────── */

/* The homepage's hero carries a button and this one does not (Rex's
   copy has none), so on a phone this page keeps the header's "Meet with
   our team" beside the menu button, compact, rather than leaving the
   first way to book at the foot of the page. Below 360px there is no
   room, and the menu carries it. */
@media (max-width: 900px) {
  .bar .bar-cta {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    margin-left: auto;
    margin-right: -6px;
    padding: 0 14px;
    font-size: 14px;
  }
  .bar-inner { gap: 12px; }
  /* The open menu carries its own button; never show two. */
  body.mobile-menu-open .bar .bar-cta { visibility: hidden; }
}
@media (max-width: 359px) {
  .bar .bar-cta { display: none; }
}

/* ── Hero ───────────────────────────────────────────────────────── */

/* Same proportions as the homepage hero, so the two first viewports
   are the same shape: copy left, picture right. */
.mk-hero { padding: 72px 0 64px; }

.mk-hero-grid {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: 56px;
  align-items: center;
}
@media (max-width: 1040px) {
  .mk-hero-grid { grid-template-columns: 1fr; gap: 40px; }
}

/* Display size, the homepage's own, so the step from one page to the
   other does not shrink the headline. One sentence, broken at the comma
   into two spans; at Display size each wraps, so it sets on three lines
   at every width, as the homepage's headline does. */
.mk-hero h1 { max-width: 9.6em; }
.mk-hero h1 .line { display: block; }
.mk-hero h1 .line + .line { margin-top: 0.1em; }

.mk-hero-sub {
  font-size: clamp(18px, 1.8vw, 22px);
  line-height: 1.52;
  color: var(--body);
  margin-top: 26px;
  max-width: 25em;
}

/* ── Sections ───────────────────────────────────────────────────── */

/* Grounds run Paper (hero), Tint, Paper, Tint, Ink, Paper (close): the
   Alternating Ground Rule, with the page's one Ink band in the same
   place in the sequence as the homepage's. */
.mk-sec { padding: 96px 0 104px; }
@media (max-width: 700px) {
  .mk-sec { padding: 68px 0 76px; }
}

.mk-head h2 { max-width: 19.5em; }

/* ── Rows: one point of copy beside its picture ─────────────────── */

.mk-rows {
  display: grid;
  gap: 88px;
  margin-top: 56px;
}
@media (max-width: 1040px) {
  .mk-rows { gap: 64px; margin-top: 44px; }
}

/* Copy 5 parts, picture 7: at 1440 the plate is about 674px wide. The
   picture side alternates row to row (.is-flip puts it on the left),
   and the alternation carries on across sections so the page zigzags
   from top to bottom. */
.mk-row {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: 64px;
  align-items: center;
}
.mk-row.is-flip { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
.mk-row.is-flip .mk-copy { order: 2; }
.mk-row.is-flip .vis { order: 1; }

/* At 1040 and below, copy always sits above its picture. */
@media (max-width: 1040px) {
  .mk-row,
  .mk-row.is-flip { grid-template-columns: minmax(0, 1fr); gap: 28px; }
  .mk-row.is-flip .mk-copy,
  .mk-row.is-flip .vis { order: 0; }
}

/* The point itself, at lede size. Body colour on the light grounds,
   Dark Body on Ink (below). */
.mk-point {
  font-size: 19px;
  line-height: 1.6;
  color: var(--body);
  max-width: 26em;
}
@media (max-width: 700px) {
  .mk-point { font-size: 18px; }
}

/* Content Marketing's two points: hairline rows, as the homepage's
   problem lists are, not bullets. No dots: on these pages a dot is an
   account. The question that opens each point is set in Ink. */
.mk-list {
  list-style: none;
  margin-top: 26px;
  max-width: 30em;
  border-top: 1px solid var(--rule);
}
.mk-list li {
  padding: 16px 0;
  border-bottom: 1px solid var(--rule);
  font-size: 16.5px;
  line-height: 1.58;
  color: var(--body);
}
.mk-list b { color: var(--ink); font-weight: 600; }

/* ── The plate every picture sits on ────────────────────────────── */

/* The homepage's plate: Surface, 1px Rule, 14px radius, no shadow. Each
   picture sets its own shape and inner padding through three custom
   properties in its own section, so no picture has to out-specify
   this file or re-declare the phone breakpoint:

     [data-vis="filter"] {
       --vis-ratio: 1.55 / 1;       width / height above 520px
       --vis-ratio-phone: 0.9 / 1;  width / height at 520px and below
       --vis-pad: 26px;             inner padding above 520px
       --vis-pad-phone: 18px;       inner padding at 520px and below
     }

   Plate widths: about 674px at 1440, up to 680px when stacked between
   520 and 1040, and 335px on a 375px phone. At the defaults that is
   about 421px tall on desktop and 353px on a phone. */
.plate {
  margin: 0;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 14px;
  overflow: hidden;
}

.vis {
  /* The homepage canvas's verdict fills and score ink, once for every
     picture: a dot is Teal for target now, Blue at 55% for monitor for
     timing signals, Grey at 45% for hold off; a score is Ink at 62% on
     Track. */
  --v-target: rgba(0, 168, 138, 0.95);
  --v-monitor: rgba(47, 99, 218, 0.55);
  --v-hold: rgba(118, 127, 137, 0.45);
  --score-ink: rgba(17, 22, 27, 0.62);
  position: relative;
  display: block;
  width: 100%;
  min-width: 0;
  aspect-ratio: var(--vis-ratio, 1.6 / 1);
  padding: var(--vis-pad, 26px);
  /* Everything drawn on a plate is instrument chrome or a figure, so
     the plate sets the body face; pictures set Mono where a figure has
     to align. */
  font-family: var(--text);
  color: var(--ink);
}
@media (max-width: 1040px) {
  .vis { max-width: 680px; }
}
@media (max-width: 520px) {
  .vis {
    aspect-ratio: var(--vis-ratio-phone, 0.95 / 1);
    padding: var(--vis-pad-phone, 18px);
  }
}

/* On Ink a white plate reads as a screen, which is what the two
   pictures in that band are. The hairline would be invisible there, so
   it goes. */
.blk.dark .vis { border-color: transparent; }

/* ── Before the player arms a picture ───────────────────────────── */

/* marketing-arm.js marks <html> with .mk-arm before first paint (never
   under reduced motion or without script). Until the player has armed a
   picture (data-step) or let it rest (.is-done), what is drawn on it is
   hidden, so the finished frame never flashes before the first one. If
   the player never arrives, it shows anyway after 4s. */
html.mk-arm [data-vis]:not([data-step]):not(.is-done) > * {
  visibility: hidden;
  animation: mk-unarm 0s linear 4s forwards;
}
@keyframes mk-unarm { to { visibility: visible; } }

/* ── The player's reset between passes ──────────────────────────── */

/* marketing.js fades a picture out before replaying it, snaps it back
   to its first frame with every transition inside it switched off, then
   fades it back in. Owned here, not by any picture. */
[data-vis] { transition: opacity 350ms ease; }
[data-vis].is-resetting { opacity: 0; }
[data-vis].is-snapping,
[data-vis].is-snapping * { transition: none !important; animation: none !important; }

/* On Ink a whole white plate blinking out to Ink and back is a flash, so
   there the plate stays lit and only what is drawn on it fades. */
.blk.dark [data-vis].is-resetting { opacity: 1; }
.blk.dark [data-vis] > * { transition: opacity 350ms ease; }
.blk.dark [data-vis].is-resetting > * { opacity: 0; }

/* ── Learn From & Educate the Market (the Ink band) ─────────────── */

/* Dark Body on Ink, as the homepage's compounding band sets its lede. */
.blk.dark .mk-point { color: var(--dark-body); }

/* ── The close ──────────────────────────────────────────────────── */

/* The homepage's close, so the two pages end the same, with Rex's
   paragraph above the button as his copy has it: it is the offer, so it
   is set in Body rather than as a muted note. */
.mk-plan { padding: 104px 0 96px; }
.mk-plan .accent-rule { margin-left: auto; margin-right: auto; }
.mk-plan h2 { font-size: clamp(33px, 4.5vw, 57px); }
.mk-plan-body {
  margin: 22px auto 0;
  max-width: 31em;
  font-size: 16.5px;
  line-height: 1.58;
  color: var(--body);
}
.mk-plan .actions { margin-top: 30px; }

/* Two rows of unread accounts, hollow Slate rings, with the read line
   waiting at their edge in Ink at 35%. Drawn twice in the template, 32
   a row and 18 a row, and the width picks one, as on the homepage. */
.mk-unread {
  margin: 56px auto 0;
  max-width: 760px;
}
.mk-unread svg { display: block; width: 100%; height: auto; }
.mk-unread-narrow { display: none !important; }
@media (max-width: 520px) {
  .mk-unread-wide { display: none !important; }
  .mk-unread-narrow { display: block !important; }
}
.mk-unread-rings circle {
  fill: none;
  stroke: rgba(183, 190, 196, 0.95);
  stroke-width: 1.2;
}
.mk-unread-line {
  fill: none;
  stroke: rgba(17, 22, 27, 0.35);
  stroke-width: 1.6;
}


/* ════ PICTURE: Hero: one database feeds every program [data-vis="hero"] ════ */

/* The hero picture on /for-marketing: one database feeds every program.
   The right-hand column of the hero (.mk-hero-grid in marketing.css).

   A card in the homepage hero chart's own build (Surface, 1px Rule, 14px
   radius, 20px 22px 22px padding) holding:
     .mk-hero-head   the grid's name and the homepage chart's colour key,
                     so a reader who lands here first knows what the
                     three colours mean before the rest of the page
                     teaches them
     .mk-hero-frame  the grid, on canvas, in an inset frame like the
                     homepage chart's (1px Rule, 8px radius, #FCFDFC)
     .mk-hero-links  one strip cut into four programs, each a real link
                     to its section, each joined to the grid by a hairline

   The markup with NO data-step is the finished picture: grid read,
   every tile lit. Earlier frames are written as exceptions below:
     step 0  the grid unread, every tile unlit
     step 1  the line reads the grid (drawn by the hero section of js/marketing.js)
     step 2  Campaign Targeting lights
     step 3  Account-Based Marketing lights
     step 4  Content Marketing lights
     step 5  Learn From & Educate the Market lights, and the picture holds

   Transitions are switched on only once step 1 is reached, so arming the
   picture at load (finished frame to step 0) snaps rather than fading
   every tile out in front of the reader. Nothing here sets transition
   on the [data-vis] root: marketing.css owns that for the fade between
   passes. */

[data-vis="hero"] {
  /* A lit hairline: Ink at 40% laid over Surface. */
  --hero-wire-on: #A0A2A4;
  --hero-drop: 20px;
  /* The picture lays itself out by its own width, not the viewport's:
     between 1040 and about 1300 the hero is two columns and this card
     is narrower than it is on a phone held sideways. */
  container-type: inline-size;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 14px;
  padding: 20px 22px 22px;
  min-width: 0;
}
@media (max-width: 1040px) {
  [data-vis="hero"] { max-width: 680px; }
}
@media (max-width: 520px) {
  [data-vis="hero"] { padding: 16px 16px 18px; }
}

/* ── The grid's name and key ────────────────────────────────────── */

/* The name as a plate title, the key as the homepage chart's key (9px
   swatches, 13px Muted); the swatches are marks, so plain Teal. */
[data-vis="hero"] .mk-hero-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 6px 20px;
  margin: 0 2px 14px;
}
[data-vis="hero"] .mk-hero-name {
  margin: 0;
  font-family: var(--display);
  font-size: 15px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--ink);
}
[data-vis="hero"] .mk-hero-key {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
}
[data-vis="hero"] .mk-hero-key li {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  line-height: 1.4;
  color: var(--muted);
}
[data-vis="hero"] .mk-hero-key i {
  flex: none;
  width: 9px;
  height: 9px;
  border-radius: 50%;
}
[data-vis="hero"] .mk-hero-key .k-good { background: var(--teal); }
[data-vis="hero"] .mk-hero-key .k-fit { background: var(--blue); }
[data-vis="hero"] .mk-hero-key .k-none { background: #767F89; }

/* ── The grid ───────────────────────────────────────────────────── */

[data-vis="hero"] .mk-hero-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 1.62 / 1;
  border: 1px solid var(--rule);
  border-radius: 8px;
  background: #FCFDFC;
  overflow: hidden;
}
[data-vis="hero"] .mk-hero-canvas {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}
@container (max-width: 519px) {
  [data-vis="hero"] .mk-hero-frame { aspect-ratio: 1.2 / 1; }
}
@container (max-width: 399px) {
  [data-vis="hero"] .mk-hero-frame { aspect-ratio: 1.08 / 1; }
  [data-vis="hero"] .mk-hero-head { margin-bottom: 12px; }
  [data-vis="hero"] .mk-hero-key { gap: 4px 14px; }
  [data-vis="hero"] .mk-hero-key li { font-size: 12.5px; }
}

/* ── The four programs ──────────────────────────────────────────── */

/* One strip in the grid frame's own build (1px Rule, 8px radius,
   #FCFDFC), cut into four by hairlines, so the programs read as the
   instrument's outputs rather than as a row of feature cards. Each cell
   is a real link: the site's focus ring (base.css), a thumb-sized
   target, and the link colour on hover. */
[data-vis="hero"] .mk-hero-links {
  position: relative;
  list-style: none;
  margin: var(--hero-drop) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: 1fr;
  border: 1px solid var(--rule);
  border-radius: 8px;
  background: #FCFDFC;
}
[data-vis="hero"] .mk-hero-links li {
  position: relative;
  display: flex;
  min-width: 0;
}
[data-vis="hero"] .mk-hero-links li + li { border-left: 1px solid var(--rule); }

[data-vis="hero"] .mk-hero-links a {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 44px;
  padding: 16px 14px 15px;
  color: var(--ink);
  text-decoration: none;
  border-radius: 6px;
}
/* At rest each label ends in an arrow, so the tiles read as links. On
   hover the tile takes an Ink hairline and its label the link colour. */
[data-vis="hero"] .mk-hero-links a:hover .lbl { color: var(--teal-deep); }
[data-vis="hero"] .mk-hero-links a:hover:not(:focus-visible) {
  outline: 1px solid var(--ink);
  outline-offset: -1px;
}
/* Inline, not inline-block, so the no-break space keeps the arrow on the
   last word's line instead of letting it wrap onto a line of its own. */
[data-vis="hero"] .go {
  position: relative;
  left: 0;
  font-family: var(--text);
  font-weight: 500;
  transition: left 200ms ease-out;
}
[data-vis="hero"] .mk-hero-links a:hover .go { left: 2px; }

[data-vis="hero"] .g {
  display: block;
  width: 100%;
  max-width: 104px;
  height: auto;
  overflow: visible;
}
[data-vis="hero"] .lbl {
  display: block;
  margin-top: 14px;
  font-family: var(--display);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.005em;
  color: var(--ink);
}

/* The hairlines. In a card 520px wide and up: one straight drop from the grid's frame
   to the top of each program, each lit with its program. */
[data-vis="hero"] .mk-hero-links li::before,
[data-vis="hero"] .mk-hero-links::before {
  content: '';
  position: absolute;
  top: calc(-1 * var(--hero-drop) - 1px);
  width: 1px;
  height: var(--hero-drop);
  background: var(--hero-wire-on);
  pointer-events: none;
}
[data-vis="hero"] .mk-hero-links li::before { left: 50%; }
[data-vis="hero"] .mk-hero-links::before { display: none; left: 50%; }

/* Below 520px of card the programs sit two by two, and one drop from the
   grid lands on the strip's middle hairline, which carries it on down
   between them: the same one-to-four, folded. */
@container (max-width: 519px) {
  [data-vis="hero"] .mk-hero-links { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  [data-vis="hero"] .mk-hero-links li + li { border-left: 0; }
  [data-vis="hero"] .mk-hero-links li:nth-child(even) { border-left: 1px solid var(--rule); }
  [data-vis="hero"] .mk-hero-links li:nth-child(n+3) { border-top: 1px solid var(--rule); }
  [data-vis="hero"] .mk-hero-links li::before { display: none; }
  [data-vis="hero"] .mk-hero-links::before { display: block; left: calc(50% - 0.5px); }
  [data-vis="hero"] .mk-hero-links a { padding: 14px 12px 13px; }
  [data-vis="hero"] .lbl { margin-top: 12px; }
}

/* ── What each tile draws (finished) ────────────────────────────── */

/* Glyph Grey (#C3C9CE) for the accounts outside the audience, as on the
   homepage's problem lattices. Teal for the gathered audience and for
   target now, light-ground Blue at 55% for monitor for timing, exactly
   as home.js fills a cell. */
[data-vis="hero"] .aud-rest circle { fill: #C3C9CE; }
[data-vis="hero"] .aud-in circle { fill: rgba(0, 168, 138, 0.95); }

[data-vis="hero"] .g .trk { fill: var(--track); }
[data-vis="hero"] .g .val { fill: rgba(17, 22, 27, 0.62); }
[data-vis="hero"] .g .dot { fill: rgba(0, 168, 138, 0.95); }
[data-vis="hero"] .g .dot-fit { fill: rgba(47, 99, 218, 0.55); }
[data-vis="hero"] .g .val-rise { transform-box: fill-box; transform-origin: left center; }

[data-vis="hero"] .tb { fill: rgba(17, 22, 27, 0.62); }

[data-vis="hero"] .pg { fill: var(--surface); stroke: #C3C9CE; stroke-width: 1; }
[data-vis="hero"] .ln { fill: #C3C9CE; transform-box: fill-box; transform-origin: left center; }
[data-vis="hero"] .ln-t { fill: rgba(17, 22, 27, 0.62); }
[data-vis="hero"] .ax { fill: var(--rule); }
[data-vis="hero"] .fb { fill: rgba(17, 22, 27, 0.62); transform-box: fill-box; transform-origin: center bottom; }

/* ── Transitions, from step 1 on ────────────────────────────────── */

[data-vis="hero"][data-reached~="1"] .lbl { transition: color 400ms ease-out; }
[data-vis="hero"][data-reached~="1"] .mk-hero-links li::before,
[data-vis="hero"][data-reached~="1"] .mk-hero-links::before { transition: background-color 320ms ease-out; }
[data-vis="hero"][data-reached~="1"] .g circle,
[data-vis="hero"][data-reached~="1"] .g rect {
  transition: fill 380ms ease-out 160ms, stroke 380ms ease-out 160ms;
}
[data-vis="hero"][data-reached~="1"] .aud-in circle {
  transition: fill 380ms ease-out 160ms,
    transform 560ms cubic-bezier(0.22, 1, 0.36, 1) calc(320ms + var(--d, 0ms));
}
[data-vis="hero"][data-reached~="1"] .tb {
  transition: fill 380ms ease-out 160ms, transform 600ms cubic-bezier(0.65, 0, 0.35, 1) 520ms;
}
[data-vis="hero"][data-reached~="1"] .ln,
[data-vis="hero"][data-reached~="1"] .fb {
  transition: fill 380ms ease-out 160ms, transform 420ms cubic-bezier(0.22, 1, 0.36, 1) calc(240ms + var(--d, 0ms));
}

/* ── Unlit: a tile before its step ──────────────────────────────── */

/* The tile is there from the start, its drawing in Slate outline and
   its name in Muted, so the four programs read as waiting on the
   database rather than appearing from nowhere. */
[data-vis="hero"][data-step]:not([data-reached~="2"]) .t-aud,
[data-vis="hero"][data-step]:not([data-reached~="3"]) .t-abm,
[data-vis="hero"][data-step]:not([data-reached~="4"]) .t-top,
[data-vis="hero"][data-step]:not([data-reached~="5"]) .t-rep {
  --hero-wire-on: var(--rule);
}
[data-vis="hero"][data-step]:not([data-reached~="2"]) .mk-hero-links::before { background: var(--rule); }
:is(
  [data-vis="hero"][data-step]:not([data-reached~="2"]) .t-aud,
  [data-vis="hero"][data-step]:not([data-reached~="3"]) .t-abm,
  [data-vis="hero"][data-step]:not([data-reached~="4"]) .t-top,
  [data-vis="hero"][data-step]:not([data-reached~="5"]) .t-rep
) .lbl { color: var(--muted); }

/* Unread accounts: Slate rings, as an unread cell in the grid. */
:is(
  [data-vis="hero"][data-step]:not([data-reached~="2"]) .t-aud,
  [data-vis="hero"][data-step]:not([data-reached~="3"]) .t-abm
) circle {
  fill: rgba(183, 190, 196, 0);
  stroke: var(--slate);
  stroke-width: 1.1;
}
[data-vis="hero"] .g circle { stroke: rgba(183, 190, 196, 0); stroke-width: 1.1; }

/* Campaign Targeting: the seven start in the lattice. */
[data-vis="hero"][data-step]:not([data-reached~="2"]) .aud-in circle {
  transform: translate(var(--dx), var(--dy));
}

/* Account-Based Marketing: the bars empty, and the rows in their old
   order, the riser at the bottom. */
[data-vis="hero"][data-step]:not([data-reached~="3"]) .t-abm .val { fill: rgba(17, 22, 27, 0); }
[data-vis="hero"][data-step]:not([data-reached~="3"]) .row-a { transform: translateY(26px); }
[data-vis="hero"][data-step]:not([data-reached~="3"]) .row-b,
[data-vis="hero"][data-step]:not([data-reached~="3"]) .row-c { transform: translateY(-13px); }
[data-vis="hero"][data-step]:not([data-reached~="3"]) .val-rise { transform: scaleX(0.405); }

/* Content Marketing: the bars unsorted and unread. */
[data-vis="hero"][data-step]:not([data-reached~="4"]) .tb {
  fill: var(--slate);
  transform: translateY(var(--dy));
}

/* Learn From & Educate the Market: a blank page. */
[data-vis="hero"][data-step]:not([data-reached~="5"]) .pg { stroke: var(--slate); }
[data-vis="hero"][data-step]:not([data-reached~="5"]) .ln,
[data-vis="hero"][data-step]:not([data-reached~="5"]) .ln-t { fill: var(--slate); transform: scaleX(0); }
[data-vis="hero"][data-step]:not([data-reached~="5"]) .fb { fill: var(--slate); transform: scaleY(0); }

/* ── Account-Based Marketing, as it lights ──────────────────────── */

/* The riser is coloured in as it stands (monitor for timing), then its
   timing rises, it crosses into target now and moves to the top while
   the two above it step down. Keyframes rather than a transition, for
   the blue it passes through. Only while the picture plays: at rest
   the static finished styles above take over at the same values. */
[data-vis="hero"][data-step][data-reached~="3"] .row-a {
  animation: hero-abm-rise 1300ms both;
}
[data-vis="hero"][data-step][data-reached~="3"] .row-b,
[data-vis="hero"][data-step][data-reached~="3"] .row-c {
  animation: hero-abm-step 1300ms both;
}
[data-vis="hero"][data-step][data-reached~="3"] .row-a .val-rise {
  animation: hero-abm-grow 1300ms both;
}
[data-vis="hero"][data-step][data-reached~="3"] .row-a .dot {
  animation: hero-abm-turn 1300ms both;
}
@keyframes hero-abm-rise {
  0%, 42% { transform: translateY(26px); animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1); }
  100% { transform: translateY(0); }
}
@keyframes hero-abm-step {
  0%, 42% { transform: translateY(-13px); animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1); }
  100% { transform: translateY(0); }
}
@keyframes hero-abm-grow {
  0%, 18% { transform: scaleX(0.405); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
  55%, 100% { transform: scaleX(1); }
}
@keyframes hero-abm-turn {
  0% { fill: rgba(47, 99, 218, 0); }
  14%, 36% { fill: rgba(47, 99, 218, 0.55); }
  56%, 100% { fill: rgba(0, 168, 138, 0.95); }
}

@media (prefers-reduced-motion: reduce) {
  [data-vis="hero"] * { animation: none !important; transition: none !important; }
}


/* ════ PICTURE: Campaign Targeting 1: the filter and the trait [data-vis="filter"] ════ */

/* The "filter" picture on /for-marketing: Campaign Targeting, point 1.

   An ad platform's Employee count filter is opened, set to 101-1000
   employees and crossed out in Amber (the problem). Beside it, the trait
   "Adding staff to keep up with volume" is read across the market, one
   dot per account under the teal read line, and ticked in Teal.

   The two halves are drawn in two hands on purpose. The filter is plain
   form UI, the way any platform draws it: a form label, a grey-bordered
   select, an option list. The trait is ours: a Surface 2 card on a
   hairline, a Mono instrument label, the trait in Outfit, and the dot
   strip with its count.

   Steps (timings in the filter section of js/marketing.js):
     0  the filter, closed, showing "Any"
     1  the list opens and 101-1000 employees is picked (neutral tint,
        not teal: nothing has been confirmed)
     2  the list closes on the choice
     3  the Amber cross drops onto it and the filter dims behind it
     4  the trait lands in the card, which has waited from step 0 with
        its label, an unknown slot and its accounts unread; the read line
        crosses the accounts, the ones that have the trait fill Teal, the
        count follows
     5  the Teal check drops onto the trait
   No data-step is the finished picture (also no-JS and reduced motion).

   Every selector is scoped under [data-vis="filter"]. The root's own
   transition belongs to marketing.css (the fade between passes). */

/* The plate is as tall as the drawing (auto), with the two halves
   top-aligned, so nothing floats in empty white; the option list still
   has room to drop below the select. It lays itself out by its own width:
   under 600px of plate the trait goes under the filter. */
[data-vis="filter"] {
  --vis-ratio: auto;
  --vis-ratio-phone: auto;
  container-type: inline-size;
  --fl-dim: #C3C9CE;          /* Glyph Grey: read, trait not found */
  --fl-field-edge: #C9CED2;   /* a stock form control's border */
  --fl-drop: cubic-bezier(0.2, 0.9, 0.3, 1.08);  /* quick ease-out, a hair of settle */
}

/* ── Layout ─────────────────────────────────────────────────────── */

[data-vis="filter"] .fl {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.08fr);
  gap: 44px;
  align-items: start;
}
@container (max-width: 599px) {
  [data-vis="filter"] .fl {
    grid-template-columns: minmax(0, 1fr);
    gap: 26px;
  }
}

/* ── The platform's filter ──────────────────────────────────────── */

/* A stock control is a fixed size, not the width of whatever holds it,
   so on a wide stacked plate the cross still lands near the value. */
[data-vis="filter"] .fl-filter {
  position: relative;
  max-width: 320px;
  /* Room below the select for the option list to open inside the
     plate. Stacked, the list opens over the trait card instead. */
  min-height: 244px;
}
@container (max-width: 599px) {
  [data-vis="filter"] .fl-filter { min-height: 0; }
}

[data-vis="filter"] .fl-label {
  display: block;
  font-size: 14px;
  font-weight: 500;
  color: var(--body);
  margin-bottom: 9px;
  transition: opacity 360ms ease;
}

[data-vis="filter"] .fl-control { position: relative; }

[data-vis="filter"] .fl-select {
  position: relative;
  height: 48px;
  display: flex;
  align-items: center;
  padding: 0 40px 0 14px;
  background: var(--surface);
  border: 1px solid var(--fl-field-edge);
  border-radius: 6px;
  font-size: 16px;
  color: var(--ink);
  white-space: nowrap;
  transition: opacity 360ms ease, border-color 160ms ease;
}
/* The value stops short of the cross's place, so the cross lands on the
   field's empty end, between the value and the chevron. */
[data-vis="filter"] .fl-value {
  position: absolute;
  left: 14px;
  right: 92px;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: opacity 160ms ease;
}
[data-vis="filter"] .fl-value-any { opacity: 0; color: var(--muted); }
[data-vis="filter"] .fl-chev {
  position: absolute;
  right: 15px;
  top: 50%;
  width: 12px;
  height: 8px;
  margin-top: -4px;
  fill: none;
  stroke: var(--muted);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 220ms ease;
}

/* The option list: closed in the finished picture. */
[data-vis="filter"] .fl-menu {
  list-style: none;
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  top: calc(100% + 6px);
  margin: 0;
  padding: 4px;
  background: var(--surface);
  border: 1px solid var(--fl-field-edge);
  border-radius: 6px;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity 200ms ease, transform 220ms ease, visibility 0s linear 220ms;
}
[data-vis="filter"] .fl-menu li {
  padding: 8px 10px;
  border-radius: 5px;
  font-size: 14.5px;
  line-height: 1.4;
  color: var(--body);
  white-space: nowrap;
  transition: background-color 160ms ease, color 160ms ease;
}

/* ── The marks ──────────────────────────────────────────────────── */

[data-vis="filter"] .fl-stamp {
  position: absolute;
  z-index: 3;
  width: 72px;
  height: 72px;
  fill: none;
  stroke-width: 11;
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: none;
  transform-origin: 50% 50%;
  transition: opacity 180ms ease, transform 420ms var(--fl-drop);
}
/* The cross sits on the select's empty right end, just inside the
   chevron, so the choice it strikes out stays readable beside it and the
   field still reads as a drop-down. */
[data-vis="filter"] .fl-x {
  stroke: var(--amber);
  right: 30px;
  top: 24px;               /* the select's middle */
  margin-top: -36px;
}
/* The check sits on the trait card's right edge, level with the trait. */
[data-vis="filter"] .fl-check {
  stroke: var(--teal);
  right: -16px;
  top: 30px;
}
@media (max-width: 520px) {
  [data-vis="filter"] .fl-select { height: 46px; font-size: 15.5px; }
  [data-vis="filter"] .fl-card { padding: 18px 20px 17px; }
  [data-vis="filter"] .fl-trait-text { font-size: 19.5px; }
  [data-vis="filter"] .fl-stamp { width: 60px; height: 60px; stroke-width: 10.5; }
  [data-vis="filter"] .fl-x { right: 28px; top: 23px; margin-top: -30px; }
  [data-vis="filter"] .fl-check { right: -8px; top: 26px; }
}

/* Crossed out: the filter steps back behind its cross, still readable
   (about 3.5:1 for its value). */
[data-vis="filter"] .fl-label,
[data-vis="filter"] .fl-select { opacity: 0.6; }

/* ── The trait, as ours ─────────────────────────────────────────── */

[data-vis="filter"] .fl-trait { position: relative; }
[data-vis="filter"] .fl-card {
  background: var(--surface-2);
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: 20px 22px 19px;
}
[data-vis="filter"] .fl-kicker {
  /* Micro, at the page's 12px floor, as persona and topics set their
     part labels. */
  display: block;
  font-family: var(--text);
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
}
/* The trait's place. Until it is found, an unknown: two Track lines,
   the same slot the account-based marketing card waits with. */
[data-vis="filter"] .fl-trait-slot { position: relative; margin-top: 8px; }
[data-vis="filter"] .fl-skel {
  position: absolute;
  inset: 4px 34px 4px 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 10px;
  opacity: 0;
  transition: opacity 200ms ease;
}
[data-vis="filter"] .fl-skel i {
  display: block;
  width: 78%;
  height: 6px;
  border-radius: 2px;
  background: var(--track);
}
[data-vis="filter"] .fl-skel i + i { width: 46%; }
[data-vis="filter"] .fl-trait-text {
  margin: 0;
  padding-right: 34px;     /* room for the check */
  transition: opacity 380ms ease 80ms, transform 420ms ease-out 80ms;
  font-family: var(--display);
  font-weight: 600;
  font-size: 20px;
  line-height: 1.26;
  letter-spacing: -0.016em;
  color: var(--ink);
}

/* The market, read for the trait: one dot per account. */
[data-vis="filter"] .fl-read {
  position: relative;
  width: 100%;
  margin-top: 18px;
  padding: 6px 0;
  overflow: hidden;
}
[data-vis="filter"] .fl-dots { display: block; width: 100%; height: auto; overflow: visible; }
[data-vis="filter"] .fl-dots circle {
  stroke-width: 1.2;
  transition: fill 240ms ease, stroke 240ms ease;
}
[data-vis="filter"] .fl-dots .is-has { fill: var(--teal); stroke: var(--teal); }
[data-vis="filter"] .fl-dots .is-not { fill: var(--fl-dim); stroke: var(--fl-dim); }

/* The read line: a 1.6px Teal stroke at 85% with its flat 38px band
   behind it, shown only while it moves. */
[data-vis="filter"] .fl-line {
  position: absolute;
  top: 0;
  bottom: 0;
  left: -38px;
  width: 38px;
  background: rgba(0, 168, 138, 0.08);
  border-right: 1.6px solid rgba(0, 168, 138, 0.85);
  opacity: 0;
  pointer-events: none;
}

[data-vis="filter"] .fl-count {
  display: block;
  margin-top: 10px;
  font-family: var(--mono);
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  transition: opacity 300ms ease;
}

/* ── Earlier steps, as exceptions to the finished picture ───────── */

/* 0-2: the filter at full strength, no cross yet. */
[data-vis="filter"][data-step]:not([data-reached~="3"]) .fl-label,
[data-vis="filter"][data-step]:not([data-reached~="3"]) .fl-select { opacity: 1; }
[data-vis="filter"][data-step]:not([data-reached~="3"]) .fl-x {
  opacity: 0;
  transform: scale(1.4);
}

/* 0-1: nothing chosen yet. At step 2 "Any" goes first and the choice
   follows it, so the two are never seen on top of each other. */
[data-vis="filter"][data-step]:not([data-reached~="2"]) .fl-value-any { opacity: 1; }
[data-vis="filter"][data-step]:not([data-reached~="2"]) .fl-value-pick { opacity: 0; }
[data-vis="filter"][data-step="2"] .fl-value-pick { transition-delay: 160ms; }

/* 1: open. The select takes focus in Ink, the list drops, and after a
   beat the pick lights in a neutral tint. */
[data-vis="filter"][data-step="1"] .fl-select { border-color: var(--ink); }
[data-vis="filter"][data-step="1"] .fl-chev { transform: rotate(180deg); }
[data-vis="filter"][data-step="1"] .fl-menu {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 200ms ease, transform 220ms ease, visibility 0s;
}
[data-vis="filter"][data-step="1"] .fl-menu .is-picked {
  background: var(--pill-none-bg);
  color: var(--ink);
  transition-delay: 620ms;
}

/* 0-3: the card waits with its label and its accounts unread; the
   trait is an unknown. */
[data-vis="filter"][data-step]:not([data-reached~="4"]) .fl-skel { opacity: 1; }
[data-vis="filter"][data-step]:not([data-reached~="4"]) .fl-trait-text {
  opacity: 0;
  transform: translateY(6px);
}
[data-vis="filter"][data-step]:not([data-reached~="4"]) .fl-dots circle {
  fill: transparent;
  stroke: var(--slate);
}
[data-vis="filter"][data-step]:not([data-reached~="4"]) .fl-count { opacity: 0; }

/* 4: the read. The line crosses the strip (450ms in, for 1000ms; the
   per-dot delays in the partial are timed to it), from 4px before the
   strip to 4px after it at whatever width the strip is, and the count
   lands once it has passed. */
[data-vis="filter"][data-step="4"] .fl-line {
  animation: fl-sweep 1000ms linear 450ms both;
}
[data-vis="filter"][data-step="4"] .fl-count { transition-delay: 1450ms; }
@keyframes fl-sweep {
  0%   { opacity: 0; left: -42px; }
  8%   { opacity: 1; }
  88%  { opacity: 1; }
  100% { opacity: 0; left: calc(100% - 34px); }
}

/* 0-4: no check yet. */
[data-vis="filter"][data-step]:not([data-reached~="5"]) .fl-check {
  opacity: 0;
  transform: scale(1.4);
}


/* ════ PICTURE: Campaign Targeting 2: 50 intent alerts, split [data-vis="intent"] ════ */

/* The "intent" picture on /for-marketing: 50 intent alerts come out of
   an app as accounts, are read, and split along two arrows into 25 that
   won't ever buy (Slate, thumbs down) and 25 worth the budget (Teal,
   thumbs up). Markup: views/partials/marketing/intent.ejs. Motion:
   the intent section of js/marketing.js.

   Rules this file keeps:
   - Every selector is scoped under [data-vis="intent"].
   - The markup with NO data-step is the finished picture. Earlier steps
     are exceptions written as [data-step]:not([data-reached~="N"]).
   - No transition on the [data-vis] root (marketing.css owns it for the
     fade between passes).

   Colour, by DESIGN.md: the badge is the only Amber (the alerts are the
   problem). Slate is ruled out, Teal is worth working, a slate ring is
   an account not yet read, and the read line is Teal at 85% on a flat
   38px band of Teal at 8%. Lines are hairlines; nothing has a shadow.

   Geometry is set by custom properties on .iv, and .iv is a size
   container, so the picture switches to its compact arrangement by its
   own width (under 500px), not the viewport's. The script measures the
   rendered positions, so it follows whatever this file lays out. */

/* A fixed shape, because .iv is a size container that the script
   measures. On a phone the shape is square, so the two blocks sit close
   to the plate's edges rather than in a band of empty white. */
[data-vis="intent"] {
  --vis-ratio: 1.6 / 1;
  --vis-ratio-phone: 1 / 1;
}

[data-vis="intent"] .iv {
  position: relative;
  height: 100%;
  container-type: size;
}
[data-vis="intent"] .iv-in {
  --app: 72px;          /* icon size */
  --fork: 46%;          /* where the stem forks */
  --out: 58%;           /* where the blocks start */
  --row-a: 25%;         /* the upper arrow */
  --row-b: 75%;         /* the lower arrow */
  --q: 12px;            /* queue pitch */
  --qcols: 10;
  --dot: 9px;
  --gap: 10px;
  --branch-r: 12px;
  --line: rgba(17, 22, 27, 0.34);
  position: absolute;
  inset: 0;
}

/* ── The app and its badge ─────────────────────────────────────────── */

[data-vis="intent"] .iv-app {
  position: absolute;
  left: 0;
  top: calc(50% - var(--app) / 2);
  width: var(--app);
  height: var(--app);
  border-radius: 14px;
  background: var(--ink);
}
[data-vis="intent"] .iv-glyph {
  position: absolute;
  inset: 20%;
  width: 60%;
  height: 60%;
  overflow: visible;
}
[data-vis="intent"] .iv-glyph circle { fill: var(--bg); }
[data-vis="intent"] .iv-glyph path {
  fill: none;
  stroke: var(--bg);
  stroke-width: 2.1;
  stroke-linecap: round;
}
[data-vis="intent"] .iv-glyph path + path { opacity: 0.55; }

/* A 5px badge, the site's badge radius, not a pill. Ink on Amber,
   because white on Amber does not clear 3:1. */
[data-vis="intent"] .iv-badge {
  position: absolute;
  top: -9px;
  right: -12px;
  min-width: 30px;
  height: 22px;
  padding: 0 6px;
  border-radius: 5px;
  background: var(--amber);
  color: var(--ink);
  border: 2px solid var(--surface);
  box-sizing: content-box;
  font-family: var(--mono);
  font-weight: 500;
  font-size: 13px;
  line-height: 22px;
  font-variant-numeric: tabular-nums;
  text-align: center;
  transform-origin: 30% 70%;
  transition: opacity 260ms ease-out, transform 360ms cubic-bezier(0.25, 1, 0.5, 1);
}

[data-vis="intent"] .iv-src-label {
  position: absolute;
  left: 0;
  top: calc(50% + var(--app) / 2 + 12px);
  font-size: 13px;
  line-height: 1.35;
  color: var(--muted);
  white-space: nowrap;
}

/* ── The queue the read line passes over ──────────────────────────── */

/* Empty slots, never drawn. The script measures them and parks the 50
   dots on them while they are read. */
[data-vis="intent"] .iv-queue {
  position: absolute;
  top: 50%;
  left: calc((var(--app) + var(--fork)) / 2);
  transform: translate(-50%, -50%);
  display: grid;
  grid-template-columns: repeat(var(--qcols), var(--q));
  grid-auto-rows: var(--q);
  visibility: hidden;
}

/* ── Stem, arrows, heads ──────────────────────────────────────────── */

[data-vis="intent"] .iv-stem {
  position: absolute;
  top: 50%;
  left: calc(var(--app) + 10px);
  width: calc(var(--fork) - var(--app) - 10px);
  border-top: 1px solid var(--line);
  clip-path: inset(-2px -2px -2px -2px);
  transition: clip-path 360ms ease-out;
}
[data-vis="intent"] .iv-branch {
  position: absolute;
  left: var(--fork);
  width: calc(var(--out) - var(--fork) - 12px);
  border-left: 1px solid var(--line);
  clip-path: inset(-2px -2px -2px -2px);
  transition: clip-path 520ms cubic-bezier(0.25, 0.7, 0.3, 1) 220ms;
}
[data-vis="intent"] .iv-branch-no {
  top: var(--row-a);
  height: calc(50% - var(--row-a));
  border-top: 1px solid var(--line);
  border-top-left-radius: var(--branch-r);
}
[data-vis="intent"] .iv-branch-yes {
  top: 50%;
  height: calc(var(--row-b) - 50%);
  border-bottom: 1px solid var(--line);
  border-bottom-left-radius: var(--branch-r);
}
/* An open chevron at each arrow's end, the tip on the line. */
[data-vis="intent"] .iv-head {
  position: absolute;
  left: calc(var(--out) - 12px);
  width: 6px;
  height: 6px;
  border-top: 1px solid var(--line);
  border-right: 1px solid var(--line);
  transform: translate(-5px, -3px) rotate(45deg);
  transition: opacity 240ms ease-out 640ms;
}
[data-vis="intent"] .iv-head-no { top: var(--row-a); }
[data-vis="intent"] .iv-head-yes { top: calc(var(--row-b) - 1px); }

/* Where the alerts are headed, faint, from the first frame: the same
   stem, arrows and heads in Rule, never clipped, under the real ones.
   Gone at rest, where the real ones cover them. */
[data-vis="intent"] .is-ghost {
  border-color: var(--rule) !important;
  clip-path: none !important;
  opacity: 1 !important;
  transition: none !important;
}
[data-vis="intent"]:not([data-step]) .is-ghost,
[data-vis="intent"]:not([data-step]) .iv-ghost { display: none; }

/* ── The read line ────────────────────────────────────────────────── */

/* Shown only while it moves (step 3); the script sets its position. */
[data-vis="intent"] .iv-read {
  position: absolute;
  top: calc(50% - 46px);
  left: 0;
  width: 1.6px;
  height: 92px;
  background: rgba(0, 168, 138, 0.85);
  opacity: 0;
  pointer-events: none;
  transition: opacity 200ms ease-out;
}
[data-vis="intent"] .iv-read::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  right: 1.6px;
  width: 38px;
  background: rgba(0, 168, 138, 0.08);
}
[data-vis="intent"][data-step="3"] .iv-read { opacity: 1; }

/* ── The two outcomes ─────────────────────────────────────────────── */

[data-vis="intent"] .iv-out {
  position: absolute;
  left: var(--out);
  display: flex;
  align-items: center;
  gap: 22px;
  transform: translateY(-50%);
}
[data-vis="intent"] .iv-out-no { top: var(--row-a); }
[data-vis="intent"] .iv-out-yes { top: var(--row-b); }

[data-vis="intent"] .iv-block,
[data-vis="intent"] .iv-ghost {
  display: grid;
  grid-template-columns: repeat(5, var(--dot));
  grid-auto-rows: var(--dot);
  gap: var(--gap);
}
[data-vis="intent"] .iv-block { position: relative; flex: none; }

/* Each block's 25 places as empty rings, which the dots fill as they
   arrive, as an unread ring fills when the line reads it. */
[data-vis="intent"] .iv-ghost {
  position: absolute;
  inset: 0;
}
[data-vis="intent"] .iv-ghost i {
  display: block;
  border-radius: 50%;
  border: 1.2px solid rgba(183, 190, 196, 0.5);
}

/* One dot is one account. A dot not yet read is a Slate ring (.is-u,
   set by the script while it plays). */
[data-vis="intent"] .iv-dot {
  position: relative;
  display: block;
  width: var(--dot);
  height: var(--dot);
  border-radius: 50%;
  border: 1.2px solid;
  will-change: transform;
  transition: background-color 260ms ease-out, border-color 260ms ease-out;
}
[data-vis="intent"] .iv-out-no .iv-dot {
  background: var(--slate);
  border-color: var(--slate);
}
[data-vis="intent"] .iv-out-yes .iv-dot {
  background: var(--v-target);
  border-color: var(--v-target);
}
[data-vis="intent"] .iv-dot.is-u {
  background: transparent;
  border-color: rgba(183, 190, 196, 0.95);
  border-width: 1.3px;
}

[data-vis="intent"] .iv-meta {
  display: flex;
  align-items: center;
  gap: 12px;
  transition: opacity 420ms ease-out 1050ms, transform 420ms ease-out 1050ms;
}
[data-vis="intent"] .iv-thumb {
  flex: none;
  width: 26px;
  height: 26px;
  overflow: visible;
}
[data-vis="intent"] .iv-thumb rect,
[data-vis="intent"] .iv-thumb path {
  fill: none;
  stroke-width: 1.5;
  stroke-linejoin: round;
  stroke-linecap: round;
}
[data-vis="intent"] .iv-out-no .iv-thumb * { stroke: var(--muted); }
[data-vis="intent"] .iv-out-yes .iv-thumb * { stroke: var(--teal); }

[data-vis="intent"] .iv-figs {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
[data-vis="intent"] .iv-count {
  font-family: var(--display);
  font-weight: 700;
  font-size: 28px;
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
[data-vis="intent"] .iv-out-no .iv-count { color: var(--muted); }
[data-vis="intent"] .iv-out-yes .iv-count { color: var(--teal-deep); }
[data-vis="intent"] .iv-label {
  font-size: 13px;
  line-height: 1.35;
  color: var(--muted);
}
[data-vis="intent"] .iv-out-yes .iv-label { color: var(--body); }

/* Why the two differ: the page's fit bar, Ink at 62% on Track, short for
   the ones that won't buy and long for the ones worth it. */
[data-vis="intent"] .iv-fit {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-top: 5px;
}
[data-vis="intent"] .iv-fit-l {
  font-family: var(--display);
  font-weight: 600;
  font-size: 12px;
  line-height: 1;
  color: var(--muted);
}
[data-vis="intent"] .iv-bar {
  position: relative;
  display: block;
  width: 56px;
  height: 5px;
  border-radius: 2px;
  background: var(--track);
  overflow: hidden;
}
[data-vis="intent"] .iv-bar i {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  border-radius: 2px;
  background: var(--score-ink);
}

/* ── Compact: a phone, or a narrow plate ──────────────────────────── */

@container (max-width: 500px) {
  [data-vis="intent"] .iv-in {
    --app: 50px;
    --fork: 44%;
    --out: 52%;
    --row-a: 21%;
    --row-b: 79%;
    --q: 9px;
    --qcols: 5;
    --dot: 7px;
    --gap: 4px;
    --branch-r: 9px;
  }
  [data-vis="intent"] .iv-app { border-radius: 12px; }
  [data-vis="intent"] .iv-badge {
    top: -8px;
    right: -11px;
    min-width: 24px;
    height: 20px;
    padding: 0 4px;
    font-size: 12px;
    line-height: 20px;
  }
  [data-vis="intent"] .iv-src-label {
    max-width: 4.6em;
    font-size: 12.5px;
    white-space: normal;
  }
  [data-vis="intent"] .iv-read { top: calc(50% - 56px); height: 112px; }
  [data-vis="intent"] .iv-out { gap: 10px; }
  [data-vis="intent"] .iv-meta {
    flex-direction: column;
    align-items: flex-start;
    gap: 7px;
  }
  [data-vis="intent"] .iv-thumb { width: 21px; height: 21px; }
  [data-vis="intent"] .iv-count { font-size: 22px; }
  [data-vis="intent"] .iv-label { font-size: 12px; max-width: 7.5em; text-wrap: balance; }
  [data-vis="intent"] .iv-fit { margin-top: 2px; }
  [data-vis="intent"] .iv-bar { width: 44px; }
}

/* ── Earlier steps ────────────────────────────────────────────────── */

/* Each hidden state sets transition: none, so arming and rewinding are
   instant and only the arrival (the finished-state transition, with its
   delay) animates. */

/* 1: the alerts arrive. */
[data-vis="intent"][data-step]:not([data-reached~="1"]) .iv-badge {
  opacity: 0;
  transform: scale(0.5);
  transition: none;
}
/* 4: the stem and the upper arrow draw, then its head, then its count. */
[data-vis="intent"][data-step]:not([data-reached~="4"]) .iv-stem {
  clip-path: inset(-2px 100% -2px -2px);
  transition: none;
}
[data-vis="intent"][data-step]:not([data-reached~="4"]) .iv-branch-no {
  clip-path: inset(100% 100% -2px -2px);
  transition: none;
}
[data-vis="intent"][data-step]:not([data-reached~="4"]) .iv-head-no,
[data-vis="intent"][data-step]:not([data-reached~="5"]) .iv-head-yes {
  opacity: 0;
  transition: none;
}
[data-vis="intent"][data-step]:not([data-reached~="4"]) .iv-out-no .iv-meta,
[data-vis="intent"][data-step]:not([data-reached~="5"]) .iv-out-yes .iv-meta {
  opacity: 0;
  transform: translateX(-6px);
  transition: none;
}
/* 5: the lower arrow, the same way. */
[data-vis="intent"][data-step]:not([data-reached~="5"]) .iv-branch-yes {
  clip-path: inset(-2px 100% 100% -2px);
  transition: none;
}


/* ════ PICTURE: Campaign Targeting 3: the buying committee [data-vis="persona"] ════ */

/* The "persona" picture on /for-marketing (Campaign Targeting, point 3):
   the buying committee at one account, and one person on it read for
   their persona.

   What it draws, top to bottom:
   - the account, as the homepage draws one: a dot in its verdict colour
     (Teal, target now) and its fit and timing as two separate short
     bars, Ink at 62% on Track. Never one combined figure.
   - a Micro caption naming the list, and the list: six people, each an
     initials square (6px, as in topics) in the neutral pill ground (people are not accounts,
     so they never take a verdict colour), a name, and a real-world title.
   - person 2's card, in front of the list: the same person at a larger
     size, the two phrases in their title lit with the read line's teal
     tint (this is the act of reading), the persona in the confirmed pill,
     and the places they were delivered to as neutral chips.

   Steps (the persona section of marketing.js holds the timings):
     0  the list, every row at full strength
     1  person 2 comes forward: the card grows out of their row while the
        other rows recede (opacity only, never blur). From here the card
        grows downward as it learns more, always to a whole number of rows
     2  "Field Operations" is lit
     3  "Workforce Planning" is lit
     4  the persona pill appears
     5  the delivered chips appear, one after another, and it holds
   The markup with NO data-step is the finished picture (step 5 at rest),
   which is also what no-JS and reduced-motion readers see.

   Rules this file keeps: every selector is scoped under
   [data-vis="persona"]; the plate's shape and padding are set with the
   custom properties marketing.css documents; no transition is set on the
   [data-vis] root itself (marketing.css owns it for the fade between
   passes). No shadows, no gradients. */

/* The plate is as tall as the list (auto), so the title wrapping onto a
   second line on a narrower plate grows it rather than cropping the
   people below the card. */
[data-vis="persona"] {
  --vis-ratio: auto;
  --vis-ratio-phone: auto;
  container-type: inline-size;

  /* One row of the list. The card in front of the list always covers a
     whole number of rows (plus a few px of lift each side), so its edge
     never cuts through the middle of a name: --cover-1 rows while it
     shows only the person, --cover-2 once the persona is in, --cover
     when it is finished. */
  --row-h: 48px;
  --cover-1: 2;
  --cover-2: 3;
  --cover: 3;
  --lift: 7px;

  --ease-out: cubic-bezier(0.22, 0.8, 0.24, 1);
}

[data-vis="persona"] .pc {
  height: 100%;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* ── The account ───────────────────────────────────────────────── */

[data-vis="persona"] .pc-acct {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
[data-vis="persona"] .pc-dot {
  flex: none;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--teal);
}
[data-vis="persona"] .pc-acct-name {
  font-weight: 600;
  font-size: 15.5px;
  line-height: 1.2;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
[data-vis="persona"] .pc-scores {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 16px;
  flex: none;
}
[data-vis="persona"] .pc-score {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
[data-vis="persona"] .pc-score-l {
  /* Fit and Timing labels: Outfit 600 12px Muted, as home.js draws them
     and as every picture on this page sets them. */
  font-family: var(--display);
  font-weight: 600;
  font-size: 12px;
  color: var(--muted);
}
[data-vis="persona"] .pc-bar {
  position: relative;
  display: block;
  width: 44px;
  height: 5px;
  border-radius: 2px;
  background: var(--track);
  overflow: hidden;
}
[data-vis="persona"] .pc-bar i {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  border-radius: 2px;
  background: var(--score-ink);
}

/* ── The list ──────────────────────────────────────────────────── */

[data-vis="persona"] .pc-cap {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-top: 18px;
  padding-bottom: 9px;
  border-bottom: 1px solid var(--rule);
}
[data-vis="persona"] .pc-cap-l {
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
}
[data-vis="persona"] .pc-cap-n {
  font-family: var(--mono);
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

[data-vis="persona"] .pc-body {
  position: relative;
  min-width: 0;
}
[data-vis="persona"] .pc-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
[data-vis="persona"] .pc-row {
  box-sizing: border-box;
  height: var(--row-h);
  display: grid;
  grid-template-columns: 28px 86px minmax(0, 1fr);
  column-gap: 14px;
  align-items: center;
  border-bottom: 1px solid var(--rule);
  /* Finished picture: the list has receded behind the card, still
     readable (names about 4.9:1). */
  opacity: 0.6;
  transition: opacity 420ms ease-out;
}
[data-vis="persona"] .pc-row:last-child { border-bottom: 0; }
/* Person 2's own row is under the card at rest. */
[data-vis="persona"] .pc-row.is-focus { opacity: 0; transition-duration: 260ms; }

[data-vis="persona"] .pc-av {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 6px;  /* people are rounded squares; a circle is an account */
  background: var(--pill-none-bg);
  color: var(--body);  /* initials as topics sets them */
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.02em;
  line-height: 1;
}
[data-vis="persona"] .pc-name {
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
[data-vis="persona"] .pc-title {
  font-size: 14px;
  color: var(--body);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Person 2, brought forward ─────────────────────────────────── */

[data-vis="persona"] .pc-card {
  position: absolute;
  z-index: 1;
  left: calc(var(--lift) * -1.4);
  right: calc(var(--lift) * -1.4);
  top: calc(var(--row-h) - var(--lift));
  min-height: calc(var(--cover) * var(--row-h) + 2 * var(--lift));
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  padding: 16px 20px;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 12px;
  transform-origin: 0 0;
  transition:
    transform 620ms var(--ease-out),
    opacity 300ms ease-out,
    min-height 520ms var(--ease-out);
}

[data-vis="persona"] .pc-card-head {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr);
  column-gap: 14px;
  align-items: center;
}
[data-vis="persona"] .pc-av-lg {
  width: 40px;
  height: 40px;
  font-size: 14px;
}
[data-vis="persona"] .pc-card-who { min-width: 0; }
[data-vis="persona"] .pc-card-name {
  margin: 0;
  font-weight: 600;
  font-size: 15px;
  line-height: 1.3;
  color: var(--ink);
}
[data-vis="persona"] .pc-card-title {
  position: relative;
  z-index: 0;
  margin: 3px 0 0;
  font-size: 18px;
  line-height: 1.4;
  color: var(--body);
}

/* The two phrases read in the title. The tint is the read line's colour
   at the confirmed pill's strength (Teal at 14%), drawn behind the words
   and swept on from the left, so the words stay crisp Ink on top. Each
   phrase is kept on one line so the sweep is one band. */
[data-vis="persona"] .pc-kw {
  position: relative;
  white-space: nowrap;
  color: var(--ink);
  transition: color 300ms ease-out;
}
[data-vis="persona"] .pc-kw::before {
  content: '';
  position: absolute;
  z-index: -1;
  left: -3px;
  right: -3px;
  top: 0.06em;
  bottom: 0.02em;
  border-radius: 3px;
  background: var(--pill-yes-bg);
  transform-origin: 0 50%;
  transition: transform 520ms var(--ease-out);
}

/* What the title adds up to, and where the person went. Indented to the
   title, under the avatar column. */
/* The foot and the delivered line open as they are reached (max-height
   and padding, below), so the card grows as it learns more instead of
   sitting half empty while it waits. */
[data-vis="persona"] .pc-card-foot {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 16px 0 0 54px;
  max-height: 140px;
  overflow: hidden;
  transition:
    max-height 520ms var(--ease-out),
    padding-top 520ms var(--ease-out);
}
[data-vis="persona"] .pc-pill {
  display: inline-block;
  padding: 4px 10px;
  border-radius: 5px;
  background: var(--pill-yes-bg);
  color: var(--teal-deep);
  font-weight: 600;
  font-size: 12px;
  line-height: 1.35;
  transition:
    opacity 360ms ease-out,
    transform 420ms var(--ease-out);
}
[data-vis="persona"] .pc-dest {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 7px;
  margin-top: 12px;
  max-height: 90px;
  transition:
    max-height 520ms var(--ease-out),
    margin-top 520ms var(--ease-out);
}
[data-vis="persona"] .pc-dest-l {
  margin-right: 4px;
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
}
[data-vis="persona"] .pc-chip {
  display: inline-block;
  padding: 3px 9px;
  border-radius: 5px;
  border: 1px solid var(--rule);
  color: var(--body);
  font-weight: 500;
  font-size: 12px;
  line-height: 1.35;
}
[data-vis="persona"] .pc-dest-l,
[data-vis="persona"] .pc-chip {
  transition:
    opacity 340ms ease-out,
    transform 400ms var(--ease-out);
}
[data-vis="persona"] .pc-chip:nth-of-type(2) { transition-delay: 110ms; }
[data-vis="persona"] .pc-chip:nth-of-type(3) { transition-delay: 220ms; }
[data-vis="persona"] .pc-chip:nth-of-type(4) { transition-delay: 330ms; }

/* ── Earlier steps ─────────────────────────────────────────────── */

/* Step 0: the plain list, nothing in front of it. */
[data-vis="persona"][data-step]:not([data-reached~="1"]) .pc-row,
[data-vis="persona"][data-step]:not([data-reached~="1"]) .pc-row.is-focus {
  opacity: 1;
}
/* The card waits on person 2's row, at that row's size (the persona
   section of marketing.js measures the offset and the scale), and grows
   out of it on step 1. */
[data-vis="persona"][data-step]:not([data-reached~="1"]) .pc-card {
  opacity: 0;
  transform: translate(var(--from-x, 0px), var(--from-y, 0px)) scale(var(--from-s, 0.94));
}

/* Steps 2 and 3: one phrase, then the other. */
[data-vis="persona"][data-step]:not([data-reached~="2"]) .pc-kw1,
[data-vis="persona"][data-step]:not([data-reached~="3"]) .pc-kw2 {
  color: var(--body);
}
[data-vis="persona"][data-step]:not([data-reached~="2"]) .pc-kw1::before,
[data-vis="persona"][data-step]:not([data-reached~="3"]) .pc-kw2::before {
  transform: scaleX(0);
}

/* Until the end, the card is only as tall as what it shows, rounded up
   to whole rows. */
[data-vis="persona"][data-step]:not([data-reached~="4"]) .pc-card {
  min-height: calc(var(--cover-1) * var(--row-h) + 2 * var(--lift));
}
[data-vis="persona"][data-step][data-reached~="4"]:not([data-reached~="5"]) .pc-card {
  min-height: calc(var(--cover-2) * var(--row-h) + 2 * var(--lift));
}

/* Step 4: the persona. */
[data-vis="persona"][data-step]:not([data-reached~="4"]) .pc-card-foot {
  max-height: 0;
  padding-top: 0;
}
[data-vis="persona"][data-step]:not([data-reached~="4"]) .pc-pill {
  opacity: 0;
  transform: translateY(5px);
}

/* Step 5: where the person was delivered. */
[data-vis="persona"][data-step]:not([data-reached~="5"]) .pc-dest {
  max-height: 0;
  margin-top: 0;
}
[data-vis="persona"][data-step]:not([data-reached~="5"]) .pc-dest-l,
[data-vis="persona"][data-step]:not([data-reached~="5"]) .pc-chip {
  opacity: 0;
  transform: translateY(5px);
}

/* A plate under 600px (side by side with the copy at about 1041 to
   1200px wide): the title takes two lines, so the finished card covers
   four rows rather than three and its edge still falls between rows. */
@container (max-width: 599px) {
  [data-vis="persona"] .pc { --cover: 4; }
}

/* ── Phone ─────────────────────────────────────────────────────── */

@media (max-width: 520px) {
  [data-vis="persona"] {
    --row-h: 52px;
    --cover-1: 2;
    --cover-2: 3;
    --cover: 4;
    --lift: 6px;
  }
  [data-vis="persona"] .pc-acct-name { font-size: 14.5px; }
  [data-vis="persona"] .pc-scores { gap: 10px; }
  [data-vis="persona"] .pc-score { gap: 5px; }
  [data-vis="persona"] .pc-bar { width: 26px; }
  [data-vis="persona"] .pc-cap { margin-top: 14px; }

  /* Name over title, so a long title still has room before it is cut. */
  [data-vis="persona"] .pc-row {
    grid-template-columns: 28px minmax(0, 1fr);
    grid-template-rows: auto auto;
    column-gap: 11px;
    row-gap: 1px;
    align-content: center;
  }
  [data-vis="persona"] .pc-av { grid-row: 1 / span 2; }
  [data-vis="persona"] .pc-name { font-size: 13px; line-height: 1.3; }
  [data-vis="persona"] .pc-title { font-size: 12.5px; line-height: 1.3; }

  [data-vis="persona"] .pc-card { padding: 14px 14px; }
  [data-vis="persona"] .pc-card-head {
    grid-template-columns: 34px minmax(0, 1fr);
    column-gap: 11px;
    align-items: start;
  }
  [data-vis="persona"] .pc-av-lg { width: 34px; height: 34px; font-size: 12.5px; }
  [data-vis="persona"] .pc-card-name { font-size: 14px; }
  [data-vis="persona"] .pc-card-title { font-size: 15.5px; line-height: 1.38; }
  [data-vis="persona"] .pc-card-foot { padding: 12px 0 0 45px; }
  [data-vis="persona"] .pc-dest { margin-top: 10px; }
  [data-vis="persona"] .pc-pill { font-size: 12px; }
  [data-vis="persona"] .pc-chip { font-size: 12px; padding: 2px 8px; }
  [data-vis="persona"] .pc-dest { gap: 6px; }
  [data-vis="persona"] .pc-dest-l { flex-basis: 100%; margin: 0 0 1px; }
}


/* ════ PICTURE: Account-Based Marketing: the account that moves up [data-vis="abm"] ════ */

/* The Account-Based Marketing picture on /for-marketing.

   One account gathers cited facts from the sources around it, its
   timing rises, and it moves up a ranked list. In the homepage's
   materials: a dot is an account, in its verdict colour; fit and timing
   are two short Ink bars on Track, never combined; Blue marks what is
   new (the two facts, the timing gained); the move is tagged in the
   colour of the account's new standing, Teal, as DESIGN.md's change
   ring rule asks, because Blue already means monitor for timing; a cited
   fact is the evidence row's shape, a 3px rule, the claim, and the
   source and date in Plex Mono.

   The markup with no data-step attribute is the finished picture: the
   ranked list, Harborline Freight 2nd, the two facts that moved it
   beneath. Steps, as the player in marketing.js sets them:
     0  the card alone: monitor for timing signals, fit high, timing low
     1  the four sources appear around it
     2  two of them send a fact into the card, each with its citation
     3  timing rises, the dot turns teal and is ringed once
     4  the card comes apart into the list: its name, dot and bars fly
        to its row at its old place, 5th, its facts to the foot
     5  it moves up to 2nd
   The flights in step 4 and the reorder in step 5 are the abm section
   of marketing.js; every fade is here.

   The plate takes its height from the list (no fixed ratio), so the
   picture never clips at any width. Layout switches on the plate's own
   width (a container query), not the viewport's, because the plate is
   narrower in the stacked tablet layout than on a wide desktop.

   Do not set transition on the [data-vis] root: marketing.css uses it
   for the fade between passes. */

[data-vis="abm"] {
  --vis-ratio: auto;
  --vis-ratio-phone: auto;
  --vis-pad: 26px 26px 22px;
  --vis-pad-phone: 18px 16px 16px;
}

[data-vis="abm"] .abm {
  position: relative;
  container-type: inline-size;
  /* List sizes; the narrow container query below changes them. */
  --abm-rank: 22px;
  --abm-rh: 34px;
  --abm-bw: 104px;
  --abm-rpad: 10px;
}

/* ── Shared pieces ──────────────────────────────────────────────── */

[data-vis="abm"] .abm-dot {
  display: block;
  flex: none;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--v-hold);
}
[data-vis="abm"] .abm-target .abm-dot,
[data-vis="abm"] .abm-dot-target,
[data-vis="abm"] .abm-why-dot,
[data-vis="abm"] .abm-card-dot { background: var(--v-target); }
[data-vis="abm"] .abm-monitor .abm-dot,
[data-vis="abm"] .abm-dot-monitor { background: var(--v-monitor); }

/* A bar shows the whole 100: Ink at 62% on Track, and where the score
   changed on this read, the part it gained in Teal, the colour of the
   account's new standing (DESIGN.md's change ring rule: Blue is already
   spent on "monitor for timing" in this picture's key). */
[data-vis="abm"] .abm-bar {
  position: relative;
  display: block;
  height: 4px;
  border-radius: 2px;
  background: var(--track);
  overflow: hidden;
}
[data-vis="abm"] .abm-bar i {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
}
[data-vis="abm"] .abm-fill { background: var(--score-ink); }
[data-vis="abm"] .abm-gain { background: var(--teal); transform-origin: left center; }

/* A cited fact: the claim over its source and date. Stacked, so it takes
   a hairline rather than a coloured side border (DESIGN.md: in a stacked
   record the colour would read as stripes). */
[data-vis="abm"] .abm-fact {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  padding: 1px 0 1px 12px;
  border-left: 1px solid var(--rule);
}
[data-vis="abm"] .abm-fact-claim {
  font-size: 14px;
  font-weight: 500;
  line-height: 1.3;
  color: var(--ink);
}
[data-vis="abm"] .abm-fact-cite {
  font-family: var(--mono);
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1.3;
  color: var(--muted);
}

/* ── The stage: the card and its sources (steps 0 to 4) ─────────── */

/* Hidden on the finished picture, but still laid out, so the script
   can measure it. Shown from arming until the card has come apart. */
[data-vis="abm"] .abm-stage {
  --abm-cw: min(340px, 100cqw - 300px);
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 160ms ease 640ms, visibility 0s linear 800ms;
}
[data-vis="abm"][data-step]:not([data-reached~="4"]) .abm-stage {
  opacity: 1;
  visibility: visible;
  transition: none;
}

[data-vis="abm"] .abm-card {
  position: relative;
  z-index: 1;
  width: var(--abm-cw);
  border: 1px solid var(--rule);
  border-radius: 12px;
  background: var(--surface-2);
  padding: 18px 20px 20px;
  transition: background-color 220ms ease, border-color 220ms ease;
}
[data-vis="abm"] .abm-card-head {
  display: flex;
  align-items: center;
  gap: 12px;
}
[data-vis="abm"] .abm-card-dot {
  position: relative;
  width: 12px;
  height: 12px;
  transition: background-color 360ms ease 520ms;
}
/* The change ring: once, in the colour of the new standing. */
[data-vis="abm"] .abm-card-dot::after {
  content: '';
  position: absolute;
  inset: -4px;
  border: 1.5px solid var(--teal);
  border-radius: 50%;
  opacity: 0;
}
[data-vis="abm"][data-reached~="3"]:not([data-reached~="4"]) .abm-card-dot::after {
  animation: abm-ring 1600ms cubic-bezier(0.2, 0.7, 0.3, 1) 520ms both;
}
@keyframes abm-ring {
  0% { opacity: 0.9; transform: scale(1); }
  100% { opacity: 0; transform: scale(2.1); }
}
[data-vis="abm"] .abm-card-id {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
[data-vis="abm"] .abm-card-name {
  display: block;
  font-family: var(--display);
  font-size: 17.5px;
  font-weight: 600;
  letter-spacing: -0.016em;
  line-height: 1.25;
  color: var(--ink);
  white-space: nowrap;
}
[data-vis="abm"] .abm-verdicts {
  display: grid;
  font-size: 13px;
  line-height: 1.35;
  color: var(--muted);
}
[data-vis="abm"] .abm-v { grid-area: 1 / 1; transition: opacity 300ms ease 520ms; }
[data-vis="abm"] .abm-v-monitor { opacity: 0; }

[data-vis="abm"] .abm-card-scores {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  margin-top: 16px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--rule);
  transition: border-color 220ms ease;
}
[data-vis="abm"] .abm-score-name {
  display: block;
  font-family: var(--display);
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: 7px;
  transition: opacity 200ms ease;
}
[data-vis="abm"] .abm-card .abm-gain { transition: transform 700ms cubic-bezier(0.2, 0.7, 0.3, 1) 80ms; }

[data-vis="abm"] .abm-card-facts {
  display: grid;
  gap: 12px;
  margin-top: 14px;
}
/* A slot waits as an unknown, a Slate rule over two empty lines, until
   a source fills it. */
[data-vis="abm"] .abm-slot { transition: border-color 260ms ease; }
[data-vis="abm"] .abm-slot .abm-fact-claim,
[data-vis="abm"] .abm-slot .abm-fact-cite {
  transition: opacity 360ms ease, transform 360ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
[data-vis="abm"] .abm-skel {
  position: absolute;
  left: 12px;
  right: 0;
  top: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 8px;
  opacity: 0;
  transition: opacity 200ms ease;
}
[data-vis="abm"] .abm-skel i {
  display: block;
  height: 4px;
  border-radius: 2px;
  background: var(--track);
  width: 62%;
}
[data-vis="abm"] .abm-skel i + i { width: 40%; height: 3px; }
[data-vis="abm"] .abm-slot[data-slot="2"] .abm-skel i { width: 80%; }
[data-vis="abm"] .abm-slot[data-slot="2"] .abm-skel i + i { width: 44%; }

/* The sources: neutral pills either side of the card, each level with
   what it feeds (the script sets their height). The two that send a
   fact turn Blue. */
[data-vis="abm"] .abm-src {
  position: absolute;
  top: 50%;
  white-space: nowrap;
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1;
  padding: 7px 10px;
  border-radius: 5px;
  background: var(--pill-none-bg);
  color: var(--muted);
  transition: opacity 360ms ease, transform 360ms cubic-bezier(0.2, 0.7, 0.3, 1),
              background-color 260ms ease, color 260ms ease;
}
[data-vis="abm"] .abm-src-1,
[data-vis="abm"] .abm-src-3 { right: calc(50% + var(--abm-cw) / 2 + 26px); }
[data-vis="abm"] .abm-src-2,
[data-vis="abm"] .abm-src-4 { left: calc(50% + var(--abm-cw) / 2 + 26px); }
[data-vis="abm"] .abm-src-1,
[data-vis="abm"] .abm-src-2 { background: var(--pill-yes-bg); color: var(--teal-deep); }

/* The lines a fact travels along, from its source to its slot. */
[data-vis="abm"] .abm-links {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  z-index: 0;
}
[data-vis="abm"] .abm-link {
  fill: none;
  stroke: var(--teal);
  stroke-opacity: 0.7;
  stroke-width: 1.2;
  stroke-dasharray: 1;
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 420ms ease-out, opacity 200ms ease;
}

/* Step 0: only the card. */
[data-vis="abm"][data-step]:not([data-reached~="1"]) .abm-src {
  opacity: 0;
  transform: translateY(5px);
}
[data-vis="abm"] .abm-src-2 { transition-delay: 110ms; }
[data-vis="abm"] .abm-src-3 { transition-delay: 220ms; }
[data-vis="abm"] .abm-src-4 { transition-delay: 330ms; }

/* Before step 2: every source neutral, every slot unknown. */
[data-vis="abm"][data-step]:not([data-reached~="2"]) .abm-src-1,
[data-vis="abm"][data-step]:not([data-reached~="2"]) .abm-src-2 {
  background: var(--pill-none-bg);
  color: var(--muted);
}
[data-vis="abm"][data-step]:not([data-reached~="2"]) .abm-link { stroke-dashoffset: 1; transition: none; }
[data-vis="abm"][data-step]:not([data-reached~="2"]) .abm-slot { border-left-color: var(--slate); }
[data-vis="abm"][data-step]:not([data-reached~="2"]) .abm-skel { opacity: 1; }
[data-vis="abm"][data-step]:not([data-reached~="2"]) .abm-slot .abm-fact-claim,
[data-vis="abm"][data-step]:not([data-reached~="2"]) .abm-slot .abm-fact-cite {
  opacity: 0;
  transform: translateX(-6px);
}

/* Step 2: the first source lights, its line draws, its fact lands;
   then the second, 900ms behind. */
[data-vis="abm"][data-reached~="2"] .abm-src-1 { transition-delay: 0ms; }
[data-vis="abm"][data-reached~="2"] .abm-src-2 { transition-delay: 900ms; }
[data-vis="abm"][data-reached~="2"] .abm-link[data-link="1"] { transition-delay: 160ms; }
[data-vis="abm"][data-reached~="2"] .abm-link[data-link="2"] { transition-delay: 1060ms; }
[data-vis="abm"][data-reached~="2"] .abm-slot[data-slot="1"] { transition-delay: 520ms; }
[data-vis="abm"][data-reached~="2"] .abm-slot[data-slot="2"] { transition-delay: 1420ms; }
[data-vis="abm"][data-reached~="2"] .abm-slot[data-slot="1"] .abm-skel { transition-delay: 480ms; }
[data-vis="abm"][data-reached~="2"] .abm-slot[data-slot="2"] .abm-skel { transition-delay: 1380ms; }
[data-vis="abm"][data-reached~="2"] .abm-slot[data-slot="1"] .abm-fact-claim { transition-delay: 560ms; }
[data-vis="abm"][data-reached~="2"] .abm-slot[data-slot="1"] .abm-fact-cite { transition-delay: 660ms; }
[data-vis="abm"][data-reached~="2"] .abm-slot[data-slot="2"] .abm-fact-claim { transition-delay: 1460ms; }
[data-vis="abm"][data-reached~="2"] .abm-slot[data-slot="2"] .abm-fact-cite { transition-delay: 1560ms; }

/* Before step 3: monitor for timing signals, timing low. */
[data-vis="abm"][data-step]:not([data-reached~="3"]) .abm-card-dot { background: var(--v-monitor); }
[data-vis="abm"][data-step]:not([data-reached~="3"]) .abm-v-monitor { opacity: 1; }
[data-vis="abm"][data-step]:not([data-reached~="3"]) .abm-v-target { opacity: 0; }
[data-vis="abm"][data-step]:not([data-reached~="3"]) .abm-card .abm-gain { transform: scaleX(0); }

/* Step 4 (and the finished picture): the card's chrome goes, so only
   the pieces that have a home in the list are left to fly to it. */
[data-vis="abm"][data-reached~="4"] .abm-src,
[data-vis="abm"][data-reached~="4"] .abm-link[data-link],
[data-vis="abm"][data-reached~="4"] .abm-score-name,
[data-vis="abm"][data-reached~="4"] .abm-verdicts {
  opacity: 0;
  transition: opacity 200ms ease;
}
[data-vis="abm"][data-reached~="4"] .abm-card {
  background-color: transparent;
  border-color: transparent;
}
[data-vis="abm"][data-reached~="4"] .abm-card-scores { border-bottom-color: transparent; }
/* The flying name is set in Outfit and its row's in Plex, so the two are
   never shown together: the card's goes the instant it lands, and the
   featured row (below) appears in that same frame. The delay is here,
   not only in the script's flight, because the script measures the
   layout before it starts the flight. */
[data-vis="abm"][data-reached~="4"] .abm-card-name {
  opacity: 0;
  transition: opacity 0s linear 640ms;
}

/* ── The ranked list (the finished picture) ─────────────────────── */

[data-vis="abm"] .abm-list {
  position: relative;
  z-index: 1;
}

/* Step 4: the list comes up as the pieces arrive. The featured row and
   the two facts appear only as the stage hands them over, so the
   flying pieces and their resting places are never both seen. */
[data-vis="abm"] .abm-head,
[data-vis="abm"] .abm-ranks,
[data-vis="abm"] .abm-row,
[data-vis="abm"] .abm-why-head,
[data-vis="abm"] .abm-key { transition: opacity 360ms ease 380ms; }
[data-vis="abm"] .abm-row.is-featured { transition: opacity 0s linear 640ms; }
[data-vis="abm"] .abm-why-facts { transition: opacity 160ms ease 640ms; }
[data-vis="abm"][data-step]:not([data-reached~="4"]) .abm-head,
[data-vis="abm"][data-step]:not([data-reached~="4"]) .abm-ranks,
[data-vis="abm"][data-step]:not([data-reached~="4"]) .abm-row,
[data-vis="abm"][data-step]:not([data-reached~="4"]) .abm-why-head,
[data-vis="abm"][data-step]:not([data-reached~="4"]) .abm-why-facts,
[data-vis="abm"][data-step]:not([data-reached~="4"]) .abm-key {
  opacity: 0;
  transition: none;
}

[data-vis="abm"] .abm-head,
[data-vis="abm"] .abm-row {
  display: grid;
  grid-template-columns: 10px minmax(0, 1fr) var(--abm-bw) var(--abm-bw);
  column-gap: 14px;
  align-items: center;
}
[data-vis="abm"] .abm-head {
  margin-left: var(--abm-rank);
  padding: 0 var(--abm-rpad) 9px;
  border-bottom: 1px solid var(--rule);
}
[data-vis="abm"] .abm-caption {
  grid-column: 1 / span 2;
  font-family: var(--mono);
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  white-space: nowrap;
}
[data-vis="abm"] .abm-col {
  font-family: var(--display);
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
}

[data-vis="abm"] .abm-table {
  position: relative;
  display: grid;
  grid-template-columns: var(--abm-rank) minmax(0, 1fr);
}
/* The rank numbers are a fixed column, counted by CSS, so they stay
   put while the rows slide past them. */
[data-vis="abm"] .abm-ranks {
  list-style: none;
  counter-reset: abm-rank;
}
[data-vis="abm"] .abm-ranks li {
  counter-increment: abm-rank;
  height: var(--abm-rh);
  display: flex;
  align-items: center;
  font-family: var(--mono);
  font-weight: 500;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}
[data-vis="abm"] .abm-ranks li::before { content: counter(abm-rank); }

[data-vis="abm"] .abm-rows { list-style: none; position: relative; }
[data-vis="abm"] .abm-row {
  position: relative;
  height: var(--abm-rh);
  padding: 0 var(--abm-rpad);
  border-bottom: 1px solid var(--rule);
  background: var(--surface);
}
[data-vis="abm"] .abm-name {
  display: block;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14px;
  line-height: 1.25;
  color: var(--ink);
}
/* The account that moved: a quiet Tint ground, so the eye can follow it
   up the list and down to its facts. */
[data-vis="abm"] .abm-row.is-featured {
  z-index: 1;
  background: var(--tint);
}
[data-vis="abm"] .abm-row.is-featured .abm-name { font-weight: 600; }

/* Why it moved: its two facts, cited, beneath the list. */
[data-vis="abm"] .abm-why {
  margin-top: 18px;
  margin-left: var(--abm-rank);
  padding: 0 var(--abm-rpad);
}
[data-vis="abm"] .abm-why-head {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
[data-vis="abm"] .abm-why-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink);
}
[data-vis="abm"] .abm-moved {
  flex: none;
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  padding: 4px 8px;
  border-radius: 5px;
  background: var(--pill-yes-bg);
  color: var(--teal-deep);
  transition: opacity 320ms ease 700ms, transform 320ms cubic-bezier(0.2, 0.7, 0.3, 1) 700ms;
}
[data-vis="abm"][data-step]:not([data-reached~="5"]) .abm-moved {
  opacity: 0;
  transform: translateY(3px);
  transition: none;
}
[data-vis="abm"] .abm-why-facts {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 12px 20px;
  margin-top: 12px;
}

[data-vis="abm"] .abm-key {
  list-style: none;
  margin: 22px 0 0 var(--abm-rank);
  padding-left: var(--abm-rpad);
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  font-size: 12px;
  line-height: 1.3;
  color: var(--muted);
}
[data-vis="abm"] .abm-key li { display: flex; align-items: center; gap: 7px; }
[data-vis="abm"] .abm-key .abm-dot { width: 8px; height: 8px; }

/* ── Narrow plates ──────────────────────────────────────────────── */

/* Too narrow for a source either side of the card (the card would drop
   under 300px): two above it, two below, the lines dropping straight
   into it. */
@container (max-width: 599px) {
  [data-vis="abm"] .abm-stage {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-rows: auto auto auto;
    align-content: center;
    column-gap: 12px;
  }
  [data-vis="abm"] .abm-card { width: auto; grid-column: 1 / span 2; grid-row: 2; padding: 16px 16px 18px; }
  [data-vis="abm"] .abm-src { position: static; justify-self: start; }
  [data-vis="abm"] .abm-src-1 { grid-column: 1; grid-row: 1; align-self: end; margin-bottom: 26px; }
  [data-vis="abm"] .abm-src-2 { grid-column: 2; grid-row: 1; align-self: end; margin-bottom: 26px; justify-self: end; }
  [data-vis="abm"] .abm-src-3 { grid-column: 1; grid-row: 3; align-self: start; margin-top: 26px; }
  [data-vis="abm"] .abm-src-4 { grid-column: 2; grid-row: 3; align-self: start; margin-top: 26px; justify-self: end; }
}

/* A phone: shorter bars and a tighter row, so the names keep room. */
@container (max-width: 400px) {
  [data-vis="abm"] .abm-list {
    --abm-rank: 16px;
    --abm-rh: 32px;
    --abm-bw: 44px;
    --abm-rpad: 8px;
  }
  [data-vis="abm"] .abm-head,
  [data-vis="abm"] .abm-row { column-gap: 9px; }
  [data-vis="abm"] .abm-name { font-size: 13px; }
  [data-vis="abm"] .abm-why { margin-top: 16px; }
  [data-vis="abm"] .abm-why-facts { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  [data-vis="abm"] .abm-fact-claim { font-size: 13.5px; }
  [data-vis="abm"] .abm-key { gap: 5px 14px; margin-top: 18px; }
}


/* ════ PICTURE: Content Marketing: problems by volume [data-vis="topics"] ════ */

/* The "topics" picture on /for-marketing (Content Marketing).

   A short ruled table of six problems. Read left to right it tells the
   section's three sentences in order: the problem, how many accounts
   have it (the volume bar), and who to invite to speak on it.

   Steps (the markup with no data-step is the finished picture):
     0  the six problems in the order a team would guess them; the bars
        are empty tracks, unread, and the counts are not shown yet.
     1  the read line passes down the list and fills each row's bar,
        with its count, as it crosses it.
     2  the rows re-sort by volume (a FLIP move in the topics section of
        marketing.js), the ranks
        1 to 6 settle in, the heading changes, and the bottom three
        recede so the top three carry the emphasis.
     3  the top three each gain the people to invite to speak on it.

   Materials are the homepage's: hairline rows, the grid's score bar
   (Ink at 62% on Track, square ends), the teal read line with its flat
   band, Plex Mono for every figure, Teal Deep for the ranks because they
   are a real order (clause 3 of the Confirmed Teal Rule).

   People are rounded squares, not circles: on this page a dot is an
   account, so a person must not be drawn as one.

   Do not set transition on the [data-vis] root: marketing.css owns it
   for the fade between passes. */

[data-vis="topics"] {
  /* The plate is as tall as the table, so a label edited in /admin that
     wraps to two lines grows the plate instead of being clipped. About
     674 by 420 at 1440. */
  --vis-ratio: auto;
  --vis-ratio-phone: auto;
  --vis-pad: 26px 28px 22px;
  --vis-pad-phone: 18px 18px 14px;

  /* One set of columns for the labels and the rows. */
  --tp-cols: 22px minmax(0, 1fr) 128px 34px 122px;
  --tp-gap: 14px;
}

[data-vis="topics"] .tp { display: block; }

/* ── Heading ─────────────────────────────────────────────────────── */

[data-vis="topics"] .tp-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin: 0 0 18px;
}

/* The two headings share one cell and cross-fade. */
[data-vis="topics"] .tp-title {
  display: grid;
  margin: 0;
  font-family: var(--display);
  font-weight: 600;
  font-size: 17px;
  line-height: 1.25;
  letter-spacing: -0.016em;
  color: var(--ink);
}
[data-vis="topics"] .tp-title > span {
  grid-area: 1 / 1;
  transition: opacity 360ms ease-out 120ms;
}
[data-vis="topics"] .tp-title-before { opacity: 0; }

[data-vis="topics"] .tp-market {
  margin: 0;
  flex: none;
  font-family: var(--mono);
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

/* ── Column labels ───────────────────────────────────────────────── */

[data-vis="topics"] .tp-cols,
[data-vis="topics"] .tp-row {
  display: grid;
  grid-template-columns: var(--tp-cols);
  column-gap: var(--tp-gap);
  align-items: center;
}

[data-vis="topics"] .tp-cols {
  align-items: end;
  padding-bottom: 9px;
  border-bottom: 1px solid var(--rule);
}

/* Micro, the label inside a panel. */
[data-vis="topics"] .tp-col {
  font-family: var(--text);
  font-weight: 600;
  font-size: 12px;
  line-height: 1.3;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
}
[data-vis="topics"] .tp-col-problem { grid-column: 2; }
[data-vis="topics"] .tp-col-accounts { grid-column: 3 / span 2; }
[data-vis="topics"] .tp-col-speakers {
  grid-column: 5;
  transition: opacity 320ms ease-out;
}

/* ── Rows ───────────────────────────────────────────────────────── */

/* isolation keeps the rows' z-index during the sort inside the
   picture, below the sticky header. */
[data-vis="topics"] .tp-body { position: relative; isolation: isolate; }

/* A grid column so the script can place rows with the order property. */
[data-vis="topics"] .tp-list {
  display: grid;
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Each row is opaque so a row that moves past another during the sort
   covers it cleanly rather than showing through. Every row is ruled
   below, the last included, as the page's own hairline lists are: the
   rows are placed by the order property, so :last-child would not
   follow the sort. */
[data-vis="topics"] .tp-row {
  position: relative;
  min-height: 50px;
  padding: 9px 0;
  background: var(--surface);
  border-bottom: 1px solid var(--rule);
}

[data-vis="topics"] .tp-rank {
  font-family: var(--mono);
  font-weight: 500;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  transition: opacity 320ms ease-out 420ms;
}
[data-vis="topics"] .tp-row.is-top .tp-rank { color: var(--teal-deep); }

[data-vis="topics"] .tp-label {
  font-size: 15px;
  line-height: 1.35;
  text-wrap: balance;
  color: var(--body);
  transition: color 420ms ease-out 380ms;
}
[data-vis="topics"] .tp-row.is-top .tp-label {
  color: var(--ink);
  font-weight: 500;
}

/* The grid's score bar: Track for the whole scale, Ink at 62% for the
   count. Square ends, as on the homepage. */
[data-vis="topics"] .tp-bar {
  position: relative;
  display: block;
  height: 8px;
  background: var(--track);
}
[data-vis="topics"] .tp-fill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  background: var(--score-ink);
  transform-origin: left center;
  /* Timed to the read line crossing this row while the list is still in
     its guessed order, where row --g sits at position --g. */
  transition: transform 460ms cubic-bezier(0.22, 1, 0.36, 1) calc(var(--g) * 225ms + 170ms);
}

[data-vis="topics"] .tp-count {
  font-family: var(--mono);
  font-weight: 500;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  text-align: right;
  color: var(--ink);
  transition: opacity 300ms ease-out calc(var(--g) * 225ms + 260ms);
}

/* People to invite to speak: initials in rounded squares, stacked. */
[data-vis="topics"] .tp-speakers {
  display: flex;
  align-items: center;
  gap: 4px;
  min-height: 28px;
}
[data-vis="topics"] .tp-av {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 6px;
  background: var(--pill-none-bg);
  font-family: var(--text);
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.02em;
  color: var(--body);  /* initials as persona sets them */
  transition:
    opacity 300ms ease-out calc(var(--k) * 150ms + var(--j) * 80ms + 160ms),
    transform 380ms cubic-bezier(0.22, 1, 0.36, 1) calc(var(--k) * 150ms + var(--j) * 80ms + 160ms);
}

/* ── The read line ──────────────────────────────────────────────── */

/* 1.6px Teal at 85% with a flat 38px band of Teal at 8% trailing it,
   moving down the list. Shown only while it moves. */
[data-vis="topics"] .tp-read {
  position: absolute;
  left: -28px;
  right: -28px;
  top: 0;
  height: 38px;
  transform: translateY(-100%);
  background: rgba(0, 168, 138, 0.08);
  border-bottom: 1.6px solid rgba(0, 168, 138, 0.85);
  opacity: 0;
  pointer-events: none;
}
[data-vis="topics"][data-step="1"] .tp-read {
  animation: tp-read 1400ms linear both;
}
@keyframes tp-read {
  0%   { top: 0;    opacity: 0; }
  6%   {            opacity: 1; }
  92%  {            opacity: 1; }
  100% { top: 100%; opacity: 0; }
}

/* ── Earlier steps ──────────────────────────────────────────────── */

/* Until the read (step 1): empty tracks, no counts. */
[data-vis="topics"][data-step]:not([data-reached~="1"]) .tp-fill { transform: scaleX(0); }
[data-vis="topics"][data-step]:not([data-reached~="1"]) .tp-count { opacity: 0; }

/* Until the sort (step 2): the guessed heading, no ranks, every row in
   the same weight of colour. */
[data-vis="topics"][data-step]:not([data-reached~="2"]) .tp-title-before { opacity: 1; }
[data-vis="topics"][data-step]:not([data-reached~="2"]) .tp-title-after { opacity: 0; }
[data-vis="topics"][data-step]:not([data-reached~="2"]) .tp-rank { opacity: 0; }
[data-vis="topics"][data-step]:not([data-reached~="2"]) .tp-label { color: var(--ink); font-weight: 400; }

/* Until step 3: no speakers. */
[data-vis="topics"][data-step]:not([data-reached~="3"]) .tp-col-speakers { opacity: 0; }
[data-vis="topics"][data-step]:not([data-reached~="3"]) .tp-av {
  opacity: 0;
  transform: translateX(-6px);
}

/* ── Phone ──────────────────────────────────────────────────────── */

/* Two lines a row: the problem across the full width, then its bar,
   its count right after it, and (top three only) its speakers. The bars
   keep one length scale because every row's track is the same width.
   The accounts label goes, since the heading already says "by number of
   accounts" and the counts sit on the bars. */
@media (max-width: 520px) {
  [data-vis="topics"] {
    --tp-cols: 16px minmax(0, 1fr) 30px 80px;
    --tp-gap: 10px;
  }
  [data-vis="topics"] .tp-head {
    display: block;
    margin-bottom: 14px;
  }
  [data-vis="topics"] .tp-title { font-size: 16px; }
  [data-vis="topics"] .tp-market { margin-top: 4px; }

  [data-vis="topics"] .tp-col-accounts { display: none; }
  [data-vis="topics"] .tp-col-speakers { grid-column: 3 / span 2; text-align: right; white-space: nowrap; }

  [data-vis="topics"] .tp-row {
    grid-template-areas:
      "rank label label label"
      "rank bar   count speakers";
    row-gap: 7px;
    align-items: center;
    min-height: 0;
    padding: 10px 0;
  }
  [data-vis="topics"] .tp-rank { grid-area: rank; align-self: start; padding-top: 1px; }
  [data-vis="topics"] .tp-label { grid-area: label; font-size: 14px; }
  [data-vis="topics"] .tp-speakers { grid-area: speakers; justify-content: flex-end; }
  [data-vis="topics"] .tp-bar { grid-area: bar; height: 6px; }
  [data-vis="topics"] .tp-count { grid-area: count; font-size: 12px; text-align: left; }
  [data-vis="topics"] .tp-read { left: -18px; right: -18px; }
  [data-vis="topics"] .tp-speakers { gap: 4px; min-height: 24px; }
  [data-vis="topics"] .tp-av { width: 24px; height: 24px; }
}


/* ════ PICTURE: Learn From & Educate 1: the dashboard and its chat [data-vis="chat"] ════ */

/* The dashboard and chat picture on /for-marketing (Learn From &
   Educate the Market, point 1).

   A market dashboard in the site's own materials, not a dashboard skin:
   hairlines rather than boxes, figures in Plex Mono, the homepage
   chart's dots and quadrant rules, and fit and timing as two bars. A
   chat panel opens over its lower right corner, separated from it by
   its own hairline and by standing a little proud of the grid, never by
   a shadow. The accounts the answer is about are ringed in Ink, so the
   answer is tied to the data it came from. Ink, not a verdict colour:
   the ring is a selection, the dots inside it keep their own standing,
   and Blue already means monitor for timing on this chart.

   The markup with no data-step attribute is the finished picture.
   Steps, as the player in marketing.js sets them:
     0  the dashboard alone
     1  the chat panel rises into the lower right
     2  the question types in (the chat section of marketing.js)
     3  the answer arrives word by word (the same), then its source
     4  the accounts it means are ringed on the chart; the rest recede
   Do not set transition on the [data-vis] root: marketing.css uses it
   for the fade between passes. */

/* The plate takes its height from what is drawn on it (auto ratio)
   rather than from a fixed shape, because the layout inside changes with
   the plate's own width (the container queries at the foot of this
   file), and a fixed shape would clip the chat panel at the widths in
   between. At 1440 it comes out about 674 by 432. */
/* The plate's padding is 12px wider on the right and below, so the
   chat panel, which stands 12px proud of the dashboard there, keeps the
   same 24px from the plate's edge as everything else. */
[data-vis="chat"] {
  --vis-ratio: auto;
  --vis-ratio-phone: auto;
  --vis-pad: 24px 36px 36px 24px;
  --vis-pad-phone: 16px;

  --ch-ease: cubic-bezier(0.22, 0.7, 0.3, 1);

  /* Fixed heights down the dashboard, so the chat panel can open exactly
     below the list's first row (Harborline Freight) and never cut a row
     in half. */
  --ch-top-h: 34px;
  --ch-figs-h: 68px;
  --ch-gap: 14px;
  --ch-head-h: 27px;
  --ch-row-h: 34px;
  --ch-body-h: 268px;

  container-type: inline-size;
}

[data-vis="chat"] .ch { position: relative; }

/* ── The dashboard ──────────────────────────────────────────────── */

[data-vis="chat"] .ch-dash {
  display: flex;
  flex-direction: column;
}

[data-vis="chat"] .ch-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  height: var(--ch-top-h);
  border-bottom: 1px solid var(--rule);
}
[data-vis="chat"] .ch-title {
  font-family: var(--display);
  font-size: 17px;
  line-height: 20px;
  font-weight: 600;
  letter-spacing: -0.012em;
  color: var(--ink);
}
[data-vis="chat"] .ch-asof,
[data-vis="chat"] .ch-list-count {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

/* Four figures in a row, divided by hairlines rather than boxed. The
   three verdict figures carry their dot, so they are also the chart's
   key. */
[data-vis="chat"] .ch-figs {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  /* The monitor figure is wider, so its name, the homepage key's four
     words, fits on one line. */
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 0.9fr) minmax(0, 1.3fr) minmax(0, 0.9fr);
  height: var(--ch-figs-h);
  border-bottom: 1px solid var(--rule);
}
[data-vis="chat"] .ch-fig {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 5px;
  padding: 12px 12px 12px 14px;
  border-left: 1px solid var(--rule);
  min-width: 0;
}
/* Fit and Timing column labels: Outfit 600 12px Muted, as home.js draws
   them and as every picture on this page sets them. */
[data-vis="chat"] .ch-col {
  font-family: var(--display);
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
}
[data-vis="chat"] .ch-fig:first-child { border-left: 0; padding-left: 0; }
[data-vis="chat"] .ch-fig-name {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  line-height: 16px;
  color: var(--muted);
  white-space: nowrap;
}
[data-vis="chat"] .ch-fig-num {
  font-family: var(--mono);
  font-size: 20px;
  font-weight: 500;
  line-height: 22px;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
[data-vis="chat"] .ch-key {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
}
[data-vis="chat"] .ch-key-target { background: var(--teal); }
[data-vis="chat"] .ch-key-monitor { background: var(--blue); }
[data-vis="chat"] .ch-key-hold { background: #767F89; }

/* The chart on the left, the list on the right. */
[data-vis="chat"] .ch-body {
  height: calc(var(--ch-gap) + var(--ch-body-h));
  display: grid;
  grid-template-columns: minmax(0, 45fr) minmax(0, 55fr);
  gap: 26px;
  padding-top: var(--ch-gap);
}

/* ── The chart ──────────────────────────────────────────────────── */

[data-vis="chat"] .ch-chart {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-height: 0;
}
[data-vis="chat"] .ch-axis {
  font-family: var(--display);
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  color: var(--muted);
}
[data-vis="chat"] .ch-axis-x { align-self: flex-end; }

/* The homepage chart's plot: a hairline box on near-white, the quadrant
   cross, and the target now quadrant washed with flat teal. */
[data-vis="chat"] .ch-plot {
  position: relative;
  flex: 1;
  min-height: 0;
  border: 1px solid var(--rule);
  border-radius: 8px;
  background: #FCFDFC;
  overflow: hidden;
}
[data-vis="chat"] .ch-wash {
  position: absolute;
  left: 50%;
  top: 0;
  right: 0;
  bottom: 50%;
  background: rgba(0, 168, 138, 0.06);
}
/* The homepage hero chart's own rules (home.js axes()): #EAEDE9 for the
   quarter lines, #D3D8D2 for the two midlines, so this scatter is that
   chart, not a lookalike. */
[data-vis="chat"] .ch-q,
[data-vis="chat"] .ch-mid { position: absolute; display: block; }
[data-vis="chat"] .ch-qv { top: 0; bottom: 0; width: 1px; background: #EAEDE9; }
[data-vis="chat"] .ch-qh { left: 0; right: 0; height: 1px; background: #EAEDE9; }
[data-vis="chat"] .ch-midv { left: 50%; top: 0; bottom: 0; width: 1.5px; margin-left: -0.75px; background: #D3D8D2; }
[data-vis="chat"] .ch-midh { top: 50%; left: 0; right: 0; height: 1.5px; margin-top: -0.75px; background: #D3D8D2; }

/* One dot is one account, in its verdict colour. */
[data-vis="chat"] .ch-pt {
  position: absolute;
  width: 7px;
  height: 7px;
  margin: -3.5px 0 0 -3.5px;
  border-radius: 50%;
  background: var(--v-hold);
  transition: opacity 500ms ease;
}
[data-vis="chat"] .ch-pt-monitor { background: var(--v-monitor); }
[data-vis="chat"] .ch-pt-target {
  width: 9px;
  height: 9px;
  margin: -4.5px 0 0 -4.5px;
  background: var(--v-target);
  border: 1px solid rgba(255, 255, 255, 0.85);
}

/* The answer's accounts: an Ink ring, a selection that claims no
   standing. The others recede so the ringed ones read as the answer. */
[data-vis="chat"] .ch-pt:not(.is-hit) { opacity: 0.5; }
[data-vis="chat"] .ch-ring {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 17px;
  height: 17px;
  margin: -8.5px 0 0 -8.5px;
  border-radius: 50%;
  border: 1.4px solid rgba(17, 22, 27, 0.7);
  transition: opacity 420ms ease var(--d, 0ms), transform 520ms var(--ch-ease) var(--d, 0ms);
}

/* ── The list ───────────────────────────────────────────────────── */

[data-vis="chat"] .ch-list { min-width: 0; }
[data-vis="chat"] .ch-list-head,
[data-vis="chat"] .ch-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 54px 54px;
  gap: 12px;
  align-items: center;
}
[data-vis="chat"] .ch-list-head {
  height: var(--ch-head-h);
  align-items: start;
  border-bottom: 1px solid var(--rule);
}
[data-vis="chat"] .ch-list-name {
  display: flex;
  align-items: baseline;
  gap: 10px;
  min-width: 0;
  white-space: nowrap;
}
[data-vis="chat"] .ch-list-title {
  font-size: 13px;
  line-height: 18px;
  font-weight: 600;
  color: var(--ink);
}
[data-vis="chat"] .ch-col { line-height: 18px; }
[data-vis="chat"] .ch-rows { list-style: none; margin: 0; padding: 0; }
[data-vis="chat"] .ch-row {
  height: var(--ch-row-h);
  border-bottom: 1px solid var(--rule);
}
[data-vis="chat"] .ch-acct {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}
[data-vis="chat"] .ch-name {
  font-size: 13px;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
[data-vis="chat"] .ch-dot {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--v-hold);
}
[data-vis="chat"] .ch-dot-target { background: var(--v-target); }
[data-vis="chat"] .ch-dot-monitor { background: var(--v-monitor); }

/* A bar shows the whole 100: Ink at 62% on Track, and the timing an
   account gained this read in Blue. */
[data-vis="chat"] .ch-bar {
  position: relative;
  display: block;
  height: 4px;
  border-radius: 2px;
  background: var(--track);
  overflow: hidden;
}
[data-vis="chat"] .ch-bar i { position: absolute; top: 0; bottom: 0; left: 0; }
[data-vis="chat"] .ch-fill { background: var(--score-ink); }
[data-vis="chat"] .ch-gain { background: var(--blue); }

/* ── The chat panel ─────────────────────────────────────────────── */

/* Over the list, standing a little proud of the dashboard's grid on the
   right and below, so it reads as a layer by position and its own
   hairline, with no shadow. */
[data-vis="chat"] .ch-panel {
  position: absolute;
  z-index: 2;
  top: calc(var(--ch-top-h) + var(--ch-figs-h) + var(--ch-gap) + var(--ch-head-h) + var(--ch-row-h) + 4px);
  right: -12px;
  bottom: -12px;
  width: calc(55% + 6px);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 12px;
  overflow: hidden;
  /* Opaque quickly, so the list does not show through it for long. */
  transition: opacity 240ms ease, transform 560ms var(--ch-ease);
}
[data-vis="chat"] .ch-convo {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 16px 16px 14px;
}

/* The question: the reader's own words, set right on a quiet ground. */
[data-vis="chat"] .ch-ask {
  position: relative;
  align-self: flex-end;
  max-width: 88%;
  margin: 0;
  padding: 8px 12px;
  border-radius: 8px;
  background: var(--tint);
  font-size: 13.5px;
  line-height: 1.42;
  color: var(--ink);
  /* Plain wrapping, not the pretty wrapping p takes from base.css, so
     the typed question breaks exactly where the finished one does. */
  text-wrap: wrap;
  transition: opacity 260ms ease;
}
[data-vis="chat"] .ch-ask-typed { display: none; }

/* The answer: plain sentences, then where it came from. */
[data-vis="chat"] .ch-answer {
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
}
[data-vis="chat"] .ch-w { transition: opacity 260ms ease; }
[data-vis="chat"] .ch-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 14px;
  margin-top: 10px;
  transition: opacity 360ms ease, transform 420ms var(--ch-ease);
}
[data-vis="chat"] .ch-source {
  padding: 3px 9px;
  border-radius: 5px;
  background: var(--pill-none-bg);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--muted);
}
[data-vis="chat"] .ch-marked {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--muted);
  transition: opacity 360ms ease;
}
[data-vis="chat"] .ch-marked-ring {
  flex: none;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  border: 1.4px solid rgba(17, 22, 27, 0.7);
}

[data-vis="chat"] .ch-input {
  margin-top: auto;
  padding: 10px 16px 11px;
  border-top: 1px solid var(--rule);
  font-size: 12.5px;
  line-height: 1.3;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Earlier steps ──────────────────────────────────────────────── */

/* 0: no panel yet. */
[data-vis="chat"][data-step]:not([data-reached~="1"]) .ch-panel {
  opacity: 0;
  transform: translateY(26px);
}

/* 1: panel open, nothing asked. 2: the question types in. The script
   keeps the untyped rest of it in place, invisible, so the bubble is
   its final size from the first character and no line reflows. */
[data-vis="chat"][data-step]:not([data-reached~="2"]) .ch-ask { opacity: 0; }
[data-vis="chat"][data-step="2"] .ch-ask-full { display: none; }
[data-vis="chat"][data-step="2"] .ch-ask-typed { display: inline; }
[data-vis="chat"] .ch-ask-off { visibility: hidden; }
/* The caret is the right border of the typed part, pulled back by its
   own width, so it adds no width and no break opportunity and the typed
   text wraps exactly as the finished question does. */
[data-vis="chat"][data-step="2"] .ch-ask-on {
  border-right: 1.5px solid var(--ink);
  margin-right: -1.5px;
}

/* 3: the answer, a word at a time (the script marks each word as it
   lands), then its source. */
[data-vis="chat"][data-step] .ch-w:not(.is-on) { opacity: 0; }
[data-vis="chat"][data-step]:not([data-reached~="3"]) .ch-meta,
[data-vis="chat"][data-step][data-meta="0"] .ch-meta {
  opacity: 0;
  transform: translateY(6px);
}

/* 4: the answer's accounts are ringed, the rest recede, and the note
   that says so appears. */
[data-vis="chat"][data-step]:not([data-reached~="4"]) .ch-ring {
  opacity: 0;
  transform: scale(1.9);
}
[data-vis="chat"][data-step]:not([data-reached~="4"]) .ch-pt:not(.is-hit) { opacity: 1; }
[data-vis="chat"][data-step]:not([data-reached~="4"]) .ch-marked { opacity: 0; }

/* ── Narrower plates ────────────────────────────────────────────── */

/* Below 580px inside the plate (side by side with the copy between
   1040 and about 1220 wide, and on small tablets) the list cannot hold
   its bars beside a readable chat panel. The figures go two by two, and
   the panel opens over the whole list column, level with the top of the
   chart. The list is still there for the first frame. */
@container (max-width: 579px) {
  [data-vis="chat"] .ch-figs {
    grid-template-columns: minmax(0, 1.18fr) minmax(0, 0.82fr);
    align-content: center;
  }
  [data-vis="chat"] .ch-fig {
    flex-direction: row;
    align-items: baseline;
    padding: 5px 0 5px 12px;
  }
  [data-vis="chat"] .ch-fig:nth-child(odd) { border-left: 0; padding-left: 0; padding-right: 10px; }
  [data-vis="chat"] .ch-fig-num { font-size: 16px; }

  [data-vis="chat"] .ch { --ch-figs-h: 74px; --ch-body-h: 300px; }
  [data-vis="chat"] .ch-panel {
    top: calc(var(--ch-top-h) + var(--ch-figs-h) + var(--ch-gap));
    left: calc((100% - 26px) * 0.45 + 20px);
    width: auto;
  }
}

/* A phone, under 400px inside the plate: one column. The chart runs the
   full width, the list keeps its heading and its first row under it, and
   the panel sits below them, overlapping nothing the answer refers to. */
@container (max-width: 399px) {
  [data-vis="chat"] .ch-title { font-size: 15px; }
  [data-vis="chat"] .ch-fig-num { font-size: 15px; }
  [data-vis="chat"] .ch-fig-name { white-space: normal; }
  [data-vis="chat"] .ch-body {
    height: auto;
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
    padding-top: 12px;
  }
  [data-vis="chat"] .ch-plot { flex: none; aspect-ratio: 1.68 / 1; }
  [data-vis="chat"] .ch-list-head,
  [data-vis="chat"] .ch-row { grid-template-columns: minmax(0, 1fr) 44px 44px; gap: 10px; }
  [data-vis="chat"] .ch-row + .ch-row { display: none; }

  [data-vis="chat"] .ch-panel {
    position: relative;
    top: auto;
    left: auto;
    right: auto;
    bottom: auto;
    width: auto;
    margin: 12px -4px -4px;
  }
  [data-vis="chat"] .ch-convo { padding: 14px 14px 12px; gap: 10px; }
  [data-vis="chat"] .ch-ask { font-size: 13px; max-width: 92%; }
  [data-vis="chat"] .ch-answer { font-size: 13.5px; }
  [data-vis="chat"] .ch-input { padding: 10px 14px 11px; font-size: 12px; }
}


/* ════ PICTURE: Learn From & Educate 2: the report [data-vis="report"] ════ */

/* The report picture on /for-marketing (Learn From & Educate the Market,
   point 2).

   The plate is the page of a report: a well set research document, the
   register DESIGN.md asks of the whole site. Hairlines, Outfit headings,
   Plex reading underneath, Plex Mono only on figures that align. The
   paragraphs are quiet Track lines, because what matters is that the
   report is being built from the market's figures, not what its prose
   says. The chart is the grid's bar idiom (Ink at 62% on Track, each
   bar scaled against the whole 100).

   The markup with no data-step attribute is the finished picture.
   Steps, as the player in marketing.js sets them (timings in the report
   section of marketing.js):
     0  an empty page: the masthead and its "Draft" status
     1  the title
     2  the three section headings, one by one, each with its lines;
        the third carries the table of named companies
     3  the figures: 1 in 4 and its caption, then the bars grow
     4  anonymize: each name is blacked out and comes back as Company A,
        B, C
     5  the read line passes over the page, and "Draft" becomes "Ready
        to publish"
   Do not set transition on the [data-vis] root: marketing.css uses it
   for the fade between passes. */

[data-vis="report"] {
  /* The page is as tall as what is written on it (about 1.55 / 1 at
     1440), so no width can clip the table off its foot. Hidden steps
     keep their space, so the height never changes while it plays. */
  --vis-ratio: auto;
  --vis-ratio-phone: auto;

  --rp-ease: cubic-bezier(0.22, 0.7, 0.3, 1);
}

[data-vis="report"] .rp {
  height: 100%;
  display: flex;
  flex-direction: column;
  container-type: inline-size;
}

/* ── Masthead ───────────────────────────────────────────────────── */

[data-vis="report"] .rp-mast {
  display: flex;
  align-items: center;
  gap: 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--rule);
}
[data-vis="report"] .rp-kicker {
  font-family: var(--display);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
}
[data-vis="report"] .rp-date,
[data-vis="report"] .rp-num,
[data-vis="report"] .rp-bv,
[data-vis="report"] .rp-n {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

/* Draft and Ready share one cell, so the swap does not move anything. */
[data-vis="report"] .rp-status {
  margin-left: auto;
  display: grid;
  justify-items: end;
}
[data-vis="report"] .rp-pill {
  grid-area: 1 / 1;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.4;
  padding: 4px 10px;
  border-radius: 5px;
  white-space: nowrap;
}
[data-vis="report"] .rp-draft {
  background: var(--pill-none-bg);
  color: var(--muted);
  opacity: 0;
  transition: opacity 280ms ease 820ms;
}
[data-vis="report"] .rp-ready {
  background: var(--pill-yes-bg);
  color: var(--teal-deep);
  transition: opacity 320ms ease 860ms, transform 420ms var(--rp-ease) 860ms;
}

/* ── Title ──────────────────────────────────────────────────────── */

[data-vis="report"] .rp-title {
  margin-top: 18px;
  max-width: 21em;
  font-family: var(--display);
  font-size: 22px;
  font-weight: 700;
  line-height: 1.16;
  letter-spacing: -0.024em;
  color: var(--ink);
  transition: opacity 520ms var(--rp-ease), transform 520ms var(--rp-ease);
}

/* ── Body: text left, figures right ─────────────────────────────── */

[data-vis="report"] .rp-body {
  flex: 1;
  min-height: 0;
  margin-top: 18px;
  display: grid;
  grid-template-columns: minmax(0, 1.14fr) minmax(0, 0.86fr);
  align-content: start;
}
[data-vis="report"] .rp-text {
  padding-right: 24px;
  display: grid;
  gap: 16px;
  align-content: start;
}
[data-vis="report"] .rp-figs {
  padding-left: 24px;
  border-left: 1px solid var(--rule);
  display: grid;
  gap: 18px;
  align-content: start;
  transition: border-color 420ms ease;
}

/* Sections */
[data-vis="report"] .rp-sec {
  transition: opacity 460ms var(--rp-ease) calc(var(--i) * 380ms),
    transform 460ms var(--rp-ease) calc(var(--i) * 380ms);
}
[data-vis="report"] .rp-h {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-family: var(--display);
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--ink);
}
[data-vis="report"] .rp-n { flex: none; min-width: 0.7em; }
[data-vis="report"] .rp-lns {
  display: grid;
  gap: 7px;
  margin-top: 10px;
  padding-left: calc(0.7em * 12 / 14.5 + 10px);
}
[data-vis="report"] .rp-ln {
  display: block;
  height: 5px;
  width: var(--w);
  border-radius: 2px;
  background: var(--track);
  transform-origin: left center;
  transition: transform 520ms var(--rp-ease) calc(var(--i) * 380ms + 160ms + var(--j) * 90ms);
}

/* Table */
[data-vis="report"] .rp-table {
  margin-top: 9px;
  padding-left: calc(0.7em * 12 / 14.5 + 10px);
}
[data-vis="report"] .rp-tr {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 7.4em 4.6em;
  gap: 10px;
  align-items: center;
  padding: 5px 0;
  border-bottom: 1px solid var(--rule);
  font-size: 12.5px;
  line-height: 1.35;
  color: var(--body);
}
[data-vis="report"] .rp-tr:last-child { border-bottom: 0; }
/* Column heads are labels, not figures, so they stay in Plex. */
[data-vis="report"] .rp-th {
  padding-top: 0;
  font-size: 12px;
  font-weight: 500;
  color: var(--muted);
}
[data-vis="report"] .rp-th span { white-space: nowrap; }
[data-vis="report"] .rp-num { text-align: right; }
[data-vis="report"] .rp-tr .rp-num { color: var(--ink); }
[data-vis="report"] .rp-th .rp-num {
  font-family: var(--text);
  letter-spacing: 0;
  color: var(--muted);
}

/* The name cell: the real name and its replacement stacked in one
   cell, and the black bar that passes over them. */
[data-vis="report"] .rp-name {
  position: relative;
  justify-self: start;
  display: inline-grid;
  max-width: 100%;
  color: var(--ink);
  font-weight: 500;
}
[data-vis="report"] .rp-real,
[data-vis="report"] .rp-anon {
  grid-area: 1 / 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
[data-vis="report"] .rp-real {
  opacity: 0;
  transition: opacity 80ms linear calc(var(--k) * 260ms + 330ms);
}
[data-vis="report"] .rp-anon {
  transition: opacity 80ms linear calc(var(--k) * 260ms + 330ms);
}
[data-vis="report"] .rp-wipe {
  position: absolute;
  left: -3px;
  right: -3px;
  top: 1px;
  bottom: 1px;
  border-radius: 2px;
  background: var(--ink);
  clip-path: inset(0 0 0 100%);
}

/* Figures */
[data-vis="report"] .rp-fig {
  display: grid;
  gap: 6px;
  transition: opacity 480ms var(--rp-ease), transform 480ms var(--rp-ease);
}
[data-vis="report"] .rp-big {
  font-family: var(--display);
  /* The Figure role, as the homepage's figures band sets it. */
  font-size: clamp(38px, 4.4vw, 54px);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.04em;
  color: var(--ink);
}
[data-vis="report"] .rp-cap {
  font-size: 13px;
  line-height: 1.45;
  color: var(--body);
  max-width: 17em;
}

/* One grid for the whole chart, each bar a subgrid row of it, so the
   label column is as wide as the longest label at every width. */
[data-vis="report"] .rp-chart {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr) max-content;
  column-gap: 10px;
  row-gap: 8px;
  padding-top: 16px;
  border-top: 1px solid var(--rule);
  transition: opacity 420ms var(--rp-ease) 200ms;
}
[data-vis="report"] .rp-chart-h {
  font-family: var(--display);
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin-bottom: 2px;
  grid-column: 1 / -1;
}
[data-vis="report"] .rp-bar {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: subgrid;
  align-items: center;
  font-size: 12.5px;
  line-height: 1.35;
  color: var(--body);
}
[data-vis="report"] .rp-track {
  display: block;
  height: 6px;
  border-radius: 2px;
  background: var(--track);
  overflow: hidden;
}
[data-vis="report"] .rp-fill {
  display: block;
  height: 100%;
  width: calc(var(--v) * 100%);
  background: var(--score-ink);
  border-radius: 2px;
  transform-origin: left center;
  transition: transform 620ms var(--rp-ease) calc(320ms + var(--k) * 110ms);
}
[data-vis="report"] .rp-bv {
  text-align: right;
  color: var(--ink);
  transition: opacity 360ms ease calc(420ms + var(--k) * 110ms);
}

/* The read line, the act of checking: 1.6px Teal at 85% with a flat
   38px band of Teal at 8% trailing it. Shown only while it moves. */
[data-vis="report"] .rp-scan {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 38px;
  pointer-events: none;
  opacity: 0;
  background: rgba(0, 168, 138, 0.08);
  border-right: 1.6px solid rgba(0, 168, 138, 0.85);
  transform: translateX(-40px);
}

/* ── Earlier steps ──────────────────────────────────────────────── */

/* Step 0: the draft status is showing, the finished status is not. */
[data-vis="report"][data-step]:not([data-reached~="5"]) .rp-draft { opacity: 1; }
[data-vis="report"][data-step]:not([data-reached~="5"]) .rp-ready {
  opacity: 0;
  transform: scale(0.94);
}

/* Before step 1: no title. */
[data-vis="report"][data-step]:not([data-reached~="1"]) .rp-title {
  opacity: 0;
  transform: translateY(8px);
}

/* Before step 2: no sections, and their lines are unwritten. The rule
   between the two columns arrives with them. */
[data-vis="report"][data-step]:not([data-reached~="2"]) .rp-figs {
  border-left-color: transparent;
}
[data-vis="report"][data-step]:not([data-reached~="2"]) .rp-sec {
  opacity: 0;
  transform: translateY(8px);
}
[data-vis="report"][data-step]:not([data-reached~="2"]) .rp-ln {
  transform: scaleX(0);
}

/* Before step 3: no figures, and the bars are empty tracks. */
[data-vis="report"][data-step]:not([data-reached~="3"]) .rp-fig {
  opacity: 0;
  transform: translateY(8px);
}
[data-vis="report"][data-step]:not([data-reached~="3"]) .rp-chart,
[data-vis="report"][data-step]:not([data-reached~="3"]) .rp-bv {
  opacity: 0;
}
[data-vis="report"][data-step]:not([data-reached~="3"]) .rp-fill {
  transform: scaleX(0);
}

/* Before step 4: the real names. At step 4 each is blacked out, swapped
   under the bar, and uncovered as its replacement. */
[data-vis="report"][data-step]:not([data-reached~="4"]) .rp-real { opacity: 1; }
[data-vis="report"][data-step]:not([data-reached~="4"]) .rp-anon { opacity: 0; }
[data-vis="report"][data-reached~="4"] .rp-wipe {
  animation: rp-wipe 760ms var(--rp-ease) calc(var(--k) * 260ms) both;
}
@keyframes rp-wipe {
  0%   { clip-path: inset(0 100% 0 0); }
  42%  { clip-path: inset(0 0 0 0); }
  56%  { clip-path: inset(0 0 0 0); }
  100% { clip-path: inset(0 0 0 100%); }
}

/* Step 5: the read line crosses the page once, then the status turns. */
[data-vis="report"][data-reached~="5"] .rp-scan {
  animation: rp-scan 1000ms cubic-bezier(0.45, 0.05, 0.4, 1) both;
}
@keyframes rp-scan {
  0%   { opacity: 0; left: 0; transform: translateX(-40px); }
  8%   { opacity: 1; }
  88%  { opacity: 1; }
  100% { opacity: 0; left: 100%; transform: translateX(0); }
}

/* Two columns on a narrow plate (windows of about 1041 to 1240px): the
   table drops its industry column so the names keep their room. Not on
   a phone, where the table has the plate's full width. */
@media (min-width: 521px) {
  @container (max-width: 600px) {
    [data-vis="report"] .rp-tr { grid-template-columns: minmax(0, 1fr) 4.6em; }
    [data-vis="report"] .rp-ind,
    [data-vis="report"] .rp-th span:nth-child(2) { display: none; }
    [data-vis="report"] .rp-chart { column-gap: 8px; }
  }
}

/* ── Phone ──────────────────────────────────────────────────────── */

/* One column, in the order the page is written: title, the sections,
   then the figures, so it builds from the top down. All three sections
   stay, numbered 1, 2, 3; sections 1 and 2 keep one line each, so the
   page keeps a phone's shape. */
@media (max-width: 520px) {
  [data-vis="report"] .rp-mast { gap: 10px; padding-bottom: 10px; }
  [data-vis="report"] .rp-kicker { font-size: 14px; }
  [data-vis="report"] .rp-title { margin-top: 14px; font-size: 19px; }
  [data-vis="report"] .rp-body {
    margin-top: 16px;
    grid-template-columns: minmax(0, 1fr);
    gap: 18px;
  }
  [data-vis="report"] .rp-text { padding-right: 0; gap: 14px; }
  [data-vis="report"] .rp-lns { margin-top: 8px; }
  [data-vis="report"] .rp-ln + .rp-ln { display: none; }
  [data-vis="report"] .rp-tr { grid-template-columns: minmax(0, 1fr) 7.2em 5.2em; gap: 8px; }
  [data-vis="report"] .rp-tr,
  [data-vis="report"] .rp-bar { font-size: 12px; }

  /* The figures under a hairline that arrives with them. */
  [data-vis="report"] .rp-figs {
    padding-left: 0;
    padding-top: 16px;
    border-left: 0;
    border-top: 1px solid var(--rule);
    gap: 14px;
  }
  [data-vis="report"][data-step]:not([data-reached~="3"]) .rp-figs {
    border-top-color: transparent;
  }
  [data-vis="report"] .rp-fig {
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    gap: 14px;
  }
  [data-vis="report"] .rp-chart { padding-top: 12px; row-gap: 7px; }
}
