/* Hero "without / with" comparison animation.
   Each beat shows the pain and the benefit side by side; both sides loop while
   the beat is active. The global prefers-reduced-motion rule in styles.css
   disables every animation and transition. */

.inbox-stage.has-beats {
  display: flex;
  flex-direction: column;
}
.beats {
  position: relative;
  z-index: 2;
  flex: 1;
  display: grid;
  margin-top: 14px;
}
/* One direction carries the whole panel: a beat waits to the right, rests in
   place while it plays, and leaves to the left. Exit and entry therefore share
   an axis and a direction, so the cut reads as one continuous move rather than
   seven slides swapped by a crossfade. */
.beat {
  grid-area: 1 / 1;
  display: grid;
  grid-template-rows: auto 1fr;
  gap: 12px;
  opacity: 0;
  visibility: hidden;
  transform: translateX(30px);
  transition:
    opacity 380ms var(--ease),
    transform 520ms var(--ease),
    visibility 0s linear 520ms;
}
.beat.is-active {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s;
}
.beat.is-leaving {
  transform: translateX(-30px);
}
.beat-kicker {
  color: #aebcb6;
  font: 500 0.67rem/1.2 var(--mono);
  letter-spacing: 0.1em;
}
.beat .mono {
  font-family: var(--mono);
}

/* ---------- comparison layout ---------- */
.compare {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  align-items: stretch;
}
.side {
  position: relative;
  display: grid;
  grid-template-rows: auto 1fr;
  gap: 10px;
  min-height: 380px;
  padding: 16px 16px 14px;
  border-radius: 12px;
}
.side--pain {
  background: #1d2724;
  border: 1px dashed #4a5a55;
  color: #dfe7e3;
}
.side--benefit {
  background: #ffffff;
  color: var(--text);
  box-shadow: 0 22px 50px #0007;
}
.side-head {
  display: grid;
  gap: 6px;
  align-content: start;
}
.side-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  width: fit-content;
  padding: 3px 9px;
  border-radius: 999px;
  font: 600 0.64rem/1.4 var(--mono);
  letter-spacing: 0.06em;
}
.side-tag--pain {
  background: #2c3a36;
  color: #b8c5c0;
}
.side-tag--benefit {
  background: #dcebe2;
  color: var(--success);
}
.side-title {
  margin: 0;
  font-family: var(--display);
  font-size: 1.12rem;
  line-height: 1.3;
  font-weight: 700;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
.side--pain .side-title {
  color: #eef3f0;
  font-weight: 600;
}
.side-sub {
  margin: 0;
  font-size: 0.78rem;
  line-height: 1.5;
}
.side--pain .side-sub {
  color: #8f9c98;
}
.side--benefit .side-sub {
  color: var(--muted);
}
.side-stage {
  position: relative;
  min-height: 210px;
  align-self: center;
}

/* ---------- shared pieces ---------- */
.person {
  position: absolute;
  display: grid;
  justify-items: center;
  gap: 4px;
  font: 500 0.64rem/1.2 var(--mono);
  text-align: center;
}
.person-head {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 2px solid currentColor;
}
.person-body {
  width: 34px;
  height: 24px;
  border: 2px solid currentColor;
  border-bottom: 0;
  border-radius: 17px 17px 0 0;
}
.person small {
  max-width: 72px;
  color: inherit;
}
.person--busy {
  left: 4px;
  top: 80px;
  color: #c9d3cf;
  animation: fidget 1.6s ease-in-out infinite;
}
.person--calm {
  left: 4px;
  top: 80px;
  color: var(--success);
}
.card {
  position: absolute;
  padding: 11px 13px;
  background: #eef2f1;
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 10px;
}
.card b {
  display: block;
  font-size: 0.92rem;
  line-height: 1.25;
  letter-spacing: -0.01em;
}
.card small {
  display: block;
  margin-top: 3px;
  color: var(--muted);
  font-size: 0.68rem;
  line-height: 1.3;
}
.card--dark {
  background: #17201f;
  color: #f3f7f5;
  border-color: #17201f;
  box-shadow: 0 14px 30px #17201f33;
}
.card--dark small {
  color: #aebcb6;
}

/* ---------- pain side: refresh loop ---------- */
.tab-cloud {
  position: absolute;
  left: 56px;
  top: 6px;
  right: 0;
  height: 170px;
  overflow: hidden;
}
.tab {
  position: absolute;
  left: calc(var(--x) * 1px);
  top: calc(var(--y) * 1px);
  padding: 5px 8px;
  border-radius: 5px;
  background: #ffffff;
  color: var(--text);
  font: 500 0.58rem/1 var(--mono);
  letter-spacing: 0.06em;
  box-shadow: 0 6px 16px #0006;
  transform: rotate(calc(var(--r) * 1deg));
  animation: jitter 2.4s ease-in-out infinite;
  animation-delay: calc(var(--i) * -0.3s);
}
.tab::before {
  content: "↻ ";
  display: inline-block;
  color: var(--accent);
  animation: spin 1.4s linear infinite;
  animation-delay: calc(var(--i) * -0.2s);
}
.counter-chip {
  position: absolute;
  left: 0;
  bottom: 0;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  border-radius: 999px;
  background: #2c3a36;
  color: #dfe7e3;
  font: 500 0.66rem/1.2 var(--mono);
}
.counter-chip .spin {
  display: inline-block;
  color: var(--accent);
  animation: spin 1.4s linear infinite;
}

/* ---------- benefit side: one arrival loop ---------- */
.monitor {
  left: 66px;
  top: 74px;
  width: 168px;
  padding-right: 34px;
}
.monitor-eye {
  position: absolute;
  right: 11px;
  top: 10px;
  color: var(--success);
  font-size: 0.9rem;
  animation: blink 4.5s ease-in-out infinite;
}
/* The monitor hands the matched change down a short vertical rail into the inbox. */
.rail {
  position: absolute;
  left: 150px;
  top: 134px;
  width: 1px;
  height: 46px;
  background: var(--border);
}
.rail::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--accent);
  transform-origin: top center;
  animation: rail-grow 4.5s cubic-bezier(0.3, 0, 0.2, 1) infinite;
}
.rail-token {
  position: absolute;
  left: -11px;
  top: -11px;
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  font: 600 0.7rem/1 var(--mono);
  animation: token-travel 4.5s cubic-bezier(0.3, 0, 0.2, 1) infinite;
}
.inbox-chip {
  right: 0;
  top: 180px;
  width: 164px;
  animation: chip-arrive 4.5s var(--ease) infinite;
}

