*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent;}
:root{
  /* ── Palette ────────────────────────────────────────────────────────
     Five hues, each as a ladder mixed toward white and black so every
     surface, border and text colour is derived rather than invented.

     Cool hues carry the whole interface; warm appears in exactly two
     places (see the amber note below).

     Every fill is FLAT. No gradients anywhere in this file — colour
     transitions are the house style of AI products, and this is meant to
     read as a clinical tool.

     Cards are separated by a BORDER, never a shadow. Doing both is the
     usual giveaway of a mockup. Shadow is reserved for things that
     genuinely float above the page: the modal sheet, the toast, and the
     controls that sit on top of them.                                   */

  --lavender-50:#F9F8FB;  --lavender-100:#F4F1F6; --lavender-200:#E7E0ED;
  --lavender-300:#D4C9DF; --lavender-500:#B8A5C9; --lavender-700:#81748D;

  --purple-50:#F4F2F7;  --purple-100:#EAE5EF; --purple-200:#D2C8DD;
  --purple-300:#B09EC3; --purple-500:#7B5E9B; --purple-600:#6A5185;
  --purple-700:#56426C; --purple-800:#423354;

  --peri-50:#F6F9FD;  --peri-100:#EDF2FA; --peri-200:#D9E4F5;
  --peri-300:#BCCFEE; --peri-500:#90AFE2; --peri-600:#7C96C2;
  --peri-700:#657A9E; --peri-800:#4E5E7A;

  --teal-50:#F1F8F6;  --teal-100:#E3F0EE; --teal-200:#C3E0DA;
  --teal-300:#95C8BE; --teal-500:#4FA492; --teal-600:#448D7E;
  --teal-700:#377366; --teal-800:#2B594F;

  --mint-50:#F9FCFB;  --mint-100:#F2F9F7; --mint-200:#E4F1EE;
  --mint-300:#CFE7E0; --mint-500:#AFD7CC; --mint-700:#7A968F;

  /* ── Semantic roles ──────────────────────────────────────────────── */
  --primary:var(--purple-500);        /* actions, brand            */
  --primary-dark:var(--purple-600);
  --secondary:var(--teal-600);        /* progress, completion      */
  --accent:var(--peri-500);           /* calm, informational       */

  --bg:var(--peri-50);
  --surface:#FFFFFF;
  --surface2:var(--peri-100);
  --border:var(--peri-200);

  /* 14.9:1 on white — a near-black carrying the purple undertone so it
     sits with the palette instead of fighting it. */
  --text:#2B2438;
  --muted:#6E6482;                    /* 5.5:1 on white            */

  --green:var(--teal-600);            /* white on teal-500 is only 3.0:1 */

  /* ── Warm ────────────────────────────────────────────────────────
     Amber does double duty: the streak (energy, keeping it going) and
     clinical attention. Alerts stay distinguishable because they pair
     amber with an icon and sit in the header, never as a big soft card. */
  --amber-50:#FEF8EE;  --amber-100:#FEF1DD; --amber-200:#FCE0B1;
  --amber-300:#F9C771; --amber-500:#F59E0B; --amber-600:#C98209;
  --amber-700:#9D6507; --amber-800:#764C05;

  --orange:var(--amber-500);
  --red:#EF4444;

  --radius:16px;
  --nav-h:72px;
  --header-h:64px;                    /* headroom for the fitted title */
}
html,body{height:100%;background:#CBD5E1;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;-webkit-font-smoothing:antialiased;}

/* ── Phone Frame (desktop) ── */
#phoneFrame{
  position:fixed;inset:0;display:flex;align-items:center;justify-content:center;
  background:#1E1B29;
}
#app{
  width:390px;height:844px;max-height:90vh;
  background:var(--bg);border-radius:40px;
  overflow:hidden;display:flex;flex-direction:column;
  box-shadow:0 30px 80px rgba(0,0,0,0.5),inset 0 0 0 1px rgba(255,255,255,0.1);
  position:relative;
}
@media(max-width:430px){
  #phoneFrame{background:var(--bg);}
  #app{width:100%;height:100%;border-radius:0;box-shadow:none;}
}

/* ── Header ── */
#appHeader{
  height:var(--header-h);background:var(--surface);
  border-bottom:1px solid var(--border);
  /* Centred, and stays centred: the offline warning is taken out of flow so
     it can't shove the practitioner off-axis when it appears. */
  position:relative;
  display:flex;align-items:center;justify-content:center;
  padding:0 20px;flex-shrink:0;z-index:10;
}
.header-brand{
  display:flex;align-items:center;justify-content:center;
  gap:8px;width:100%;min-width:0;cursor:pointer;
}
/* Icon and caret stay a fixed size so the NAME is what expands — scaling
   all three together would spend most of the new width on a giant emoji. */
.header-ico{font-size:19px;line-height:1;flex:none;}
.header-caret{font-size:13px;line-height:1;flex:none;color:var(--muted);}
/* font-size is written by fitHeaderTitle(); nowrap is what lets it be
   measured at a reference size and scaled to fit. */
/* flex:none matters — with the default shrink the browser squeezes the box
   below the size just computed for it and the text spills out of it. The
   fit maths already guarantees it fits, so the box must be left alone. */
.header-title{
  flex:none;
  font-weight:700;color:var(--text);
  white-space:nowrap;line-height:1.1;font-size:17px;
}
.header-right{
  position:absolute;right:20px;top:50%;transform:translateY(-50%);
  display:flex;align-items:center;gap:12px;
}
.streak-badge{
  background:var(--mint-100);border:1px solid var(--teal-200);
  color:var(--teal-700);font-size:12px;font-weight:700;
  padding:5px 10px;border-radius:999px;
}

/* ── Main Content ── */
#mainContent{
  flex:1;overflow:hidden;position:relative;
}
.page{
  position:absolute;inset:0;overflow-y:auto;
  padding:16px 16px calc(var(--nav-h) + 16px);
  display:none;animation:fadeUp .22s ease-out;
}
.page.active{display:block;}
@keyframes fadeUp{from{opacity:0;transform:translateY(8px);}to{opacity:1;transform:translateY(0);}}

