/* One typeface, the logo's (founder, 2026-11-08): the website sets its UI font to the wordmark font (Sora). Website-only;
   the brand tokens keep DM Sans for the product. */
:root { --font-ui: var(--font-wordmark); }
/* Waitlist page, "the empty seats": one screen, no scrolling. Values come from brand/tokens.css
   (synced from lusolo/packages/brand). Brand layer: --brand-ground, --brand-line (ink), --brand-lead (cobalt).
   One column on every size: logo, title, the seats drawing (takes all the height left), form. */
* { box-sizing: border-box; }
/* Job colours in the seats drawing (founder, 2026-11-08): blue requesting, red processing, green ready.
   A deliberate exception to the product palette (tokens.json bans green and keeps red-orange for "needs you"):
   website brand layer only, never on a product screen. */
/* "You" is the one human in the drawing: a skin-warm pink, also a founder exception (website only). */
/* --on-request: words and controls on a blue (request) bubble. White in both themes (cobalt #2A4BD7 light, #6F8BFF dark). */
:root { --flow-request: var(--brand-lead); --on-request: #fff; --flow-process: #E5432A; --flow-ready: #14935A; --you: #E8899A; }
@media (prefers-color-scheme: dark) { :root { --flow-process: #FF6B4F; --flow-ready: #3DD68C; --you: #F4A7B5; } }
html, body { height: 100%; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; overflow: hidden;
  background: var(--brand-ground); color: var(--brand-line);
  font: 400 17px/1.5 var(--font-ui);
}

.screen {
  height: 100vh; height: 100svh;
  padding: max(18px, env(safe-area-inset-top)) 24px max(18px, env(safe-area-inset-bottom));
  display: grid; grid-template-rows: auto minmax(0, 1fr);
}
/* "Early access" sits under the logo, left-aligned with it (founder, 2026-11-08). */
.top { display: flex; flex-direction: column; align-items: stretch; gap: 12px; width: max-content; justify-self: start; }
.top .label { display: block; }   /* its rule runs the full width of the logo (founder, 2026-11-08) */
.logo-link { display: block; color: var(--brand-line); border-radius: 6px; }
.logo { display: block; height: 40px; width: auto; overflow: visible; }
.logo path { fill: currentColor; }
.logo .logo-door { transform-box: fill-box; }
.logo .logo-roof, .logo .logo-body, .logo .mark { transform-box: fill-box; transform-origin: 50% 100%; }
/* The logo is alive (founder, 2026-11-08): once built, its roof breathes. The L (door) stays still: the dots already
   carry the motion (founder, 2026-11-08). `translate` is separate from what the build animation (Motion) moves. */
.logo.alive .logo-roof { animation: roof-breathe 3.6s ease-in-out infinite; }
@keyframes roof-breathe { 50% { translate: 0 -7%; } }
@media (prefers-reduced-motion: reduce) { .logo.alive .logo-roof { animation: none; } }

.main {
  width: 100%; max-width: 1240px; margin: 0 auto;   /* the logo stays at the window's left edge; the content is centred */
  min-height: 0; display: grid; grid-template-rows: auto minmax(0, 1fr) auto;
  justify-items: center; text-align: center;
}
.head { padding-top: clamp(48px, 11vh, 120px); }
.stage { min-height: 0; width: 100%; display: flex; align-items: center; justify-content: center; padding: clamp(4px, 2vh, 24px) 0; }
#seats { width: 100%; height: 100%; overflow: visible; }

.label {
  display: inline-block; margin: 0;
  font-size: 13px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
  border-top: 3px solid var(--brand-line); padding-top: 9px;
}
h1 {
  margin: 0 0 12px; text-wrap: balance;
  font-family: var(--font-display); font-weight: var(--font-display-weight);
  font-size: clamp(34px, min(5.6vw, 7.4vh), 76px); line-height: 1.03; letter-spacing: -0.02em;
}
.lead { margin: 0 auto; max-width: 62ch; font-size: clamp(16px, 2.1vh, 19px); color: var(--brand-line); }

/* Form */
form { width: 100%; max-width: 480px; }
.row { display: flex; gap: 8px; }
input[type=email] {
  flex: 1 1 auto; min-width: 0; min-height: 48px; padding: 0 14px;
  font: inherit; color: var(--color-ink); background: var(--color-card);
  border: 2px solid var(--brand-line); border-radius: var(--radius-control);
}
button {
  flex: 0 0 auto; min-height: 48px; padding: 0 18px;
  font: 600 16px var(--font-ui); color: var(--color-on-action); background: var(--color-action);
  border: 0; border-radius: var(--radius-control); cursor: pointer;
  transition: transform var(--motion-fast) var(--motion-ease);
}
button:active:not([disabled]) { transform: scale(0.97); }
button[disabled] { opacity: .45; cursor: not-allowed; }
input[aria-invalid="true"] { border-color: var(--color-state-attention); }
.yet { display: inline-block; }
/* The field shows focus with its own border (cobalt), not a second ring round it. */
input[type=email]:focus { outline: none; border-color: var(--you); caret-color: var(--you); }   /* the same pink as "You" */
button:focus-visible, a:focus-visible { outline: 2px solid var(--brand-lead); outline-offset: 2px; }
input[aria-invalid="true"]:focus { border-color: var(--color-state-attention); }
.sr, .hp { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
.status { min-height: 1.4em; margin: 8px 0 2px; font-weight: 500; }
.status.error { color: var(--color-state-attention-text); }
.fine { margin: 0; font-size: min(13px, 3.3vw); white-space: nowrap; color: var(--color-text-muted); }   /* one line */
form.done .row { display: none; }

/* The seats drawing. Lines are ink; the only colour is cobalt on solids. */
#seats .line { fill: none; stroke: var(--brand-line); stroke-linecap: butt; }
/* The rule continues into the email field's border: same colour, same 2px on screen at any size. */
#seats .rule { stroke-width: 2px; vector-effect: non-scaling-stroke; }
#seats .bundle { stroke-width: 1.5; }
#seats .flow { stroke-width: 3.5; }   /* work travelling between seats; colour set per layer in app.js */
/* "You" is ink on the ground line; the team lead is the cobalt dot every seat branches from. */
#seats .owner { fill: var(--you); transform-box: fill-box; transform-origin: 50% 100%; }
/* People are pink: you and your customers. */
#seats .people { fill: var(--you); transform-box: fill-box; transform-origin: 50% 50%; }
#seats .client { stroke-width: 1.5; }
#seats .you .you-text.heard { fill: var(--flow-ready); }
#seats .you .you-text.asking { fill: var(--color-text-secondary); }
/* The team lead is ink; blue only while it makes a request; green while it updates you (founder, 2026-11-08).
   Idle: blank and slowly blinking. Processing: blinking faster. */
#seats .hub { fill: var(--brand-line); transform-box: fill-box; transform-origin: 50% 50%;
  transition: fill var(--motion-base) var(--motion-ease); }
#seats .hub[data-mode="asking"] { fill: var(--brand-lead); }
#seats .hub[data-mode="updating"] { fill: var(--flow-ready); }
#seats .hub[data-mode="final"] { fill: var(--brand-lead); }
/* The end: every animation stops; the thank-you is the only text. */
#seats.ending * { animation: none !important; }
#seats .thanks-title { font-family: var(--font-display); font-weight: var(--font-display-weight); fill: var(--brand-line); letter-spacing: -0.02em; }
#seats .thanks-line { font-family: var(--font-ui); font-weight: 500; fill: var(--brand-line); }
form.done .status { position: absolute; left: -10000px; }
/* Running totals beside "You": what the jobs earned and saved. */
#seats .ledger { font: 600 15px var(--font-ui); fill: var(--brand-line); }
#seats .ledger tspan { transition: fill var(--motion-base) var(--motion-ease); }
#seats .ledger .counting { fill: var(--flow-ready); }
#seats .ledger-sep { fill: var(--color-text-muted); }
#seats .ledger-day { fill: var(--color-text-muted); }
#seats .ledger .ledger-day.counting { fill: var(--brand-line); }
/* Saved is grey (founder, 2026-11-08), even while it counts up: green is kept for money earned. */
#seats .ledger .ledger-saved, #seats .ledger .ledger-saved.counting, #seats .money.saved { fill: var(--color-text-secondary); }
#seats .money { font: 700 18px var(--font-ui); fill: var(--flow-ready); }
#seats .hub[data-mode="idle"] { animation: think 2.6s cubic-bezier(0.45, 0, 0.55, 1) infinite; }
#seats .hub[data-mode="processing"] { animation: think 0.9s cubic-bezier(0.45, 0, 0.55, 1) infinite; }
/* Waiting (founder, 2026-11-08: "when a dot is waiting it needs to be blinking"): the lead blinks like a ready seat. */
#seats .hub[data-mode="waiting"] { animation: waiting 0.7s ease-in-out infinite; }
#seats .hub-state { fill: var(--color-text-muted); }
#seats .hub[data-mode="asking"] ~ .hub-state { fill: var(--brand-lead); }
#seats .hub[data-mode="updating"] ~ .hub-state { fill: var(--flow-ready); }
/* People (you, your customers) sway a little all the time, like someone standing there. */
#seats .human { transform-box: fill-box; transform-origin: 50% 100%; animation: sway 3.4s ease-in-out infinite; }
#seats .human.customers { transform-origin: 50% 50%; animation-duration: 2.9s; animation-delay: -1.3s; }
@keyframes sway { 0%, 100% { transform: none; } 30% { transform: translate(0.8px, -1.4px) rotate(-3deg); } 65% { transform: translate(-0.7px, 0.4px) rotate(2.5deg); } }
#seats .ring { fill: transparent; stroke: var(--brand-line); stroke-width: 4; transform-box: fill-box; transform-origin: 50% 50%;
  transition: fill var(--motion-base) var(--motion-ease), stroke var(--motion-base) var(--motion-ease),
    scale 420ms cubic-bezier(0.23, 1, 0.32, 1); }
/* Size says who is busy (founder, 2026-11-08): a seat that is not working (on duty, or showing a result it handed
   back) shrinks a little; the moment it is asked it grows back to full size. `scale` is separate from the
   transforms Motion animates (pulse, finale), so the two never fight. */
#seats .seat[data-state="hired"] .ring, #seats .seat[data-state="done"] .ring { scale: 0.8; }
/* On duty is still busy: the grey dot breathes slowly (out of step with its neighbours, via --d), unlike the
   fast blink of a seat that is waiting. The delay lets it shrink first. */
#seats .seat[data-state="hired"] .ring { animation: busy 2.6s ease-in-out var(--d, 0.6s) infinite; }
@keyframes busy { 50% { scale: 0.88; } }
/* Learning (just deployed): full size, outlined in ink with a grey fill, a slow even pulse while it studies you. */
#seats .seat[data-state="learning"] .ring { --idle: color-mix(in srgb, var(--brand-line) 42%, var(--brand-ground));
  fill: var(--idle); stroke: var(--brand-line); animation: learn 1.5s ease-in-out infinite; }
@keyframes learn { 50% { opacity: 0.55; } }
/* Not deployed yet: a small dot. It grows to full size the moment its line to the lead arrives (founder, 2026-11-08). */
#seats .seat[data-state="empty"] .ring { scale: 0.4; }
/* Waiting: a ready seat blinks until the lead picks up its result. */
#seats .seat[data-state="ready"] .ring { animation: waiting 0.7s ease-in-out infinite; }
@keyframes waiting { 50% { opacity: 0.4; } }
#seats .seat[data-state="hiring"] .ring { fill: var(--brand-lead); stroke: var(--brand-lead); }
/* Spinning (founder, 2026-11-08): red while a request comes in from someone else, white while it works on it. An arc
   spins round the edge, like an AI thinking. Only the arc moves (dash offset): the dot and its icon never turn (founder). */
#seats .seat[data-state="received"] .ring, #seats .seat[data-state="working"] .ring {
  stroke-dasharray: 0.32 0.68 !important; stroke-linecap: round; animation: spin 0.9s linear infinite; }