@keyframes rail-grow {
  0%,
  8% {
    transform: scaleY(0);
  }
  38%,
  88% {
    transform: scaleY(1);
  }
  100% {
    transform: scaleY(0);
  }
}
@keyframes token-travel {
  0%,
  8% {
    transform: translateY(0);
    opacity: 0;
  }
  12% {
    opacity: 1;
  }
  38%,
  44% {
    transform: translateY(46px);
    opacity: 1;
  }
  50%,
  100% {
    transform: translateY(46px);
    opacity: 0;
  }
}
@keyframes chip-arrive {
  0%,
  42% {
    opacity: 0;
    transform: translateY(8px);
  }
  50%,
  88% {
    opacity: 1;
    transform: none;
  }
  100% {
    opacity: 0;
    transform: translateY(8px);
  }
}
@keyframes blink {
  0%,
  40%,
  100% {
    opacity: 1;
  }
  44% {
    opacity: 0.2;
  }
}
@keyframes jitter {
  0%,
  100% {
    transform: rotate(calc(var(--r) * 1deg)) translate(0, 0);
  }
  50% {
    transform: rotate(calc(var(--r) * 1deg)) translate(2px, -3px);
  }
}
@keyframes fidget {
  0%,
  100% {
    transform: translateX(0);
  }
  50% {
    transform: translateX(3px);
  }
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}
.side-stage {
  container-type: inline-size;
}

