/* ============================================================
   Ask Failing Daily — app styles
   Brand tokens come from /assets/failingdaily-tokens.css.
   Black ground, white type, one gold accent leading per view.
   ============================================================ */

/* ---------- scale ---------- */
:root {
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-6: 2rem;
  --s-7: 3rem;

  --col: 44rem;              /* reading column */
  --tap: 44px;               /* minimum touch target */

  --pad-x: max(var(--s-4), env(safe-area-inset-left));
  --pad-r: max(var(--s-4), env(safe-area-inset-right));

  --ease: cubic-bezier(0.2, 0, 0.2, 1);
}

*, *::before, *::after { box-sizing: border-box; }

html { background: var(--fd-black); }

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  height: 100dvh;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  background: var(--fd-black);
  color: var(--fd-white);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.6;
  overflow: hidden;
  -webkit-text-size-adjust: 100%;
  text-rendering: optimizeLegibility;
}

/* ---------- utility ---------- */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip: rect(0 0 0 0); clip-path: inset(50%);
  overflow: hidden; white-space: nowrap;
}

.skip-link {
  position: absolute; left: var(--s-2); top: -100%;
  z-index: 50;
  background: var(--fd-gold); color: var(--fd-black);
  font-weight: 700; padding: var(--s-2) var(--s-4);
  border-radius: var(--radius-md);
}
.skip-link:focus { top: calc(env(safe-area-inset-top) + var(--s-2)); text-decoration: none; }

:focus-visible {
  outline: 2px solid var(--fd-gold);
  outline-offset: 2px;
  border-radius: 2px;
}

/* ============================================================
   MASTHEAD
   ============================================================ */
.masthead {
  min-width: 0;
  padding-top: env(safe-area-inset-top);
  border-bottom: 1px solid var(--color-divider);
  background: var(--fd-black);
}
.masthead__inner {
  width: 100%;
  max-width: var(--col);
  margin-inline: auto;
  padding: var(--s-4) var(--pad-r) var(--s-3) var(--pad-x);
}

.masthead__lockup {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s-4);
}

/* The signature treatment: white serif title → thin white rule → gold tagline.
   The tagline sits under the full rule width so it never breaks mid-phrase. */
.masthead__title {
  flex: 0 1 auto;
  width: fit-content;   /* the rule hugs the wordmark, as in the logo lockup */
  min-width: 0;
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.6rem, 7.5vw, 2.4rem);
  line-height: 1.05;
  letter-spacing: var(--tracking-display);
  color: var(--fd-white);
  border-bottom: 2px solid var(--fd-white);
  padding-bottom: 0.14em;
}
.masthead__tagline {
  margin: 0.42em 0 0;
  font-size: clamp(0.74rem, 3.1vw, 0.95rem);
  font-weight: 400;
  letter-spacing: var(--tracking-tagline);
  color: var(--fd-gold);
  line-height: 1.3;
  text-wrap: balance;
}
/* The stippled portrait mark is deliberately NOT rendered in the header.
   The source asset is 150px and reads as visual noise at header scale — the
   serif masthead + rule + gold tagline carry the brand on their own, which is
   the treatment the brand guide calls the "signature rhythm". The mark still
   lives in /assets and is the source for the app icons. */

.disclosure {
  margin: var(--s-3) 0 0;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--fd-ash);
  border-top: 1px solid var(--color-divider);
  padding-top: var(--s-2);
}

/* Once a conversation is running the masthead condenses — the disclosure stays
   in full, it just stops eating half of a phone screen. */
body:not(.is-empty) .masthead__inner { padding-top: var(--s-3); padding-bottom: var(--s-2); }
body:not(.is-empty) .masthead__title { font-size: clamp(1.25rem, 5.2vw, 1.6rem); }
body:not(.is-empty) .masthead__tagline { font-size: 0.75rem; }
body:not(.is-empty) .disclosure { font-size: 0.75rem; margin-top: var(--s-2); }
.disclosure strong { color: var(--fd-fog); font-weight: 600; }

/* ============================================================
   MAIN / SCROLL AREA
   ============================================================ */
.main {
  min-width: 0;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-y: contain;
  scrollbar-gutter: stable;
}
.main__inner {
  width: 100%;
  max-width: var(--col);
  min-height: 100%;
  margin-inline: auto;
  padding: var(--s-5) var(--pad-r) var(--s-5) var(--pad-x);
  display: flex;
  flex-direction: column;
}

/* ---------- empty state ---------- */
.intro__h {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.35rem, 5.5vw, 1.75rem);
  line-height: 1.2;
}
.intro__sub {
  margin: var(--s-3) 0 0;
  color: var(--fd-fog);
  font-size: 0.9375rem;
  max-width: 34rem;
}
.intro__chips-h {
  margin: var(--s-6) 0 var(--s-3);
  font-family: var(--font-body);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  font-size: 0.7rem;
  color: var(--fd-ash);
}

