/* ==========================================================================
   Product-page device kit
   The .dmv primitives (body, row, label, foot) are shared by every product
   page; the device classes below them are per-page. Built for Decision Makers
   first, extended for Company Dataset.
   Six bespoke devices, one per card. Each one animates the verb in its
   heading rather than decorating it: a score fills, a check sweeps and
   stamps, a champion travels, a question is typed, a market grows, a record
   populates. All gated on .build-cases.is-visible so they run once, on
   arrival, and never loop.
   ========================================================================== */

.dmv {
  --dmv-step: 120ms;
  display: grid;
  /* Two rows, not a flow: the device body takes the slack and the caption
     pins to the bottom, so every caption in a row sits on one line at one
     height regardless of how tall its device is. */
  grid-template-rows: minmax(0, 1fr) auto;
  gap: .5rem;
  height: 100%;
  width: min(18.5rem, 100%);
  font-family: var(--zl-font-mono);
  font-size: .68rem;
  color: var(--zl-muted-text);
}

.dmv__body {
  display: grid;
  gap: .5rem;
  align-content: center;
  min-height: 0;
}

/* The shared caption band. A rule above it makes the alignment legible even
   when two neighbouring devices are different heights. */
.dmv__foot {
  /* Fixed height, not min-height: the score caption carries a larger figure
     whose line box grew past the minimum and pushed that one caption 2px off
     its neighbours. */
  height: 1.75rem;
  display: flex;
  justify-content: space-between;
  gap: .5rem;
  align-items: center;
  margin: 0;
  padding-top: .4rem;
  border-top: 1px solid var(--zl-line);
  letter-spacing: var(--zl-tracking-label);
  text-transform: uppercase;
}

/* The caption is the device's punchline — "direction, not just size", "built,
   not claimed" — so it should read as an assertion rather than as a legend.
   Inheriting muted grey made it the quietest thing on the card when it is the
   sharpest. Raised to ink, and marked with the same leading rule the eyebrow
   uses, so the emphasis is the system's own language rather than a new one.
   The mark sits on the inner span, not on .dmv__foot: the foot is a
   space-between flex row and some devices carry a figure on the right, which a
   ::before on the parent would have pushed out of alignment. */
.dmv__foot > span {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  min-width: 0;
  color: var(--zl-ink);
  font-weight: var(--zl-weight-medium);
}
.dmv__foot > span::before {
  content: "";
  flex: none;
  width: .85rem;
  height: 1px;
  background: var(--zl-vermilion);
}

.dmv__label {
  margin: 0;
  letter-spacing: var(--zl-tracking-label);
  text-transform: uppercase;
}

.dmv__row {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .42rem .6rem;
  border: 1px solid var(--zl-line-strong);
  background: var(--zl-surface);
}

.dmv__row b { flex: 1; font-size: .78rem; font-weight: var(--zl-weight-medium); color: var(--zl-ink); }
.dmv__row em { font-style: normal; }

/* build-section.css hides every grandchild of a panel (`> * > *`) and animates
   it back with bc-rise. Any element here that declares its own animation
   replaces bc-rise and would stay stuck at opacity 0 — so opt the whole device
   out, and let [data-in] put the hidden start back where it is wanted. */
.build-cases__panel > .dmv > *:not([data-in]),
.build-cases__panel > .dmv > * > *:not([data-in]) { opacity: 1; transform: none; }

/* Shared entrance ------------------------------------------------------- */
.dmv [data-in] { opacity: 0; transform: translateY(.35rem); }
.build-cases.is-visible .dmv [data-in] {
  animation: dmv-in 420ms var(--zl-ease-out) forwards;
  animation-delay: calc(var(--i, 0) * var(--dmv-step) + 160ms);
}
@keyframes dmv-in { to { opacity: 1; transform: none; } }

/* 1 — Score: a committee meter fills as members are counted in ----------- */
.dmv-score__meter {
  position: relative;
  height: .5rem;
  border: 1px solid var(--zl-line-strong);
  background: var(--zl-paper);
  overflow: hidden;
}
.dmv-score__meter i {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  background: var(--zl-cobalt);
}
.build-cases.is-visible .dmv-score__meter i {
  animation: dmv-fill 1.1s var(--zl-ease-out) 620ms forwards;
}
@keyframes dmv-fill { to { width: 78%; } }

.dmv__foot b { color: var(--zl-cobalt); font-size: .78rem; line-height: 1; }

/* 2 — Gate: a scan sweeps the lead, then a verdict stamps ---------------- */
.dmv-gate__scan { position: relative; overflow: hidden; }
.dmv-gate__scan::after {
  position: absolute;
  inset: 0 auto 0 -40%;
  width: 40%;
  background: linear-gradient(90deg, transparent, var(--zl-cobalt-a12, rgb(28 47 110 / .14)), transparent);
  content: "";
}
.build-cases.is-visible .dmv-gate__scan::after {
  animation: dmv-sweep 900ms var(--zl-ease-standard) 420ms 2;
}
@keyframes dmv-sweep { to { left: 100%; } }

.dmv-gate__stamp {
  padding: .1rem .4rem;
  border: 1px solid currentColor;
  color: var(--zl-cobalt);
  opacity: 0;
  transform: scale(.7);
}
.dmv-gate__stamp--no { color: var(--zl-vermilion); }
.build-cases.is-visible .dmv-gate__stamp {
  animation: dmv-stamp 380ms var(--zl-ease-out) forwards;
  animation-delay: calc(1.5s + var(--i, 0) * 260ms);
}
@keyframes dmv-stamp { to { opacity: 1; transform: none; } }

/* 3 — Travel: a champion leaves one company and lands at another --------- */
.dmv-travel__lane {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: .4rem;
}
.dmv-travel__co {
  padding: .3rem .45rem;
  border: 1px dashed var(--zl-line-strong);
  text-align: center;
}
.dmv-travel__co--to { border-style: solid; color: var(--zl-cobalt); }
.dmv-travel__path { position: relative; height: 1px; background: var(--zl-line-strong); }
.dmv-travel__dot {
  position: absolute;
  top: 50%;
  left: 0;
  width: .5rem;
  height: .5rem;
  margin-top: -.25rem;
  border-radius: 50%;
  background: var(--zl-vermilion);
}
.build-cases.is-visible .dmv-travel__dot {
  animation: dmv-travel 1.3s var(--zl-ease-in-out) 700ms forwards;
}
@keyframes dmv-travel {
  to { left: 100%; margin-left: -.5rem; background: var(--zl-cobalt); }
}

/* 4 — Ask: the question types itself, then the answer lands -------------- */
.dmv-ask__q {
  display: inline-block;
  max-width: 100%;
  padding: .3rem .5rem;
  background: var(--zl-ink);
  color: var(--zl-on-dark);
  white-space: nowrap;
  overflow: hidden;
  width: 0;
}
.build-cases.is-visible .dmv-ask__q {
  animation: dmv-type 1s steps(24) 320ms forwards;
}
@keyframes dmv-type { to { width: 100%; } }

/* 5 — Market: committee size grows across stages ------------------------- */
.dmv-market__bars {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: .45rem;
  align-items: stretch;
  height: 4.75rem;
}
/* The column stretches and reserves its label row, so the bar's percentage
   height resolves against a definite track. With align-content:end the column
   was content-sized and the percentage collapsed to zero. */
