/* ============================================================
   components.css — the full component library. Every rule here
   references tokens.css variables; nothing is hardcoded. See
   styleguide.html for a live, visual index of everything below.
   ============================================================ */

*, *::before, *::after { box-sizing: border-box; }

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

body {
  margin: 0;
  font-family: var(--font-sans);
  background: var(--bg-app);
  color: var(--text-primary);
  font-size: var(--text-body-size);
  font-weight: var(--text-body-weight);
  line-height: var(--text-body-lh);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-feature-settings: "cv11", "ss03";
}
::selection { background: var(--accent-soft); color: var(--accent-deep); }

/* ---------------------------------------------------------------
   Editorial headings. Every h1/h2 in the app speaks in the serif at
   weight 400 - hierarchy comes from size and tracking, never from
   bold. !important because the four evaluation pages were built with
   their own heading rules at 600-700; this is the one place the voice
   is decided. h3 and below stay in Inter, where UI lives.
--------------------------------------------------------------- */
h1, h2, .text-page-title, .text-display, .serif {
  font-family: var(--font-serif) !important;
  font-weight: 400 !important;
  font-optical-sizing: auto;
}
h1, h2 { letter-spacing: -.018em; text-wrap: balance; }
.text-display {
  font-size: var(--text-display-size); line-height: 1.05;
  letter-spacing: var(--text-display-spacing); color: var(--text-primary);
}
/* One italic phrase inside a headline - the Steep device. */
h1 em, h2 em, .text-display em, .text-page-title em { font-style: italic; }
h3, h4 { font-weight: 550; letter-spacing: -.006em; }

/* Links: plain hyperlinks. Interactive text is set in ink at weight 500 and
   carries no underline at rest (the Steep rule); the underline appears on
   hover and keyboard focus only, in the text's own colour. The decorative
   ember underline that used to sit under every link is gone - it made plain
   text links read as buttons. */
a:not([class]), .text-link {
  color: var(--text-primary); font-weight: 500;
  text-decoration: none; cursor: pointer;
}
a:not([class]):hover, .text-link:hover,
a:not([class]):focus-visible, .text-link:focus-visible {
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px;
}
:focus-visible { outline-color: var(--accent); }

/* ---------------------------------------------------------------
   Typography utility classes - one class per role from the tokens
   table, so no page ever hand-rolls a font-size/weight combo.
--------------------------------------------------------------- */
.text-metric { font-family: var(--font-serif); font-size: var(--text-metric-size); font-weight: var(--text-metric-weight); line-height: var(--text-metric-lh); letter-spacing: var(--text-metric-spacing); color: var(--text-primary); font-variant-numeric: tabular-nums; }
.text-page-title { font-family: var(--font-serif); font-size: var(--text-page-title-size); font-weight: var(--text-page-title-weight); line-height: var(--text-page-title-lh); letter-spacing: var(--text-page-title-spacing); color: var(--text-primary); }
.text-card-title { font-family: var(--font-serif); font-size: var(--text-card-title-size); font-weight: var(--text-card-title-weight); line-height: var(--text-card-title-lh); letter-spacing: var(--text-card-title-spacing); color: var(--text-primary); }
.text-body { font-size: var(--text-body-size); font-weight: var(--text-body-weight); line-height: var(--text-body-lh); }
.text-label { font-size: var(--text-label-size); font-weight: var(--text-label-weight); line-height: var(--text-label-lh); letter-spacing: var(--text-label-spacing); color: var(--text-secondary); }
.text-eyebrow { font-size: var(--text-eyebrow-size); font-weight: var(--text-eyebrow-weight); letter-spacing: var(--text-eyebrow-spacing); text-transform: none; color: var(--text-tertiary); }
.text-secondary { color: var(--text-secondary); }
.text-tertiary { color: var(--text-tertiary); }

/* ---------------------------------------------------------------
   Card
--------------------------------------------------------------- */
/* Flat mist, 24px corners, no border, no shadow: a card separates from
   paper by tone alone. Inside a card the surface ladder is re-pointed,
   so anything nested that asks for the "alternate" surface steps back
   up to paper (the Steep pattern: white artifacts on mist), and
   anything that asks for "the surface" matches the card it sits on. */
.card {
  --bg-surface: var(--bg-card);
  --bg-surface-alt: var(--paper);
  --border: var(--hairline-on-mist);
  background: var(--bg-card);
  border: 0;
  border-radius: var(--radius-card);
  box-shadow: none;
  transition: background var(--duration-hover) var(--ease-standard);
}
.card-hoverable:hover { background: var(--mist-strong); }
/* A floating artifact: paper, lifted. The only card that casts a shadow. */
.card.card-float, .card-float {
  --bg-surface: var(--paper); --bg-surface-alt: var(--mist); --border: var(--hairline);
  background: var(--paper); box-shadow: var(--shadow-lg); border-radius: 20px;
}
/* Editorial accent: the one warm surface on a page. */
.card.card-accent { --bg-surface: var(--accent-soft); background: var(--accent-soft); color: var(--accent-deep); }
.card-body { padding: clamp(24px, 20px + 1vw, 36px); }
@media (max-width: 767px) { .card-body { padding: var(--sp-5); } }

/* Divider between rows INSIDE a card. Inset from the card's own padding
   so it never runs edge to edge - taken from the reference, and the
   reason a stack of rows reads as one object rather than a table. */
.card-divider { height: 1px; background: var(--border); margin: var(--sp-5) clamp(24px, 20px + 1vw, 36px); border: 0; }
@media (max-width: 767px) { .card-divider { margin: var(--sp-4) var(--sp-5); } }

/* Prose measure helper - cap running text so lines stay readable. */
.prose { max-width: var(--measure); }
.prose p { margin: 0 0 var(--sp-4); line-height: var(--text-body-lh); }
.prose p:last-child { margin-bottom: 0; }
.card-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: clamp(22px, 18px + 1vw, 32px) clamp(24px, 20px + 1vw, 36px) 0;
  border-bottom: 0;
}
.card-header .text-card-title { margin: 0; }
.card-header-actions { display: flex; align-items: center; gap: var(--sp-2); }