.chips {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}
.chip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  width: 100%;
  min-height: var(--tap);
  text-align: left;
  padding: var(--s-3) var(--s-4);
  background: transparent;
  color: var(--fd-white);
  font-family: var(--font-body);
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.35;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease);
}
.chip::after {
  content: "\2192";
  flex: 0 0 auto;
  color: var(--fd-ash);
}
.chip:hover { border-color: var(--fd-gold); background: var(--fd-near-black); }
.chip:hover::after { color: var(--fd-gold); }

/* ---------- theme picker (landing screen only) ----------
   It lives inside .intro, so the `body:not(.is-empty) .intro { display: none }`
   rule below takes it off the conversation view for free. No second rule to
   keep in sync, and nothing for positionComposer() to trip over — that function
   only ever moves the composer <form>, and it inserts it BEFORE #starters-h,
   which puts the picker after it. Reading and tab order stay:
   heading -> ask box -> "Or start with one of these" -> picker -> chips.

   The markup ships with [hidden] on it. app.js removes that only once
   starters.json has produced themes with real starters behind them, so a failed
   fetch, an offline first load, or a cached v1 file leaves no dead control on
   screen. */
.themer { margin: 0 0 var(--s-3); }
.themer[hidden] { display: none; }

.themer__row { display: flex; align-items: stretch; gap: var(--s-2); }

/* A native <select>: on a phone that means the iOS wheel or the Android sheet,
   which is one tap, OS-rendered, and cannot fight the soft keyboard or trap a
   scroll. appearance:none restyles only the closed box — the picker itself is
   still the platform's. */
.themer__select {
  flex: 1 1 auto;
  min-width: 0;
  min-height: var(--tap);
  appearance: none;
  -webkit-appearance: none;
  background-color: var(--fd-near-black);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath fill='%23CA9800' d='M0 0h10L5 6z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--s-4) center;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  color: var(--fd-white);
  font-family: var(--font-body);
  font-size: 1rem;            /* 16px — stops iOS zoom-on-focus, same as the composer */
  font-weight: 500;
  line-height: 1.35;
  padding: var(--s-2) calc(var(--s-4) + var(--s-5)) var(--s-2) var(--s-3);
  cursor: pointer;
  transition: border-color 0.15s var(--ease);
}
.themer__select:hover { border-color: var(--fd-gold); }
/* Windows and Android render the open list from these two properties and
   ignore almost everything else, so set them explicitly rather than trusting
   color-scheme to carry the dark list everywhere. */
.themer__select option { background: var(--fd-black); color: var(--fd-white); }

/* Redraws the current view. A native select fires no event when you re-pick the
   theme you are already on, so this is the affordance that is always honest —
   and the one a keyboard user can reach without opening a menu at all. */
.themer__shuffle {
  flex: 0 0 auto;
  min-height: var(--tap);
  background: transparent;
  color: var(--fd-white);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.875rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--s-2) var(--s-4);
  cursor: pointer;
  transition: border-color 0.15s var(--ease), color 0.15s var(--ease);
}
.themer__shuffle:hover { border-color: var(--fd-gold); color: var(--fd-gold); }

/* Only on screen while a theme is filtering the chips. "Any theme" is also the
   first option in the select, but a one-tap way out beats making somebody open
   a ten-item menu to undo a choice. */
.themer__reset {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding: 0;
  background: transparent;
  border: 0;
  color: var(--fd-ash);      /* #8A8A8A — 6.08:1 on black */
  font-family: var(--font-body);
  font-size: 0.8125rem;
  text-align: left;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.themer__reset:hover { color: var(--fd-gold); }
.themer__reset[hidden] { display: none; }

/* A theme with fewer starters than there are chips leaves a slot empty; app.js
   hides that <li> rather than stranding the previous theme's question in it.
   Specificity here has to beat `.chips > li { display: flex }` in the 40rem
   block further down, which is why the attribute is on the same selector. */
.chips > li[hidden] { display: none; }

/* Four short phrases swapping in place can read as "nothing happened" —
   especially on a re-pick, where only one of the five changes. A single beat of
   fade says the set is new. The global prefers-reduced-motion block below
   flattens this to nothing, which is why app.js has no branch for it. */
@keyframes chips-in { from { opacity: 0.3; } to { opacity: 1; } }
.chips.is-fresh { animation: chips-in 180ms var(--ease) both; }

body:not(.is-empty) .intro { display: none; }

/* ============================================================
   THREAD
   ============================================================ */
.thread {
  display: flex;
  flex-direction: column;
  gap: var(--s-6);
}
body.is-empty .thread { display: none; }

.turn { margin: 0; }

.turn__label {
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--fd-ash);
  margin-bottom: var(--s-2);
}

/* ---------- user turn ---------- */
.turn--user { display: flex; flex-direction: column; align-items: flex-end; }
.turn--user .turn__label { align-self: flex-end; }
.turn--user .turn__text {
  margin: 0;
  max-width: 90%;
  background: var(--fd-charcoal);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg) var(--radius-lg) var(--radius-sm) var(--radius-lg);
  padding: var(--s-3) var(--s-4);
  color: var(--fd-white);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* ---------- coach turn ---------- */