.dmv-market__bar {
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  gap: .3rem;
  align-items: end;
  text-align: center;
}
.dmv-market__bar i {
  display: block;
  align-self: end;
  height: 0;
  border: 1px solid var(--zl-line-strong);
  border-bottom: 0;
  background: var(--zl-paper);
}
.dmv-market__bar--now i { background: var(--zl-cobalt); border-color: var(--zl-cobalt); }
.build-cases.is-visible .dmv-market__bar i {
  animation: dmv-grow 760ms var(--zl-ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 200ms + 420ms);
}
@keyframes dmv-grow { to { height: var(--h, 40%); } }

/* 6 — Fill: an empty record populates, once ------------------------------ */
.dmv-fill__field {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .34rem .5rem;
  border: 1px dashed var(--zl-line-strong);
}
.dmv-fill__field b { flex: 1; color: var(--zl-muted-text); font-weight: 400; font-size: .72rem; }
.dmv-fill__field em { font-style: normal; opacity: 0; color: var(--zl-cobalt); }
.build-cases.is-visible .dmv-fill__field {
  animation: dmv-solid 420ms var(--zl-ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 260ms + 520ms);
}
.build-cases.is-visible .dmv-fill__field em {
  animation: dmv-in 320ms var(--zl-ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 260ms + 700ms);
}
@keyframes dmv-solid {
  to { border-style: solid; border-color: var(--zl-line-strong); background: var(--zl-surface); }
}

@media (prefers-reduced-motion: reduce) {
  .dmv [data-in],
  .dmv-gate__stamp,
  .dmv-fill__field em { opacity: 1; transform: none; animation: none; }
  .dmv-score__meter i { width: 78%; animation: none; }
  .dmv-gate__scan::after { animation: none; opacity: 0; }
  .dmv-travel__dot { left: 100%; margin-left: -.5rem; background: var(--zl-cobalt); animation: none; }
  .dmv-ask__q { width: 100%; animation: none; }
  .dmv-market__bar i { height: var(--h, 40%); animation: none; }
  .dmv-fill__field { border-style: solid; background: var(--zl-surface); animation: none; }
}


/* ==========================================================================
   Company Dataset devices
   ========================================================================== */

/* 1 — Filter: criteria light up and the list narrows to what matches -------- */
.cdv-filter__chips { display: flex; flex-wrap: wrap; gap: .3rem; }
.cdv-filter__chips span {
  padding: .12rem .4rem;
  border: 1px solid var(--zl-line-strong);
  color: var(--zl-muted-text);
}
.build-cases.is-visible .cdv-filter__chips span {
  animation: cdv-chip 380ms var(--zl-ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 180ms + 320ms);
}
@keyframes cdv-chip { to { border-color: var(--zl-cobalt); color: var(--zl-cobalt); } }

.cdv-filter__out em { color: var(--zl-cobalt); }

/* 2 — Ladder: funding stages fill from the bottom -------------------------- */
.cdv-ladder { display: grid; gap: .25rem; }
.cdv-ladder__rung {
  position: relative;
  display: flex;
  justify-content: space-between;
  padding: .28rem .5rem;
  border: 1px solid var(--zl-line-strong);
  overflow: hidden;
}
.cdv-ladder__rung::before {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  background: var(--zl-cobalt-a12, rgb(28 47 110 / .12));
  content: "";
}
.build-cases.is-visible .cdv-ladder__rung::before {
  animation: cdv-rung 620ms var(--zl-ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 220ms + 420ms);
}
@keyframes cdv-rung { to { width: var(--w, 60%); } }
.cdv-ladder__rung b, .cdv-ladder__rung em { position: relative; }

/* 3 — Portfolio: a grid of holdings, one of which changes ------------------ */
.cdv-portfolio { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .3rem; }
.cdv-portfolio span {
  padding: .5rem .35rem;
  border: 1px solid var(--zl-line-strong);
  text-align: center;
  background: var(--zl-surface);
}
.cdv-portfolio span.is-hit { color: var(--zl-vermilion); }
.build-cases.is-visible .cdv-portfolio span.is-hit {
  animation: cdv-hit 700ms var(--zl-ease-out) 900ms forwards;
}
@keyframes cdv-hit {
  0% { border-color: var(--zl-line-strong); }
  40% { border-color: var(--zl-vermilion); transform: translateY(-2px); }
  100% { border-color: var(--zl-vermilion); transform: none; }
}

/* 4 — Merge: three spellings collapse into one canonical row --------------- */
.cdv-merge { display: grid; gap: .25rem; }
.cdv-merge__in {
  padding: .26rem .5rem;
  border: 1px dashed var(--zl-line-strong);
  color: var(--zl-muted-text);
}
.build-cases.is-visible .cdv-merge__in {
  animation: cdv-collapse 520ms var(--zl-ease-in-out) forwards;
  animation-delay: calc(var(--i, 0) * 120ms + 700ms);
}
@keyframes cdv-collapse { to { opacity: .25; transform: translateY(.55rem) scaleY(.85); } }

.cdv-merge__out {
  display: flex;
  justify-content: space-between;
  padding: .32rem .5rem;
  border: 1px solid var(--zl-cobalt);
  color: var(--zl-cobalt);
  opacity: 0;
}
.build-cases.is-visible .cdv-merge__out {
  animation: dmv-in 420ms var(--zl-ease-out) 1.25s forwards;
}

/* 5 — Backed: an investor fans out to the companies it holds --------------- */
.cdv-backed__seed {
  justify-self: start;
  padding: .26rem .5rem;
  background: var(--zl-ink);
  color: var(--zl-on-dark);
}
.cdv-backed__fan { display: flex; flex-wrap: wrap; gap: .3rem; }
.cdv-backed__fan span {
  padding: .22rem .45rem;
  border: 1px solid var(--zl-cobalt);
  color: var(--zl-cobalt);
  opacity: 0;
  transform: translateX(-.4rem);
}
.build-cases.is-visible .cdv-backed__fan span {
  animation: cdv-fan 420ms var(--zl-ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 150ms + 620ms);
}
@keyframes cdv-fan { to { opacity: 1; transform: none; } }

/* 6 — Context: facts stack under a question ------------------------------- */
.cdv-context__fact { display: flex; justify-content: space-between; gap: .5rem; }
.cdv-context__fact em { color: var(--zl-ink); }

@media (prefers-reduced-motion: reduce) {
  .cdv-filter__chips span { border-color: var(--zl-cobalt); color: var(--zl-cobalt); animation: none; }
  .cdv-ladder__rung::before { width: var(--w, 60%); animation: none; }
  .cdv-portfolio span.is-hit { border-color: var(--zl-vermilion); animation: none; }
  .cdv-merge__in { opacity: .25; animation: none; }
  .cdv-merge__out, .cdv-backed__fan span { opacity: 1; transform: none; animation: none; }
}

/* ==========================================================================
   People Enrichment devices
   ========================================================================== */

/* Truncated code sample — Crustdata's register: a few illustrative fields on
   one or two lines, never a full schema. */
