:root {
  /* Deep warm charcoal-brown — the base of the palette. Warm dark earth,
     never black, never cool navy. This is the ground everything else sits on. */
  --bg-deep: #1c1712;
  --bg-mid: #2b2019;
  --bg-light: #3d2f24;

  /* Soft amber — primary text/accent color. The color of late light on
     water: warm, inviting, never harsh or neon. */
  --amber: #dba463;
  --amber-soft: #bd8a54;
  --amber-dim: color-mix(in srgb, var(--amber) 30%, transparent);

  /* Muted sage green — secondary accent. River grass, restoration, growth.
     Used for quieter, secondary interactions rather than primary calls to action. */
  --sage: #93a67d;
  --sage-dim: color-mix(in srgb, var(--sage) 28%, transparent);

  /* Soft terracotta — warmth accent. Oklahoma red dirt. Used for warmth,
     emphasis, and gentle "notice this" moments rather than alarm. */
  --terracotta: #bf6f4f;
  --terracotta-dim: color-mix(in srgb, var(--terracotta) 30%, transparent);

  /* Pale warm cream — primary body text. Easier on anxious eyes than
     bright white; still reads clearly against the dark charcoal-brown base. */
  --cream: #efe3d1;
  --text-muted: #c6b49b;

  /* Text color painted directly on top of a solid --amber-filled surface
     (selected buttons, the send button, a playing preview icon). Dusk,
     Dawn, and Forest are all dark themes where --bg-deep already reads as
     dark text on a bright accent fill, so this just mirrors it by default
     for all three — see body[data-theme="forest"] below. */
  --accent-contrast: var(--bg-deep);

  /* How much room every screen holds open for the app's floating chrome —
     the navigation pill, the voice/appearance/account pill, the footer.
     None of that chrome sits *in* the page the way a paragraph does; it
     floats on top of everything, so each screen has to deliberately keep
     its own content out from under it.

     These are variables rather than numbers typed into each rule because
     the chrome MOVES as the window narrows. On a wide screen the nav is a
     tall pill against the right edge, so screens hold room open on the
     right. On a phone there is no room for a right-hand column at all, so
     the nav becomes a bar across the bottom and the room being held open
     has to move to the bottom with it. The narrow-screen rules at the end
     of this file do exactly that by reassigning this one value.

     This is worth the small ceremony because the two halves silently drifted
     apart before: screens reserved a 200px right-hand margin at every window
     size, including a phone, where the nav it was making room for had nowhere
     to be. On a 375px-wide phone that left the conversation a 175px ribbon —
     text broke to one or two words a line and the message box shrank to
     thirty pixels. Keeping the reservation and the chrome tied to the same
     values is what stops that from happening again.

     The four numbers are read clockwise from the top: top, right, bottom,
     left — the order CSS uses for padding everywhere.

     The 48px along the bottom is for the footer's crisis line. It used to be
     zero, on the assumption that a tall desktop window has room to spare —
     but on a short one, such as a tablet held on its side, the bottom of the
     panel slid under the footer. Both are translucent, so where they overlap
     the tint doubles and a darker band appears across the foot of the panel.
     Nothing was unreachable, but it looked like a rendering fault. */
  --chrome-room: 0px 200px 48px 0px;
}

* {
  box-sizing: border-box;
}

html {
  font-size: 18.5px;
}

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  width: 100%;
  overflow: hidden;
  background: linear-gradient(180deg, #1c1712 0%, #2c2018 12%, #4a2f20 24%, #79492f 40%, #9c6f42 50%, #86603c 60%, var(--bg-light) 72%, var(--bg-mid) 86%, var(--bg-deep) 100%);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  color: var(--cream);
}

/* ---------- Alternate color themes ---------- */
/* Dusk (above, the default) is the original warm Oklahoma sunset palette.
   Dawn and Forest override the same custom properties — every element in
   this file reads its color from these variables via var() or the
   color-mix() expressions below, so re-theming the whole app is just a
   matter of swapping the attribute on <body>. The background gradient is
   overridden per-theme too since its warmest highlight stops are a few
   literal colors rather than a single variable. Applied and persisted by
   app.js (see the "Color scheme" section). */