.answer { overflow-wrap: anywhere; }
.answer__body > *:first-child { margin-top: 0; }
.answer p { margin: 0 0 var(--s-4); color: var(--fd-fog); }
.answer strong { color: var(--fd-white); font-weight: 600; }
.answer em { color: var(--fd-fog); }
.answer code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.9em;
  background: var(--fd-charcoal);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 0.05em 0.35em;
}
.answer ul, .answer ol { margin: 0 0 var(--s-4); padding-left: 1.15rem; color: var(--fd-fog); }
.answer li { margin-bottom: var(--s-2); }
.answer li::marker { color: var(--fd-ash); }
.answer a { color: var(--fd-gold); text-decoration: underline; text-underline-offset: 2px; }
.answer a:hover { color: var(--fd-gold-bright); }

/* Section headings from the system prompt (The real issue, Options, …) */
.answer .ans-h {
  margin: var(--s-5) 0 var(--s-2);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.0625rem;
  line-height: 1.25;
  color: var(--fd-white);
}
.answer .ans-h:first-child { margin-top: 0; }

.answer__tail {
  margin: 0;
  color: var(--fd-fog);
  white-space: pre-wrap;
}
.answer__tail:empty { display: none; }

/* ---------- coach turn that is ONLY questions ---------- */
/* This is the coach loop, not a broken answer — make it read that way. */
.turn--ask .answer {
  border-left: 3px solid var(--fd-gold);
  padding-left: var(--s-4);
}
.turn--ask .answer p,
.turn--ask .answer__tail {
  font-size: 1.125rem;
  line-height: 1.5;
  color: var(--fd-white);
}
.turn--ask .answer p:last-child { margin-bottom: 0; }
.turn--ask .turn__label { color: var(--fd-gold); }

/* ---------- typing indicator ---------- */
.thinking {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  color: var(--fd-ash);
  font-size: 0.875rem;
  padding: var(--s-1) 0;
}
.thinking__dots { display: inline-flex; gap: 4px; }
.thinking__dots i {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--fd-ash);
  animation: dot 1.1s var(--ease) infinite;
}
.thinking__dots i:nth-child(2) { animation-delay: 0.15s; }
.thinking__dots i:nth-child(3) { animation-delay: 0.3s; }
@keyframes dot {
  0%, 60%, 100% { opacity: 0.25; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-3px); }
}

/* ============================================================
   SOURCE CARDS — the channel-lift mechanic. Give it weight.
   ============================================================ */
.sources { margin-top: var(--s-5); }
.sources__h {
  margin: 0 0 var(--s-3);
  font-family: var(--font-body);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  font-size: 0.7rem;
  color: var(--fd-ash);
  display: flex;
  align-items: center;
  gap: var(--s-3);
}
.sources__h::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--color-divider);
}
.sources__list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-3); }

.source-card {
  display: block;
  position: relative;
  background: var(--fd-charcoal);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--fd-gold);
  border-radius: var(--radius-md);
  padding: var(--s-4);
  color: var(--fd-white);
  text-decoration: none;
  transition: background-color 0.15s var(--ease), border-color 0.15s var(--ease);
}
.source-card:hover {
  background: #212121;
  text-decoration: none;
  border-color: var(--fd-gold);
  border-left-color: var(--fd-gold-bright);
}
.source-card__kind {
  display: inline-block;
  font-size: 0.66rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--fd-ash);
  margin-bottom: var(--s-2);
}
.source-card__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.0625rem;
  line-height: 1.25;
  color: var(--fd-white);
}
.source-card__speaker {
  margin: var(--s-1) 0 0;
  font-size: 0.8125rem;
  color: var(--fd-fog);
}
.source-card__snippet {
  margin: var(--s-3) 0 0;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--fd-fog);
  border-left: 1px solid var(--fd-graphite);
  padding-left: var(--s-3);
}
.source-card__cta {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  margin-top: var(--s-3);
  font-size: 1rem;
  font-weight: 700;
  color: var(--fd-gold);
  letter-spacing: 0.01em;
}
.source-card:hover .source-card__cta { color: var(--fd-gold-bright); }

/* ============================================================
   EMAIL GATE — sits BELOW the answer and its sources, never over them
   ============================================================ */
.gate {
  margin-top: var(--s-6);
  background: var(--fd-near-black);
  border: 1px solid var(--color-border);
  border-top: 2px solid var(--fd-gold);
  border-radius: var(--radius-md);
  padding: var(--s-5) var(--s-4);
}
.gate__h {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.25rem;
  line-height: 1.2;
}
.gate__sub {
  margin: var(--s-2) 0 var(--s-4);
  color: var(--fd-fog);
  font-size: 0.9375rem;
}
.gate__field { display: flex; flex-direction: column; gap: var(--s-2); }
.gate__label {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--fd-fog);
}
.gate__input {
  width: 100%;
  min-height: var(--tap);
  background: var(--fd-black);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  color: var(--fd-white);
  font-family: var(--font-body);
  font-size: 1rem;
  padding: var(--s-3);
}
.gate__input::placeholder { color: var(--fd-ash); }
.gate__input:focus-visible { border-color: var(--fd-gold); }

