:root {
  --color-primary: #104f55;
  --color-chat-bubble: #f0f4f5;
  --color-bg-main: #ffffff;
  --color-bg-soft: #f8f9fa;
  --color-text-primary: #1a1d20;
  --color-text-secondary: #636e72;
  --color-on-track: #198754;
  --color-alert: #d63031;

  /* Soft tints derived from the tokens above, for friendlier card surfaces
     and shadows — not a departure from the design.md palette. */
  --color-primary-tint: #e9f0ef;
  --color-on-track-tint: #e8f5ec;
  --color-patient: #6b8f9c;
  /* Brighter cyan-teal reserved for the AI marker — related to the brand
     primary but distinctly more synthetic, so it reads as "generated". */
  --color-ai-accent: #12989e;
  /* Comparison card: bars sit a shade lighter than the brand primary so the
     dark benchmark line reads clearly where it crosses them. */
  --color-cohort-bar: #3a7d84;
  --color-cohort-line: #16323a;
  --shadow-soft: 0 4px 20px rgba(16, 79, 85, 0.08);
  --shadow-softer: 0 2px 10px rgba(16, 79, 85, 0.06);

  --radius-card: 22px;
  --radius-item: 16px;

  --font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", Roboto, sans-serif;

  --space-xs: 6px;
  --space-sm: 12px;
  --space-md: 20px;

  --touch-target-min: 48px;
  --mobile-viewport: 393px;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: var(--font-family);
  background: var(--color-bg-soft);
  color: var(--color-text-primary);
}

.icon-agent {
  width: 22px;
  height: 22px;
}

.icon-person {
  width: 24px;
  height: 24px;
}

.h1-greeting {
  font-size: 28px;
  line-height: 36px;
  font-weight: 700;
  margin: 0;
}

.h2-section {
  font-size: 20px;
  line-height: 26px;
  font-weight: 600;
  margin: 0;
}

.body-chat-text {
  font-size: 16px;
  line-height: 24px;
  font-weight: 400;
}

.caption-label {
  font-size: 14px;
  line-height: 20px;
  font-weight: 500;
}

.disclaimer-text {
  font-size: 12px;
  line-height: 16px;
  font-weight: 400;
  color: var(--color-text-secondary);
}

[hidden] {
  display: none !important;
}

.app {
  max-width: var(--mobile-viewport);
  margin: 0 auto;
  min-height: 100vh;
  /* Never resolves to pure white — the tint runs the full height so the white
     cards stay legible as raised surfaces rather than blending into the page. */
  background: linear-gradient(180deg, #e2edeb 0%, #edf4f3 38%, #f1f7f6 100%);
  position: relative;
  display: flex;
  flex-direction: column;
  overflow-x: hidden;
}

.screen {
  flex: 1;
  display: flex;
  flex-direction: column;
  /* Anchors the care team sheet, which covers the screen it belongs to. */
  position: relative;
}

/* The chat sits on plain white. The hub's tint is there to lift its cards off
   the page; a message feed has no cards to lift, so the tint just competed
   with the bubbles. */
.screen--chat {
  background: var(--color-bg-main);
}

.screen--hub {
  padding: var(--space-md) 16px calc(var(--touch-target-min) + var(--space-md) * 2);
  gap: var(--space-md);
}

.app:not([data-route="hub"]) .chat-fab {
  display: none;
}

/* Brand lockup */

.brand-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  min-width: 0;
}

.brand__mark {
  flex: 0 0 auto;
  display: flex;
  color: var(--color-primary);
}

.brand__mark svg {
  width: 32px;
  height: 32px;
}

.brand__text {
  display: flex;
  flex-direction: column;
  line-height: 1;
}

/* Supplied logo artwork sits on a flat cream field. `darken` keeps the dark
   teal strokes and lets the header show through anywhere the art is lighter
   than the backdrop, which hides the rectangle without needing an alpha cut. */
.brand__logo {
  height: 54px;
  width: auto;
  mix-blend-mode: darken;
}

/* Art mode: photo artwork vs. the drawn icon set. */
[data-art="photo"] .brand__mark,
[data-art="photo"] .brand__text,
[data-art="icon"] .brand__logo {
  display: none;
}

[data-art="photo"] .checklist__thumb svg,
[data-art="icon"] .checklist__photo {
  display: none;
}

.brand__platform {
  font-size: 12px;
  font-weight: 500;
  color: var(--color-text-secondary);
  letter-spacing: 0.01em;
}

.brand__name {
  font-size: 22px;
  font-weight: 700;
  color: var(--color-primary);
  letter-spacing: -0.02em;
}

/* Welcome banner */

.welcome-banner {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-sm);
}

.welcome-banner__eyebrow {
  color: var(--color-text-secondary);
  margin: 0 0 var(--space-xs);
}

.welcome-banner__greeting {
  color: var(--color-text-primary);
}

/* Recovery day reference — always visible rather than behind a swipe.
   Bottom-aligned so it shares a baseline with the patient's name instead of
   floating in the gap between the two lines of the greeting. */
.day-chip {
  flex: 0 0 auto;
  align-self: flex-end;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  padding: 7px 12px;
  border-radius: 999px;
  background: var(--color-bg-main);
  color: var(--color-primary);
  font-weight: 600;
  white-space: nowrap;
  box-shadow: var(--shadow-softer);
}

.day-chip__icon {
  display: flex;
}