/* ── Bottom Nav ── */
#bottomNav{
  height:var(--nav-h);background:var(--surface);
  border-top:1px solid var(--border);
  display:flex;align-items:center;
  /* border-top already separates it, and nothing scrolls underneath. */
  padding:0 8px;flex-shrink:0;
}
.nav-btn{
  flex:1;display:flex;flex-direction:column;align-items:center;
  gap:4px;padding:8px 4px;border:none;background:transparent;cursor:pointer;
  color:var(--muted);transition:color .15s;border-radius:12px;
}
.nav-btn.active{color:var(--primary);}
.nav-btn svg{width:22px;height:22px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;}
.nav-btn.active svg{stroke:var(--primary);}
.nav-label{font-size:10px;font-weight:600;letter-spacing:.2px;}
.nav-dot{
  width:4px;height:4px;border-radius:50%;background:var(--primary);
  margin-top:2px;opacity:0;transition:opacity .15s;
}
.nav-btn.active .nav-dot{opacity:1;}

/* ── Cards ── */
.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:16px;color:var(--text);margin-bottom:12px;}
.card-title{font-size:14px;font-weight:700;color:var(--text);margin-bottom:12px;}

/* ── Buttons ── */
.btn{border:none;cursor:pointer;border-radius:12px;font-size:14px;font-weight:600;transition:all .15s;font-family:inherit;}
.btn-primary{background:var(--primary);color:#fff;padding:12px 20px;box-shadow:0 2px 6px rgba(86,66,108,0.18);}
.btn-primary:active{transform:scale(0.97);background:var(--primary-dark);}
.btn-secondary{background:var(--surface2);border:1px solid var(--border);color:var(--text);padding:10px 16px;}
/* For a CTA sitting on a saturated banner. A coloured button on a coloured
   panel separates by barely 1.2:1 — the light fill is what makes it read as
   a button at all. */
.btn-on-dark{background:#fff;color:var(--purple-700);padding:12px 20px;font-weight:700;}
.btn-on-dark:active{transform:scale(0.97);background:var(--purple-50);}
.btn-sm{padding:7px 14px;font-size:12px;border-radius:8px;}
.btn-block{width:100%;display:block;text-align:center;}

/* ── Section Headers ── */
.section-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;}
.section-title{font-size:18px;font-weight:700;color:var(--text);}
.section-sub{font-size:13px;color:var(--muted);margin-top:2px;}

/* ═══════════════════════════════════════
   HOME PAGE — CHAT
═══════════════════════════════════════ */
#pageHome{padding:0;display:flex;flex-direction:column;}
#chatContainer{
  display:flex;flex-direction:column;height:100%;
}
#chatMessages{
  flex:1;overflow-y:auto;padding:16px 16px 8px;
  display:flex;flex-direction:column;gap:10px;
}
.msg-row{display:flex;align-items:flex-end;gap:8px;}
.msg-row.user{flex-direction:row-reverse;}
.ai-avatar{
  width:32px;height:32px;border-radius:50%;flex-shrink:0;
  background:var(--lavender-200);
  display:grid;place-items:center;font-size:14px;
}
.bubble{
  max-width:72%;padding:10px 14px;border-radius:16px;
  font-size:14px;line-height:1.45;word-break:break-word;
}
.bubble.ai{background:var(--surface);border:1px solid var(--border);color:var(--text);border-bottom-left-radius:4px;}
.bubble.user{background:var(--primary);color:#fff;border-bottom-right-radius:4px;}
.typing-dots{display:flex;gap:4px;align-items:center;padding:6px 4px;}
.typing-dots span{width:6px;height:6px;border-radius:50%;background:var(--muted);animation:dot .9s infinite;}
.typing-dots span:nth-child(2){animation-delay:.2s;}
.typing-dots span:nth-child(3){animation-delay:.4s;}
@keyframes dot{0%,60%,100%{transform:scale(1);}30%{transform:scale(1.4);}}

.quick-chips{display:flex;flex-wrap:wrap;gap:6px;padding:0 16px 8px;}
.chip{
  background:var(--surface);border:1.5px solid var(--primary);
  color:var(--primary);padding:8px 14px;border-radius:999px;
  font-size:13px;font-weight:600;cursor:pointer;transition:all .15s;
}
.chip:active{background:var(--primary);color:#fff;}

#chatInputArea{
  padding:10px 16px calc(var(--nav-h) + 10px);
  border-top:1px solid var(--border);background:var(--surface);
  display:flex;gap:8px;align-items:center;flex-shrink:0;
}
#chatInput{
  flex:1;border:1.5px solid var(--border);background:var(--surface2);
  padding:10px 14px;border-radius:12px;font-size:14px;
  outline:none;color:var(--text);font-family:inherit;
}
#chatInput:focus{border-color:var(--primary);}
#chatSendBtn{
  width:40px;height:40px;border-radius:50%;flex-shrink:0;
  background:var(--primary);
  border:none;cursor:pointer;display:grid;place-items:center;
  box-shadow:0 2px 6px rgba(86,66,108,0.18);
}
#chatSendBtn:active{background:var(--primary-dark);}
#chatSendBtn svg{width:18px;height:18px;stroke:#fff;fill:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;}

/* ═══════════════════════════════════════
   EXERCISES PAGE
═══════════════════════════════════════ */
.ex-card{
  display:flex;align-items:center;gap:14px;
  background:var(--surface);border:1px solid var(--border);
  border-radius:var(--radius);padding:14px;margin-bottom:10px;
}
.ex-icon-box{
  width:52px;height:52px;border-radius:12px;flex-shrink:0;
  display:grid;place-items:center;font-size:24px;
  background:var(--surface2);border:1px solid var(--border);
}
.ex-info{flex:1;}
.ex-name{font-size:15px;font-weight:700;color:var(--text);}
.ex-meta{font-size:12px;color:var(--muted);margin-top:2px;}
.ex-status{font-size:11px;font-weight:700;padding:4px 10px;border-radius:999px;}
.ex-status.done{background:var(--mint-200);color:var(--teal-800);}
.ex-status.next{background:var(--peri-200);color:var(--purple-700);}
.ex-status.pending-s{background:var(--lavender-100);color:var(--muted);}

