/* portal/styles.css — Portal SPA shell (Task 6). Palette, spacing and card
   language ported from mindfulous-site-deploy/portal.html (the token-based
   portal this SPA replaces) — phone-first, same navy/teal brand. */
:root {
  --navy:#002a68; --navy-2:#0a3a82; --ink:#0a1f3d; --slate:#5a6b86; --bg:#eef3fb;
  --accent:#2b66c6; /* #4885ee as text was 3.58:1 on white, 3.21:1 on --bg (S4); 5.50/4.94 now */ --teal:#0f7267; --teal-d:#0d6259; /* CTA gradient sampled 2.93/3.44/4.64 under white labels (S4); computed stops 4.57/5.80/7.22 keep the hue and 64% of the gloss delta */ --line:#e2e9f5; --card:#ffffff;
  --amber-bg:#fff7ed; --amber-ink:#9a3412; --green-bg:#ecfdf5; --green-ink:#047857;
}
* { box-sizing: border-box; }
html, body { margin:0; padding:0; }
body {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color: var(--ink); background: var(--bg); -webkit-font-smoothing: antialiased;
  overflow-x: hidden; /* never let a wide child create a horizontal scroll / clip */
}

/* Visually hidden but still in the accessibility tree. NOT [hidden] and NOT
   display:none — either would drop the node from the a11y tree entirely, which
   is the whole point of keeping it (see #brandname in index.html). Mirrors the
   clinic's .sr-only. */
.sr-only {
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap; border:0;
}

/* Brand bar.
   ⛔⛔ THIS BAR IS LIGHT ON PURPOSE, AND IT IS NOT A COSMETIC PREFERENCE.
   It carried a navy gradient and forced `filter: brightness(0) invert(1)` on
   the logo, which is how the old flat Mindfulous wordmark was made readable.
   The Wondehrful lockup is navy-and-cyan artwork on TRANSPARENT: on navy it
   disappears, and inverted it flattens to a white silhouette that throws away
   the cyan loops mark and the "ehr" accent. A light bar is the treatment the
   lockup was designed and approved for (clinic/styles.css #brand-header) and
   it is what makes the patient and clinician surfaces read as one product.
   ⚠️ Changing the bar's background changed EVERY colour sitting on it, and
   those were all picked for navy. Measured against #ffffff before shipping:
     .tag was #cbd9f2  -> 1.42:1  FAIL   (invisible, not merely dim)
     .tag now var(--slate) #5a6b86 -> 5.41:1  AA
     signout label var(--ink) #0a1f3d -> 16.45:1  AA
     signout border var(--slate) -> 5.41:1, clearing the 3:1 non-text floor
   ⛔ Do NOT use var(--line) #e2e9f5 for that border: it measures 1.22:1 on
   white, so the button would lose its visible bounds. */
.topbar { background: var(--card); border-bottom: 1px solid var(--line); padding: 14px 16px; }
.topbar-inner { max-width: 680px; margin: 0 auto; display:flex; align-items:center; gap:12px; min-width:0; }
.topbar img { height: 34px; width:auto; display:block; flex:0 0 auto; }
/* .sr-only in the markup hides this today (the lockup already shows the name).
   The colour is kept correct for the light bar so a tenant that needs the name
   visible again does not inherit white-on-white. */