body[data-theme="dawn"] {
  /* Deep purple fading into pale blue into silver light — dawn with the
     last of the night still visible above the horizon. Muted lavender and
     soft violet now run alongside the original slate blue and silver,
     cooler and quieter than Dusk, but richer and more contemplative than
     a plain cool palette. */
  --bg-deep: #12101c;
  --bg-mid: #1d1a2c;
  --bg-light: #322c48;
  --amber: #b9aed9;
  --amber-soft: #9186bd;
  --amber-dim: color-mix(in srgb, var(--amber) 30%, transparent);
  --sage: #8fae9c;
  --sage-dim: color-mix(in srgb, var(--sage) 28%, transparent);
  --terracotta: #a888c6;
  --terracotta-dim: color-mix(in srgb, var(--terracotta) 30%, transparent);
  --cream: #eeecf6;
  --text-muted: #bcb4cf;
  background: linear-gradient(180deg, #0e0a18 0%, #171228 12%, #241f3a 24%, #33324f 40%, #4a5170 50%, #6b7c95 60%, var(--bg-light) 72%, var(--bg-mid) 86%, var(--bg-deep) 100%);
}

body[data-theme="forest"] {
  /* Deep forest green, warm brown, soft gold, cream — a cabin in the trees.
     Dark and enveloping like Dusk and Dawn, not a light theme. The one
     departure from the original palette: at the very top of the screen the
     gradient opens onto a brief, pale sky blue — a glimpse of sky through
     the canopy — before quickly deepening into the same dark greens below.
     --accent-contrast is left at its :root default (var(--bg-deep)) since
     this is a dark theme again, same as Dusk and Dawn. */
  --bg-deep: #14190f;
  --bg-mid: #1f2a17;
  --bg-light: #33422a;
  --amber: #c9a668;
  --amber-soft: #a8843f;
  --amber-dim: color-mix(in srgb, var(--amber) 30%, transparent);
  --sage: #7a9c63;
  --sage-dim: color-mix(in srgb, var(--sage) 28%, transparent);
  --terracotta: #8a5a3b;
  --terracotta-dim: color-mix(in srgb, var(--terracotta) 30%, transparent);
  --cream: #f1e9d6;
  --text-muted: #c9bfa0;
  background: linear-gradient(180deg, #9fd3ec 0%, #5a9bb0 6%, #2f4a35 14%, #223018 22%, #33431f 40%, #47572a 50%, #3d4d24 60%, var(--bg-light) 72%, var(--bg-mid) 86%, var(--bg-deep) 100%);
}

#river {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  height: 100dvh;
  z-index: 0;
  display: block;
}

/* A phone browser's address bar slides away as you scroll and slides back when
   you scroll up, so the visible height of the page is not one fixed number.
   "100vh" means the TALLEST the window ever gets — with the address bar hidden
   — which on a phone means the bottom of the screen sits underneath the address
   bar whenever it is showing, hiding the message box just when someone reaches
   for it. "100dvh" is the same idea but measured against the window as it
   actually is right now, so the layout follows the address bar in and out. The
   plain 100vh line is kept immediately above it for older browsers that do not
   understand dvh and would otherwise skip the rule entirely. */
.screen {
  position: relative;
  z-index: 1;
  height: 100vh;
  height: 100dvh;
  width: 100vw;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.9s ease;
}

.screen.hidden {
  opacity: 0;
  pointer-events: none;
  position: absolute;
  top: 0;
  left: 0;
}

/* ---------- Landing ---------- */

.welcome {
  max-width: 640px;
  text-align: center;
  padding: 44px 40px;
  background: color-mix(in srgb, var(--bg-deep) 42%, transparent);
  border-radius: 28px;
  backdrop-filter: blur(3px);
}

.line {
  opacity: 0;
  transform: translateY(12px);
  animation: fade-up 1.4s ease forwards;
  font-weight: 300;
  letter-spacing: 0.01em;
}

.line-1 {
  font-size: 2.6rem;
  color: var(--cream);
  margin: 0 0 20px;
  animation-delay: 0.3s;
  text-shadow: 0 0 30px color-mix(in srgb, var(--amber) 25%, transparent);
}

.line-2 {
  font-size: 1.35rem;
  color: var(--text-muted);
  margin: 0 0 48px;
  line-height: 1.6;
  animation-delay: 1.1s;
}

@keyframes fade-up {
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.ready-btn {
  opacity: 0;
  animation: fade-up 1.2s ease forwards;
  animation-delay: 2.2s;
  background: transparent;
  border: 1px solid var(--amber-soft);
  color: var(--amber);
  font-size: 1.1rem;
  letter-spacing: 0.03em;
  padding: 15px 40px;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.3s ease, color 0.3s ease, box-shadow 0.3s ease;
}

.ready-btn:hover {
  background: var(--amber-dim);
  color: var(--cream);
  box-shadow: 0 0 24px var(--amber-dim);
}

/* ---------- Voice preference ---------- */

.voice-pref-welcome {
  max-height: 86vh;
  overflow-y: auto;
}

.voice-pref-heading {
  font-size: 1.8rem;
  font-weight: 300;
  color: var(--cream);
  margin: 0 0 14px;
  text-shadow: 0 0 24px color-mix(in srgb, var(--amber) 20%, transparent);
}

.voice-pref-subtext {
  font-size: 1.1rem;
  color: var(--text-muted);
  margin: 0 0 30px;
  line-height: 1.6;
}

.voice-pref-options {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.voice-pref-row {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* Plain "Voice N" label — deliberately not a button. The person previews
   and selects by sound alone, so the number is just a placeholder, not a
   name or description to weigh. */
.voice-pref-label {
  flex: 1;
  text-align: left;
  font-size: 1.08rem;
  color: var(--text-muted);
}

.voice-pref-btn {
  flex-shrink: 0;
  background: transparent;
  border: 1px solid var(--amber-soft);
  color: var(--amber);
  font-family: inherit;
  font-size: 0.95rem;
  padding: 10px 22px;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.3s ease, color 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
}

.voice-pref-row-text {
  justify-content: center;
}

.voice-pref-row-text .voice-pref-btn {
  flex: 1;
  max-width: 220px;
  text-align: center;
  padding: 12px 18px;
}

.voice-pref-btn:hover {
  background: var(--amber-dim);
  color: var(--cream);
  box-shadow: 0 0 22px var(--amber-dim);
}

.voice-pref-btn.selected {
  background: var(--amber);
  border-color: var(--amber);
  color: var(--accent-contrast);
  box-shadow: 0 0 22px var(--amber-dim);
}

.voice-preview-btn {
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--amber-soft);
  background: transparent;
  color: var(--amber);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease;
}

.voice-preview-btn svg {
  width: 15px;
  height: 15px;
  margin-left: 2px; /* optical centering of the play triangle */
}

.voice-preview-btn:hover {
  background: var(--amber-dim);
  color: var(--cream);
}

.voice-preview-btn.loading {
  opacity: 0.5;
  cursor: wait;
}

.voice-preview-btn.playing {
  background: var(--amber);
  border-color: var(--amber);
  color: var(--accent-contrast);
  box-shadow: 0 0 14px var(--amber-dim);
}

.voice-settings-nav {
  position: fixed;
  top: 24px;
  right: 24px;
  z-index: 2;
  display: flex;
  gap: 4px;
  padding: 8px;
  background: color-mix(in srgb, var(--bg-deep) 66%, transparent);
  border: 1px solid color-mix(in srgb, var(--amber) 15%, transparent);
  border-radius: 999px;
  backdrop-filter: blur(6px);
  transition: opacity 0.5s ease;
}

.voice-settings-nav.hidden {
  opacity: 0;
  pointer-events: none;
}

/* ---------- Color scheme ---------- */

.color-pref-options {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
}

.color-pref-btn {
  display: flex;
  flex: 1 1 160px;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  background: transparent;
  border: 1px solid var(--amber-soft);
  color: var(--amber);
  font-family: inherit;
  padding: 18px 16px;
  border-radius: 16px;
  cursor: pointer;
  transition: background 0.3s ease, color 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
}

.color-pref-btn:hover {
  background: var(--amber-dim);
  color: var(--cream);
  box-shadow: 0 0 22px var(--amber-dim);
}

.color-pref-btn.selected {
  background: var(--amber);
  border-color: var(--amber);
  color: var(--accent-contrast);
  box-shadow: 0 0 22px var(--amber-dim);
}

.color-pref-btn.selected .color-pref-desc {
  color: var(--accent-contrast);
  opacity: 0.75;
}

/* Each swatch is a fixed, non-variable gradient (not tied to the live theme
   variables) so all three options stay visible as a true preview no matter
   which theme is currently active. */
.color-pref-swatch {
  display: block;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid rgba(0, 0, 0, 0.25);
}

.swatch-dusk {
  background: linear-gradient(135deg, #dba463 0%, #79492f 45%, #1c1712 100%);
}

.swatch-dawn {
  background: linear-gradient(135deg, #b9aed9 0%, #6b7c95 45%, #12101c 100%);
}

.swatch-forest {
  background: linear-gradient(135deg, #c9a668 0%, #47572a 45%, #14190f 100%);
}

.color-pref-name {
  font-size: 1.05rem;
}

.color-pref-desc {
  font-size: 0.82rem;
  color: var(--text-muted);
  text-align: center;
}

/* ---------- Onboarding (disclaimer + how WITHIN learns) ---------- */

/* This screen carries the most text of any in the app — a disclaimer box and two
   paragraphs about how WITHIN learns — and it is the one screen a person cannot
   get past without pressing the button at the foot of it. On a short phone the
   whole card used to run off both ends of the viewport, because .screen is a
   fixed-height flex container that centres its child and does not scroll, so a
   card taller than the screen simply had its top and bottom cut away. The button
   went with the bottom, which left first-time visitors on a small phone with no
   way into the app at all.

   The card is now a column that never grows past the viewport: the reading
   matter scrolls inside it and the button sits outside that scrolling region,
   so it stays visible no matter how far down the text someone is. */
.onboarding-welcome {
  max-width: 620px;
  text-align: left;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* min-height:0 is the part that actually does the work. A flex child's default
   floor is the height of its own content, which would push the card back past
   the viewport and undo everything above — this lets it shrink and scroll. */
.onboarding-scroll {
  overflow-y: auto;
  min-height: 0;
}

/* Without a gutter the card would sit flush against the edges of a small phone.
   #onboarding is deliberately not in the --chrome-room list, because the nav and
   footer have not been revealed yet when this screen is shown. */
#onboarding {
  padding: 16px;
}

.onboarding-section {
  margin: 0 0 26px;
}

.onboarding-disclaimer {
  font-size: 1.02rem;
  line-height: 1.7;
  color: var(--cream);
  background: color-mix(in srgb, var(--terracotta) 8%, transparent);
  border: 1px solid var(--terracotta-dim);
  border-left: 3px solid var(--terracotta);
  border-radius: 12px;
  padding: 18px 22px;
  margin: 0;
}

.onboarding-learn {
  font-size: 1.05rem;
  line-height: 1.75;
  color: var(--text-muted);
  margin: 0;
}

/* The learning disclosure runs to two paragraphs — what WITHIN learns about
   the person, and then that WITHIN itself is still becoming. The second one
   needs room to land as its own thought rather than butting straight up
   against the first. */
.onboarding-learn + .onboarding-learn {
  margin-top: 16px;
}

/* flex-shrink:0 keeps the button at its full height when the text above is long
   enough to be fighting for room — otherwise the browser would squeeze the
   button itself rather than scrolling the paragraphs. */
.onboarding-welcome .ready-btn {
  display: block;
  flex-shrink: 0;
  margin: 8px auto 0;
  opacity: 1;
  animation: none;
  text-align: center;
}

/* ---------- Chat ---------- */

.chat-shell {
  width: min(720px, 84vw);
  height: min(720px, 86vh);
  display: flex;
  flex-direction: column;
  background: color-mix(in srgb, var(--bg-deep) 74%, transparent);
  border: 1px solid color-mix(in srgb, var(--amber) 15%, transparent);
  border-radius: 20px;
  backdrop-filter: blur(8px);
  overflow: hidden;
}

/* Every screen that can be reached while the floating chrome is on screen has
   to hold room open for it. #privacy was missing from this list, which is why
   on a window around 1024px wide the privacy text slid underneath the
   navigation pill — the same class of mistake as the phone layout, just
   quieter and easier to miss. */
#chat,
#emotions,
#virtues,
#journal,
#feedback,
#flow,
#privacy,
#voice-pref,
#color-scheme {
  padding: var(--chrome-room);
}

.messages {
  flex: 1;
  overflow-y: auto;
  padding: 28px 26px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.chat-welcome {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 10px;
  padding: 20px;
}

.chat-welcome-heading {
  font-size: 1.8rem;
  font-weight: 300;
  color: var(--cream);
  margin: 0;
  text-shadow: 0 0 24px color-mix(in srgb, var(--amber) 20%, transparent);
}

.chat-welcome-subtext {
  font-size: 1.05rem;
  color: var(--text-muted);
  margin: 0;
}

.messages::-webkit-scrollbar {
  width: 6px;
}

.messages::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--amber) 25%, transparent);
  border-radius: 3px;
}

.bubble {
  max-width: 78%;
  padding: 14px 19px;
  border-radius: 16px;
  line-height: 1.6;
  font-size: 1.08rem;
  white-space: pre-wrap;
  word-wrap: break-word;
  animation: fade-up 0.4s ease forwards;
}

.bubble.user {
  align-self: flex-end;
  background: color-mix(in srgb, var(--amber) 16%, transparent);
  color: var(--cream);
  border-bottom-right-radius: 4px;
}

.bubble.assistant {
  align-self: flex-start;
  background: color-mix(in srgb, var(--cream) 5%, transparent);
  color: var(--cream);
  border: 1px solid color-mix(in srgb, var(--amber) 10%, transparent);
  border-bottom-left-radius: 4px;
}

/* Shown on every spoken reply, always — browsers only allow audio.play() to
   succeed inside a real user gesture, and by the time the audio is fetched
   and ready that gesture is gone. So instead of a silently-failing autoplay
   attempt, this is the one guaranteed way to hear a reply: deliberately
   large and unmissable rather than a small icon, so it reads as the primary
   way to listen, not a fallback. */
.bubble-play-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 12px;
  padding: 10px 20px;
  border: 1px solid var(--amber);
  border-radius: 999px;
  background: color-mix(in srgb, var(--amber) 18%, transparent);
  color: var(--amber);
  font-size: 0.98rem;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.2s ease, box-shadow 0.2s ease;
}

.bubble-play-btn:hover {
  background: color-mix(in srgb, var(--amber) 30%, transparent);
  box-shadow: 0 0 18px var(--amber-dim);
}

.bubble-play-btn svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

.chat-form {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  padding: 16px 20px;
  border-top: 1px solid color-mix(in srgb, var(--amber) 12%, transparent);
}

.chat-input {
  flex: 1;
  resize: none;
  max-height: 140px;
  background: color-mix(in srgb, var(--cream) 4%, transparent);
  border: 1px solid color-mix(in srgb, var(--amber) 18%, transparent);
  border-radius: 14px;
  color: var(--cream);
  font-size: 1.05rem;
  font-family: inherit;
  padding: 12px 14px;
  outline: none;
}

.chat-input:focus {
  border-color: var(--amber-soft);
}

.chat-input::placeholder {
  color: var(--text-muted);
}

.send-btn {
  width: 42px;
  height: 42px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 1px solid var(--amber-soft);
  background: var(--amber);
  color: var(--accent-contrast);
  font-size: 1.2rem;
  cursor: pointer;
  transition: opacity 0.2s ease, transform 0.15s ease;
}

.send-btn:hover {
  transform: scale(1.05);
}

.send-btn:disabled {
  opacity: 0.4;
  cursor: default;
  transform: none;
}

/* ---------- Emotions & Virtues ---------- */

.card-shell {
  padding: 36px 32px;
  overflow-y: auto;
  display: block;
}

.emotions-flow {
  display: flex;
  flex-direction: column;
  gap: 22px;
  max-width: 480px;
  margin: 0 auto;
}

.emotions-prompt {
  font-size: 1.3rem;
  font-weight: 300;
  color: var(--cream);
  line-height: 1.6;
  margin: 0;
  text-align: center;
}

.emotions-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
}

.emotions-grid.single-column,
.emotions-entry-grid {
  grid-template-columns: 1fr;
}

.emotion-btn {
  background: transparent;
  border: 1px solid var(--amber-soft);
  color: var(--amber);
  font-size: 1.05rem;
  font-family: inherit;
  padding: 15px 14px;
  border-radius: 14px;
  cursor: pointer;
  transition: background 0.3s ease, color 0.3s ease, box-shadow 0.3s ease;
}

.emotion-btn:hover {
  background: var(--amber-dim);
  color: var(--cream);
  box-shadow: 0 0 22px var(--amber-dim);
}

.entry-btn {
  padding: 20px 18px;
  font-size: 1.1rem;
}

.emotions-textarea {
  width: 100%;
  resize: vertical;
  min-height: 120px;
  background: color-mix(in srgb, var(--cream) 4%, transparent);
  border: 1px solid color-mix(in srgb, var(--amber) 18%, transparent);
  border-radius: 14px;
  color: var(--cream);
  font-size: 1.05rem;
  font-family: inherit;
  line-height: 1.6;
  padding: 14px 16px;
  outline: none;
}

.emotions-textarea:focus {
  border-color: var(--amber-soft);
}

.emotions-textarea::placeholder {
  color: var(--text-muted);
}

.emotions-error {
  font-size: 0.95rem;
  color: var(--terracotta);
  text-align: center;
  margin: -8px 0 0;
}

.emotions-error.hidden {
  display: none;
}

.emotions-back {
  align-self: flex-start;
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 1rem;
  font-family: inherit;
  cursor: pointer;
  padding: 0;
}

.emotions-back:hover {
  color: var(--sage);
}

.emotions-result-heading {
  font-size: 2rem;
  font-weight: 300;
  color: var(--amber);
  margin: 4px 0 0;
  text-align: center;
  text-shadow: 0 0 24px color-mix(in srgb, var(--amber) 30%, transparent);
}

.emotions-result-body {
  font-size: 1.1rem;
  line-height: 1.75;
  color: var(--text-muted);
  margin: 0;
}

.emotions-result-why {
  font-size: 1.02rem;
  line-height: 1.75;
  color: var(--terracotta);
  font-style: italic;
  margin: -10px 0 0;
}

.emotions-result-question {
  font-size: 1.14rem;
  line-height: 1.75;
  color: var(--cream);
  font-style: italic;
  margin: 6px 0 0;
}

.tool-reveal-btn {
  align-self: center;
  margin-top: 4px;
  font-size: 0.98rem;
  padding: 12px 20px;
  opacity: 0.85;
}

.tool-reveal-btn:hover {
  opacity: 1;
}

.emotions-tool-section {
  display: flex;
  flex-direction: column;
  gap: 22px;
}

.emotions-tool-section.hidden {
  display: none;
}

.start-over-btn {
  align-self: center;
  margin-top: 8px;
}

/* The "I don't know" path opens with a paragraph that is neither a question nor an
   instruction — it is there to explain that a feeling without a name is still a real
   feeling. It is set left-aligned rather than centred, because centred text reads as a
   pronouncement and this is meant to read as someone talking to you. The same class
   carries the closing paragraph where two or three possible emotions are offered. */
.emotions-guided-frame {
  font-size: 1.14rem;
  font-weight: 300;
  line-height: 1.8;
  color: var(--cream);
  margin: 0;
}

/* Every prompt on the guided path can be passed over. The skip sits below the way
   forward and is deliberately quiet — it should be findable by anyone who wants it and
   invisible to anyone who does not, so that nobody feels nudged towards giving up. */
.emotions-skip {
  align-self: center;
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 0.95rem;
  font-family: inherit;
  cursor: pointer;
  padding: 9px 14px;
  margin-top: -12px;
}

.emotions-skip:hover {
  color: var(--sage);
}

.emotions-spectrum {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* A plain range input looks like a volume control on every platform, which is the wrong
   register entirely for a question about how something feels. Stripping the browser's
   own appearance and drawing the track and handle by hand is the only way to get a line
   that looks like a line. */
.emotions-spectrum-slider {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 28px;
  background: transparent;
  cursor: pointer;
  outline: none;
}

.emotions-spectrum-slider::-webkit-slider-runnable-track {
  height: 2px;
  border-radius: 2px;
  background: var(--amber-soft);
}

.emotions-spectrum-slider::-moz-range-track {
  height: 2px;
  border-radius: 2px;
  background: var(--amber-soft);
}

/* The handle is sized past the 24px that touch guidelines ask for, because this is one
   of the few controls in the app that has to be dragged rather than tapped. */
.emotions-spectrum-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 26px;
  height: 26px;
  margin-top: -12px;
  border-radius: 50%;
  background: var(--amber);
  box-shadow: 0 0 18px var(--amber-dim);
  border: none;
}

.emotions-spectrum-slider::-moz-range-thumb {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--amber);
  box-shadow: 0 0 18px var(--amber-dim);
  border: none;
}