.session-banner{
  background:var(--purple-600);
  border-radius:var(--radius);padding:18px;color:#fff;margin-bottom:16px;
}
.session-banner h2{font-size:18px;font-weight:800;margin-bottom:4px;}
.session-banner p{font-size:13px;opacity:.9;margin-bottom:14px;}

/* ═══════════════════════════════════════
   PROGRESS PAGE
═══════════════════════════════════════ */
.progress-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:18px;margin-bottom:12px;}
.progress-label{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;}
.progress-name{font-size:14px;font-weight:700;color:var(--text);}
.progress-pct{font-size:14px;font-weight:700;color:var(--primary);}
.progress-track{height:10px;background:var(--peri-100);border-radius:999px;overflow:hidden;margin-bottom:8px;}
.progress-fill{height:100%;border-radius:999px;transition:width .6s ease;}
.fill-blue{background:var(--primary);}
.fill-mint{background:var(--teal-600);}
.progress-sub{font-size:12px;color:var(--muted);}

.stats-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:12px;}
.stat-mini{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:14px;text-align:center;}
.stat-mini-val{font-size:24px;font-weight:800;color:var(--text);}
.stat-mini-lbl{font-size:11px;color:var(--muted);margin-top:2px;text-transform:uppercase;letter-spacing:.4px;}

/* ═══════════════════════════════════════
   SCHEDULE PAGE
═══════════════════════════════════════ */
.appt-card{
  display:flex;align-items:center;gap:12px;
  background:var(--surface);border:1px solid var(--border);
  border-radius:var(--radius);padding:14px;margin-bottom:10px;
}
.appt-date-box{
  width:48px;text-align:center;background:var(--surface2);
  border:1px solid var(--border);border-radius:10px;padding:6px 0;flex-shrink:0;
}
.appt-day{font-size:20px;font-weight:800;color:var(--text);}
.appt-mon{font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:.5px;}
.appt-info{flex:1;}
.appt-name{font-size:14px;font-weight:700;color:var(--text);}
.appt-meta{font-size:12px;color:var(--muted);margin-top:2px;}
.tag{padding:4px 10px;border-radius:999px;font-size:11px;font-weight:700;}
.tag-blue{background:var(--peri-200);color:var(--purple-700);}
.tag-orange{background:#FEF3C7;color:#B45309;}
.tag-green{background:var(--mint-200);color:var(--teal-800);}

/* ═══════════════════════════════════════
   PROFILE PAGE
═══════════════════════════════════════ */
.profile-hero{
  text-align:center;background:var(--surface);border:1px solid var(--border);
  border-radius:var(--radius);padding:24px 16px;margin-bottom:12px;
}
.profile-avatar{
  width:76px;height:76px;border-radius:50%;margin:0 auto 12px;
  background:var(--primary);
  display:grid;place-items:center;color:#fff;font-size:26px;font-weight:800;
}
.profile-name{font-size:22px;font-weight:800;color:var(--text);}
.profile-since{font-size:13px;color:var(--muted);margin-top:2px;}

/* Kept from the old XP list — now just a plain settings row. */
.xp-row{
  display:flex;align-items:center;justify-content:space-between;
  padding:12px;background:var(--surface2);border-radius:10px;
}
.xp-row-name{font-size:14px;color:var(--text);}
.xp-row-val{font-size:14px;font-weight:700;color:var(--primary);}

/* ═══════════════════════════════════════
   MODALS
═══════════════════════════════════════ */
.modal-overlay{
  position:absolute;inset:0;background:rgba(0,0,0,.5);
  z-index:100;display:flex;flex-direction:column;justify-content:flex-end;
  display:none;
}
.modal-overlay.open{display:flex;}
.modal-sheet{
  background:var(--surface);border-radius:24px 24px 0 0;
  padding:20px;max-height:90%;overflow-y:auto;
}
.modal-handle{width:36px;height:4px;border-radius:2px;background:var(--border);margin:0 auto 18px;}
.modal-title{font-size:20px;font-weight:800;color:var(--text);margin-bottom:6px;}
.modal-sub{font-size:14px;color:var(--muted);margin-bottom:20px;}

/* Exercise session modal */
.video-placeholder{
  background:var(--purple-800);
  border-radius:16px;aspect-ratio:16/9;display:flex;align-items:center;justify-content:center;
  margin-bottom:16px;position:relative;overflow:hidden;
}
.play-btn{
  width:56px;height:56px;border-radius:50%;
  background:rgba(255,255,255,.2);backdrop-filter:blur(10px);
  display:grid;place-items:center;cursor:pointer;
  border:2px solid rgba(255,255,255,.4);
}
.play-btn svg{width:22px;height:22px;fill:#fff;}
.exercise-step-name{font-size:19px;font-weight:800;color:var(--text);margin-bottom:4px;}
.exercise-step-meta{font-size:13px;color:var(--muted);margin-bottom:14px;}
.exercise-desc{font-size:14px;color:var(--text);line-height:1.5;background:var(--surface2);border-radius:12px;padding:14px;margin-bottom:16px;}

/* Pain slider */
.pain-slider-wrap{margin:16px 0;}
.pain-slider-labels{display:flex;justify-content:space-between;font-size:11px;color:var(--muted);margin-bottom:6px;font-weight:600;}
#painSlider,#finalPainSlider{
  width:100%;height:6px;border-radius:3px;outline:none;cursor:pointer;
  -webkit-appearance:none;appearance:none;
  /* Deliberately a neutral track. The old green→red ramp coloured the scale
     before the person had answered, which nudges a self-report toward the
     end they're sitting nearest. The number and the face carry the meaning. */
  background:var(--peri-200);
}
#painSlider::-webkit-slider-thumb,#finalPainSlider::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;width:22px;height:22px;border-radius:50%;
  background:#fff;border:3px solid var(--primary);cursor:pointer;
  box-shadow:0 2px 8px rgba(0,0,0,.2);
}
.pain-display{text-align:center;font-size:32px;font-weight:900;color:var(--text);margin:10px 0;}
.pain-emoji{font-size:28px;margin-bottom:4px;display:block;text-align:center;}

