/* Website Concierge — chat assistant (Erlach Glass · 80% Apple / 20% Studio Erlach) */

:root {
  --font-ui: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Helvetica Neue', 'Segoe UI', sans-serif;
  --font-brand: 'Fraunces', Georgia, serif;
  --font-mono: ui-monospace, 'SF Mono', Menlo, monospace;

  /* Erlach ice wallpaper */
  --wall-1: #eff5f6;
  --wall-2: #ddecef;
  --wall-3: #e8f1ee;
  --blob-a: #a8dbe6;
  --blob-b: #bfe0d6;

  --glass: rgba(255, 255, 255, 0.6);
  --glass-strong: rgba(255, 255, 255, 0.82);
  --glass-border: rgba(255, 255, 255, 0.7);
  --glass-shadow: 0 8px 32px rgba(10, 26, 30, 0.1), 0 1px 2px rgba(10, 26, 30, 0.05);

  --label: #101d20;
  --label-2: rgba(35, 58, 62, 0.6);
  --label-3: rgba(35, 58, 62, 0.33);
  --separator: rgba(35, 58, 62, 0.12);
  --fill: rgba(120, 138, 140, 0.12);

  --blue: #0da4c2; /* per-site accent overrides at runtime */
  --cyan: #22c7e5;
  --green: #1f9d43;
  --orange: #e8830c;
  --red: #e5493d;
  --gray: #8e979a;

  --radius: 24px;
  --radius-s: 14px;
}

@font-face {
  font-family: 'Fraunces';
  src: url('/fonts/fraunces.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-display: swap;
}

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

html { -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--font-ui);
  font-size: 16px;
  line-height: 1.45;
  color: var(--label);
  background: var(--wall-2);
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
}

.hidden { display: none !important; }

/* content for screen readers only — kept in the layout, not in the picture */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---- wallpaper ---- */
.wallpaper {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden; /* blobs reach past the edge and widened the mobile viewport */
  background:
    radial-gradient(900px 460px at 78% -8%, rgba(34, 199, 229, 0.16), transparent 62%),
    linear-gradient(160deg, var(--wall-1) 0%, var(--wall-2) 55%, var(--wall-3) 100%);
  overflow: hidden;
}
/* Pre-blurred via radial gradients, NOT filter: blur(90px) on 55vmax at 3x
   DPR made every backdrop-filter re-snapshot (glass navbar/composer) cost
   >1s on iPhone — measured as the first-tap stall. Same look, zero filter. */
.blob { position: absolute; width: 78vmax; height: 78vmax; opacity: 0.5; }
/* bell-curve falloff — a plain two-stop gradient reads as a hard-edged disc,
   a real blur fades like a gaussian */
