/* livedemo.css — the /livedemo stage: URL in, live receptionist out.
 *
 * Built for an iPad first. That decision drives most of what looks unusual here:
 *
 *   - Sizes are clamp()ed against the 768–1194px band, not scaled down from a
 *     desktop layout. The demo is given hand-to-hand at a counter, so nothing
 *     may need a second look to read.
 *   - Every target is >= 56px. There is no hover on a tablet, so hover only ever
 *     adds polish; :active carries the real feedback.
 *   - 100dvh, never 100vh — iPadOS Safari's toolbar makes vh taller than the
 *     visible page, which pushed the call button under the chrome.
 *   - The stage is one element that swaps states (form → reading → ready →
 *     live). No route change, no scroll: on a handheld screen the whole demo
 *     has to live inside one frame.
 *
 * Tokens, buttons and type come from base.css / components.css — this file adds
 * only what the landing page has no equivalent for.
 */

/* ---------------------------------------------------------------- shell ---- */

.ld {
  position: relative;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  padding: calc(env(safe-area-inset-top) + 92px) var(--pad)
           calc(env(safe-area-inset-bottom) + 40px);
  overflow: hidden;
}

.ld__gradient {
  position: absolute;
  inset: -20% -10% auto -10%;
  height: 80%;
  background:
    radial-gradient(48% 60% at 22% 18%, rgba(246, 201, 168, 0.55), transparent 70%),
    radial-gradient(42% 52% at 82% 12%, rgba(207, 195, 232, 0.45), transparent 72%),
    radial-gradient(36% 46% at 60% 52%, rgba(243, 182, 176, 0.38), transparent 70%);
  filter: blur(8px);
  pointer-events: none;
}

/* Same grain the hero uses — it is what keeps the flat cream from looking like
   a default background colour on a bright tablet screen in a bright room. */
.ld__grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.32;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
}

.ld__inner {
  position: relative;
  width: 100%;
  max-width: 1080px;
  margin: 0 auto;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: clamp(22px, 3.4vw, 38px);
}

/* ------------------------------------------------------------- intro ------ */

.ld__eyebrow {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-mute);
  margin: 0 0 14px;
}

.ld__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.4rem, 5.4vw, 4rem);
  line-height: 1.02;
  letter-spacing: -0.03em;
  margin: 0 0 16px;
  max-width: 16ch;
}

/* Only the first screen gets hero type. Once the demo is running, the heading
   is a step label above the thing that matters (the log, the card) — at hero
   size it out-shouts its own content. */
[data-ld-pane="reading"] .ld__title,
[data-ld-pane="ready"] .ld__title {
  font-size: clamp(1.9rem, 3.4vw, 2.6rem);
  max-width: 24ch;
  margin-bottom: 24px;
}

.ld__title em {
  font-style: normal;
  color: var(--accent);
}

.ld__sub {
  font-size: clamp(1.05rem, 1.8vw, 1.28rem);
  line-height: 1.5;
  color: var(--ink-soft);
  max-width: 46ch;
  margin: 0;
}

/* --------------------------------------------------------------- ask ------ */

/* One column, held at reading width and centred in the stage. The right half
   used to carry a painted sphere; it read as decoration rather than product, so
   the first screen is now the sentence and the field, nothing else. */
/* Centred, not left-aligned: on a tablet held in two hands the field should sit
   under the eye, not off to one side. */
.ld__ask {
  max-width: 760px;
  margin-inline: auto;
  text-align: center;
}

.ld__ask .ld__title,
.ld__ask .ld__sub { max-width: none; }
.ld__ask .ld__form { margin-inline: auto; }

/* --------------------------------------------------------------- form ----- */

.ld__form {
  display: flex;
  gap: 12px;
  align-items: stretch;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: calc(var(--radius) + 8px);
  padding: 10px;
  box-shadow: 0 24px 60px -34px rgba(22, 19, 15, 0.45);
  max-width: 640px;
}

.ld__input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  font-family: var(--font-body);
  /* 17px minimum: iOS Safari zooms the whole page in on focus for anything
     smaller, which on the iPad throws the stage off-centre mid-demo. */
  font-size: 1.12rem;
  color: var(--ink);
  padding: 0 14px;
  min-height: 60px;
}