/* ---------------------------------------------------------------
   Stat card
--------------------------------------------------------------- */
.stat-card { position: relative; padding: 28px; }
.stat-card .stat-icon {
  position: absolute; top: 24px; right: 24px;
  width: 40px; height: 40px; border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-surface-alt); color: var(--text-secondary);
}
.stat-card .stat-label { display: block; margin-bottom: var(--sp-2); }
.stat-card .stat-value { display: block; margin-bottom: var(--sp-2); }
.stat-card .stat-delta { display: inline-flex; align-items: center; gap: 4px; font-size: var(--text-xs); font-weight: 500; }
.stat-card .stat-delta.up { color: var(--success); }
.stat-card .stat-delta.down { color: var(--danger); }
.stat-card .stat-delta .stat-delta-note { color: var(--text-tertiary); font-weight: 400; margin-left: 2px; }

/* ---------------------------------------------------------------
   Progress bar
--------------------------------------------------------------- */
/* Thicker and fully rounded, per the dashboard reference - a 6px hairline
   track reads as a loading indicator, a 12px pill reads as a measurement.
   The remainder is hatched rather than flat grey so "not yet done" is
   visibly a quantity, not just empty space. */
.progress-track {
  height: 8px; border-radius: var(--radius-pill);
  background: var(--mist-strong); overflow: hidden; width: 100%;
}
/* The hatch is drawn in the surrounding text colour at low strength, not in
   a fixed grey: the track sits on paper, on mist and on every case colour
   (Alex's card is the same #e8e8e8 the hatch used to be, which made the
   remainder vanish), and currentColor is by definition legible on all of
   them. */
.progress-track.hatched {
  background:
    repeating-linear-gradient(
      -45deg,
      color-mix(in srgb, currentColor 22%, transparent) 0 3px,
      color-mix(in srgb, currentColor 7%, transparent) 3px 7px
    );
}
.progress-track.slim { height: 6px; }
.progress-fill {
  height: 100%; border-radius: var(--radius-pill);
  background: var(--accent);
  transition: width var(--duration-progress) ease-out;
}
.progress-row { display: flex; align-items: center; gap: var(--sp-3); }
.progress-row .progress-track { flex: 1; }
.progress-row .progress-pct { font-family: var(--font-mono); font-size: var(--text-xs); font-weight: 400; color: var(--text-primary); min-width: 42px; text-align: right; font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------
   Badge
--------------------------------------------------------------- */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  border-radius: var(--radius-pill); padding: 5px 12px;
  font-size: var(--text-xs); font-weight: 480; line-height: 1.4; white-space: nowrap;
  border: none;
}
.badge-neutral { background: transparent; color: var(--text-secondary); box-shadow: inset 0 0 0 1px var(--border); }
.badge-success { background: var(--success-soft); color: var(--success); }
.badge-warning { background: var(--warning-soft); color: var(--warning); }
.badge-danger  { background: var(--danger-soft);  color: var(--danger); }
.badge-info    { background: var(--info-soft);    color: var(--info); }
/* domain variants: badge-domain-{psychosis|mood|anxiety|substance} */
.badge-domain-psychosis { background: var(--domain-psychosis-soft); color: var(--domain-psychosis-ink); }
.badge-domain-mood      { background: var(--domain-mood-soft);      color: var(--domain-mood-ink); }
.badge-domain-anxiety   { background: var(--domain-anxiety-soft);   color: var(--domain-anxiety-ink); }
.badge-domain-substance { background: var(--domain-substance-soft); color: var(--domain-substance-ink); }
.badge .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex-shrink: 0; }

/* Case-status badges. A green "Complete" next to Darren's purple card read
   as two unrelated colour systems, so the three states are now three
   strengths of the case's own colour, set per card as --case-color /
   --case-ink. Contrast was checked for all four cases in both themes; the
   weakest combination is 4.52:1.
     not started - barely tinted, muted text
     in progress - clearly tinted, full-strength text
     complete    - the solid case colour, as strong as the progress bar
   "Complete" fills with a colour that is mid-tone in light and pale in
   dark, so its label cannot use --text-primary (which inverts with the
   theme and would vanish on one of them). It takes the sidebar's fixed
   dark instead - the same theme-invariant trick .btn-primary uses. */
/* All three states share the palest tint - the one Not started had - and
   the label alone carries the state. Three strengths of the same hue made
   a grid of eight cards read as a colour chart. */
.badge-case { background: transparent; box-shadow: inset 0 0 0 1px var(--border); color: var(--text-secondary); }
.badge-case.is-progress { color: var(--text-primary); background: var(--paper); box-shadow: none; }
.badge-case.is-progress::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }
.badge-case.is-complete { color: var(--ink-text); background: var(--ink); box-shadow: none; }
/* Seminar instance: a patient the seminar leader closed or scheduled. */
.badge-locked { gap: 4px; background: transparent; box-shadow: inset 0 0 0 1px var(--border); color: var(--text-muted); }
.badge-locked svg { width: 12px; height: 12px; }

/* ---------------------------------------------------------------
   Button
--------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 44px; padding: 0 var(--sp-6); border-radius: var(--radius-pill);
  font-family: var(--font-sans); font-size: var(--text-sm); font-weight: 480;
  border: 1px solid transparent; cursor: pointer; text-decoration: none; white-space: nowrap;
  transition: background var(--duration-hover) var(--ease-standard),
              border-color var(--duration-hover) var(--ease-standard),
              color var(--duration-hover) var(--ease-standard);
}
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn-sm { height: 34px; padding: 0 var(--sp-4); font-size: var(--text-xs); }

/* Deliberately monochrome, not colored - a bright accent here would
   compete with whatever domain color a page is theming its own content
   in (e.g. Dennis's pink CDDR items). text-primary/bg-surface invert
   cleanly between light/dark themes on their own, so this never needs
   a separate dark-mode override. */
/* Deliberately monochrome, not colored - a bright accent here would
   compete with whatever domain color a page is theming its own content
   in (e.g. Dennis's pink CDDR items). Uses the sidebar's own fixed
   color rather than text-primary/bg-surface, so primary actions read
   as an echo of the app's persistent chrome - intentional, not
   arbitrary. Theme-invariant on purpose, matching the sidebar itself. */
/* Sentence case, not uppercase-tracked. The uppercase pill came from the
   e-commerce reference; this reference keeps its buttons quiet and lets
   the numbers and charts carry the emphasis. */
