/* public-help/styles.css
   ─────────────────────────────────────────────────────────────────────────────
   A phone app a host opens mid-setup, often in a dark room with one hand. Dark
   by default to match the desktop, large tap targets, and nothing that needs a
   second hand.

   Colours track the desktop's zinc palette so the two read as one product. */

:root {
  /* ── THE DESKTOP'S PALETTE, NOT AN APPROXIMATION OF IT ────────────────────
     Taken from src/index.css and src/pages/Help.tsx in phenom-bingo-2.0, which
     is the same screen on a bigger display. The first cut of this file guessed
     "zinc and indigo" and was wrong twice: the app's greys are NEUTRAL (hue 0)
     rather than zinc's blue-tinted ones, and the brand colour is the green from
     the logo, not indigo.

     The Help page itself uses Tailwind's zinc-* for its panels, so those values
     are zinc here too. Only the page background and the brand come from the
     app's CSS variables. Where the two disagree, the Help page wins — it is the
     screen this app is a copy of. */

  /* --background: 0 0% 4% */
  --bg: #0a0a0a;
  --panel: #18181b;          /* zinc-900: assistant bubble, composer, menu */
  --panel-2: #27272a;        /* zinc-800: inline code, secondary buttons */
  --line: #27272a;           /* zinc-800: every border on the Help page */
  --line-strong: #3f3f46;    /* zinc-700: hover and focus */
  --text: #f4f4f5;           /* zinc-100 */
  --text-2: #e4e4e7;         /* zinc-200: answer body */
  --muted: #a1a1aa;          /* zinc-400 */
  --dim: #71717a;            /* zinc-500: the "From:" label, quiet chips */

  /* The Phenom green. --primary: 87 78% 49% in the desktop's index.css, and
     the `phenom` scale in tailwind.config.js. */
  --brand: #84e019;          /* phenom-500 */
  --brand-300: #abed50;      /* source chips */
  --brand-50: #f4fde8;       /* text inside the host's own bubble */
  /* --primary-foreground: 0 0% 5%. The green is bright enough that white text
     on it fails contrast; the desktop puts near-black on it and so does this. */
  --brand-on: #0d0d0d;
  --brand-tint: rgba(132, 224, 25, 0.15);   /* bg-phenom-500/15 */
  --brand-edge: rgba(132, 224, 25, 0.25);   /* border-phenom-500/25 */

  /* amber-500/10 and /30, amber-200 — the desktop's own warning treatment. */
  --warn-bg: rgba(245, 158, 11, 0.10);
  --warn-line: rgba(245, 158, 11, 0.30);
  --warn-text: #fde68a;
  --warn-dim: rgba(252, 211, 77, 0.8);      /* amber-300/80 */

  --error: #fca5a5;

  /* --radius: 0.5rem. Bubbles are rounded-2xl (16px) with one small corner as
     a tail, which is what makes them read as speech rather than as cards. */
  --radius: 8px;
  --radius-bubble: 16px;
  --radius-tail: 4px;

  /* Safe areas, so the composer clears the home indicator and the header
     clears the notch. Without these the send button is unreachable on any
     modern iPhone in standalone mode. */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
}

* { box-sizing: border-box; }

/* ── `hidden` MUST WIN ───────────────────────────────────────────────────────
   The HTML `hidden` attribute is only `display: none` from the UA stylesheet, so
   ANY author `display` rule beats it. `.menu { display: flex }` did exactly
   that: the menu was permanently open, the JS toggling `hidden` changed a
   property nobody could see, and a check asserting `menu.hidden === false`
   passed while the screen was wrong.
   One rule, before anything sets `display`, so it cannot happen again to the
   banner, the install sheet or the next thing that uses the attribute. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, sans-serif;
  /* 16px minimum on inputs or iOS zooms the page when one is focused, which in
     a standalone app leaves the host pinched in with no way back. */
  -webkit-text-size-adjust: 100%;
}

