/* ==========================================================================
   Closed Door Marketing — page stylesheet
   Authored against the SEMANTIC tokens only (--h1, --body, --gap-para,
   --btn-h ...). The --m- and --d- tokens are never referenced here; they
   exist only to feed the semantic layer in tokens.css.
   Sections separate by band change. Never a rule, border or container edge.
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* The page opens and closes on ink, so overscroll at either end shows ink
     rather than a blank paper screen under the form. */
  background: var(--ink);
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--body);
  font-weight: var(--w-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img, svg { display: block; max-width: 100%; }
img { height: auto; }
p { margin: 0; }
button, input, select, textarea { font: inherit; color: inherit; }

::selection { background: var(--brass); color: var(--ink); }
:focus-visible { outline: 2px solid var(--cta-strong); outline-offset: 3px; }
.band--ink :focus-visible { outline-color: var(--brass); }

.u-visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

/* --------------------------------------------------------------------------
   BANDS. The only thing that separates one section from the next is the
   background changing, plus a brass hairline at the join.
   -------------------------------------------------------------------------- */

.band {
  position: relative;
  padding-block: var(--pad-section);
  padding-inline: var(--pad-gutter);
}

.band--paper { background: var(--paper); }

/* --------------------------------------------------------------------------
   HEADER. Laid over the hero rather than given a band of its own, so the hero
   gradient runs behind it unbroken. Three things and no navigation: a line on
   the left, the mark in the centre, the one exit on the right. On phones the
   mark alone; the dock owns the invite there. Not sticky: the page has one
   direction.
   -------------------------------------------------------------------------- */
.site-header {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 6;
  height: var(--header-h);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--sp-4);
  padding-inline: var(--pad-gutter);
}

/* A signature, not a wordmark: it needs most of the bar's height to read. */
.site-header__logo { height: calc(var(--header-h) - 12px); }
.site-header__logo img { display: block; height: 100%; width: auto; }
.site-header__word { font-family: var(--font-display); font-size: var(--h3); line-height: 1; text-transform: uppercase; color: var(--ink); }

.site-header__side {
  margin: 0;
  font-family: var(--font-label);
  font-weight: var(--w-label);
  font-size: var(--eyebrow);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  line-height: var(--lh-mono);
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}
.site-header__side--l {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  /* A phone number, not a label: no caps tracking. */
  letter-spacing: .02em;
  text-transform: none;
  font-size: var(--small);
  color: var(--ink);
}
.site-header__icon { width: 18px; height: 18px; fill: var(--pop-deep); flex: none; }
.site-header__side--r { justify-self: end; padding-bottom: 3px; border-bottom: 3px solid var(--pop); }
.site-header__side--r:hover { border-color: var(--pop-deep); }
.site-header__side--r:focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; }

@media (max-width: 767px) {
  .site-header { grid-template-columns: 1fr; justify-items: center; }
  .site-header__side { display: none; }
}

/* The hero makes room for it: header height plus a fixed gap, not the
   section padding (that gave 212px on desktop; the client wants 160). */
.hero { padding-top: calc(var(--header-h) + var(--hero-top)); }

/* The hero ground. Ink with brass in it: a warm charcoal that darkens toward
   the top, a brass bloom off the left shoulder, a fainter one top-right, and
   grain screened over the whole thing so it reads as a surface, not a fill.
   The page opens and closes on ink; the letter arrives on paper between. */
.hero {
  position: relative;
  z-index: 3;
  isolation: isolate;
  color: var(--text-ink);
  background:
    radial-gradient(58% 44% at 8% -6%, rgba(198, 151, 73, .34) 0%, transparent 62%),
    radial-gradient(46% 40% at 96% 4%, rgba(198, 151, 73, .14) 0%, transparent 64%),
    linear-gradient(180deg, var(--hero-ink-top) 0%, var(--hero-ink) 48%, var(--hero-ink-end) 100%);
}

.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: .35;
  /* Screen, not multiply: multiply is invisible on ink. */
  mix-blend-mode: screen;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 62%, transparent 96%);
  mask-image: linear-gradient(180deg, #000 0%, #000 62%, transparent 96%);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.32'/%3E%3C/svg%3E");
}

/* Everything in the hero re-inked for the dark ground. */
.hero .h1 { color: var(--text-ink); }
.hero .circled { color: var(--hero-alert); }
.hero .lead, .hero .hero__note { color: var(--hero-text-2); }
.hero .cta__proof { color: var(--hero-text-3); }
.hero .pill { background: var(--paper); color: var(--ink); }
.hero .pill__text { color: var(--ink); }
.site-header__side { color: var(--text-ink); }
.site-header__side--l { color: var(--text-ink); }
.site-header__word { color: var(--text-ink); }
.site-header__side--r:focus-visible { outline-color: var(--text-ink); }

.hero__cue {
  margin-top: var(--gap-block);
  font-size: var(--h3);
  line-height: 1;
  color: var(--brass);
}

@media (prefers-reduced-motion: no-preference) {
  .hero__cue { animation: cdm-cue 2400ms ease-in-out infinite; }
}

@keyframes cdm-cue {
  0%, 100% { transform: translateY(0); opacity: .55; }
  50%      { transform: translateY(7px); opacity: 1; }
}

/* One intro block, on the body measure rather than the narrow lead measure,
   so it does not read as a second column under a full-width heading. Scoped
   under .room: at equal specificity the .lead measure (34ch) was winning. */
.room .room__name { max-width: var(--measure-body); margin-inline: auto; }

/* --------------------------------------------------------------------------
   THE FLOATING FRAME. Sits across the join from the hero into the letter, the
   way the reference floats a device over its own band edge. Desktop only:
   there is no room beside a caps headline on a phone. Not a video - it is the
   product, arriving, built from the same chrome as the frames further down.
   -------------------------------------------------------------------------- */

.hero__float { display: none; }

@media (min-width: 1024px) {
  .hero__float {
    display: block;
    position: absolute;
    right: 5%;
    bottom: calc(-1 * var(--wedge-h) - 70px);
    z-index: 4;
    filter: drop-shadow(0 26px 46px rgba(46, 38, 24, .22));
  }
}

.phone--float { --phone-w: 208px; text-align: left; }

.typing {
  align-self: flex-start;
  display: inline-flex;
  gap: 4px;
  padding: 10px 12px;
  background: #FFFFFF;
  border-radius: 10px 10px 10px 2px;
}

.typing i {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #9E9A93;
}

.bubble--lands { opacity: 0; }

@media (prefers-reduced-motion: no-preference) {
  .typing i { animation: cdm-typing 1200ms ease-in-out infinite; }
  .typing i:nth-child(2) { animation-delay: 160ms; }
  .typing i:nth-child(3) { animation-delay: 320ms; }
  .typing { animation: cdm-typing-out 7000ms ease-in-out infinite; }
  .bubble--lands { animation: cdm-lands 7000ms ease-in-out infinite; }
}

@keyframes cdm-typing { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }

@keyframes cdm-typing-out {
  0%, 42%   { opacity: 1; max-height: 40px; }
  50%, 100% { opacity: 0; max-height: 0; }
}

@keyframes cdm-lands {
  0%, 46%   { opacity: 0; transform: translateY(8px); }
  56%, 92%  { opacity: 1; transform: none; }
  100%      { opacity: 0; transform: translateY(8px); }
}

