/* ==========================================================================
   CarbonLabs — the / page.
   Light CarbonWeb world: white ground, charcoal ink, Raleway, the green→teal
   signature reserved for the one line and the live states. Two set pieces:
   a window-chrome frame for the video agent, and a dark band with a call bar
   for the voice agent. Tokens come from tokens.css; every var carries a
   fallback so a missing token degrades to the brand hex, not to nothing.
   ========================================================================== */

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
/* The hidden attribute must always win. Several state elements here (.window-live, .window-hud,
   .voice-live) carry class display values, and a class's `display: flex` silently overrides the
   UA's `[hidden] { display: none }` — the LIVE pill was showing on an idle window for exactly this
   reason. This is the third time this codebase has hit that trap; the important rule goes first. */
[hidden] { display: none !important; }
body {
  margin: 0;
  font-family: var(--cw-font-sans, 'Raleway', sans-serif);
  color: var(--cw-ink-2, #323031);
  background: #fff;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; }
a { color: inherit; }

:focus-visible { outline: 2px solid var(--cw-teal, #00B0C2); outline-offset: 3px; border-radius: 6px; }

/* ---------------------------------------------------------------- header */
.lab-head {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px clamp(20px, 5vw, 64px);
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid #ECEEF2;
}
.lab-brand { display: inline-flex; align-items: center; gap: 10px; text-decoration: none; }
.lab-tag {
  font: 700 11px/1 var(--cw-font-mono, 'Roboto Mono', monospace);
  letter-spacing: 0.14em; text-transform: uppercase;
  color: #fff; padding: 5px 9px 4px; border-radius: 6px;
  background: linear-gradient(90deg, #12a150, #00919f);
}
.lab-nav { display: flex; align-items: center; gap: clamp(14px, 2.5vw, 28px); }
.lab-nav a {
  font: 600 14px/1 var(--cw-font-sans, 'Raleway', sans-serif);
  text-decoration: none; color: var(--cw-fg-2, #55565A);
}
.lab-nav a:hover { color: var(--cw-ink-2, #323031); }
.lab-nav .lab-cta {
  color: var(--cw-teal-dark, #00828F);
  border: 1.5px solid currentColor; border-radius: 999px; padding: 9px 16px;
}
.lab-nav .lab-cta:hover { background: #E4F6F8; color: var(--cw-teal-dark, #00828F); }

/* ------------------------------------------------------------------ hero */
.hero { padding: clamp(56px, 10vh, 120px) clamp(20px, 5vw, 64px) clamp(40px, 7vh, 88px); max-width: 880px; }
.hero h1 {
  margin: 0 0 18px;
  font-weight: 800; font-size: clamp(38px, 6vw, 72px); line-height: 1.04;
  letter-spacing: -0.025em; color: var(--cw-ink-2, #323031);
}
/* The signature, on the one line that earns it. Stops measured ≥3:1 on white. */
.hero h1 em {
  font-style: normal;
  color: var(--cw-teal-dark, #00828F);
}
.hero p { margin: 0 0 30px; max-width: 56ch; font-size: clamp(15.5px, 1.9vw, 18px); line-height: 1.7; color: var(--cw-fg-2, #55565A); }
.hero-links { display: flex; flex-wrap: wrap; gap: 12px; }

/* --------------------------------------------------------------- buttons */
.btn {
  display: inline-flex; align-items: center; gap: 9px;
  font: 700 15px/1 var(--cw-font-sans, 'Raleway', sans-serif);
  padding: 15px 24px; border-radius: 999px; border: 0;
  text-decoration: none; cursor: pointer;
  transition: transform 140ms ease, box-shadow 140ms ease, background-color 140ms ease;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
.btn-solid { background: var(--cw-teal-dark, #00828F); color: #fff; box-shadow: 0 8px 20px -10px rgba(0, 130, 143, 0.55); }
.btn-solid:hover { background: #00737e; }
.btn-ghost { background: transparent; color: var(--cw-ink-2, #323031); border: 1.5px solid #D6DAE1; }
.btn-ghost:hover { border-color: var(--cw-ink-2, #323031); }

/* ---------------------------------------------------------- offer layout */
.offer {
  display: grid; grid-template-columns: minmax(280px, 5fr) minmax(0, 7fr);
  gap: clamp(28px, 5vw, 72px); align-items: center;
  padding: clamp(48px, 9vh, 110px) clamp(20px, 5vw, 64px);
  max-width: 1280px; margin: 0 auto;
}
.offer-copy h2 { margin: 0 0 14px; font-weight: 800; font-size: clamp(26px, 3.4vw, 40px); letter-spacing: -0.02em; }
.offer-copy > p { margin: 0 0 20px; font-size: 16px; line-height: 1.7; color: var(--cw-fg-2, #55565A); max-width: 46ch; }
.offer-points { margin: 0; padding: 0; list-style: none; display: grid; gap: 10px; }
.offer-points li { position: relative; padding-left: 26px; font-size: 14.5px; line-height: 1.55; color: var(--cw-fg-2, #55565A); }
.offer-points li::before {
  content: ''; position: absolute; left: 0; top: 3px;
  width: 15px; height: 15px; border-radius: 50%;
  background: linear-gradient(135deg, #12a150, #00919f);
}
.offer-points li::after {
  content: ''; position: absolute; left: 4.5px; top: 8px;
  width: 6px; height: 3.5px; border-left: 1.8px solid #fff; border-bottom: 1.8px solid #fff;
  transform: rotate(-45deg);
}

/* -------------------------------------------------- the video window */
.window {
  margin: 0; border-radius: 16px; overflow: hidden;
  border: 1px solid #E3E6EC; background: #fff;
  box-shadow: 0 1px 2px rgba(20, 24, 33, 0.05), 0 24px 48px -24px rgba(20, 24, 33, 0.28);
}
.window-bar {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 14px; background: #F6F7F9; border-bottom: 1px solid #E3E6EC;
}
.window-dots { display: inline-flex; gap: 5px; }
.window-dots i { width: 9px; height: 9px; border-radius: 3px; border: 1.5px solid #C9CED8; }
.window-dots i:first-child { background: linear-gradient(135deg, #12a150, #00919f); border-color: transparent; }
.window-title {
  font: 500 11px/1 var(--cw-font-mono, 'Roboto Mono', monospace);
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--cw-fg-2, #55565A);
}
.window-live {
  margin-left: auto; display: inline-flex; align-items: center; gap: 6px;
  font: 700 11px/1 var(--cw-font-mono, 'Roboto Mono', monospace); letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--cw-green-dark, #2F7D22);
}
.window-live i { width: 8px; height: 8px; border-radius: 50%; background: var(--cw-green, #69D757); }
@media (prefers-reduced-motion: no-preference) {
  .window-live i { animation: pulse 1.6s ease-in-out infinite; }
  @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
}

.window-body { position: relative; aspect-ratio: 16 / 10; background: #101215; }
.window-poster { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% 22%; }
.window-video { position: absolute; inset: 0; }
.window[data-stage="live"] .window-poster { visibility: hidden; }

.window-veil {
  position: absolute; inset: 0; z-index: 2;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  padding-bottom: clamp(20px, 4vh, 36px); gap: 10px;
  background: linear-gradient(180deg, transparent 45%, rgba(10, 12, 14, 0.55) 100%);
}
.btn-speak { background: var(--cw-teal-dark, #00828F); color: #fff; box-shadow: 0 10px 26px -10px rgba(0, 0, 0, 0.5); }
.btn-speak:hover { background: #00737e; }
.btn-speak[disabled] { opacity: 0.75; cursor: wait; transform: none; }
.window-note { margin: 0; font-size: 12.5px; color: rgba(255, 255, 255, 0.85); }

.window-hud {
  position: absolute; inset: auto 0 0 0; z-index: 3;
  display: flex; align-items: center; justify-content: center; gap: 14px;
  padding: 12px; background: linear-gradient(180deg, transparent, rgba(10, 12, 14, 0.72));
}
.hud-btn {
  font: 700 13px/1 var(--cw-font-sans, 'Raleway', sans-serif);
  color: #fff; background: rgba(255, 255, 255, 0.16); border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 999px; padding: 10px 16px; cursor: pointer;
}
.hud-btn:hover { background: rgba(255, 255, 255, 0.26); }
.hud-btn[aria-pressed="true"] { background: #fff; color: var(--cw-ink-2, #323031); }
.hud-end { background: rgba(214, 69, 69, 0.85); border-color: transparent; }
.hud-end:hover { background: #d64545; }
.hud-clock { font: 500 13px/1 var(--cw-font-mono, 'Roboto Mono', monospace); color: rgba(255, 255, 255, 0.9); min-width: 42px; text-align: center; }

/* ---------------------------------------------------- the voice band */
.offer-dark {
  max-width: none; position: relative; color: #fff;
  background:
    radial-gradient(90% 120% at 85% 0%, rgba(0, 145, 159, 0.28), transparent 55%),
    radial-gradient(70% 100% at 10% 100%, rgba(18, 161, 80, 0.18), transparent 60%),
    #16181C;
  /* carbonweb.co's chamfered band: the top edge steps down after the left shoulder, the bottom
     edge steps down before the right shoulder — both cuts on the same 45° slash. The notch depth
     scales with viewport and the extra padding keeps content out of the clipped zones. */
  --notch: clamp(34px, 5vw, 64px);
  --notch-run: calc(var(--notch) * 1.3);
  clip-path: polygon(
    0 0,
    36% 0,
    calc(36% + var(--notch-run)) var(--notch),
    100% var(--notch),
    100% 100%,
    calc(62% + var(--notch-run)) 100%,
    62% calc(100% - var(--notch)),
    0 calc(100% - var(--notch))
  );
  padding-top: calc(clamp(48px, 9vh, 110px) + var(--notch));
  padding-bottom: calc(clamp(48px, 9vh, 110px) + var(--notch));
}
.offer-dark .offer-copy h2 { color: #fff; }
.offer-dark .offer-copy > p { color: rgba(255, 255, 255, 0.78); }
.offer-dark .offer-points li { color: rgba(255, 255, 255, 0.78); }

.voice-panel { display: grid; gap: 14px; justify-items: start; }
.voice-bar {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: stretch;
  width: min(100%, 520px);
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 14px; overflow: hidden;
  backdrop-filter: blur(6px);
}
.voice-pick { display: grid; align-content: center; gap: 2px; padding: 10px 18px; border-right: 1px solid rgba(255, 255, 255, 0.14); }
.voice-pick-label {
  font: 500 10px/1 var(--cw-font-mono, 'Roboto Mono', monospace);
  letter-spacing: 0.14em; text-transform: uppercase; color: rgba(255, 255, 255, 0.55);
}
.voice-pick select {
  appearance: none; -webkit-appearance: none;
  background: transparent url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23ffffff' stroke-width='1.6' fill='none' stroke-linecap='round'/%3E%3C/svg%3E") right center no-repeat;
  border: 0; color: #fff; font: 600 15.5px/1.3 var(--cw-font-sans, 'Raleway', sans-serif);
  padding: 2px 20px 2px 0; cursor: pointer; max-width: 100%;
}
.voice-pick select:focus-visible { outline: 2px solid #7CE5F0; outline-offset: 2px; }
.voice-pick select option { color: #16181C; }

.btn-initiate {
  display: inline-flex; align-items: center; gap: 9px;
  font: 700 15px/1 var(--cw-font-sans, 'Raleway', sans-serif);
  background: #fff; color: #16181C; border: 0; cursor: pointer;
  padding: 0 26px; border-radius: 0;
  transition: background-color 140ms ease;
}
.btn-initiate:hover { background: #E4F6F8; }
.btn-initiate[disabled] { opacity: 0.6; cursor: not-allowed; }
.voice-bar[data-stage="live"] .btn-initiate { background: #d64545; color: #fff; }
.voice-bar[data-stage="live"] .btn-initiate:hover { background: #c23a3a; }
.voice-bar[data-stage="connecting"] .btn-initiate { cursor: wait; }

.voice-note {
  margin: 0; font-size: 12.5px; color: rgba(255, 255, 255, 0.6);
  text-decoration: underline dotted rgba(255, 255, 255, 0.45); text-underline-offset: 4px;
}
.voice-live { display: inline-flex; align-items: center; gap: 12px; font: 600 14px/1 var(--cw-font-sans, 'Raleway', sans-serif); color: rgba(255, 255, 255, 0.9); }
.voice-orb { width: 22px; height: 22px; border-radius: 50%; background: linear-gradient(135deg, #12a150, #00919f); }
@media (prefers-reduced-motion: no-preference) {
  .voice-orb[data-mode="listening"] { animation: breathe 2.2s ease-in-out infinite; }
  .voice-orb[data-mode="speaking"] { animation: breathe 0.7s ease-in-out infinite; }
  @keyframes breathe { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.25); } }
}

/* ---------------------------------------------------------------- footer */
.lab-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  padding: 26px clamp(20px, 5vw, 64px); border-top: 1px solid #ECEEF2;
}
.lab-foot p { margin: 0; font-size: 13px; color: var(--cw-fg-3, #6F6F6F); }
.lab-foot a { color: var(--cw-teal-dark, #00828F); }

/* ------------------------------------------------------------ responsive */
@media (max-width: 900px) {
  .offer { grid-template-columns: 1fr; gap: 26px; }
  .offer-copy > p { max-width: none; }
  .voice-bar { width: 100%; }
}
@media (max-width: 560px) {
  .lab-nav a:not(.lab-cta) { display: none; }
  .voice-bar { grid-template-columns: 1fr; }
  .voice-pick { border-right: 0; border-bottom: 1px solid rgba(255, 255, 255, 0.14); padding: 12px 18px; }
  .btn-initiate { padding: 15px 26px; justify-content: center; }
}

/* ------------------------------------------------------- lab registry ---
   The Google-Labs half of the page: numbered experiments with honest status
   labels. The tags are mono because they are registry entries, not headings;
   status colours reuse the AA-safe brand variants. */
.hero-more {
  display: inline-flex; align-items: center; align-self: center;
  font: 600 14px/1 var(--cw-font-sans, 'Raleway', sans-serif);
  color: var(--cw-teal-dark, #00828F); text-decoration: none; padding: 15px 6px;
}
.hero-more:hover { text-decoration: underline; text-underline-offset: 4px; }

.exp-tag {
  margin: 0 0 12px; display: flex; align-items: center; gap: 8px;
  font: 500 11.5px/1 var(--cw-font-mono, 'Roboto Mono', monospace);
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--cw-fg-3, #6F6F6F);
}
.exp-tag span {
  padding: 4px 8px 3px; border-radius: 6px;
  background: #EEF1F5; color: var(--cw-ink-2, #323031); font-weight: 500;
}
.exp-tag em { font-style: normal; color: var(--cw-green-dark, #2F7D22); }
.exp-tag-dark { color: rgba(255, 255, 255, 0.6); }
.exp-tag-dark span { background: rgba(255, 255, 255, 0.14); color: #fff; }
.exp-tag-dark em { color: var(--cw-green, #69D757); }

.registry { padding: clamp(48px, 9vh, 110px) clamp(20px, 5vw, 64px); max-width: 1280px; margin: 0 auto; }
.registry > h2 { margin: 0 0 12px; font-weight: 800; font-size: clamp(26px, 3.4vw, 40px); letter-spacing: -0.02em; }
.registry-lede { margin: 0 0 34px; max-width: 56ch; font-size: 16px; line-height: 1.7; color: var(--cw-fg-2, #55565A); }
.registry-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 18px; }
.reg-card {
  padding: 22px 22px 24px; border: 1px solid #E3E6EC; border-radius: 14px; background: #fff;
  transition: transform 160ms ease, box-shadow 160ms ease;
}
.reg-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 1px 2px rgba(20, 24, 33, 0.05), 0 18px 34px -20px rgba(20, 24, 33, 0.3);
}
.reg-card h3 { margin: 0 0 8px; font-weight: 700; font-size: 18px; letter-spacing: -0.01em; }
.reg-card p:last-child { margin: 0; font-size: 14px; line-height: 1.65; color: var(--cw-fg-2, #55565A); }
.st { font-style: normal; }
.st-live { color: var(--cw-green-dark, #2F7D22); }
.st-testing { color: var(--cw-teal-dark, #00828F); }
.st-bench { color: #9A6300; }
.registry-note { margin: 30px 0 0; font-size: 14px; color: var(--cw-fg-2, #55565A); }
.registry-note a { color: var(--cw-teal-dark, #00828F); }

/* ------------------------------------------------- scroll reveals ---
   Sections arrive rather than sit. Once each — the observer removes
   itself — and reduced-motion renders everything in place. */
[data-reveal] { opacity: 0; transform: translateY(22px); }
[data-reveal].in {
  opacity: 1; transform: none;
  transition: opacity 640ms cubic-bezier(0.16, 1, 0.3, 1), transform 640ms cubic-bezier(0.16, 1, 0.3, 1);
}
.flow-grid [data-reveal].in:nth-child(2) { transition-delay: 110ms; }
.registry-grid [data-reveal].in:nth-child(2) { transition-delay: 90ms; }
.registry-grid [data-reveal].in:nth-child(3) { transition-delay: 180ms; }
.registry-grid [data-reveal].in:nth-child(4) { transition-delay: 270ms; }
@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; transform: none; }
}

/* ------------------------------------------------------ tilt + glare ---
   The window leans toward the cursor while idle — product-shot physics —
   and locks flat the moment a call is anything but idle. Transform only. */
.window { will-change: transform; transition: transform 420ms cubic-bezier(0.16, 1, 0.3, 1); }
.window.tilting { transition: none; }
.window-glare {
  position: absolute; inset: 0; z-index: 4; pointer-events: none; opacity: 0;
  background: linear-gradient(115deg, transparent 30%, rgba(255, 255, 255, 0.14) 46%, transparent 62%);
  transform: translateX(-40%);
  transition: opacity 300ms ease, transform 600ms cubic-bezier(0.16, 1, 0.3, 1);
}
.window.tilting .window-glare { opacity: 1; transform: translateX(0); }
@media (prefers-reduced-motion: reduce) {
  .window { transition: none; }
  .window-glare { display: none; }
}

/* ------------------------------------------------------ voice waveform ---
   A full-width strip along the bottom of the dark band. Idle: calm bars that
   ripple under the cursor. Live: driven by the agent's real output level. */
.offer-dark { overflow: hidden; }
.voice-wave {
  /* Spans the full bottom INCLUDING the chamfer: the canvas is 92px of wave plus the notch depth,
     and the draw code stands each bar on the clipped edge — flat, down the diagonal, flat — so the
     strip reaches the section's true bottom everywhere. JS reads the notch as offsetHeight - 92. */
  position: absolute; left: 0; right: 0; bottom: 0;
  width: 100%; height: calc(92px + var(--notch, 0px));
  z-index: 1; pointer-events: none; opacity: 0.85;
}
.offer-dark .offer-copy, .offer-dark .voice-panel { position: relative; z-index: 5; }
@media (prefers-reduced-motion: reduce) { .voice-wave { display: none; } }

/* ------------------------------------------------------- the closer ---
   Closing band: the question, the answer, one action. Deliberately reuses
   the hero's type scale rather than inventing a third heading size — the
   page now opens and closes on the same voice, with the two live displays
   between them. Centred, because it is the only section with no second
   column to balance against. */
.closer {
  padding: clamp(56px, 10vh, 120px) clamp(20px, 5vw, 64px);
  max-width: 720px;
  margin: 0 auto;
  text-align: center;
}
.closer h2 {
  margin: 0 0 16px;
  font-weight: 800;
  font-size: clamp(26px, 3.6vw, 42px);
  letter-spacing: -0.02em;
  line-height: 1.1;
}
/* Same emphasis treatment as the hero's <em>, so the two bookend each other. */
.closer h2 em {
  font-style: normal;
  color: var(--cw-green-dark, #2F7D22);
}
.closer > p {
  margin: 0 auto 28px;
  max-width: 58ch;
  font-size: clamp(15.5px, 1.9vw, 17px);
  line-height: 1.7;
  color: var(--cw-fg-2, #55565A);
}
.closer-links { display: flex; justify-content: center; gap: 12px; flex-wrap: wrap; }

/* Three types, three columns. The shared .registry-grid is auto-fit, which was sized for the old
   four-card registry — with three cards it opened a fourth empty track on a wide viewport and left
   the row looking like something had failed to load. Pinned here rather than in .registry-grid so
   the monday one-pager's use of the same class is untouched. */
#types .registry-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 900px) {
  #types .registry-grid { grid-template-columns: repeat(auto-fit, minmax(258px, 1fr)); }
}

/* ---------------------------------------------- page-specific tuning ---
   Kicker under the H1. As a kicker above the title it competed for the first read; below it, it
   answers "built on what?" instead of announcing it. */
.hero-kicker { margin: -12px 0 22px; }

/* Face to Face: pulled up so the agent's face clears the fold without scrolling. The shared .offer
   padding is tuned for a mid-page section; this is the first thing under the hero, so it carries far
   less top room. The window is also nudged up within its own grid cell. */
/* Nudged back down: the -14px lift plus near-zero top padding had it sitting tight under the hero. */
.offer#video { padding-top: clamp(16px, 2.4vh, 38px); }
.offer#video .window { transform: none; }

/* The window has to sit the same distance from the right edge as the H1 does from the left — 64px,
   the shared clamp(20px, 5vw, 64px) page inset. It could not, because .offer is max-width: 1280px
   and centred: on a wide viewport that leaves a couple of hundred pixels of dead margin outside the
   padding, so the window stopped well short of the edge. Dropping the cap makes the section
   full-bleed, which lands both the copy column and the H1 on the same 64px line as a bonus.
   The second column is capped so the window does not balloon with the viewport and push the agent's
   face back below the fold — the reason it was raised in the first place. */
@media (min-width: 900px) {
  .offer#video { max-width: none; grid-template-columns: minmax(280px, 1fr) min(46vw, 640px); }
}

/* Feeling shy?: sized to read as a band rather than a full-height section. The bottom keeps more room
   than the top on purpose — the wave canvas is a fixed 92px plus the notch, and the voice panel has to
   clear it. Taking the bottom much below this starts pushing the Initiate Call button into the waves,
   which is the bug that put that button under text once already. */
.offer-dark {
  padding-top: calc(clamp(30px, 5vh, 60px) + var(--notch));
  /* The taller of the two columns is the copy, not the panel — at 74px its last line crossed into the
     wave strip by a few pixels. Measured up from the overlap rather than guessed. */
  padding-bottom: calc(clamp(86px, 12vh, 130px) + var(--notch));
}

/* Agent-type labels, larger. .exp-tag is 11.5px mono for a quiet metadata line — as the label
   naming each type it was too small to function as the label. Numeral keeps the mono badge; the word
   steps up to the body face so it reads as a title, not a tag. */
.card-label {
  margin: 0 0 10px; display: flex; align-items: center; gap: 10px;
  font-weight: 700; font-size: 15px; letter-spacing: 0.01em;
  color: var(--cw-green-dark, #2F7D22);
}
.card-label span {
  font: 500 12.5px/1 var(--cw-font-mono, 'Roboto Mono', monospace);
  letter-spacing: 0.08em;
  padding: 5px 8px; border-radius: 6px;
  background: var(--cw-green-tint, #EAF7E7); color: var(--cw-green-dark, #2F7D22);
}
/* Equal-length copy still needs equal boxes — stretch cards to the tallest in the row. */
#types .registry-grid { align-items: stretch; }
#types .reg-card { display: flex; flex-direction: column; }

/* The hero was sized as a full-height statement, which pushed the agent's face to the fold line.
   Trimming its vertical padding is what actually lifts the video — #video's own padding was already
   near zero, so there was nothing left to take from it. */
.hero { padding-top: clamp(28px, 4.5vh, 56px); padding-bottom: clamp(20px, 3vh, 40px); }
.hero h1 { line-height: 1.04; }
.hero p { margin-bottom: 22px; }

/* --------------------------------------------------- post-call result ---
   The artifact the video call leaves behind, rendered inside the veil where
   the start button lives — the visitor ends the call and the spec is already
   where their eyes are. Scrolls internally past ~60% height so a long spec
   can never push the start button out of the window frame. */
.window-result {
  width: min(86%, 460px); max-height: 62%; overflow-y: auto;
  margin-bottom: 14px; padding: 14px 16px; text-align: left;
  background: rgba(255, 255, 255, 0.94); border: 1px solid #E3E6EC; border-radius: 12px;
  font-size: 13px; line-height: 1.5; color: var(--cw-fg-2, #55565A);
}
.window-result .result-head {
  margin: 0 0 8px; font-weight: 700; font-size: 13.5px; color: var(--cw-fg-1, #1B1C20);
}
.window-result .result-row { padding: 3px 0; }
.window-result .result-row span {
  display: block; font: 500 10.5px/1.6 var(--cw-font-mono, 'Roboto Mono', monospace);
  letter-spacing: 0.07em; text-transform: uppercase; color: var(--cw-fg-3, #6F6F6F);
}
.window-result .result-row em { font-style: normal; font-size: 11.5px; color: var(--cw-fg-3, #6F6F6F); }
.window-result .result-miss { margin: 8px 0 0; font-size: 12px; color: #A8642A; }

/* Replaces the dead select in the voice bar: same slot, real words. Styled to read as the
   bar's content rather than a control pretending to be configurable. */
.voice-pick-value { font: 600 14px/1.3 var(--cw-font-sans, 'Raleway', sans-serif); color: #fff; }

/* Booking link in the call HUD — green so it reads as the one positive action there. */
.hud-book { background: var(--cw-green-dark, #2F7D22); color: #fff; text-decoration: none; }
.hud-book:hover { background: #276a1c; }

/* ------------------------------------------------- density pass (wide) ---
   At 1920 the video row measured 1080px of copy column holding 441px of text —
   639px of dead white space — beside a window capped at 640px. The copy column
   now hugs its text and the window takes the room instead, which both tightens
   the page and makes the agent bigger. Vertical rhythm comes down ~25% too:
   the old values were tuned at 1440 and read as sparse on a large display. */
@media (min-width: 1200px) {
  .offer#video {
    grid-template-columns: minmax(280px, 560px) minmax(0, 1fr);
    gap: clamp(28px, 3vw, 56px);
    padding-top: clamp(12px, 1.8vh, 28px);
    align-items: center;
  }
  /* Grows with the viewport instead of stopping at 640. Right edge still lands on
     the shared 64px page inset, so it stays aligned with the H1 on the left. */
  .offer#video .window { justify-self: end; width: 100%; max-width: 880px; }

  .hero { padding-bottom: clamp(14px, 2vh, 30px); }
  .offer-dark { padding-top: calc(clamp(24px, 4vh, 48px) + var(--notch)); }
  .registry { padding-top: clamp(40px, 6vh, 72px); padding-bottom: clamp(40px, 6vh, 72px); }
  .closer { padding-top: clamp(40px, 6vh, 76px); padding-bottom: clamp(48px, 7vh, 88px); }
}

/* ------------------------------------------------- live booking panel ---
   Opens as a new tab STACKED ON the agent: same grid area, same box, one layer up.
   Copies the window shell rather than reusing the .window class — `#video .window`
   carries agent-specific rules and inheriting them shrank the agent to 560px.
   Chrome children (.window-bar/.window-dots/.window-title) are generic and shared. */
.book-panel {
  /* Absolute, positioned by JS to sit exactly over the agent. It used to be a grid item, which
     meant opening it re-sized the section's rows and shoved the Face to Face block sideways.
     An overlay participates in no layout at all — the section behind it never moves. */
  position: absolute; z-index: 5;
  display: flex; flex-direction: column; min-width: 0; margin: 0;
  border: 1px solid #E3E6EC; border-radius: 16px; overflow: hidden; background: #fff;
  /* Deeper than the agent's shadow, because it is physically in front of it. */
  box-shadow: 0 2px 6px rgba(20, 24, 33, 0.08), 0 30px 60px -24px rgba(20, 24, 33, 0.45);
}

/* Safari's tab close: no chrome at rest, a soft grey disc under the cursor. */
/* macOS/Safari close: the traffic-light red disc, white glyph. */
.book-close {
  margin-left: auto; display: grid; place-items: center;
  width: 20px; height: 20px; padding: 0; border: 0; border-radius: 50%;
  background: #ff5f57; color: #7d1410; cursor: pointer;
  box-shadow: inset 0 0 0 0.5px rgba(0, 0, 0, 0.14);
  transition: background-color 120ms ease, color 120ms ease;
}
.book-close:hover  { background: #ff4136; color: #fff; }
.book-close:active { background: #e0443e; color: #fff; }

/* Zoomed-out embed so the WHOLE calendar fits with no scrollbar.
   Calendly's inline widget needs roughly 700px of height for the two-column month + slots view,
   and the panel only has ~542px under the title bar. Rather than grow the window (which has to
   stay the same size as the agent), the iframe is laid out at 1/scale of the available box and
   then scaled down — so Calendly still *thinks* it has a big viewport and keeps its wide layout,
   but it renders inside the smaller frame. Absolutely positioned because a transform does not
   change layout size: as a flex child the unscaled box would have overflowed the panel. */
/* No `position` here — the overlay rule above sets `absolute`, and this later declaration was
   overriding it, which put the panel back in flow and collapsed the agent to 560px. `absolute`
   is itself a containing block, so the scaled iframe still anchors correctly. */
.book-panel { --fs: 0.78; --bar-h: 41px; }
.book-panel iframe {
  position: absolute; top: var(--bar-h); left: 0;
  width: calc(100% / var(--fs));
  height: calc((100% - var(--bar-h)) / var(--fs));
  transform: scale(var(--fs));
  transform-origin: top left;
  border: 0; display: block;
}
.book-panel-fallback { display: none; }
.book-panel-fallback a { color: var(--cw-teal-dark, #00828F); }

/* Rises onto the agent rather than fading in place — the motion of a tab being brought forward. */
/* The stack offset. Nudged up and left so the agent's bottom-right corner stays visible behind
   the panel — that peeking edge is the whole reason it reads as a tab in front of another window
   rather than a box that replaced it. */
.book-panel { --book-x: -140px; --book-y: -68px; transform: translate(var(--book-x), var(--book-y)); }

@media (prefers-reduced-motion: no-preference) {
  .book-panel { animation: bookIn 420ms cubic-bezier(0.16, 1, 0.3, 1); }
  /* Ends ON the offset, not on `none` — otherwise the animation resets the stack. */
  @keyframes bookIn {
    from { opacity: 0; transform: translate(var(--book-x), calc(var(--book-y) + 26px)) scale(0.97); }
    to   { opacity: 1; transform: translate(var(--book-x), var(--book-y)); }
  }
}

/* The section is just the positioning context now. Nothing about the grid changes when booking
   opens — that was what made the Face to Face column jump. */
#video { position: relative; }

@media (max-width: 900px) {

  /* Single column: the panel still stacks on the agent, both in column one. */
  .book-panel { --book-x: 0px; --book-y: 0px; }
  .book-panel { --book-x: 0px; --book-y: 0px; }
  .book-panel iframe { min-height: 560px; }
}

/* ----------------------------------------------- hero waveform (scroll) ---
   Decorative twin of the voice section's strip, parked in the hero's top-right.
   Behind the type (z-index 0 against the hero's own stacking) and pointer-inert,
   so it can never intercept a click on the CTAs. Hidden on narrow screens where
   it would collide with the headline instead of sitting beside it. */
.hero { position: relative; }
.hero > * { position: relative; z-index: 1; }
#labMain { position: relative; }
.hero-wave {
  /* A VERTICAL strip: starts just under the header (level with "Book a demo") and runs down to
     roughly where the Face to Face section begins. Narrow, because the bars now extend leftward
     out of the right gutter rather than marching across the page. */
  /* Sits lower than the header now rather than tucked right under it. Height is trimmed by roughly
     the same amount as the drop, so the strip's bottom edge only moves down a little and the clear
     space above Face to Face survives. */
  position: absolute; top: clamp(40px, 6vh, 72px);
  right: clamp(20px, 4vw, 64px);   /* the page's own gutter, not the hero's narrow box */
  /* Longest bar reaches ~2/5 of the way from the right gutter toward the Face to Face section's
     left edge (both sit on the same 64px page inset), so ~40vw at a wide viewport. */
  /* Wider than the longest bar by design: the wave and the hover bulge both need headroom, and
     a canvas sized to the resting length is what made the top bars go flat against the edge. */
  width: clamp(300px, 44vw, 820px); height: clamp(290px, 51vh, 560px);
  z-index: 0; pointer-events: none; opacity: 0.9;
}
@media (max-width: 1100px) { .hero-wave { display: none; } }
/* Reduced motion keeps the bars — they just stop responding to scroll (handled in JS). */

/* ===========================================================================
   Agent types in the dark band (2026-08-07, Doug).
   The chamfered dark section used to belong to the phone demo. With that gone
   the page ran light the whole way down and lost its one break; the agent
   types take the band instead. Same chamfer geometry and palette as
   .offer-dark so it reads as the same device, not a second dark style.
   =========================================================================== */
.registry-dark {
  max-width: none;            /* full-bleed: .registry caps at 1280px, which would band only the middle */
  position: relative;
  color: #fff;
  overflow: hidden;
  background:
    radial-gradient(90% 120% at 85% 0%, rgba(0, 145, 159, 0.28), transparent 55%),
    radial-gradient(70% 100% at 10% 100%, rgba(18, 161, 80, 0.18), transparent 60%),
    #16181C;
  --notch: clamp(34px, 5vw, 64px);
  --notch-run: calc(var(--notch) * 1.3);
  clip-path: polygon(
    0 0,
    36% 0,
    calc(36% + var(--notch-run)) var(--notch),
    100% var(--notch),
    100% 100%,
    calc(62% + var(--notch-run)) 100%,
    62% calc(100% - var(--notch)),
    0 calc(100% - var(--notch))
  );
  /* The extra padding keeps content clear of the two clipped corners. */
  padding-top: calc(clamp(48px, 9vh, 110px) + var(--notch));
  padding-bottom: calc(clamp(48px, 9vh, 110px) + var(--notch));
  /* No inner wrapper exists to constrain the copy, so the inline padding centres it:
     the page gutter, or half the leftover once past 1280px — whichever is larger. */
  padding-inline: max(clamp(20px, 5vw, 64px), calc((100% - 1280px) / 2));
}
.registry-dark > h2 { color: #fff; }
.registry-dark .registry-lede { color: rgba(255, 255, 255, 0.78); }
/* Cards belong to the band rather than sitting on top of it: a translucent lift off
   the same near-black, not a white panel. Contrast is carried by the text, which is
   why the body copy is .74 white — measured ~9:1 on the card, well clear of the floor
   — instead of the mid-grey it uses on a white page, which would have been unreadable
   here. */
.registry-dark .reg-card {
  background: rgba(255, 255, 255, 0.055);
  border-color: rgba(255, 255, 255, 0.10);
  padding: 26px 26px 28px;
}
.registry-dark .reg-card h3 { color: #fff; }
.registry-dark .reg-card p:last-child { color: rgba(255, 255, 255, 0.74); }
.registry-dark .reg-card:hover {
  background: rgba(255, 255, 255, 0.085);
  border-color: rgba(255, 255, 255, 0.18);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .22), 0 22px 44px -24px rgba(0, 0, 0, .65);
}

/* Spacing. The band's chamfer eats into its own bottom edge, so the closer was sitting
   almost against the diagonal. The band gets breathing room beneath it and the closer
   opens with more air of its own — measured from the clipped edge, not the box. */
.registry-dark { margin-bottom: clamp(28px, 5vh, 64px); }
.registry-dark .registry-lede { margin-bottom: clamp(30px, 4.5vh, 46px); }
.registry-dark .registry-grid { gap: clamp(18px, 2vw, 26px); }
.registry-dark ~ .closer,
.closer { padding-top: clamp(72px, 12vh, 148px); }

/* ===========================================================================
   /voice — the two-direction call flows live below.
   The hero that used to sit above them (.hero-split / .hero-call) was replaced
   by .vhero, and its rules were removed along with it.
   =========================================================================== */

/* ===========================================================================
   /voice — "One line. Two directions."
   Two opposed panels instead of a card grid: the direction is the taxonomy, so
   the layout carries it. The arrows point into and out of a baseline, which is
   the whole idea in one glyph. The custom build sits underneath as a band —
   it is not a third direction, it is the same two wired to your stack.
   =========================================================================== */
.flow {
  max-width: 1280px;
  margin: 0 auto;
  padding: clamp(48px, 9vh, 104px) clamp(20px, 5vw, 64px);
}
.flow-head { max-width: 68ch; margin-bottom: clamp(28px, 4.5vh, 52px); }
.flow-head h2 {
  margin: 0 0 14px;
  font-weight: 800; font-size: clamp(30px, 4.2vw, 48px); line-height: 1.08;
  letter-spacing: -0.022em; color: var(--cw-ink-2, #323031);
}
/* Solid, not gradient: the h1 above carries the page's one gradient as its established
   signature, and repeating it on every heading turns a signature into a texture. */
.flow-head h2 em { font-style: normal; color: var(--cw-teal-dark, #00828F); }
.flow-lede { margin: 0; color: var(--cw-fg-2); font-size: clamp(15px, 1.9vw, 18px); line-height: 1.6; }

.flow-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(16px, 2.4vw, 30px);
}

.flow-card {
  display: flex; flex-direction: column;
  padding: clamp(22px, 3.2vh, 38px);
  border: 1px solid var(--cw-border-1, #E1E7F0);
  border-radius: 20px;
  background: #fff;
  box-shadow: 0 1px 2px rgba(16, 24, 40, .03), 0 14px 34px -20px rgba(16, 24, 40, .18);
}
/* The two arrows are mirror images — in points down to the line, out points up off it. */
/* The direction arrow reads as part of the title, not as a badge above it: one glyph,
   optically centred on the cap height rather than the line box. */
.flow-title {
  display: flex; align-items: baseline; gap: 11px;
  margin: 0 0 10px;
  font-weight: 700; font-size: clamp(20px, 2.4vw, 26px); letter-spacing: -0.015em;
  text-wrap: balance;
  color: var(--cw-ink-2, #323031);
}
.flow-arrow { flex: none; align-self: center; color: var(--cw-teal-dark, #00828F); }
.flow-card > p { margin: 0 0 20px; color: var(--cw-fg-2); line-height: 1.62; }

/* The use cases are a real list, not prose — they are the part people scan for
   their own job, so they get their own rhythm and a hairline between each. */
.flow-list { list-style: none; margin: auto 0 0; padding: 0; }
.flow-list li {
  padding: 11px 0 11px 26px;
  position: relative;
  border-top: 1px solid var(--cw-border-1, #E1E7F0);
  font-size: clamp(14px, 1.6vw, 15.5px);
  color: var(--cw-fg-1);
}
.flow-list li::before {
  content: '';
  position: absolute; left: 4px; top: 50%;
  width: 7px; height: 7px; margin-top: -3.5px;
  border-radius: 50%;
  background: var(--cw-teal, #00B0C2);
}

.flow-custom {
  margin-top: clamp(16px, 2.4vw, 30px);
  padding: clamp(24px, 3.4vh, 40px) clamp(24px, 3.6vw, 46px);
  border-radius: 20px;
  color: #fff;
  background:
    radial-gradient(80% 140% at 92% 0%, rgba(0, 145, 159, .30), transparent 58%),
    radial-gradient(70% 120% at 6% 100%, rgba(18, 161, 80, .20), transparent 62%),
    #16181C;
}
.flow-custom h3 {
  margin: 0 0 10px;
  font-weight: 700; font-size: clamp(19px, 2.2vw, 24px); letter-spacing: -0.012em; color: #fff;
}
.flow-custom p { margin: 0; max-width: 76ch; color: rgba(255, 255, 255, .82); line-height: 1.62; }

@media (max-width: 860px) {
  .flow-grid { grid-template-columns: 1fr; }
}

/* ===========================================================================
   The Labs hub — "/" (2026-08-10, Doug).
   Built from the "Carbon Labs" comp: a washed hero over a bench of tilted
   experiment cards, then a call-type picker. The live cards are doors — the
   demos themselves live on /conversational-ai and /voice.
   =========================================================================== */

/* ---- hero -------------------------------------------------------------- */
.hub-hero {
  position: relative;
  max-width: 1280px; margin: 0 auto;
  padding: clamp(48px, 9vh, 104px) clamp(20px, 5vw, 64px) clamp(20px, 3vh, 34px);
  text-align: center;
}
/* The brand ramp, on the lab's name only. Deliberately the DARK end of it: the token
   gradient (#00B0C2 → #69D757) measures 2.5:1 and 1.9:1 on white and fails large-text
   contrast at both stops, which is not a trade worth making on a page headline. */
.hub-brand {
  background: linear-gradient(135deg, #12a150 0%, #00919f 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.hub-hero h1 {
  margin: 0 auto 18px;
  max-width: 18ch;
  font-weight: 800; font-size: clamp(36px, 5.6vw, 66px); line-height: 1.06;
  letter-spacing: -0.028em; text-wrap: balance;
  color: var(--cw-ink-2, #323031);
}
.hub-lede {
  margin: 0 auto; max-width: 62ch;
  font-size: clamp(16px, 2vw, 19px); line-height: 1.6; color: var(--cw-fg-2, #55565A);
}

/* ---- the bench --------------------------------------------------------- */
/* The outer cards sit two steps off centre, which is past the viewport on a narrow
   screen and was adding a horizontal scrollbar. `clip` rather than `hidden` because
   hidden on one axis forces a scroll container on the other, and the cards' shadows
   and tilt need to overflow vertically. Applied at the page rather than the padded
   wrapper so cards still bleed to the screen edge instead of stopping at the gutter. */
/* The gradient field runs the whole page rather than stopping under the hero, so the
   bench and the booking box below it sit in the same light. The lights are pinned to a
   900px band at the top via background-size; the tints carry on to the bottom. */
.lab-hub {
  position: relative; overflow-x: clip;
  /* Not a margin on the last child: that collapses out of main and takes the strip
     above the footer out of the gradient with it. */
  padding-bottom: clamp(56px, 10vh, 116px);
}
.lab-hub::before {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-color: #fff;
  background-image:
    radial-gradient(54% 66% at 8% 18%, rgba(0, 176, 194, .50), transparent 72%),
    radial-gradient(52% 62% at 92% 10%, rgba(105, 215, 87, .52), transparent 72%),
    linear-gradient(180deg, #F2F8FA 0%, rgba(255, 255, 255, 0) 100%),
    linear-gradient(0deg, rgba(0, 145, 159, .20) 0%, rgba(255, 255, 255, 0) 46%);
  background-size: 100% 900px, 100% 900px, 100% 900px, 100% 100%;
  background-position: top, top, top, bottom;
  background-repeat: no-repeat;
}
.lab-hub > * { position: relative; z-index: 1; }
.bench-wrap { padding: 0 clamp(20px, 5vw, 64px) clamp(10px, 2vh, 24px); }
.bench {
  position: relative;
  height: clamp(430px, 58vh, 520px);
  margin: 0 auto;
  touch-action: pan-y;                 /* horizontal belongs to the drag */
  cursor: grab;
}
.bench.is-dragging { cursor: grabbing; }

.frame {
  position: absolute; top: 50%; left: 50%;
  width: min(360px, 78vw);
  display: flex; flex-direction: column;
  border-radius: 20px;
  background: #fff;
  border: 1px solid var(--cw-border-1, #E1E7F0);
  box-shadow: 0 1px 2px rgba(16, 24, 40, .04), 0 26px 54px -30px rgba(16, 24, 40, .40);
  text-decoration: none;
  overflow: hidden;
  will-change: transform;
  /* No transition until the first layout has been placed. Without this every load
     animates all six cards out from the centre, because they start untransformed and
     the first paint is itself a transition — and if animations are throttled (a
     backgrounded tab) they never arrive at all and the bench renders stacked. */
  transition: none;
}
.bench.is-ready .frame {
  transition: transform 480ms cubic-bezier(.16,1,.3,1), opacity 480ms cubic-bezier(.16,1,.3,1),
              box-shadow 260ms cubic-bezier(.16,1,.3,1);
}
/* While dragging, the pointer is the clock — easing would lag behind the finger. */
.bench.is-ready.is-dragging .frame { transition: none; }
@media (prefers-reduced-motion: reduce) {
  .bench.is-ready .frame { transition: opacity 200ms linear; }
}
/* Every visible card takes a pointer: the centre one opens its page, the turned ones
   bring themselves to the front (see the capture-phase click handler on the page). Cards
   further out than a slot carry the `hidden` attribute, so they are not clickable at all.
   The prev/next buttons remain the keyboard and screen-reader path to every card. */
.frame { cursor: pointer; }
/* A centred card with nothing to open is not a control. */
.frame.is-pending.is-centre { cursor: default; }
a.frame.is-centre:hover {
  box-shadow: 0 1px 2px rgba(16, 24, 40, .05), 0 34px 66px -30px rgba(16, 24, 40, .48);
}
a.frame.is-centre:hover .frame-action { gap: 12px; }
a.frame:focus-visible { outline: 2px solid var(--cw-teal, #00B0C2); outline-offset: 4px; }

/* Inset. Flush to the card's edges the media read as the card's own background rather
   than as a thing sitting in a frame; the padding plus a hairline gives it an edge. */
.frame-media { position: relative; padding: 10px 10px 0; }
.frame-media > img,
.frame-media > video,
.frame-wave,
.frame-pending {
  display: block; width: 100%;
  aspect-ratio: 16 / 10;
  border-radius: 13px;
  border: 1px solid rgba(16, 24, 40, .11);
  overflow: hidden;
}
.frame-media > img,
.frame-media > video { object-fit: cover; }

/* The voice card has no still to show, so it shows what it sounds like. Static SVG
   rather than a canvas — six of these on one page should not each own a draw loop. */
.frame-wave {
  display: grid; place-items: center;
  padding: 0 18px;
  background:
    radial-gradient(90% 120% at 82% 4%, rgba(0, 145, 159, .34), transparent 58%),
    radial-gradient(72% 104% at 8% 96%, rgba(18, 161, 80, .22), transparent 62%),
    #16181C;
}
.frame-wave svg { width: 100%; height: 58%; }
.frame-wave rect {
  fill: rgba(120, 232, 214, .82);
  /* scaleY rather than the height attribute: it is a compositor-only property, so 34 bars
     animate without laying out anything. fill-box makes the origin the bar itself, so each
     one grows from its own middle instead of the SVG's. */
  transform-box: fill-box;
  transform-origin: 50% 50%;
  animation: wave-bar 1.5s ease-in-out infinite alternate;
}
@keyframes wave-bar {
  from { transform: scaleY(0.42); }
  to   { transform: scaleY(1.1); }
}
@media (prefers-reduced-motion: reduce) {
  .frame-wave rect { animation: none; }
}

/* Unbuilt experiments get a drafting hatch: plainly a placeholder, not a broken image. */
.frame-pending {
  background:
    repeating-linear-gradient(-45deg, #F4F6FA 0 11px, #EDF0F6 11px 22px);
}

/* The sales-coach card shows what the drill hands back: a scorecard ring. Same dark
   ground as the voice card so the two live "no still" cards read as one family. */
.frame-ring {
  position: relative;
  display: grid; place-items: center;
  aspect-ratio: 16 / 10; width: 100%;
  border-radius: 13px; border: 1px solid rgba(16, 24, 40, .11); overflow: hidden;
  background:
    radial-gradient(90% 120% at 82% 4%, rgba(0, 145, 159, .34), transparent 58%),
    radial-gradient(72% 104% at 8% 96%, rgba(18, 161, 80, .22), transparent 62%),
    #16181C;
}
.frame-ring svg { width: 54%; height: auto; transform: rotate(-90deg); }
.frame-ring circle { fill: none; stroke-width: 9; }
.frame-ring-track { stroke: rgba(255, 255, 255, .12); }
.frame-ring-arc { stroke: rgba(120, 232, 214, .95); stroke-linecap: round; }
.frame-ring-num {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -62%);
  font-size: 30px; font-weight: 800; letter-spacing: -0.03em; color: #fff;
}
.frame-ring-lbl {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, 72%);
  font: 700 9.5px/1 var(--cw-font-mono, 'Roboto Mono', monospace); letter-spacing: .14em; text-transform: uppercase;
  color: rgba(120, 232, 214, .95);
}

.frame-badge {
  position: absolute; top: 20px; right: 20px;
  padding: 6px 11px; border-radius: 999px;
  font: 500 10px/1 var(--cw-font-mono, 'Roboto Mono', monospace);
  letter-spacing: .13em; text-transform: uppercase;
  color: var(--cw-ink-2, #323031);
  background: rgba(255, 255, 255, .94);
  border: 1px solid rgba(16, 24, 40, .08);
  box-shadow: 0 1px 2px rgba(16, 24, 40, .06);
}
.frame-badge.is-soon { color: var(--cw-fg-3, #676879); }

.frame-body { padding: 20px 22px 24px; }
.frame-body h2 {
  margin: 0 0 9px;
  font-weight: 800; font-size: 21px; letter-spacing: -0.018em; text-wrap: balance;
  color: var(--cw-ink-2, #323031);
}
.frame-body p {
  margin: 0; font-size: 14px; line-height: 1.6; color: var(--cw-fg-2, #55565A);
}
.frame-action {
  display: inline-flex; align-items: center; gap: 8px;
  margin-top: 16px;
  font-weight: 700; font-size: 14px; color: var(--cw-teal-dark, #00828F);
  transition: gap 200ms cubic-bezier(.16,1,.3,1);
}
/* An unbuilt card is present but recessed, so the bench reads as "two of these work". */
.frame.is-pending { background: #FCFDFE; }
.frame.is-pending .frame-body h2 { color: var(--cw-fg-1, #333); }

.bench-nav {
  display: flex; align-items: center; justify-content: center; gap: 18px;
  padding-top: clamp(14px, 2vh, 24px);
}
.bench-btn {
  display: grid; place-items: center;
  width: 44px; height: 44px; border-radius: 50%;
  border: 1px solid var(--cw-border-1, #E1E7F0);
  background: #fff; color: var(--cw-ink-2, #323031);
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(16, 24, 40, .05);
  transition: background 180ms ease, border-color 180ms ease, opacity 180ms ease;
}
.bench-btn:hover:not(:disabled) { background: var(--cw-bg-1, #F6F7FB); border-color: var(--cw-border-3, #C5C7D0); }
.bench-btn:disabled { opacity: .38; cursor: default; }
.bench-count {
  margin: 0; min-width: 6ch; text-align: center;
  font: 500 12px/1 var(--cw-font-mono, 'Roboto Mono', monospace);
  letter-spacing: .1em; color: var(--cw-fg-3, #676879);
}

/* ---- join the experiment ----------------------------------------------- */
/* One claim, one action, centred. This replaced a five-chip picker whose branches all
   ended at the same booking link — the choosing was work for the visitor and told us
   nothing. */
.join {
  width: min(860px, calc(100% - clamp(40px, 10vw, 128px)));
  margin: clamp(20px, 4vh, 48px) auto 0;
  padding: clamp(40px, 7vh, 76px) clamp(28px, 5vw, 64px);
  border: 1px solid rgba(16, 24, 40, .10);
  border-radius: 26px;
  background: rgba(255, 255, 255, .78);
  box-shadow: 0 1px 2px rgba(16, 24, 40, .04), 0 28px 62px -36px rgba(16, 24, 40, .34);
  text-align: center;
}
.join h2 {
  margin: 0 0 16px;
  font-weight: 800; font-size: clamp(28px, 3.8vw, 44px); line-height: 1.1;
  letter-spacing: -0.022em; text-wrap: balance; color: var(--cw-ink-2, #323031);
}
.join > p {
  margin: 0 auto 30px; max-width: 56ch;
  font-size: clamp(15.5px, 1.9vw, 17px); line-height: 1.66; color: var(--cw-fg-2, #55565A);
}

/* ===========================================================================
   /voice — the Voice AI product page (2026-08-10, Doug).
   Built from the "Carbon Voice AI" comp. The comp's hero sits on a stock photo
   of someone on a headset; there is no licensed photo in this repo, so the hero
   is the dark ground plus the live waveform — which is also the more honest
   visual for the product you HEAR rather than watch.
   =========================================================================== */

/* ---------------------------------------------------------------- hero --- */
.vhero {
  position: relative;                 /* the booking overlay anchors here */
  overflow: hidden;
  color: #fff;
  padding: clamp(56px, 11vh, 132px) clamp(20px, 5vw, 64px) clamp(64px, 12vh, 140px);
  background:
    radial-gradient(80% 130% at 88% 0%, rgba(0, 145, 159, .34), transparent 58%),
    radial-gradient(70% 120% at 6% 100%, rgba(18, 161, 80, .22), transparent 62%),
    #15171C;
}
/* Full width and anchored to the floor of the hero: the wave is the hero's
   photograph. Low enough opacity that the copy never has to fight it. */
/* A floor, not a backdrop. At full height the bars ran straight through the body copy
   and made it unreadable; at a low enough opacity to fix that they vanished into
   #15171C entirely (measured: 166k opaque pixels that could not be seen). So the strip
   is short, sits under the copy, and is masked to fade out upward — legible copy and a
   visible wave, instead of trading one for the other. */
.vhero-wave {
  position: absolute; inset: auto 0 0 0;
  width: 100%; height: clamp(120px, 20vh, 176px);
  opacity: .7; pointer-events: none; z-index: 0;
  -webkit-mask-image: linear-gradient(to top, #000 42%, transparent 100%);
  mask-image: linear-gradient(to top, #000 42%, transparent 100%);
}
.vhero-inner {
  position: relative; z-index: 1;
  max-width: 1280px; margin: 0 auto;
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(300px, 42%);
  gap: clamp(28px, 5vw, 80px); align-items: center;
}
.vhero-copy h1 {
  margin: 0 0 20px;
  text-wrap: balance;
  font-weight: 800; font-size: clamp(38px, 5.6vw, 68px); line-height: 1.04;
  letter-spacing: -0.028em; color: #fff;
}
/* The lighter end of the brand ramp — the teal→green used on white sits too dark
   on this ground to read as emphasis. */
.vhero-copy h1 em {
  font-style: normal;
  /* The brand teal rather than teal-dark: on #15171C the dark end drops to ~1.9:1.
     This measures 7.1:1, which clears the floor for body text, never mind display. */
  color: var(--cw-teal, #00B0C2);
}
.vhero-copy > p {
  margin: 0 0 30px; max-width: 48ch;
  font-size: clamp(15.5px, 1.9vw, 18px); line-height: 1.66; color: rgba(255, 255, 255, .78);
}
/* The solid CTA is built for a white page — its own white text on the brand teal is
   fine, but the hover state slides green under it and the whole pill goes light. On
   this ground it needs no change beyond sitting above the wave. */
.vhero-copy .btn-solid { position: relative; z-index: 1; }

/* The live line, raised off the hero on its own surface so it reads as a control
   panel rather than more hero furniture. */
.vhero-call {
  padding: clamp(18px, 2.6vw, 28px);
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: 18px;
  background: rgba(255, 255, 255, .045);
}
.vhero-call-label {
  margin: 0 0 14px;
  font: 500 11.5px/1 var(--cw-font-mono, 'Roboto Mono', monospace);
  letter-spacing: .12em; text-transform: uppercase; color: rgba(255, 255, 255, .55);
}
.vhero-call .voice-panel { justify-items: stretch; }
.vhero-call .voice-note,
.vhero-call .voice-pick-value { color: rgba(255, 255, 255, .82); }
.vhero-call .voice-pick-label { color: rgba(255, 255, 255, .55); }

@media (max-width: 900px) {
  .vhero-inner { grid-template-columns: 1fr; gap: clamp(24px, 5vh, 40px); }
}

/* ------------------------------------------------- what one call does --- */
/* One panel split by hairlines rather than four separate cards: the four beats are
   one continuous call, and four floating boxes would read as four choices. */
.vpipe {
  max-width: 1280px; margin: 0 auto;
  padding: clamp(40px, 7vh, 84px) clamp(20px, 5vw, 64px) 0;
}
.vpipe-grid {
  margin: 0; padding: 0; list-style: none;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  border: 1px solid var(--cw-border-1, #E1E7F0);
  border-radius: 20px;
  background: var(--cw-bg-1, #F6F7FB);
  overflow: hidden;
}
.vpipe-step {
  padding: clamp(22px, 2.6vw, 34px) clamp(18px, 2vw, 28px);
  border-left: 1px solid var(--cw-border-1, #E1E7F0);
}
.vpipe-step:first-child { border-left: 0; }
.vpipe-n {
  margin: 0 0 12px;
  font: 500 11px/1 var(--cw-font-mono, 'Roboto Mono', monospace);
  letter-spacing: .14em; text-transform: uppercase; color: var(--cw-fg-3, #676879);
}
.vpipe-step h3 {
  margin: 0 0 10px;
  font-weight: 700; font-size: clamp(16px, 1.7vw, 18px); letter-spacing: -0.01em;
  color: var(--cw-ink-2, #323031);
}
.vpipe-body { margin: 0; font-size: 14px; line-height: 1.6; color: var(--cw-fg-2, #55565A); }

@media (max-width: 1000px) {
  .vpipe-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* With two per row the third and fourth need a rule above them, and the left rule
     has to reset at the start of each row instead of only on the first cell. */
  .vpipe-step:nth-child(odd) { border-left: 0; }
  .vpipe-step:nth-child(n + 3) { border-top: 1px solid var(--cw-border-1, #E1E7F0); }
}
@media (max-width: 620px) {
  .vpipe-grid { grid-template-columns: 1fr; }
  .vpipe-step { border-left: 0; }
  .vpipe-step + .vpipe-step { border-top: 1px solid var(--cw-border-1, #E1E7F0); }
}

/* ------------------------------------------------ the board as backend --- */
.vboard {
  max-width: 1280px; margin: 0 auto;
  padding: clamp(40px, 8vh, 96px) clamp(20px, 5vw, 64px);
  display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: clamp(28px, 5vw, 72px); align-items: center;
}
.vboard-copy h2 {
  margin: 0 0 16px;
  text-wrap: balance;
  font-weight: 800; font-size: clamp(28px, 3.8vw, 44px); line-height: 1.1;
  letter-spacing: -0.022em; color: var(--cw-ink-2, #323031);
}
.vboard-copy h2 em { font-style: normal; color: var(--cw-teal-dark, #00828F); }
.vboard-copy > p {
  margin: 0 0 24px; max-width: 48ch;
  font-size: 16px; line-height: 1.68; color: var(--cw-fg-2, #55565A);
}
.vboard-points { margin: 0; padding: 0; list-style: none; display: grid; gap: 12px; }
.vboard-points li {
  position: relative; padding-left: 26px;
  font-size: 14.5px; line-height: 1.55; color: var(--cw-fg-2, #55565A);
}
.vboard-points li::before {
  content: ''; position: absolute; left: 0; top: 3px;
  width: 15px; height: 15px; border-radius: 50%;
  background: linear-gradient(135deg, #12a150, #00919f);
}
.vboard-points li::after {
  content: ''; position: absolute; left: 4.5px; top: 8px;
  width: 6px; height: 3.5px; border-left: 1.8px solid #fff; border-bottom: 1.8px solid #fff;
  transform: rotate(-45deg);
}

/* An illustration of the output, at monday's own radii (7px on a board card). */
.vboard-mock {
  margin: 0; overflow: hidden;
  border: 1px solid var(--cw-border-1, #E1E7F0); border-radius: 12px;
  background: #fff;
  box-shadow: 0 1px 2px rgba(16, 24, 40, .04), 0 20px 44px -26px rgba(16, 24, 40, .28);
}
.vboard-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 13px 16px; border-bottom: 1px solid var(--cw-border-1, #E1E7F0);
  background: var(--cw-bg-1, #F6F7FB);
}
.vboard-name { font-weight: 700; font-size: 13.5px; color: var(--cw-ink-2, #323031); }
/* Says plainly that this is a mock. Without it a realistic board reads as a screenshot
   of somebody's live data. */
.vboard-tag {
  font: 500 10.5px/1 var(--cw-font-mono, 'Roboto Mono', monospace);
  letter-spacing: .1em; text-transform: uppercase; color: var(--cw-fg-3, #676879);
  padding: 5px 9px; border: 1px solid var(--cw-border-1, #E1E7F0); border-radius: 6px;
  background: #fff;
}
/* Scrolls inside the frame rather than being clipped by it. min-width keeps the four
   columns legible instead of crushing them to fit. */
.vboard-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.vboard-table { width: 100%; min-width: 400px; border-collapse: collapse; font-size: 13.5px; }
.vboard-table th {
  padding: 11px 16px; text-align: left;
  font: 500 10.5px/1 var(--cw-font-mono, 'Roboto Mono', monospace);
  letter-spacing: .1em; text-transform: uppercase; color: var(--cw-fg-3, #676879);
  border-bottom: 1px solid var(--cw-border-1, #E1E7F0);
}
.vboard-table td {
  padding: 13px 16px; color: var(--cw-fg-2, #55565A);
  border-bottom: 1px solid var(--cw-bg-3, #E3E5EF);
}
.vboard-table tr:last-child td { border-bottom: 0; }
/* monday's item cell carries a colour bar at the row's head — the one detail that
   makes a plain table read as a board. */
.vboard-item {
  position: relative; padding-left: 24px !important;
  font-weight: 600; color: var(--cw-ink-2, #323031) !important;
}
.vboard-item::before {
  content: ''; position: absolute; left: 10px; top: 50%;
  width: 4px; height: 20px; margin-top: -10px; border-radius: 2px;
  background: linear-gradient(180deg, #12a150, #00919f);
}
.vboard-pill {
  display: inline-block; padding: 4px 10px; border-radius: 6px;
  font-size: 12px; font-weight: 600;
  background: var(--cw-bg-3, #E3E5EF); color: var(--cw-fg-2, #55565A);
}
.vboard-pill.is-done { background: rgba(0, 200, 117, .16); color: #116846; }
.vboard-foot {
  margin: 0; padding: 12px 16px;
  border-top: 1px solid var(--cw-border-1, #E1E7F0);
  background: var(--cw-bg-1, #F6F7FB);
  font-size: 12.5px; color: var(--cw-fg-3, #676879);
}

@media (max-width: 960px) {
  .vboard { grid-template-columns: 1fr; }
}