/* Clinic cards */
.clinic-card{
  background:var(--surface2);border:1px solid var(--border);border-radius:12px;
  padding:14px;margin-bottom:10px;cursor:pointer;transition:all .15s;
}
.clinic-card:active,.clinic-card.selected{border-color:var(--primary);background:var(--peri-100);}
.clinic-name{font-size:15px;font-weight:700;color:var(--text);}
.clinic-meta{font-size:12px;color:var(--muted);margin-top:3px;}
.clinic-stars{color:#F59E0B;font-size:13px;margin-top:4px;}

/* Filter chips */
.filter-row{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:14px;}
.filter-chip{
  padding:6px 12px;border-radius:999px;font-size:12px;font-weight:600;
  border:1.5px solid var(--border);background:var(--surface);color:var(--muted);cursor:pointer;transition:all .15s;
}
.filter-chip.active{border-color:var(--primary);background:var(--primary);color:#fff;}

/* Triage result */
.triage-card{
  border-radius:16px;padding:20px;text-align:center;margin-bottom:16px;
}
.triage-card.safe{background:var(--mint-200);border:1px solid var(--mint-300);}
.triage-card.moderate{background:#FEF3C7;border:1px solid #FDE68A;}
.triage-card.urgent{background:#FEE2E2;border:1px solid #FECACA;}
.triage-icon{font-size:36px;display:block;margin-bottom:10px;}
.triage-title{font-size:18px;font-weight:800;color:var(--text);}
.triage-desc{font-size:13px;color:var(--muted);margin-top:6px;line-height:1.5;}

/* Confetti / XP toast */
.toast{
  position:absolute;bottom:calc(var(--nav-h) + 16px);left:50%;transform:translateX(-50%);
  background:var(--text);
  color:#fff;padding:10px 20px;border-radius:999px;font-size:13px;font-weight:700;
  z-index:200;box-shadow:0 4px 14px rgba(43,36,56,0.28);
  animation:toastIn .4s ease-out,toastOut .4s ease-in 2s forwards;
  white-space:nowrap;
}
@keyframes toastIn{from{opacity:0;transform:translateX(-50%) translateY(10px);}to{opacity:1;transform:translateX(-50%) translateY(0);}}
@keyframes toastOut{from{opacity:1;}to{opacity:0;}}

/* ── Input field ── */
.field-wrap{margin-bottom:14px;}
.field-label{font-size:12px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.5px;margin-bottom:6px;display:block;}
.field-input{
  width:100%;border:1.5px solid var(--border);background:var(--surface2);
  padding:12px 14px;border-radius:12px;font-size:14px;
  outline:none;color:var(--text);font-family:inherit;
}
.field-input:focus{border-color:var(--primary);}
textarea.field-input{resize:none;height:80px;}

/* ═══════════════════════════════════════
   PRACTITIONER PICKER
═══════════════════════════════════════ */
.picker-overlay{
  position:absolute;inset:0;z-index:300;background:var(--bg);
  display:none;flex-direction:column;
}
.picker-overlay.open{display:flex;animation:fadeUp .25s ease-out;}
.picker-head{padding:26px 20px 14px;flex-shrink:0;}
.picker-back{
  background:none;border:none;color:var(--muted);font-size:13px;font-weight:600;
  cursor:pointer;padding:0 0 12px;font-family:inherit;
}
.picker-head h1{font-size:22px;font-weight:800;color:var(--text);margin-bottom:6px;line-height:1.25;}
.picker-head p{font-size:13px;color:var(--muted);line-height:1.45;}
.picker-scroll{flex:1;overflow-y:auto;padding:6px 16px 28px;}
.picker-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;}
.picker-card{
  background:var(--surface);border:1.5px solid var(--border);border-radius:16px;
  padding:14px;cursor:pointer;transition:transform .12s,border-color .12s,background .12s;
  text-align:left;display:flex;flex-direction:column;gap:8px;
  font-family:inherit;
}
.picker-card:active{transform:scale(.97);}
.picker-card.selected{border-color:var(--primary);background:var(--peri-100);}
.picker-card-icon{
  width:42px;height:42px;border-radius:12px;display:grid;place-items:center;
  font-size:21px;background:var(--surface2);border:1px solid var(--border);
}
.picker-card-name{font-size:13.5px;font-weight:700;color:var(--text);line-height:1.25;}
.picker-card-blurb{font-size:11px;color:var(--muted);line-height:1.35;}
/* The old max-width:260px + ellipsis lived here. It has to stay gone: the
   title is now sized to fit by fitHeaderTitle(), so a hard cap just
   truncated every long name to "Physiothe…" no matter what size was set. */

/* ── Booking: practitioner type rows ── */
.book-type-list{display:flex;flex-direction:column;gap:8px;margin-bottom:8px;}
.book-type{
  display:flex;align-items:center;gap:12px;width:100%;
  background:var(--surface2);border:1.5px solid var(--border);border-radius:12px;
  padding:11px 14px;cursor:pointer;font-family:inherit;text-align:left;
  transition:border-color .12s,background .12s,transform .12s;
}
.book-type:active{transform:scale(.98);}
.book-type.current{border-color:var(--primary);background:var(--peri-100);}
.book-type-ico{font-size:20px;width:26px;text-align:center;flex-shrink:0;}
.book-type-text{flex:1;display:flex;flex-direction:column;gap:2px;min-width:0;}
.book-type-name{font-size:13.5px;font-weight:700;color:var(--text);line-height:1.25;}
.book-type-sub{font-size:11px;color:var(--muted);line-height:1.3;}
.book-type-arrow{color:var(--muted);font-size:16px;flex-shrink:0;}
.book-type-tag{
  background:var(--primary);color:#fff;font-size:9px;font-weight:800;
  padding:2px 7px;border-radius:999px;letter-spacing:.4px;flex-shrink:0;
}

/* ═══════════════════════════════════════
   VOICE + LOCAL MODEL STATUS
═══════════════════════════════════════ */
#micBtn{
  width:40px;height:40px;border-radius:50%;flex-shrink:0;
  background:var(--surface2);border:1.5px solid var(--border);
  cursor:pointer;display:grid;place-items:center;transition:all .15s;
}
#micBtn svg{width:18px;height:18px;stroke:var(--muted);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;}
#micBtn:active{transform:scale(.94);}
#micBtn.recording{
  background:var(--red);border-color:var(--red);
  animation:micPulse 1.2s ease-in-out infinite;
}
#micBtn.recording svg{stroke:#fff;}
#micBtn.busy{opacity:.55;pointer-events:none;}
#micBtn[hidden]{display:none !important;}
@keyframes micPulse{
  0%,100%{box-shadow:0 0 0 0 rgba(239,68,68,.45);}
  50%{box-shadow:0 0 0 8px rgba(239,68,68,0);}
}

.voice-hint{
  font-size:11px;color:var(--muted);text-align:center;
  padding:0 16px 6px;min-height:16px;
}
.voice-hint.live{color:var(--red);font-weight:700;}

/* Shown only when the local model is down — silence is the healthy state. */
.local-warning{
  background:#FFFBEB;border:1px solid #FDE68A;color:#B45309;
  font-size:10px;font-weight:700;letter-spacing:.2px;
  padding:4px 9px;border-radius:999px;white-space:nowrap;
}

/* ── Streak hero (Progress tab) ──
   The only metric kept, so it leads the page rather than sitting in a row
   of bars. */
.streak-hero{
  background:var(--amber-50);
  border:1px solid var(--amber-200);border-radius:18px;
  padding:22px 18px 18px;text-align:center;margin-bottom:16px;
}
.streak-hero-ico{font-size:30px;line-height:1;}
.streak-hero-num{
  font-size:46px;font-weight:800;color:var(--amber-700);
  line-height:1.05;margin-top:4px;font-variant-numeric:tabular-nums;
}
.streak-hero-lbl{
  font-size:12px;font-weight:700;color:var(--amber-800);
  text-transform:uppercase;letter-spacing:.6px;margin-top:2px;
}
.streak-hero-track{
  height:7px;border-radius:999px;background:var(--amber-200);
  overflow:hidden;margin:14px 4px 8px;
}
.streak-hero-fill{
  height:100%;border-radius:999px;
  background:var(--amber-600);
  transition:width .5s ease;
}
.streak-hero-sub{font-size:11.5px;color:var(--amber-800);opacity:.85;}

/* Speaker toggle sits with the quick chips */
#speakToggle{
  background:var(--surface);border:1.5px solid var(--border);
  color:var(--muted);padding:6px 12px;border-radius:999px;
  font-size:11px;font-weight:700;cursor:pointer;font-family:inherit;
}
#speakToggle.on{border-color:var(--primary);color:var(--primary);background:var(--peri-100);}

