/*
 * Paytrack product site (kirbyservice.net): Grow's component (round 3,
 * plan.md). One floating panel of the app turns its pages as the story
 * moves, Ai (the reminder bot) stands beside it, his line above him on wide
 * screens. Markup in obj/part_grow.php, the typing, the counts and Ai's
 * moves in js/parts/grow.js, the runner in js/parts/part.js. Keep this file
 * ASCII.
 *
 * Five steps, six pages (each named for what it shows): 0 interval, then
 * thread (one flow: the machine comes due, the bot books Tom in), 1 map,
 * 2 skip, 3 team, 4 sold (Maria's items, then Ryan's).
 *
 * The whole scene is sized in em: .pt-part-stage takes the unit from the
 * column's width (container units) and the screen's height, so every part
 * keeps its place at every size and no text drops below 10px (the smallest
 * text is .8em of at least 12.5px). Two compositions: wide (desktop and
 * tablet, 35 x 17.3 em: the bubble, Ai, the panel) and narrow (phones,
 * 25.5 x 13.4 em: Ai small, the panel; no bubble), and on tall phones the
 * narrow one with Ai and his line on top (25.5 x 18.9 em). Motion is
 * transform and opacity only; the steps are the pt-sN classes and data-step
 * (part.js), the beats inside a step are transition delays and the gb-*
 * classes (grow.js). Elements marked .gw-mv take the quick and snap modes at
 * the end of this file; every one-shot effect also says :not(.gw-quick).
 *
 * Spacing (Dimitar, 02/10/2026, on Get paid: "things overlap"): the objects
 * never touch, with at least 8 px of air on desktop and 6 on phones, the
 * bobs, the hop and Ai's lean towards the pointer included; every text fits
 * its box inside its padding. Checked with tools/browser/paytrack_overlap_check.js.
 */

/* ---------- the stage: the unit, the depth ------------------------------- */
.pt-part-grow { container-type: inline-size; }
.pt-part-grow .pt-part-stage { position: relative; font-size: 14px;
  font-size: max(12.5px, min(16px, calc(100cqw / 35), 2vh));
  perspective: 1100px; perspective-origin: 56% 42%; }
.pt-part-grow .pt-part-tilt { transform-style: preserve-3d; transition: transform .6s cubic-bezier(.2, .8, .3, 1); }
.pt-part-grow .gw-set { position: relative; width: 35em; height: 17.3em; margin: 0 auto; transform-style: preserve-3d; }
.pt-part-grow .gw-set i { display: block; font-style: normal; }

/* The light in the room: a warm pool under the panel, a cool one under Ai.
   No surface edges anywhere (Dimitar: invisible, nothing that gives a shape away). */
.pt-part-grow .gw-glow { position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(36% 34% at 66% 78%, rgba(217, 197, 154, .10), rgba(217, 197, 154, 0) 72%),
    radial-gradient(18% 20% at 24% 88%, rgba(147, 183, 198, .10), rgba(147, 183, 198, 0) 72%);
  transform: translateZ(-3em); }

/* ---------- Ai, the reminder bot, and his line ---------------------------- */
/* He stands left of the panel, a little in front of it. His own bob is 6 px
   here (not site.css's 12), so his line above keeps its air. */
.pt-part-grow .gw-ai { position: absolute; left: 5.3em; bottom: .6em; width: 6.2em; transform: translateZ(1.4em); pointer-events: none; }
.pt-part-grow .gw-ai .pt-char { width: 100%; }
.pt-part-grow .gw-ai .pt-char-ai { animation-name: gw-hover; }
@keyframes gw-hover { 0%, 100% { translate: 0 0; } 50% { translate: 0 -6px; } }
.pt-part-grow .gw-ai-in { transform-origin: 50% 100%; }
/* A hop when the new engineer joins (grow.js; site.css also swells him with .is-hop). */
.pt-part-grow.gb-hop:not(.gw-quick) .gw-ai-in { animation: gw-hop .62s cubic-bezier(.3, .7, .4, 1); }
@keyframes gw-hop { 0%, 62%, 100% { transform: translateY(0); } 35% { transform: translateY(-1em); } 78% { transform: translateY(-.22em); } }

/* His line, above him, its tail down between his antennae. */
.pt-part-grow .gw-say { position: absolute; left: .3em; top: 1.4em; width: 10.6em; transform: translateZ(1em); }
.pt-part-grow .gw-say .pt-bubble { max-width: none; margin: 0; padding: .72em .95em; font-size: .86em; line-height: 1.4;
  border-radius: 1.3em 1.3em .45em 1.3em; transform-origin: 75% 100%; }
.pt-part-grow .gw-say .pt-bubble::before { left: auto; right: calc(3em - 6px); bottom: -6px; clip-path: polygon(100% 0, 100% 100%, 0 100%); }
html:not(.js) .pt-part-grow .pt-bubble { opacity: 1; transform: none; }

/* ---------- the panel: floats, turned towards Ai --------------------------- */
.pt-part-grow .gw-shadow { position: absolute; left: 13.7em; width: 19.9em; top: 14.6em; height: 1.8em; pointer-events: none;
  background: radial-gradient(closest-side, rgba(0, 0, 0, .5), rgba(0, 0, 0, 0));
  animation: gw-shadow 6s ease-in-out infinite; }
.pt-part-grow .gw-float { position: absolute; left: 12.7em; top: .7em; width: 21.9em; height: 14.4em; transform-style: preserve-3d;
  animation: gw-bob 6s ease-in-out infinite; }
@keyframes gw-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-.35em); } }
@keyframes gw-shadow { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .72; transform: scale(.9); } }
/* The card: raised, a thin sand band along the top (Grow's tone; a
   background, so it follows the rounded corners), a soft static shadow.
   Flat inside: its pages turn in their own perspective, drawn on the card,
   so a turning page never cuts through it. */
.pt-part-grow .gw-panel { position: absolute; inset: 0; border-radius: .95em; color: var(--pt-bone);
  background:
    linear-gradient(var(--pt-sand), var(--pt-sand)) 0 0 / 100% .3em no-repeat,
    linear-gradient(180deg, rgba(236, 230, 218, .05), rgba(236, 230, 218, 0) 45%),
    var(--pt-raised);
  box-shadow: 0 1.8em 2.6em -1.2em rgba(0, 0, 0, .75), 0 .2em .5em rgba(0, 0, 0, .25), inset 0 0 0 1px rgba(236, 230, 218, .07);
  transform: rotateY(-9deg) rotateX(3deg); }
