/*
 * One screen, one button.
 *
 * The rules this is built to, in the order they overrode ordinary taste:
 *
 *   Nothing scrolls. If a reply is too long to fit, the type shrinks — she
 *   should never have to discover that there is more below the fold.
 *   Nothing is small. The button is most of the screen; the two secondary
 *   controls are still larger than the 44px minimum by half again.
 *   Nothing is grey-on-grey. Warm off-white on warm near-black is about 15:1,
 *   well past AAA, and easier on an older eye at night than pure white.
 *   Nothing moves without meaning. The only animation in the file is the
 *   listening pulse and the thinking shimmer, and both say what state it is in.
 */

:root {
  --bg: #17140f;
  --ink: #f4ede0;
  --dim: #9b917f;
  --amber: #e3a04a;
  --amber-deep: #b8762a;
  --green: #7fb069;
  --red: #d9776a;

  /* Set from JS to the real viewport height — iOS Safari's 100vh lies, and
     the bottom of the button ends up under the browser chrome. */
  --vh: 100vh;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;                       /* nothing scrolls, ever */
  background: var(--bg);
  color: var(--ink);
  font-family: ui-rounded, "SF Pro Rounded", -apple-system, "Segoe UI", system-ui, sans-serif;
  /* She is holding the phone and will press things hard and often; none of
     that should ever select text or trigger a magnifier. */
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  overscroll-behavior: none;
}

.screen {
  height: var(--vh);
  display: flex;
  flex-direction: column;
  padding: max(1rem, env(safe-area-inset-top)) 1.25rem max(1.25rem, env(safe-area-inset-bottom));
}
[hidden] { display: none !important; }

/* ── Signing in ──────────────────────────────────────────────── */

#signin { align-items: center; justify-content: center; gap: 1.5rem; text-align: center; }
.signin-title { font-size: 3rem; font-weight: 600; margin: 0; letter-spacing: -0.02em; }
.signin-note { font-size: 1.25rem; color: var(--dim); margin: 0; max-width: 20rem; line-height: 1.5; }
.signin-error {
  color: var(--red); font-size: 1.1rem; line-height: 1.5;
  max-width: 22rem; margin: 0; padding: 0 1rem;
}

/* Typed once, by you, standing next to her. Big enough to check at arm's
   length, and monospaced so a 5 cannot be mistaken for an S. */
.claim { display: flex; flex-direction: column; gap: 1rem; align-items: center; width: min(22rem, 86vw); }
.claim-code {
  width: 100%; padding: 0.9rem 1rem; text-align: center;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 1.6rem; letter-spacing: 0.12em; text-transform: uppercase;
  border: 2px solid var(--dim); border-radius: 0.75rem;
  background: transparent; color: inherit;
}
.claim-code:focus { outline: none; border-color: currentColor; }
.claim-go {
  width: 100%; padding: 0.9rem 1rem; font-size: 1.25rem; font-weight: 600;
  border: 0; border-radius: 0.75rem; cursor: pointer;
}
.claim-go:disabled { opacity: 0.5; }

/* ── The conversation ────────────────────────────────────────── */

#conversation {
  flex: 1 1 auto;
  min-height: 0;                          /* lets the flex child actually shrink */
  overflow: hidden;                       /* and makes scrollHeight meaningful to fitReply() */
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.9rem;
  padding: 0.5rem 0.25rem;
}

/* What she said, shown small — it is only there so she can see it heard her
   correctly. The answer is the thing that matters. */
.heard {
  margin: 0;
  font-size: 1.05rem;
  line-height: 1.4;
  color: var(--dim);
  text-align: center;
  max-height: 4.2em;
  overflow: hidden;
}
.heard::before { content: "“"; }
.heard::after  { content: "”"; }

#reply-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.85rem;
  min-height: 0;
}

.shot {
  max-width: min(58vw, 15rem);
  max-height: 28vh;
  border-radius: 1rem;
  object-fit: cover;
  box-shadow: 0 0.4rem 1.4rem rgba(0, 0, 0, 0.45);
}