.ld__input::placeholder { color: var(--ink-mute); }
.ld__input:focus { outline: none; }
.ld__form:focus-within { border-color: var(--accent); }

.ld__go {
  min-height: 60px;
  padding-inline: clamp(22px, 3vw, 34px);
  white-space: nowrap;
}

.ld__hint {
  font-size: 0.92rem;
  color: var(--ink-mute);
  margin: 12px 0 0;
}

.ld__error {
  color: var(--accent-text);
  font-size: 0.98rem;
  margin: 12px 0 0;
  min-height: 1.2em;
}

/* ------------------------------------------------------------ reading ----- */

/* The read takes 3–8 seconds. Rather than a spinner, the page shows what is
   actually happening, line by line, as the SSE events land — on a tablet handed
   to somebody, those seconds are the pitch, not dead time. */
.ld__log {
  list-style: none;
  /* A reading list that runs the full 1080px reads as an empty page with four
     stray lines on it; at text width it reads as a terminal doing work. */
  max-width: 620px;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-family: var(--font-mono);
  font-size: clamp(0.92rem, 1.5vw, 1.02rem);
}

.ld__log li {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 4px;
  border-bottom: 1px solid var(--line);
  color: var(--ink-soft);
  opacity: 0;
  transform: translateY(8px);
  animation: ldLine 0.45s var(--ease-out) forwards;
}

.ld__log li:last-child { border-bottom: 0; }

@keyframes ldLine {
  to { opacity: 1; transform: none; }
}

.ld__log b {
  font-weight: 500;
  color: var(--ink);
}

.ld__mark {
  flex: none;
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  font-size: 0.72rem;
  color: #fff;
  background: var(--accent);
}

.ld__mark--run {
  background: transparent;
  border: 2px solid var(--line);
  border-top-color: var(--accent);
  animation: ldSpin 0.8s linear infinite;
}

@keyframes ldSpin { to { transform: rotate(360deg); } }

/* ------------------------------------------------------------- ready ------ */

.ld__card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(22px, 3vw, 34px);
  box-shadow: 0 30px 70px -40px rgba(22, 19, 15, 0.5);
}

.ld__card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}

.ld__card-name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.5rem, 2.8vw, 2.1rem);
  letter-spacing: -0.02em;
  margin: 0;
}

.ld__card-meta {
  font-family: var(--font-mono);
  font-size: 0.86rem;
  color: var(--ink-mute);
}

.ld__facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 14px 26px;
  margin: 0 0 22px;
}

/* Opening hours and the caller notes run long — a 200px grid column turns them
   into a ragged stack of two-word lines. */
.ld__fact--wide { grid-column: 1 / -1; }

.ld__fact dt {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-mute);
  margin-bottom: 4px;
}

.ld__fact dd {
  margin: 0;
  font-size: 1.02rem;
  line-height: 1.45;
  color: var(--ink);
}

.ld__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.ld__chip {
  font-size: 0.92rem;
  padding: 7px 14px;
  border-radius: 999px;
  background: rgba(255, 90, 60, 0.1);
  color: var(--accent-text);
}

.ld__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  margin-top: 22px;
}

.ld__actions .btn { min-height: 62px; }

.ld__again {
  background: none;
  border: 0;
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--ink-mute);
  text-decoration: underline;
  text-underline-offset: 4px;
  padding: 18px 6px;
  cursor: pointer;
}

/* -------------------------------------------------------------- live ------ */

/* Landscape iPad: calendar and orb side by side, because the whole point is
   watching the grid fill while Lina talks. Portrait stacks them, orb first —
   the voice is what the visitor is looking at until a booking happens. */
/* [hidden] has to be restated: .btn sets display:inline-flex, which beats the
   UA stylesheet's [hidden]{display:none} and left the post-call CTA on screen
   for the whole call. */
[hidden] { display: none !important; }

.ld__live {
  display: grid;
  grid-template-columns: 1.35fr 1fr;
  gap: clamp(16px, 2.2vw, 26px);
  align-items: stretch;
  /* Without a floor the two panels shrink to their content and the stage looks
     like it lost something. The week grid is the tallest thing either will
     hold, so this is roughly "as tall as the calendar wants to be". */
  min-height: min(70dvh, 660px);
}