.btn-primary {
  background: var(--ink); color: var(--ink-text); border-color: transparent;
  font-size: var(--text-sm); font-weight: 500; letter-spacing: 0;
}
.btn-primary:hover:not(:disabled) { background: var(--ink-hover); opacity: 1; }
.btn-primary:active:not(:disabled) { transform: translateY(1px); }

.btn-secondary { background: transparent; color: var(--text-primary); border-color: var(--text-primary); }
.btn-secondary:hover:not(:disabled) { background: var(--ink); color: var(--ink-text); }
/* Arrow link - the lowest-emphasis action. The arrow is the affordance. */
.btn-link { height: auto; padding: 6px 0; background: none; border: 0; color: var(--text-primary); border-radius: 0; }
.btn-link::after { content: "→"; transition: transform var(--duration-hover) var(--ease-standard); }
.btn-link:hover::after { transform: translateX(3px); }

.btn-ghost { background: transparent; color: var(--text-secondary); }
.btn-ghost:hover:not(:disabled) { background: var(--bg-surface-alt); color: var(--text-primary); }

/* ---------------------------------------------------------------
   Case card - the dashboard's centerpiece
--------------------------------------------------------------- */
.case-card { padding: clamp(24px, 20px + 1vw, 32px); display: flex; flex-direction: column; gap: var(--sp-5); cursor: default; }
/* A touch more lift on hover: the old -2px was barely perceptible on a
   white page. Transform and shadow both animate, and the border warms to
   the case's own colour. Respects reduced-motion below. */
.case-card { transition: transform var(--duration-hover) var(--ease-standard),
             box-shadow var(--duration-hover) var(--ease-standard),
             border-color var(--duration-hover) var(--ease-standard); }
.case-card:hover { background: var(--mist-strong); }
.case-card:active { transform: scale(.998); }
@media (prefers-reduced-motion: reduce) {
  .case-card, .case-card:hover, .case-card:active { transform: none; transition: none; }
}
.case-card-top { display: flex; align-items: flex-start; gap: var(--sp-3); }
.case-card-icon {
  width: 44px; height: 44px; border-radius: var(--radius-md); flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
}
.case-card-icon.domain-psychosis { background: var(--domain-psychosis-soft); color: var(--domain-psychosis-ink); }
.case-card-icon.domain-mood      { background: var(--domain-mood-soft);      color: var(--domain-mood-ink); }
.case-card-icon.domain-anxiety   { background: var(--domain-anxiety-soft);   color: var(--domain-anxiety-ink); }
.case-card-icon.domain-substance { background: var(--domain-substance-soft); color: var(--domain-substance-ink); }
.case-card-identity { flex: 1; min-width: 0; }
.case-card-name { font-family: var(--font-serif); font-size: var(--text-card-title-size); font-weight: 400; letter-spacing: -.012em; color: var(--text-primary); margin-bottom: 2px; }
.case-card-meta { font-size: var(--text-sm); color: var(--text-secondary); }

.case-card-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3) var(--sp-4);
  padding: var(--sp-4); border: none;
  background: var(--bg-surface-alt); border-radius: var(--radius-md);
}
/* Label above value, matching the stat cards and the reference. The markup
   puts the value first, so the column is reversed here rather than in four
   template literals. */
.case-card-grid-item { display: flex; flex-direction: column-reverse; justify-content: flex-end; gap: 4px; }
.case-card-grid-item .val { font-family: var(--font-serif); font-size: var(--text-xl); font-weight: 400; letter-spacing: -.015em; color: var(--text-primary); font-variant-numeric: tabular-nums; }
.case-card-grid-item .lbl { font-size: var(--text-xs); font-weight: 450; letter-spacing: 0; text-transform: none; color: var(--text-tertiary); }

.case-card-footer { display: flex; gap: var(--sp-2); }
.case-card-footer .btn { flex: 1; }

/* ---------------------------------------------------------------
   Table
--------------------------------------------------------------- */
.table-wrap {
  overflow-x: auto;
  scrollbar-width: thin; scrollbar-color: var(--border) transparent;
}
.table-wrap::-webkit-scrollbar { height: 6px; }
.table-wrap::-webkit-scrollbar-track { background: transparent; }
.table-wrap::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.table { width: 100%; border-collapse: collapse; font-size: var(--text-base); }
.table thead th {
  background: var(--bg-surface-alt); text-align: left;
  font-size: var(--text-xs); font-weight: 480; text-transform: none; letter-spacing: 0;
  color: var(--text-tertiary); padding: var(--sp-3) var(--sp-4);
  border-bottom: none; white-space: nowrap;
}
.table thead th.sortable { cursor: pointer; user-select: none; }
.table thead th.sortable:hover { color: var(--text-secondary); }
.table tbody tr { height: 52px; box-shadow: inset 0 -1px 0 var(--border); transition: background var(--duration-hover); }
.table tbody tr:last-child { box-shadow: none; }
.table tbody tr:hover { background: var(--bg-surface-alt); }
.table tbody td { padding: 0 var(--sp-4); color: var(--text-primary); }

@media (max-width: 768px) {
  .table-wrap.collapse-mobile thead { display: none; }
  .table-wrap.collapse-mobile, .table-wrap.collapse-mobile tbody, .table-wrap.collapse-mobile tr, .table-wrap.collapse-mobile td { display: block; width: 100%; }
  .table-wrap.collapse-mobile tr {
    height: auto; padding: var(--sp-4); margin-bottom: var(--sp-3);
    border: none; background: var(--bg-surface-alt); border-radius: var(--radius-md);
  }
  .table-wrap.collapse-mobile td { padding: 4px 0; border: none; }
  .table-wrap.collapse-mobile td::before { content: attr(data-label); display: block; font-size: var(--text-xs); color: var(--text-tertiary); }
}

/* ---------------------------------------------------------------
   Chat
--------------------------------------------------------------- */
.chat-scroll {
  display: flex; flex-direction: column; gap: var(--sp-4); padding: var(--sp-5); overflow-y: auto;
  scrollbar-width: thin; scrollbar-color: var(--border) transparent;
}
.chat-scroll::-webkit-scrollbar { width: 6px; }
.chat-scroll::-webkit-scrollbar-track { background: transparent; }
.chat-scroll::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.chat-row { display: flex; flex-direction: column; max-width: 72%; }
.chat-row.from-patient { align-self: flex-start; align-items: flex-start; }
.chat-row.from-student { align-self: flex-end; align-items: flex-end; }

