/*
 * roc-home.css: the home page's tools and sections that no other page needs
 * (D2, D2.1). Loaded right after roc.css, only on home and /ecommerce/
 * ($page['styles'] in their index.php; partials/roc/head.php prints it), so
 * /pricing/, /coach/ and the rest don't carry it render-blocking.
 *
 *   25    Flow revenue map (js/roc-fmap.js)
 *   26    The week, replayed (js/roc-replay.js)
 *   29.1  What's running vs a complete program (home #gap)
 *   29.3+ D2.1: calculator, flow map door, branches, scroll-told week,
 *         proof, home pricing, FAQ aside, QA fixes
 *
 * Tokens, keyframes (mo-*) and the motion layer (§24) stay in roc.css.
 * Rationale for each part: docs/experts/D2-motion-brief.md.
 */

/* 25  FLOW REVENUE MAP (js/roc-fmap.js; D2-T6), home #build */
.fmap {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.fmap__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 24px;
  padding: 16px 18px;
  border-radius: var(--r-panel);
  background: var(--ice-light);
}
.fmap__q {
  margin: 0;
  font-size: 17px;
  font-weight: 620;
}
.fmap__toggle {
  height: 44px;
  padding: 0 20px;
  font-size: 15px;
}
.fmap__panel {
  position: sticky;
  bottom: 12px;
  z-index: 4;
  display: grid;
  gap: 12px;
}
.fmap__how[hidden],
.fmap__next[hidden] {
  display: none;
}
.is-mapping .flow__in :is(input, label) {
  scroll-margin-bottom: 120px;
}
.fmap__panel[hidden] {
  display: none;
}
.fmap__how,
.fmap__next {
  margin: 0;
  max-width: 720px;
  color: var(--cocoa-soft);
  font-size: 15px;
}
.fmap__next {
  padding: 0 4px;
}
.fmap__next a {
  color: var(--cocoa);
  font-weight: 620;
}
.fmap__total {
  display: grid;
  gap: 4px;
  padding: 12px 16px;
  border-radius: var(--r-panel);
  background: var(--cocoa);
  color: var(--ice);
  box-shadow: 0 18px 40px color-mix(in srgb, var(--cocoa) 22%, transparent);
}
.fmap__label {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--mist);
}
.fmap__fig {
  font-family: var(--stack-wide);
  font-size: 22px;
  font-variation-settings: 'wdth' 125;
  font-weight: 640;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.fmap__note {
  color: var(--mist);
  font-size: 13px;
}
.flow {
  flex-wrap: wrap;
}
.flow__in {
  flex: 1 0 100%;
  display: grid;
  gap: 10px 20px;
  grid-template-columns: minmax(0, 1fr);
  padding-top: 6px;
}
.flow__in[hidden] {
  display: none;
}
.flow__field {
  display: grid;
  gap: 4px;
}
.flow__lab {
  font-size: 14px;
  font-weight: 600;
}
.flow__num {
  box-sizing: border-box;
  width: 100%;
  max-width: 220px;
  height: 46px;
  padding: 0 14px;
  border: 1px solid var(--ice-deep);
  border-radius: var(--r-input);
  background: var(--white);
  color: var(--cocoa);
  font: inherit;
  font-family: var(--font-mono);
  font-size: 15px;
}
.flow__num:focus-visible {
  outline: 2px solid var(--cocoa);
  outline-offset: 2px;
}
.flow__hint {
  color: var(--cocoa-soft);
  font-size: 13px;
}
.flow__live {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  font-size: 14px;
  cursor: pointer;
}
.flow__live input {
  width: 18px;
  height: 18px;
  accent-color: var(--cocoa);
}
.flow__out {
  display: grid;
  gap: 8px;
  align-content: center;
}
.flow__est {
  font-size: 15px;
  font-variant-numeric: tabular-nums;
}
.flow__meter {
  display: block;
  height: 6px;
  overflow: hidden;
  border-radius: 6px;
  background: var(--ice-deep);
}
.flow__meter i {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--cocoa);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform .45s var(--mo-ease);
}
.flow.is-live .flow__meter i {
  background: var(--mist);
}
.flow.is-live .flow__est {
  color: var(--cocoa-soft);
}
.flow__none {
  margin: 0;
  color: var(--cocoa-soft);
  font-size: 14px;
}
@media (min-width: 768px) {
  .fmap__bar {
    padding: 18px 18px 18px 26px;
  }
  .fmap__total {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    padding: 16px 24px;
  }
  .fmap__fig {
    font-size: 32px;
    text-align: right;
  }
  .flow__in {
    grid-column: 1 / -1;
    grid-template-columns: minmax(0, 1.1fr) auto minmax(0, 1fr);
    align-items: center;
    padding-top: 0;
  }
  .flow__in:has(.flow__none) {
    grid-template-columns: minmax(0, 1fr);
  }
  .flow__est {
    text-align: right;
  }
}

