/* ============================================================
   Platform blocks — the schematic card that sits in each
   service slide.

   Ported from "Static Blocks.dc.html" in the Claude Design
   project. These are deliberately wordless: abstract bars and
   shapes that read as a dashboard without competing with the
   slide's own headline and copy. No animation, no JS.

   The source authors each card at 480px tall inside a 1560px
   three-column grid. Here one card fills the slide's left
   column, so the fixed pixel sizes become proportional and the
   card scales with its container.
   ============================================================ */

.pblock {
  --pb:      255, 241, 232;          /* cream, the ink of these blocks */
  --pb-line: rgba(var(--pb), 0.24);
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 22px;
  aspect-ratio: 5 / 6;
  padding: 7%;
  border-radius: 26px;
  box-sizing: border-box;
  background: linear-gradient(152deg, rgba(var(--pb), 0.17), rgba(var(--pb), 0.07));
  border: 1px solid var(--pb-line);
  container-type: inline-size;
}

/* The card turns very slowly on two axes, the way a hanging mirror
   drifts — never repeating on the same beat, because the X and Y
   periods differ (23s against 31s) so the pair only realigns after
   about ten minutes. Slow enough to read as depth, not as motion. */
/* The perspective sits on the parent of whatever rotates. The card's own
   loop rotates .pblock, so .pblock__tilt carries it for that; the
   pointer rotates .pblock__tilt itself, so its parent carries it too —
   see .slide__block below. */
.pblock__tilt {
  perspective: 1400px;
  perspective-origin: 50% 50%;
}
/* The tilt is declared here for any block outside a slide; inside one,
   the entrance rule below restates it alongside the fade so the two
   share a single animation shorthand. */
/* The card rests flat. It only turns under the cursor — see the
   pointer-driven tilt below — so nothing moves on its own. */
.pblock__tilt > .pblock {
  transform-style: preserve-3d;
}

/* ---------- entrance ----------
   The card fades in, then draws itself: bars grow from their base,
   tracks fill from the left, rings sweep round, the chart line draws
   along its own length. Everything is CSS on elements that already
   exist — no JS, no extra DOM, and the whole thing is keyed off the
   slide becoming active so it replays each time you return to it.

   `--e` staggers the parts: each rule adds its own beat on top. */
.slide .pblock,
.slide .pblock * { animation-play-state: paused; }
.slide.is-active .pblock,
.slide.is-active .pblock * { animation-play-state: running; }

.slide__block .pblock {
  opacity: 0;
  animation: pblock-in 700ms var(--ease) forwards;
}

/* ---------- pointer-driven tilt ----------
   The card is still at rest. The cursor is the only thing that turns
   it: JS writes the rotation as --ry/--rx and the surface follows,
   the way a mirror does. Letting go coasts it back to flat on a long
   ease, so the motion carries a little past the cursor rather than
   stopping dead with it.

   Nothing here runs without JS: --ry/--rx never appear, .is-live is
   never set, and the block simply sits flat.

   JS writes --ry/--rx as finished angles (with units) rather than bare
   numbers to multiply here: a custom property is an unparsed token
   stream, so any arithmetic on it that fails silently invalidates the
   whole transform and the card just sits flat. */
.pblock__tilt {
  transform-style: preserve-3d;
  transition: transform 620ms cubic-bezier(.22, .61, .36, 1);
}
.pblock__tilt.is-live {
  transform: rotateY(var(--ry, 0deg)) rotateX(var(--rx, 0deg));
  transition-duration: 160ms;   /* tracks the cursor closely while held */
}
/* Let go and the short tracking duration gives way to the long ease, so
   the card coasts back to flat instead of snapping. This has to outrank
   .is-live, which is still applied through the settle. */
.pblock__tilt.is-live.is-leaving {
  transition-duration: 760ms;
}
.pblock__tilt.is-live.is-leaving > .pblock::after {
  transition-duration: 760ms;
}

@keyframes pblock-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* bars grow out of the floor */
.slide.is-active .pblock .bars > i {
  transform-origin: bottom;
  animation: pb-grow 620ms var(--ease) backwards;
  animation-delay: calc(360ms + var(--e, 0) * 55ms);
}
.pblock .bars > i:nth-child(1) { --e: 0; }
.pblock .bars > i:nth-child(2) { --e: 1; }
.pblock .bars > i:nth-child(3) { --e: 2; }
.pblock .bars > i:nth-child(4) { --e: 3; }
.pblock .bars > i:nth-child(5) { --e: 4; }
.pblock .bars > i:nth-child(6) { --e: 5; }
.pblock .bars > i:nth-child(7) { --e: 6; }
.pblock .bars > i:nth-child(8) { --e: 7; }
.pblock .bars > i:nth-child(9) { --e: 8; }
@keyframes pb-grow { from { transform: scaleY(0); } }