/* The two poles are the model's words for what the person described, so they can be any
   length at all. Each label is held to just under half the width and allowed to wrap,
   which keeps a long phrase from shunting the opposite pole off the end of the line. */
.emotions-spectrum-labels {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  font-size: 0.98rem;
  line-height: 1.5;
  color: var(--terracotta);
}

.emotions-spectrum-labels span {
  max-width: 45%;
}

.emotions-spectrum-labels span:last-child {
  text-align: right;
}

.placeholder-content {
  max-width: 420px;
  margin: 0 auto;
  text-align: center;
}

.placeholder-title {
  font-size: 1.6rem;
  font-weight: 300;
  color: var(--amber);
  margin: 0 0 12px;
}

.placeholder-body {
  font-size: 1.1rem;
  color: var(--text-muted);
  line-height: 1.6;
  margin: 0;
}

/* ---------- FLOW (guided practice: Find, Let in the Light, Open with
   Kindness, Welcome Home) ---------- */

.flow-progress {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin-bottom: 4px;
}

.flow-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--amber) 30%, transparent);
  transition: background 0.4s ease, box-shadow 0.4s ease, transform 0.4s ease;
}

.flow-dot.active {
  background: var(--amber);
  box-shadow: 0 0 14px var(--amber-dim);
  transform: scale(1.25);
}