/* 26  THE WEEK, REPLAYED (js/roc-replay.js; D2-T7): the Shopper Test timeline
   gains a test inbox and a playhead. The playhead is the route's live tip,
   so it's Spark (BRAND.md orange rule). */
.tl__stop {
  transition: opacity .4s ease;
}
.has-replay .tl__stop.is-future {
  opacity: .42;
}
.tl__hit {
  position: absolute;
  top: -6px;
  left: -42px;
  width: calc(100% + 48px);
  height: 30px;
  z-index: 3;
  padding: 0;
  border: 0;
  border-radius: 12px;
  background: none;
  cursor: pointer;
}
.tl__hit:focus-visible {
  outline: 2px solid var(--cocoa);
  outline-offset: 2px;
}
.tl__playhead {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  width: 14px;
  height: 14px;
  margin: -7px 0 0 -7px;
  border-radius: 50%;
  background: var(--spark);
  box-shadow: 0 0 0 4px var(--ice-light);
  opacity: 0;
  transition: transform .9s var(--mo-ease-io), opacity .3s ease;
  pointer-events: none;
}
.tl__playhead.is-on {
  opacity: 1;
}
.tl__playhead::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--spark);
  opacity: 0;
}
.mo .tl__playhead.is-on::after {
  animation: mo-ping 1.8s var(--mo-ease) 3;
}
.mo .tl:not(.is-replaying) .tl__playhead::after {
  animation: none;
}
.has-replay .tl__stop.is-on .tl__what {
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
}

.tlr {
  display: grid;
  gap: 20px;
  margin: 26px 0 0 -34px;
  padding-top: 24px;
  border-top: 2px dashed var(--ice-deep);
}
.tlr__inbox {
  overflow: hidden;
  min-height: 452px;   /* the whole week's rows: no shift while it plays */
  padding: 14px 0 8px;
  border-radius: var(--r-frame);
  background: var(--white);
  box-shadow: 0 1px 0 var(--ice-deep), 0 22px 44px color-mix(in srgb, var(--cocoa) 8%, transparent);
}
.tlr__head {
  display: flex;
  justify-content: space-between;
  padding: 0 16px 10px;
  color: var(--cocoa-soft);
  font-size: 12px;
}
.tlr__tabs {
  display: flex;
  gap: 6px;
  padding: 0 12px 12px;
  border-bottom: 1px solid var(--ice-deep);
}
.tlr__tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  padding: 0 10px;
  border-radius: var(--r-pill);
  background: var(--ice-light);
  color: var(--cocoa-soft);
  font-size: 12px;
  font-weight: 600;
  transition: background-color .3s ease, color .3s ease;
}
.tlr__tab b {
  font-family: var(--font-mono);
  font-weight: 500;
}
.tlr__tab.is-hit {
  background: var(--cocoa);
  color: var(--ice);
}
.tlr__list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.tlr__row {
  display: grid;
  grid-template-columns: 10px minmax(0, 1fr) auto;
  gap: 2px 10px;
  align-items: baseline;
  padding: 11px 16px;
  border-bottom: 1px solid var(--ice-deep);
  font-size: 14px;
}
.tlr__dot {
  grid-row: span 2;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--cocoa);
  align-self: center;
}
.tlr__row.is-new .tlr__dot {
  background: var(--spark);
}
.tlr__from {
  font-weight: 640;
}
.tlr__subj {
  grid-column: 2;
}
.tlr__at {
  grid-column: 3;
  grid-row: 1;
  color: var(--cocoa-soft);
  font-size: 11px;
}
.tlr__tag {
  grid-column: 3;
  grid-row: 2;
  justify-self: end;
  color: var(--cocoa-soft);
  font-size: 12px;
}
.tlr__row--act {
  grid-template-columns: minmax(0, 1fr);
  color: var(--cocoa-soft);
}
.tlr__row--act .tlr__subj {
  grid-column: 1;
  font-size: 12px;
}
.tlr__row--none {
  grid-template-columns: minmax(0, 1fr) auto;
  margin: 8px 12px;
  border: 2px dashed var(--mist);
  border-radius: 10px;
  color: var(--cocoa-soft);
}
.tlr__row--none .tlr__subj {
  grid-column: 1;
}
.tlr__row--none .tlr__at {
  grid-column: 2;
}
.tlr__row--report {
  grid-template-columns: minmax(0, 1fr);
  margin: 8px 12px;
  border: 0;
  border-radius: 10px;
  background: var(--cocoa);
  color: var(--ice);
  font-weight: 620;
}
.tlr__row--report .tlr__subj {
  grid-column: 1;
}
.tlr__side {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: space-between;
  gap: 18px;
}
.tlr__now {
  display: grid;
  align-content: start;
  gap: 8px;
  min-height: 178px;   /* the longest stop's text: nothing below moves */
}
.tlr__time {
  color: var(--cocoa-soft);
  font-size: 13px;
}
.tlr__time:empty::before {
  content: 'Day 0';
}
.tlr__what {
  font-family: var(--stack-wide);
  font-size: 24px;
  font-variation-settings: 'wdth' 112;
  font-weight: 640;
  line-height: 1.1;
}
.tlr__where {
  max-width: 420px;
  color: var(--cocoa-soft);
  font-size: 16px;
}
.tlr__play {
  height: 44px;
  padding: 0 20px;
  font-size: 15px;
}
@media (prefers-reduced-motion: no-preference) {
  .tlr__row.is-new {
    animation: mo-land .55s var(--mo-ease) both;
  }
  .tlr__now {
    animation: none;
  }
}
@keyframes mo-land {
  from { opacity: 0; transform: translateY(-14px); }
}
@media (min-width: 1024px) {
  .tl__hit {
    top: -8px;
    left: -8px;
    width: calc(100% + 16px);
    height: 60px;
  }
  .tlr {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    gap: 40px;
    margin: 34px 0 0;
    padding-top: 30px;
  }
  .tlr__what {
    font-size: 30px;
    font-variation-settings: 'wdth' 125;
  }
  .tlr__side {
    padding: 8px 0;
  }
  .tlr__now {
    min-height: 0;
  }
}