/* tracks, stages and progress fills wipe in from the left */
.slide.is-active .pblock .track > u,
.slide.is-active .pblock .stage > u {
  transform-origin: left;
  animation: pb-wipe 760ms var(--ease) backwards;
  animation-delay: calc(420ms + var(--e, 0) * 90ms);
}
@keyframes pb-wipe { from { transform: scaleX(0); } }
.pblock .row:nth-child(2) .track > u { --e: 1; }
.pblock .row:nth-child(3) .track > u { --e: 2; }

/* rings sweep round from their start */
.slide.is-active .pblock .ring .fg {
  animation: pb-ring 1100ms var(--ease) 460ms backwards;
}
@keyframes pb-ring { from { stroke-dashoffset: 327; } }

/* the chart line draws along its own length, the area fades under it */
.slide.is-active .pblock .chart .line {
  stroke-dasharray: 620;
  animation: pb-draw 1200ms var(--ease) 420ms backwards;
}
@keyframes pb-draw { from { stroke-dashoffset: 620; } }

/* venn circles drift together from outside */
.slide.is-active .pblock .venn .c1,
.slide.is-active .pblock .venn .c2 {
  animation: pb-venn 900ms var(--ease) backwards;
  animation-delay: calc(380ms + var(--e, 0) * 110ms);
  transform-origin: center;
}
.pblock .venn .c1 { --e: 0; }
.pblock .venn circle:nth-child(2) { --e: 1; }
.pblock .venn circle:nth-child(3) { --e: 2; }
@keyframes pb-venn { from { opacity: 0; transform: scale(0.86); } }
.slide.is-active .pblock .venn .core {
  animation: pb-pop 520ms var(--ease) 900ms backwards;
}
@keyframes pb-pop { from { opacity: 0; transform: scale(0.2); } }

/* the small parts — labels, slabs, list rows — lift into place */
.slide.is-active .pblock .b,
.slide.is-active .pblock .slab,
.slide.is-active .pblock .item,
.slide.is-active .pblock .thumbs > i,
.slide.is-active .pblock .fields > i,
.slide.is-active .pblock .frame {
  animation: pb-lift 560ms var(--ease) backwards;
  animation-delay: calc(300ms + var(--e, 0) * 70ms);
}
@keyframes pb-lift { from { opacity: 0; transform: translateY(9px); } }
.pblock .item:nth-child(1), .pblock .thumbs > i:nth-child(1), .pblock .fields > i:nth-child(1) { --e: 0; }
.pblock .item:nth-child(2), .pblock .thumbs > i:nth-child(2), .pblock .fields > i:nth-child(2) { --e: 1; }
.pblock .item:nth-child(3), .pblock .thumbs > i:nth-child(3), .pblock .fields > i:nth-child(3) { --e: 2; }

/* A light that slides across the face as the card turns — the part
   that makes it read as a mirror rather than a rotating rectangle. */
.pblock::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(104deg,
    rgba(var(--pb), 0) 34%,
    rgba(var(--pb), 0.09) 48%,
    rgba(var(--pb), 0) 62%);
  /* The highlight rides with the tilt rather than travelling on a loop:
     --sheen is 0 at rest and follows the cursor while the card is held,
     so the light only moves when the surface does. */
  opacity: calc(0.45 + var(--lit, 0) * 0.55);
  transform: translateX(calc(var(--sheen, 0) * 26%));
  transition: transform 620ms cubic-bezier(.22, .61, .36, 1),
              opacity 620ms cubic-bezier(.22, .61, .36, 1);
}
.pblock__tilt.is-live > .pblock::after {
  transition-duration: 160ms;
}

/* On a light ground the same block inverts to forest ink. */
.is-cream .pblock,
.is-white .pblock,
.is-butter .pblock { --pb: 65, 111, 59; }

/* Every measurement below is a share of the card's own width, so
   the block keeps its proportions at any column size. */
.pblock * { box-sizing: border-box; }

/* ---------- primitives ---------- */
.pblock i,
.pblock u { display: block; font-style: normal; text-decoration: none; }