/* The size is set from JS, which shrinks it to fit rather than letting it
   overflow — see fitReply(). This is the starting point. */
.reply {
  margin: 0;
  font-size: 2rem;
  line-height: 1.32;
  font-weight: 500;
  text-align: center;
  text-wrap: pretty;
  letter-spacing: -0.01em;
  overflow: hidden;
}
.reply.is-error { color: var(--red); font-size: 1.5rem; }

/* ── The button ──────────────────────────────────────────────── */

#controls { flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; gap: 1.1rem; }

.talk {
  position: relative;
  width: min(72vw, 20rem);
  aspect-ratio: 1;
  border: none;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 38%, #2a241a, #1d190f 70%);
  box-shadow:
    inset 0 0 0 0.34rem var(--amber-deep),
    0 0.5rem 2rem rgba(0, 0, 0, 0.5);
  color: var(--ink);
  font: inherit;
  font-size: 1.5rem;
  font-weight: 600;
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: transform 0.12s ease, box-shadow 0.2s ease;
}
.talk:active { transform: scale(0.97); }
.talk-label { position: relative; z-index: 1; padding: 0 1.5rem; text-align: center; line-height: 1.25; }

/* The ring is the only thing that reports state, so each state has to look
   unmistakably different from across a room. */
.talk-ring {
  position: absolute;
  inset: -0.1rem;
  border-radius: 50%;
  pointer-events: none;
}

/* Listening: a slow pulse, plus a ring that tracks how loud she is, so she
   can see it is picking her up without having to trust it. */
.talk[data-state="listening"] {
  box-shadow:
    inset 0 0 0 0.34rem var(--green),
    0 0 calc(1.5rem + var(--level, 0) * 3rem) rgba(127, 176, 105, calc(0.25 + var(--level, 0) * 0.5)),
    0 0.5rem 2rem rgba(0, 0, 0, 0.5);
}
.talk[data-state="listening"] .talk-ring {
  animation: pulse 2s ease-in-out infinite;
  border: 0.12rem solid rgba(127, 176, 105, 0.55);
}
@keyframes pulse {
  0%, 100% { transform: scale(1);    opacity: 0.7; }
  50%      { transform: scale(1.06); opacity: 0; }
}

.talk[data-state="thinking"] { box-shadow: inset 0 0 0 0.34rem #4a4335, 0 0.5rem 2rem rgba(0,0,0,0.5); color: var(--dim); }
.talk[data-state="thinking"] .talk-ring {
  border: 0.34rem solid transparent;
  border-top-color: var(--amber);
  animation: spin 1.1s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.talk[data-state="speaking"] { box-shadow: inset 0 0 0 0.34rem var(--amber), 0 0.5rem 2rem rgba(0,0,0,0.5); }

.talk[data-state="error"] { box-shadow: inset 0 0 0 0.34rem var(--red), 0 0.5rem 2rem rgba(0,0,0,0.5); }

/* ── The two things that are not the button ──────────────────── */

.extras { display: flex; gap: 2.5rem; }

.extra {
  background: none;
  border: none;
  color: var(--dim);
  font: inherit;
  font-size: 0.95rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.2rem;
  padding: 0.5rem 1rem;                   /* keeps the touch target ~66px tall */
  cursor: pointer;
}
.extra:active { color: var(--amber); }
.extra svg {
  width: 1.9rem; height: 1.9rem;
  fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}

/* ── Short phones ────────────────────────────────────────────── */

@media (max-height: 700px) {
  .talk { width: min(58vw, 15rem); font-size: 1.3rem; }
  .reply { font-size: 1.6rem; }
  .extras { gap: 2rem; }
}

/* Someone who has turned motion down has usually done it for a reason. The
   state still has to be legible, so colour carries it and only the movement
   goes away. */
@media (prefers-reduced-motion: reduce) {
  .talk-ring, .talk[data-state="thinking"] .talk-ring { animation: none !important; }
  .talk[data-state="thinking"] .talk-ring { border-color: var(--amber); }
}