.ld__panel {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(16px, 2vw, 24px);
  box-shadow: 0 30px 70px -44px rgba(22, 19, 15, 0.5);
  min-height: 0;
}

.ld__panel--cal {
  overflow: auto;
  -webkit-overflow-scrolling: touch;
}

.ld__panel--voice {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  text-align: center;
}

.ld__orb {
  position: relative;
  width: clamp(140px, 20vw, 210px);
  aspect-ratio: 1;
  border-radius: 50%;
}

.ld__orb canvas {
  position: relative;
  width: 100%;
  height: 100%;
  display: block;
  border-radius: 50%;
}

/* No ring here — on an iPad the pulsing border broke out of the panel. The
   blob canvas carries the state on its own, so the element only breathes. */
.ld__orb[data-orb-state="idle"] { animation: ldBreathe 3s ease-in-out infinite; }
.ld__orb[data-orb-state="thinking"] { animation: ldBreathe 1.4s ease-in-out infinite; }

@keyframes ldBreathe {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.04); }
}

.ld__status {
  font-family: var(--font-mono);
  font-size: 0.94rem;
  color: var(--ink-mute);
  min-height: 1.4em;
  margin: 0;
}

.ld__who {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.15rem;
  margin: 0;
}

/* ------------------------------------------------------------- states ----- */

/* One stage, four faces. Hidden panes are display:none rather than
   visibility:hidden so the calendar never lays out (and never animates) until
   the call it belongs to actually starts. */
[data-ld-pane] { display: none; }
[data-ld-pane].is-on { display: block; }
.ld__live[data-ld-pane].is-on { display: grid; }
.ld__pane-fade { animation: ldFade 0.5s var(--ease-out) both; }

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

/* ---------------------------------------------------------- responsive ---- */

/* iPad portrait (768 / 834) and anything narrower: one column, orb above the
   grid, and the panels get a fixed share of the viewport so the call button
   stays reachable with a thumb. */
@media (max-width: 980px) {
  .ld__live {
    grid-template-columns: 1fr;
    grid-template-rows: auto 1fr;
  }
  .ld__panel--voice { order: -1; }
  .ld__panel--cal { max-height: 42dvh; }
  .ld__form { flex-direction: column; }
  .ld__go { width: 100%; }
}

@media (max-width: 600px) {
  .ld { padding-top: calc(env(safe-area-inset-top) + 76px); }
  .ld__facts { grid-template-columns: 1fr; }
  .ld__actions { flex-direction: column; align-items: stretch; }
  .ld__actions .btn { width: 100%; justify-content: center; }
}

/* A tablet has no pointer to hover with, so the lift belongs on press. */
@media (hover: none) {
  .ld__go:active,
  .ld__actions .btn:active { transform: scale(0.98); }
}

@media (prefers-reduced-motion: reduce) {
  .ld__log li,
  .ld__pane-fade,
  .ld__orb,
  .ld__mark--run { animation: none; opacity: 1; transform: none; }
}

/* ------------------------------------------------------- the week grid ---- */

/* calendar.js renders the same .cal-cell / .cal-event markup the homepage
   dashboard uses, and components.css sizes those for a desktop section. Here
   the whole week (7 days x 8 hours) has to fit one iPad panel without
   scrolling, so the cells are compacted exactly as demo-popup.css compacts them
   for the modal. Nothing is restyled — only resized. */
.ld__panel--cal .cal-cell { min-height: clamp(32px, 4.6dvh, 52px); }
.ld__panel--cal .cal-cell--head {
  min-height: 36px;
  font-size: 0.78rem;
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--card);
}
.ld__panel--cal .cal-cell--time { font-size: 0.68rem; }
.ld__panel--cal .cal-event { padding: 4px 6px; font-size: 0.66rem; }
.ld__panel--cal .cal-event small { font-size: 0.58rem; margin-top: 1px; }
.ld__panel--cal .cal-event__title {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The slot Lina just booked is the point of the whole screen: the pre-filled
   ambience recedes so the new event is the only saturated thing on the grid. */
.ld__panel--cal .cal-event--a,
.ld__panel--cal .cal-event--b,
.ld__panel--cal .cal-event--c,
.ld__panel--cal .cal-event--d { opacity: 0.72; }
.ld__panel--cal .cal-event--live { opacity: 1; }
