/* frontend/visitor/app.css */
* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--color-background);
  color: var(--color-text-on-dark);
  font-family: var(--font-ui);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* R3.2: the one shared raised-surface style, applied everywhere — no
   per-control shadow/radius values anywhere else in this stylesheet. */
.raised-surface {
  background: var(--color-surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow-raised);
  border: none;
  /* The surface is light and <body> is dark, so anything landing on a raised
     surface must flip its text colour with it. Without this the four non-button
     surfaces (#mic-status, #speaking-indicator, #slide-counter, #lead-status)
     render --color-text-on-dark on --color-surface: a 1.09 contrast ratio, i.e.
     invisible. Declared on the shared class rather than per element so surfaces
     added later inherit the fix. */
  color: var(--color-text);
}

button.raised-surface,
a.raised-surface {
  color: var(--color-text);
  font-size: var(--text-md);
  font-weight: 600;
  padding: var(--space-3) var(--space-4);
  cursor: pointer;
}

button.raised-surface:disabled {
  opacity: 0.4;
  cursor: default;
}

/* Anchors included because the WhatsApp handoff (#whatsapp-link) is an <a> that
   must look and measure like the raised accent button beside it — element-typed
   to keep the same specificity as button.raised-surface, which would otherwise
   win the colour and paint dark text on the accent fill. */
button.accent,
a.accent {
  background: var(--color-accent);
  /* NEAR-BLACK, not --color-text-on-dark. The accent used to be a dark blue
     and near-white text on it was correct. It is now a light patina, where
     the same rule would paint white on teal and be unreadable. */
  color: var(--color-on-accent);
  font-weight: 700;
}

/* Small caps label. Used on the start screen and above the contact card's
   heading — the same eyebrow/display pairing the owner dashboard uses, so the
   two surfaces read as one product. */
.eyebrow {
  margin: 0;
  font-size: var(--text-caps);
  font-weight: 600;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--color-slate-400);
}

#start-screen {
  height: 100dvh;
  width: 100dvw;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-5);
  text-align: center;
  padding: var(--space-5) var(--space-4);
  position: relative;
  /* One soft pool of light behind the name instead of a flat field. Before the
     deck loads this is the only thing giving the screen a centre, and after it
     loads it is what stops a single line of type floating in a black
     rectangle. Tokens only — no literal colour. */
  background: radial-gradient(
    120% 78% at 50% 38%,
    var(--color-slate-800) 0%,
    var(--color-background) 62%
  );
}

#start-intro {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  max-width: 34rem;
}

#start-screen h1 {
  font-family: var(--font-display);
  /* --text-lg on phones, --text-xl from 600px up (below). Business names here
     run long — "Concrete Accessory Solutions" — so the display size is the one
     that fits the narrow case, and the big one is the enhancement. */
  font-size: var(--text-lg);
  line-height: 1.06;
  letter-spacing: var(--tracking-tight);
  font-weight: 700;
  margin: 0;
  overflow-wrap: break-word;
}

@media (min-width: 600px) {
  #start-screen h1 { font-size: var(--text-xl); }
}

#start-blurb {
  margin: 0;
  max-width: 30rem;
  font-size: var(--text-sm);
  line-height: 1.55;
  color: var(--color-slate-300);
}

#start-btn {
  min-width: 240px;
  min-height: 56px;
}

/* Pinned to the foot of the screen rather than sitting in the centred stack.
   In the stack it floated an indeterminate distance below the button — the
   flex gap plus an empty #start-status — and read as something that had come
   loose. At the bottom it reads as what it is: a footnote. */
#start-note {
  position: absolute;
  left: var(--space-4);
  right: var(--space-4);
  bottom: max(var(--space-5), env(safe-area-inset-bottom));
  margin: 0;
  font-size: var(--text-xs);
  color: var(--color-slate-500);
}

/* An empty status paragraph is the normal case, and in a flex column with a
   gap it still spends a full gap on nothing. */
#start-status:empty {
  display: none;
}

/* Set by app.js on all three deck-load failures. Everything that presumes a
   loaded deck goes away and #start-status is left holding the screen on its
   own, at reading size rather than as a caption under an absent heading. */
#start-screen.empty #start-intro,
#start-screen.empty #start-btn,
#start-screen.empty #start-note {
  display: none;
}

#start-screen.empty #start-status {
  font-size: var(--text-md);
  color: var(--color-slate-300);
}

#presentation-screen {
  position: relative;
  height: 100dvh;
  width: 100dvw;
  display: none;
  background: var(--color-video-backdrop);
}

