/* ============================================================================
   Echo — TTS cache for Pipecat

   Design system: a painted day sky.

   The ground is the Futwork deck's own sky — pale cerulean and cloud white —
   with a living field of brushstrokes moving through it (see field.js). Van
   Gogh's skies are a vector field made visible, every stroke laid along a
   flow; sound travelling through air is a field too, so the motif is the
   subject rather than decoration on top of it. The daylight paintings are the
   reference rather than the night ones: white and cream cloud strokes over
   blue, with wheat-gold and green for warmth.

   No neon. Colour comes from the deck: sky, cloud, navy, and the greens.
   ========================================================================= */

@font-face { font-family: "Lato"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("../fonts/lato-latin-400-normal.woff2") format("woff2"); }
@font-face { font-family: "Lato"; font-style: italic; font-weight: 400; font-display: swap;
  src: url("../fonts/lato-latin-400-italic.woff2") format("woff2"); }
@font-face { font-family: "Lato"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("../fonts/lato-latin-700-normal.woff2") format("woff2"); }
@font-face { font-family: "Lato"; font-style: normal; font-weight: 900; font-display: swap;
  src: url("../fonts/lato-latin-900-normal.woff2") format("woff2"); }

:root {
  /* the sky, sampled from the deck's own pages */
  --sky: #bee2f9;
  --sky-page: #e9f4fe;   /* the deck's own page tint, for surfaces */
  --cloud: #fbfcfe;
  --sky-2: #d8eafd;
  --sky-deep: #bcdcf8;

  /* ink, sampled from the deck's wordmark */
  --ink: #001b30;
  --ink-2: #3f5b74;
  /* The quiet grey. Kept dark, and only a little lighter than --ink-2: on a
     painted ground a pale grey at small sizes simply disappears, whatever its
     contrast ratio says. */
  --ink-3: #44607a;
  --line: rgba(0, 27, 48, .1);
  --line-2: rgba(0, 27, 48, .17);

  /* Light, happy tints of the deck's colours. Everything that carries copy is
     pale enough to take the navy ink at better than 9:1, so the palette can be
     cheerful without any of it being a legibility problem. */
  --mint: #a5e4c6;
  --mint-2: #c8f0dd;
  --butter: #ffdf9b;
  --butter-2: #fff0cc;
  --peri: #afcff2;       /* periwinkle */
  --peri-2: #d8e8fa;
  --blush: #ffd6cb;
  --grass: #1baf7e;      /* the deck's green, for small marks */
  --sun: #f2b544;
  --cobalt: #2f5d92;     /* the one deeper surface, a friendly blue now */
  --cerulean: #7fb8ea;

  /* the Echo logo greens, exactly as supplied */
  --green: #12a85e;
  --green-2: #4fc28a;
  --green-3: #97dcb8;

  --wrap: 1120px;
  --r: 20px;
  --font: "Lato", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
}

/* The site commits to one daylight, so both theme stamps resolve the same way
   rather than inverting into an unreadable half-dark page. */
:root[data-theme="dark"], :root[data-theme="light"] { color-scheme: light; }

* { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--sky);
  color: var(--ink);
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { margin: 0; font-weight: 900; letter-spacing: -.03em; line-height: 1.06; text-wrap: balance; }
p { margin: 0; }
a { color: inherit; }

.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 26px; position: relative; z-index: 1; }

/* ------------------------------------------------------------- the field */
/* The painted ground. Fixed to the viewport and behind everything, so the
   strokes are weather the page travels through rather than wallpaper stuck to
   it. It paints its own sky, so nothing shows through from behind. */
#field {
  position: fixed; inset: 0; z-index: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  display: block;
}

/* ---------------------------------------------------------------- the mark */
/* The mark is wide and short (23:12), so it is sized by height and left to
   take its own width from the viewBox — pinning both to a square would
   letterbox it and throw the spacing beside the wordmark. */
.mark { height: 21px; width: auto; flex: none; }
.mark.md { height: 27px; }

.brand {
  display: inline-flex; align-items: center; gap: 10px;
  font-weight: 900; font-size: 22px; letter-spacing: -.03em;
}

/* ------------------------------------------------------------------ header */
/* No bar at all: the sky runs straight up behind the brand. It also stops
   being sticky, because a transparent bar that stays put has the page sliding
   through it — the words underneath and the words in it end up on top of each
   other. It scrolls away instead, and the calls to action repeat further down. */
header.site {
  position: relative; z-index: 50;
  background: transparent;
}
.nav { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding-block: 13px; }
.nav-right { display: flex; align-items: center; gap: 14px; }
.pill {
  font-size: 12px; font-weight: 700; letter-spacing: .02em;
  padding: 6px 13px; border-radius: 999px;
  background: var(--mint); color: var(--ink);
}
/* The way through to the platform. A quiet text link rather than a second
   button: there is one primary action in this bar and it is the one beside it.
   Full-strength ink, because the bar is transparent and the painting runs
   straight up behind the words. */