/* Reduced motion: the message has simply arrived. */
@media (prefers-reduced-motion: reduce) {
  .typing { display: none; }
  .bubble--lands { opacity: 1; }
}
.band--tint  { background: var(--paper-tint); }
.band--ink   { background: var(--ink); color: var(--text-ink); }

/* Sections still separate by background change: the join is a diagonal of the
   previous band's colour laid over the top of the next one, with a thin accent
   on its edge. No rule, no border, no container edge. */
.band > .wrap { position: relative; z-index: 1; }

.band[data-wedge]::before,
.band[data-wedge]::after {
  content: "";
  position: absolute;
  /* Pulled a pixel above the band. The band's own background and the wedge
     round to different device pixels at fractional offsets, which left a 1px
     grey seam along the join. */
  inset: -1px 0 auto;
  height: calc(var(--wedge-h) + 1px);
  z-index: 0;
  pointer-events: none;
}

.band[data-wedge]::before {
  background: var(--wedge-from);
  clip-path: polygon(0 0, 100% 0, 0 100%);
}

/* The lit edge of the diagonal. */
.band[data-wedge]::after {
  background: var(--pop);
  /* Every point stays inside the box. The old bottom-left point sat 7px below
     it, so the accent thinned out and vanished at the left edge. */
  clip-path: polygon(0 calc(100% - 12px), 100% 0, 100% 12px, 0 100%);
}

/* On ink the lime is doing too much; brass carries the edge instead. */
.band--ink[data-wedge]::after { background: var(--brass); }

.wedge--paper { --wedge-from: var(--paper); }
.wedge--tint  { --wedge-from: var(--paper-tint); }
.wedge--ink   { --wedge-from: var(--ink); }
.wedge--hero  { --wedge-from: var(--hero-ink-end); }

.wrap {
  width: 100%;
  max-width: 1080px;
  margin-inline: auto;
  /* Every section centres. Reading text opts back out below - ragged on both
     edges is unreadable at letter length on a phone. */
  text-align: center;
}

/* --------------------------------------------------------------------------
   TYPE ROLES
   -------------------------------------------------------------------------- */

/* The pill eyebrow. A stamp, not a line of text: dark capsule, live dot, a
   filled chip, then the line itself. */
.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-4) var(--sp-2) var(--sp-2);
  border-radius: 999px;
  background: var(--ink);
  font-family: var(--font-label);
  font-weight: var(--w-label);
  font-size: var(--eyebrow);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  line-height: var(--lh-mono);
  color: var(--text-ink);
}

.pill__dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--alert);
  box-shadow: 0 0 0 4px rgba(200, 50, 31, .28);
  flex: none;
  margin-left: var(--sp-2);
}

.pill__chip {
  padding: 3px var(--sp-3);
  border-radius: 999px;
  background: var(--alert);
  color: var(--paper);
}

.pill__text { padding-right: var(--sp-1); }

@media (max-width: 767px) {
  /* At 390 the line broke three ways and the capsule turned into a paragraph.
     Tighten it, let the label sit left of the text, and cap it at two lines. */
  .pill {
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-3) var(--sp-2) var(--sp-2);
    font-size: 11px;
    letter-spacing: .12em;
    text-align: left;
    max-width: 100%;
  }

  .pill__dot { margin-left: var(--sp-1); width: 8px; height: 8px; }
  .pill__chip { padding: 3px var(--sp-2); }
}

@media (prefers-reduced-motion: no-preference) {
  .pill__dot { animation: cdm-live 2200ms ease-in-out infinite; }
}

@keyframes cdm-live {
  0%, 100% { box-shadow: 0 0 0 3px rgba(200, 50, 31, .30); }
  50%      { box-shadow: 0 0 0 7px rgba(200, 50, 31, .10); }
}

.eyebrow {
  margin: 0;
  font-family: var(--font-label);
  font-weight: var(--w-label);
  font-size: var(--eyebrow);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--cta-strong);
  line-height: var(--lh-mono);
}

.band--ink .eyebrow { color: var(--brass); }

/* Manual breaks, desktop only: the caps lockup is set, not wrapped. */
.brk { display: none; }
/* The mirror of .brk: a break that exists only on phones, for headings whose
   balanced wrap the engines disagree on. */
.brk-m { display: inline; }
@media (min-width: 768px) { .brk-m { display: none; } }
.nowrap { white-space: nowrap; }
/* Headings balance their lines: no single-word last line where the engine
   can avoid it. Forced breaks (.brk) still apply inside the balanced block. */
h1, h2, h3, .h1, .h2, .h3 { text-wrap: balance; }

@media (min-width: 1024px) {
  .brk { display: inline; }
  /* The breaks are doing the wrapping now, so the measure has to get out of
     the way or it wraps a second time and the lockup runs to six lines. */
  .hero .h1 { max-width: none; }
}

.h1 {
  margin-inline: auto;
  margin-block: 0;
  overflow: visible;
  line-height: var(--lh-h1);
  letter-spacing: var(--ls-h1);
  font-family: var(--font-display);
  /* All caps, on instruction, after the reference page. Note that tokens.css
     picked Figtree over Poppins specifically for a Title Case setting; at this
     size the caps hold, but the measure has to widen to carry them. */
  text-transform: uppercase;
  font-size: var(--h1);
  text-shadow: 0 2px 0 rgba(16, 19, 23, .06);
  font-weight: var(--w-black);
  line-height: var(--lh-h1);
  letter-spacing: var(--ls-h1);
  max-width: 17ch;
}

.h2 {
  margin-inline: auto;
  margin-block: 0;
  font-family: var(--font-display);
  font-size: var(--h2);
  font-weight: var(--w-black);
  line-height: var(--lh-h2);
  letter-spacing: var(--ls-h2);
  text-transform: uppercase;
  max-width: 24ch;
}

.h3 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--h3);
  font-weight: var(--w-bold);
  line-height: var(--lh-h3);
}

.lead {
  font-size: var(--lead);
  line-height: var(--lh-lead);
  font-weight: var(--w-body);
  max-width: var(--measure-lead);
  margin-inline: auto;
}

.standfirst {
  font-size: var(--body);
  line-height: var(--lh-body);
  max-width: var(--measure-body);
  margin-inline: auto;
  color: var(--text-2);
}

.band--ink .standfirst { color: var(--text-ink-2); }

/* A standfirst always follows a heading block, so it always owns that gap. */
.stack-eyebrow + .standfirst,
.stack-eyebrow + .lead,
.h2 + .standfirst,
.h2 + .lead { margin-top: var(--gap-head-body); }

.caption {
  font-size: var(--caption);
  line-height: var(--lh-body);
  color: var(--text-2);
  max-width: var(--measure-body);
  margin-inline: auto;
}

.small { font-size: var(--small); line-height: var(--lh-body); }

/* The four vertical rhythms, largest to smallest. */
.stack-eyebrow > * + * { margin-top: var(--gap-eyebrow); }
.stack-head    > * + * { margin-top: var(--gap-head-body); }
.stack-block   > * + * { margin-top: var(--gap-block); }

/* --------------------------------------------------------------------------
   THE BUTTON. One component, five placements, never restyled. The micro-proof
   sits under the button, not inside it: carrying it inside turned every call
   to action into a tall block rather than a button.
   -------------------------------------------------------------------------- */

