/* Signed-out landing page. */
.hire-button {
  background: var(--accent);
  color: var(--bg);
  border: none;
  padding: 0.625rem 1.5rem;
  border-radius: var(--radius-sm);
  font-size: 0.95rem;
  font-weight: 700;
  cursor: pointer;
  transition: background 0.15s ease;
  white-space: nowrap;

  &:hover {
    background: var(--accent-hover);
  }
}

/* Section lead-in: the claim, set ABOVE its heading so the heading still owns
   the type hierarchy and the paragraph reads as the run-up to it. Measure is
   held near 40rem: two full lines, no widow on the second. Scoped under
   .marketing-section where the generic p rule is class+element, so an unscoped
   rule would lose. */

.marketing-section .marketing-lede {
  font-size: 1.0625rem;
  line-height: 1.55;
  color: var(--text-muted);
  /* The claim's own measure (section-claim caps at 34rem): a paragraph under a
     statement on a different right edge reads as a misprint. */
  max-width: 34rem;
  margin-bottom: var(--space-2);
  text-wrap: pretty;
}

/* The heading closes the run-up, so its own bottom margin gives way to the
   grid's top one — one gap between header and list, not two stacked. */

.marketing-section .marketing-lede + h2 {
  margin-bottom: 0;
}

/* Capabilities: term over description, two columns. A dl rather than a ul —
   these are definitions, and six bold-then-muted bullet lines read as a wall.
   Wide column gap and a narrow measure per cell so each pair reads as one
   block; the descriptions carry the smaller step so the terms scan first.
   Second user since 2026-09-15: every section of /security, which was thirty
   identical bullets at a 109-character measure. */

.capability-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-8) var(--space-16);
  max-width: 58rem;
  margin-top: var(--space-12);
}

.capability-grid dt {
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text);
  margin-bottom: var(--space-1);
}

.capability-grid dd {
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--text-muted);
  text-wrap: pretty;
}

@media (max-width: 48rem) {
  .capability-grid {
    grid-template-columns: 1fr;
    gap: var(--space-6);
    margin-top: var(--space-8);
    /* One column at tablet width would otherwise run the full 45rem: the cap
       keeps the description near 70 characters. Below ~34rem it does nothing,
       so the phone is unaffected. */
    max-width: 34rem;
  }
}

/* The FAQ answers objections; it does not make the case, so its heading steps
   down under the floors' — the page's own order of importance. */
#faq h2 {
  font-size: clamp(1.375rem, 2.2vw, 1.75rem);
}

/* The landing's own cut of the grid: one line per capability, two columns,
   ruled like a ledger. Six cards of bold-then-muted prose took four hundred
   pixels to say what six lines say — and the page already argues its case in
   the floors below, so this only has to be scannable. /security and /pricing
   keep the bare grid; this modifier is the landing's. After the base media
   query, so its one-column rule doesn't win the cascade over the two below. */

.capability-grid--marks {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 var(--space-8);
  margin-top: 0;
  max-width: none;
}

.capability-grid--marks > div {
  padding: var(--space-3) 0;
  border-top: 1px solid var(--hairline);
}

.capability-grid--marks dt {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  font-size: 0.9375rem;
  font-weight: 600;
  white-space: nowrap;
}

/* Under its name and lined up with it, past the mark. A step down in size, so
   the scan hits the six names first and the clause only when the eye stops. */
.capability-grid--marks dd {
  padding-left: 1.95em;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--text-muted);
  text-wrap: pretty;
}

/* The one accent per line, at 3:1+ on white — a mark is a control-sized glyph,
   not body text, so --accent carries it. */
.capability-grid--marks dt .mark {
  width: 1.2em;
  height: 1.2em;
  margin-right: 0;
  color: var(--accent);
}

@media (max-width: 48rem) {
  .capability-grid--marks {
    grid-template-columns: 1fr;
    gap: 0;
    max-width: 34rem;
  }
}

/* ===== Work loop =====
   One task running, on a loop, in the two panes the real company has: the
   shell the agent types in and the browser it drives. Both run off one step
   number (workloop_controller) — the `[computer] click` line and the cursor
   landing on the button are the same beat, and a click that happened in only
   one pane would be the whole point missed.

   Screen surfaces, so the darks are literal and not themed: the shell is the
   terminal's own #0d1117, the window chrome its #161b22, and the page inside
   the browser stays a light page because that is what a page is. Nothing here
   changes layout as it plays — every line holds its row from the first frame. */

.worklog {
  /* The section's own width, like every other block on the page: a panel that
     stops 11rem short of the right edge reads as a column that missed. */
  margin: 0;
  /* Narrow enough that the app inside fills its window: wider than this and the
     page keeps a hand's width of empty white down its right side. */
  max-width: 44rem;
  /* Local to this panel, like the simulator's: a pointer is not part of the
     interface mark set. Drawn twice in the one file — a white stroke under a
     dark fill — because a single-colour arrow disappears into a dark row or a
     coloured button the moment it lands on one. */
  --worklog-cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 3v16.2l4.1-3.8 2.5 5.6 2.8-1.3-2.5-5.4 5.5-.4z' fill='%230f172a' stroke='%23ffffff' stroke-width='2.4' stroke-linejoin='round'/%3E%3Cpath d='M6 3v16.2l4.1-3.8 2.5 5.6 2.8-1.3-2.5-5.4 5.5-.4z' fill='%230f172a'/%3E%3C/svg%3E");
}

/* No shell of its own: the panel IS the window, with the log and the subtitles
   living inside it. */
.worklog__panes {
  position: relative;
  display: block;
}

.worklog__screen {
  display: flex;
  flex-direction: column;
  min-width: 0;
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: 0 0.5rem 1.75rem rgba(15, 23, 42, 0.14), 0 0 0 1px rgba(15, 23, 42, 0.06);
}

/* A laptop's screen, chrome included: one window, with the log and the
   subtitles living inside it rather than competing for the eye beside it. */
.worklog__screen {
  position: relative;
  background: #ffffff;
  /* 16:10, a laptop's own ratio. The extra height over 16:9 is not empty: it is
     the strip the log and the subtitles sit in, which is how they stay off the
     rows — a name hidden under the log is the context of the screen gone. */
  aspect-ratio: 16 / 10;
}

/* ===== The subtitles =====
   The one line that says what is happening, in the words someone would use to
   say it, sitting where a film puts them: over the picture, near its foot. The
   log beside it is the machine's account of the same beat, so reading that is
   optional. Beats are long enough to read this one — see workloop_controller. */