body { overscroll-behavior-y: none; }

#app { height: 100%; }

/* Screens: exactly one is shown, chosen by data-screen on <body>. */
.screen { display: none; height: 100%; }
body[data-screen="signin"]  .screen-signin,
body[data-screen="chat"]    .screen-chat,
body[data-screen="blocked"] .screen-blocked,
body[data-screen="loading"] .screen-loading,
body[data-screen="offline"] .screen-offline { display: flex; flex-direction: column; }
body:not([data-screen]) .screen-loading { display: flex; flex-direction: column; }

.pad {
  padding: calc(24px + var(--safe-top)) 20px calc(24px + var(--safe-bottom));
  max-width: 520px;
  width: 100%;
  margin: 0 auto;
  overflow-y: auto;
}
.centred-block { display: grid; place-items: center; height: 100%; }
.mark { display: block; border-radius: 12px; margin-bottom: 20px; }

h1 { font-size: 1.5rem; margin: 0 0 6px; letter-spacing: -0.01em; }
.lede { color: var(--muted); margin: 0 0 24px; }
.fine { color: var(--muted); font-size: 0.85rem; }
.centred { display: block; margin: 12px auto 0; }

/* ── forms ───────────────────────────────────────────────────────────────── */

label {
  display: block;
  font-size: 0.85rem;
  color: var(--muted);
  margin: 16px 0 6px;
}
input[type="email"], input[type="password"], textarea {
  width: 100%;
  font: inherit;
  color: var(--text);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 13px 14px;
}
input:focus, textarea:focus {
  /* The desktop's composer focuses to zinc-600 rather than a coloured ring.
     A green ring on every field would make the whole form shout. */
  outline: none;
  border-color: var(--line-strong);
}
/* Keyboard users still get a visible ring — matching the desktop's quiet focus
   must not mean removing focus. */
button:focus-visible, input:focus-visible, textarea:focus-visible, a:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

button {
  font: inherit;
  cursor: pointer;
  border-radius: var(--radius);
  border: 1px solid transparent;
  /* 46px: a thumb target, not a mouse target. */
  min-height: 46px;
  padding: 11px 16px;
}
.primary { width: 100%; background: var(--brand); color: var(--brand-on); margin-top: 22px; font-weight: 600; }
.secondary { width: 100%; background: var(--panel-2); color: var(--text); border-color: var(--line-strong); }
.primary:disabled, .send:disabled { opacity: 0.55; cursor: default; }
.link { background: none; border: none; color: var(--muted); text-decoration: underline; padding: 10px 4px; min-height: 44px; }
.link:hover { color: var(--text); }

.form-error { color: var(--error); font-size: 0.9rem; margin: 14px 0 0; }

/* ── chat ────────────────────────────────────────────────────────────────── */