.cta { width: var(--cta-w); margin-inline: auto; }

.cta__btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: var(--btn-h);
  padding: var(--sp-4) var(--sp-6);
  border: 0;
  border-radius: var(--btn-radius);
  background: var(--pop);
  color: var(--ink);
  box-shadow: 0 3px 0 var(--pop-deep);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 160ms var(--ease-out), transform 90ms var(--ease-out);
}

.cta__btn:hover { background: var(--pop-deep); }
.cta__btn:active { transform: translateY(3px); box-shadow: none; }
.cta__btn[disabled] { opacity: .62; cursor: default; }

.cta__label {
  display: block;
  font-family: var(--font-display);
  font-size: var(--h3);
  font-weight: var(--w-black);
  line-height: var(--lh-h3);
  letter-spacing: var(--ls-h2);
  text-transform: uppercase;
}

.cta__proof {
  margin-top: var(--btn-gap-proof);
  font-family: var(--font-label);
  font-weight: var(--w-label);
  font-size: var(--proof-size);
  letter-spacing: var(--ls-micro);
  text-transform: uppercase;
  text-align: center;
  color: var(--text-2);
}

.band--ink .cta__proof { color: var(--text-ink-2); }

/* --------------------------------------------------------------------------
   STICKERS. Four placements, nothing else. One scale-and-settle, then still.
   -------------------------------------------------------------------------- */

.sticker {
  position: absolute;
  width: var(--sticker);
  height: auto;
  pointer-events: none;
  user-select: none;
  opacity: 0;
  transform: scale(.72) rotate(-6deg);
  transition: opacity var(--dur-settle) var(--ease-settle),
              transform var(--dur-settle) var(--ease-settle);
  /* Behind the text, never over it. Each one is hung off the container edge
     by a negative offset so it overlaps the edge and nothing else. */
  z-index: 0;
}

.sticker.is-in { opacity: 1; transform: scale(1) rotate(-6deg); }

/* --------------------------------------------------------------------------
   1 · HERO
   -------------------------------------------------------------------------- */

.hero__inner { position: relative; }
.hero .lead + .lead { margin-top: var(--gap-para); }
.hero__lede { margin-top: var(--gap-head-body); }
.hero .cta { margin-top: var(--gap-block); }

.hero__note {
  margin-inline: auto;
  margin-top: var(--gap-head-body);
  font-size: var(--small);
  line-height: var(--lh-body);
  color: var(--text-2);
  max-width: var(--measure-lead);
}

.hero__inner, .letter__body, .gp__beat { position: relative; }
/* The stickers must keep position:absolute; this rule sits at the same
   specificity and would otherwise drop them back into the flow. */
.hero__inner > *:not(.sticker),
.letter__body > p,
.gp__beat > strong { position: relative; z-index: 1; }

/* Bottom-aligned with the headline: it hangs off the right of the last line
   rather than floating at the top of the band. */
.hero .stack-eyebrow { position: relative; }
.hero .sticker--sideeye { top: auto; bottom: 0; right: 0; }
.letter .sticker--idea { right: calc(-1 * var(--sticker) / 2); margin-top: -2.4em; }
.gp__beat .sticker { top: 50%; right: calc(-1 * var(--sticker) / 2); transform: translateY(-50%) scale(.72) rotate(-6deg); }
.gp__beat .sticker.is-in { transform: translateY(-50%) scale(1) rotate(-6deg); }

/* The letter runs to a 62ch column, so the sticker has to clear the column
   edge, not the wrap edge, or it lands on the highlighted sentence. */
.letter .sticker--idea { right: calc(-1 * var(--sticker) - var(--sp-5)); }

@media (max-width: 1199px) {
  /* Below this there is no margin to hang into, so rather than let a sticker
     sit on a text run it takes its own slot at the right edge of the block.
     Placement is still fixed and deliberate; it just stops being an overlap. */
  .sticker {
    position: relative;
    inset: auto;
    display: block;
    margin-left: auto;
    margin-right: 0;
    transform: scale(.72) rotate(-6deg);
  }

  /* The desktop offsets are more specific than the .sticker reset above, so
     they survive `inset: auto` and push the sticker past the viewport edge.
     Reset them at matching specificity. */
  .hero .sticker--sideeye,
  .letter .sticker--idea,
  .gp__beat .sticker { top: auto; right: auto; }

  .sticker.is-in { transform: scale(1) rotate(-6deg); }
  .gp__beat .sticker,
  .gp__beat .sticker.is-in { transform: scale(1) rotate(-6deg); }
  /* Under the headline, centred, on its own line. */
  .hero .sticker--sideeye {
    margin: var(--sp-4) auto 0;
  }
  /* Left, with the reading text; it was hanging on the right of a left-aligned column. */
  .letter .sticker--idea { margin-block: var(--sp-5); margin-left: 0; margin-right: auto; }
  .gp__beat .sticker { margin-bottom: var(--sp-3); }
}

/* --------------------------------------------------------------------------
   2 · THE LETTER. One sentence per paragraph, at --lh-letter.
   -------------------------------------------------------------------------- */

.letter .stack-eyebrow,
.letter .h2 { max-width: var(--measure-letter); margin-inline: auto; }

.letter__body {
  position: relative;
  margin-top: var(--gap-block);
  /* The block is centred in the viewport; the sentences inside it are not. */
  max-width: var(--measure-letter);
  margin-inline: auto;
  text-align: left;
}

/* Direct children only. The figures inside the letter carry their own type -
   as a descendant selector this was blowing chat bubbles up to letter size. */
.letter__body > p {
  font-size: var(--letter);
  line-height: var(--lh-letter);
  font-weight: var(--w-body);
  max-width: var(--measure-letter);
}

.letter__body > p + p { margin-top: var(--gap-para); }
/* The highlighted sentence follows the sticker image, not a paragraph, so the
   p + p rule skipped it and it sat tight under the line above. */
.letter__body > .sticker + p { margin-top: var(--gap-para); }

/* Emphasis, about one paragraph in five. The single brass fill stays the only
   <mark> on the page; these are weight and rule, not highlight. */
.letter__body > p strong { font-weight: var(--w-bold); color: var(--ink); }

.letter__body > p u {
  text-decoration: underline;
  text-decoration-color: var(--brass);
  text-decoration-thickness: 2px;
  text-underline-offset: 5px;
  font-weight: var(--w-med);
  color: var(--ink);
}

/* The one highlighted sentence on the page. Brass fill, ink text. */
.letter__body p.is-highlight {
  font-weight: var(--w-med);
  color: var(--ink);
}