.topbar .name { color:var(--ink); font-weight:700; font-size:17px; letter-spacing:.2px; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.topbar .tag { color:var(--slate); font-size:12px; margin-left:auto; display:flex; align-items:center; gap:5px; flex:0 0 auto; white-space:nowrap; }

/* ⚠️ `color` is stated explicitly, never inherited: this repo has five
   documented invisible-button incidents from a global button{color:#fff}
   default (impeccable D5). On a white bar that default is white-on-white. */
.signout-btn {
  appearance:none; border:1px solid var(--slate); cursor:pointer;
  padding:7px 13px; background: var(--card); color: var(--ink); font-weight:700;
  font-size:12.5px; border-radius:8px; flex:0 0 auto; white-space:nowrap;
  transition: background .12s ease, transform .12s ease;
}
.signout-btn:hover { background: #eef3fb; }
.signout-btn:active { transform: scale(.97); }
.signout-btn:disabled { opacity:.6; cursor:default; transform:none; }

/* Nav tabs (hash router) */
.nav-tabs {
  display:flex; gap:4px; overflow-x:auto; -webkit-overflow-scrolling:touch;
  justify-content: safe center; /* center the tabs; falls back to start when they overflow a small screen (no clipping) */
  background: var(--card); border-bottom:1px solid var(--line);
  padding: 8px 12px; scrollbar-width: none;
}
.nav-tabs::-webkit-scrollbar { display:none; }
.nav-tab {
  flex:0 0 auto; display:inline-block; padding:8px 14px; border-radius:999px;
  font-size:13.5px; font-weight:700; color: var(--slate); text-decoration:none;
  white-space:nowrap; background:transparent;
  transition: background .12s ease, color .12s ease;
}
.nav-tab:hover { background:#f4f7fd; color: var(--navy); }
.nav-tab.active { background: var(--navy); color:#fff; box-shadow: 0 2px 8px -2px rgba(0,42,104,.45); }

.wrap { max-width: 680px; margin: 0 auto; padding: 22px 16px 64px; }

/* Hero greeting */
.hero { margin: 6px 2px 18px; }
.hero h1 { font-family: Georgia, "Times New Roman", serif; color: var(--navy); font-size: 26px; line-height:1.2; margin: 0 0 6px; }
.hero p { color: var(--slate); margin:0; font-size:15px; }

/* At-a-glance overview tiles */
.glance-cap { color: var(--slate); font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.7px; margin: 4px 2px 9px; }
.glance { display:grid; grid-template-columns: repeat(3, 1fr); gap:10px; margin: 0 0 8px; }
.tile { background: var(--card); border:1px solid var(--line); border-radius:14px; padding:14px 14px 15px; box-shadow: 0 1px 2px rgba(10,31,61,.04); }
.tile .k { color: var(--slate); font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.6px; margin:0 0 7px; display:flex; align-items:center; gap:5px; }
.tile .v { color: var(--navy); font-size:18px; font-weight:700; line-height:1.15; font-variant-numeric: tabular-nums; }
.tile .v.sm { font-size:14px; font-weight:600; color: var(--ink); }
.tile.due .v { color: var(--amber-ink); }
@media (max-width: 520px) {
  .glance { grid-template-columns: 1fr 1fr; }
  .tile.msgs { grid-column: span 2; }
  .tile.msgs .v { font-size:15px; }
}

/* Sections */
section { margin-top: 26px; }
.sec-head { display:flex; align-items:center; gap:9px; margin: 0 2px 11px; }
.sec-head .ico { width:26px; height:26px; border-radius:8px; background:#e7f0ff; color:var(--navy); display:flex; align-items:center; justify-content:center; font-size:15px; flex:0 0 auto; }
.sec-head h2 { color: var(--navy); font-size:14px; text-transform:uppercase; letter-spacing:.6px; margin:0; font-weight:700; }

.card { background: var(--card); border:1px solid var(--line); border-radius:14px; padding:15px 17px; margin:0 0 11px; box-shadow: 0 1px 2px rgba(10,31,61,.05), 0 12px 26px -18px rgba(10,31,61,.18); }
/* Things to do (unit 2, 2026-08-04): outstanding work carries a quiet amber
   left edge so it reads as "needs you" without shouting — the same accent
   family the clinic uses for pending states. Cards inside .todo only. */
.todo .card { border-left: 3px solid #e8a33d; }
.row { display:flex; justify-content:space-between; align-items:flex-start; gap:12px; }
.ttl { font-weight:700; font-size:16px; color: var(--ink); margin:0; }
.when { color: var(--slate); font-size:14px; margin:5px 0 0; display:flex; align-items:center; gap:6px; }
.when .cal { color: var(--accent); }
.pill { display:inline-block; font-size:11.5px; font-weight:700; padding:4px 11px; border-radius:999px; background:#eef3ff; color: var(--navy); text-transform:capitalize; white-space:nowrap; letter-spacing:.2px; }

/* Sign-in / reply-style form controls (shared card language) */
.reply { margin-top:12px; }
.reply-label { display:block; font-size:13px; font-weight:700; color: var(--navy); margin:0 0 8px; }
.reply-input { width:100%; border:1px solid var(--line); border-radius:10px; padding:11px 12px; font:inherit; font-size:15px; color: var(--ink); resize:vertical; min-height:74px; }
.signin-input { min-height:0; resize:none; }
.reply-input:focus { outline:none; border-color: var(--accent); box-shadow:0 0 0 3px rgba(72,133,238,.15); }
.reply-actions { display:flex; align-items:center; gap:12px; margin-top:11px; flex-wrap:wrap; }
/* Primary action buttons share one glossy, kinetic language (Send / Pay /
   Set up membership). Motion is transform-only; the gloss + brighten on hover
   are paint-only (gradient + shadow), so nothing triggers layout. */
.reply-btn, .pay-btn, .mem-btn {
  appearance:none; border:0; cursor:pointer; padding:11px 22px;
  background: linear-gradient(180deg, #128478 0%, var(--teal) 52%, var(--teal-d) 100%);
  color:#fff; font-weight:700; font-size:15px; border-radius:10px; text-decoration:none;
  box-shadow: 0 2px 6px rgba(15,155,142,.30), inset 0 1px 0 rgba(255,255,255,.22);
  transition: background .14s ease, box-shadow .16s ease, transform .14s ease;
}
.reply-btn:hover, .pay-btn:hover, .mem-btn:hover {
  background: linear-gradient(180deg, var(--teal) 0%, var(--teal-d) 52%, #0b544d 100%); /* hover darkens instead of lightening; the old #1cb6a6 stop was 2.5:1 */
  box-shadow: 0 9px 20px -5px rgba(15,155,142,.45), inset 0 1px 0 rgba(255,255,255,.28);
  transform: translateY(-1px);
}
.reply-btn:active, .pay-btn:active, .mem-btn:active {
  transform: translateY(0) scale(.98);
  box-shadow: 0 2px 5px rgba(15,155,142,.30), inset 0 1px 0 rgba(255,255,255,.18);
}
.reply-btn:disabled, .mem-btn:disabled { opacity:.55; cursor:default; transform:none; box-shadow: 0 1px 3px rgba(15,155,142,.20); }
.reply-status { font-size:13.5px; font-weight:600; color: var(--green-ink); }
.reply-status.err { color: var(--amber-ink); }

.chooser-btn { padding:9px 16px; font-size:14px; }

.empty { color: var(--slate); font-size:14px; padding:14px 16px; background: var(--card); border:1px dashed var(--line); border-radius:12px; }

.foot { color: var(--slate); font-size:13px; line-height:1.6; margin: 30px 0 0; text-align:center; }
.foot a { color: var(--accent); text-decoration:none; font-weight:600; }
.foot .secure { display:block; margin-top:6px; font-size:12px; color:#8a98b0; }

.err { color: var(--amber-ink); background: var(--amber-bg); border:1px solid #fed7aa; padding:18px; border-radius:12px; font-size:15px; line-height:1.55; margin-bottom:14px; }
.err a { color: var(--amber-ink); font-weight:700; }
.loading { color: var(--slate); padding: 30px 4px; }

/* Status pills (invoices, care-plan goals, membership) */
.pill.open { background: var(--amber-bg); color: var(--amber-ink); }
.pill.paid, .pill.active, .pill.achieved { background: var(--green-bg); color: var(--green-ink); }
.pill.cp-active { background:#f1f3f7; color: var(--slate); }
.cp-chips { display:flex; gap:6px; flex-wrap:wrap; justify-content:flex-end; }
.pill.cp-coach { background:#eef3ff; color: var(--navy); text-transform:none; }
.pill.past_due { background:#fff1f0; color:#b42318; }
.pill.canceled, .pill.incomplete_expired, .pill.unpaid, .pill.paused { background:#f1f3f7; color: var(--slate); }
.pill.trialing, .pill.incomplete { background:#eef3ff; color: var(--navy); }

/* Invoices */
.inv-amts { color: var(--slate); font-size:13.5px; margin:7px 0 0; font-variant-numeric: tabular-nums; }
.inv-amts .bal { color: var(--navy); font-weight:700; }
.pay-btn { display:inline-flex; align-items:center; gap:7px; margin-top:13px; }
.receipt-btn {
  display:inline-flex; align-items:center; gap:7px; margin-top:11px; padding:9px 16px;
  background:#eef3ff; color: var(--navy); font-weight:700; font-size:14px; text-decoration:none; border-radius:10px;
  transition: background .14s ease, transform .14s ease, box-shadow .16s ease;
}
.receipt-btn:hover { background:#e2e9f5; transform: translateY(-1px); box-shadow:0 6px 14px -6px rgba(0,42,104,.30); }
.receipt-btn:active { transform: translateY(0) scale(.98); }

/* Records / document downloads */
.doc-dl { display:inline-flex; align-items:center; gap:6px; font-size:14px; font-weight:700; color: var(--accent); text-decoration:none; white-space:nowrap; flex:0 0 auto; }
.doc-dl:hover { text-decoration:underline; }
.docs { list-style:none; margin:9px 0 0; padding:0; display:flex; flex-wrap:wrap; gap:6px; }
.docs li { font-size:12.5px; color: var(--navy); background:#eef3ff; border-radius:8px; padding:4px 9px; }

/* Messages */
.msg { display:flex; gap:12px; }
.avatar { flex:0 0 auto; width:38px; height:38px; border-radius:50%; background:#e7f0ff; color:var(--navy); display:flex; align-items:center; justify-content:center; font-weight:700; font-size:14px; }
.msg-body { flex:1 1 auto; min-width:0; }
.message { white-space: pre-wrap; word-break: break-word; font-size:15px; line-height:1.55; color: var(--ink); margin:0; }
.muted { color: var(--slate); font-size:12.5px; margin:8px 0 0; }

/* Messages — nav unread badge (Task 8). #b45309 (amber-700) on white text
   (or vice versa) measures ~5.0:1 contrast — passes WCAG AA (>=4.5:1) for
   normal-size bold text. */
.nav-badge {
  display:inline-flex; align-items:center; justify-content:center;
  min-width:18px; height:18px; padding:0 5px; margin-left:6px;
  border-radius:999px; background:#b45309; color:#fff;
  font-size:11px; font-weight:800; line-height:1; vertical-align:middle;
}

/* Messages — thread list (Task 8) */
.thread-list-head { display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap; margin:0 2px 14px; }
.thread-list-head h2 { color: var(--navy); font-size:14px; text-transform:uppercase; letter-spacing:.6px; margin:0; font-weight:700; }
.new-convo-btn { padding:9px 16px; font-size:13.5px; min-height:44px; display:inline-flex; align-items:center; }
.thread-list { display:flex; flex-direction:column; }
.thread-card {
  display:block; width:100%; text-align:left; appearance:none; border:1px solid var(--line);
  cursor:pointer; min-height:44px; transition: box-shadow .16s ease, transform .14s ease;
}
.thread-card:hover { transform: translateY(-1px); box-shadow: 0 1px 2px rgba(10,31,61,.06), 0 16px 30px -18px rgba(10,31,61,.28); }
.thread-card:active { transform: translateY(0) scale(.995); }
.thread-row-head { display:flex; align-items:center; justify-content:space-between; gap:10px; }
.thread-topic { font-weight:700; font-size:15.5px; color: var(--ink); margin:0; flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.thread-preview { color: var(--slate); font-size:13.5px; margin:7px 0 0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.thread-meta { display:flex; align-items:center; justify-content:space-between; gap:10px; margin-top:9px; }
.thread-time { color: var(--slate); font-size:12px; }
.thread-unread-badge {
  background:#b45309; color:#fff; font-weight:800; font-size:11.5px; min-width:20px; height:20px;
  border-radius:999px; display:inline-flex; align-items:center; justify-content:center; padding:0 6px;
}
.pill.lane-provider { background:#eef3ff; color: var(--navy); }
.pill.lane-clinical { background: var(--green-bg); color: var(--green-ink); }
.pill.lane-office { background:#f1f3f7; color: var(--slate); }

/* Messages — start-a-new-conversation lane picker (Task 8) */
.thread-back-btn {
  appearance:none; border:0; background:none; cursor:pointer; padding:8px 2px; margin:0 0 10px;
  color: var(--accent); font-weight:700; font-size:14px; min-height:44px; display:inline-flex; align-items:center;
}
.lane-picker { display:flex; flex-direction:column; gap:9px; margin:2px 0 16px; }
.lane-card {
  appearance:none; text-align:left; border:1px solid var(--line); background:#fff; border-radius:12px;
  padding:13px 15px; cursor:pointer; min-height:44px; width:100%;
  transition: border-color .14s ease, box-shadow .16s ease, transform .14s ease;
}
.lane-card:hover { transform: translateY(-1px); box-shadow: 0 8px 18px -8px rgba(0,42,104,.25); }
.lane-card:active { transform: translateY(0) scale(.99); }
.lane-card.selected { border-color: var(--teal); box-shadow: 0 0 0 3px rgba(15,155,142,.16); }
.lane-title { font-weight:700; color: var(--navy); font-size:15px; margin:0 0 3px; }
.lane-sub { color: var(--slate); font-size:12.5px; margin:0; line-height:1.4; }
.new-convo-subject { width:100%; margin-bottom:12px; min-height:44px; }

/* Messages — thread view + chat bubbles (Task 8) */
.thread-view-title { color: var(--navy); font-size:14px; text-transform:uppercase; letter-spacing:.6px; margin:0; font-weight:700; }
.msg-list { display:flex; flex-direction:column; gap:12px; padding:6px 2px 16px; min-height:60px; }
.msg-row { display:flex; gap:10px; align-items:flex-end; width:100%; }
.msg-row.theirs { justify-content:flex-start; }
.msg-row.mine { justify-content:flex-end; }
.msg-row .avatar { width:32px; height:32px; font-size:12px; }
.msg-col { display:flex; flex-direction:column; gap:4px; min-width:0; max-width:78%; }
.msg-row.mine .msg-col { align-items:flex-end; }
.msg-sender { font-size:11.5px; font-weight:700; color: var(--slate); margin:0 3px; }
.msg-bubble { border-radius:16px; padding:10px 14px; font-size:15px; line-height:1.5; white-space:pre-wrap; word-break:break-word; margin:0; }
.msg-row.theirs .msg-bubble { background:#fff; border:1px solid var(--line); color: var(--ink); border-bottom-left-radius:4px; }
.msg-row.mine .msg-bubble {
  background: linear-gradient(180deg, #128478 0%, var(--teal) 52%, var(--teal-d) 100%); color:#fff;
  border-bottom-right-radius:4px; box-shadow: 0 2px 6px rgba(15,155,142,.22);
}
.msg-time { font-size:11px; color: var(--slate); margin:0 3px; }
.msg-doc-chip {
  display:inline-flex; align-items:center; gap:6px; font-size:12.5px; font-weight:700; color: var(--navy);
  background:#eef3ff; border-radius:8px; padding:5px 10px; text-decoration:none; margin-top:2px;
}
.msg-doc-chip:hover { background:#e2e9f5; }
.msg-pending .msg-bubble { opacity:.55; }
.msg-failed .msg-bubble { background:#fff1f0; color:#b42318; border:1px solid #fecaca; }
.msg-failed-note {
  appearance:none; border:0; background:none; cursor:pointer; text-align:right;
  font-size:12.5px; color:#b42318; font-weight:700; text-decoration:underline;
  min-height:44px; padding:0 2px; display:inline-flex; align-items:center; justify-content:flex-end;
}

/* Messages — sticky composer (Task 8), safe-area-aware for iOS home bars */
.composer {
  position:sticky; bottom:0; display:flex; gap:8px; align-items:flex-end;
  background: var(--bg); border-top:1px solid var(--line); margin-top:14px;
  padding: 10px 2px calc(10px + env(safe-area-inset-bottom));
}
.composer-textarea {
  flex:1 1 auto; min-height:44px; max-height:140px; border:1px solid var(--line); border-radius:14px;
  padding:11px 14px; font:inherit; font-size:15px; resize:none; color: var(--ink);
}
.composer-textarea:focus { outline:none; border-color: var(--accent); box-shadow:0 0 0 3px rgba(72,133,238,.15); }
.composer-send { flex:0 0 auto; min-width:44px; min-height:44px; padding:0 20px; }

/* Care plan */
.cp-summary { color: var(--slate); font-size:14px; line-height:1.55; margin:0 0 12px; }
.cp-spark { display:block; margin-top:10px; color: var(--accent); }

/* Membership (Concierge Care) — the portal's signature card */
.mem-card {
  background: linear-gradient(180deg,#ffffff 0%, #f9fdfc 100%);
  box-shadow: 0 1px 2px rgba(10,31,61,.05), 0 14px 30px -18px rgba(12,131,119,.30), inset 0 2px 0 rgba(15,155,142,.55);
}
.mem-plan-name { font-family: Georgia, "Times New Roman", serif; color: var(--navy); font-size:19px; margin:0 0 3px; }
.mem-price { color: var(--ink); font-size:15px; font-weight:600; margin:0; font-variant-numeric: tabular-nums; }
.mem-price .per { color: var(--slate); font-weight:400; font-size:13px; }
.mem-detail { color: var(--slate); font-size:13.5px; margin:6px 0 0; }
.mem-detail strong { color: var(--ink); font-weight:600; }
.mem-tagline { color: var(--slate); font-size:12.5px; margin:9px 0 0; line-height:1.5; }
.mem-note { color: var(--slate); font-size:12.5px; margin-top:10px; line-height:1.5; }
.mem-banner { display:flex; align-items:flex-start; gap:10px; background: var(--amber-bg); border:1px solid #fed7aa; color: var(--amber-ink); border-radius:12px; padding:14px 16px; margin:0 0 12px; font-size:14px; line-height:1.5; }
.mem-banner .ico { font-size:18px; flex:0 0 auto; background:none; width:auto; height:auto; }
.mem-actions { display:flex; gap:10px; flex-wrap:wrap; margin-top:14px; }
.mem-form { margin-top:14px; padding-top:14px; border-top:1px solid var(--line); }
#mem-payment-element { min-height:150px; margin-bottom:12px; width:100%; }
.mem-err { color: var(--amber-ink); background: var(--amber-bg); border:1px solid #fed7aa; padding:11px 13px; border-radius:10px; font-size:13.5px; margin-top:11px; line-height:1.5; }
.mem-notice { color: var(--teal-d); background: var(--green-bg); border:1px solid #b8ecd9; padding:11px 13px; border-radius:10px; font-size:13.5px; margin-top:11px; line-height:1.5; }
.mem-confirm { background:#f8f5ff; border:1px solid #e3d9fb; border-radius:12px; padding:13px 15px; margin-top:13px; }
.mem-confirm p { margin:0 0 11px; font-size:14px; color: var(--ink); line-height:1.5; }
.mem-secure { display:flex; align-items:center; gap:6px; color: var(--slate); font-size:11.5px; margin-top:10px; }

/* Secondary + danger membership buttons: kinetic lift, quieter than primary */
.mem-btn-secondary {
  appearance:none; border:1px solid var(--line); cursor:pointer; padding:10px 18px; background:#fff;
  color: var(--navy); font-weight:700; font-size:14px; border-radius:10px;
  transition: background .14s ease, transform .14s ease, box-shadow .16s ease;
}
.mem-btn-secondary:hover { background:#f4f7fd; transform: translateY(-1px); box-shadow:0 6px 14px -6px rgba(0,42,104,.28); }
.mem-btn-secondary:active { transform: translateY(0) scale(.98); }
.mem-btn-secondary:disabled { opacity:.55; cursor:default; transform:none; box-shadow:none; }
.mem-btn-danger {
  appearance:none; border:0; cursor:pointer; padding:10px 18px; background:#c0362c;
  color:#fff; font-weight:700; font-size:14px; border-radius:10px;
  box-shadow:0 2px 6px rgba(192,54,44,.28);
  transition: background .14s ease, transform .14s ease, box-shadow .16s ease;
}
.mem-btn-danger:hover { background:#a52e25; transform: translateY(-1px); box-shadow:0 8px 18px -5px rgba(192,54,44,.42); }
.mem-btn-danger:active { transform: translateY(0) scale(.98); }
.mem-btn-danger:disabled { opacity:.55; cursor:default; transform:none; box-shadow:none; }

.mem-fade { animation: memFadeIn .28s ease both; }
@keyframes memFadeIn { from { opacity:0; transform: translateY(4px); } to { opacity:1; transform:none; } }

/* Kinetic UI: transform/opacity only, honors prefers-reduced-motion */
.fade-in { animation: portalFadeIn .28s ease both; }
@keyframes portalFadeIn { from { opacity:0; transform: translateY(4px); } to { opacity:1; transform:none; } }
@media (prefers-reduced-motion: reduce) {
  .fade-in, .mem-fade { animation:none; opacity:1; transform:none; }
  .signout-btn, .reply-btn, .pay-btn, .mem-btn, .mem-btn-secondary, .mem-btn-danger, .receipt-btn, .nav-tab,
  .thread-card, .lane-card { transition:none; }
  .signout-btn:active, .reply-btn:active, .reply-btn:hover,
  .pay-btn:active, .pay-btn:hover, .mem-btn:active, .mem-btn:hover,
  .mem-btn-secondary:active, .mem-btn-secondary:hover,
  .mem-btn-danger:active, .mem-btn-danger:hover,
  .receipt-btn:active, .receipt-btn:hover,
  .thread-card:active, .thread-card:hover,
  .lane-card:active, .lane-card:hover { transform:none; }
}

/* ── Results (portal campaign pillar 2) ────────────────────────────────────
   ⚠️ This stylesheet is the FULL stylesheet for the portal SPA: any class a
   module emits and this file does not define ships UNSTYLED, which is exactly
   how "Set up membership" once shipped as a plain grey button. Every class
   emitted by portal/results-ui.js is defined below.

   The results LIST follows the portal's existing card/row idiom, like every
   other section. The analyte DETAIL is a real table because it genuinely is
   tabular and a patient reads down the columns; the portal had no table rules
   at all before this, so they are defined here from scratch rather than
   inherited. The wrapper scrolls on its own so a wide table never makes the
   PAGE scroll sideways on a phone. */

.res-meta {
  margin:0 0 10px; font-size:12px; font-weight:600; letter-spacing:.04em;
  text-transform:uppercase; color:var(--slate);
}

.res-note, .res-impression {
  margin:0 0 12px; padding:12px 14px; border-radius:8px;
  background:var(--bg); border-left:3px solid var(--teal);
}
.res-impression { border-left-color:var(--accent); }
.res-note p, .res-impression p { margin:4px 0 0; font-size:15px; line-height:1.5; color:var(--ink); }
.res-note-label {
  font-size:11px; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
  color:var(--slate);
}

/* The table's own scroll container. Without this a long analyte name or a wide
   reference range would push the whole page sideways on a narrow screen. */
.res-table-wrap { width:100%; overflow-x:auto; -webkit-overflow-scrolling:touch; }

.res-table {
  width:100%; border-collapse:collapse; font-size:14px;
  /* min-width is a FLOOR, not a competing width: below this the wrapper
     scrolls rather than the columns collapsing into unreadable slivers. */
  min-width:320px;
}
.res-table th {
  text-align:left; padding:8px 10px; border-bottom:2px solid var(--line);
  font-size:11px; font-weight:700; letter-spacing:.05em; text-transform:uppercase;
  color:var(--slate); white-space:nowrap;
}
.res-table td { padding:10px; border-bottom:1px solid var(--line); vertical-align:top; color:var(--ink); }
.res-table tr:last-child td { border-bottom:none; }

.res-analyte-name  { font-weight:600; }
.res-analyte-value { white-space:nowrap; }
.res-analyte-range { color:var(--slate); white-space:nowrap; }

/* A flag chip sits beside the value rather than in its own column, so the
   table stays three columns wide on a phone. */
.res-flag {
  display:inline-block; margin-left:8px; padding:2px 8px; border-radius:999px;
  font-size:11px; font-weight:700; background:var(--amber-bg); color:var(--amber-ink);
  white-space:nowrap;
}
.res-flag-critical { background:#fef2f2; color:#b91c1c; }

/* ── Visits (scheduling tab) ────────────────────────────────────────────
   ⚠️ Every class portal/visits-ui.js emits is defined below, or it reuses an
   existing class from another module's section above (card, row, ttl, when,
   pill, the mem- family, reply-btn, new-convo-btn, thread-back-btn,
   thread-list-head, receipt-btn, sec-head, loading, empty, err, fade-in —
   all already defined).
   #visit-payment-element is an id (not a class), styled to mirror
   #mem-payment-element above, since Stripe Elements is mounted onto it the
   same way billing-ui.js mounts onto #mem-payment-element.

   DO NOT WRITE A STAR FOLLOWED BY A SLASH ANYWHERE IN A CSS COMMENT.
   The first draft of this header listed reused classes as a slash-separated
   run and wrote the mem- family as a glob: a star, then a slash before the
   next name. That sequence CLOSES A CSS COMMENT. Everything after it was
   parsed as CSS, and the parser's error recovery swallowed the very next
   rule (.visit-cutoff-hint) into an invalid selector — so the rule was
   present in the FILE and absent from the STYLESHEET.
   Grepping styles.css for the class name found it and reported fine. Only a
   COMPUTED-STYLE check caught it: the element rendered identically to a bare
   div. Same class of trap as the unstyled modal that four review rounds and a
   whole test suite missed.
   (The second attempt at this warning failed the same way, because it QUOTED
   the offending sequence in order to explain it. Describe it in words.) */

.visit-cutoff-hint { color: var(--amber-ink); font-size:12.5px; margin:8px 0 0; line-height:1.4; }

/* HEALTH COACHING S5: the provider line and the join line under a visit's time
   (Visits list, Home list, confirm and pay screens). Secondary text in the
   slate token (5.41:1 on the card); no colour carries meaning; no motion. */
.visit-with { color: var(--slate); font-size:13.5px; margin:4px 0 0; line-height:1.4; }
.visit-join { color: var(--slate); font-size:13.5px; margin:2px 0 0; line-height:1.4; }
.visit-what { margin:0 0 12px; }

.visit-type-grid { display:flex; flex-direction:column; gap:10px; margin:2px 0 4px; }
.visit-type-card {
  appearance:none; text-align:left; border:1px solid var(--line); background:#fff; border-radius:12px;
  padding:13px 15px; cursor:pointer; min-height:44px; width:100%; display:flex; align-items:center; gap:12px;
  transition: border-color .14s ease, box-shadow .16s ease, transform .14s ease;
}
.visit-type-card:hover { transform: translateY(-1px); box-shadow: 0 8px 18px -8px rgba(0,42,104,.25); }
.visit-type-card:active { transform: translateY(0) scale(.99); }
.visit-type-color { flex:0 0 auto; width:14px; height:14px; border-radius:50%; background: var(--accent); }
.visit-type-name { font-weight:700; color: var(--navy); font-size:15px; margin:0; }
.visit-type-duration { color: var(--slate); font-size:12.5px; margin:2px 0 0; }

.visit-slot-day { color: var(--navy); font-size:13px; font-weight:700; margin:16px 2px 8px; }
.visit-slot-day:first-child { margin-top:2px; }
.visit-slot-grid { display:flex; flex-wrap:wrap; gap:8px; margin-bottom:4px; }
.visit-slot-btn {
  appearance:none; border:1px solid var(--line); background:#fff; color: var(--navy);
  font-weight:700; font-size:13.5px; padding:9px 14px; border-radius:10px; cursor:pointer; min-height:44px;
  transition: background .14s ease, border-color .14s ease, transform .14s ease;
}
.visit-slot-btn:hover { background:#f4f7fd; transform: translateY(-1px); }
.visit-slot-btn:active { transform: translateY(0) scale(.97); }
.visit-slot-btn:disabled { opacity:.5; cursor:default; transform:none; }

.visit-attestation-box { background: var(--bg); border-left:3px solid var(--teal); border-radius:8px; padding:13px 15px; margin:12px 0; font-size:14px; line-height:1.5; color: var(--ink); }
.visit-attestation-row { display:flex; align-items:flex-start; gap:9px; margin:12px 0; font-size:14px; color: var(--ink); line-height:1.45; }
.visit-attestation-row input[type="checkbox"] { margin-top:3px; flex:0 0 auto; width:17px; height:17px; }

.visit-pay-amount { color: var(--navy); font-size:22px; font-weight:700; margin:0; font-variant-numeric: tabular-nums; }
.visit-pay-expiry { color: var(--slate); font-size:13px; margin:6px 0 0; }
#visit-payment-element { min-height:150px; margin:14px 0 12px; width:100%; }

/* Card-on-file offer on the booked-confirmation screen (queue-2 unit 2).
   Separated from the confirmation above by the same rule .mem-form uses, so
   the offer reads as a second, optional thing rather than as part of the
   booking result. */
.visit-card-offer { margin-top:16px; padding-top:14px; border-top:1px solid var(--line); }
/* ⭐ The money sentence, and the highest-stakes line on this screen (B4): it
   is the one statement a patient will check before typing a card number. It
   gets its own weight and colour rather than dissolving into .mem-detail's
   grey. --green-ink on white measures 5.48:1, comfortably past 4.5:1 (and
   5.20:1 if it ever lands on --green-bg). */
.visit-card-reassure { color: var(--green-ink); font-weight:600; font-size:13.5px; margin:8px 0 0; line-height:1.5; }
#visit-card-element { min-height:150px; margin:14px 0 12px; width:100%; }

@media (prefers-reduced-motion: reduce) {
  .visit-type-card, .visit-slot-btn { transition:none; }
  .visit-type-card:active, .visit-type-card:hover,
  .visit-slot-btn:active, .visit-slot-btn:hover { transform:none; }
}

/* ── Assigned forms (pillar 4 unit B) ──────────────────────────────────────
   Every class portal/forms-ui.js emits is defined here. This stylesheet is the
   WHOLE stylesheet for this SPA, so an undefined class ships unstyled and the
   only symptom is a form that looks broken to a patient. */

.form-open-btn, .form-back-btn, .form-submit-btn {
  appearance:none; cursor:pointer; font-weight:700; border-radius:10px;
  transition: background .14s ease, transform .14s ease, box-shadow .16s ease;
}
.form-open-btn, .form-submit-btn {
  border:none; padding:10px 18px; font-size:14.5px;
  background: var(--navy); color:#fff;
}
.form-open-btn { margin-top:11px; }
.form-open-btn:hover, .form-submit-btn:hover { background: var(--navy-2); transform: translateY(-1px); box-shadow:0 8px 18px -6px rgba(0,42,104,.42); }
.form-open-btn:active, .form-submit-btn:active { transform: translateY(0) scale(.98); }
.form-submit-btn:disabled { opacity:.5; cursor:default; transform:none; box-shadow:none; }

.form-back-btn {
  border:1px solid var(--line); background:#fff; color: var(--navy);
  padding:7px 13px; font-size:13px; margin-bottom:12px;
}
.form-back-btn:hover { background:#f4f7fd; }
.form-back-btn:disabled { opacity:.5; cursor:default; }

.form-status-done { color: var(--green-ink); font-size:13.5px; margin:8px 0 0; line-height:1.5; }
.form-instruction { color: var(--ink); font-size:15px; line-height:1.55; margin:4px 0 10px; }
.form-due { color: var(--slate); font-size:13px; margin:0 0 12px; }
.form-attribution { color: var(--slate); font-size:11.5px; line-height:1.5; margin:18px 0 0; }
.form-submitted-note { color: var(--ink); font-size:15px; line-height:1.55; margin:6px 0 0; }

.form-save-status { color: var(--slate); font-size:12.5px; min-height:17px; margin:0 0 10px; }
.form-save-failed { color: var(--amber-ink); }
.form-err-inline { color: var(--amber-ink); font-size:13px; line-height:1.5; margin:8px 0 0; }

.form-turnstile { background: var(--card); border:1px solid var(--line); border-radius:12px; padding:13px 15px; margin:0 0 14px; }
.form-turnstile-note { color: var(--slate); font-size:13px; margin:0 0 10px; line-height:1.5; }
.form-turnstile-host { min-height:65px; }

.form-items { display:flex; flex-direction:column; gap:12px; }

.form-item {
  background: var(--card); border:1px solid var(--line); border-radius:12px;
  padding:14px 16px; margin:0; min-width:0;
}
/* ⚠️ .form-item-text is a <legend>. A legend's default rendering sits ASTRIDE
   the fieldset's top border, so the question text rode out of the card frame
   (Hani, 2026-08-04 smoke, GAD-7 screenshot). Any float value other than none
   strips that special rendering per the HTML spec, in every engine, without
   costing the fieldset/legend semantics screen readers announce. The width
   pins it to the card's content box; the clear on .form-choices closes the
   float's formatting context. */
.form-item-text { float:left; width:100%; color: var(--ink); font-size:15px; font-weight:600; line-height:1.5; padding:0; margin:0; }
.form-choices { clear:both; display:flex; flex-direction:column; gap:7px; margin-top:11px; }
.form-choice { display:flex; align-items:flex-start; gap:9px; cursor:pointer; font-size:14.5px; color: var(--ink); line-height:1.45; }
.form-choice-input { margin-top:2px; flex:0 0 auto; width:18px; height:18px; }
.form-choice-input:disabled { cursor:default; }
.form-choice-label { min-width:0; }

/* ⛔⛔ The flagged item and the crisis panel below it. This is the safety
   surface, not decoration: it has to read as urgent and it has to be legible on
   a phone at 2am. Do not tone it down to match the rest of the palette. */
.form-item-flagged { border-color:#f0b6b0; box-shadow:0 0 0 3px rgba(192,54,44,.10); }

.form-crisis {
  background:#fff5f4; border:1px solid #f0b6b0; border-left:4px solid #c0362c;
  border-radius:12px; padding:16px 17px; margin:0;
}
.form-crisis-head { color:#8f2018; font-size:16.5px; font-weight:700; margin:0 0 9px; line-height:1.35; }
.form-crisis-line { color: var(--ink); font-size:15px; line-height:1.55; margin:0 0 9px; }
.form-crisis-actions { display:flex; gap:10px; flex-wrap:wrap; margin:12px 0 4px; }
.form-crisis-call {
  display:inline-flex; align-items:center; justify-content:center; gap:7px;
  padding:11px 20px; background:#c0362c; color:#fff; font-weight:700; font-size:15.5px;
  text-decoration:none; border-radius:10px;
  transition: background .14s ease, transform .14s ease;
}
.form-crisis-call:hover { background:#a52e25; transform: translateY(-1px); }
.form-crisis-call:active { transform: translateY(0) scale(.98); }
.form-crisis-note { color: var(--slate); font-size:13px; line-height:1.5; margin:11px 0 0; }
.form-crisis-ack {
  appearance:none; cursor:pointer; margin-top:13px; padding:9px 16px;
  border:1px solid #f0b6b0; background:#fff; color:#8f2018;
  font-weight:700; font-size:14px; border-radius:10px;
  transition: background .14s ease;
}
.form-crisis-ack:hover { background:#fff0ee; }
.form-crisis-ack:disabled { opacity:.5; cursor:default; }

.form-submit-row { display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap; margin-top:16px; }
.form-unanswered { color: var(--slate); font-size:13px; margin:0; }

/* Uploading a record from the Records tab (mig 244 + 247, Option B).
   ⛔ Every class this feature emits has a rule here. Rule B1's first row: an
   emitted class with no CSS rule ships a highest-stakes screen as browser-default
   scratch HTML, which this campaign counted 6 of on the results-release panel
   alone. */
.doc-upload-input {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 0.95rem;
  color: var(--ink, #23303b);
}
.doc-upload-btn {
  flex: 0 0 auto;
  padding: 0.55rem 1.1rem;
  border: 0;
  border-radius: 8px;
  background: #17607a;
  color: #fff;
  font-weight: 600;
  cursor: pointer;
}
.doc-upload-btn:disabled {
  opacity: 0.6;
  cursor: default;
}
/* ⚠️ Tap target on a phone. The portal's primary actions are 44px and this is
   one; a control a patient cannot reliably hit is not a control. */
@media (pointer: coarse) {
  .doc-upload-btn { min-height: 44px; }
}
.doc-upload-status {
  margin-top: 0.5rem;
  min-height: 1.2em;
}