.day-chip__icon svg {
  width: 15px;
  height: 15px;
}

/* User menu */

.user-menu {
  position: relative;
  flex: 0 0 auto;
}

.user-menu__avatar {
  width: var(--touch-target-min);
  height: var(--touch-target-min);
  border-radius: 50%;
  border: none;
  background: var(--color-bg-main);
  color: var(--color-text-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: var(--shadow-softer);
}

.user-menu__panel {
  position: absolute;
  top: calc(100% + var(--space-xs));
  right: 0;
  z-index: 10;
  display: flex;
  flex-direction: column;
  min-width: 196px;
  background: var(--color-bg-main);
  border-radius: var(--radius-item);
  box-shadow: var(--shadow-soft);
  padding: var(--space-xs);
}

.user-menu__item {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  min-height: var(--touch-target-min);
  padding: 0 var(--space-sm);
  background: none;
  border: none;
  border-radius: 12px;
  color: var(--color-text-primary);
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
}

.user-menu__item:hover {
  background: var(--color-bg-soft);
}

.user-menu__icon {
  font-size: 16px;
}

/* Demo affordance, not a patient feature — set apart from the real items. */
.user-menu__item--reset {
  margin-top: 4px;
  padding-top: 8px;
  border-top: 1px solid #eceff0;
  border-radius: 0 0 12px 12px;
  color: var(--color-text-secondary);
  font-size: 13px;
  white-space: nowrap;
}

/* Metric carousel */

.metric-carousel {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.metric-track {
  display: flex;
  gap: var(--space-sm);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  /* Bleed to the screen edges so the next card peeks in, then pad back. */
  margin: 0 -16px;
  padding: 4px 16px;
}

.metric-track::-webkit-scrollbar {
  display: none;
}

.metric-card {
  position: relative;
  flex: 0 0 100%;
  scroll-snap-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-xs);
  text-align: center;
  background: var(--color-bg-main);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-soft);
  padding: var(--space-md);
}

.metric-card__title {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
}

.metric-card__title--top {
  margin-top: var(--space-xs);
}

.metric-card__check {
  color: var(--color-on-track);
  font-size: 18px;
  font-weight: 700;
}

.metric-card__subtitle {
  color: var(--color-text-secondary);
  margin: 0;
}

.metric-card__body {
  margin: 0;
  color: var(--color-text-secondary);
}

.metric-card__body strong {
  color: var(--color-text-primary);
  font-weight: 700;
}

/* Info affordance */

.info-btn {
  position: absolute;
  top: var(--space-sm);
  right: var(--space-sm);
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: none;
  background: #dfe4e6;
  color: #ffffff;
  font-family: Georgia, "Times New Roman", serif;
  font-style: italic;
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  z-index: 2;
}

.info-btn[aria-expanded="true"] {
  background: var(--color-primary);
}

.info-popover {
  position: absolute;
  top: calc(var(--space-sm) + 26px);
  right: var(--space-sm);
  left: var(--space-sm);
  z-index: 3;
  text-align: left;
  background: var(--color-text-primary);
  border-radius: 14px;
  padding: var(--space-sm);
  box-shadow: var(--shadow-soft);
}

.info-popover p {
  margin: 0;
  color: #ffffff;
}

/* Dot navigation */

.metric-dots {
  display: flex;
  justify-content: center;
  gap: var(--space-xs);
}

.metric-dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: #cfd6d8;
  cursor: pointer;
  transition: background 0.2s ease, width 0.2s ease;
}

.metric-dot[aria-selected="true"] {
  background: var(--color-primary);
  width: 20px;
  border-radius: 4px;
}

/* Walking chart */

.walk-chart {
  position: relative;
  width: 100%;
  margin: var(--space-xs) 0 var(--space-sm);
}

/* --- Card entrances --- */
/* Each runs once, when its card is first actually looked at. */

.metric-card__title.is-revealing {
  animation: title-rise 0.55s ease-out 0.45s backwards;
}

@keyframes title-rise {
  from { opacity: 0; transform: translateY(9px); }
  to { opacity: 1; transform: translateY(0); }
}

.metric-card__title.is-revealing .metric-card__check {
  display: inline-block;
  animation: check-pop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) 0.72s backwards;
}

@keyframes check-pop {
  from { opacity: 0; transform: scale(0.2) rotate(-25deg); }
  to { opacity: 1; transform: scale(1) rotate(0deg); }
}

/* Bars grow out of the baseline, left to right. fill-box so the origin is the
   bar's own bottom edge rather than the SVG's. */
.walk-chart.is-revealing .walk-chart__bar,
.cohort-chart.is-revealing .cohort-chart__bar {
  transform-box: fill-box;
  transform-origin: bottom;
  animation: bar-grow 0.55s cubic-bezier(0.22, 0.61, 0.36, 1) backwards;
}

@keyframes bar-grow {
  from { transform: scaleY(0); }
  to { transform: scaleY(1); }
}

/* The benchmark line wipes in after the bars it is measuring. Clip rather
   than stroke-dashoffset, which is already spoken for by the dash pattern. */
.cohort-chart.is-revealing .cohort-chart__line--cohort {
  animation: line-wipe 0.75s ease-out 0.5s backwards;
}

@keyframes line-wipe {
  from { clip-path: inset(0 100% 0 0); }
  to { clip-path: inset(0 -6px 0 0); }
}