#seats .seat[data-state="received"] .ring { fill: var(--flow-process); stroke: var(--flow-process); animation-duration: 0.6s; }
#seats .seat[data-state="working"] .ring { fill: #fff; stroke: var(--brand-line); }
#seats .seat[data-state="received"] .state { fill: var(--flow-process); }
@keyframes spin { from { stroke-dashoffset: 0; } to { stroke-dashoffset: -1; } }
#seats .seat[data-state="ready"] .ring { fill: var(--flow-ready); stroke: var(--flow-ready); }
/* On duty (just watching) the dot greys back; a result it just delivered stays ink until it fades to duty. */
#seats .seat[data-state="hired"] .ring { --idle: color-mix(in srgb, var(--brand-line) 42%, var(--brand-ground)); fill: var(--idle); stroke: var(--idle); }
#seats .seat[data-state="done"] .ring { fill: var(--brand-line); stroke: var(--brand-line); }
#seats .role { font: 600 17px var(--font-ui); fill: var(--brand-line); transition: fill var(--motion-base) var(--motion-ease); }
#seats .state { font: 400 13px var(--font-ui);   /* 13px: Sora runs wider than DM Sans */ fill: var(--color-text-muted); }
#seats .seat[data-state="hiring"] .state { fill: var(--brand-lead); }
#seats .seat[data-state="working"] .state { fill: var(--brand-line); }
#seats .seat[data-state="ready"] .state { fill: var(--flow-ready); }
#seats .seat[data-state="empty"] .role { fill: var(--color-text-secondary); }
#seats .you { font: 600 16px var(--font-ui); fill: var(--brand-line); }
/* A ground-coloured edge round all drawing text, so a line passing close by never runs into the letters. */
#seats text { paint-order: stroke; stroke: var(--brand-ground); stroke-width: 5px; stroke-linejoin: round; }

