:root {
  /* Grounds: Elias Gardens and Grounds green on warm paper (George picked it, 4 Nov). */
  --bg: #f6f4ee;
  --bar: #f6f4ee;
  --line: #e2ded2;
  --text: #1d2620;
  --muted: #7d867f;
  --me: #2f7a4d;
  --me-text: #ffffff;
  --them: #ffffff;
  --them-text: #1d2620;
  --card: #ffffff;
  --accent: #2f7a4d;
  --brand: #1f5134;
  --brand-text: #ffffff;
  --brand-soft: #e8efe6;
  --shadow: 0 1px 2px rgba(40, 50, 30, 0.08);
  --danger: #c0262d;
  /* Plus Jakarta Sans throughout (George picked option B, 4 Nov); the name uses the bold weight. */
  --display: "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-family: "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, sans-serif;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #101511;
    --bar: #101511;
    --line: #26302a;
    --text: #e8eee9;
    --muted: #8d988f;
    --them: #19211b;
    --them-text: #e8eee9;
    --card: #19211b;
    --accent: #46b06e;
    --brand: #173d27;
    --brand-soft: #1d2b21;
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
    --danger: #ff6961;
  }
}
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; background: var(--bg); color: var(--text); }
body { -webkit-text-size-adjust: 100%; }
[hidden] { display: none !important; }
/* Sized to the visual viewport (set from app.js), so that with the iPhone keyboard up the
   header, the newest messages and the message box all sit in the part of the screen that
   is still visible, instead of the bottom of the chat hiding behind the keyboard. */
.screen {
  position: fixed; left: 0; right: 0; top: var(--app-top, 0px); height: var(--app-height, 100%);
  display: flex; flex-direction: column;
}

.bar {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  padding: calc(env(safe-area-inset-top) + 6px) 12px 8px;
  background: var(--bar); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  border-bottom: 0.5px solid var(--line); z-index: 2;
}
.bar-btn { background: none; border: 0; color: var(--me); font-size: 16px; padding: 6px 0; cursor: pointer; }
.bar-btn:first-child { justify-self: start; }
.bar-btn:last-child { justify-self: end; }
.who { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.avatar { width: 40px; height: 40px; border-radius: 50%; }
.who-name { font-size: 12px; color: var(--text); }

/* The typing dots live inside the scrolling area, after the last message, so they push the
   messages up rather than covering the bottom of the last bubble. */
#scroller {
  flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column;
  overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
}
#thread { flex: none; padding: 12px 12px 8px; display: flex; flex-direction: column; gap: 2px; }
#typing { flex: none; }
/* With the keyboard up, the home-indicator gap under the message box isn't needed. */
.keyboard #composer, .keyboard #recorder { padding-bottom: 8px; }
.stamp { align-self: center; color: var(--muted); font-size: 11px; margin: 12px 0 6px; }
.bubble {
  max-width: 78%; padding: 8px 13px; border-radius: 19px; font-size: 16px; line-height: 1.32;
  white-space: pre-wrap; overflow-wrap: anywhere; position: relative;
}
.bubble.me { align-self: flex-end; background: var(--me); color: var(--me-text); }
.bubble.them { align-self: flex-start; background: var(--them); color: var(--them-text); }
.bubble.me + .bubble.them, .bubble.them + .bubble.me { margin-top: 8px; }
.bubble.tail.me { border-bottom-right-radius: 5px; }
.bubble.tail.them { border-bottom-left-radius: 5px; }
.bubble a { color: inherit; }