/* 29.1 What's running vs what a complete program runs. Shape and motion carry
   the meaning, not red and green (off-brand, and about 1 in 12 men can't
   tell them apart). Left: grey dashed rings turn like a loader that stalls.
   Right: rings go live one by one, a Spark centre and a ping (orange rule:
   Spark marks what is live). Static and complete without .mo. */
.gap-list__dot {
  position: relative;
}
.gap-list--now .gap-list__dot {
  border-color: var(--mist);
}
.gap-list--full .gap-list__dot::after {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--spark);
}
@media (min-width: 768px) {
  .gap-list__dot {
    flex-basis: 12px;
    height: 12px;
  }
}
.mo .gap-list--now li:not(.mo-wait) .gap-list__dot {
  animation: mo-stall 2.6s cubic-bezier(.3, .1, .2, 1) calc(250ms + var(--mo-i, 0) * 160ms) both;
}
.mo .gap-list--full li:not(.mo-wait) .gap-list__dot {
  animation: mo-live-ring .7s var(--mo-ease) calc(500ms + var(--mo-i, 0) * 260ms) both;
}
.mo .gap-list--full li:not(.mo-wait) .gap-list__dot::after {
  animation: mo-live-dot .5s var(--mo-ease) calc(700ms + var(--mo-i, 0) * 260ms) both;
}
.mo .gap-list--full li:not(.mo-wait) .gap-list__dot::before {
  content: '';
  position: absolute;
  inset: -3px;
  border-radius: 50%;
  background: var(--spark);
  opacity: 0;
  animation: mo-ping 1s var(--mo-ease) calc(720ms + var(--mo-i, 0) * 260ms) 1 forwards;
}
@keyframes mo-stall {
  0% { transform: rotate(0); }
  55% { transform: rotate(320deg); }
  70% { transform: rotate(300deg); }
  82% { transform: rotate(318deg); }
  100% { transform: rotate(310deg); }
}
@keyframes mo-live-ring {
  0% { border-color: var(--mist); transform: scale(.85); }
  60% { border-color: var(--cocoa); transform: scale(1.3); }
  100% { border-color: var(--cocoa); transform: scale(1); }
}
@keyframes mo-live-dot {
  from { transform: scale(0); }
}

/* 29.3 The calculator: the CTA under its figure; the formula becomes the
   visitor's own working. */
.calc__next {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 18px;
}
.calc__next-note {
  max-width: 260px;
  color: var(--cocoa-soft);
  font-size: 14px;
}
.calc__work {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 14px;
  margin: 0;
  padding: 14px 16px;
  border-radius: 14px;
  background: var(--white);
  box-shadow: 0 1px 0 var(--ice-deep);
  color: var(--cocoa);
  font-size: 14px;
}
.calc__work-label {
  color: var(--cocoa-soft);
  font-size: 11px;
}
.calc__work-sum {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}
.calc__tok {
  padding: 3px 8px;
  border-radius: 8px;
  background: var(--ice);
  font-variant-numeric: tabular-nums;
}
.calc__tok--out {
  background: var(--cocoa);
  color: var(--ice);
}
@media (min-width: 768px) {
  .calc__out {
    justify-content: flex-start;
    gap: 30px;
  }
  .calc__foot {
    align-items: center;
  }
  .calc__work {
    flex: 1 1 100%;
    padding: 16px 20px;
    font-size: 16px;
  }
}