.walk-chart.is-revealing .walk-chart__peak-label,
.cohort-chart.is-revealing .cohort-chart__peak-label {
  animation: label-fade 0.4s ease-out 0.95s backwards;
}

@keyframes label-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .metric-card__title.is-revealing,
  .metric-card__title.is-revealing .metric-card__check,
  .walk-chart.is-revealing .walk-chart__bar,
  .cohort-chart.is-revealing .cohort-chart__bar,
  .cohort-chart.is-revealing .cohort-chart__line--cohort,
  .walk-chart.is-revealing .walk-chart__peak-label,
  .cohort-chart.is-revealing .cohort-chart__peak-label {
    animation: none;
  }
}

/* --- Cohort comparison chart --- */

.chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 10px;
  font-size: 12px;
  color: var(--color-text-secondary);
}

.chart-legend__item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* "You" is a filled block because it is a bar; the cohort is a dashed rule
   because it is a benchmark. Shape carries the difference, not just colour. */
.chart-legend__swatch--you {
  width: 11px;
  height: 11px;
  border-radius: 3px;
  background: var(--color-cohort-bar);
}

.chart-legend__swatch--cohort {
  width: 16px;
  height: 0;
  border-top: 2.5px dashed var(--color-cohort-line);
}

.cohort-chart {
  position: relative;
  width: 100%;
  margin: 6px 0 var(--space-sm);
}

.cohort-chart__svg {
  width: 100%;
  height: auto;
  display: block;
  overflow: visible;
}

.cohort-chart__baseline {
  stroke: #dfe6e8;
  stroke-width: 1;
}

.cohort-chart__bar {
  fill: var(--color-cohort-bar);
}