.dmv-code {
  display: grid;
  gap: .3rem;
  padding: .5rem .6rem;
  border: 1px solid var(--zl-line-strong);
  background: var(--zl-paper);
  font-size: .66rem;
  line-height: 1.5;
  overflow-x: auto;
}
.dmv-code span { color: var(--zl-muted-text); }
.dmv-code b { color: var(--zl-ink); font-weight: var(--zl-weight-medium); }
.dmv-code i { color: var(--zl-cobalt); font-style: normal; }

/* Resolve: an email lands and a profile assembles under it */
.pev-resolve__in {
  justify-self: start;
  padding: .26rem .5rem;
  background: var(--zl-ink);
  color: var(--zl-on-dark);
}
.pev-resolve__hit { color: var(--zl-cobalt); }

/* Stack: history rows layer up, most recent last */
.pev-stack { display: grid; gap: .22rem; }
.pev-stack span {
  display: flex;
  justify-content: space-between;
  padding: .26rem .5rem;
  border-left: 2px solid var(--zl-line-strong);
  background: var(--zl-surface);
  opacity: 0;
  transform: translateX(-.4rem);
}
.pev-stack span.is-now { border-left-color: var(--zl-cobalt); color: var(--zl-cobalt); }
.build-cases.is-visible .pev-stack span {
  animation: cdv-fan 400ms var(--zl-ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 170ms + 480ms);
}

/* Batch: a file of rows resolving one by one into a counter */
.pev-batch__bar {
  position: relative;
  height: .45rem;
  border: 1px solid var(--zl-line-strong);
  overflow: hidden;
}
.pev-batch__bar i { position: absolute; inset: 0 auto 0 0; width: 0; background: var(--zl-cobalt); }
.build-cases.is-visible .pev-batch__bar i { animation: dmv-fill 1.4s var(--zl-ease-out) 520ms forwards; }

@media (prefers-reduced-motion: reduce) {
  .pev-stack span { opacity: 1; transform: none; animation: none; }
  .pev-batch__bar i { width: 78%; animation: none; }
}

/* --- Enrichment flow: typed in, fetched, loaded -------------------------
   Both input modes run the same device — the input differs, the record does
   not, and that sameness is the argument. It loops because the transformation
   IS the message here, and it runs the sequence a developer would actually
   see: the identifier is typed, the call goes out, the rows come back as
   skeletons and then resolve. One cycle length keeps both panels in step;
   per-element delays are the stagger. */
.pev-flow {
  --pev-cycle: 8s;
  display: grid;
  gap: .25rem;
  justify-items: stretch;
}

/* Input — typed, with a caret that stops once the text is in. Widths are in
   ch and the face is monospace, so the reveal lands exactly on the last
   character rather than mid-glyph. */
.pev-flow__in {
  justify-self: start;
  padding: .26rem .5rem;
  border: 1px solid var(--zl-line-strong);
  color: var(--zl-muted-text);
}
.pev-flow__in--email { border-color: var(--zl-ink); background: var(--zl-ink); color: var(--zl-on-dark); }
.pev-flow__in i {
  display: inline-block;
  width: 0;
  overflow: hidden;
  white-space: nowrap;
  vertical-align: bottom;
  border-right: 1px solid transparent;
  font-style: normal;
}

.pev-flow__link {
  position: relative;
  display: flex;
  align-items: center;
  gap: .45rem;
  min-height: .95rem;
  padding-left: .85rem;
  color: var(--zl-cobalt);
}
.pev-flow__link::before {
  position: absolute;
  top: 0;
  left: .5rem;
  width: 1px;
  height: 0;
  background: var(--zl-cobalt);
  content: "";
}
.pev-flow__link span { opacity: 0; }

.pev-flow__out {
  display: grid;
  gap: 1px;
  border: 1px solid var(--zl-line-strong);
  background: var(--zl-line);
}
.pev-flow__out span {
  position: relative;
  display: flex;
  justify-content: space-between;
  gap: .5rem;
  padding: .22rem .5rem;
  background: var(--zl-surface);
  opacity: 0;
}
.pev-flow__out span b,
.pev-flow__out span em { opacity: 0; }
.pev-flow__out span em { color: var(--zl-muted-text); font-style: normal; }
.pev-flow__out span b { color: var(--zl-ink); font-weight: var(--zl-weight-medium); }
.pev-flow__out span.is-more b,
.pev-flow__out span.is-more em { color: var(--zl-cobalt); }

/* Skeleton bar sitting over the row until its content resolves. */
.pev-flow__out span::after {
  position: absolute;
  top: 50%;
  left: .5rem;
  right: .5rem;
  height: .5rem;
  margin-top: -.25rem;
  background:
    linear-gradient(90deg, var(--zl-line) 0%, var(--zl-line-strong) 35%, var(--zl-line) 70%)
    0 0 / 220% 100%;
  content: "";
  opacity: 0;
}

@keyframes pev-type {
  0%        { width: 0; border-right-color: currentColor; }
  11%       { width: calc(var(--ch, 20) * 1ch); border-right-color: currentColor; }
  15%, 84%  { width: calc(var(--ch, 20) * 1ch); border-right-color: transparent; }
  94%, 100% { width: 0; border-right-color: transparent; }
}
@keyframes pev-fade {
  0%        { opacity: 0; }
  7%, 84%   { opacity: 1; }
  94%, 100% { opacity: 0; }
}
@keyframes pev-line {
  0%, 3%    { height: 0; }
  11%, 84%  { height: 100%; }
  94%, 100% { height: 0; }
}
@keyframes pev-row   { 0%, 15% { opacity: 0; } 20%, 84% { opacity: 1; } 94%, 100% { opacity: 0; } }
@keyframes pev-skel  { 0%, 18% { opacity: 0; } 21% { opacity: 1; } 34% { opacity: 1; } 40%, 100% { opacity: 0; } }
@keyframes pev-text  { 0%, 34% { opacity: 0; } 41%, 84% { opacity: 1; } 94%, 100% { opacity: 0; } }
@keyframes pev-shimmer { to { background-position: 220% 0; } }

.build-cases.is-visible .pev-flow__in i {
  animation: pev-type var(--pev-cycle) var(--zl-ease-standard) .2s infinite;
}
.build-cases.is-visible .pev-flow__link::before {
  animation: pev-line var(--pev-cycle) var(--zl-ease-standard) .9s infinite;
}
.build-cases.is-visible .pev-flow__link span {
  animation: pev-fade var(--pev-cycle) var(--zl-ease-standard) 1.2s infinite;
}
.build-cases.is-visible .pev-flow__out span {
  animation: pev-row var(--pev-cycle) var(--zl-ease-standard) infinite;
  animation-delay: calc(1.35s + var(--i, 0) * .1s);
}
.build-cases.is-visible .pev-flow__out span::after {
  animation:
    pev-skel var(--pev-cycle) linear infinite,
    pev-shimmer 1.1s linear infinite;
  animation-delay: calc(1.35s + var(--i, 0) * .1s), 0s;
}
.build-cases.is-visible .pev-flow__out span b,
.build-cases.is-visible .pev-flow__out span em {
  animation: pev-text var(--pev-cycle) var(--zl-ease-standard) infinite;
  animation-delay: calc(1.35s + var(--i, 0) * .1s);
}

@media (prefers-reduced-motion: reduce) {
  .pev-flow__in i { width: auto; border-right-color: transparent; animation: none !important; }
  .pev-flow__link span,
  .pev-flow__out span,
  .pev-flow__out span b,
  .pev-flow__out span em { opacity: 1; animation: none !important; }
  .pev-flow__out span::after { display: none; }
  .pev-flow__link::before { height: 100%; animation: none !important; }
}