/* ---------------------------------------------------------------------------
   CHROME OVER THE SLIDE.

   Every control that floats on top of the deck is dark, not the white
   .raised-surface used elsewhere. This is a legibility fix as much as a style
   one: uploaded decks are overwhelmingly white, so a white pill carrying the
   slide counter or the mic warning disappeared into the slide behind it
   exactly when the slide filled the viewport. Dark chrome reads on a white
   slide, on a photo, and on the black letterbox alike.

   The contact card and the WhatsApp handoff stay light — they are a document
   the visitor is reading, not chrome sitting over one.

   Shadow is dropped in favour of a hairline. A drop shadow on a black backdrop
   is invisible and only softens the edge; the border is what actually
   separates the control from the slide.
   ------------------------------------------------------------------------ */
#control-bar .raised-surface,
#speaking-indicator,
#mic-status,
#contact-btn,
#pause-btn {
  background: var(--color-slate-800);
  color: var(--color-text-on-dark);
  border: 1px solid var(--color-slate-700);
  box-shadow: none;
}

#control-bar .raised-surface:hover:not(:disabled),
#contact-btn:hover,
#pause-btn:hover {
  background: var(--color-slate-700);
}

#text-input::placeholder {
  color: var(--color-slate-400);
}

/* One visible focus ring for everything on this screen, in the accent, so
   keyboard use is never a guess. Tokenised colour; the outline width is a
   hairline, not a size token. */
#presentation-screen :focus-visible,
#start-screen :focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

#slide-image {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

#speaking-indicator {
  position: absolute;
  top: var(--space-3);
  left: 50%;
  transform: translateX(-50%);
  padding: var(--space-1) var(--space-3);
  /* Caps label rather than sentence case: it is a status light, not a
     sentence, and at this size lowercase read as a stray caption. */
  font-size: var(--text-caps);
  font-weight: 600;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  opacity: 0;
  transition: opacity 200ms ease;
}

#speaking-indicator.active {
  opacity: 1;
}

#mic-status {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-xs);
  line-height: 1.4;
  max-width: 60%;
}

/* R2.9: control fade — 250ms out, 150ms back in, per the spec's exact timings. */
#control-bar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: max(var(--space-4), env(safe-area-inset-bottom));
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: 0 var(--space-3);
  /* Capped and centred. Stretched edge to edge on a laptop the question field
     became a 1,100px trough — the bar stopped reading as a control strip and
     started reading as a page footer. */
  max-width: 760px;
  margin: 0 auto;
  transition: opacity 150ms ease;
  opacity: 1;
}

#control-bar.faded {
  opacity: 0;
  pointer-events: none;
  transition: opacity 250ms ease;
}

/* Mono, because it is a pair of numbers that changes every few seconds — a
   proportional face makes the whole pill twitch sideways on every advance. */
#slide-counter {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  padding: var(--space-1) var(--space-3);
  white-space: nowrap;
  display: flex;
  align-items: center;
  min-height: 44px;
}

/* R2.11 #2: every tappable control is at least 44x44. Five controls have to fit
   inside a 320px viewport (288px of content box), and the default button
   padding spends 48px per button on horizontal air — enough that the flex row
   squeezes the text input down to 32x37. It trades that air for the 44px floor:
   narrower padding, explicit minimums, no overflow at any of the three widths. */
#control-bar button {
  padding-left: var(--space-2);
  padding-right: var(--space-2);
  min-width: 44px;
  min-height: 44px;
}

#text-input {
  flex: 1;
  min-width: 44px;
  min-height: 44px;
  font-size: var(--text-md);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius);
  border: none;
}

/* Hold-to-talk and Stop never fade (spec R2.8) — the row sits above the
   control bar with its own fixed position, unaffected by the bar's opacity
   transition. A row rather than two independently positioned buttons: Stop
   used to be offset off the centre line by half the talk button's width, a
   number that was only correct while that button was a 72px circle. */
#talk-row {
  position: absolute;
  left: 0;
  right: 0;
  bottom: max(calc(var(--space-5) * 3), calc(env(safe-area-inset-bottom) + 96px));
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: 0 var(--space-3);
  /* The row spans the viewport so its contents centre, but it must not sit as
     an invisible sheet over the slide swallowing clicks. */
  pointer-events: none;
}

#talk-row > * {
  pointer-events: auto;
}

/* Was a 72px circle carrying a single 🎤. It is the primary way a visitor
   speaks to the agent and nothing said so — an unlabelled icon button asks
   people to guess, and "hold" in particular is not a convention anyone can
   infer from a microphone. Takes the standard --radius, so the previous
   `border-radius: 50%` exception to the one-radius rule is retired with it. */
#talk-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  /* Measured off the design: ~132x44 with the standard corner, not a pill.
     44 is also the tap-target floor, so the two agree. */
  min-width: 132px;
  min-height: 44px;
  padding: 0 var(--space-3);
  border-radius: var(--radius);
  font-size: var(--text-sm);
  white-space: nowrap;
  /* Held, not tapped — a text selection starting under the thumb on a long
     press is the usual way this control feels broken on mobile. */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

#talk-btn svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

#talk-btn.talking {
  background: var(--color-danger);
  /* --color-on-accent is near-black, which is correct on the light patina and
     unreadable on the oxide red this swaps in. */
  color: var(--color-text-on-dark);
}

