/* Inloop landing page (inlooop.com). Colours, radii, shadows and type are the app's own Night
   values (app/globals.css); every glow is one of those colours, blurred. Urbanist 400/500 only. */

@font-face {
  font-family: "Urbanist";
  src: url("fonts/urbanist-400.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Urbanist";
  src: url("fonts/urbanist-500.ttf") format("truetype");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

:root {
  color-scheme: dark;
  --canvas-top: #22211f;
  --canvas-bottom: #171614;
  --surface: #262523;
  --field: #2c2b29;
  --tray: #33322f;
  --bubble: #302f2c;
  --line: #3a3936;
  --line-strong: #75736d;
  --ink: #edece8;
  --ink-2: #bab8b0;
  --muted: #9a9890;

  --blue: #4a9edb;
  --blue-light: #6cb8ec;
  --pink: #ff9b99;
  --yellow: #f4be50;
  --green: #5fc454;
  --blue-tint: #173049;
  --blue-label: #85b7eb;
  --blue-strong: #bfddf7;
  --yellow-tint: #3d2b13;
  --yellow-label: #ef9f27;
  --yellow-strong: #fac775;
  --green-tint: #24371a;
  --green-label: #97c459;
  --green-strong: #c0dd97;
  --pink-tint: #45201f;
  --pink-label: #f09595;
  --pink-strong: #f7c1c1;
  --app-tile: #393939; /* the app icon's tile (Day ink) */

  --glass: rgb(38 37 35 / 0.55);
  --glass-deep: rgb(51 50 47 / 0.74);
  --shadow-solid: 0 1px 2px rgb(0 0 0 / 0.3), 0 10px 30px -12px rgb(0 0 0 / 0.55);
  --shadow-lift: 0 2px 4px rgb(0 0 0 / 0.35), 0 18px 40px -12px rgb(0 0 0 / 0.7);
  --shadow-glass: inset 0 0 0 1px rgb(255 255 255 / 0.06), 0 16px 48px -16px rgb(0 0 0 / 0.55);
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.09'/%3E%3C/svg%3E");

  --pad: clamp(16px, 5vw, 56px);
  --max: 1240px;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* Base */
*,
*::before,
*::after {
  box-sizing: border-box;
}
* {
  margin: 0;
}
html {
  background: var(--canvas-bottom);
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior-y: none;
  scroll-padding-top: 96px;
}
html:focus-within {
  scroll-behavior: smooth;
}
body {
  font: 400 17px/1.5 Urbanist, ui-sans-serif, system-ui, sans-serif;
  color: var(--ink);
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
/* The app's canvas, at Night: warm charcoal with a faint grain and a little light from above. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background:
    var(--grain),
    radial-gradient(110% 55% at 50% 0%, rgb(255 255 255 / 0.035), transparent 70%),
    linear-gradient(180deg, var(--canvas-top), var(--canvas-bottom));
}
::selection {
  background: var(--blue-tint);
}
:focus-visible {
  outline: 1px solid var(--ink-2); /* a thin grey line, never a blue ring (the owner, 18 Oct) */
  outline-offset: 3px;
}
a {
  color: inherit;
}
button {
  font: inherit;
  color: inherit;
}
h1,
h2,
h3 {
  font-weight: 500;
  text-wrap: balance;
}
h2 {
  font-size: clamp(34px, 4.4vw, 62px);
  line-height: 1.04;
  letter-spacing: -0.032em;
}
p {
  text-wrap: pretty;
}
.sub {
  font-size: clamp(17px, 1.3vw, 20px);
  line-height: 1.5;
  color: var(--ink-2);
  max-width: 32em;
}
.wrap {
  width: min(var(--max), 100% - 2 * var(--pad));
  margin-inline: auto;
}
.sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}
.ic {
  width: 16px;
  height: 16px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.logo {
  width: 32px;
  height: 32px;
  flex: none;
  color: var(--ink);
}
.skip {
  position: fixed;
  z-index: 100;
  top: 12px;
  left: 12px;
  padding: 10px 16px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--surface);
  text-decoration: none;
  translate: 0 -200%;
}
.skip:focus {
  translate: none;
}
.c-blue {
  color: var(--blue-label);
}
.c-yellow {
  color: var(--yellow-label);
}
.c-green {
  color: var(--green-label);
}
.c-pink {
  color: var(--pink-label);
}
.at {
  color: var(--blue-label);
}

/* Buttons: the app's pills. Hover lifts them; the primary one picks up the signature colours underneath. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 52px;
  padding: 0 26px;
  border-radius: 999px;
  font: 500 16px/1 Urbanist, ui-sans-serif, system-ui, sans-serif;
  text-decoration: none;
  white-space: nowrap;
  transition:
    transform 200ms ease-out,
    box-shadow 300ms ease-out;
}
.btn-sm {
  height: 44px;
  padding: 0 20px;
  font-size: 15px;
}
.btn-primary {
  background: var(--ink);
  color: var(--surface);
  box-shadow: var(--shadow-solid);
}
.btn-glass {
  background: var(--glass);
  -webkit-backdrop-filter: blur(20px) saturate(1.3);
  backdrop-filter: blur(20px) saturate(1.3);
  box-shadow: var(--shadow-glass);
  color: var(--ink);
}
@media (hover: hover) {
  .btn:hover {
    transform: translateY(-2px) scale(1.01);
  }
  .btn-primary:hover {
    box-shadow: var(--shadow-lift);
  }
}
.btn:active {
  transform: scale(0.98);
}
.ctas {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin-top: 32px;
}

/* Top bar: the app's glass pill. The strip it floats in is canvas, so nothing shows above it. */
/* Solid down to the bar's bottom edge, so nothing shows in the gaps beside it, then a short fade. */
.bar-fade {
  position: fixed;
  z-index: 40;
  inset: 0 0 auto;
  height: 100px;
  pointer-events: none;
  background: var(--grain), var(--canvas-top);
  -webkit-mask-image: linear-gradient(#000 0 76px, transparent 100px);
  mask-image: linear-gradient(#000 0 76px, transparent 100px);
}
.bar {
  position: fixed;
  z-index: 50;
  top: 12px;
  left: 50%;
  translate: -50% 0;
  width: max-content; /* as wide as its contents, so there's no empty stretch in the middle */
  max-width: calc(100% - 24px);
  height: 64px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 10px 0 12px;
  border-radius: 999px;
  background: var(--glass);
  -webkit-backdrop-filter: blur(20px) saturate(1.3);
  backdrop-filter: blur(20px) saturate(1.3);
  box-shadow: var(--shadow-glass);
}
.bar-logo {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
}
.bar-logo .logo {
  width: 34px;
  height: 34px;
}
.bar-links {
  display: flex;
  gap: 2px;
  margin-left: 6px;
}
.bar-links a,
.bar-signin {
  padding: 10px 14px;
  border-radius: 999px;
  font-size: 15px;
  color: var(--ink-2);
  text-decoration: none;
  transition:
    color 200ms,
    background-color 200ms;
}
.bar-signin {
  color: var(--ink);
}
@media (hover: hover) {
  .bar-links a:hover,
  .bar-signin:hover {
    color: var(--ink);
    background: rgb(237 236 232 / 0.06);
  }
}
.bar-end {
  margin-left: 6px;
  display: flex;
  align-items: center;
  gap: 4px;
}
/* Once the opening run lands: a light in the four colours sweeps once round the bar (the app's bar-glow). */
.bar-glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
}
.bar.glow .bar-glow {
  animation: bar-glow 1.6s cubic-bezier(0.33, 1, 0.68, 1) both;
}
.bar-glow > span {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: 999px;
  padding: 1.5px;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}
.bar-glow > span > span {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 110%;
  aspect-ratio: 1;
  background: conic-gradient(var(--blue), var(--pink), var(--yellow), var(--green), var(--blue));
  transform: translate(-50%, -50%);
}
.bar.glow .bar-glow > span > span {
  animation: bar-glow-sweep 1.6s var(--ease) both;
}
.bar-glow-halo {
  filter: blur(12px);
}
.bar-glow-halo > span {
  padding: 6px;
}
@keyframes bar-glow {
  18% {
    opacity: 1;
  }
  55% {
    opacity: 0.85;
  }
  to {
    opacity: 0;
  }
}
@keyframes bar-glow-sweep {
  from {
    transform: translate(-50%, -50%) rotate(-90deg);
  }
  to {
    transform: translate(-50%, -50%) rotate(270deg);
  }
}
@media (max-width: 860px) {
  .bar-links {
    display: none;
  }
}
@media (max-width: 639px) {
  .bar {
    top: 10px;
    height: 58px;
    max-width: calc(100% - 20px);
    padding-left: 8px;
  }
  .bar-fade {
    height: 92px;
    -webkit-mask-image: linear-gradient(#000 0 68px, transparent 92px);
    mask-image: linear-gradient(#000 0 68px, transparent 92px);
  }
  .bar-signin {
    padding: 10px;
  }
  .btn-sm {
    height: 42px;
    padding: 0 16px;
  }
}

/* 1. Hero: the wordmark, its three O's as loops. */
.hero {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 112px var(--pad) 72px;
}
.hero h1 {
  font-size: clamp(36px, 5.4vw, 78px);
  line-height: 1;
  letter-spacing: -0.035em;
}
.hero .sub {
  margin: 20px auto 0;
}
.mark {
  position: relative;
  isolation: isolate;
  width: min(980px, 90vw, 108svh);
  margin-bottom: clamp(28px, 5svh, 56px);
  transform: perspective(1400px) rotateX(var(--tx, 0deg)) rotateY(var(--ty, 0deg));
  transition: transform 600ms var(--ease);
}
.mark[data-hero] {
  cursor: pointer;
}
.word {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}
.letters {
  fill: var(--ink);
}
.ring {
  fill: none;
  stroke-linecap: round;
}
.ring .ghost {
  stroke: var(--line);
  stroke-width: 8.07;
}
.ring .halo {
  stroke: var(--c);
  stroke-width: 15;
  filter: url(#f-halo);
  opacity: 0.6;
}
.ring .glow {
  stroke: var(--c);
  stroke-width: 9.5;
  filter: url(#f-glow);
}
.ring .tube {
  stroke: var(--core);
  stroke-width: 8.07;
}
.ring.lit .halo {
  animation: flare 1.1s var(--ease);
}
@keyframes flare {
  25% {
    opacity: 1;
    stroke-width: 24;
  }
}
.dot {
  fill: var(--yellow);
  transform-box: fill-box;
  transform-origin: 50% 100%;
}
.dot-glow {
  fill: var(--yellow);
  filter: url(#f-dot);
  opacity: 0.85;
}
.trail {
  fill: var(--yellow);
}
.mark.landed .dot {
  animation: land 520ms var(--ease);
}
@keyframes land {
  30% {
    transform: scale(1.3, 0.72);
  }
  62% {
    transform: scale(0.92, 1.1);
  }
}
.o-label {
  position: absolute;
  left: var(--x);
  top: 79%;
  translate: -50% 0;
  font-size: clamp(12px, 1.3vw, 18px);
  color: var(--ink-2);
  transition:
    opacity 600ms,
    translate 600ms var(--ease);
  pointer-events: none;
}
/* Soft coloured light each O throws on the "wall" once it's lit. */
.room {
  position: absolute;
  z-index: -1;
  left: var(--x);
  top: 50%;
  width: 46%;
  aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  background: radial-gradient(closest-side, var(--g), transparent);
  mix-blend-mode: screen;
  pointer-events: none;
  transition: opacity 1400ms ease-out;
}
/* With JavaScript the O's start dark and light one by one; without it they are simply lit. */
.js .mark .draw,
.js .mark .room,
.js .mark .o-label {
  opacity: 0;
}
.js .mark .o-label {
  translate: -50% 6px;
}
.js .mark .ring.on .tube,
.js .mark .ring.on .glow {
  opacity: 1;
}
.js .mark .ring.on .halo {
  opacity: 0.6;
}
.js .mark .room.on {
  opacity: 1;
}
.js .mark .o-label.on {
  opacity: 1;
  translate: -50% 0;
}

/* The hero's pop-up, then the task it opens. Wide screens: bottom right, clear of the headline and
   buttons. Narrower ones: under the buttons, in a box already the card's height, so nothing below
   moves when the pop-up becomes the card. */
.hello {
  position: absolute;
  z-index: 2;
  right: var(--pad);
  bottom: clamp(28px, 6svh, 64px);
  width: min(336px, (100vw - 680px) / 2 - 24px);
  text-align: left;
  pointer-events: none;
}
.hello.in {
  pointer-events: auto;
}
.hello-pop {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 14px;
  border-radius: 22px;
  background: var(--glass-deep);
  -webkit-backdrop-filter: blur(20px) saturate(1.3);
  backdrop-filter: blur(20px) saturate(1.3);
  box-shadow: var(--shadow-glass);
  opacity: 0;
  translate: 0 16px;
  transition:
    opacity 500ms,
    translate 600ms var(--ease);
}
.hello.in .hello-pop {
  opacity: 1;
  translate: none;
}
.hello-acts {
  display: flex;
  gap: 6px;
  margin-top: 8px;
}
.hello-acts button {
  padding: 6px 12px;
  border: 0;
  border-radius: 999px;
  background: rgb(237 236 232 / 0.1);
  font-size: 13px;
  color: var(--ink);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 200ms;
}
@media (hover: hover) {
  .hello-acts button:hover {
    background: rgb(237 236 232 / 0.18);
  }
}
.hello .hello-card,
.hello.opened .hello-pop {
  display: none;
}
.hello.opened .hello-card {
  display: flex;
}
/* One shape for the pop-up and the card it becomes, so the browser can morph one into the other. */
.hello:not(.opened) .hello-pop,
.hello.opened .hello-card {
  view-transition-name: hello-task;
}
::view-transition-group(hello-task) {
  animation-duration: 450ms;
  animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
}
.hello-you {
  font-size: 13px;
  color: var(--ink-2);
}
.hello-by {
  font-size: 13px;
  color: var(--ink-2);
}
/* Opening it is Got it: the loop round your photo closes. */
.hello.got .av-ring {
  stroke-dashoffset: 0;
}
.hello.got .av-dot {
  scale: 0;
}
.hello.got .av-loop {
  opacity: 0;
}
.hello-note {
  margin-top: 12px;
  padding: 0 4px;
  font-size: 14px;
  color: var(--ink-2);
  opacity: 0;
  translate: 0 6px;
  transition:
    opacity 400ms,
    translate 500ms var(--ease);
}
.hello-note a {
  color: var(--ink);
  text-underline-offset: 3px;
}
.hello.got .hello-note {
  opacity: 1;
  translate: none;
}
.hello.gone {
  opacity: 0;
  pointer-events: none;
  transition: opacity 300ms;
}
@media (max-width: 1179px) {
  .hello {
    position: relative;
    right: auto;
    bottom: auto;
    width: min(340px, 100%);
    height: 236px;
    margin: 32px auto 0;
  }
}

/* 2. Story: chaos gathers into a loop, then a task goes round it. */
/* The values main.js writes on every scroll frame. Not inherited, and written only on the elements that
   use them, so a frame restyles those few elements rather than the whole scene. */
@property --rp {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}
@property --a-o {
  syntax: "<number>";
  inherits: false;
  initial-value: 1;
}
@property --b-o {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}
@property --c-o {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}
@property --s-o {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}
@property --l-o {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}
@property --l-x {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;
}
@property --l-y {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;
}
.story {
  position: relative;
  height: 720vh;
}
/* Menu links land with the scene pinned at the top (the page's scroll padding would stop them short). */
.story,
.runway {
  scroll-margin-top: -96px;
}
.story-pin {
  --D: clamp(400px, min(68svh, 44vw), 620px);
  --R: calc(var(--D) / 2 - 3px);
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  column-gap: clamp(32px, 5vw, 96px);
  padding: 96px max(var(--pad), (100% - var(--max)) / 2) 32px;
}
.msgs {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.msg {
  position: absolute;
  left: 50%;
  top: 50%;
  max-width: 250px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 12px 6px;
  border-radius: 18px;
  background: var(--bubble);
  box-shadow: var(--shadow-solid);
  font-size: 15px;
  line-height: 1.35;
  white-space: nowrap;
  transform: translate(-50%, -50%) translate(calc(var(--x) * 50vw), calc(var(--y) * 50vh)) rotate(calc(var(--r) * 1deg));
  filter: blur(calc((1 - var(--z)) * 3px));
  will-change: transform, opacity;
}
.msg .who {
  font-size: 13px;
}
.msg .meta,
.bub .meta {
  align-self: flex-end;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 11px;
  color: var(--muted);
}
.msg.me {
  background: var(--tray);
}
.msg.sys {
  flex-direction: row;
  align-items: center;
  gap: 8px;
  padding: 9px 16px;
  border-radius: 999px;
  background: var(--field);
  font-size: 13px;
  color: var(--ink-2);
}
/* Anil's request, the one message that matters: clear at first, then buried as the chat piles up
   (main.js story). */
.msg.ask {
  width: max-content; /* centred from left: 50%, it would only get half the screen */
  max-width: min(300px, 100vw - 48px);
  white-space: normal;
  box-shadow:
    0 0 0 1px rgb(74 158 219 / 0.5),
    var(--shadow-solid);
  transition: none;
}
/* The task in his request: who, what and when light up one after another, just before it becomes the card. */
.msg.ask > * {
  opacity: var(--t-o, 1); /* its words fade before it becomes the card */
}
.ask .hl {
  margin: 0 -3px;
  padding: 0 3px;
  border-radius: 5px;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  transition:
    background-color 400ms var(--ease),
    color 400ms var(--ease);
}
.ask.picked .hl-who {
  background: var(--blue-tint);
}
.ask.picked .hl-what {
  background: rgb(237 236 232 / 0.1);
  color: var(--ink);
  transition-delay: 200ms;
}
.ask.picked .hl-when {
  background: var(--yellow-tint);
  color: var(--yellow-strong);
  transition-delay: 400ms;
}
.typing .dots {
  display: inline-flex;
  gap: 3px;
}
.typing .dots i {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: currentColor;
  animation: typing 1.2s infinite;
}
.typing .dots i:nth-child(2) {
  animation-delay: 0.2s;
}
.typing .dots i:nth-child(3) {
  animation-delay: 0.4s;
}
@keyframes typing {
  30% {
    opacity: 1;
  }
  0%,
  60%,
  100% {
    opacity: 0.3;
  }
}
.msg .file {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 3px 0 1px;
  padding: 8px 10px;
  border-radius: 12px;
  background: var(--field);
  font-size: 14px;
}
.tick {
  width: 15px;
  height: 15px;
}
.say {
  position: absolute;
  z-index: 1;
  left: 50%;
  top: 50%;
  translate: -50% -50%;
  width: min(780px, 100% - 2 * var(--pad));
  text-align: center;
  pointer-events: none;
}
/* A soft pool of the canvas behind the words, so a drifting bubble never runs over them. */
.say::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -32px -16px;
  background: radial-gradient(closest-side, rgb(34 33 31 / 0.9), transparent);
}
.say h2 {
  font-size: clamp(36px, 5.4vw, 76px);
  letter-spacing: -0.035em;
}
.say p {
  margin: 18px auto 0;
  max-width: 28em;
  font-size: clamp(17px, 1.35vw, 20px);
  color: var(--ink-2);
}
.say-a {
  opacity: var(--a-o, 1);
}
.say-b {
  opacity: var(--b-o, 0);
  width: min(calc(var(--D) * 0.74), 100% - 2 * var(--pad));
}
.say-b h2 {
  font-size: clamp(30px, 3.4vw, 50px);
}
/* Beside the loop, in the step texts' place (main.js story): left-aligned like them on wide screens. */
@media (min-width: 900px) {
  .say-b {
    text-align: left;
  }
  .say-b p {
    margin-left: 0;
  }
}

.stages {
  list-style: none;
  padding: 0;
  display: grid;
  max-width: 30rem;
  opacity: var(--s-o, 0);
}
/* A step's text leaves quickly, and the next one comes in just after, so two never overlap. */
.stages li {
  grid-area: 1 / 1;
  opacity: 0;
  translate: 0 16px;
  transition:
    opacity 140ms ease,
    translate 600ms var(--ease);
}
.stages h3 {
  margin-bottom: 14px;
  font-size: clamp(32px, 3.6vw, 52px);
  line-height: 1.04;
  letter-spacing: -0.032em;
}
.stages p {
  font-size: clamp(17px, 1.35vw, 20px);
  color: var(--ink-2);
}
[data-stage="0"] .stages li:nth-child(1),
[data-stage="1"] .stages li:nth-child(2),
[data-stage="2"] .stages li:nth-child(3),
[data-stage="3"] .stages li:nth-child(4),
[data-stage="4"] .stages li:nth-child(5),
[data-stage="5"] .stages li:nth-child(6) {
  opacity: 1;
  translate: none;
  transition:
    opacity 300ms ease 140ms,
    translate 600ms var(--ease) 140ms;
}

.stage {
  display: grid;
  place-items: center;
}
.loop {
  position: relative;
  width: var(--D);
  height: var(--D);
  display: grid;
  place-items: center;
  opacity: var(--l-o, 0);
  transform: translate(var(--l-x, 0px), var(--l-y, 0px));
  will-change: transform, opacity;
}
@property --draw {
  syntax: "<number>";
  inherits: false;
  initial-value: 1;
}
/* The ring draws itself round Anil's request (main.js story), clockwise from the top. Masked only while it
   draws, so its outer glow isn't cut once it's whole. */
.loop.drawing .loop-track {
  -webkit-mask: conic-gradient(#000 calc(var(--draw) * 360deg), transparent 0);
  mask: conic-gradient(#000 calc(var(--draw) * 360deg), transparent 0);
}
.loop-track {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow:
    inset 0 0 0 6px rgb(237 236 232 / 0.07),
    0 0 60px -10px rgb(237 236 232 / 0.06);
}
/* The coloured loop fills clockwise from the top as the task moves (--rp, 0–1). The halo is
   blurred inside its own box, so only the progress cut-out changes as you scroll. */
.loop-prog {
  position: absolute;
  inset: -48px;
  -webkit-mask: conic-gradient(#000 calc(var(--rp, 0) * 360deg), transparent 0);
  mask: conic-gradient(#000 calc(var(--rp, 0) * 360deg), transparent 0);
}
/* The loop's glow: a soft band either side of the ring drawn with a mask, not a blur filter, which
   weak graphics chips struggle with while the progress cut-out changes every frame. */
.loop-halo {
  position: absolute;
  inset: 0;
}
.loop-halo .loop-ring {
  inset: 20px;
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 62px), rgb(0 0 0 / 0.14) calc(100% - 46px), rgb(0 0 0 / 0.42) calc(100% - 34px), rgb(0 0 0 / 0.42) calc(100% - 28px), rgb(0 0 0 / 0.14) calc(100% - 16px), transparent 100%);
  mask: radial-gradient(farthest-side, transparent calc(100% - 62px), rgb(0 0 0 / 0.14) calc(100% - 46px), rgb(0 0 0 / 0.42) calc(100% - 34px), rgb(0 0 0 / 0.42) calc(100% - 28px), rgb(0 0 0 / 0.14) calc(100% - 16px), transparent 100%);
}
.loop-ring {
  position: absolute;
  inset: 48px;
  border-radius: 50%;
  background: conic-gradient(var(--blue) 0deg, var(--blue) 70deg, var(--yellow) 190deg, var(--green) 290deg, var(--green) 360deg);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 6px), #000 calc(100% - 5.5px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 6px), #000 calc(100% - 5.5px));
}
.loop-flash {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow:
    0 0 0 2px var(--green),
    0 0 48px 8px rgb(95 196 84 / 0.55);
  opacity: 0;
  pointer-events: none;
}
[data-stage="5"] .loop-flash {
  animation: loop-flash 1.5s var(--ease) both;
}
@keyframes loop-flash {
  20% {
    opacity: 1;
  }
  to {
    opacity: 0;
    scale: 1.16;
  }
}
.station {
  position: absolute;
  left: calc(50% + sin(var(--a)) * var(--R));
  top: calc(50% - cos(var(--a)) * var(--R));
  width: 0;
  height: 0;
  opacity: var(--s-o, 0); /* only once the loop has settled */
}
.station::before {
  content: "";
  position: absolute;
  left: -5px;
  top: -5px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--canvas-bottom);
  box-shadow: 0 0 0 1.5px var(--line-strong);
  transition:
    background-color 400ms,
    box-shadow 400ms;
}
.station > span {
  position: absolute;
  left: calc(sin(var(--a)) * 26px);
  top: calc(cos(var(--a)) * -26px);
  translate: calc(-50% + var(--sx, 0) * 50%) -50%;
  font-size: 14px;
  color: var(--muted);
  white-space: nowrap;
  transition: color 400ms;
}
.station.on::before {
  background: var(--ink);
  box-shadow:
    0 0 0 1.5px var(--ink),
    0 0 14px 2px rgb(237 236 232 / 0.45);
}
.station.on > span {
  color: var(--ink);
}
.runner {
  position: absolute;
  inset: 0;
  rotate: calc(var(--rp, 0) * 360deg);
  pointer-events: none;
}
.runner::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 3px;
  width: 16px;
  height: 16px;
  translate: -50% -50%;
  border-radius: 50%;
  background: var(--yellow);
  box-shadow:
    0 0 0 5px rgb(244 190 80 / 0.16),
    0 0 26px 6px rgb(244 190 80 / 0.55);
  transition: scale 500ms var(--ease) 200ms;
}
/* Loop closed: the dot is taken in, as it is round a photo once someone taps Got it. */
.s5 .runner::before {
  scale: 0;
}
/* Anil and Neha just outside the loop, where it starts and where the work happens. Whoever must act
   next glows in that step's colour: Anil blue as he gives it, Neha yellow while she works, Anil yellow
   while he reviews and green once he approves. */
.who-face {
  --f: 44px;
  position: absolute;
  z-index: 1;
  left: calc(50% + sin(var(--a)) * (var(--D) / 2 + 36px));
  top: calc(50% - cos(var(--a)) * (var(--D) / 2 + 36px));
  width: var(--f);
  height: var(--f);
  translate: -50% -50%;
  opacity: var(--s-o, 0);
  pointer-events: none;
}
.wf-img {
  display: block;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: 50%;
  box-shadow: 0 0 0 1.5px var(--line-strong);
  transition: box-shadow 450ms;
}
.wf-img img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.wf-name {
  position: absolute;
  top: 50%;
  translate: 0 -50%;
  font-size: 13px;
  color: var(--muted);
  white-space: nowrap;
  transition: color 400ms;
}
.anil .wf-name {
  right: calc(100% + 10px);
}
.neha .wf-name {
  left: calc(100% + 10px);
}
[data-stage="0"] .anil .wf-img {
  box-shadow:
    0 0 0 2px var(--blue),
    0 0 26px 2px rgb(74 158 219 / 0.55);
}
[data-stage="1"] .neha .wf-img,
[data-stage="2"] .neha .wf-img,
[data-stage="3"]:not(.b3) .neha .wf-img,
[data-stage="3"].b3 .anil .wf-img,
[data-stage="4"]:not(.b3) .anil .wf-img {
  box-shadow:
    0 0 0 2px var(--yellow),
    0 0 26px 2px rgb(244 190 80 / 0.5);
}
[data-stage="4"].b3 .anil .wf-img {
  box-shadow:
    0 0 0 2px var(--green),
    0 0 26px 2px rgb(95 196 84 / 0.5);
}
[data-stage="0"] .anil .wf-name,
[data-stage="1"] .neha .wf-name,
[data-stage="2"] .neha .wf-name,
[data-stage="3"]:not(.b3) .neha .wf-name,
[data-stage="3"].b3 .anil .wf-name,
[data-stage="4"] .anil .wf-name {
  color: var(--ink);
}
@media (max-width: 899px) {
  .who-face {
    --f: 32px;
    left: calc(50% + sin(var(--a)) * (var(--D) / 2 + 22px));
    top: calc(50% - cos(var(--a)) * (var(--D) / 2 + 22px));
  }
  .who-face.neha {
    --a: 144deg !important; /* phones show no station labels, and the bottom belongs to the step text */
  }
  .wf-name {
    font-size: 12px;
  }
}

/* Pop-up, card and chat share one column in the ring. The pop-up and chat rows open (0fr → 1fr) only
   in their own step, so the card glides up or down to make room and nothing overlaps. */
.stack {
  position: relative;
  z-index: 2;
  width: min(344px, 74%);
  display: flex;
  flex-direction: column;
  opacity: var(--c-o, 0); /* no scale: the card appears exactly in Anil's stretched request */
}
.fold {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 600ms var(--ease);
}
.fold > * {
  min-height: 0;
  overflow: hidden;
}
.stack > .fold > * {
  margin: 0 -20px; /* room for shadows at the sides */
}
/* Open before the card shows too, so the card doesn't move while Anil's request lands on the pop-up. */
[data-stage="-1"] .fold-toast,
[data-stage="0"] .fold-toast {
  grid-template-rows: 1fr;
}
/* Talk: the task's chat takes the card's place, centred in the loop (card plus three messages would
   be taller than the ring on a laptop). */
.fold-chat {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  translate: 0 -50%;
  grid-template-rows: 1fr;
}
.s2:not(.s3) .card {
  opacity: 0;
  scale: 0.94;
}
.chat-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 4px 2px;
  font-size: 13px;
  color: var(--ink-2);
  opacity: 0;
  transition: opacity 350ms;
}
.chat-head .ic {
  width: 15px;
  height: 15px;
}
[data-stage="2"] .chat-head {
  opacity: 1;
}

/* The task card: the app's card at Night, with the panel's status badge. */
.card {
  --card-r: 20px;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 18px 20px 16px;
  border-radius: var(--card-r);
  background: var(--surface);
  box-shadow:
    var(--shadow-lift),
    inset 0 0 0 1px rgb(255 255 255 / 0.05);
  transition:
    opacity 350ms,
    scale 350ms var(--ease);
}
.card-top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 28px;
  padding: 0 12px;
  border-radius: 999px;
  font-size: 13px;
  white-space: nowrap;
  background: var(--tray);
  color: var(--ink-2);
}
.b-blue {
  background: var(--blue-tint);
  color: var(--blue-strong);
}
.b-yellow {
  background: var(--yellow-tint);
  color: var(--yellow-strong);
}
.b-green {
  background: var(--green-tint);
  color: var(--green-strong);
}
/* High priority: the app's pink badge. */
.b-pink {
  background: var(--pink-tint);
  color: var(--pink-strong);
}
/* Every status sits in the same cell, so the badge never changes size as it changes. */
.status {
  display: inline-grid;
}
.status .badge {
  grid-area: 1 / 1;
  opacity: 0;
  transition: opacity 350ms;
}
/* Each step's beats (b1 to b3, from main.js) move the status on: In progress once the timer starts,
   In review once the work is handed in, Done once it's approved. */
[data-stage="-1"] .status [data-v="todo"],
[data-stage="0"] .status [data-v="todo"],
[data-stage="1"]:not(.b3) .status [data-v="todo"],
[data-stage="1"].b3 .status [data-v="doing"],
[data-stage="2"] .status [data-v="doing"],
[data-stage="3"]:not(.b3) .status [data-v="doing"],
[data-stage="3"].b3 .status [data-v="review"],
[data-stage="4"]:not(.b3) .status [data-v="review"],
[data-stage="4"].b3 .status [data-v="done"],
[data-stage="5"] .status [data-v="done"] {
  opacity: 1;
}
.due {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
  font-size: 14px;
  color: var(--ink-2);
}
.card-title {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 18px;
  font-weight: 500;
  line-height: 1.3;
  transition: color 400ms;
}
/* The priority dot before the title (PriorityDot in the app): 12px, pink for High. */
.pdot {
  flex: none;
  width: 12px;
  height: 12px;
  margin-top: 6px;
  border-radius: 50%;
  background: var(--pink);
}
[data-stage="4"].b3 .card-title,
.s5 .card-title {
  color: var(--ink-2);
}
.card-by {
  margin-top: -6px;
  font-size: 13px;
  color: var(--ink-2);
}
.card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.card-meta {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 13px;
  color: var(--ink-2);
}
.swap {
  display: inline-grid;
  justify-items: end;
}
.swap > * {
  grid-area: 1 / 1;
}
.timer {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 24px;
  padding: 0 10px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--surface);
  font-size: 12px;
  opacity: 0;
  transition: opacity 350ms;
}
.timer .ic {
  width: 14px;
  height: 14px;
}
/* The timer runs once Got it is pressed. It's off while the chat has the card's place, so when the card
   comes back for Hand in, only the Hand in button is there (not the timer for a moment first). */
[data-stage="1"].b3 .timer {
  opacity: 1;
}
/* The buttons Neha and Anil press: a pill, pressed with a small push and an ink ripple. */
.act {
  position: relative;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 30px;
  padding: 0 14px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--surface);
  font-size: 13px;
  white-space: nowrap;
}
.act::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 32px;
  height: 32px;
  margin: -16px 0 0 -16px;
  border-radius: 50%;
  background: rgb(23 22 20 / 0.3);
  opacity: 0;
}
.swap .act {
  opacity: 0;
  transition: opacity 300ms;
}
/* Got it waits at Give and is pressed in Got it's first beat; Hand in is there from the start of its step
   and is pressed as the last checklist step is ticked. */
[data-stage="0"] .gotit,
[data-stage="1"]:not(.b2) .gotit,
[data-stage="3"]:not(.b3) .handin {
  opacity: 1;
}
[data-stage="1"].b1 .gotit,
[data-stage="3"].b2 .handin,
[data-stage="4"].b2 .review .ok {
  animation: push 380ms var(--ease);
}
[data-stage="1"].b1 .gotit::after,
[data-stage="3"].b2 .handin::after,
[data-stage="4"].b2 .review .ok::after {
  animation: ripple 480ms ease-out;
}
@keyframes push {
  40% {
    scale: 0.93;
  }
}
@keyframes ripple {
  from {
    opacity: 1;
    transform: scale(0.4);
  }
  to {
    opacity: 0;
    transform: scale(1.8);
  }
}
/* Seen, once Neha has tapped Got it: what Anil sees on his side. */
.who-row {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.seen {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  color: var(--ink-2);
  white-space: nowrap;
  opacity: 0;
  translate: -4px 0;
  transition:
    opacity 350ms,
    translate 450ms var(--ease);
}
.seen .tick {
  width: 14px;
  height: 14px;
  color: var(--blue-light);
}
[data-stage="1"].b2 .seen,
.s2 .seen {
  opacity: 1;
  translate: none;
}
/* Anil's decision: a row of two buttons that opens under the card at the review step. */
[data-stage="4"].b1:not(.b3) .fold-review {
  grid-template-rows: 1fr;
}
.review {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  padding-top: 12px;
}
.review .back {
  background: var(--tray);
  color: var(--ink);
}
.checks {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-variant-numeric: tabular-nums;
  transition: color 400ms;
}
[data-stage="3"].b2 .checks,
.s4 .checks {
  color: var(--green-label);
}

/* Avatars: initials on the surface; the logo's open loop while Got it is pending (Avatar in ui.tsx). */
.av {
  position: relative;
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  font-size: 11px;
  background: var(--surface);
  color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--line);
}
.av.sm {
  width: 26px;
  height: 26px;
}
.av.lg {
  width: 52px;
  height: 52px;
  font-size: 17px;
}
.t-blue {
  background: var(--blue-tint);
  color: var(--blue-strong);
  box-shadow: none;
}
.t-green {
  background: var(--green-tint);
  color: var(--green-strong);
  box-shadow: none;
}
.t-yellow {
  background: var(--yellow-tint);
  color: var(--yellow-strong);
  box-shadow: none;
}
.av-loop {
  position: absolute;
  inset: -3px;
  width: calc(100% + 6px);
  height: calc(100% + 6px);
  overflow: visible;
  pointer-events: none;
  transition: opacity 250ms 500ms;
}
.av-ring {
  fill: none;
  stroke: var(--ink);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-dasharray: 98.96;
  stroke-dashoffset: 9.5;
  transition: stroke-dashoffset 450ms ease-out;
}
.av-dot {
  fill: var(--yellow);
  transform-box: fill-box;
  transform-origin: center;
  transition: scale 450ms ease-out;
}
/* Got it's second beat: the open loop round Neha's photo closes. */
[data-stage="1"].b2 .av-ring,
.s2 .av-ring {
  stroke-dashoffset: 0;
}
[data-stage="1"].b2 .av-dot,
.s2 .av-dot {
  scale: 0;
}
[data-stage="1"].b2 .av-loop,
.s2 .av-loop {
  opacity: 0;
}

/* The task's signature edge (ProgressEdge in the app): the colours fill along the card's bottom border,
   turn green, then fade. It is the card's own rounded outline, cut to its lower edge: the ends fade out
   as they curve up the corners instead of stopping in a hard line. The box reaches 24px below the card
   so the glow can spill out. */
.edge {
  position: absolute;
  inset: 0 0 -24px;
  pointer-events: none;
  opacity: 0;
  -webkit-mask-image: linear-gradient(to top, #000 0, #000 32px, transparent calc(22px + var(--card-r)));
  mask-image: linear-gradient(to top, #000 0, #000 32px, transparent calc(22px + var(--card-r)));
}
.edge-ring {
  position: absolute;
  inset: 0 0 24px;
  border-radius: var(--card-r);
}
.edge-halo {
  filter: blur(8px);
  opacity: 0.9;
}
.edge-fill,
.edge-ok {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 2px; /* as thick as the Critical edge it lies on */
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}
.edge-fill {
  background: linear-gradient(90deg, var(--blue), var(--pink), var(--yellow), var(--green));
  clip-path: inset(0 100% 0 0);
}
.edge-ok {
  background: var(--green);
  opacity: 0;
}
[data-stage="4"].b3 .edge,
.s5 .edge {
  animation: edge-show 2.6s ease both;
}
[data-stage="4"].b3 .edge-fill,
.s5 .edge-fill {
  animation: edge-fill 900ms var(--ease) both;
}
[data-stage="4"].b3 .edge-ok,
.s5 .edge-ok {
  animation: edge-ok 400ms ease 900ms both;
}
@keyframes edge-show {
  0%,
  78% {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}
@keyframes edge-fill {
  to {
    clip-path: inset(0 0 0 0);
  }
}
@keyframes edge-ok {
  to {
    opacity: 1;
  }
}

/* The pop-up Neha gets (the app's push: task title on top, what happened underneath, two actions). */
.toast {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 0 20px 12px;
  padding: 12px 14px;
  border-radius: 22px;
  background: var(--glass-deep);
  -webkit-backdrop-filter: blur(20px) saturate(1.3);
  backdrop-filter: blur(20px) saturate(1.3);
  box-shadow: var(--shadow-glass);
  translate: 0 -10px;
  opacity: 0;
  transition:
    opacity 400ms,
    translate 500ms var(--ease);
}
[data-stage="0"] .toast {
  opacity: 1;
  translate: none;
  transition-delay: 250ms;
}
.toast-app,
.note-app {
  display: grid;
  place-items: center;
  flex: none;
  width: 36px;
  height: 36px;
  border-radius: 10px;
  background: var(--app-tile);
}
.toast-app .logo,
.note-app .logo {
  width: 26px;
  height: 26px;
  color: #fff;
}
.toast-body,
.note-body {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.toast-title,
.note-title {
  font-size: 14px;
  font-weight: 500;
  line-height: 1.3;
}
.toast-text,
.note-text {
  font-size: 13px;
  color: var(--ink-2);
}
.toast-acts,
.note-acts {
  display: flex;
  gap: 6px;
  margin-top: 8px;
}
.toast-acts span,
.note-acts span {
  padding: 5px 10px;
  border-radius: 999px;
  background: rgb(237 236 232 / 0.08);
  font-size: 12px;
  white-space: nowrap;
}

/* The task's own chat. */
.chat {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 12px 20px 16px;
}
.bub {
  max-width: 84%;
  display: flex;
  flex-direction: column;
  padding: 8px 12px 6px;
  border-radius: 18px;
  background: var(--bubble);
  box-shadow: var(--shadow-solid);
  font-size: 14px;
  line-height: 1.35;
  opacity: 0;
  translate: 0 10px;
  transition:
    opacity 400ms,
    translate 500ms var(--ease);
}
.bub .who {
  font-size: 12px;
}
.bub.me {
  align-self: flex-end;
  background: var(--tray);
}
/* Talk's beats: Anil's @mention, Neha's voice note playing, then her PDF; the ticks turn blue once read. */
[data-stage="2"].b1 .m1,
[data-stage="2"].b2 .m2,
[data-stage="2"].b3 .m3 {
  opacity: 1;
  translate: none;
}
.bub .tick {
  color: var(--muted);
  transition: color 300ms;
}
[data-stage="2"].b3 .bub .tick {
  color: var(--blue-light);
  transition-delay: 600ms;
}
.vn {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 2px 0 4px;
}
.vn-play {
  position: relative;
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--ink);
}
.vn-play::after {
  /* the play triangle */
  content: "";
  position: absolute;
  left: 11px;
  top: 9px;
  border-style: solid;
  border-width: 6px 0 6px 10px;
  border-color: transparent transparent transparent var(--surface);
}
.vn-bars {
  display: flex;
  align-items: center;
  gap: 3px;
  height: 20px;
}
.vn-bars span {
  width: 3px;
  height: calc(var(--h) * 0.8px);
  border-radius: 2px;
  background: rgb(237 236 232 / 0.3);
  transition: background-color 120ms;
}
/* It plays: the bars fill one after another, about a second and a quarter for all twenty. */
[data-stage="2"].b2 .vn-bars span {
  background: var(--ink);
  transition-delay: calc(var(--i) * 62ms);
}
.vn-time {
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}
.file-card {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 2px 0 6px;
}
.file-kind {
  display: grid;
  place-items: center;
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 10px;
  background: var(--pink-tint);
  color: var(--pink-label);
  font-size: 11px;
}
.file-name {
  display: flex;
  flex-direction: column;
  font-size: 13px;
}
.file-name small {
  font-size: 12px;
  color: var(--ink-2);
}

@media (max-width: 899px) {
  .story-pin {
    --D: min(88vw, 48svh, 460px);
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto;
    align-content: center;
    justify-items: center;
    row-gap: 26px;
    padding: 84px var(--pad) 24px;
  }
  .stages {
    grid-row: 2;
    text-align: center;
    max-width: 26rem;
  }
  .stages h3 {
    margin-bottom: 8px;
  }
  .station > span {
    display: none;
  }
}
@media (max-width: 699px) {
  .msg.desk {
    display: none;
  }
  /* Inside a phone-sized ring there's room for the headline only. */
  .say-b {
    width: min(calc(var(--D) * 0.62), 100% - 2 * var(--pad));
  }
  .say-b h2 {
    font-size: 28px;
  }
  .say-b p {
    display: none;
  }
  .msg {
    font-size: 14px;
    max-width: 210px;
  }
  .card {
    --card-r: 18px;
    gap: 9px;
    padding: 14px 14px 12px;
  }
  .card-title {
    font-size: 15px;
    gap: 8px;
  }
  .card-title .pdot {
    margin-top: 4px;
  }
  .badge {
    height: 24px;
    padding: 0 9px;
    font-size: 12px;
  }
  .due {
    font-size: 12px;
    gap: 4px;
  }
  .due .ic {
    width: 14px;
    height: 14px;
  }
  .card-by {
    font-size: 12px;
    margin-top: -4px;
  }
  .card-meta {
    gap: 8px;
    font-size: 12px;
  }
  .gotit {
    height: 26px;
    padding: 0 11px;
    font-size: 12px;
  }
  .stack {
    width: 80%;
  }
  .toast {
    padding: 10px 12px;
    gap: 10px;
  }
  .toast-acts {
    display: none;
  }
  .bub {
    font-size: 13px;
  }
}

/* 3. Team: the company as rings, the three O's again. */
.team {
  --top-pad: clamp(96px, 12vw, 168px);
  padding: var(--top-pad) 0;
  scroll-margin-top: calc(4px - var(--top-pad)); /* the menu link lands with the rings just under the bar */
  overflow-x: clip; /* the turning ring boxes' corners would widen the page */
}
.team-grid,
.kpi-grid,
.phone-grid {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: clamp(40px, 6vw, 96px);
  align-items: center;
}
.team-text .sub,
.kpi-text .sub,
.phone-text .sub,
.runway-text .sub {
  margin-top: 20px;
}
.seeing {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-height: 4.2em;
  margin-top: 36px;
}
.seeing-who {
  font-size: 20px;
  font-weight: 500;
}
.seeing-rule {
  color: var(--ink-2);
}
.hint {
  margin-top: 14px;
  font-size: 14px;
  color: var(--muted);
}
/* While the rings show themselves, a thin line fills for each person in turn. */
.tour {
  display: block;
  width: 96px;
  height: 2px;
  margin-top: 14px;
  background: var(--line);
  opacity: 0;
  transition: opacity 300ms;
}
.tour.on {
  opacity: 1;
}
.tour > span {
  display: block;
  height: 100%;
  background: var(--muted);
  transform-origin: left;
  scale: 0 1;
}
.orbit {
  --r1: 17cqi;
  --r2: 31cqi;
  --r3: 45cqi;
  --f: clamp(30px, 7.4cqi, 46px);
  position: relative;
  container-type: inline-size;
  width: min(100%, 640px);
  aspect-ratio: 1;
  margin-inline: auto;
}
.orbit::before {
  content: "";
  position: absolute;
  inset: 26%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgb(237 236 232 / 0.06), transparent);
}
.orbit-line {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(var(--r) * 2);
  height: calc(var(--r) * 2);
  translate: -50% -50%;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px var(--line);
}
.orbit-ring {
  position: absolute;
  inset: 0;
  animation: spin var(--t) linear infinite;
}
.orbit-ring.rev {
  animation-direction: reverse;
}
.face {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--f);
  height: var(--f);
  margin: calc(var(--f) / -2) 0 0 calc(var(--f) / -2);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  font-size: clamp(11px, 2.4cqi, 14px);
  font-weight: 500;
  transform: rotate(var(--a)) translateY(calc(var(--r) * -1)) rotate(calc(var(--a) * -1));
  cursor: pointer;
  transition: opacity 400ms;
}
/* The ring turns; each face turns back the other way, so it stays upright. */
.face > span {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: var(--shadow-solid);
  animation: spin var(--t) linear infinite reverse;
  transition: scale 300ms var(--ease);
}
.orbit-ring.rev .face > span {
  animation-direction: normal;
}
/* Each branch of the company keeps its colour, as a thin ring round the photo. */
.face.t-blue > span {
  background: var(--blue-tint);
  box-shadow:
    0 0 0 2px rgb(74 158 219 / 0.75),
    var(--shadow-solid);
}
.face.t-green > span {
  background: var(--green-tint);
  box-shadow:
    0 0 0 2px rgb(95 196 84 / 0.7),
    var(--shadow-solid);
}
.face.t-yellow > span {
  background: var(--yellow-tint);
  box-shadow:
    0 0 0 2px rgb(244 190 80 / 0.7),
    var(--shadow-solid);
}
/* Photos sit over the initials, which stay underneath in case a photo doesn't load. */
.face > span {
  position: relative;
}
.av > img,
.face img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
}
.face.owner {
  --a: 0deg;
  --r: 0px;
  --f: clamp(44px, 11cqi, 66px);
  font-size: clamp(13px, 3cqi, 18px);
}
.face.owner > span {
  background: var(--ink);
  color: var(--surface);
  box-shadow:
    0 0 0 2px var(--ink),
    0 0 28px rgb(237 236 232 / 0.22);
  animation: none;
}
.orbit:hover .orbit-ring,
.orbit:hover .face > span,
.orbit:focus-within .orbit-ring,
.orbit:focus-within .face > span {
  animation-play-state: paused;
}
/* Faces outside the picked person's view fade, their photos and branch rings to grey. The grey goes on
   the photo itself: a filter on the turning button breaks the circle in Safari. */
.orbit.picked .face:not(.see) {
  opacity: 0.22;
}
.orbit.picked .face:not(.see) img {
  filter: grayscale(1);
}
.orbit.picked .face:not(.see) > span {
  box-shadow:
    0 0 0 2px var(--line),
    var(--shadow-solid);
}
.face[aria-pressed="true"] > span {
  scale: 1.12;
  outline: 1px solid var(--ink-2);
  outline-offset: 3px;
}
/* The picked person's loop: lines to each person whose work they see, then the yellow dot draws a loop
   round the group (main.js orbit). The rings hold still meanwhile, and the loop marks the picked face in
   place of its outline. */
.orbit-draw {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}
.od-loop {
  fill: none;
  stroke-width: 1.5;
  stroke-linecap: round;
}
.od-spoke {
  fill: none;
  stroke: var(--ink);
  stroke-opacity: 0.35;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: od-draw 360ms var(--ease) calc(var(--i) * 70ms) forwards;
}
.orbit-draw.still .od-spoke {
  animation: none;
  stroke-dashoffset: 0;
}
@keyframes od-draw {
  to {
    stroke-dashoffset: 0;
  }
}
.od-dot,
.od-glow {
  fill: var(--yellow);
}
.od-glow {
  opacity: 0.22;
}
.orbit.picked .orbit-ring,
.orbit.picked .face > span {
  animation-play-state: paused;
}
.orbit.picked .face[aria-pressed="true"] > span {
  outline-color: transparent;
}
@media (hover: hover) {
  .face:hover > span {
    scale: 1.1;
  }
}
@keyframes spin {
  to {
    rotate: 360deg;
  }
}

/* 4. Deadlines: a week passes as you scroll. */
.runway {
  position: relative;
  height: 320vh;
}
.runway-pin {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  display: flex;
  align-items: center;
  padding: 88px 0 24px;
}
/* The heading and the week's clock on one line, then the board across the whole width. */
.runway-stack {
  display: flex;
  flex-direction: column;
  gap: clamp(16px, 2.6svh, 26px);
}
.runway-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
}
.runway-text h2 {
  font-size: clamp(30px, 3.6vw, 52px);
}
.runway-text .sub {
  max-width: 36em;
}
/* The clock: its day and time roll over like a departure board as the week passes. Each roll shows
   one of its stacked words; main.js picks which (--i). Fixed widths, so nothing beside it moves. */
.clock-big {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  font-weight: 500;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.roll {
  display: inline-block;
  height: 1.25em; /* tall enough for a word's descender, so none peeks in from the one above */
  overflow: hidden;
  vertical-align: bottom;
}
.roll > span {
  display: block;
  height: 1.25em;
  line-height: 1.25;
  translate: 0 calc(var(--i, 0) * -100%);
  transition: translate 420ms var(--ease);
  will-change: translate;
}
.roll.snap > span {
  transition: none;
}
.roll-day {
  font-size: 18px;
  color: var(--ink-2);
  text-align: right;
}
.clock-time {
  font-size: clamp(34px, 3.8vw, 54px);
  letter-spacing: -0.02em;
}
.roll-h > span {
  text-align: right;
}
/* In a box like the digits' so it shares their line (as plain text it sat lower), lifted to sit centred
   on them like a clock's. */
.colon {
  display: inline-block;
  height: 1.25em;
  line-height: 1.25;
  vertical-align: bottom;
  translate: 0 -0.06em;
}
.roll-ap {
  margin-left: 0.2em;
  font-size: 0.42em;
  letter-spacing: 0;
  color: var(--ink-2);
  vertical-align: baseline;
}
.board-top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 24px;
  min-height: 40px;
  margin-bottom: 12px;
}
.board .key {
  margin: 0;
  font-size: 13px;
  gap: 8px 18px;
}
.board {
  --who: 116px;
  position: relative;
  padding: 18px 18px 22px;
  border-radius: 28px;
  background:
    linear-gradient(180deg, rgb(255 255 255 / 0.035), transparent 30%),
    rgb(38 37 35 / 0.72);
  box-shadow: var(--shadow-glass), var(--shadow-lift);
}
.board-days {
  display: grid;
  grid-template-columns: var(--who) repeat(6, minmax(0, 1fr));
  padding: 2px 0 12px;
  font-size: 13px;
  color: var(--muted);
}
.board-days span {
  padding-left: 10px;
  transition: color 300ms;
}
/* Today's name lights up as the week goes by. */
.board-days .on {
  color: var(--ink);
}
.board-body {
  position: relative;
}
/* Day columns, behind the bars; Saturday, the weekend, a shade darker. */
.board-grid {
  position: absolute;
  inset: 0 0 0 var(--who);
  pointer-events: none;
  background:
    linear-gradient(90deg, transparent calc(500% / 6), rgb(0 0 0 / 0.14) 0),
    linear-gradient(90deg, rgb(237 236 232 / 0.06) 1px, transparent 1px) 0 0 / calc(100% / 6) 100%;
}
.board-row {
  position: relative;
  display: grid;
  grid-template-columns: var(--who) minmax(0, 1fr);
  align-items: center;
  height: clamp(44px, 6.4svh, 60px);
  border-top: 1px solid rgb(237 236 232 / 0.06);
}
/* Each person's photo and name is its own layer, so it's never redrawn as the week changes around it: on 1x
   screens Safari redrew those rows a pixel up or down while scrolling, and the photos flickered. */
.board-who {
  will-change: transform;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  color: var(--ink-2);
}
.board-track {
  position: relative;
  height: 100%;
}
/* A task: a glass pill from the day it was given to its due date, in its state's colour, with a sheen
   on top and a fine edge. */
.run-bar {
  --s: 0;
  --e: 1;
  --split: 1;
  --tint: var(--tray);
  --edge: rgb(237 236 232 / 0.08);
  --glow: 0 0 0 transparent;
  --sheen: linear-gradient(180deg, rgb(255 255 255 / 0.07), transparent 65%);
  position: absolute;
  top: 50%;
  left: calc(var(--s) / 6 * 100%);
  width: calc((var(--e) - var(--s)) / 6 * 100%);
  height: clamp(32px, 4.6svh, 40px);
  translate: 0 -50%;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 14px;
  border-radius: 999px;
  font-size: 13px;
  white-space: nowrap;
  overflow: hidden;
  color: var(--ink-2);
  background: var(--sheen), var(--tint);
  box-shadow:
    inset 0 0 0 1px var(--edge),
    var(--glow);
  transition:
    color 350ms,
    box-shadow 350ms,
    opacity 350ms;
}
.run-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  font-weight: 500;
}
/* What is happening, in words, at the bar's end: "Due tomorrow", "2 days late", "Moved to Saturday". */
.run-state {
  flex: none;
  margin-left: auto;
  opacity: 0.9;
}
.run-bar[data-state="future"] {
  opacity: 0.35;
}
.run-bar[data-state="soon"] {
  transition:
    width 450ms var(--ease),
    color 350ms,
    box-shadow 350ms,
    opacity 350ms;
  --tint: var(--yellow-tint);
  --edge: rgb(244 190 80 / 0.35);
  --glow: 0 0 28px -6px rgb(244 190 80 / 0.55);
  --ping: rgb(244 190 80 / 0.6);
  color: var(--yellow-strong);
}
.run-bar[data-state="done"] {
  --tint: var(--green-tint);
  --edge: rgb(95 196 84 / 0.3);
  color: var(--green-strong);
  transition:
    width 450ms var(--ease),
    color 350ms,
    box-shadow 350ms;
}
/* Moved with a reason: a thin line where the old due date was, then the extra days, striped. */
.run-bar[data-state="moved"] {
  --edge: rgb(74 158 219 / 0.35);
  --glow: 0 0 28px -6px rgb(74 158 219 / 0.5);
  color: var(--blue-strong);
  transition:
    width 450ms var(--ease),
    color 350ms,
    box-shadow 350ms;
  background:
    var(--sheen),
    linear-gradient(90deg, var(--blue-tint) calc(var(--split) * 100% - 1px), rgb(74 158 219 / 0.9) 0 calc(var(--split) * 100% + 1px), transparent 0),
    repeating-linear-gradient(-45deg, rgb(74 158 219 / 0.24) 0 5px, rgb(74 158 219 / 0.08) 5px 10px);
}
/* Past its due date: the bar keeps growing until the work is done, its overdue days striped and moving. */
.run-bar[data-state="late"] {
  --edge: rgb(255 155 153 / 0.35);
  --glow: 0 0 28px -6px rgb(255 155 153 / 0.5);
  --ping: rgb(255 155 153 / 0.6);
  color: var(--pink-strong);
  background:
    var(--sheen),
    linear-gradient(90deg, var(--pink-tint) calc(var(--split) * 100%), transparent 0),
    repeating-linear-gradient(-45deg, rgb(255 155 153 / 0.3) 0 5px, rgb(255 155 153 / 0.1) 5px 10px);
  background-size: auto, auto, 1414.2px 100%;
  animation: march 1.2s linear infinite;
}
@keyframes march {
  to {
    background-position:
      0 0,
      0 0,
      28.28px 0;
  }
}
/* At risk (due soon, late): a small dot that keeps pinging. Done: a tick. */
.run-bar:is([data-state="soon"], [data-state="late"]) .run-state::before {
  content: "";
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-right: 7px;
  vertical-align: 1px;
  border-radius: 50%;
  background: currentColor;
  animation: ping 1.6s ease-out infinite;
}
@keyframes ping {
  from {
    box-shadow: 0 0 0 0 var(--ping);
  }
  to {
    box-shadow: 0 0 0 7px transparent;
  }
}
.run-bar[data-state="done"] .run-state::before {
  content: "";
  display: inline-block;
  width: 12px;
  height: 12px;
  margin-right: 6px;
  vertical-align: -1px;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat;
}
/* The colour key under the text. */
.key {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 20px;
  margin-top: 26px;
  padding: 0;
  font-size: 15px;
  color: var(--ink-2);
}
.key li {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.key li::before {
  content: "";
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--c);
  box-shadow: 0 0 10px var(--c);
}
/* Now: a playhead over the week, a soft light around it and a dot at its foot. */
.board-now {
  position: absolute;
  inset: 0 0 0 var(--who);
  pointer-events: none;
  container-type: inline-size;
}
/* It slides on the graphics chip (translate, its own layer), so moving it redraws nothing under it. */
.today {
  position: absolute;
  top: -8px;
  bottom: -6px;
  left: 0;
  translate: calc(var(--t, 0) / 6 * 100cqw) 0;
  will-change: translate;
  width: 2px;
  margin-left: -1px;
  border-radius: 2px;
  background: linear-gradient(180deg, var(--ink), rgb(237 236 232 / 0.35));
  box-shadow: 0 0 14px rgb(237 236 232 / 0.45);
}
.today::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 150px;
  translate: -50% 0;
  background: radial-gradient(50% 60% at 50% 50%, rgb(237 236 232 / 0.07), transparent);
}
.today::after {
  content: "";
  position: absolute;
  bottom: -4px;
  left: 50%;
  width: 8px;
  height: 8px;
  translate: -50% 0;
  border-radius: 50%;
  background: var(--ink);
  box-shadow: 0 0 12px rgb(237 236 232 / 0.7);
}
.alerts {
  display: flex;
  justify-content: flex-end;
  min-width: 0;
}
.alert {
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: 100%;
  padding: 8px 14px;
  border-radius: 999px;
  background: var(--glass-deep); /* no backdrop blur: the board behind it is one flat colour anyway */
  box-shadow: var(--shadow-glass), var(--shadow-lift);
  font-size: 14px;
  line-height: 1.35;
  transform-origin: 18px 50%; /* it grows out of its dot, where a bell has just landed */
}
.alert.empty {
  visibility: hidden;
}
/* Wider screens: the pill is a fixed slot, so its dot (where the bells land) stays put whatever the message. */
@media (min-width: 700px) {
  .board-top .alerts {
    flex: 0 1 480px;
  }
  .alerts .alert {
    flex: 1;
  }
}
.alert > span:last-child {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.alert-dot {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--c);
  box-shadow: 0 0 10px var(--c);
}
.alert small {
  margin-left: 8px;
  font-size: 13px;
  color: var(--ink-2);
}
/* Hours under each day: 9, 12, 3 and 5 (a day here runs 9 am to 7 pm). */
.board-ruler {
  display: grid;
  grid-template-columns: var(--who) repeat(6, minmax(0, 1fr));
  height: 16px;
  margin: -8px 0 4px;
  font-size: 10px;
  color: var(--muted);
}
.board-ruler > span {
  position: relative;
}
.board-ruler > span > span {
  position: absolute;
  top: 0;
  translate: -50% 0;
}
.board-ruler > span > span:nth-child(1) {
  left: 6%;
}
.board-ruler > span > span:nth-child(2) {
  left: 30%;
}
.board-ruler > span > span:nth-child(3) {
  left: 60%;
}
.board-ruler > span > span:nth-child(4) {
  left: 80%;
}
/* The rest of the week's work: calm grey bars running on past the board's edge into next week. */
.run-bar[data-calm] {
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 90px), transparent);
  mask-image: linear-gradient(90deg, #000 calc(100% - 90px), transparent);
}
.board-row.calm .board-who {
  opacity: 0.75;
}
/* A deadline the beam is about to reach: a slow light runs along the bar. */
.run-bar::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(100deg, transparent 35%, rgb(255 255 255 / 0.12) 50%, transparent 65%) 0 0 / 260% 100%;
  opacity: 0;
  transition: opacity 400ms;
  pointer-events: none;
}
.run-bar[data-near]::after {
  opacity: 1;
  animation: sheen 2.2s linear infinite;
}
@keyframes sheen {
  from {
    background-position: 130% 0;
  }
  to {
    background-position: -130% 0;
  }
}
/* Moved: the bar's end springs out to its new date (a small overshoot, so it stays inside the card). */
.run-bar[data-state="moved"] {
  transition:
    width 650ms cubic-bezier(0.34, 1.2, 0.64, 1),
    color 350ms,
    box-shadow 350ms;
}
/* Late: a small pink dot on the person's photo while the work is overdue. */
.board-row .av::after {
  content: "";
  position: absolute;
  right: -2px;
  top: -2px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--pink);
  box-shadow: 0 0 0 2px var(--surface);
  scale: 0;
  transition: scale 350ms var(--ease);
}
.board-row.is-late .av::after {
  scale: 1;
}
/* Moved: the reason, pinned where the old due date was, above the extra days. */
.pin-note {
  position: absolute;
  z-index: 2;
  left: calc(var(--at) / 6 * 100% + 4px);
  bottom: calc(50% + clamp(16px, 2.3svh, 20px) + 4px);
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--blue-tint);
  color: var(--blue-strong);
  font-size: 12px;
  white-space: nowrap;
  box-shadow: inset 0 0 0 1px rgb(74 158 219 / 0.35);
  opacity: 0;
  scale: 0.85;
  translate: 0 4px;
  transform-origin: 0 100%;
  transition:
    opacity 300ms,
    scale 450ms cubic-bezier(0.34, 1.56, 0.64, 1),
    translate 450ms var(--ease);
  pointer-events: none;
}
.board-row.is-moved .pin-note {
  opacity: 1;
  scale: 1;
  translate: none;
}
/* The moment a state changes: a spark at the spot on the bar where it happened. */
.spark {
  position: absolute;
  z-index: 2;
  top: 50%;
  width: 30px;
  height: 30px;
  margin: -15px 0 0 -15px;
  border-radius: 50%;
  pointer-events: none;
  animation: spark 800ms ease-out forwards;
}
.spark-soon {
  box-shadow: 0 0 0 2px var(--yellow), 0 0 18px var(--yellow);
}
.spark-late {
  background: radial-gradient(closest-side, rgb(255 155 153 / 0.95), transparent);
}
.spark-moved {
  box-shadow: 0 0 0 2px var(--blue), 0 0 18px var(--blue);
}
.spark-done {
  box-shadow: 0 0 0 2px var(--green), 0 0 18px var(--green);
}
@keyframes spark {
  from {
    opacity: 1;
    transform: scale(0.3);
  }
  to {
    opacity: 0;
    transform: scale(2.2);
  }
}
/* ...and its bell, flying from the bar to the stack below the board (main.js moves it). */
.fly {
  position: absolute;
  z-index: 3;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--glass-deep);
  box-shadow: var(--shadow-glass);
  color: var(--c, var(--ink));
  pointer-events: none;
}
.fly .ic {
  width: 15px;
  height: 15px;
}
.fly-soon {
  --c: var(--yellow);
}
.fly-late {
  --c: var(--pink);
}
.fly-moved {
  --c: var(--blue);
}
.fly-done {
  --c: var(--green);
}