/* a bar: --w width in %, --h height in px-ish cqw, --o opacity */
.pblock .b {
  height: calc(var(--h, 2) * 1cqw);
  width: calc(var(--w, 30) * 1%);
  border-radius: 99px;
  background: rgba(var(--pb), var(--o, 0.34));
  flex: none;
}
.pblock .b--solid { background: rgb(var(--pb)); }
/* a filled slab — the stand-in for a big number */
.pblock .slab {
  height: calc(var(--h, 8) * 1cqw);
  width: calc(var(--w, 26) * 1%);
  border-radius: calc(1.8 * 1cqw);
  background: rgba(var(--pb), var(--o, 0.62));
  flex: none;
}
.pblock .slab--solid { background: rgb(var(--pb)); }

.pblock .row  { display: flex; align-items: center; gap: calc(2.4 * 1cqw); }
.pblock .col  { display: flex; flex-direction: column; gap: calc(2.2 * 1cqw); }
.pblock .between { justify-content: space-between; }
.pblock .grow { flex: 1; min-height: 0; }
.pblock .push { margin-top: auto; }

.pblock .dot {
  width: calc(2.2 * 1cqw); height: calc(2.2 * 1cqw);
  border-radius: 50%; background: rgb(var(--pb)); flex: none;
}
.pblock .pill {
  height: calc(5.2 * 1cqw); width: calc(13 * 1cqw);
  border-radius: 99px; background: rgba(var(--pb), 0.16); flex: none;
}

/* a panel: the inset surface used for charts and lists.
   The floor matters: the panel is the only flexible row in most cards,
   so on a short card the fixed rows would starve it to zero and the
   chart would vanish rather than shrink. */
.pblock .panel {
  position: relative;
  border-radius: calc(3.8 * 1cqw);
  background: rgba(var(--pb), 0.05);
  overflow: hidden;
  /* the panel is the only flexible row in most cards: without a floor
     the fixed rows starve it to zero on a short card and the chart
     disappears instead of shrinking */
  min-height: calc(18 * 1cqw);
}
.pblock .frame {
  border-radius: calc(3.4 * 1cqw);
  border: 1px solid rgba(var(--pb), 0.24);
  background: rgba(var(--pb), 0.06);
  padding: calc(2.6 * 1cqw);
  min-height: calc(22 * 1cqw);   /* same floor as .panel, see above */
}

/* column chart */
.pblock .bars { display: flex; align-items: flex-end; gap: calc(1.6 * 1cqw); height: calc(11 * 1cqw); }
.pblock .bars > i {
  flex: 1; border-radius: calc(0.9 * 1cqw);
  height: calc(var(--v, 50) * 1%);
  background: rgba(var(--pb), 0.28);
}
.pblock .bars > i.on { background: rgb(var(--pb)); }

/* progress track */
.pblock .track {
  height: calc(1.5 * 1cqw); border-radius: 99px;
  background: rgba(var(--pb), 0.18); overflow: hidden;
}
.pblock .track > u {
  height: 100%; width: calc(var(--v, 50) * 1%);
  border-radius: 99px; background: rgba(var(--pb), 0.55);
}
.pblock .track > u.on { background: rgb(var(--pb)); }

/* funnel stage — a taller track */
.pblock .stage { height: calc(6.4 * 1cqw); border-radius: calc(1.7 * 1cqw); background: rgba(var(--pb), 0.10); overflow: hidden; }
.pblock .stage > u { height: 100%; border-radius: calc(1.7 * 1cqw); width: calc(var(--v, 50) * 1%); background: rgba(var(--pb), var(--o, 0.26)); }
.pblock .stage > u.on { background: rgb(var(--pb)); }

/* list row — the search result / feed item */
.pblock .item {
  height: calc(15.5 * 1cqw);
  border-radius: calc(3.8 * 1cqw);
  border: 1px solid rgba(var(--pb), 0.14);
  background: rgba(var(--pb), 0.04);
  display: flex; align-items: center; gap: calc(3.4 * 1cqw);
  padding: 0 calc(3.4 * 1cqw);
}
.pblock .item.on { border-color: rgba(var(--pb), 0.44); background: rgba(var(--pb), 0.10); }
.pblock .item .ico {
  width: calc(10.6 * 1cqw); height: calc(10.6 * 1cqw);
  border-radius: calc(2.9 * 1cqw);
  background: rgba(var(--pb), 0.18); flex: none;
}
.pblock .item.on .ico { background: rgba(var(--pb), 0.42); }
.pblock .item .lines { flex: 1; display: flex; flex-direction: column; gap: calc(1.9 * 1cqw); }