/* Phone: the seats stand in a column (app.js switches the drawing), the long lead is dropped. */
@media (max-width: 767px) {
  .screen { padding-left: 16px; padding-right: 16px; }
  .logo { height: 32px; }
  .head { padding-top: clamp(32px, 6vh, 56px); }
  h1 { font-size: clamp(28px, min(8.6vw, 5.4vh), 42px); margin-bottom: 8px; }
  .lead { font-size: 15px; }
  .lead .more { display: none; }
  .row { flex-direction: column; }
  button { width: 100%; }
}
/* Short screens: drop the lead first, so the drawing keeps its size. */
@media (max-width: 767px) and (max-height: 760px) { .lead { display: none; } }
@media (max-height: 620px) { .lead { display: none; } }

@media (prefers-reduced-motion: reduce) { #seats .ring, #seats .hub, #seats .human { transition: none; animation: none !important; } }

/* People have faces (founder, 2026-11-08): eyes always open (below), a faster blink while they talk or act. */
#seats .face { transform-box: fill-box; transform-origin: 50% 100%; }
#seats .customers-face { transform-origin: 50% 50%; }
/* Founder, 2026-11-08: "keep the eyes for the humans and make them blink sometimes": always open, a blink every few
   seconds (you and your customers out of step), and a quicker one while talking. */
#seats .eye { fill: var(--brand-ground); opacity: 1; transform-box: fill-box; transform-origin: 50% 50%; scale: 1 1;
  animation: blink-rare 4.7s ease-in-out 1.2s infinite;
  transition: opacity 160ms ease-out, scale 200ms cubic-bezier(0.23, 1, 0.32, 1); }
