/* This file is built from the home page parts. Edit the parts, not this file. */

/* ---------- scene: parts, streams ---------- */

/* A part's ordinary css is where it ends up, and that is what stands there
   whenever the scene is not playing: at first paint, mid-scroll, with motion
   refused. A scene is NEVER blank. Only once it starts to play do its parts
   step back to where they come from, and they arrive from there. */
.armed [data-scene].is-playing .part {
  opacity: 0;
  transform: translateY(16px) scale(0.96);
  transition:
    opacity   .5s var(--ease),
    transform .85s var(--settle);
}
.armed [data-scene].is-playing .part[data-how="fade"] { transform: none; }
.armed [data-scene].is-playing .part[data-how="rise"] { transform: translateY(12px); }
.armed [data-scene].is-playing .part.on { opacity: 1; transform: none; }
.armed [data-scene].is-playing .part.off {
  opacity: 0;
  transform: none;
  transition: opacity .3s var(--ease);
}
/* at rest, a part that leaves during the play is simply not there */
.armed [data-scene]:not(.is-playing) .part[data-off] { display: none; }
/* between two plays a looping scene lets go of its frame softly */
.armed [data-scene].is-resetting .part,
.armed [data-scene].is-playing.is-resetting .part.on {
  opacity: 0;
  transform: translateY(-8px);
  filter: blur(6px);
  transition: opacity .45s var(--ease), transform .45s var(--ease), filter .45s var(--ease);
}
/* a part that leaves gives its room back */
.armed [data-scene].is-playing .part[data-collapse].off { display: none; }

.armed [data-scene].is-playing [data-stream] .sw {
  opacity: 0;
  transition: opacity .4s var(--ease) var(--d, 0ms);
}
.armed [data-scene].is-playing [data-stream].on .sw { opacity: 1; }

.is-still .part, .is-still .sw,
[data-scene].is-still .part, [data-scene].is-still .sw { transition: none !important; }

@media (prefers-reduced-motion: reduce) {
  .armed [data-scene] .part, .armed [data-scene].is-playing [data-stream] .sw { transition: none; transform: none; }
}

/* a section out of sight costs nothing: whatever loops in it waits (home.js) */
.is-offscreen *, .is-offscreen *::before, .is-offscreen *::after { animation-play-state: paused !important; }

/* ---------- surfaces ---------- */

.card {
  background: var(--card);
  border-radius: var(--r-card);
  box-shadow: var(--ladder-lite), 0 0 0 1px rgba(0, 0, 0, 0.04);
}
.card.is-deep {
  background: var(--deep);
  color: var(--ink-on-deep);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), 0 18px 40px -18px rgba(12, 13, 16, 0.5);
}

/* text drawn as bars. Length by --w, never letters. */
.bar {
  display: block;
  height: 0.62em;
  width: var(--w, 60%);
  border-radius: 999px;
  background: var(--bar);
}
.bar.is-2 { background: var(--bar-2); }
.bar.is-3 { background: var(--bar-3); }
.bars { display: grid; gap: 0.62em; }