/* 29.4 The flow map's door: a dark tool card that can't be scrolled past,
   with a worked example (420 × $6.77 → × $13.70, rounded to $10). */
.fmap__bar {
  position: relative;
  align-items: flex-end;
  padding: 22px 20px;
  border-radius: var(--r-panel);
  background: var(--cocoa);
  color: var(--ice);
}
.fmap__pitch {
  display: grid;
  gap: 8px;
  max-width: 640px;
}
.fmap__tag {
  justify-self: start;
  padding: 4px 10px;
  border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--ice) 14%, transparent);
  color: var(--ice);
  font-size: 12px;
}
.fmap__q {
  margin: 0;
  font-family: var(--stack-wide);
  font-size: 22px;
  font-variation-settings: 'wdth' 112;
  font-weight: 640;
  line-height: 1.12;
}
.fmap__eg {
  margin: 0;
  color: var(--mist);
  font-size: 12px;
}
.fmap__toggle {
  position: relative;
  height: 50px;
  padding: 0 24px;
  border: 0;
  background: var(--ice);
  color: var(--cocoa);
  font-size: 16px;
}
.fmap__toggle[aria-expanded="true"] {
  border: 2px solid var(--ice);
  background: transparent;
  color: var(--ice);
}
@media (hover: hover) {
  .fmap__toggle:hover {
    border-color: var(--spark);
    background: var(--spark);
    color: var(--cocoa);
  }
}
.fmap__toggle:focus-visible {
  outline: 2px solid var(--ice);
  outline-offset: 3px;
}
.mo .fmap__toggle[aria-expanded="false"]::after {
  content: '';
  position: absolute;
  top: -4px;
  right: -4px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--spark);
  box-shadow: 0 0 0 3px var(--cocoa);
  animation: mo-halo 2.4s cubic-bezier(.2, .7, .3, 1) .8s 3;
}
@media (min-width: 768px) {
  .fmap__bar {
    padding: 28px 28px 28px 32px;
  }
  .fmap__q {
    font-size: 30px;
    font-variation-settings: 'wdth' 125;
  }
  .fmap__eg {
    font-size: 13px;
  }
}

/* 29.5 The flows branch off as the route reaches them, tied to the scroll
   (and back again on the way up): the branch draws from the spine, a Spark
   runs out along it, the ring lands. Chromium and Safari 26; elsewhere
   §24.1's arrival draw stays. */
@supports (animation-timeline: view()) {
  .mo .flow {
    view-timeline-name: --mo-flow;
  }
  .mo .flow .flow__branch {
    transform-origin: 0 50%;
    animation: mo-branch linear both;
    animation-timeline: --mo-flow;
    animation-range: cover 24% cover 37%;
  }
  .mo .flow::after {
    content: '';
    position: absolute;
    top: 39.5px;
    left: -62px;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--spark);
    pointer-events: none;
    animation: mo-branch-run linear both;
    animation-timeline: --mo-flow;
    animation-range: cover 24% cover 40%;
  }
  .mo .flow .flow__node {
    animation: mo-branch-node linear both;
    animation-timeline: --mo-flow;
    animation-range: cover 34% cover 40%;
  }
}
@keyframes mo-branch {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}
@keyframes mo-branch-run {
  0% { opacity: 0; transform: translateX(0); }
  12% { opacity: 1; }
  80% { opacity: 1; transform: translateX(var(--mo-run, 16px)); }
  100% { opacity: 0; transform: translateX(var(--mo-run, 16px)); }
}
@media (max-width: 767.98px) {
  .mo .flow::after {
    display: none;
  }
}
@media (min-width: 1200px) {
  .mo .flow {
    --mo-run: 40px;
  }
  .mo .flow::after {
    left: -86px;
  }
}
@keyframes mo-branch-node {
  0% { opacity: 0; transform: scale(.4); border-color: var(--spark); }
  60% { opacity: 1; transform: scale(1.35); border-color: var(--spark); }
  100% { opacity: 1; transform: scale(1); }
}

/* 29.6 The week, told by the scroll (roc-replay.js v2). */
.has-replay .tl__stop {
  cursor: pointer;
}
.tl__lit {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
  width: 3px;
  height: 1px;
  background: var(--spark);
  transform-origin: 0 0;
  opacity: 0;
  transition: transform .5s var(--mo-ease-io), opacity .3s ease;
  pointer-events: none;
}
.tl__lit.is-on {
  opacity: 1;
}
@media (min-width: 1024px) {
  .tl__lit {
    width: 1px;
    height: 3px;
  }
}
.tl__playhead {
  transition: transform .5s var(--mo-ease-io), opacity .3s ease;
}
.tlr__hint {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  color: var(--cocoa-soft);
  font-size: 14px;
}
.tlr__hint-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--spark);
}
.mo .tlr__hint-dot {
  animation: mo-hint 1.6s ease-in-out 3;
}
@keyframes mo-hint {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(5px); }
}
.is-click .tlr__hint {
  display: none;
}