/* 5. KPIs */
.kpi {
  --top-pad: clamp(120px, 14vw, 200px);
  padding: var(--top-pad) 0 clamp(96px, 12vw, 168px);
  scroll-margin-top: calc(4px - var(--top-pad)); /* the menu link lands with the heading just under the bar */
}
.kpi-grid {
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  align-items: stretch; /* the card runs the full height of the text and scenes beside it */
}
/* The fairness rules as four tiny scenes; main.js adds .play as each comes into view (and again on a tap).
   Before that, with JavaScript, each scene waits at its first frame; without it, at its last. */
.scenes {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin-top: 28px;
}
.scene {
  margin: 0;
  padding: 16px 16px 14px;
  border-radius: 24px;
  background: var(--field);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.03);
  cursor: pointer;
}
.scene figcaption {
  margin-top: 12px;
  font-size: 14px;
  line-height: 1.4;
  color: var(--ink-2);
}
.sc-art {
  position: relative;
  height: 100px;
  font-size: 12px;
  color: var(--ink-2);
}
@keyframes sc-grow {
  from {
    transform: scaleX(0);
  }
}
@keyframes sc-pop {
  from {
    opacity: 0;
    scale: 0.6;
  }
}
@keyframes sc-fade {
  from {
    opacity: 0;
  }
}
/* 1. Priority weights: four bars grow to 1, 2, 4 and 8. */
.sc-weight .sc-art {
  display: grid;
  align-content: space-between;
}
.wrow {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr);
  align-items: center;
  gap: 8px;
  height: 18px;
}
.wtrack {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.wlab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.pd {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--c);
}
.wbar {
  flex: none;
  width: calc(var(--w) / 8 * (100% - 30px));
  height: 8px;
  border-radius: 4px;
  background: var(--line-strong);
  transform-origin: left;
}
.wx {
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.scene.play .wbar {
  animation: sc-grow 600ms var(--ease) calc(var(--i) * 220ms) both;
}
.scene.play .wx {
  animation: sc-fade 300ms ease calc(var(--i) * 220ms + 400ms) both;
}
/* 2. Blame: Neha finishes before Friday; Anil's review runs past it, and those days are his. */
.sc-blame .sc-art {
  --who: 42px;
}
.bl-due {
  position: absolute;
  top: 14px;
  bottom: 30px;
  left: calc(var(--who) + (100% - var(--who)) * 0.7);
  border-left: 1px dashed var(--line-strong);
}
.bl-due span {
  position: absolute;
  bottom: 100%;
  left: 0;
  translate: -50% -2px;
  font-size: 11px;
  white-space: nowrap;
  color: var(--muted);
}
.bl-row {
  position: absolute;
  left: 0;
  right: 0;
  display: grid;
  grid-template-columns: var(--who) minmax(0, 1fr);
  align-items: center;
  height: 18px;
}
.bl-row.r1 {
  top: 20px;
}
.bl-row.r2 {
  top: 44px;
}
.bl-track {
  position: relative;
  height: 100%;
}
.bl-bar {
  position: absolute;
  top: 2px;
  bottom: 2px;
  border-radius: 7px;
  transform-origin: left;
}
.bl-work {
  left: 0;
  width: 48%;
  background: var(--green-tint);
  box-shadow: inset 0 0 0 1px rgb(95 196 84 / 0.3);
}
.bl-tick {
  position: absolute;
  left: calc(48% - 16px);
  top: 50%;
  width: 11px;
  height: 11px;
  translate: 0 -50%;
  background: var(--green-label);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat;
}
.bl-rev {
  left: 48%;
  width: 42%;
  background:
    linear-gradient(90deg, var(--yellow-tint) calc(22 / 42 * 100%), transparent 0),
    repeating-linear-gradient(-45deg, rgb(255 155 153 / 0.35) 0 4px, rgb(255 155 153 / 0.12) 4px 8px);
  box-shadow: inset 0 0 0 1px rgb(244 190 80 / 0.25);
}
.bl-chip {
  position: absolute;
  right: 0;
  bottom: 0;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--green-tint);
  color: var(--green-strong);
}
.scene.play .bl-work {
  animation: sc-grow 600ms var(--ease) both;
}
.scene.play .bl-tick {
  animation: sc-pop 300ms var(--ease) 600ms both;
}
.scene.play .bl-rev {
  animation: sc-grow 900ms var(--ease) 850ms both;
}
.scene.play .bl-chip {
  animation: sc-pop 400ms var(--ease) 1800ms both;
}
/* 3. Deleted but counted: the done task drops into the bin; the count doesn't move. */
.bin-count {
  position: absolute;
  left: 0;
  top: 0;
  display: flex;
  align-items: baseline;
  gap: 4px;
}
.bin-count .n {
  font-size: 22px;
  font-weight: 500;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.bin-still {
  margin-left: 6px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--green-tint);
  color: var(--green-strong);
  font-size: 11px;
}
.bin-card {
  position: absolute;
  left: 0;
  bottom: 6px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border-radius: 12px;
  background: var(--surface);
  box-shadow: var(--shadow-solid);
  color: var(--ink);
  white-space: nowrap;
}
.bin-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--green);
}
.bin-done {
  color: var(--green-label);
}
.bin-can {
  position: absolute;
  right: 2px;
  bottom: 4px;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 12px;
  background: var(--tray);
}
.scene.play .bin-card {
  animation: bin-in 900ms var(--ease) 400ms both;
}
.scene.play .bin-can {
  animation: bin-shake 420ms ease 1250ms both;
}
.scene.play .bin-count .n {
  animation: sc-pulse 520ms ease 1450ms both;
}
.scene.play .bin-still {
  animation: sc-pop 380ms var(--ease) 1600ms both;
}
@keyframes bin-in {
  to {
    left: calc(100% - 196px);
    opacity: 0.6;
  }
}
.bin-tag {
  display: inline-grid;
}
.bin-tag > span {
  grid-area: 1 / 1;
}
.bin-del {
  color: var(--ink-2);
  opacity: 0;
}
.scene.play .bin-done {
  animation: sc-out 220ms ease 1150ms both;
}
.scene.play .bin-del {
  animation: sc-in 260ms ease 1250ms both;
}
@keyframes sc-out {
  to {
    opacity: 0;
  }
}
@keyframes sc-in {
  to {
    opacity: 1;
  }
}
@keyframes bin-shake {
  30% {
    rotate: -9deg;
  }
  65% {
    rotate: 6deg;
  }
}
@keyframes sc-pulse {
  40% {
    scale: 1.14;
    color: var(--green-strong);
  }
}
/* 4. The flag: five reviewers' send-backs; one runs far past the rest and gets the flag. */
.sc-flag .sc-art {
  display: grid;
  align-content: space-between;
}
.fl-head {
  font-size: 11px;
  color: var(--muted);
}
.fl-row {
  display: grid;
  grid-template-columns: 14px minmax(0, 1fr);
  align-items: center;
  gap: 8px;
  height: 13px;
}
.fl-track {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.fl-n {
  font-size: 11px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.fl-flag {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 11px;
  color: var(--ink);
}
.fl-row img {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  object-fit: cover;
}
.fl-bar {
  flex: none;
  width: calc(var(--n) / 10 * (100% - 78px));
  height: 6px;
  border-radius: 3px;
  background: var(--line-strong);
  transform-origin: left;
}
.is-flag .fl-bar {
  background: var(--ink-2);
}
.fl-ic {
  width: 13px;
  height: 13px;
  color: var(--ink-2);
}
.scene.play .fl-n {
  animation: sc-fade 300ms ease calc(var(--i) * 160ms + 380ms) both;
}
.scene.play .fl-bar {
  animation: sc-grow 500ms var(--ease) calc(var(--i) * 160ms) both;
}
.scene.play .fl-flag {
  animation: sc-pop 350ms var(--ease) 1250ms both;
}
.js .scene:not(.play) :is(.wbar, .bl-work, .bl-rev, .fl-bar) {
  transform: scaleX(0);
}
.js .scene:not(.play) :is(.wx, .bl-tick, .bl-chip, .bin-still, .fl-n, .fl-flag) {
  opacity: 0;
}
.kpi-card {
  display: flex;
  flex-direction: column;
  padding: 22px;
  border-radius: 28px;
  background: var(--surface);
  box-shadow: var(--shadow-lift), inset 0 0 0 1px var(--line);
}
.kpi-head {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 18px;
}
.kpi-name {
  display: flex;
  flex-direction: column;
  font-size: 18px;
  font-weight: 500;
  line-height: 1.3;
}
.kpi-name small {
  font-size: 13px;
  font-weight: 400;
  color: var(--ink-2);
}
.seg {
  display: flex;
  margin-left: auto;
  padding: 4px;
  border-radius: 999px;
  background: var(--tray);
  font-size: 13px;
}
.seg span {
  padding: 6px 12px;
  border-radius: 999px;
  color: var(--ink-2);
}
.seg .on {
  background: var(--ink);
  color: var(--surface);
}
.kpi-rings {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
.kpi-tiles {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin-top: 12px;
}
.tile {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 18px;
  border-radius: 24px;
  background: var(--field);
}
.ring-tile {
  flex-direction: row;
  align-items: center;
  gap: 16px;
}
.ring-box {
  position: relative;
  flex: none;
  width: 92px;
  height: 92px;
}
.kring {
  width: 100%;
  height: 100%;
  rotate: -90deg;
}
.kring-track {
  fill: none;
  stroke: var(--line);
  stroke-width: 10;
}
.kring-fill {
  fill: none;
  stroke: var(--c);
  stroke-width: 10;
  stroke-linecap: round;
  stroke-dasharray: 314.16;
  stroke-dashoffset: calc(314.16px * (1 - var(--v)));
  transition: stroke-dashoffset 1.4s var(--ease);
}
.js .kpi-card:not(.in) .kring-fill {
  stroke-dashoffset: 314.16;
}
.tile-num {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 24px;
  font-weight: 500;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.tile-big {
  font-size: clamp(28px, 2.6vw, 36px);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.tile-label {
  display: flex;
  flex-direction: column;
  font-size: 14px;
  line-height: 1.35;
}
.tile-label small {
  font-size: 13px;
  color: var(--muted);
}
/* More of the person's page (the app's KPI page): finished each week, and how quickly she works. This row
   takes only the height the card has spare beside the text and scenes (size containment: it never makes the
   card taller), and the week bars grow into it. */
.kpi-more {
  flex: 1;
  container-type: size;
  min-height: 110px;
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
  gap: 12px;
  margin-top: 12px;
}
.kpi-more > * {
  min-height: 0;
  overflow: hidden; /* a safety net: never spill over the quote below */
  padding: 14px 16px;
}
.weeks-tile {
  gap: 8px;
}
.kd {
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-right: 5px;
  border-radius: 50%;
  background: var(--c);
  vertical-align: 1px;
}
.kd:not(:first-child) {
  margin-left: 8px;
}
.weeks-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 12px;
  font-size: 14px;
}
.weeks-head small {
  font-size: 12px;
  color: var(--muted);
}
/* One row per week, a bar out of 10 tasks: on time in green, any late ones in pink at its end. The rows share
   whatever height the card has spare. */
.weeks {
  flex: 1;
  display: grid;
  grid-template-rows: repeat(4, minmax(0, 1fr));
  gap: 4px;
  min-height: 0;
}
.wk {
  display: grid;
  grid-template-columns: 46px minmax(0, 1fr) 22px;
  align-items: center;
  gap: 10px;
}
.wk-day {
  font-size: 12px;
  line-height: 1.2;
  color: var(--muted);
}
.wk-track {
  height: min(12px, 100%);
}
.wk-bar {
  display: block;
  width: calc(var(--n) * 10%);
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--green) calc(100% - var(--late) / var(--n) * 100%), var(--pink) 0);
  transform-origin: 0 50%;
  transition: scale 900ms var(--ease) calc(var(--i) * 90ms);
}
.wk-n {
  font-size: 13px;
  line-height: 1.2;
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
  transition: opacity 400ms calc(var(--i) * 90ms + 500ms);
}
.js .kpi-card:not(.in) .wk-bar {
  scale: 0 1;
}
.js .kpi-card:not(.in) .wk-n {
  opacity: 0;
}
.speed {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 8px;
  margin: 0;
}
.speed > div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}
.speed dt {
  display: flex;
  flex-direction: column;
  font-size: 13px;
  line-height: 1.35;
  color: var(--ink-2);
}
.speed dt small {
  font-size: 12px;
  color: var(--muted);
}
.speed dd {
  margin: 0;
  font-size: 16px;
  font-weight: 500;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* A tight fit (short laptop screens): the small legend and the note step aside. */
@container (height < 132px) {
  .weeks-head small,
  .speed dt small {
    display: none;
  }
}
/* A narrow card (smaller two-column screens): no room for both, so the weeks take the whole row. */
@container (width < 500px) {
  .speed {
    display: none;
  }
  .weeks-tile {
    grid-column: 1 / -1;
  }
}
/* One column (tablets, phones): nothing beside the card, so the row takes its own height. */
@media (max-width: 899px) {
  .kpi-more {
    container-type: normal;
  }
  .weeks {
    min-height: 120px;
  }
}
.reason {
  margin-top: 12px;
  padding: 16px 18px;
  border-radius: 24px;
  background: var(--field);
}
.reason p {
  font-size: 15px;
}
.reason footer {
  margin-top: 4px;
  font-size: 13px;
  color: var(--muted);
}

/* 5b. Pricing: three plans side by side; the main one is lifted, and on phones it comes first. */
.pricing {
  --top-pad: clamp(96px, 12vw, 168px);
  padding: var(--top-pad) 0;
  scroll-margin-top: calc(4px - var(--top-pad)); /* the menu link lands with the heading just under the bar */
}
.pricing-head {
  text-align: center;
}
.pricing-head .sub {
  margin: 20px auto 0;
}
.plans {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin-top: 56px;
}
.plan {
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 28px;
  border-radius: 28px;
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
}
.plan-main {
  background: var(--field);
  box-shadow:
    var(--shadow-lift),
    inset 0 0 0 1px var(--line-strong);
}
.plan h3 {
  font-size: 22px;
}
.plan-for {
  margin-top: -10px;
  font-size: 15px;
  color: var(--ink-2);
}
.plan-price {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 100px; /* the same on every card, so the buttons line up */
}
.plan-amount {
  font-size: 52px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.03em;
}
.plan-per {
  max-width: 17em;
  font-size: 14px;
  line-height: 1.4;
  color: var(--muted);
}
.plan .btn {
  width: 100%;
}
.plan-list {
  list-style: none;
  display: grid;
  gap: 10px;
  padding: 0;
  font-size: 15px;
  line-height: 1.4;
  color: var(--ink-2);
}
.plan-list li {
  display: flex;
  gap: 10px;
}
.plan-list .ic {
  margin-top: 2px;
  color: var(--ink);
}
.plans-note {
  margin-top: 24px;
  font-size: 14px;
  color: var(--muted);
  text-align: center;
}
@media (max-width: 899px) {
  .plans {
    grid-template-columns: minmax(0, 1fr);
    max-width: 480px;
    margin-inline: auto;
  }
  .plan-main {
    order: -1;
  }
  .plan-price {
    min-height: 0;
  }
}

/* 6. Phone */
.phone {
  padding: clamp(96px, 12vw, 168px) 0;
}
.phone-grid {
  grid-template-columns: minmax(0, 6fr) minmax(0, 5fr);
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 30px;
  padding: 12px 20px;
  border-radius: 999px;
  background: var(--glass);
  box-shadow: var(--shadow-glass);
  font-size: 16px;
}
.chip .ic {
  width: 18px;
  height: 18px;
  color: var(--green-label);
}
.device {
  position: relative;
  justify-self: center;
  width: min(340px, 84vw, (100svh - 140px) * 0.466); /* the whole phone fits on screen under the bar */
  aspect-ratio: 9 / 19.3;
  padding: 11px;
  border-radius: 54px;
  background: var(--canvas-bottom);
  box-shadow:
    inset 0 0 0 1.5px var(--line),
    inset 0 0 0 4px var(--canvas-bottom),
    inset 0 0 0 5px var(--line),
    0 50px 100px -30px rgb(0 0 0 / 0.85);
}
/* Placed inside the frame rather than given height: 100%, which Safari let stretch the frame's aspect-ratio box. */
.screen {
  position: absolute;
  inset: 11px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 54px 12px 12px;
  border-radius: 44px;
  background:
    radial-gradient(60% 38% at 18% 18%, rgb(74 158 219 / 0.5), transparent),
    radial-gradient(50% 36% at 88% 34%, rgb(255 155 153 / 0.34), transparent),
    radial-gradient(60% 46% at 28% 88%, rgb(95 196 84 / 0.34), transparent),
    radial-gradient(52% 40% at 84% 80%, rgb(244 190 80 / 0.38), transparent),
    var(--canvas-top);
}
.screen::before {
  /* the camera island */
  content: "";
  position: absolute;
  top: 14px;
  left: 50%;
  width: 96px;
  height: 28px;
  translate: -50% 0;
  border-radius: 999px;
  background: var(--canvas-bottom);
}
.clock {
  display: flex;
  flex-direction: column;
  align-items: center;
  font-size: 66px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.03em;
  color: rgb(237 236 232 / 0.92);
}
.clock small {
  order: -1;
  margin-bottom: 6px;
  font-size: 15px;
  letter-spacing: 0;
  color: var(--ink-2);
}
.notes {
  width: 100%;
  margin-top: 28px;
  display: flex;
  flex-direction: column;
}
/* Each pop-up opens its own row, so a new one lands on top and pushes the rest down. */
.note-wrap {
  display: grid;
  grid-template-rows: 1fr;
  transition:
    grid-template-rows 550ms var(--ease),
    opacity 400ms;
}
.js .note-wrap:not(.show) {
  grid-template-rows: 0fr;
  opacity: 0;
}
.note-wrap > div {
  min-height: 0;
  overflow: hidden;
}
.note {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 8px;
  padding: 12px;
  border-radius: 22px;
  /* Frosted glass over the wallpaper, a fine light edge and no drop shadow (a shadow here gets cut off
     by the row that opens, which left a dark band under each pop-up). */
  background: rgb(237 236 232 / 0.09);
  -webkit-backdrop-filter: blur(24px) saturate(1.5);
  backdrop-filter: blur(24px) saturate(1.5);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.08);
}
.note-body {
  flex: 1;
}
.note-top {
  display: flex;
  justify-content: space-between;
  font-size: 12px;
  color: var(--muted);
}
/* A phone pop-up's actions: one full-width row of two equal buttons under the text, never wrapping. */
.note-acts {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  width: 100%;
  margin-top: 4px;
}
.note-acts span {
  padding: 9px 8px;
  border-radius: 14px;
  background: rgb(237 236 232 / 0.1);
  font-size: 13px;
  text-align: center;
}

/* 7. The end */
.end {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: clamp(96px, 16svh, 180px) var(--pad) clamp(72px, 12svh, 140px);
}
.mark-end {
  width: min(640px, 84vw, 78svh);
}
/* Then the three O's become the logo (main.js wordmark logo): the letters drift off, the light turns
   white, and the i's stem rises inside the one ring. */
.mark.merging .letters path {
  opacity: 0;
  translate: -14px 0;
  transition:
    opacity 500ms,
    translate 700ms var(--ease);
}
.mark.merging .letters path:last-child {
  translate: 14px 0;
}
.mark.merging .ring path {
  stroke: var(--ink);
  transition: stroke 900ms;
}
/* While the O's move, their blurred glow is off and stays off: redrawing a blur on every frame is what makes
   slower machines stutter. The finished logo's glow is drawn once on layers of its own (.logo-glow) and only
   fades in. */
.js .mark.merging .ring :is(.halo, .glow),
.mark.merging .dot-glow {
  visibility: hidden;
  opacity: 0;
  transition:
    opacity 150ms,
    visibility 0s 150ms; /* fades before anything moves, then isn't drawn at all */
}
.mark.merging .ring .ghost {
  visibility: hidden; /* under the lit O it never shows; in the logo's gap it would */
}
.mark.merging .room {
  transition-duration: 300ms;
}
.logo-glow {
  position: absolute;
  z-index: -1; /* under the shapes, as each O's glow was */
  left: 0;
  top: 0;
  width: 100%;
  height: auto;
  overflow: visible;
  pointer-events: none;
  opacity: 0.001; /* not 0, so it's drawn as the merge starts (unseen) and fading in costs nothing later */
  will-change: opacity;
  transition: opacity 800ms ease;
}
.logo-glow.on {
  opacity: 1;
}
.lg-halo,
.lg-glow {
  fill: none;
  stroke: var(--ink);
  stroke-linecap: round;
}
.lg-halo {
  stroke-width: 15;
  filter: url(#f-halo);
  opacity: 0.3; /* white light carries further than coloured */
}
.lg-glow {
  stroke-width: 9.5;
  filter: url(#f-glow);
}
.lg-dot {
  fill: var(--yellow);
  filter: url(#f-dot);
  opacity: 0.85;
}
.logo-stem {
  fill: var(--ink);
}
.end h2 {
  font-size: clamp(36px, 5vw, 72px);
  letter-spacing: -0.035em;
}
.end .sub {
  margin: 20px auto 0;
}

.foot {
  padding: 36px 0 calc(36px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
}
.foot-in {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 24px;
  font-size: 14px;
  color: var(--muted);
}
.foot-logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 16px;
  color: var(--ink);
  text-decoration: none;
}
.foot-logo .logo {
  width: 28px;
  height: 28px;
}
.foot-links {
  display: flex;
  gap: 20px;
  margin-left: auto;
}
.foot-links a {
  text-decoration: none;
  color: var(--ink-2);
}
@media (hover: hover) {
  .foot-links a:hover {
    color: var(--ink);
  }
}

/* Tablets and phones: one column. */
@media (max-width: 899px) {
  .team-grid,
  .kpi-grid,
  .phone-grid {
    grid-template-columns: minmax(0, 1fr);
  }
  .runway-head {
    flex-direction: column;
    align-items: flex-start;
  }
  .clock-big {
    align-items: flex-start;
  }
  .roll-day {
    font-size: 15px;
    text-align: left;
  }
  .clock-time {
    font-size: 34px;
  }
  .board-ruler,
  .board-row.calm {
    display: none;
  }
  .runway-pin {
    padding-top: 80px;
  }
  .runway-text .sub {
    font-size: 16px;
  }
  .board {
    --who: 52px;
    padding: 14px 12px 18px;
    border-radius: 24px;
  }
  .board-who > span:last-child {
    display: none;
  }
  .board-row {
    height: 58px;
  }
  /* Phones: the task's name over its state, so neither gets cut off. */
  .run-bar {
    height: 44px;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 1px;
    padding: 0 12px;
    font-size: 12px;
    line-height: 1.2;
  }
  .run-name {
    max-width: 100%;
  }
  .run-state {
    margin-left: 0;
    font-size: 11px;
  }
  .board-top .alerts {
    width: 100%;
    justify-content: flex-start;
  }
  .alert > span:last-child {
    white-space: normal;
  }
  .alert small {
    display: block;
    margin-left: 0;
    font-size: 12px;
  }
  .kpi-tiles {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }
  .kpi-tiles .tile:last-child {
    grid-column: span 2;
  }
}
@media (max-width: 559px) {
  .scenes {
    grid-template-columns: minmax(0, 1fr);
  }
  .kpi-more {
    grid-template-columns: minmax(0, 1fr);
    gap: 8px;
    margin-top: 8px;
  }
  .kpi-card {
    padding: 14px;
    border-radius: 24px;
  }
  .kpi-head {
    flex-wrap: wrap;
  }
  .seg {
    margin-left: 0;
  }
  .kpi-rings {
    gap: 8px;
  }
  .ring-tile {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }
  .ring-box {
    width: 76px;
    height: 76px;
  }
  .tile-num {
    font-size: 19px;
  }
  .kpi-tiles {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
    margin-top: 8px;
  }
  .kpi-tiles .tile:last-child {
    grid-column: auto;
  }
  .tile {
    gap: 6px;
    padding: 14px;
    border-radius: 20px;
  }
  .tile-big {
    font-size: 24px;
  }
  .tile-label {
    font-size: 13px;
  }
  .tile-label small {
    font-size: 12px;
  }
  .runway-text h2 {
    font-size: 32px;
  }
}

/* Phones and tablets: the caption about who sees what goes under the rings, next to the faces you tap. */
@media (max-width: 899px) {
  .team-text {
    display: contents;
  }
  .team-grid {
    row-gap: 0;
  }
  .team-text h2 {
    order: 1;
  }
  .team-text .sub {
    order: 2;
  }
  .orbit {
    order: 3;
    margin-top: 36px;
  }
  .seeing {
    order: 4;
    align-items: center;
    margin-top: 28px;
    text-align: center;
  }
  .tour {
    order: 5;
    margin-inline: auto;
  }
  .hint {
    order: 6;
    text-align: center;
  }
}
/* Phones: the Talk chat and the week board both have to fit inside one screen (both are pinned, so
   whatever runs past the bottom could never be scrolled to). */
@media (max-width: 699px) {
  .chat {
    gap: 6px;
    margin: 8px 12px 10px;
  }
  .chat-head {
    display: none;
  }
  .bub {
    padding: 6px 10px 5px;
    font-size: 12px;
  }
  .bub .who {
    font-size: 11px;
  }
  .bub .meta {
    font-size: 10px;
  }
  .vn {
    gap: 8px;
  }
  .vn-play {
    width: 24px;
    height: 24px;
  }
  .vn-play::after {
    left: 9px;
    top: 7px;
    border-width: 5px 0 5px 8px;
  }
  .vn-bars {
    gap: 2px;
    height: 16px;
  }
  .vn-bars span {
    width: 2px;
    height: calc(var(--h) * 0.6px);
  }
  .file-card {
    gap: 8px;
    margin: 0 0 4px;
  }
  .file-kind {
    width: 30px;
    height: 30px;
    border-radius: 8px;
    font-size: 10px;
  }
  .file-name {
    font-size: 12px;
  }
  /* The week: its reason shows in the bell line above; the clock on one line; a compact key. */
  .runway-pin {
    padding: 74px 0 12px;
  }
  .runway-stack {
    gap: 12px;
  }
  .runway-text h2 {
    font-size: 28px;
  }
  .runway-text .sub {
    margin-top: 10px;
    font-size: 15px;
  }
  .pin-note {
    display: none;
  }
  .clock-big {
    flex-direction: row;
    align-items: baseline;
    gap: 10px;
  }
  .roll-day {
    font-size: 17px;
    color: var(--ink);
  }
  .clock-time {
    font-size: 26px;
  }
  .board .key {
    gap: 6px 12px;
    font-size: 11px;
  }
  .board .key li::before {
    width: 8px;
    height: 8px;
  }
  .board-top {
    gap: 8px;
    margin-bottom: 8px;
  }
  .board-row {
    height: 52px;
  }
  .run-bar {
    height: 42px;
  }
}
.runway-pin {
  overflow-x: clip; /* nothing on the board may widen the page */
}
/* The smallest phones: the card keeps its status, priority, title and people. */
@media (max-width: 380px) {
  .card-by,
  .due {
    display: none;
  }
}
/* Short phones (an iPhone SE with its toolbars): the week board and the phone mock-up lose their extras. */
@media (max-height: 640px) and (max-width: 899px) {
  .runway-text .sub,
  .key {
    display: none;
  }
  .board-row {
    height: 46px;
  }
  .clock {
    font-size: 44px;
  }
  .notes {
    margin-top: 12px;
  }
  .note {
    gap: 8px;
    padding: 9px;
  }
  .note-title {
    font-size: 13px;
  }
  .note-text {
    font-size: 12px;
  }
  .note-acts span {
    padding: 7px 6px;
    font-size: 12px;
  }
}
/* Sections out of sight stop their looping animations (main.js sets .off). */
.off *,
.off *::before,
.off *::after {
  animation-play-state: paused !important;
}

/* Less motion: everything lands in its final place at once. Scroll still moves the story along. */
@media (prefers-reduced-motion: reduce) {
  html:focus-within {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
  }
  .orbit-ring,
  .face > span {
    animation: none !important;
  }
  .mark {
    transform: none;
  }
}

/* Without JavaScript the pinned scenes become plain sections. */
html:not(.js) .story,
html:not(.js) .runway {
  height: auto;
}
html:not(.js) .story-pin,
html:not(.js) .runway-pin {
  position: static;
  height: auto;
  display: block;
  padding-block: 120px;
}
html:not(.js) .msgs,
html:not(.js) .say-b,
html:not(.js) .stage,
html:not(.js) .board {
  display: none;
}
html:not(.js) .say {
  position: static;
  translate: none;
  margin: 0 auto 56px;
}
html:not(.js) .stages {
  opacity: 1;
  display: block;
  margin: 0 auto;
}
html:not(.js) .stages li {
  opacity: 1;
  translate: none;
  margin-bottom: 36px;
}