/* small white pill: `done`, `ready`, `added by Ola` */
.tag {
  display: inline-flex;
  align-items: center;
  gap: 0.42em;
  height: 2em;
  padding: 0 0.85em;
  border-radius: 999px;
  background: #fff;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.07), 0 1px 2px rgba(0, 0, 0, 0.05);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: -0.004em;
  color: var(--ink);
  white-space: nowrap;
}
.tag svg { width: 1.05em; height: 1.05em; fill: none; stroke: var(--good); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.tag.is-live { background: var(--live); color: #fff; box-shadow: 0 6px 16px -6px rgba(44, 99, 210, 0.55); }

/* the mark in a rounded white tile, the way the app shows it */
.marktile {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 18px;
  background: #fff;
  box-shadow: var(--ladder-lite), 0 0 0 1px rgba(0, 0, 0, 0.04);
  color: var(--ink);
}
.marktile svg { width: 58%; height: 58%; }

/* ---------- the request capsule ---------- */

/* what somebody says to Ola, in the product's own composer: a near-black pill
   with a white voice key at its end */
.capsule {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  min-height: 58px;
  max-width: 100%;
  padding: 8px 8px 8px 24px;
  border-radius: 999px;
  background: #121316;
  color: #F2F3F5;
  font-size: 16.5px;
  font-weight: 450;
  letter-spacing: -0.012em;
  line-height: 1.25;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 16px 34px -14px rgba(12, 13, 16, 0.5);
}
.capsule > span:first-child { padding: 6px 0; text-wrap: balance; }
.voicekey {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  margin-left: auto;
  border-radius: 50%;
  background: #fff;
  color: #121316;
}

/* five bars. At rest it is the glyph; with `.is-speaking` on an ancestor it speaks. */
.wave { display: inline-flex; align-items: center; gap: 2.5px; height: 18px; }
.wave i {
  display: block;
  width: 2.5px;
  height: var(--h, 40%);
  border-radius: 2px;
  background: currentColor;
  transform-origin: center;
}
.wave i:nth-child(1) { --h: 32%; }
.wave i:nth-child(2) { --h: 68%; }
.wave i:nth-child(3) { --h: 100%; }
.wave i:nth-child(4) { --h: 56%; }
.wave i:nth-child(5) { --h: 28%; }
.is-speaking .wave i { animation: wave 1.1s ease-in-out infinite; }
.is-speaking .wave i:nth-child(2) { animation-delay: -.62s; animation-duration: .9s; }
.is-speaking .wave i:nth-child(3) { animation-delay: -.28s; animation-duration: 1.25s; }
.is-speaking .wave i:nth-child(4) { animation-delay: -.84s; animation-duration: .95s; }
.is-speaking .wave i:nth-child(5) { animation-delay: -.4s; }
@keyframes wave { 0%, 100% { transform: scaleY(0.35); } 50% { transform: scaleY(1); } }
@media (prefers-reduced-motion: reduce) { .is-speaking .wave i { animation: none; } }
.is-still .wave i { animation: none !important; }

/* ---------- ambient video ---------- */

/* The picture's own ground is the page's ground, and the mask feathers the
   last of the rectangle away, so the object floats with no box and no alpha. */
.loopbox { position: relative; }
.loopbox video, .loopbox img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.loopbox.is-round video, .loopbox.is-round img {
  -webkit-mask-image: radial-gradient(closest-side, #000 80%, transparent 100%);
          mask-image: radial-gradient(closest-side, #000 80%, transparent 100%);
}
.loopbox.is-wide video, .loopbox.is-wide img {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent), linear-gradient(180deg, transparent, #000 12%, #000 88%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent), linear-gradient(180deg, transparent, #000 12%, #000 88%, transparent);
  -webkit-mask-composite: source-in;
          mask-composite: intersect;
}

/* ---------- the phone ---------- */

/* Drawn to the real proportions: 412 x 884 body, 5 bezel, radii 60 and 55,
   island 125 x 36 seated 11 below the glass. Everything inside is sized in em
   against the device's own width, so the interface scales as one object. */
.phone {
  container-type: inline-size;
  width: var(--pw, 320px);
  max-width: 100%;
  flex: 0 0 auto;
}
.phone-body {
  position: relative;
  aspect-ratio: 412 / 884;
  padding: 1.214cqw;
  border-radius: 14.56cqw;
  background: linear-gradient(145deg, #D9DADE 0%, #A5A8AF 22%, #ECEDEF 48%, #8D9098 76%, #C9CBD0 100%);
  box-shadow:
    inset 0 0 0 0.35cqw rgba(255, 255, 255, 0.35),
    0 0.6cqw 1.2cqw rgba(12, 13, 16, 0.10),
    0 6cqw 9cqw -2cqw rgba(12, 13, 16, 0.22),
    0 16cqw 22cqw -8cqw rgba(12, 13, 16, 0.20);
}
.phone-body::before {   /* the black between the band and the glass */
  content: "";
  position: absolute;
  inset: 0.55cqw;
  border-radius: 14cqw;
  background: #08090B;
}
.phone-screen {
  position: relative;
  height: 100%;
  overflow: hidden;
  border-radius: 13.35cqw;
  background: linear-gradient(180deg, #F6F6F8, #EBECEF);
  font-size: 3.883cqw;          /* 16px at the real 412 */
  line-height: 1.35;
  color: var(--ink);
  display: flex;
  flex-direction: column;
  isolation: isolate;
}
.phone-island {
  position: absolute;
  z-index: 5;
  top: 0.6875em;
  left: 50%;
  width: 7.8125em;
  height: 2.25em;
  margin-left: -3.90625em;
  border-radius: 999px;
  background: #08090B;
}
.phone-status {
  flex: 0 0 auto;
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: 3.4em;
  padding: 0.5em 2.1em 0 2.4em;
  font-size: 0.97em;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.phone-status svg { height: 0.78em; width: auto; fill: currentColor; }

/* the app's own header: the mark, centred */
.app-head {
  flex: 0 0 auto;
  position: relative;
  display: grid;
  place-items: center;
  height: 3.6em;
  color: var(--ink);
}
.app-head > svg { width: 2.3em; height: 2.3em; }
.app-head .app-more, .app-head .app-back {
  position: absolute;
  top: 50%;
  display: grid;
  place-items: center;
  width: 2.3em;
  height: 2.3em;
  margin-top: -1.15em;
  border-radius: 50%;
  color: var(--ink-body);
}
.app-head .app-more { right: 1.25em; background: rgba(255, 255, 255, 0.7); box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.06); }
.app-head .app-back { left: 1em; }
.app-head .app-more svg, .app-head .app-back svg { width: 1.2em; height: 1.2em; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

.app-body { flex: 1 1 auto; min-height: 0; padding: 0.4em 1.25em 0; display: flex; flex-direction: column; gap: 0.75em; overflow: hidden; }

.app-title { display: flex; align-items: center; gap: 0.5em; padding: 0.3em 0.35em 0; font-size: 1.5em; font-weight: 600; letter-spacing: -0.03em; }
.app-count {
  display: inline-grid;
  place-items: center;
  min-width: 1.75em;
  height: 1.75em;
  padding: 0 0.5em;
  border-radius: 999px;
  background: rgba(20, 21, 25, 0.07);
  font-size: 0.5em;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--ink-body);
  font-variant-numeric: tabular-nums;
}

.app-card {
  border-radius: 1.75em;
  background: #fff;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.045), 0 0.1em 0.2em rgba(0, 0, 0, 0.03), 0 0.6em 1.6em rgba(0, 0, 0, 0.05);
}

.task { display: grid; grid-template-columns: 1fr auto; gap: 0.15em 0.75em; align-items: center; padding: 0.95em 1.1em; }
.task + .task { border-top: 1px solid rgba(0, 0, 0, 0.06); }
.task-title { font-size: 1em; font-weight: 550; letter-spacing: -0.015em; }
.task-state { font-size: 0.8em; color: var(--ink-body); display: flex; align-items: center; gap: 0.45em; }
.task-state b { font-weight: 500; color: var(--ink); }
.task-state .dot { width: 0.5em; height: 0.5em; border-radius: 50%; background: var(--live); }
.task-state .dot.is-good { background: var(--good); }
.task-state .dot.is-idle { background: var(--bar-3); }
.task-line { font-size: 0.8em; color: var(--ink-quiet); }
.is-swap { display: grid; }
.is-swap > * { grid-area: 1 / 1; display: flex; align-items: center; gap: 0.45em; }
.task-side { grid-row: 1 / span 3; grid-column: 2; display: flex; align-items: center; gap: 0.6em; color: var(--bar-3); }
.task-side > svg { width: 0.9em; height: 0.9em; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }

/* the agent's own screen, small: a browser being driven */
.agentframe {
  position: relative;
  width: 5.6em;
  aspect-ratio: 16 / 11;
  overflow: hidden;
  border-radius: 0.55em;
  background: #F3F4F6;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08);
}
.agentframe::before {   /* its address bar */
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 22%;
  background: #E4E6EA;
}
.agentframe .af-page { position: absolute; inset: 30% 10% 0 10%; display: grid; gap: 9%; align-content: start; }
.agentframe .af-page i { display: block; height: 0.32em; border-radius: 1em; background: #CDD1D8; width: var(--w, 80%); }
.agentframe .af-cursor {
  position: absolute;
  left: 30%;
  top: 46%;
  width: 0.55em;
  height: 0.55em;
  border-radius: 50%;
  background: var(--live);
  box-shadow: 0 0 0 0.22em rgba(44, 99, 210, 0.22);
}
.is-live .agentframe .af-cursor { animation: drive 4.2s var(--ease) infinite; }
.is-live .agentframe .af-page { animation: scrollpage 4.2s var(--ease) infinite; }
@keyframes drive {
  0%, 12% { transform: translate(0, 0); }
  30%, 46% { transform: translate(2.2em, 0.9em); }
  62%, 78% { transform: translate(0.6em, 1.6em); }
  100% { transform: translate(0, 0); }
}
@keyframes scrollpage {
  0%, 40% { transform: translateY(0); }
  58%, 84% { transform: translateY(-22%); }
  100% { transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) { .is-live .agentframe .af-cursor, .is-live .agentframe .af-page { animation: none; } }
.is-still .agentframe .af-cursor, .is-still .agentframe .af-page { animation: none !important; }

.app-stop {
  display: inline-grid;
  place-items: center;
  height: 1.9em;
  padding: 0 0.85em;
  border-radius: 999px;
  background: #fff;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
  font-size: 0.78em;
  font-weight: 500;
  color: var(--ink);
}

/* the composer: near-black pill and the white voice key beside it */
.app-composer { flex: 0 0 auto; display: flex; align-items: center; gap: 0.6em; padding: 0.75em 1.1em 1.9em; }
.app-composer .app-input {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  height: 3.4em;
  padding: 0 1.4em;
  border-radius: 999px;
  background: #121316;
  color: #9EA3AB;
  font-size: 1em;
}
.app-composer .app-voice {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 3.6em;
  height: 3.6em;
  border-radius: 50%;
  background: #fff;
  color: #121316;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.06), 0 0.4em 1em rgba(0, 0, 0, 0.08);
}
.app-composer .wave { height: 1.15em; gap: 0.16em; }
.app-composer .wave i { width: 0.16em; }
.phone-home {   /* the home indicator */
  position: absolute;
  left: 50%;
  bottom: 0.5em;
  width: 8.6em;
  height: 0.32em;
  margin-left: -4.3em;
  border-radius: 999px;
  background: rgba(20, 21, 25, 0.85);
}

/* chat */
.chat { display: flex; flex-direction: column; gap: 0.9em; padding: 0 0.35em; }
.chat .me {
  align-self: flex-end;
  max-width: 82%;
  padding: 0.7em 1em;
  border-radius: 1.35em 1.35em 0.4em 1.35em;
  background: #E6E7EB;
  font-size: 0.97em;
  letter-spacing: -0.01em;
}
.chat .ola { max-width: 94%; font-size: 0.97em; letter-spacing: -0.01em; line-height: 1.42; }
.chat .thinking { display: flex; align-items: center; gap: 0.6em; font-size: 0.9em; color: var(--ink-body); }
.chat .thinking .app-stop { margin-left: auto; font-size: 0.86em; }
.spin {
  width: 1em;
  height: 1em;
  border-radius: 50%;
  border: 0.14em solid rgba(20, 21, 25, 0.14);
  border-top-color: var(--ink-body);
  animation: spin .9s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spin { animation: none; } }
.chat .steps { display: grid; gap: 0.3em; padding-left: 1.6em; font-size: 0.84em; color: var(--ink-quiet); }

/* ---------- section furniture ---------- */

.pair {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(28px, 5vw, 80px);
  align-items: center;
}
@media (max-width: 860px) { .pair { grid-template-columns: 1fr; } }

.head + .stage { margin-top: clamp(40px, 6vw, 84px); }

/* ---------- hero ---------- */

/* The hero: the sentence, the field, and Ola at work. One ask at a time; the
   job it becomes stands in front, and when the next ask lands it shrinks into
   the tray and keeps running there. Ola is one ink shape on a canvas over the
   whole stage (assets/ola-ink.js): she flows between the jobs, melts into
   several to cover what runs at once, and the little ones flow home when their
   job is done. hero.js moves things and switches state; every place and size
   is here. */
.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: clamp(84px, 9.5vh, 116px) var(--gutter) clamp(40px, 5.5vh, 72px);
  background: var(--ground);
}

/* ---------- the words ---------- */

.hero-say {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  width: 100%;
  max-width: 820px;
}
@media (min-width: 1080px) { .hero-say { max-width: 700px; } }
.hero-h { font-weight: 400; letter-spacing: -0.048em; line-height: 1; font-size: clamp(40px, 9vw, 148px); }
.say-hero .hero-line { display: block; text-align: center; white-space: nowrap; }
.say-hero .vow { vertical-align: baseline; }
/* while a word leaves it is out of flow; an invisible letter keeps the slot's
   box and baseline where the words are, so nothing drops a line */
.say-hero .vow::before { content: "x"; grid-area: 1 / 1; width: 0; visibility: hidden; }

.hero .capture { margin-top: clamp(26px, 3vw, 40px); max-width: 480px; }
.hero .note { padding-left: 0; color: var(--ink-quiet); }
.hero .capture-status { left: 0; right: 0; text-align: center; color: #26364A; }

/* ---------- the stage ---------- */

/* Ola stands in the middle and every job has its own place around her.

   Phone and tablet: the ask on top, then the field. In the field Ola's room is
   centred, one job waits to her left, one to her right, one above her, all at
   a third of full size; the job in front comes to the big place under her at
   the full width. Sizes are shares of the stage's width (cqw).

   Desktop: the field is wide and the four jobs hold its four corners; the one
   she is at grows in its own corner, the others stay a little smaller in
   theirs. Ola and the ask stand in the middle between them. */
.hero-stage {
  --ola: 41cqw;                        /* she is the main character: 140 px on a 390 phone */
  --fw: 100cqw;                        /* a job at full size */
  --fh: 62cqw;
  --back: .27;                         /* a job around her, as a share of full size */
  --top: 19.5cqw;                      /* the row above her: one small job */
  --mid: calc(var(--top) + var(--ola) / 2);   /* the middle of Ola's row */
  --front: calc(var(--top) + var(--ola) + 4cqw);   /* the top of the big place under her */
  /* at rest: the four jobs one size, a two by two grid in the big place, and
     Ola centred in the open band above it */
  --rest-k: .33;
  /* at rest the four keep the places they spread to, one size, a cross round
     her: the call above, the app on her left, the tickets on her right, the
     chat below; she stands a little smaller at its middle */
  --rest-s: .72;
  --rest-dy: 18.98cqw;
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 440px;
  margin-top: 16px;
  container-type: inline-size;
  display: grid;
  grid-template-areas: "ask" "work";
  justify-items: center;
  row-gap: 12px;
}

/* the field: Ola's row with the jobs around her, then the big place under her */
.hero-work {
  grid-area: work;
  position: relative;
  justify-self: stretch;
  height: calc(var(--top) + var(--ola) + 4cqw + var(--fh));
}
.hero-room {
  position: absolute;
  left: calc(50% - var(--ola) / 2);
  top: var(--top);
  width: var(--ola);
  height: var(--ola);
}

@media (min-width: 1080px) {
  .hero-stage {
    --ola: 220px;
    --fw: 360px;
    --fh: 224px;
    --back: .72;
    --rest-k: .8;
    --rest-s: 1;
    --rest-dy: 55px;
    max-width: 1180px;
    margin-top: 12px;
    display: block;
  }
  .hero-work { width: 100%; height: 410px; }
  .hero-room { left: calc(50% - var(--ola) / 2); top: 40px; }
  /* the ask stands under her, in the middle of the field */
  .hero-ask { position: absolute; z-index: 4; left: 50%; top: 286px; transform: translateX(-50%); }
}

/* ---------- the ask ---------- */

.hero-ask {
  grid-area: ask;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  max-width: 100%;
  padding: 9px 18px 9px 14px;
  border-radius: 999px;
  background: #121316;
  color: #F2F3F5;
  font-size: 14.5px;
  font-weight: 450;
  letter-spacing: -0.012em;
  line-height: 1.2;
  white-space: nowrap;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.28), 0 14px 30px -14px rgba(12, 13, 16, 0.5);
}
.hero-ask-wave { display: grid; place-items: center; width: 22px; height: 22px; border-radius: 50%; background: rgba(255, 255, 255, 0.12); }
.hero-ask .wave { height: 12px; gap: 2px; }
.hero-ask .wave i { width: 2px; background: #F2F3F5; }
.hero-ask-text { overflow: hidden; text-overflow: ellipsis; }
@media (min-width: 1080px) { .hero-ask { font-size: 15px; } }

/* ---------- the jobs ---------- */

/* Every job is the same card at the same size; where it stands and how big it
   is are one transform, so whatever it is doing keeps doing it wherever it is. */
.hero-slot {
  position: absolute;
  left: 0;
  top: 0;
  width: var(--fw);
  height: var(--fh);
  overflow: hidden;
  border-radius: 24px;
  background: #fff;
  box-shadow: var(--ladder), 0 0 0 1px rgba(0, 0, 0, 0.045);
  container: slot / size;
  transform-origin: 0 0;
  transition: transform .8s var(--settle), opacity .3s var(--ease), box-shadow .5s var(--ease);
}
.hero-slot.is-focus { z-index: 3; }
.hero-slot.is-back { z-index: 2; box-shadow: var(--ladder-lite), 0 0 0 1px rgba(0, 0, 0, 0.05); }

/* phone: the big place under her, and three small places round her: one to
   each side of her (a little low, so her face stays clear) and one above */
.hero-slot.is-focus { transform: translate(0, calc(var(--top) + var(--ola) + 4cqw)) scale(1); }
.hero-slot.is-back[data-station="1"] { transform: translate(0, calc(var(--mid) - 2cqw)) scale(var(--back)); }
.hero-slot.is-back[data-station="2"] { transform: translate(73cqw, calc(var(--mid) - 2cqw)) scale(var(--back)); }
.hero-slot.is-back[data-station="3"] { transform: translate(36.5cqw, 0) scale(var(--back)); }
.hero-slot.is-back[data-station="4"] { transform: translate(36.5cqw, calc(var(--top) + var(--ola) + 4cqw)) scale(var(--back)); }
/* a job nobody has asked for yet is nowhere: it waits just under the big
   place, unseen, and rises into it when its ask lands */
.hero-slot.is-waiting {
  z-index: 4;
  opacity: 0;
  transform: translate(0, calc(var(--top) + var(--ola) + 8cqw)) scale(.95);
  transition: transform .8s var(--settle), opacity .2s var(--ease);
}

@media (min-width: 1080px) {
  /* desktop: each job keeps its corner; the one in front is full size there,
     the others .72, both held against the corner they belong to */
  .hero-slot[data-station="1"].is-focus { transform: translate(0, 0) scale(1); }
  .hero-slot[data-station="2"].is-focus { transform: translate(calc(100cqw - var(--fw)), 0) scale(1); }
  .hero-slot[data-station="3"].is-focus { transform: translate(0, calc(410px - var(--fh))) scale(1); }
  .hero-slot[data-station="4"].is-focus { transform: translate(calc(100cqw - var(--fw)), calc(410px - var(--fh))) scale(1); }
  .hero-slot[data-station="1"].is-back { transform: translate(0, 0) scale(var(--back)); }
  .hero-slot[data-station="2"].is-back { transform: translate(calc(100cqw - var(--fw) * var(--back)), 0) scale(var(--back)); }
  .hero-slot[data-station="3"].is-back { transform: translate(0, calc(410px - var(--fh) * var(--back))) scale(var(--back)); }
  .hero-slot[data-station="4"].is-back { transform: translate(calc(100cqw - var(--fw) * var(--back)), calc(410px - var(--fh) * var(--back))) scale(var(--back)); }
  /* waiting: in its own corner, small and unseen, so it grows out of it */
  .hero-slot[data-station="1"].is-waiting { transform: translate(0, 0) scale(.6); }
  .hero-slot[data-station="2"].is-waiting { transform: translate(calc(100cqw - var(--fw) * .6), 0) scale(.6); }
  .hero-slot[data-station="3"].is-waiting { transform: translate(0, calc(410px - var(--fh) * .6)) scale(.6); }
  .hero-slot[data-station="4"].is-waiting { transform: translate(calc(100cqw - var(--fw) * .6), calc(410px - var(--fh) * .6)) scale(.6); }
}

/* ---------- at rest ---------- */

/* When the story is not playing (first paint, motion refused, no script, and
   for good once it has played) the jobs stand at one size, done, in the places
   they spread to: on a phone a cross round her, on a desktop the four
   corners. At rest a card turns about its own middle, so the translate below
   is its top left place less half of what the scale took off. */
.hero-stage {
  --odx: calc(var(--fw) * (1 - var(--rest-k)) / 2);
  --ody: calc(var(--fh) * (1 - var(--rest-k)) / 2);
}
.hero-stage:not(.is-playing) .hero-slot[data-station] {
  z-index: 2;
  transform-origin: 50% 50%;
  box-shadow: var(--ladder-lite), 0 0 0 1px rgba(0, 0, 0, 0.05);
}
.hero-stage:not(.is-playing) .hero-slot[data-station="1"] { transform: translate(calc(0px - var(--odx)), calc(48.75cqw - var(--ody))) scale(var(--rest-k)) rotate3d(var(--tx, 0), var(--ty, 1), 0, var(--ta, 0deg)); }
.hero-stage:not(.is-playing) .hero-slot[data-station="2"] { transform: translate(calc(67cqw - var(--odx)), calc(48.75cqw - var(--ody))) scale(var(--rest-k)) rotate3d(var(--tx, 0), var(--ty, 1), 0, var(--ta, 0deg)); }
.hero-stage:not(.is-playing) .hero-slot[data-station="3"] { transform: translate(calc(33.5cqw - var(--odx)), calc(2cqw - var(--ody))) scale(var(--rest-k)) rotate3d(var(--tx, 0), var(--ty, 1), 0, var(--ta, 0deg)); }
.hero-stage:not(.is-playing) .hero-slot[data-station="4"] { transform: translate(calc(33.5cqw - var(--odx)), calc(95.5cqw - var(--ody))) scale(var(--rest-k)) rotate3d(var(--tx, 0), var(--ty, 1), 0, var(--ta, 0deg)); }
.hero-stage:not(.is-playing) .hero-slot .slot-state { transform: scale(calc(1 / var(--rest-k))); }
@media (min-width: 1080px) {
  .hero-stage:not(.is-playing) .hero-slot[data-station="1"] { transform: translate(calc(0px - var(--odx)), calc(0px - var(--ody))) scale(var(--rest-k)) rotate3d(var(--tx, 0), var(--ty, 1), 0, var(--ta, 0deg)); }
  .hero-stage:not(.is-playing) .hero-slot[data-station="2"] { transform: translate(calc(100cqw - var(--fw) * var(--rest-k) - var(--odx)), calc(0px - var(--ody))) scale(var(--rest-k)) rotate3d(var(--tx, 0), var(--ty, 1), 0, var(--ta, 0deg)); }
  .hero-stage:not(.is-playing) .hero-slot[data-station="3"] { transform: translate(calc(0px - var(--odx)), calc(410px - var(--fh) * var(--rest-k) - var(--ody))) scale(var(--rest-k)) rotate3d(var(--tx, 0), var(--ty, 1), 0, var(--ta, 0deg)); }
  .hero-stage:not(.is-playing) .hero-slot[data-station="4"] { transform: translate(calc(100cqw - var(--fw) * var(--rest-k) - var(--odx)), calc(410px - var(--fh) * var(--rest-k) - var(--ody))) scale(var(--rest-k)) rotate3d(var(--tx, 0), var(--ty, 1), 0, var(--ta, 0deg)); }
}

/* Once it has played the cards are not frozen: two of them breathe, a few px,
   out of step; and on a pointer a card tips toward the cursor and lifts a
   little (hero.js sets --tx, --ty and --ta). Nothing changes size, nothing drifts off its
   place. */
.hero-stage:not(.is-playing) .hero-slot[data-station] {
  transition: transform .8s var(--settle), transform-origin .8s var(--settle), translate .5s var(--ease), box-shadow .4s var(--ease), opacity .3s var(--ease);
}
/* while the cursor is on a card its tilt follows quickly */
.hero-stage:not(.is-playing) .hero-slot[data-station].is-tilting {
  transition: transform .22s var(--ease), translate .5s var(--ease), box-shadow .4s var(--ease), opacity .3s var(--ease);
}
.hero-work { perspective: 1200px; }
.hero-stage.is-alive:not(.is-playing) .hero-slot[data-station="2"]:not(:hover) { animation: rest-float 6.4s ease-in-out infinite; }
.hero-stage.is-alive:not(.is-playing) .hero-slot[data-station="3"]:not(:hover) { animation: rest-float 7.2s ease-in-out -3.1s infinite; }
@keyframes rest-float { 50% { translate: 0 -3px; } }
@media (hover: hover) {
  .hero-stage.is-alive:not(.is-playing) .hero-slot[data-station]:hover {
    translate: 0 -4px;
    box-shadow: var(--ladder-hover), 0 0 0 1px rgba(0, 0, 0, 0.05);
  }
}
@media (prefers-reduced-motion: reduce) {
  .hero-stage .hero-slot[data-station] { animation: none !important; translate: none !important; --ta: 0deg !important; }
}

/* at rest the ask has been said; she stands in the open space, and the still
   mark (no script, or before she is drawn) stands exactly where she does */
.hero-stage:not(.is-playing) .hero-ask { opacity: 0; }
.hero-ask { transition: opacity .4s var(--ease); }
.hero-ink-still { transform: translateY(var(--rest-dy)) scale(var(--rest-s)); }

/* its state, top right: a live dot while it runs, a tick when it is done. A
   job around her is drawn smaller, so its state is drawn larger by the same
   share and stays the same size on screen. */
.slot-state {
  position: absolute;
  z-index: 8;
  top: 10px;
  right: 10px;
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  pointer-events: none;
  transform-origin: 100% 0;
  transition: transform .5s var(--ease);
}
.hero-slot.is-back .slot-state { transform: scale(calc(1 / var(--back))); }
.slot-state > * { grid-area: 1 / 1; }
/* each job has its own colour, and its live dot wears it */
.hero-slot[data-surface="phone"]   { --job: #8DBE12; }
.hero-slot[data-surface="browser"] { --job: #FF7A3D; }
.hero-slot[data-surface="call"]    { --job: #7A5CFF; }
.hero-slot[data-surface="chat"]    { --job: #3D6BFF; }
.slot-live {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--job, var(--live));
  opacity: 0;
  transition: opacity .3s var(--ease);
}
.hero-stage.is-playing .hero-slot.is-live .slot-live { opacity: 1; animation: slot-pulse 1.3s ease-in-out infinite; }
@keyframes slot-pulse { 50% { transform: scale(1.5); opacity: .45; } }
.slot-tick {
  width: 20px;
  height: 20px;
  padding: 3px;
  border-radius: 50%;
  background: var(--good);
  fill: none;
  stroke: #fff;
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
  box-shadow: 0 4px 10px -3px rgba(47, 180, 87, 0.55);
  transition: opacity .25s var(--ease), transform .5s var(--spring);
}
.hero-stage.is-playing .hero-slot:not(.is-done) .slot-tick { opacity: 0; transform: scale(.4); }

/* ---------- Ola ---------- */

/* Her canvas covers the stage and a margin round it, so she can stretch past
   an edge on her way somewhere. Transparent everywhere she is not. */
.hero-ink {
  position: absolute;
  z-index: 6;
  inset: -48px;
  width: calc(100% + 96px);
  max-width: none;            /* ola.css caps every canvas at 100%; hers reaches past the stage */
  height: calc(100% + 96px);
  pointer-events: none;
}
/* With no script, or before she is drawn: the mark itself, in her room. */
.hero-room { position: relative; }
.hero-ink-still {
  display: block;
  width: 100%;
  height: 100%;
  color: var(--ink);
  transition: opacity .3s var(--ease);
}
.hero-stage.has-ink .hero-ink-still { opacity: 0; }

/* ---------- parts inside a job ---------- */

/* THE CONTRACT with every part file (plan/HERO.md section 5): a part's ordinary
   css is where it ends up. Only while the stage plays does it step back and
   arrive at its data-at. data-how picks the arrival; "none" leaves it to the part. */
.hero-stage.is-playing .hero-slot .part {
  opacity: 0;
  transform: translateY(8px) scale(0.97);
  transition: opacity .45s var(--ease), transform .7s var(--settle);
}
.hero-stage.is-playing .hero-slot .part[data-how="fade"] { transform: none; }
.hero-stage.is-playing .hero-slot .part[data-how="rise"] { transform: translateY(12px); }
.hero-stage.is-playing .hero-slot .part[data-how="pop"]  { transform: scale(0.6); transition: opacity .3s var(--ease), transform .55s var(--spring); }
.hero-stage.is-playing .hero-slot .part[data-how="none"] { opacity: 1; transform: none; transition: none; }
.hero-stage.is-playing .hero-slot .part.on { opacity: 1; transform: none; }
.hero-stage.is-playing .hero-slot .part.off { opacity: 0; transform: none; transition: opacity .25s var(--ease); }
/* a part that leaves during the play is not there at rest */
.hero-slot .part[data-off] { opacity: 0; visibility: hidden; }
.hero-stage.is-playing .hero-slot .part[data-off].on:not(.off) { opacity: 1; visibility: visible; }
.hero-stage.is-playing .hero-slot .part[data-off].off { visibility: hidden; transition: opacity .25s var(--ease), visibility 0s linear .25s; }

.hero-stage.is-playing .hero-slot [data-stream] .sw { opacity: 0; transition: opacity .35s var(--ease) var(--d, 0ms); }
.hero-stage.is-playing .hero-slot [data-stream].on .sw { opacity: 1; }
.hero-stage.is-playing .hero-slot [data-type] .ch { opacity: 0; transition: opacity .06s linear var(--d, 0ms); }
.hero-stage.is-playing .hero-slot [data-type].on .ch { opacity: 1; }

/* ---------- the ask while it plays ---------- */

.hero-stage.is-playing .hero-ask { transition: opacity .3s var(--ease), transform .5s var(--settle); }
.hero-stage.is-playing .hero-ask.is-away { opacity: 0; transform: translateY(6px); }

/* between two loops the finished frame lets go softly */
.hero-stage.is-resetting .hero-slot .part,
.hero-stage.is-resetting .hero-ask {
  opacity: 0 !important;
  filter: blur(5px);
  transition: opacity .42s var(--ease), filter .42s var(--ease) !important;
}

/* ---------- narrower ---------- */

@media (max-width: 760px) {
  .hero { padding-top: 76px; padding-bottom: 32px; }
  .hero-h { font-size: clamp(38px, 12.2vw, 56px); }
  .hero .capture { margin-top: 22px; }
  .hero .note { margin-top: 12px; }
  .hero-stage { margin-top: 14px; row-gap: 10px; }
}
@media (max-width: 360px) {
  .hero-stage { --back: .27; }
  .hero-ask { font-size: 13.5px; padding: 8px 14px 8px 11px; }
}

/* ---------- still ---------- */

@media (prefers-reduced-motion: reduce) {
  .hero-slot, .hero-slot .part, .slot-tick, .slot-live, .slot-state, .hero-ask { transition: none !important; }
  .hero-stage.is-playing .hero-slot.is-live .slot-live { animation: none; }
}

/* ---------- hero: hero-phone ---------- */

/* hero-phone: Ola builds an app for a gym split, and then uses it.

   Two moments inside one window. First the app assembles: the screen wakes,
   a blueprint of outlines stands where the pieces go, and the pieces land in
   them one after another. Then she uses what she built: a touch travels to a
   day, the day pill slides under it, the chart re-forms, the number moves and
   the rows follow. One short line ends it: app ready.

   NOTHING IS SPELLED OUT. One label, one number. Everything else is shape:
   blocks, chips, rows, bars. The phone is drawn to the real proportions
   (412 x 884 body, 5 bezel, radii 60 and 55, island 125 x 36 seated 11 below
   the glass) in --u, one point of the 412 body, and it rises from the foot of
   the slot so the slot crops it instead of framing it.

   Its colour is lime with ink on it, and lime is where the change is: the
   app's mark, the day she picks, that day's bar, the tick on the label. The
   ground around the phone is washed with it, so the card reads as this job
   at a glance and not as one more grey box.

   Ola's fingertip: the one press is marked with data-ola-tap (ms after the
   job goes live), on the fourth day chip, at the moment the pick slides under
   it. When her ink is on the stage (.hero-stage.has-ink) she is the finger,
   so the drawn contact disc stands aside; the ripple stays, as the chip's
   answer to her.

   Ordinary css is the finished frame: the app built and used, the day on the
   fourth chip, the number at 24, the label there, no outlines and no touch. */

.mini-phone {
  --pw: 76cqh;                     /* the phone across */
  --top: 6cqh;                     /* how far under the slot's top it stands */
  --u: calc(var(--pw) / 412);      /* one point of the device */
  --step: calc(71.2 * var(--u));   /* one day chip */
  --line: rgba(20, 21, 25, 0.50);
  --line-2: rgba(20, 21, 25, 0.20);
  --line-3: rgba(20, 21, 25, 0.28);
  --fill: rgba(20, 21, 25, 0.06);
  --fill-2: rgba(20, 21, 25, 0.055);
  --job: #C6F135;                  /* lime: this job's own colour, ink on it */
  --job-deep: #8DBE12;             /* the same lime, deep enough to draw a line in */
  position: absolute;
  inset: 0;
  overflow: hidden;
  font-variant-numeric: tabular-nums;
  background:
    radial-gradient(58% 44% at 50% 18%, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0) 70%),
    radial-gradient(86% 64% at 50% 104%, rgba(198, 241, 53, 0.22), rgba(198, 241, 53, 0) 72%),
    linear-gradient(180deg, #F9FCF1 0%, #F1F6E0 100%);
}
/* the desktop slot is the wider box of the set, so the phone grows into it */
@container slot (min-width: 500px) {
  .mini-phone { --pw: 80cqh; --top: 7cqh; }
}

/* ---------- the device ---------- */

.gp-phone {
  position: absolute;
  top: var(--top);
  left: 50%;
  width: var(--pw);
  height: calc(var(--pw) * 884 / 412);
  margin-left: calc(var(--pw) / -2);
  padding: calc(5 * var(--u));
  border-radius: calc(60 * var(--u));
  background: linear-gradient(145deg, #D9DADE 0%, #A5A8AF 22%, #ECEDEF 48%, #8D9098 76%, #C9CBD0 100%);
  box-shadow:
    inset 0 0 0 calc(1.4 * var(--u)) rgba(255, 255, 255, 0.38),
    0 calc(2 * var(--u)) calc(5 * var(--u)) rgba(12, 13, 16, 0.10),
    0 calc(22 * var(--u)) calc(34 * var(--u)) calc(-8 * var(--u)) rgba(12, 13, 16, 0.20),
    0 calc(60 * var(--u)) calc(86 * var(--u)) calc(-28 * var(--u)) rgba(12, 13, 16, 0.24);
}
.gp-phone::before {   /* the black between the band and the glass */
  content: "";
  position: absolute;
  inset: calc(2.3 * var(--u));
  border-radius: calc(57.7 * var(--u));
  background: #08090B;
}
.gp-screen {
  position: relative;
  height: 100%;
  overflow: hidden;
  border-radius: calc(55 * var(--u));
  background: linear-gradient(180deg, #FFFFFF 0%, #F6F7F9 100%);
  color: var(--ink);
}
.gp-island {
  position: absolute;
  z-index: 6;
  top: calc(11 * var(--u));
  left: 50%;
  width: calc(125 * var(--u));
  height: calc(36 * var(--u));
  margin-left: calc(-62.5 * var(--u));
  border-radius: 999px;
  background: #08090B;
}

/* the glass while the screen sleeps: dark, with one gleam across it, so an
   idle phone is still unmistakably a phone */
.gp-off {
  position: absolute;
  z-index: 5;
  inset: 0;
  opacity: 0;
  pointer-events: none;
  background:
    linear-gradient(118deg, rgba(255, 255, 255, 0) 30%, rgba(255, 255, 255, 0.07) 44%, rgba(255, 255, 255, 0) 58%),
    linear-gradient(160deg, #15171C 0%, #0A0B0D 62%);
  transition: opacity .55s var(--ease);
}
.hero-slot.is-idle .mini-phone .gp-off { opacity: 1; }

/* the status bar, suggested: the time on the left ear, the rest on the right */
.gp-status {
  position: absolute;
  z-index: 4;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: calc(58 * var(--u));
  padding: 0 calc(34 * var(--u));
}
.gp-status i {
  display: block;
  height: calc(13 * var(--u));
  border-radius: 999px;
  background: var(--line-3);
}
.gp-status i:first-child { width: calc(44 * var(--u)); }
.gp-status i:last-child { width: calc(52 * var(--u)); }

/* ---------- the app ---------- */

.gp-app {
  position: absolute;
  inset: calc(60 * var(--u)) 0 0;
  padding: 0 calc(20 * var(--u));
}

/* every block stands in a slot, and the slot's outline is its blueprint */
.gp-slot { position: relative; }
.gp-ghost {
  position: absolute;
  inset: 0;
  border: 1px dashed rgba(20, 21, 25, 0.24);
  border-radius: var(--r);
  background: rgba(198, 241, 53, 0.12);
  opacity: 0;
  pointer-events: none;
}
.hero-slot.is-live .mini-phone .gp-ghost { opacity: 1; transition: opacity .34s var(--ease) .14s; }
.hero-slot.is-live .mini-phone .part.on + .gp-ghost { opacity: 0; transition: opacity .22s var(--ease); }

/* the header: the app's own mark, its name as two bars, an account button */
.gp-head-slot { --r: calc(18 * var(--u)); height: calc(66 * var(--u)); }
.gp-head { display: flex; align-items: center; height: 100%; }
.gp-icon {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: calc(52 * var(--u));
  height: calc(52 * var(--u));
  border-radius: calc(15 * var(--u));
  background: var(--job);
  box-shadow: inset 0 0 0 1px rgba(20, 21, 25, 0.06), 0 calc(3 * var(--u)) calc(8 * var(--u)) rgba(92, 120, 0, 0.22);
}
.gp-icon svg { width: 62%; height: 62%; fill: var(--ink); }
.gp-titles {
  display: grid;
  gap: calc(8 * var(--u));
  margin-left: calc(13 * var(--u));
}
.gp-titles i { display: block; border-radius: 999px; }
.gp-t1 { width: calc(100 * var(--u)); height: calc(13 * var(--u)); background: var(--line); }
.gp-t2 { width: calc(64 * var(--u)); height: calc(9 * var(--u)); background: var(--line-2); }
.gp-face {
  width: calc(34 * var(--u));
  height: calc(34 * var(--u));
  margin-left: auto;
  border-radius: 50%;
  background: var(--fill);
}

/* the days: five chips and the one she picks */
.gp-days-slot { --r: 999px; height: calc(44 * var(--u)); margin-top: calc(16 * var(--u)); }
.gp-days {
  position: relative;
  display: flex;
  height: 100%;
  padding: calc(3 * var(--u));
  border-radius: 999px;
  background: var(--fill-2);
}
.gp-seg {
  flex: 1 1 0;
  display: grid;
  place-items: center;
}
.gp-seg::before {
  content: "";
  display: block;
  width: calc(26 * var(--u));
  height: calc(9 * var(--u));
  border-radius: 999px;
  background: var(--line-3);
}
.gp-seg:nth-child(2)::before { width: calc(29 * var(--u)); }
.gp-seg:nth-child(3)::before { width: calc(23 * var(--u)); }
.gp-seg:nth-child(5)::before { width: calc(25 * var(--u)); }
/* the pick is one chip wide and sits over the fourth; while she is still
   building it rests on the second */
.gp-pick-move {
  position: absolute;
  z-index: 2;
  top: calc(3 * var(--u));
  left: calc(3 * var(--u) + 3 * var(--step));
  width: var(--step);
  height: calc(38 * var(--u));
}
.gp-pick {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  border-radius: 999px;
  background: var(--job);
  box-shadow: inset 0 0 0 1px rgba(20, 21, 25, 0.07), 0 calc(3 * var(--u)) calc(8 * var(--u)) rgba(92, 120, 0, 0.30);
}
.gp-pick::before {
  content: "";
  display: block;
  width: calc(26 * var(--u));
  height: calc(9 * var(--u));
  border-radius: 999px;
  background: var(--ink);
}

/* the card: the one number the app reports, and the week beside it */
.gp-card-slot { --r: calc(28 * var(--u)); height: calc(108 * var(--u)); margin-top: calc(16 * var(--u)); }
.gp-card {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  height: 100%;
  padding: calc(16 * var(--u)) calc(18 * var(--u));
  border-radius: var(--r);
  background: #fff;
  box-shadow:
    0 0 0 1px rgba(20, 21, 25, 0.045),
    0 calc(2 * var(--u)) calc(4 * var(--u)) rgba(20, 21, 25, 0.03),
    0 calc(10 * var(--u)) calc(24 * var(--u)) rgba(20, 21, 25, 0.05);
}
.gp-stat { display: grid; gap: calc(10 * var(--u)); justify-items: start; padding-bottom: calc(6 * var(--u)); }
.gp-digits { display: grid; }
.gp-digits b {
  grid-area: 1 / 1;
  font-size: calc(44 * var(--u));
  font-weight: 600;
  letter-spacing: -0.035em;
  line-height: 1;
  color: var(--ink);
}
.gp-unit { display: block; width: calc(46 * var(--u)); height: calc(9 * var(--u)); border-radius: 999px; background: var(--line-2); }
.gp-chart {
  position: relative;
  display: flex;
  align-items: flex-end;
  gap: calc(12 * var(--u));
  height: calc(72 * var(--u));
}
.gp-bar {
  width: calc(20 * var(--u));
  height: calc(var(--h) * var(--u));
  border-radius: calc(7 * var(--u));
  background: var(--fill);
}
.gp-acc {
  position: absolute;
  bottom: 0;
  width: calc(20 * var(--u));
  border-radius: calc(7 * var(--u));
  background: var(--job);
  box-shadow: inset 0 0 0 1px rgba(20, 21, 25, 0.07);
}
.gp-acc-a { left: calc(32 * var(--u)); height: calc(66 * var(--u)); }
.gp-acc-b { left: calc(96 * var(--u)); height: calc(72 * var(--u)); }

/* the rows of the day */
.gp-row-slot { --r: calc(22 * var(--u)); height: calc(66 * var(--u)); margin-top: calc(9 * var(--u)); }
.gp-card-slot + .gp-row-slot { margin-top: calc(12 * var(--u)); }
.gp-row {
  display: flex;
  align-items: center;
  height: 100%;
  padding: 0 calc(14 * var(--u));
  border-radius: var(--r);
  background: #fff;
  box-shadow:
    0 0 0 1px rgba(20, 21, 25, 0.04),
    0 calc(6 * var(--u)) calc(16 * var(--u)) rgba(20, 21, 25, 0.04);
}
.gp-thumb {
  flex: 0 0 auto;
  width: calc(40 * var(--u));
  height: calc(40 * var(--u));
  border-radius: calc(13 * var(--u));
  background: var(--fill);
}
.gp-lines { display: grid; gap: calc(8 * var(--u)); margin-left: calc(12 * var(--u)); }
.gp-lines i { display: block; border-radius: 999px; }
.gp-l1 { height: calc(12 * var(--u)); background: var(--line); transform-origin: left center; }
.gp-l2 { height: calc(9 * var(--u)); background: var(--line-2); }
.gp-chip {
  width: calc(52 * var(--u));
  height: calc(26 * var(--u));
  margin-left: auto;
  border-radius: 999px;
  background: var(--fill-2);
}

/* ---------- she uses it ---------- */

/* the touch: a soft disc that travels to the fourth day and presses. It sits a
   little under the chip's line, the way a fingertip does, so the chip it is
   pressing stays whole. Where her ink is on the stage she is the fingertip,
   and the disc stands aside (see the end of this file) */
.gp-touch {
  position: absolute;
  z-index: 4;
  top: 50%;
  left: calc(3 * var(--u) + 3.5 * var(--step));
  width: calc(62 * var(--u));
  height: calc(62 * var(--u));
  margin: calc(-17 * var(--u)) 0 0 calc(-31 * var(--u));
}
.gp-press {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background:
    radial-gradient(circle at 50% 46%,
      rgba(20, 21, 25, 0.30) 0%,
      rgba(20, 21, 25, 0.22) 46%,
      rgba(20, 21, 25, 0.08) 68%,
      rgba(20, 21, 25, 0) 76%);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.34);
}
.gp-ripple {
  position: absolute;
  z-index: 3;
  top: 50%;
  left: calc(3 * var(--u) + 3.5 * var(--step));
  width: calc(52 * var(--u));
  height: calc(52 * var(--u));
  margin: calc(-26 * var(--u)) 0 0 calc(-26 * var(--u));
  border: max(1.4px, calc(2.8 * var(--u))) solid var(--job-deep);
  border-radius: 50%;
  opacity: 0;
}
/* where her fingertip lands: the fourth chip, the same point the disc
   presses, a little under the chip's middle so the pick stays in sight as it
   slides under her. Empty and sizeless, so without her ink it is nothing */
.gp-tap {
  position: absolute;
  top: calc(50% + 14 * var(--u));
  left: calc(3 * var(--u) + 3.5 * var(--step));
  width: 0;
  height: 0;
  pointer-events: none;
}

/* ---------- the one line it says ---------- */

/* the one line the surface says. Near black, because a white pill on white
   cards reads as a row that slipped rather than as the app speaking */
.gp-label {
  position: absolute;
  z-index: 7;
  left: 50%;
  /* centred on the second row of the app, whatever the slot's size: the
     screen's top, the app's own top, and eight blocks down to that row */
  bottom: calc(100cqh - var(--top) - 435 * var(--u) - 1.1em);
  display: inline-flex;
  align-items: center;
  gap: 0.44em;
  height: 2.2em;
  padding: 0 0.9em 0 0.74em;
  border-radius: 999px;
  background: #121316;
  color: #F2F3F5;
  font-size: clamp(10px, 4.3cqh, 13.5px);
  font-weight: 500;
  letter-spacing: -0.006em;
  line-height: 1;
  white-space: nowrap;
  transform: translateX(-50%);
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.26),
    0 10px 24px -10px rgba(12, 13, 16, 0.55);
}
.gp-label svg {
  width: 1.05em;
  height: 1.05em;
  fill: none;
  stroke: var(--job);
  stroke-width: 2.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ---------- while the surface plays ---------- */

/* Everything below is the step back: where a piece comes FROM. The engine
   only adds .on at its data-at and .off at its data-off; the rules above are
   where every piece ends up. Six classes, because these beat hero.css's own
   arrival for the pieces that need their own. */

/* the pick slides two chips over, under her finger */
.hero-stage.is-playing .hero-slot .mini-phone .gp-pick-move {
  transform: translateX(calc(-2 * var(--step)));
  transition: transform .52s var(--settle);
}
.hero-stage.is-playing .hero-slot .mini-phone .gp-pick-move.on { transform: none; }

/* the pick itself arrives with the chips, not from nothing */
.hero-stage.is-playing .hero-slot .mini-phone .gp-pick {
  opacity: 0;
  transform: scale(0.86);
  transition: opacity .3s var(--ease), transform .55s var(--spring);
}
.hero-stage.is-playing .hero-slot .mini-phone .gp-pick.on { opacity: 1; transform: none; }

/* the number she asked for moves: the old one leaves up, the new one rises */
.hero-stage.is-playing .hero-slot .mini-phone .gp-digits b {
  opacity: 0;
  transform: translateY(calc(14 * var(--u)));
  transition: opacity .3s var(--ease), transform .5s var(--settle);
}
.hero-stage.is-playing .hero-slot .mini-phone .gp-digits b.on { opacity: 1; transform: none; }
.hero-stage.is-playing .hero-slot .mini-phone .gp-digits b.off {
  visibility: hidden;
  opacity: 0;
  transform: translateY(calc(-14 * var(--u)));
  transition: opacity .2s var(--ease), transform .34s var(--ease), visibility 0s linear .34s;
}

/* the week re-forms under the new day */
.hero-stage.is-playing .hero-slot .mini-phone .gp-bar {
  transform: scaleY(var(--pre));
  transform-origin: 50% 100%;
  transition: transform .58s var(--settle);
}
.hero-stage.is-playing .hero-slot .mini-phone .gp-bar.on { transform: none; }

/* the highlight hands over from the day she was on to the day she picked */
.hero-stage.is-playing .hero-slot .mini-phone .gp-acc {
  opacity: 0;
  transform: scaleY(0.4);
  transform-origin: 50% 100%;
  transition: opacity .3s var(--ease), transform .55s var(--spring);
}
.hero-stage.is-playing .hero-slot .mini-phone .gp-acc.on { opacity: 1; transform: none; }
.hero-stage.is-playing .hero-slot .mini-phone .gp-acc.off {
  visibility: hidden;
  opacity: 0;
  transform: scaleY(0.72);
  transition: opacity .16s var(--ease), transform .34s var(--ease), visibility 0s linear .34s;
}

/* the rows follow the new day: their first line takes a new length */
.hero-stage.is-playing .hero-slot .mini-phone .gp-l1 {
  transform: scaleX(var(--pre, 1));
  transition: transform .55s var(--settle);
}
.hero-stage.is-playing .hero-slot .mini-phone .gp-l1.on { transform: none; }

/* the touch comes up from under the card and leaves when it is done */
.hero-stage.is-playing .hero-slot .mini-phone .gp-touch {
  opacity: 0;
  transform: translate(calc(-1.7 * var(--step)), calc(52 * var(--u))) scale(1.08);
  transition: opacity .34s var(--ease), transform .68s var(--settle);
}
.hero-stage.is-playing .hero-slot .mini-phone .gp-touch.on { opacity: 1; transform: none; }
.hero-stage.is-playing .hero-slot .mini-phone .gp-touch.off {
  visibility: hidden;
  opacity: 0;
  transform: translateY(calc(-10 * var(--u))) scale(0.86);
  transition: opacity .3s var(--ease), transform .42s var(--ease), visibility 0s linear .42s;
}
.hero-stage.is-playing .hero-slot .mini-phone .gp-press {
  transform: none;
  transition: transform .34s var(--spring);
}
.hero-stage.is-playing .hero-slot .mini-phone .gp-press.on { transform: scale(0.84); }

/* the tap itself, once, and only while the surface is working */
.hero-slot.is-live .mini-phone .gp-ripple.on { animation: gp-ripple .66s var(--ease) both; }
@keyframes gp-ripple {
  from { opacity: .75; transform: scale(0.28); }
  to   { opacity: 0;   transform: scale(2.1); }
}

/* the label is the surface's own voice, so it lands on a spring */
.hero-stage.is-playing .hero-slot .mini-phone .gp-label {
  opacity: 0;
  transform: translate(-50%, calc(10 * var(--u))) scale(0.94);
  transition: opacity .3s var(--ease), transform .55s var(--spring);
}
.hero-stage.is-playing .hero-slot .mini-phone .gp-label.on { opacity: 1; transform: translateX(-50%); }

/* ---------- in the deck ---------- */

/* Behind the card in front, only the top edge of this one shows, so the phone
   rises into that strip: its crown and its island are what the deck reads. */
.mini-phone .gp-phone { transition: transform .55s var(--settle); }
.hero-slot.is-back .mini-phone .gp-phone { transform: translateY(-4cqh); }

/* behind and blurred, the fine grain is noise: the silhouette, the mark, the
   chips, the card and the rows are what has to read */
.hero-slot.is-back .mini-phone .gp-t2,
.hero-slot.is-back .mini-phone .gp-l2,
.hero-slot.is-back .mini-phone .gp-unit,
.hero-slot.is-back .mini-phone .gp-status,
.hero-slot.is-back .mini-phone .gp-label { visibility: hidden; }
.hero-slot.is-back .mini-phone { --line-2: rgba(20, 21, 25, 0.26); --line-3: rgba(20, 21, 25, 0.34); }

/* ---------- Ola's own hand ---------- */

/* With her ink on the stage she is the fingertip, so the drawn one stands
   aside. With no ink (no WebGL, motion refused, no script) it is still here. */
.hero-stage.has-ink .mini-phone .gp-touch { display: none; }

/* ---------- still ---------- */

@media (prefers-reduced-motion: reduce) {
  .mini-phone .gp-off, .mini-phone .gp-ghost { transition: none !important; }
  .hero-slot.is-live .mini-phone .gp-ripple.on { animation: none; }
  .hero-stage.is-playing .hero-slot .mini-phone .gp-pick-move,
  .hero-stage.is-playing .hero-slot .mini-phone .gp-pick,
  .hero-stage.is-playing .hero-slot .mini-phone .gp-digits b,
  .hero-stage.is-playing .hero-slot .mini-phone .gp-bar,
  .hero-stage.is-playing .hero-slot .mini-phone .gp-acc,
  .hero-stage.is-playing .hero-slot .mini-phone .gp-l1,
  .hero-stage.is-playing .hero-slot .mini-phone .gp-touch,
  .hero-stage.is-playing .hero-slot .mini-phone .gp-press,
  .hero-stage.is-playing .hero-slot .mini-phone .gp-label { transform: none; transition: opacity .2s var(--ease); }
}

/* ---------- hero: hero-browser ---------- */

/* hero-browser: the slot IS the window. A chrome bar with three neutral dots
   and an address pill, a page under it, edge to edge, so the thing is a
   browser at 40px tall and at 560.

   Ola works the web in front of you and none of it is spelled out. The address
   fills as bars, not letters. The page is a seat map: an arc for the stage and
   four rows of seats. She scrolls, her cursor arrives carrying her name, and
   two seats go orange. One line of real copy says it landed, one real number
   sits beside it, and nothing else asks to be read.

   Its colour is orange, and orange is where the change is: the page loading,
   the two seats she takes, the dot on the label. The page is washed with it
   and the chrome a little more, so the card reads as this job at a glance.
   Every grey on the page is ink at an alpha, so it sits on the wash instead
   of standing out of it as a cold patch.

   Ola's cursor: data-ola-tap (ms after the job goes live) marks where her
   cursor comes onto the page, the row under the pair at 705, as the page
   starts to scroll under it, and the pair she takes at 1860, as they go
   orange. When her ink is on the stage (.hero-stage.has-ink) she is the
   cursor, so the drawn arrow with her name and the grey hover stand aside;
   the selection and the ripple stay, as the page's answer to her.

   Ordinary css is that finished frame. is-idle is an empty tab, is-live is the
   work, is-done is the frame with the label on it. Everything that moves moves
   by transform and opacity, and nothing loops. */
.mini-browser {
  --p: 11px;                         /* page and chrome inset */
  --c: 30px;                         /* chrome height */
  --seat: 9px;                       /* one seat, the unit the page is drawn in */
  --sgap: 5px;                       /* between seats */
  --rgap: 5px;                       /* between rows */
  --sr: 2.5px;                       /* a seat's corner */
  --bar-h: 6px;                      /* a suggested line of heading */
  --lab: 10.5px;                     /* the one line of copy, and the price */
  --scroll: calc(var(--seat) * 2.4); /* how far the page travels when she scrolls */
  --cx: calc(var(--seat) * 4.2);     /* where her cursor comes in from */
  --cy: calc(var(--seat) * 7.6);
  --job: #FF7A3D;                    /* orange: this job's own colour */
  --seat-c: rgba(20, 21, 25, 0.105); /* a seat, as ink on the page */
  --seat-gone: rgba(20, 21, 25, 0.045);
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: #FFF8F4;
  font-family: var(--sans);
  color: var(--ink);
  line-height: 1.2;
  letter-spacing: -0.006em;
  font-variant-numeric: tabular-nums;
}
.mini-browser svg { display: block; }

/* ---------- the chrome ---------- */

.mb-chrome {
  position: absolute;
  z-index: 2;
  top: 0;
  left: 0;
  right: 0;
  height: var(--c);
  display: flex;
  align-items: center;
  gap: calc(var(--p) * 0.85);
  padding: 0 var(--p);
  background: #FFEDE3;
  box-shadow: inset 0 -1px 0 rgba(20, 21, 25, 0.065);
}
.mb-dots { flex: 0 0 auto; display: flex; gap: calc(var(--c) * 0.16); }
.mb-dots i { width: calc(var(--c) * 0.21); height: calc(var(--c) * 0.21); border-radius: 50%; background: rgba(20, 21, 25, 0.15); }

/* the address bar stops short of the stage's badge corner */
.mb-url {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: calc(var(--c) * 0.2);
  height: calc(var(--c) * 0.58);
  margin-right: calc(var(--p) + 22px);
  padding: 0 calc(var(--c) * 0.28);
  border-radius: 999px;
  background: #fff;
  box-shadow: inset 0 0 0 1px rgba(20, 21, 25, 0.055);
}
.mb-url > svg { flex: 0 0 auto; width: calc(var(--c) * 0.3); height: calc(var(--c) * 0.3); fill: none; stroke: #A7ACB5; stroke-width: 2.6; stroke-linecap: round; }

/* what she typed, as two bars: it grows in steps, which is typing without
   letters. Full width is the resting state, because the page is loaded. */
.mb-typed { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: calc(var(--c) * 0.17); transform-origin: 0 50%; }
.mb-typed i { height: calc(var(--c) * 0.12); border-radius: 999px; background: var(--bar-2); }
.mb-typed i:first-child { flex: 0 0 36%; background: var(--bar-3); }
.mb-typed i:last-child { flex: 0 0 22%; }

/* the page loading, on the chrome's own edge */
.mb-load {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: var(--job);
  transform: scaleX(0);
  transform-origin: 0 50%;
  opacity: 0;
}

/* ---------- the page ---------- */

.mb-page { position: absolute; top: var(--c); left: 0; right: 0; bottom: 0; overflow: hidden; }
.mb-doc {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  padding: var(--p) var(--p) calc(var(--p) * 0.92);
}

/* an empty tab, before she gets here: never blank, still a browser */
.mb-blank { position: absolute; z-index: 3; inset: 0; display: grid; place-items: center; opacity: 0; transition: opacity .38s var(--ease); }
.mb-blank i { display: grid; place-items: center; width: calc(var(--seat) * 4); height: calc(var(--seat) * 4); border-radius: 50%; background: rgba(20, 21, 25, 0.05); }
.mb-blank svg { width: 42%; height: 42%; fill: none; stroke: #B2B7BF; stroke-width: 2.3; stroke-linecap: round; }

/* the page's head: a picture and two lines, suggested, never readable. The
   picture carries a little light so the block reads as a page and not as a
   skeleton waiting for one, and the top line is the darker of the two. */
.mb-head { flex: 0 0 auto; display: flex; align-items: center; gap: calc(var(--p) * 0.72); }
.mb-thumb {
  flex: 0 0 auto;
  width: calc(var(--seat) * 2.3);
  height: calc(var(--seat) * 2.3);
  border-radius: calc(var(--seat) * 0.55);
  background: linear-gradient(145deg, rgba(20, 21, 25, 0.06), rgba(20, 21, 25, 0.15));
}
.mb-lines { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: calc(var(--bar-h) * 0.78); }
.mb-lines i { display: block; height: var(--bar-h); border-radius: 999px; }
.mb-lines i:first-child { width: 42%; background: var(--bar-3); }
.mb-lines i:last-child { width: 24%; height: calc(var(--bar-h) - 1px); background: var(--bar-2); }

/* the map: one arc for the stage, four rows that fan out from it */
.mb-map { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: calc(var(--rgap) * 1.7); }
.mb-stage {
  width: 30%;
  height: calc(var(--seat) * 0.8);
  border-top: max(2.5px, calc(var(--seat) * 0.18)) solid var(--bar-2);
  border-radius: 50% / 100% 100% 0 0;
}
.mb-rows { position: relative; display: flex; flex-direction: column; align-items: center; gap: var(--rgap); }
.mb-row { position: relative; display: flex; gap: var(--sgap); }
/* the row she takes carries the cursor, so it stands above the rows under it */
.mb-row.is-here { z-index: 3; }
.mb-row i, .mb-pair i { flex: 0 0 auto; width: var(--seat); height: var(--seat); border-radius: var(--sr); background: var(--seat-c); }
.mb-row i.is-gone, .mb-pair i.is-gone { background: var(--seat-gone); }

.mb-pair { position: relative; display: flex; gap: var(--sgap); }
.mb-seat { position: relative; }
.mb-seat b { position: absolute; inset: 0; border-radius: inherit; background: var(--job); }
.mb-hov, .mb-sel { position: absolute; inset: calc(var(--sgap) * -0.62); border-radius: calc(var(--sr) + var(--sgap) * 0.5); }
.mb-hov { background: rgba(20, 21, 25, 0.05); opacity: 0; }
.mb-sel { background: rgba(255, 122, 61, 0.13); box-shadow: inset 0 0 0 1px rgba(255, 122, 61, 0.42); }
.mb-ripple {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(var(--seat) * 2.2);
  height: calc(var(--seat) * 2.2);
  margin: calc(var(--seat) * -1.1) 0 0 calc(var(--seat) * -1.1);
  border-radius: 50%;
  background: rgba(255, 122, 61, 0.2);
}

/* her cursor: the tip rests on the pair she took, her name hangs below it,
   like a second person in the document. Her name is on ink, because she is
   ink; the orange belongs to what she does */
.mb-cursor { position: absolute; z-index: 4; left: calc(100% - var(--seat) * 0.14); top: calc(100% - var(--seat) * 0.26); width: 0; height: 0; }
.mb-cy { position: absolute; left: 0; top: 0; }
.mb-arrow {
  position: absolute;
  left: -1.5px;
  top: -1.5px;
  width: calc(var(--seat) * 1.35);
  height: calc(var(--seat) * 1.64);
  max-width: none;
  overflow: visible;
  transform-origin: 2px 2px;
  filter: drop-shadow(0 1px 1.5px rgba(20, 21, 25, 0.26));
}
.mb-arrow path { fill: var(--ink); stroke: #fff; stroke-width: 1.6; stroke-linejoin: round; paint-order: stroke; }
.mb-tag {
  position: absolute;
  left: calc(var(--seat) * 0.95);
  top: calc(var(--seat) * 1.35);
  height: max(14px, calc(var(--seat) * 1.1));
  padding: 0 calc(var(--seat) * 0.45);
  border-radius: 999px;
  background: var(--ink);
  color: #fff;
  font-size: max(9px, calc(var(--seat) * 0.6));
  font-weight: 500;
  line-height: max(14px, calc(var(--seat) * 1.1));
  letter-spacing: 0;
  white-space: nowrap;
  box-shadow: 0 2px 6px -2px rgba(20, 21, 25, 0.45);
}

/* the foot: the one line, and the one number */
.mb-foot { flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.mb-label {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--seat) * 0.42);
  height: calc(var(--seat) * 2.05);
  padding: 0 calc(var(--seat) * 0.78) 0 calc(var(--seat) * 0.4);
  border-radius: 999px;
  background: #fff;
  box-shadow: 0 0 0 1px rgba(20, 21, 25, 0.07), 0 3px 8px -3px rgba(20, 21, 25, 0.2);
  font-size: var(--lab);
  font-weight: 500;
  white-space: nowrap;
}
.mb-label i { flex: 0 0 auto; display: grid; place-items: center; width: calc(var(--seat) * 1.25); height: calc(var(--seat) * 1.25); border-radius: 50%; background: var(--job); }
.mb-label svg { width: 62%; height: 62%; fill: none; stroke: var(--ink); stroke-width: 3.4; stroke-linecap: round; stroke-linejoin: round; }
.mb-price { font-size: var(--lab); font-weight: 600; letter-spacing: -0.012em; }

/* where her cursor comes onto the page: the middle of the row under the
   pair (two rows of seats and two gaps down, then half a seat), as the page
   starts to scroll under it. It stands first in the rows so the taps come in
   the order she makes them; the pair carries the second. Empty and sizeless,
   so without her ink it is nothing */
.mb-in { position: absolute; left: 50%; top: calc(var(--seat) * 2.5 + var(--rgap) * 2); width: 0; height: 0; pointer-events: none; }

/* the thumb that says she scrolled */
.mb-track {
  position: absolute;
  z-index: 2;
  top: calc(var(--p) * 0.6);
  right: calc(var(--p) * 0.35);
  width: max(3px, calc(var(--seat) * 0.3));
  height: 30%;
  border-radius: 999px;
  background: rgba(20, 21, 25, 0.13);
  opacity: 0;
}

/* ---------- the sizes it is asked for ---------- */

/* 280x190, 342x219, 382x244, 440x280, 560x320: one unit, --seat, carries them
   all. Both sides are asked for, because the smallest slot is short AND narrow
   and the widest row (15 seats) has to stay inside the page at every step. */
@container slot (min-width: 330px) and (min-height: 200px) {
  .mini-browser { --p: 13px; --c: 34px; --seat: 12px; --sgap: 7px; --rgap: 7px; --sr: 3px; --bar-h: 7px; --lab: 11px; }
}
@container slot (min-width: 370px) and (min-height: 232px) {
  .mini-browser { --p: 15px; --c: 36px; --seat: 14px; --sgap: 8px; --rgap: 8px; --sr: 3.5px; --bar-h: 8px; --lab: 11.5px; }
}
@container slot (min-width: 420px) and (min-height: 268px) {
  .mini-browser { --p: 18px; --c: 38px; --seat: 16px; --sgap: 9px; --rgap: 9px; --sr: 4px; --bar-h: 9px; --lab: 12.5px; }
}
@container slot (min-width: 520px) and (min-height: 306px) {
  .mini-browser { --p: 20px; --c: 42px; --seat: 20px; --sgap: 12px; --rgap: 11px; --sr: 5px; --bar-h: 10px; --lab: 13.5px; }
}

/* ---------- idle: an empty tab ---------- */

/* the transition lives inside the state, so leaving it is instant and the work
   arrives on its own cues instead of fading in twice */
.hero-slot.is-idle .mb-blank { opacity: 1; }
.hero-slot.is-idle .mb-doc { opacity: 0; transition: opacity .2s var(--ease); }
.hero-slot.is-idle .mb-typed { transform: scaleX(0); }

/* ---------- live: she works it ---------- */

.hero-slot.is-live .mb-load   { animation: mb-load 700ms var(--ease) 40ms both; }
.hero-slot.is-live .mb-typed  { animation: mb-type 430ms steps(9, end) 90ms both; }
.hero-slot.is-live .mb-doc    { animation: mb-scroll 1500ms linear both; }
.hero-slot.is-live .mb-track  { animation: mb-track 2100ms linear 340ms both; }
.hero-slot.is-live .mb-cursor { animation: mb-cx 1840ms linear both, mb-cshow 1840ms linear both; }
.hero-slot.is-live .mb-cy     { animation: mb-cy 1840ms linear both; }
.hero-slot.is-live .mb-hov    { animation: mb-hov 430ms linear 1520ms both; }
.hero-slot.is-live .mb-arrow  { animation: mb-press 300ms var(--ease) 1820ms both; }

@keyframes mb-load {
  0%   { opacity: 1; transform: scaleX(0.03); animation-timing-function: var(--ease); }
  58%  { opacity: 1; transform: scaleX(0.74); animation-timing-function: var(--ease); }
  84%  { opacity: 1; transform: scaleX(1); }
  100% { opacity: 0; transform: scaleX(1); }
}
@keyframes mb-type { from { transform: scaleX(0.05); } to { transform: scaleX(1); } }
/* she scrolls once, at 705ms, and the page settles where it rests */
@keyframes mb-scroll {
  0%, 47% { transform: translateY(var(--scroll)); animation-timing-function: var(--settle); }
  100%    { transform: none; }
}
@keyframes mb-track {
  0%, 10%  { opacity: 0; transform: none; }
  17%      { opacity: 1; transform: none; animation-timing-function: var(--settle); }
  55%, 84% { opacity: 1; transform: translateY(150%); }
  100%     { opacity: 0; transform: translateY(150%); }
}
/* x and y ride different curves, so her way in is an arc and not a ruler line,
   and she pauses a beat short of the pair before she takes it */
@keyframes mb-cx {
  0%, 32%  { transform: translateX(var(--cx)); animation-timing-function: cubic-bezier(0.22, 0.86, 0.3, 1); }
  72%, 80% { transform: translateX(calc(var(--seat) * 0.85)); animation-timing-function: cubic-bezier(0.4, 0, 0.18, 1); }
  100%     { transform: none; }
}
@keyframes mb-cy {
  0%, 32%  { transform: translateY(var(--cy)); animation-timing-function: cubic-bezier(0.45, 0.04, 0.3, 1); }
  72%, 80% { transform: translateY(calc(var(--seat) * 1.3)); animation-timing-function: cubic-bezier(0.4, 0, 0.18, 1); }
  100%     { transform: none; }
}
@keyframes mb-cshow { 0%, 30% { opacity: 0; } 36%, 100% { opacity: 1; } }
@keyframes mb-hov { 0% { opacity: 0; } 22%, 74% { opacity: 1; } 100% { opacity: 0; } }
@keyframes mb-press { 0% { transform: none; } 34% { transform: scale(0.86); } 100% { transform: none; } }

/* ---------- in the deck ---------- */

/* behind the card in front she is scaled and blurred and only her top shows:
   the cursor and the scrollbar belong to the live moment, not to the deck */
.hero-slot.is-back .mb-cursor, .hero-slot.is-back .mb-track { display: none; }

/* ---------- Ola's own hand ---------- */

/* With her ink on the stage she is the cursor, so the drawn arrow and her
   name stand aside, and so does the hover, which would light before her ink
   is over the pair. With no ink (no WebGL, motion refused, no script) they
   are still here, the arrow resting on the pair in the finished frame. */
.hero-stage.has-ink .mini-browser .mb-cursor,
.hero-stage.has-ink .mini-browser .mb-hov { display: none; }

@media (prefers-reduced-motion: reduce) {
  .mini-browser *, .mini-browser *::after { animation: none !important; }
}

/* ---------- hero: hero-call ---------- */

/* hero-call: Ola rings a barber shop and it lands. Glanceable, not readable.

   Four things, one column. Every size is a clamp on the slot's own width, and
   the slack falls in the middle row, so one arrangement carries 280 x 174
   through to 520 x 322 with no breakpoints. Around Ola the same card stands
   at the stage's back scale, and when that is small it is only the shop and
   its voice:

     1  who she called: an avatar and a short name, at the top
     2  the meta line under the name: "calling" before it connects, the running
        clock once it does, the length once it is over
     3  the waveform: edge to edge, tall, the loudest thing on the card. Its
        colour and its height say who is speaking. Ola is the call's violet;
        the shop is `--ink-body`; nobody is a quiet grey ripple
     4  the floor: two soft speech shapes, one turn each, arriving from their
        own side, which give way to the one real line, `booked, sat 10:00`

   Nothing is transcribed. The only words are the shop's name, the clock and
   the label. Ordinary css with no state class on the slot is the finished
   frame: the call is over, the time is booked. */

.mini-call {
  /* every size rides the slot's own width, so there are no breakpoints */
  --pad:     clamp(12px, 4.4cqw, 26px);
  --av:      clamp(32px, 11.4cqw, 56px);
  --gap-av:  clamp(10px, 3.4cqw, 18px);
  --fs-name: clamp(12.5px, 4.05cqw, 20px);
  --fs-meta: clamp(11px, 3.3cqw, 15.5px);
  --wave-h:  clamp(52px, 22cqw, 118px);
  --bar-gap: 0.72cqw;
  --word:    clamp(6px, 2.1cqw, 11px);
  --fs-chip: clamp(11px, 3.4cqw, 16px);
  --call:    2600ms;           /* the scripted call, from live: the voices' clock; goodbyes fill any time after it */
  --violet:  #7A5CFF;          /* the call's own colour: Ola's voice on it */
  --quiet:   #C9CDD4;          /* the line when nobody is speaking */
  --them:    var(--ink-body);  /* the shop's voice */
  --ola-say: #D6CCFF;          /* what she said, unread: the violet at about a third */
  --them-say:#D7DAE0;
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  row-gap: clamp(10px, 3.5cqw, 20px);
  padding: var(--pad);
  /* the card's own ground: white with about four percent of the violet. Ink
     on it is 17.2:1 and the grey of the clock 5.9:1, so every word stays AA. */
  background: #F9F7FF;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  text-align: left;
}

/* ---------- 1 + 2: who she called ---------- */

.cc-who {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-rows: auto auto;
  column-gap: var(--gap-av);
  align-items: center;
  /* the stage keeps its own badge in the top right: never reach into it */
  padding-right: 26px;
}

.cc-av {
  position: relative;
  grid-row: 1 / span 2;
  display: grid;
  place-items: center;
  width: var(--av);
  height: var(--av);
  border-radius: 50%;
  background: var(--ground-deep);
  color: #3B3E45;
}
.cc-av svg {
  width: 54%;
  height: 54%;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.9;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Where Ola sits while she talks, for the stage's ink to find: a point on the
   avatar's rim, down and in, the side that faces the middle of the card. It
   is empty and has no size, so with no ink on the stage it is nothing. Its
   data-ola-tap is when her first turn starts, in ms after the call goes live
   (7 percent of the window, where her voice begins to rise). */
.cc-ola-tap {
  position: absolute;
  left: 85.4%;
  top: 85.4%;
  width: 0;
  height: 0;
  pointer-events: none;
}

.cc-name {
  align-self: end;
  font-size: var(--fs-name);
  line-height: 1.2;
  font-weight: 600;
  letter-spacing: -0.016em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* one cell, three answers: before, during, after */
.cc-meta {
  align-self: start;
  display: grid;
  margin-top: 0.22em;
  font-size: var(--fs-meta);
  line-height: 1.25;
  font-weight: 500;
  letter-spacing: -0.006em;
  color: var(--ink-body);
  white-space: nowrap;
}
.cc-meta > * { grid-area: 1 / 1; justify-self: start; }
.cc-pre { opacity: 0; transition: opacity .3s var(--ease); }
.hero-slot.is-idle .cc-pre { opacity: 1; }

/* ---------- 3: the waveform ---------- */

/* Edge to edge, and feathered out at the two ends so it reads as sound going
   on rather than a block that stops.

   Three layers, and not one of them repaints while it moves:
     .cc-bars    the resting line: 52 still DOM bars, grey, painted once. It is
                 the whole of the rest frame, the idle line and the quiet ends.
     .cc-v-ola   her voice, violet
     .cc-v-them  the shop's voice, ink, with its own shape and its own tempo
   A voice is four lanes. A lane is one SVG path holding every fourth bar or
   so (never two neighbours), and it breathes on one scaleY of its own, so the
   bars move out of step with no bar animated by itself. Who is speaking is
   which voice is showing: opacity, never colour. Every live animation here is
   a single transform or opacity on a single element, run by the compositor. */
.cc-wave {
  position: relative;
  align-self: center;
  /* it wants --wave-h, and it never takes more than the row it is given, so a
     shorter card shortens the waveform instead of overflowing */
  height: min(var(--wave-h), 100%);
  margin-inline: calc(var(--pad) * -1);
}
.cc-bars {
  display: flex;
  align-items: center;
  gap: var(--bar-gap);
  height: 100%;
  color: var(--quiet);
  transform: scaleY(.58);
  transform-origin: 50% 50%;
  /* when the call is done the grey line comes back and opens out to rest */
  transition: transform .8s var(--ease), opacity .4s var(--ease);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
}
.cc-bars i {
  flex: 1 1 0;
  min-width: 0;
  height: calc(var(--h) * 100%);
  min-height: 0.9cqw;
  border-radius: 99px;
  background: currentColor;
}
/* the shape of the sound: two coprime cycles, 11 and 5, so 52 bars never
   repeat themselves. --h is the two multiplied. Her voice's paths are these
   same heights, bar for bar; the shop's are the same cycles read 23 bars on,
   so it has a shape of its own. In the 1000 x 220 viewBox a bar is 12.17
   wide and the pitch is 19.37, which is the flex row above: 0.72cqw gaps,
   52 bars filling 100cqw, 22cqw tall. */
.cc-bars i { --h: calc(var(--h1) * var(--h2)); }
.cc-bars i:nth-child(11n + 1)  { --h1: .96; }
.cc-bars i:nth-child(11n + 2)  { --h1: .44; }
.cc-bars i:nth-child(11n + 3)  { --h1: .72; }
.cc-bars i:nth-child(11n + 4)  { --h1: .38; }
.cc-bars i:nth-child(11n + 5)  { --h1: .88; }
.cc-bars i:nth-child(11n + 6)  { --h1: .58; }
.cc-bars i:nth-child(11n + 7)  { --h1: 1;   }
.cc-bars i:nth-child(11n + 8)  { --h1: .5;  }
.cc-bars i:nth-child(11n + 9)  { --h1: .78; }
.cc-bars i:nth-child(11n + 10) { --h1: .34; }
.cc-bars i:nth-child(11n)      { --h1: .66; }
.cc-bars i:nth-child(5n + 1) { --h2: .94; }
.cc-bars i:nth-child(5n + 2) { --h2: .78; }
.cc-bars i:nth-child(5n + 3) { --h2: 1;   }
.cc-bars i:nth-child(5n + 4) { --h2: .86; }
.cc-bars i:nth-child(5n)     { --h2: .72; }

/* the voices sit exactly over the resting bars: a 1000 x 220 viewBox is
   100cqw x 22cqw, so a path's bar lands where the DOM bar stands */
.cc-voice {
  position: absolute;
  inset: 0;
  opacity: 0;
  transform-origin: 50% 50%;
  transition: opacity .35s var(--ease);
}
.cc-lane {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  overflow: visible;
  fill: none;
  stroke-width: 12.17;
  stroke-linecap: round;
  transform-origin: 50% 50%;
}
.cc-v-ola  .cc-lane { stroke: url(#cc-ink-ola); }
.cc-v-them .cc-lane { stroke: url(#cc-ink-them); }
/* the same feather as the resting line, drawn into the stroke, so it costs
   nothing to move */
.cc-inks { position: absolute; width: 0; height: 0; overflow: hidden; }
.cc-ink-ola  stop { stop-color: var(--violet); }
.cc-ink-them stop { stop-color: var(--them); }

/* ---------- 4: the floor ---------- */

/* the turns and the result share one cell: what was said gives the room back
   to what came of it */
.cc-floor { display: grid; }
.cc-floor > * { grid-area: 1 / 1; }

/* a turn is what a sentence looks like from across the room: a few soft word
   shapes, her side or theirs, and no letters to read */
.cc-talk {
  display: grid;
  gap: clamp(7px, 2.5cqw, 13px);
  align-self: center;
}
.cc-say { display: flex; gap: clamp(4px, 1.35cqw, 8px); }
.cc-say i { display: block; height: var(--word); border-radius: 99px; background: currentColor; }
.cc-ola  { justify-content: flex-end;   color: var(--ola-say);  transform-origin: 100% 50%; }
.cc-them { justify-content: flex-start; color: var(--them-say); transform-origin: 0 50%; }
.cc-ola  i:nth-child(1) { width: 21%; }
.cc-ola  i:nth-child(2) { width: 12%; }
.cc-ola  i:nth-child(3) { width: 17%; }
.cc-them i:nth-child(1) { width: 15%; }
.cc-them i:nth-child(2) { width: 10%; }
.cc-them i:nth-child(3) { width: 13.5%; }

.mini-call .cc-done {
  justify-self: center;
  align-self: center;
  height: 2.1em;
  padding: 0 0.92em 0 0.72em;
  gap: 0.42em;
  font-size: var(--fs-chip);
  font-weight: 500;
}
.mini-call .cc-done .cc-dot { width: .5em; height: .5em; border-radius: 50%; background: var(--violet); }

/* ---------- the call itself ---------- */

/* about to ring: every bar the same low mark, so the line is flat, because
   there is nothing on it yet */
.hero-slot.is-idle .cc-bars { transform: none; gap: 0.32cqw; }
.hero-slot.is-idle .cc-bars i { --h1: .06; --h2: 1; min-height: 2px; }

/* connecting: she leans in once, and it is answered */
.hero-slot.is-live .cc-av { animation: call-connect 760ms var(--settle) both; }
@keyframes call-connect {
  0%   { transform: scale(.9); }
  100% { transform: scale(1); }
}

/* Who is talking, over the 2600ms the call is given. The grey line is the
   ring and the quiet at the end; Ola opens; the shop answers with its own
   shape on its own beat; Ola confirms; the line quiets. A hand over happens
   while the line is low, so the swap of voice reads as a turn, not a flash. */
.hero-slot.is-live .cc-bars  { animation: call-rest var(--call) var(--ease) both, call-hush 1s linear var(--call) infinite; }
.hero-slot.is-live .cc-v-ola  { animation: call-ola  var(--call) var(--ease) both, call-ola-bye  1.3s var(--ease) var(--call) infinite forwards; }
.hero-slot.is-live .cc-v-them { animation: call-them var(--call) var(--ease) both, call-them-bye 1.3s var(--ease) var(--call) infinite forwards; }

@keyframes call-rest {
  0%, 7%    { transform: scaleY(.12); opacity: 1; }
  9.5%      { transform: scaleY(.4);  opacity: 0; }
  85%       { transform: scaleY(.14); opacity: 0; }
  88%       { transform: scaleY(.16); opacity: 1; }
  93%, 100% { transform: scaleY(.3);  opacity: 1; }
}
@keyframes call-ola {
  0%, 7%    { transform: scaleY(.12); opacity: 0; }
  12%       { transform: scaleY(1);   opacity: 1; }
  30%       { transform: scaleY(.96); opacity: 1; }
  34%       { transform: scaleY(.18); opacity: 1; }
  37%, 66%  { transform: scaleY(.16); opacity: 0; }
  69%       { transform: scaleY(.16); opacity: 1; }
  72%       { transform: scaleY(.9);  opacity: 1; }
  81%       { transform: scaleY(.86); opacity: 1; }
  85%       { transform: scaleY(.14); opacity: 1; }
  88%, 100% { transform: scaleY(.16); opacity: 0; }
}
@keyframes call-them {
  0%, 34%   { transform: scaleY(.18); opacity: 0; }
  37%       { transform: scaleY(.18); opacity: 1; }
  41%       { transform: scaleY(.82); opacity: 1; }
  49%       { transform: scaleY(.58); opacity: 1; }
  56%       { transform: scaleY(.88); opacity: 1; }
  62%       { transform: scaleY(.6);  opacity: 1; }
  66%       { transform: scaleY(.16); opacity: 1; }
  69%, 100% { transform: scaleY(.16); opacity: 0; }
}

/* The call is booked inside the window, but the engine may keep it live a
   while longer, moving round to its place beside Ola. Until it hangs up the
   two sides trade short, low goodbyes, so a call that is still running still
   looks like one. The grey line keeps out of it until then. */
@keyframes call-hush { 0%, 100% { opacity: 0; } }
@keyframes call-ola-bye {
  0%        { transform: scaleY(.14); opacity: 1; }
  14%       { transform: scaleY(.52); opacity: 1; }
  30%       { transform: scaleY(.42); opacity: 1; }
  42%       { transform: scaleY(.14); opacity: 1; }
  46%, 96%  { transform: scaleY(.14); opacity: 0; }
  100%      { transform: scaleY(.14); opacity: 1; }
}
@keyframes call-them-bye {
  0%, 44%   { transform: scaleY(.14); opacity: 0; }
  48%       { transform: scaleY(.14); opacity: 1; }
  62%       { transform: scaleY(.46); opacity: 1; }
  78%       { transform: scaleY(.36); opacity: 1; }
  90%       { transform: scaleY(.14); opacity: 1; }
  94%, 100% { transform: scaleY(.14); opacity: 0; }
}

/* the bars' own speech: each lane on its own curve and its own tempo. Hers
   are quick, the shop's slower, so the two voices do not move alike. */
.hero-slot.is-live .cc-lane { animation: var(--lane) ease-in-out var(--ld) infinite; }
.cc-l1 { --lane: call-lane-a .62s; --ld: -.11s; }
.cc-l2 { --lane: call-lane-b .74s; --ld: -.47s; }
.cc-l3 { --lane: call-lane-c .56s; --ld: -.29s; }
.cc-l4 { --lane: call-lane-d .86s; --ld: -.63s; }
.cc-v-them .cc-l1 { --lane: call-lane-c .92s;  --ld: -.2s;  }
.cc-v-them .cc-l2 { --lane: call-lane-a 1.08s; --ld: -.61s; }
.cc-v-them .cc-l3 { --lane: call-lane-d .8s;   --ld: -.35s; }
.cc-v-them .cc-l4 { --lane: call-lane-b .7s;   --ld: -.05s; }
@keyframes call-lane-a { 0%, 100% { transform: scaleY(.6); }  38% { transform: scaleY(1.04); } 70% { transform: scaleY(.72); } }
@keyframes call-lane-b { 0%, 100% { transform: scaleY(.9); }  30% { transform: scaleY(.52); } 64% { transform: scaleY(1); } }
@keyframes call-lane-c { 0%, 100% { transform: scaleY(.66); } 45% { transform: scaleY(.98); } 75% { transform: scaleY(.5); } }
@keyframes call-lane-d { 0%, 100% { transform: scaleY(1); }   35% { transform: scaleY(.62); } 68% { transform: scaleY(.9); } }

/* a speech shape grows out of the side it came from */
.hero-stage.is-playing .hero-slot .cc-say.part { transform: scale(.55, .7); }
.hero-stage.is-playing .hero-slot .cc-say.part.on { transform: none; }

/* Around Ola, a job stands at the stage's --back scale: .33 on a phone (about
   113 x 70), .72 on a desktop (about 274 x 170). At .72 the card is still a
   card, so it stays whole. At .33 words would be four pixels tall, so they go,
   and so does the floor; what stays is the shop's avatar and its voice, both
   drawn bigger, with the stage's own live dot or tick in the corner, and the
   voice keeps moving while the call runs. --small is 1 below a back scale of
   .5 and 0 above it, so this follows the stage's own number rather than a
   breakpoint of its own. All of it is the individual scale and translate
   properties and opacity, on the slot's own .8s settle, so it composes with
   the connect beat and the lanes. */
.mini-call { --small: clamp(0, calc((0.5 - var(--back, 1)) * 100), 1); }
.cc-av { transform-origin: 0 0; transition: scale .8s var(--settle); }
.cc-wave { transition: scale .8s var(--settle), translate .8s var(--settle); }
.cc-name, .cc-meta, .cc-floor { transition: opacity .3s var(--ease); }
.hero-slot.is-back .cc-av { scale: calc(1 + 0.6 * var(--small)); }
.hero-slot.is-back .cc-wave { translate: 0 calc(39% * var(--small)); scale: 1 calc(1 + 0.42 * var(--small)); }
.hero-slot.is-back .cc-name,
.hero-slot.is-back .cc-meta,
.hero-slot.is-back .cc-floor { opacity: calc(1 - var(--small)); }

/* Between two plays the whole card lets go, furniture included. It fades as
   one layer and nothing inside it blurs: a blur over a card this size at dpr 3
   was a measured share of the dropped frames, and under a fade nobody sees it. */
.hero-stage.is-resetting .mini-call {
  opacity: 0;
  transition: opacity .42s var(--ease);
}
.hero-stage.is-resetting .mini-call .part { filter: none; }

@media (prefers-reduced-motion: reduce) {
  .mini-call *, .mini-call *::before, .mini-call *::after { animation: none !important; transition: none !important; }
}
.is-still .mini-call * { animation: none !important; }

/* ---------- hero: hero-chat ---------- */

/* hero-chat: Ola tells a group chat you are running late. Glanceable, not
   readable.

   The card IS the chat: a header with four faces and the group's name, the
   thread, and the composer at the foot, edge to edge. The only words are the
   name and the one line it ends on, `sent to 4`. Every message is a bubble of
   soft word shapes; nobody's text is spelled out.

   What happens, on one clock: she types in the composer, sends, and her
   bubble rises out of it on the right while the thread moves up to make room.
   A small tick says it went. Someone starts typing, answers; a heart lands on
   her bubble; a second person answers; a thumbs up joins the heart. The tick
   under her bubble turns green and says `sent to 4`.

   One unit, --u, is a point of the 342 wide card, so every size is the same
   drawing (the card keeps one shape, 100 by 62, from 280 to 520 wide). The two
   lines of copy are clamped so they stay legible at the smallest and calm at
   the largest.

   Its colour is blue, and blue is where the change is: her bubble, the send
   key that sends it, the heart that lands on it, the tick that says all four
   have it. The chat is washed with it, so the card reads as this job at a
   glance; the friends' bubbles are white on that wash, the way a chat with a
   wallpaper draws them.

   Ola's hand: data-ola-tap (ms after the job goes live) marks the composer
   at 40, just past where the words grow, which is where her typing dots sit
   while she writes, and the send key at 500, as it dips and her bubble
   leaves. Nothing here is a drawn pointer, so nothing stands aside under
   .hero-stage.has-ink; the key's own dip stays as its answer to her.

   Ordinary css with no state class on the slot is the finished frame: the
   thread risen, both replies in, both reactions on, `sent to 4` by a blue
   tick. */

.mini-chat {
  --u: calc(100cqw / 342);
  --head: calc(46 * var(--u));
  --foot: calc(40 * var(--u));
  --job: #3D6BFF;                  /* blue: this job's own colour */
  --tint: #F3F6FF;                 /* the chat's ground, washed with it */
  --them: #fff;                    /* a friend's bubble */
  --them-ink: #C9CDD4;             /* a friend's words, as shapes */
  --me-ink: rgba(255, 255, 255, 0.62);
  --fs-name: clamp(10px, 3.3cqw, 15px);
  --fs-line: clamp(10.5px, 3.3cqw, 16px);
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: var(--tint);
  color: var(--ink);
  font-family: var(--sans);
  letter-spacing: -0.006em;
}
.mini-chat svg { display: block; }

/* ---------- the faces ---------- */

/* a face is a soft disc in its own tone with a head and shoulders in white,
   the way a phone draws a contact it has no picture for */
.gc-av {
  flex: 0 0 auto;
  display: block;
  width: calc(18 * var(--u));
  height: calc(18 * var(--u));
  border-radius: 50%;
  background:
    radial-gradient(18% 18% at 50% 38%, rgba(255, 255, 255, 0.95) 86%, rgba(255, 255, 255, 0) 100%),
    radial-gradient(38% 40% at 50% 104%, rgba(255, 255, 255, 0.95) 94%, rgba(255, 255, 255, 0) 100%),
    linear-gradient(180deg, var(--t1), var(--t2));
}
.gc-a { --t1: #C4CAD3; --t2: #A1A9B6; }
.gc-b { --t1: #D8CEC1; --t2: #B6A999; }
.gc-c { --t1: #A3A9B3; --t2: #7D8490; }
.gc-d { --t1: #D3D7DE; --t2: #B3B9C3; }

/* ---------- the header ---------- */

.gc-head {
  position: absolute;
  z-index: 3;
  top: 0;
  left: 0;
  right: 0;
  height: var(--head);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(3.5 * var(--u));
  background: var(--tint);
  box-shadow: 0 1px 0 rgba(20, 21, 25, 0.06);
}
.gc-back {
  position: absolute;
  left: calc(10 * var(--u));
  top: 50%;
  width: calc(15 * var(--u));
  height: calc(15 * var(--u));
  margin-top: calc(-7.5 * var(--u));
  fill: none;
  stroke: var(--job);
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.gc-faces { display: flex; }
.gc-faces .gc-av {
  width: calc(20 * var(--u));
  height: calc(20 * var(--u));
  box-shadow: 0 0 0 calc(1.6 * var(--u)) var(--tint);
}
.gc-faces .gc-av + .gc-av { margin-left: calc(-5.5 * var(--u)); }
.gc-name {
  font-size: var(--fs-name);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.012em;
  white-space: nowrap;
}
/* the name as a shape, for the tray, where letters would only be grain */
.gc-name-bar {
  display: none;
  width: calc(66 * var(--u));
  height: calc(7 * var(--u));
  border-radius: 99px;
  background: var(--bar-3);
}

/* ---------- the thread ---------- */

/* It stands on the composer and grows upward. What scrolls off the top passes
   under the header through a short fade. */
.gc-view {
  position: absolute;
  top: var(--head);
  bottom: var(--foot);
  left: 0;
  right: 0;
  overflow: hidden;
}
.gc-view::before {
  content: "";
  position: absolute;
  z-index: 2;
  top: 0;
  left: 0;
  right: 0;
  height: calc(16 * var(--u));
  background: linear-gradient(180deg, var(--tint) 10%, rgba(243, 246, 255, 0));
  pointer-events: none;
}
.gc-w1 { position: absolute; left: 0; right: 0; bottom: 0; }
.gc-thread {
  display: flex;
  flex-direction: column;
  padding: 0 calc(12 * var(--u)) calc(6 * var(--u));
}

.gc-row { display: flex; align-items: flex-end; gap: calc(6 * var(--u)); margin-top: calc(8 * var(--u)); }
.gc-row:first-child { margin-top: 0; }
.gc-row.is-run { margin-top: calc(3 * var(--u)); }
.gc-row.is-me { justify-content: flex-end; }
.gc-row.is-ola { margin-top: calc(22 * var(--u)); }
.gc-row.is-reply { margin-top: 0; }
.gc-row.is-reply + .gc-row.is-reply { margin-top: calc(5 * var(--u)); }
.gc-spacer { flex: 0 0 auto; width: calc(18 * var(--u)); }

/* a message: a bubble of word shapes. Theirs are white on the left with the
   corner by the face tucked in; hers is blue on the right. */
.gc-bub {
  position: relative;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: calc(3.5 * var(--u));
  height: calc(24 * var(--u));
  padding: 0 calc(11 * var(--u));
  border-radius: calc(12 * var(--u)) calc(12 * var(--u)) calc(12 * var(--u)) calc(4 * var(--u));
  background: var(--them);
  box-shadow: 0 0 0 1px rgba(20, 21, 25, 0.035), 0 calc(1 * var(--u)) calc(3 * var(--u)) rgba(30, 50, 120, 0.06);
}
.gc-bub i {
  flex: 0 0 auto;
  display: block;
  width: calc(var(--w) * var(--u));
  height: calc(5 * var(--u));
  border-radius: 99px;
  background: var(--them-ink);
}
.is-me .gc-bub {
  border-radius: calc(12 * var(--u)) calc(12 * var(--u)) calc(4 * var(--u)) calc(12 * var(--u));
  background: linear-gradient(180deg, #4C77FF, var(--job));
  box-shadow: 0 calc(3 * var(--u)) calc(8 * var(--u)) calc(-3 * var(--u)) rgba(61, 107, 255, 0.45);
}
.is-me .gc-bub i { background: var(--me-ink); }

/* someone is typing: three dots in a small bubble, in the cell the answer
   will take */
.gc-cell { display: grid; }
.gc-cell > * { grid-area: 1 / 1; justify-self: start; align-self: end; }
.gc-bub.gc-typing { gap: calc(3.2 * var(--u)); padding: 0 calc(10 * var(--u)); }
.gc-typing i { width: calc(5 * var(--u)); height: calc(5 * var(--u)); border-radius: 50%; background: #A4AAB3; }

/* reactions, on the corner of her bubble: a heart, then a thumbs up beside it */
.gc-taps { position: absolute; left: calc(-9 * var(--u)); top: calc(-12 * var(--u)); width: 0; height: 0; }
.gc-tap {
  position: absolute;
  top: 0;
  display: grid;
  place-items: center;
  width: calc(19 * var(--u));
  height: calc(19 * var(--u));
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 0 calc(1.6 * var(--u)) var(--tint), 0 calc(1 * var(--u)) calc(3 * var(--u)) rgba(30, 50, 120, 0.12);
}
.gc-tap svg { width: calc(11.5 * var(--u)); height: calc(11.5 * var(--u)); }
.gc-heart { left: 0; z-index: 2; }
.gc-heart svg { fill: var(--job); }
.gc-up { left: calc(-16 * var(--u)); top: calc(1.5 * var(--u)); z-index: 1; }
.gc-up svg { fill: var(--ink-body); }

/* under her bubble: a small tick when it goes, and the line when it lands */
.gc-status {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: calc(4 * var(--u));
  height: calc(20 * var(--u));
}
.gc-sent {
  font-size: var(--fs-line);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.006em;
  color: var(--ink);
  white-space: nowrap;
}
.gc-ticks { display: grid; }
.gc-ticks > * { grid-area: 1 / 1; }
.gc-tick {
  display: grid;
  place-items: center;
  width: calc(13 * var(--u));
  height: calc(13 * var(--u));
  border-radius: 50%;
  background: var(--bar-3);
}
.gc-tick.is-good { background: var(--job); }
.gc-tick svg { width: 72%; height: 72%; fill: none; stroke: #fff; stroke-width: 3.2; stroke-linecap: round; stroke-linejoin: round; }

/* ---------- the composer ---------- */

.gc-foot {
  position: absolute;
  z-index: 3;
  left: 0;
  right: 0;
  bottom: 0;
  height: var(--foot);
  display: flex;
  align-items: center;
  gap: calc(7 * var(--u));
  padding: 0 calc(12 * var(--u)) calc(3 * var(--u));
  background: var(--tint);
}
.gc-plus {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: calc(24 * var(--u));
  height: calc(24 * var(--u));
  border-radius: 50%;
  background: rgba(20, 21, 25, 0.05);
}
.gc-plus svg { width: 50%; height: 50%; fill: none; stroke: #8A909A; stroke-width: 2.4; stroke-linecap: round; }
.gc-field {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: calc(6 * var(--u));
  height: calc(26 * var(--u));
  padding: 0 calc(3 * var(--u)) 0 calc(11 * var(--u));
  border-radius: 99px;
  background: #fff;
  box-shadow: inset 0 0 0 1px rgba(20, 21, 25, 0.1);
}
/* where her typing dots sit while she writes: just past the end of the words
   she types, so the words stay in sight as they grow. Empty and sizeless */
.gc-caret { position: absolute; left: calc(146 * var(--u)); top: 50%; width: 0; height: 0; pointer-events: none; }
.gc-input { flex: 1 1 auto; min-width: 0; display: grid; align-items: center; }
.gc-input > * { grid-area: 1 / 1; }
.gc-ph { display: block; width: 34%; height: calc(5 * var(--u)); border-radius: 99px; background: #E4E6EA; }
.gc-typed { display: flex; gap: calc(3.5 * var(--u)); transform-origin: 0 50%; }
.gc-typed i { flex: 0 0 auto; display: block; width: calc(var(--w) * var(--u)); height: calc(5 * var(--u)); border-radius: 99px; background: var(--bar-3); }
.gc-send {
  position: relative;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: calc(20 * var(--u));
  height: calc(20 * var(--u));
  border-radius: 50%;
  background: #D3D6DC;
}
.gc-send > * { grid-area: 1 / 1; }
.gc-send b { width: 100%; height: 100%; border-radius: 50%; background: var(--job); }
.gc-send svg { position: relative; width: 62%; height: 62%; fill: none; stroke: #fff; stroke-width: 2.8; stroke-linecap: round; stroke-linejoin: round; }

/* ---------- while it plays ---------- */

/* Everything below is where a piece comes FROM. The engine adds .on at its
   data-at and .off at its data-off; the rules above are where it ends up.
   Arrivals carry their transition on .on, so a new play snaps back to the
   start instead of sliding there. */

/* the thread rises by exactly what arrives under it: her bubble with its
   status line, the typing row, the second answer */
.hero-stage.is-playing .hero-slot .mini-chat .gc-w1 { transform: translateY(calc(66 * var(--u))); }
.hero-stage.is-playing .hero-slot .mini-chat .gc-w2 { transform: translateY(calc(24 * var(--u))); }
.hero-stage.is-playing .hero-slot .mini-chat .gc-w3 { transform: translateY(calc(29 * var(--u))); }
.hero-stage.is-playing .hero-slot .mini-chat .gc-w1.on,
.hero-stage.is-playing .hero-slot .mini-chat .gc-w2.on,
.hero-stage.is-playing .hero-slot .mini-chat .gc-w3.on { transform: none; transition: transform .62s var(--settle); }
/* between two plays the thread lets go as one layer and comes back the same
   way, already scrolled down to where the next play starts */
.hero-stage.is-playing .hero-slot .mini-chat .gc-w1 { transition: opacity .45s var(--ease); }
.hero-stage.is-playing .hero-slot .mini-chat .gc-w1.on { transition: transform .62s var(--settle), opacity .45s var(--ease); }

/* she types: the words grow in the field in steps, the placeholder steps
   aside, the send key lights and is pressed */
.hero-stage.is-playing .hero-slot .mini-chat .gc-typed { opacity: 0; }
.hero-stage.is-playing .hero-slot .mini-chat .gc-typed.on:not(.off) { opacity: 1; }
.hero-stage.is-playing .hero-slot .mini-chat .gc-typed.off { opacity: 0; transition: opacity .12s var(--ease), visibility 0s linear .12s; }
.hero-slot.is-live .mini-chat .gc-typed.on { animation: gc-type 420ms steps(9, end) 20ms both; }
@keyframes gc-type { from { transform: scaleX(0.06); } to { transform: none; } }
.hero-stage.is-playing .hero-slot .mini-chat .gc-ph { transition: opacity .3s var(--ease) .12s; }
.hero-stage.is-playing .hero-slot .mini-chat .gc-typed.on:not(.off) + .gc-ph { opacity: 0; transition: opacity .12s var(--ease); }
.hero-stage.is-playing .hero-slot .mini-chat .gc-send b { opacity: 0; }
.hero-stage.is-playing .hero-slot .mini-chat .gc-send b.on:not(.off) { opacity: 1; transition: opacity .18s var(--ease); }
.hero-slot.is-live .mini-chat .gc-send { animation: gc-press 460ms var(--ease) 500ms both; }
@keyframes gc-press { 0% { transform: none; } 32% { transform: scale(0.78); } 100% { transform: none; } }

/* her bubble comes up out of the composer, with a little give */
.hero-stage.is-playing .hero-slot .mini-chat .gc-ola { opacity: 0; transform: scale(0.9); transform-origin: 100% 100%; }
.hero-stage.is-playing .hero-slot .mini-chat .gc-ola.on { opacity: 1; transform: none; transition: opacity .2s var(--ease), transform .6s var(--spring); }

/* their faces and bubbles grow out of the corner they speak from */
.hero-stage.is-playing .hero-slot .mini-chat .gc-in { opacity: 0; transform: scale(0.88); transform-origin: 0 100%; }
.hero-stage.is-playing .hero-slot .mini-chat .gc-in.on:not(.off) { opacity: 1; transform: none; transition: opacity .2s var(--ease), transform .6s var(--spring); }
.hero-stage.is-playing .hero-slot .mini-chat .gc-in.off {
  visibility: hidden;
  opacity: 0;
  transform: scale(0.92);
  transition: opacity .16s var(--ease), transform .3s var(--ease), visibility 0s linear .3s;
}
.hero-stage.is-playing .hero-slot .mini-chat .gc-av.gc-in { transform: scale(0.7); transform-origin: 50% 50%; }
.hero-slot.is-live .mini-chat .gc-typing.on:not(.off) i { animation: gc-dot 1s ease-in-out infinite; }
.hero-slot.is-live .mini-chat .gc-typing.on:not(.off) i:nth-child(2) { animation-delay: .15s; }
.hero-slot.is-live .mini-chat .gc-typing.on:not(.off) i:nth-child(3) { animation-delay: .3s; }
@keyframes gc-dot {
  0%, 56%, 100% { transform: none; opacity: .5; }
  26%           { transform: translateY(calc(-2.2 * var(--u))); opacity: 1; }
}

/* a reaction lands on her bubble */
.hero-stage.is-playing .hero-slot .mini-chat .gc-tap { opacity: 0; transform: scale(0.78); }
.hero-stage.is-playing .hero-slot .mini-chat .gc-tap.on { opacity: 1; transform: none; transition: opacity .16s var(--ease), transform .55s var(--spring); }

/* the tick: grey as it goes, green when all four have it, and the line */
.hero-stage.is-playing .hero-slot .mini-chat .gc-tick { opacity: 0; transform: scale(0.7); }
.hero-stage.is-playing .hero-slot .mini-chat .gc-tick.on { opacity: 1; transform: none; transition: opacity .16s var(--ease), transform .55s var(--spring); }
.hero-stage.is-playing .hero-slot .mini-chat .gc-sent { opacity: 0; transform: translateX(calc(6 * var(--u))); }
.hero-stage.is-playing .hero-slot .mini-chat .gc-sent.on { opacity: 1; transform: none; transition: opacity .3s var(--ease), transform .5s var(--settle); }

/* ---------- in the tray ---------- */

/* At a third of its size the words are grain: the faces, the bubbles, the
   reactions, the ticks and the composer are what read, and they keep moving. */
.hero-slot.is-back .mini-chat { --tint: #EBF0FF; --them: #fff; }
.hero-slot.is-back .mini-chat .gc-bub i,
.hero-slot.is-back .mini-chat .gc-sent,
.hero-slot.is-back .mini-chat .gc-name,
.hero-slot.is-back .mini-chat .gc-input { visibility: hidden; }
.hero-slot.is-back .mini-chat .gc-name { position: absolute; }
.hero-slot.is-back .mini-chat .gc-name-bar { display: block; }

/* ---------- between two plays, and still ---------- */

/* the thread fades as one layer; nothing inside it blurs */
.hero-stage.is-resetting .mini-chat .part { filter: none; }

@media (prefers-reduced-motion: reduce) {
  .mini-chat *, .mini-chat *::before, .mini-chat *::after { animation: none !important; transition: none !important; }
}
.is-still .mini-chat * { animation: none !important; }

/* ---------- does ---------- */

/* does: thirteen asks on a ring. One is in front and working; the one before
   and the one after stand behind it, turned a little and softened, so it is
   never in doubt which one you are watching. The ring turns when the one in
   front has said what it did. Ordinary css is the first three standing still
   with the middle one finished, which is what no script, `?still` and refused
   motion all show. */

.does .head .lede { max-width: 700px; }

.does-ring {
  --cw: clamp(300px, min(30vw, 45svh), 440px);   /* and never taller than the screen it is seen on */
  position: relative;
  height: calc(var(--cw) * 4 / 3);
  margin-top: clamp(36px, 5vw, 72px);
  perspective: 1500px;
  touch-action: pan-y;
  outline: none;
  /* the ones on their way out are cut here, not at the document's edge */
  overflow-x: clip;
  overflow-y: visible;
}
/* an even card width halves to a whole pixel, so the card, the chip, the strip
   and the rail inside it all land on the device grid instead of between it */
@supports (width: round(down, 6px, 3px)) {
  .does-ring { --cw: round(down, clamp(300px, min(30vw, 45svh), 440px), 6px); }
}
/* promoted for the turn and handed straight back. `filter` is named as well as
   `transform`, so a card about to take on a blur already has the surface */
.does-ring.is-turning .does-card { will-change: transform, filter; }
/* the keyboard says which card it is on, not which box it is in */
.does-ring:focus-visible .does-card.is-centre { outline: 2px solid var(--ink); outline-offset: 5px; }

.does-card {
  container-type: inline-size;
  --t: clamp(0, (100cqw - 280px) / 130px, 1);
  --in: 12px;                          /* the one inset the chip and the strip both keep */
  --pad: 0.95em;                       /* and the one rail their contents start on */
  --fs: calc(13px + 2px * var(--t));   /* one small size: the ask, the status, the result */
  position: absolute;
  left: 50%;
  top: 0;
  width: var(--cw);
  margin-left: calc(var(--cw) / -2);
  aspect-ratio: 3 / 4;
  visibility: visible;
  border-radius: var(--r-card);
  background: var(--bg, var(--ground-deep));
  box-shadow: var(--ladder), 0 0 0 1px rgba(0, 0, 0, .05);
  transition:
    transform .9s var(--ease),
    filter .9s var(--ease),
    opacity .9s var(--ease),
    z-index .9s var(--ease);
}
/* a hairline is one device pixel, not one css pixel */
@media (min-resolution: 2dppx) {
  .does-card { box-shadow: var(--ladder), 0 0 0 .5px rgba(0, 0, 0, .07); }
}
/* the flanks stand back behind a veil of the room's own colour rather than by
   going part transparent: an opaque card cannot show the card behind it */
.does-card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  border-radius: inherit;
  background: var(--ground);
  opacity: 0;
  pointer-events: none;
  transition: opacity .9s var(--ease);
}
/* the fourth layer of --ladder-hover, on a pseudo so a lift costs one opacity */
.does-card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: 0 22px 44px -18px rgba(24, 28, 38, .18);
  opacity: 0;
  pointer-events: none;
}

/* the five places on the ring, and the nowhere behind it */
.does-card.is-centre { z-index: 5; transform: none; }
.does-card.is-left { z-index: 4; transform: translateX(calc(var(--cw) * -.56)) scale(.78) rotateY(7deg); }
.does-card.is-right { z-index: 4; transform: translateX(calc(var(--cw) * .56)) scale(.78) rotateY(-7deg); }
.does-card.is-left, .does-card.is-right { filter: blur(2.6px) saturate(.78) brightness(.9); }
.does-card.is-left::before, .does-card.is-right::before { opacity: .2; }
.does-card.is-far-left { z-index: 3; transform: translateX(calc(var(--cw) * -.98)) scale(.6) rotateY(11deg); }
.does-card.is-far-right { z-index: 3; transform: translateX(calc(var(--cw) * .98)) scale(.6) rotateY(-11deg); }
.does-card.is-far-left, .does-card.is-far-right { opacity: 0; filter: blur(5px) saturate(.7) brightness(.84); }
.does-card.is-far-left::before, .does-card.is-far-right::before { opacity: .3; }
.does-card.is-hidden {
  z-index: 1;
  transform: scale(.55);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity .9s var(--ease), transform 0s .9s, visibility 0s .9s;
}
/* a card behind the ring fetches no photograph: it is fetched once the card
   comes within two places of the front, still unseen, seconds before it is
   shown, so only the cards in sight load with the page */
.does-card.is-hidden .does-shot img { display: none; }
/* a flank is a thing to click where there is a pointer, and a thing to swipe
   past where there is a thumb: a peeking sliver is not a tap target */
@media (hover: hover) { .does-card.is-left, .does-card.is-right { cursor: pointer; } }
@media (hover: none) { .does-card.is-left, .does-card.is-right { pointer-events: none; } }

.does-shot {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: inherit;
  background: var(--bg, var(--ground-deep));   /* the photograph's own colour while it loads */
}
.does-shot picture { display: contents; }
.does-shot img { width: 100%; height: 100%; object-fit: cover; }
/* the foot of the picture goes quiet so the strip has something to sit on.
   Five stops: a straight ramp shows its own starting line on a flat sky */
.does-shot::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 42%;
  background: linear-gradient(180deg,
    rgba(8, 10, 14, 0) 0%,
    rgba(8, 10, 14, .05) 36%,
    rgba(8, 10, 14, .16) 60%,
    rgba(8, 10, 14, .32) 82%,
    rgba(8, 10, 14, .44) 100%);
  pointer-events: none;
}

/* the ask, in the app's own black, small */
.does-ask {
  position: absolute;
  z-index: 2;
  left: var(--in);
  top: var(--in);
  max-width: calc(100% - 2 * var(--in));
  padding: .52em var(--pad);
  border-radius: 999px;
  background: rgba(18, 19, 22, .86);
  -webkit-backdrop-filter: blur(8px) saturate(140%);
          backdrop-filter: blur(8px) saturate(140%);
  color: #F2F3F5;
  font-size: var(--fs);
  font-weight: 450;
  letter-spacing: -.012em;
  line-height: 1.3;
}

/* one glass strip at the foot, and it belongs to the card in front */
.does-strip {
  position: absolute;
  z-index: 2;
  left: var(--in);
  right: var(--in);
  bottom: var(--in);
  display: flex;
  align-items: center;
  gap: .6em;
  /* two lines are always kept, so a line that wraps never resizes the strip
     and a swap moves nothing but the words */
  height: calc(2 * 1.3em + 1em);
  padding: 0 var(--pad);
  border-radius: calc(var(--r-card) - var(--in));   /* concentric with the card's corner */
  /* the glass is nine tenths opaque, so twelve pixels of blur behind it says
     everything twenty said and asks the phone for a third of the work */
  background: rgba(255, 255, 255, .9);
  -webkit-backdrop-filter: blur(12px) saturate(160%);
          backdrop-filter: blur(12px) saturate(160%);
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, .9),
    0 0 0 1px rgba(255, 255, 255, .4),
    0 10px 26px -12px rgba(8, 10, 14, .6);
  font-size: var(--fs);
  color: var(--ink);
  opacity: 0;
  transition: opacity .24s var(--ease);
}
@media (min-resolution: 2dppx) {
  .does-strip {
    box-shadow:
      inset 0 .5px 1px rgba(255, 255, 255, .9),
      0 0 0 .5px rgba(255, 255, 255, .45),
      0 10px 26px -12px rgba(8, 10, 14, .6);
  }
}
/* the leaving strip is gone before the arriving one starts, so there is never
   a moment with two of them on the screen */
.does-card.is-centre .does-strip { opacity: 1; transition: opacity .42s var(--ease) .3s; }

.does-dot {
  position: relative;
  flex: 0 0 auto;
  width: .58em;
  height: .58em;
  border-radius: 50%;
  background: var(--good);
}
/* the live blue is a second dot over the green one, so the change of state is
   a cross fade and not a snap, and only opacity moves */
.does-dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--live);
  opacity: 0;
  transition: opacity .3s var(--ease);
}
.does-card.is-run .does-dot::after { opacity: 1; }

.does-say {
  flex: 1 1 auto;
  min-width: 0;
  max-height: 2.6em;
  overflow: hidden;
  letter-spacing: -.012em;
  line-height: 1.3;
  font-variant-numeric: tabular-nums;   /* times and amounts keep one column */
}
.does-card.is-run .does-say { padding-right: var(--livew, 4.9em); }

/* what only exists while a task is in flight: the line it is listening to and
   the way to stop it. Finished, the strip is one line and a quiet dot. */
.does-live {
  position: absolute;
  top: 0;
  bottom: 0;
  right: var(--pad);
  display: flex;
  align-items: center;
  gap: .55em;
  opacity: 0;
  pointer-events: none;
  transition: opacity .3s var(--ease);
}
.does-card.is-run .does-live { opacity: 1; }
.does-live .wave { height: 1.05em; gap: .13em; }
.does-live .wave i { width: .13em; }
.does-live .app-stop { height: 2.1em; font-size: max(12px, calc(var(--fs) - 1px)); }

/* ---------- her ---------- */

/* She sits on the top edge of the card in front, at its right shoulder, clear
   of the ask on its left. Her box is the mark's 64 units; the ring's foot is
   at 55.1 of them, and it goes 5px into the card so she sits, not floats. */
.does-ola {
  position: absolute;
  z-index: 6;
  left: calc(50% + var(--cw) / 2 - 20px - var(--ob) * .861);
  top: calc(var(--ob) * -.861 + 8px);
  width: var(--ob);
  height: var(--ob);
  cursor: default;
  -webkit-tap-highlight-color: transparent;
}
.does-ola-hop, .does-ola-ring, .does-ola-face, .does-ola-lids, .does-ola-cheeks { position: absolute; inset: 0; }
.does-ola-hop { transform-origin: 50% 86%; }
.does-ola svg { width: 100%; height: 100%; overflow: visible; }
.does-ola-ring circle { fill: var(--ground); stroke: var(--ink); stroke-width: 6.6; }
.does-ola-lids circle { fill: var(--ink); }
.does-ola-cheeks circle { fill: var(--ground); }
/* where she looks, set by the script in the mark's own units */
.does-ola-face { transition: transform .5s var(--settle, var(--ease)); }
.does-ola-lids { transform-origin: 50% 48.125%; }
/* a smile is the lower lids rising, worn briefly */
.does-ola-cheeks { opacity: 0; transition: transform .34s var(--ease), opacity 0s linear .34s; }
.does-ola.is-happy .does-ola-cheeks { opacity: 1; transform: translateY(-8.125%); transition: transform .34s var(--ease), opacity 0s; }
/* her size goes with the card's, and the ring keeps the room she sits in */
.does-ring {
  --ob: clamp(76px, calc(var(--cw) * .235), 104px);
  margin-top: calc(clamp(28px, 3vw, 44px) + var(--ob) * .861 - 8px);
}

/* where you are among the thirteen */
.does-rail {
  position: relative;
  width: min(300px, 62%);
  height: 3px;
  margin: clamp(26px, 3vw, 40px) auto 0;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(20, 21, 25, .08);
}
/* thirteen whole pixels wide, so the one moving segment is a whole pixel too */
@supports (width: round(down, 6px, 3px)) {
  .does-rail { width: round(down, min(300px, 62%), 26px); }
}
.does-seg {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: calc(100% / var(--n, 13));
  border-radius: inherit;
  background: rgba(20, 21, 25, .58);
  transition: transform .9s var(--ease);
}

/* ---------- alive ---------- */

@keyframes does-ken { to { transform: scale(1.06); } }
@keyframes does-beat { 50% { transform: scale(.6); } }

.does-shot img {
  animation: does-ken 14s ease-in-out var(--ken, 0s) infinite alternate;
  animation-play-state: paused;   /* paused holds its value, so nothing jumps when it runs */
  transition: scale .6s var(--ease);
}
.does.is-seen .does-card.is-centre .does-shot img { animation-play-state: running; }
/* the whole dot beats, not the blue over the green, or the one under it
   would show as a ring every time the beat shrank the one on top */
.does.is-seen .does-card.is-run .does-dot { animation: does-beat 1.5s ease-in-out infinite; }
.does.is-seen .does-card.is-run .wave i { animation: wave var(--wt, 1.1s) ease-in-out var(--wd, 0s) infinite; }

@media (hover: hover) {
  .does-card::after { transition: opacity .4s var(--ease); }
  .does-card.is-centre:hover::after { opacity: 1; }
  .does-card.is-centre:hover .does-shot img { scale: 1.03; }
  .does-card.is-left:hover, .does-card.is-right:hover { filter: blur(1px) saturate(.92) brightness(.96); }
  .does-card.is-left:hover::before, .does-card.is-right:hover::before { opacity: .06; }
}

/* ---------- the phone ---------- */

@media (max-width: 899px) {
  .does-ring {
    --cw: min(78vw, 360px);
    perspective: 1100px;
    width: calc(100% + 2 * var(--gutter));
    margin-inline: calc(-1 * var(--gutter));
  }
  .does-card.is-left { transform: translateX(calc(var(--cw) * -.82)) scale(.86) rotateY(6deg); }
  .does-card.is-right { transform: translateX(calc(var(--cw) * .82)) scale(.86) rotateY(-6deg); }
  .does-card.is-far-left { transform: translateX(calc(var(--cw) * -1.35)) scale(.72) rotateY(9deg); }
  .does-card.is-far-right { transform: translateX(calc(var(--cw) * 1.35)) scale(.72) rotateY(-9deg); }
  .does-rail { width: min(220px, 64%); }
  @supports (width: round(down, 6px, 3px)) {
    .does-ring { --cw: round(down, min(78vw, 360px), 6px); }
    .does-rail { width: round(down, min(220px, 64%), 26px); }
  }
}

/* ---------- refused, still ---------- */

.is-still .does-shot img, .is-still .does-dot, .is-still .wave i { animation: none; }
.is-still .does-say, .is-still .does-card, .is-still .does-seg, .is-still .does-strip,
.is-still .does-card::before, .is-still .does-card::after, .is-still .does-dot::after,
.is-still .does-live, .is-still .does-ola-face, .is-still .does-ola-cheeks { transition: none; }

/* the turn keeps its places and loses its travel: the cards cross over */
@media (prefers-reduced-motion: reduce) {
  .does-card { transition: opacity .3s var(--ease); }
  .does-card.is-hidden { transition: opacity .3s var(--ease), visibility 0s .3s; }
  .does-shot img { animation: none; transition: none; }
  .does-card::before { transition: opacity .3s var(--ease); }
  .does-say, .does-live, .does-strip, .does-seg, .does-card::after, .does-dot::after, .does-ola-face, .does-ola-cheeks { transition: none; }
  .does.is-seen .does-card.is-run .does-dot, .does.is-seen .does-card.is-run .wave i { animation: none; }
}

/* ---------- apps ---------- */

/* apps: one phone, three apps. Each is asked for and built into its own
   blueprint, then a second ask and Ola uses it. Glanceable, not readable: an
   app says its name, one number and one short line; everything else is shape
   and motion. The chips choose. */

/* Beside the device the words start where the device starts: the heading's cap
   line and the top of the phone are one line. The column is a compact block at
   that line, on one rhythm: 24 between rows, 48 under the heading block. */
.apps-stage {
  display:grid;
  grid-template-columns:minmax(0,1fr) auto;
  grid-template-areas:"head  dev" "ask   dev" "chips dev" ".     dev";
  grid-template-rows:auto auto auto 1fr;
  gap:24px clamp(32px,6vw,88px);
  align-items:start;
}
.apps-head { grid-area:head;margin-bottom:24px;}
/* line-height is 1, so the cap of the heading sits 0.137em below its box: lift
   the box by exactly that and the cap line meets the top of the device */
.apps-head .h2 { margin-top:-0.137em;}
.apps-asks { grid-area:ask;display:grid;justify-items:start;width:100%;container-type:inline-size;}
/* the longest thing any of the three will ever say, holding the column's
   height open so a two line ask never moves the phone or the chips */
.apps-gauge { visibility:hidden;pointer-events:none;}

.apps-ask {
  grid-area:1 / 1;--t:clamp(0,(100cqw - 290px) / 250px,1);
  min-height:calc(58px + 13px * var(--t));
  padding-left:calc(24px + 6px * var(--t));font-size:calc(16.5px + 4.5px * var(--t));
}
.apps-ask .voicekey { width:calc(42px + 10px * var(--t));height:calc(42px + 10px * var(--t));}
/* typed over a hidden copy of the sentence, so nothing reflows */
.apps-line { display:grid;}
.apps-line > span { grid-area:1 / 1;}
.apps-ghost { visibility:hidden;}
.apps-line.is-typing .apps-typed::after {
  content:"";display:inline-block;width:2px;height:1.05em;margin-left:2px;
  vertical-align:-0.16em;background:currentColor;animation:apps-caret 1.02s steps(1,end) infinite;
}
@keyframes apps-caret { 0%,52% { opacity:1;} 53%,100% { opacity:0;} }

/* ---------- the phone, drawn in one unit ---------- */

/* inside the phone everything is drawn in --u, one point of a 356 wide device,
   and its multiples (--8 is eight units); a caption never goes under 12px */
@property --u { syntax:"<length>";inherits:true;initial-value:1px;}
.apps-dev { grid-area:dev;}
.apps-dev .phone { --pw:clamp(300px,29vw,356px);}
.apps-dev .phone-screen {
  --t:clamp(0,(100cqw - 280px) / 76px,1);
  --u:calc(0.96px + 0.107px * var(--t));
  font-size:var(--15);
  font-variant-numeric:tabular-nums;
  --hl:0 0 0 .5px rgba(0,0,0,.08);
  --line:rgba(20,21,25,.30);
  --line-2:rgba(20,21,25,.13);
  --fill:rgba(20,21,25,.055);
  --lift:0 0 0 .5px rgba(20,21,25,.06),0 calc(var(--u)*2) calc(var(--u)*4) rgba(20,21,25,.03),0 calc(var(--u)*10) calc(var(--u)*24) rgba(20,21,25,.06);
  --2: calc(var(--u)*2);--4: calc(var(--u)*4);--6: calc(var(--u)*6);--8: calc(var(--u)*8);--10: calc(var(--u)*10);--12: calc(var(--u)*12);--13: calc(var(--u)*13);--14: calc(var(--u)*14);--15: calc(var(--u)*15);--16: calc(var(--u)*16);--18: calc(var(--u)*18);--20: calc(var(--u)*20);--22: calc(var(--u)*22);--24: calc(var(--u)*24);--28: calc(var(--u)*28);--32: calc(var(--u)*32);--36: calc(var(--u)*36);
}
/* the status bar stands over a map that runs under it */
.apps-dev .phone-status { position:relative;z-index:3;height:calc(var(--u)*50);}
.apps-dev .phone-home { z-index:7;}
.apps-body { display:grid;grid-template-rows:minmax(0,1fr);padding:var(--8) var(--16) var(--24);overflow:visible;}

/* ---------- three apps on one screen ---------- */

.apps-app {
  --acc:var(--live);--tint:color-mix(in srgb,var(--acc) 13%,#fff);
  grid-area:1 / 1;display:flex;flex-direction:column;min-height:0;gap:var(--12);
  opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity .42s var(--ease),transform .42s var(--ease),visibility 0s linear .42s;
}
.apps-dev:not([data-app]) .apps-app-a,
.apps-dev[data-app="a"] .apps-app-a,
.apps-dev[data-app="b"] .apps-app-b,
.apps-dev[data-app="c"] .apps-app-c { opacity:1;visibility:visible;transform:none;transition-delay:0s;}
/* the plant doctor's photograph is fetched once the app before it is on the
   phone (or it is chosen), not with the page */
.apps-dev:not([data-app="b"]):not([data-app="c"]) .apps-app-c:not(.is-going) .apps-photo img { display:none;}
/* the app leaving keeps the screen until the next has something on it */
.apps-dev .apps-app.is-going {
  visibility:visible;opacity:0;transform:translateY(-8px) scale(.985);
  transition:opacity .24s var(--ease),transform .3s var(--ease);
}
/* while the stage plays, the arriving app carries no fade of its own: its
   pieces do the arriving, so the two apps are never both readable */
.apps-stage.is-playing .apps-app { transition:none;}
.apps-stage.is-playing .apps-app.is-going { transition:opacity .2s var(--ease),transform .34s var(--ease);}

.apps-run { --acc:var(--good);}
.apps-plant { --acc:#4F8F62;--water:var(--live);}

/* ---------- the blueprint ---------- */

/* every piece stands in a slot, and while she builds, the slot's outline is
   drawn first and the piece lands in it */
.apps-slot { position:relative;flex:0 0 auto;}
.apps-slot::after {
  content:"";position:absolute;inset:0;border:1px dashed rgba(44,99,210,.34);border-radius:var(--r,var(--20));
  background:rgba(44,99,210,.045);opacity:0;pointer-events:none;
}
.apps-slot.is-head { --r:var(--12);}
.apps-slot.is-pill { --r:999px;}
.apps-slot.is-bleed { --r:0;}
.apps-slot.is-sheet { --r:var(--24) var(--24) 0 0;}
.apps-stage.is-playing .apps-dev.is-building .apps-slot::after { opacity:1;transition:opacity .3s var(--ease) calc(90ms + var(--o,0) * 80ms);}
.apps-stage.is-playing .apps-dev.is-building .apps-slot:has(> .apps-part.on)::after { opacity:0;transition:opacity .22s var(--ease);}

/* ---------- what every app is made of ---------- */

/* the app's own header: its icon, which Ola signs, and its name */
.apps-top { display:flex;align-items:center;gap:var(--10);height:calc(var(--u)*40);}
.apps-icon {
  position:relative;flex:0 0 auto;display:grid;place-items:center;width:var(--36);height:var(--36);
  border-radius:calc(var(--u)*11);color:#fff;
  background:linear-gradient(155deg,color-mix(in srgb,var(--acc) 72%,#fff),var(--acc) 72%);
  box-shadow:inset 0 0 0 .5px rgba(255,255,255,.28),0 calc(var(--u)*3) calc(var(--u)*8) calc(var(--u)*-2) color-mix(in srgb,var(--acc) 60%,transparent);
}
.apps-icon > svg { width:var(--20);height:var(--20);}
.apps-badge {
  position:absolute;right:calc(var(--u)*-5);bottom:calc(var(--u)*-5);display:grid;place-items:center;
  width:var(--18);height:var(--18);border-radius:50%;background:#fff;color:var(--ink);
  box-shadow:0 0 0 calc(var(--u)*1.5) #F3F4F6,0 var(--u) calc(var(--u)*3) rgba(0,0,0,.2);
}
.apps-badge svg { width:var(--14);height:var(--14);}
.apps-name { font-size:var(--22);line-height:var(--28);font-weight:600;letter-spacing:-0.028em;white-space:nowrap;}

/* words drawn as bars: a title and the line under it, their lengths in units */
.apps-lines { display:grid;gap:calc(var(--u)*7);justify-items:start;min-width:0;}
.apps-lines i { display:block;width:calc(var(--w) * var(--u));max-width:100%;height:var(--10);border-radius:999px;background:var(--line);}
.apps-lines i + i { height:var(--8);background:var(--line-2);}

.apps-card { background:#fff;border-radius:var(--20);box-shadow:var(--lift);}
.apps-ico { flex:0 0 auto;display:grid;place-items:center;width:var(--32);height:var(--32);border-radius:50%;background:var(--tint);color:var(--acc);}
.apps-ico svg { width:var(--16);height:var(--16);}
.apps-dev svg.apps-chev { flex:0 0 auto;width:var(--16);height:var(--16);color:var(--bar-3);margin-left:auto;}
.apps-grab { flex:0 0 auto;align-self:center;width:calc(var(--u)*36);height:var(--4);border-radius:999px;background:var(--bar);}
.apps-sheet-top { display:flex;align-items:center;justify-content:space-between;margin-top:var(--10);}
.apps-chip-shape { display:grid;place-items:center;width:calc(var(--u)*54);height:var(--24);border-radius:999px;background:var(--fill);}
.apps-chip-shape::after { content:"";width:var(--24);height:var(--6);border-radius:999px;background:var(--line-2);}
.apps-dev em { font-style:normal;}

/* Ola's own touch: a little Ola that comes up to the thing, presses it and
   goes. It sits a little under the point, the way a fingertip does, so what
   it presses stays in sight. */
.apps-tap {
  position:absolute;z-index:6;left:var(--x,50%);top:var(--y,50%);
  width:calc(var(--u)*40);height:calc(var(--u)*40);margin:calc(var(--u) * var(--ty,-10)) 0 0 calc(var(--u) * var(--tx,-12));pointer-events:none;
}
.apps-press {
  display:grid;place-items:center;width:100%;height:100%;border-radius:50%;background:#fff;color:var(--ink);
  box-shadow:0 0 0 .5px rgba(20,21,25,.12),0 var(--2) var(--4) rgba(20,21,25,.14),0 var(--8) var(--18) calc(var(--u)*-4) rgba(20,21,25,.34);
}
.apps-press svg { width:calc(var(--u)*29);height:calc(var(--u)*29);}
.apps-ripple {
  position:absolute;z-index:5;left:var(--x,50%);top:var(--y,50%);width:calc(var(--u)*44);height:calc(var(--u)*44);
  margin:calc(var(--u)*-22);border-radius:50%;border:var(--2) solid var(--acc);opacity:0;pointer-events:none;
}

/* building: the island opens into a live activity, Ola in it, one line and a
   turning ring. It is drawn in the island's own em (the screen's type size),
   as two round ends and the black between them, so opening it is a travel and
   a stretch of plain black: the ends stay round the whole way. */
.apps-building {
  position:absolute;z-index:6;top:.6875em;left:50%;width:13em;height:2.25em;margin-left:-6.5em;
  pointer-events:none;color:#fff;
}
.apps-isl { position:absolute;top:0;height:100%;background:#08090B;}
.apps-isl.is-l,.apps-isl.is-r { width:2.25em;border-radius:50%;}
.apps-isl.is-l { left:0;}
.apps-isl.is-r { right:0;}
.apps-isl.is-m { left:1.125em;right:1.125em;}
.apps-isl-in {
  position:absolute;inset:0;display:flex;align-items:center;gap:.5em;padding:0 .62em 0 .5em;
  font-size:.84em;font-weight:500;letter-spacing:-0.005em;white-space:nowrap;
}
.apps-isl-in > svg { flex:0 0 auto;width:1.6em;height:1.6em;}
.apps-spin { flex:0 0 auto;width:1.15em;height:1.15em;margin-left:auto;border-radius:50%;border:.17em solid rgba(255,255,255,.22);border-top-color:#fff;}
@keyframes apps-turn { to { transform:rotate(360deg);} }
/* the status bar steps aside while the island is open, and comes back once
   it has closed */
.apps-dev .phone-status > * { transition:opacity .3s var(--ease) .42s;}
.apps-stage.is-playing .apps-dev.is-building .phone-status > * { opacity:0;transition-delay:0s;}

/* ---------- a running coach ---------- */

.apps-run .is-map { flex:1 1 auto;min-height:calc(var(--u)*110);}
.apps-map { position:relative;height:100%;overflow:hidden;contain:paint;border-radius:var(--20);box-shadow:var(--hl);}
.apps-map > svg { position:absolute;inset:0;width:100%;height:100%;}
.apps-map svg { color:var(--acc);}
.apps-runner { transform:translate(138px,146px);}

/* the one number the run reports, in a strip on the map */
.apps-stats {
  position:absolute;left:var(--10);top:var(--10);display:flex;align-items:center;gap:var(--14);
  padding:var(--8) var(--14) var(--8) var(--12);border-radius:var(--14);
  background:rgba(255,255,255,.95);box-shadow:0 0 0 .5px rgba(0,0,0,.06),0 var(--4) var(--12) calc(var(--u)*-4) rgba(20,21,25,.2);
}
.apps-num { display:flex;align-items:baseline;gap:var(--2);}
.apps-num b { font-size:var(--24);line-height:var(--28);font-weight:600;letter-spacing:-0.03em;}
.apps-num i { font-style:normal;font-size:var(--13);font-weight:500;color:var(--ink-body);}
.apps-stat { display:grid;gap:calc(var(--u)*6);padding-left:var(--14);border-left:.5px solid rgba(0,0,0,.1);}
.apps-stat i { display:block;width:calc(var(--w) * var(--u));height:var(--8);border-radius:999px;background:var(--line);}
.apps-stat i + i { height:var(--6);background:var(--line-2);}

.apps-low { position:relative;flex:0 0 auto;height:calc(var(--u)*196);display:flex;flex-direction:column;gap:var(--12);}
.apps-low .is-card { flex:1 1 auto;}
.apps-low .is-pill { height:calc(var(--u)*48);}
/* the run's heart, as zones: one bar in four shades of the app's colour, and
   the four figures under it drawn as bars */
.apps-zones { height:100%;display:flex;flex-direction:column;justify-content:space-between;gap:var(--12);padding:var(--14) var(--16) var(--16);}
.apps-zones-top { display:flex;align-items:center;gap:var(--10);}
.apps-zbar { display:flex;gap:calc(var(--u)*3);height:var(--12);}
.apps-zbar i { flex:var(--z) 1 0;border-radius:999px;transform-origin:0 50%;}
.apps-zbar i:nth-child(1),.apps-zkey i:nth-child(1)::before { background:color-mix(in srgb,var(--acc) 28%,#fff);}
.apps-zbar i:nth-child(2),.apps-zkey i:nth-child(2)::before { background:color-mix(in srgb,var(--acc) 52%,#fff);}
.apps-zbar i:nth-child(3),.apps-zkey i:nth-child(3)::before { background:var(--acc);}
.apps-zbar i:nth-child(4),.apps-zkey i:nth-child(4)::before { background:color-mix(in srgb,var(--acc) 72%,#141519);}
.apps-zkey { display:grid;grid-template-columns:repeat(4,1fr);gap:var(--8);}
.apps-zkey i { display:flex;align-items:center;gap:var(--6);}
.apps-zkey i::before { content:"";flex:0 0 auto;width:var(--8);height:var(--8);border-radius:50%;}
.apps-zkey i::after { content:"";width:calc(var(--u)*26);height:var(--8);border-radius:999px;background:var(--line-2);}

/* the button she presses */
.apps-cta {
  position:relative;display:flex;align-items:center;justify-content:center;gap:var(--10);height:100%;
  border-radius:999px;background:var(--acc);color:#fff;
  box-shadow:inset 0 0 0 .5px rgba(255,255,255,.2),0 var(--4) var(--12) calc(var(--u)*-4) color-mix(in srgb,var(--acc) 70%,transparent);
}
.apps-cta > svg { width:var(--18);height:var(--18);}
.apps-cta > i:not([class]) { width:calc(var(--u)*66);height:var(--10);border-radius:999px;background:rgba(255,255,255,.88);}
/* the button answers her press: a light over it that is gone at once */
.apps-flash { position:absolute;inset:0;border-radius:inherit;background:#fff;opacity:0;pointer-events:none;}

/* the plan rises over the run as a sheet, and climbs to a flag */
.apps-sheet {
  position:absolute;z-index:3;left:calc(var(--u)*-16);right:calc(var(--u)*-16);top:calc(var(--u)*-30);bottom:calc(var(--u)*-24);
  display:flex;flex-direction:column;padding:var(--8) var(--16) var(--24);
  background:#fff;border-radius:var(--24) var(--24) 0 0;
  box-shadow:0 -.5px 0 rgba(0,0,0,.07),0 calc(var(--u)*-10) calc(var(--u)*30) calc(var(--u)*-14) rgba(20,21,25,.24);
}
.apps-plot { position:relative;flex:1 1 auto;min-height:calc(var(--u)*56);margin:var(--16) 0 var(--12);}
.apps-chart { position:absolute;inset:0;overflow:hidden;}
.apps-chart-in { position:absolute;inset:0;}
.apps-chart svg { position:absolute;inset:0;width:100%;height:100%;overflow:visible;color:var(--acc);}
.apps-wk,.apps-now {
  position:absolute;left:var(--x);top:var(--y);width:calc(var(--u)*7);height:calc(var(--u)*7);margin:calc(var(--u)*-3.5);
  border-radius:50%;background:#fff;box-shadow:inset 0 0 0 calc(var(--u)*1.6) color-mix(in srgb,var(--acc) 55%,#fff);
}
.apps-now {
  width:var(--12);height:var(--12);margin:calc(var(--u)*-6);background:var(--acc);
  box-shadow:0 0 0 calc(var(--u)*2.5) #fff,0 0 0 calc(var(--u)*6) color-mix(in srgb,var(--acc) 22%,transparent);
}
.apps-flag {
  position:absolute;left:var(--x);top:var(--y);width:var(--24);height:var(--24);
  margin:calc(var(--u)*-22) 0 0 calc(var(--u)*-5);color:var(--ink);transform-origin:21% 92%;
}
.apps-flag svg { width:100%;height:100%;fill:currentColor;}
.apps-next { flex:0 0 auto;display:flex;align-items:center;gap:var(--12);padding-top:var(--12);border-top:.5px solid rgba(0,0,0,.09);}
.apps-next b { font-size:var(--16);line-height:var(--20);font-weight:600;letter-spacing:-0.014em;white-space:nowrap;}

/* ---------- a trip planner ---------- */

/* the city runs to the edges of the glass and under the status bar; the day
   is a sheet over its foot */
.apps-trip { gap:0;}
.apps-trip .is-bleed { flex:1 1 auto;min-height:calc(var(--u)*150);margin:calc(var(--u)*-58) calc(var(--u)*-16) 0;}
.apps-trip .apps-map { border-radius:0;box-shadow:none;container-type:size;}
.apps-canvas { position:absolute;left:50%;top:50%;width:max(100cqw,85cqh);aspect-ratio:340 / 400;transform:translate(-50%,-50%);}
.apps-canvas > svg { position:absolute;inset:0;width:100%;height:100%;}
.apps-float {
  position:absolute;z-index:2;left:var(--16);top:calc(var(--u)*60);display:flex;align-items:center;gap:var(--10);
  height:calc(var(--u)*48);padding:0 var(--18) 0 var(--6);border-radius:999px;
  background:rgba(255,255,255,.94);box-shadow:0 0 0 .5px rgba(0,0,0,.06),0 var(--6) var(--18) calc(var(--u)*-6) rgba(20,21,25,.28);
}
.apps-float .apps-name { font-size:var(--20);line-height:var(--24);}
.apps-locate {
  position:absolute;z-index:2;right:var(--16);top:calc(var(--u)*62);display:grid;place-items:center;
  width:calc(var(--u)*44);height:calc(var(--u)*44);border-radius:50%;color:var(--acc);
  background:rgba(255,255,255,.94);box-shadow:0 0 0 .5px rgba(0,0,0,.06),0 var(--6) var(--18) calc(var(--u)*-6) rgba(20,21,25,.28);
}
.apps-locate svg { width:var(--18);height:var(--18);}

/* a pin: the drop stands on its point, its shadow on the ground under it */
.apps-pin { position:absolute;left:var(--x);top:var(--y);}
.apps-pin::after {
  content:"";position:absolute;left:calc(var(--u)*-7);top:calc(var(--u)*-3);width:var(--14);height:var(--6);
  border-radius:50%;background:rgba(20,21,25,.24);filter:blur(1px);
}
.apps-pin > i { position:absolute;z-index:1;left:calc(var(--u)*-12);top:calc(var(--u)*-29);display:grid;place-items:center;width:var(--24);height:var(--24);}
.apps-pin > i::before {
  content:"";position:absolute;inset:0;border-radius:50% 50% 50% 0;transform:rotate(-45deg);background:var(--acc);
  box-shadow:0 0 0 calc(var(--u)*2.5) #fff,calc(var(--u)*-2) calc(var(--u)*3) calc(var(--u)*8) rgba(20,21,25,.26);
}
.apps-pin > i::after { content:"";position:relative;width:var(--8);height:var(--8);border-radius:50%;background:#fff;}
.apps-pin.is-sun > i { left:calc(var(--u)*-15);top:calc(var(--u)*-36);width:calc(var(--u)*30);height:calc(var(--u)*30);color:#fff;}
.apps-pin.is-sun > i::before { background:linear-gradient(135deg,#F8C27E,#EE9744);}
.apps-pin.is-sun > i::after { content:none;}
.apps-pin.is-sun svg { position:relative;width:var(--16);height:var(--16);color:#fff;}

.apps-trip .is-sheet { flex:0 0 auto;z-index:2;margin:calc(var(--u)*-24) calc(var(--u)*-16) calc(var(--u)*-24);}
.apps-tsheet {
  display:flex;flex-direction:column;padding:var(--8) var(--16) var(--24);background:#fff;border-radius:var(--24) var(--24) 0 0;
  box-shadow:0 -.5px 0 rgba(0,0,0,.06),0 calc(var(--u)*-10) calc(var(--u)*30) calc(var(--u)*-14) rgba(20,21,25,.24);
}

/* the day: a time, the walk between stops, a picture of the place, two lines */
.apps-day { display:grid;margin-top:var(--8);}
.apps-day > li:not(.apps-mover),.apps-mover > span {
  position:relative;display:grid;grid-template-columns:calc(var(--u)*30) var(--12) var(--36) minmax(0,1fr) auto;
  align-items:center;column-gap:var(--10);height:calc(var(--u)*50);
}
.apps-tt { width:calc(var(--u)*28);height:var(--8);border-radius:999px;background:var(--line-2);}
.apps-rail { position:relative;align-self:stretch;}
.apps-rail::before { content:"";position:absolute;left:50%;top:0;bottom:0;width:1.5px;margin-left:-.75px;background:var(--bar);}
.apps-rail::after {
  content:"";position:absolute;left:50%;top:50%;width:var(--10);height:var(--10);margin:calc(var(--u)*-5);
  border-radius:50%;background:#fff;box-shadow:inset 0 0 0 calc(var(--u)*2) var(--acc);
}
.apps-day > li:first-child .apps-rail::before { top:50%;}
.apps-mover .apps-rail::before { bottom:50%;}
.apps-thumb { width:var(--36);height:var(--36);border-radius:var(--10);background:var(--th,var(--fill));}
.apps-new { margin:0 calc(var(--u)*-8);padding:0 var(--8);border-radius:var(--14);background:#FDF3E8;}
.apps-new .apps-tt { background:rgba(214,132,56,.34);}
.apps-new .apps-rail::after { background:#EE9744;box-shadow:0 0 0 calc(var(--u)*3) rgba(238,151,68,.22);}
.apps-thumb.is-sunset { position:relative;overflow:hidden;background:linear-gradient(180deg,#FBE0B4 0%,#F6B574 62%,#F09A52 100%);}
.apps-thumb.is-sunset i { position:absolute;left:50%;bottom:calc(var(--u)*-7);width:var(--16);height:var(--16);margin-left:calc(var(--u)*-8);border-radius:50%;background:#FFF6E6;box-shadow:0 0 var(--8) rgba(255,246,230,.9);}
.apps-new b { font-size:var(--16);line-height:var(--20);font-weight:600;letter-spacing:-0.014em;white-space:nowrap;}
.apps-time {
  display:inline-grid;place-items:center;height:var(--24);padding:0 var(--10);border-radius:999px;background:#fff;
  font-size:var(--13);font-weight:600;color:var(--ink);box-shadow:0 0 0 .5px rgba(0,0,0,.08),0 var(--2) var(--6) rgba(20,21,25,.08);
}

/* ---------- a plant doctor ---------- */

.apps-plant .is-view { flex:1 1 auto;min-height:calc(var(--u)*110);}
/* the photograph is lazy, so a blur of it stands in until it lands; the marks
   sit on the picture itself, so they stay on the leaves at any crop */
.apps-view {
  position:relative;height:100%;overflow:hidden;contain:paint;border-radius:var(--20);container-type:size;
  background:var(--plate) 50% / cover no-repeat;
}
/* its crop leans toward the damaged leaves: the picture is placed so that a
   point a little right of its centre stands at the window's centre, held so
   the picture always covers the window */
.apps-photo {
  --wc:max(100cqw,150.06cqh);
  position:absolute;top:50%;width:var(--wc);aspect-ratio:1280 / 853;transform:translateY(-50%);
  left:clamp(calc(100cqw - var(--wc)),calc(50cqw - var(--wc) * .56),0px);
}
.apps-photo img { width:100%;height:100%;object-fit:cover;}
.apps-frame { position:absolute;inset:0;width:100%;height:100%;stroke-width:calc(var(--u)*2.4);}
.apps-scan {
  position:absolute;left:0;right:0;top:0;height:42%;opacity:0;pointer-events:none;
  background:linear-gradient(180deg,rgba(255,255,255,0),rgba(255,255,255,.16) 70%,rgba(255,255,255,.62));
}
@keyframes apps-sweep { 0% { transform:translateY(-100%);opacity:0;} 16%,84% { opacity:1;} 100% { transform:translateY(240%);opacity:0;} }
.apps-spot {
  position:absolute;left:var(--x);top:var(--y);width:var(--20);height:var(--20);margin:calc(var(--u)*-10);
  border-radius:50%;border:var(--2) solid #fff;background:rgba(242,193,78,.34);box-shadow:0 var(--u) var(--6) rgba(0,0,0,.4);
}
.apps-spot::after { content:"";position:absolute;inset:calc(var(--u)*-2);border-radius:50%;border:var(--2) solid #fff;opacity:0;}
@keyframes apps-ping { 0% { transform:scale(1);opacity:.9;} 100% { transform:scale(2.3);opacity:0;} }

.apps-dx { display:flex;flex-direction:column;gap:var(--12);padding:var(--14) var(--16) var(--16);}
.apps-dx-top { display:flex;align-items:baseline;justify-content:space-between;gap:var(--8);}
.apps-l,.apps-pct { font-size:var(--20);line-height:var(--24);font-weight:600;letter-spacing:-0.024em;}
.apps-pct { color:var(--acc);}
.apps-pct b { font-weight:inherit;}
.apps-meter { display:block;height:var(--6);border-radius:999px;background:var(--bar);overflow:hidden;}
.apps-meter i { display:block;width:92%;height:100%;border-radius:inherit;background:var(--acc);transform-origin:0 50%;}
.apps-care { display:grid;gap:var(--8);margin-top:var(--2);}
.apps-care > span { display:flex;align-items:center;gap:var(--10);}
.apps-care i:not(.apps-dot) { display:block;width:calc(var(--w) * var(--u));height:var(--8);border-radius:999px;background:var(--line-2);}
.apps-dot { flex:0 0 auto;display:grid;place-items:center;width:var(--24);height:var(--24);border-radius:50%;background:var(--tint);color:var(--acc);}
.apps-dot svg { width:var(--14);height:var(--14);}

.apps-remind { display:flex;flex-direction:column;gap:var(--12);padding:var(--12) var(--14) var(--14) var(--12);}
.apps-remind-top { display:flex;align-items:center;gap:var(--10);}
.apps-remind-top .apps-ico { background:color-mix(in srgb,var(--water) 12%,#fff);color:var(--water);}
.apps-remind-top .apps-lines { flex:1 1 auto;}
/* the switch she turns on */
.apps-switch { position:relative;flex:0 0 auto;width:calc(var(--u)*46);height:var(--28);border-radius:999px;background:var(--bar);}
.apps-switch-on { position:absolute;inset:0;border-radius:inherit;background:var(--water);}
.apps-knob {
  position:absolute;left:var(--2);top:var(--2);width:var(--24);height:var(--24);border-radius:50%;background:#fff;
  box-shadow:0 0 0 .5px rgba(0,0,0,.05),0 var(--2) var(--6) rgba(0,0,0,.22);transform:translateX(var(--18));
}
.apps-switch .apps-ripple { border-color:var(--water);}
.apps-days { display:grid;grid-template-columns:repeat(7,1fr);}
.apps-days > span { position:relative;display:flex;flex-direction:column;align-items:center;gap:var(--6);}
.apps-days em { font-size:var(--12);line-height:var(--14);color:var(--ink-quiet);}
.apps-days > span:has(.apps-drop) em { color:var(--ink);font-weight:600;}
.apps-days i { width:var(--8);height:var(--8);border-radius:50%;background:var(--bar);}
.apps-drop {
  position:absolute;left:50%;bottom:calc(var(--u)*-5);display:grid;place-items:center;width:var(--18);height:var(--18);
  margin-left:calc(var(--u)*-9);border-radius:50%;background:var(--water);color:#fff;
  box-shadow:0 0 0 calc(var(--u)*3) color-mix(in srgb,var(--water) 18%,transparent);
}
.apps-drop svg { width:calc(var(--u)*11);height:calc(var(--u)*11);fill:currentColor;}

/* ---------- the clock ---------- */

/* one clock: parts are `.apps-part`, driven by apps.js. Never blank: ordinary
   css is the finished frame; only `.is-playing` steps a part back to where it
   arrives from. `data-how="none"` parts say where they come from below. */
.apps-stage.is-playing .apps-part { opacity:0;transform:translateY(14px) scale(0.97);}
.apps-stage.is-playing .apps-part[data-how="fade"] { transform:none;}
.apps-stage.is-playing .apps-part[data-how="rise"] { transform:translateY(10px);}
.apps-stage.is-playing .apps-part[data-how="none"] { transform:none;}
.apps-stage.is-playing .apps-part.on { opacity:1;transform:none;transition:opacity .45s var(--ease),transform .8s var(--settle);}
.apps-stage.is-playing .apps-part.off { opacity:0;transform:none;transition:opacity .3s var(--ease);}
.apps-stage:not(.is-playing) .apps-part[data-off] { display:none;}
/* out of sight the clock stops, and so does anything that loops */
.apps-stage.is-away *,.apps-stage.is-away *::after { animation-play-state:paused;}
.apps-stage.is-resetting .apps-part { opacity:0;transform:translateY(-8px);transition:opacity .45s var(--ease),transform .45s var(--ease);}

/* the island opens while she builds, and closes when the last piece is in */
.apps-stage.is-playing .apps-dev .apps-building.apps-part { opacity:1;transform:none;}
.apps-stage.is-playing .apps-dev .apps-building.apps-part .is-l { transform:translateX(2.59375em);}
.apps-stage.is-playing .apps-dev .apps-building.apps-part .is-r { transform:translateX(-2.59375em);}
.apps-stage.is-playing .apps-dev .apps-building.apps-part .is-m { transform:scaleX(.5174);}
.apps-stage.is-playing .apps-dev .apps-building.apps-part .apps-isl-in { opacity:0;}
.apps-stage.is-playing .apps-dev .apps-building.apps-part.on .apps-isl { transform:none;transition:transform .56s var(--settle);}
.apps-stage.is-playing .apps-dev .apps-building.apps-part.on .apps-isl-in { opacity:1;transition:opacity .3s var(--ease) .2s;}
.apps-stage.is-playing .apps-dev .apps-building.apps-part.on .apps-spin { animation:apps-turn .8s linear infinite;}
.apps-stage.is-playing .apps-dev .apps-building.apps-part.off .apps-spin { animation:none;}
.apps-stage.is-playing .apps-dev .apps-building.apps-part.off .is-l { transform:translateX(2.59375em);}
.apps-stage.is-playing .apps-dev .apps-building.apps-part.off .is-r { transform:translateX(-2.59375em);}
.apps-stage.is-playing .apps-dev .apps-building.apps-part.off .is-m { transform:scaleX(.5174);}
.apps-stage.is-playing .apps-dev .apps-building.apps-part.off .apps-isl { transition:transform .46s var(--ease) .1s;}
.apps-stage.is-playing .apps-dev .apps-building.apps-part.off .apps-isl-in { opacity:0;transition:opacity .16s var(--ease);}

/* her touch: up from under the glass, a press, a ring, and away */
.apps-stage.is-playing .apps-dev .apps-tap.apps-part { opacity:0;transform:translate(calc(var(--u)*30),calc(var(--u)*70)) scale(1.06);}
.apps-stage.is-playing .apps-dev .apps-tap.apps-part.on { opacity:1;transform:none;transition:opacity .3s var(--ease),transform .7s var(--settle);}
.apps-stage.is-playing .apps-dev .apps-tap.apps-part.off { opacity:0;transform:translate(var(--8),var(--18)) scale(.9);transition:opacity .3s var(--ease),transform .45s var(--ease);}
.apps-stage.is-playing .apps-dev .apps-press.apps-part { opacity:1;transform:none;}
.apps-stage.is-playing .apps-dev .apps-press.apps-part.on { animation:apps-press .46s var(--ease) both;}
@keyframes apps-press { 38% { transform:scale(.82);} 100% { transform:none;} }
.apps-stage.is-playing .apps-dev .apps-flash.apps-part { opacity:0;}
.apps-stage.is-playing .apps-dev .apps-flash.apps-part.on { animation:apps-flash .5s var(--ease) both;}
@keyframes apps-flash { 0% { opacity:0;} 20% { opacity:.26;} 100% { opacity:0;} }
.apps-stage.is-playing .apps-dev .apps-ripple.apps-part { opacity:0;transform:scale(.3);}
.apps-stage.is-playing .apps-dev .apps-ripple.apps-part.on { animation:apps-ring .72s var(--ease) both;}
@keyframes apps-ring { 0% { opacity:.55;transform:scale(.3);} 100% { opacity:0;transform:scale(2.1);} }

/* a running coach: the route draws piece by piece with the runner at its tip,
   the zones fill, then the plan rises and climbs */
.apps-stage.is-playing .apps-dev .apps-route.apps-part { opacity:1;transform:none;}
.apps-stage.is-playing .apps-dev .apps-route .apps-casing,
.apps-stage.is-playing .apps-dev .apps-route .apps-rs path,
.apps-stage.is-playing .apps-dev .apps-route .apps-runner { opacity:0;}
.apps-stage.is-playing .apps-dev .apps-route .apps-start { opacity:0;transform:scale(.8);transform-box:fill-box;transform-origin:center;}
.apps-stage.is-playing .apps-dev .apps-route.on .apps-casing { opacity:1;transition:opacity .5s var(--ease);}
.apps-stage.is-playing .apps-dev .apps-route.on .apps-rs path { opacity:1;transition:opacity .18s linear calc(var(--i) * 64ms);}
.apps-stage.is-playing .apps-dev .apps-route.on .apps-start { opacity:1;transform:none;transition:opacity .2s var(--ease),transform .5s var(--spring);}
.apps-stage.is-playing .apps-dev .apps-route.on .apps-runner { opacity:1;animation:apps-run .9s linear both;transition:opacity .15s var(--ease);}
@keyframes apps-run {
  0% { transform: translate(104px, 142px); } 2.5% { transform: translate(102.9px, 130.3px); } 5% { transform: translate(101.5px, 118.6px); } 7.5% { transform: translate(99.7px, 107px); } 10% { transform: translate(97.1px, 95.5px); } 12.5% { transform: translate(92px, 85.1px); } 15% { transform: translate(82.8px, 77.8px); } 17.5% { transform: translate(72.6px, 72px); } 20% { transform: translate(62.8px, 65.6px); } 22.5% { transform: translate(56.5px, 55.9px); } 25% { transform: translate(57.5px, 44.4px); } 27.5% { transform: translate(65px, 35.5px); } 30% { transform: translate(75.8px, 31px); } 32.5% { transform: translate(87.4px, 30.1px); } 35% { transform: translate(99px, 32.2px); } 37.5% { transform: translate(109.7px, 37px); } 40% { transform: translate(118.5px, 44.7px); } 42.5% { transform: translate(124.4px, 54.8px); } 45% { transform: translate(130.6px, 64.8px); } 47.5% { transform: translate(138.8px, 73.2px); } 50% { transform: translate(149px, 78.9px); } 52.5% { transform: translate(160.4px, 81.8px); } 55% { transform: translate(172.1px, 82.3px); } 57.5% { transform: translate(183.7px, 80.8px); } 60% { transform: translate(195px, 77.5px); } 62.5% { transform: translate(205.8px, 72.8px); } 65% { transform: translate(215.9px, 66.8px); } 67.5% { transform: translate(227px, 63.6px); } 70% { transform: translate(237.9px, 67.3px); } 72.5% { transform: translate(242.6px, 77.7px); } 75% { transform: translate(239px, 88.7px); } 77.5% { transform: translate(230.9px, 97.2px); } 80% { transform: translate(221px, 103.6px); } 82.5% { transform: translate(210.5px, 108.7px); } 85% { transform: translate(199.6px, 113.2px); } 87.5% { transform: translate(188.6px, 117.3px); } 90% { transform: translate(177.6px, 121.4px); } 92.5% { transform: translate(166.8px, 126.1px); } 95% { transform: translate(156.3px, 131.4px); } 97.5% { transform: translate(146.5px, 137.9px); } 100% { transform: translate(138px, 146px); }
}
.apps-stage.is-playing .apps-dev .apps-zones .apps-zbar i { transform:scaleX(0);}
.apps-stage.is-playing .apps-dev .apps-zones.on .apps-zbar i { transform:none;transition:transform .6s var(--settle) calc(160ms + var(--i) * 90ms);}
.apps-stage.is-playing .apps-dev .apps-zones .apps-zkey i { opacity:0;}
.apps-stage.is-playing .apps-dev .apps-zones.on .apps-zkey i { opacity:1;transition:opacity .3s var(--ease) calc(260ms + var(--i) * 90ms);}
.apps-stage.is-playing .apps-dev .apps-sheet.apps-part { opacity:1;transform:translateY(106%);}
.apps-stage.is-playing .apps-dev .apps-sheet.apps-part.on { transform:none;transition:transform .78s var(--settle);}
/* the curve is uncovered from the left: the window and what is in it travel
   in opposite directions on one curve, so the picture stands still */
.apps-stage.is-playing .apps-dev .apps-chart.apps-part { opacity:1;transform:translateX(-100%);}
.apps-stage.is-playing .apps-dev .apps-chart.apps-part > .apps-chart-in { transform:translateX(100%);}
.apps-stage.is-playing .apps-dev .apps-chart.apps-part.on,
.apps-stage.is-playing .apps-dev .apps-chart.apps-part.on > .apps-chart-in { transform:none;transition:transform 1.05s var(--ease);}
.apps-stage.is-playing .apps-dev .apps-now.apps-part { opacity:0;transform:scale(.8);}
.apps-stage.is-playing .apps-dev .apps-now.apps-part.on { opacity:1;transform:none;transition:opacity .2s var(--ease),transform .5s var(--spring);}
.apps-stage.is-playing .apps-dev .apps-flag.apps-part { opacity:0;transform:scale(.8) rotate(-8deg);}
.apps-stage.is-playing .apps-dev .apps-flag.apps-part.on { opacity:1;transform:none;transition:opacity .2s var(--ease),transform .55s var(--spring);}

/* a trip planner: the pins drop onto the city, and later one more; the walk
   bends through it and the day moves down to make room */
.apps-stage.is-playing .apps-dev .apps-pin.apps-part { opacity:1;}
.apps-stage.is-playing .apps-dev .apps-pin.apps-part > i,
.apps-stage.is-playing .apps-dev .apps-pin.apps-part::after { opacity:0;}
.apps-stage.is-playing .apps-dev .apps-pin.apps-part.on > i { opacity:1;animation:apps-drop .62s both;}
.apps-stage.is-playing .apps-dev .apps-pin.apps-part.on::after { opacity:1;animation:apps-shade .62s both;}
@keyframes apps-drop {
  0% { transform:translateY(calc(var(--u) * -26));opacity:0;animation-timing-function:cubic-bezier(.5,0,.9,.5);}
  12% { opacity:1;}
  55% { transform:none;animation-timing-function:cubic-bezier(.2,.7,.4,1);}
  74% { transform:translateY(calc(var(--u) * -5));animation-timing-function:cubic-bezier(.5,0,.8,.5);}
  100% { transform:none;}
}
@keyframes apps-shade { 0% { transform:scale(.3);opacity:0;} 55% { transform:none;opacity:1;} 74% { transform:scale(.8);} 100% { transform:none;} }
.apps-stage.is-playing .apps-dev .apps-mover.apps-part { opacity:1;transform:translateY(calc(var(--u) * -50));}
.apps-stage.is-playing .apps-dev .apps-mover.apps-part.on { transform:none;transition:transform .62s var(--settle);}
.apps-stage.is-playing .apps-dev .apps-new.apps-part { opacity:0;transform:scale(.96);transform-origin:50% 0;}
.apps-stage.is-playing .apps-dev .apps-new.apps-part.on { opacity:1;transform:none;transition:opacity .36s var(--ease) .1s,transform .62s var(--settle);}
.apps-stage.is-playing .apps-dev .apps-time.apps-part { opacity:0;transform:scale(.8);}
.apps-stage.is-playing .apps-dev .apps-time.apps-part.on { opacity:1;transform:none;transition:opacity .2s var(--ease),transform .5s var(--spring);}

/* a plant doctor: the camera finds the spots, the reading fills, then she
   switches the reminder on and the watering days fill in */
.apps-stage.is-playing .apps-view.on .apps-scan { animation:apps-sweep 1.3s var(--ease) .25s 1 both;}
.apps-stage.is-playing .apps-dev .apps-spot.apps-part { opacity:0;transform:scale(.8);}
.apps-stage.is-playing .apps-dev .apps-spot.apps-part.on { opacity:1;transform:none;transition:opacity .2s var(--ease),transform .5s var(--spring);}
.apps-stage.is-playing .apps-dev .apps-spot.apps-part.on::after { animation:apps-ping 1.1s var(--ease) 2;}
.apps-stage.is-playing .apps-dev .apps-meter.apps-part { opacity:1;transform:none;}
.apps-stage.is-playing .apps-dev .apps-meter.apps-part > i { transform:scaleX(0);}
.apps-stage.is-playing .apps-dev .apps-meter.apps-part.on > i { transform:none;transition:transform .9s var(--settle);}
.apps-stage.is-playing .apps-dev .apps-switch-on.apps-part { opacity:0;}
.apps-stage.is-playing .apps-dev .apps-switch-on.apps-part.on { opacity:1;transition:opacity .28s var(--ease) .06s;}
.apps-stage.is-playing .apps-dev .apps-knob.apps-part { opacity:1;transform:none;}
.apps-stage.is-playing .apps-dev .apps-knob.apps-part.on { transform:translateX(var(--18));transition:transform .46s var(--settle);}
.apps-stage.is-playing .apps-dev .apps-drop.apps-part { opacity:0;transform:translateY(calc(var(--u) * -10)) scale(.7);}
.apps-stage.is-playing .apps-dev .apps-drop.apps-part.on { opacity:1;transform:none;transition:opacity .2s var(--ease),transform .6s var(--settle);}

/* ---------- the three asks it is waiting for ---------- */

.apps-chips { position:relative;grid-area:chips;display:flex;flex-wrap:wrap;gap:10px;}
/* the white pill travels to the chip that was chosen instead of appearing on
   it. Its width is the widest chip's, scaled from the left, so only transform
   moves. Without a script it never shows and the chip carries its own white. */
.apps-chips::before {
  content:"";position:absolute;z-index:0;left:0;top:0;width:var(--mb,140px);height:44px;
  border-radius:999px;background:#fff;box-shadow:var(--ladder-lite),0 0 0 1px rgba(20,21,25,.16);
  opacity:0;transform-origin:left center;
  transform:translate3d(var(--mx,0),var(--my,0),0) scaleX(var(--ms,1));
  transition:transform .46s var(--settle);
}
.apps-chips.is-marked::before { opacity:1;}
.apps-chip {
  position:relative;z-index:1;
  display:inline-flex;align-items:center;height:44px;padding:0 18px;
  border:0;border-radius:999px;background:rgba(255,255,255,.62);box-shadow:0 0 0 1px var(--hairline);
  font:500 14.5px/1 var(--sans);letter-spacing:-0.01em;color:var(--ink-body);white-space:nowrap;cursor:pointer;
  transition:transform .16s var(--ease),background-color .26s var(--ease),color .26s var(--ease);
}
.apps-chip[aria-pressed="true"] { background:#fff;color:var(--ink);box-shadow:var(--ladder-lite),0 0 0 1px rgba(20,21,25,.16);}
.apps-chips.is-marked .apps-chip[aria-pressed="true"] { background:transparent;color:var(--ink);box-shadow:none;}
.apps-chip:focus-visible { outline:2px solid var(--ink);outline-offset:3px;}
@media (hover:hover) { .apps-chip:hover { background-color:#fff;color:var(--ink);} }
.apps-chip:active { transform:scale(0.97);}

/* ---------- narrow ---------- */

/* On a phone the same column, on one rhythm: 16 under the heading, 32 to the
   ask, 32 to the device, 24 to the chips, and all of it on the page's centre
   line, as every other section is on a phone. */
@media (max-width:860px) {
  .apps-stage {
    grid-template-columns:minmax(0,1fr);grid-template-areas:"head" "ask" "dev" "chips";
    grid-template-rows:auto auto auto auto;gap:24px;
  }
  .apps-head { margin-bottom:8px;text-align:center;}
  .apps-head .h2 { margin-top:0;}
  .apps-head .lede { margin-top:16px;margin-inline:auto;}
  .apps-asks { margin-bottom:8px;justify-items:center;}
  .apps-dev { display:flex;justify-content:center;}
  /* the ask and the whole phone on one screen, as the browser's own bars leave
     it (svh): the phone is as tall as the screen allows under the ask, never
     narrower than 280 and never wider than the column */
  .apps-dev .phone { --pw:clamp(280px,calc((100svh - 190px) * .466),380px);}
  .apps-chips { justify-content:center;}
}
@media (max-width:380px) {
  .apps-chip { padding:0 15px;font-size:13.5px;}
}

/* with motion refused the stage never plays; only a chip can move a thing */
@media (prefers-reduced-motion:reduce) {
  .apps-app,.apps-chip,.apps-dev .apps-app.is-going,.apps-chips::before { transition:none;}
}
.apps-stage.is-still .apps-chips::before { transition:none;}

/* ---------- people ---------- */

/* people: leave the forms to me. One large screen, Ola's own browser, and her
   cursor with her name on it; beside it the phone shows the same screen,
   small, in the task's row.

   Glanceable, not readable. Each site says what it is by its silhouette: a
   flat's photo and its price, a jacket and its sizes, a map, a dark official
   band and weeks of booked out slots. Every form is shapes. Ola moves through
   it quickly, what she picks turns her blue, one real value lands (18:30, L,
   8:40), and one short line says it is done.

   Ordinary css is the finished frame: the viewing booked, the cursor resting
   beside the line that says so. Only once the stage is playing do things step
   back to where they come from. Everything moves by transform and opacity. */

.people-stage {
  position: relative;
  container-type: inline-size;
  --ppw: clamp(232px, 20vw, 288px);
  padding-bottom: calc(var(--ppw) * 0.2);
}

/* ---------- the window ---------- */

.people-win {
  --a: clamp(0, (100cqw - 340px) / 560px, 1);
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(1000px, calc(100% - var(--ppw) * 0.7));
  aspect-ratio: calc(0.8 + 0.8 * var(--a));
  overflow: hidden;
  border-radius: 20px;
  background: #fff;
  box-shadow: var(--ladder), 0 0 0 1px rgba(0, 0, 0, 0.07), 0 40px 70px -40px rgba(24, 28, 38, 0.32);
}

/* the chrome: three neutral dots and an address that is typed as bars, the
   same browser the hero draws */
.people-bar {
  flex: 0 0 auto;
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 440px) minmax(0, 1fr);
  align-items: center;
  height: calc(38px + 6px * var(--a));
  padding: 0 14px;
  background: #F4F5F7;
  box-shadow: inset 0 -1px 0 rgba(20, 21, 25, 0.065);
}
.people-dots { display: flex; gap: 7px; }
.people-dots i { width: 10px; height: 10px; border-radius: 50%; background: #D7D9DE; }
.people-url {
  display: flex;
  align-items: center;
  gap: 8px;
  height: calc(24px + 4px * var(--a));
  padding: 0 12px;
  border-radius: 999px;
  background: #fff;
  box-shadow: inset 0 0 0 1px rgba(20, 21, 25, 0.06);
}
.people-url svg { flex: 0 0 auto; width: 12px; height: 12px; fill: none; stroke: #A7ACB5; stroke-width: 2.2; stroke-linecap: round; }
.people-typed { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 5px; transform-origin: 0 50%; }
.people-typed i { flex: 0 0 var(--u1, 34%); height: calc(4px + 1.5px * var(--a)); border-radius: 999px; background: var(--bar-3); }
.people-typed i + i { flex-basis: var(--u2, 22%); background: var(--bar-2); }
.people-win[data-on="b"] { --u1: 24%; --u2: 30%; }
.people-win[data-on="c"] { --u1: 42%; --u2: 15%; }

/* the page loading, on the chrome's own edge */
.people-load {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: var(--live);
  opacity: 0;
  transform: scaleX(0);
  transform-origin: 0 50%;
}
.people-win.is-typing .people-typed { animation: people-type 440ms steps(9, end) 40ms both; }
.people-win.is-loading .people-load { animation: people-load 760ms var(--ease) 90ms both; }
@keyframes people-type { from { transform: scaleX(0.05); } to { transform: scaleX(1); } }
@keyframes people-load {
  0%   { opacity: 1; transform: scaleX(0.03); animation-timing-function: var(--ease); }
  58%  { opacity: 1; transform: scaleX(0.74); animation-timing-function: var(--ease); }
  84%  { opacity: 1; transform: scaleX(1); }
  100% { opacity: 0; transform: scaleX(1); }
}

.people-view { flex: 1 1 auto; position: relative; overflow: hidden; container-type: size; background: #fff; }

/* ---------- the pages ---------- */

/* Each page is drawn off the screen it is in, so the same page is a page on a
   monitor and on a phone, and its small copy in the phone is exact. Narrow, it
   is one column: the site's picture on top, the form under it. From 560 it is
   two: the form on the left, the picture on the right, where the phone may
   stand over it. The picture takes whatever height is left. */
.people-page {
  --t: clamp(0, (100cqw - 280px) / 640px, 1);
  --pad: calc(16px + 14px * var(--t));
  --hh: calc(40px + 14px * var(--t));
  --gap: calc(10px + 5px * var(--t));
  --ch: calc(30px + 8px * var(--t));
  --bh: calc(6px + 2px * var(--t));
  --r: calc(9px + 3px * var(--t));
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  font-size: calc(12px + 1.5px * var(--t));
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  opacity: 0;
  visibility: hidden;
  transition: opacity .26s var(--ease), visibility 0s linear .26s;
}
.people-page.is-on { opacity: 1; visibility: visible; transition: opacity .3s var(--ease), visibility 0s; }

/* a page arrives in pieces, top first, the way a page paints */
.people-stage.is-playing .pp-in { transition: opacity .42s var(--ease) var(--d, 0ms), transform .7s var(--settle) var(--d, 0ms); }
.people-page.is-pre .pp-in { opacity: 0; transform: translateY(10px); transition: none; }
.pp-jump, .pp-jump *, .pp-jump *::before, .pp-jump *::after { transition: none !important; animation: none !important; }

.pp-site {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--hh);
  padding: 0 var(--pad);
  box-shadow: inset 0 -1px 0 var(--hairline);
}
.pp-logo { display: flex; align-items: center; gap: calc(7px + 2px * var(--t)); }
.pp-mk { flex: 0 0 auto; width: calc(15px + 4px * var(--t)); height: calc(15px + 4px * var(--t)); border-radius: 50%; }
.pp-name { width: calc(50px + 22px * var(--t)); height: calc(var(--bh) + 1px); border-radius: 999px; background: rgba(20, 21, 25, 0.78); }
.pp-nav { display: flex; align-items: center; gap: calc(10px + 9px * var(--t)); }
.pp-nav i { width: calc(20px + 10px * var(--t)); height: calc(var(--bh) * 0.8); border-radius: 999px; background: var(--bar-2); }
.pp-nav i:nth-child(2) { width: calc(26px + 12px * var(--t)); }
.pp-nav i:nth-child(3) { width: calc(17px + 8px * var(--t)); }
.pp-nav svg { width: calc(16px + 3px * var(--t)); height: calc(16px + 3px * var(--t)); fill: none; stroke: var(--ink); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

.pp-main {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  gap: calc(var(--gap) + 2px);
  padding: calc(var(--pad) * 0.8) var(--pad) var(--pad);
}
.pp-media { position: relative; min-height: 0; overflow: hidden; border-radius: var(--r); container-type: size; }
.pp-media > svg { position: absolute; inset: 0; width: 100%; height: 100%; }

.pp-form { display: grid; align-content: start; gap: var(--gap); min-width: 0; }
.pp-head { display: none; gap: calc(var(--bh) * 0.9); }
.pp-head i { display: block; width: 62%; height: calc(var(--bh) * 1.7); border-radius: 999px; background: rgba(20, 21, 25, 0.8); }
.pp-head i + i { width: 40%; height: var(--bh); background: var(--bar-2); }
.pp-lab { display: none; width: calc(34px + 12px * var(--t)); height: calc(var(--bh) * 0.8); margin-bottom: calc(var(--gap) * -0.4); border-radius: 999px; background: var(--bar-2); }

@container (min-height: 360px) {
  .pp-head { display: grid; }
}
@container (min-width: 560px) {
  .pp-main { grid-template-rows: minmax(0, 1fr); grid-template-columns: minmax(0, 1fr) minmax(0, 1.08fr); gap: calc(var(--pad) * 1.25); padding-top: var(--pad); }
  .pp-form { grid-area: 1 / 1; align-self: center; width: 100%; max-width: calc(250px + 130px * var(--t)); gap: calc(var(--gap) + 3px * var(--t)); }
  .pp-media { grid-area: 1 / 2; }
  .pp-head { display: grid; margin-bottom: calc(4px * var(--t)); }
  .pp-lab { display: block; }
}

/* ---------- the controls, one set across the three sites ---------- */

/* what Ola picks turns her blue: a fill that pops in under the content */
.pp-day, .pp-chip, .pp-arrow, .pp-btn, .pp-field { position: relative; isolation: isolate; }
.pp-day::before, .pp-chip::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  border-radius: inherit;
  background: var(--live);
  opacity: 0;
  transform: scale(0.86);
  transition: opacity .18s var(--ease), transform .5s var(--spring);
}
.pp-day.is-on::before, .pp-chip.is-on::before { opacity: 1; transform: none; }
/* where the hand rests, before it presses */
.pp-day::after, .pp-chip::after, .pp-arrow::after, .pp-btn::after, .pp-seg::after {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  border-radius: inherit;
  background: rgba(20, 21, 25, 0.06);
  opacity: 0;
  transition: opacity .2s var(--ease);
}
.pp-btn::after { z-index: 0; background: rgba(255, 255, 255, 0.14); }
.is-hot::after { opacity: 1; }

/* a day: two short lines, the weekday over the date */
.pp-days { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: calc(5px + 3px * var(--t)); }
.pp-day {
  display: grid;
  place-items: center;
  align-content: center;
  gap: calc(4px + 2px * var(--t));
  height: calc(var(--ch) + 9px + 6px * var(--t));
  border-radius: var(--r);
  box-shadow: inset 0 0 0 1px rgba(20, 21, 25, 0.12);
  font-style: normal;
}
.pp-day b { position: relative; display: block; width: 42%; height: calc(var(--bh) * 0.75); border-radius: 999px; background: var(--bar-2); }
.pp-day b + b { width: 32%; height: calc(var(--bh) * 1.3); background: var(--bar-3); }
.pp-day b::after, .pp-seg b::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: #fff;
  opacity: 0;
  transition: opacity .2s var(--ease) .04s;
}
.pp-day.is-on b::after { opacity: 1; }
.pp-day.is-on b + b::after { opacity: 1; }

/* a chip: a bar until it is picked, then the one real value */
.pp-times { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: calc(5px + 3px * var(--t)); }
.pp-chip { display: grid; place-items: center; height: var(--ch); border-radius: 999px; box-shadow: inset 0 0 0 1px rgba(20, 21, 25, 0.12); font-style: normal; }
.pp-chip > * { grid-area: 1 / 1; }
.pp-chip > b { display: block; width: 40%; height: var(--bh); border-radius: 999px; background: var(--bar-3); transition: opacity .14s var(--ease); }
.pp-chip > em {
  font-style: normal;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: #fff;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity .22s var(--ease) .06s, transform .5s var(--settle) .06s;
}
.pp-chip.is-on > b { opacity: 0; }
.pp-chip.is-on > em { opacity: 1; transform: none; }

/* a field: Ola's focus is her blue, and her typing is bars that grow in steps */
.pp-field {
  display: none;
  align-items: center;
  height: calc(var(--ch) + 4px);
  padding: 0 calc(12px + 2px * var(--t));
  border-radius: calc(var(--r) - 2px);
  box-shadow: inset 0 0 0 1px rgba(20, 21, 25, 0.14);
}
.pp-field::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 0 0 1.6px var(--live), 0 0 0 3px rgba(44, 99, 210, 0.12);
  opacity: 0;
  transition: opacity .2s var(--ease);
}
.pp-field.is-focus::before { opacity: 1; }
.pp-typed { display: flex; align-items: center; gap: calc(5px + 1px * var(--t)); transform-origin: 0 50%; }
.pp-typed i { width: calc(38px + 12px * var(--t)); height: var(--bh); border-radius: 999px; background: rgba(20, 21, 25, 0.6); }
.pp-typed i + i { width: calc(54px + 16px * var(--t)); }
.people-stage.is-playing .pp-field:not(.is-on) .pp-typed { transform: scaleX(0); }
.people-stage.is-playing .pp-field.is-on .pp-typed { animation: people-type 560ms steps(10, end) 60ms both; }
@container (min-width: 560px) {
  .pp-field { display: flex; }
}

/* the button, and the line that takes its place */
.pp-act { display: grid; justify-items: start; margin-top: calc(var(--gap) * 0.35); }
.pp-act > * { grid-area: 1 / 1; }
.pp-btn {
  display: grid;
  place-items: center;
  height: var(--ch);
  padding: 0 calc(18px + 8px * var(--t));
  border-radius: 999px;
  background: var(--ink);
  transition: transform .12s var(--ease), opacity .2s var(--ease);
}
.pp-btn i { position: relative; z-index: 1; width: calc(46px + 18px * var(--t)); height: var(--bh); border-radius: 999px; background: rgba(255, 255, 255, 0.9); }
.pp-btn.is-press { transform: scale(0.95); }
.pp-ok {
  display: inline-flex;
  align-items: center;
  gap: calc(7px + 1px * var(--t));
  height: var(--ch);
  padding: 0 calc(13px + 3px * var(--t)) 0 calc(5px + 1px * var(--t));
  border-radius: 999px;
  background: #fff;
  box-shadow: 0 0 0 1px rgba(20, 21, 25, 0.07), 0 4px 12px -4px rgba(20, 21, 25, 0.22);
  font-weight: 500;
  letter-spacing: -0.012em;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(6px) scale(0.94);
  transform-origin: 0 50%;
  transition: opacity .2s var(--ease), transform .3s var(--ease);
}
.pp-ok > i { flex: 0 0 auto; display: grid; place-items: center; width: calc(var(--ch) - 10px); height: calc(var(--ch) - 10px); border-radius: 50%; background: var(--good); }
.pp-ok svg { width: 62%; height: 62%; fill: none; stroke: #fff; stroke-width: 3.2; stroke-linecap: round; stroke-linejoin: round; }
.people-page.is-done .pp-btn { opacity: 0; transform: scale(0.92); }
.people-page.is-done .pp-ok { opacity: 1; transform: none; transition: opacity .26s var(--ease) .06s, transform .55s var(--spring) .06s; }

/* ---------- a letting site: the flat ---------- */

.pp-a .pp-mk { background: #D08A26; box-shadow: inset -0.28em -0.2em 0 #FDF0DC; }
.pp-photo { background: #EEE6DA; }
.pp-price {
  position: absolute;
  left: calc(8px + 4px * var(--t));
  bottom: calc(8px + 4px * var(--t));
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: calc(24px + 5px * var(--t));
  padding: 0 calc(10px + 2px * var(--t));
  border-radius: 999px;
  background: #fff;
  box-shadow: 0 2px 8px -3px rgba(20, 21, 25, 0.28);
  font-weight: 600;
  letter-spacing: -0.02em;
}
.pp-price i { width: calc(14px + 4px * var(--t)); height: calc(var(--bh) * 0.7); border-radius: 999px; background: var(--bar-2); }
.pp-pics { position: absolute; left: 50%; bottom: calc(13px + 6px * var(--t)); display: flex; gap: 5px; transform: translateX(-50%); }
.pp-pics i { width: 5px; height: 5px; border-radius: 50%; background: #fff; opacity: 0.55; }
.pp-pics i:first-child { opacity: 1; }

/* ---------- a shop: the jacket ---------- */

.pp-b .pp-mk { width: calc(13px + 3px * var(--t)); height: calc(13px + 3px * var(--t)); border-radius: 0.24em; background: var(--ink); transform: rotate(45deg); }
.pp-garment { background: linear-gradient(165deg, #F3EFFC, #E6E0F7); }
.pp-garment > svg { inset: 50% auto auto 50%; width: min(80cqh, 64cqw); height: min(80cqh, 64cqw); transform: translate(-50%, -48%); }

/* the choice between two: a thumb that slides to what she picks */
.pp-seg {
  position: relative;
  isolation: isolate;
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  justify-items: center;
  height: var(--ch);
  border-radius: 999px;
  background: rgba(20, 21, 25, 0.055);
}
.pp-thumb {
  position: absolute;
  left: 3px;
  top: 3px;
  bottom: 3px;
  width: calc(50% - 3px);
  border-radius: 999px;
  background: #fff;
  box-shadow: 0 1px 3px rgba(20, 21, 25, 0.16);
  transform: translateX(100%);
  transition: transform .55s var(--settle);
}
.pp-thumb::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--live);
  box-shadow: 0 3px 8px -3px rgba(44, 99, 210, 0.6);
  opacity: 0;
  transition: opacity .24s var(--ease) .12s;
}
.pp-seg.is-on .pp-thumb { transform: none; }
.pp-seg.is-on .pp-thumb::before { opacity: 1; }
.pp-seg b { position: relative; z-index: 1; display: block; width: 38%; height: var(--bh); border-radius: 999px; background: var(--bar-3); }
.pp-seg b:first-of-type { width: 46%; }
.pp-seg.is-on b:first-of-type::after { opacity: 1; }

/* sizes: the real letters, because the size is what this page is about */
.pp-sizes { display: grid; grid-template-columns: repeat(4, minmax(0, calc(44px + 16px * var(--t)))); gap: calc(5px + 3px * var(--t)); }
.pp-size {
  display: grid;
  place-items: center;
  height: var(--ch);
  border-radius: calc(var(--r) - 2px);
  box-shadow: inset 0 0 0 1px rgba(20, 21, 25, 0.12);
  font-style: normal;
  font-weight: 500;
  letter-spacing: -0.01em;
}
.pp-size.pp-chip { border-radius: calc(var(--r) - 2px); }
.pp-size.pp-chip > b { width: auto; height: auto; background: none; font-weight: 500; }
.pp-size.is-mine { background: #F2F3F5; box-shadow: none; color: var(--ink-quiet); }

/* ---------- a test centre: a map, a dark band, weeks of booked out slots ---------- */

.pp-c .pp-site { background: #1D2430; box-shadow: none; }
.pp-c .pp-mk { box-shadow: inset 0 0 0 calc(2.5px + 0.5px * var(--t)) #fff; }
.pp-c .pp-name { background: rgba(255, 255, 255, 0.88); }
.pp-c .pp-nav i { background: rgba(255, 255, 255, 0.34); }
.pp-map { background: #E9EDE6; }
.pp-pin {
  position: absolute;
  left: 54%;
  top: 52%;
  display: grid;
  place-items: center;
  width: calc(32px + 8px * var(--t));
  height: calc(32px + 8px * var(--t));
  margin: calc(-38px - 9px * var(--t)) 0 0 calc(-16px - 4px * var(--t));
  border-radius: 50%;
  background: var(--ink);
  box-shadow: 0 0 0 3px #fff, 0 8px 16px -6px rgba(20, 21, 25, 0.5);
}
.pp-pin::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -7px;
  width: 11px;
  height: 11px;
  margin-left: -5.5px;
  border-radius: 0 0 3px 0;
  background: var(--ink);
  transform: rotate(45deg);
}
.pp-pin svg { position: relative; z-index: 1; width: 64%; height: 64%; fill: none; stroke: #fff; stroke-width: 2; stroke-linecap: round; }

.pp-wk { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 10px; }
.pp-wk > i { justify-self: center; width: calc(56px + 24px * var(--t)); height: var(--bh); border-radius: 999px; background: var(--bar-3); transform: scaleX(0.78); transition: transform .5s var(--settle); }
/* the week's dates take a new length as each week slides in */
.pp-wk.is-w1 > i { transform: scaleX(0.9); }
.pp-wk.is-w2 > i { transform: none; }
.pp-arrow {
  display: grid;
  place-items: center;
  width: calc(var(--ch) - 2px);
  height: calc(var(--ch) - 2px);
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(20, 21, 25, 0.14);
  transition: transform .12s var(--ease);
}
.pp-arrow:first-child { opacity: 0.45; }
.pp-arrow svg { position: relative; width: 52%; height: 52%; fill: none; stroke: var(--ink); stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.pp-arrow.is-press { transform: scale(0.9); }

.pp-slots { overflow: hidden; }
.pp-track { display: flex; transition: transform .62s var(--settle); }
.pp-slots.is-w1 .pp-track { transform: translateX(-100%); }
.pp-slots.is-w2 .pp-track { transform: translateX(-200%); }
.pp-week { flex: 0 0 100%; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: calc(4px + 3px * var(--t)); }
.pp-week > b { justify-self: center; width: 38%; height: calc(var(--bh) * 0.75); margin-bottom: calc(1px + 2px * var(--t)); border-radius: 999px; background: var(--bar-2); }
.pp-week > i {
  display: grid;
  place-items: center;
  height: calc(var(--ch) - 4px);
  border-radius: calc(var(--r) - 3px);
  background: repeating-linear-gradient(135deg, rgba(20, 21, 25, 0.05) 0 1.5px, rgba(20, 21, 25, 0) 1.5px 5px), #F5F6F8;
  font-style: normal;
}
.pp-week > i.is-free { background: #fff; box-shadow: inset 0 0 0 1px rgba(20, 21, 25, 0.2); }
.pp-week > i.is-free > b { display: block; width: 44%; height: var(--bh); border-radius: 999px; background: var(--bar-3); }
.pp-week > i.pp-chip { border-radius: calc(var(--r) - 3px); }
.pp-week > .is-r3 { display: none; }
@container (min-width: 560px) {
  .pp-week > .is-r3 { display: grid; }
}

/* ---------- the hand: Ola's cursor, her name hanging under it ---------- */

/* two axes on two curves, so it travels on an arc and lands without a bump */
.people-cur {
  --t: clamp(0, (100cqw - 280px) / 640px, 1);
  position: absolute;
  z-index: 6;
  left: 0;
  top: 0;
  --rx: calc(158px + 38px * var(--t));
  --ry: calc(100cqh - 42px - 19px * var(--t));
  transform: translateX(var(--x, var(--rx)));
  transition: transform var(--md, .6s) cubic-bezier(.3, 1.06, .42, 1);
  pointer-events: none;
}
.people-cur > span { position: relative; display: block; transform: translateY(var(--y, var(--ry))); transition: transform var(--md, .6s) cubic-bezier(.5, 0, .2, 1); }
/* with no script the hand rests where the script would park it: past the end
   of the line that says it is done, measured at nine sizes */
@container (min-width: 560px) {
  .people-cur { --ry: calc(50cqh + 104px + 50px * var(--t)); }
}
.people-cur svg {
  position: absolute;
  left: -2px;
  top: -2px;
  width: calc(15px + 3px * var(--t));
  height: calc(18px + 3.6px * var(--t));
  max-width: none;
  overflow: visible;
  transform-origin: 2px 2px;
  filter: drop-shadow(0 1px 1.5px rgba(20, 21, 25, 0.28)) drop-shadow(0 4px 8px rgba(20, 21, 25, 0.12));
  transition: transform .12s var(--ease);
}
.people-cur path { fill: var(--ink); stroke: #fff; stroke-width: 1.6; stroke-linejoin: round; paint-order: stroke; }
/* it is her, as the hero draws her when she is a pointer: two eyes on the
   arrow, and now and then a blink */
.people-eyes { fill: #fff; transform-box: fill-box; transform-origin: 50% 50%; animation: people-blink 4.6s var(--ease) infinite; }
@keyframes people-blink { 0%, 93%, 100% { transform: none; } 95.5% { transform: scaleY(0.12); } }
.people-cur.is-press svg { transform: scale(0.86); }
.people-tag {
  position: absolute;
  left: calc(12px + 2px * var(--t));
  top: calc(17px + 3px * var(--t));
  height: calc(18px + 2px * var(--t));
  padding: 0 calc(7px + 1px * var(--t));
  border-radius: 999px;
  background: var(--live);
  color: #fff;
  font-size: calc(12px + 1px * var(--t));   /* a caption never goes under 12px */
  font-weight: 500;
  line-height: calc(18px + 2px * var(--t));
  letter-spacing: 0;
  white-space: nowrap;
  box-shadow: 0 2px 6px -2px rgba(44, 99, 210, 0.55);
  transition: transform .4s var(--settle);
}
.people-cur.is-flip .people-tag { transform: translateX(calc(-100% - 20px - 3px * var(--t))); }
.people-rip {
  position: absolute;
  left: -15px;
  top: -15px;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: rgba(44, 99, 210, 0.16);
  opacity: 0;
}
.people-cur.is-click .people-rip { animation: people-rip .55s var(--ease); }
@keyframes people-rip { from { opacity: 1; transform: scale(0.3); } to { opacity: 0; transform: scale(1.6); } }

/* ---------- the phone ---------- */

.people-phone { position: absolute; z-index: 3; right: 0; bottom: 0; --pw: var(--ppw); }
.people-phone .app-head { height: 3.1em; }
.people-phone .app-back svg { transform: scaleX(-1); }
.people-phone .app-body { justify-content: flex-end; padding-bottom: 0.4em; }
.people-phone .app-stop { height: 2.1em; padding: 0 0.95em; font-size: 0.92em; }
.people-thread { gap: 0.8em; padding: 0; }
.people-job { padding: 0.55em 0.55em 0.5em; }
.people-row { display: flex; align-items: center; justify-content: space-between; gap: 0.6em; min-height: 2.6em; padding: 0.45em 0.45em 0 0.5em; }
.people-row .task-state { font-size: 0.88em; color: var(--ink); }
.people-dot { flex: 0 0 auto; width: 0.52em; height: 0.52em; border-radius: 50%; background: var(--good); }
.is-busy .people-dot { background: var(--live); }
.people-stop { opacity: 0; transition: opacity .3s var(--ease); }
.is-busy .people-stop { opacity: 1; }

/* the task's own screen, small. The live copy replaces the drawn one. */
.people-pv {
  position: relative;
  overflow: hidden;
  aspect-ratio: 43 / 25;
  border-radius: 1.2em;
  /* with no script: the finished page drawn small, so it is never empty: the
     flat's photo on the right, the picked day and time, the line at the foot */
  background:
    linear-gradient(var(--good), var(--good)) 4.6% 73.5% / 1.8% 3% no-repeat,
    linear-gradient(#F1F2F4, #F1F2F4) 3.6% 74.3% / 13% 5.8% no-repeat,
    linear-gradient(var(--bar), var(--bar)) 4.8% 64.4% / 36% 4.5% no-repeat,
    linear-gradient(#fff, #fff) 17.4% 56.1% / 5% 1.6% no-repeat,
    linear-gradient(var(--live), var(--live)) 15% 56.5% / 11.6% 7% no-repeat,
    linear-gradient(var(--bar), var(--bar)) 4.8% 56.5% / 36% 7% no-repeat,
    linear-gradient(var(--live), var(--live)) 26.1% 44% / 5.5% 9% no-repeat,
    linear-gradient(var(--bar), var(--bar)) 4.8% 44% / 36% 9% no-repeat,
    linear-gradient(var(--bar-2), var(--bar-2)) 3.6% 33.9% / 13% 1.2% no-repeat,
    linear-gradient(rgba(20, 21, 25, 0.8), rgba(20, 21, 25, 0.8)) 3.9% 30.2% / 21% 2.2% no-repeat,
    linear-gradient(#9AAC9F, #9AAC9F) 90% 57.5% / 20% 13% no-repeat,
    linear-gradient(#D5E4EF, #D5E4EF) 64% 36.4% / 11% 34% no-repeat,
    linear-gradient(#D9C4A6, #D9C4A6) 94.3% 91.6% / 47% 17% no-repeat,
    linear-gradient(#EEE6DA, #EEE6DA) 94.3% 68.2% / 47% 78% no-repeat,
    linear-gradient(rgba(20, 21, 25, 0.78), rgba(20, 21, 25, 0.78)) 6.2% 4.3% / 7% 1.4% no-repeat,
    linear-gradient(#D08A26, #D08A26) 3.2% 3.9% / 2% 3.2% no-repeat,
    linear-gradient(var(--hairline), var(--hairline)) 0 9.6% / 100% 0.6% no-repeat,
    #fff;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08);
}
.people-pv.is-live { background: #fff; }
.people-clone { position: absolute; left: 0; top: 0; transform-origin: 0 0; pointer-events: none; }

/* ---------- on a phone: the task's row as a glass bar under the screen ---------- */

.people-strip { display: none; }

@media (max-width: 1080px) {
  .people-stage { padding-bottom: 0; }
  .people-win { width: 100%; }
  .people-phone { display: none; }
  .people-strip {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 14px;
    padding: 10px 12px 10px 10px;
    border-radius: 20px;
    background: rgba(255, 255, 255, 0.78);
    backdrop-filter: blur(18px) saturate(160%);
    -webkit-backdrop-filter: blur(18px) saturate(160%);
    box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.9), 0 0 0 1px rgba(0, 0, 0, 0.05), 0 12px 30px -16px rgba(24, 28, 38, 0.3);
  }
  .people-tile { flex: 0 0 auto; display: grid; place-items: center; width: 40px; height: 40px; border-radius: 13px; background: #fff; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.06); }
  .people-tile svg { width: 24px; height: 24px; }
  .people-strip-t { flex: 1 1 auto; min-width: 0; display: grid; gap: 2px; }
  .people-strip-t b { font-size: 14.5px; font-weight: 500; letter-spacing: -0.015em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .people-strip-t > span { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--ink-body); }
  .people-strip .app-stop { height: 30px; font-size: 12.5px; }
}
/* a phone's own browser: the address follows the dots instead of centring */
@media (max-width: 560px) {
  .people-bar { grid-template-columns: auto minmax(0, 1fr); gap: 12px; padding: 0 12px 0 14px; }
  .people-dots { gap: 6px; }
  .people-dots i { width: 9px; height: 9px; }
}
/* the row is the ask and how it is going; stopping it is for a wider screen */
@media (max-width: 420px) {
  .people-strip .app-stop { display: none; }
}

/* ---------- motion refused, motion stopped ---------- */

@media (prefers-reduced-motion: reduce) {
  .people-cur, .people-cur > span, .people-cur svg, .pp-in, .pp-track, .pp-thumb, .pp-ok, .pp-btn,
  .pp-day::before, .pp-chip::before, .pp-chip > em, .pp-chip > b { transition: none !important; }
  .people-page { transition: opacity .2s var(--ease), visibility 0s linear .2s; }
  .people-cur.is-click .people-rip, .people-win .people-typed, .people-win .people-load, .pp-typed, .people-eyes { animation: none !important; }
}
.is-still .people-cur, .is-still .people-cur > span { transition: none; }

/* the first play lets go of the finished page softly; a new ask, a new state */
.people-view.is-letgo .people-page.is-on { opacity: 0; transition: opacity .42s var(--ease); }
[data-step].is-new, [data-ask].is-new { animation: people-say .4s var(--ease); }
@keyframes people-say { from { opacity: 0.25; } }

/* ---------- call ---------- */

/* call: a phone call, both ends of it, on the page's own ground. The ask on
   top; under it Ola and whoever she rang, side by side on one line; under
   them one short line from whoever is talking, and at the end the one line
   that came of it.

   Violet is the call's colour on this site, and it is only ever her voice:
   the ripples off her ring, the glow while she talks, the tick when it lands.
   The other side is ink. Ordinary css is the finished call. Everything that
   moves is one transform or one opacity on one element, run by the section's
   script. */

.call-stage {
  --violet: #7A5CFF;
  --ola: clamp(90px, 28.5vw, 116px);    /* her ring, edge to edge */
  --box: calc(var(--ola) * 1.3853);     /* the mark's own square around it */
  --disc: calc(var(--ola) * 0.66);      /* the other side */
  --apart: clamp(40px, 13vw, 60px);     /* ring to disc */
  --cap: clamp(16px, 4.6vw, 18px);      /* the line under them */
  margin-top: 32px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* the sentence breaks on its own sense, not on the measure */
.call .head .lede { max-width: 680px; text-wrap: balance; }

/* ---------- the ask ---------- */

/* one fixed width, so a longer or a shorter ask never moves its edges */
.call-ask { width: min(100%, 440px); }

/* ---------- the two ends ---------- */

.call-pair {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  margin-top: 40px;
}

.call-ola {
  position: relative;
  flex: 0 0 auto;
  width: var(--box);
  height: var(--box);
}
.call-body, .call-ring, .call-face, .call-lids, .call-cheeks {
  position: absolute;
  inset: 0;
}
.call-ring, .call-lids svg, .call-cheeks svg { width: 100%; height: 100%; overflow: visible; }
.call-ring circle { fill: var(--ground); stroke: var(--ink); stroke-width: 6.6; }
.call-lids circle { fill: var(--ink); }
.call-cheeks circle { fill: var(--ground); }

/* where her eyes are looking, set by the script in the mark's own units */
.call-face { transition: transform .5s var(--settle); }
/* a blink closes both eyes on their own centre line */
.call-lids { transform-origin: 50% 48.125%; }
/* a smile is the lower lids rising, and only ever worn briefly. The cheeks
   are there only while she smiles, so wherever she looks they never touch
   her ring. */
.call-cheeks { opacity: 0; transition: transform .34s var(--ease), opacity 0s linear .34s; }
.call-ola.is-happy .call-cheeks { opacity: 1; transform: translateY(-8.125%); transition: transform .34s var(--ease), opacity 0s; }

/* her voice: rings that leave the edge of her own ring, and a glow under it */
.call-rip {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(var(--ola) * 1.62);
  height: calc(var(--ola) * 1.62);
  margin: calc(var(--ola) * -0.81) 0 0 calc(var(--ola) * -0.81);
  border: 2px solid var(--violet);
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
}
.call-rip.is-bloom { border-width: 3px; }
.call-halo {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(var(--ola) * 1.9);
  height: calc(var(--ola) * 1.9);
  margin: calc(var(--ola) * -0.95) 0 0 calc(var(--ola) * -0.95);
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(122, 92, 255, 0.2) 50%, rgba(122, 92, 255, 0.07) 72%, rgba(122, 92, 255, 0));
  opacity: 0;
  pointer-events: none;
}

.call-them {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: var(--disc);
  /* the disc's centre on her centre, and the gap measured ring to disc */
  margin-top: calc((var(--box) - var(--disc)) / 2);
  margin-left: calc(var(--apart) - (var(--box) - var(--ola)) / 2);
  /* her box is wider than her ring by this on each side; the same on this
     side, so the pair as it is seen stands on the centre line */
  margin-right: calc((var(--box) - var(--ola)) / 2);
}
.call-av { position: relative; width: var(--disc); height: var(--disc); }
.call-disc {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: #fff;
  box-shadow: var(--ladder-lite), 0 0 0 1px rgba(0, 0, 0, 0.05);
  color: var(--ink);
}
.call-disc svg {
  width: 44%;
  height: 44%;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* their voice is a quieter ring that stays close to the disc */
.call-av .call-rip {
  width: calc(var(--disc) * 1.34);
  height: calc(var(--disc) * 1.34);
  margin: calc(var(--disc) * -0.67) 0 0 calc(var(--disc) * -0.67);
  border: 1.5px solid rgba(20, 21, 25, 0.42);
}

.call-name, .call-clock { white-space: nowrap; text-align: center; }
.call-name {
  margin-top: 14px;
  font-size: 14px;
  line-height: 18px;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.call-clock {
  margin-top: 1px;
  font-size: 13px;
  line-height: 17px;
  letter-spacing: -0.004em;
  color: var(--ink-quiet);
  font-variant-numeric: tabular-nums;
}

/* ---------- the line ---------- */

/* one line, always: every line anybody says fits it at 320 */
.call-said {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: calc(var(--cap) * 1.3);
  margin-top: 26px;
}
.call-cap {
  display: inline-flex;
  align-items: center;
  gap: 0.42em;
  font-size: var(--cap);
  line-height: 1.3;
  font-weight: 500;
  letter-spacing: -0.016em;
  color: var(--ink);
  white-space: nowrap;
}
/* the other side is the quieter voice on the page as well as on the line */
.call-cap.is-them { font-weight: 400; color: var(--ink-body); }
.call-t .call-w { display: inline-block; }

/* the one tick in the section, on the line that ends the call, in her colour */
.call-tick {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 1.12em;
  height: 1.12em;
  border-radius: 50%;
  background: var(--violet);
  color: #fff;
}
.call-tick svg {
  width: 66%;
  height: 66%;
  fill: none;
  stroke: currentColor;
  stroke-width: 3.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ---------- a phone ---------- */

@media (max-width: 760px) {
  .call-ask { min-height: 50px; padding: 6px 6px 6px 20px; font-size: clamp(13px, 3.75vw, 15px); }
  .call-ask .voicekey { width: 38px; height: 38px; }
}
/* the narrowest phones: every ask is given two lines of the composer, so a
   longer one never makes it taller */
@media (max-width: 377px) {
  .call-ask { min-height: 62px; }
}

/* ---------- wider: the call gets the room ---------- */

@media (min-width: 761px) {
  .call-stage { --ola: 132px; --disc: 88px; --apart: 104px; --cap: 22px; margin-top: 48px; }
  .call-pair { margin-top: 56px; }
  .call-said { margin-top: 36px; }
  .call-rip { border-width: 2.5px; }
  .call-name { margin-top: 16px; font-size: 15px; line-height: 20px; }
  .call-clock { font-size: 14px; line-height: 19px; }
}
@media (min-width: 1101px) {
  .call-stage { --ola: clamp(160px, 12.4vw, 184px); --disc: calc(var(--ola) * 0.64); --apart: calc(var(--ola) * 0.84); --cap: clamp(26px, 2vw, 30px); }
  .call-pair { margin-top: 64px; }
  .call-said { margin-top: 44px; }
  .call-rip { border-width: 3px; }
  .call-rip.is-bloom { border-width: 4px; }
  .call-name { margin-top: 18px; font-size: 17px; line-height: 22px; }
  .call-clock { font-size: 15px; line-height: 20px; }
}

@media (prefers-reduced-motion: reduce) {
  .call-face, .call-cheeks { transition: none; }
}

/* ---------- memory ---------- */

/* memory: Ola and what she keeps. One column on a phone, read top down: the
   ask, a stack of four notes at one size, Ola, and her answer in one line with
   its two replies. On a wide screen the same pieces stand in a row: the notes
   on her left, the answer on her right, the ask over her.

   Honey is this section's one colour and it is worn by one thing only: a note
   she is using. Ordinary css is the finished frame; the engine's parts step
   back only while the scene plays, and everything moves by transform and
   opacity. */

.memory {
  --mem-honey: #FFC94F;
  --mem-w: min(100%, 300px);          /* the column: the ask and the notes */
  --mem-ola: clamp(96px, 24vw, 124px);
  --mem-card: 46px;
  --mem-note: 16px;
  --mem-say: 19px;
}

.mem-stage {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
}

/* ---------- the ask ---------- */

.mem-ask { width: var(--mem-w); margin-bottom: 24px; }
.mem-ask .voicekey { margin-left: auto; }

/* ---------- what she keeps: cards in a pocket ---------- */

/* four cards in a stack, each standing in front of the one before and lower
   by the height of its own line, so every card shows its top strip and casts
   a soft shadow up onto the one behind */
.mem-notes {
  --strip: var(--mem-card);
  position: relative;
  z-index: 2;
  display: grid;
  width: var(--mem-w);
}
.mem-note {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: flex-start;
  height: calc(var(--strip) + 20px);
  margin-top: -20px;
  padding: 0 18px;
  line-height: var(--strip);
  border-radius: 16px;
  background: #fff;
  box-shadow: 0 0 0 1px rgba(20, 21, 25, 0.05), 0 -5px 12px -8px rgba(20, 21, 25, 0.16);
  font-size: var(--mem-note);
  letter-spacing: -0.012em;
  color: var(--ink);
  white-space: nowrap;
}
.mem-note:first-child { margin-top: 0; }
.mem-note:last-child { height: var(--strip); box-shadow: 0 0 0 1px rgba(20, 21, 25, 0.05), 0 -5px 12px -8px rgba(20, 21, 25, 0.16), 0 8px 20px -12px rgba(20, 21, 25, 0.2); }
/* a note she is using: honey, poured in under its words */
.mem-lit {
  position: absolute;
  z-index: -1;
  inset: 0;
  border-radius: inherit;
  background: var(--mem-honey);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45), 0 4px 12px -6px rgba(150, 100, 0, 0.45);
}
/* every part of this scene keeps a transition at rest too: when the first play
   lets go of the finished frame and then hides the parts, they are carried
   from one hidden state to the other and never flash back up in between */
.armed .mem-stage .part { transition: opacity .3s var(--ease); }
.armed .mem-stage.is-playing .mem-lit { opacity: 0; transform: scale(0.94); transition: opacity .24s var(--ease), transform .6s var(--settle); }
.armed .mem-stage.is-playing .mem-lit.on { opacity: 1; transform: none; }
.armed .mem-stage.is-resetting .mem-lit { transform: none; filter: none; }

/* a tab of a lit note's honey on its way into her, drawn by the script. It
   starts tucked behind its card: the notes stand in front of it. */
.mem-tab {
  position: absolute;
  z-index: 1;
  width: 30px;
  height: 16px;
  margin: -8px 0 0 -15px;
  border-radius: 8px;
  background: var(--mem-honey);
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.55), 0 4px 10px -3px rgba(150, 100, 0, 0.55);
  pointer-events: none;
}

/* ---------- Ola ---------- */

.mem-ola { width: var(--mem-ola); margin-top: 26px; color: var(--ink); }
.mem-ola svg { width: 100%; height: auto; overflow: visible; }
.mem-ring { fill: none; stroke: currentColor; stroke-width: 6.6; }
.mem-eye { fill: currentColor; }
.mem-body, .mem-eye { transform-box: fill-box; transform-origin: 50% 50%; }
.mem-eyes { transition: transform .5s var(--settle); }
.mem-cheeks { transition: transform .34s var(--ease); }
.mem-ola.is-happy .mem-cheeks { transform: translateY(-5.2px); }

/* ---------- her answer, out of her ---------- */

.mem-reply { display: grid; justify-items: center; gap: 16px; margin-top: 16px; text-align: center; }
.mem-say { font-size: var(--mem-say); line-height: 1.3; letter-spacing: -0.018em; color: var(--ink); }
.mem-chips { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
.mem-chip {
  display: inline-flex;
  align-items: center;
  height: 40px;
  padding: 0 18px;
  border-radius: var(--radius);
  background: #fff;
  box-shadow: 0 0 0 1px rgba(20, 21, 25, 0.09);
  font-size: 14.5px;
  font-weight: 500;
  letter-spacing: -0.008em;
  color: var(--ink);
  white-space: nowrap;
}
.mem-chip.is-yes { background: var(--ink); color: var(--ground); box-shadow: 0 1px 2px rgba(24, 28, 38, 0.28); }

.armed .mem-stage.is-playing .mem-say { transform: translateY(-14px) scale(0.94); transform-origin: 50% 0; transition: opacity .45s var(--ease), transform .8s var(--settle); }
.armed .mem-stage.is-playing .mem-chip { transform: translateY(6px) scale(0.92); transition: opacity .3s var(--ease), transform .6s var(--settle); }
.armed .mem-stage.is-playing .mem-say.on, .armed .mem-stage.is-playing .mem-chip.on { transform: none; }

/* ---------- a tablet: the same column, a size up ---------- */

@media (min-width: 600px) and (max-width: 959px) {
  .memory { --mem-w: 340px; --mem-card: 50px; --mem-note: 17px; --mem-say: 21px; }
  .mem-ask { margin-bottom: 28px; }
  .mem-ola { margin-top: 32px; }
  .mem-reply { margin-top: 20px; }
  .mem-chip { height: 42px; padding: 0 20px; font-size: 15px; }
}

/* ---------- a wide screen: the notes, Ola, the answer, in a row ---------- */

@media (min-width: 960px) {
  .memory { --mem-w: clamp(292px, 23vw, 320px); --mem-ola: clamp(148px, 12vw, 172px); --mem-card: 52px; --mem-note: 17px; --mem-say: clamp(24px, 2vw, 28px); }
  .mem-stage { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); column-gap: clamp(56px, 6.4vw, 96px); align-items: center; }
  .mem-ask { grid-column: 1 / -1; width: 360px; margin-bottom: 64px; }
  .mem-chip { height: 44px; padding: 0 20px; font-size: 15.5px; }
  .mem-tab { width: 36px; height: 20px; margin: -10px 0 0 -18px; border-radius: 10px; }
  .mem-notes { grid-area: 2 / 1; justify-self: end; }
  .mem-ola { grid-area: 2 / 2; margin: 0; }
  .mem-reply { grid-area: 2 / 3; justify-self: start; justify-items: start; margin: 0; text-align: left; }
  .armed .mem-stage.is-playing .mem-say { transform: translateX(-18px) scale(0.96); transform-origin: 0 50%; }
}

/* ---------- motion refused ---------- */

@media (prefers-reduced-motion: reduce) {
  .mem-eyes, .mem-cheeks { transition: none; }
}

/* ---------- close ---------- */

/* The page ends on Ola itself: the mark, drawn as large as the page is wide,
   half risen over the foot of a night-blue slab and looking back at you. */
.close {
  /* one unit of the mark: the ring's outer diameter is 46.2 of them */
  --D: clamp(880px, 68vw, 1080px);   /* never smaller than the words it holds */
  /* rounded to an even number of px so the svg's left edge (viewport/2 - D/2)
     and its width both land on whole device pixels: the two hairline rims are
     1.25px non-scaling strokes and a half pixel turns them to mush. The plain
     declaration above stands wherever round() is not understood. */
  --D: round(clamp(880px, 68vw, 1080px), 2px);
  --u: calc(var(--D) / 46.2);
  --top: 22px;                /* the crown, under the slab's top edge */
  --k: 54px;                  /* the heading, set inside the crown */
  --gap: 96px;                /* between the eyes and the foot: where the ring dissolves */
  --h2: clamp(32px, 3.6vw, 52px);
  --m: clamp(18px, 2vw, 26px);

  --glow-y: calc(var(--top) + var(--D) * 0.55);
  --sky-top: #0B1530;
  --sky-foot: #050A18;
  --glow: rgba(86, 120, 255, 0.26);
  --pale: 232, 238, 255;
  --eye: #F4F7FF;

  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: calc(var(--top) + var(--k)) var(--gutter) 0;
  margin-top: clamp(24px, 4vw, 56px);
  color: var(--ink-on-deep);
  background:
    radial-gradient(calc(var(--D) * 0.7) calc(var(--D) * 0.6) at 50% var(--glow-y), var(--glow), transparent),
    linear-gradient(180deg, var(--sky-top), var(--sky-foot));
  /* the light room ends on a soft round shoulder */
  border-radius: clamp(28px, 4vw, 56px) clamp(28px, 4vw, 56px) 0 0;
}

.close-grid { position: relative; z-index: 2; display: flex; justify-content: center; }
.close-say { display: flex; flex-direction: column; align-items: center; text-align: center; width: 100%; }
.close .h2 { color: var(--ink-on-deep); font-size: var(--h2); letter-spacing: -0.046em; line-height: 1; white-space: nowrap; }
.close .capture { margin-top: var(--m); max-width: 440px; }
/* the pill is night glass here: it lies across the lit crown, and its words must not */
.close .capture.on-deep { background: rgba(9, 16, 40, 0.5); }
.close .note { padding-left: 0; }
/* the answer is longer than the question: the pill makes room for it */
.close .capture.is-joined { max-width: 540px; }
.close .joined { text-align: left; }
.close .joined [data-joined-text] { text-wrap: pretty; }

/* The stage starts at the crown and is exactly as tall as the crown to the
   foot of the eyes, plus the gap: at every width the eyes stand just clear of
   the foot, and the rest of the ring goes down behind it into the night. */
.close-stage {
  position: relative;
  z-index: 0;
  flex: 0 0 auto;
  height: calc(var(--u) * 25.14 + var(--gap));
  margin: calc(-1 * (var(--h2) + var(--m) + var(--field-h) + 33.5px + var(--k))) calc(-1 * var(--gutter)) 0;
  pointer-events: none;
}
/* the fade that makes it half there. Its box is wider and taller than the
   ring by --pad, so a lean or a breath never meets its edge. */
.close-sky {
  --pad: calc(var(--u) * 3);
  /* Solid to the foot of the eyes, then gone by the top of the foot's type.
     The ring is cut near its equator, where its legs are vertical and at their
     brightest, so a short straight ramp reads as a scissor cut. This one runs
     the whole gap and is shaped like a smoothstep: it leaves full strength
     slowly, gives up the middle quickly, and arrives at nothing slowly, so
     neither end of the dissolve has a visible kink. */
  --solid: calc(var(--pad) + var(--u) * 25.14);
  --run: calc(var(--gap) + 16px);
  --fade: linear-gradient(180deg,
      #000               var(--solid),
      rgba(0, 0, 0, .93) calc(var(--solid) + var(--run) * 0.18),
      rgba(0, 0, 0, .70) calc(var(--solid) + var(--run) * 0.42),
      rgba(0, 0, 0, .34) calc(var(--solid) + var(--run) * 0.66),
      rgba(0, 0, 0, .10) calc(var(--solid) + var(--run) * 0.85),
      transparent        calc(var(--solid) + var(--run)));
  position: absolute;
  left: 50%;
  top: calc(-1 * var(--pad));
  width: calc(var(--D) + 2 * var(--pad));
  height: calc(var(--D) + var(--pad));
  translate: -50% 0;
  -webkit-mask-image: var(--fade);
          mask-image: var(--fade);
}
.close-ola {
  position: absolute;
  left: var(--pad);
  top: var(--pad);
  width: var(--D);
  height: var(--D);
  overflow: visible;
  transform-origin: 50% 90%;
}
.close.is-awake .close-ola { animation: close-breathe 2.6s ease-in-out infinite alternate; }
/* breathing: a rise of a few pixels and a stretch you feel more than see */
@keyframes close-breathe { to { transform: translateY(calc(var(--u) * -0.2)) scale(0.998, 1.004); } }

/* the mark itself, flat: the same Ola the page has shown all the way down,
   not a picture of one in glass. At night her ring is a shade of the dark and
   her eyes are the light, so the words written over her ring stay readable */
.close-ring { fill: none; stroke: rgba(var(--pale), .13); stroke-width: 6.6; }
.close-rim { display: none; }
.close-eye circle { fill: var(--ink-on-deep); }

/* ---------- the foot ---------- */

.foot {
  position: relative;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 28px;
  padding-block: 14px calc(18px + env(safe-area-inset-bottom));
}
.foot-mark { display: inline-flex; align-items: center; color: var(--ink-on-deep); text-decoration: none; font-size: 19px; font-weight: 500; letter-spacing: 0.012em; line-height: 1; }
/* The row is aligned by its middles, and a 19px word's baseline sits about
   2px under a 13px word's when the two are centred on the same axis. Measured
   at 2.25px; taken back by a whole pixel pair so the glyphs stay on the grid. */
.foot-mark { translate: 0 -2px; }
.foot-mark svg { width: 22px; height: 22px; }
.foot-mark span { margin-left: -1px; }
.foot .legal { flex: 1 1 auto; }
.foot-mail { font-size: var(--micro); color: rgba(255, 255, 255, 0.86); text-decoration: none; }
@media (hover: hover) { .foot-mail:hover { color: #fff; text-decoration: underline; text-underline-offset: 3px; } }

/* The consent card appends its own control to this nav. It arrives two steps
   quieter than the links beside it and in a taller box, which puts its word
   off the row's baseline. Here it is one of the links. */
.close .legal .ola-privacy-choices { min-height: 0; opacity: 1; }
.close .legal .ola-privacy-dot { opacity: 1; }
.close .legal .ola-privacy-choices:focus-visible { border-radius: 4px; }

/* the field's button is dark ink on a light pill standing on a dark slab: its
   ring has to be the light one, and a pill's ring is a pill */
.close .go:focus-visible { outline-color: var(--ink-on-deep); border-radius: var(--radius); }

/* a finger gets 44px of the foot's links without the row changing size */
@media (pointer: coarse) {
  .close .legal a, .close .legal button, .close .foot-mail { padding-block: 13px; margin-block: -13px; }
  /* a short word gets the width too, and the mark in the foot its height */
  .close .legal a { padding-inline: 4px; margin-inline: -4px; }
  .close .foot-mark { padding-block: 11px; margin-block: -11px; }
  /* the join button is a whole 44px, a pixel nearer the pill's edge each side */
  .close .capture .go { height: max(44px, calc(var(--field-h) - 14px)); }
}

/* On a phone the words stand above the crown and the ring is wider than the
   screen: only the arch of its head and its eyes are there. */
@media (max-width: 760px) {
  .close { --D: min(112vw, 560px); --D: round(min(112vw, 560px), 2px); --top: 36px; --k: 0px; --gap: 96px; --h2: clamp(30px, 9vw, 42px); --m: 18px; --glow-y: calc(100% - var(--D) * 0.2); }
  .close-stage { margin-top: 14px; }
  /* the foot stands on its own night, so no link ever lies across her ring */
  .foot {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 14px 16px;
    align-items: center;
    width: calc(100% + 2 * var(--gutter));
    max-width: none;
    margin-inline: calc(-1 * var(--gutter));
    padding: 22px var(--gutter) calc(20px + env(safe-area-inset-bottom));
    background: linear-gradient(180deg, rgba(5, 10, 24, 0), #050A18 18px);
    border-top: 1px solid rgba(255, 255, 255, 0.06);
  }
  /* Six links do not wrap tidily behind separators: at every phone width one
     dot ends up dangling at the end of a line. On a phone the dots go and the
     six links break into two even rows of three instead. */
  .foot .legal { grid-column: 1 / -1; grid-row: 1; gap: 10px 18px; }
  .foot .legal > span { display: none; }
  .close .capture.is-joined { height: auto; min-height: var(--field-h); padding-block: 12px; border-radius: 26px; }
  .close .joined { flex-wrap: wrap; row-gap: 6px; }
  .close .joined [data-joined-text] { flex: 1 1 200px; }
  .close .joined a { margin-left: 34px; }
}

/* Under 381px "Beta confidentiality" and "privacy choices" cannot share a row,
   so the six stand in two columns instead of breaking into a ragged run. */
@media (max-width: 380px) {
  .foot .legal { display: grid; grid-template-columns: repeat(2, auto); justify-content: start; gap: 10px 14px; }
}

/* At 320 the shared field and its button leave "Your email" 4px short of its
   own width, here and in the hero. This is the close's own room to give. */
@media (max-width: 380px) {
  .close .field { padding-left: 18px; }
  .close .go { padding: 0 13px; }
  .close .capture-status { left: 18px; }
}

@media (prefers-reduced-motion: reduce) { .close.is-awake .close-ola { animation: none; } }
.is-still .close.is-awake .close-ola { animation: none; }