/* ═══════════════════════════════════════
   INSTALLED / MOBILE (PWA)
═══════════════════════════════════════ */

/* On a real phone the desktop "phone frame" must get out of the way, and the
   app has to respect the notch and home indicator. */
@media (max-width:430px), (display-mode:standalone){
  #phoneFrame{background:var(--bg);padding:0;}
  #app{
    width:100%;height:100%;max-height:none;border-radius:0;box-shadow:none;
    padding-top:env(safe-area-inset-top);
  }
  #appHeader{padding-left:max(20px,env(safe-area-inset-left));padding-right:max(20px,env(safe-area-inset-right));}
  #bottomNav{
    height:calc(var(--nav-h) + env(safe-area-inset-bottom));
    padding-bottom:env(safe-area-inset-bottom);
  }
  #chatInputArea{padding-bottom:calc(var(--nav-h) + env(safe-area-inset-bottom) + 10px) !important;}
  .page{padding-bottom:calc(var(--nav-h) + env(safe-area-inset-bottom) + 16px);}
  .modal-sheet{padding-bottom:calc(20px + env(safe-area-inset-bottom));}
}

/* Standalone gets the full viewport, including behind the status bar. */
@media (display-mode:standalone){
  html,body{height:100vh;height:100dvh;overscroll-behavior:none;}
  #phoneFrame{position:fixed;inset:0;}
  /* No text selection callouts on long-press — it should feel native. */
  body{-webkit-touch-callout:none;-webkit-user-select:none;user-select:none;}
  input,textarea{-webkit-user-select:text;user-select:text;}
}

/* 16px minimum stops iOS zooming the page when a field is focused. */
@media (max-width:430px){
  #chatInput,.field-input{font-size:16px;}
}

/* Update-available banner */
#updateBar{
  position:absolute;left:50%;transform:translateX(-50%);
  bottom:calc(var(--nav-h) + env(safe-area-inset-bottom) + 14px);
  background:var(--text);color:#fff;border:none;
  padding:10px 18px;border-radius:999px;font-size:13px;font-weight:700;
  font-family:inherit;cursor:pointer;z-index:400;
  box-shadow:0 8px 24px rgba(0,0,0,.3);display:none;
}
#updateBar.show{display:block;}

/* ═══════════════════════════════════════
   VOICE STAGE — the blob owns the home tab
═══════════════════════════════════════ */