/* ==========================================================================
   People Search devices (psv-*)
   Search is not documented, so this page shows no payloads, no endpoint paths
   and no field names (page rule 4.5). These devices carry the understanding a
   code block would have carried, so the MOTION is the argument, not decoration
   around one: a population collapses, a selection travels, evidence lights up,
   a role is left and another taken, an account is scanned open, a query is
   typed and answered.

   Two constraints learned the hard way and enforced throughout:
   - Every loop keeps its content legible at all times. Nothing animates from
     opacity 0, because the cycle starts when the section scrolls in — so t=0
     is exactly what a visitor sees, and an empty device reads as broken.
   - Where N states cycle, each is lit for exactly 1/N of the cycle with a
     matching negative delay, so one is always lit and the device never
     looks dead between states.
   ========================================================================== */

.psv { --psv-cycle: 9s; }   /* kept in step with --csv-cycle */

/* 1 — Narrow: a billion collapses to the few hundred that match ------------ */
.psv-narrow__bar {
  position: relative;
  height: .5rem;
  border: 1px solid var(--zl-line-strong);
  background: var(--zl-paper);
  overflow: hidden;
}
.psv-narrow__bar i { position: absolute; inset: 0 auto 0 0; width: 100%; background: var(--zl-cobalt); }
.build-cases.is-visible .psv-narrow__bar i {
  animation: psv-narrow var(--psv-cycle) var(--zl-ease-standard) infinite;
}
@keyframes psv-narrow {
  0%, 10%   { width: 100%; }
  50%, 88%  { width: 9%; }
  100%      { width: 100%; }
}
.psv-narrow__ends { display: flex; justify-content: space-between; margin: 0; }
.psv-narrow__ends span,
.psv-narrow__ends b { transition: none; }
.psv-narrow__ends b { font-weight: var(--zl-weight-medium); color: var(--zl-ink); }
/* The count resolves as the bar settles. It never disappears — it dims. */
.build-cases.is-visible .psv-narrow__ends b {
  animation: psv-resolve var(--psv-cycle) var(--zl-ease-standard) infinite;
}
.build-cases.is-visible .psv-narrow__ends span {
  animation: psv-dim var(--psv-cycle) var(--zl-ease-standard) infinite;
}
@keyframes psv-resolve {
  0%, 12%   { opacity: .35; transform: translateY(.15rem); }
  46%, 90%  { opacity: 1; transform: none; }
  100%      { opacity: .35; transform: translateY(.15rem); }
}
@keyframes psv-dim {
  0%, 10%   { opacity: 1; }
  50%, 90%  { opacity: .4; }
  100%      { opacity: 1; }
}

/* 2 — Moved: the role left, and the role taken ---------------------------- */
.psv-move__was,
.psv-move__now {
  display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  border: 1px solid var(--zl-line-strong);
  background: var(--zl-surface);
  padding: .42rem .55rem;
  margin: 0;
}
.psv-move__was b { font-weight: var(--zl-weight-regular); position: relative; }
/* the strike sweeps rather than simply being there */
.psv-move__was b::after {
  content: ""; position: absolute; left: 0; top: 50%; height: 1px; width: 0;
  background: currentColor;
}
.build-cases.is-visible .psv-move__was b::after {
  animation: psv-strike var(--psv-cycle) var(--zl-ease-standard) infinite;
}
@keyframes psv-strike {
  0%, 8%    { width: 0; }
  30%, 88%  { width: 100%; }
  100%      { width: 0; }
}
.build-cases.is-visible .psv-move__was {
  animation: psv-leave var(--psv-cycle) var(--zl-ease-standard) infinite;
}
@keyframes psv-leave {
  0%, 8%    { opacity: 1; color: var(--zl-ink); }
  34%, 88%  { opacity: .5; color: var(--zl-muted-text); }
  100%      { opacity: 1; color: var(--zl-ink); }
}
.psv-move__arrow { display: block; text-align: center; line-height: 1; margin: 0; }
.build-cases.is-visible .psv-move__arrow {
  animation: psv-drop 2.2s var(--zl-ease-standard) infinite;
}
@keyframes psv-drop {
  0%, 100% { opacity: .3; transform: translateY(-.12rem); }
  50%      { opacity: 1; transform: translateY(.12rem); }
}
.psv-move__now b { color: var(--zl-ink); font-weight: var(--zl-weight-medium); }
.psv-move__tag { color: var(--zl-vermilion); }
/* the new role arrives — it is always readable, it just lands */
.build-cases.is-visible .psv-move__now {
  animation: psv-arrive var(--psv-cycle) var(--zl-ease-standard) infinite;
}
@keyframes psv-arrive {
  0%, 20%   { border-color: var(--zl-line-strong); transform: translateY(.3rem); opacity: .55; }
  44%, 88%  { border-color: var(--zl-vermilion); transform: none; opacity: 1; }
  100%      { border-color: var(--zl-line-strong); transform: translateY(.3rem); opacity: .55; }
}

/* 3 — Embed: a query typed inside someone else's product ------------------ */
.psv-embed__bar {
  display: flex;
  align-items: center;
  gap: .4rem;
  border: 1px solid var(--zl-line-strong);
  background: var(--zl-surface);
  padding: .38rem .5rem;
  margin: 0;
  min-height: 1.7rem;
}
.psv-embed__bar i {
  display: inline-block;
  width: 0;
  overflow: hidden;
  white-space: nowrap;
  vertical-align: bottom;
  border-right: 1px solid transparent;
  font-style: normal;
  color: var(--zl-ink);
}
.build-cases.is-visible .psv-embed__bar i {
  animation: psv-type var(--psv-cycle) var(--zl-ease-standard) infinite;
}
@keyframes psv-type {
  0%        { width: 0; border-right-color: currentColor; }
  16%       { width: calc(var(--ch, 20) * 1ch); border-right-color: currentColor; }
  20%, 92%  { width: calc(var(--ch, 20) * 1ch); border-right-color: transparent; }
  99%, 100% { width: 0; border-right-color: transparent; }
}
.psv-embed__hits span { display: flex; justify-content: space-between; }
/* results land after the query is typed and stay for most of the cycle */
.build-cases.is-visible .psv-embed__hits span {
  animation: psv-hit var(--psv-cycle) var(--zl-ease-standard) infinite;
  animation-delay: calc(var(--i, 0) * 140ms);
}
@keyframes psv-hit {
  0%, 18%   { opacity: 0; transform: translateY(.25rem); }
  26%, 90%  { opacity: 1; transform: none; }
  98%, 100% { opacity: 0; transform: translateY(.25rem); }
}