.flow-movement-name {
  font-size: 1.9rem;
  font-weight: 300;
  color: var(--amber);
  margin: 4px 0 0;
  text-align: center;
  text-shadow: 0 0 24px color-mix(in srgb, var(--amber) 30%, transparent);
}

.flow-movement-text {
  font-size: 1.14rem;
  line-height: 1.85;
  color: var(--cream);
  text-align: center;
  margin: 4px 0 0;
}

.flow-continue-btn {
  min-width: 200px;
}

/* A step already walked stays lit, more faintly than the one being read now.
   Four movements is few enough that showing the whole shape of the practice —
   where they are, and how much is still ahead — settles more than it pressures. */
.flow-dot.done {
  background: color-mix(in srgb, var(--amber) 62%, transparent);
}

/* The two ways through the practice. Each button carries a title and a quiet
   line under it, so the choice can be made without having to guess what either
   one means. */
.flow-mode-btn {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 18px 16px;
  text-align: center;
}

.flow-mode-title {
  font-size: 1.1rem;
}

.flow-mode-note {
  font-size: 0.94rem;
  line-height: 1.5;
  color: var(--text-muted);
}

/* Only present on the voice-guided path. The status word and the replay sit on
   one quiet line beneath the movement, well away from Continue, so that neither
   competes with the words being read. */
.flow-voice-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  min-height: 28px;
  margin-top: -8px;
}

.flow-voice-status {
  font-size: 0.92rem;
  color: var(--sage);
  letter-spacing: 0.02em;
}

.flow-replay-btn {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 0.92rem;
  font-family: inherit;
  cursor: pointer;
  padding: 6px 10px;
}

.flow-replay-btn:hover {
  color: var(--sage);
}

.flow-prompt {
  font-size: 1.08rem;
  line-height: 1.7;
  color: var(--terracotta);
  text-align: center;
  margin: 6px 0 -6px;
}

/* Back and Continue share a row, with Continue centred and Back tucked to its
   left. Steps 2 and 3 have both; the first step has only Continue and Welcome
   Home has only Back, and the centring holds in every case because Back is
   absolutely positioned out of the flow rather than taking a share of the
   width. */
.flow-actions {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 52px;
  margin-top: 4px;
}

/* Welcome Home has no Continue — the two doors above this row are the way
   forward — so the row is left holding only the small back link and there is no
   reason for it to keep reserving a button's worth of height. Collapsing it
   hands the space back to the scrolling letter above. */
.flow-actions.back-only {
  min-height: 0;
  margin-top: 12px;
  justify-content: flex-start;
}

.flow-back-btn {
  position: absolute;
  left: 0;
  align-self: center;
}

/* With nothing centred in the row there is nothing for an absolutely positioned
   Back to sit beside, so on Welcome Home it takes part in the layout normally
   and the row simply wraps to its height. */
.flow-actions.back-only .flow-back-btn {
  position: static;
}

.flow-actions .flow-continue-btn {
  align-self: center;
  margin-top: 0;
}

.flow-closing-text {
  font-size: 1.14rem;
  line-height: 1.85;
  color: var(--cream);
  text-align: center;
  margin: 0 0 6px;
}

/* While a movement is on screen the card stops being one long scrolling column
   and becomes a fixed frame: the words scroll inside it, the buttons underneath
   never move. Only the four movements ask for this — the mode choice is short
   and releases it, so it stays centred like every other card in the app.
   `min-height: 0` on the scrolling part is what makes it work: without it
   a flex child refuses to shrink below its content and overflows the frame
   instead of scrolling inside it. */
#flow .card-shell.flow-anchored {
  display: flex;
  flex-direction: column;
  overflow-y: hidden;
}

#flow .card-shell.flow-anchored .emotions-flow {
  flex: 1;
  min-height: 0;
  width: 100%;
}

.flow-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 22px;
}

#flow .card-shell.flow-anchored .flow-actions,
#flow .card-shell.flow-anchored .flow-outro {
  flex-shrink: 0;
}