.gate__consent {
  display: flex;
  gap: var(--s-3);
  align-items: flex-start;
  margin: var(--s-4) 0;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--fd-ash);
  cursor: pointer;
}
.gate__consent input {
  flex: 0 0 auto;
  width: 20px; height: 20px;
  margin: 2px 0 0;
  accent-color: var(--fd-gold);
}
.gate__consent a { color: var(--fd-fog); text-decoration: underline; }

.gate__cta {
  width: 100%;
  min-height: var(--tap);
  background: var(--fd-gold);
  color: var(--fd-black);
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 1rem;
  letter-spacing: 0.02em;
  border: none;
  border-radius: var(--radius-md);
  padding: var(--s-3) var(--s-5);
  cursor: pointer;
  transition: background-color 0.15s var(--ease);
}
.gate__cta:hover { background: var(--fd-gold-bright); }
.gate__cta[disabled] { opacity: 0.6; cursor: progress; }

.gate__error {
  margin: var(--s-3) 0 0;
  font-size: 0.875rem;
  color: #FF9A8B;
}
.gate__error:empty { display: none; }
.gate__fine {
  margin: var(--s-3) 0 0;
  font-size: 0.75rem;
  color: var(--fd-ash);
}

.gate--done {
  border-top-color: var(--fd-white);
}

/* ============================================================
   ERROR STATE
   ============================================================ */
.errcard {
  background: var(--fd-near-black);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--fd-fog);
  border-radius: var(--radius-md);
  padding: var(--s-4);
}
.errcard__h {
  margin: 0 0 var(--s-2);
  font-family: var(--font-display);
  font-size: 1.0625rem;
  font-weight: 700;
}
.errcard__p { margin: 0 0 var(--s-4); color: var(--fd-fog); font-size: 0.9375rem; }
.errcard__p:last-child { margin-bottom: 0; }
.errcard__retry {
  min-height: var(--tap);
  background: transparent;
  color: var(--fd-white);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.9375rem;
  border: 1.5px solid rgba(255,255,255,0.4);
  border-radius: var(--radius-md);
  padding: var(--s-2) var(--s-5);
  cursor: pointer;
}
.errcard__retry:hover { border-color: var(--fd-gold); color: var(--fd-gold); }

/* ============================================================
   FOOTER
   ============================================================ */
.siteftr {
  margin-top: auto;
  padding-top: var(--s-6);
  color: var(--fd-ash);
  font-size: 0.75rem;
}
.siteftr__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  flex-wrap: wrap;
  border-top: 1px solid var(--color-divider);
  padding-top: var(--s-3);
}
.siteftr__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  color: var(--fd-fog);
  text-decoration: underline;
  text-underline-offset: 2px;
  font-size: 0.8125rem;
}
.siteftr__link:hover { color: var(--fd-gold); }
.install-btn {
  min-height: var(--tap);
  background: transparent;
  color: var(--fd-white);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.8125rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--s-2) var(--s-4);
  cursor: pointer;
}
.install-btn:hover { border-color: var(--fd-gold); color: var(--fd-gold); }
.siteftr__hint { margin: var(--s-3) 0 0; color: var(--fd-ash); font-size: 0.8125rem; }
.siteftr__hint strong { color: var(--fd-fog); }
.siteftr__stamp {
  margin: var(--s-3) 0 0;
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  color: var(--fd-ash);   /* #8A8A8A — 6.08:1 on black; #6E6E6E measured 4.12:1 */
}

/* ============================================================
   COMPOSER — pinned above the keyboard and the home indicator
   ============================================================ */
.composer {
  min-width: 0;
  background: var(--fd-black);
  border-top: 1px solid var(--color-divider);
  padding-bottom: env(safe-area-inset-bottom);
}
.composer__inner {
  width: 100%;
  max-width: var(--col);
  margin-inline: auto;
  padding: var(--s-3) var(--pad-r) var(--s-2) var(--pad-x);
}
.composer__field {
  display: flex;
  align-items: flex-end;
  gap: var(--s-2);
  background: var(--fd-near-black);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--s-2);
  transition: border-color 0.15s var(--ease);
}
.composer__field:focus-within { border-color: rgba(255,255,255,0.38); }

.composer__input {
  /* flex-basis 0 + min-width 0: a textarea's intrinsic column width must not
     become the page's min-content width (it pushed 320px viewports to 347px). */
  flex: 1 1 0;
  min-width: 0;
  min-height: 2.5rem;
  max-height: 40vh;
  resize: none;
  background: transparent;
  border: 0;
  outline-offset: 0;
  color: var(--fd-white);
  font-family: var(--font-body);
  font-size: 1rem;          /* 16px — stops iOS zoom-on-focus */
  line-height: 1.5;
  padding: var(--s-2) var(--s-2);
}
.composer__input::placeholder { color: var(--fd-ash); }
.composer__input:focus { outline: none; }
.composer__field:focus-within { outline: 2px solid transparent; }

body.is-empty .composer__input { min-height: 6.5rem; }