/* 4 — Account: a scan travels down the people inside a company ------------ */
.psv-account__co {
  display: flex; align-items: center; justify-content: space-between;
  border: 1px solid var(--zl-cobalt);
  background: var(--zl-surface);
  padding: .42rem .55rem;
  margin: 0;
}
.psv-account__co b { font-size: .78rem; font-weight: var(--zl-weight-medium); color: var(--zl-ink); }
.psv-account__who { display: grid; gap: .3rem; padding-left: .8rem; border-left: 1px solid var(--zl-line-strong); }
.psv-account__who span {
  display: flex; justify-content: space-between;
  padding: .1rem .3rem;
  /* always legible; the scan raises one at a time */
  opacity: .55;
}
.build-cases.is-visible .psv-account__who span {
  animation: psv-scan var(--psv-cycle) var(--zl-ease-standard) infinite;
  animation-delay: calc(var(--i, 0) * (var(--psv-cycle) / 3));
}
@keyframes psv-scan {
  0%, 33.32%   { opacity: 1; color: var(--zl-ink); background: var(--zl-paper); transform: translateX(.15rem); }
  33.33%, 100% { opacity: .55; color: inherit; background: transparent; transform: none; }
}

/* 5 — Skill: the evidence behind a developer lights up -------------------- */
.psv-skill__chips { display: flex; flex-wrap: wrap; gap: .3rem; }
.psv-skill__chips b {
  border: 1px solid var(--zl-line-strong);
  background: var(--zl-paper);
  padding: .16rem .42rem;
  font-weight: var(--zl-weight-regular);
}
.build-cases.is-visible .psv-skill__chips b {
  animation: psv-lit var(--psv-cycle) var(--zl-ease-standard) infinite;
  animation-delay: calc(var(--i, 0) * 220ms);
}
@keyframes psv-lit {
  0%, 6%    { border-color: var(--zl-line-strong); color: var(--zl-muted-text); background: var(--zl-paper); }
  20%, 88%  { border-color: var(--zl-cobalt); color: var(--zl-ink); background: var(--zl-surface); }
  99%, 100% { border-color: var(--zl-line-strong); color: var(--zl-muted-text); background: var(--zl-paper); }
}
.build-cases.is-visible .psv-skill__row {
  animation: psv-evidence var(--psv-cycle) var(--zl-ease-standard) infinite;
}
@keyframes psv-evidence {
  0%, 26%   { opacity: .4; transform: translateY(.2rem); }
  44%, 90%  { opacity: 1; transform: none; }
  100%      { opacity: .4; transform: translateY(.2rem); }
}

/* 6 — Population: the selection travels, one lit at a time ---------------- */
.psv-pop__opts { display: grid; gap: .3rem; }
.psv-pop__opts span {
  display: flex; justify-content: space-between;
  border: 1px solid var(--zl-line-strong);
  background: var(--zl-paper);
  padding: .34rem .5rem;
}
.psv-pop__opts span b { font-weight: var(--zl-weight-medium); }
.build-cases.is-visible .psv-pop__opts span {
  animation: psv-select var(--psv-cycle) var(--zl-ease-standard) infinite;
  animation-delay: calc(var(--i, 0) * (var(--psv-cycle) / 3));
}
/* 33.32/33.33 rather than a gap: with three items each lit for exactly a
   third, one is always lit. An earlier version left ~16% of the cycle with
   nothing selected, and the device looked switched off. */
@keyframes psv-select {
  0%, 33.32%   { border-color: var(--zl-vermilion); background: var(--zl-surface); color: var(--zl-ink); }
  33.33%, 100% { border-color: var(--zl-line-strong); background: var(--zl-paper); color: var(--zl-muted-text); }
}

@media (prefers-reduced-motion: reduce) {
  /* Every device rests in its finished state rather than losing the point. */
  .psv-narrow__bar i { width: 9%; }
  .psv-embed__bar i { width: auto; border-right-color: transparent; }
  .psv-move__was b::after { width: 100%; }
  .psv-move__was { opacity: .5; color: var(--zl-muted-text); }
  .psv-move__now { border-color: var(--zl-vermilion); }
  .psv-embed__hits span { opacity: 1; }
  .psv-account__who span:first-child { opacity: 1; color: var(--zl-ink); background: var(--zl-paper); }
  .psv-skill__chips b { border-color: var(--zl-cobalt); color: var(--zl-ink); background: var(--zl-surface); }
  .psv-pop__opts span:first-child { border-color: var(--zl-vermilion); background: var(--zl-surface); color: var(--zl-ink); }
  .build-cases.is-visible .psv-narrow__bar i,
  .build-cases.is-visible .psv-narrow__ends b,
  .build-cases.is-visible .psv-narrow__ends span,
  .build-cases.is-visible .psv-move__was,
  .build-cases.is-visible .psv-move__was b::after,
  .build-cases.is-visible .psv-move__arrow,
  .build-cases.is-visible .psv-move__now,
  .build-cases.is-visible .psv-embed__bar i,
  .build-cases.is-visible .psv-embed__hits span,
  .build-cases.is-visible .psv-account__who span,
  .build-cases.is-visible .psv-skill__chips b,
  .build-cases.is-visible .psv-skill__row,
  .build-cases.is-visible .psv-pop__opts span { animation: none !important; }
}

/* ==========================================================================
   Company Search devices (csv-*)
   Company Search is not documented either, so the same rule applies: no
   payloads, no endpoint paths, no field names. Each device animates the verb
   of its card — a headcount climbs, a round lands, one department pulls away
   from the others, openings accumulate, a seat changes hands.
   Same two constraints as psv-*: nothing animates from opacity 0, and where
   N states cycle each is lit exactly 1/N of the time.
   ========================================================================== */

.csv { --csv-cycle: 9s; }   /* slowed from 5.6s so the counts are readable [Arjun, 2026-08-06] */

/* 1 — Growth: the company is bigger than when you last looked ------------- */
.csv-growth__plot { display: flex; align-items: flex-end; gap: .22rem; height: 3.1rem; }
.csv-growth__plot i {
  flex: 1;
  background: var(--zl-cobalt);
  transform-origin: bottom;
  height: var(--h, 40%);
}
.build-cases.is-visible .csv-growth__plot i {
  animation: csv-rise var(--csv-cycle) var(--zl-ease-out) infinite;
  animation-delay: calc(var(--i, 0) * 90ms);
}
@keyframes csv-rise {
  0%, 6%    { transform: scaleY(.35); opacity: .5; }
  40%, 88%  { transform: scaleY(1); opacity: 1; }
  100%      { transform: scaleY(.35); opacity: .5; }
}
.csv-growth__delta { color: var(--zl-vermilion); }

/* A direction marker, the way a market ticker shows one: a caret plus the
   delta. Drawn with borders rather than a glyph so it inherits colour and can
   never be a missing character in some font [Arjun, 2026-08-06]. */
.csv-trend {
  display: inline-flex;
  align-items: center;
  gap: .28rem;
  font-style: normal;
  white-space: nowrap;
  color: var(--zl-positive);          /* growth reads green, decline red */
  font-variant-numeric: tabular-nums;
}
.csv-trend::before {
  content: "";
  width: 0; height: 0;
  border-left: .22rem solid transparent;
  border-right: .22rem solid transparent;
  border-bottom: .3rem solid currentColor;
}
.csv-trend.is-down { color: var(--zl-vermilion); }
/* Some markers carry a state rather than a direction; those drop the caret. */
.csv-trend.is-flat { color: var(--zl-muted-text); }
.csv-trend.is-flat::before { display: none; }
.csv-trend.is-down::before {
  border-bottom: 0;
  border-top: .3rem solid currentColor;
}