/* PIN: the panel holds still while six bands of scroll pass the window's
   centre (each band is one day). */
.tl-pin {
  --step: 40vh;
  position: relative;
}
/* Sticky holds only inside its parent's content box, so the run is a
   block in the flow, not padding. */
.tl-pin__run {
  height: calc(6 * var(--step));
}
.tl-pin > .tl__panel {
  position: sticky;
  top: var(--pin-top, 40px);
}
.tl-pin__bands {
  position: absolute;
  top: calc(50vh - var(--pin-top, 40px));
  left: 0;
  right: 0;
  display: grid;
  grid-template-rows: repeat(6, var(--step));
  pointer-events: none;
}
/* The pinned inbox holds the whole week's height from day 0, so nothing
   shifts as rows land, and the fit check (js) measures the real thing.
   D2.2: its height is what the window can spare (--tlr-h, set by the fit
   check, 220-410px), so a 13-inch laptop window pins too. Shorter than the
   whole week, the oldest rows fade out at the bottom; the newest is on top. */
.is-pin .tlr {
  margin-top: 18px;
  padding-top: 18px;
}
.is-pin .tlr__inbox {
  box-sizing: border-box;
  height: var(--tlr-h, 410px);
  min-height: 0;
}
.is-pin.is-short .tlr__inbox {
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 56px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 56px), transparent);
}
/* The week's progress, above the hint: six segments that fill as the days
   pass, and "3 of 6". The last segment is Spark: day 7, the report. */
.tlr__foot {
  display: grid;
  gap: 12px;
  width: 100%;
}
.tlr__prog {
  display: flex;
  align-items: center;
  gap: 14px;
}
.tlr__prog-n {
  flex: 0 0 auto;
  min-width: 4.5em;
  color: var(--cocoa-soft);
  font-size: 12px;
}
.tlr__prog-bar {
  display: grid;
  flex: 1 1 auto;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 6px;
  max-width: 280px;
}
.tlr__prog-bar i {
  height: 6px;
  border-radius: var(--r-pill);
  background: var(--mist);
  transition: background-color .3s ease;
}
.tlr__prog-bar i.is-on {
  background: var(--cocoa);
}
.tlr__prog-bar i:last-child.is-on {
  background: var(--spark);
}
.is-stack .tlr__foot {
  display: none;
}

/* Tighter still, for windows under about 560px: the day chips go (the
   inbox and the line beside it carry the same facts) and the padding
   narrows. */