#seats .face.awake .eye { opacity: 1; scale: 1 1; animation: blink 1.9s ease-in-out 0.5s infinite; }
#seats .customers .eye { animation-duration: 6.1s; animation-delay: 2.6s; }
@keyframes blink-rare { 0%, 95%, 100% { scale: 1 1; } 97% { scale: 1 0.1; } }
@keyframes blink { 0%, 44%, 52%, 100% { scale: 1 1; } 48% { scale: 1 0.1; } }
#seats.ending .eye { display: none; }
/* Requests from people sit in a chat bubble with a tail to the speaker. */
#seats .bubble { fill: var(--flow-request); }
#seats .bubble-text { font: 500 15px var(--font-ui); fill: var(--on-request); }
#seats.ending .bubble { display: none; }
@media (prefers-reduced-motion: reduce) { #seats .eye, #seats .face.awake .eye { animation: none; } }

/* The answer box (founder, 2026-11-08): your chat bubble becomes a real text field for a few seconds. */
.answer { position: absolute; z-index: 5; display: flex; align-items: center; gap: 6px; width: 250px; max-width: calc(100vw - 32px);
  min-height: 34px; padding: 0 3px 0 14px;
  border-radius: var(--radius-pill); background: var(--flow-request); box-shadow: 0 0 0 4px color-mix(in srgb, var(--flow-request) 22%, transparent);
  animation: answer-in var(--motion-base) var(--motion-ease); }
/* The bubble's tail, back towards "You", like the drawn bubbles. */
.answer::after { content: ''; position: absolute; left: -6px; bottom: 0; width: 12px; height: 12px; background: var(--flow-request);
  clip-path: polygon(100% 0, 100% 100%, 0 100%); }
@keyframes answer-in { from { opacity: 0; scale: 0.96; } }
.answer input { all: unset; width: 100%; font: 500 16px var(--font-ui); color: var(--on-request); caret-color: var(--on-request); }
.answer input::placeholder { color: color-mix(in srgb, var(--on-request) 70%, transparent); }
.answer.auto input { color: var(--on-request); }
/* The 4-second clock: a hairline that runs out along the bottom of the bubble. */
/* Sits on the rim of the pill, well clear of the words, so it never reads as an underline. */
.answer-time { position: absolute; left: 16px; right: 16px; bottom: 1px; height: 1.5px; border-radius: 2px;
  background: color-mix(in srgb, var(--on-request) 45%, transparent); transform-origin: left; scale: 0 1; }
.answer.counting .answer-time { animation: answer-clock var(--answer-ms, 20s) linear forwards; }
@keyframes answer-clock { from { scale: 1 1; } to { scale: 0 1; } }
.answer.engaged .answer-time { opacity: 0; transition: opacity var(--motion-fast) var(--motion-ease); }
@media (prefers-reduced-motion: reduce) { .answer { animation: none; } }

/* Sound switch, top right, quiet until you look for it. */
.sound { position: fixed; top: max(14px, env(safe-area-inset-top)); right: max(16px, env(safe-area-inset-right)); z-index: 6;
  display: inline-flex; align-items: center; gap: 6px; padding: 6px 10px; border: 0; border-radius: var(--radius-pill); background: transparent;
  font: 500 13px var(--font-ui); color: var(--color-text-secondary); cursor: pointer; transition: color var(--motion-fast) ease, transform var(--motion-fast) var(--motion-ease); }
.sound:hover { color: var(--brand-line); }
.sound:active { transform: scale(0.97); }
.sound svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.sound[aria-pressed="false"] .wave { opacity: 0; }
.sound:focus-visible { outline: 2px solid var(--flow-request); outline-offset: 2px; }

/* Share your link, under the form after you join. */
.share { justify-self: center; margin-top: 6px; padding: 10px 18px; border: 1px solid var(--brand-line); border-radius: var(--radius-pill);
  background: transparent; color: var(--brand-line); font: 600 15px var(--font-ui); cursor: pointer; transition: transform var(--motion-fast) var(--motion-ease); }
.share:active { transform: scale(0.97); }
.share[hidden] { display: none; }

/* Seats are tappable: they show what they last finished. */
#seats .seat .ring { cursor: pointer; }
#seats .seat.recall .state { fill: var(--brand-line); }
#seats .eye { transition: opacity var(--motion-fast) var(--motion-ease), scale 200ms var(--motion-ease), translate var(--motion-fast) var(--motion-ease); }

/* Grey dots are working too (founder, 2026-11-08: "it needs to spin also when it's grey"): a slow arc runs round a
   seat on duty or learning your business. Slower than a job (0.9s) so the busy ones still stand out. */
#seats .seat[data-state="hired"] .ring, #seats .seat[data-state="learning"] .ring {
  stroke-dasharray: 0.3 0.7 !important; stroke-linecap: round; stroke-width: 2.5; }