/* Defaults, so a bubble rendered outside a .chat-row (the styleguide does
   this) still has a surface under it rather than inheriting whatever
   colour its container happened to set. */
.chat-bubble {
  padding: var(--sp-3) var(--sp-4); font-size: var(--text-base); line-height: 1.55;
  background: var(--bg-surface-alt); color: var(--text-primary);
  border-radius: var(--radius-lg);
}
.chat-row.from-patient .chat-bubble {
  background: var(--bg-surface-alt); color: var(--text-primary);
  border-radius: var(--radius-lg) var(--radius-lg) var(--radius-lg) 4px;
}
.chat-row.from-student .chat-bubble {
  background: var(--ink);
  color: var(--ink-text);
  border-radius: var(--radius-lg) var(--radius-lg) 4px var(--radius-lg);
}
.chat-timestamp { font-size: var(--text-xs); color: var(--text-tertiary); margin-top: 4px; padding: 0 4px; }

.chat-speaker { display: flex; align-items: center; gap: 5px; font-size: var(--text-xs); font-weight: 480; color: var(--text-tertiary); margin-bottom: 4px; padding: 0 4px; text-transform: none; letter-spacing: 0; }
.chat-row.from-student .chat-speaker { flex-direction: row-reverse; }
.chat-speaker svg { flex-shrink: 0; opacity: .75; }

.chat-typing { display: inline-flex; align-items: center; gap: 4px; padding: var(--sp-3) var(--sp-4);
  background: var(--bg-surface-alt); border-radius: var(--radius-lg) var(--radius-lg) var(--radius-lg) 4px; }
.chat-typing .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--text-tertiary); animation: chat-typing-bounce 1.2s infinite ease-in-out; }
.chat-typing .dot:nth-child(2) { animation-delay: .15s; }
.chat-typing .dot:nth-child(3) { animation-delay: .3s; }
@keyframes chat-typing-bounce { 0%, 60%, 100% { transform: translateY(0); opacity:.5; } 30% { transform: translateY(-3px); opacity:1; } }

.chat-composer {
  display: flex; align-items: flex-end; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5); border-top: 1px solid var(--border);
  background: var(--bg-surface); position: sticky; bottom: 0;
}
@media (max-width: 767px) {
  /* the accessibility toggle sits fixed bottom-right (52px + 20px
     margin); without extra room here, the Ask button renders right
     underneath it. Shrinking the input (rather than shifting the
     button) lets normal flex reflow push the button left naturally,
     since padding/margin on the button or row had no visible effect
     here for reasons not fully understood - this does. */
  .chat-composer #chat-input { max-width: calc(100% - 130px); }
}
.chat-composer input, .chat-composer textarea {
  flex: 1; resize: none; border: 1px solid var(--border); border-radius: var(--radius-md);
  padding: 12px 18px; font-family: var(--font-sans); font-size: var(--text-base); color: var(--text-primary);
  background: var(--paper); max-height: 120px; line-height: 1.5;
}
.chat-composer input:focus, .chat-composer textarea:focus { outline: none; border-color: var(--text-primary); }
.chat-composer input::placeholder, .chat-composer textarea::placeholder { color: var(--text-placeholder); }

/* ---------------------------------------------------------------
   Empty state
--------------------------------------------------------------- */
.empty-state { display: flex; flex-direction: column; align-items: center; text-align: center;
  padding: var(--sp-8) var(--sp-5); gap: var(--sp-3); color: var(--text-tertiary); }
.empty-state svg { color: var(--text-tertiary); }
.empty-state .empty-title { font-size: var(--text-base); font-weight: 600; color: var(--text-primary); }
.empty-state .empty-note { font-size: var(--text-sm); color: var(--text-secondary); max-width: 36ch; }

/* ---------------------------------------------------------------
   Activity row - a single timeline entry (dashboard "Recent
   activity", progress.html "Full activity history"). Always built
   from real, timestamped events - never a placeholder feed.
--------------------------------------------------------------- */
.activity-row { display: flex; align-items: flex-start; gap: var(--sp-3); padding: var(--sp-4) 0; box-shadow: inset 0 -1px 0 var(--border); }
.activity-row:last-child { box-shadow: none; }
.activity-dot { width: 8px; height: 8px; border-radius: 50%; margin-top: 6px; flex-shrink: 0; }
.activity-text { font-size: var(--text-base); color: var(--text-primary); }
.activity-time { font-size: var(--text-xs); color: var(--text-tertiary); margin-top: 2px; }

.grid-2-col { display: grid; grid-template-columns: 1.4fr 1fr; gap: var(--sp-5); align-items: start; margin-bottom: var(--sp-6); }
@media (max-width: 1100px) { .grid-2-col { grid-template-columns: 1fr; } }

/* ---------------------------------------------------------------
   Skeleton
--------------------------------------------------------------- */
.skeleton {
  background: linear-gradient(90deg, var(--bg-surface-alt) 25%, var(--border) 37%, var(--bg-surface-alt) 63%);
  background-size: 400% 100%;
  animation: skeleton-shimmer 1.5s ease-in-out infinite;
  border-radius: var(--radius-sm);
}
@keyframes skeleton-shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; }
  .chat-typing .dot { animation: none; opacity: .7; }
  .card, .btn, .progress-fill { transition: none; }
}

/* ---------------------------------------------------------------
   Icon tile - rounded square, soft domain fill, glyph in the
   saturated hue. Replaces loose floating icons; gives every data
   block a consistent anchor at its top-left.
--------------------------------------------------------------- */
.icon-tile {
  width: 40px; height: 40px; border-radius: var(--radius-md); flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--bg-surface-alt); color: var(--text-secondary);
}
.icon-tile.domain-psychosis { background: var(--domain-psychosis-soft); color: var(--domain-psychosis-ink); }
.icon-tile.domain-mood      { background: var(--domain-mood-soft);      color: var(--domain-mood-ink); }
.icon-tile.domain-anxiety   { background: var(--domain-anxiety-soft);   color: var(--domain-anxiety-ink); }
.icon-tile.domain-substance { background: var(--domain-substance-soft); color: var(--domain-substance-ink); }
.icon-tile.accent { background: var(--accent-soft); color: var(--accent-ink); }

/* Label/value pair - the repeating motif. Small muted uppercase label
   above a large near-black value. */