.is-pin.is-tight .tl__panel {
  padding-top: 24px;
  padding-bottom: 22px;
}
.is-pin.is-tight .tl__stop .chip {
  /* out of the layout, still read by screen readers */
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.is-pin.is-tight .tlr {
  margin-top: 12px;
  padding-top: 12px;
}
/* While the scroll drives it, the tip and the live rule follow the scroll
   frame by frame: a transition would only make them lag behind it. */
.tl__playhead.is-scrub,
.tl__lit.is-scrub {
  transition: opacity .3s ease;
}
.is-pin .tlr__row {
  padding-top: 7px;
  padding-bottom: 7px;
}

/* STACK: the inbox sticks at the top of the panel; the days scroll up
   under it and the one crossing the line beneath it is current. */
.is-stack .tlr {
  position: sticky;
  top: 10px;
  z-index: 4;
  margin: 0 0 24px -34px;
  padding: 0 0 12px;
  border-top: 0;
  background: var(--ice-light);
}
.is-stack .tlr__side {
  display: none;
}
.is-stack .tlr__inbox {
  height: 238px;
  min-height: 0;
  box-shadow: 0 1px 0 var(--ice-deep), 0 16px 30px color-mix(in srgb, var(--cocoa) 12%, transparent);
}
.is-stack .tlr__row {
  padding-top: 8px;
  padding-bottom: 8px;
}
.is-stack .tl__track {
  padding-bottom: 36vh;
}
/* Each day holds for about a thumb's flick (~140px), so a quick scroll
   still lands on every day instead of skipping two at once. */
.is-stack .tl__list {
  gap: 64px;
}
.is-stack .tl__stop {
  transition: opacity .3s ease;
}
@media (prefers-reduced-motion: reduce) {
  .tl__lit,
  .tl__playhead {
    transition: none;
  }
}

/* 29.7, 29.8, 29.9 (proof, pricing on home, FAQ aside) moved to roc-parts.css (D2.5). */

/* 29.10 D2.1 QA fixes (independent review, 17 Oct). */

/* Phone: the calculator's button fills its row again (it shrank to its
   text inside the new flex row). */
@media not all and (min-width: 768px) {
  .calc__next .btn {
    flex: 1 1 100%;
  }

  .calc__next-note {
    max-width: none;
  }

  .calc__work {
    padding: 12px 14px;
    font-size: 13px;
  }

  .calc__work-sum,
  .calc__work-g {
    gap: 4px;
  }

  .calc__tok {
    padding: 2px 6px;
  }
}

/* "Your working" breaks only before "=", never inside the brackets. */
.calc__work-g {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}

/* A day not reached yet is faded, but never its focus ring. */
.has-replay .tl__stop:focus-within {
  opacity: 1;
}

/* Phone inbox: the last visible row fades out instead of being cut
   through a line; the tabs fit down to 320px. */
.is-stack .tlr__inbox {
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 44px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 44px), transparent);
}
@media (max-width: 420px) {
  .tlr__tabs {
    gap: 4px;
    padding-right: 10px;
    padding-left: 10px;
  }

  .tlr__tab {
    gap: 4px;
    padding: 0 8px;
    font-size: 11px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .is-stack .tl__stop,
  .tl__stop {
    transition: none;
  }
}

/* 30  D2.2: MOIN'S SECOND HOME REVIEW (17 Oct, 16:16) */

/* 30.1 The two lists, in colour (D2.2-1). Moin: the complete program reads
   as done (green), what's probably running as a problem (orange). Colour
   never carries it alone (orange and green are a pair many colour-blind
   visitors confuse; WCAG 1.4.1): "complete" is a filled disc with a check,
   "probably running" an open dashed ring that spins like a loader and
   stalls: running, but not finished. --done is a status colour for
   completed states only, not a brand colour (#1F7A4D, 4.5:1 on ice; the
   white check 5:1 on it). The rings are --spark-text, the brand's orange
   for use on ice (4.9:1; Spark itself is 2.6:1 there, too faint for a
   status mark, WCAG 1.4.11), so Spark stays the colour of what's live and
   what to do next. Both play each time the lists come back into
   view: one row at a time (D2.3, below). Without .mo they rest finished. */
.gap-lists {
  --done: #1F7A4D;
  --k: 1;
}
.gap-lists.is-again {
  --k: .6;
}
.gap-list__items > li {
  align-items: flex-start;
}
.gap-list__dot,
.gap-list--now .gap-list__dot,
.gap-list--full .gap-list__dot {
  position: relative;
  box-sizing: border-box;
  flex: 0 0 18px;
  width: 18px;
  height: 18px;
  margin-top: calc((1.55em - 18px) / 2);
  border-radius: 50%;
}
.gap-list--now .gap-list__dot {
  border: 2.5px dashed var(--spark-text);
  transform: rotate(310deg);
}
.gap-list--full .gap-list__dot {
  border: 0;
  background: var(--done);
}
.gap-list--full .gap-list__dot::after {
  content: '';
  position: absolute;
  inset: 0;
  width: auto;
  height: auto;
  margin: 0;
  border-radius: 0;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18'%3E%3Cpath d='M5 9.4l2.6 2.6L13 6.6' fill='none' stroke='%23fff' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 18px 18px no-repeat;
  clip-path: inset(0);
}
.gap-list--full .gap-list__dot::before {
  content: none;
}
.gap-list--full .gap-list__title::after {
  content: none;
}
@media (min-width: 768px) {
  .gap-list__dot,
  .gap-list--now .gap-list__dot,
  .gap-list--full .gap-list__dot {
    flex-basis: 20px;
    width: 20px;
    height: 20px;
    margin-top: calc((1.55em - 20px) / 2);
  }
  .gap-list--full .gap-list__dot::after {
    background-size: 20px 20px;
  }
}

/* The D2.1 one-shot animations give way to the row-by-row ones. */
.mo .gap-list--now li:not(.mo-wait) .gap-list__dot,
.mo .gap-list--full li:not(.mo-wait) .gap-list__dot,
.mo .gap-list--full li:not(.mo-wait) .gap-list__dot::after,
.mo .gap-list--full li:not(.mo-wait) .gap-list__dot::before {
  animation: none;
}
/* D2.3 (Moin: "a bit too fast, people may not see it"). One row at a time,
   as each row reaches the reading zone of the window (roc-motion.js 2c:
   li.is-on), at least 260ms apart, and slow enough to watch: the loader
   about 1.6s, the tick about 1.2s. Waiting rows (not yet .is-on) show the
   start: a grey loader and an empty ring. A row resets only once it's
   wholly off screen, so each visit, from above or below, plays it again. */
.mo .gap-lists li:not(.is-on) .gap-list__dot {
  transition: none;
}
.mo .gap-list--now li:not(.is-on) .gap-list__dot {
  border-color: var(--mist);
  transform: rotate(0);
}
.mo .gap-list--full li:not(.is-on) .gap-list__dot {
  background: transparent;
  box-shadow: inset 0 0 0 2px var(--mist);
}
.mo .gap-list--full li:not(.is-on) .gap-list__dot::after {
  clip-path: inset(0 100% 0 0);
}
/* Probably running: a grey loader spins up, slows, stalls short of done,
   shudders, and turns orange: running, never finished. */
.mo .gap-list--now li.is-on .gap-list__dot {
  animation: mo-stuck 1.6s cubic-bezier(.25, .1, .25, 1) both;
}
/* Complete: the ring fills green, the tick draws, one soft ping. */
.mo .gap-list--full li.is-on .gap-list__dot {
  animation: mo-done .7s var(--mo-ease) .1s both;
}
.mo .gap-list--full li.is-on .gap-list__dot::after {
  animation: mo-check .5s cubic-bezier(.65, 0, .35, 1) .55s both;
}
.mo .gap-list--full li.is-on .gap-list__dot::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--done);
  opacity: 0;
  animation: mo-ping 1.1s var(--mo-ease) .95s 1 forwards;
}
@keyframes mo-stuck {
  0% { border-color: var(--mist); transform: scale(.7) rotate(0); }
  12% { transform: scale(1) rotate(80deg); }
  58% { border-color: var(--mist); transform: rotate(560deg); }
  68% { border-color: var(--spark-text); transform: rotate(640deg); }
  76% { transform: rotate(622deg); }
  84% { transform: rotate(640deg); }
  91% { transform: rotate(628deg); }
  100% { border-color: var(--spark-text); transform: rotate(670deg); }
}
@keyframes mo-done {
  0% { background: transparent; box-shadow: inset 0 0 0 2px var(--mist); transform: scale(.7); }
  60% { background: var(--done); box-shadow: inset 0 0 0 2px var(--done); transform: scale(1.2); }
  100% { background: var(--done); box-shadow: inset 0 0 0 0 var(--done); transform: scale(1); }
}
@keyframes mo-check {
  from { clip-path: inset(0 100% 0 0); }
  to { clip-path: inset(0); }
}