.blob-a {
  background: radial-gradient(
    circle closest-side,
    var(--blob-a) 0%,
    color-mix(in srgb, var(--blob-a) 88%, transparent) 24%,
    color-mix(in srgb, var(--blob-a) 55%, transparent) 44%,
    color-mix(in srgb, var(--blob-a) 26%, transparent) 62%,
    color-mix(in srgb, var(--blob-a) 9%, transparent) 78%,
    transparent 92%
  );
  top: -30vmax;
  right: -24vmax;
  animation: drift-a 70s ease-in-out infinite alternate;
}
.blob-b {
  background: radial-gradient(
    circle closest-side,
    var(--blob-b) 0%,
    color-mix(in srgb, var(--blob-b) 88%, transparent) 24%,
    color-mix(in srgb, var(--blob-b) 55%, transparent) 44%,
    color-mix(in srgb, var(--blob-b) 26%, transparent) 62%,
    color-mix(in srgb, var(--blob-b) 9%, transparent) 78%,
    transparent 92%
  );
  bottom: -34vmax;
  left: -28vmax;
  animation: drift-b 55s ease-in-out infinite alternate;
}
@keyframes drift-a { to { transform: translate(-10vmax, 12vmax) scale(1.12); } }
@keyframes drift-b { to { transform: translate(9vmax, -9vmax) scale(0.92); } }
@media (prefers-reduced-motion: reduce) {
  .blob-a, .blob-b { animation: none; }
  * { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

/* ---- shared ---- */
.glass {
  background: var(--glass);
  -webkit-backdrop-filter: blur(24px) saturate(170%);
  backdrop-filter: blur(24px) saturate(170%);
  border: 0.5px solid var(--glass-border);
  border-radius: var(--radius);
  box-shadow: var(--glass-shadow);
}

.brand-lockup { display: flex; align-items: center; gap: 10px; }
.login-lockup { justify-content: center; }
.brand-logo { height: 11px; display: block; }
.lockup-x { font-size: 13px; color: var(--label-3); }
.wordmark { font-family: var(--font-brand); font-weight: 500; font-size: 19px; }
.wordmark-sans { font-family: var(--font-ui); font-weight: 700; font-size: 14px; letter-spacing: 0.2em; text-transform: uppercase; }

/* no double-tap-zoom arbitration on controls — taps must fire immediately */
button, .btn, .field, .composer-field { touch-action: manipulation; }

.btn {
  font: inherit;
  font-size: 16px;
  font-weight: 600;
  border: none;
  border-radius: 999px;
  padding: 11px 20px;
  cursor: pointer;
  color: var(--blue);
  background: transparent;
  white-space: nowrap;
  transition: transform 0.15s ease, opacity 0.15s ease;
}
.btn:active { transform: scale(0.97); opacity: 0.85; }
.btn:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.btn:disabled { opacity: 0.4; cursor: default; }
.btn-primary { background: var(--blue); color: #fff; }
.btn-danger { color: var(--red); }
.btn-block { width: 100%; margin-top: 14px; }

.field {
  width: 100%;
  font: inherit;
  color: var(--label);
  background: var(--fill);
  border: none;
  border-radius: var(--radius-s);
  padding: 13px 16px;
  outline-offset: 2px;
}
.field::placeholder { color: var(--label-3); }
.field:focus-visible { outline: 2px solid var(--blue); }

/* ---- entrance choreography (initReveals adds .rv, .in triggers) ---- */
.rv {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity 0.7s ease var(--rvd, 0s),
    transform 0.7s cubic-bezier(0.22, 0.8, 0.25, 1) var(--rvd, 0s);
}
.rv.in { opacity: 1; transform: none; }
/* the bubble layer centers via translateX — fade only, and slower (atmosphere) */
.hero-bubbles.rv, .hero-bubbles.rv.in { transform: translateX(-50%); }
.hero-bubbles.rv { transition: opacity 1.3s ease var(--rvd, 0s); }

/* ---- landing ---- */
.landing { min-height: 100vh; display: flex; flex-direction: column; align-items: center; padding: 0 22px calc(28px + env(safe-area-inset-bottom)); }
.nav-wordmark {
  /* the nav wordmark is the brand speaking — same serif voice as the h1,
     matching the chat navbar's .wordmark; mono stays for utility labels */
  font-family: var(--font-brand);
  font-size: 20px;
  font-weight: 560;
  letter-spacing: -0.01em;
  color: var(--label);
}
.landing-nav {
  width: min(720px, 100%);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 0;
}
.landing-hero { text-align: center; padding: 9vh 0 0; position: relative; width: min(1080px, 100%); }

/* floating requests behind the hero — depth of field */
.hero-bubbles {
  position: absolute;
  top: -4%;
  bottom: 0;
  left: 50%;
  width: min(100vw, 1760px);
  transform: translateX(-50%);
  pointer-events: none;
  z-index: 0;
}
.landing-hero > :not(.hero-bubbles) { position: relative; z-index: 1; }
.hb {
  position: absolute;
  left: var(--x);
  top: var(--y);
  max-width: 210px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  font-size: 12.5px;
  line-height: 1.45;
  text-align: left;
  color: var(--label-2);
  animation: hb-float var(--d) ease-in-out var(--dl) infinite alternate both;
  /* keep the float on the compositor — blur + shadows repainted every frame */
  will-change: transform;
  transform: translateZ(0);
}
.hb-bubble {
  padding: 10px 15px;
  border-radius: 19px;
  border-bottom-right-radius: 4px; /* the sent-message tail — reads as chat, not box */
  background: color-mix(in srgb, var(--blue, #22c7e5) 13%, #ffffff 80%);
  border: 0.5px solid color-mix(in srgb, var(--blue, #22c7e5) 22%, transparent);
}
.hb { opacity: var(--o, 0.8); transition: opacity 0.48s ease; }
.hb.swapping { opacity: 0; }
.hb-near { --o: 0.82; }
.hb-mid { --o: 0.58; filter: blur(0.7px); transform: scale(0.93); }
.hb-far { --o: 0.42; filter: blur(1.6px); transform: scale(0.86); }
@keyframes hb-float {
  from { translate: 0 -7px; }
  to { translate: 0 7px; }
}
@media (prefers-reduced-motion: reduce) { .hb { animation: none; } }
@media (max-width: 1100px) { .hb { display: none; } } /* bubbles need edge space — inside the column they fight the copy */

/* die Quelle — rings rippling out of the orb */
.quelle { position: relative; width: 104px; height: 104px; margin: 0 auto 24px; display: grid; place-items: center; }
.quelle .ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--cyan, #22c7e5) 45%, transparent);
  /* "both": delayed rings hold the 0% keyframe (invisible) until they start */
  animation: quelle-ripple 5.2s cubic-bezier(0.2, 0.6, 0.4, 1) infinite both;
  pointer-events: none;
}
.quelle .r2 { animation-delay: 1.7s; }
.quelle .r3 { animation-delay: 3.4s; }
@keyframes quelle-ripple {
  0% { transform: scale(0.6); opacity: 0; }
  18% { opacity: 0.55; }
  100% { transform: scale(2.2); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .quelle .ring { animation: none; opacity: 0.25; transform: scale(1.35); }
  .quelle .r2 { transform: scale(1.7); opacity: 0.15; }
  .quelle .r3 { display: none; }
}
.quelle .hero-orb { width: 84px; height: 84px; position: relative; z-index: 1; margin: 0; }
.quelle .hero-orb canvas { width: 78px; height: 78px; }
.quelle::before {
  content: '';
  position: absolute;
  inset: -52px;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--cyan, #22c7e5) 16%, transparent) 0%, transparent 62%);
  pointer-events: none;
}

.landing-h1 {
  /* the brand serif carries the hero — one loud element, everything else quiet */
  font-family: var(--font-brand);
  font-size: clamp(50px, 8.5vw, 80px);
  font-weight: 560;
  letter-spacing: -0.015em;
  line-height: 1.04;
  margin: 0 auto 16px;
}
.btn-ghost {
  /* the same glass the cards use — a hairline separator border disappears on the ice wallpaper */
  background: var(--glass);
  color: var(--label);
  border: 1px solid color-mix(in srgb, var(--label-3) 60%, transparent);
  border-radius: 999px;
  padding: 9px 20px;
  transition: transform 0.15s ease, opacity 0.15s ease, background-color 0.15s ease;
}
.btn-ghost:hover { background: var(--glass-strong); }
.landing-sub { font-size: 17px; line-height: 1.6; color: var(--label-2); margin: 0 auto 28px; max-width: 27em; text-wrap: balance; }
@media (max-width: 640px) { .landing-sub { font-size: 18px; } }
.landing-nav-right { display: flex; align-items: center; gap: 12px; }
.lang-switch {
  display: inline-flex;
  background: color-mix(in srgb, var(--label-3) 14%, transparent);
  border-radius: 999px;
  padding: 2.5px;
}
.lang-switch button {
  border: none;
  background: transparent;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--label-2);
  padding: 5px 12px;
  border-radius: 999px;
  cursor: pointer;
  transition: all 0.2s ease;
}
.lang-switch button.active {
  background: #fff;
  color: var(--label);
  box-shadow: 0 1px 4px rgba(12, 26, 29, 0.12);
}
.interest-form {
  display: flex;
  gap: 8px;
  justify-content: center;
  max-width: 420px;
  margin: 0 auto;
}
.interest-form .field {
  flex: 1;
  background: color-mix(in srgb, #ffffff 74%, transparent);
  border: 0.5px solid var(--separator);
  border-radius: 999px;
  padding: 12px 18px;
}
.interest-form .btn { border-radius: 999px; padding: 12px 22px; white-space: nowrap; }
@media (max-width: 480px) {
  .interest-form { flex-direction: column; }
  .interest-form .field { text-align: center; }
}
.landing-hint a { color: var(--label); }
.landing-hint { font-size: 13px; color: var(--label-3); margin-top: 12px; }
/* the demo is the strongest argument on the page — its link speaks up */
.landing-demo-link a, .demo-try a { color: var(--blue); font-weight: 650; text-decoration: none; font-size: 14.5px; }
.landing-demo-link { margin-top: 16px; }
.demo-try { text-align: center; margin-top: 18px; }
@media (max-width: 560px) { .br-wide { display: none; } }

.landing-kicker {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--label-3);
  margin-bottom: 12px;
  text-align: center;
}

/* chat vignette — the product demos itself, one chat, many trades */
.landing-demo { margin-top: 13vh; width: min(580px, 100%); }
/* the section speaks in the brand serif — mono uppercase is reserved for the
   utility labels below, so the headline no longer drowns in its own accent */
.demo-heading {
  font-family: var(--font-brand);
  font-size: clamp(30px, 4.5vw, 40px);
  font-weight: 560;
  letter-spacing: -0.012em;
  line-height: 1.15;
  text-align: center;
  text-wrap: balance;
  margin: 0 0 18px;
}
.industry-tabs { position: relative; display: flex; justify-content: center; gap: 8px; flex-wrap: wrap; margin-bottom: 16px; }
.industry-tabs button {
  /* unselected = a tappable glass object (the ghost button's language), not a
     disabled outline. Sans, not mono: these are controls now, and the page's
     controls speak sans — mono is reserved for pure metadata */
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0;
  padding: 7px 15px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--label-3) 55%, transparent);
  background: var(--glass);
  color: var(--label-2);
  cursor: pointer;
  transition: all 0.2s ease;
}
.industry-tabs button:hover { background: var(--glass-strong); }
.industry-tabs button:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.industry-tabs button.active {
  /* selected = the sent-message language: solid brand blue, like the chat's own bubble */
  background: var(--blue);
  border-color: var(--blue);
  color: #fff;
  box-shadow: 0 4px 14px color-mix(in srgb, var(--blue) 30%, transparent);
}
/* AFTER the base button rules — same specificity, so source order decides */
@media (max-width: 640px) {
  /* one edge-to-edge scrolling row instead of a ragged wrap; bigger touch targets */
  .industry-tabs {
    flex-wrap: nowrap;
    justify-content: flex-start;
    gap: 9px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    scroll-snap-type: x proximity;
    /* overflow-x forces vertical clipping too — vertical padding gives the
       pill shadow room, the negative margins hand the space back */
    margin: -10px -22px 2px;
    padding: 12px 22px 20px;
  }
  .industry-tabs::-webkit-scrollbar { display: none; }
  .industry-tabs button {
    /* real touch targets: ~44px tall per Apple's HIG */
    flex-shrink: 0;
    scroll-snap-align: center;
    font-size: 14px;
    padding: 12px 18px;
  }
}
.demo-row { display: flex; gap: 8px; align-items: flex-end; }
.demo-row.demo-mine { justify-content: flex-end; }
.demo-avatar { align-self: flex-end; }
.demo-bubble {
  max-width: 82%;
  padding: 10px 14px;
  border-radius: 18px;
  font-size: 16px;
  line-height: 1.5;
}
.demo-bubble.mine {
  background: var(--blue);
  color: #fff;
  border-bottom-right-radius: 6px;
  box-shadow: 0 4px 16px color-mix(in srgb, var(--blue) 28%, transparent);
}
.demo-bubble.assistant {
  /* --fill was made for inside a white window; floating on the ice it needs glass */
  background: var(--glass-strong);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  backdrop-filter: blur(18px) saturate(160%);
  border: 0.5px solid var(--glass-border);
  box-shadow: 0 6px 24px rgba(10, 26, 30, 0.09), 0 1px 2px rgba(10, 26, 30, 0.05);
  color: var(--label);
  border-bottom-left-radius: 6px;
}
.demo-bubble .sender { margin-bottom: 4px; }
.demo-chip {
  display: inline-block;
  margin-left: 6px;
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 3px 9px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--cyan, #22c7e5) 16%, transparent);
  color: color-mix(in srgb, var(--cyan, #22c7e5) 80%, #063a44);
  white-space: nowrap;
}
.demo-chip.live { background: rgba(52, 199, 89, 0.16); color: #1d7a3c; }

/* attached-photo placeholders in the demo request bubble */
.demo-thumbs { display: flex; gap: 6px; margin-top: 9px; }
.demo-thumb {
  width: 52px;
  height: 52px;
  border-radius: 10px;
  display: grid;
  place-items: center;
  color: rgba(255, 255, 255, 0.85);
  border: 0.5px solid rgba(255, 255, 255, 0.35);
}
.demo-thumb:nth-child(1) { background: linear-gradient(135deg, #7fb6c4, #4d7c8a); }
.demo-thumb:nth-child(2) { background: linear-gradient(135deg, #c4a97f, #8a6f4d); }
.demo-thumb:nth-child(3) { background: linear-gradient(135deg, #8fae93, #55705c); }
.hb .demo-thumbs { gap: 5px; margin: 0; }
.hb .demo-thumb { width: 34px; height: 34px; border-radius: 8px; border: none; box-shadow: none; }
/* the one completed exchange — question + answer swap as a single unit */
.hb-pair { flex-direction: column; align-items: flex-end; gap: 7px; max-width: 240px; }
.hb-reply-row { display: flex; align-items: flex-end; gap: 7px; align-self: flex-start; }
.hb-reply-bubble {
  background: color-mix(in srgb, #ffffff 86%, transparent);
  border: 0.5px solid var(--separator);
  border-radius: 19px;
  border-bottom-left-radius: 4px;
  border-bottom-right-radius: 19px;
}
.hb-avatar {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: #fff;
  display: grid;
  place-items: center;
  flex-shrink: 0;
  overflow: hidden;
}
.hb-avatar canvas { width: 20px; height: 20px; border-radius: 50%; display: block; }
/* attachments sit above the bubble, outside it, left-bound */
.demo-stack { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; max-width: 82%; }
.demo-stack .demo-bubble { max-width: 100%; }
.demo-stack .demo-thumbs { margin: 0; }

/* ---- demo browser: Quell's own workspace, in miniature ------------------
   Left the tool, right the client's site. A pointer types a real request into
   the composer, sends it, and the answer lands as a visible change in the
   page — ringed and labelled, the way the real preview marks it.

   The card's height is fixed by ratio, never by content: a hero that grows
   when a gallery appears and shrinks when a message scrolls out would shove
   the whole page around mid-sentence. Both panes clip instead. */
.landing-demo {
  width: min(1020px, 100%);
  /* the accent as ink: --blue on white is 3:1, too thin to read at 9px */
  --dbs-mark: color-mix(in srgb, var(--blue) 70%, #04303a);
  --dbs-ink: #1b2528;
  --dbs-ink-2: #5a686b;
  --dbs-line: rgba(27, 37, 40, 0.1);
}
/* The clip that hides the parked pointer lives HERE, not on .db-body: one level
   down it sits flush against the composer, and cut off its focus outline and
   its drop shadow. The card's own padding is the breathing room those need. */
.demo-browser { padding: 13px; border-radius: 22px; overflow: hidden; }
.db-body {
  position: relative; /* the pointer is placed against this box */
  display: grid;
  grid-template-columns: minmax(0, 37fr) minmax(0, 63fr);
  gap: 13px;
  aspect-ratio: 2 / 1;
  min-height: 440px;
  max-height: 540px;
  /* Chrome derives the WIDTH from the ratio once min-height clamps the height,
     which pushed the card past the viewport between 700 and 950px. */
  max-width: 100%;
  isolation: isolate;
  /* The pointer waits just off-stage and flies in. What keeps it from giving
     the page a horizontal scrollbar is the clip on .demo-browser — clipping
     here would land on the composer's outline and shadow instead. */
}

/* ---- left: the chat ---- */
/* No card of its own: the chat IS the glass, the site is paper laid on it.
   Two bordered panes side by side would read as two windows, not as one tool
   looking at one website. */
.db-chat { display: flex; flex-direction: column; min-height: 0; }
.db-chat-top { display: flex; align-items: center; gap: 8px; padding: 2px 4px 12px; flex: none; }
.db-orb { align-self: center; width: 22px; height: 22px; }
.db-chat-name { font-size: 13px; font-weight: 650; letter-spacing: -0.01em; color: var(--label); }

.demo-thread {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 9px;
  padding: 4px 3px 12px;
  overflow: hidden;
  /* the thread clips from the top by design — a hard cut mid-word reads as a
     bug, a fade reads as a conversation that started before you looked */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 18px);
  mask-image: linear-gradient(to bottom, transparent 0, #000 18px);
}
/* Bubbles keep their size. As flex children they would shrink once the thread
   runs full, squashing a bubble mid-morph — the thread clips at the top. */
.db-chat .demo-bubble { flex: none; max-width: 92%; font-size: 14px; padding: 9px 13px; border-radius: 15px; }
.db-chat .demo-bubble.mine { align-self: flex-end; }
.db-chat .demo-bubble.assistant {
  align-self: flex-start;
  /* the glass recipe is for floating on the wallpaper; inside a glass card a
     second backdrop-filter only costs a snapshot and muddies the text */
  background: #fff;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border: 0.5px solid var(--separator);
  box-shadow: 0 2px 8px rgba(10, 26, 30, 0.06);
}
.db-chat .demo-bubble .typing { margin: 0; padding: 2px 0; }
.demo-rise { animation: demo-rise 0.34s cubic-bezier(0.16, 1, 0.3, 1) both; }
@keyframes demo-rise { from { opacity: 0; transform: translateY(7px) scale(0.985); } }
/* The opening line arrives in an empty pane with nobody to announce it, so it
   may take longer than a reply inside a running conversation. */
.demo-rise-open { animation: demo-rise-open 0.66s cubic-bezier(0.16, 1, 0.3, 1) both; }
@keyframes demo-rise-open { from { opacity: 0; transform: translateY(11px) scale(0.97); } }

.demo-composer {
  flex: none;
  display: flex;
  align-items: flex-end;
  gap: 8px;
  padding: 6px 6px 6px 12px;
  background: #fff;
  border: 0.5px solid var(--separator);
  border-radius: 14px;
  box-shadow: 0 2px 8px rgba(10, 26, 30, 0.06);
  transition: border-color 0.22s ease, outline-color 0.22s ease;
  outline: 2px solid transparent;
  outline-offset: 1px;
}
.demo-composer.is-focus {
  border-color: color-mix(in srgb, var(--blue) 55%, transparent);
  outline-color: color-mix(in srgb, var(--blue) 26%, transparent);
}
.demo-input {
  flex: 1;
  min-width: 0;
  font-size: 14px;
  line-height: 1.45;
  color: var(--label);
  /* wrap, never clip — otherwise the words being typed disappear */
  white-space: normal;
  overflow-wrap: anywhere;
  /* the send button stays at the bottom on two lines (align-items: flex-end),
     so one-line text needs matching height or it sits lower than the button */
  min-height: 26px;
  padding: 3.5px 0;
}
.demo-input.is-empty::before {
  content: attr(data-placeholder);
  color: color-mix(in srgb, var(--label) 68%, #fff); /* 4.9:1 — --label-2 is 2.6:1 */
}
/* the caret as a pseudo-element: a child span would defeat the empty state */
.demo-input::after {
  content: '';
  display: inline-block;
  width: 1.5px;
  height: 1em;
  margin-left: 1px;
  vertical-align: -0.16em;
  background: var(--blue);
  opacity: 0;
}
.demo-composer.is-focus .demo-input::after { animation: demo-caret 1.05s steps(1) infinite; }
@keyframes demo-caret { 0%, 55% { opacity: 1; } 56%, 100% { opacity: 0; } }
.demo-send {
  flex: none;
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: 9px;
  background: var(--blue);
  color: #fff;
  transition: transform 0.16s ease, filter 0.16s ease;
}
.demo-send svg { display: block; }
.demo-send.is-press { transform: scale(0.86); filter: brightness(1.12); }

/* ---- right: the client's website ---- */
.db-preview {
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: #fff;
  border: 0.5px solid var(--separator);
  border-radius: 16px;
  box-shadow: 0 10px 30px rgba(10, 26, 30, 0.1), 0 1px 2px rgba(10, 26, 30, 0.05);
  overflow: hidden;
}
.db-bar {
  flex: none;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 9px 13px;
  border-bottom: 1px solid var(--dbs-line);
}
.db-dots { display: inline-flex; gap: 5px; flex: none; }
.db-dots i { width: 7px; height: 7px; border-radius: 50%; background: rgba(27, 37, 40, 0.13); }
.db-url {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--dbs-ink-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.db-live {
  margin-left: auto;
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--dbs-ink-2);
  transition: color 0.3s ease;
}
.db-live b { width: 5px; height: 5px; border-radius: 50%; background: currentColor; }
.db-preview.is-changed .db-live { color: var(--dbs-mark); }

/* The mock page is small, but it has real page anatomy: header with nav, a
   hero split between words and picture, a titled section. Without the picture
   and the section frame it reads as a text document, not as a website. */
.db-site { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }
.dbs-nav { flex: none; display: flex; align-items: center; gap: 9px; padding: 11px 15px; border-bottom: 1px solid var(--dbs-line); }
.dbs-logo {
  width: 20px;
  height: 20px;
  border-radius: 6px;
  display: grid;
  place-items: center;
  font-size: 10px;
  font-weight: 700;
  background: var(--dbs-tint);
  color: #fff;
}
.dbs-name { font-family: var(--font-brand); font-size: 12.5px; font-weight: 560; color: var(--dbs-ink); }
.dbs-menu { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.dbs-menu i { width: 16px; height: 2.5px; border-radius: 2px; background: rgba(27, 37, 40, 0.15); }
.dbs-cta { width: 32px; height: 12px; border-radius: 999px; border: 1px solid color-mix(in srgb, var(--dbs-tint) 45%, transparent); }

/* hero: words left, picture right — the strongest "this is a website" cue */
.dbs-hero { flex: none; display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); gap: 16px; align-items: center; padding: 20px 15px; }
.dbs-head { font-family: var(--font-brand); font-size: 18px; font-weight: 560; line-height: 1.16; letter-spacing: -0.015em; color: var(--dbs-ink); }
.dbs-line { font-size: 10.5px; line-height: 1.5; color: var(--dbs-ink-2); margin-top: 8px; max-width: 34ch; }
.dbs-btn { display: inline-block; margin-top: 13px; font-size: 10px; font-weight: 700; padding: 7px 14px; border-radius: 999px; background: var(--dbs-tint); color: #fff; }
/* a photo, not a glow: one flat gradient in the client's own tone plus a
   horizon arc, so six mock sites never look like the same template */
.dbs-shot {
  /* wider than tall: the picture must not push the changeable section out of
     the frame, and a website hero image is rarely a portrait */
  aspect-ratio: 3 / 2;
  border-radius: 8px;
  overflow: hidden;
  position: relative;
  background: linear-gradient(155deg, var(--dbs-tint), color-mix(in srgb, var(--dbs-tint) 34%, #eef3f4) 84%);
}
.dbs-shot::after {
  content: '';
  position: absolute;
  inset: auto -12% -34% 38%;
  height: 60%;
  border-radius: 50% 50% 0 0;
  background: rgba(255, 255, 255, 0.26);
}

/* the changeable section, always framed and titled like a real one */
.dbs-host { flex: none; }
.dbs-sec { position: relative; padding: 14px 15px; border-top: 1px solid var(--dbs-line); background: rgba(27, 37, 40, 0.025); }
.dbs-sec-t { display: block; font-size: 9px; font-weight: 700; letter-spacing: 0.11em; text-transform: uppercase; color: var(--dbs-ink-2); margin-bottom: 10px; }
.dbs-spacer { flex: 1; min-height: 0; }

/* three columns with the number carrying the weight — prices, hours */
.dbs-rows { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.dbs-rows div { display: flex; flex-direction: column; padding: 10px 12px; border-radius: 9px; background: #fff; border: 1px solid var(--dbs-line); }
.dbs-rows span { display: block; font-size: 8.5px; font-weight: 600; letter-spacing: 0.07em; text-transform: uppercase; color: var(--dbs-ink-2); }
/* the numbers line up across the three tiles even when one label wraps */
.dbs-rows b { display: block; margin-top: auto; padding-top: 4px; font-size: 13.5px; font-weight: 700; letter-spacing: -0.02em; color: var(--dbs-ink); font-variant-numeric: tabular-nums; }
/* the closed day steps back and the changed one lights up — otherwise a
   single digit moves and nobody sees the difference */
.dbs-rows .is-off { background: transparent; }
.dbs-rows .is-off b { font-weight: 600; font-size: 11px; color: var(--dbs-ink-2); }
.dbs-rows .is-hot { border-color: color-mix(in srgb, var(--blue) 50%, transparent); background: color-mix(in srgb, var(--blue) 8%, #fff); }
.dbs-rows .is-hot span, .dbs-rows .is-hot b { color: var(--dbs-mark); }

/* service cards, each with its own picture strip */
.dbs-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.dbs-card { border-radius: 8px; background: #fff; border: 1px solid var(--dbs-line); overflow: hidden; }
.dbs-card em { display: block; height: 34px; background: linear-gradient(145deg, var(--dbs-tint), color-mix(in srgb, var(--dbs-tint) 30%, #eef3f4) 86%); }
.dbs-card div { padding: 9px 10px 11px; display: flex; flex-direction: column; gap: 6px; }
.dbs-card b { font-size: 10px; font-weight: 700; letter-spacing: -0.01em; color: var(--dbs-ink); }
.dbs-card i { height: 3px; border-radius: 2px; background: rgba(27, 37, 40, 0.1); }
.dbs-card i:last-child { width: 60%; }

/* a project gallery */
.dbs-gal { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.dbs-gal em { display: block; aspect-ratio: 4 / 3; border-radius: 6px; background: linear-gradient(150deg, var(--dbs-tint), color-mix(in srgb, var(--dbs-tint) 28%, #eef3f4) 82%); }
.dbs-gal em:nth-child(2) { filter: hue-rotate(-14deg) brightness(1.05); }
.dbs-gal em:nth-child(3) { filter: hue-rotate(12deg) brightness(0.94); }
.dbs-gal em:nth-child(4) { filter: hue-rotate(-6deg) brightness(1.1); }

/* a download teaser: cover, title, button */
.dbs-teaser { display: flex; align-items: center; gap: 12px; padding: 10px 11px; border-radius: 9px; background: #fff; border: 1px solid var(--dbs-line); }
.dbs-teaser em { flex: none; width: 36px; height: 46px; border-radius: 4px; background: linear-gradient(150deg, var(--dbs-tint), color-mix(in srgb, var(--dbs-tint) 30%, #eef3f4) 84%); }
.dbs-teaser div { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 7px; }
.dbs-teaser b { font-size: 10.5px; font-weight: 700; letter-spacing: -0.01em; color: var(--dbs-ink); }
.dbs-teaser i { height: 3px; border-radius: 2px; background: rgba(27, 37, 40, 0.1); }
.dbs-teaser i:last-child { width: 58%; }
.dbs-teaser span { flex: none; font-size: 9.5px; font-weight: 700; padding: 7px 12px; border-radius: 999px; background: var(--dbs-tint); color: #fff; white-space: nowrap; }

/* a contact strip */
.dbs-contact { display: flex; flex-wrap: wrap; gap: 7px; }
.dbs-contact div {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 11px;
  border-radius: 999px;
  background: #fff;
  border: 1px solid var(--dbs-line);
  font-size: 10px;
  font-weight: 600;
  color: var(--dbs-ink);
}
.dbs-contact i { flex: none; width: 6px; height: 6px; border-radius: 50%; background: var(--dbs-tint); }

/* the quiet "before" filler — two text bars under a heading */
.dbs-bars { display: flex; flex-direction: column; gap: 5px; }
.dbs-bars i { height: 3px; border-radius: 2px; background: rgba(27, 37, 40, 0.09); }
.dbs-bars i:nth-child(1) { width: 92%; }
.dbs-bars i:nth-child(2) { width: 74%; }

/* ---- the mark: ring and chip ---- */
/* The flash draws the eye; the hairline that stays IS the marker. It does not
   fade out — the visitor should still see what changed while reading the
   reply. Drawn on an overlay so only colour and opacity animate; the section
   runs full-bleed, so an outward outline would be clipped at the pane edge. */
.dbs-sec.is-changed::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  border: 1.5px solid var(--blue);
  animation: dbs-mark 1.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes dbs-mark {
  0% { opacity: 0; border-width: 2px; }
  18% { opacity: 1; border-width: 2px; }
  65% { opacity: 1; border-width: 2px; border-color: var(--blue); }
  100% { opacity: 1; border-width: 1.5px; border-color: color-mix(in srgb, var(--blue) 50%, transparent); }
}
.dbs-chip {
  position: absolute;
  top: -9px;
  right: 11px;
  /* above the ring, the section and the hero picture beside it — a marker
     with a clipped edge reads as a rendering fault */
  z-index: 3;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: #0c1a1d;
  color: #d9f6fb;
  padding: 3px 9px 3px 7px;
  border-radius: 999px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.01em;
  white-space: nowrap;
  box-shadow: 0 2px 7px rgba(10, 26, 30, 0.3);
  animation: dbs-chip 0.42s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.dbs-chip svg { display: block; color: var(--cyan); }
@keyframes dbs-chip { from { opacity: 0; transform: translateY(4px) scale(0.92); } }

/* ---- the pointer ---- */
/* It walks to the composer and taps, the way a person would. Transform-only,
   so it never costs a layout. */
.db-cursor {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 4;
  pointer-events: none;
  opacity: 0;
  transform: translate3d(-50px, -50px, 0);
  transition: transform 0.72s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.3s ease;
}
.db-cursor.visible { opacity: 1; }
.db-cursor svg { display: block; filter: drop-shadow(0 2px 5px rgba(10, 26, 30, 0.35)); }
.db-cursor-ring {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 2px solid var(--blue);
  opacity: 0;
  transform: scale(0.4);
}
.db-cursor.tapping .db-cursor-ring { animation: db-tap 0.55s ease-out 1; }
@keyframes db-tap {
  0% { opacity: 0.9; transform: scale(0.4); }
  100% { opacity: 0; transform: scale(3.4); }
}
.db-cursor.tapping svg { transform: scale(0.88); transition: transform 0.12s ease; }

@media (max-width: 700px) {
  /* Stacked, the chat goes ON TOP and the preview below — cause over effect.
     The typing happens above, the change appears below, and the eye follows
     the sequence downward instead of jumping back and forth. */
  .db-body {
    grid-template-columns: 1fr;
    grid-template-rows: minmax(0, 45fr) minmax(0, 55fr);
    aspect-ratio: auto;
    height: 700px;
    min-height: 0;
    max-height: none;
    gap: 11px;
  }
  .demo-browser { padding: 11px; border-radius: 18px; }
  .db-chat-top { padding-bottom: 9px; }
  .demo-thread { gap: 8px; padding-bottom: 10px; }
  .db-chat .demo-bubble { max-width: 86%; }
  /* The hero picture becomes a flat banner above the words. It may take only
     as much room as leaves the changed section safely in frame — cropped, the
     animation shows nothing. */
  .dbs-hero { grid-template-columns: 1fr; gap: 10px; padding: 13px 13px 15px; }
  .dbs-shot { aspect-ratio: auto; height: 52px; order: -1; }
  .dbs-head { font-size: 16px; }
  .dbs-line, .dbs-btn { display: none; }
  .dbs-nav { padding: 10px 13px; }
  .dbs-sec { padding: 12px 13px; }
}
@media (max-width: 460px) {
  .db-body { height: 680px; grid-template-rows: minmax(0, 46fr) minmax(0, 54fr); }
  .dbs-shot { height: 44px; }
  .dbs-head { font-size: 15px; }
  .db-chat .demo-bubble { font-size: 13.5px; }
  .dbs-rows { gap: 6px; }
  .dbs-rows div { padding: 8px 9px; }
  .dbs-rows b { font-size: 12px; }
  .dbs-cards, .dbs-gal { gap: 6px; }
  .dbs-card em { height: 26px; }
  .dbs-card div { padding: 8px 9px 9px; }
  .dbs-contact div { font-size: 9.5px; padding: 6px 9px; }
}

/* Motion off: no pointer, no typing — every scenario arrives as a finished
   state instead. The ring and the chip must still land, or the change loses
   the one thing that points at it. */
@media (prefers-reduced-motion: reduce) {
  .db-cursor { display: none; }
}

/* ---- build section: a marketing-team request assembles a real section ---- */
.landing-build { margin-top: 13vh; width: min(580px, 100%); text-align: center; }
.landing-build .build-sub { margin-bottom: 30px; }
.build-demo { display: flex; flex-direction: column; gap: 14px; text-align: left; }
/* the one contained card on the page — deliberately: it depicts a piece of a
   website, not our UI. Blocks inside assemble via the reveal stagger. */
.build-canvas {
  width: min(400px, 92%);
  margin: 2px auto;
  border-radius: 18px;
  overflow: hidden; /* the full-bleed preview bar must not poke past the rounded corners */
  padding: 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}
/* content fades in place — the generic rv rise looks like parts flying
   through the card; only the card itself moves. (Never give these children
   their own opacity rule — it would out-specificity the .rv reveal.) */
.build-canvas .rv, .build-canvas .rv.in { transform: none; }
/* the preview bar frames everything below as the CLIENT's site, not this page */
.bc-bar {
  width: calc(100% + 40px);
  margin: -20px -20px 6px;
  padding: 8px 14px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 0.5px solid var(--separator);
  background: rgba(255, 255, 255, 0.45);
}
.bc-url { font-family: var(--font-mono); font-size: 9.5px; letter-spacing: 0.04em; color: var(--label-3); }
.bc-tag {
  font-family: var(--font-mono);
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--cyan, #22c7e5) 16%, transparent);
  color: color-mix(in srgb, var(--cyan, #22c7e5) 80%, #063a44);
}
.bc-head { font-size: 15px; font-weight: 700; letter-spacing: -0.01em; color: var(--label); }
.bc-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 4px; width: 100%; }
.bc-card {
  background: #fff;
  border: 0.5px solid var(--separator);
  border-radius: 10px;
  padding: 10px 11px;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.bc-card blockquote { font-size: 11.5px; line-height: 1.4; color: var(--label); }
.bc-card figcaption { font-size: 9.5px; color: var(--label-3); }
.bc-logo {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  color: #fff;
  font-size: 10px;
  font-weight: 700;
}
.bc-logo-a { background: linear-gradient(135deg, #7fb6c4, #4d7c8a); }
.bc-logo-b { background: linear-gradient(135deg, #c4a97f, #8a6f4d); }
.bc-logo-c { background: linear-gradient(135deg, #8fae93, #55705c); }
.bc-btn {
  /* mock content, not a real control: quiet outline in the card family —
     solid brand blue here competed with the page's actual CTAs */
  display: inline-block;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--label-2);
  padding: 6px 14px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--label-3) 55%, transparent);
  background: #fff;
  margin-top: 6px;
}
@media (max-width: 640px) { .bc-grid { grid-template-columns: 1fr; } }

/* three promises — quiet columns over a hairline */
.landing-promises {
  margin-top: 12vh;
  width: min(720px, 100%);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 40px;
}
.landing-promises .promise {
  border-top: 1px solid color-mix(in srgb, var(--cyan, #22c7e5) 30%, transparent);
  padding-top: 16px;
  text-align: left;
}
.landing-promises .landing-kicker { text-align: left; margin-bottom: 8px; color: color-mix(in srgb, var(--cyan, #22c7e5) 70%, #063a44); }
.landing-promises .promise p:last-child { font-size: 15.5px; line-height: 1.6; color: var(--label-2); }
@media (max-width: 640px) { .landing-promises { grid-template-columns: 1fr; gap: 26px; } }

.landing-footer { margin-top: 12vh; text-align: center; }
.landing-footer .brand-lockup { justify-content: center; opacity: 0.55; }
.landing-footer .brand-logo { height: 12px; }
.landing-by { font-size: 12.5px; color: var(--label-3); margin-top: 10px; }
.landing-by a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }

.login-back { margin-top: 16px; font-size: 13px; }
.login-back a { color: var(--label-3); text-decoration: none; }
.login-back a:hover { color: var(--label-2); }

/* ---- login ---- */
.login { min-height: 100vh; display: grid; place-items: center; padding: 24px; }
/* no card between the client and the door — the form floats on the ice
   like everything else; fields carry their own glass */
.login-card { width: min(360px, 100%); text-align: center; }
.login-orb {
  width: 68px;
  height: 68px;
  margin: 0 auto 18px;
  border-radius: 50%;
  background: #fff; /* light mask — dark bled through the canvas's antialiased rim */
  display: grid;
  place-items: center;
  box-shadow: 0 12px 34px rgba(34, 199, 229, 0.28), 0 2px 8px rgba(12, 26, 29, 0.08);
}
.login-orb canvas { width: 64px; height: 64px; border-radius: 50%; display: block; }
.login-title {
  font-family: var(--font-brand);
  font-size: 42px;
  font-weight: 560;
  letter-spacing: -0.015em;
  margin: 0 0 10px;
}
.login-sub { font-size: 16px; line-height: 1.55; color: var(--label-2); margin-bottom: 26px; text-wrap: balance; }
#login-form { display: grid; gap: 10px; }
#login-form .field {
  background: color-mix(in srgb, #ffffff 74%, transparent);
  border: 0.5px solid var(--separator);
  border-radius: 999px;
  padding: 13px 20px;
}
#login-form .btn-block { margin-top: 6px; }
.login-lockup { margin-top: 22px; opacity: 0.55; }
.login-lockup .brand-logo { height: 12px; }
.login-error { color: var(--red); font-size: 13px; margin-top: 12px; min-height: 1em; }

/* ---- workspace: chat rail + persistent live preview ---- */
/* The window never scrolls here — the feed and the preview scroll internally,
   so the publish bar and the composer are always at hand. */
.workspace {
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh; /* dvh: the iOS toolbar must not hide the composer */
  overflow: hidden;
}
.workspace-body {
  flex: 1;
  min-height: 0; /* lets the children own their scroll */
  display: grid;
  grid-template-columns: minmax(340px, 27%) 1fr;
}
.chat-rail {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  border-right: 0.5px solid var(--separator);
}

/* the preview is the site itself — it gets the room */
.preview-pane {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  padding: 14px 16px calc(14px + env(safe-area-inset-bottom)) 14px;
}
.preview-pane-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 4px 10px;
}
/* device toggle — the preview is the client's site, seen the way their
   visitors see it */
.device-seg { display: inline-flex; background: var(--fill); border-radius: 999px; padding: 2px; }
.device-btn {
  display: grid;
  place-items: center;
  width: 30px;
  height: 26px;
  border: none;
  background: transparent;
  color: var(--label-3);
  border-radius: 999px;
  cursor: pointer;
  transition: color 0.15s ease, background-color 0.15s ease;
}
.device-btn:hover { color: var(--label-2); }
.device-btn.active { background: #fff; color: var(--label); box-shadow: 0 1px 3px rgba(12, 26, 29, 0.14); }

/* page picker */
.page-picker { position: relative; }
.page-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font: inherit;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--label-2);
  background: var(--fill);
  border: none;
  border-radius: 999px;
  padding: 6px 11px 6px 13px;
  cursor: pointer;
  max-width: 230px;
}
.page-btn:hover { color: var(--label); }
.page-btn-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.page-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 30;
  min-width: 190px;
  max-height: 300px;
  overflow-y: auto;
  padding: 5px;
  background: var(--glass-strong);
  -webkit-backdrop-filter: blur(24px) saturate(170%);
  backdrop-filter: blur(24px) saturate(170%);
  border: 0.5px solid var(--glass-border);
  border-radius: 14px;
  box-shadow: var(--glass-shadow);
}
.page-menu button {
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  font-size: 13.5px;
  color: var(--label);
  background: transparent;
  border: none;
  border-radius: 9px;
  padding: 8px 11px;
  cursor: pointer;
}
.page-menu button:hover { background: var(--fill); }
.page-menu button.active { color: var(--blue); font-weight: 650; }
.pane-actions { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.pane-icon-btn {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border: none;
  border-radius: 999px;
  background: var(--fill);
  color: var(--label-2);
  cursor: pointer;
  text-decoration: none;
  transition: color 0.15s ease, background-color 0.15s ease;
}
.pane-icon-btn:hover { color: var(--label); }
.select-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--label);
  background: var(--glass);
  border: 1px solid color-mix(in srgb, var(--label-3) 60%, transparent);
  border-radius: 999px;
  padding: 6px 14px;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.select-btn:hover { background: var(--glass-strong); }
.select-btn.active {
  background: color-mix(in srgb, var(--cyan) 16%, #ffffff 70%);
  border-color: color-mix(in srgb, var(--cyan) 55%, transparent);
  color: #075a6b;
}
.preview-pane-body {
  position: relative;
  flex: 1;
  min-height: 0;
  border-radius: 18px;
  overflow: hidden;
  border: 0.5px solid var(--glass-border);
  background: #fff;
  box-shadow: var(--glass-shadow);
  /* The client site inside sizes to THIS box, not to the browser window, and
     anything it pins with position:fixed — a cookie bar, a notice popup, a
     dimming overlay — pins to THIS box too. Both are the iframe's own job now
     that the demo site is a document rather than a div in this pane, but they
     still hold the box itself steady against whatever is put in it. */
  container-type: inline-size;
  contain: layout;
}
/* phone view: the same page, at the width a visitor's phone gives it */
.preview-pane.device-mobile .preview-pane-body {
  width: 390px;
  max-width: 100%;
  margin: 0 auto;
  border-radius: 28px;
  border: 8px solid #14201f;
  box-shadow: 0 22px 60px rgba(10, 26, 30, 0.28);
}
/* focus mode: the site gets the whole window, chat steps aside.
   ONE column — with the rail display:none'd, the pane becomes the first grid
   item, and a `0 1fr` template would drop it into the zero-width track. */
.workspace.focus-preview .workspace-body { grid-template-columns: 1fr; }
.workspace.focus-preview .chat-rail { display: none; }
#focus-btn[aria-pressed='true'] { background: color-mix(in srgb, var(--cyan) 18%, transparent); color: #075a6b; }
.preview-pane-body iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: none;
  background: #fff;
}
.preview-pane-body .preview-spinner { z-index: 1; }
.preview-pane-body.loaded .preview-spinner { opacity: 0; pointer-events: none; }

/* publish — the one primary action of the whole bar */
.publish-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  padding: 8px 16px;
}
.publish-btn:disabled { opacity: 0.45; }
.count-badge {
  display: inline-grid;
  place-items: center;
  min-width: 19px;
  height: 19px;
  padding: 0 5px;
  border-radius: 999px;
  background: #fff;
  color: var(--blue);
  font-style: normal;
  font-size: 12px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
/* the moment something is publishable, the button quietly asks for attention:
   one swell that decelerates like a real object — no overshoot, no bounce */
.publish-btn.armed { animation: publish-arm 0.55s cubic-bezier(0.16, 1, 0.3, 1) 1; }
@keyframes publish-arm { 35% { transform: scale(1.05); } }

/* ---- /demo: the demo site is a document in the preview iframe now, and it
   styles itself. The ring, the chip and select mode live in quell-frame.js,
   inside the frame, because the frame cannot see this stylesheet. What is
   left here is the portal's own side of the demo. ---- */
.composer-hint .demo-cta-link { color: var(--blue); font-weight: 700; text-decoration: none; }
/* The demo's last word is Quell talking, not a system label — the mono
   all-caps hint style is for states, and this one is a sentence. */
.composer-hint:has(.demo-cta-link) {
  font-family: var(--font-ui);
  font-size: 13.5px;
  font-weight: 500;
  line-height: 1.45;
  letter-spacing: 0;
  text-transform: none;
  color: var(--label);
}

/* The demo's opening suggestions are not labels — they are whole sentences the
   visitor can send. So they are drafted messages: the shape and the tint of an
   outgoing bubble, unsent, filling in under the finger as it is pressed. */
.demo-suggest { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; margin: 12px 0 4px; }
.suggest-chip {
  display: block;
  max-width: 78%;
  min-height: 44px;
  text-align: left;
  font: inherit;
  font-size: 15px;
  line-height: 1.4;
  color: var(--label);
  background: color-mix(in srgb, var(--blue) 7%, #fff 55%);
  border: 1px solid color-mix(in srgb, var(--blue) 20%, transparent);
  border-radius: 20px;
  border-bottom-right-radius: 7px;
  padding: 11px 15px;
  cursor: pointer;
  transition: background-color 0.16s ease, border-color 0.16s ease;
}
.suggest-chip:hover { background: color-mix(in srgb, var(--blue) 12%, #fff 58%); }
.suggest-chip:active { background: color-mix(in srgb, var(--blue) 16%, #fff 60%); }
.suggest-chip:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }

/* ---- the dock: the conversation, over the live site, below 901px ---------
   Desktop keeps the two-column workspace and never sees any of this. */
.dock-handle,
.dock-strip { display: none; }


.navbar { position: sticky; top: 0; z-index: 20; }
.glass-bar {
  background: color-mix(in srgb, var(--glass) 82%, transparent);
  -webkit-backdrop-filter: blur(24px) saturate(170%);
  backdrop-filter: blur(24px) saturate(170%);
  border-bottom: 0.5px solid var(--separator);
}
.navbar-inner {
  max-width: 720px;
  margin: 0 auto;
  padding: 13px 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.pill {
  font-size: 13px;
  font-weight: 600;
  color: var(--label-2);
  background: var(--fill);
  border-radius: 999px;
  padding: 5px 12px;
  white-space: nowrap;
  transition: background-color 0.25s ease, color 0.25s ease;
}
/* the pill mirrors the composer mode: blue while building, red at 0 left */
.pill.build { background: color-mix(in srgb, var(--blue, #22c7e5) 16%, transparent); color: color-mix(in srgb, var(--blue, #22c7e5) 78%, #063a44); }
.pill.empty { background: color-mix(in srgb, var(--red) 14%, transparent); color: color-mix(in srgb, var(--red) 82%, #3a0f0b); }
.navbar-right { display: flex; align-items: center; gap: 8px; }
.logout-btn {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border: none;
  border-radius: 999px;
  background: var(--fill);
  color: var(--label-2);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.logout-btn:hover { color: var(--label); }

.feed {
  flex: 1;
  min-height: 0;
  width: 100%;
  margin: 0 auto;
  padding: 20px 16px 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  overflow-y: auto;
  overscroll-behavior: contain;
}
/* the workspace bar spans the full window — no reading column to center on */
.workspace .navbar-inner { max-width: none; }

.feed-more {
  align-self: center;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--label-2);
  background: var(--fill);
  border: none;
  border-radius: 999px;
  padding: 8px 16px;
  margin: 2px 0 10px;
  cursor: pointer;
}

/* day/context divider — the Erlach mono voice */
.divider {
  align-self: center;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--label-3);
  margin: 18px 0 10px;
}

/* ---- bubbles ---- */
.msg-row { display: flex; gap: 9px; margin-top: 10px; }
.msg-row.mine { justify-content: flex-end; }
/* attachments live above the bubble, outside it, left-bound to its edge */
.msg-stack { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; max-width: 78%; }
.msg-stack .bubble { max-width: 100%; }
.msg-stack .bubble-thumbs { margin: 0; }

.avatar {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: #fff; /* light mask — dark bled through the canvas's antialiased rim */
  flex-shrink: 0;
  align-self: flex-end;
  display: grid;
  place-items: center;
  overflow: hidden;
  box-shadow: 0 1px 5px rgba(10, 26, 30, 0.18);
}
/* fallback dot behind the orb canvas (shows if WebGL is unavailable) */
.avatar::after { content: ''; grid-area: 1/1; width: 9px; height: 9px; border-radius: 50%; background: var(--cyan); }
.avatar canvas { grid-area: 1/1; width: 100%; height: 100%; display: block; position: relative; z-index: 1; }
.avatar.working { animation: avatar-breathe 1.6s ease-in-out infinite; }
.avatar.avatar-team { background: var(--fill); color: var(--label-2); border: 0.5px solid var(--separator); }
.avatar.avatar-team::after { content: none; } /* the cyan fallback dot belongs under the orb canvas only */
.avatar.avatar-team svg { grid-area: 1/1; }
@keyframes avatar-breathe { 50% { transform: scale(1.12); box-shadow: 0 1px 12px rgba(34, 199, 229, 0.5); } }
.msg-row .avatar-spacer { width: 26px; flex-shrink: 0; }

@media (max-width: 520px) {
  .lockup-x, .lockup-client { display: none; } /* wordmark + pill only — the lockup wrapped and blew up the bar */
  .navbar-inner { padding: 12px 14px; }
  .bubble, .msg-stack { max-width: 88%; }
  .feed { padding: 18px 12px 12px; }
  /* thumb-sized controls in the composer */
  .attach-btn, .send-btn { width: 40px; height: 40px; }
  .mode-switch button { font-size: 14px; padding: 9px 18px; }
  .logout-btn { width: 36px; height: 36px; }
}

.bubble {
  max-width: 78%;
  padding: 11px 15px;
  font-size: 16px;
  border-radius: 20px;
  background: var(--glass-strong);
  -webkit-backdrop-filter: blur(20px) saturate(170%);
  backdrop-filter: blur(20px) saturate(170%);
  border: 0.5px solid var(--glass-border);
  box-shadow: 0 2px 10px rgba(10, 26, 30, 0.06);
  overflow-wrap: anywhere;
}
.bubble.assistant { border-bottom-left-radius: 7px; }
.bubble.mine {
  background: color-mix(in srgb, var(--blue) 16%, white 60%);
  border-color: color-mix(in srgb, var(--blue) 22%, transparent);
  border-bottom-right-radius: 7px;
}
.bubble.question { border-color: color-mix(in srgb, var(--cyan) 55%, transparent); box-shadow: 0 2px 14px color-mix(in srgb, var(--cyan) 22%, transparent); }
.bubble .sender,
.demo-bubble .sender {
  display: block;
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--label-3);
  margin-bottom: 3px;
}
.bubble-time { font-size: 11px; color: var(--label-3); margin-top: 4px; text-align: right; }
.bubble-meta { display: block; margin-top: 8px; }
.bubble-meta .elapsed { margin-left: 0; }
.job-duration {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--label-3);
  font-variant-numeric: tabular-nums;
}
.elapsed {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--label-3);
  margin-left: 10px;
  font-variant-numeric: tabular-nums;
}

.data-changes { list-style: none; margin: 4px 0 2px; display: flex; flex-direction: column; gap: 5px; }
.data-changes li { font-size: 14px; color: var(--label); display: flex; gap: 8px; align-items: baseline; }
.dc-op { font-weight: 700; width: 16px; text-align: center; flex-shrink: 0; }
.dc-insert { color: #1d7a3c; }
.dc-update { color: color-mix(in srgb, var(--cyan, #22c7e5) 80%, #063a44); }
.dc-delete { color: var(--red, #d33); }

.preview-label {
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--label-3);
  margin: 14px 0 6px;
}

.preview-spinner {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: color-mix(in srgb, var(--glass) 88%, transparent);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  transition: opacity 0.35s ease;
}
.preview-spinner span {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 2.5px solid color-mix(in srgb, var(--blue) 25%, transparent);
  border-top-color: var(--blue);
  animation: preview-spin 0.8s linear infinite;
}
@keyframes preview-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .preview-spinner span { animation-duration: 2.4s; }
}

.bubble-thumbs { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
.bubble-thumbs img { width: 84px; height: 84px; object-fit: cover; border-radius: 12px; border: 0.5px solid var(--separator); cursor: zoom-in; }

/* typing/progress bubble */
.working-label { color: var(--label-2); font-size: 15px; }
.typing { display: inline-flex; gap: 4px; margin-left: 8px; vertical-align: 1px; }
.typing i { width: 5px; height: 5px; border-radius: 50%; background: var(--label-3); animation: typing 1.2s ease-in-out infinite; }
.typing i:nth-child(2) { animation-delay: 0.15s; }
.typing i:nth-child(3) { animation-delay: 0.3s; }
@keyframes typing { 30% { transform: translateY(-3px); opacity: 1; } }

/* outcome micro-chips (centered, mono — the 20% Erlach) */
.outcome {
  align-self: center;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  border-radius: 999px;
  padding: 4px 12px;
  margin: 12px 0 2px;
}
.outcome-live { color: #14691f; background: rgba(40, 167, 69, 0.14); }
.outcome-discarded { color: var(--label-2); background: var(--fill); }
.outcome-team { color: #8a4c02; background: rgba(232, 131, 12, 0.15); }

/* ---- inline review card ---- */
.review-card {
  max-width: 92%;
  margin-top: 10px;
  padding: 18px 20px;
  border-bottom-left-radius: 7px; /* assistant-bubble tail — it speaks in the thread */
}
.review-head { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; }
.review-head .job-duration { flex-shrink: 0; }
.review-card .review-summary { font-size: 16px; font-weight: 550; }
.review-card .review-notes { font-size: 13.5px; color: var(--label-2); margin-top: 6px; }
.segment { display: flex; background: var(--fill); border-radius: 12px; padding: 2px; margin: 14px 0 10px; }
.segment button {
  flex: 1;
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--label);
  border: none;
  background: transparent;
  border-radius: 10px;
  padding: 6px 0;
  cursor: pointer;
}
.segment button.active { background: var(--glass-strong); box-shadow: 0 1px 4px rgba(0, 0, 0, 0.12); }
.shots { display: flex; flex-direction: column; gap: 12px; }
.shot-label { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--label-2); margin-bottom: 5px; }
.shot img { width: 100%; border-radius: var(--radius-s); border: 0.5px solid var(--separator); display: block; cursor: zoom-in; }
.review-actions { display: flex; flex-wrap: wrap; gap: 10px; justify-content: flex-end; align-items: center; margin-top: 14px; padding-top: 13px; border-top: 0.5px solid var(--separator); }
.review-actions .preview-link { flex-basis: auto; }
@media (max-width: 520px) { .review-actions .preview-link { flex-basis: 100%; } }
.preview-link { font-size: 14.5px; font-weight: 600; color: var(--blue); text-decoration: none; margin-right: auto; }

.review-actions .staged-chip { margin-right: auto; }

/* a sensitive category the agency wants named — informative, not alarming */
.review-warn {
  display: flex;
  gap: 8px;
  align-items: baseline;
  margin-top: 11px;
  padding: 9px 12px;
  font-size: 13.5px;
  color: #7a4402;
  background: color-mix(in srgb, var(--orange) 11%, transparent);
  border-radius: var(--radius-s);
}
.review-warn::before { content: '!'; font-weight: 800; opacity: 0.7; }

/* one-tap undo, only on the newest staged change */
.undo-btn {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border: none;
  border-radius: 999px;
  background: var(--fill);
  color: var(--label-2);
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.undo-btn:hover { background: color-mix(in srgb, var(--label-3) 22%, transparent); color: var(--label); }
.undo-btn:active { transform: scale(0.93); }

/* a staged change: in the preview, waiting for publish */
.staged-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #075a6b;
  background: color-mix(in srgb, var(--cyan) 15%, transparent);
  border-radius: 999px;
  padding: 4px 11px;
}
.staged-chip i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--cyan);
  animation: staged-pulse 2.4s ease-in-out infinite;
}
@keyframes staged-pulse { 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) { .staged-chip i { animation: none; } }

/* anchor chips: each visibly changed element, tap = the preview jumps there */
.anchor-chips { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 11px; }
.anchor-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--label);
  background: var(--fill);
  border: 0.5px solid var(--separator);
  border-radius: 999px;
  padding: 6px 13px;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}
.anchor-chip:hover { background: color-mix(in srgb, var(--cyan) 12%, transparent); border-color: color-mix(in srgb, var(--cyan) 45%, transparent); }
.anchor-chip i { width: 6px; height: 6px; border-radius: 50%; background: var(--cyan); flex-shrink: 0; }
.anchor-chip .anchor-page {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--label-3);
}

/* the element picked via point-and-edit, shown above the composer */
.target-chip {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 2px 2px 10px;
  padding: 8px 12px;
  font-size: 13.5px;
  color: var(--label);
  background: color-mix(in srgb, var(--cyan) 10%, transparent);
  border: 0.5px solid color-mix(in srgb, var(--cyan) 40%, transparent);
  border-radius: var(--radius-s);
}
.target-chip .target-kicker {
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #075a6b;
  flex-shrink: 0;
}
.target-chip .target-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.target-chip .rm {
  margin-left: auto;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  border: none;
  border-radius: 50%;
  background: var(--fill);
  color: var(--label-2);
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
}

/* ---- composer ---- */
.composer-bar { position: sticky; bottom: 0; z-index: 20; padding: 10px 14px calc(14px + env(safe-area-inset-bottom)); }
.composer-inner { max-width: 720px; margin: 0 auto; padding: 10px 12px; border-radius: 26px; }
.composer-row { display: flex; align-items: center; gap: 9px; }
.composer-field {
  flex: 1;
  font: inherit;
  font-size: 16px;
  line-height: 22px;
  color: var(--label);
  background: transparent;
  border: none;
  resize: none;
  max-height: 130px;
  padding: 6px 4px;
}
.composer-field:focus { outline: none; }
.composer-field::placeholder { color: var(--label-3); }
/* request mode: adjust | build — only rendered for sites with the entitlement.
   A real segmented control; picking build transforms the composer itself. */
.mode-switch { display: flex; align-items: center; gap: 10px; margin: 2px 2px 10px; }
.mode-seg { position: relative; display: inline-flex; background: var(--fill); border-radius: 999px; padding: 3px; }
/* the sliding thumb IS the mode: it travels to the picked segment and turns
   brand blue for build (JS sets width/translateX from the measured button) */
.mode-thumb {
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 0;
  width: 0;
  border-radius: 999px;
  background: #fff;
  box-shadow: 0 1px 4px rgba(12, 26, 29, 0.14);
  /* Deliberately no motion on this thumb. Moving its edge inside a
     backdrop-filter parent forces iOS to re-layout and re-snapshot the blur
     on every frame — the suspected source of the lag we chased. */
}
.mode-seg.build .mode-thumb { background: var(--blue); }
.mode-switch button {
  position: relative;
  z-index: 1;
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  padding: 7px 18px;
  border-radius: 999px;
  border: none;
  background: transparent;
  color: var(--label-2);
  cursor: pointer;
  transition: color 0.22s ease;
}
.mode-switch button.active { color: var(--label); }
#mode-build.active { color: #fff; }
.mode-switch button:disabled { opacity: 0.4; cursor: default; }
/* build mode is visible on the input itself — a blue ring around the bubble.
   The ring is an overlay child, NOT a box-shadow on the glass: mutating
   paint properties of a backdrop-filter element makes iOS re-snapshot the
   blur — measured as a 1s main-thread stall on the first mode switch. */
.composer-inner { position: relative; }
.composer-inner.build-mode::after {
  content: '';
  position: absolute;
  inset: -3px;
  border-radius: 29px;
  border: 3px solid color-mix(in srgb, var(--blue, #22c7e5) 30%, transparent);
  pointer-events: none;
}
.bubble.mine .mode-tag {
  display: block;
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.75;
  margin-bottom: 3px;
}
.attach-btn {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--fill);
  color: var(--label-2);
  display: grid;
  place-items: center;
  cursor: pointer;
  flex-shrink: 0;
}
.send-btn {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: none;
  background: var(--blue);
  color: #fff;
  display: grid;
  place-items: center;
  cursor: pointer;
  flex-shrink: 0;
  transition: transform 0.15s ease, opacity 0.15s ease;
}
.send-btn:active { transform: scale(0.92); }
.send-btn:disabled { opacity: 0.35; }
.composer-hint {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--label-2);
  padding: 2px 6px 8px;
}
.composer-hint.answering { color: #075a6b; }
.attach-previews { display: flex; gap: 8px; padding: 4px 6px 10px; flex-wrap: wrap; }
.attach-previews .thumb { position: relative; }
.attach-previews img { width: 54px; height: 54px; object-fit: cover; border-radius: 10px; border: 0.5px solid var(--separator); }
.attach-previews .rm {
  position: absolute;
  top: -6px;
  right: -6px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: none;
  background: var(--label);
  color: #fff;
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
}

/* ---- lightbox / toast ---- */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: rgba(10, 26, 30, 0.75);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  display: grid;
  place-items: center;
  cursor: zoom-out;
}
.lightbox img { max-width: 92vw; max-height: 88vh; border-radius: 14px; }

.toast {
  position: fixed;
  z-index: 60;
  top: 14px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 15px;
  font-weight: 600;
  padding: 12px 22px;
  border-radius: 999px;
  animation: toast-in 0.3s cubic-bezier(0.32, 0.72, 0, 1);
}
@keyframes toast-in { from { transform: translate(-50%, -140%); } }

@media (max-width: 520px) {
  .bubble { max-width: 86%; }
  .review-card { max-width: 100%; }
}

/* status chips inside assistant bubbles */
.status-chip {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  border-radius: 999px;
  padding: 3px 10px;
  margin-top: 8px;
}

/* ---- in-app confirm dialog ---- */
.confirm-backdrop {
  position: fixed;
  inset: 0;
  z-index: 70;
  background: rgba(10, 26, 30, 0.35);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  display: grid;
  place-items: center;
  padding: 24px;
}
.confirm-card {
  width: min(400px, 100%);
  padding: 24px 24px 20px;
  background: var(--glass-strong);
  animation: confirm-in 0.22s cubic-bezier(0.32, 0.72, 0, 1);
}
@keyframes confirm-in { from { transform: scale(0.94); opacity: 0; } }
.confirm-text { font-size: 16px; font-weight: 550; }
.confirm-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }
.confirm-actions .btn { background: var(--fill); color: var(--label); }
.confirm-actions .btn-primary { background: var(--blue); color: #fff; }
.confirm-actions .btn-danger-solid { background: var(--red); color: #fff; }

/* ---- attach menu ---- */
.attach-wrap { position: relative; flex-shrink: 0; }
.attach-btn { border: none; transition: transform 0.15s ease, background 0.15s ease; }
.attach-btn:hover { background: rgba(120, 138, 140, 0.22); }
.attach-btn:active { transform: scale(0.92); }
.attach-btn:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.attach-menu {
  position: fixed; /* body-level: nested backdrop-filter is ignored by Chrome */
  min-width: 214px;
  padding: 6px;
  border-radius: 16px;
  background: var(--glass);
  -webkit-backdrop-filter: blur(24px) saturate(170%);
  backdrop-filter: blur(24px) saturate(170%);
  border: 0.5px solid var(--glass-border);
  animation: menu-in 0.16s ease-out;
  z-index: 65;
}
@keyframes menu-in { from { opacity: 0; } }
.attach-item {
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  border: none;
  background: transparent;
  border-radius: 11px;
  padding: 10px 12px;
  cursor: pointer;
}
.attach-item:hover { background: var(--fill); }
.attach-item-title { display: block; font-size: 15px; font-weight: 600; color: var(--label); }
.attach-item-sub {
  display: block;
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.12em;
  color: var(--label-3);
  margin-top: 1px;
}

/* attach menu polish */
.attach-menu {
  -webkit-backdrop-filter: blur(24px) saturate(170%);
  backdrop-filter: blur(24px) saturate(170%);
  box-shadow: 0 12px 34px rgba(10, 26, 30, 0.18);
}
.attach-item { display: flex; align-items: center; gap: 11px; }
.attach-item-icon { color: var(--blue); flex-shrink: 0; }
.attach-item-text { display: block; }

/* drag & drop state */
body.dragging .composer-inner {
  outline: 2px dashed var(--blue);
  outline-offset: -2px;
}
body.dragging .composer-field::placeholder { color: var(--blue); }

/* upload progress */
.upload-progress {
  height: 3px;
  border-radius: 2px;
  background: var(--fill);
  margin: 2px 8px 10px;
  overflow: hidden;
}
.upload-progress i {
  display: block;
  height: 100%;
  width: 100%;
  border-radius: 2px;
  background: var(--blue);
  /* the fill is driven by scaleX, not width — same look, no layout per frame */
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.15s ease;
}

@media (max-width: 900px) {
  /* The chat rail stops being a column and becomes two fixed layers: the dock
     at the bottom, and the thread on a sheet above it. */
  .chat-rail { display: contents; }
  .workspace-body { display: block; position: relative; }

  /* the site owns the screen, right down to the dock's edge */
  .preview-pane {
    height: 100%;
    padding: 0 0 var(--dock-h, 132px);
  }
  .preview-pane-head { gap: 8px; padding: 5px 12px 6px; }
  .preview-pane-body {
    border-radius: 14px 14px 0 0;
    border-bottom: none;
  }
  /* on a phone you are already looking at a phone; the device toggle, the
     full-width switch and the new-tab link all describe a window there isn't */
  .device-seg,
  #focus-btn,
  #preview-open,
  .preview-pane-head .select-btn { display: none; }
  .page-btn { padding: 8px 11px 8px 13px; min-height: 38px; max-width: 60vw; }
  #preview-reload { width: 38px; height: 38px; }
  .logout-btn { width: 38px; height: 38px; }

  /* the thread: a sheet that rises out of the dock */
  .feed {
    position: fixed;
    left: 0;
    right: 0;
    bottom: var(--dock-h, 132px);
    top: var(--top-h, 100px);
    z-index: 39;
    padding: 14px 16px 18px;
    border-radius: 20px 20px 0 0;
    background: color-mix(in srgb, #fff 90%, var(--wall-2));
    -webkit-backdrop-filter: blur(26px) saturate(170%);
    backdrop-filter: blur(26px) saturate(170%);
    border-top: 0.5px solid var(--glass-border);
    box-shadow: 0 -14px 40px rgba(10, 26, 30, 0.16);
    transform: translateY(12px);
    opacity: 0;
    visibility: hidden;
    transition: transform 0.34s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.22s ease,
      visibility 0s linear 0.34s;
  }
  /* a short thread belongs at the bottom, where the talking is — the same
     free-space eater every chat uses, and a no-op once it scrolls */
  .feed::before { content: ''; margin-top: auto; }
  .workspace.thread-open .feed {
    transform: none;
    opacity: 1;
    visibility: visible;
    transition: transform 0.34s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.22s ease,
      visibility 0s;
  }
  /* the dock carries them now — two copies would be one too many */
  .demo-suggest { display: none; }

  /* the dock itself */
  .composer-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 41;
    padding: 0 12px calc(10px + env(safe-area-inset-bottom));
    background: color-mix(in srgb, var(--glass-strong) 96%, transparent);
    -webkit-backdrop-filter: blur(26px) saturate(170%);
    backdrop-filter: blur(26px) saturate(170%);
    border-top: 0.5px solid var(--separator);
    box-shadow: 0 -6px 22px rgba(10, 26, 30, 0.09);
  }
  .dock-handle {
    display: grid;
    place-items: center;
    width: 100%;
    height: 30px;
    border: none;
    background: transparent;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    /* the drag belongs to the dock: without this the browser claims the
       gesture as a scroll and cancels the pointer mid-swipe */
    touch-action: none;
  }
  .dock-handle i {
    display: block;
    width: 38px;
    height: 4px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--label-3) 70%, transparent);
    transition: background-color 0.15s ease;
  }
  .workspace.thread-open .dock-handle i { background: color-mix(in srgb, var(--blue) 70%, transparent); }
  .dock-handle:focus-visible { outline: 2px solid var(--blue); outline-offset: -3px; border-radius: 12px; }

  .dock-strip { display: block; padding: 0 2px; cursor: pointer; }
  .dock-row {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    min-height: 26px;
    padding-bottom: 9px;
    transition: opacity 0.2s ease;
  }
  /* the sheet says it in full; the line under it would only say it twice */
  .workspace.thread-open .dock-row { opacity: 0; }
  .dock-orb { width: 22px; height: 22px; flex: none; align-self: flex-start; margin-top: 1px; }
  .dock-line {
    flex: 1;
    min-width: 0;
    font-size: 14.5px;
    line-height: 1.35;
    color: var(--label);
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
  }
  .dock-line .typing { vertical-align: 2px; }
  .dock-line .elapsed { margin-left: 8px; }
  .dock-mark {
    display: inline-block;
    width: 7px;
    height: 7px;
    margin-right: 7px;
    border-radius: 50%;
    background: var(--cyan);
    vertical-align: 1px;
  }
  .dock-act {
    flex: none;
    align-self: center;
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    margin: -7px -2px -7px 0;
    border: none;
    border-radius: 999px;
    background: var(--fill);
    color: var(--label-2);
    cursor: pointer;
  }
  .dock-act:active { transform: scale(0.93); }
  /* In the dock they are the whole invitation, so they take the width: a
     bigger target and one clean left edge under the line above them. */
  .dock-chips { display: flex; flex-direction: column; gap: 6px; padding-bottom: 9px; }
  .dock-chips .suggest-chip { max-width: none; min-height: 42px; font-size: 14.5px; padding: 10px 14px; }

  /* the composer sits inside the dock — one glass panel, not two */
  .composer-inner {
    padding: 0;
    border-radius: 0;
    background: transparent;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    border: none;
    box-shadow: none;
  }
  .composer-row {
    gap: 7px;
    padding: 5px 6px 5px 8px;
    border-radius: 24px;
    background: color-mix(in srgb, #fff 62%, transparent);
    border: 0.5px solid var(--glass-border);
  }
  .composer-inner.build-mode::after { inset: 0; border-radius: 24px; }
  .composer-field { font-size: 16px; padding: 9px 2px; }
  .attach-btn,
  .send-btn,
  .select-btn-m { width: 40px; height: 40px; }
  .select-btn-m {
    display: grid;
    place-items: center;
    flex: none;
    border: none;
    border-radius: 999px;
    background: var(--fill);
    color: var(--label-2);
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
  }
  .select-btn-m.active {
    background: color-mix(in srgb, var(--cyan) 22%, #fff 55%);
    color: #075a6b;
  }
  .select-btn-m:active { transform: scale(0.93); }

  /* the bar is tight: the action keeps a name, just the short one */
  .publish-btn .publish-label-long { display: none; }
  .publish-btn { padding: 9px 14px; }
  .navbar-inner { padding: 10px 14px; }
  /* At 360px the bar ran off the screen and took the sign-out button with it.
     The counter is the only thing here that can give ground, so it does. */
  .navbar-inner .brand-lockup { flex: none; }
  .navbar-right { min-width: 0; }
  .pill {
    font-size: 12.5px;
    padding: 5px 10px;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
  }
}

/* landscape on a phone: the site has almost no height left, so the dock says
   its piece in one line and the suggestions wait for the thread */
@media (max-width: 900px) and (max-height: 560px) {
  .navbar-inner { padding: 6px 14px; }
  .preview-pane-head { padding: 3px 12px 4px; }
  .page-btn { padding: 5px 10px 5px 12px; }
  #preview-reload { width: 30px; height: 30px; }
  .dock-handle { height: 20px; }
  .dock-row { padding-bottom: 7px; }
  .dock-line { -webkit-line-clamp: 1; }
  /* no room for them under the composer — they wait in the thread instead */
  .dock-chips { display: none; }
  .demo-suggest { display: flex; }
}

@media (min-width: 901px) {
  .publish-btn .publish-label-short { display: none; }
  .select-btn-m { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .feed { transition: opacity 0.01s linear, visibility 0s; transform: none; }
  .workspace.thread-open .feed { transition: opacity 0.01s linear, visibility 0s; }
}