.letter__body p.is-highlight mark {
  background: var(--brass);
  color: var(--ink);
  padding: .12em .18em;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

.letter .cta { margin-top: var(--gap-block); }

/* --------------------------------------------------------------------------
   4 · WHAT ARRIVES — phone frames, rebuilt to spec
   -------------------------------------------------------------------------- */

.frames {
  margin-top: var(--gap-block);
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: var(--sp-6);
  animation: cdm-float var(--dur-drift) ease-in-out infinite alternate;
}

.phone {
  --phone-w: 200px;
  flex: none;
  width: var(--phone-w);
  aspect-ratio: 9 / 19.5;
  border-radius: var(--radius-phone);
  border: 8px solid var(--ink);
  background: #E8E4DA;
  overflow: hidden;
  position: relative;
  display: flex;
  flex-direction: column;
  box-shadow: inset 0 1px 0 rgba(244, 241, 234, .22), 0 10px 26px rgba(11, 13, 16, .14);
}

@media (min-width: 1024px) {
  .phone { --phone-w: 260px; }
}

@media (max-width: 767px) {
  /* The desktop composition, scaled. `zoom` rather than `transform: scale()`
     because zoom takes the layout box with it - a transform would leave the
     row at its full 648px and push the page sideways. Shrinking --phone-w
     instead was worse: the chrome stayed put while the text inside collapsed
     to two words a line. */
  .frames { flex-wrap: nowrap; zoom: .52; }
}

/* All three are the same size, on the same line, with the same gap between
   them. They used to drift on three separate keyframes, which meant the gaps
   were a different width at every moment; the whole row floats as one now, so
   the spacing is fixed and the motion survives. */
@keyframes cdm-float {
  from { transform: translate3d(-6px, 0, 0); }
  to   { transform: translate3d(6px, 0, 0); }
}

/* Status bar, on the WhatsApp header green. */
.phone__status {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 5px 10px 2px;
  background: #075E54;
  color: var(--ink);
  font-size: 10px;
  font-weight: var(--w-bold);
}

.phone__status-glyphs { display: flex; align-items: center; gap: 4px; }
.phone__status svg { width: 11px; height: 11px; fill: var(--ink); }

.phone__header {
  flex: none;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px 8px;
  background: #075E54;
  color: #F4F1EA;
}

.phone__header svg { width: 13px; height: 13px; fill: #F4F1EA; flex: none; }
.phone__avatar { width: 24px; height: 24px; border-radius: 50%; background: #9E9A93; flex: none; }
.phone__who { min-width: 0; flex: 1; line-height: 1.15; }

.phone__name {
  display: flex;
  align-items: center;
  gap: 3px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

.phone__name svg { width: 10px; height: 10px; fill: #C69749; }
.phone__sub { font-size: 9px; opacity: .78; white-space: nowrap; }

.phone__chat {
  flex: 1;
  min-height: 0;
  background: #E8E4DA;
  padding: 8px 8px 4px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  overflow: hidden;
}


/* Incoming only. There is never an outgoing bubble in this room. */
.bubble {
  align-self: flex-start;
  max-width: 92%;
  background: #FFFFFF;
  border-radius: 10px 10px 10px 2px;
  padding: 12px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text);
  position: relative;
}

@media (min-width: 1024px) { .bubble { font-size: 14px; } }

.bubble p + p { margin-top: .7em; }
.bubble time { display: block; text-align: right; margin-top: 4px; font-size: 11px; color: var(--text-2); }

/* The blur begins mid-bubble, on a gradient mask, not at a hard edge. */
.bubble__veil {
  filter: blur(var(--msg-blur));
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 42%);
  mask-image: linear-gradient(180deg, transparent 0%, #000 42%);
}

.phone__empty { flex: 1; }

.phone__divider {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-block: 6px;
  font-size: 9px;
  color: var(--text-2);
  text-align: center;
}

.phone__divider::before,
.phone__divider::after { content: ""; flex: 1; height: 1px; background: rgba(74, 70, 64, .22); }

.phone__input {
  flex: none;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px;
  background: #F4F1EA;
  /* Still visibly disabled, but dark enough to clear AA. The glyphs beside it
     carry the greyed-out reading on their own. */
  color: #736F66;
  font-size: 10px;
}

.phone__input svg { width: 12px; height: 12px; fill: #B7B2AA; flex: none; }
.phone__input span { flex: 1; }
/* --------------------------------------------------------------------------
   THE ROOM. The plain-facts section: what this is, in six lines, then the
   frames. Centred, and it has to be scannable in about ten seconds, so the
   facts are a two-column grid on desktop and a single column on a phone.
   -------------------------------------------------------------------------- */

.room { text-align: center; }
.room .h2 { max-width: 24ch; margin-inline: auto; }
.room .standfirst { margin-top: var(--gap-head-body); margin-inline: auto; }

/* Six facts, six cards. Centred labels over centred lines drifted apart and
   there was nothing holding a pair together, so each one is now a panel with
   its answer left-aligned under its own label. */
.room__facts {
  margin-top: var(--gap-block);
  display: grid;
  gap: var(--sp-4);
  text-align: left;
}

@media (min-width: 768px) {
  .room__facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
  .room__facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.room__fact {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-6);
  background: var(--paper-tint);
  border-radius: var(--radius-card);
  border-top: 2px solid var(--brass);
}

.room__fact-label {
  font-family: var(--font-label);
  font-weight: var(--w-label);
  font-size: var(--eyebrow);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--cta-strong);
  line-height: var(--lh-mono);
}

.room__fact-line {
  font-size: var(--small);
  line-height: var(--lh-body);
}

.room__framelead {
  margin-top: var(--gap-block);
  font-size: var(--body);
  font-weight: var(--w-med);
  color: var(--text-2);
}

.room .frames { margin-top: var(--gap-head-body); }

/* The section is centred; a phone screen is not. */
.room .phone { text-align: left; }

.room__terms { margin-top: var(--gap-block); }
.room__terms p { max-width: var(--measure-body); margin-inline: auto; }
.room__terms p + p { margin-top: var(--gap-para); }

.room .cta { margin-top: var(--gap-block); }
.gp .cta { margin-top: var(--gap-block); }

/* --------------------------------------------------------------------------
   5 · GURPREET + CLOSE + FORM
   -------------------------------------------------------------------------- */

.gp__grid {
  margin-top: var(--gap-block);
  display: grid;
  gap: var(--gap-block);
  max-width: 1080px;
  margin-inline: auto;
  text-align: left;
}

@media (min-width: 900px) {
  /* The portrait was a stamp next to a wall of text. Give it real width and
     pull the beats in to a comfortable measure so the column reads as a pair. */
  .gp__grid { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); align-items: start; gap: var(--gap-block) var(--sp-16); }
  /* The portrait rides along while the right column scrolls, instead of
     leaving a well of ink under itself. */
  .gp__portrait { position: sticky; top: var(--sp-8); }
}

.gp__portrait { aspect-ratio: 4 / 5; overflow: hidden; border-radius: var(--radius-card); background: #16181C; }
.gp__portrait img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 18%; }
/* Direct children only. As a descendant selector this also caught the beats,
   which are grid items, so each one carried a paragraph margin on top of the
   grid gap and the three drifted apart. */
.gp__intro > p + p { margin-top: var(--gap-para); }

/* 32px above the beats and 32px between them, at every width. */
.gp__beats { margin-top: var(--sp-8); display: grid; gap: var(--sp-8); }
.gp__beats > .gp__beat { margin-top: 0; }
/* Each beat is hung off a small brass key: these three are the conditions of
   getting in, so the bullet is the thing the section is actually about.

   A hanging indent, NOT a grid. Making the <p> a grid container turns its
   own inline content into grid items and the sentence breaks one word per
   row. */
.gp__beat {
  position: relative;
  max-width: 46ch;
  text-align: left;
  padding-left: calc(22px + var(--sp-4));
}

.gp__beat::before {
  content: "";
  position: absolute;
  left: 0;
  top: .2em;
  width: 22px;
  height: 22px;
  background: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23C69749' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'><circle cx='8.4' cy='8.4' r='4.4'/><path d='M11.6 11.6 20 20'/><path d='M16.6 16.6 14.6 18.6'/><path d='M19 19 17 21'/></svg>") no-repeat center / contain;
}
.gp__beat strong { font-weight: var(--w-bold); color: var(--text-ink); }
.gp__beat { color: var(--text-ink-2); }
/* 1.75x the block gap: at 1x the close read as part of the bio grid. */
.close { margin-top: calc(var(--gap-block) * 1.75); }
.close .h2 { color: var(--text-ink); }
.close__body { margin-top: var(--gap-head-body); }
.close__body p { max-width: var(--measure-body); margin-inline: auto; color: var(--text-ink-2); }
.close__body p + p { margin-top: var(--gap-para); }

/* ---- the form ---- */

.form { margin-top: var(--gap-block); }
/* The block is centred in the band; everything inside it lines up with the
   left edge of the inputs. Without this the controls inherit the section's
   centring and the placeholders sit in the middle of the field. */
.form__fields {
  margin-top: var(--gap-block);
  display: grid;
  gap: var(--sp-6);
  max-width: 560px;
  margin-inline: auto;
  text-align: left;
}
.field { display: flex; flex-direction: column; gap: var(--sp-2); }

.field__label {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  font-size: var(--small);
  font-weight: var(--w-med);
  color: var(--text-ink);
}

.field__no {
  font-family: var(--font-label);
  font-weight: var(--w-label);
  font-size: var(--eyebrow);
  letter-spacing: .14em;
  color: var(--brass);
  flex: none;
}

.field__control {
  width: 100%;
  min-height: 54px;
  padding: 14px 16px;
  border: 1px solid var(--field-line);
  border-radius: var(--btn-radius);
  background: var(--field);
  color: var(--text);
  font-size: 18px;
  line-height: var(--lh-body);
}

textarea.field__control { min-height: 140px; resize: vertical; }

select.field__control {
  appearance: none;
  padding-right: 44px;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--cta) 50%),
    linear-gradient(135deg, var(--cta) 50%, transparent 50%);
  background-position: calc(100% - 22px) calc(50% + 1px), calc(100% - 16px) calc(50% + 1px);
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
}

.field__control:focus { outline: 2px solid var(--brass); outline-offset: 1px; }
.field__control[aria-invalid="true"] { border-color: #C0574B; }
.field__hint { font-size: var(--caption); line-height: var(--lh-body); color: var(--text-ink-2); }
.field__birthday { display: grid; grid-template-columns: 1fr 1.4fr; gap: var(--sp-3); }
.field--honey { position: absolute !important; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.form__note { margin-top: var(--gap-head-body); }
.field__birthday { text-align: left; }

.form__consent {
  margin-inline: auto;
  margin-top: var(--gap-head-body);
  text-align: center;
  font-size: var(--small);
  line-height: var(--lh-body);
  color: var(--text-ink-2);
  max-width: var(--measure-body);
}

.form__error {
  margin-top: var(--sp-4);
  text-align: center;
  font-family: var(--font-label);
  font-weight: var(--w-label);
  font-size: var(--eyebrow);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #E29A8E;
}

.form__error:empty { display: none; }
.form__success { max-width: var(--measure-body); margin-inline: auto; }
.form__success h3 { margin-bottom: var(--gap-head-body); color: var(--text-ink); font-size: var(--h2); font-weight: var(--w-black); line-height: var(--lh-h2); }
.form__success p { color: var(--text-ink-2); }
.form__success p + p { margin-top: var(--gap-para); }
.form .cta { margin-top: var(--gap-block); }

/* --------------------------------------------------------------------------
   THE ENQUIRY THAT WENT QUIET. The letter's argument in the medium the letter
   is about: an enquiry arrives, you answer, you quote, and then nothing. The
   outgoing bubbles are the only ones on the site - this is the reader's own
   phone, not the room.
   -------------------------------------------------------------------------- */

.thread { margin: var(--gap-block) auto; max-width: var(--measure-body); text-align: center; }
.thread__phone { display: flex; justify-content: center; }
.phone--thread { --phone-w: 300px; aspect-ratio: auto; text-align: left; }
.thread__chat { gap: 8px; padding-bottom: 12px; position: relative; }

/* Scoped: at equal specificity .sketch's width:100% / height:auto was
   winning and the ring came out twice the size. */
.thread__chat .thread__ring {
  position: absolute;
  left: -2px;
  bottom: 0;
  width: 108px;
  height: 54px;
  pointer-events: none;
}

.bubble--out {
  align-self: flex-end;
  background: #E7F3D8;
  border-radius: 10px 10px 2px 10px;
}

.thread__gap {
  align-self: center;
  padding: 3px 10px;
  border-radius: 999px;
  background: rgba(16, 19, 23, .07);
  font-family: var(--font-label);
  font-weight: var(--w-label);
  font-size: 9px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-2);
}

.thread__last { opacity: .55; }

/* The beat that actually hurts: he starts typing, and then he doesn't. */
.typing--ghost { align-self: flex-start; opacity: 0; }

@media (prefers-reduced-motion: no-preference) {
  .thread.is-in .typing--ghost { animation: cdm-ghost 6400ms ease-in-out 2000ms infinite; }
}

@keyframes cdm-ghost {
  0%, 42%   { opacity: 0; transform: translateY(4px); }
  50%, 74%  { opacity: 1; transform: none; }
  84%, 100% { opacity: 0; transform: translateY(4px); }
}
.thread__caption { margin-top: var(--gap-head-body); font-size: var(--caption); color: var(--text-2); }

@media (prefers-reduced-motion: no-preference) {
  .thread .bubble { opacity: 0; transform: translateY(6px); transition: opacity 420ms var(--ease-out), transform 420ms var(--ease-out); }
  .thread .thread__gap { opacity: 0; transition: opacity 420ms var(--ease-out); }
  .thread.is-in .bubble, .thread.is-in .thread__gap { opacity: 1; transform: none; }
  .thread.is-in .bubble:nth-of-type(2) { transition-delay: 180ms; }
  .thread.is-in .bubble:nth-of-type(3) { transition-delay: 360ms; }
  .thread.is-in .bubble:nth-of-type(4) { transition-delay: 540ms; }
  .thread.is-in .bubble:nth-of-type(5) { transition-delay: 860ms; }
  .thread.is-in .bubble:nth-of-type(6) { transition-delay: 1180ms; }
  .thread.is-in .thread__last { opacity: .55; }
}

/* --------------------------------------------------------------------------
   THE PILE. Four invoices thrown on a desk, stamped, overlapping, at angles -
   and a fifth sheet underneath that nobody ever wrote. A stack of paper, not
   a row of cards with icons in them.
   -------------------------------------------------------------------------- */

.pile { margin: var(--gap-block) auto; max-width: 760px; text-align: center; }

/* One composition at every width. The stack is a size container and every
   dimension inside it is a fraction of its width, so a phone gets the desktop
   pile scaled down rather than rebuilt as a column. 1cqw = 7.6px at the 760px
   width these numbers were drawn at. */
.pile__stack { position: relative; container-type: inline-size; aspect-ratio: 76 / 43; }

.inv {
  position: absolute;
  left: calc(50% + var(--x));
  top: var(--y);
  /* 27, not 31: sheets sit on 25% centres, and at 31 each one covered the
     end of the previous sheet's longest line. */
  width: 27cqw;
  display: flex;
  flex-direction: column;
  gap: 1.05cqw;
  padding: 2.6cqw;
  background: #FBFAF6;
  border-radius: 2px;
  text-align: left;
  transform: translateX(-50%) rotate(var(--r));
  box-shadow: 0 1.8cqw 4cqw rgba(46, 38, 24, .17), 0 .3cqw .5cqw rgba(46, 38, 24, .10);
}

.inv__head {
  font-family: var(--font-label);
  font-weight: var(--w-label);
  font-size: 1.6cqw;
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--text-2);
}

.inv__line { font-size: 2.25cqw; font-weight: var(--w-bold); line-height: 1.25; color: var(--ink); }
.inv__sub { font-size: 1.85cqw; color: var(--text-2); }
.inv__rule { height: max(1px, .13cqw); margin-top: 1.6cqw; background: var(--paper-edge); }

/* The stamp. Rotated, slightly transparent, sitting over the ruled line. On
   the leading edge: each sheet overlaps the one before it, so a stamp on the
   right vanishes under the next sheet. */
.inv__stamp {
  position: absolute;
  /* Inside the sheet. Hanging off the edge it landed on the previous sheet's text. */
  left: 1.4cqw;
  bottom: 1.4cqw;
  padding: .4cqw 1.3cqw;
  border: max(1px, .26cqw) solid var(--alert);
  border-radius: 3px;
  color: var(--alert);
  font-family: var(--font-label);
  font-weight: var(--w-label);
  font-size: 1.7cqw;
  letter-spacing: .18em;
  text-transform: uppercase;
  transform: rotate(-11deg);
  opacity: .82;
}

/* The one that was never written. Underneath the pile, unstamped. */
.inv--none {
  background: transparent;
  border: max(1px, .26cqw) dashed var(--brass);
  box-shadow: none;
}

.inv--none .inv__head--none { color: var(--cta-strong); }
.inv--none .inv__sub { color: var(--cta-strong); font-weight: var(--w-bold); }
.pile__caption { margin-top: var(--gap-head-body); font-size: var(--caption); color: var(--text-2); }

@media (prefers-reduced-motion: no-preference) {
  .inv { opacity: 0; transform: translateX(-50%) rotate(var(--r)) translateY(2cqw); transition: opacity 460ms var(--ease-out), transform 460ms var(--ease-settle); }
  .pile.is-in .inv { opacity: 1; transform: translateX(-50%) rotate(var(--r)); }
  .pile.is-in .inv:nth-child(2) { transition-delay: 110ms; }
  .pile.is-in .inv:nth-child(3) { transition-delay: 220ms; }
  .pile.is-in .inv:nth-child(4) { transition-delay: 330ms; }
  .pile.is-in .inv--none { transition-delay: 760ms; }
}

@media (max-width: 1023px) {
  /* Up to and including tablet: at 768 the wrap is narrower than the pile's
     overhang, so the same pull-in applies there.
     Inside the page margins, nothing clipped. An earlier version bled the pile
     to 100vw under overflow: clip; that put sheets past the margins and cut
     the tilted top corners flat. Now the spread is pulled in so the outer
     sheets stay inside the wrap, and the stack carries head-room for the
     corners that rise above its top. */
  .pile__stack { padding-top: 5cqw; }
  .inv { left: calc(50% + var(--x) * .88); }
}

/* --------------------------------------------------------------------------
   LAST WEEK'S MESSAGE. Four beliefs, plain step numbers. The numerals keep the
   supplied component's type treatment; only the count-up is gone.
   -------------------------------------------------------------------------- */

/* On the slant. At the horizontal centre the wedge line is exactly half a
   wedge-height below the band's top edge, so that is the anchor; the memoji
   is centred on it, half on the paper above and half on the tint below. It
   is a child of the band, not the wrap, so the offset is band-relative. */
.beliefs__mark {
  position: absolute;
  left: 50%;
  top: calc(var(--wedge-h) / 2);
  width: clamp(88px, 12vw, 148px);
  height: auto;
  margin: 0;
  transform: translate(-50%, -50%);
  z-index: 2;
  pointer-events: none;
}
/* Room under the memoji's lower half before the eyebrow. */
.beliefs > .wrap { padding-top: var(--sp-8); }

.beliefs__grid {
  margin-top: calc(var(--gap-block) * 1.6);
  display: grid;
  gap: var(--gap-block) var(--sp-10);
}

@media (min-width: 768px) { .beliefs__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.belief {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-4);
  opacity: 0;
  transform: translateY(10px);
  transition: opacity var(--dur-reveal) var(--ease-out), transform var(--dur-reveal) var(--ease-out);
}

.beliefs__grid.is-in .belief { opacity: 1; transform: none; }
.beliefs__grid.is-in .belief--02 { transition-delay: 110ms; }
.beliefs__grid.is-in .belief--03 { transition-delay: 220ms; }
.beliefs__grid.is-in .belief--04 { transition-delay: 330ms; }

.belief__numeral {
  /* Four is set larger and carries a fill, so its box is taller than the other
     three and their headings fell off the same line. One shared height, with
     every numeral sitting on the same baseline. */
  display: flex;
  align-items: flex-end;
  justify-content: center;
  min-height: calc(var(--numeral) * 1.05);
  /* Matches the padding inside four's filled span, so all four numerals sit
     on one baseline. */
  padding-bottom: .06em;
  font-family: var(--font-display);
  font-size: var(--numeral);
  font-weight: var(--w-black);
  line-height: .86;
  /* Tracked open like the headings, not tight: Anton's tight fit made 01
     read as a single glyph. */
  letter-spacing: .04em;
  font-variant-numeric: tabular-nums;
  color: var(--text-2);
}

.belief--04 .belief__numeral { padding-bottom: 0; }

.belief--04 .belief__numeral > span {
  display: inline-block;
  /* Same size as the other three: at 1.24x the row never lined up. The fill
     carries the emphasis. */
  font-size: var(--numeral);
  /* Line-height 1 plus vertical padding: the fill is the inline box, and at
     .84 it was shorter than the glyphs it sat behind. */
  line-height: .86;
  letter-spacing: .04em;
  color: var(--ink);
  background: var(--brass);
  /* Anton's 4 overhangs its advance width, and the fill is the inline box:
     at .1em the glyph's right edge ran past the brass. */
  padding: .1em .2em .06em .16em;
}

.belief__head { max-width: 18ch; }

@media (min-width: 1024px) {
  /* One line each, so the four numerals and their headings line up. */
  .belief__head { max-width: none; white-space: nowrap; }
}
.belief__body { max-width: 40ch; color: var(--text-2); }

.payoff {
  margin-top: var(--gap-block);
  max-width: var(--measure-body);
  margin-inline: auto;
  padding-top: var(--gap-head-body);
  border-top: var(--hair-w) solid var(--brass);
}

.payoff p { font-size: var(--lead); line-height: var(--lh-lead); font-weight: var(--w-med); }
.payoff p + p { margin-top: var(--gap-para); }
.payoff em { font-style: italic; color: var(--cta-strong); }

/* --------------------------------------------------------------------------
   THE MUTED FORTY. The same phone chrome as the frames, holding a chat list
   in which one row is awake.
   -------------------------------------------------------------------------- */

/* Three marks for the three things the room does not carry. They replace the
   chat-list frame that used to sit here. */
.trio {
  margin-top: var(--gap-block);
  display: flex;
  justify-content: center;
  align-items: center;
  gap: clamp(var(--sp-6), 5vw, var(--sp-16));
}

.trio__mark {
  width: clamp(64px, 11vw, 116px);
  height: auto;
  opacity: 0;
  transform: translateY(10px) scale(.82);
  transition: opacity var(--dur-settle) var(--ease-settle),
              transform var(--dur-settle) var(--ease-settle);
}

.trio.is-in .trio__mark { opacity: 1; transform: none; }
.trio.is-in .trio__mark:nth-child(2) { transition-delay: 120ms; }
.trio.is-in .trio__mark:nth-child(3) { transition-delay: 240ms; }

.trio__caption {
  margin-top: var(--gap-head-body);
  font-size: var(--caption);
  color: var(--text-ink-2);
}

.muted {
  margin-top: var(--gap-block);
  display: flex;
  justify-content: center;
  align-items: center;
  /* It was a small object marooned in a wide dark band. A soft pool of light
     behind it gives it something to sit on. */
  background: radial-gradient(46% 60% at 50% 50%, rgba(198, 151, 73, .10), transparent 70%);
}

.phone--list { --phone-w: 258px; text-align: left; }
.phone__header--list { justify-content: flex-start; padding: 8px 12px 10px; }
.phone__header--list .phone__name { font-size: 13px; }
.phone__list { flex: 1; min-height: 0; background: #F4F1EA; overflow: hidden; }

.mrow {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 9px;
  filter: blur(var(--msg-blur));
}

.mrow__avatar { width: 26px; height: 26px; border-radius: 50%; background: #C9C4BB; flex: none; }
.mrow__text { flex: 1; min-width: 0; }
.mrow__name { display: block; font-size: 11px; font-weight: var(--w-bold); color: var(--text); }
.mrow__prev { display: block; font-size: 10px; color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mrow__bell { width: 11px; height: 11px; fill: #A8A39A; flex: none; }

/* The one row that is awake. */
.mrow--live {
  filter: none;
  background: #FFFFFF;
  transform: translateY(0);
  transition: transform var(--dur-settle) var(--ease-settle);
}

.muted.is-in .mrow--live { transform: translateY(-2px); }

.mrow__badge {
  flex: none;
  display: grid;
  place-items: center;
  min-width: 17px;
  height: 17px;
  padding: 0 4px;
  border-radius: 9px;
  background: var(--brass);
  color: var(--ink);
  font-size: 10px;
  font-weight: var(--w-bold);
  opacity: 0;
  transition: opacity var(--dur-settle) var(--ease-out) 420ms;
}

.muted.is-in .mrow__badge { opacity: 1; }

/* --------------------------------------------------------------------------
   FOOTER. A name and a place. No links.
   -------------------------------------------------------------------------- */

/* The form and the footer are both ink, so a band change cannot separate
   them. The strip is a shade lighter with a brass hairline on top of it. */
.site-footer {
  padding-block: var(--sp-10);
  background: #16181C;
  border-top: var(--hair-w) solid var(--hair-ink);
}
.site-footer__name { font-weight: var(--w-bold); color: var(--text-ink); }

.site-footer__place {
  margin-top: var(--sp-2);
  font-family: var(--font-label);
  font-weight: var(--w-label);
  font-size: var(--eyebrow);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--text-ink-2);
}

/* --------------------------------------------------------------------------
   FAQ. Native disclosure elements: keyboard and screen reader behaviour for
   free, and it still opens with JavaScript off.
   -------------------------------------------------------------------------- */

.faq__list {
  margin-top: var(--gap-block);
  max-width: var(--measure-body);
  margin-inline: auto;
  text-align: left;
}

.faq__item { background: var(--paper-tint); border-radius: var(--radius-card); }
.faq__item + .faq__item { margin-top: var(--sp-3); }

.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-5) var(--sp-6);
  min-height: 56px;
  font-size: var(--small);
  font-weight: var(--w-bold);
  line-height: var(--lh-h3);
  cursor: pointer;
  list-style: none;
}

.faq__q::-webkit-details-marker { display: none; }

.faq__sign {
  flex: none;
  width: 22px;
  height: 22px;
  position: relative;
  border-radius: 50%;
  background: var(--brass);
}

.faq__sign::before,
.faq__sign::after {
  content: "";
  position: absolute;
  inset: 50% 5px auto;
  height: 2px;
  margin-top: -1px;
  background: var(--ink);
  transition: transform var(--dur-base) var(--ease-out);
}

.faq__sign::after { transform: rotate(90deg); }
.faq__item[open] .faq__sign::after { transform: rotate(0deg); }

.faq__a {
  padding: 0 var(--sp-6) var(--sp-6);
  font-size: var(--small);
  line-height: var(--lh-body);
  color: var(--text-2);
  max-width: 56ch;
}

/* --------------------------------------------------------------------------
   THE WHITEBOARD. Everything hand-drawn on the page runs through this: a
   marker hand for the words, thick round-capped ink for the lines, red for
   anything that points or rings, brass for a bracket. Every path carries
   pathLength="1" so it draws itself on with one dash rule regardless of its
   real length, and its own --d for the order things get drawn in.
   -------------------------------------------------------------------------- */

.hand {
  font-family: var(--font-hand);
  font-weight: 700;
  font-size: var(--lead);
  line-height: 1.2;
  color: var(--ink);
  margin: 0;
}

.sketch { display: block; width: 100%; height: auto; overflow: visible; }

.sketch .st {
  fill: none;
  stroke: var(--ink);
  stroke-width: 4.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.sketch .st--red { stroke: var(--alert); stroke-width: 4; }
/* Crosses drawn over text: lighter so the word under them still reads. */
.sketch .st--soft { stroke-opacity: .45; }
.sketch .st--brass { stroke: var(--brass); stroke-width: 3.5; }
.sketch text { font-family: var(--font-hand); font-weight: 700; fill: var(--ink); }
.sketch text.red { fill: var(--alert); }

.sketch-wrap { margin: var(--gap-block) auto; max-width: var(--measure-body); text-align: center; }

/* Sketches scale to whatever width they are given, on every screen. No
   sideways scrolling, on instruction. */

.sketch .st--faint { stroke: var(--text-2); stroke-width: 3.5; opacity: .55; }
.sketch .st--dash { stroke-dasharray: 10 12; }
.sketch .dot { fill: var(--alert); }
.sketch .dot--brass { fill: var(--brass); }
.sketch .fill-brass { fill: var(--brass); }
.sketch .fill-paper { fill: var(--paper); }
.sketch text.brass { fill: var(--cta-strong); }
.sketch text.muted { fill: var(--text-2); }

/* Dots and fills pop in on the same clock as the words. */
@media (prefers-reduced-motion: no-preference) {
  .sketch .dot, .sketch .fill-brass, .sketch .fill-paper { opacity: 0; }
  .is-in .sketch .dot, .is-in .sketch .fill-brass, .is-in .sketch .fill-paper { animation: cdm-fade 400ms var(--ease-out) forwards; animation-delay: var(--d, 0ms); }
}
.sketch-wrap--wide { max-width: 980px; margin-top: var(--gap-block); margin-bottom: 0; }
.sketch__cap { margin-top: var(--gap-head-body); font-size: var(--body); color: var(--text-2); }

/* Draw-on. Lines draw, words fade, each on its own beat. */
@media (prefers-reduced-motion: no-preference) {
  .sketch .st { stroke-dasharray: 1; stroke-dashoffset: 1; }
  .sketch text { opacity: 0; }
  .is-in .sketch .st, .hero .sketch .st { animation: cdm-draw 900ms var(--ease-out) forwards; animation-delay: var(--d, 0ms); }
  .is-in .sketch text, .hero .sketch text { animation: cdm-fade 400ms var(--ease-out) forwards; animation-delay: var(--d, 0ms); }
}

@keyframes cdm-draw { to { stroke-dashoffset: 0; } }
@keyframes cdm-fade { to { opacity: 1; } }

/* The marked phrase in a headline. Colour, not a drawn mark: a ring or an
   underline over caps at this leading either crosses the letters or reads as
   belonging to the line below. Red carries the emphasis on its own. */
.circled { color: var(--alert); }

/* Marker notes: a handwritten line and a red arrow, hung beside an object. */
.note { display: none; }

@media (min-width: 900px) {
  .note { display: block; position: absolute; width: 230px; text-align: left; pointer-events: none; }
  .note .hand { font-size: 24px; }
  .note__arrow { width: 90px; margin-top: 4px; }

  .thread { position: relative; }
  /* Five marks around the enquiry thread, hung off the 300px phone: each
     step the owner got right, then the one that died. Offsets (--y) are
     measured against the bubbles at the phone's fixed width, so they hold at
     any viewport from 900 up. Left notes read toward the phone. */
  .note--t { top: var(--y); width: 220px; }
  .note--tl { right: calc(50% + 172px); text-align: right; }
  .note--tr { left: calc(50% + 172px); text-align: left; }
  .note--t .hand { font-size: 22px; line-height: 1.1; }
  .note--tl .note__arrow { display: block; margin-left: auto; margin-right: -26px; }
  .note--tr .note__arrow { display: block; margin-left: -26px; }
  .note--red .hand { color: var(--alert); }


  .room .frames { position: relative; }
  .note--frames { position: relative; margin: var(--gap-block) auto 0; width: auto; text-align: center; }
  .note--frames .hand { font-size: var(--lead); }
  /* 26px, not 2: the 35deg turn lifts the tail into the handwriting above. */
  .note--frames .note__arrow { display: block; margin: 26px auto 0; transform: rotate(35deg); }
}

@media (max-width: 899px) {
  /* Notes are hung off desktop geometry. On a phone the frames keep their
     label as plain text; the other notes simply don't show. */
  .note--frames { display: block; position: static; width: auto; text-align: center; margin-top: var(--gap-block); }
  .note--frames .note__arrow { display: none; }
  .note--frames .hand { font-size: var(--lead); }
}

/* --------------------------------------------------------------------------
   REDUCED MOTION. Marquee hidden, numerals already at final values, no drift,
   no parallax. Nothing that carries meaning is animation-dependent.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  .marquee { display: none; }
  .pill__dot { animation: none; }

  .frames { animation: none; }

  .sticker { opacity: 1; transform: scale(1) rotate(-6deg); transition: none; }
  .gp__beat .sticker { transform: translateY(-50%) scale(1) rotate(-6deg); }

  /* End states, drawn immediately rather than animated. */
  .seq__rail { transform: scaleX(1); }
  .seq__step--paid .seq__block { opacity: 1; }
  .quote__row { opacity: 1; transform: none; }
  .belief { opacity: 1; transform: none; }
  .mrow__badge { opacity: 1; }
  .mrow--live { transform: none; }
  .trio__mark { opacity: 1; transform: none; }
  .sketch .st { stroke-dasharray: none; stroke-dashoffset: 0; animation: none; }
  .sketch .st--dash { stroke-dasharray: 10 12; }
  .sketch text, .sketch .dot, .sketch .fill-brass, .sketch .fill-paper { opacity: 1; animation: none; }

  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
}

/* --------------------------------------------------------------------------
   HERO BARS. Colour blocks riding the hero's diagonal, the way the reference
   stacks slabs along its band edge. They live in the hero so they paint over
   the next band's wedge; the floating phone (z4) stays above them and the
   headline block (.wrap, z1) never sits under one. preserveAspectRatio="none"
   keeps every slab parallel to the wedge at any viewport width.
   -------------------------------------------------------------------------- */
.hero__bars {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(-1.6 * var(--wedge-h));
  width: 100%;
  height: calc(2.6 * var(--wedge-h));
  z-index: 0;
  display: block;
  pointer-events: none;
}
.hero__bars .bar       { fill: var(--pop); }
.hero__bars .bar--pale { opacity: .38; }
.hero__bars .bar--line { fill: none; stroke: var(--brass); stroke-width: 2; vector-effect: non-scaling-stroke; }

/* The pile's note is part of the scaled composition, so unlike the other
   notes it shows at every width, sized in the stack's own units (1cqw = 7.6px
   at the 760px design width). The handwriting has a 12px floor; the arrow
   scales with the sheets. Kept clear of the dashed sheet: at 25cqw wide it
   ends 5cqw before that sheet's left edge. */
.pile__stack .note--pile {
  display: block;
  position: absolute;
  left: calc(50% - 41cqw);
  top: 46%;
  width: 25cqw;
  text-align: left;
  pointer-events: none;
}
.pile__stack .note--pile .hand { font-size: max(12px, 3.15cqw); line-height: 1.1; color: var(--alert); }
.pile__stack .note--pile .note__arrow { width: 11.8cqw; margin-top: .5cqw; }

/* --------------------------------------------------------------------------
   STICKY INVITE DOCK. Phones only. JS turns it on whenever no other invite
   button, the application or the footer is in view, so it never doubles a
   visible CTA and never sits over a form control. Off-screen when off, and
   inert, so it cannot take focus from there.
   -------------------------------------------------------------------------- */
.dock { display: none; }

@media (max-width: 767px) {
  .dock {
    display: block;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 40;
    padding: var(--sp-3) var(--pad-gutter) calc(var(--sp-3) + env(safe-area-inset-bottom));
    background: var(--paper);
    box-shadow: 0 -1px 0 var(--paper-edge), 0 -10px 30px rgba(46, 38, 24, .12);
    transform: translateY(110%);
  }
  .dock.is-on { transform: none; }
  .dock__btn { min-height: 54px; padding-block: var(--sp-3); }

  @media (prefers-reduced-motion: no-preference) {
    .dock { transition: transform 320ms var(--ease-settle); }
  }
}

/* On the scaled frames (under 1024 the three phones are the desktop frames
   shrunk) the third frame's "No older messages" rule fell below the chat box.
   At that size its text is ~7px anyway; desktop keeps it. */
@media (max-width: 1023px) {
  .frames .phone__empty,
  .frames .phone__divider { display: none; }
}