/* At every page turn it swings a little (two names in turn, so the swing
   starts again each time; from and to are its own pose). */
.pt-part-grow[data-step="0"]:not(.gw-quick) .gw-panel,
.pt-part-grow[data-step="1"]:not(.gw-quick) .gw-panel,
.pt-part-grow[data-step="3"]:not(.gw-quick) .gw-panel { animation: gw-swing-a 1s ease-in-out; }
.pt-part-grow.gb-thread:not(.gw-quick) .gw-panel,
.pt-part-grow[data-step="2"]:not(.gw-quick) .gw-panel,
.pt-part-grow[data-step="4"]:not(.gw-quick) .gw-panel { animation: gw-swing-b 1s ease-in-out; }
@keyframes gw-swing-a { 40% { transform: rotateY(-14deg) rotateX(4.5deg) translateZ(-.3em); } }
@keyframes gw-swing-b { 40% { transform: rotateY(-14deg) rotateX(4.5deg) translateZ(-.3em); } }

/* The pages, stacked in one cell: the one in play is up, the ones before it
   turned away above, the ones after it waiting below. Step 0 holds two:
   interval, then thread once grow.js sets gb-thread. */
.pt-part-grow .gw-pages { position: absolute; inset: 1.05em 1em .9em; display: grid; grid-template: minmax(0, 1fr) / minmax(0, 1fr);
  perspective: 40em; transition: opacity .35s ease; }
.pt-part-grow .gw-page { grid-area: 1 / 1; display: flex; flex-direction: column; min-width: 0; min-height: 0;
  opacity: 0; transform: translate3d(0, .9em, 0) rotateX(-20deg); transition: opacity .3s ease, transform .6s var(--pt-spring); }
.pt-part-grow[data-step="-1"] .gw-pg-interval,
.pt-part-grow[data-step="0"]:not(.gb-thread) .gw-pg-interval,
.pt-part-grow.gb-thread .gw-pg-thread,
.pt-part-grow[data-step="1"] .gw-pg-map,
.pt-part-grow[data-step="2"] .gw-pg-skip,
.pt-part-grow[data-step="3"] .gw-pg-team,
.pt-part-grow[data-step="4"] .gw-pg-sold { opacity: 1; transform: none; }
.pt-part-grow.gb-thread .gw-pg-interval,
.pt-part-grow.pt-s1 .gw-pg-interval,
.pt-part-grow.pt-s1 .gw-pg-thread,
.pt-part-grow.pt-s2 .gw-pg-map,
.pt-part-grow.pt-s3 .gw-pg-skip,
.pt-part-grow.pt-s4 .gw-pg-team { transform: translate3d(0, -.7em, 0) rotateX(20deg); }
/* The new page comes up just after the old one has gone. */
.pt-part-grow:not(.gw-quick)[data-step="0"]:not(.gb-thread) .gw-pg-interval,
.pt-part-grow:not(.gw-quick).gb-thread .gw-pg-thread,
.pt-part-grow:not(.gw-quick)[data-step="1"] .gw-pg-map,
.pt-part-grow:not(.gw-quick)[data-step="2"] .gw-pg-skip,
.pt-part-grow:not(.gw-quick)[data-step="3"] .gw-pg-team,
.pt-part-grow:not(.gw-quick)[data-step="4"] .gw-pg-sold { transition-delay: .2s; }

/* Every page: a header line (its title, a chip or a note on the right), then its body. */
.pt-part-grow .gw-hd { flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; gap: .6em;
  height: 2.1em; padding-bottom: .5em; margin-bottom: .3em; box-shadow: 0 1px 0 rgba(236, 230, 218, .08); }
.pt-part-grow .gw-hd-t { display: flex; min-width: 0; }
.pt-part-grow .gw-hd-t b,
.pt-part-grow .gw-who { font: 500 .95em/1.2 var(--pt-head); letter-spacing: -.01em; color: var(--pt-bone); white-space: nowrap; }
.pt-part-grow .gw-hd-who { display: flex; align-items: center; gap: .5em; min-width: 0; }
.pt-part-grow .gw-hd-note { font: 500 .8em/1.2 var(--pt-text); color: var(--pt-lichen); white-space: nowrap; }
.pt-part-grow .gw-bd { position: relative; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; justify-content: center; }

/* Initials in a round badge, each person in their own colour. The letter is
   .8em (never under 10px), so a badge's size is in its own em: 2.875 of
   them are 2.3 of the scene's. */
.pt-part-grow .gw-av { flex: 0 0 auto; display: flex; align-items: center; justify-content: center; width: 2.6em; height: 2.6em; border-radius: 50%;
  font: 600 .8em/1 var(--pt-head); color: var(--pt-night); background: var(--pt-mist); }
.pt-part-grow .gw-hd-who .gw-av { width: 1.95em; height: 1.95em; }
.pt-part-grow .gw-av-kim { background: rgba(167, 175, 164, .3); color: var(--pt-bone); }
.pt-part-grow .gw-av-maria { background: var(--pt-dusk); }
.pt-part-grow .gw-av-ryan { background: var(--pt-sage); }

/* Chips: a pill, its words in their own span (above the shine). */
.pt-part-grow .gw-chip { position: relative; flex: 0 0 auto; display: inline-flex; align-items: center; gap: .42em; padding: .34em .78em; border-radius: 999px;
  font: 600 .8em/1.2 var(--pt-text); white-space: nowrap; }
.pt-part-grow .gw-chip > span { position: relative; }
.pt-part-grow .gw-sand { background: rgba(217, 197, 154, .16); color: var(--pt-sand); }
.pt-part-grow .gw-sage { background: rgba(157, 184, 159, .17); color: var(--pt-sage); }
.pt-part-grow .gw-mute { background: rgba(167, 175, 164, .13); color: var(--pt-lichen); }
/* Pops: a ring that spreads and fades, a shine clipped to the chip (the
   chips of llm.php). */
.pt-part-grow .gw-pop::before { content: ""; position: absolute; inset: -.24em; border-radius: inherit; border: .12em solid currentColor;
  opacity: 0; pointer-events: none; }
.pt-part-grow .gw-shine { position: absolute; inset: 0; border-radius: inherit; overflow: hidden; pointer-events: none; }
.pt-part-grow .gw-shine::after { content: ""; position: absolute; top: -20%; bottom: -20%; left: 0; width: 45%;
  background: linear-gradient(105deg, rgba(236, 230, 218, 0), rgba(236, 230, 218, .42) 50%, rgba(236, 230, 218, 0));
  transform: translateX(-120%); }