/* Column layout, not centred content.
   Centring the whole stack with justify-content:center and hiding the
   overflow meant a long reply was clipped at BOTH ends with no way to reach
   it, and ran underneath the status and the controls. Now the caption is the
   one flexible child: it takes the space that's left and scrolls past that,
   so no reply is ever unreadable. The auto margins on the mark and the
   controls keep everything vertically balanced when the text is short. */
#voiceStage{
  position:absolute;inset:0;
  display:none;flex-direction:column;align-items:center;justify-content:flex-start;
  padding:18px 22px calc(var(--nav-h) + env(safe-area-inset-bottom) + 12px);
  gap:0;text-align:center;overflow:hidden;
  background:var(--bg);
}
#voiceStage.on > #blobWrap{flex:none;margin-top:auto;}
#voiceStage.on > #voiceStatus,
#voiceStage.on > #voiceChips{flex:none;}
#voiceStage.on > #voiceControls{flex:none;margin-top:auto;}
#voiceStage.on{display:flex;}

/* Chat log is kept for state/history but hidden while the blob is in charge. */
#voiceStage.on ~ #chatMessages{display:none !important;}

/* ── The voice mark ──
   A ring with five bars. It replaced an animated blob: a blob is decorative
   and says nothing, whereas these bars can show the actual microphone level,
   so the thing you look at while talking is also the thing telling you it
   heard you. Drawn as SVG rather than the source PNG so it stays sharp at
   any size and takes its colour from the palette. */

#blobWrap{
  position:relative;width:236px;height:236px;flex-shrink:0;
  display:grid;place-items:center;
  /* --level is driven from JS by the mic analyser (0 → 1) */
  --level:0;
  transition:transform .25s ease;
}

#voiceMark{
  position:absolute;inset:0;width:100%;height:100%;
  overflow:visible;
}

.vm-ring{
  fill:none;stroke:var(--purple-700);stroke-width:3.2;
  transition:stroke .3s ease;
}

.vm-bar{
  stroke:var(--purple-700);stroke-width:5;stroke-linecap:round;
  /* fill-box keeps each bar growing from its own centre rather than the
     SVG origin, which is what makes them read as a level meter. */
  transform-box:fill-box;transform-origin:center;
  transition:transform .09s ease-out,stroke .3s ease;
}

/* ── Tap target ── */

#blobBtn{
  position:absolute;inset:0;z-index:3;
  width:100%;height:100%;border-radius:50%;
  border:none;background:transparent;cursor:pointer;
  font-family:inherit;-webkit-tap-highlight-color:transparent;
}

/* Expanding ring while listening */
#blobRing{
  position:absolute;inset:0;margin:auto;
  width:212px;height:212px;border-radius:50%;
  border:2px solid var(--teal-300);
  opacity:0;pointer-events:none;z-index:2;
}

/* ── States ── */

/* Idle before first tap — quietly breathing, inviting a tap */
#blobWrap.idle .vm-bar{animation:vmRest 4s ease-in-out infinite;}
#blobWrap.idle .vm-bar:nth-child(2){animation-delay:.35s;}
#blobWrap.idle .vm-bar:nth-child(3){animation-delay:.7s;}
#blobWrap.idle .vm-bar:nth-child(4){animation-delay:.5s;}
#blobWrap.idle .vm-bar:nth-child(5){animation-delay:.2s;}
@keyframes vmRest{
  0%,100%{transform:scaleY(1);}
  50%{transform:scaleY(1.12);}
}

/* Listening — the bars ARE the level meter.
   The multipliers are close together on purpose. Letting the short outer
   bars grow fastest flattens the silhouette into a block at speaking volume
   and the mark stops being recognisable; near-uniform growth keeps the wave
   shape and just makes it bigger. The centre bar is the binding constraint:
   voicesession clamps level to 1, and at 0.45 its round cap lands 33.0 units
   out against the ring's inner edge at 36.4 — clear even at a shout. */
#blobWrap.listening .vm-ring{stroke:var(--teal-600);}
#blobWrap.listening .vm-bar{stroke:var(--teal-600);animation:none;}
#blobWrap.listening .vm-bar:nth-child(1){transform:scaleY(calc(1 + var(--level) * 0.50));}
#blobWrap.listening .vm-bar:nth-child(2){transform:scaleY(calc(1 + var(--level) * 0.55));}
#blobWrap.listening .vm-bar:nth-child(3){transform:scaleY(calc(1 + var(--level) * 0.45));}
#blobWrap.listening .vm-bar:nth-child(4){transform:scaleY(calc(1 + var(--level) * 0.56));}
#blobWrap.listening .vm-bar:nth-child(5){transform:scaleY(calc(1 + var(--level) * 0.52));}
#blobWrap.listening #blobRing{animation:ringPulse 1.6s ease-out infinite;}
@keyframes ringPulse{
  0%{opacity:.7;transform:scale(.92);}
  100%{opacity:0;transform:scale(1.18);}
}

/* Thinking — desaturated, bars stepping in sequence */
#blobWrap.thinking .vm-ring{stroke:var(--muted);}
#blobWrap.thinking .vm-bar{stroke:var(--muted);animation:vmThink 1.1s ease-in-out infinite;}
#blobWrap.thinking .vm-bar:nth-child(2){animation-delay:.12s;}
#blobWrap.thinking .vm-bar:nth-child(3){animation-delay:.24s;}
#blobWrap.thinking .vm-bar:nth-child(4){animation-delay:.36s;}
#blobWrap.thinking .vm-bar:nth-child(5){animation-delay:.48s;}
@keyframes vmThink{
  0%,100%{opacity:.3;transform:scaleY(.8);}
  50%{opacity:1;transform:scaleY(1);}
}