/* 1b — the headcount itself tickers, with the delta that caused it --------
   Bars alone showed a trend without a number [Arjun, 2026-08-06]. The count now
   climbs — and dips — the way a real headcount does, with the change that
   produced each move flashing beside it.

   tabular-nums matters more than it looks: proportional digits change width as
   they roll, so an un-tabulated ticker jitters horizontally the whole time it
   counts. The deltas are stacked in one grid cell for the same reason — they
   swap without moving anything next to them. */
@property --csv-count {
  syntax: "<integer>";
  initial-value: 1180;
  inherits: true;
}

.csv-tick { display: flex; align-items: baseline; gap: .5rem; margin: 0; }
.csv-tick__num {
  font-size: .95rem;
  font-weight: var(--zl-weight-medium);
  color: var(--zl-ink);
  font-variant-numeric: tabular-nums;
}
.csv-tick__num::after {
  counter-reset: heads var(--csv-count);
  content: counter(heads);
}
.build-cases.is-visible .csv-tick__num {
  animation: csv-count var(--csv-cycle) linear infinite;
}
/* Up, a small correction, then up harder — a headcount does not only rise. */
@keyframes csv-count {
  0%,     6%   { --csv-count: 1180; }
  24%,    30%  { --csv-count: 1246; }
  38%,    44%  { --csv-count: 1232; }
  62%,    68%  { --csv-count: 1358; }
  88%,    99%  { --csv-count: 1420; }
  99.5%, 100%  { --csv-count: 1180; }
}

.csv-tick__deltas { display: grid; font-variant-numeric: tabular-nums; }
.csv-tick__deltas em {
  grid-area: 1 / 1;              /* stacked, so swapping one never shifts the row */
  font-style: normal;
  white-space: nowrap;
  opacity: 0;
}
.build-cases.is-visible .csv-tick__deltas em {
  animation: csv-delta var(--csv-cycle) var(--zl-ease-out) infinite;
}
.build-cases.is-visible .csv-tick__deltas em:nth-child(1) { animation-delay: .15s; }
.build-cases.is-visible .csv-tick__deltas em:nth-child(2) { animation-delay: 1.9s; }
.build-cases.is-visible .csv-tick__deltas em:nth-child(3) { animation-delay: 3.1s; }
.build-cases.is-visible .csv-tick__deltas em:nth-child(4) { animation-delay: 4.5s; }
@keyframes csv-delta {
  0%       { opacity: 0; transform: translateY(.3rem); }
  6%       { opacity: 1; transform: none; }
  16%      { opacity: 1; transform: none; }
  24%,100% { opacity: 0; transform: translateY(-.3rem); }
}

/* 2 — Funding: the round lands ------------------------------------------- */
.csv-round__seq { display: flex; align-items: center; gap: .3rem; }
.csv-round__seq b {
  border: 1px solid var(--zl-line-strong);
  background: var(--zl-paper);
  padding: .16rem .45rem;
  font-weight: var(--zl-weight-regular);
}
.build-cases.is-visible .csv-round__seq b {
  animation: csv-round var(--csv-cycle) var(--zl-ease-standard) infinite;
  animation-delay: calc(var(--i, 0) * (var(--csv-cycle) / 3));
}
@keyframes csv-round {
  0%, 33.32%   { border-color: var(--zl-vermilion); background: var(--zl-surface); color: var(--zl-ink); }
  33.33%, 100% { border-color: var(--zl-line-strong); background: var(--zl-paper); color: var(--zl-muted-text); }
}

/* 2b — the amount tracks the highlighted round, and the total counts up ----
   The pills alone were a lie by omission: "Series B" lit while a fixed $40M
   sat underneath it, so the figure contradicted the round [Arjun, 2026-08-06].
   Now each round carries its own amount, and the running total animates to the
   new cumulative figure as each round lands.

   The count is a registered custom property, which is what makes an integer
   interpolate — plain custom properties would snap between keyframes instead
   of counting. Where @property is unsupported the value still renders and
   still changes per round; it simply steps rather than climbs. */
@property --csv-total {
  syntax: "<integer>";
  initial-value: 4;
  inherits: true;    /* the ::after that draws it must inherit the animated value */
}

/* The round amount rolls to the new figure rather than swapping to it, so the
   number moves with the highlight instead of blinking [Arjun, 2026-08-06]. The
   hold/travel windows match --csv-total exactly, and both are timed to the
   pill changeover at 33.3% and 66.6% of the cycle — so the highlight, the round
   amount and the running total all move as one. */
@property --csv-round-amt {
  syntax: "<integer>";
  initial-value: 4;
  inherits: true;    /* the ::after that draws it must inherit the animated value */
}

.csv-round__amt {
  font-size: .78rem;
  font-weight: var(--zl-weight-medium);
  color: var(--zl-ink);
  font-variant-numeric: tabular-nums;
}
.csv-round__amt::after {
  counter-reset: amt var(--csv-round-amt);
  content: "$" counter(amt) "M";
}
.build-cases.is-visible .csv-round__amt {
  animation: csv-amt var(--csv-cycle) linear infinite;
}
@keyframes csv-amt {
  0%,     28%  { --csv-round-amt: 4; }
  38%,    61%  { --csv-round-amt: 12; }
  71%,    99%  { --csv-round-amt: 40; }
  99.5%, 100%  { --csv-round-amt: 4; }
}

.csv-round__count { font-style: normal; color: var(--zl-vermilion); font-variant-numeric: tabular-nums; }
.csv-round__count::after {
  counter-reset: raised var(--csv-total);
  content: "$" counter(raised) "M";
}
.build-cases.is-visible .csv-round__count {
  animation: csv-total var(--csv-cycle) linear infinite;
}
@keyframes csv-total {
  0%,     28%  { --csv-total: 4; }    /* seed */
  38%,    61%  { --csv-total: 16; }   /* + series A */
  71%,    99%  { --csv-total: 56; }   /* + series B */
  99.5%, 100%  { --csv-total: 4; }    /* snap back, not a count down */
}

/* 3 — Departments: every team moves, one pulls away ----------------------
   Only the lead bar grew, so the other two read as static furniture — but a
   company hires across the board, and the point is the RELATIVE pull, not that
   one department is the only one doing anything [Arjun, 2026-08-06]. All three
   now grow to their own target, and the percentages ticker up with them. */
@property --csv-dept-a { syntax: "<integer>"; initial-value: 41; inherits: true; }
/* --n on each em is the target; the keyframes read it, so one set of rules
   serves pages carrying different figures. */
@property --csv-dept-b { syntax: "<integer>"; initial-value: 6;  inherits: true; }
@property --csv-dept-c { syntax: "<integer>"; initial-value: 2;  inherits: true; }

.csv-dept { display: grid; gap: .26rem; }
.csv-dept__row { display: grid; grid-template-columns: 5.2rem 1fr auto; gap: .4rem; align-items: center; margin: 0; }
.csv-dept__track { height: .42rem; border: 1px solid var(--zl-line-strong); background: var(--zl-paper); position: relative; overflow: hidden; }
.csv-dept__track i { position: absolute; inset: 0 auto 0 0; width: var(--w, 30%); background: var(--zl-muted-text); }
.csv-dept__row--lead .csv-dept__track i { background: var(--zl-cobalt); }