#seats .seat[data-state="hired"] .ring { stroke: var(--color-text-secondary);
  animation: busy 2.6s ease-in-out var(--d, 0.6s) infinite, spin 2.4s linear infinite; }
#seats .seat[data-state="learning"] .ring { animation: learn 1.5s ease-in-out infinite, spin 1.6s linear infinite; }
#seats.ending .seat .ring { animation: none; }
/* Send: a white circle with an arrow, at the end of the bubble; dim until there is something to send. */
.answer-send { flex: none; display: grid; place-items: center; width: 28px; height: 28px; padding: 0; border: 0; border-radius: var(--radius-pill);
  background: var(--on-request); color: var(--flow-request); cursor: pointer; transition: opacity var(--motion-fast) ease, transform var(--motion-fast) var(--motion-ease); }
.answer-send:disabled { opacity: 0.45; cursor: default; }
.answer-send:not(:disabled):active { transform: scale(0.92); }
.answer-send svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.answer-send:focus-visible { outline: 2px solid var(--on-request); outline-offset: 2px; }
.answer.auto .answer-send { opacity: 0.45; }
.answer-time { right: 40px; }
/* The hint fades out and back in as it changes. */
.answer input::placeholder { color: color-mix(in srgb, var(--on-request) 72%, transparent); transition: opacity var(--motion-base) ease; }
.answer.swap input::placeholder { opacity: 0; }

/* Lusolo checks what it understood (founder, 2026-11-08: "ask the user to confirm things"): your bubble offers two
   answers. Brand tokens only: the action colour, pill radius, the brand's motion. */
.answer.choices { width: auto; gap: 6px; padding: 3px; }
.answer.choices .answer-time { left: 12px; right: 12px; }
.answer-choice { flex: none; height: 28px; padding: 0 14px; border: 0; border-radius: var(--radius-pill); cursor: pointer;
  font: 600 14px var(--font-ui); background: var(--on-request); color: var(--flow-request);
  transition: transform var(--motion-fast) var(--motion-ease), opacity var(--motion-fast) ease; }
.answer-choice.alt { background: transparent; color: var(--on-request); box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--on-request) 60%, transparent); }
.answer-choice:active { transform: scale(0.96); }
.answer-choice:focus-visible { outline: 2px solid var(--on-request); outline-offset: 2px; }
#seats .customers-name { font-size: 18px; }