.navlink {
  font-size: 14.5px; font-weight: 900; letter-spacing: -.01em;
  color: var(--ink); text-decoration: none; white-space: nowrap;
  padding: 6px 2px; border-bottom: 2px solid transparent;
  transition: color .14s ease, border-color .14s ease;
}
.navlink:hover { color: #0c7150; border-bottom-color: var(--green-2); }

/* ----------------------------------------------------------------- buttons */
.btn {
  border: none; border-radius: 999px; cursor: pointer;
  font-family: inherit; font-weight: 900; font-size: 15px; letter-spacing: -.01em;
  padding: 14px 26px; line-height: 1;
  transition: transform .14s ease, box-shadow .14s ease, background-color .14s ease;
}
/* Deep navy against the sky for the main action, wheat-gold for the closing
   one. Both carry their contrast in the pairing rather than in a glow. */
.btn-primary {
  background: var(--ink); color: #fff;
  box-shadow: 0 4px 10px -4px rgba(0, 27, 48, .3);
}
.btn-primary:hover { transform: translateY(-1px); box-shadow: 0 6px 14px -4px rgba(0, 27, 48, .38); }
.btn-dark { background: var(--butter); color: var(--ink); box-shadow: 0 4px 10px -4px rgba(120, 82, 8, .3); }
.btn-dark:hover { transform: translateY(-1px); box-shadow: 0 6px 14px -4px rgba(120, 82, 8, .4); }
.btn-nav { padding: 11px 20px; font-size: 14px; }
.btn:disabled { opacity: .6; cursor: default; transform: none; }
.btn-ghost {
  border: 1px solid var(--line-2); background: rgba(255, 255, 255, .7); color: var(--ink-2);
  border-radius: 999px; padding: 7px 15px; font: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
}
.btn-ghost:hover { border-color: var(--grass); color: #0c7150; }

a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, .pcheck:focus-within {
  outline: 3px solid var(--cobalt); outline-offset: 2px;
}

/* -------------------------------------------------------- the page ground */
/* One wash, painted once across the whole of <main> — not one per section.
   A band-scoped gradient has to begin and end at that band's own edges, and
   every one of those stops lands on a section join and reads as a ruled line.
   Fading each one out at its edges removes the line but pinches the colour to
   nothing at every join, so the page arrives back at bare ground over and
   over. Painting the whole descent as a single layer solves both: there are no
   internal edges to see, and a bloom is free to start in one section and
   finish in the next, so colour actually travels top to bottom.
   These are translucent only — the field has to read through them. */
/* The sections stay positioned so they paint after the wash and after the
   field: a section that carries its own colour has to sit on top of the
   ground, not under it. Their own backgrounds are transparent, so the wash
   reads straight through everywhere else, and .wrap's z-index keeps content
   above it. */
.hero, .band { position: relative; }
main { position: relative; z-index: 0; }
main::before {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 0;
  /* Blooms alternate right/left as they descend and are spaced closer than
     their own height, so consecutive blooms always overlap — the colour is
     handed from one to the next and never drops out. */
  background:
    radial-gradient(58% 7% at 86% 1%, rgba(255, 255, 255, .16), transparent 72%),
    radial-gradient(56% 7% at 96% 23%, rgba(255, 223, 155, .12), transparent 72%),
    radial-gradient(54% 7% at 2% 35%, rgba(255, 255, 255, .14), transparent 72%),
    radial-gradient(56% 7% at 3% 59%, rgba(255, 255, 255, .12), transparent 72%),
    radial-gradient(58% 8% at 6% 84%, rgba(255, 223, 155, .14), transparent 72%);
}

/* ------------------------------------------------- words over the painting */
/* No halo behind the glyphs. There was one, from when the ground was a
   saturated cerulean and the paint could be darker than the ink: a stack of
   pale shadows that bought contrast where a stroke crossed a letter. The sky
   is high-key now and every stroke is lighter than the ink, so it was buying
   nothing — measured without it, the worst any glyph gets is 12.3:1 against
   the darkest ground behind it. All it was still doing was fuzzing the edge
   of every letter, which reads as type that will not quite come into focus.
   The sky is a bold surface, though, so only strong ink goes on it: the
   secondary greys that are fine on a white card are not used out here. */
.hero-copy .checks li,
.band > .wrap > .lead { color: var(--ink); }
.hero-copy .fineprint { color: #29455e; }
/* A green dark enough to hold its own on the sky, rather than the mid green
   that only works on white. */
.band > .wrap > .eyebrow { color: #064a34; }

/* -------------------------------------------------------------------- hero */
.hero { padding: 74px 0 88px; }
.hero-inner { display: grid; grid-template-columns: 1.02fr .98fr; gap: 54px; align-items: center; }
.hero h1 { font-size: clamp(38px, 5.2vw, 62px); max-width: 13ch; }

/* The one loud typographic move: a swipe of wheat-gold behind the words. It
   works on a light ground in a way it could not on a dark one — the block only
   ever covers the middle of a line, and here the ink still reads on the sky
   where the swipe falls short. */
.hl { position: relative; white-space: nowrap; }
.hl::before {
  content: ""; position: absolute; left: -.07em; right: -.07em; top: 12%; bottom: 4%;
  background: var(--butter); border-radius: 42% 58% 50% 50% / 58% 46% 54% 42%;
  transform: rotate(-1.3deg); z-index: -1;
}

.checks { list-style: none; margin: 26px 0 0; padding: 0; display: grid; gap: 11px; }
.checks li { display: flex; gap: 12px; align-items: flex-start; font-size: 17px; color: var(--ink-2); }
.tick {
  flex: none; width: 24px; height: 24px; border-radius: 50%;
  background: var(--mint); color: #0a5b41; display: grid; place-items: center; margin-top: 2px;
}
.tick svg { width: 14px; height: 14px; }

.subline { margin-top: 22px; font-size: 19px; font-weight: 700; max-width: 34ch; }

.capture {
  margin-top: 22px; display: inline-flex; gap: 8px; align-items: center; flex-wrap: wrap;
  padding: 9px; border-radius: 999px; background: #fff;
  box-shadow: 0 4px 10px -4px rgba(0, 27, 48, .16), inset 0 0 0 1px var(--line);
}
.capture input {
  border: none; background: transparent; font: inherit; font-size: 15px;
  padding: 10px 8px 10px 16px; min-width: 210px; color: var(--ink);
}
.capture input::placeholder { color: var(--ink-3); }
.capture input:focus { outline: none; }
/* Below about 480px the field and the button can no longer sit side by side,
   and a 999px radius drawn around two stacked rows reads as a white blob with
   a button loose inside it. Take the pill apart before it gets there: the
   field keeps the pill shape on its own, the button goes full width under it.
   16px on the input as well — anything smaller and iOS zooms the page in when
   it is tapped. */
@media (max-width: 560px) {
  .capture {
    display: grid; gap: 10px; width: 100%;
    padding: 0; border-radius: 0; background: none; box-shadow: none;
  }
  .capture input {
    width: 100%; min-width: 0; font-size: 16px; padding: 15px 20px;
    border-radius: 999px; background: #fff;
    box-shadow: 0 10px 24px -16px rgba(0, 27, 48, .55), inset 0 0 0 1px var(--line);
  }
  .capture .btn { width: 100%; padding: 16px 26px; }
}

.fineprint { margin-top: 14px; font-size: 14.5px; color: var(--ink-3); }
.form-msg { margin-top: 10px; font-size: 14px; min-height: 1em; }
.form-msg.err { color: #c2185b; font-weight: 700; }
.form-msg.ok { color: #0c7150; font-weight: 700; }

/* ------------------------------------------------------------- hero stage  */
.hero-stage { position: relative; }
.wave-card {
  background: #fff; border-radius: 26px; padding: 22px 22px 18px;
  box-shadow: 0 8px 20px -8px rgba(0, 27, 48, .16), inset 0 0 0 1px var(--line);
}
.wc-head {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 12.5px; font-weight: 900; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3);
}
.wc-head .live { display: inline-flex; align-items: center; gap: 8px; color: var(--ink); }
.wc-head .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--sun); animation: blip 1.6s ease-in-out infinite; }
@keyframes blip { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
.wc-meta { font-family: var(--mono); font-size: 11.5px; letter-spacing: 0; text-transform: none; }

.wave-block { margin-top: 16px; }
.wave-label {
  display: block; font-family: var(--mono); font-size: 11.5px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 6px;
}
.wave-label.echo-label { color: #0c7150; }

.wc-foot { margin-top: 16px; display: flex; gap: 8px; flex-wrap: wrap; }
.chip { font-size: 11px; font-weight: 900; letter-spacing: .07em; text-transform: uppercase; border-radius: 999px; padding: 6px 12px; }
.chip.hit { background: var(--mint); color: var(--ink); }
.chip.zero { background: var(--butter); color: var(--ink); }

/* The cached dialogue, surfacing out of the wave. Each phrase is a bubble that
   pops up over the waveform, holds, and gives way to the next — which is what a
   call actually does, rather than a list of quotes sitting underneath a picture
   of a call. What it costs to say it again rides on the bubble. */
.stage { position: relative; }
.stage .wave { height: 132px; }
.pops { list-style: none; margin: 0; padding: 0; }
.pops li {
  position: absolute; z-index: 2;
  display: inline-flex; align-items: center; gap: 9px; white-space: nowrap;
  background: #fff; border-radius: 15px 15px 15px 5px;
  padding: 8px 10px 8px 13px;
  box-shadow: 0 5px 14px -5px rgba(0, 27, 48, .3), inset 0 0 0 1px var(--line);
  opacity: 0;
  animation: surface 9s cubic-bezier(.2, .8, .2, 1) infinite;
  animation-delay: calc(var(--i) * 3s);
}
.pops li:nth-child(1) { left: 0; top: 30px; }
.pops li:nth-child(2) { left: 16%; top: 66px; }
.pops li:nth-child(3) { left: 5%; top: 104px; }
.pops .said { font-size: 14px; font-weight: 700; color: var(--ink); }
.pops .cost {
  flex: none; font-size: 12px; font-weight: 900; letter-spacing: .04em;
  background: var(--mint); color: var(--ink); border-radius: 999px; padding: 4px 10px;
}
/* Each holds for a third of the loop, so exactly one is up at a time.
   Named `surface`, not `pop`: the confetti in the success panel already owns
   `pop`, it is defined later in this file, and a duplicate keyframes name is
   simply overwritten — these bubbles were inheriting the confetti's spin. */
@keyframes surface {
  0% { opacity: 0; transform: translateY(12px) scale(.94); }
  4% { opacity: 1; transform: none; }
  29% { opacity: 1; transform: none; }
  35% { opacity: 0; transform: translateY(-10px) scale(.97); }
  100% { opacity: 0; transform: translateY(12px) scale(.94); }
}
/* Nothing pops: the phrases simply sit under the wave, all three at once. */
@media (prefers-reduced-motion: reduce) {
  .pops { display: grid; gap: 7px; margin-top: 12px; }
  .pops li { position: static; opacity: 1; transform: none; animation: none; }
}

/* ------------------------------------------------------------- the waveform */
/* One motif, reused at every scale: a phrase plays, then repeats free.
   The shapes are filled wave bodies, built in main.js — see the note there on
   why they are bodies rather than stroked lines. */
/* The wave rolls on past both ends, so it fades out rather than being cut off
   — a clipped edge stops it dead and turns a moving wave into a rectangle. */
.wave {
  height: 104px; width: 100%; overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 7%, #000 93%, transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 7%, #000 93%, transparent 100%);
}
.wave .flow { display: block; width: 100%; height: 100%; }
/* The shape is three periods wide; sliding one period lands on the same shape,
   so the roll is seamless. */
.wave .flow g { animation: drift 10s linear infinite; }
@keyframes drift { to { transform: translateX(-500px); } }
/* The pointer-driven wave keeps its own clock — see main.js. */
.wave.live .flow g { animation: none; }

.wave.sm { height: 66px; }
.wave.lg { height: 92px; max-width: 620px; }
@media (prefers-reduced-motion: reduce) { .wave .flow g { animation: none; } }

/* ------------------------------------------------------------------- bands */
.band { padding: 92px 0; scroll-margin-top: 24px; }

.eyebrow {
  font-family: var(--mono); font-size: 12.5px; letter-spacing: .14em; text-transform: uppercase;
  color: #0a5b41; margin-bottom: 16px;
}
h2.sec { font-size: clamp(28px, 3.6vw, 44px); max-width: 20ch; }
.lead { margin-top: 16px; font-size: 18px; color: var(--ink-2); max-width: 64ch; }

/* --------------------------------------------------------------- entrances */
/* Components arrive as they scroll into view: they slide in from the side and
   fade up, with a small stagger between the members of a row so a group deals
   in instead of snapping in as one body.
   They come from the left because that is the way the wave travels — content
   arrives on the same current as the sound. It is also the safe direction:
   overflow to the left of the viewport is not scrollable in LTR, so an
   entrance can never put a horizontal scrollbar on the page.
   Only opacity and transform animate, so nothing reflows and no text shifts
   under someone mid-read. JS sets the attribute and only ever on elements
   below the fold, so the page is fully visible both without the script and
   above the fold, where an entrance you never scrolled to is just a flash. */
[data-enter] {
  opacity: 0;
  transform: translateX(var(--enter-x, -32px));
  transition:
    opacity .62s cubic-bezier(.2, .7, .2, 1) var(--enter-d, 0s),
    transform .62s cubic-bezier(.2, .7, .2, 1) var(--enter-d, 0s);
}
[data-enter].in { opacity: 1; transform: none; }
/* Small components travel less — the distance should stay proportional. */
.prov[data-enter], .turn[data-enter], .call-top[data-enter], .callend[data-enter],
footer.site [data-enter] { --enter-x: -16px; }
@media (prefers-reduced-motion: reduce) {
  [data-enter] { opacity: 1; transform: none; transition: none; }
}

/* ------------------------------------------------------- 01 · cost diagram */
.panel {
  margin-top: 44px; background: #fff; border-radius: 24px; padding: 22px;
  box-shadow: 0 8px 20px -8px rgba(0, 27, 48, .15), inset 0 0 0 1px var(--line);
}
.panel-head { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; }
.panel-head .t { font-weight: 900; font-size: 15px; letter-spacing: -.01em; }
.panel-note { text-align: right; margin: 10px 0 8px; min-height: 28px; }
.tag-note {
  display: inline-block; font-size: 11.5px; font-weight: 900; letter-spacing: .07em; text-transform: uppercase;
  background: var(--butter); color: var(--ink); border-radius: 999px; padding: 6px 13px;
}

.bars { display: flex; gap: 8px; align-items: stretch; }
/* Height carries no meaning here — only width does — so the segments are kept
   as short as the two lines of type inside them need. Taller boxes just read
   as four large blocks of colour. */
.seg {
  border-radius: 15px; padding: 13px 15px; min-height: 88px;
  display: flex; flex-direction: column; justify-content: flex-end;
  flex-basis: 0; flex-shrink: 1; min-width: 0; overflow: hidden;
  clip-path: inset(0 100% 0 0); opacity: 0;
}
.seg .pct { font-size: clamp(19px, 1.9vw, 25px); font-weight: 900; letter-spacing: -.04em; line-height: 1; white-space: nowrap; }
.seg .cap { margin-top: 6px; font-size: 12.5px; font-weight: 700; line-height: 1.25; white-space: nowrap; }
/* Speech to text is a tenth of the bill and gets a tenth of the row, which is
   not enough width for its own name on one line. It is the only caption that
   has to fold; the others are on segments three times as wide, and keeping
   them on one line stops the growing Echo segment changing line count as it
   opens. */
.seg.stt .cap { white-space: normal; }
/* The resting state is the end of the story — text-to-speech already halved,
   Echo holding the other half. JS winds it back to the beginning before
   playing, so without a script, or with motion turned down, the panel simply
   shows the conclusion rather than a half-told version of it. */
/* Left to right the row runs smallest to largest, and the two blues run pale
   to deeper with it, so the tints climb with the widths rather than against
   them. */
.seg.stt { flex-grow: 15; background: var(--peri-2); color: var(--ink-2); }
.seg.llm { flex-grow: 25; background: var(--peri); color: var(--ink); }
.seg.tts { flex-grow: 30; background: var(--butter); color: var(--ink); }
.seg.echo { flex-grow: 30; background: var(--mint); color: var(--ink); position: relative; }

/* Only the three real costs wipe in. Echo is not wiped in at all: it arrives
   by taking the width text-to-speech gives up, which is the point. */
.bars.play .seg.llm, .bars.play .seg.stt, .bars.play .seg.tts {
  animation: segIn .9s cubic-bezier(.2, .8, .2, 1) forwards;
}
.bars.play .seg.stt { animation-delay: .25s; }
.bars.play .seg.llm { animation-delay: .95s; }
.bars.play .seg.tts { animation-delay: 1.65s; }
.bars.play .seg.echo { clip-path: none; opacity: 1; }
.bars.done .seg.echo::after {
  content: ""; position: absolute; inset: 0; border-radius: 15px;
  box-shadow: 0 0 0 0 rgba(120, 200, 170, .9);
  animation: ping 1.6s ease-out .3s 2;
}
@keyframes segIn { to { clip-path: inset(0 0 0 0); opacity: 1; } }
@keyframes ping { to { box-shadow: 0 0 0 22px rgba(120, 200, 170, 0); } }
/* The claim only appears once the panel has made it. */
.panel-note { opacity: 0; transition: opacity .6s ease; }
.panel-note.shown, .panel:not(:has(.bars)) .panel-note { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .seg { clip-path: none; opacity: 1; }
  .bars.play .seg { animation: none; }
  .bars.done .seg.echo::after { animation: none; }
  .panel-note { opacity: 1; }
}

.after-bars {
  margin-top: 22px; display: flex; align-items: center; justify-content: space-between;
  gap: 26px; flex-wrap: wrap;
}
.after-copy { font-size: 15.5px; color: var(--ink-2); max-width: 52ch; }
.after-copy b { color: var(--ink); }
.pipecat { text-align: center; }
/* The bubble and its dash meet the pipe at the pipe's own middle, which is
   low in the artwork because the ears take the top of it. */
.pipecat-row { display: flex; align-items: flex-end; gap: 12px; }
.pipecat-row .bubble, .pipecat-row .dashlink { margin-bottom: 19px; }
.bubble {
  background: var(--butter); color: var(--ink); font-size: 13.5px; font-weight: 900;
  padding: 9px 15px; border-radius: 999px;
}
.dashlink { width: 44px; border-top: 2.5px dashed var(--line-2); }
.pipecat-cap { margin-top: 9px; font-family: var(--mono); font-size: 12px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); }

.diagram-foot {
  margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--line);
  display: flex; align-items: center; justify-content: space-between; gap: 20px; flex-wrap: wrap;
}
.foot-line { font-style: italic; color: var(--ink-3); font-size: 16px; max-width: 44ch; }
.badge {
  background: var(--mint); color: var(--ink); border-radius: 999px; padding: 10px 18px;
  font-size: 13px; font-weight: 900; letter-spacing: .02em; white-space: nowrap;
}

/* --------------------------------------------------- 02 · colour-blocked steps */
.grid { display: grid; gap: 18px; margin-top: 50px; }
.cols-3 { grid-template-columns: repeat(3, 1fr); }
/* Tight shadows throughout. A wide, soft, far-thrown shadow on a pale sky does
   not read as a card lifted off the page, it reads as a glow around it. */
.step {
  border-radius: 24px; padding: 26px 24px 20px;
  display: flex; flex-direction: column;
  box-shadow: 0 30px 60px -34px #000;
}
.step .s {
  font-family: var(--mono); font-size: 11.5px; letter-spacing: .14em; text-transform: uppercase;
  opacity: .72;
}
.step h3 { margin-top: 10px; font-size: 25px; }
.step p { margin-top: 12px; font-size: 15.5px; }
.step .wave { margin-top: auto; padding-top: 22px; }
/* The three colours a wheatfield-under-sky is built from: the green of the
   field, the gold of the crop, the cobalt overhead. */
.block-y { background: var(--mint); color: var(--ink); box-shadow: 0 8px 20px -8px rgba(0, 27, 48, .16); }
.block-p { background: var(--butter); color: var(--ink); box-shadow: 0 8px 20px -8px rgba(0, 27, 48, .16); }
.block-c { background: var(--peri); color: var(--ink); box-shadow: 0 8px 20px -8px rgba(0, 27, 48, .16); }

/* ------------------------------------------------------ 03 · annotated call */
.call-grid { display: grid; grid-template-columns: 1.42fr .58fr; gap: 22px; margin-top: 42px; align-items: start; }
.transcript {
  background: #fff; border-radius: 26px; padding: 26px;
  box-shadow: 0 8px 20px -8px rgba(0, 27, 48, .15), inset 0 0 0 1px var(--line);
}
.call-top { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; flex-wrap: wrap; padding-bottom: 16px; border-bottom: 1px solid var(--line); }
.call-top h3 { font-size: 17px; }
.call-top .meta { font-family: var(--mono); font-size: 12.5px; color: var(--ink-3); }

.turn { padding: 16px 0; border-bottom: 1px solid var(--line); }
.turn .who { font-family: var(--mono); font-size: 11.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); }
.turn .say-line { margin-top: 5px; font-size: 16px; }
.turn.cust .say-line { color: var(--ink-2); }
.chiptag {
  display: inline-flex; align-items: center; gap: 7px; margin-top: 10px;
  border-radius: 999px; padding: 5px 6px 5px 12px; font-size: 11px; font-weight: 900;
  letter-spacing: .06em; text-transform: uppercase;
}
.chiptag .v { border-radius: 999px; padding: 3px 9px; }
.chiptag.match { background: var(--mint-2); color: #0a5b41; }
.chiptag.match .v { background: var(--mint); color: var(--ink); }
.chiptag.stream { background: var(--butter-2); color: #7a5200; }
.chiptag.stream .v { background: var(--butter); color: var(--ink); }

.callend { margin-top: 18px; text-align: center; font-family: var(--mono); font-size: 12.5px; letter-spacing: .1em; color: var(--ink-3); }
.summary {
  margin-top: 20px; background: var(--mint); border-radius: 20px; padding: 20px 22px;
  display: grid; justify-items: center; gap: 4px; color: var(--ink);
}
.summary .wave { color: var(--ink); }
.summary .big { font-size: 22px; font-weight: 900; letter-spacing: -.02em; margin-top: 8px; }
.summary .sub { font-size: 14px; font-weight: 700; opacity: .78; }

.call-aside { display: grid; gap: 18px; position: sticky; top: 84px; }
.aside {
  background: #fff; border-radius: 22px; padding: 22px;
  box-shadow: 0 8px 20px -8px rgba(0, 27, 48, .15), inset 0 0 0 1px var(--line);
}
.aside .cap { font-family: var(--mono); font-size: 11.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.aside .note { margin-top: 14px; font-size: 14px; color: var(--ink-3); }

/* the one deep surface on the page — the cobalt at the top of the sky */
.aside.screen {
  background: var(--cobalt); box-shadow: 0 8px 20px -8px rgba(0, 27, 48, .25);
  color: #f2f8ff;
}
/* This panel got lighter and happier, so its own text had to come up with it —
   the pale blues that read fine on the old deep cobalt sit at about 4:1 here. */
.aside.screen .cap, .aside.screen .note { color: #e6f0fb; }
.counter { display: flex; align-items: baseline; gap: 10px; margin-top: 12px; }
.counter .n { font-size: 34px; font-weight: 900; letter-spacing: -.04em; line-height: 1; }
.counter .n.hit { color: var(--mint); }
.counter .n.tts { color: var(--butter); }
.counter .l { font-size: 13px; font-weight: 700; color: #e6f0fb; }
.cachechip {
  margin-top: 8px; font-size: 12.5px; padding: 8px 12px; border-radius: 12px;
  background: rgba(255, 255, 255, .08); color: #eef5fd; border: 1px solid rgba(255, 255, 255, .2);
}
.idle { display: flex; align-items: center; gap: 14px; margin-top: 12px; color: var(--ink-3); }
.idle .wave { flex: 1; }
.zzz { font-family: var(--mono); font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3); }

/* --------------------------------------------------------------- the cat */
/* Pipecat, drawn as line art and sitting down in the pipe itself, at the end
   of the pipeline row — which is where the Echo mark used to sit, and the cat
   says the same thing better. The rim is drawn twice, once behind him and once
   in front, so he is inside the pipe rather than resting on it. */
.cat { margin: 0; width: 112px; flex: none; }
.cat svg { display: block; width: 100%; height: auto; }
.pc-body, .pc-lip { fill: #fffdf6; }
.pc-rim { fill: #f1ede3; }
.pc-fur { fill: #fffdf6; }
.pc-body, .pc-lip, .pc-rim, .pc-fur, .pc-face, .pc-rule {
  stroke: #123a5e; stroke-width: 5; stroke-linecap: round; stroke-linejoin: round;
}
.pc-face, .pc-rule { fill: none; }
.pc-face .pc-nose { fill: #123a5e; stroke-width: 4; }
.pc-face .pc-whisker { stroke-width: 3.6; }
.pc-rule { stroke-width: 3.4; opacity: .35; }

/* His ears flick as you come to him. */
.pc-cat { transform-box: fill-box; transform-origin: 50% 92%; }
.cat.tip .pc-cat { animation: catnotice 1.5s cubic-bezier(.34, .8, .3, 1); }
@keyframes catnotice {
  0%, 100% { transform: none; }
  24% { transform: translateY(-7px) rotate(-4deg); }
  60% { transform: translateY(-2px) rotate(2deg); }
}
@media (prefers-reduced-motion: reduce) { .cat.tip .pc-cat { animation: none; } }

/* -------------------------------------------------------- 04 · providers */
.providers { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 30px; }
.prov {
  background: #fff; border-radius: 999px; padding: 11px 19px;
  font-size: 14.5px; font-weight: 700; color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--line-2);
}
/* Sits on the sky, not on a chip, so it takes the mid-navy rather than the
   secondary grey — see the note on words laid straight on the painting. */
.prov.more { background: transparent; box-shadow: none; color: #29455e; font-style: italic; font-weight: 400; }

/* ------------------------------------------------------------------- CTA */
/* The close is a break in the weather rather than a flat block: the cloud
   builds and the sun comes through it, so the section arrives out of the sky
   instead of starting at a line. */
.band.cta {
  text-align: center; padding: 84px 0 96px;
  background:
    radial-gradient(120% 80% at 50% 122%, rgba(255, 223, 155, .5), transparent 66%),
    radial-gradient(80% 55% at 50% 108%, rgba(255, 255, 255, .8), transparent 60%),
    linear-gradient(180deg, transparent 0, rgba(255, 255, 255, .5) 44%, rgba(214, 234, 252, .75) 100%);
}
.band.cta h2.sec { max-width: none; }
.band.cta .lead { color: var(--ink-2); margin-inline: auto; }
.band.cta .form-msg { margin-inline: auto; }
/* Held back through the ink rather than through `opacity`, which the entrance
   needs to animate — a rule with its own opacity outranks [data-enter] and the
   component would lift into view without ever fading. */
.band.cta .wave.lg { color: rgba(0, 62, 122, .62); margin: 0 auto 26px; }

/* ---------------------------------------------------------------- footer */
/* Positioned so it paints above the fixed field — a static background would
   sit in an earlier paint layer and the canvas would cover it. */
footer.site {
  position: relative; z-index: 1;
  background: #0d3355; color: #eaf3ff; padding: 46px 0;
  --m1: #2fd47f; --m2: #7ce0ab; --m3: #b6ecd0;
}
footer.site .wrap { display: flex; align-items: center; justify-content: space-between; gap: 18px; flex-wrap: wrap; }
footer.site .tagline { color: #8fabc4; font-size: 14.5px; }
footer.site .devlink {
  font-family: var(--mono); font-size: 12.5px; letter-spacing: .08em;
  color: var(--butter); text-decoration: none; border-bottom: 1px solid rgba(255, 223, 155, .5); padding-bottom: 2px;
}
footer.site .devlink:hover { border-bottom-color: var(--butter); }

/* ----------------------------------------------------------------- modal */
.modal-overlay {
  position: fixed; inset: 0; z-index: 100; display: none;
  background: rgba(0, 27, 48, .5); backdrop-filter: blur(6px);
  padding: 24px; overflow-y: auto;
}
.modal-overlay.open { display: grid; place-items: center; }
.modal {
  position: relative; width: min(560px, 100%); background: #fff; border-radius: 26px;
  padding: 34px 32px 30px;
  box-shadow: 0 18px 44px -18px rgba(0, 27, 48, .45);
}
.modal h3 { font-size: 27px; }
.modal-sub { margin-top: 8px; font-size: 15px; color: var(--ink-2); }
.modal-close {
  position: absolute; top: 16px; right: 16px; width: 34px; height: 34px; border-radius: 50%;
  border: none; background: var(--peri-2); color: var(--ink-2); font-size: 14px; cursor: pointer;
}
.modal-close:hover { background: var(--peri); color: var(--ink); }

.modal .fields { display: grid; gap: 14px; margin-top: 22px; }
.modal label {
  display: grid; gap: 6px; font-size: 12.5px; font-weight: 900;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3);
}
.modal input[type="text"], .modal input[type="email"], .modal select {
  font: inherit; font-size: 15px; color: var(--ink); text-transform: none; letter-spacing: normal;
  padding: 12px 14px; border-radius: 13px; border: 1.5px solid var(--line-2); background: #fff;
}
.modal input.invalid, .modal select.invalid { border-color: #c2185b; }
.modal select { appearance: none; background-image: linear-gradient(45deg, transparent 50%, var(--ink-3) 50%), linear-gradient(135deg, var(--ink-3) 50%, transparent 50%); background-position: calc(100% - 20px) 21px, calc(100% - 15px) 21px; background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; }
.modal select option { background: #fff; color: var(--ink); }

.providers-field { border: none; margin: 4px 0 0; padding: 0; }
.providers-field legend { font-size: 12.5px; font-weight: 900; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); padding: 0; margin-bottom: 9px; }
.providers-field.invalid legend { color: #c2185b; }
.provider-grid { display: flex; flex-wrap: wrap; gap: 8px; }
/* scoped past `.modal label`, which would otherwise uppercase the chips */
.modal .pcheck {
  display: inline-flex; align-items: center; gap: 0; margin: 0;
  font-size: 13.5px; font-weight: 700; letter-spacing: normal; text-transform: none;
  color: var(--ink-2); cursor: pointer;
}
.modal .pcheck input { position: absolute; opacity: 0; width: 0; height: 0; }
.modal .pcheck span {
  border-radius: 999px; padding: 8px 14px; background: var(--peri-2);
  box-shadow: inset 0 0 0 1.5px transparent; transition: background-color .14s ease, color .14s ease;
}
.modal .pcheck input:checked + span { background: var(--mint); color: var(--ink); font-weight: 900; }

.modal form > .btn { width: 100%; margin-top: 20px; }
.modal .form-msg { text-align: center; }

/* success */
.modal.done { text-align: center; }
.modal-success { display: grid; justify-items: center; }
/* `hidden` is only `display:none` from the UA sheet, which a class rule beats —
   without this the success panel renders underneath the live form. */
.modal-success[hidden] { display: none; }
.success-wave { position: relative; width: 220px; padding: 16px 0 6px; color: var(--grass); }
.success-wave .wave { height: 56px; }
.success-check {
  position: absolute; right: -6px; top: 0; width: 36px; height: 36px; border-radius: 50%;
  background: var(--grass); display: grid; place-items: center;
  box-shadow: 0 3px 8px -3px rgba(27, 175, 126, .6);
}
.success-check svg { width: 19px; height: 19px; }
.confetti { position: absolute; width: 8px; height: 8px; border-radius: 2px; opacity: 0; animation: pop .9s ease-out forwards; }
.c1 { background: var(--butter); left: 6%; top: 10%; animation-delay: .05s; }
.c2 { background: var(--peri); left: 24%; top: -8%; animation-delay: .14s; }
.c3 { background: var(--grass); right: 20%; top: -6%; animation-delay: .1s; }
.c4 { background: var(--blush); right: 4%; top: 22%; animation-delay: .2s; }
.c5 { background: var(--peri); left: 44%; top: -14%; animation-delay: .26s; }
.c6 { background: var(--grass); right: 38%; top: 26%; animation-delay: .32s; }
@keyframes pop { 0% { opacity: 0; transform: scale(.4) translateY(6px); } 40% { opacity: 1; } 100% { opacity: 0; transform: scale(1) translateY(-24px) rotate(40deg); } }
@media (prefers-reduced-motion: reduce) { .confetti { animation: none; opacity: 0; } }
.modal-success h3 { margin-top: 16px; }
.success-sub { margin-top: 8px; font-size: 15px; color: var(--ink-2); }
.success-who { margin-top: 12px; font-family: var(--mono); font-size: 12.5px; color: var(--ink-3); }
.success-done { margin-top: 22px; }

/* ------------------------------------------------------------ responsive */
@media (max-width: 1000px) {
  .hero-inner { grid-template-columns: 1fr; gap: 44px; }
  .hero h1 { max-width: 16ch; }
  .call-grid { grid-template-columns: 1fr; }
  .call-aside { position: static; grid-template-columns: 1fr 1fr; }
}
@media (max-width: 860px) {
  .cols-3 { grid-template-columns: 1fr; }
  .nav .pill { display: none; }
}
/* Brand, platform link and the call to action stop fitting on one line around
   here, and the button is the first thing to break — its label wraps to two
   lines inside the pill. Give the pair their own row instead of shrinking or
   dropping either of them. */
@media (max-width: 480px) {
  .nav { flex-wrap: wrap; row-gap: 12px; }
  .nav-right { width: 100%; }
}
@media (max-width: 720px) {
  body { font-size: 16px; }
  .hero { padding: 48px 0 62px; }
  .band { padding: 62px 0; }
  .bars { flex-direction: column; }
  /* Stacked, the growth factors would divide height instead of width, and a
     zero basis would flatten every segment to its own padding. Let them size
     to their contents and let the numbers alone tell the story. */
  .seg { min-height: 0; padding: 14px 16px; flex-basis: auto; }
  .seg .pct { font-size: 22px; }
  .call-aside { grid-template-columns: 1fr; }
  .after-bars { flex-direction: column; align-items: flex-start; }
  .modal { padding: 28px 20px 24px; }
  footer.site .wrap { flex-direction: column; align-items: flex-start; }
}