.flow-outro {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

/* The letter, and then the closing line and two doors beneath it, are faded in
   on a timer rather than by a delayed CSS animation. A delayed animation with
   `fill-mode: both` holds an element at zero opacity until it runs, and a
   backgrounded tab does not run it — which would leave the two doors invisible
   but still clickable, the worst possible state for the only way out of the
   practice. A timer fires regardless, so the words always arrive. */
.flow-reveal {
  opacity: 0;
  transform: translateY(7px);
  transition: opacity 1.3s ease, transform 1.3s ease;
}

.flow-reveal.shown {
  opacity: 1;
  transform: none;
}

/* The closing letter, which sits underneath the Welcome Home movement and above
   the two doors out. Everything here is doing one job: making
   it read as a different kind of speech than the movement above it. Left-aligned
   where the practice is centred, serif where the practice is sans, warmer paper
   than the card it sits on, and a single amber edge down the left the way a
   quoted passage is marked. Someone should be able to tell at a glance that the
   app has stopped guiding and started speaking to them. */
.flow-letter {
  margin: 14px 0 2px;
  padding: 20px 22px;
  text-align: left;
  border-radius: 14px;
  border-left: 2px solid color-mix(in srgb, var(--amber) 55%, transparent);
  background: color-mix(in srgb, var(--amber) 7%, transparent);
}

.flow-letter p {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 1.06rem;
  line-height: 1.9;
  color: var(--cream);
  margin: 0 0 14px;
}

.flow-letter p:last-child {
  margin-bottom: 0;
  color: var(--amber);
}

/* Anyone who has asked their system for less motion gets the words plainly,
   with no travel and no fade — the timer still spaces them out, but nothing
   slides. */
@media (prefers-reduced-motion: reduce) {
  .flow-reveal {
    transform: none;
    transition: none;
  }
}

/* ---------- Virtues quiz ---------- */

.virtues-progress {
  font-size: 0.85rem;
  color: var(--sage);
  text-align: center;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin: -6px 0 2px;
}

.virtues-domain-heading {
  font-size: 1.15rem;
  font-weight: 400;
  color: var(--amber);
  margin: 22px 0 2px;
}

.virtues-domain-heading:first-of-type {
  margin-top: 6px;
}

.virtues-domain-body {
  font-size: 1.05rem;
  line-height: 1.7;
  color: var(--text-muted);
  margin: 0;
}

.virtues-virtue-label {
  font-size: 0.9rem;
  color: var(--terracotta);
  text-align: center;
  font-style: italic;
  margin: 0 0 -8px;
}

.virtues-quote-lead {
  font-size: 0.95rem;
  color: var(--text-muted);
  text-align: center;
  margin: 4px 0 -6px;
}

.virtues-rogers-quote {
  background: color-mix(in srgb, var(--amber) 8%, transparent);
  border: 1px solid var(--amber-dim);
  border-left: 3px solid var(--amber-soft);
  border-radius: 12px;
  padding: 16px 20px;
  margin: 0;
}

.virtues-rogers-quote p {
  font-size: 1rem;
  font-style: italic;
  line-height: 1.7;
  color: var(--cream);
  margin: 0 0 8px;
}

.virtues-rogers-quote cite {
  font-size: 0.85rem;
  font-style: normal;
  color: var(--sage);
}

.virtues-signature-heading {
  margin-top: 10px;
}

.virtues-signature-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.virtues-signature-card {
  background: color-mix(in srgb, var(--amber) 8%, transparent);
  border: 1px solid var(--amber-dim);
  border-radius: 16px;
  padding: 16px 20px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.virtues-signature-name {
  font-size: 1.05rem;
  font-weight: 500;
  color: var(--amber);
  margin: 0;
}

.virtues-signature-reason {
  font-size: 0.98rem;
  line-height: 1.6;
  color: var(--text-muted);
  margin: 0;
}

/* ---------- Q-sort ranking screen ---------- */

.qsort-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.qsort-card {
  display: flex;
  align-items: center;
  gap: 12px;
  background: color-mix(in srgb, var(--sage) 8%, transparent);
  border: 1px solid var(--sage-dim);
  border-radius: 14px;
  padding: 12px 16px;
  cursor: grab;
  transition: box-shadow 0.2s ease, border-color 0.2s ease;
}

.qsort-card:hover {
  border-color: var(--sage);
}

.qsort-card.qsort-dragging {
  opacity: 0.5;
  box-shadow: 0 0 18px var(--sage-dim);
}

.qsort-rank {
  font-size: 0.95rem;
  color: var(--sage);
  min-width: 20px;
  text-align: center;
}

.qsort-name {
  flex: 1;
  font-size: 1.05rem;
  color: var(--cream);
}

.qsort-controls {
  display: flex;
  gap: 6px;
}

.qsort-move-btn {
  background: transparent;
  border: 1px solid var(--sage-dim);
  color: var(--sage);
  font-size: 0.95rem;
  padding: 4px 9px;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease;
}

.qsort-move-btn:hover:not(:disabled) {
  background: var(--sage-dim);
  color: var(--cream);
}

.qsort-move-btn:disabled {
  opacity: 0.3;
  cursor: default;
}

/* ---------- Feedback ---------- */

.feedback-field-label {
  font-size: 0.9rem;
  color: var(--sage);
  letter-spacing: 0.02em;
  margin: 4px 0 -10px;
}

.feedback-toggle-row {
  display: flex;
  gap: 12px;
}

.feedback-toggle-btn {
  flex: 1;
  background: transparent;
  border: 1px solid var(--amber-soft);
  color: var(--amber);
  font-size: 1.05rem;
  font-family: inherit;
  padding: 15px 14px;
  border-radius: 14px;
  cursor: pointer;
  transition: background 0.3s ease, color 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
}

.feedback-toggle-btn:hover {
  background: var(--amber-dim);
  color: var(--cream);
}

.feedback-toggle-btn.selected {
  background: var(--amber);
  border-color: var(--amber);
  color: var(--accent-contrast);
  box-shadow: 0 0 22px var(--amber-dim);
}

/* ---------- Main nav ---------- */

.main-nav {
  position: fixed;
  top: 50%;
  right: 122px;
  transform: translateY(-50%);
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 8px;
  background: color-mix(in srgb, var(--bg-deep) 66%, transparent);
  border: 1px solid color-mix(in srgb, var(--amber) 15%, transparent);
  border-radius: 999px;
  backdrop-filter: blur(6px);
  transition: opacity 0.5s ease;
}

.main-nav.hidden {
  opacity: 0;
  pointer-events: none;
}

.nav-btn {
  position: relative;
  width: 46px;
  height: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition: color 0.3s ease, background 0.3s ease;
}

.nav-btn svg {
  width: 22px;
  height: 22px;
}

.nav-btn:hover {
  color: var(--sage);
}

.nav-btn.active {
  color: var(--amber);
  background: color-mix(in srgb, var(--amber) 12%, transparent);
}

.nav-tooltip {
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%) translateY(2px);
  margin-top: 8px;
  padding: 5px 11px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--bg-deep) 94%, transparent);
  border: 1px solid color-mix(in srgb, var(--amber) 22%, transparent);
  color: var(--cream);
  font-size: 0.72rem;
  letter-spacing: 0.01em;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s ease;
  z-index: 3;
}

.nav-btn:hover .nav-tooltip,
.nav-btn:focus-visible .nav-tooltip {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* A navigation button that says its own name out loud instead of waiting to be
   hovered. Used for exactly one button — the account door — because that is the
   only one a person can be actively hunting for, and the only one whose absence
   reads as "this app has no way to log in" rather than "I haven't found that
   setting yet." It stops being a circle and becomes a rounded rectangle wide
   enough to hold the word, which is also what makes it read as a thing to press
   rather than one more decorative icon in a row of them. */
.nav-btn-labelled {
  width: auto;
  gap: 7px;
  padding: 0 14px 0 11px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--amber) 30%, transparent);
  color: var(--amber);
}

.nav-btn-labelled:hover {
  background: color-mix(in srgb, var(--amber) 14%, transparent);
  color: var(--amber);
}

.nav-btn-label {
  font-size: 0.85rem;
  font-family: inherit;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

/* ---------- Voice input ---------- */

.mic-btn {
  position: relative;
  width: 42px;
  height: 42px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--amber) 30%, transparent);
  background: transparent;
  color: var(--amber);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}

.mic-btn-icon {
  display: flex;
  align-items: center;
  justify-content: center;
}

.mic-btn svg {
  width: 19px;
  height: 19px;
}

.mic-btn:hover {
  background: var(--amber-dim);
  color: var(--cream);
}

.mic-btn:hover .nav-tooltip,
.mic-btn:focus-visible .nav-tooltip {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* The mic and conversation-mode buttons sit in the very bottom row of the chat
   card, and a tooltip that drops downward from a button that low has nowhere
   left to land — it runs past the bottom edge of the card, which is
   `overflow: hidden` so that the scrolling message list stays inside the
   rounded corners. The label came out sliced off along its bottom border,
   jammed into the corner, looking broken rather than helpful.

   Worth being clear about why raising z-index does not fix this, since that is
   the natural first guess: `overflow: hidden` doesn't put the overflowing part
   behind anything, it removes it from the picture altogether. Stacking order
   only decides what gets painted in front of what among the parts that are
   still being drawn at all — so no z-index, however large, brings back
   something the parent has already cut away.

   Removing the clipping instead would work, but it is holding the message list
   inside the card's rounded corners, so taking it away trades a cut tooltip for
   messages spilling past the corners on every scroll. So the label rises
   instead, into the message area, where there is room to spare. This is the
   same answer the bottom navigation bar already uses for the same reason. */
.chat-form .nav-tooltip {
  top: auto;
  bottom: 100%;
  margin-top: 0;
  margin-bottom: 8px;
  transform: translateX(-50%) translateY(-2px);
}

.chat-form .mic-btn:hover .nav-tooltip,
.chat-form .mic-btn:focus-visible .nav-tooltip {
  transform: translateX(-50%) translateY(0);
}

.mic-btn.recording {
  color: var(--terracotta);
  border-color: var(--terracotta);
  background: var(--terracotta-dim);
  animation: mic-pulse 1.4s ease-in-out infinite;
}

.mic-btn:disabled {
  color: var(--text-muted);
  border-color: color-mix(in srgb, var(--text-muted) 30%, transparent);
  background: transparent;
  cursor: not-allowed;
  opacity: 0.4;
  animation: none;
}

.mic-btn:disabled:hover {
  background: transparent;
  color: var(--text-muted);
}

.mic-btn:disabled .nav-tooltip,
.mic-btn:disabled:hover .nav-tooltip {
  opacity: 0;
}

/* A gentler, persistent cousin of .nav-tooltip: shown (via .visible, added
   in JS) when voice input can't be used — Safari's unreliable speech
   recognition, a denied microphone permission, no microphone at all —
   rather than left as a button that silently does nothing. Wider and
   allowed to wrap, since this carries a full sentence rather than a label. */
.voice-fallback-note {
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%) translateY(2px);
  margin-top: 8px;
  padding: 8px 12px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--bg-deep) 94%, transparent);
  border: 1px solid color-mix(in srgb, var(--amber) 22%, transparent);
  color: var(--cream);
  font-size: 0.74rem;
  line-height: 1.35;
  width: 200px;
  max-width: 70vw;
  text-align: center;
  white-space: normal;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
  z-index: 4;
}