/* Robin's formatted replies: paragraphs, lists and headings with breathing room. */
.bubble.rich { white-space: normal; line-height: 1.42; padding: 9px 14px; }
.bubble.rich > :first-child { margin-top: 0; }
.bubble.rich > :last-child { margin-bottom: 0; }
.bubble.rich p { margin: 0 0 9px; }
.bubble.rich ul, .bubble.rich ol { margin: 2px 0 10px; padding-left: 20px; }
.bubble.rich li { margin: 0 0 5px; padding-left: 2px; }
.bubble.rich li:last-child { margin-bottom: 0; }
.bubble.rich ul li::marker { color: var(--accent); }
.bubble.rich ol li::marker { color: var(--muted); font-variant-numeric: tabular-nums; }
.bubble.rich .rt-head {
  font-weight: 650; margin: 14px 0 5px; padding-top: 10px;
  border-top: 0.5px solid rgba(127, 127, 127, 0.28);
}
.bubble.rich > .rt-head:first-child { padding-top: 0; border-top: 0; }
.bubble.rich strong { font-weight: 650; }
.bubble.rich code {
  font: 0.9em ui-monospace, SFMono-Regular, Menlo, monospace; padding: 1px 5px; border-radius: 6px;
  background: rgba(127, 127, 127, 0.16);
}
.bubble.rich > br { display: none; }
.bubble.rich .play { display: flex; width: fit-content; margin-top: 8px; }
/* Long replies on wide screens keep a comfortable line length. */
.bubble.them.rich { max-width: min(86%, 620px); }
@media (prefers-color-scheme: dark) { .bubble.rich ul li::marker { color: #34c759; } }

.card {
  align-self: flex-start; max-width: 86%; background: var(--card); border: 0.5px solid var(--line);
  border-radius: 16px; overflow: hidden; margin: 6px 0; flex: none;
}
.card-title { font-size: 13px; color: var(--muted); padding: 10px 14px 0; }
.card-body { padding: 6px 14px 12px; font-size: 15px; white-space: pre-wrap; }
.card-actions { display: flex; border-top: 0.5px solid var(--line); }
.card-actions button {
  flex: 1; background: none; border: 0; padding: 12px 8px; font-size: 16px; color: var(--me); cursor: pointer;
  min-width: 0; line-height: 1.2;
}
.card-actions button:disabled { opacity: 0.5; }
.card-actions button + button { border-left: 0.5px solid var(--line); }
.card-actions button.go { font-weight: 600; }
.card-actions a.go {
  flex: 1; padding: 12px 8px; font-size: 16px; font-weight: 600; line-height: 1.2; text-align: center;
  color: var(--accent, var(--me)); text-decoration: none; min-width: 0;
}
.card-actions a + button, .card-actions button + a { border-left: 0.5px solid var(--line); }
.card-edit {
  display: block; width: calc(100% - 20px); margin: 0 10px 10px; padding: 8px 10px; resize: none;
  border: 1px solid var(--line); border-radius: 12px; font: inherit; font-size: 16px; line-height: 1.35;
  background: var(--bg); color: var(--text);
}
.card-edit:focus { outline: none; border-color: var(--me); }
.card-questions { padding: 0 14px 12px; display: flex; flex-direction: column; gap: 12px; }
.card-q-label { font-size: 15px; font-weight: 600; margin-bottom: 6px; }
.card-q-options { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 6px; }
.card-q-chip {
  border: 1px solid var(--line); background: var(--bg); color: var(--text); border-radius: 999px;
  padding: 7px 12px; font: inherit; font-size: 15px; cursor: pointer; min-height: 36px; max-width: 100%;
  text-align: left;
}
.card-q-chip.is-on { background: var(--accent); border-color: var(--accent); color: #fff; }
.card-q-typed {
  display: block; width: 100%; padding: 8px 10px; border: 1px solid var(--line); border-radius: 12px;
  font: inherit; font-size: 16px; background: var(--bg); color: var(--text);
}
.card-q-typed:focus { outline: none; border-color: var(--accent); }
.bubble.pending { opacity: 0.6; }
.card-done { padding: 10px 14px; font-size: 13px; color: var(--muted); border-top: 0.5px solid var(--line); }

.typing { display: flex; gap: 4px; padding: 12px 14px; margin: 2px 12px 10px; width: fit-content; }
.typing span { width: 8px; height: 8px; border-radius: 50%; background: var(--muted); animation: blink 1.2s infinite; }
.typing span:nth-child(2) { animation-delay: 0.2s; }
.typing span:nth-child(3) { animation-delay: 0.4s; }
.typing.drafting { display: block; white-space: pre-wrap; max-width: 78%; }
@keyframes blink { 0%, 80%, 100% { opacity: 0.3; } 40% { opacity: 1; } }

#composer {
  display: flex; align-items: flex-end; gap: 8px;
  padding: 8px 10px calc(env(safe-area-inset-bottom) + 8px);
  background: var(--bar); border-top: 0.5px solid var(--line);
}
#input {
  flex: 1; resize: none; border: 1px solid var(--line); border-radius: 19px; padding: 8px 14px;
  font: inherit; font-size: 16px; line-height: 1.3; max-height: 140px; background: var(--bg); color: var(--text);
}
#input:focus { outline: none; border-color: var(--muted); }
#send {
  width: 32px; height: 32px; border-radius: 50%; border: 0; background: var(--me); color: #fff;
  display: grid; place-items: center; margin-bottom: 3px; cursor: pointer;
}
#send:disabled { background: var(--line); }
#send svg { width: 18px; height: 18px; }