/* Words sized in screen pixels (--u, set in app.js), never smaller than their drawn size. Lusolo's status line is the
   one to read: 15px on screen, and while it asks you something it is bold and blue (founder, 2026-11-08). */
#seats { --u: 1; }
#seats .hub-state { font-size: max(13px, calc(15px * var(--u))); }
#seats .hub[data-mode="asking"] ~ .hub-state, #seats .hub-state.asking { font-weight: 600; fill: var(--flow-request); }
#seats .bubble-text { font-size: max(15px, calc(15px * var(--u))); }
#seats .you { font-size: max(16px, calc(14px * var(--u))); }
#seats .customers-name { font-size: max(18px, calc(14px * var(--u))); }
#seats .ledger { font-size: max(15px, calc(12px * var(--u))); }
#seats .hub-name { font-size: max(17px, calc(14px * var(--u))); }

/* The composer (founder, 2026-11-08: "make it clear we want their input … like ChatGPT's input box"). Lusolo's
   question sits above it in the status style; the box breathes a soft ring until you touch it. On phones it spans
   the screen over a blurred strip of the drawing, so it reads as the place to type. */
.ask { position: absolute; z-index: 5; display: grid; gap: 12px; width: max-content; max-width: calc(100vw - 32px); }
.ask-q { margin: 0 0 0 4px; font: 600 15px/1.3 var(--font-ui); color: var(--flow-request); }
.ask .answer { position: relative; width: 270px; max-width: 100%; min-height: 44px; padding: 0 5px 0 18px; }
.ask .answer.choices { width: auto; padding: 5px; justify-self: start; }
.ask .answer-choice { height: 34px; padding: 0 18px; font-size: 15px; }
.ask .answer-send { width: 34px; height: 34px; }
.ask .answer:not(.engaged):not(.auto) { animation: answer-in var(--motion-base) var(--motion-ease); }   /* no blue ring (founder, 2026-11-08) */
@keyframes invite {
  0%, 100% { box-shadow: 0 0 0 4px color-mix(in srgb, var(--flow-request) 22%, transparent); }
  50% { box-shadow: 0 0 0 9px color-mix(in srgb, var(--flow-request) 10%, transparent); }
}
.ask.wide { width: calc(100vw - 8px); padding: 12px; margin: -12px; border-radius: var(--radius-card);
  background: color-mix(in srgb, var(--brand-ground) 82%, transparent); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }
.ask.wide .answer { width: 100%; min-height: 50px; }
.ask.wide .answer::after { display: none; }
.ask.wide .ask-q { font-size: 16px; }
@media (prefers-reduced-motion: reduce) { .ask .answer:not(.engaged):not(.auto) { animation: none; } }
.ask:not(.wide) .ask-q { display: none; }   /* desktop: the question is the status line beside Lusolo */
/* While Lusolo waits for your answer the drawing steps back (founder, 2026-11-08: "change the interface when it asks"):
   everything but Lusolo, you and the line between you fades, so the eye goes to the question and the box. */
#seats > * { transition: opacity var(--motion-slow) var(--motion-ease); }
#seats.listening > :not(.hub):not(.hub-name):not(.hub-state):not(.rule):not(.you):not(.human:not(.customers)):not(defs):not(.bubble):not(.bubble-text) { opacity: 0.25; }
/* Turnstile's invisible check: shown only if Cloudflare needs the visitor to click (rare), bottom-right. */
.human-check { position: fixed; right: 16px; bottom: 16px; z-index: 7; }
.human-check:empty { display: none; }
/* Likely answers under the box: tap one instead of typing. */
.ask-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.ask-chip { height: 32px; padding: 0 14px; border: 0; border-radius: var(--radius-pill); cursor: pointer;
  font: 500 14px var(--font-ui); color: var(--flow-request); background: color-mix(in srgb, var(--flow-request) 14%, var(--brand-ground));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--flow-request) 35%, transparent);
  transition: transform var(--motion-fast) var(--motion-ease), background var(--motion-fast) ease; }
.ask-chip:hover { background: color-mix(in srgb, var(--flow-request) 24%, var(--brand-ground)); }
.ask-chip:active { transform: scale(0.96); }
.ask-chip:focus-visible { outline: 2px solid var(--flow-request); outline-offset: 2px; }
.ask-who { margin-right: 8px; color: var(--brand-line); }
.ask-who::before { content: ''; display: inline-block; width: 9px; height: 9px; margin-right: 6px; border-radius: var(--radius-pill);
  background: var(--brand-lead); vertical-align: 1px; }