.composer__send {
  flex: 0 0 auto;
  min-height: var(--tap);
  min-width: 4.5rem;
  background: var(--fd-white);
  color: var(--fd-black);
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.9375rem;
  letter-spacing: 0.02em;
  border: none;
  border-radius: var(--radius-md);
  padding: var(--s-2) var(--s-4);
  cursor: pointer;
  transition: background-color 0.15s var(--ease), opacity 0.15s var(--ease);
}
.composer__send:hover { background: var(--fd-fog); }
.composer__send[disabled] { opacity: 0.45; cursor: not-allowed; }
.composer__send:focus-visible { outline-offset: 3px; }

.composer__meta {
  display: flex;
  justify-content: space-between;
  gap: var(--s-3);
  margin-top: var(--s-2);
}
.composer__help, .composer__count {
  margin: 0;
  font-size: 0.6875rem;
  color: var(--fd-ash);   /* AA at this size needs 4.5:1 */
}
.composer__count.is-near { color: var(--fd-fog); }

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (min-width: 40rem) {
  .masthead__inner { padding-top: var(--s-5); padding-bottom: var(--s-4); }

  .chips { flex-direction: row; flex-wrap: wrap; }
  .chips > li { flex: 1 1 calc(50% - var(--s-2)); min-width: 0; display: flex; }
  .main__inner { padding-top: var(--s-6); }
  .gate { padding: var(--s-6); }
  .gate__cta { width: auto; min-width: 14rem; }
  .composer__inner { padding-top: var(--s-4); padding-bottom: var(--s-3); }
}

@media (min-width: 64rem) {
  :root { --col: 46rem; }
  .sources__list { gap: var(--s-4); }
}

/* Short viewports (landscape phones): trim the masthead. The disclosure is
   persistent chrome per the spec — it shrinks, it never disappears. */