.voice-fallback-note.visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

@keyframes mic-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--terracotta) 40%, transparent); }
  50% { box-shadow: 0 0 0 8px transparent; }
}

.textarea-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}

.textarea-row .emotions-textarea {
  flex: 1;
}

/* ---------- Journal ---------- */

.journal-title-input {
  min-height: unset;
}

.journal-entry-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 6px;
}

.journal-entry-item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  text-align: left;
  background: color-mix(in srgb, var(--cream) 4%, transparent);
  border: 1px solid color-mix(in srgb, var(--amber) 14%, transparent);
  border-radius: 12px;
  padding: 12px 16px;
  cursor: pointer;
  color: var(--cream);
  font-family: inherit;
  transition: background 0.2s ease, border-color 0.2s ease;
}

.journal-entry-item:hover {
  background: color-mix(in srgb, var(--amber) 8%, transparent);
  border-color: var(--amber-soft);
}

.journal-entry-date {
  font-size: 0.85rem;
  color: var(--sage);
  letter-spacing: 0.02em;
}

.journal-entry-title {
  font-size: 1.02rem;
  color: var(--cream);
}

.journal-entry-body {
  white-space: pre-wrap;
}

.journal-delete-btn {
  align-self: center;
  margin-top: 18px;
  color: var(--terracotta);
}

.journal-reflection-card {
  background: color-mix(in srgb, var(--sage) 8%, transparent);
  border: 1px solid var(--sage-dim);
  border-radius: 16px;
  padding: 18px 20px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

/* ---------- Footer ---------- */

.app-footer {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  padding: 10px 24px;
  text-align: center;
  background: color-mix(in srgb, var(--bg-deep) 55%, transparent);
  backdrop-filter: blur(4px);
  transition: opacity 0.5s ease;
}

.app-footer.hidden {
  opacity: 0;
  pointer-events: none;
}

.app-footer p {
  margin: 0;
  font-size: 0.72rem;
  line-height: 1.5;
  color: var(--text-muted);
  opacity: 0.7;
}

.privacy-email-link {
  color: var(--amber);
}

.journal-reflection-heading {
  font-size: 1.15rem;
  color: var(--sage);
  text-shadow: none;
}

/* ---------- Accounts ---------- */

.account-prompt-banner {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 0 20px 14px;
  padding: 14px 16px;
  background: color-mix(in srgb, var(--amber) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--amber) 22%, transparent);
  border-radius: 14px;
  animation: fade-up 0.4s ease forwards;
}

.account-prompt-text {
  margin: 0;
  font-size: 0.98rem;
  color: var(--cream);
  line-height: 1.5;
}

.account-prompt-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.account-prompt-btn {
  background: transparent;
  border: 1px solid var(--amber-soft);
  color: var(--amber);
  font-size: 0.9rem;
  font-family: inherit;
  padding: 8px 14px;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease;
}

.account-prompt-btn:hover {
  background: var(--amber-dim);
  color: var(--cream);
}

.account-prompt-btn-primary {
  background: var(--amber);
  border-color: var(--amber);
  color: var(--accent-contrast);
}

.account-prompt-btn-primary:hover {
  background: var(--amber-soft);
  color: var(--accent-contrast);
}

/* The standing invitation, as opposed to the banner above it. The banner
   interrupts once and then goes away; this is a quiet line that simply lives at
   the bottom of the journal, where the stakes are most concrete — a journal is
   the thing a person would actually mind losing, and "on this device only" is a
   sentence that means something there in a way it doesn't in the abstract. It
   never asks to be dismissed because it never gets in the way, and it does not
   appear at all for anyone who has already said no thanks to accounts. */
.account-guest-invite {
  margin: 18px 0 0;
  padding: 14px 16px;
  border-top: 1px solid color-mix(in srgb, var(--cream) 10%, transparent);
  text-align: center;
}

.account-guest-invite-text {
  margin: 0 0 8px;
  font-size: 0.88rem;
  line-height: 1.55;
  color: var(--text-muted);
}

.account-guest-invite-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
}

.account-guest-invite-btn {
  background: transparent;
  border: 1px solid var(--amber-soft);
  color: var(--amber);
  font-family: inherit;
  font-size: 0.86rem;
  padding: 7px 14px;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease;
}

.account-guest-invite-btn:hover {
  background: var(--amber-dim);
  color: var(--cream);
}

.account-modal {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--bg-deep) 70%, transparent);
  backdrop-filter: blur(6px);
}

.account-modal.hidden {
  display: none;
}

.account-modal-card {
  position: relative;
  width: min(380px, 88vw);
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 32px 26px 26px;
  background: var(--bg-mid);
  border: 1px solid color-mix(in srgb, var(--amber) 20%, transparent);
  border-radius: 20px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
}

.account-modal-close {
  position: absolute;
  top: 12px;
  right: 14px;
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
  padding: 4px;
}

.account-modal-close:hover {
  color: var(--cream);
}

.account-modal-heading {
  margin: 0;
  font-size: 1.3rem;
  font-weight: 300;
  color: var(--amber);
  text-align: center;
}

.account-modal-subtext {
  margin: 0;
  font-size: 0.92rem;
  line-height: 1.55;
  color: var(--text-muted);
  text-align: center;
}

#account-modal-choose,
#account-modal-loggedout,
#account-modal-loggedin,
#account-modal-forgot,
#account-modal-newpassword {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

#account-modal-choose.hidden,
#account-modal-loggedout.hidden,
#account-modal-loggedin.hidden,
#account-modal-forgot.hidden,
#account-modal-newpassword.hidden {
  display: none;
}

/* The two named doors on the opening panel. "Create an account" is the filled
   amber button (it reuses .start-over-btn, the app's primary button); this is
   the outlined one beside it, used for both "Log in" and "Continue as a guest"
   so that neither of them looks like the lesser option. */
.account-choose-btn {
  width: 100%;
  box-sizing: border-box;
  background: transparent;
  border: 1px solid var(--amber-soft);
  border-radius: 999px;
  color: var(--amber);
  font-family: inherit;
  font-size: 1rem;
  padding: 13px 16px;
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease;
}

.account-choose-btn:hover {
  background: var(--amber-dim);
  color: var(--cream);
}

.account-choose-btn:disabled {
  opacity: 0.4;
  cursor: default;
}

.account-choose-btn:disabled:hover {
  background: transparent;
  color: var(--amber);
}

/* Creating an account is the filled one, because for a first-time visitor it is
   the likeliest reason to be here. It is deliberately the same width and the
   same size as "Log in" underneath it — the whole point of this panel is that a
   returning person can see the way back in at a glance, so the two doors differ
   only in fill, never in prominence. */
.account-choose-primary-btn {
  background: var(--amber);
  border-color: var(--amber);
  color: var(--accent-contrast);
}

.account-choose-primary-btn:hover {
  background: var(--amber-soft);
  color: var(--accent-contrast);
}

.account-choose-primary-btn:disabled:hover {
  background: var(--amber);
  color: var(--accent-contrast);
}

/* Guest mode is a real answer, not a refusal, but it is also the one of the
   three that changes nothing — so it sits below a divider, in the quieter
   colour, offered rather than urged. */
.account-choose-guest-btn {
  border-color: color-mix(in srgb, var(--cream) 22%, transparent);
  color: var(--text-muted);
}

.account-choose-guest-btn:hover {
  background: color-mix(in srgb, var(--cream) 6%, transparent);
  color: var(--cream);
}

/* A small word between the two account doors and the guest one, with a hairline
   running out to either side of it. The line is drawn with borders on two
   pseudo-elements rather than a background image so it inherits the theme. */
.account-choose-or {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 2px 0;
  font-size: 0.82rem;
  color: var(--text-muted);
}

.account-choose-or::before,
.account-choose-or::after {
  content: '';
  flex: 1;
  border-top: 1px solid color-mix(in srgb, var(--cream) 12%, transparent);
}

.account-choose-note {
  margin: 0;
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--text-muted);
  text-align: center;
}

/* The "Forgot your password?" link only belongs under the log-in form, so it is
   hidden outright while someone is creating an account — someone part-way
   through making a password has not forgotten one yet. It sits directly beneath
   the two fields, and it is deliberately amber rather than the muted grey the
   other small links use: a person who has come here at all has already had one
   thing fail on them today, and this is not the moment to make them squint.
   Both this and .account-toggle-link need their own .hidden rules, because they
   set `display` themselves and a bare .hidden would not override that. */