/* Speaking — a wave runs across the bars */
#blobWrap.speaking .vm-ring{stroke:var(--primary);}
#blobWrap.speaking .vm-bar{stroke:var(--primary);animation:vmSpeak .9s ease-in-out infinite;}
#blobWrap.speaking .vm-bar:nth-child(2){animation-delay:.10s;}
#blobWrap.speaking .vm-bar:nth-child(3){animation-delay:.20s;}
#blobWrap.speaking .vm-bar:nth-child(4){animation-delay:.30s;}
#blobWrap.speaking .vm-bar:nth-child(5){animation-delay:.40s;}
@keyframes vmSpeak{
  0%,100%{transform:scaleY(.72);}
  50%{transform:scaleY(1.38);}
}

/* Muted at rest — still tappable, but visibly not going to talk back */
#blobWrap.muted.idle .vm-ring{stroke:var(--lavender-300);}
#blobWrap.muted.idle .vm-bar{stroke:var(--lavender-300);animation:none;}

/* Voice unavailable — flat line, clearly inert */
#blobWrap.unavailable .vm-ring{stroke:var(--border);}
#blobWrap.unavailable .vm-bar{
  stroke:var(--lavender-300);animation:none;transform:scaleY(.18);
}

/* Someone who prefers less motion still gets colour and level, just no loops. */
@media (prefers-reduced-motion:reduce){
  .vm-bar{animation:none !important;}
}

/* ── Caption + status ── */

/* flex:0 1 auto + min-height:0 is what lets this shrink below its content
   and scroll instead of pushing the rest of the column off the screen. */
#voiceCaption{
  flex:0 1 auto;min-height:0;
  margin-top:22px;
  font-size:17px;line-height:1.45;font-weight:600;color:var(--text);
  width:100%;max-width:340px;
  overflow-y:auto;overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;
  transition:opacity .25s;
}
/* A long reply that scrolls should look like it scrolls. */
#voiceCaption::-webkit-scrollbar{width:3px;}
#voiceCaption::-webkit-scrollbar-thumb{background:var(--peri-200);border-radius:99px;}
#voiceCaption.fade{opacity:0;}
#voiceCaption .you{color:var(--muted);font-weight:500;font-size:15px;}

#voiceStatus{
  margin-top:6px;font-size:12px;font-weight:700;letter-spacing:.5px;
  text-transform:uppercase;color:var(--muted);min-height:16px;
}
#voiceStatus.live{color:var(--teal-700);}
#voiceStatus.err{color:var(--red);text-transform:none;letter-spacing:0;font-weight:600;}

#voiceChips{justify-content:center;margin-top:14px;padding:0;}

/* ── Bottom controls on the voice stage ── */

/* In flow, not absolute. Absolute took it out of the column, so the caption
   had no idea it was there and simply ran behind it. */
#voiceControls{
  display:flex;align-items:center;justify-content:center;gap:10px;
  width:100%;padding:14px 20px 0;
}
.voice-pill{
  background:var(--surface);border:1.5px solid var(--border);color:var(--muted);
  padding:8px 14px;border-radius:999px;font-size:12px;font-weight:700;
  cursor:pointer;font-family:inherit;display:flex;align-items:center;gap:6px;
}
.voice-pill.on{border-color:var(--primary);color:var(--primary);background:var(--peri-100);}


/* Text row is hidden on the voice stage until the keyboard pill is tapped. */
/* The voice stage is absolutely positioned over the whole page, so the text
   row has to be lifted above it or you can't see what you're typing. */
#pageHome #chatInputArea{display:none;}
#pageHome #chatInputArea.show{
  display:flex;
  position:absolute;left:0;right:0;bottom:0;
  z-index:40;
  box-shadow:0 -8px 28px rgba(28,46,61,.10);
}
/* Give the typed text room and get the pills out of the way. */
#voiceStage.typing #voiceControls{display:none;}
#voiceStage.typing #blobWrap{transform:scale(.72);transition:transform .25s ease;}
#voiceStage.typing #voiceCaption{margin-top:12px;font-size:15px;}
/* The text row is absolutely positioned over the stage, so the stage has to
   reserve its height or the caption scrolls to a bottom you can't see. */
#voiceStage.typing{
  padding-top:24px;
  padding-bottom:calc(var(--nav-h) + env(safe-area-inset-bottom) + 72px);
}
#voiceStage.on ~ #quickChipsArea{display:none !important;}
#voiceStage.on ~ .voice-hint{display:none;}

/* ── Keyboard-aware text row ──
   --kb is the height the on-screen keyboard covers, set from visualViewport. */
#pageHome #chatInputArea.show{
  bottom:var(--kb, 0px);
  padding-bottom:10px !important;
  transition:bottom .18s ease-out;
}
/* With the keyboard up the nav bar is hidden behind it anyway — reclaim
   the space and keep the caption visible above the field. */
body.kb-open #bottomNav{opacity:0;pointer-events:none;}
body.kb-open #voiceStage{padding-bottom:0;}
body.kb-open #voiceStage #blobWrap{transform:scale(.55);}
body.kb-open #voiceCaption{font-size:14px;margin-top:8px;}

/* ═══════════════════════════════════════
   SIGN IN / CREATE ACCOUNT
   Sits above everything, the picker included: nothing behind it is usable
   until someone is signed in. Same flat, bordered surfaces as the rest.
═══════════════════════════════════════ */
.auth-screen{
  position:absolute;inset:0;z-index:500;background:var(--bg);
  display:flex;flex-direction:column;
}
.auth-screen[hidden]{display:none;}
/* While the session is being checked, only the brand shows — no form, and
   none of the app behind it. */
.auth-checking{display:none;text-align:center;color:var(--muted);font-size:14px;}
.auth-screen.checking .auth-checking{display:flex;flex-direction:column;align-items:center;gap:14px;}
.auth-screen.checking .auth-card,.auth-screen.checking .auth-foot{display:none;}
.auth-screen.problem .auth-checking-text{display:none;}
.auth-checking .btn[hidden]{display:none;}
.auth-scroll{
  flex:1;overflow-y:auto;-webkit-overflow-scrolling:touch;
  padding:36px 20px calc(28px + env(safe-area-inset-bottom));
  display:flex;flex-direction:column;
}
.auth-brand{text-align:center;margin:8px 0 22px;}
.auth-mark{width:56px;height:56px;display:block;margin:0 auto 12px;}
.auth-mark circle{fill:var(--purple-50);stroke:var(--primary);stroke-width:3;}
.auth-mark line{stroke:var(--primary);stroke-width:5;stroke-linecap:round;}
.auth-brand h1{font-size:24px;font-weight:800;color:var(--text);letter-spacing:-.2px;}
.auth-brand p{font-size:14px;color:var(--muted);margin-top:4px;}