.pair-label {
  display: block; font-size: var(--text-sm); font-weight: 450;
  letter-spacing: 0; text-transform: none; color: var(--text-tertiary);
  margin-bottom: var(--sp-2);
}
.pair-value {
  display: block; font-family: var(--font-serif); font-size: var(--text-metric-size); font-weight: 400;
  line-height: var(--text-metric-lh); letter-spacing: var(--text-metric-spacing);
  color: var(--text-primary); font-variant-numeric: tabular-nums;
}

/* Every number in the app aligns. */
.text-metric, .pair-value, .stat-value, .table td { font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------
   Key/value row - "Label: Value" on one line, label muted and
   regular, value near-black and semibold. Reference uses this for
   its identity panel; here it fits the vignette and benchmark
   panels, where a two-line label-above-value pair wastes height.
--------------------------------------------------------------- */
.kv-list { display: flex; flex-direction: column; gap: var(--sp-2); }
.kv-row { font-size: var(--text-sm); line-height: 1.5; }
.kv-row .kv-key { color: var(--text-tertiary); }
.kv-row .kv-val { color: var(--text-primary); font-weight: 500; }

/* ---------------------------------------------------------------
   Fraction - current value carries the weight, the divisor recedes.
   "0/4" set in one uniform weight reads as a single opaque token;
   splitting it makes the number the thing you actually see.
--------------------------------------------------------------- */
.frac { font-variant-numeric: tabular-nums; }
.frac .frac-total { color: var(--text-tertiary); font-weight: 400; }

/* ---------------------------------------------------------------
   Dashed divider - softer than a solid rule, used between blocks
   inside a panel rather than between rows of the same list.
--------------------------------------------------------------- */
.divider-dashed { height: 0; border: 0; border-top: 1px solid var(--border); margin: var(--sp-5) 0; }

/* ---------------------------------------------------------------
   Segmented control - pill container on the tinted surface, active
   segment lifts out as a white chip.
--------------------------------------------------------------- */
.segmented {
  display: inline-flex; padding: 4px; gap: 2px;
  background: var(--bg-surface-alt); border-radius: var(--radius-pill);
}
.segmented button {
  border: none; background: transparent; cursor: pointer;
  font-family: var(--font-sans); font-size: var(--text-sm); font-weight: 500;
  color: var(--text-secondary); padding: 7px var(--sp-4); border-radius: var(--radius-pill);
  transition: background var(--duration-hover) var(--ease-standard), color var(--duration-hover) var(--ease-standard);
}
.segmented button:hover { color: var(--text-primary); }
.segmented button[aria-selected="true"] {
  background: var(--ink); color: var(--ink-text); font-weight: 480;
  box-shadow: none;
}

/* ---------------------------------------------------------------
   Step chip - numbered rounded square for sequential navigation.
   Replaces the plain numbered circle: a filled chip makes "where
   am I" legible at a glance, and .has-flag marks a step with
   something still outstanding.
--------------------------------------------------------------- */
.step-chip {
  position: relative; width: 34px; height: 34px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; background: var(--bg-surface-alt);
  font-family: var(--font-mono); font-size: var(--text-xs); font-weight: 400; color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
  transition: background var(--duration-hover) var(--ease-standard), color var(--duration-hover) var(--ease-standard);
}
.step-chip.done { background: var(--paper); color: var(--text-primary); box-shadow: inset 0 0 0 1px var(--border); }
.step-chip.current { background: var(--ink); color: var(--ink-text); }
.step-chip.has-flag::after {
  content: ""; position: absolute; right: -2px; bottom: -2px;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--warning); box-shadow: 0 0 0 2px var(--bg-surface);
}

/* ---------------------------------------------------------------
   Icon button row - equal rounded squares, active one takes a soft
   accent fill instead of a border.
--------------------------------------------------------------- */
.icon-row { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.icon-btn {
  width: 42px; height: 42px; border-radius: var(--radius-md); border: none;
  background: var(--bg-surface-alt); color: var(--text-secondary);
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
  transition: background var(--duration-hover) var(--ease-standard), color var(--duration-hover) var(--ease-standard);
}
.icon-btn:hover { background: var(--border); color: var(--text-primary); }
.icon-btn.on { background: var(--ink); color: var(--ink-text); }

/* ---------------------------------------------------------------
   Heading + subtitle pairing. The reference's hierarchy device:
   a moderate semibold title with a muted line immediately under it,
   no gap, no rule. Replaces shouting with a size jump.
--------------------------------------------------------------- */
.titled { display: flex; flex-direction: column; gap: 2px; }
.titled { gap: 6px; }
.titled .titled-sub { font-size: var(--text-subtitle-size); color: var(--text-secondary); line-height: 1.5; }

/* ---------------------------------------------------------------
   Donut - see donut.js for the geometry and why there are two
   rings. The centre figure is absolutely positioned over the SVG
   rather than set as SVG <text>, so it inherits the page's real
   font metrics and tabular figures instead of rendering at a size
   the type scale knows nothing about.
--------------------------------------------------------------- */
.donut { position: relative; width: 118px; height: 118px; flex-shrink: 0; }
.donut-svg { width: 100%; height: 100%; display: block; }
.donut-arc { transition: d var(--duration-progress) var(--ease-standard); }
.donut-centre {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1px; pointer-events: none;
}
.donut-value {
  font-family: var(--font-serif); font-size: 30px; font-weight: 400; line-height: 1; letter-spacing: -.02em;
  color: var(--text-primary); font-variant-numeric: tabular-nums;
}
.donut-total {
  font-size: var(--text-sm); font-weight: 500; line-height: 1;
  color: var(--text-tertiary); font-variant-numeric: tabular-nums;
}
.donut-sm { width: 92px; height: 92px; }
.donut-sm .donut-value { font-size: 24px; }

/* Legend: dot, value at weight, label muted - all on one line. */
.donut-legend { display: flex; flex-direction: column; gap: var(--sp-3); }
.donut-legend-row { display: flex; align-items: center; gap: var(--sp-3); font-size: var(--text-sm); }
.donut-legend-dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }
.donut-legend-val { font-weight: 550; color: var(--text-primary); font-variant-numeric: tabular-nums; min-width: 14px; }
.donut-legend-lbl { color: var(--text-secondary); }