.account-forgot-link {
  align-self: center;
  margin-top: -2px;
  background: none;
  border: none;
  color: var(--amber);
  font-size: 0.9rem;
  font-family: inherit;
  text-decoration: underline;
  cursor: pointer;
  padding: 2px;
}

.account-forgot-link:hover {
  color: var(--amber-soft);
}

.account-forgot-link.hidden,
.account-toggle-link.hidden {
  display: none;
}

/* Both doors, side by side, at the top of the panel. Creating an account and
   logging back in are equally likely reasons to open this, and a returning
   person should never have to discover that logging in exists — previously it
   was a faint underlined line of text below the button, easy to read past. */
.account-mode-switch {
  display: flex;
  gap: 4px;
  padding: 4px;
  margin-bottom: 2px;
  background: color-mix(in srgb, var(--amber) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--amber) 18%, transparent);
  border-radius: 999px;
}

.account-mode-btn {
  flex: 1;
  background: transparent;
  border: none;
  color: var(--text-muted);
  font-family: inherit;
  /* Sized so "Create account" still sits on a single line at 375px wide —
     wrapped onto two lines it made the two options look unequal, as though
     one were the real choice and the other an afterthought. */
  font-size: 0.88rem;
  white-space: nowrap;
  padding: 9px 8px;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease;
}

.account-mode-btn:hover {
  color: var(--cream);
}

.account-mode-btn.active {
  background: var(--amber);
  color: var(--accent-contrast);
}

.account-input {
  width: 100%;
  box-sizing: border-box;
  background: color-mix(in srgb, var(--cream) 4%, transparent);
  border: 1px solid color-mix(in srgb, var(--amber) 18%, transparent);
  border-radius: 12px;
  color: var(--cream);
  font-size: 1rem;
  font-family: inherit;
  padding: 12px 14px;
  outline: none;
}

.account-input:focus {
  border-color: var(--amber-soft);
}

.account-input::placeholder {
  color: var(--text-muted);
}

.account-error {
  margin: 0;
  font-size: 0.9rem;
  color: var(--terracotta);
  text-align: center;
}

.account-error.hidden {
  display: none;
}

.account-toggle-link {
  align-self: center;
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 0.88rem;
  font-family: inherit;
  text-decoration: underline;
  cursor: pointer;
  padding: 0;
}

.account-toggle-link:hover {
  color: var(--amber);
}

.account-loggedin-email {
  margin: 0;
  font-size: 0.98rem;
  color: var(--cream);
  text-align: center;
  word-break: break-all;
}

.nav-btn.account-signed-in {
  color: var(--amber);
  border-color: var(--amber);
}

/* ---------- Delete account and all data ---------- */

.account-delete-btn {
  align-self: center;
  margin-top: 4px;
  background: none;
  border: none;
  color: var(--terracotta);
  font-size: 0.85rem;
  font-family: inherit;
  text-decoration: underline;
  cursor: pointer;
  padding: 0;
  opacity: 0.8;
}

.account-delete-btn:hover {
  opacity: 1;
}

#account-delete-confirm {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

#account-delete-confirm.hidden {
  display: none;
}

.account-delete-warning {
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.55;
  color: var(--cream);
  text-align: center;
}

.account-delete-confirm-btn {
  background: var(--terracotta);
  border: 1px solid var(--terracotta);
  color: var(--accent-contrast);
  font-size: 1rem;
  font-family: inherit;
  padding: 12px 16px;
  border-radius: 14px;
  cursor: pointer;
  transition: opacity 0.2s ease;
}

.account-delete-confirm-btn:hover {
  opacity: 0.88;
}

.account-delete-confirm-btn:disabled {
  opacity: 0.5;
  cursor: default;
}

/* ---------- Clear my memory ----------
   A gentler, narrower cousin of account deletion — same shape (in-place
   confirm panel, disabled-while-in-flight button), but styled in the
   app's own warm amber rather than the terracotta reserved for
   irreversible full deletion. This is the person choosing to let go of
   what's been learned about them, not losing anything they made. */

.account-clear-memory-btn {
  align-self: center;
  margin-top: 4px;
  background: none;
  border: none;
  color: var(--amber);
  font-size: 0.85rem;
  font-family: inherit;
  text-decoration: underline;
  cursor: pointer;
  padding: 0;
  opacity: 0.85;
}

.account-clear-memory-btn:hover {
  opacity: 1;
}

#account-clear-memory-confirm {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

#account-clear-memory-confirm.hidden {
  display: none;
}

.account-clear-memory-confirm-btn {
  background: var(--amber);
  border: 1px solid var(--amber);
  color: var(--accent-contrast);
  font-size: 1rem;
  font-family: inherit;
  padding: 12px 16px;
  border-radius: 14px;
  cursor: pointer;
  transition: opacity 0.2s ease;
}

.account-clear-memory-confirm-btn:hover {
  opacity: 0.88;
}

.account-clear-memory-confirm-btn:disabled {
  opacity: 0.5;
  cursor: default;
}

.account-clear-memory-status {
  margin: 0;
  font-size: 0.88rem;
  color: var(--amber);
  text-align: center;
}

.account-clear-memory-status.hidden {
  display: none;
}

/* ---------- Password reset ---------- */
/* Quiet confirmations rather than errors — "a reset link is on its way,"
   "your password has been updated." Amber like the rest of the app's good
   news, deliberately not the terracotta used for things going wrong. */

.account-notice {
  margin: 0;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--amber);
  text-align: center;
}

.account-notice.hidden {
  display: none;
}

/* ---------- Conversation mode ---------- */

.conversation-mode-btn.recording {
  color: var(--terracotta);
  border-color: var(--terracotta);
  background: var(--terracotta-dim);
  animation: mic-pulse 1.4s ease-in-out infinite;
}

.conversation-mode-status {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin: 0 20px 8px;
  font-size: 0.82rem;
  color: var(--text-muted);
}

.conversation-mode-status.hidden {
  display: none;
}

.conversation-mode-status::before {
  content: '';
  width: 8px;
  height: 8px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--sage);
  animation: conversation-dot-pulse 1.4s ease-in-out infinite;
}

.conversation-mode-status[data-state="thinking"]::before {
  background: var(--amber);
  animation: conversation-dot-spin 1s linear infinite;
}

.conversation-mode-status[data-state="speaking"]::before {
  background: var(--terracotta);
}

@keyframes conversation-dot-pulse {
  0%, 100% { opacity: 0.4; transform: scale(0.85); }
  50% { opacity: 1; transform: scale(1.15); }
}

@keyframes conversation-dot-spin {
  0%, 100% { opacity: 0.5; }
  50% { opacity: 1; }
}

/* ==================================================================
   Narrow screens — tablets held upright, and phones
   ==================================================================

   Everything above this point describes WITHIN on a wide screen, which is
   where it was designed and where it still looks the way it is meant to.
   Nothing above has been changed for small screens; the rules below only
   step in when the window is actually too narrow for that arrangement to
   work, and they hand back over the moment there is room again.

   Three thresholds, and each one exists for a specific reason rather than
   because it is a round number:

   1024px — below this the tall navigation pill on the right no longer has
   room to stand beside the conversation. This figure was arrived at by
   measuring rather than by picking a familiar number: the panel is 720px
   at its widest and the chrome down the right takes 200px, so the moment
   the window drops below about 1005px the panel gets shoved flat against
   the left edge of the screen and its top right corner slides underneath
   the voice/appearance/account pill. 1024px is the first common screen
   width comfortably clear of that. Below it the navigation stops being a
   column on the right and becomes a row across the bottom, the way it
   would be in almost any app on a phone, and the room each screen holds
   open moves from the right edge to the bottom edge to follow it.

   560px — below this it is a phone in the hand rather than a small window
   on a desk. Type comes down, the generous desktop padding comes in, and
   the row of controls under the message box is tightened so that the box
   itself keeps a usable share of the width.

   400px — the oldest phones still in circulation, and a single correction
   rather than a layout of its own. It is explained where it appears at the
   very bottom of this file.
   ================================================================== */