#mic {
  width: 36px; height: 36px; border-radius: 50%; border: 0; background: none; color: var(--muted);
  display: grid; place-items: center; margin-bottom: 1px; cursor: pointer; flex: none;
}
#mic svg { width: 24px; height: 24px; }
#recorder {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px calc(env(safe-area-inset-bottom) + 8px);
  background: var(--bar); border-top: 0.5px solid var(--line);
}
#rec-cancel, #rec-send {
  width: 40px; height: 40px; border-radius: 50%; border: 0; display: grid; place-items: center;
  cursor: pointer; flex: none;
}
#rec-cancel { background: var(--card); color: var(--text); }
#rec-send { background: var(--me); color: #fff; }
#rec-cancel svg, #rec-send svg { width: 20px; height: 20px; }
.rec-live {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; height: 40px; padding: 0 14px;
  border-radius: 20px; background: var(--bg); border: 1px solid var(--line); font-variant-numeric: tabular-nums;
}
.rec-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--danger); animation: blink 1.2s infinite; flex: none; }
.rec-hint { color: var(--muted); font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.play {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 6px; padding: 5px 12px 5px 10px;
  border-radius: 14px; border: 0; font: inherit; font-size: 14px; cursor: pointer;
  background: rgba(127, 127, 127, 0.18); color: inherit;
}
.play[aria-pressed="true"] { background: rgba(127, 127, 127, 0.32); }
.bubble .voice-tag { opacity: 0.8; }

.connections { padding: 4px 14px 10px; }
.conn { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 10px 0; border-top: 0.5px solid var(--line); }
.conn:first-of-type { border-top: 0; }
.conn > span { min-width: 0; overflow-wrap: anywhere; }
.conn small { color: var(--muted); display: block; }
.connections h3 { font-size: 13px; color: var(--muted); font-weight: 500; margin: 10px 0 4px; text-transform: uppercase; }
.conn-btn {
  flex: none; background: var(--me); color: #fff; border: 0; border-radius: 14px; padding: 7px 14px;
  font: inherit; font-size: 15px; text-decoration: none; cursor: pointer;
}
.conn-btn.quiet { background: none; color: var(--me); padding: 7px 0; }
.conn select { font: inherit; font-size: 15px; padding: 6px 8px; border-radius: 10px; border: 1px solid var(--line); background: var(--bg); color: var(--text); }
.connect-note { background: var(--card); border-radius: 12px; padding: 10px 14px; margin: 0 0 12px; font-size: 15px; }

.signin-card {
  margin: auto; text-align: center; padding: 32px 24px; max-width: 360px; width: 100%;
}
.signin-icon { width: 88px; height: 88px; border-radius: 22px; }
.signin-card h1 { margin: 16px 0 4px; font-size: 28px; }
.signin-card p { color: var(--muted); margin: 0 0 28px; }
.primary {
  display: block; background: var(--me); color: #fff; text-decoration: none; padding: 14px; border-radius: 14px;
  font-size: 17px; font-weight: 600;
}
.note { margin-top: 16px !important; color: var(--danger) !important; }

.people-list { flex: 1; overflow-y: auto; padding: 12px 16px calc(env(safe-area-inset-bottom) + 16px); }
.person { background: var(--card); border-radius: 14px; margin-bottom: 14px; overflow: hidden; }
.person summary { padding: 14px; cursor: pointer; list-style: none; display: flex; justify-content: space-between; }
.person summary::-webkit-details-marker { display: none; }
.person .role { color: var(--muted); font-size: 14px; }
.group { padding: 4px 14px 10px; }
.group h3 { font-size: 13px; color: var(--muted); font-weight: 500; margin: 10px 0 4px; text-transform: uppercase; }
.perm { display: flex; justify-content: space-between; align-items: center; padding: 8px 0; border-top: 0.5px solid var(--line); gap: 12px; }
.perm small { color: var(--muted); display: block; }
.switch { appearance: none; width: 51px; height: 31px; border-radius: 16px; background: var(--line); position: relative; cursor: pointer; flex: none; transition: background 0.2s; }
.switch::after { content: ""; position: absolute; top: 2px; left: 2px; width: 27px; height: 27px; border-radius: 50%; background: #fff; transition: transform 0.2s; box-shadow: 0 2px 4px rgba(0,0,0,0.2); }
.switch:checked { background: #34c759; }
.switch:checked::after { transform: translateX(20px); }
.switch:disabled { opacity: 0.5; }

/* Folding phones and tablets.
   Cover screens are narrow (about 340-380px): bubbles may use more of the width.
   Unfolded (about 700-900px) the chat keeps a readable column instead of stretching, and the
   People page sits beside it. When the fold is reported (viewport segments), nothing sits
   across the hinge: the chat stays on one side. */
@media (max-width: 380px) {
  .bubble { max-width: 86%; font-size: 15.5px; }
  .bubble.them.rich { max-width: 92%; }
  .card { max-width: 94%; }
  .card-actions button { font-size: 15px; padding: 12px 6px; }
  .bar { padding-left: 8px; padding-right: 8px; }
  .rec-hint { display: none; }
}
@media (min-width: 640px) {
  #thread, #composer, #recorder, .people-list { padding-left: max(16px, calc((100% - 760px) / 2)); padding-right: max(16px, calc((100% - 760px) / 2)); }
  .bubble { max-width: 70%; }
  .card { max-width: 72%; }
  .typing { margin-left: max(16px, calc((100% - 760px) / 2)); }
}
@media (horizontal-viewport-segments: 2) {
  .screen { right: auto; width: env(viewport-segment-width 0 0, 50%); }
  #thread, #composer, #recorder, .people-list { padding-left: 12px; padding-right: 12px; }
  .bubble { max-width: 80%; }
}
@media (vertical-viewport-segments: 2) {
  /* Laptop-style fold: messages on top, typing on the bottom half. */
  #chat main { flex: none; height: calc(env(viewport-segment-bottom 0 0, 50vh) - 70px); }
  #composer, #recorder { margin-top: auto; }
}

/* ===== Grounds look ======================================================================
   The chat's look on top of the layout above: a green header with a rounded base, warm
   paper behind the chat, garden-green bubbles for you and white ones for Robin, a white
   message box with the mic always in reach, and quick questions above it. */
.bar {
  background: var(--brand); color: var(--brand-text); border-bottom: 0;
  backdrop-filter: none; -webkit-backdrop-filter: none;
  border-radius: 0 0 22px 22px; padding-bottom: 12px;
}
.bar .bar-btn { color: var(--brand-text); }
.bar .who-name { color: var(--brand-text); font-family: var(--display); font-weight: 700; font-size: 17px; }
.chat-bar { display: flex; gap: 8px; padding-left: 14px; padding-right: 12px; }
.chat-bar .who { flex: 1; min-width: 0; flex-direction: row; align-items: center; gap: 10px; }
.chat-bar .avatar { width: 38px; height: 38px; border-radius: 50%; background: var(--brand-soft); display: grid; place-items: center; flex: none; overflow: hidden; }
.chat-bar .avatar img { width: 100%; height: 100%; }
.who-text { min-width: 0; }
.chat-bar .who-name { font-size: 18px; line-height: 1.1; }
.who-status { display: flex; align-items: center; gap: 5px; font-size: 12px; color: #cfe3d4; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.who-status i { width: 7px; height: 7px; border-radius: 50%; background: #8fe0a6; flex: none; }
.who-status i.off { background: #f2b366; }
.icon-btn {
  width: 38px; height: 38px; border-radius: 50%; border: 0; display: grid; place-items: center; flex: none;
  background: rgba(255, 255, 255, 0.14); color: var(--brand-text); cursor: pointer;
}
.icon-btn svg { width: 20px; height: 20px; }
.icon-btn:active { background: rgba(255, 255, 255, 0.26); }
.icon-btn:focus-visible, .chips button:focus-visible, #mic:focus-visible, #send:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.stamp { color: var(--muted); }
.bubble { border-radius: 20px; }
.bubble.me { margin-top: 2px; }
.bubble.them { box-shadow: var(--shadow); }
.bubble.tail.me { border-bottom-right-radius: 6px; }
.bubble.tail.them { border-bottom-left-radius: 6px; }
.bubble.me + .bubble.them, .bubble.them + .bubble.me, .card + .bubble, .bubble + .card { margin-top: 10px; }
.bubble.rich ul li::marker { color: var(--accent); }
.bubble.me a { color: #fff; }
.typing { background: var(--them); box-shadow: var(--shadow); border-radius: 18px 18px 18px 6px; }
.typing span { background: var(--accent); }
.typing.drafting { border-radius: 20px 20px 20px 6px; }

.card { background: var(--card); border-color: var(--line); border-radius: 18px; box-shadow: var(--shadow); }
.card-actions button, .card-progress { color: var(--accent); }
.card-progress { background: var(--accent); }
.card-actions button.is-busy::after { border-color: var(--accent); border-right-color: transparent; }
.card-edit:focus { border-color: var(--accent); }

/* Quick questions: shown while the message box is empty; one tap asks Robin. */
.chips { display: flex; gap: 6px; overflow-x: auto; padding: 4px 10px 2px; background: var(--bg); scrollbar-width: none; flex: none; }
.chips::-webkit-scrollbar { display: none; }
.chips button {
  flex: none; border: 0; border-radius: 999px; padding: 7px 12px; font: inherit; font-size: 14px;
  background: var(--brand-soft); color: var(--accent); cursor: pointer;
}
.chips button:active { filter: brightness(0.95); }
.chips.is-new { animation: rw-fade-in 200ms var(--ease-out, ease) both; }
.chips:empty { display: none; }

#composer, #recorder { background: var(--bg); border-top: 0; padding-top: 6px; }
#input { background: var(--card); border: 0; box-shadow: var(--shadow), 0 0 0 1px var(--line); border-radius: 22px; padding: 9px 15px; }
#input:focus { box-shadow: var(--shadow), 0 0 0 1.5px var(--accent); }
#send { width: 36px; height: 36px; background: var(--accent); margin-bottom: 1px; }
#send:disabled { background: var(--line); }
#mic { width: 36px; height: 36px; background: var(--accent); color: #fff; margin-bottom: 1px; }
#mic svg { width: 20px; height: 20px; }
#talk-btn {
  width: 36px; height: 36px; border-radius: 50%; border: 0; flex: none; cursor: pointer;
  display: grid; place-items: center; margin-bottom: 1px;
  background: var(--card); color: var(--accent); box-shadow: var(--shadow), 0 0 0 1px var(--line);
}
#talk-btn svg { width: 20px; height: 20px; }
#talk-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.rec-live { background: var(--card); border: 0; box-shadow: var(--shadow), 0 0 0 1px var(--line); }
#rec-send { background: var(--accent); }
#rec-cancel { background: var(--card); box-shadow: var(--shadow), 0 0 0 1px var(--line); }
.jump { color: var(--accent); background: var(--card); }
.earlier { flex: none; align-self: center; margin: 12px auto 0; padding: 7px 14px; border: 0; border-radius: 999px; font: inherit; font-size: 13px; color: var(--accent); background: var(--card); cursor: pointer; }
.earlier:disabled { opacity: .6; }

.person, .connect-note { background: var(--card); box-shadow: var(--shadow); }
.conn-btn { background: var(--accent); }
.conn-btn.quiet { background: none; color: var(--accent); }
.switch:checked { background: var(--accent); }

#signin { background: var(--bg); }
.signin-card h1 { font-family: var(--display); font-weight: 700; }
.primary { background: var(--brand); }

@media (min-width: 640px) {
  .chips { padding-left: max(16px, calc((100% - 760px) / 2)); padding-right: max(16px, calc((100% - 760px) / 2)); }
}

/* ===== Motion ============================================================================
   Everything that moves lives in this block, keyed off class names (.card, .card-actions,
   .card-done and the modifiers app.js adds), so the look of the cards can change without
   touching it. Only transform and opacity are animated, so it stays smooth on a folding
   phone's cover screen and never fights the unfolded layout. Reduce Motion turns it into
   short fades at the end of the block. */
:root {
  --spring: cubic-bezier(0.2, 0.9, 0.3, 1.18);
  --ease-out: cubic-bezier(0.25, 0.8, 0.25, 1);
  --ok: #1f9d55;
}
@media (prefers-color-scheme: dark) { :root { --ok: #34c759; } }

/* Messages: yours lifts off the message box, Robin's fades up from the left. */
.bubble.me { transform-origin: 100% 100%; }
.bubble.them { transform-origin: 0 100%; }
.bubble.me.is-new { animation: rw-send-in 380ms var(--spring) both; }
.bubble.them.is-new { animation: rw-them-in 300ms var(--ease-out) both; }
.bubble.me.sending { opacity: 0.85; }
.bubble.me.failed { opacity: 0.6; cursor: pointer; margin-bottom: 18px; position: relative; }
.bubble.me.failed::after {
  content: "Not sent · Tap to try again"; position: absolute; right: 2px; top: 100%; margin-top: 3px;
  font-size: 12px; color: var(--danger); white-space: nowrap;
}
@keyframes rw-send-in { from { opacity: 0; transform: translateY(26px) scale(0.86); } 60% { opacity: 1; } }
@keyframes rw-them-in { from { opacity: 0; transform: translateY(8px) scale(0.94); } }
@keyframes rw-fade-in { from { opacity: 0; } }

/* The mic and the send arrow swap with a quick turn. */
#send.is-new, #mic.is-new { animation: rw-swap 220ms var(--ease-out); }
@keyframes rw-swap { from { opacity: 0; transform: scale(0.4) rotate(-40deg); } }

/* Typing: the dots ripple, the bubble grows in from its corner and shrinks away. */
.typing span { opacity: 0.45; animation: rw-wave 1.1s ease-in-out infinite; }
.typing span:nth-child(2) { animation-delay: 0.14s; }
.typing span:nth-child(3) { animation-delay: 0.28s; }
@keyframes rw-wave { 0%, 60%, 100% { transform: none; opacity: 0.45; } 30% { transform: translateY(-4px); opacity: 1; } }
#typing { transform-origin: 0 100%; }
#typing.is-new { animation: rw-them-in 240ms var(--spring) both; }
#typing.is-leaving { animation: rw-pop-out 160ms var(--ease-out) both; }
@keyframes rw-pop-out { to { opacity: 0; transform: scale(0.8); } }
/* Words as they're written: each new piece fades in. */
.typing.drafting { overflow: hidden; }
.typing.drafting span.words {
  width: auto; height: auto; border-radius: 0; background: none; opacity: 1;
  animation: rw-words 340ms var(--ease-out) both; animation-delay: 0s;
}
@keyframes rw-words { from { opacity: 0; filter: blur(3px); } }

/* Cards slide up into the chat. */
.card { position: relative; transform-origin: 0 100%; }
.card.is-new { animation: rw-card-in 420ms var(--spring) both; }
@keyframes rw-card-in { from { opacity: 0; transform: translateY(16px) scale(0.96); } }
.card-fold { display: grid; grid-template-rows: 1fr; transition: grid-template-rows 360ms var(--ease-out), opacity 260ms; }
.card-fold-inner { overflow: hidden; min-height: 0; }
/* Finished cards fold down to their result line; tapping the line opens them again. */
.card--done .card-fold { grid-template-rows: 0fr; opacity: 0; }
.card--done.card--peek .card-fold, .card--done.card--closing .card-fold { grid-template-rows: 1fr; opacity: 1; }
.card--done .card-done {
  display: flex; align-items: center; gap: 8px; width: 100%; margin: 0; background: none; border: 0;
  border-top: 0.5px solid var(--line); font: inherit; font-size: 13.5px; text-align: left; cursor: pointer;
}
.card--done:not(.card--peek) .card-done { border-top-color: transparent; }
.card--send .card-done, .card--save .card-done, .card--confirm .card-done { color: var(--text); }
.card--skipped { opacity: 0.62; transition: opacity 300ms; }
.card-tick {
  width: 20px; height: 20px; flex: none; border-radius: 50%; display: grid; place-items: center;
  background: var(--ok); color: #fff;
}
.card-tick svg { width: 12px; height: 12px; }
.card-tick path { stroke-dasharray: 20; stroke-dashoffset: 0; }
.card--save .card-tick { background: var(--me); }
.card--skipped .card-tick { background: none; border: 1.5px solid var(--muted); width: 14px; height: 14px; margin: 0 3px; }
.card--just-done .card-done { animation: rw-them-in 280ms var(--ease-out) both; }
.card--just-done .card-tick { animation: rw-pop 380ms var(--spring) both 80ms; }
.card--just-done .card-tick path { animation: rw-draw 300ms var(--ease-out) both 220ms; }
.card--just-done.card--send { animation: rw-glow 900ms var(--ease-out); }
@keyframes rw-pop { from { transform: scale(0); } }
@keyframes rw-draw { from { stroke-dashoffset: 20; } }
@keyframes rw-glow { from { box-shadow: 0 0 0 0 rgba(52, 199, 89, 0.5); } to { box-shadow: 0 0 0 10px rgba(52, 199, 89, 0); } }
/* While a tap is being answered: a spinner on that button and a thin bar along the top. */
.card-progress { position: absolute; left: 0; top: 0; height: 2px; width: 0; background: var(--me); pointer-events: none; }
.card--sending .card-progress { animation: rw-progress 1.6s var(--ease-out) forwards; }
@keyframes rw-progress { to { width: 85%; } }
.card-actions button { position: relative; }
.card-actions button.is-busy:disabled { opacity: 1; color: transparent; }
.card-actions button.is-busy::after {
  content: ""; position: absolute; inset: 0; margin: auto; width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid var(--me); border-right-color: transparent; animation: rw-spin 700ms linear infinite;
}
@keyframes rw-spin { to { transform: rotate(360deg); } }
/* It didn't go through: a small shake, and the card stays open. */
.card.is-shaking { animation: rw-shake 360ms var(--ease-out); }
@keyframes rw-shake {
  20% { transform: translateX(-6px); } 40% { transform: translateX(5px); }
  60% { transform: translateX(-3px); } 80% { transform: translateX(2px); }
}
.card-note { color: var(--danger); font-size: 13px; padding: 0 14px 10px; }
.card-edit.is-new { animation: rw-fade-in 200ms var(--ease-out) both; }

/* Voice notes: the recorder slides up, bars follow your voice, and the note shimmers while
   it's turned into words. Robin's spoken reply fills its button as it plays. */
#recorder.is-new { animation: rw-slide-up 280ms var(--spring) both; }
#composer.is-new { animation: rw-fade-in 200ms var(--ease-out) both; }
@keyframes rw-slide-up { from { opacity: 0; transform: translateY(100%); } }
.rec-dot { animation: rw-breathe 1.4s ease-in-out infinite; }
@keyframes rw-breathe { 50% { transform: scale(0.7); opacity: 0.5; } }
.rec-bars { flex: 1; min-width: 0; height: 22px; display: flex; align-items: center; justify-content: flex-end; gap: 2px; overflow: hidden; }
.rec-bars i { width: 3px; flex: none; border-radius: 2px; background: var(--muted); animation: rw-bar-in 120ms linear both; transform-origin: center; }
@keyframes rw-bar-in { from { transform: scaleY(0.2); } }
.rec-live:has(.rec-bars:not(:empty)) .rec-hint { display: none; }
.voice-pending { display: flex; flex-direction: column; gap: 8px; }
.bubble.pending.voice-pending { opacity: 1; }
.voice-wave { display: flex; align-items: center; gap: 2px; height: 22px; }
.voice-wave i { width: 3px; border-radius: 2px; background: rgba(255, 255, 255, 0.85); }
.voice-shimmer {
  display: block; height: 9px; width: 70%; border-radius: 5px;
  background: linear-gradient(90deg, rgba(255,255,255,.2) 0%, rgba(255,255,255,.55) 50%, rgba(255,255,255,.2) 100%);
  background-size: 200% 100%; animation: rw-shimmer 1.1s linear infinite;
}
@keyframes rw-shimmer { from { background-position: 200% 0; } to { background-position: 0 0; } }
.play, .play[aria-pressed="true"] {
  background: linear-gradient(90deg, rgba(127,127,127,.38) var(--played, 0%), rgba(127,127,127,.18) var(--played, 0%));
}

/* Scrolled up when something new comes in: a pill to take you down. It sits over the bottom
   of the chat without taking any room. */
.jump-wrap { position: sticky; bottom: 10px; height: 0; flex: none; display: flex; align-items: flex-start; justify-content: center; overflow: visible; z-index: 2; }
.jump {
  flex: none; white-space: nowrap;
  transform: translateY(-100%); border: 0.5px solid var(--line); border-radius: 999px; padding: 7px 14px;
  background: var(--bg); color: var(--me); font: inherit; font-size: 14px; font-weight: 500; cursor: pointer;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.16);
}
.jump.is-new { animation: rw-jump-in 360ms var(--spring) both; }
@keyframes rw-jump-in { from { opacity: 0; transform: translateY(-40%) scale(0.9); } }

/* Chat and People slide across. */
.screen-push-in, .screen-pop-out { z-index: 3; background: var(--bg); box-shadow: -8px 0 24px rgba(0, 0, 0, 0.12); }
.screen-push-in { animation: rw-from-right 360ms var(--ease-out) both; }
.screen-push-out { animation: rw-to-left 360ms var(--ease-out) both; }
.screen-pop-in { animation: rw-from-left 360ms var(--ease-out) both; }
.screen-pop-out { animation: rw-to-right 360ms var(--ease-out) both; }
@keyframes rw-from-right { from { transform: translateX(100%); } }
@keyframes rw-to-left { to { transform: translateX(-25%); opacity: 0.6; } }
@keyframes rw-from-left { from { transform: translateX(-25%); opacity: 0.6; } }
@keyframes rw-to-right { to { transform: translateX(100%); } }
.screen-push-in .person { animation: rw-them-in 320ms var(--ease-out) both 120ms; }

/* Reduce Motion: nothing slides, bounces or spins; things that arrive fade in quickly. */
@media (prefers-reduced-motion: reduce) {
  .is-new, #typing.is-new, .bubble.me.is-new, .bubble.them.is-new, .card.is-new, .jump.is-new,
  #recorder.is-new { animation: rw-fade-in 160ms linear both; }
  #send.is-new, #mic.is-new, .rec-bars i, .screen-push-in .person, .card--just-done .card-done,
  .card--just-done .card-tick, .card--just-done .card-tick path, .card--just-done.card--send,
  .card.is-shaking, #typing.is-leaving, .typing.drafting span.words { animation: none; }
  .typing span, .rec-dot { animation: none; opacity: 0.6; }
  .voice-shimmer { animation: none; background: rgba(255, 255, 255, 0.35); }
  .card--sending .card-progress { animation: none; width: 85%; opacity: 0.5; }
  .card-actions button.is-busy::after { animation-duration: 1.6s; }
  .card-fold, .card--skipped { transition: none; }
}

/* Receipts and bills: the paperclip, the photo or PDF in the chat, and the expense card's
   form when its details are being corrected. */
#attach {
  width: 36px; height: 36px; border-radius: 50%; border: 0; background: none; color: var(--muted);
  display: grid; place-items: center; margin-bottom: 1px; cursor: pointer; flex: none; padding: 0;
}
#attach svg { width: 22px; height: 22px; }
#attach:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.bubble.file { padding: 4px; background: var(--me); }
.bubble.file .file-img {
  display: block; max-width: min(240px, 100%); max-height: 320px; border-radius: 16px; cursor: zoom-in;
  background: var(--brand-soft);
}
.bubble.file .file-caption { padding: 6px 10px 4px; white-space: pre-wrap; }
.bubble.file.failed { opacity: 0.75; }
.bubble.file.failed .file-caption:last-child { font-size: 13px; }
.file-chip {
  display: flex; align-items: center; gap: 10px; padding: 8px 12px 8px 8px; border-radius: 16px;
  background: rgba(255, 255, 255, 0.16); color: inherit; text-decoration: none; max-width: 260px;
}
.file-icon {
  flex: none; width: 34px; height: 40px; border-radius: 6px; background: #fff; color: var(--danger);
  display: grid; place-items: center; font-size: 11px; font-weight: 700; letter-spacing: 0.02em;
}
.file-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 15px; }
.receipt-form { display: grid; gap: 8px; padding: 8px 12px 12px; }
.rf-row { display: grid; gap: 3px; font-size: 12.5px; color: var(--muted); }
.rf-row input, .rf-row select {
  width: 100%; min-width: 0; padding: 8px 10px; border: 1px solid var(--line); border-radius: 10px;
  font: inherit; font-size: 16px; color: var(--text); background: var(--bg); -webkit-appearance: none;
  appearance: none;
}
.rf-row select {
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%),
    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 16px) 55%, calc(100% - 11px) 55%;
  background-size: 5px 5px; background-repeat: no-repeat; padding-right: 28px;
}
.rf-row input:focus, .rf-row select:focus { outline: none; border-color: var(--accent); }
.receipt-form.is-new { animation: rw-fade-in 200ms var(--ease-out) both; }
/* On a wide screen (an unfolded phone, a tablet) the short fields sit two to a row. */
@media (min-width: 560px) {
  .receipt-form { grid-template-columns: 1fr 1fr; column-gap: 10px; }
  .rf-row:nth-child(1), .rf-row:nth-child(6), .rf-row:nth-child(9) { grid-column: 1 / -1; }
}
.card--file .card-done { color: var(--text); }
@media (prefers-reduced-motion: reduce) { .receipt-form.is-new { animation: none; } }
/* ===== Needs you =========================================================================
   The list of what needs George (needs.py): a round button with an urgent-only badge in
   the chat header, a screen with Urgent / Today / a folded This week, and the round-up
   cards in the chat. Uses the Grounds tokens: --accent green, --card white, --danger red. */
.needs-btn { position: relative; }
.needs-badge {
  position: absolute; top: -3px; right: -3px; min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: 9px; background: var(--danger); color: #fff; font-size: 11px; font-weight: 700;
  line-height: 18px; text-align: center; box-shadow: 0 0 0 2px var(--brand);
}
.needs-sub { font-size: 12px; color: #cfe3d4; }
.needs-main {
  flex: 1; overflow-y: auto; padding: 12px 16px calc(env(safe-area-inset-bottom) + 20px);
  display: flex; flex-direction: column; gap: 6px;
}
#needs-list { display: flex; flex-direction: column; gap: 14px; }
.needs-group { display: flex; flex-direction: column; }
.needs-head {
  margin: 0 0 2px; font-size: 12px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted); display: flex; align-items: center; gap: 8px;
}
.needs-head::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--accent); flex: none; }
.needs-group--urgent .needs-head { color: var(--danger); }
.needs-group--urgent .needs-head::before { background: var(--danger); }
.needs-group--week .needs-head { cursor: pointer; list-style: none; padding: 8px 0; }
.needs-group--week .needs-head::-webkit-details-marker { display: none; }
.needs-group--week .needs-head::before { background: var(--muted); }
.needs-group--week:not([open]) .needs-head::after { content: "▸"; }
.needs-group--week[open] .needs-head::after { content: "▾"; }
#needs-list .card { max-width: none; width: 100%; align-self: stretch; }
#needs-list .card--urgent { border-color: var(--danger); box-shadow: inset 3px 0 0 var(--danger); }
#needs-list .card--urgent .card-title { color: var(--danger); font-weight: 600; }
.needs-empty { color: var(--muted); text-align: center; margin: 48px 12px; font-size: 15px; line-height: 1.45; }
.needs-push {
  display: flex; align-items: center; gap: 12px; background: var(--card); border: 0.5px solid var(--line);
  border-radius: 14px; padding: 10px 12px; font-size: 14px; color: var(--text); margin-bottom: 6px;
}
.needs-push span { flex: 1; }
.needs-push button {
  flex: none; background: var(--accent); color: #fff; border: 0; border-radius: 999px; padding: 7px 14px;
  font: inherit; font-weight: 600; cursor: pointer;
}
.needs-push button.quiet { background: none; color: var(--accent); padding: 7px 4px; }

