:root {
  --bg: #f9f6f1;
  --ink: #1d1d1f;
  --muted: #6e6e73;
  --faint: #a1a1a6;
  --card: #ffffff;
  --line: rgba(0, 0, 0, 0.08);
  --bubble: #e9e9eb;
  --bubble-ink: #111111;
  --blue: #0a84ff;
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  /* Three spacing roles, so the gaps say what belongs together:
     tight = inside one thought, unit = parts of one component,
     group = between groups. Every vertical gap uses one of these. */
  --tight: 6px;
  --unit: 12px;
  --group: 22px;
  --serif: ui-serif, "New York", Georgia, "Times New Roman", serif;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* Controls: kill the rectangular tap flash and text selection, but keep a
   proper keyboard focus ring (there was none before). */
button, .cta {
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none;
  user-select: none;
}

button:focus-visible, .cta:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

html, body { height: 100%; }

html {
  overflow-x: hidden;
  /* Softens the ios rubber-band into the area past the page. The bounce
     itself is platform behaviour every site has; this reins it in where
     supported and costs nothing where not. */
  overscroll-behavior-y: none;
  /* Paints the whole canvas, including iOS overscroll above and below the
     page. Without it those areas fall back to white. */
  background-color: var(--bg);
}

body {
  /* A shallow pool of light: barely lighter under the card, a little deeper at
     the edges, so the white card reads as sitting on a surface rather than
     pasted onto a flat colour. Roughly 6 points of luminance top to edge. */
  /* Grain rides as a second background layer rather than a fixed overlay: an
     overlay would be a full-viewport composite layer above the animating demo.
     Its opacity is baked into the svg, since one layer cannot be faded alone.
     It also dithers the gradient, which spans few enough luminance steps to
     band on cheaper panels. */
  background-color: var(--bg);
  background-image:
    url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n' color-interpolation-filters='sRGB'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/><feComponentTransfer><feFuncR type='linear' slope='0' intercept='0.20'/><feFuncG type='linear' slope='0' intercept='0.19'/><feFuncB type='linear' slope='0' intercept='0.16'/><feFuncA type='linear' slope='0.12' intercept='0'/></feComponentTransfer></filter><rect width='140' height='140' filter='url(%23n)'/></svg>"),
    radial-gradient(135% 95% at 50% 8%,
      #fefcf8 0%,
      var(--bg) 46%,
      #f2eee6 100%);
  background-size: 140px 140px, cover;
  background-repeat: repeat, no-repeat;
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Keep the grain around one device pixel: a 160px tile on a 3x screen would
   otherwise render as coarse sand. */
@media (min-resolution: 2dppx) {
  body { background-size: 84px 84px, cover; }
}

@media (min-resolution: 3dppx) {
  body { background-size: 56px 56px, cover; }
}

/* ---------- the one-screen frame ---------- */

.frame {
  height: 100dvh;
  max-width: 560px;
  margin: 0 auto;
  padding: 18px 24px 18px;
  display: flex;
  flex-direction: column;
}

/* ---------- header ---------- */

.top { flex: none; }

/* The caps mark the stressed syllable, so this must never be uppercased in
   css: KAH-chee carries information that KAH-CHEE would lose. */
.say-it {
  display: block;
  margin-top: -1px;
  font-size: 10px;
  /* Slashes carry their own visual width, so the tracking eases off. */
  letter-spacing: 0.1em;
  color: var(--faint);
}

.wordmark {
  display: block;
  /* Tight leading pulls the respelling up under the name; "Kachi" has no
     descenders, so nothing is clipped. */
  line-height: 1.08;
  font-family: var(--serif);
  font-size: 19px;
  letter-spacing: 0.01em;
  text-decoration: none;
  color: var(--ink);
}

/* ---------- hero ---------- */

.hero {
  flex: none;
  text-align: center;
  padding-top: var(--group);
}

/* Keeps "whole circle." intact so the headline breaks after "your". */
.nb { white-space: nowrap; }

h1 {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(26px, 7.5vw, 38px);
  line-height: 1.12;
  letter-spacing: -0.015em;
}

.sub {
  margin: var(--tight) auto 0;
  max-width: 42ch;
  color: var(--muted);
  font-size: 15px;
}

/* ---------- demo ---------- */

.demo {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: var(--group) 0 0;
}

/* The stage holds one card per person. Narrow screens stack them and show the
   active one; wide screens lay them side by side so all sides are visible. */
.stage {
  flex: 1;
  min-height: 0;
  /* The longest conversation needs about 350px of card. Past that the card
     just grows white space inside itself, so stop it and let the extra room
     fall to the page, where it reads as paper instead of an empty screen. */
  max-height: 460px;
  position: relative;
  /* Edge to edge: the 24px page margin was the only room the neighbouring
     phones could have shown in, and it was going unused. */
  margin-left: -24px;
  margin-right: -24px;
  /* The off-centre phones sit well outside this box. Clip them here, or they
     bleed past the viewport and make the whole page scroll sideways.
     clip-margin keeps the cards' shadows from being sliced off. */
  overflow-x: clip;
  overflow-y: visible;
}

/* Narrow screens can only foreground one phone, so the others sit just off
   centre and stay visible at the edges: the circle is there before you read a
   word, and switching reads as moving between people rather than a swap. */
.slot {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: min(calc(100% - 82px), 340px);
  display: flex;
  flex-direction: column;
  align-items: center;
  opacity: 0.3;
  pointer-events: none;
  transform: translateX(-50%);
  transition: transform 420ms var(--ease-out), opacity 300ms var(--ease-out);
}

.slot.active {
  opacity: 1;
  pointer-events: auto;
  z-index: 2;
}

.slot[data-off="-1"] { transform: translateX(calc(-50% - 100% - 10px)); }
.slot[data-off="1"]  { transform: translateX(calc(-50% + 100% + 10px)); }

.slot[data-off="-2"] { transform: translateX(calc(-50% - 200% - 28px)); opacity: 0; }
.slot[data-off="2"]  { transform: translateX(calc(-50% + 200% + 28px)); opacity: 0; }

/* A solo goal keeps the same card size: switching scenarios must never
   resize the card, or the text reads as though it changed size. */

.whose { display: none; }

.phone {
  width: 100%;
  max-width: 380px;
  min-height: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  background: var(--card);
  border-radius: 26px;
  overflow: hidden;
  /* Blur kept under the downward offset so the shadow never reaches back up
     over the tabs; it falls below the card instead of haloing it. */
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, 0.05),
    0 1px 2px rgba(0, 0, 0, 0.04),
    0 14px 20px -6px rgba(0, 0, 0, 0.07);
}

.phone-head {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 9px 16px 7px;
  background: #f7f7f8;
  border-bottom: 1px solid rgba(0, 0, 0, 0.07);
}

.avatar .mark {
  width: 72%;
  height: auto;
  color: #fff;
}

.avatar {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--ink);
  color: #fff;
  font-family: var(--serif);
  font-size: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.contact {
  font-size: 12px;
  color: var(--ink);
  letter-spacing: -0.01em;
}

/* The disclosure chevron iOS puts after a contact's name. */
.chev {
  color: var(--faint);
  font-size: 12px;
  margin-left: 3px;
}

.substatus {
  font-size: 11px;
  color: var(--faint);
  margin-top: -3px;
}

.messages {
  flex: 1;
  min-height: 0;
  padding: 12px 12px 14px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 7px;
  overflow: hidden;
}

.bubble {
  position: relative;
  max-width: 84%;
  padding: 8px 13px;
  border-radius: 18px;
  font-size: 16px;
  line-height: 1.35;
}

.bubble.in {
  align-self: flex-start;
  background: var(--bubble);
  color: var(--bubble-ink);
}

.bubble.out {
  align-self: flex-end;
  background: var(--blue);
  color: #fff;
}

/* iMessage tails: a colored curl past the edge, masked into a crescent. */

.bubble::before,
.bubble::after {
  content: "";
  position: absolute;
  bottom: 0;
  height: 18px;
}

.bubble.in::before {
  left: -7px;
  width: 20px;
  background: var(--bubble);
  border-bottom-right-radius: 16px 14px;
}

.bubble.in::after {
  left: -7px;
  width: 7px;
  background: var(--card);
  border-bottom-right-radius: 10px;
}

.bubble.out::before {
  right: -7px;
  width: 20px;
  background: var(--blue);
  border-bottom-left-radius: 16px 14px;
}

.bubble.out::after {
  right: -7px;
  width: 7px;
  background: var(--card);
  border-bottom-left-radius: 10px;
}

.bubble.pop {
  animation: pop 0.32s cubic-bezier(0.2, 0.9, 0.3, 1.2) both;
}

@keyframes pop {
  from { opacity: 0; transform: translateY(10px) scale(0.92); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

.typing {
  position: relative;
  align-self: flex-start;
  background: var(--bubble);
  border-radius: 18px;
  padding: 12px 14px;
  display: flex;
  gap: 4px;
  margin-bottom: 6px;
}

/* The typing indicator's trailing dots, like the real one. */

.typing::before,
.typing::after {
  content: "";
  position: absolute;
  border-radius: 50%;
  background: var(--bubble);
}

.typing::before {
  width: 10px;
  height: 10px;
  left: 0;
  bottom: -3px;
}

.typing::after {
  width: 5px;
  height: 5px;
  left: -5px;
  bottom: -8px;
}

.typing i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #a8a8ad;
  animation: blink 1.2s infinite both;
}

.typing i:nth-child(2) { animation-delay: 0.18s; }
.typing i:nth-child(3) { animation-delay: 0.36s; }

@keyframes blink {
  0%, 60%, 100% { opacity: 0.35; }
  30% { opacity: 1; }
}

.row {
  flex: none;
  display: flex;
  justify-content: center;
  gap: 4px;
}

.scenarios { margin-bottom: var(--unit); }

.people { margin-top: var(--unit); }

.person {
  background: none;
  border: none;
  font-family: var(--sans);
  font-size: 13px;
  color: var(--faint);
  padding: 6px 12px;
  border-radius: 999px;
  cursor: pointer;
  white-space: nowrap;
  /* Weight stays constant so the active pill never nudges its neighbours.
     Kept short so two pills are never both clearly lit mid-change. */
  transition: color 150ms var(--ease-out), background 150ms var(--ease-out),
              transform 160ms var(--ease-out);
}

.person.on {
  color: var(--ink);
  /* White with a hairline ring: the same elevation language as the cards.
     The old grey pill sank into the textured paper. */
  background: var(--card);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.05);
}

.person:active { transform: scale(0.96); }

@media (hover: hover) and (pointer: fine) {
  .person:not(.on):hover { color: var(--muted); }
}

/* Time passing inside a thread, like an iMessage timestamp. */
.divider {
  align-self: center;
  font-size: 11px;
  color: var(--faint);
  padding: 2px 0;
}

/* ---------- bottom: cta + links ---------- */

.bottom {
  flex: none;
  text-align: center;
  padding-top: var(--group);
}

.cta {
  display: block;
  margin: 0 auto;
  max-width: 380px;
  background: var(--ink);
  color: #fff;
  text-decoration: none;
  font-size: 17px;
  font-weight: 600;
  padding: 15px 34px;
  border-radius: 999px;
  transition: transform 160ms var(--ease-out), opacity 160ms var(--ease-out);
}

.cta:active { transform: scale(0.96); }

@media (hover: hover) and (pointer: fine) {
  .cta:hover { opacity: 0.9; }
}

.quiet {
  margin-top: var(--tight);
  font-size: 12.5px;
  color: var(--faint);
  line-height: 1.6;
}

.quiet a { color: var(--faint); text-underline-offset: 3px; text-decoration-color: var(--line); }

.fallback {
  margin: 10px auto 0;
  max-width: 40ch;
  font-size: 13.5px;
  color: var(--muted);
}

.fallback .num { white-space: nowrap; font-variant-numeric: tabular-nums; }

.foot {
  max-width: 560px;
  margin: 0 auto;
  padding: 16px 24px calc(22px + env(safe-area-inset-bottom));
  text-align: center;
  font-size: 11px;
  color: rgba(0, 0, 0, 0.26);
}

.foot a {
  color: inherit;
  text-decoration: none;
}

@media (hover: hover) and (pointer: fine) {
  .foot a:hover { color: var(--muted); }
}


/* A pointer means no collapsing browser chrome to tuck the footer under, so
   the whole page fits the viewport instead of scrolling a stray 50px. */
@media (hover: hover) and (pointer: fine) {
  body {
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }

  /* As a column flex item, `margin: 0 auto` stops the frame stretching, so it
     has to be told to fill the width before max-width caps it. */
  .frame {
    height: auto;
    flex: 1;
    min-height: 0;
    width: 100%;
  }

  .foot {
    flex: none;
    width: 100%;
  }
}

/* Between phone and desktop the stage would stay full bleed while the card
   caps at 340px, so the peek grew to 200px+ on a tablet. Rein the stage in
   to card + peek once there is more width than a phone. */
@media (min-width: 500px) and (max-width: 1079px) {
  .stage {
    /* Explicit width: auto margins switch off flex stretching, and with only
       absolute children the stage otherwise collapses to zero. */
    width: min(100%, 430px);
    margin-left: auto;
    margin-right: auto;
  }

  /* Taller screens can afford a little more card, but not much: past this the
     conversation stops reaching the top and the card looks unused. */
  .stage { max-height: 490px; }
}

/* ---------- wide screens: every phone at once ---------- */

@media (min-width: 1080px) {
  .frame { max-width: 1120px; }

  .stage {
    position: static;
    overflow: visible;
    margin-left: 0;
    margin-right: 0;
    display: flex;
    justify-content: center;
    align-items: stretch;
    gap: 22px;
    /* The name above each card eats into the cap, so allow a little more. */
    max-height: 500px;
  }

  .slot {
    position: static;
    transform: none;
    width: auto;
    flex: 1;
    max-width: 330px;
    opacity: 0.55;
    pointer-events: auto;
  }

  .slot[data-off] { transform: none; opacity: 0.55; }
  .slot[data-off].active { opacity: 1; }

  .slot.active { opacity: 1; }

  .stage.solo .slot { max-width: 360px; width: auto; }

  .whose {
    display: block;
    flex: none;
    margin-bottom: 8px;
    font-family: var(--serif);
    font-style: italic;
    font-size: 14px;
    color: var(--muted);
  }

  /* All three are on screen, so switching between them is unnecessary. */
  .people { display: none; }

  /* One agent, three conversations: the repeated location adds nothing here. */
  .substatus { display: none; }

  .phone { max-width: none; }

  h1 { font-size: 44px; }
  .nb { white-space: normal; }
}

/* ---------- short screens ---------- */

/* Browser chrome eats about 100px, so a 844px phone is really ~745px here.
   Tighten from 780 or the thread gets cut on ordinary phones. */
@media (max-height: 780px), (max-width: 380px) {
  :root {
    --tight: 4px;
    --unit: 8px;
    --group: 14px;
  }

  .bubble { font-size: 15px; padding: 7px 12px; line-height: 1.3; }
  .messages { gap: 5px; padding: 10px 10px 12px; }
  .phone-head { padding: 8px 16px 7px; gap: 3px; }
  .avatar { width: 32px; height: 32px; font-size: 13px; }
  .substatus { display: none; }
}

/* 360px devices wrap onto more lines than 375px ones, and a tall 360 screen
   still shows the subline, so the bubbles give back the difference. */
@media (max-width: 380px) {
  .bubble { font-size: 14.5px; padding: 6px 11px; }
  .messages { gap: 4px; }
}

/* Small iPhones (SE, 8): the subline is the next thing that can go. */
@media (max-height: 700px) {
  .sub { display: none; }
}

/* Shorter still (Android 640, older SE): the longest thread is three bubbles
   and it has to survive intact, so the chrome gives up its space first. */
@media (max-height: 660px) {
  .say-it { display: none; }
  h1 { font-size: 24px; }
  .bubble { font-size: 13.5px; padding: 6px 10px; line-height: 1.25; }
  .messages { gap: 4px; padding: 8px 8px 10px; }
  .phone-head { padding: 6px 14px 5px; }
  .avatar { width: 28px; height: 28px; font-size: 12px; }
  .contact { font-size: 12px; }
  .cta { padding: 14px 22px; font-size: 15px; }
  .quiet { font-size: 11px; }
}

/* 320px wide (SE 1, 5s): the last things to go are the page's own words, so
   the conversation itself still arrives whole. */
@media (max-width: 340px) {
  .frame { padding-left: 16px; padding-right: 16px; }
  .quiet { display: none; }
  h1 { font-size: 21px; }
  .bubble { font-size: 12.5px; padding: 5px 9px; line-height: 1.24; }
  .messages { gap: 3px; padding: 7px 7px 9px; }
  .avatar { width: 26px; height: 26px; font-size: 11px; }
  .cta { padding: 13px 20px; font-size: 15px; }
}

/* ---------- reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  .bubble.pop { animation: none; }
  .typing i { animation: none; }
}

/* ---------- the magpie ---------- */

/* No pointer, no hover: the double-click is meant to be found, not offered.
   touch-action stops iOS reading the second tap as a zoom. */
.wordmark { touch-action: manipulation; }

body.egg-open { overflow: hidden; }

.egg {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 64px 26px 44px;
  overflow-y: auto;
  background: rgba(249, 246, 241, 0.93);
  -webkit-backdrop-filter: blur(22px) saturate(120%);
  backdrop-filter: blur(22px) saturate(120%);
}

.egg[hidden] { display: none; }

.egg.in { animation: eggIn 320ms var(--ease-out) both; }

@keyframes eggIn { from { opacity: 0; } to { opacity: 1; } }

.egg-inner {
  max-width: 36ch;
  margin: auto;
  text-align: center;
}

.egg-row { opacity: 0; animation: eggRow 620ms var(--ease-out) both; }

@keyframes eggRow {
  from { opacity: 0; transform: translateY(9px); }
  to { opacity: 1; transform: none; }
}

.egg-inner p {
  margin: 0 0 var(--group);
  font-size: 15px;
  line-height: 1.62;
  color: var(--muted);
}

.egg-inner .egg-mark {
  font-family: var(--serif);
  font-size: 34px;
  line-height: 1.05;
  color: var(--ink);
  margin-bottom: var(--group);
}

.egg-say {
  display: block;
  margin-top: 3px;
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: 0.1em;
  color: var(--faint);
}

.egg-inner .egg-lead {
  font-family: var(--serif);
  font-size: 20px;
  line-height: 1.34;
  color: var(--ink);
  margin-bottom: var(--unit);
}

.egg-inner .egg-short {
  margin: 0;
  padding-top: var(--group);
  border-top: 1px solid var(--line);
  font-family: var(--serif);
  font-style: italic;
  font-size: 17px;
  line-height: 1.45;
  color: var(--ink);
}

.egg-bridge {
  display: block;
  width: 190px;
  height: 42px;
  margin: 6px auto var(--group);
}

.egg-bridge circle {
  opacity: 0;
  animation: eggDot 520ms var(--ease-out) both;
}

.egg-bridge .lover { fill: var(--ink); }
.egg-bridge .magpie { fill: var(--faint); }

@keyframes eggDot {
  from { opacity: 0; transform: translateY(5px); }
  to { opacity: 1; transform: none; }
}

/* The bird lands last, after the story it belongs to. */
.egg-perch { margin-top: var(--group); }

.egg-bird {
  display: block;
  width: 124px;
  height: 124px;
  margin: 0 auto;
  color: var(--ink);
}

/* The bird is the payoff, so it has to stay on screen. Short phones get a
   smaller one rather than the story scrolling away from it. */
@media (max-height: 800px) {
  .egg { padding: 46px 22px 30px; }
  .egg-perch { margin-top: var(--unit); }
  .egg-bird { width: 96px; height: 96px; }
}

@media (max-height: 680px) {
  .egg-bird { width: 74px; height: 74px; }
}

.egg-x {
  position: absolute;
  top: 16px;
  right: 16px;
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--faint);
  font-size: 26px;
  line-height: 1;
  cursor: pointer;
  transition: color 180ms var(--ease-out), background 180ms var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .egg-x:hover { color: var(--ink); background: rgba(0, 0, 0, 0.045); }
}


@media (prefers-reduced-motion: reduce) {
  .egg.in, .egg-row, .egg-bridge circle { animation: none; opacity: 1; }
}