.build-cases.is-visible .csv-dept__track i {
  animation: csv-grow var(--csv-cycle) var(--zl-ease-out) infinite;
  animation-delay: calc(var(--i, 0) * 140ms);
}
/* Each bar grows to its own --w, so they keep their proportions. */
@keyframes csv-grow {
  0%,  8%   { width: 8%; }
  46%, 88%  { width: var(--w, 30%); }
  100%      { width: 8%; }
}

.csv-dept__row em { font-style: normal; color: var(--zl-muted-text); font-variant-numeric: tabular-nums; }
.csv-dept__row--lead em { color: var(--zl-vermilion); }
.csv-dept__row:nth-child(1) em::after { counter-reset: d var(--csv-dept-a); content: "+" counter(d) "%"; }
.csv-dept__row:nth-child(2) em::after { counter-reset: d var(--csv-dept-b); content: "+" counter(d) "%"; }
.csv-dept__row:nth-child(3) em::after { counter-reset: d var(--csv-dept-c); content: "+" counter(d) "%"; }
.build-cases.is-visible .csv-dept__row:nth-child(1) em { animation: csv-dept-a var(--csv-cycle) linear infinite; }
.build-cases.is-visible .csv-dept__row:nth-child(2) em { animation: csv-dept-b var(--csv-cycle) linear infinite; }
.build-cases.is-visible .csv-dept__row:nth-child(3) em { animation: csv-dept-c var(--csv-cycle) linear infinite; }
@keyframes csv-dept-a { 0%,8% { --csv-dept-a: 0; } 46%,92% { --csv-dept-a: var(--n, 41); } 99.5%,100% { --csv-dept-a: 0; } }
@keyframes csv-dept-b { 0%,12%{ --csv-dept-b: 0; } 50%,92% { --csv-dept-b: var(--n, 6); }  99.5%,100% { --csv-dept-b: 0; } }
@keyframes csv-dept-c { 0%,16%{ --csv-dept-c: 0; } 54%,92% { --csv-dept-c: var(--n, 2); }  99.5%,100% { --csv-dept-c: 0; } }

/* 4 — Hiring: openings accumulate ---------------------------------------- */
.csv-open__rows { display: grid; gap: .28rem; }
.csv-open__rows span {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: .5rem;
  align-items: baseline;
  opacity: .5;
}
.build-cases.is-visible .csv-open__rows span {
  animation: csv-open var(--csv-cycle) var(--zl-ease-standard) infinite;
  animation-delay: calc(var(--i, 0) * 260ms);
}
@keyframes csv-open {
  0%, 6%    { opacity: .5; transform: translateX(-.2rem); }
  26%, 88%  { opacity: 1; transform: none; }
  100%      { opacity: .5; transform: translateX(-.2rem); }
}
/* The role counts accumulate rather than sitting there — openings appear over
   time, and a static number undersold that [Arjun, 2026-08-06]. One registered
   property per row so each can carry its own target, and so the initial-value
   is the FINAL number: where @property is unsupported the row still reads 7,
   4, 2 rather than collapsing to zero. */
@property --csv-open-a { syntax: "<integer>"; initial-value: 7; inherits: true; }
@property --csv-open-b { syntax: "<integer>"; initial-value: 4; inherits: true; }
@property --csv-open-c { syntax: "<integer>"; initial-value: 2; inherits: true; }

.csv-open__tick { color: var(--zl-vermilion); font-style: normal; font-variant-numeric: tabular-nums; }
.csv-open__rows--counts span:nth-child(1) .csv-open__tick::after { counter-reset: o var(--csv-open-a); content: counter(o); }
.csv-open__rows--counts span:nth-child(2) .csv-open__tick::after { counter-reset: o var(--csv-open-b); content: counter(o); }
.csv-open__rows--counts span:nth-child(3) .csv-open__tick::after { counter-reset: o var(--csv-open-c); content: counter(o); }
.build-cases.is-visible .csv-open__rows--counts span:nth-child(1) .csv-open__tick { animation: csv-open-a var(--csv-cycle) linear infinite; }
.build-cases.is-visible .csv-open__rows--counts span:nth-child(2) .csv-open__tick { animation: csv-open-b var(--csv-cycle) linear infinite; }
.build-cases.is-visible .csv-open__rows--counts span:nth-child(3) .csv-open__tick { animation: csv-open-c var(--csv-cycle) linear infinite; }
/* The marker arrives as its own count settles, so the pair reads as one event
   rather than as a number and a decoration that happen to share a row. */
.csv-open__rows .csv-trend { opacity: 0; }
.build-cases.is-visible .csv-open__rows .csv-trend {
  animation: csv-trend-in var(--csv-cycle) var(--zl-ease-out) infinite;
  animation-delay: calc(var(--i, 0) * 8ms);
}
@keyframes csv-trend-in {
  0%,  48%  { opacity: 0; transform: translateY(.25rem); }
  56%, 94%  { opacity: 1; transform: none; }
  99%, 100% { opacity: 0; transform: translateY(.25rem); }
}
@keyframes csv-open-a { 0%,10% { --csv-open-a: 0; } 52%,96% { --csv-open-a: 7; } 99.5%,100% { --csv-open-a: 0; } }
@keyframes csv-open-b { 0%,18% { --csv-open-b: 0; } 60%,96% { --csv-open-b: 4; } 99.5%,100% { --csv-open-b: 0; } }
@keyframes csv-open-c { 0%,26% { --csv-open-c: 0; } 68%,96% { --csv-open-c: 2; } 99.5%,100% { --csv-open-c: 0; } }

/* 5 — Leadership: the seat stays, the person rolls through it -------------
   A crossfade said "this text changed"; a decision maker leaving and another
   arriving is a handover, and should look like one [Arjun, 2026-08-06]. The
   seat is a fixed, clipped window — the role does not move — and the occupants
   roll up through it, so the outgoing name physically leaves and the incoming
   one takes the position. Same ticker language as the counters. */
.csv-seat {
  display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  border: 1px solid var(--zl-line-strong);
  background: var(--zl-surface);
  padding: .3rem .55rem;
  margin: 0;
  overflow: hidden;
}
.csv-seat__who {
  position: relative;
  height: 1.15rem;
  overflow: hidden;      /* the window the occupants roll through */
  flex: 1;
  min-width: 0;
}
.csv-seat__track { display: grid; }
.csv-seat__track span {
  height: 1.15rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  white-space: nowrap;
}
/* The status belongs to the person, so it rolls with them rather than sitting
   outside the window describing whoever happens to be in it. */
.csv-seat__track span em { font-style: normal; }
.csv-seat__track span:first-child em { color: var(--zl-muted-text); }
.csv-seat__track span:last-child  em { color: var(--zl-vermilion); }
.csv-seat__track span:first-child b { color: var(--zl-muted-text); font-weight: var(--zl-weight-regular); }
.csv-seat__track span:last-child  b { color: var(--zl-ink); font-weight: var(--zl-weight-medium); }
.build-cases.is-visible .csv-seat__track {
  animation: csv-roll var(--csv-cycle) var(--zl-ease-standard) infinite;
}
@keyframes csv-roll {
  0%,   26%  { transform: translateY(0); }
  42%,  92%  { transform: translateY(-1.15rem); }   /* one row up: handover */
  99.6%,100% { transform: translateY(0); }
}
/* the tag lands with the new occupant rather than sitting there throughout */
.csv-seat__tag { color: var(--zl-vermilion); font-style: normal; opacity: 0; }
.build-cases.is-visible .csv-seat__tag {
  animation: csv-tag var(--csv-cycle) var(--zl-ease-out) infinite;
}
@keyframes csv-tag {
  0%,   30%  { opacity: 0; transform: translateX(.3rem); }
  46%,  92%  { opacity: 1; transform: none; }
  99%, 100%  { opacity: 0; transform: translateX(.3rem); }
}