.card.roundup { padding-bottom: 4px; }
.roundup-chips { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 14px 2px; }
.roundup-chip { font-size: 13px; font-weight: 600; padding: 3px 9px; border-radius: 999px; background: var(--brand-soft); color: var(--accent); }
.roundup-chip--urgent { background: color-mix(in srgb, var(--danger) 14%, transparent); color: var(--danger); }
.roundup-chip--done { background: none; color: var(--muted); font-weight: 500; padding-left: 2px; }
.roundup-fyi { margin: 6px 0 0; padding: 0 14px 0 32px; font-size: 14px; color: var(--muted); }
.roundup-fyi li { margin: 2px 0; }
.roundup-open {
  display: block; background: none; border: 0; color: var(--accent); font: inherit; font-size: 15px;
  font-weight: 600; padding: 8px 14px 8px; cursor: pointer;
}
@media (min-width: 640px) {
  .needs-main { align-items: center; }
  .needs-main > * { width: min(100%, 640px); }
}
#needs-list .card-title { display: flex; align-items: center; gap: 8px; }
#needs-list .card-title > span { flex: 1; min-width: 0; }
.card-later {
  flex: none; background: var(--brand-soft); color: var(--accent); border: 0; border-radius: 999px;
  font: inherit; font-size: 13px; font-weight: 600; padding: 4px 10px; cursor: pointer;
}
.card-later:disabled { opacity: 0.5; }