@keyframes gw-ring { 0% { opacity: .85; transform: scale(.94); } 100% { opacity: 0; transform: scale(1.18, 1.6); } }
@keyframes gw-shine { 0% { transform: translateX(-120%); } 100% { transform: translateX(300%); } }
@keyframes gw-press { 0%, 100% { transform: none; } 35% { transform: scale(.9); } }
/* The sage tick, the plus and the lock, drawn in CSS. */
.pt-part-grow .gw-tick,
.pt-part-grow .gw-plus { position: relative; flex: 0 0 auto; width: 1.1em; height: 1.1em; border-radius: 50%; background: var(--pt-sage); }
.pt-part-grow .gw-tick::after { content: ""; position: absolute; left: .39em; top: .2em; width: .28em; height: .52em;
  border: solid var(--pt-night); border-width: 0 .13em .13em 0; transform: rotate(45deg); }
.pt-part-grow .gw-plus::before,
.pt-part-grow .gw-plus::after { content: ""; position: absolute; left: 50%; top: 50%; width: .56em; height: .13em; margin: -.065em 0 0 -.28em;
  border-radius: .07em; background: var(--pt-night); }
.pt-part-grow .gw-plus::after { transform: rotate(90deg); }
.pt-part-grow .gw-lock { position: relative; flex: 0 0 auto; width: .8em; height: .64em; margin-top: .34em; border-radius: .14em; background: currentColor; }
.pt-part-grow .gw-lock::before { content: ""; position: absolute; left: .14em; right: .14em; bottom: 100%; height: .38em; margin-bottom: -.05em;
  border: .12em solid currentColor; border-bottom: 0; border-radius: .3em .3em 0 0; }

/* Reports: bars that stand still while a band of light sweeps behind them
   (Dimitar's rule for reports), on the team and sold pages. */
.pt-part-grow .gw-sweep { position: absolute; inset: -.2em -.3em; border-radius: .7em; overflow: hidden; pointer-events: none; }
.pt-part-grow .gw-sweep i { position: absolute; top: 0; bottom: 0; left: 0; width: 35%;
  background: linear-gradient(100deg, rgba(217, 197, 154, 0), rgba(217, 197, 154, .12) 50%, rgba(217, 197, 154, 0)); transform: translateX(-110%); }
@keyframes gw-sweep { 0% { transform: translateX(-110%); } 55%, 100% { transform: translateX(300%); } }

/* ---------- step 0, page interval: the machine comes due ------------------ */
/* Its past services land on the line, then the marker slides from the last
   one into the next due date. No interval label (Dimitar, 02/10/2026). */
.pt-part-grow .gw-own { display: flex; align-items: center; gap: .5em; margin: 0 0 1em; }
.pt-part-grow .gw-own .gw-av { width: 2em; height: 2em; }
.pt-part-grow .gw-own > span { font: 500 .84em/1.2 var(--pt-text); color: var(--pt-lichen); white-space: nowrap; }
.pt-part-grow .gw-line { position: relative; height: 3em; margin: 0 .35em; }
.pt-part-grow .gw-track,
.pt-part-grow .gw-done,
.pt-part-grow .gw-fill { position: absolute; top: 1em; height: .2em; margin-top: -.1em; border-radius: .1em; }
.pt-part-grow .gw-track { left: 0; right: 0; background: rgba(236, 230, 218, .1); }
/* The services done: a sage line that grows as they land. */
.pt-part-grow .gw-done { left: 6%; width: 52%; background: rgba(157, 184, 159, .45);
  transform: scaleX(0); transform-origin: 0 50%; transition: transform .55s cubic-bezier(.4, 0, .3, 1); }
.pt-part-grow.pt-s0 .gw-done { transform: none; }
.pt-part-grow .gw-fill { left: 58%; width: 34%; background: linear-gradient(90deg, rgba(217, 197, 154, .3), var(--pt-sand));
  transform: scaleX(0); transform-origin: 0 50%; transition: transform 1.15s cubic-bezier(.45, .05, .4, 1); }
.pt-part-grow.pt-s0 .gw-fill { transform: none; }
.pt-part-grow .gw-svc { position: absolute; top: 1em; width: 0; height: 0; }
.pt-part-grow .gw-svc1 { left: 6%; }
.pt-part-grow .gw-svc2 { left: 32%; }
.pt-part-grow .gw-svc3 { left: 58%; }
.pt-part-grow .gw-svc i { position: absolute; left: -.52em; top: -.52em; width: 1.04em; height: 1.04em; border-radius: 50%; background: var(--pt-sage);
  box-shadow: 0 0 0 .22em var(--pt-raised); opacity: 0; transform: scale(.3); transition: opacity .2s ease, transform .5s var(--pt-spring); }
.pt-part-grow .gw-svc i::after { content: ""; position: absolute; left: .37em; top: .19em; width: .26em; height: .48em;
  border: solid var(--pt-night); border-width: 0 .12em .12em 0; transform: rotate(45deg); }
.pt-part-grow .gw-svc small { position: absolute; left: 0; top: .82em; font: 500 .8em/1.2 var(--pt-text); color: var(--pt-lichen); white-space: nowrap;
  opacity: 0; transform: translateX(-50%); transition: opacity .3s ease; }
.pt-part-grow.pt-s0 .gw-svc i { opacity: 1; transform: none; }
.pt-part-grow.pt-s0 .gw-svc small { opacity: 1; }
/* The next due date: a sand ring waiting at the end of the line. */
.pt-part-grow .gw-due { position: absolute; left: 92%; top: 1em; width: 1.5em; height: 1.5em; margin: -.75em 0 0 -.75em; border-radius: 50%;
  box-shadow: inset 0 0 0 .14em rgba(217, 197, 154, .75), 0 0 0 .2em var(--pt-raised); background: var(--pt-raised); }
.pt-part-grow .gw-due::after { content: ""; position: absolute; inset: -.3em; border-radius: 50%; border: .12em solid var(--pt-sand); opacity: 0; }
/* The marker rides a strip as wide as the line, so it slides by a share of it. */
.pt-part-grow .gw-slide { position: absolute; left: 0; right: 0; top: 1em; height: 0; transform: translateX(-34%);
  transition: transform 1.15s cubic-bezier(.45, .05, .4, 1); }