@media (prefers-reduced-motion: reduce) {
  .csv-growth__plot i { transform: none; opacity: 1; }
  .csv-dept__track i { width: var(--w, 30%); }
  .build-cases.is-visible .csv-dept__track i,
  .build-cases.is-visible .csv-dept__row em { animation: none !important; }
  .csv-open__rows span,
  .csv-open__rows .csv-trend { opacity: 1; transform: none; }
  .build-cases.is-visible .csv-open__tick { animation: none !important; }
  .csv-seat__who span:first-child { opacity: 0; }
  .csv-seat__who span:last-child { opacity: 1; transform: none; }
  .csv-round__seq b:last-child { border-color: var(--zl-vermilion); background: var(--zl-surface); color: var(--zl-ink); }
  .csv-tick__num { --csv-count: 1420; }
  .csv-tick__deltas em { opacity: 0; }
  .csv-tick__deltas em:last-child { opacity: 1; }
  .build-cases.is-visible .csv-tick__num,
  .build-cases.is-visible .csv-tick__deltas em { animation: none !important; }
  .csv-round__amt { --csv-round-amt: 40; }
  .csv-round__count { --csv-total: 56; }
  .build-cases.is-visible .csv-round__amt,
  .build-cases.is-visible .csv-round__count { animation: none !important; }
  .build-cases.is-visible .csv-growth__plot i,
  .build-cases.is-visible .csv-round__seq b,
  .build-cases.is-visible .csv-dept__row--lead .csv-dept__track i,
  .build-cases.is-visible .csv-open__rows span,
  .build-cases.is-visible .csv-seat__track,
  .build-cases.is-visible .csv-seat__tag { animation: none !important; }
}


/* ==========================================================================
   In-product search (csv-find)
   The old version typed a query and dropped two bare names underneath, which
   read as labels rather than results [Arjun, 2026-08-06]. This runs the whole
   sequence a user would actually see: an empty field with a placeholder, the
   query typed into it, a pulsing "searching", then a numbered result list with
   the decision-maker count that makes each row worth clicking.
   ========================================================================== */
.csv-find { --csv-find-cycle: var(--csv-cycle); display: grid; gap: .4rem; }
.csv-find__out { display: grid; }
.csv-find__out > * { grid-area: 1 / 1; }

.csv-find__bar {
  position: relative;
  display: flex; align-items: center;
  border: 1px solid var(--zl-line-strong);
  background: var(--zl-surface);
  padding: .38rem .5rem;
  margin: 0;
  min-height: 1.7rem;
}
.csv-find__ph { color: var(--zl-muted-text); }
.build-cases.is-visible .csv-find__ph {
  animation: csv-ph var(--csv-find-cycle) steps(1) infinite;
}
@keyframes csv-ph { 0%, 6% { opacity: 1; } 7%, 100% { opacity: 0; } }

.csv-find__q {
  position: absolute; left: .5rem;
  display: inline-block;
  width: 0;
  overflow: hidden;
  white-space: nowrap;
  border-right: 1px solid transparent;
  font-style: normal;
  color: var(--zl-ink);
}
.build-cases.is-visible .csv-find__q {
  animation: csv-typing var(--csv-find-cycle) var(--zl-ease-standard) infinite;
}
@keyframes csv-typing {
  0%,  7%   { width: 0; border-right-color: currentColor; }
  26%       { width: calc(var(--ch, 24) * 1ch); border-right-color: currentColor; }
  30%, 94%  { width: calc(var(--ch, 24) * 1ch); border-right-color: transparent; }
  99%, 100% { width: 0; border-right-color: transparent; }
}

/* the pause where a real product would be waiting on the network */
.csv-find__busy { margin: 0; color: var(--zl-muted-text); opacity: 0; }
.build-cases.is-visible .csv-find__busy {
  animation: csv-busy var(--csv-find-cycle) linear infinite;
}
@keyframes csv-busy {
  0%,  28%  { opacity: 0; }
  30%       { opacity: 1; }
  36%       { opacity: .35; }
  42%       { opacity: 1; }
  46%, 100% { opacity: 0; }
}

.csv-find__hits { list-style: none; margin: 0; padding: 0; display: grid; gap: .22rem; }
.csv-find__hits li {
  display: grid;
  grid-template-columns: 1rem 1fr auto;
  gap: .4rem;
  align-items: baseline;
  opacity: 0;
}
.csv-find__hits li b { color: var(--zl-muted-text); font-weight: var(--zl-weight-regular); }
.csv-find__hits li span { color: var(--zl-ink); font-weight: var(--zl-weight-medium); }
.csv-find__hits li em { font-style: normal; color: var(--zl-vermilion); white-space: nowrap; }
.build-cases.is-visible .csv-find__hits li {
  animation: csv-hit var(--csv-find-cycle) var(--zl-ease-out) infinite;
  animation-delay: calc(var(--i, 0) * 130ms);
}
@keyframes csv-hit {
  0%,  46%  { opacity: 0; transform: translateY(.3rem); }
  52%       { opacity: 1; transform: none; }
  92%       { opacity: 1; transform: none; }
  97%, 100% { opacity: 0; transform: translateY(.3rem); }
}

@media (prefers-reduced-motion: reduce) {
  .csv-find__ph { opacity: 0; }
  .csv-find__q { position: static; width: auto; border-right-color: transparent; }
  .csv-find__busy { opacity: 0; }
  .csv-find__hits li { opacity: 1; transform: none; }
  .build-cases.is-visible .csv-find__ph,
  .build-cases.is-visible .csv-find__q,
  .build-cases.is-visible .csv-find__busy,
  .build-cases.is-visible .csv-find__hits li { animation: none !important; }
}


/* Monthly intake — the same ticker, on its own scale.
   The base .csv-tick counts a headcount (1180 to 1420); reusing it here would
   have shown a company's staff count under the label "added this month"
   [Arjun, 2026-08-07]. Its own property so the two cannot collide. */
@property --csv-intake {
  syntax: "<integer>";
  initial-value: 1500;
  inherits: true;
}
.csv-tick--intake .csv-tick__num::after {
  counter-reset: intake var(--csv-intake);
  content: counter(intake) "k";
}
.build-cases.is-visible .csv-tick--intake .csv-tick__num {
  animation: csv-intake var(--csv-cycle) linear infinite;
}
@keyframes csv-intake {
  0%,     6%   { --csv-intake: 0; }
  26%,   32%   { --csv-intake: 412; }
  50%,   56%   { --csv-intake: 806; }
  72%,   78%   { --csv-intake: 1180; }
  92%,   99%   { --csv-intake: 1500; }
  99.5%, 100%  { --csv-intake: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .csv-tick--intake .csv-tick__num { --csv-intake: 1500; }
  .build-cases.is-visible .csv-tick--intake .csv-tick__num { animation: none !important; }
}