/* Stat card with a donut: legend left, ring right, as in the reference. */
.stat-card.has-donut {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
}
.stat-card.has-donut .stat-icon { display: none; }
.stat-card-figures { min-width: 0; }
@media (max-width: 560px) { .stat-card.has-donut { gap: var(--sp-3); } }

/* ---------------------------------------------------------------
   Chat empty state - see chat.js renderEmptyState(). A 680px-tall
   empty scroll area reads as a broken page; this gives it a reason
   to be there and a first move to make.
--------------------------------------------------------------- */
.chat-empty {
  height: 100%; min-height: 240px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; padding: var(--sp-7) var(--sp-6); gap: var(--sp-2);
}
.chat-empty-icon {
  width: 52px; height: 52px; border-radius: var(--radius-lg);
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-surface-alt); color: var(--text-tertiary);
  margin-bottom: var(--sp-3);
}
.chat-empty-icon svg { width: 24px; height: 24px; }
.chat-empty-title {
  margin: 0; font-family: var(--font-serif); font-size: var(--text-xl); font-weight: 400;
  letter-spacing: -.015em; color: var(--text-primary);
}
.chat-empty-hint {
  margin: 0; font-size: var(--text-sm); line-height: 1.6;
  color: var(--text-tertiary); max-width: 44ch;
}

/* ---------------------------------------------------------------
   Toast - the one blocking message in the app. See toast.js for
   why it inverts with the theme and why it centres on the working
   column rather than the window.
--------------------------------------------------------------- */
.cc-toast {
  position: fixed; bottom: 30px; z-index: 700;
  display: flex; align-items: flex-start; gap: 14px;
  min-width: 340px; max-width: min(540px, calc(100vw - 32px));
  padding: 15px 14px 16px 18px;
  border-radius: 14px; overflow: hidden;
  background: var(--toast-bg);
  -webkit-backdrop-filter: blur(20px) saturate(150%);
  backdrop-filter: blur(20px) saturate(150%);
  box-shadow: 0 24px 50px -14px rgba(0,0,0,.45), 0 2px 8px rgba(0,0,0,.24),
              inset 0 0 0 1px var(--toast-ring),
              inset 0 1px 0 var(--toast-ring);
  color: var(--toast-fg); font-family: var(--font-sans);
  opacity: 0;
  transition: opacity 180ms var(--ease-standard), translate 220ms var(--ease-standard);
  translate: 0 10px;
}
.cc-toast.cc-toast-in { opacity: 1; translate: 0 0; }
.cc-toast.cc-toast-out { opacity: 0; translate: 0 6px; }

.cc-toast-n {
  font-size: 22px; font-weight: 700; letter-spacing: -.02em; line-height: 1.2;
  font-variant-numeric: tabular-nums; color: var(--toast-mark); flex-shrink: 0;
}
.cc-toast-stack { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.cc-toast-hd { font-size: 15px; font-weight: 600; line-height: 1.3; }
.cc-toast-sub { font-size: 12.5px; line-height: 1.45; color: var(--toast-fg-dim); }

.cc-toast-x {
  width: 28px; height: 28px; flex-shrink: 0; margin-left: 6px;
  border: none; background: transparent; border-radius: 50%;
  color: var(--toast-fg-dim); font-size: 13px; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background var(--duration-hover) var(--ease-standard),
              color var(--duration-hover) var(--ease-standard);
}
.cc-toast-x:hover { background: rgba(255,255,255,.10); color: var(--toast-fg); }
.cc-toast-x:focus-visible { outline: 2px solid var(--toast-fg); outline-offset: 1px; }

.cc-toast-bar { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: var(--toast-track); }
.cc-toast-bar i { display: block; height: 100%; width: 100%; background: var(--toast-mark); }

@media (max-width: 767px) {
  .cc-toast { left: 16px !important; right: 16px; bottom: 20px; min-width: 0;
              max-width: none; width: calc(100vw - 32px); transform: none !important; }
}
@media (prefers-reduced-motion: reduce) {
  .cc-toast { transition: none; translate: none; }
}

/* ---------------------------------------------------------------
   "Try the task yourself" — the entry point to the optional, ungraded
   cognitive demos. It used to be a bare <details> whose triangle read as
   a stray bullet and invited nothing. It is still a <details>, so it stays
   keyboard- and screen-reader-friendly, but the summary is drawn as a card
   with a clear call to action.
   --------------------------------------------------------------- */
.try-task { margin-top: var(--sp-7); }
.try-task > summary {
  display: flex; align-items: center; gap: var(--sp-4);
  padding: var(--sp-5); cursor: pointer; list-style: none;
  background: var(--bg-card); border: 1px solid transparent;
  border-radius: var(--radius-lg);
  transition: border-color var(--duration-hover) var(--ease-standard),
              box-shadow var(--duration-hover) var(--ease-standard),
              background var(--duration-hover) var(--ease-standard);
}
.try-task > summary::-webkit-details-marker,
.try-task > summary::marker { display: none; content: ""; }
.try-task > summary:hover { background: var(--mist-strong); }
.try-task > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.try-task[open] > summary {
  border-bottom-left-radius: 0; border-bottom-right-radius: 0;
  border-bottom-color: transparent; background: var(--bg-surface-alt);
}
.try-task-icon {
  flex: 0 0 auto; width: 40px; height: 40px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent-soft); color: var(--accent-ink);
}
.try-task-copy { flex: 1 1 auto; min-width: 0; }
.try-task-title { display: block; font-family: var(--font-serif); font-weight: 400; font-size: var(--text-lg); color: var(--text-primary); }
.try-task-sub { display: block; margin-top: 2px; font-size: var(--text-sm); color: var(--text-secondary); }
.try-task-badges { display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--sp-3); }
/* The neutral badge's fill matches the open card, so these get an outline
   of their own instead of disappearing into it. */
.try-task-badges .badge { background: transparent; box-shadow: inset 0 0 0 1px var(--border); color: var(--text-secondary); }
.try-task-cta {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 14px; border-radius: var(--radius-pill);
  background: var(--ink); color: var(--ink-text);
  font-size: var(--text-sm); font-weight: 500; white-space: nowrap;
}
.try-task-cta svg { transition: transform var(--duration-hover) var(--ease-standard); }
.try-task[open] .try-task-cta { background: var(--bg-surface); color: var(--text-primary); box-shadow: inset 0 0 0 1px var(--border); }
.try-task[open] .try-task-cta svg { transform: rotate(180deg); }
.try-task[open] .try-task-cta .cta-open,
.try-task:not([open]) .try-task-cta .cta-close { display: none; }
.try-task-body {
  border: 1px solid var(--border); border-top: none;
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
  padding: var(--sp-5);
}
@media (max-width: 640px) {
  .try-task > summary { flex-wrap: wrap; }
  .try-task-cta { width: 100%; justify-content: center; }
}