/* ---------- nav / controls ---------- */
.beat-nav {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 14px;
}
.beat-segments {
  display: flex;
  flex: 1;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.beat-segments li {
  flex: 1;
  display: flex;
}
.beat-seg {
  position: relative;
  width: 100%;
  /* WCAG 2.5.8 asks for 24x24. Eight segments sharing one row with the counter
     and the toggle left each of them 22px wide on a phone, so the row wraps and
     the segments take a line of their own below. */
  min-width: 24px;
  min-height: 24px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
}
.beat-seg::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 10px;
  height: 3px;
  border-radius: 2px;
  background: #40514a;
}
.beat-seg::after {
  content: "";
  position: absolute;
  left: 0;
  top: 10px;
  height: 3px;
  width: 0;
  border-radius: 2px;
  background: #e07a57;
}
.beat-seg[aria-current="true"]::after {
  width: 100%;
  transition: width var(--beat-ms, 4200ms) linear;
}
.beat-seg.is-done::after {
  width: 100%;
}
.beat-seg:focus-visible {
  outline: 2px solid #e07a57;
  outline-offset: 3px;
}
.beat-toggle {
  min-width: 64px;
  min-height: 32px;
  padding: 4px 10px;
  border: 1px solid #40514a;
  border-radius: 6px;
  background: transparent;
  color: #dfe7e3;
  font: 500 0.7rem/1 var(--mono);
  cursor: pointer;
}
.beat-toggle:focus-visible {
  outline: 2px solid #e07a57;
  outline-offset: 2px;
}
.beat-counter {
  min-width: 56px;
  color: #aebcb6;
  font: 500 0.67rem/1 var(--mono);
  letter-spacing: 0.08em;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.inbox-stage.is-paused .beat-seg[aria-current="true"]::after {
  transition: none;
}
.inbox-stage.is-paused .beat * {
  animation-play-state: paused !important;
}
.beat-toggle .when-paused,
.inbox-stage.is-paused .beat-toggle .when-playing {
  display: none;
}
.inbox-stage.is-paused .beat-toggle .when-paused {
  display: inline;
}

@media (max-width: 1100px) and (min-width: 761px) {
  .side {
    min-height: 360px;
  }
}
@media (max-width: 760px) {
  .compare {
    grid-template-columns: 1fr;
    gap: 10px;
  }
  .side {
    min-height: 0;
    padding: 14px 14px 12px;
  }
  .side-title {
    font-size: 1.02rem;
  }
  .person--busy,
  .person--calm {
    top: 56px;
  }
  .tab-cloud {
    height: 140px;
    transform: scale(0.86);
    transform-origin: left top;
  }
  .side-stage {
    min-height: 214px;
  }
  .monitor {
    top: 54px;
    width: 150px;
  }
  .rail {
    left: 141px;
    top: 114px;
  }
  .inbox-chip {
    top: 160px;
    width: 150px;
  }
  /* The approval labels vary widely by locale. Anchor them to the stage's
     safe right edge on phones instead of assuming the desktop offset leaves
     enough room for every translation. */
  .b6 .act {
    left: auto;
    right: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .rail::before {
    transform: scaleY(1);
  }
  .rail-token {
    transform: translateY(46px);
  }
  .inbox-chip {
    opacity: 1;
  }
}

/* ======================================================================
   Beats 2–7 (same without / with layout; each side loops on its own)
   ====================================================================== */
.tag {
  display: inline-block;
  padding: 2px 7px;
  border-radius: 3px;
  font: 600 0.6rem/1.4 var(--mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.tag--ok {
  background: #dcebe2;
  color: var(--success);
}
.tag--warn {
  background: #f5e4dd;
  color: var(--accent);
}
.tag--mute {
  background: #eef2f1;
  color: var(--muted);
}
.token {
  position: absolute;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  font: 500 0.66rem/1.2 var(--mono);
  white-space: nowrap;
}
.token--ghost {
  background: #2c3a36;
  color: #b8c5c0;
}
.side--benefit .token--ghost {
  background: #eef2f1;
  color: var(--muted);
}
.token--ok {
  background: var(--success);
}
.token--rust {
  background: var(--accent);
}
.card--ghost {
  background: #243230;
  border: 1px dashed #4a5a55;
  color: #dfe7e3;
}
.card--ghost small {
  color: #8f9c98;
}
.card--gate {
  background: #ffffff;
  border: 2px solid var(--accent);
}
.card--black {
  background: #0d1412;
  border-color: #0d1412;
  color: #f3f7f5;
}
.card--black small {
  color: #aebcb6;
}
.person--low {
  top: 130px;
}
.counter-chip--rust {
  background: var(--accent);
  color: #fff;
}

/* ---- beat 2 ---- */
.noise-feed {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 168px;
  margin: 0;
  padding: 0;
  list-style: none;
  overflow: hidden;
  mask-image: linear-gradient(
    180deg,
    transparent,
    #000 14%,
    #000 86%,
    transparent
  );
}
.noise-row {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 28px;
  padding: 0 4px;
  border-bottom: 1px solid #2c3a36;
  color: #b8c5c0;
  font: 500 0.66rem/1 var(--mono);
  animation: feed-scroll 6s linear infinite;
}
.noise-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  opacity: 0.8;
}
@keyframes feed-scroll {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(-168px);
  }
}
.b2 .gate {
  left: 0;
  right: 0;
  top: 0;
}
.b2 .bounce {
  left: 0;
  top: 96px;
  animation: bounce-off 4.5s var(--ease) infinite;
}
.b2 .bounce--b {
  top: 130px;
  animation-delay: 0.9s;
}
@keyframes bounce-off {
  0%,
  10% {
    transform: translateX(-24px);
    opacity: 0;
  }
  22% {
    opacity: 1;
  }
  40% {
    transform: translateX(28px);
    opacity: 1;
  }
  52% {
    transform: translateX(6px);
    opacity: 0.5;
  }
  70%,
  100% {
    transform: translateX(6px);
    opacity: 0;
  }
}
.b2 .rail--gate {
  left: auto;
  right: 60px;
  top: 78px;
  height: 40px;
}
.b2 .inbox-chip--gate {
  top: 118px;
  width: 172px;
}
@keyframes token-travel-40 {
  0%,
  8% {
    transform: translateY(0);
    opacity: 0;
  }
  12% {
    opacity: 1;
  }
  38%,
  44% {
    transform: translateY(40px);
    opacity: 1;
  }
  50%,
  100% {
    transform: translateY(40px);
    opacity: 0;
  }
}
.b2 .rail--gate .rail-token {
  animation-name: token-travel-40;
}

/* ---- beat 3 ---- */
.b3 .changed {
  left: 0;
  top: 0;
  width: 130px;
  text-align: center;
}
.b3 .changed b {
  font-size: 1.1rem;
}
.skeleton {
  position: absolute;
  left: 146px;
  right: 0;
  top: 8px;
  display: grid;
  gap: 10px;
}
.skeleton i {
  display: block;
  height: 8px;
  border-radius: 4px;
  background: #2c3a36;
}
.skeleton i:nth-child(2) {
  width: 70%;
}
.skeleton i:nth-child(3) {
  width: 85%;
}
.skeleton .scan {
  position: absolute;
  left: 0;
  top: -8px;
  color: var(--accent);
  font-size: 1.1rem;
  animation: scan 3s ease-in-out infinite;
}
@keyframes scan {
  0%,
  100% {
    transform: translate(0, 0);
  }
  33% {
    transform: translate(60px, 18px);
  }
  66% {
    transform: translate(20px, 36px);
  }
}
.evidence {
  left: 0;
  right: 0;
  top: 0;
  padding: 12px 14px 10px;
  background: #ffffff;
  border: 1px solid var(--border);
  box-shadow: 0 12px 30px #17201f14;
}
.ev-top {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  color: var(--muted);
  font: 500 0.58rem/1.2 var(--mono);
  letter-spacing: 0.06em;
  margin-bottom: 9px;
}
.ev-row {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 8px;
  align-items: center;
}
.ev-cell {
  padding: 8px 10px;
  border-radius: 8px;
  background: #eef2f1;
}
.ev-cell--now {
  background: #f5e4dd;
  border: 1px solid #e9c8bb;
  animation: cell-pulse 4.5s ease-in-out infinite;
}
@keyframes cell-pulse {
  0%,
  100% {
    box-shadow: 0 0 0 0 #b3442400;
  }
  30% {
    box-shadow: 0 0 0 5px #b3442433;
  }
}
.ev-cell small {
  display: block;
  margin: 0 0 2px;
  color: var(--muted);
  font: 500 0.56rem/1.2 var(--mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.ev-cell b {
  display: block;
  font: 600 0.98rem/1.2 var(--mono);
}
.ev-cell--now b {
  color: var(--accent);
}
.ev-arrow {
  color: var(--accent);
  font-size: 1.1rem;
}
.ev-foot {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 12px;
  margin-top: 10px;
  color: var(--muted);
  font: 500 0.62rem/1.4 var(--mono);
}
.ev-foot span::before {
  content: "✓ ";
  color: var(--success);
}

/* ---- beat 4 ---- */
.b4 .status {
  left: 0;
  right: 0;
  top: 0;
}
.b4 .status .tag {
  margin-top: 6px;
}
.b4 .status .tag + .tag {
  margin-left: 4px;
}
.b4 .expired {
  left: 12px;
  top: 96px;
  animation: hidden-blink 3s ease-in-out infinite;
}
@keyframes hidden-blink {
  0%,
  100% {
    opacity: 0.25;
  }
  50% {
    opacity: 0.7;
  }
}
.b4 .status--honest {
  border-color: var(--accent);
}
.b4 .status--honest .tag--warn {
  animation: warn-pulse 3s ease-in-out infinite;
}
@keyframes warn-pulse {
  0%,
  100% {
    box-shadow: 0 0 0 0 #b3442400;
  }
  50% {
    box-shadow: 0 0 0 4px #b3442433;
  }
}
.b4 .rule {
  position: absolute;
  left: 0;
  top: 112px;
  padding: 6px 12px;
  border-radius: 999px;
  background: #17201f;
  color: #f3f7f5;
  font: 600 0.66rem/1.2 var(--mono);
}

/* ---- beat 5 ---- */
.form-stack {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 6px;
}
.field {
  display: grid;
  grid-template-columns: 62px 1fr;
  align-items: center;
  gap: 8px;
  color: #b8c5c0;
  font: 500 0.62rem/1.2 var(--mono);
}
.field i {
  display: block;
  height: 20px;
  border-radius: 5px;
  border: 1px dashed #4a5a55;
  background: #1a2421;
}
@keyframes field-in {
  0% {
    opacity: 0;
    transform: translateY(6px);
  }
  12%,
  85% {
    opacity: 1;
    transform: none;
  }
  100% {
    opacity: 0;
  }
}
.b5 .sentence {
  left: 0;
  right: 0;
  top: 0;
  padding: 14px 16px;
  background: #ffffff;
  border: 1px solid var(--border);
  box-shadow: 0 12px 30px #17201f14;
}
.b5 .sentence b {
  font-size: 0.98rem;
  line-height: 1.45;
}
.parts {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 12px;
}
.parts span {
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--muted);
  font: 500 0.6rem/1.3 var(--mono);
  animation: part-in 4.5s var(--ease) infinite;
  animation-delay: calc(var(--i) * 0.45s);
}
.parts span::before {
  content: "→ ";
  color: var(--accent);
}
.parts span:first-child::before {
  content: "";
}
@keyframes part-in {
  0%,
  10% {
    opacity: 0;
    transform: translateY(5px);
  }
  22%,
  88% {
    opacity: 1;
    transform: none;
  }
  100% {
    opacity: 0;
  }
}

/* ---- beat 6 ---- */
.b6 .auto-run {
  left: 0;
  top: 22px;
  animation: auto-run 4.5s var(--ease) infinite;
}
@keyframes auto-run {
  0%,
  10% {
    transform: translateX(0);
    opacity: 0;
  }
  18% {
    opacity: 1;
  }
  45%,
  88% {
    transform: translateX(28px);
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
.b6 .rail--auto {
  left: 118px;
  top: 34px;
  width: 1px;
  height: 44px;
}
.b6 .rail--auto .rail-token {
  animation-name: token-travel-44;
}
@keyframes token-travel-44 {
  0%,
  8% {
    transform: translateY(0);
    opacity: 0;
  }
  12% {
    opacity: 1;
  }
  38%,
  44% {
    transform: translateY(44px);
    opacity: 1;
  }
  50%,
  100% {
    transform: translateY(44px);
    opacity: 0;
  }
}
.b6 .receipt {
  left: 40px;
  right: 0;
  top: 84px;
  animation: chip-arrive 4.5s var(--ease) infinite;
}
.b6 .person--low {
  top: 138px;
  left: 0;
}
.gate-ring {
  position: absolute;
  left: 0;
  top: 26px;
  width: 96px;
  height: 96px;
  display: grid;
  place-content: center;
  padding: 8px;
  text-align: center;
  border-radius: 50%;
  background: #f5e4dd;
  border: 2px solid var(--accent);
}
.gate-ring b {
  display: block;
  font-size: 0.78rem;
  line-height: 1.2;
}
.gate-ring small {
  color: var(--muted);
  font-size: 0.56rem;
}
.b6 .act {
  left: 116px;
  top: calc(20px + var(--i) * 34px);
}
.b6 .act--blocked {
  animation: bump 3s var(--ease) infinite;
  animation-delay: calc(var(--i) * 0.6s);
}
@keyframes bump {
  0%,
  100% {
    transform: translateX(0);
  }
  40% {
    transform: translateX(-8px);
  }
  55% {
    transform: translateX(2px);
  }
}
.b6 .act--allow {
  top: calc(96px + var(--i) * 34px);
  animation: allow-pulse 3s ease-in-out infinite;
  animation-delay: calc(var(--i) * 0.6s);
}
@keyframes allow-pulse {
  0%,
  100% {
    box-shadow: 0 0 0 0 #236b4a00;
  }
  40% {
    box-shadow: 0 0 0 4px #236b4a33;
  }
}
.b6 .result {
  left: 0;
  top: 150px;
  width: 128px;
}

/* ---- beat 7 ---- */
.b7 .blackbox {
  left: 0;
  right: 0;
  top: 0;
  text-align: center;
  padding: 16px 14px;
}
.b7 .blackbox b {
  font-size: 1.05rem;
}
.b7 .confidence {
  left: 50%;
  top: 104px;
  transform: translateX(-50%);
  animation: confidence-flicker 3s ease-in-out infinite;
}
@keyframes confidence-flicker {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.45;
  }
}
.lane-card {
  left: 0;
  right: 0;
  display: grid;
  grid-template-columns: 30px 1fr;
  gap: 10px;
  align-items: center;
  background: #ffffff;
  border: 1px solid var(--border);
  box-shadow: 0 12px 30px #17201f14;
}
.lane-card--exact {
  top: 0;
}
.lane-card--semantic {
  top: 96px;
}
.lane-card b {
  font-size: 0.86rem;
}
.lane-card .tag {
  margin-top: 5px;
}
.lane-icon {
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  border-radius: 8px;
  font: 600 0.9rem/1 var(--mono);
}
.lane-icon--exact {
  background: #dcebe2;
  color: var(--success);
}
.lane-icon--semantic {
  background: #f5e4dd;
  color: var(--accent);
}
.lane-card--exact .lane-icon {
  animation: allow-pulse 3s ease-in-out infinite;
}

/* ======================================================================
   Play-once story timelines. Every beat plays its arrival story exactly
   once (ambient loops such as tab jitter keep running), then the controller
   crossfades to the next beat. Inactive beats hold no animation, so each
   activation restarts the story from the beginning.
   ====================================================================== */
.beat:not(.is-active) * {
  animation: none !important;
}

@keyframes rail-grow {
  from {
    transform: scaleY(0);
  }
  to {
    transform: scaleY(1);
  }
}
@keyframes token-travel {
  0% {
    transform: translateY(0);
    opacity: 0;
  }
  12% {
    opacity: 1;
  }
  72% {
    transform: translateY(46px);
    opacity: 1;
  }
  100% {
    transform: translateY(46px);
    opacity: 0;
  }
}
@keyframes token-travel-40 {
  0% {
    transform: translateY(0);
    opacity: 0;
  }
  12% {
    opacity: 1;
  }
  72% {
    transform: translateY(40px);
    opacity: 1;
  }
  100% {
    transform: translateY(40px);
    opacity: 0;
  }
}
@keyframes token-travel-44 {
  0% {
    transform: translateY(0);
    opacity: 0;
  }
  12% {
    opacity: 1;
  }
  72% {
    transform: translateY(44px);
    opacity: 1;
  }
  100% {
    transform: translateY(44px);
    opacity: 0;
  }
}
@keyframes chip-arrive {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes bounce-off {
  0% {
    transform: translateX(-24px);
    opacity: 0;
  }
  25% {
    opacity: 1;
  }
  60% {
    transform: translateX(28px);
    opacity: 1;
  }
  100% {
    transform: translateX(6px);
    opacity: 0.45;
  }
}
@keyframes auto-run {
  0% {
    transform: translateX(0);
    opacity: 0;
  }
  30% {
    opacity: 1;
  }
  100% {
    transform: translateX(28px);
    opacity: 1;
  }
}
@keyframes part-in {
  from {
    opacity: 0;
    transform: translateY(5px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes cell-pulse {
  0%,
  100% {
    box-shadow: 0 0 0 0 #b3442400;
  }
  50% {
    box-shadow: 0 0 0 5px #b3442433;
  }
}
@keyframes warn-pulse {
  0%,
  100% {
    box-shadow: 0 0 0 0 #b3442400;
  }
  50% {
    box-shadow: 0 0 0 4px #b3442433;
  }
}

.beat.is-active .rail::before {
  animation: rail-grow 600ms cubic-bezier(0.3, 0, 0.2, 1) 450ms both;
}
.beat.is-active .rail-token {
  animation: token-travel 1300ms cubic-bezier(0.3, 0, 0.2, 1) 550ms both;
}
.beat.is-active .inbox-chip {
  animation: chip-arrive 500ms var(--ease) 2200ms both;
}
.beat.is-active.b2 .bounce {
  animation: bounce-off 1100ms var(--ease) 450ms both;
}
.beat.is-active.b2 .bounce--b {
  animation-delay: 850ms;
}
.beat.is-active.b2 .rail--gate::before {
  animation-delay: 1500ms;
}
.beat.is-active.b2 .rail--gate .rail-token {
  animation: token-travel-40 1200ms cubic-bezier(0.3, 0, 0.2, 1) 1600ms both;
}
.beat.is-active.b2 .inbox-chip--gate {
  animation-delay: 3150ms;
}
.beat.is-active.b3 .ev-cell--now {
  animation: cell-pulse 1200ms ease-in-out 700ms 2 both;
}
.beat.is-active.b4 .status--honest .tag--warn {
  animation: warn-pulse 1200ms ease-in-out 600ms 2 both;
}
.beat.is-active.b5 .parts span {
  animation: part-in 400ms var(--ease) calc(700ms + var(--i) * 150ms) both;
}
.beat.is-active.b6 .auto-run {
  animation: auto-run 900ms var(--ease) 450ms both;
}
.beat.is-active.b6 .rail--auto::before {
  animation-delay: 1000ms;
}
.beat.is-active.b6 .rail--auto .rail-token {
  animation: token-travel-44 1100ms cubic-bezier(0.3, 0, 0.2, 1) 1100ms both;
}
.beat.is-active.b6 .receipt {
  animation: chip-arrive 500ms var(--ease) 2550ms both;
}

/* ======================================================================
   Index and position variables, assigned by selector rather than by inline
   style attribute. The production Content-Security-Policy sets
   style-src 'self' with no unsafe-inline, so an inline style attribute is
   dropped and every positioned element would collapse onto the same spot.
   ====================================================================== */
.tab:nth-of-type(1) {
  --x: 0;
  --y: 0;
  --r: -6;
  --i: 0;
}
.tab:nth-of-type(2) {
  --x: 72;
  --y: 10;
  --r: 4;
  --i: 1;
}
.tab:nth-of-type(3) {
  --x: 136;
  --y: 2;
  --r: -3;
  --i: 2;
}
.tab:nth-of-type(4) {
  --x: 20;
  --y: 58;
  --r: 7;
  --i: 3;
}
.tab:nth-of-type(5) {
  --x: 92;
  --y: 66;
  --r: -5;
  --i: 4;
}
.tab:nth-of-type(6) {
  --x: 138;
  --y: 46;
  --r: 5;
  --i: 5;
}
.tab:nth-of-type(7) {
  --x: 44;
  --y: 118;
  --r: -4;
  --i: 6;
}
.tab:nth-of-type(8) {
  --x: 120;
  --y: 124;
  --r: 6;
  --i: 7;
}

.noise-row:nth-of-type(1) {
  --i: 0;
}
.noise-row:nth-of-type(2) {
  --i: 1;
}
.noise-row:nth-of-type(3) {
  --i: 2;
}
.noise-row:nth-of-type(4) {
  --i: 3;
}
.noise-row:nth-of-type(5) {
  --i: 4;
}
.noise-row:nth-of-type(6) {
  --i: 5;
}
.noise-row:nth-of-type(7) {
  --i: 6;
}
.noise-row:nth-of-type(8) {
  --i: 7;
}
.noise-row:nth-of-type(9) {
  --i: 8;
}
.noise-row:nth-of-type(10) {
  --i: 9;
}
.noise-row:nth-of-type(11) {
  --i: 10;
}
.noise-row:nth-of-type(12) {
  --i: 11;
}

.field:nth-of-type(1) {
  --i: 0;
}
.field:nth-of-type(2) {
  --i: 1;
}
.field:nth-of-type(3) {
  --i: 2;
}
.field:nth-of-type(4) {
  --i: 3;
}
.field:nth-of-type(5) {
  --i: 4;
}

.parts span:nth-of-type(1) {
  --i: 0;
}
.parts span:nth-of-type(2) {
  --i: 1;
}
.parts span:nth-of-type(3) {
  --i: 2;
}
.parts span:nth-of-type(4) {
  --i: 3;
}

.b6 .act--blocked:nth-of-type(1) {
  --i: 0;
}
.b6 .act--blocked:nth-of-type(2) {
  --i: 1;
}
/* The allowed pair are the third and fourth spans in the stage, so their
   index restarts at zero rather than continuing the blocked pair's count. */
.b6 .act--allow:nth-of-type(3) {
  --i: 0;
}
.b6 .act--allow:nth-of-type(4) {
  --i: 1;
}

/* ======================================================================
   Staged reveals and a tighter beat.
   Every beat used to finish its story in 1.1–3.7s and then sit still for the
   rest of its 5.6s, which reads as the panel waiting rather than performing.
   The beat is now 4.2s, and the beats whose story was shortest gain their
   information in stages instead of arriving all at once.
   ====================================================================== */
@keyframes reveal-up {
  from {
    opacity: 0;
    transform: translateY(7px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Beat 3: the evidence card assembles — source line, the before figure, the
   arrow, then the changed figure, then what was kept. */
.beat.is-active.b3 .ev-top,
.beat.is-active.b3 .ev-row > *,
.beat.is-active.b3 .ev-foot span {
  animation: reveal-up 340ms var(--ease) both;
}
.beat.is-active.b3 .ev-top {
  animation-delay: 260ms;
}
.beat.is-active.b3 .ev-row > *:nth-of-type(1) {
  animation-delay: 520ms;
}
.beat.is-active.b3 .ev-row > *:nth-of-type(2) {
  animation-delay: 740ms;
}
.beat.is-active.b3 .ev-row > *:nth-of-type(3) {
  animation-delay: 920ms;
}
.beat.is-active.b3 .ev-foot span:nth-of-type(1) {
  animation-delay: 1240ms;
}
.beat.is-active.b3 .ev-foot span:nth-of-type(2) {
  animation-delay: 1380ms;
}
.beat.is-active.b3 .ev-foot span:nth-of-type(3) {
  animation-delay: 1520ms;
}
.beat.is-active.b3 .ev-cell--now {
  animation:
    reveal-up 340ms var(--ease) 920ms both,
    cell-pulse 1200ms ease-in-out 1400ms 2 both;
}

/* Beat 4: the honest row lands, then names what broke, then the rule that
   separates "nothing changed" from "cannot see". */
.beat.is-active.b4 .status--honest,
.beat.is-active.b4 .status--honest .tag,
.beat.is-active.b4 .rule {
  animation: reveal-up 340ms var(--ease) both;
}
.beat.is-active.b4 .status--honest {
  animation-delay: 300ms;
}
.beat.is-active.b4 .status--honest .tag:nth-of-type(1) {
  animation-delay: 700ms;
}
.beat.is-active.b4 .status--honest .tag:nth-of-type(2) {
  animation-delay: 880ms;
}
.beat.is-active.b4 .rule {
  animation-delay: 1400ms;
}
.beat.is-active.b4 .status--honest .tag--warn {
  animation:
    reveal-up 340ms var(--ease) 700ms both,
    warn-pulse 1200ms ease-in-out 1200ms 2 both;
}

/* Beat 5: the sentence arrives before it is taken apart. */
.beat.is-active.b5 .sentence {
  animation: reveal-up 380ms var(--ease) 260ms both;
}
.beat.is-active.b5 .parts span {
  animation: part-in 400ms var(--ease) calc(900ms + var(--i) * 170ms) both;
}

/* Beat 7: the two lanes separate out of the black box in turn. */
.beat.is-active.b7 .lane-card--exact {
  animation: reveal-up 360ms var(--ease) 420ms both;
}
.beat.is-active.b7 .lane-card--semantic {
  animation: reveal-up 360ms var(--ease) 900ms both;
}
.beat.is-active.b7 .lane-card .tag {
  animation: reveal-up 300ms var(--ease) both;
}
.beat.is-active.b7 .lane-card--exact .tag {
  animation-delay: 900ms;
}
.beat.is-active.b7 .lane-card--semantic .tag {
  animation-delay: 1380ms;
}

/* Beat 2's chain started late enough to overrun the shorter beat. */
.beat.is-active.b2 .rail--gate::before {
  animation-delay: 1200ms;
}
.beat.is-active.b2 .rail--gate .rail-token {
  animation: token-travel-40 1200ms cubic-bezier(0.3, 0, 0.2, 1) 1300ms both;
}
.beat.is-active.b2 .inbox-chip--gate {
  animation-delay: 2850ms;
}

/* Ambient loops are finite so the whole beat can be seeked to a timestamp and
   reproduced exactly. Each count covers the 4.2s beat with room to spare; an
   unbounded animation has no end time and cannot be measured. */
.beat.is-active .tab {
  animation-iteration-count: 2;
  animation-fill-mode: both;
}
.beat.is-active .tab::before,
.beat.is-active .counter-chip .spin {
  animation-iteration-count: 4;
  animation-fill-mode: both;
}
.beat.is-active .person--busy {
  animation-iteration-count: 3;
  animation-fill-mode: both;
}
.beat.is-active .monitor-eye,
.beat.is-active .noise-row {
  animation-iteration-count: 1;
  animation-fill-mode: both;
}
.beat.is-active .skeleton .scan,
.beat.is-active .expired,
.beat.is-active .confidence,
.beat.is-active .act--allow {
  animation-iteration-count: 2;
  animation-fill-mode: both;
}
.beat.is-active .act--blocked {
  animation-iteration-count: 2;
  animation-fill-mode: both;
}

/* Every ambient loop is retimed to finish exactly with the beat. A loop that
   runs past the cut cannot be seeked to a timestamp and leaves the measurement
   reporting a story longer than the beat that contains it. */
.beat.is-active .tab {
  animation-duration: 1400ms;
  animation-iteration-count: 3;
}
.beat.is-active .tab::before,
.beat.is-active .counter-chip .spin {
  animation-duration: 1400ms;
  animation-iteration-count: 3;
}
.beat.is-active .person--busy {
  animation-duration: 1400ms;
  animation-iteration-count: 3;
}
.beat.is-active .monitor-eye {
  animation-duration: 4200ms;
  animation-iteration-count: 1;
}
.beat.is-active .noise-row {
  animation-duration: 4200ms;
  animation-iteration-count: 1;
}
.beat.is-active .skeleton .scan,
.beat.is-active .expired,
.beat.is-active .confidence,
.beat.is-active .act--allow,
.beat.is-active .lane-card--exact .lane-icon {
  animation-duration: 2100ms;
  animation-iteration-count: 2;
  animation-fill-mode: both;
}
.beat.is-active .act--blocked {
  animation-duration: 1400ms;
  animation-iteration-count: 3;
}

/* Beat 5 held its frame still for well over half the beat; the sentence now
   comes apart across a wider span so the frame keeps gaining information. */
.beat.is-active.b5 .parts span {
  animation: part-in 400ms var(--ease) calc(1100ms + var(--i) * 300ms) both;
}

/* The allowed chips carried a per-item delay that pushed their pulse past the
   cut; their stagger already reads from position, so the delay is not needed. */
.beat.is-active .act--allow {
  animation-delay: 0ms;
}

.beat.is-active .act--blocked {
  animation-delay: 0ms;
}

/* ======================================================================
   Light, depth and colour.
   Everything here ramps; nothing strobes. The animation brief commits to no
   flicker, and rapid flashing is both an accessibility hazard and, per the
   motion doctrine, a way of filling time rather than telling a story. Light is
   spent the same way the accent colour is: only where something arrives.
   ====================================================================== */

/* A soft rust bloom swells behind a result and lands on the same frame the
   result settles, so the two read as one event powering on rather than a card
   appearing next to a glow. Peak stays low so the frame is lit, not washed. */
@keyframes bloom-in {
  from {
    opacity: 0;
    transform: scale(0.82);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
.inbox-chip,
.inbox-chip--gate,
.receipt,
.ev-cell--now,
.result {
  position: absolute;
  isolation: isolate;
}
.inbox-chip::before,
.inbox-chip--gate::before,
.receipt::before,
.ev-cell--now::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -26px -32px;
  border-radius: 40px;
  background: radial-gradient(
    ellipse at center,
    #b3442455 0%,
    #b3442422 45%,
    transparent 72%
  );
  opacity: 0;
}
.beat.is-active .inbox-chip::before {
  animation: bloom-in 620ms var(--ease) 1980ms both;
}
.beat.is-active.b2 .inbox-chip--gate::before {
  animation: bloom-in 620ms var(--ease) 2630ms both;
}
.beat.is-active.b6 .receipt::before {
  animation: bloom-in 620ms var(--ease) 2330ms both;
}
.beat.is-active.b3 .ev-cell--now::before {
  animation: bloom-in 620ms var(--ease) 820ms both;
}

/* The safe actions carry a green halo instead of a second rust accent, so the
   two meanings never share a colour. */
.act--allow {
  isolation: isolate;
}
.act--allow::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -14px -18px;
  border-radius: 999px;
  background: radial-gradient(ellipse at center, #236b4a4d 0%, transparent 70%);
  opacity: 0;
}
.beat.is-active .act--allow::before {
  animation: bloom-in 560ms var(--ease) 1500ms both;
}

/* One highlight travels through the benefit headline as the beat opens. The
   gradient is wider than its own box, because background-position only moves a
   background that is larger than the element it fills. */
/* Guarded: without background-clip the fill colour must stay opaque, or the
   headline would render as transparent text on a white card. */
@supports (background-clip: text) or (-webkit-background-clip: text) {
  .side--benefit .side-title {
    background-image: linear-gradient(
      100deg,
      var(--text) 0%,
      var(--text) 34%,
      var(--accent) 47%,
      var(--text) 60%,
      var(--text) 100%
    );
    background-size: 320% 100%;
    background-position: 100% 50%;
    background-repeat: no-repeat;
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
  }
}
@keyframes title-sweep {
  from {
    background-position: 100% 50%;
  }
  to {
    background-position: 0% 50%;
  }
}
.beat.is-active .side--benefit .side-title {
  animation: title-sweep 1500ms cubic-bezier(0.4, 0, 0.2, 1) 220ms both;
}

/* The pain side's grid drifts against the panel's direction. Slower and
   smaller than anything in front of it, so it reads as depth, not as motion
   competing for attention. */
.beat.is-active .side--pain::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  border-radius: inherit;
  background-image:
    linear-gradient(#ffffff08 1px, transparent 1px),
    linear-gradient(90deg, #ffffff08 1px, transparent 1px);
  background-size: 34px 34px;
  animation: grid-drift 4200ms linear 1 both;
}
@keyframes grid-drift {
  from {
    transform: translate3d(-7px, 0, 0);
  }
  to {
    transform: translate3d(0, 0, 0);
  }
}
.side--pain > * {
  position: relative;
  z-index: 1;
}

/* A single warm wash sits under the benefit card so the two sides differ in
   temperature as well as in content. It does not move. */
.side--benefit {
  background-image: radial-gradient(
    120% 80% at 88% 4%,
    #b344240f 0%,
    transparent 58%
  );
}

@media (max-width: 900px) {
  .beat-nav {
    flex-wrap: wrap;
  }
  .beat-segments {
    order: -1;
    flex: 1 0 100%;
  }
}