/* 30.2 The calculator's ranges (D2.2-2): the part left of the thumb is
   filled (--p, roc-calc.js): cocoa at rest, Spark while it's hovered, held,
   focused or showing itself (.is-demo, the target only). Spark beside white
   is 3.1:1 (WCAG 1.4.11); the thumb is cocoa with a white rim, so the
   control is clear in any state. */
[data-calc] input[type=range] {
  --fill: var(--cocoa);
  -webkit-appearance: none;
  appearance: none;
  height: 28px;
  margin: 0;
  background: transparent;
  cursor: pointer;
}
[data-calc] input[type=range]::-webkit-slider-runnable-track {
  height: 8px;
  border-radius: var(--r-pill);
  background: linear-gradient(to right, var(--fill) 0 calc(var(--p, .5) * (100% - 24px) + 12px), var(--white) 0);
  box-shadow: inset 0 0 0 1px var(--cocoa-soft);
}
[data-calc] input[type=range]::-moz-range-track {
  height: 8px;
  border-radius: var(--r-pill);
  background: var(--white);
  box-shadow: inset 0 0 0 1px var(--cocoa-soft);
}
[data-calc] input[type=range]::-moz-range-progress {
  height: 8px;
  border-radius: var(--r-pill);
  background: var(--fill);
}
[data-calc] input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  box-sizing: border-box;
  width: 24px;
  height: 24px;
  margin-top: -8px;
  border: 3px solid var(--white);
  border-radius: 50%;
  background: var(--cocoa);
  box-shadow: 0 0 0 1px var(--cocoa), 0 2px 6px color-mix(in srgb, var(--cocoa) 28%, transparent);
  transition: transform .2s var(--mo-ease), box-shadow .2s ease;
}
[data-calc] input[type=range]::-moz-range-thumb {
  box-sizing: border-box;
  width: 24px;
  height: 24px;
  border: 3px solid var(--white);
  border-radius: 50%;
  background: var(--cocoa);
  box-shadow: 0 0 0 1px var(--cocoa), 0 2px 6px color-mix(in srgb, var(--cocoa) 28%, transparent);
  transition: transform .2s var(--mo-ease), box-shadow .2s ease;
}
[data-calc] input[type=range]:focus-visible {
  outline: 2px solid var(--cocoa);
  outline-offset: 4px;
  border-radius: 6px;
}
[data-calc] input[type=range]:is(:hover, :focus-visible, :active),
[data-calc].is-demo [data-calc-tgt] {
  --fill: var(--spark);
}
[data-calc] input[type=range]:active::-webkit-slider-thumb {
  transform: scale(1.15);
}
[data-calc] input[type=range]:active::-moz-range-thumb {
  transform: scale(1.15);
}