/* On the design system (founder, 2026-11-08: "the send must be with the design system"): the composer is a field like
   the email field (card, 2px border, control radius), outlined in the request blue because Lusolo is asking; send is
   the standard button (action colour, control radius) with an arrow; options are buttons too. */
.ask .answer { background: var(--color-card); border: 2px solid var(--flow-request); border-radius: var(--radius-control);
  min-height: 48px; padding: 0 4px 0 14px; }
.ask .answer::after { display: none; }
.ask .answer input, .ask .answer.auto input { color: var(--color-ink); caret-color: var(--flow-request); }
.ask .answer input::placeholder { color: var(--color-text-muted); }
.ask .answer-time { background: var(--flow-request); bottom: -2px; left: -2px; right: -2px; height: 2px; border-radius: 0; }
.ask .answer-send { width: 38px; height: 38px; min-height: 0; padding: 0; border-radius: var(--radius-control);
  background: var(--color-action); color: var(--color-on-action); }
.ask .answer-send svg { width: 18px; height: 18px; stroke-width: 2; }
.ask .answer-send:focus-visible { outline: 2px solid var(--flow-request); outline-offset: 2px; }
.ask .answer.choices { border: 0; background: transparent; padding: 0; gap: 8px; box-shadow: none; animation: answer-in var(--motion-base) var(--motion-ease); }
.ask .answer.choices .answer-time { display: none; }
.ask .answer-choice { height: 44px; min-height: 0; padding: 0 18px; border-radius: var(--radius-control); font: 600 16px var(--font-ui);
  background: var(--color-action); color: var(--color-on-action); }
.ask .answer-choice.alt { background: var(--color-card); color: var(--color-ink); box-shadow: inset 0 0 0 2px var(--brand-line); }
.ask .answer-choice:focus-visible { outline: 2px solid var(--flow-request); }
.ask-chip { height: 36px; min-height: 0; border-radius: var(--radius-control); color: var(--color-ink); background: var(--color-card);
  box-shadow: inset 0 0 0 1.5px var(--color-hairline); font: 500 15px var(--font-ui); }
.ask-chip:hover { background: var(--color-hover); }
@keyframes invite {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--flow-request) 0%, transparent); }
  50% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--flow-request) 22%, transparent); }
}

/* The composer IS the design system's input bar, the "echo bar" (lusolo docs/design/design-system-plan.md, decided
   2026-11-07; CSS from packages/renderer/preview/app.css .pv-cmp.echo): a white soft body with uneven corners, a 1px
   ink edge, an ink copy offset behind it like cut paper. No blue, no glow (the chat pill with a shadow was rejected).
   It asks for attention the system's way: the copy drifts out and back until you touch it, and settles closer while
   you type. Send is the system's icon button (44px, ink, hover tint). The low line is the clock. */
.ask .answer, .ask.wide .answer { position: relative; isolation: isolate; background: none; border: 0; border-radius: 0; box-shadow: none;
  min-height: 52px; padding: 4px 6px 4px 20px; animation: answer-in var(--motion-base) var(--motion-ease); }
.ask .answer:not(.choices)::before, .ask .answer:not(.choices)::after { content: ''; display: block; position: absolute; inset: 0; left: 0; bottom: 0;
  width: auto; height: auto; clip-path: none; border-radius: 28px 24px 26px 22px / 26px 28px 22px 24px; pointer-events: none; }