/* --- Talk mode: a live spoken conversation (talk.py) ------------------------------------ */
/* One full screen over the chat: big words, one big End button, so it can be used from a
   dash mount at a glance, folded or open. */
.talk {
  position: fixed; inset: 0; z-index: 20;
  display: flex; flex-direction: column; align-items: center; justify-content: space-between;
  padding: calc(env(safe-area-inset-top) + 28px) 20px calc(env(safe-area-inset-bottom) + 28px);
  background: var(--brand); color: var(--brand-text); text-align: center;
}
.talk-top { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.talk-top .avatar { width: 56px; height: 56px; }
.talk-top .avatar img { width: 100%; height: 100%; }
.talk-name { font-family: var(--display); font-size: 26px; font-weight: 700; }
.talk-state { font-size: 16px; opacity: 0.8; min-height: 1.3em; }
/* The live waveform: your voice while listening, Robin's while it talks, a slow ripple while
   it thinks. Drawn on a canvas by app.js (drawWave). */
.talk-wave { width: min(100%, 420px); height: 140px; flex: none; }
@keyframes rw-talk-breathe { 50% { transform: scale(1.1); } }
.talk-words { width: 100%; max-width: 560px; display: flex; flex-direction: column; gap: 14px; }
.talk-words p { margin: 0; overflow-wrap: anywhere; }
.talk-you { font-size: 17px; opacity: 0.75; min-height: 1.4em; }
.talk-rowan { font-size: 22px; line-height: 1.35; min-height: 2.7em; }
.talk-note { margin: 0; font-size: 13px; opacity: 0.65; }
.talk-actions { display: flex; flex-direction: column; align-items: center; gap: 18px; }
.talk-hush {
  background: rgba(255, 255, 255, 0.16); color: inherit; border: 0; border-radius: 999px;
  padding: 12px 22px; font-size: 16px; cursor: pointer;
}
.talk-actions .talk-hush[hidden] { display: none; }
/* A talk carrying on while the chat is shown ("show me"): a bar under the header leads back. */
.talk-bar {
  display: flex; align-items: center; gap: 10px; width: 100%; flex: none;
  padding: 9px 16px; border: 0; cursor: pointer; font: inherit; font-size: 15px; text-align: left;
  background: var(--brand); color: var(--brand-text);
}
.talk-bar[hidden] { display: none; }
.talk-bar i { width: 9px; height: 9px; border-radius: 50%; background: #7ee08a; flex: none; animation: rw-talk-pulse 1.6s ease-in-out infinite; }
.talk-bar span { flex: 1; opacity: 0.9; }
.talk-bar b { font-weight: 600; }
@keyframes rw-talk-pulse { 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) { .talk-bar i { animation: none; } }
.talk-end {
  width: 76px; height: 76px; border-radius: 50%; border: 0; cursor: pointer;
  background: #d93a3f; color: #fff; display: grid; place-items: center;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.25);
}
.talk-end svg { width: 30px; height: 30px; }
.talk-end:focus-visible, .talk-hush:focus-visible { outline: 3px solid #fff; outline-offset: 3px; }
@media (max-height: 560px) {
  .talk-top .avatar { display: none; }
  .talk-wave { height: 84px; }
}