.cohort-chart__line {
  fill: none;
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Near-black so the benchmark stays legible both where it crosses the bars
   and where it runs over the white card. */
.cohort-chart__line--cohort {
  stroke: var(--color-cohort-line);
  stroke-dasharray: 5 4;
}

.cohort-chart__axis-label {
  font-size: 10px;
  fill: var(--color-text-secondary);
  text-anchor: middle;
}

.cohort-chart__peak-label {
  font-size: 11px;
  font-weight: 700;
  fill: var(--color-cohort-line);
  text-anchor: middle;
}

.cohort-chart__hit {
  fill: transparent;
  cursor: pointer;
}

.cohort-chart__tip {
  position: absolute;
  transform: translate(-50%, -100%);
  display: flex;
  flex-direction: column;
  gap: 1px;
  background: var(--color-text-primary);
  color: #ffffff;
  border-radius: 8px;
  padding: 6px 9px;
  font-size: 11px;
  line-height: 1.45;
  white-space: nowrap;
  pointer-events: none;
  z-index: 3;
}

.walk-chart__svg {
  width: 100%;
  height: auto;
  display: block;
  overflow: visible;
}

.walk-chart__bar {
  fill: var(--color-primary);
  cursor: pointer;
  transition: opacity 0.15s ease;
}

.walk-chart__bar:hover,
.walk-chart__bar[data-active="true"] {
  opacity: 0.75;
}

.walk-chart__baseline {
  stroke: #e4e8e9;
  stroke-width: 1;
}

.walk-chart__axis-label {
  fill: var(--color-text-secondary);
  font-size: 10px;
  font-family: var(--font-family);
  text-anchor: middle;
}

.walk-chart__peak-label {
  fill: var(--color-text-primary);
  font-size: 11px;
  font-weight: 700;
  font-family: var(--font-family);
  text-anchor: middle;
}

.walk-chart__tip {
  position: absolute;
  transform: translate(-50%, -100%);
  background: var(--color-text-primary);
  color: #ffffff;
  border-radius: 8px;
  padding: 4px 8px;
  font-size: 11px;
  line-height: 1.4;
  white-space: nowrap;
  pointer-events: none;
}

.donut-ring {
  --pct: 0;
  position: relative;
  width: 168px;
  height: 168px;
  margin: var(--space-xs) 0;
}

/* The circles carry their own rotation so the gradient stays fixed in place. */
.donut-ring__svg {
  width: 100%;
  height: 100%;
  overflow: visible;
}

.donut-ring__track {
  fill: none;
  stroke: #e6ebec;
  stroke-width: 16;
}

.donut-ring__progress {
  fill: none;
  stroke: url(#ringGradient);
  stroke-width: 16;
  stroke-linecap: round;
  stroke-dasharray: 364.42;
  stroke-dashoffset: calc(364.42 - (364.42 * var(--pct) / 100));
  /* Matches DONUT_DURATION in app.js so the arc and the number land together. */
  transition: stroke-dashoffset 0.9s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.donut-ring__label {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.donut-ring__value {
  font-size: 32px;
  font-weight: 700;
  color: var(--color-text-primary);
}

/* Daily rehab checklist */

.checklist__title {
  margin: 0;
}

.checklist__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.checklist__item {
  width: 100%;
  min-height: var(--touch-target-min);
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  background: var(--color-bg-main);
  border: none;
  border-radius: var(--radius-item);
  box-shadow: var(--shadow-softer);
  padding: var(--space-sm) var(--space-md);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.checklist__box {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  border-radius: 8px;
  border: 2px solid var(--color-primary);
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #ffffff;
  transition: background 0.2s ease, border-color 0.2s ease, transform 0.28s cubic-bezier(0.34, 1.8, 0.5, 1);
}

.checklist__box svg {
  width: 18px;
  height: 18px;
}

/* The tick draws itself in rather than popping. */
.checklist__box path {
  stroke-dasharray: 24;
  stroke-dashoffset: 24;
  transition: stroke-dashoffset 0.28s ease 0.06s;
}

.checklist__item[data-checked="true"] .checklist__box {
  background: var(--color-on-track);
  border-color: var(--color-on-track);
}

.checklist__item[data-checked="true"] .checklist__box path {
  stroke-dashoffset: 0;
}

/* Spring pop on the moment of completion. Keyframes rather than a transition
   so it overshoots, settles back past the mark, then lands. */
.checklist__item.is-celebrating .checklist__box {
  animation: box-pop 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes box-pop {
  0% { transform: scale(1); }
  35% { transform: scale(1.55); }
  62% { transform: scale(0.9); }
  82% { transform: scale(1.08); }
  100% { transform: scale(1); }
}

/* Ring that expands out of the checkbox and fades. */
.checklist__box::before {
  content: "";
  position: absolute;
  inset: -5px;
  border-radius: 13px;
  border: 2.5px solid var(--color-on-track);
  opacity: 0;
  pointer-events: none;
}

.checklist__item.is-celebrating .checklist__box::before {
  animation: ring-pulse 0.65s ease-out;
}

@keyframes ring-pulse {
  0% { transform: scale(0.7); opacity: 0.9; }
  100% { transform: scale(2.6); opacity: 0; }
}

.checklist__item.is-celebrating {
  animation: row-glow 0.7s ease;
}

@keyframes row-glow {
  0% { box-shadow: var(--shadow-softer); transform: scale(1); }
  30% { box-shadow: 0 0 0 4px var(--color-on-track-tint), var(--shadow-soft); transform: scale(1.025); }
  100% { box-shadow: var(--shadow-softer); transform: scale(1); }
}

/* The icon tile gives a smaller, slightly later echo of the pop. */
.checklist__item.is-celebrating .checklist__thumb {
  animation: thumb-pop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) 0.08s;
}

@keyframes thumb-pop {
  0% { transform: scale(1) rotate(0deg); }
  45% { transform: scale(1.22) rotate(-7deg); }
  100% { transform: scale(1) rotate(0deg); }
}

/* Burst of dots radiating from the checkbox. */
.spark {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 7px;
  height: 7px;
  margin: -3.5px 0 0 -3.5px;
  border-radius: 50%;
  background: var(--color-on-track);
  pointer-events: none;
  animation: spark-fly 0.65s cubic-bezier(0.2, 0.7, 0.3, 1) forwards;
}

@keyframes spark-fly {
  0% { transform: translate(0, 0) scale(0.4); opacity: 0; }
  15% { transform: translate(calc(var(--dx) * 0.2), calc(var(--dy) * 0.2)) scale(1.15); opacity: 1; }
  100% { transform: translate(var(--dx), var(--dy)) scale(0.15); opacity: 0; }
}

/* Progress counter */

.checklist__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-sm);
  margin-bottom: var(--space-sm);
}

.checklist__title {
  flex: 1;
  min-width: 0;
}

.checklist__progress {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  white-space: nowrap;
  color: var(--color-text-secondary);
  transition: color 0.3s ease;
}

.progress-icon {
  width: 15px;
  height: 15px;
  flex: 0 0 auto;
}

.checklist__progress[data-complete="true"] {
  color: var(--color-on-track);
  font-weight: 700;
  position: relative;
  background: var(--color-on-track-tint);
  border-radius: 999px;
  padding: 3px 10px;
}

/* The finish line: label swings in, then a slow shine sweeps across it. */
.checklist__progress.is-finishing {
  animation: all-done-pop 0.75s cubic-bezier(0.34, 1.7, 0.5, 1);
}

@keyframes all-done-pop {
  0% { transform: scale(0.6) rotate(-8deg); opacity: 0.2; }
  45% { transform: scale(1.32) rotate(4deg); opacity: 1; }
  70% { transform: scale(0.94) rotate(-2deg); }
  100% { transform: scale(1) rotate(0deg); }
}

.checklist__progress.is-finishing::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: linear-gradient(100deg, transparent 25%, rgba(255, 255, 255, 0.85) 50%, transparent 75%);
  animation: all-done-shine 0.9s ease-out 0.2s;
}

@keyframes all-done-shine {
  from { transform: translateX(-120%); }
  to { transform: translateX(120%); }
}

/* Confetti raining down the finished list. */
.checklist {
  position: relative;
}

.confetti {
  position: absolute;
  top: 0;
  width: 9px;
  height: 14px;
  border-radius: 2px;
  pointer-events: none;
  z-index: 5;
  animation: confetti-fall 1.6s cubic-bezier(0.3, 0.6, 0.5, 1) forwards;
}

/* Hold full opacity most of the way down, then fade only at the very end. */
@keyframes confetti-fall {
  0% { transform: translateY(-10px) rotate(0deg); opacity: 0; }
  8% { opacity: 1; }
  78% { opacity: 1; }
  100% { transform: translateY(var(--fall)) rotate(var(--spin)); opacity: 0; }
}

/* Patients who prefer reduced motion get the state change without the show. */
@media (prefers-reduced-motion: reduce) {
  .checklist__box,
  .checklist__box path {
    transition: none;
  }

  .checklist__item.is-celebrating,
  .checklist__item.is-celebrating .checklist__box,
  .checklist__item.is-celebrating .checklist__box::before,
  .checklist__item.is-celebrating .checklist__thumb {
    animation: none;
    transform: none;
  }

  .spark,
  .confetti {
    display: none;
  }

  .checklist__progress.is-finishing {
    animation: none;
  }

  .checklist__progress.is-finishing::after {
    display: none;
  }
}

.checklist__text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.checklist__label {
  font-weight: 600;
}

.checklist__meta {
  color: var(--color-text-secondary);
  font-weight: 400;
}

.checklist__thumb {
  flex: 0 0 auto;
  width: 52px;
  height: 52px;
  border-radius: 14px;
  background: var(--color-primary-tint);
  color: var(--color-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.checklist__thumb svg {
  width: 24px;
  height: 24px;
}

.checklist__photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Completed photos desaturate so finished rows recede. */
.checklist__item[data-checked="true"] .checklist__photo {
  filter: grayscale(0.55);
  opacity: 0.7;
}

.checklist__item[data-checked="true"] .checklist__label {
  color: var(--color-text-secondary);
  text-decoration: line-through;
}

.checklist__item[data-checked="true"] .checklist__thumb {
  background: var(--color-on-track-tint);
  color: var(--color-on-track);
}

/* Chat floating action button */

.chat-fab {
  position: fixed;
  left: 50%;
  bottom: var(--space-md);
  transform: translateX(-50%);
  width: calc(var(--mobile-viewport) - 32px);
  max-width: calc(100vw - 32px);
  min-height: var(--touch-target-min);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  background: var(--color-primary);
  color: #ffffff;
  border: none;
  border-radius: 999px;
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 4px 16px rgba(16, 79, 85, 0.3);
}

.chat-fab__icon {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Sparkle sits over the agent's shoulder rather than replacing the figure,
   so Cora still reads as a person who happens to be automated. */
.chat-fab__spark {
  position: absolute;
  top: -5px;
  right: -8px;
  width: 13px;
  height: 13px;
  color: #9fe3c0;
}

/* Chat screen */

.chat-header {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-md) 16px;
  background: var(--color-bg-main);
  box-shadow: var(--shadow-softer);
  position: relative;
  z-index: 1;
}

.chat-header__back {
  flex: 0 0 auto;
  width: var(--touch-target-min);
  height: var(--touch-target-min);
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  font-size: 20px;
  color: var(--color-primary);
  cursor: pointer;
  border-radius: 8px;
}

.chat-header__id {
  flex: 1;
  min-width: 0;
}

.chat-header__title {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 6px;
}

/* Same sparkle as the Ask Cora button, so the AI marker is consistent
   wherever her name appears. */
.chat-header__spark {
  flex: 0 0 auto;
  width: 17px;
  height: 17px;
  color: var(--color-ai-accent);
}

.chat-header__subtitle {
  margin: 0;
}

/* Standing transparency note. Persistent rather than per-message, so it is
   read once and does not become noise the patient learns to skip. */
.chat-notice {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin: 0;
  padding: 8px 16px;
  background: var(--color-primary-tint);
  color: var(--color-text-secondary);
}

/* Announced on entry rather than pulsed. A small icon scaling briefly is
   invisible next to the greeting typing itself out, so the whole strip
   arrives as a highlighted banner, holds long enough to be read, then
   settles into its quiet resting state. */
.chat-notice.is-entering {
  animation: notice-announce 2.6s ease-out;
}

@keyframes notice-announce {
  0% { opacity: 0; transform: translateY(-16px); background: #8fc9c0; color: #0b3a3f; font-weight: 700; }
  8% { opacity: 1; transform: translateY(0); background: #8fc9c0; color: #0b3a3f; font-weight: 700; }
  62% { background: #8fc9c0; color: #0b3a3f; font-weight: 700; }
  100% { background: var(--color-primary-tint); color: var(--color-text-secondary); font-weight: 400; }
}

.chat-notice.is-entering .chat-notice__icon {
  animation: notice-eye 2.6s ease-out;
}

/* Two deliberate blinks at a size that actually reads at 16px. */
@keyframes notice-eye {
  0% { transform: scale(0.5); }
  9% { transform: scale(1.9); }
  18% { transform: scale(1); }
  27% { transform: scale(1.9); }
  36% { transform: scale(1); }
  100% { transform: scale(1); }
}

.chat-notice__icon {
  display: flex;
  flex: 0 0 auto;
}

.chat-notice__icon svg {
  width: 16px;
  height: 16px;
}

/* --- Attachments --- */

.attachment {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.attachment--file {
  flex-direction: row;
  align-items: center;
  gap: 8px;
}

.attachment__image {
  display: block;
  width: 100%;
  max-width: 200px;
  max-height: 220px;
  object-fit: cover;
  border-radius: 12px;
}

.attachment__icon {
  font-size: 22px;
  line-height: 1;
}

.attachment__meta {
  font-size: 12px;
  opacity: 0.85;
  word-break: break-word;
}

/* Paired routes to a human. */
.message__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.chat-header__team {
  flex: 0 0 auto;
  width: var(--touch-target-min);
  height: var(--touch-target-min);
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: var(--color-primary-tint);
  color: var(--color-primary);
  cursor: pointer;
}

.chat-header__team svg {
  width: 21px;
  height: 21px;
}

/* --- Care team message sheet --- */

.sheet {
  position: absolute;
  inset: 0;
  z-index: 40;
  display: flex;
  align-items: flex-end;
}

.sheet__scrim {
  position: absolute;
  inset: 0;
  background: rgba(16, 30, 34, 0.42);
}

.sheet__panel {
  position: relative;
  width: 100%;
  background: var(--color-bg-main);
  border-radius: 20px 20px 0 0;
  padding: var(--space-md);
  padding-bottom: calc(var(--space-md) + env(safe-area-inset-bottom, 0px));
  box-shadow: 0 -8px 32px rgba(16, 30, 34, 0.18);
}

.sheet__title {
  margin: 0 0 6px;
}

.sheet__body {
  margin: 0 0 var(--space-sm);
  color: var(--color-text-secondary);
}

.sheet__field {
  width: 100%;
  padding: 12px 14px;
  border: 1px solid #d9e1e3;
  border-radius: 14px;
  background: var(--color-bg-soft);
  color: var(--color-text-primary);
  font-family: inherit;
  resize: vertical;
}

.sheet__field:focus {
  outline: 2px solid var(--color-primary);
  outline-offset: 1px;
}

.sheet__actions {
  display: flex;
  gap: var(--space-sm);
  margin-top: var(--space-sm);
}

.sheet__btn {
  flex: 1;
  min-height: var(--touch-target-min);
  border-radius: 999px;
  border: none;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
}

.sheet__btn--ghost {
  background: var(--color-bg-soft);
  color: var(--color-text-secondary);
}

.sheet__btn--primary {
  background: var(--color-primary);
  color: #ffffff;
}

.sheet__call {
  display: block;
  min-height: var(--touch-target-min);
  margin-top: var(--space-xs);
  line-height: var(--touch-target-min);
  text-align: center;
  font-size: 14px;
  font-weight: 600;
  color: var(--color-primary);
}

/* Human replies are visually separated from Cora's — no gradient, no
   sparkle, and a named sender above the bubble. */
.message__avatar--careteam {
  background: var(--color-patient);
}

.message__sender {
  margin: 0 0 4px;
  font-weight: 700;
  color: var(--color-text-secondary);
}

/* Care team messages carry a sender line above the bubble, so their avatar
   needs to clear that too or it floats above the message. */
.message--careteam .message__avatar {
  /* timestamp + gap + sender line + its margin + gap */
  margin-top: calc(16px + var(--space-xs) + 16px + 4px + var(--space-xs));
}

.message__bubble--careteam {
  background: #ffffff;
  color: var(--color-text-primary);
  border: 1px solid #dde5e7;
  border-bottom-left-radius: 4px;
}

.chat-header__restart {
  flex: 0 0 auto;
  width: var(--touch-target-min);
  height: var(--touch-target-min);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-primary-tint);
  border: none;
  border-radius: 50%;
  color: var(--color-primary);
  cursor: pointer;
}

.chat-header__restart svg {
  width: 20px;
  height: 20px;
}

.chat-feed {
  flex: 1;
  overflow-y: auto;
  padding: var(--space-md) 16px;
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

/* Top-aligned so the avatar sits beside the message it belongs to. With
   flex-end it sank to the bottom of the column, landing next to the trailing
   disclaimer instead of next to Cora's words. */
.message__row {
  display: flex;
  gap: var(--space-sm);
  align-items: flex-start;
}

.message--patient .message__row {
  flex-direction: row-reverse;
}

.message__avatar {
  flex: 0 0 auto;
  /* Clears the timestamp line (16px) plus the column gap, so the avatar
     lines up with the top of the bubble rather than the timestamp. */
  margin-top: calc(16px + var(--space-xs));
  width: 32px;
  height: 32px;
  border-radius: 50%;
  color: #ffffff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.02em;
}

/* Cora keeps the brand teal; the patient gets a lighter slate so the two
   speakers are told apart by colour as well as by side. */
.message__avatar--ai {
  background: var(--color-primary);
}

.message__avatar--patient {
  background: var(--color-patient);
}

.message__avatar .icon-agent {
  width: 18px;
  height: 18px;
}

.message__bubble-col {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  max-width: 78%;
}

.message--patient .message__bubble-col {
  align-items: flex-end;
}

.message__timestamp {
  margin: 0;
  color: var(--color-text-secondary);
}

.message__bubble {
  padding: 12px var(--space-md);
  border-radius: 20px;
  box-shadow: var(--shadow-softer);
}

.message__bubble p {
  margin: 0;
}

.message__bubble > p + p,
.message__bubble > ul + p {
  margin-top: 10px;
}

.message__list {
  margin: 8px 0 0;
  padding-left: 18px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.message__list li::marker {
  color: var(--color-primary);
}

/* Typing indicator shown while Cora composes. */
.typing {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 3px 0;
}

.typing span {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-text-secondary);
  opacity: 0.45;
  animation: typing-bounce 1.15s ease-in-out infinite;
}

.typing span:nth-child(2) {
  animation-delay: 0.16s;
}

.typing span:nth-child(3) {
  animation-delay: 0.32s;
}

@keyframes typing-bounce {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.35; }
  30% { transform: translateY(-5px); opacity: 0.85; }
}

.message__bubble--patient .message__list li::marker {
  color: rgba(255, 255, 255, 0.7);
}

/* Cora's bubbles carry a faint iridescent wash — ice teal drifting to the
   barest lavender — so a generated answer is distinguishable from a human
   one at a glance, without raising the contrast of the text behind it. */
.message__bubble--ai {
  background: linear-gradient(142deg, #e8f2f4 0%, #f1f5f6 40%, #f4f2f7 74%, #f8f1f4 100%);
  background-size: 100% 100%;
  color: var(--color-text-primary);
  border-bottom-left-radius: 4px;
  box-shadow: var(--shadow-softer), inset 0 0 0 1px rgba(255, 255, 255, 0.55);
}

/* While she is composing, the wash drifts. It settles to static the moment
   the message is finished, so the movement means "generating" rather than
   becoming permanent decoration on a screen a patient may leave open. */
.message__bubble--ai.is-writing {
  background-size: 260% 260%;
  animation: ai-shimmer 3.2s ease-in-out infinite;
}

@keyframes ai-shimmer {
  0% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}

@media (prefers-reduced-motion: reduce) {
  .message__bubble--ai.is-writing {
    background-size: 100% 100%;
    animation: none;
  }
}

.message__bubble--patient {
  background: var(--color-primary);
  color: #ffffff;
  border-bottom-right-radius: 4px;
}

.message__meta {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin: 0;
  color: var(--color-text-secondary);
}

.message__speak {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: none;
  border: none;
  padding: 4px 0;
  color: var(--color-primary);
  font-family: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  min-height: 32px;
}

.message__followups {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  margin-top: var(--space-xs);
  width: 100%;
}

.message__followup-btn {
  min-height: 40px;
  padding: 0 var(--space-md);
  border-radius: 999px;
  border: 1px solid var(--color-primary);
  background: var(--color-bg-main);
  color: var(--color-primary);
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}

.message__followup-btn:disabled {
  opacity: 0.5;
  cursor: default;
}

.message__action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--touch-target-min);
  margin-top: var(--space-xs);
  padding: 0 var(--space-md);
  background: var(--color-primary);
  color: #ffffff;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 600;
  font-family: inherit;
  text-decoration: none;
  border: none;
  cursor: pointer;
}

/* Message Sarah is the quieter of the two — calling stays the primary route
   for anything that cannot wait. Declared after the base so it wins. */
.message__action--secondary {
  background: var(--color-bg-main);
  color: var(--color-primary);
  border: 1px solid var(--color-primary);
}

.quick-replies {
  display: flex;
  gap: var(--space-sm);
  padding: 0 16px var(--space-sm);
  overflow-x: auto;
}

.quick-reply {
  flex: 0 0 auto;
  min-height: var(--touch-target-min);
  padding: 0 var(--space-md);
  display: flex;
  align-items: center;
  /* design.md specifies a white chip with a grey border, but that was written
     against a tinted feed. On the white background these now sit on, a white
     chip is invisible — the tint keeps the spec's intent (a clearly tappable
     suggestion in Primary Action Teal) rather than its literal value. */
  background: var(--color-primary-tint);
  border: 1px solid #c5d8d5;
  border-radius: 999px;
  box-shadow: none;
  color: var(--color-primary);
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}

.input-hint {
  min-height: 16px;
  margin: 0;
  padding: 0 16px;
}

.input-dock {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm) 16px var(--space-md);
  background: var(--color-bg-main);
  box-shadow: var(--shadow-softer);
  position: relative;
  z-index: 1;
}

/* Sized to sit alongside the mail and reset icons in the header. Slightly
   larger than those because the camera body is a squat shape and reads
   smaller than a square glyph at the same box size. */
.input-dock__icon-btn svg {
  width: 22px;
  height: 22px;
}

.input-dock__icon-btn {
  flex: 0 0 auto;
  width: var(--touch-target-min);
  height: var(--touch-target-min);
  border-radius: 50%;
  border: none;
  background: var(--color-primary-tint);
  color: var(--color-primary);
  font-size: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.input-dock__icon-btn[aria-pressed="true"] {
  background: var(--color-primary);
  color: #ffffff;
}

.input-dock__icon-btn--send {
  background: var(--color-primary);
  color: #ffffff;
}

.input-dock__field {
  flex: 1;
  min-width: 0;
  min-height: var(--touch-target-min);
  border: none;
  background: var(--color-bg-soft);
  border-radius: 999px;
  /* 16px rather than the 20px stack step: three 48px buttons share this row,
     and the placeholder needs the width back on a narrow handset. */
  padding: 0 16px;
  font-family: inherit;
}

/* Below the 393px design target, buy the placeholder more room by tightening
   the row rather than shrinking type the patient needs to read. */
@media (max-width: 374px) {
  .input-dock {
    gap: 8px;
  }

  .input-dock__field {
    padding: 0 12px;
  }
}

/* Safety escalation screen */

.screen--safety {
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--space-md) 24px;
  background: var(--color-bg-main);
}

.safety-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-sm);
  max-width: 320px;
  /* Restarts each time the screen goes from display:none to shown. */
  animation: safety-card-in 0.4s ease-out;
}

/* Deliberately calm. Nothing bounces, overshoots or pulses — this screen is
   read by someone who may already be frightened, and motion that reads as
   alarm makes it harder to act. Every delay is short, and the call buttons
   carry the shortest of all: a patient cannot tap what is not yet visible. */
@keyframes safety-card-in {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes safety-rise {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

.safety-card__icon {
  animation: safety-icon-in 0.5s cubic-bezier(0.22, 0.61, 0.36, 1) 0.06s backwards;
}

@keyframes safety-icon-in {
  from { opacity: 0; transform: scale(0.72); }
  to { opacity: 1; transform: scale(1); }
}

.safety-card__title { animation: safety-rise 0.32s ease-out 0.08s backwards; }
.safety-card__body { animation: safety-rise 0.32s ease-out 0.11s backwards; }
.safety-card__emergency { animation: safety-rise 0.32s ease-out 0.13s backwards; }
/* Call 911 is fully legible by ~0.4s. An emergency control should not still be
   fading up while someone is trying to hit it. */
.safety-card__call--emergency { animation: safety-rise 0.28s ease-out 0.12s backwards; }
.safety-card__call--care { animation: safety-rise 0.3s ease-out 0.17s backwards; }
.safety-card__back { animation: safety-rise 0.3s ease-out 0.22s backwards; }

@media (prefers-reduced-motion: reduce) {
  .safety-card,
  .safety-card > * {
    animation: none;
  }
}

.safety-card__icon {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: #fbeaea;
  color: var(--color-alert);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 32px;
  margin-bottom: var(--space-xs);
}

.safety-card__title {
  color: var(--color-text-primary);
}

.safety-card__body {
  color: var(--color-text-secondary);
}

.safety-card__call {
  min-height: var(--touch-target-min);
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  color: #ffffff;
  font-weight: 700;
  font-size: 16px;
  text-decoration: none;
}

/* Two destinations, not two priorities: crimson is emergency services, teal is
   your own care team. Colour carries which is which, so neither is mistaken
   for the other in a hurry. */
.safety-card__call--emergency {
  margin-top: var(--space-xs);
  background: var(--color-alert);
  box-shadow: 0 4px 16px rgba(214, 48, 49, 0.3);
}

.safety-card__call--care {
  background: var(--color-primary);
  box-shadow: 0 4px 16px rgba(16, 79, 85, 0.24);
}

/* This line is not fine print — it is the triage instruction that tells the
   patient which of the two buttons is theirs, so it is sized to be read at a
   glance by someone frightened, not squinted at. Deeper crimson than the
   button so it clears AA contrast on the tint. */
.safety-card__emergency {
  margin: var(--space-xs) 0 0;
  padding: 12px 14px;
  width: 100%;
  background: #fdeeee;
  border-radius: 14px;
  color: #a81f22;
  font-size: 17px;
  line-height: 1.45;
  font-weight: 500;
}

.safety-card__emergency strong {
  font-weight: 800;
}

.safety-card__back {
  margin-top: var(--space-sm);
  min-height: var(--touch-target-min);
  background: none;
  border: none;
  color: var(--color-text-secondary);
  text-decoration: underline;
  font-family: inherit;
  font-size: 14px;
  cursor: pointer;
}

/* Portfolio copy: product name replaced; show only the mark from the supplied art. */
.brand__logo--custom{display:inline-flex;align-items:center;gap:6px;height:54px;mix-blend-mode:normal}
.brand__logo-clip{display:block;height:54px;flex:0 0 auto}
.brand__logo-clip img{height:54px;width:auto;max-width:none;mix-blend-mode:darken;display:block}
.brand__logo-words{display:flex;flex-direction:column;line-height:1}
.brand__logo-platform{font-size:15px;font-weight:500;color:var(--color-text-secondary);letter-spacing:.01em}
.brand__logo-name{font-size:27px;font-weight:700;color:var(--color-primary);letter-spacing:-.02em}

/* Research-variant switches: labelled so reviewers know they are test tools. */
.user-menu__section{margin-top:4px;padding:10px var(--space-sm) 4px;border-top:1px solid #eceff0;display:flex;flex-direction:column;gap:2px;max-width:220px}
.user-menu__section strong{font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--color-primary)}
.user-menu__section span{font-size:12px;line-height:16px;color:var(--color-text-secondary)}
.user-menu__item--variant{color:var(--color-text-secondary);font-size:13px;white-space:nowrap}

/* Context note for portfolio visitors. Corner card on wide screens, slim top card on phones. */
.proto-note{position:fixed;left:24px;bottom:24px;z-index:50;max-width:300px;padding:16px 40px 16px 18px;border-radius:16px;background:#fff;box-shadow:0 12px 32px -12px rgba(16,79,85,.35);font-family:var(--font-family);font-size:13px;line-height:19px;color:var(--color-text-secondary)}
.proto-note strong{display:block;margin-bottom:4px;font-size:14px;color:var(--color-primary)}
.proto-note p{margin:0 0 6px}.proto-note p:last-child{margin:0}
.proto-note__close{position:absolute;top:8px;right:8px;width:28px;height:28px;border:none;border-radius:50%;background:#eef3f3;color:var(--color-primary);font-size:18px;line-height:1;cursor:pointer}
@media (max-width: 760px){.proto-note{left:12px;right:12px;bottom:auto;top:12px;max-width:none}}

/* Way back to the portfolio: corner pill on wide screens, small pill under the header on phones. */
.back-portfolio{position:fixed;left:24px;top:20px;z-index:60;display:inline-flex;align-items:center;gap:8px;height:44px;padding:0 18px;border-radius:999px;background:#1E2A4A;color:#fff;font-family:var(--font-family);font-size:14px;font-weight:600;text-decoration:none;box-shadow:0 10px 24px -12px rgba(30,42,74,.6)}
.back-portfolio:hover{background:#2F55C8}
@media (max-width: 760px){.back-portfolio{left:auto;right:12px;top:auto;bottom:92px;height:40px;padding:0 14px;font-size:13px}}