/* 30.3 The landing (D2.2-2): when the sweep ends, the gap figure's Spark
   mark draws under it and the target's thumb pulses once. The mark stays:
   the figure is the section's one orange-marked thing, while the figure
   itself stays cocoa (Spark text on ice-light would be 2.9:1). */
.calc__fig {
  position: relative;
  align-self: flex-start;
  padding-bottom: 12px;
}
.calc__fig::after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 6px;
  border-radius: var(--r-pill);
  background: var(--spark);
  transform-origin: 0 50%;
}
@media (min-width: 768px) {
  .calc__fig {
    padding-bottom: 16px;
  }
  .calc__fig::after {
    height: 8px;
  }
}
.mo [data-calc].is-landed .calc__fig::after {
  animation: mo-mark-land .7s var(--mo-ease) both;
}
.mo [data-calc].is-landed [data-calc-tgt]::-webkit-slider-thumb {
  animation: mo-thumb .9s var(--mo-ease) 1;
}
.mo [data-calc].is-landed [data-calc-tgt]::-moz-range-thumb {
  animation: mo-thumb .9s var(--mo-ease) 1;
}
@keyframes mo-mark-land {
  0% { transform: scaleY(1); }
  35% { transform: scaleY(1.9); }
  100% { transform: scaleY(1); }
}
@keyframes mo-thumb {
  0% { box-shadow: 0 0 0 1px var(--cocoa), 0 0 0 0 rgba(255, 92, 31, .55); }
  100% { box-shadow: 0 0 0 1px var(--cocoa), 0 0 0 12px rgba(255, 92, 31, 0); }
}

/* 30.4 (projects) moved to roc-parts.css (D2.5). */

/* 30.5 D2.2 QA fixes (independent review, 17 Oct). */

/* The rule's centre line on the nodes' centres (40px): the lit part of the
   rule, which now follows the scroll, covers it exactly (it sat 1.5px low,
   inherited from the boards' 37px). */
@media (min-width: 1024px) {
  .has-replay .tl__rule {
    top: 38px;
  }
}

/* Print shows the lists finished, whatever was on screen. */
@media print {
  .mo .gap-lists .gap-list--now .gap-list__dot {
    border-color: var(--spark-text);
  }
  .mo .gap-lists .gap-list--full .gap-list__dot {
    background: var(--done);
    box-shadow: none;
  }
  .mo .gap-lists .gap-list--full .gap-list__dot::after {
    clip-path: inset(0);
  }
  .mo .gap-lists .gap-list__dot,
  .mo .gap-lists .gap-list__dot::before,
  .mo .gap-lists .gap-list__dot::after {
    animation: none !important;
  }
}

/* 30.6 The calculator, shown by hand (D2.4; Moin: slower, and clear that
   visitors can put their own numbers in). The interaction designer's
   reasoning: a slider that moves on its own reads as a chart playing; a
   hand dragging it reads as "you can do this". So a hand (Lucide's
   pointer, ISC) appears on the target thumb, presses it (.is-held: the
   thumb grows, the fill turns Spark), drags it down and back up, and lets
   go; the figure follows the whole way. The words say it too: "Type your
   revenue, drag the two sliders, and watch the gap change." And the
   revenue field carries a pencil, the plain sign for "you can edit this". */
.calc {
  position: relative;
}
.calc__hand {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 3;
  width: 40px;
  height: 40px;
  margin: 2px 0 0 -13px;   /* the fingertip (8,2 of 24) on the thumb */
  opacity: 0;
  transform-origin: 13px 3px;
  pointer-events: none;
  filter: drop-shadow(0 6px 10px color-mix(in srgb, var(--cocoa) 30%, transparent));
}
.calc__hand svg {
  display: block;
  width: 100%;
  height: 100%;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.calc__hand-halo {
  stroke: var(--white);
  stroke-width: 5;
}
.calc__hand-line {
  stroke: var(--cocoa);
  stroke-width: 1.9;
}
[data-calc].is-held [data-calc-tgt] {
  --fill: var(--spark);
}
[data-calc].is-held [data-calc-tgt]::-webkit-slider-thumb {
  transform: scale(1.18);
  box-shadow: 0 0 0 1px var(--cocoa), 0 0 0 7px color-mix(in srgb, var(--spark) 28%, transparent);
}
[data-calc].is-held [data-calc-tgt]::-moz-range-thumb {
  transform: scale(1.18);
  box-shadow: 0 0 0 1px var(--cocoa), 0 0 0 7px color-mix(in srgb, var(--spark) 28%, transparent);
}
[data-calc] input[type=range] {
  cursor: grab;
}
[data-calc] input[type=range]:active {
  cursor: grabbing;
}
.calc__edit {
  flex: 0 0 18px;
  width: 18px;
  height: 18px;
  margin-left: auto;
  fill: none;
  stroke: var(--cocoa-soft);
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