.pt-part-grow.pt-s0 .gw-slide { transform: none; }
.pt-part-grow .gw-mark { position: absolute; left: 92%; top: 0; width: .9em; height: .9em; margin: -.45em 0 0 -.45em; border-radius: 50%;
  background: radial-gradient(circle at 35% 32%, #FFF6E2, var(--pt-sand) 55%, #A88E5F); box-shadow: 0 0 .7em rgba(217, 197, 154, .55);
  opacity: 0; transform: scale(.4); transition: opacity .25s ease, transform .45s var(--pt-spring); }
.pt-part-grow.pt-s0 .gw-mark { opacity: 1; transform: none; }
.pt-part-grow .gw-due-t { position: absolute; right: -.35em; top: 1.95em; font: 600 .8em/1.2 var(--pt-text); color: var(--pt-sand); white-space: nowrap;
  opacity: 0; transform: translateY(.4em); transition: opacity .3s ease, transform .5s var(--pt-spring); }
.pt-part-grow.pt-s0 .gw-due-t { opacity: 1; transform: none; }
.pt-part-grow:not(.gw-quick)[data-step="0"] .gw-done,
.pt-part-grow:not(.gw-quick)[data-step="0"] .gw-svc1 i,
.pt-part-grow:not(.gw-quick)[data-step="0"] .gw-svc1 small { transition-delay: .45s; }
.pt-part-grow:not(.gw-quick)[data-step="0"] .gw-svc2 i,
.pt-part-grow:not(.gw-quick)[data-step="0"] .gw-svc2 small { transition-delay: .65s; }
.pt-part-grow:not(.gw-quick)[data-step="0"] .gw-svc3 i,
.pt-part-grow:not(.gw-quick)[data-step="0"] .gw-svc3 small { transition-delay: .85s; }
.pt-part-grow:not(.gw-quick)[data-step="0"] .gw-mark { transition-delay: 1.05s; }
.pt-part-grow:not(.gw-quick)[data-step="0"] .gw-slide,
.pt-part-grow:not(.gw-quick)[data-step="0"] .gw-fill { transition-delay: 1.25s; }
.pt-part-grow:not(.gw-quick)[data-step="0"] .gw-due-t { transition-delay: 2.35s; }
.pt-part-grow:not(.gw-quick)[data-step="0"] .gw-due::after { animation: gw-ring .8s ease-out 2.3s forwards; }

/* ---------- step 0, page thread: the reminder bot books Tom in ----------- */
/* Ai's text is typed (grow.js, his antennae glow), Tom types, replies, and
   the booking chip pops. Beats: gb-msg, gb-dots, gb-reply, gb-booked; the
   end state also holds while the page turns away (pt-s1). */
.pt-part-grow .gw-thread { gap: .5em; }
.pt-part-grow .gw-msg { position: relative; display: block; max-width: 80%; padding: .52em .8em .56em; border-radius: 1.05em;
  font: 500 .84em/1.32 var(--pt-text); color: var(--pt-bone);
  opacity: 0; transform: translateY(.5em) scale(.9); transition: opacity .25s ease, transform .5s var(--pt-spring); }
.pt-part-grow .gw-out { align-self: flex-end; border-bottom-right-radius: .3em; background: rgba(147, 183, 198, .22); transform-origin: 100% 100%; }
/* The finished text, unseen, gives the bubble its size; the typed copy sits
   on it. One sentence a line (the text holds a line break). */
.pt-part-grow .gw-ghost,
.pt-part-grow .gw-typed { white-space: pre-line; }
.pt-part-grow .gw-ghost { visibility: hidden; }
.pt-part-grow .gw-typed { position: absolute; inset: .52em .8em .56em; }
.pt-part-grow .gw-typed.is-typing::after { content: ""; display: inline-block; width: 2px; height: 1.05em; margin-left: 1px; vertical-align: -.17em;
  background: var(--pt-mist); animation: gw-caret .9s linear infinite; }
@keyframes gw-caret { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }
.pt-part-grow .gw-in-wrap { display: grid; justify-items: start; align-self: flex-start; max-width: 80%; }
.pt-part-grow .gw-in-wrap > * { grid-area: 1 / 1; }
.pt-part-grow .gw-in { max-width: none; border-bottom-left-radius: .3em; background: rgba(236, 230, 218, .09); transform-origin: 0 100%; }
.pt-part-grow .gw-dots { display: flex; align-items: center; gap: .26em; padding-left: .9em; padding-right: .9em; }
.pt-part-grow .gw-dots i { width: .42em; height: .42em; border-radius: 50%; background: var(--pt-lichen); }
.pt-part-grow.gb-dots .gw-dots i { animation: gw-dot 1s ease-in-out infinite; }
.pt-part-grow.gb-dots .gw-dots i:nth-child(2) { animation-delay: .15s; }
.pt-part-grow.gb-dots .gw-dots i:nth-child(3) { animation-delay: .3s; }
@keyframes gw-dot { 0%, 60%, 100% { opacity: .45; transform: translateY(0); } 30% { opacity: 1; transform: translateY(-.22em); } }
.pt-part-grow.gb-msg .gw-out,
.pt-part-grow.pt-s1 .gw-out,
.pt-part-grow.gb-dots .gw-dots,
.pt-part-grow.gb-reply .gw-reply,
.pt-part-grow.pt-s1 .gw-reply { opacity: 1; transform: none; }
.pt-part-grow .gw-booked { display: flex; justify-content: center; margin-top: .2em; }
.pt-part-grow .gw-booked .gw-chip { opacity: 0; transform: scale(.55); transition: opacity .25s ease, transform .55s var(--pt-spring); }
.pt-part-grow.gb-booked .gw-booked .gw-chip,
.pt-part-grow.pt-s1 .gw-booked .gw-chip { opacity: 1; transform: none; }
.pt-part-grow.gb-booked:not(.gw-quick) .gw-booked .gw-chip::before { animation: gw-ring .7s ease-out .12s forwards; }
.pt-part-grow.gb-booked:not(.gw-quick) .gw-booked .gw-shine::after { animation: gw-shine .9s ease-in-out .3s; }

/* ---------- step 1, page map: campaigns, one area at a time --------------- */
/* A map of postcode tiles laid back in 3D; Canning Vale lights up and rises, its
   count pops, and Ai's messages fly to it (only there). */
.pt-part-grow .gw-due38 { opacity: 0; transform: scale(.55); transform-origin: 100% 50%; transition: opacity .25s ease, transform .55s var(--pt-spring); }
.pt-part-grow.pt-s1 .gw-due38 { opacity: 1; transform: none; }
.pt-part-grow .gw-pg-map .gw-bd { perspective: 30em; perspective-origin: 50% 10%; }
/* Tiles of 4.7 x 2.35 em, .9 em apart (8 px and more once laid back), the
   second row set off by half a tile. */
.pt-part-grow .gw-map { position: relative; width: 18.7em; height: 5.7em; margin: 0 auto; transform-style: preserve-3d; transform: rotateX(20deg); }
.pt-part-grow .gw-pc { position: absolute; width: 4.7em; height: 2.35em; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .12em;
  border-radius: .6em; background: rgba(236, 230, 218, .045); box-shadow: inset 0 0 0 1px rgba(236, 230, 218, .08); }
.pt-part-grow .gw-pc1 { left: 0; top: 0; }
.pt-part-grow .gw-pc2 { left: 5.6em; top: 0; }
.pt-part-grow .gw-pc3 { left: 11.2em; top: 0; }
.pt-part-grow .gw-pc4 { left: 2.8em; top: 3.35em; }
.pt-part-grow .gw-pc5 { left: 8.4em; top: 3.35em; }
.pt-part-grow .gw-pc6 { left: 14em; top: 3.35em; }
.pt-part-grow .gw-pc b { position: relative; font: 500 .8em/1.1 var(--pt-head); letter-spacing: .02em; color: rgba(167, 175, 164, .62); }
/* One line: "Canning Vale" (Dimitar's example address, 02/10/2026) is 60 px
   at .8em in a 59 px tile, where "Midvale" was 36; at .66em it keeps 5 px a side. */
.pt-part-grow .gw-pc small { position: relative; font: 600 .66em/1.1 var(--pt-text); letter-spacing: -.01em; white-space: nowrap; color: var(--pt-sand); }
.pt-part-grow .gw-pc-on b { color: var(--pt-bone); }
.pt-part-grow .gw-pc-on { transition: transform .6s var(--pt-spring); }
.pt-part-grow.pt-s1 .gw-pc-on { transform: translateZ(.6em); }
.pt-part-grow .gw-pc-lit { position: absolute; inset: 0; border-radius: inherit; background: rgba(217, 197, 154, .2);
  box-shadow: inset 0 0 0 .1em rgba(217, 197, 154, .7), 0 .5em 1.3em rgba(217, 197, 154, .22); opacity: 0; transition: opacity .45s ease; }
.pt-part-grow.pt-s1 .gw-pc-lit { opacity: 1; }
.pt-part-grow .gw-pc-on::after { content: ""; position: absolute; inset: -.25em; border-radius: .8em; border: .12em solid var(--pt-sand); opacity: 0; pointer-events: none; }
/* The messages: five dots from Ai's side of the panel, in an arc, onto the tile. */
.pt-part-grow .gw-fly { position: absolute; left: 13.55em; top: 1.175em; width: .55em; height: .55em; margin: -.275em 0 0 -.275em; border-radius: 50%;
  background: var(--pt-mist); box-shadow: 0 0 .5em rgba(147, 183, 198, .8); opacity: 0; }
.pt-part-grow .gw-fly2 { --d: .14s; }
.pt-part-grow .gw-fly3 { --d: .28s; }
.pt-part-grow .gw-fly4 { --d: .42s; }
.pt-part-grow .gw-fly5 { --d: .56s; }
@keyframes gw-fly {
  0% { opacity: 0; transform: translate3d(-14em, 2.4em, .5em) scale(.6); }
  14% { opacity: 1; }
  55% { transform: translate3d(-6.6em, -1.2em, 2.6em) scale(1); }
  86% { opacity: 1; }
  100% { opacity: 0; transform: translate3d(0, 0, .8em) scale(.45); }
}
.pt-part-grow:not(.gw-quick)[data-step="1"] .gw-pc-lit,
.pt-part-grow:not(.gw-quick)[data-step="1"] .gw-pc-on { transition-delay: .75s; }
.pt-part-grow:not(.gw-quick)[data-step="1"] .gw-due38 { transition-delay: 1.05s; }
.pt-part-grow:not(.gw-quick)[data-step="1"] .gw-due38::before { animation: gw-ring .7s ease-out 1.15s forwards; }
.pt-part-grow:not(.gw-quick)[data-step="1"] .gw-due38 .gw-shine::after { animation: gw-shine .9s ease-in-out 1.3s; }
.pt-part-grow:not(.gw-quick)[data-step="1"] .gw-fly { animation: gw-fly .95s cubic-bezier(.45, .05, .55, .95) calc(1.5s + var(--d, 0s)) both; }
.pt-part-grow:not(.gw-quick)[data-step="1"] .gw-pc-on::after { animation: gw-ring .8s ease-out 2.4s forwards; }

/* ---------- step 2, page skip: nobody texted twice, opt-outs honoured ----- */
/* Tom's cooldown ring fills (two halves, each a half ring that turns in its
   own clipped half); Kim's STOP comes in and turns into a muted, locked chip. */
.pt-part-grow .gw-rows { gap: .72em; }
.pt-part-grow .gw-row { display: flex; align-items: center; gap: .75em; padding: .5em .7em; border-radius: .85em; background: rgba(236, 230, 218, .045); }
.pt-part-grow .gw-row > .gw-av { width: 2.875em; height: 2.875em; }
.pt-part-grow .gw-row-t { display: flex; flex-direction: column; gap: .14em; flex: 1 1 auto; min-width: 0; }
.pt-part-grow .gw-row-t b { font: 600 .88em/1.25 var(--pt-text); color: var(--pt-bone); }
.pt-part-grow .gw-row-t small { font: 500 .8em/1.25 var(--pt-text); color: var(--pt-lichen); white-space: nowrap; }
.pt-part-grow .gw-ring { position: relative; flex: 0 0 auto; display: flex; align-items: center; justify-content: center; width: 2.3em; height: 2.3em; border-radius: 50%;
  background: rgba(147, 183, 198, .12); box-shadow: inset 0 0 0 .2em rgba(236, 230, 218, .1); }
.pt-part-grow .gw-ring > b { position: relative; font: 600 .8em/1 var(--pt-head); color: var(--pt-mist); }
.pt-part-grow .gw-half { position: absolute; top: 0; bottom: 0; width: 50%; overflow: hidden; }
.pt-part-grow .gw-half-r { left: 50%; }
.pt-part-grow .gw-half-l { left: 0; }
.pt-part-grow .gw-half i { position: absolute; top: 0; width: 200%; height: 100%; border-radius: 50%; border: .2em solid transparent;
  transform: rotate(-135deg); transition: transform .55s linear; }
.pt-part-grow .gw-half-r i { left: -100%; border-top-color: var(--pt-sand); border-right-color: var(--pt-sand); }
.pt-part-grow .gw-half-l i { left: 0; border-bottom-color: var(--pt-sand); border-left-color: var(--pt-sand); }
.pt-part-grow.pt-s2 .gw-half i { transform: rotate(45deg); }
.pt-part-grow:not(.gw-quick)[data-step="2"] .gw-half-r i { transition-delay: .6s; }
.pt-part-grow:not(.gw-quick)[data-step="2"] .gw-half-l i { transition-delay: 1.15s; }
.pt-part-grow .gw-swap { flex: 0 0 auto; display: grid; justify-items: end; align-items: center; }
.pt-part-grow .gw-swap > * { grid-area: 1 / 1; }
.pt-part-grow .gw-stop { padding: .34em .78em .36em; border-radius: 1em 1em 1em .3em; background: rgba(236, 230, 218, .1);
  font: 700 .8em/1.2 var(--pt-text); letter-spacing: .08em; color: var(--pt-bone); opacity: 0; transform-origin: 50% 100%; }
.pt-part-grow:not(.gw-quick)[data-step="2"] .gw-stop { animation: gw-stop 1.05s ease 1.85s both; }
@keyframes gw-stop { 0% { opacity: 0; transform: translateY(.45em) scale(.7); } 22%, 70% { opacity: 1; transform: none; } 100% { opacity: 0; transform: scale(.55); } }
.pt-part-grow .gw-opt { opacity: 0; transform: scale(.5); transition: opacity .25s ease, transform .55s var(--pt-spring); }
.pt-part-grow.pt-s2 .gw-opt { opacity: 1; transform: none; }
.pt-part-grow:not(.gw-quick)[data-step="2"] .gw-opt { transition-delay: 2.6s; }
.pt-part-grow:not(.gw-quick)[data-step="2"] .gw-opt::before { animation: gw-ring .7s ease-out 2.7s forwards; }
.pt-part-grow:not(.gw-quick)[data-step="2"] .gw-opt .gw-shine::after { animation: gw-shine .9s ease-in-out 2.85s; }

/* ---------- step 3, page team: more engineers, every one tracked ---------- */
/* Add engineer is pressed, Ryan (the engineer) turns up under Maria (the
   manager), the counts roll (grow.js). Each bar is that figure's share of
   the larger of the two people's. */
.pt-part-grow .gw-team { gap: .74em; perspective: 30em; }
.pt-part-grow[data-step="3"] .gw-team .gw-sweep i { animation: gw-sweep 3.4s ease-in-out 2.5s infinite; }
/* The tiles share the row by what they hold: jobs is short, sales is the
   longest figure ($24,428). */
.pt-part-grow .gw-pp { position: relative; display: grid; grid-template-columns: 2.3em minmax(0, .8fr) minmax(0, 1.3fr) minmax(0, 1fr);
  column-gap: .74em; row-gap: .78em; }
.pt-part-grow .gw-pp > .gw-av { grid-row: 1 / 3; align-self: center; width: 2.875em; height: 2.875em; }
.pt-part-grow .gw-pp-n { grid-column: 2 / 5; justify-self: start; display: flex; align-items: baseline; gap: .5em; min-width: 0; line-height: 1.25; }
.pt-part-grow .gw-pp-n b { font: 600 .88em/1.15 var(--pt-text); color: var(--pt-bone); }
.pt-part-grow .gw-pp-n small { font: 500 .8em/1.15 var(--pt-text); color: var(--pt-lichen); white-space: nowrap; }
.pt-part-grow .gw-st { position: relative; display: flex; flex-direction: column; min-width: 0; padding: .3em .45em .44em; border-radius: .55em;
  background: rgba(236, 230, 218, .05); box-shadow: inset 0 0 0 1px rgba(236, 230, 218, .06); }
.pt-part-grow .gw-st b { font: 500 .88em/1.15 var(--pt-head); letter-spacing: -.01em; color: var(--pt-bone); white-space: nowrap; font-variant-numeric: tabular-nums; }
.pt-part-grow .gw-st small { margin-top: .14em; font: 500 .8em/1.2 var(--pt-text); color: var(--pt-lichen); white-space: nowrap; }
.pt-part-grow .gw-bar { position: absolute; left: .45em; right: .45em; bottom: .14em; height: .16em; border-radius: .1em; background: var(--pt-dusk);
  transform: scaleX(var(--w, 1)); transform-origin: 0 50%; }
.pt-part-grow .gw-pp-ryan .gw-bar { background: var(--pt-sage); }
.pt-part-grow .gw-pp-ryan { opacity: 0; transform: translate3d(0, 1.2em, 0) rotateX(-55deg); transform-origin: 50% 0;
  transition: opacity .35s ease, transform .7s var(--pt-spring); }
.pt-part-grow.pt-s3 .gw-pp-ryan { opacity: 1; transform: none; }
.pt-part-grow:not(.gw-quick)[data-step="3"] .gw-add { animation: gw-press .45s ease-out .9s; }
.pt-part-grow:not(.gw-quick)[data-step="3"] .gw-add::before { animation: gw-ring .7s ease-out .95s forwards; }
.pt-part-grow:not(.gw-quick)[data-step="3"] .gw-add .gw-shine::after { animation: gw-shine .9s ease-in-out 1.05s; }
.pt-part-grow:not(.gw-quick)[data-step="3"] .gw-pp-ryan { transition-delay: 1.2s; }

/* ---------- step 4, page sold: what they sold, not just how much ---------- */
/* Items sold per person: Maria's list while grow.js holds gb-maria, then
   the switch slides to Ryan and his list comes in (also the state at rest,
   without JS and on a jump). Each count rolls up; each bar is the item's
   share of all that person's items. */
.pt-part-grow .gw-switch { position: relative; flex: 0 0 auto; display: grid; grid-template-columns: 1fr 1fr; padding: .2em; border-radius: 999px;
  background: rgba(236, 230, 218, .06); box-shadow: inset 0 0 0 1px rgba(236, 230, 218, .08); }
.pt-part-grow .gw-switch > span { position: relative; padding: .26em .8em .28em; text-align: center; font: 600 .8em/1.2 var(--pt-text); color: var(--pt-lichen); white-space: nowrap; }
.pt-part-grow .gw-switch > .gw-sw-ryan,
.pt-part-grow.gb-maria .gw-switch > .gw-sw-maria { color: var(--pt-bone); }
.pt-part-grow.gb-maria .gw-switch > .gw-sw-ryan { color: var(--pt-lichen); }
.pt-part-grow .gw-thumb { position: absolute; left: .2em; top: .2em; bottom: .2em; width: calc(50% - .2em); border-radius: 999px;
  background: rgba(236, 230, 218, .12); box-shadow: inset 0 0 0 1px rgba(236, 230, 218, .14);
  transform: translateX(100%); transition: transform .5s var(--pt-spring); }
.pt-part-grow.gb-maria .gw-thumb { transform: none; }
.pt-part-grow[data-step="4"] .gw-sold .gw-sweep i { animation: gw-sweep 3.4s ease-in-out 1.4s infinite; }
.pt-part-grow .gw-lists { position: relative; display: grid; }
.pt-part-grow .gw-items { grid-area: 1 / 1; display: flex; flex-direction: column; gap: .82em;
  transition: opacity .3s ease, transform .55s var(--pt-spring); }
.pt-part-grow .gw-items-maria { opacity: 0; transform: translateX(-.8em); }
.pt-part-grow.gb-maria .gw-items-maria { opacity: 1; transform: none; }
.pt-part-grow.gb-maria .gw-items-ryan { opacity: 0; transform: translateX(.8em); }
.pt-part-grow:not(.gw-quick)[data-step="4"]:not(.gb-maria) .gw-items-ryan { transition-delay: .12s; }
.pt-part-grow .gw-item { position: relative; display: flex; align-items: baseline; justify-content: space-between; gap: .8em; padding: 0 .15em .66em; }
.pt-part-grow .gw-item-n { font: 600 .86em/1.25 var(--pt-text); color: var(--pt-bone); white-space: nowrap; }
.pt-part-grow .gw-qty { display: flex; align-items: baseline; gap: .22em; white-space: nowrap; }
.pt-part-grow .gw-qty small { font: 500 .8em/1.2 var(--pt-text); color: var(--pt-lichen); }
.pt-part-grow .gw-qty b { font: 500 .92em/1.15 var(--pt-head); letter-spacing: -.01em; color: var(--pt-bone); font-variant-numeric: tabular-nums; }
.pt-part-grow .gw-share { position: absolute; left: .15em; right: .15em; bottom: .12em; height: .22em; border-radius: .11em; overflow: hidden;
  background: rgba(236, 230, 218, .08); }
.pt-part-grow .gw-share::after { content: ""; position: absolute; inset: 0; border-radius: inherit; background: var(--pt-dusk);
  transform: scaleX(var(--w, 1)); transform-origin: 0 50%; }
.pt-part-grow .gw-items-ryan .gw-share::after { background: var(--pt-sage); }

/* ---------- the rewind: the pages fade, the set stays --------------------- */
.pt-part-grow.is-rewind .gw-pages { opacity: 0; }

/* ---------- the steps under the scene -------------------------------------- */
/* Desktop: small floating pills in a compact wrap; the one in play is lit in sand. */
.pt-part-grow .pt-part-steps { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; margin: 12px 0 0; padding: 0; list-style: none; }
.pt-part-grow .pt-part-steps li { position: relative; isolation: isolate; display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 12px 6px 9px; border-radius: 999px; background: rgba(236, 230, 218, .06); color: var(--pt-bone);
  font: 500 var(--pt-fs-say)/1.3 var(--pt-text); cursor: default;
  animation: gw-pill 6s ease-in-out infinite; animation-delay: calc(var(--i, 0) * -1.2s); }
.pt-part-grow .pt-part-steps li::before { content: ""; flex: 0 0 auto; width: 7px; height: 7px; border-radius: 50%;
  background: var(--tone, var(--pt-sand)); opacity: .45; transform: scale(.85); transition: opacity .3s ease, transform .4s var(--pt-spring); }
/* The lit state: a brighter ground and the dot's glow, one layer that fades in. */
.pt-part-grow .pt-part-steps li::after { content: ""; position: absolute; z-index: -1; inset: 0; border-radius: inherit;
  background: radial-gradient(circle at 12.5px 50%, rgba(217, 197, 154, .5), rgba(217, 197, 154, 0) 15px), rgba(236, 230, 218, .07);
  opacity: 0; transition: opacity .35s ease; }
.pt-part-grow .pt-part-steps li > span { opacity: .7; transition: opacity .3s ease; }
.pt-part-grow .pt-part-steps li.is-on::before { opacity: 1; transform: scale(1.2); }
.pt-part-grow .pt-part-steps li.is-on::after,
.pt-part-grow .pt-part-steps li.is-on > span { opacity: 1; }
.pt-part-grow .pt-part-steps li:focus-visible { outline: 2px solid var(--pt-sand); outline-offset: 3px; }
@keyframes gw-pill { 0%, 100% { translate: 0 0; } 50% { translate: 0 -3px; } }
/* The lg column (444 wide): a size smaller, so the pills pair up in three
   rows instead of five single ones. */
@media (min-width: 992px) and (max-width: 1199.98px) {
  .pt-part-grow .pt-part-steps li { gap: 6px; padding: 5px 10px 5px 8px; font-size: calc(var(--pt-fs-say) - 2px); }
  .pt-part-grow .pt-part-steps li::after { background: radial-gradient(circle at 11px 50%, rgba(217, 197, 154, .5), rgba(217, 197, 154, 0) 14px), rgba(236, 230, 218, .07); }
}

/* Nothing moves in a layer that is not the one in front. */
.pt-layer:not(.is-current) .pt-part-grow .gw-float,
.pt-layer:not(.is-current) .pt-part-grow .gw-shadow,
.pt-layer:not(.is-current) .pt-part-grow .gw-sweep i,
.pt-layer:not(.is-current) .pt-part-grow .gw-dots i,
.pt-layer:not(.is-current) .pt-part-grow .gw-typed::after,
.pt-layer:not(.is-current) .pt-part-grow .pt-part-steps li { animation-play-state: paused; }

/* ---------- phones: the narrow composition --------------------------------- */
/* No room for his line: Ai stands small at the left, the panel takes the
   rest; the steps become one line, five dots and the caption of the one in play. */
@media (max-width: 575.98px) {
  .pt-part-grow .pt-part-stage { font-size: 12.5px; font-size: max(12.5px, min(14px, calc(100cqw / 25.5))); perspective: 820px; perspective-origin: 60% 45%; }
  .pt-part-grow .gw-set { width: 25.5em; height: 13.4em; }
  .pt-part-grow .gw-glow { background:
      radial-gradient(44% 34% at 62% 80%, rgba(217, 197, 154, .10), rgba(217, 197, 154, 0) 72%),
      radial-gradient(16% 22% at 8% 86%, rgba(147, 183, 198, .10), rgba(147, 183, 198, 0) 72%); }
  .pt-part-grow .gw-say { display: none; }
  .pt-part-grow .gw-ai { left: 0; bottom: .45em; width: 3.9em; transform: translateZ(.8em); }
  .pt-part-grow .gw-ai .pt-char-ai { animation-name: gw-hover-sm; }
  .pt-part-grow .gw-shadow { left: 5.6em; width: 19.2em; top: 12.3em; height: 1.1em; }
  .pt-part-grow .gw-float { left: 4.95em; top: .3em; width: 20.5em; height: 12.6em; }
  .pt-part-grow .gw-panel { border-radius: .85em; transform: rotateY(-7deg) rotateX(2deg); }
  .pt-part-grow .gw-pages { inset: .72em .72em .5em; }
  .pt-part-grow .gw-hd { height: 1.95em; padding-bottom: .42em; margin-bottom: .2em; }
  .pt-part-grow .gw-own { margin-bottom: .8em; }
  .pt-part-grow .gw-thread { gap: .5em; }
  .pt-part-grow .gw-out { max-width: 84%; }
  .pt-part-grow .gw-rows { gap: .66em; }
  .pt-part-grow .gw-row { padding: .42em .6em; }
  .pt-part-grow .gw-team { gap: .66em; }
  .pt-part-grow .gw-pp { grid-template-columns: 1.9em minmax(0, .8fr) minmax(0, 1.3fr) minmax(0, 1fr); column-gap: .56em; row-gap: .6em; }
  .pt-part-grow .gw-pp > .gw-av { width: 2.375em; height: 2.375em; }
  .pt-part-grow .gw-st { padding: .22em .4em .36em; }
  .pt-part-grow .gw-st small { line-height: 1.1; }
  .pt-part-grow .gw-bar { left: .4em; right: .4em; bottom: .1em; height: .14em; }
  .pt-part-grow .gw-items { gap: .62em; }
}
@keyframes gw-hover-sm { 0%, 100% { translate: 0 0; } 50% { translate: 0 -4px; } }
/* The phone caption: five dots and the lit step's line (with JS; without it
   the pills above stay, all five). */
@media (max-width: 575.98px) {
  html.js .pt-part-grow .pt-part-steps { position: relative; flex-wrap: nowrap; justify-content: flex-start; gap: 0; height: 22px; margin-top: 6px; }
  html.js .pt-part-grow .pt-part-steps li { position: static; isolation: auto; flex: 0 0 15px; justify-content: center; width: 15px; height: 22px; padding: 0;
    background: none; animation: none; }
  html.js .pt-part-grow .pt-part-steps li::after { display: none; }
  html.js .pt-part-grow .pt-part-steps li::before { width: 6px; height: 6px; }
  html.js .pt-part-grow .pt-part-steps li.is-on::before { transform: scale(1.5); }
  html.js .pt-part-grow .pt-part-steps li > span { position: absolute; left: 81px; top: 0; font-size: calc(var(--pt-fs-say) - 1px); line-height: 22px; white-space: nowrap;
    opacity: 0; transform: translateY(6px); pointer-events: none; transition: opacity .3s ease, transform .45s var(--pt-spring); }
  html.js .pt-part-grow .pt-part-steps li.is-on > span { opacity: 1; transform: none; pointer-events: auto; }
  html.js .pt-part-grow[data-step="-1"] .pt-part-steps li:first-child > span { opacity: .5; transform: none; }
}
/* Tall phones (390 x 844 has about 300 px below the copy): room for his line.
   Ai at the top left with it beside him, its tail at his head; the panel
   below, the whole width. After the phone rules, which it overrides. */
@media (max-width: 575.98px) and (min-height: 760px) {
  .pt-part-grow .gw-set { height: 18.9em; }
  .pt-part-grow .gw-glow { background:
      radial-gradient(44% 30% at 50% 80%, rgba(217, 197, 154, .10), rgba(217, 197, 154, 0) 72%),
      radial-gradient(16% 16% at 9% 16%, rgba(147, 183, 198, .10), rgba(147, 183, 198, 0) 72%); }
  .pt-part-grow .gw-ai { left: .3em; top: 0; bottom: auto; }
  .pt-part-grow .gw-say { display: block; left: 5.1em; top: 0; width: 15.5em; transform: translateZ(.6em); }
  .pt-part-grow .gw-say .pt-bubble { border-radius: 1.3em 1.3em 1.3em .45em; transform-origin: 0 50%; }
  .pt-part-grow .gw-say .pt-bubble::before { left: -6px; right: auto; bottom: auto; top: calc(1.95em - 6px); clip-path: polygon(0 0, 0 100%, 100% 100%); }
  .pt-part-grow .gw-float { left: .3em; top: 5.9em; width: 24.9em; height: 12.6em; }
  .pt-part-grow .gw-shadow { left: 1.2em; width: 23.1em; top: 17.7em; }
  .pt-part-grow .gw-panel { transform: rotateY(-5deg) rotateX(2deg); }
  .pt-part-grow .gw-items { gap: .82em; }
}

/* ---------- instant draws (grow.js) ---------------------------------------- */
/* A jump to a step (a hover, a tap, the test hook) glides there quickly with
   no delays; the reset snaps. Last, to win the ties. */
.pt-part-grow.gw-quick .gw-mv { transition-duration: .3s; transition-delay: 0s; }
.pt-part-grow.gw-snap .gw-mv,
.pt-part-grow.gw-snap .gw-mv *,
.pt-part-grow.gw-snap .gw-mv::before,
.pt-part-grow.gw-snap .gw-mv::after { transition: none; animation: none; }