.continue-hero { transition: transform var(--duration-hover) var(--ease-standard), box-shadow var(--duration-hover) var(--ease-standard), border-color var(--duration-hover) var(--ease-standard); }
.continue-hero:hover { transform: none; }
@media (prefers-reduced-motion: reduce) { .continue-hero, .continue-hero:hover { transform: none; transition: none; } }

/* ---------------------------------------------------------------
   Rating controls, unified.
   The four cases were built at different times and their answer
   buttons had drifted apart: 40x40 with square corners in three of
   them, 44x44 with rounded corners in the fourth, and font sizes
   from 14 to 16px. They are one control now, at the 44px touch
   target, whatever markup each page happens to use.
   --------------------------------------------------------------- */
.likert label,
.rating-btn,
.likert-buttons button,
.option-row > * {
  min-width: 44px; min-height: 44px;
  /* explicit, because two of the pages redefine --radius-sm locally and
     the controls would end up 6px on one case and 8px on the rest */
  border-radius: var(--radius-pill) !important;
  font-size: var(--text-sm) !important;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background var(--duration-hover) var(--ease-standard),
              box-shadow var(--duration-hover) var(--ease-standard),
              color var(--duration-hover) var(--ease-standard);
}
.likert label:focus-visible,
.rating-btn:focus-visible,
.likert-buttons button:focus-visible,
.option-row > *:focus-visible,
.likert input:focus-visible + span,
.likert input:focus-visible ~ span {
  outline: 2px solid var(--accent); outline-offset: 2px;
}

/* ---------------------------------------------------------------
   Report figures (see charts.js). The depression report referenced
   .t-track / .t-marker / .t-big and none of them had any CSS, so the
   severity bar rendered as four lines of bare text. These are the
   shared versions, used by every case.
   --------------------------------------------------------------- */
.sev { margin: var(--sp-4) 0 var(--sp-3); }
.sev-head { display: flex; align-items: baseline; gap: var(--sp-4); flex-wrap: wrap; margin-bottom: var(--sp-4); }
.sev-score { display: flex; align-items: baseline; gap: 6px; }
.sev-score strong {
  font-family: var(--font-serif); font-size: var(--text-metric-size); font-weight: 400; letter-spacing: -.02em;
  line-height: 1; font-variant-numeric: tabular-nums; color: var(--text-primary);
}
.sev-score span { font-size: var(--text-sm); color: var(--text-tertiary); font-variant-numeric: tabular-nums; }
.sev-band {
  padding: 5px 12px; border-radius: var(--radius-pill);
  background: var(--select-fill); border: 1px solid var(--select-line);
  color: var(--select-ink, var(--text-primary)); font-size: var(--text-xs); font-weight: 500;
}
.sev-answered { font-size: var(--text-xs); color: var(--text-tertiary); margin-left: auto; }

.sev-track {
  position: relative; display: flex; gap: 2px; height: 34px;
  border-radius: var(--radius-sm); overflow: visible;
}
.sev-seg {
  min-width: 0; display: flex; align-items: center; justify-content: center;
  border-radius: 4px; overflow: hidden;
}
.sev-seg span {
  font-size: 10px; letter-spacing: .02em; color: var(--text-secondary);
  white-space: nowrap; padding: 0 4px; overflow: hidden; text-overflow: ellipsis;
}
.sev-seg.is-active span { color: var(--text-primary); font-weight: 600; }
.sev-marker {
  position: absolute; top: -6px; bottom: -6px; width: 2px;
  background: var(--text-primary); transform: translateX(-1px);
}
.sev-marker span {
  position: absolute; top: -20px; left: 50%; transform: translateX(-50%);
  font-family: var(--font-mono); font-size: 11px; font-weight: 600;
  color: var(--text-primary); background: var(--bg-surface); padding: 0 4px;
}
.sev-axis {
  display: flex; justify-content: space-between; margin-top: 10px;
  font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-tertiary);
}
@media (max-width: 640px) { .sev-seg span { display: none; } }

.ncurve { margin: var(--sp-5) 0 var(--sp-3); }
.ncurve-label { font-size: var(--text-xs); font-weight: 600; color: var(--text-secondary); margin-bottom: 6px; }
.ncurve canvas { display: block; width: 100%; }
.ncurve-key { font-size: var(--text-xs); color: var(--text-tertiary); line-height: 1.6; margin-top: 8px; }

/* Report verdict line: the categorical result, stated once and plainly.
   It used to be a free-floating tinted pill with no card around it. */
.verdict {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 18px; border-radius: var(--radius-md);
  background: var(--bg-surface-alt); border: 0;
  font-size: var(--text-sm); font-weight: 500; color: var(--text-primary);
  margin-bottom: var(--sp-5);
}
.verdict-mark {
  width: 22px; height: 22px; flex: 0 0 auto; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; background: var(--border); color: var(--text-secondary);
}
.verdict.diag-pos { background: var(--accent-soft); color: var(--accent-deep); }
.verdict.diag-pos .verdict-mark { background: var(--accent-deep); color: var(--accent-soft); }
.rpt-note { font-size: var(--text-xs); color: var(--text-tertiary); line-height: 1.65; margin-top: var(--sp-4); }
.count-strip { display: flex; gap: var(--sp-5); flex-wrap: wrap; }
.count-cell {
  flex: 1; min-width: 120px; display: flex; flex-direction: column; gap: 4px;
  padding: var(--sp-4) 0;
}
.count-num { font-family: var(--font-serif); font-size: var(--text-xl); font-weight: 400; font-variant-numeric: tabular-nums; color: var(--text-primary); }
.count-desc { font-size: var(--text-xs); color: var(--text-tertiary); }
.sev-cut {
  position: absolute; top: -4px; bottom: -4px; width: 0;
  border-left: 2px dashed var(--text-tertiary);
}
.sev-cut span {
  position: absolute; bottom: -22px; left: 4px; white-space: nowrap;
  font-family: var(--font-mono); font-size: 10px; color: var(--text-tertiary);
}
.sev-axis { margin-top: 24px; }