.bar {
  padding: calc(10px + var(--safe-top)) 0 0;
  background: var(--bg);
}
.who {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
  padding: 0 16px 8px;
}
.who strong { font-size: 0.95rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.status { font-size: 0.78rem; color: var(--warn-dim); }

/* Lucide icons, inline. Stroke-drawn at 24x24 with round caps, which is what
   makes them look like the desktop's rather than like clip art. */
.icon {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex: none;
}

/* THE RIBBON, not a dropdown. Four actions, always visible, one tap each. A
   menu that hides four items behind a button spends a tap revealing what it
   could have shown — and on a phone the top of the screen is the one place a
   thumb does not naturally reach anyway, so hiding things up there twice over
   is the wrong trade. */
.ribbon {
  display: flex;
  gap: 2px;
  padding: 2px 6px 6px;
  border-bottom: 1px solid var(--line);
  background: var(--bg);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.ribbon::-webkit-scrollbar { display: none; }
.ribbon-item {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: none;
  background: none;
  border: none;
  border-radius: 6px;
  padding: 8px 10px;
  min-height: 40px;
  color: var(--muted);
  font-size: 0.82rem;
  white-space: nowrap;
}
.ribbon-item:hover { color: var(--text); background: var(--panel); }
.ribbon-item:active { background: var(--panel-2); }

.label-short { display: none; }

/* NARROW PHONES. Four labelled items are 408px of content, so on anything under
   about 420px the last one — Install — sits off the right-hand edge, which is
   the discoverability problem the ribbon exists to solve.
   The labels are what make the icons unambiguous, so they are the last thing to
   go: the spacing tightens first, then the longest label shortens. The ribbon
   still scrolls below that, for the few phones narrow enough to need it. */
@media (max-width: 420px) {
  .ribbon { gap: 0; padding-left: 4px; padding-right: 4px; }
  .ribbon-item { padding: 8px 7px; gap: 5px; font-size: 0.8rem; }
  .label-long { display: none; }
  .label-short { display: inline; }
}


.banner {
  background: var(--warn-bg);
  border-bottom: 1px solid var(--warn-line);
  color: var(--warn-text);
  padding: 12px 16px;
}
.banner p { margin: 0 0 10px; font-size: 0.9rem; }
.pay-row { display: flex; gap: 8px; }
.pay-row.stacked { flex-direction: column; margin-top: 22px; }
.pay {
  flex: 1;
  background: var(--panel-2);
  color: var(--text);
  border-color: var(--line);
  font-size: 0.9rem;
}

.thread {
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.empty { margin: auto; text-align: center; color: var(--muted); }
.empty p { margin: 0 0 6px; }

.msg { max-width: 92%; border-radius: var(--radius-bubble); padding: 10px 16px; }
/* A TINT, NOT A SLAB. The desktop draws the host's own words as
   bg-phenom-500/15 with a /25 edge — the brand present but quiet, because the
   words are the host's, not the product's. A solid green block would make every
   question shout louder than its answer. */
.msg.user {
  align-self: flex-end;
  background: var(--brand-tint);
  border: 1px solid var(--brand-edge);
  color: var(--brand-50);
  border-bottom-right-radius: var(--radius-tail);
  /* Shown exactly as typed, including line breaks — never parsed. */
  white-space: pre-wrap;
}
.msg.user p { margin: 0; }
.msg.assistant {
  align-self: flex-start;
  background: var(--panel);
  border: 1px solid var(--line);
  color: var(--text-2);
  padding: 12px 16px;
  border-bottom-left-radius: var(--radius-tail);
  line-height: 1.6;
}
.msg.pending { color: var(--muted); font-style: italic; }

/* The rendered answer. `pre-wrap` on paragraphs keeps the leading spaces the
   parser deliberately left literal, so an unsupported nested list still reads
   as a sub-step. */
.answer p { margin: 0 0 10px; white-space: pre-wrap; }
.answer p:last-child { margin-bottom: 0; }
.answer ol, .answer ul { margin: 0 0 10px; padding-left: 22px; }
.answer li { margin-bottom: 4px; }
.answer li::marker { color: var(--dim); }
.answer strong { font-weight: 650; }
.answer code {
  background: var(--panel-2);
  color: var(--text);
  border-radius: 5px;
  padding: 1px 5px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.87em;
  /* An identifier like current_venue_id must not be broken across lines in a
     way that makes it look like two words. */
  word-break: break-word;
}
/* Sources, as the desktop draws them: a quiet "From:" label and a row of pills.
   A video gets the brand colour because it is worth tapping; a document is named
   in grey. Naming it at all is the point — it tells the host the answer came
   from the manual rather than from thin air, which is the basis for following an
   instruction in front of a room. */
.sources {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
  padding-left: 2px;
}
.sources-label { font-size: 0.75rem; color: var(--dim); }
.source {
  font-size: 0.75rem;
  border-radius: 999px;
  padding: 4px 10px;
  border: 1px solid var(--line);
  color: var(--dim);
  text-decoration: none;
}
.source.video {
  color: var(--brand-300);
  border-color: var(--brand-edge);
}

/* An answer the knowledge base did not cover. The prose already hedges, and a
   hedge is something the reader has to interpret; this says it outright and
   says the question was recorded, which is what turns a dead end into the thing
   that gets the missing page written. Same words as the desktop. */
.unanswered-note {
  display: flex;
  gap: 8px;
  margin-top: 10px;
  padding-left: 2px;
  font-size: 0.78rem;
  color: var(--warn-dim);
}

.composer {
  display: flex;
  gap: 8px;
  align-items: flex-end;
  padding: 10px 12px calc(10px + var(--safe-bottom));
  border-top: 1px solid var(--line);
  background: var(--bg);
}
.composer textarea { resize: none; max-height: 160px; }
.send {
  background: var(--brand);
  color: var(--brand-on);
  display: grid;
  place-items: center;
  width: 46px;
  padding: 0;
  flex: none;
}
.send .icon { width: 20px; height: 20px; stroke-width: 2.2; }
/* The desktop spins Loader2 while a question is in flight; so does this, and it
   replaces the send icon rather than sitting beside it, because the button is
   now exactly one icon wide. */
@keyframes spin { to { transform: rotate(360deg); } }
.send .spinner { animation: spin 900ms linear infinite; }
@media (prefers-reduced-motion: reduce) { .send .spinner { animation: none; } }
.composer-error { margin: 0; padding: 0 16px 8px; }

.blocked-message { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 14px; }

/* The install instructions, for a browser that will not offer a real prompt.
   A sheet rather than a screen: it is an aside, and the host should come back
   to exactly what they were doing. */
.sheet {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(0, 0, 0, 0.6);
}
.sheet-panel {
  width: 100%;
  max-width: 520px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-bubble) var(--radius-bubble) 0 0;
  padding: 22px 20px calc(22px + var(--safe-bottom));
}
.sheet-panel h2 { margin: 0; font-size: 1.1rem; }
.sheet-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.icon-button {
  background: none; border: none; color: var(--muted);
  min-height: 44px; min-width: 44px; display: grid; place-items: center;
  margin: -10px -10px -10px 0;
}
.icon-button:hover { color: var(--text); }

/* Past conversations. Each row is the question that started it, which is how
   somebody recognises the one they want — a date alone tells them nothing. */
.thread-list { list-style: none; margin: 0 0 10px; padding: 0; max-height: 46vh; overflow-y: auto; }
.thread-row { display: flex; align-items: stretch; gap: 4px; }
.thread-open {
  flex: 1;
  min-width: 0;
  text-align: left;
  background: none;
  border: none;
  border-radius: 6px;
  padding: 10px;
  color: var(--text);
  font-size: 0.9rem;
}
.thread-open:hover { background: var(--panel-2); }
.thread-open .when { display: block; margin-top: 2px; font-size: 0.72rem; color: var(--dim); }
.thread-open .what { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.thread-delete {
  background: none; border: none; color: var(--dim);
  min-width: 44px; display: grid; place-items: center; border-radius: 6px;
}
.thread-delete:hover { color: var(--error); background: var(--panel-2); }
.sheet-steps { margin: 0 0 20px; padding-left: 20px; color: var(--muted); font-size: 0.92rem; }
.sheet-steps li { margin-bottom: 9px; }
.sheet-steps strong { color: var(--text); font-weight: 600; }
.sheet-panel .secondary { margin-top: 0; }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Some hosts will have their phone set to light. The app stays dark — it
   matches the desktop and it is used in dark rooms — but the form controls have
   to be told, or the browser renders them light on a dark panel. */
@media (prefers-color-scheme: light) {
  input, textarea { color-scheme: dark; }
}

@media (prefers-reduced-motion: no-preference) {
  .msg { animation: rise 120ms ease-out; }
  @keyframes rise { from { opacity: 0; transform: translateY(3px); } }
}