@media (max-height: 34rem) {
  .masthead__inner { padding-top: var(--s-2); padding-bottom: var(--s-2); }
  .masthead__title { font-size: 1.35rem; }
  .disclosure { font-size: 0.75rem; margin-top: var(--s-2); }
  body.is-empty .composer__input { min-height: 3rem; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .thinking__dots i { opacity: 0.7; }
}

/* Forced colors / high contrast */
@media (forced-colors: active) {
  .chip, .source-card, .gate, .errcard,
  .themer__select, .themer__shuffle { border: 1px solid CanvasText; }
}

/* ============================================================
   NARROW WINDOW / DESKTOP POPUP
   The installed PWA is meant to live in a small floating window beside
   whatever you're actually working on. Chrome remembers the size you drag it
   to; these rules make ~380-560px look deliberate instead of squeezed.
   ============================================================ */
@media (max-width: 560px) and (min-height: 500px) {
  .masthead__inner,
  .main__inner,
  .composer__inner { max-width: none; }

  /* Reclaim vertical space: in a small window the disclosure and tagline
     were eating a third of the height before a single answer appeared. */
  body.is-empty .intro__chips-h { margin-top: var(--s-4); }
  .masthead__inner { padding-top: var(--s-3); padding-bottom: var(--s-2); }
  .masthead__title { font-size: clamp(1.2rem, 6vw, 1.5rem); }
  .disclosure { font-size: 0.7rem; line-height: 1.35; }
  .intro__sub { font-size: 0.875rem; }
  .chips { gap: var(--s-2); }
  .chip { padding: var(--s-2) var(--s-3); font-size: 0.875rem; min-height: 40px; }

  /* Source cards are the point of the app; keep them readable when narrow. */
  .answer__body { font-size: 0.9375rem; }
}

/* Window Controls Overlay: when Chrome hands us the titlebar area, don't let
   content slide under the OS window buttons. */
@media (display-mode: window-controls-overlay) {
  .masthead {
    padding-top: env(titlebar-area-height, env(safe-area-inset-top));
    -webkit-app-region: drag;
  }
  .masthead a, .masthead button { -webkit-app-region: no-drag; }
}

/* ============================================================
   LANDING: the ask box sits high, above the starter chips.
   Pinning it to the bottom on an empty screen buried the one thing the
   visitor is there to do under a heading, a paragraph and four chips —
   worst on a phone, where the chips pushed it under the fold entirely.
   Once a conversation exists it returns to the bottom, which is what a
   chat thread wants. Pure CSS ordering: the markup never moves, so the
   tab order and the screen-reader flow stay intact.
   ============================================================ */
/* The composer is MOVED INTO .intro by app.js on the landing screen (see
   positionComposer) so the order reads: heading -> ask box -> "Or start with
   one of these" -> chips. These rules make it look like an invitation there
   rather than a docked footer. */
body.is-empty .composer {
  position: static;
  border-top: 0;
  background: transparent;
  margin: var(--s-4) 0 var(--s-6);
}
body.is-empty .composer__inner {
  max-width: none;
  padding-left: 0;
  padding-right: 0;
  padding-top: 0;
}
body.is-empty .composer__input { min-height: 4.5rem; font-size: 1.0625rem; }
body.is-empty .intro__h { font-size: clamp(1.25rem, 5vw, 1.6rem); margin-bottom: var(--s-2); }
body.is-empty .intro__sub { margin-bottom: 0; }
body.is-empty .intro__chips-h { margin-top: var(--s-5); }

/* ---- mobile ---- */
@media (max-width: 520px) {
  body.is-empty .composer__input { min-height: 3.5rem; font-size: 1rem; }
  body.is-empty .composer { margin: var(--s-3) 0 var(--s-5); }
  .chip { min-height: 44px; }               /* full touch target */
  .composer__send { min-height: 44px; min-width: 4.25rem; }
  .source__link { min-height: 44px; display: inline-flex; align-items: center; }
  .answer__body { font-size: 1rem; line-height: 1.62; }
  /* iOS: keep the composer clear of the home indicator */
  .composer__inner { padding-bottom: max(var(--s-3), env(safe-area-inset-bottom)); }
}

/* ---- build stamp copy button ------------------------------------------
   Bill reads this number off the screen constantly to check which build is
   actually live after a deploy. One tap beats selecting 30 characters of
   monospace on a phone. */
.siteftr__stamp { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.siteftr__copy {
  font: inherit;
  font-size: 0.6875rem;
  line-height: 1;
  padding: 0.25rem 0.45rem;
  color: var(--fd-ash);
  background: transparent;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: color 0.15s var(--ease), border-color 0.15s var(--ease);
}
.siteftr__copy:hover { color: var(--fd-gold); border-color: var(--fd-gold); }
.siteftr__copy.is-done { color: var(--fd-gold); border-color: var(--fd-gold); }
@media (max-width: 520px) { .siteftr__copy { padding: 0.35rem 0.55rem; } }

/* =========================================================
   Answer actions — share and rate
   =========================================================

   Sits under the answer, above the source cards' visual weight, and stays
   quiet: the clips are the product and these must not compete with them.
   Rendered only when the server returned a questionId.
   ========================================================= */

.actions {
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
  margin-top: .9rem;
}

.actions__btn {
  padding: .38rem .8rem;
  background: transparent;
  color: var(--fd-fog);
  border: 1px solid rgba(255, 255, 255, .22);
  border-radius: 999px;
  font: inherit;
  font-size: .82rem;
  line-height: 1.2;
  cursor: pointer;
}

.actions__btn:hover:not(:disabled) {
  color: var(--fd-black);
  background: var(--fd-gold);
  border-color: var(--fd-gold);
}

.actions__btn:focus-visible { outline: 2px solid var(--fd-gold); outline-offset: 2px; }
.actions__btn:disabled { opacity: .5; cursor: default; }

.actions__status {
  color: var(--fd-ash);
  font-size: .78rem;
}

.rating { display: inline-flex; gap: .1rem; }

.rating__star {
  padding: .15rem .18rem;
  background: none;
  border: 0;
  /* Dim by default. Gold is the site's one accent and a row of five gold stars
     shouting at the reader would outrank the source cards, which are the
     thing we actually want tapped. */
  color: rgba(255, 255, 255, .28);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}

.rating__star:hover,
.rating__star.is-on { color: var(--fd-gold); }
.rating__star:focus-visible { outline: 2px solid var(--fd-gold); outline-offset: 1px; }

/* Once rated the row is a record, not a control. */
.rating.is-rated .rating__star { cursor: default; }
.rating.is-rated .rating__star:hover { color: rgba(255, 255, 255, .28); }
.rating.is-rated .rating__star.is-on:hover { color: var(--fd-gold); }

@media (prefers-reduced-motion: no-preference) {
  .actions__btn { transition: background-color .12s ease, color .12s ease, border-color .12s ease; }
  .rating__star { transition: color .12s ease; }
}

/* ============================================================
   MASTHEAD PAINT ORDER                              2026-09-01
   The installed PWA was ghosting the masthead over the scrolled
   answer. .masthead and .main are static siblings, so .main —
   later in source — paints on top wherever they overlap, and the
   masthead has no clip of its own to stop its text spilling into
   the scroll area.

   Two changes: give the masthead a stacking context above the
   scroller and clip its own overflow, and stop making the WHOLE
   scrolling header a window-drag region. A drag region belongs on
   the fixed titlebar strip, not on a block that scrolls — the
   drag layer is what makes a stale paint stick.

   VERIFY IN THE INSTALLED PWA. A screenshot cannot tell a layout
   overflow from a compositor repaint artifact, and this fix
   targets both.
   ============================================================ */
.masthead {
  position: relative;
  z-index: 2;
  overflow: clip;
  overflow-clip-margin: 6px;   /* focus rings still escape the clip */
}
.main { position: relative; z-index: 0; }

@media (display-mode: window-controls-overlay) {
  /* Reserve real height for the titlebar instead of only padding it:
     env(titlebar-area-height) resolves after first layout in Chromium,
     so a grid track sized before it resolved came up short. */
  .masthead { min-height: calc(env(titlebar-area-height, 0px) + 2.75rem); }

  /* Narrow the drag region to the titlebar strip only. Overrides the
     earlier block, which put -webkit-app-region: drag on the whole
     scrolling masthead. */
  .masthead { -webkit-app-region: no-drag; }
  .masthead::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: env(titlebar-area-height, 0px);
    -webkit-app-region: drag;
    pointer-events: none;
  }
}

/* ============================================================
   ANSWER FURNITURE                                  2026-09-01
   The clip cue, the verdict, the share block and the community
   line. Everything sits below the answer except the cue, which is
   the one thing that has to be seen before anyone scrolls.
   ============================================================ */

/* The promise that clips exist, in the space the redundant
   "ASK FAILING DAILY" label used to hold. A jump link, NOT a tab:
   nothing is hidden, so every reader who scrolls still passes the
   cards. Hiding them behind a toggle would trade a guaranteed
   impression for a click we would have to earn — on the one
   mechanic that actually sends people to YouTube. */
.sourcecue {
  margin: 0 0 var(--s-3);
  font-size: 0.8125rem;
  line-height: 1.3;
}
.sourcecue a {
  color: var(--fd-ash);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.sourcecue a:hover,
.sourcecue a:focus-visible { color: var(--fd-gold); }
.sourcecue[hidden] { display: none; }

.answer__after { margin-top: var(--s-4); }

/* Share, promoted out of the quiet pill row into a block of its own,
   placed AFTER the source cards — the end of the reading flow, which
   is the only point at which anyone would share. Ghost weight by
   default: gold is the source cards' accent, and a gold button sitting
   under three gold-bordered cards splits the reader's attention four
   ways. It EARNS gold when someone says the answer helped. */
.sharecta {
  margin-top: var(--s-4);
  padding-top: var(--s-3);
  border-top: 1px solid var(--color-divider);
}
.sharecta__ask {
  margin: 0 0 var(--s-2);
  color: var(--fd-fog);
  font-size: 0.9375rem;
  line-height: 1.35;
}
.sharecta__btn {
  min-height: var(--tap);
  padding: var(--s-2) var(--s-5);
  background: transparent;
  color: var(--fd-white);
  /* 1.5px at .42 alpha measures 3.4:1 on black. The old pill used
     rgba(255,255,255,.22) — 1.8:1, failing WCAG 1.4.11 for a control
     boundary, which is the measurable half of "too small to notice". */
  border: 1.5px solid rgba(255, 255, 255, 0.42);
  border-radius: var(--radius-md);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 1rem;
  cursor: pointer;
}
.sharecta__btn:hover:not(:disabled),
.sharecta__btn:focus-visible {
  background: var(--fd-gold);
  color: var(--fd-black);
  border-color: var(--fd-gold);
}
.sharecta__btn:disabled { opacity: 0.55; cursor: default; }

.sharecta.is-earned .sharecta__btn {
  background: var(--fd-gold);
  color: var(--fd-black);
  border-color: var(--fd-gold);
  font-weight: 700;
}
.sharecta.is-earned .sharecta__btn:hover:not(:disabled) { background: var(--fd-gold-bright); }

/* Verdict: one decision at two 44px targets, replacing five 20px stars
   at rgba(255,255,255,.28) — 2.3:1, under the 3:1 WCAG 1.4.11 needs for
   a control boundary and under the 24px floor in 2.5.8. */
.verdict { display: inline-flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.verdict__q { color: var(--fd-ash); font-size: 0.8125rem; }
.verdict__btn {
  min-width: var(--tap);
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.42);
  border-radius: var(--radius-md);
  color: var(--fd-fog);
  font-size: 1.05rem;
  line-height: 1;
  cursor: pointer;
}
.verdict__btn:hover { border-color: var(--fd-gold); color: var(--fd-gold); }
.verdict__btn:focus-visible { outline: 2px solid var(--fd-gold); outline-offset: 2px; }
.verdict__btn.is-on {
  border-color: var(--fd-gold);
  color: var(--fd-gold);
  background: rgba(245, 183, 0, 0.12);
}
.verdict.is-done .verdict__btn { cursor: default; }
.verdict.is-done .verdict__btn:not(.is-on) { opacity: 0.4; }

/* The community ask, made only after a yes. Never a popup, never an
   interstitial — the one moment someone has told us it worked. */
.commu {
  margin: var(--s-3) 0 0;
  font-size: 0.875rem;
  line-height: 1.4;
  color: var(--fd-fog);
}
.commu a {
  color: var(--fd-gold);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.commu a:hover { color: var(--fd-gold-bright); }

.actions { margin-top: 0; }

/* ============================================================
   FOOTER — the four places to go next, on every surface
   ============================================================ */
.siteftr__links {
  display: flex;
  align-items: center;
  gap: var(--s-2) var(--s-4);
  flex-wrap: wrap;
  min-width: 0;
}
.siteftr__link--community {
  color: var(--fd-gold);
  font-weight: 700;
  text-decoration: none;
  border: 1px solid var(--fd-gold);
  border-radius: 999px;
  padding: 0 var(--s-3);
  min-height: 36px;
}
.siteftr__link--community:hover,
.siteftr__link--community:focus-visible {
  background: var(--fd-gold);
  color: var(--fd-black);
  text-decoration: none;
}

/* ============================================================
   VERTICAL SPACE                                    2026-09-01
   The app asked for a scroll before it had finished saying
   anything. Biggest win first.
   ============================================================ */
/* 1. Source cards lost the transcript snippet entirely — see
      renderSources() in app.js. The quotes were raw caption text
      ("multiple sc's ... doing feif for service for") and cost about
      60px per card to actively damage credibility. Rule kept so any
      cached markup still collapses. */
.source-card__snippet { display: none; }
.source-card { padding: var(--s-3) var(--s-4); }
.source-card__cta { margin-top: var(--s-2); font-size: 0.9375rem; }
.sources { margin-top: var(--s-4); }
.sources__list { gap: var(--s-2); }

/* 2. The coach turn lost its "ASK FAILING DAILY" label — the masthead
      two inches above already says it. */
.turn--coach > .turn__label { display: none; }

/* 3. The footer no longer needs a blank screen above it. */
.siteftr { padding-top: var(--s-4); }

/* 4. Once a conversation is running the masthead is chrome, not a
      title page. The disclosure stays in full — it is required
      behaviour, not decoration — it just stops eating the fold. */
body:not(.is-empty) .masthead__inner { padding-top: var(--s-2); padding-bottom: var(--s-2); }
body:not(.is-empty) .disclosure { margin-top: var(--s-2); padding-top: var(--s-2); line-height: 1.35; }


/* ============================================================
   FIXES FROM THE FIRST REAL PWA SESSION            2026-09-01b
   Everything here was measured in a real browser against the
   live site, not inferred from a screenshot.
   ============================================================ */

/* 1. overflow:clip is GONE.
   It was added to stop the masthead ghosting over the answer. In the
   installed PWA it cut the tagline and the "Not Bill" disclosure off
   instead — trading a cosmetic bug for missing required chrome, which
   is the worse of the two by a distance.
   Measured live at a 600px viewport, conversation state: the masthead
   box is 119px and its content is 118px. It clips nothing, WITH or
   WITHOUT the rule. The rule bought nothing and cost the disclosure.
   The paint-order fix that actually matters is the stacking context
   below — the masthead's own black background covers what scrolls
   under it. */
.masthead { overflow: visible; }

/* 2. The clip cue rendered perfectly and nobody could see it.
   Measured live after one answer: the cue's top sat 1257px ABOVE the
   viewport. It is the first thing in the turn and the turn is 3000px
   long, so it scrolls away before the answer has finished writing. A
   promise you scroll past instantly is not a promise.
   Sticky pins it to the top of the scroller for exactly as long as you
   are reading the answer it belongs to. */
.sourcecue {
  position: sticky;
  top: 0;
  z-index: 1;
  margin: 0 0 var(--s-3);
  padding: var(--s-2) 0;
  background: var(--fd-black);
  font-size: 0.8125rem;
}
.sourcecue a {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  min-height: 32px;
  padding: 0.2rem var(--s-3);
  border: 1px solid rgba(245, 183, 0, 0.45);
  border-radius: 999px;
  color: var(--fd-gold);
  text-decoration: none;
  font-weight: 600;
}
.sourcecue a:hover,
.sourcecue a:focus-visible {
  background: var(--fd-gold);
  border-color: var(--fd-gold);
  color: var(--fd-black);
  text-decoration: none;
}

/* 3. "One question back" was styled exactly like "Options" and "Next
   action" — three headings of equal weight, so nothing said which one
   was addressed to the reader. It is the mechanic that makes anyone
   type a second time, so it gets the gold rule the coach's own
   questions already use elsewhere in this file. */
.answer__body .ans-h.askback {
  margin-top: var(--s-5);
  padding: var(--s-2) 0 0 var(--s-4);
  border-left: 3px solid var(--fd-gold);
  color: var(--fd-gold);
}
.answer__body .ans-h.askback ~ p {
  margin-top: 0;
  padding: 0 0 var(--s-2) var(--s-4);
  border-left: 3px solid var(--fd-gold);
  color: var(--fd-white);
  font-size: 1.0625rem;
  line-height: 1.5;
}

/* 4. Start over. */
.masthead__lockup { align-items: center; }
.masthead__new {
  display: none;
  align-items: center;
  min-height: 36px;
  padding: 0 var(--s-3);
  background: transparent;
  color: var(--fd-fog);
  border: 1px solid rgba(255, 255, 255, 0.42);
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: 0.8125rem;
  font-weight: 600;
  white-space: nowrap;
  flex: 0 0 auto;
  cursor: pointer;
}
body:not(.is-empty) .masthead__new { display: inline-flex; }
.masthead__new:hover,
.masthead__new:focus-visible { border-color: var(--fd-gold); color: var(--fd-gold); }

/* 5. Dead space between the disclosure and "What are you working
   through?" on the landing screen. */
.masthead__inner { padding-bottom: var(--s-2); }
body.is-empty .main__inner { padding-top: var(--s-3); }