/* Distribution panels (charts.js). One per spectrum, side by side. */
.dist-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: var(--sp-5); margin: var(--sp-5) 0; }
.dist-panel { margin: 0; }
.dist-panel figcaption { font-size: var(--text-xs); font-weight: 600; color: var(--text-secondary); margin-bottom: 6px; }
.dist-panel canvas { display: block; width: 100%; }
.dist-note { font-size: var(--text-xs); color: var(--text-tertiary); line-height: 1.6; margin: 6px 0 0; }

/* T-score bars, the shape the cognitive tables already used. */
.tbars { margin: var(--sp-4) 0 var(--sp-3); }
.tbars-group {
  font-family: var(--font-serif); font-size: var(--text-lg);
  letter-spacing: -.01em; text-transform: none;
  color: var(--text-tertiary); margin: var(--sp-5) 0 var(--sp-3);
  padding-top: var(--sp-3); border-top: 1px solid var(--border);
}
.tbars-group:first-child { margin-top: 0; padding-top: 0; border-top: none; }
.tbars-row { display: grid; grid-template-columns: minmax(120px, 1.1fr) minmax(0, 2fr) 76px; align-items: center; gap: var(--sp-4); padding: 7px 0; }
.tbars-label { font-size: var(--text-sm); color: var(--text-primary); }
.tbars-track { height: 16px; position: relative; }
.tbars-rail {
  width: 100%; height: 10px; border-radius: var(--radius-pill);
  position: relative; top: 3px; overflow: hidden;
  background: repeating-linear-gradient(-45deg, var(--border) 0 5px, var(--bg-surface-alt) 5px 10px);
}
.tbars-norm { position: absolute; left: 20%; width: 40%; height: 100%; background: var(--select-fill); }
.tbars-fill { position: absolute; left: 0; height: 100%; border-radius: var(--radius-pill); background: var(--accent); }
.tbars-mid { position: absolute; left: 40%; top: 1px; width: 2px; height: 14px; border-radius: 1px; background: var(--text-tertiary); }
.tbars-val { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-secondary); text-align: right; font-variant-numeric: tabular-nums; }
.tbars-axis { display: flex; justify-content: space-between; margin-top: 8px; font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-tertiary); }
@media (max-width: 640px) { .tbars-row { grid-template-columns: 1fr 64px; } .tbars-track { grid-column: 1 / -1; } }

/* ---------------------------------------------------------------
   Alpha: the chat window is a floating artifact - paper, lifted,
   the one shadowed surface on a chat page (Steep's AI composer).
   The patient speaks on mist, the student in ink.
--------------------------------------------------------------- */
.card.chat-card {
  --bg-surface: var(--paper); --bg-surface-alt: var(--mist); --border: var(--hairline);
  background: var(--paper); box-shadow: var(--shadow-lg); border-radius: 24px;
}
.card.chat-card .chat-composer { background: var(--paper); border-top-color: var(--hairline); }

/* Every paragraph inside a "Try it yourself" box runs the full width of the
   box. The reading measure that caps prose elsewhere left these stopping
   halfway across, beside an empty right half. */
.try-task-body p { max-width: none !important; }

/* ---------------------------------------------------------------
   Student model choice (seminar instance only, built by chat.js):
   a two-way segmented pill at the top of the chat card. The chosen
   model is an ink pill, like every other selected control.
--------------------------------------------------------------- */
.chat-model {
  /* A header strip across the top of the chat card: same left inset as the
     messages, clear of the fullscreen button (top/right 10px, 32px), and
     vertically centred on it. */
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap; flex-shrink: 0;
  margin: 0; padding: 7px 56px 7px var(--sp-5);
  border-bottom: 1px solid var(--hairline);
}
.chat-model-label { font-size: var(--text-sm); color: var(--text-tertiary); }
.chat-model-toggle { display: inline-flex; gap: 2px; padding: 3px; border-radius: var(--radius-pill); background: var(--mist); }
.chat-model-toggle button {
  display: inline-flex; align-items: baseline; gap: 6px; height: 32px; align-items: center;
  padding: 0 14px; border: 0; border-radius: var(--radius-pill); background: transparent;
  font: 500 var(--text-sm)/1 var(--font-sans); color: var(--text-secondary); cursor: pointer;
  transition: background var(--duration-hover, .15s) ease, color var(--duration-hover, .15s) ease;
}
.chat-model-toggle button span { font-weight: 400; color: var(--text-tertiary); }
.chat-model-toggle button:hover { color: var(--text-primary); }
.chat-model-toggle button[aria-pressed="true"] { background: var(--ink); color: var(--ink-text); }
.chat-model-toggle button[aria-pressed="true"] span { color: inherit; opacity: .7; }
.chat-model-toggle button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* On a phone the word "Model" would push the toggle onto a second line;
   the buttons name the models themselves, so the label is kept for
   screen readers only. */
@media (max-width: 480px) {
  .chat-model-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}

/* ---- Announcements from the seminar leader (uvt.clincog.net, shell.js) ---- */
.announce-stack { display: flex; flex-direction: column; gap: var(--sp-2); max-width: var(--shell-content-max, 1200px); margin: 0 auto calc(-1 * var(--sp-4)); padding: var(--sp-5) clamp(24px, 16px + 2vw, 48px) 0; }
@media (max-width: 1023px) { .announce-stack { padding: var(--sp-4) var(--sp-4) var(--sp-2); margin-bottom: 0; } }
.announce { display: flex; align-items: flex-start; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); border-radius: var(--radius-md, 10px); background: var(--paper); box-shadow: inset 0 0 0 1px var(--border); color: var(--text-primary); font-size: 14px; line-height: 1.5; }
.announce.is-important { background: var(--ink); color: var(--ink-text); box-shadow: none; }
.announce-icon { flex: none; display: flex; margin-top: 2px; color: var(--accent); }
.announce.is-important .announce-icon { color: currentColor; }
.announce-text { flex: 1; min-width: 0; white-space: pre-line; overflow-wrap: anywhere; }
.announce-close { flex: none; border: 0; background: transparent; color: inherit; opacity: .7; cursor: pointer; padding: 2px; border-radius: 6px; display: flex; }
.announce-close:hover { opacity: 1; }
.announce-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