.auth-card{
  background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);
  padding:18px;
}
.auth-tabs{
  display:grid;grid-template-columns:1fr 1fr;gap:4px;padding:4px;margin-bottom:18px;
  background:var(--surface2);border:1px solid var(--border);border-radius:12px;
}
.auth-tabs[hidden]{display:none;}
.auth-tab{
  border:none;background:transparent;border-radius:9px;padding:9px 8px;
  font-family:inherit;font-weight:600;font-size:14px;line-height:1.2;color:var(--muted);cursor:pointer;
}
.auth-tab.active{background:var(--surface);color:var(--text);box-shadow:0 0 0 1px var(--border);}
.auth-tab[hidden]{display:none;}
.auth-tabs.single{grid-template-columns:1fr;}

.auth-form[hidden]{display:none;}
.auth-form-title{font-size:18px;font-weight:800;color:var(--text);margin-bottom:6px;}
.auth-form-sub{font-size:13px;color:var(--muted);line-height:1.45;margin-bottom:16px;}
.auth-form .btn-primary{margin-top:4px;}
.auth-form .btn-primary:disabled{opacity:.6;cursor:default;transform:none;}

.pw-wrap{position:relative;}
.pw-wrap .field-input{padding-right:64px;}
.pw-toggle{
  position:absolute;right:6px;top:50%;transform:translateY(-50%);
  border:none;background:transparent;color:var(--primary);font-family:inherit;font-weight:600;font-size:13px;line-height:1;
  padding:8px 10px;cursor:pointer;
}
.pw-meter{height:4px;border-radius:2px;background:var(--peri-100);margin-top:8px;overflow:hidden;}
.pw-meter span{display:block;height:100%;width:0;border-radius:2px;background:var(--peri-500);transition:width .2s,background .2s;}
.pw-meter span.weak{background:var(--red);}
.pw-meter span.ok{background:var(--amber-500);}
.pw-meter span.good{background:var(--teal-600);}
.field-hint{font-size:12px;color:var(--muted);margin-top:6px;line-height:1.4;}

.auth-consent{
  display:flex;gap:10px;align-items:flex-start;margin:4px 0 14px;
  font-size:12.5px;line-height:1.45;color:var(--muted);cursor:pointer;
}
.auth-consent[hidden]{display:none;}
.auth-consent input{width:18px;height:18px;margin-top:1px;flex:none;accent-color:var(--primary);}

.auth-error,.auth-success,.auth-notice{
  font-size:13px;line-height:1.45;border-radius:10px;padding:10px 12px;margin-bottom:12px;
}
.auth-error{color:#991B1B;background:#FEF2F2;border:1px solid #FECACA;}
.auth-success{color:var(--teal-800);background:var(--teal-50);border:1px solid var(--teal-200);}
.auth-notice{color:var(--purple-800);background:var(--purple-50);border:1px solid var(--purple-200);}
.auth-notice.warn{color:var(--amber-800);background:var(--amber-50);border-color:var(--amber-200);}
.auth-error[hidden],.auth-success[hidden],.auth-notice[hidden]{display:none;}

.link-btn{
  border:none;background:none;color:var(--primary);font-family:inherit;font-weight:600;font-size:13px;line-height:1.3;
  cursor:pointer;padding:0;text-decoration:underline;text-underline-offset:2px;
}
.auth-alt{display:block;margin:14px auto 0;text-decoration:none;}
.auth-foot{font-size:12px;color:var(--muted);text-align:center;line-height:1.5;margin:18px 12px 0;}

/* ── Account card on the profile tab ── */
.acct-line{display:flex;justify-content:space-between;align-items:baseline;gap:12px;margin-bottom:10px;}
.acct-label{font-size:13px;color:var(--muted);flex:none;}
.acct-value{font-size:14px;font-weight:600;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;}
.acct-verify{
  font-size:12.5px;color:var(--amber-800);background:var(--amber-50);border:1px solid var(--amber-200);
  border-radius:10px;padding:9px 11px;margin-bottom:12px;line-height:1.45;
}
.acct-verify[hidden]{display:none;}
.acct-verify .link-btn{font-size:12.5px;color:var(--amber-800);}
.acct-actions{display:flex;flex-direction:column;gap:8px;}
.acct-actions a.btn{text-decoration:none;}
.acct-actions [hidden]{display:none;}
.danger-zone{display:flex;flex-direction:column;gap:8px;margin:16px 0 8px;}
.btn-danger{color:var(--red);border-color:#FECACA;background:#FFF7F7;}

/* ── Account sheet contents ── */
.sheet-actions{display:flex;flex-direction:column;gap:10px;margin-top:6px;}
.sheet-cancel{display:block;margin:12px auto 0;color:var(--muted);text-decoration:none;}
.device-row{
  display:flex;align-items:center;gap:12px;padding:12px 0;border-top:1px solid var(--border);
}
.device-row:first-of-type{border-top:none;}
.device-info{flex:1;min-width:0;}
.device-name{font-size:14px;font-weight:700;color:var(--text);}
.device-meta{font-size:12px;color:var(--muted);margin-top:2px;}
.device-tag{
  font-size:11px;font-weight:700;color:var(--teal-800);background:var(--teal-50);
  border:1px solid var(--teal-200);border-radius:999px;padding:3px 9px;flex:none;
}
.btn-danger-solid{background:var(--red);color:#fff;padding:12px 20px;}
.btn-danger-solid:disabled{opacity:.6;}