@media (max-width: 1023px) {
  /* Room held open moves from the right edge to the bottom edge, and a
     little is added at the top for the settings pill in the corner, which
     on a narrow screen sits over the panel rather than clear of it.
     Reading clockwise: 74px at the top for the settings pill, 14px of
     breathing room at the sides, 134px at the bottom for the navigation
     bar with the footer's single crisis line resting just above it. */
  :root {
    --chrome-room: 74px 14px 134px 14px;
  }

  /* The navigation: a column standing against the right edge becomes a row
     lying across the bottom. Stretching it between left and right rather
     than giving it a fixed width lets the six buttons space themselves out,
     so it still fits on the narrowest phone in common use. The 420px ceiling
     stops it from becoming a very long thin bar with the buttons stranded
     far apart on a wider screen — past that width it settles into a centred
     pill instead of spreading to the edges. */
  .main-nav {
    top: auto;
    bottom: 12px;
    left: 14px;
    right: 14px;
    max-width: 420px;
    margin-inline: auto;
    transform: none;
    flex-direction: row;
    justify-content: space-between;
  }

  /* Each navigation button's little name label normally drops downward. Now
     that the buttons sit at the very bottom of the screen, downward is off
     the edge, so for this bar the labels rise instead. Only the bottom bar
     is changed — the settings pill in the top corner still has room below
     it and keeps pointing down. */
  .main-nav .nav-tooltip {
    top: auto;
    bottom: 100%;
    margin-top: 0;
    margin-bottom: 8px;
    transform: translateX(-50%) translateY(-2px);
  }

  .main-nav .nav-btn:hover .nav-tooltip,
  .main-nav .nav-btn:focus-visible .nav-tooltip {
    transform: translateX(-50%) translateY(0);
  }

  /* The settings pill moves in tighter to the corner so it takes less of the
     screen away from the panel underneath it. */
  .voice-settings-nav {
    top: 10px;
    right: 10px;
  }

  /* The `:not()` matters. Shrinking every button in this pill to a 40px circle
     would also shrink the account button, which is the one button here that is
     not a circle — it has a word inside it. Squeezing it back to 40px wide
     clipped "Log in" down to about one and a half letters, which is worse than
     no label at all. So the round ones get smaller and the labelled one keeps
     its width, losing a little height and padding instead. */
  .voice-settings-nav .nav-btn:not(.nav-btn-labelled) {
    width: 40px;
    height: 40px;
  }

  .voice-settings-nav .nav-btn-labelled {
    height: 40px;
    gap: 6px;
    padding: 0 12px 0 10px;
  }

  .voice-settings-nav .nav-btn-label {
    font-size: 0.82rem;
  }

  /* The footer has to leave a clear strip along the bottom for the navigation
     bar that floats above it, so the crisis line never ends up behind the
     buttons. The bar itself only needs 76px of that strip; the rest is
     deliberate breathing room, because text that stops a hair's breadth above
     a row of buttons reads as crowded even when nothing is technically
     overlapping. */
  .app-footer {
    padding: 8px 16px 92px;
  }

  /* The panel now fills whatever room is left over once the chrome has taken
     its share, instead of asking for a fraction of the whole window and then
     being squeezed into far less. This is the rule that actually undoes the
     one-word-per-line wrapping: give the panel the width it is owed and the
     text inside it has somewhere to go.

     The 720px ceiling from the desktop layout is kept, because a line of text
     much wider than that is tiring to read — the eye loses its place coming
     back to the start of the next line. On a phone this ceiling never comes
     into play and the panel simply fills the screen; on a tablet held upright
     it keeps the conversation to a comfortable column. */
  .chat-shell {
    width: min(720px, 100%);
    height: 100%;
  }

  .voice-pref-welcome {
    max-height: 100%;
  }
}

@media (max-width: 560px) {
  /* Very nearly the same as the range above. "In crisis? Call or text 988."
     stays on one line at every width down to 320px, so unlike the long
     disclaimer this replaced, the space it needs no longer grows as the
     screen narrows. */
  :root {
    --chrome-room: 76px 10px 132px 10px;
  }

  /* Every size in this file is written as a multiple of this one number, so
     bringing it down gently scales the whole app at once — headings, body
     text, buttons, spacing — rather than requiring each to be listed
     separately. 18.5px suits a screen an arm's length away; on a phone held
     at reading distance it runs large and pushes everything into overflow. */
  html {
    font-size: 16.5px;
  }

  .welcome {
    padding: 30px 22px;
    border-radius: 22px;
  }

  /* The opening line is the one piece of type big enough to need its own
     adjustment — proportionally it is far larger than anything else, so the
     overall reduction above is not enough on its own. */
  .line-1 {
    font-size: 2rem;
    margin-bottom: 16px;
  }

  .line-2 {
    margin-bottom: 34px;
  }

  .messages {
    padding: 18px 14px;
    gap: 12px;
  }

  /* The closing letter is the tallest single block in the practice, and the
     two doors below it are pinned, so every pixel the frame gives back is a
     pixel less scrolling through the last thing the app says. */
  .flow-letter {
    padding: 16px 16px;
    margin-top: 6px;
  }

  .flow-letter p {
    margin-bottom: 11px;
  }

  /* Message bubbles may take a little more of the width here. The 78% of a
     wide panel that reads as a comfortable margin becomes wasted space when
     the panel is only a phone wide. */
  .bubble {
    max-width: 88%;
    padding: 12px 15px;
  }

  /* The row under the message box holds the box itself plus three round
     buttons — microphone, conversation mode, send. Those three never shrink,
     so on a narrow screen they took the width first and left the message box
     with thirty pixels, with the send button pushed past the edge of the
     panel and clipped in half. Trimming the buttons and closing up the gaps
     hands the leftover width back to the box, which is the part that
     actually needs it. */
  .chat-form {
    padding: 10px 12px;
    gap: 6px;
  }

  .mic-btn,
  .send-btn {
    width: 38px;
    height: 38px;
  }

  .mic-btn svg {
    width: 17px;
    height: 17px;
  }

  /* Even with the buttons trimmed, "Share what's on your mind..." is a whole
     sentence and will not sit on one line across a phone — it needs about
     220px and there are about 170px to give it, and shrinking the type enough
     to fit would make it too small to read comfortably. So the box is simply
     given the height of two lines to start with. The invitation is then shown
     in full rather than cut off halfway through, and there is more room to
     write in besides. It still grows from there as someone types. */
  .chat-input {
    min-height: 66px;
  }

  .card-shell {
    padding: 22px 16px;
  }

  .emotions-flow {
    gap: 18px;
  }

  .emotions-grid {
    gap: 8px;
  }

  .emotion-btn {
    padding: 14px 10px;
  }

  /* The three palette choices each carry a name and a description, so they
     are given a full row apiece rather than being squeezed side by side
     where the descriptions would break into narrow stacks of single words. */
  .color-pref-btn {
    flex: 1 1 100%;
    flex-direction: row;
    justify-content: flex-start;
    gap: 14px;
    padding: 14px 16px;
  }

  .color-pref-desc {
    text-align: left;
  }

  .color-pref-swatch {
    width: 34px;
    height: 34px;
    flex-shrink: 0;
  }

  /* A 200px floor on this button was wider than the space it had to sit in
     once the card's own padding was taken off a phone-width screen. */
  .flow-continue-btn {
    min-width: 0;
  }

  /* This note carries a full sentence explaining why voice input is
     unavailable. A fixed 200px was chosen for a wide screen; letting it
     size itself to the space available reads better on a phone. */
  .voice-fallback-note {
    width: auto;
    max-width: 78vw;
  }

  .account-modal-card {
    width: min(380px, 92vw);
    padding: 28px 18px 22px;
  }

  .app-footer {
    padding: 8px 12px 92px;
  }
}

/* The oldest and smallest phones still in circulation — a first-generation SE
   is 320px across. Only one thing actually breaks between here and 375px, so
   this is a single correction rather than another whole layout.

   "Share what's on your mind..." needs two lines to fit on a 375px phone and
   three on a 320px one, so the two-line message box set above cuts the
   invitation off partway through the last word. Someone arriving at a blank
   conversation for the first time reads that box to find out what this is for;
   a sentence that stops mid-air is a poor welcome. Three lines is the height
   at which the whole invitation is visible on the narrowest screen anyone is
   likely to bring. It costs a little of the space where messages appear, which
   on a screen this small is a real trade — but the box grows as someone types
   either way, and an unreadable prompt is the worse of the two problems. */
@media (max-width: 400px) {
  .chat-input {
    min-height: 88px;
  }
}