/* ring */
.pblock .ring { width: calc(21 * 1cqw); height: calc(21 * 1cqw); flex: none; }
.pblock .ring circle { fill: none; stroke-width: 11; }
.pblock .ring .bg { stroke: rgba(var(--pb), 0.18); }
.pblock .ring .fg { stroke: rgb(var(--pb)); stroke-linecap: round; }

/* chart panel */
.pblock .chart { position: absolute; inset: 0; width: 100%; height: 100%; }
.pblock .chart .grid { stroke: rgba(var(--pb), 0.13); stroke-width: 1; }
.pblock .chart .line { fill: none; stroke: rgb(var(--pb)); stroke-width: 4; stroke-linecap: round; stroke-linejoin: round; }
.pblock .tag {
  position: absolute; right: calc(4.6 * 1cqw); top: calc(3.6 * 1cqw);
  width: calc(15 * 1cqw); height: calc(5.5 * 1cqw);
  border-radius: 99px; background: rgb(var(--pb));
}

/* venn */
.pblock .venn { width: 68%; height: auto; align-self: center; }
.pblock .venn circle { stroke-width: 1.5; }
.pblock .venn .c1 { fill: rgba(var(--pb), 0.10); stroke: rgb(var(--pb)); }
.pblock .venn .c2 { fill: rgba(var(--pb), 0.10); stroke: rgba(var(--pb), 0.42); }
.pblock .venn .core { fill: rgb(var(--pb)); stroke: none; }

/* creative thumbnails */
.pblock .thumbs { display: flex; gap: calc(2.4 * 1cqw); align-items: flex-start; }
.pblock .thumbs > i {
  width: calc(11 * 1cqw); height: calc(19.5 * 1cqw);
  border-radius: calc(2.4 * 1cqw);
  background: rgba(var(--pb), 0.14);
  border: 1px solid rgba(var(--pb), 0.20);
}
.pblock .thumbs > i.on {
  width: calc(12.5 * 1cqw); height: calc(22 * 1cqw); margin-top: calc(-1.5 * 1cqw);
  background: rgba(var(--pb), 0.30); border-color: rgba(var(--pb), 0.55);
}

/* search bar */
.pblock .search {
  height: calc(12 * 1cqw); flex: none;
  border-radius: calc(3.4 * 1cqw);
  border: 1px solid rgba(var(--pb), 0.24);
  background: rgba(var(--pb), 0.10);
  display: flex; align-items: center; gap: calc(2.9 * 1cqw);
  padding: 0 calc(3.9 * 1cqw);
}
.pblock .search svg { width: calc(3.9 * 1cqw); height: calc(3.9 * 1cqw); flex: none; stroke: rgba(var(--pb), 0.58); fill: none; stroke-width: 2; }

/* form fields */
.pblock .fields { flex: 1; display: flex; flex-direction: column; gap: calc(2.4 * 1cqw); }
.pblock .fields > i {
  height: calc(8.2 * 1cqw); border-radius: calc(2.4 * 1cqw);
  border: 1px solid rgba(var(--pb), 0.24);
  background: rgba(var(--pb), 0.05);
}
.pblock .fields > i.on { background: rgb(var(--pb)); border-color: transparent; }

/* the caption under the card, as in the source */
.pblock__cap {
  margin-top: 14px;
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(var(--pb), 0.62);
}

/* ---------- inside a service slide ----------
   The block takes whatever height the column has left under the
   number, and its width follows from the 5/6 ratio — so it never
   pushes the stage into the rail no matter how short the viewport. */
/* The block is its own column, but it stops short of the full stage
   height — at 80% it reads as a panel sitting in the slide rather than
   a wall, and it centres against the copy beside it. */
.slide__vis { min-height: 0; display: flex; align-items: center; }
.slide__block {
  min-height: 0;
  flex: 1;
  display: flex;
  align-items: stretch;   /* the card fills the 80%, rather than sitting in it */
  height: 80%;
  perspective: 1400px;    /* gives the pointer rotation its depth */
  perspective-origin: 50% 50%;
}
.pblock__tilt { width: 100%; display: flex; }
.slide__block .pblock {
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  padding: clamp(var(--s-4), 2vw, var(--s-5));
  gap: clamp(var(--s-3), 1.7vw, var(--s-4));
}

@media (max-width: 960px) {
  /* the stacked list leads with the copy; the block would push
     the headline off the first screen */
  /* scoped to the pinned slides: the service hero has its own breakpoint */
  .slide__vis, .pin .slide__block { display: none; }
}