.worklog__now {
  position: absolute;
  left: var(--space-3);
  bottom: var(--space-3);
  z-index: 2;
  max-width: calc(100% - 1.5rem);
  display: flex;
  align-items: center;
  gap: 0.4375rem;
  padding: 0.3125rem 0.6875rem;
  border-radius: var(--radius-pill);
  background: rgba(15, 23, 42, 0.88);
  transition: background var(--dur) ease;
  overflow: hidden;
  box-shadow: 0 0.5rem 1.5rem rgba(15, 23, 42, 0.22);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

/* Every line in one cell, so the bar can't change width mid-sentence — which
   also means the pill is as wide as the longest of the eight. Centred, each
   shorter line sat at its own x and the mark jumped left and right on every
   beat; flush left, the mark and the first letter hold one vertical for the
   whole run and only the tail moves. It is also where the fill starts. */
.worklog__acts {
  position: relative;
  display: grid;
  min-width: 0;
}

.worklog__act {
  grid-area: 1 / 1;
  display: flex;
  align-items: center;
  gap: 0.5em;
  min-width: 0;
  font-size: 0.71875rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  /* Literal light ink: this rides on a dark bar over the page, not on chrome. */
  color: #f1f5f9;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: 0;
  transform: translateY(0.1875rem);
  /* The line that is leaving goes first and quickly; the one arriving waits for
     it, then eases in over twice as long. Cross-faded at the same instant, the
     two sat on top of each other and the swap read as a flicker. */
  transition: opacity 160ms ease-in, transform 160ms ease-in;
}

.worklog__act.is-on {
  opacity: 1;
  transform: none;
  transition: opacity 320ms cubic-bezier(0.22, 0.61, 0.36, 1) 120ms,
              transform 320ms cubic-bezier(0.22, 0.61, 0.36, 1) 120ms;
}

/* Only the ending keeps a glyph. Through the run the words already say what is
   happening in fewer characters than the icon takes to read, and seven glyphs
   swapping in ten seconds is one more moving thing beside a page where the real
   movement — the pointer, the click, the row — is the point. The check is the
   exception: it marks a state, not an action. */
.worklog__act .mark { display: none; }

.worklog__act--done .mark {
  display: inline-block;
  width: 1.05em;
  height: 1.05em;
  margin-right: 0;
  color: #4ade80;
}

/* The one beat where the screen has nothing to show: a still panel reads as a
   stall, so the clock breathes through it. */
.worklog[data-step="7"] .worklog__act.is-on .mark {
  animation: worklog-waiting 1.4s ease-in-out infinite;
}

@keyframes worklog-waiting {
  50% { opacity: 0.35; }
}

/* The bubble IS the bar: the whole pill fills, which is what makes it read as
   one modern object rather than as a caption with a rail bolted under it. */
.worklog__progress {
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

.worklog__progress-fill {
  display: block;
  height: 100%;
  width: var(--progress, 0%);
  /* The leading edge fades out over its last 1.25rem instead of cutting the
     sentence with a vertical line — that hard edge was the only thing wrong
     with filling the pill. */
  background: linear-gradient(90deg,
    rgba(125, 211, 252, 0.17) 0,
    rgba(125, 211, 252, 0.17) calc(100% - 1.25rem),
    rgba(125, 211, 252, 0) 100%);
  /* Linear and exactly as long as the beat it crosses: the controller hands it
     both the target and the time it has to get there, so the line crawls like a
     player's scrubber instead of dashing and waiting. */
  transition: width var(--progress-dur, 420ms) linear, background var(--dur) ease;
}

/* Full and paid: the bubble goes deep green, and the fill drops its fading
   tail — at 100% that fade left the last 1.25rem of the pill looking unfilled,
   so the bar seemed to stop just short of the end. */
.worklog:is([data-step="8"], [data-step="9"]) .worklog__now {
  background: rgba(6, 78, 59, 0.94);
}

/* The loop's restart is a cut, not a rewind: the bubble would otherwise fade
   green to navy in front of the visitor. The bar's own rewind is cut in the
   controller, which has to restore its transition immediately afterwards. */
.worklog[data-step="0"] .worklog__now {
  transition: none;
}

.worklog:is([data-step="8"], [data-step="9"]) .worklog__progress-fill {
  background: rgba(134, 239, 172, 0.16);
}

/* ===== The window chrome =====
   A tab strip over an address bar, because the agent changing app is the
   middle of the story and a 10px hostname does not tell it.

   Light, like the browser on most desks and like the pages it shows: the dark
   chrome it replaced put a slab of night on top of two white apps and made the
   panel read as a terminal with a page in it. */

.worklog__chrome {
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  background: #dee1e6;
}

.worklog__tabs {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.4375rem 0.625rem 0;
}

.worklog__dot {
  width: 0.4375rem;
  height: 0.4375rem;
  border-radius: var(--radius-pill);
  background: #c3c7ce;
  flex: 0 0 auto;
}

.worklog__dot:nth-of-type(3) { margin-right: 0.375rem; }

.worklog__tab {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  max-width: 11rem;
  padding: 0.375rem 0.625rem;
  border-radius: 0.5rem 0.5rem 0 0;
  font-size: 0.625rem;
  font-weight: 600;
  color: #5f6368;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: background var(--dur) ease, color var(--dur) ease;
}

.worklog__tab.is-on {
  background: #ffffff;
  color: #202124;
}

/* The favicon is the fastest signal in a tab strip, so each app keeps its
   own — drawn, not borrowed: a coloured square is not a logo. */
.worklog__favicon {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 0.125rem;
  flex: 0 0 auto;
}

.worklog__favicon.is-mail { background: #ea4335; }
.worklog__favicon.is-stripe { background: #635bff; }

.worklog__address {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.375rem var(--space-3) 0.5rem;
  background: #ffffff;
  /* The toolbar and the page are both white; without this line the chrome and
     the app it frames run into each other. */
  box-shadow: inset 0 -1px 0 rgba(15, 23, 42, 0.09);
}

.worklog__address .mark {
  width: 0.75rem;
  height: 0.75rem;
  margin-right: 0;
  color: #5f6368;
}

.worklog__url {
  flex: 1;
  padding: 0.1875rem 0.5rem;
  border-radius: var(--radius-pill);
  background: #f1f3f4;
  color: #202124;
  font-size: 0.6875rem;
  line-height: 1.5;
}

/* Both addresses sit in the one pill; only the current one is laid out, so the
   bar can't grow or shrink when the agent navigates. */
.worklog__host { display: none; }
.worklog__host.is-on { display: inline; }

/* Before the controller has counted once there is no data-step on the panel,
   and nothing is `is-on`: the address pill had no line to hold, so the chrome
   grew a row on every reload, and the tab strip flashed from blank to lit. The
   first frame is drawn here instead — mail open, mail lit. */
.worklog:not([data-step]) .worklog__host[data-until] { display: inline; }

.worklog:not([data-step]) .worklog__tab[data-until] {
  background: #ffffff;
  color: #202124;
}

/* Only the opening line: every act carries a `data-until`, and lighting all
   of them printed the whole script on top of itself. */
.worklog:not([data-step]) .worklog__act:not([data-at]) { opacity: 1; transform: none; }

/* ===== The apps =====
   Everything below is someone ELSE's product seen through the browser — a mail
   client, a payments dashboard. They carry their own colours so they are
   recognised at a glance; those colours are literal and never become tokens. */

.worklog__page {
  position: relative;
  flex: 1;
  display: grid;
  min-height: 0;
}

/* Positioned, so each view paints as one unit: unpositioned boxes paint every
   background first and every line of text after, which let one page's rows read
   straight through the opaque page on top of them. */
.worklog__view {
  position: relative;
  grid-area: 1 / 1;
  display: flex;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-3) 3.25rem;
  background: #ffffff;
  transition: opacity 260ms ease-in-out;
}

.worklog__view[data-at] { opacity: 0; }
.worklog__view[data-at].is-on { opacity: 1; }

.worklog__view--mail { --app-ink: #1a73e8; }
.worklog__view--pay  { --app-ink: #635bff; }

/* The furniture down the left of both apps: what makes a page read as an app
   rather than as a list on white. */
.worklog__nav {
  display: flex;
  flex-direction: column;
  gap: 0.1875rem;
  width: 6.25rem;
  flex: 0 0 auto;
  font-size: 0.625rem;
}

.worklog__compose {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  align-self: flex-start;
  margin-bottom: var(--space-2);
  padding: 0.375rem 0.625rem;
  border-radius: var(--radius-pill);
  background: #c2e7ff;
  color: #001d35;
  font-weight: 700;
}

.worklog__compose .mark {
  width: 0.875rem;
  height: 0.875rem;
  margin-right: 0;
}

/* Inset to the nav items' own padding, so the wordmark and the labels sit on
   one vertical and only the active pill hangs into the gutter — which is what a
   sidebar's pill is for. */
.worklog__brand {
  padding-inline: 0.625rem;
  margin-bottom: var(--space-3);
  color: #635bff;
  font-size: 0.875rem;
  font-weight: 700;
  letter-spacing: -0.03em;
}

.worklog__nav-item {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.3125rem 0.625rem;
  border-radius: var(--radius-pill);
  color: #5f6368;
  font-weight: 500;
}

.worklog__nav-item.is-on {
  background: color-mix(in srgb, var(--app-ink) 12%, transparent);
  color: var(--app-ink);
  font-weight: 700;
}

.worklog__nav-count {
  margin-left: auto;
  font-size: 0.5625rem;
  font-weight: 700;
}

/* The column's own rhythm is a step tighter than the page's: at 12 the head,
   the card, the table and the button did not fit above the subtitles, and the
   button ended up on the bubble's shoulder.

   The inset lives HERE, and the blocks that are meant to bleed (the rows, the
   search bar, the card, the action row) are pulled back out by the same step —
   so every line of text starts on one vertical and only tinted grounds run
   wider than it, which is what those grounds are for. */
.worklog__app {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding-inline: var(--space-3);
  flex: 1;
  min-width: 0;
  max-width: 34rem;
}

/* The bar belongs to the window, not to the list or the letter under it, so it
   keeps a step more air than the column's own rhythm gives. */
.worklog__search {
  margin-block: 0 var(--space-2);
  margin-inline: calc(var(--space-3) * -1);
  padding: 0.375rem var(--space-3);
  border-radius: var(--radius-pill);
  background: #f1f3f4;
  color: #80868b;
  font-size: 0.6875rem;
}

.worklog__head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
}

.worklog__page-title {
  font-size: 0.875rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: #0a2540;
}

.worklog__chip {
  padding: 0.0625rem 0.5rem;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--app-ink) 12%, transparent);
  color: var(--app-ink);
  font-size: 0.5625rem;
  font-weight: 700;
}

/* The rows follow the title and anything under them follows the rows:
   stretching the list opened a white hole in the middle of the page at every
   width where the box is tall. */
.worklog .worklog__list {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  list-style: none;
  /* Out by the column's own inset, so the tinted rows run the full width while
     their text keeps the one vertical. The shorthand has to come before the
     inline margin, or it resets it. */
  margin: 0 calc(var(--space-3) * -1);
  max-width: none;
  padding: 0;
  width: auto;
}

.worklog .worklog__mail,
.worklog .worklog__row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: 0.3125rem var(--space-3);
  border-radius: 0.5rem;
  font-size: 0.6875rem;
  line-height: 1.5;
}

/* A payments table is a table: hairlines, not cards, and nothing ruled off
   under the last row. */
.worklog .worklog__row {
  border-radius: 0;
  border-bottom: 1px solid #e6e9ef;
}

.worklog .worklog__row:last-child { border-bottom: none; }

/* The row the agent is working, tinted from the beat it is clicked, so the page
   agrees with the log about which one it is. */
/* Under the pointer, not before it: each target lights up 700ms into its beat,
   which is how long the cursor takes to cross to it. The delay rides on the
   hover rule itself, so the press that follows is still instant. */
.worklog:is([data-step="1"], [data-step="2"]) .worklog__mail.is-target {
  background: #e8f0fe;
  transition: background var(--dur) ease 700ms;
}

/* Held back until the pointer has actually crossed to it — the travel takes
   760ms — and lighter than the lit tab, because a hover is not a state. */
/* Pressed, for the beat of the click itself — the row and the button, not the
   tab: a browser tab doesn't depress, it just becomes the one in front. */
.worklog[data-step="2"] .worklog__mail.is-target {
  background: #d2e3fc;
  transition: background 90ms ease;
}


.worklog[data-step="6"] .worklog__button {
  transform: scale(0.96);
  background: #4f46e5;
  transition: transform 90ms ease, background 90ms ease;
}

.worklog[data-step="3"] .worklog__tab[data-at] {
  background: rgba(255, 255, 255, 0.55);
  /* The label carries most of the hover: between the strip and the white tab
     there is not enough room for a background to say it on its own. */
  color: #202124;
  transition: background var(--dur) ease 700ms, color var(--dur) ease 700ms;
}

.worklog[data-step="5"] .worklog__button {
  background: #4f46e5;
  transform: translateY(-1px);
  transition: background var(--dur) ease 700ms, transform var(--dur) var(--ease-out) 700ms;
}

.worklog .worklog__mail.is-new { background: #f8fafd; }

.worklog__who {
  font-weight: 700;
  color: #202124;
  white-space: nowrap;
}

.worklog__subject {
  min-width: 0;
  color: #5f6368;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* An initial in a disc — what every mail client draws, and what makes a column
   of rows read as people. */
.worklog__avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.375rem;
  height: 1.375rem;
  border-radius: var(--radius-pill);
  font-size: 0.5625rem;
  font-weight: 700;
  color: #ffffff;
  flex: 0 0 auto;
}

.worklog__avatar.is-teal   { background: #0f9d8f; }
.worklog__avatar.is-amber  { background: #e8890c; }
.worklog__avatar.is-violet { background: #7c4dff; }
.worklog__avatar.is-blue   { background: #1a73e8; }

.worklog__time {
  margin-left: auto;
  font-size: 0.625rem;
  color: #5f6368;
  flex: 0 0 auto;
}

.worklog__amount {
  margin-left: auto;
  min-width: 4rem;
  text-align: right;
  font-weight: 600;
  color: #0a2540;
  font-variant-numeric: tabular-nums;
  flex: 0 0 auto;
}

/* Stripe's own vocabulary of states: pastel fill, dark ink, and only the paid
   one is green. */
.worklog__state {
  display: grid;
  justify-items: end;
  min-width: 2.75rem;
  flex: 0 0 auto;
}

.worklog__state .worklog__pill { grid-area: 1 / 1; }

.worklog__pill {
  padding: 0.0625rem 0.5rem;
  border-radius: var(--radius-pill);
  background: #cbf4c9;
  color: #0e6245;
  font-size: 0.5625rem;
  font-weight: 700;
  flex: 0 0 auto;
}

.worklog__pill.worklog__pill--draft { background: #e3e8ee; color: #4f566b; }
.worklog__pill.worklog__pill--sent  { background: #d6ecff; color: #3d4eac; }

.worklog__from {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 0.6875rem;
}

/* The letter goes on past the line worth reading — as two grey bars, because
   the rest of a mock letter is not for reading. */
.worklog__bar {
  width: 100%;
  height: 0.5rem;
  border-radius: var(--radius-pill);
  background: #eef1f6;
}

.worklog__bar--short { width: 42%; }

/* The one line of the letter worth reading: it is what makes the invoice that
   follows obviously the right invoice. */
.worklog__said {
  max-width: 28rem;
  font-size: 0.75rem;
  line-height: 1.7;
  color: #202124;
}

/* ===== The money =====
   A balance, the week behind it, and the moment it moves. */

.worklog__card {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  width: auto;
  margin-inline: calc(var(--space-3) * -1);
  padding: var(--space-2) var(--space-3);
  border-radius: 0.75rem;
  background: linear-gradient(135deg, #f5f4ff 0%, #ffffff 55%, #f2fbf6 100%);
  box-shadow: inset 0 0 0 1px #e6e4ff;
  transition: box-shadow var(--dur-slow) var(--ease-out);
}


.worklog__balance {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  min-width: 0;
}

.worklog__balance-label {
  font-size: 0.5625rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #697386;
}

/* Both figures ride in one cell, so the balance changing can't move the chart
   under it, and the grid keeps them at the left. */
.worklog__money {
  display: grid;
  grid-template-columns: auto auto;
  justify-content: start;
  align-items: baseline;
  gap: var(--space-2);
}

.worklog__figure {
  grid-area: 1 / 1;
  font-size: 1.375rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: #0a2540;
  font-variant-numeric: tabular-nums;
}

.worklog__figure.is-on { animation: worklog-pop 420ms cubic-bezier(0.34, 1.56, 0.64, 1); }

@keyframes worklog-pop {
  0% { transform: scale(0.94); }
  60% { transform: scale(1.03); }
  100% { transform: scale(1); }
}

.worklog__delta {
  grid-column: 2;
  padding: 0.0625rem 0.4375rem;
  border-radius: var(--radius-pill);
  background: #cbf4c9;
  color: #0e6245;
  font-size: 0.6875rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* A week of takings beside the figure, filling the card's other half. */
.worklog__chart {
  display: flex;
  align-items: flex-end;
  gap: 0.4375rem;
  flex: 0 1 10.5rem;
  height: 1.75rem;
}

.worklog__chart span {
  flex: 1;
  min-width: 0;
  height: var(--h, 40%);
  border-radius: 0.125rem;
  background: rgba(99, 91, 255, 0.28);
}

/* The day the money lands: the bar grows into it and turns green. */
.worklog__bar-live {
  height: 20%;
  background: rgba(99, 91, 255, 0.5);
  transition: height var(--dur-slow) var(--ease-out), background var(--dur-slow) ease;
}

.worklog:is([data-step="8"], [data-step="9"]) .worklog__bar-live {
  height: 100%;
  background: #0e9f6e;
}

/* Confetti around the display, not inside the dashboard: two cannons at the
   foot of the window firing up and out past its edges, once, on the beat the
   money lands. It sits on the panel rather than in the page, because a
   celebration that stops at the frame is not one. */
.worklog__confetti {
  position: absolute;
  bottom: 8%;
  z-index: 3;
  pointer-events: none;
}

.worklog__confetti--left { left: 3%; }

/* The right cannon is the left one mirrored — same throws, opposite side. */
.worklog__confetti--right { right: 3%; transform: scaleX(-1); }

.worklog__confetti span {
  position: absolute;
  width: 0.4375rem;
  height: 0.625rem;
  border-radius: 0.0625rem;
  opacity: 0;
}

/* After the bar is full, not with it: the celebration was going off while the
   progress still had a step to run. */
.worklog__confetti.is-on span {
  animation: worklog-confetti 1600ms cubic-bezier(0.12, 0.75, 0.3, 1) forwards;
  animation-delay: calc(460ms + var(--d, 0ms));
}

@keyframes worklog-confetti {
  0% { opacity: 0; transform: translate(0, 0) rotate(0) scale(0.4); }
  10% { opacity: 1; }
  100% { opacity: 0; transform: translate(var(--dx), var(--dy)) rotate(var(--r)) scale(1); }
}

.worklog__confetti span:nth-child(1) { --dx: -3rem;  --dy: -9rem;  --r: -260deg; background: #7c4dff; --d: 0ms; }
.worklog__confetti span:nth-child(2) { --dx: 1rem;   --dy: -13rem; --r: 200deg;  background: #0e9f6e; --d: 60ms; }
.worklog__confetti span:nth-child(3) { --dx: 5rem;   --dy: -16rem; --r: -140deg; background: #e8890c; --d: 30ms; }
.worklog__confetti span:nth-child(4) { --dx: 10rem;  --dy: -14rem; --r: 300deg;  background: #1a73e8; --d: 110ms; }
.worklog__confetti span:nth-child(5) { --dx: 15rem;  --dy: -11rem; --r: -180deg; background: #7c4dff; --d: 45ms; }
.worklog__confetti span:nth-child(6) { --dx: 20rem;  --dy: -7rem;  --r: 240deg;  background: #0e9f6e; --d: 150ms; }
.worklog__confetti span:nth-child(7) { --dx: -6rem;  --dy: -5rem;  --r: -220deg; background: #e8890c; --d: 90ms; }
.worklog__confetti span:nth-child(8) { --dx: 25rem;  --dy: -3rem;  --r: 160deg;  background: #1a73e8; --d: 190ms; }

/* Right under the invoice it sends, not pinned to the floor: on a page with one
   row the button sat alone at the bottom of a white field. */
.worklog__actions {
  display: flex;
  justify-content: flex-end;
  margin: var(--space-3) calc(var(--space-3) * -1) 0;
}

.worklog__button {
  padding: 0.3125rem 0.75rem;
  border-radius: 0.375rem;
  background: #635bff;
  color: #ffffff;
  font-size: 0.6875rem;
  font-weight: 700;
  box-shadow: 0 1px 2px rgba(10, 37, 64, 0.2);
  transition: transform var(--dur-fast) var(--ease-out), background var(--dur-fast) ease;
}

/* Everything the loop turns on and off shares one entrance: up a little, in. */
.worklog__pill,
.worklog__figure,
.worklog__delta,
.worklog__actions {
  opacity: 0;
  transform: translateY(0.3125rem);
  transition: opacity 300ms var(--ease-out), transform 300ms var(--ease-out);
}

.worklog__pill.is-on,
.worklog__figure.is-on,
.worklog__delta.is-on,
.worklog__actions.is-on {
  opacity: 1;
  transform: none;
}

/* A pill that is simply there, not one the loop turns on: only the timed ones
   carry a window. */
.worklog__pill:not([data-at]):not([data-until]) { opacity: 1; transform: none; }

/* The carrier is the page box, so its translate percentages ARE page
   percentages — the cursor rides at its origin and the box does the moving,
   which is what lets one transition ease a click across the page. */
.worklog__carrier {
  position: absolute;
  inset: 0;
  pointer-events: none;
  --cx: 74%;
  --cy: 86%;
  transform: translate(var(--cx), var(--cy));
  /* A hand's travel, not a cut: long and decelerating, so the click looks
     aimed. */
  transition: transform 760ms cubic-bezier(0.32, 0.72, 0.28, 1);
}

/* The tip lands on the row, then on the button's lower edge — never across the
   label it is about to press, which reads as a typo. */
/* On Rosa's row from the beat before the click, and on the button from the
   beat the invoice is written: the hand arrives, then presses. A pointer that
   lands at the same instant as the page it opened reads as the page opening
   itself. */
/* Measured against the real boxes, not guessed: a quarter into Rosa's row, on
   the Stripe tab (above the page, hence the negative y), and inside the Send
   button below its label. scratchpad/aim2.js reads all three back as
   percentages of the page, which is what the carrier translates by. */
.worklog[data-step="1"] .worklog__carrier,
.worklog[data-step="2"] .worklog__carrier { --cx: 39.8%; --cy: 43.3%; }

.worklog[data-step="3"] .worklog__carrier,
.worklog[data-step="4"] .worklog__carrier { --cx: 28.4%; --cy: -15.5%; }

/* The hand stays where it clicked — it has nothing else to do — but relaxes a
   few points once the button is gone from under it. */
.worklog:is([data-step="5"], [data-step="6"]) .worklog__carrier { --cx: 93.7%; --cy: 77.7%; }

.worklog:is([data-step="7"], [data-step="8"], [data-step="9"]) .worklog__carrier { --cx: 90%; --cy: 84%; }

.worklog__cursor {
  position: absolute;
  width: 0.9375rem;
  height: 0.9375rem;
  background: var(--worklog-cursor) center / contain no-repeat;
  filter: drop-shadow(0 1px 1.5px rgba(15, 23, 42, 0.35));
}

.worklog__ping {
  position: absolute;
  width: 1.75rem;
  height: 1.75rem;
  margin: -0.625rem 0 0 -0.625rem;
  border: 1.5px solid var(--accent);
  border-radius: var(--radius-pill);
  opacity: 0;
}

.worklog__ping.is-on { animation: worklog-ping 600ms var(--ease-out); }

@keyframes worklog-ping {
  from { opacity: 0.9; transform: scale(0.25); }
  to { opacity: 0; transform: scale(1); }
}

@media (max-width: 48rem) {
  /* The browser goes 4:3: at 16:10 a tablet-width window is short enough to
     cut the page off after three rows. */
  .worklog__screen { aspect-ratio: 4 / 3; }

  /* The page is a different shape here, so the targets are in different places:
     measured again at this width, not scaled from the desktop's. */
  .worklog[data-step="1"] .worklog__carrier,
  .worklog[data-step="2"] .worklog__carrier { --cx: 36.9%; --cy: 29.3%; }

  .worklog[data-step="3"] .worklog__carrier,
  .worklog[data-step="4"] .worklog__carrier { --cx: 24.5%; --cy: -10.4%; }

  .worklog:is([data-step="5"], [data-step="6"]) .worklog__carrier { --cx: 91.2%; --cy: 52.5%; }

  .worklog:is([data-step="7"], [data-step="8"], [data-step="9"]) .worklog__carrier { --cx: 88%; --cy: 60%; }
}

/* Phone. The browser turns portrait, because 4:3 at 21rem wide is still not
   tall enough for a balance, three rows and the button under them; the log
   drops a step in size, since half its lines wrap at this width; and the strip
   keeps the words and loses the progress line, which is the one thing there
   that says nothing on its own. */
@media (max-width: 30rem) {
  /* Square, not portrait: at 3:4 the page filled its top half and the rest was
     a white field with the subtitles floating at the bottom of it. */
  .worklog__screen { aspect-ratio: 1 / 1; }
  /* Two lines of log on a phone: the page underneath is the thing being
     watched, and the tail is the receipt. */

  /* One invoice is the story; the two settled ones are context a phone has no
     room for, and with them the page ran past the foot of the window. */
  .worklog__row:not(.is-target) { display: none; }

  .worklog[data-step="1"] .worklog__carrier,
  .worklog[data-step="2"] .worklog__carrier { --cx: 26.8%; --cy: 49.4%; }

  .worklog[data-step="3"] .worklog__carrier,
  .worklog[data-step="4"] .worklog__carrier { --cx: 50.5%; --cy: -17.6%; }

  .worklog:is([data-step="5"], [data-step="6"]) .worklog__carrier { --cx: 88.9%; --cy: 65.9%; }

  .worklog:is([data-step="7"], [data-step="8"], [data-step="9"]) .worklog__carrier { --cx: 86%; --cy: 72%; }
  /* The subtitle wraps rather than being cut: a line that ends in "the paym"
     is worse than a line that takes two rows. */
  .capability-grid--marks { grid-template-columns: 1fr; }

  /* No sidebar on a phone — which is also what these apps do at this width,
     and what keeps the rows from running off the right edge. */
  .worklog__nav { display: none; }

  .worklog__act {
    font-size: 0.8125rem;
    white-space: normal;
  }

  .worklog__now { max-width: calc(100% - 1.5rem); }
  .worklog__progress { display: none; }
  .worklog__time { display: none; }
  .worklog__figure { font-size: 1.25rem; }
}

/* Reduced motion keeps the story and drops the travel: pieces still turn on,
   they just stop sliding and the cursor stops crossing the page. */
@media (prefers-reduced-motion: reduce) {
  .worklog__view,
  .worklog__pill,
  .worklog__figure,
  .worklog__delta,
  .worklog__actions,
  .worklog__carrier,
  .worklog__button {
    transition: none;
  }

  .worklog__pill,
  .worklog__figure,
  .worklog__delta,
  .worklog__actions {
    transform: none;
  }

  .worklog__ping.is-on,
  .worklog__confetti.is-on span,
  .worklog[data-step="7"] .worklog__act.is-on .mark { animation: none; }
}

/* The demo panel rides ON the cover, between the promise and the ask — the
   product is the fold's argument, so it must not wait for a scroll. Hero
   children inherit the cover's white text-shadow; the panel is a surface of
   its own and takes none of it. */
.demo-stage {
  width: 100%;
  max-width: 46rem;
  /* The cover is three groups — promise, demo, ask — and the air between two
     groups has to beat the air inside one, or six centred rows read as a list.
     Two steps either side of the stage; the picker sits one step under its
     panel and the price one step over its button. */
  margin: var(--space-4) 0 var(--space-8);
  text-shadow: none;
}

/* .site-footer left with the /companies empty-desk page (2026-08-25) — the
   marketing layout carries its own .marketing-footer. */


/* ===== Demo simulator =====
   The landing's one moving explanation: a stripped-down copy of the real
   company playing a week on a loop — you ask, the agent answers, the board
   fills and ticks itself off, the shop goes live. The timeline is a step
   number set by demo_controller; everything here only says what a piece looks
   like ON (.is-on) and OFF. Nothing changes layout as it plays: every row and
   bubble holds its space from the start, so the panel never jumps mid-loop. */

.demo-sim {
  margin-inline: auto;
  /* The cover centres its copy; the panel is an interface, not a caption. */
  text-align: left;
  /* Two glyphs only this mock needs, kept local rather than added to the
     shared mark set in 01_base.css. */
  --demo-mark-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round' d='M5 12.5 10 17.5 19 7'/%3E%3C/svg%3E");
  --demo-mark-send: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round' d='M12 20V5M6 11l6-6 6 6'/%3E%3C/svg%3E");
  max-width: 46rem;
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  background: var(--bg-card);
  box-shadow:
    0 1px 2px rgba(15, 23, 42, 0.05),
    0 22px 44px -28px rgba(15, 23, 42, 0.45);
  overflow: hidden;
}

.demo-sim__bar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--hairline);
  background: var(--bg-panel);
  font-size: 0.85rem;
}

.demo-sim__dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: var(--radius-pill);
  background: var(--green);
  animation: demo-pulse 2.4s ease-in-out infinite;
}

.demo-sim__name {
  font-weight: 600;
  color: var(--text);
}

.demo-sim__role {
  margin-left: auto;
  color: var(--text-muted);
}

.demo-sim__body {
  display: grid;
  /* The board is a rail, like the app's own: fixed and narrow, with the chat
     taking whatever the panel's width leaves. */
  grid-template-columns: minmax(0, 1fr) 17rem;
}

/* Chat side */

.demo-chat {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: var(--space-2);
  padding: var(--space-4);
  /* The whole conversation fits, so nothing is ever taken back out of it: a
     bubble that vanished as the next one landed read as a glitch, because a
     panel that doesn't scroll gives the eye no reason for it. A height rather
     than a min-height, so a line that outgrows the frame gets cut instead of
     pushing the cover down. Three rem more than this opened a hand's width of
     blank panel above the first bubble; exactly this made the panel read
     pinched. */
  height: 19.5rem;
  overflow: hidden;
}

.demo-msg {
  max-width: 17rem;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius);
  font-size: 0.9rem;
  line-height: 1.45;
  display: none;
}

/* Hidden pieces COLLAPSE rather than hold their space: a chat with three empty
   slots above the composer reads as a broken panel, and the composer is pinned
   to the bottom by the column's min-height anyway, so nothing moves under the
   panel as the loop plays. */
.demo-msg.is-on {
  display: block;
  animation: demo-in 260ms ease both;
}

.demo-msg--you {
  align-self: flex-end;
  background: var(--tint-active);
  color: var(--text);
}

.demo-msg--agent {
  background: var(--fill-soft);
  color: var(--text);
}

/* The wait before the reply, so the agent doesn't answer before it's asked. */
.demo-msg--dots.is-on {
  display: flex;
  gap: 0.3rem;
  width: fit-content;
}

.demo-msg--dots span {
  width: 0.35rem;
  height: 0.35rem;
  border-radius: var(--radius-pill);
  background: var(--text-muted);
  animation: demo-pulse 1.2s ease-in-out infinite;
}

.demo-msg--dots span:nth-child(2) { animation-delay: 0.15s; }
.demo-msg--dots span:nth-child(3) { animation-delay: 0.3s; }

.demo-composer {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-pill);
  font-size: 0.9rem;
  color: var(--text-muted);
}

.demo-composer:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--tint-active);
}

.demo-composer__field {
  position: relative;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
}

.demo-composer__input {
  display: block;
  width: 100%;
  border: 0;
  padding: 0;
  background: none;
  font: inherit;
  color: var(--text);
  outline: none;
}

.demo-composer__input::placeholder { color: var(--text-muted); }

/* The loop's line sits ON the real field rather than in it, and clears out the
   moment the field is the visitor's — focused, or holding what they typed. */
.demo-composer__ghost {
  position: absolute;
  inset: 0;
  background: var(--bg-card);
  color: var(--text);
  opacity: 0;
  pointer-events: none;
}

.demo-composer__ghost.is-on { opacity: 1; }

.demo-composer:focus-within .demo-composer__ghost,
.demo-composer__input:not(:placeholder-shown) ~ .demo-composer__ghost { opacity: 0; }

/* Typed a character at a time — the string's own length is the step count. */
.demo-composer__ghost.is-on .demo-typed {
  display: inline-block;
  max-width: 0;
  overflow: hidden;
  vertical-align: bottom;
  border-right: 1px solid var(--accent);
  animation:
    demo-type 1.1s steps(var(--chars)) forwards,
    demo-caret 0.9s steps(2) infinite;
}

.demo-composer__send {
  margin-left: auto;
  border: 0;
  padding: 0;
  cursor: pointer;
  width: 1.5rem;
  height: 1.5rem;
  flex: none;
  border-radius: var(--radius-pill);
  background: var(--accent);
  -webkit-mask: none;
}

.demo-composer__send::after {
  content: "";
  display: block;
  width: 100%;
  height: 100%;
  background: var(--bg-card);
  -webkit-mask: var(--demo-mark-send) center / 0.8rem no-repeat;
  mask: var(--demo-mark-send) center / 0.8rem no-repeat;
}

/* Board side */

.demo-board {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4);
  border-left: 1px solid var(--hairline);
  background: var(--bg);
  /* Holds the full week's height from the first frame — the five tasks and the
     card under them. Stacked on narrow screens the panel is the page's height,
     so a board that grew as it played would shove everything below it down
     mid-read. */
  min-height: 19.5rem;
}

/* Fades rather than appears: the head has nothing under it until the first
   task lands, and collapsing it would shift every row that follows. */
.demo-board__head {
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  opacity: 0;
  transition: opacity 220ms ease-out;
}

.demo-board__head.is-on { opacity: 1; }

/* Fixed gap, and the rows stack from the top: the tasks arrive one at a time,
   and a list that spread itself over the column's height re-placed every row
   already on screen each time a new one landed. */
.demo-board__list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
}

.demo-task {
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  font-size: 0.88rem;
  color: var(--text);
  display: none;
  transition: color 260ms ease;
}

.demo-task.is-on {
  display: flex;
  animation: demo-in 260ms ease both;
}

.demo-task:has(.demo-task__box.is-on) {
  color: var(--text-muted);
}

.demo-task__box {
  position: relative;
  flex: none;
  width: 1.05rem;
  height: 1.05rem;
  border: 1px solid var(--hairline-strong);
  border-radius: 0.3rem;
  transition: background 220ms ease, border-color 220ms ease;
}

.demo-task__box.is-on {
  background: var(--green);
  border-color: var(--green);
}

.demo-task__box::after {
  content: "";
  position: absolute;
  inset: 0.15rem;
  background: var(--bg-card);
  -webkit-mask: var(--demo-mark-check) center / contain no-repeat;
  mask: var(--demo-mark-check) center / contain no-repeat;
  opacity: 0;
  transform: scale(0.4);
  transition: opacity 220ms ease, transform 220ms ease;
}

.demo-task__box.is-on::after {
  opacity: 1;
  transform: none;
}

/* The payoff strip: the panel's own status line while the run is on, and the
   result — with the number that proves it — when it lands. Spans both columns
   and keeps a constant height, so the flip is the only thing that moves. */
.demo-done {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  /* Fixed, not min: the status line and the result row are different shapes,
     and the flip between them must not resize the panel. */
  height: 3rem;
  padding: 0 var(--space-4);
  border-top: 1px solid var(--hairline);
  font-size: 0.88rem;
  transition: background 400ms ease;
}

.demo-done:has(.demo-done__result.is-on) {
  background: rgba(34, 197, 94, 0.1);
}

.demo-done__working {
  color: var(--text-muted);
  display: none;
}

.demo-done__working.is-on { display: block; }

.demo-done__result {
  display: none;
  width: 100%;
  align-items: center;
  gap: var(--space-2);
}

.demo-done__result.is-on {
  display: flex;
  animation: demo-in 400ms ease both;
}

/* The mark lands with a small overshoot — the one bit of theatre on the page,
   and the moment the loop is built around. */
.demo-done__check {
  position: relative;
  flex: none;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: var(--radius-pill);
  background: var(--green);
  animation: demo-pop 420ms cubic-bezier(0.2, 1.4, 0.5, 1) both 120ms;
}

.demo-done__check::after {
  content: "";
  position: absolute;
  inset: 0.28rem;
  background: var(--bg-card);
  -webkit-mask: var(--demo-mark-check) center / contain no-repeat;
  mask: var(--demo-mark-check) center / contain no-repeat;
}

.demo-done__text {
  font-weight: 600;
  color: var(--text);
  /* The strip's height is fixed, so neither half may wrap into it. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.demo-done__metric {
  margin-left: auto;
  white-space: nowrap;
  padding: 0.15rem 0.6rem;
  border-radius: var(--radius-pill);
  background: var(--bg-card);
  color: var(--green);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* What the week was for: the address, live. */
.demo-ship {
  align-items: center;
  gap: var(--space-2);
  margin-top: auto;
  padding: var(--space-3);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  background: var(--bg-card);
  font-size: 0.88rem;
  display: none;
}

.demo-ship.is-on {
  display: flex;
  animation: demo-in 300ms ease both;
}

.demo-ship__url {
  font-weight: 600;
  color: var(--text);
}

.demo-ship__pill {
  display: none;
  margin-left: auto;
  padding: 0.1rem 0.5rem;
  border-radius: var(--radius-pill);
  background: rgba(34, 197, 94, 0.16);
  color: var(--green);
  font-size: 0.72rem;
  font-weight: 600;
}

.demo-ship__pill.is-on { display: inline-block; }

/* Still being made: the card holds its place in neutral ink and turns green
   when the thing is actually up. */
.demo-ship__pill--pending {
  background: var(--fill-soft);
  color: var(--text-muted);
}

.demo-ship:has(.demo-ship__pill--pending.is-on) .demo-ship__url { color: var(--text-muted); }

/* Which business plays. Five of them at a quarter of a minute each is longer
   than anyone waits, and the one a visitor picks is the one that sells them —
   so the choice goes on the page, and taking it also stops the loop moving on.
   The row is deliberately below the panel: the panel is the argument, this is
   the remote control. */
/* One control, not five: a segmented row reads as the panel's foot, where five
   free-floating pills read as five buttons competing with it. */
.demo-picker {
  display: flex;
  width: fit-content;
  gap: 0;
  margin: var(--space-3) auto 0;
  /* One step all round, so the capsule's own frame is even — the segments
     carry the air, not the shell. */
  padding: var(--space-1);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-pill);
  background: var(--bg-card);
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.05);
}

/* One weight, one size: the selection is carried by fill and colour, so the
   row's letters never shift as it moves. */
.demo-pick {
  padding: var(--space-2) var(--space-3);
  border: 0;
  border-radius: var(--radius-pill);
  background: none;
  color: var(--text-muted);
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: color 120ms ease, background 120ms ease;
}

.demo-pick:hover {
  background: var(--fill-soft);
  color: var(--text);
}

/* Inside the capsule: an outline outside it would be clipped by the edge. */
.demo-pick:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.demo-pick[aria-pressed="true"]:hover { background: var(--tint-active); }

.demo-pick[aria-pressed="true"] {
  background: var(--tint-active);
  color: var(--text);
}

@keyframes demo-in {
  from { opacity: 0; transform: translateY(0.375rem); }
}

@keyframes demo-pop {
  from { transform: scale(0.4); opacity: 0; }
}

@keyframes demo-type {
  to { max-width: calc(var(--chars) * 1ch); }
}

@keyframes demo-caret {
  50% { border-color: transparent; }
}

@keyframes demo-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

/* Two columns hold down to phone-adjacent widths; only the truly narrow case
   stacks, where side-by-side would squeeze both to nothing. */
/* Stacked on a phone, and compact: the panel shares the fold with the headline
   and the ask, so every row gives back what it can. The min-heights are the
   finished content's own height — the panel still never grows as it plays. */
@media (max-width: 40rem) {
  /* The button is the page's one ask; the panel below it is the argument for
     it. On a phone they stack, so the gap has to say which is which — the
     panel keeps its distance instead of crowding the button. */
  .demo-stage { margin: var(--space-8) 0 var(--space-3); }

  .demo-sim__body { grid-template-columns: 1fr; }

  .demo-sim__bar { padding: var(--space-2) var(--space-3); }

  .demo-chat,
  .demo-board { padding: var(--space-3); }

  /* The closing reply says what the shipped card already shows, and on a phone
     the fold can't afford both — nor the mid-run line. */
  .demo-msg--result.is-on,
  .demo-msg--update.is-on { display: none; }

  /* The tallest moment any scene has on a phone — the ask, the reply and the
     composer — and not a line more: every pixel here is one the fold hasn't
     got. */
  .demo-chat { height: 13rem; }

  .demo-board {
    border-left: none;
    border-top: 1px solid var(--hairline);
    gap: var(--space-2);
    min-height: 12rem;
  }

  /* The strip below says the same thing with the number attached. */
  .demo-ship.is-on { display: none; }

  .demo-done {
    padding: 0 var(--space-3);
    font-size: 0.8rem;
    gap: var(--space-2);
  }

  .demo-board__list { gap: var(--space-2); }

  .demo-msg,
  .demo-task,
  .demo-composer,
  .demo-ship { font-size: 0.85rem; }

  .demo-msg { max-width: 88%; }

  /* Two rows rather than five squeezed segments: the labels say what the
     business is, and a phone has no width to spare for them in one line. The
     width is held short of what four would need, so the split is 3 + 2 and no
     label is left on a line of its own. */
  .demo-picker {
    flex-wrap: wrap;
    justify-content: center;
    max-width: 18rem;
    border-radius: var(--radius);
    padding: var(--space-2);
    row-gap: var(--space-1);
    margin-top: var(--space-2);
  }

  .demo-pick {
    padding: var(--space-2);
    font-size: 0.72rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .demo-sim__dot,
  .demo-msg--dots span,
  .demo-composer__ghost.is-on .demo-typed { animation: none; }

  .demo-composer__ghost.is-on .demo-typed { max-width: none; }

  .demo-msg.is-on,
  .demo-task.is-on,
  .demo-ship.is-on,
  .demo-done__result.is-on,
  .demo-done__check { animation: none; }

  .demo-task,
  .demo-task__box::after { transition: none; }
}

/* Disclaimer — a notice, not an error: the label in amber (read this before you
   pay) and nothing else coloured. Red under the CTA read as "something broke".
   A hairline card on the page's own ground, sized to its copy: the notice has
   to read as its own object, and both alternatives were worse — bare prose runs
   into the sections around it, a left rule alone reads as debris. It sits on
   the wrap's left edge like every section after it. Body copy runs in
   full-strength ink: a notice nobody reads is a notice that isn't there. Scoped
   under .marketing-section so the generic p rule (class+element) loses to it. */

.marketing-disclaimer__card {
  background: var(--bg-card);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius);
  padding: var(--space-8);
  /* Prose width plus its padding, so the copy fills the card. Centred, unlike
     every other block here: signed, it is a sheet of paper, and it continues
     the cover's axis before the page settles onto its left edge below. */
  max-width: 44rem;
  margin-inline: auto;
}

/* Even air above and below, and no hairline under it: the block is already
   fenced by its own border, so the section rule below would read as a second
   frame. Element-qualified to outrank `.marketing-hero--landing + .marketing-section`. */

/* The sheet gets the same air on both sides: 7rem over it, and 1rem under it
   plus the next section's own 6rem. Written out because the number below is a
   sum of two rules, not one of them. */

section.marketing-section.marketing-disclaimer { padding: 7rem 0 1rem; }

.marketing-disclaimer + .marketing-section { border-top: none; }

/* A tracked micro-label, not a display heading: the block already shouts in
   colour, and a second 2rem headline under the h1 would fight it. Sans, because
   the display face has nothing to give at 12px. */

.marketing-section .marketing-disclaimer__label {
  font-family: var(--font-sans);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--amber);
  /* Tighter than the paragraph rhythm: the label belongs to the line under it,
     not to the stack. */
  margin-bottom: var(--space-3);
}

.marketing-section .marketing-disclaimer__card p {
  color: var(--text);
  max-width: 46rem;
  line-height: 1.65;
  margin-bottom: var(--space-4);
  text-wrap: pretty;
}

/* The opening line carries the whole notice, so it reads as the statement and
   the rest as its footnotes. */

.marketing-section .marketing-disclaimer__card p:first-of-type {
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.45;
  letter-spacing: -0.01em;
  margin-bottom: var(--space-6);
}

/* The sign-off: body size, so it cannot be mistaken for a second heading under
   the 1.25rem statement, and the weight plus the air above are what mark it as
   the last word. */

.marketing-section .marketing-disclaimer__card .marketing-disclaimer__kicker {
  font-weight: 600;
  margin-top: var(--space-8);
  margin-bottom: 0;
}

/* The signature: a written hand, sized by its height like a real one and left
   where a signature goes. `multiply` drops the image's white ground onto the
   card's own white, so there is no plate around the ink and no cut-out halo. */

.marketing-section .marketing-disclaimer__card .marketing-disclaimer__sign {
  display: block;
  width: auto;
  height: 3.25rem;
  /* Right-hand corner, where a signature goes on anything anyone has ever
     signed — and it is the one thing that balances a card of left-set prose.
     Pulled up level with the sign-off: a hand signs beside the last line, not a
     paragraph's distance under it, and the card loses a hole at its foot. */
  margin: calc(var(--space-6) * -1) 0 0 auto;
  mix-blend-mode: multiply;
}

@media (max-width: 56.25em) {
  .marketing-disclaimer__card { padding: var(--space-6); }

  /* The sign-off wraps to two lines at this width, and the signature pulled up
     beside it landed on top of the words. */
  .marketing-section .marketing-disclaimer__card .marketing-disclaimer__sign {
    margin-top: var(--space-2);
  }
}