/* Position and vertical alignment now come from #talk-row, so the offset
   arithmetic that used to live here — half of talk-btn's 72px width plus a
   gap — is gone along with the fixed-size circle it depended on. Radius and
   height come from .raised-surface and the 44px floor, matching the talk
   button beside it. */
#pause-btn {
  font-size: var(--text-sm);
  /* Vertical padding zeroed, not just the horizontal: button.raised-surface
     sets --space-3 top and bottom, which made this 51px tall beside a 44px
     talk button. The two sit side by side and must measure the same. */
  padding: 0 var(--space-3);
  min-width: 44px;
  min-height: 44px;
  /* Visibility is toggled via .active from app.js, driven off
     ActiveSpeakersChanged — never optimistically on click. opacity +
     visibility + pointer-events (not display) so it can transition and drops
     out of the tab order while hidden without ever being removed from the DOM. */
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 200ms ease, visibility 200ms ease;
}

#pause-btn.active {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}

/* Top-left, mirroring #mic-status's top-right placement. Never fades — it's a
   sibling of #control-bar, not a child, so the fade rule never touches it.
   Same padding/min-size override as #control-bar button, for the same reason:
   the default button padding is wider than this control needs. */
#contact-btn {
  position: absolute;
  top: var(--space-3);
  left: var(--space-3);
  padding-left: var(--space-2);
  padding-right: var(--space-2);
  min-width: 44px;
  min-height: 44px;
}

#lead-overlay {
  position: absolute;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  background: var(--color-overlay-scrim);
  padding: var(--space-4);
}

#lead-card {
  width: 100%;
  max-width: 420px;
  padding: var(--space-5) var(--space-4) var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

#lead-card input,
#lead-card select {
  font-size: var(--text-sm);
  padding: var(--space-3);
  border-radius: var(--radius);
  /* Hairline on three sides and a heavier bottom rule: the field reads as a
     line to write on rather than a moulded box, which is the whole point of
     dropping the old 20px radius. */
  border: 1px solid var(--color-border);
  border-bottom-color: var(--color-slate-300);
  background: var(--color-surface);
  color: var(--color-text);
  min-height: 48px;
  width: 100%;
}

#lead-card input:focus-visible,
#lead-card select:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 1px;
  border-color: var(--color-accent-deep);
}

#lead-card input::placeholder {
  color: var(--color-slate-400);
}

#lead-submit-btn {
  min-height: 52px;
  margin-top: var(--space-1);
}

/* iOS renders a bare <select> at ~32px tall — under the 44px tap-target
   floor — so it needs an explicit min-height on top of the shared rule
   above. Background/text colour are explicit because a plain <select> does
   not reliably inherit them the way a styled input does. The native dropdown
   arrow itself is left alone (see spec) — styling it needs an
   un-tokenisable background-image. */
#lead-card select {
  min-height: 44px;
  background: var(--color-surface);
  color: var(--color-text);
}

/* Flex row, not absolute positioning: at 320px the h2 below already wraps to
   two lines, and an absolutely-positioned 44px close button would land on
   top of that second line. */
#lead-card-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-2);
}

#lead-card-header h2 {
  flex: 1;
  min-width: 0;
}

#lead-close-btn {
  padding-left: var(--space-2);
  padding-right: var(--space-2);
  min-width: 44px;
  min-height: 44px;
  flex-shrink: 0;
  background: transparent;
  box-shadow: none;
  color: var(--color-text-muted);
}

#lead-close-btn:hover {
  background: var(--color-slate-050);
  color: var(--color-text);
}

#lead-card h2 {
  font-family: var(--font-display);
  font-size: var(--text-md);
  line-height: 1.2;
  letter-spacing: var(--tracking-tight);
  font-weight: 700;
  margin: 0;
  color: var(--color-text);
}

#lead-card-title {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}

/* The eyebrow sits on white here rather than on the dark start screen, so the
   slate-400 it carries by default is too faint to read. */
#lead-card .eyebrow {
  color: var(--color-accent-deep);
}

/* Deliberately sets no colour. app.js swaps this element's whole className to
   "warn" on a failed save, and an id selector here would outrank .warn and
   paint the error muted grey. Colour stays with .status / .warn. */
#lead-status {
  margin: 0;
  font-size: var(--text-xs);
}

#whatsapp-link {
  display: block;
  text-align: center;
  text-decoration: none;
  padding: var(--space-3) var(--space-4);
}

/* .status must NOT pin a colour. It is used on two different backgrounds:
   #lead-status sits inside #lead-card (a .raised-surface, which already sets
   the dark-on-white colour), while #start-status sits directly on the dark
   page background and needs body's light text. Pinning --color-text here
   rendered the start screen's status at ~1.1 contrast — invisible. Inherit
   instead, so each one picks up whichever surface it actually sits on. */
.status { color: inherit; }
.warn { color: var(--color-danger); }