.ask .answer:not(.choices)::before { z-index: -1; background: var(--echo-field, #fff); box-shadow: inset 0 0 0 1px var(--color-ink); }
.ask .answer:not(.choices)::after { z-index: -2; background: var(--color-ink); transform: translate(3px, 3.5px) rotate(-0.7deg);
  transition: transform var(--motion-slow) var(--motion-ease); }
.ask .answer:not(.choices):not(.engaged):not(.auto)::after { animation: echo-invite 2.4s var(--motion-ease) 0.6s infinite; }
@keyframes echo-invite { 0%, 100% { transform: translate(3px, 3.5px) rotate(-0.7deg); } 50% { transform: translate(6px, 7px) rotate(-1.2deg); } }
.ask .answer:focus-within::after { transform: translate(1.5px, 2px) rotate(-0.4deg); }
:root { --echo-field: #fff; }
@media (prefers-color-scheme: dark) { :root { --echo-field: color-mix(in srgb, var(--color-card) 88%, #fff); } }
.ask .answer input, .ask .answer.auto input { color: var(--color-ink); caret-color: var(--color-ink); font: 500 16px var(--font-ui); }
.ask .answer input::placeholder { color: var(--color-text-muted); }
.ask .answer-time { left: 20px; right: 56px; bottom: 9px; height: 1px; border-radius: 0; background: color-mix(in srgb, var(--color-ink) 22%, transparent); }
.ask .answer-send, .ask .answer-send:disabled { width: 44px; height: 44px; min-height: 0; padding: 0; border-radius: 50%; opacity: 1;
  background: none; color: var(--color-ink); cursor: pointer; }
.ask .answer-send:disabled { color: var(--color-text-muted); }
.ask .answer-send:hover { background: color-mix(in srgb, var(--color-ink) 7%, transparent); }
.ask .answer-send:focus-visible { outline: 2px solid var(--color-ink); outline-offset: -2px; }
.ask .answer-send svg { width: 24px; height: 24px; stroke-width: 1.5; }
/* Options: ink buttons (primary) and card buttons with an ink edge; likely answers: card chips with a hairline. */
.ask .answer-choice { background: var(--color-action); color: var(--color-on-action); border-radius: var(--radius-control); }
.ask .answer-choice.alt { background: var(--color-card); color: var(--color-ink); box-shadow: inset 0 0 0 1px var(--color-ink); }
.ask .answer-choice:focus-visible, .ask-chip:focus-visible { outline: 2px solid var(--color-ink); outline-offset: 2px; }
.ask-who::before { background: var(--color-ink); }
@media (prefers-reduced-motion: reduce) { .ask .answer::after { animation: none !important; transition: none; } }
/* A seat this business does not need yet: faint, no line, says so (founder, 2026-11-08). */
/* A seat this business doesn't need is not drawn at all (founder, 2026-11-08: the hollow rings looked broken). */
#seats .seat[data-state="unneeded"] { display: none; }

/* Approvals (founder, 2026-11-08: "show how it's asking the human to approve", "use the design system"): the card
   always shows its question, on desktop too, under a "Needs your OK" label. Design system: labels are --text-label,
   .08em caps, secondary text; "needs you" is one red-orange disc (--state-dot-attention) with a soft ping, 2.2 s x 3,
   and the only red-orange on screen (so "You · needs your OK" stays secondary text). */
.ask.approve:not(.wide) .ask-q { display: block; }
.ask.approve .ask-q { color: var(--color-ink); }
.ask-kicker { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-1);
  font: 500 var(--text-label)/1 var(--font-ui); letter-spacing: .08em; text-transform: uppercase; color: var(--color-text-secondary); }
.ask-kicker::before { content: ''; flex: none; width: var(--state-dot-attention); height: var(--state-dot-attention);
  border-radius: var(--radius-pill); background: var(--color-state-attention); animation: needs-you-ping 2200ms var(--motion-ease) 3; }
.ask.approve .ask-who { display: none; }
@keyframes needs-you-ping { 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-state-attention) 45%, transparent); }
  70%, 100% { box-shadow: 0 0 0 8px transparent; } }
@media (prefers-reduced-motion: reduce) { .ask-kicker::before { animation: none; } }

/* Tooltips (founder, 2026-11-08): the design system's card: card fill, hairline edge, control radius, small text. */
.tip { position: absolute; z-index: 6; max-width: 240px; padding: var(--space-2) var(--space-3); pointer-events: none;
  /* Frosted glass from the card token: the drawing shows through, the text stays readable (founder, 2026-11-08). */
  background: color-mix(in srgb, var(--color-card) 62%, transparent);
  -webkit-backdrop-filter: blur(14px) saturate(1.4); backdrop-filter: blur(14px) saturate(1.4);
  color: var(--color-ink); border: 1px solid color-mix(in srgb, var(--color-hairline) 70%, transparent); border-radius: var(--radius-control);
  box-shadow: 0 1px 2px color-mix(in srgb, var(--color-ink) 6%, transparent), 0 8px 24px -8px color-mix(in srgb, var(--color-ink) 18%, transparent);
  font: 400 var(--text-small)/1.4 var(--font-ui); transform-origin: top left; animation: tip-in 150ms var(--motion-ease); }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .tip { background: color-mix(in srgb, var(--color-card) 92%, transparent); }
}
.tip strong { display: block; font-weight: 600; letter-spacing: -0.005em; }
.tip p { margin: 2px 0 0; }
.tip p + p { color: var(--color-text-secondary); }
@keyframes tip-in { from { opacity: 0; transform: translateY(2px) scale(0.97); } }
@media (prefers-reduced-motion: reduce) { .tip { animation: none; } }
