/* ========================================
   Component Styles
   MGH ED Patient Hub
   ======================================== */

/* ========================================
   Header
   ======================================== */

.site-header {
  padding-top: var(--space-sm);
  padding-bottom: var(--space-xs);
  background-color: var(--bg);
  border-bottom: 1px solid var(--glass-border);
  box-shadow: var(--glass-inner-glow);
  /* Positioning lives on .ios-top-bar in ios.css (position: sticky,
     z-index: 100). Declaring position/z-index here too would silently
     depend on stylesheet order to resolve the conflict. */
}

/* Removed: .header-row, .header-group, .site-title. The iOS top bar replaced
   that header structure; no element carries these classes on any tab (the page
   title is `<p class="sr-only" id="site-title">`, an id, not this class). */

.header-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--min-touch-target);
  height: var(--min-touch-target);
  border: none;
  background: none;
  cursor: pointer;
  color: var(--text);
  border-radius: var(--border-radius-sm);
  transition: background-color var(--transition-fast);
  flex-shrink: 0;
}

.header-btn:hover {
  background-color: var(--glass-bg-medium);
}

.header-btn:focus-visible {
  outline: var(--focus-outline);
  outline-offset: var(--focus-offset);
}

.header-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}


/* Font Size Popover - inline horizontal control inside the gear menu.
   Wrapped in `.ios-gear-menu` to outrank any earlier absolute-positioned
   variants that may live elsewhere in the cascade. */
/* Removed: .font-size-wrapper - no element carries it; the font-size popover
   now lives directly inside the gear menu. */

.ios-gear-menu .font-size-popover {
  position: static;
  transform: none;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-xs);
  width: 100%;
  padding: var(--space-xs);
  background-color: var(--ios-bg-nested, var(--bg-surface));
  border: 1px solid var(--ios-border, var(--border));
  border-radius: var(--border-radius-sm);
  box-shadow: none;
  min-height: 52px;
  z-index: auto;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

.font-size-popover[hidden] {
  display: none;
}

.ios-gear-menu .font-size-step {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: none;
  background: none;
  cursor: pointer;
  color: var(--text);
  font-size: 1.75rem;
  font-weight: 300;
  border-radius: 50%;
  transition: background-color var(--transition-fast);
  line-height: 1;
  flex-shrink: 0;
  -webkit-tap-highlight-color: transparent;
}

.ios-gear-menu .font-size-step:hover {
  background-color: var(--border);
}

.ios-gear-menu .font-size-step:active {
  background-color: var(--border);
}

.ios-gear-menu .font-size-step:focus-visible {
  outline: var(--focus-outline);
  outline-offset: var(--focus-offset);
}

.ios-gear-menu .font-size-step:disabled {
  opacity: 0.25;
  cursor: not-allowed;
}

.ios-gear-menu .font-size-divider {
  width: 1px;
  height: 28px;
  background-color: var(--border);
  flex-shrink: 0;
}

.ios-gear-menu .font-size-track {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: 18px;
  flex: 1;
  padding: 0;
}

.ios-gear-menu .font-size-dot {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid var(--text-muted);
  background: transparent;
  transition: background-color var(--transition-fast), border-color var(--transition-fast), transform var(--transition-fast);
}

.font-size-dot.active {
  /* Dark brand green, not lime: the active dot is a non-text state
     indicator and needs 3:1 against the surface (lime is ~1.3:1). */
  background-color: var(--brand-secondary);
  border-color: var(--brand-secondary);
  transform: scale(1.15);
}

/* Language Selector */
/* Removed: .language-wrapper class rules. The element is
   `<div id="language-wrapper" class="sr-only">` - translate.js finds it by id,
   and .sr-only does the hiding. Nothing ever carried the class. */

.language-select {
  width: var(--min-touch-target);
  height: var(--min-touch-target);
  border: none;
  background-color: transparent;
  cursor: pointer;
  color: transparent;
  border-radius: var(--border-radius-sm);
  transition: background-color var(--transition-fast);
  font-size: 0;
  padding: 0;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231A1A1A' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='2' y1='12' x2='22' y2='12'/%3E%3Cpath d='M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: var(--icon-size);
}

[data-theme="dark"] .language-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23E5E5E5' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='2' y1='12' x2='22' y2='12'/%3E%3Cpath d='M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z'/%3E%3C/svg%3E");
}

.language-select:hover {
  background-color: var(--bg-surface);
}

.language-select:focus-visible {
  outline: var(--focus-outline);
  outline-offset: var(--focus-offset);
}

/* Translate Disclaimer Banner */
.translate-disclaimer {
  /* Pinned to the top, above the header/content but below the map overlay
     (z 1000) so the map still covers it when open - as it did before. During a
     page transition it is raised above the sliding ghost (see the
     html[data-page-transition] rule in ios.css) so the pages slide UNDER it
     instead of the banner being cloned, hidden, and flashed back - the flicker
     this fixes. Fixed (not in flow), so the top bar's padding-top reserves its
     height; centred to the app column like the header. */
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  max-width: var(--max-width);
  margin: 0 auto;
  padding: var(--space-sm);
  background-color: var(--section-yellow);
  border-bottom: 1px solid var(--section-yellow-end);
}

.translate-disclaimer[hidden] {
  display: none;
}

.translate-disclaimer-message {
  margin-bottom: 0;
  font-size: var(--font-size-sm);
  color: var(--text);
}

.translate-restore-btn {
  border: 1px solid var(--border);
  background-color: var(--bg);
  color: var(--text);
  border-radius: var(--border-radius-sm);
  min-height: var(--min-touch-target);
  padding: 0 var(--space-sm);
  font: inherit;
  font-size: var(--font-size-sm);
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  flex-shrink: 0;
}

/* Hide Google Translate's own UI elements */
.goog-te-banner-frame,
.goog-te-menu-frame,
#goog-gt-tt,
.goog-te-balloon-frame {
  display: none !important;
}

/* Google Translate parks its loading spinner offscreen (position: fixed at
   -1000, -1000) but leaves the animation running for the life of the page.
   The spinner-dash keyframes animate stroke-dasharray, which is a layout
   property on SVG, so an invisible element costs a style recalc plus a
   layout on every frame, forever - measured at 60 layouts/second while the
   page sits idle. That competes with map gestures for frame budget on
   exactly the low-end phones this site is built for. Stop the animation but
   keep the element, so Google can still position and show it mid-translate
   (as a static ring). Class names are Google's obfuscated ones: if they
   change, the rule simply stops matching and we are back to today's cost. */
.VIpgJd-ZVi9od-aZ2wEe-wOHMyf svg,
.VIpgJd-ZVi9od-aZ2wEe-wOHMyf circle {
  animation: none !important;
}

#google_translate_element {
  position: absolute;
  left: -9999px;
  height: 0;
  overflow: hidden;
}

.skiptranslate {
  height: 0 !important;
  overflow: hidden !important;
  visibility: hidden !important;
}

body {
  top: 0 !important;
  position: static !important;
}

/* Appearance choice - Auto / Light / Dark.
   Replaced a single toggle that previewed the destination theme. A toggle can
   only express two states, and the third (Auto - follow the phone) is the
   default and the one a patient needs to be able to get BACK to; see the
   markup note in index.template.html. */
.theme-choice {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.25rem;
  padding: 0.25rem;
  background: var(--ios-bg-nested);
  border: 1px solid var(--ios-border);
  border-radius: var(--border-radius-sm);
}

.theme-choice__btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  /* Full 44px target: this is tapped one-handed, often by someone unwell. */
  min-height: 44px;
  padding: 0.5rem 0.25rem;
  border: 1px solid transparent;
  border-radius: var(--border-radius-sm);
  background: transparent;
  color: var(--ios-muted);
  font-family: var(--font-family);
  font-size: 0.8125rem;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast),
    transform var(--transition-fast);
}

.theme-choice__btn svg {
  width: 18px;
  height: 18px;
  flex: none;
}

.theme-choice__btn:hover {
  color: var(--ios-ink);
  background: var(--ios-bg-card);
}

.theme-choice__btn:focus-visible {
  outline: var(--focus-outline);
  outline-offset: var(--focus-offset);
}

/* The selected state is carried by aria-pressed, not a class: the accessible
   state and the visible state cannot drift apart if they are the same thing. */
.theme-choice__btn[aria-pressed="true"] {
  background: var(--ios-bg-card);
  border-color: var(--ios-border);
  color: var(--ios-ink);
  box-shadow: var(--shadow-sm);
}

/* Colour alone must not carry the selection (WCAG 1.4.1), and the fill also
   survives forced-colors, where our background/shadow are discarded. */
.theme-choice__btn[aria-pressed="true"] svg {
  color: var(--ios-accent-strong);
}

@media (forced-colors: active) {
  .theme-choice__btn[aria-pressed="true"] {
    border-color: Highlight;
    border-width: 2px;
  }
}

/* ========================================
   Accordion Sections
   ======================================== */

.accordion-section {
  margin-bottom: var(--space-sm);
  overflow-anchor: none;
}

.accordion-section:first-child {
  margin-top: var(--space-sm);
}

.accordion-section:last-child {
  margin-bottom: 0;
}

.details-summary-label {
  flex: 1;
}

.details-chevron {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-left: var(--space-sm);
  color: var(--details-chevron-color, var(--text-secondary));
}

.details-chevron-icon {
  width: var(--details-chevron-size, 16px);
  height: var(--details-chevron-size, 16px);
  overflow: visible;
  transform-origin: center;
  transition: transform var(--transition-normal);
}

/* Content wrapper on How the ED works, Support Programs and FAQ. The
   accordion buttons that once showed and hid it were removed 2026-10-07;
   it is never [hidden] now. overflow: hidden is still load-bearing: it makes
   the wrapper a block formatting context, so the body's first and last
   child margins (FAQ search 5px top, last card 12-16px bottom) stay inside
   it rather than collapsing into the section around it. */
.accordion-content {
  overflow: hidden;
}

.accordion-body {
  padding: var(--space-sm);
}

/* ========================================
   Collapsible Subsections (Inside Accordions)
   ======================================== */

.subsection {
  border-bottom: 1px solid var(--border);
  overflow-anchor: none;
  scroll-margin-top: var(--space-sm);
}

.subsection:last-child {
  border-bottom: none;
}

.subsection summary {
  display: flex;
  align-items: center;
  cursor: pointer;
  padding: var(--space-sm) 0;
  min-height: var(--min-touch-target);
  list-style: none;
}

.subsection summary::-webkit-details-marker {
  display: none;
}

.subsection summary::marker {
  display: none;
  content: "";
}

.subsection summary :is(h2, h3) {
  margin: 0;
  flex: 1;
}

.subsection .details-chevron {
  --details-chevron-size: 16px;
}

.subsection:not([open]) .details-chevron-icon {
  transform: rotate(180deg);
}

.subsection[open] .details-chevron-icon {
  transform: rotate(0deg);
}

.subsection summary:focus-visible {
  outline: var(--focus-outline);
  outline-offset: var(--focus-offset);
  border-radius: var(--border-radius-sm);
}

.subsection-content {
  padding-bottom: var(--space-sm);
}

/* ========================================
   Expanded Cards (layout: "expanded-cards")
   Mirrors the FAQ category pattern: an <h2> heading above a bordered
   card, collapsibility only on nested .inline-details.
   ======================================== */

.expanded-card-section {
  display: block;
  scroll-margin-top: var(--space-md);
}

.expanded-card-section + .expanded-card-section {
  margin-top: var(--space-md);
}

.expanded-card-heading {
  margin: 0 0 var(--space-xs);
}

.expanded-card {
  margin: 0;
  background-color: var(--bg-surface);
  border: 1px solid var(--glass-border);
  border-radius: var(--border-radius-sm);
  padding: 0 var(--space-sm);
  box-shadow: var(--shadow-sm);
  display: flow-root;
}

.expanded-card > :first-child:not(.inline-details) { margin-top: var(--space-sm); }
.expanded-card > :last-child:not(.inline-details) { margin-bottom: var(--space-sm); }

/* Inside a card: strip the inline-details pill chrome and use a
   horizontal divider between adjacent items instead. Matches .faq-item. */
.expanded-card .inline-details {
  border: none;
  border-radius: 0;
  border-bottom: 1px solid var(--border);
  margin: 0;
  padding: 0;
  scroll-margin-top: var(--space-md);
}

.expanded-card .inline-details:last-child {
  border-bottom: none;
}

.expanded-card .inline-details > summary {
  padding: var(--space-sm) 0;
}

/* Kicker-lite treatment for sub-headings inside a card (e.g. "Good to know"). */
.expanded-card h4 {
  margin: var(--space-sm) 0 var(--space-2xs);
  font-size: var(--type-kicker);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--text-secondary);
  font-weight: 600;
}

/* ========================================
   Zone Cards (Inside How the ED Works)
   ======================================== */

.zone-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  margin-top: var(--space-sm);
  margin-bottom: var(--space-sm);
}

.zone-card {
  background-color: var(--bg-surface);
  border: 1px solid var(--glass-border);
  border-radius: var(--border-radius-sm);
  padding: var(--space-sm);
  box-shadow: var(--shadow-sm);
}

.zone-card h4 {
  margin-top: 0;
  margin-bottom: var(--space-xs);
}

.zone-card p {
  margin-bottom: 0;
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
}

/* ========================================
   Content Cards (Generic info grouping)
   ======================================== */

.content-card {
  background-color: var(--bg-surface);
  border: 1px solid var(--glass-border);
  border-radius: var(--border-radius-sm);
  padding: var(--space-sm);
  margin-bottom: var(--space-xs);
  box-shadow: var(--shadow-sm);
}

.content-card :is(h3, h4) {
  margin-top: 0;
  margin-bottom: var(--space-xs);
}

.content-card p:last-child,
.content-card ul:last-child,
.content-card ol:last-child {
  margin-bottom: 0;
}

.collapsible-card {
  padding: 0;
}

.collapsible-card summary {
  display: flex;
  align-items: center;
  cursor: pointer;
  padding: var(--space-sm);
  list-style: none;
  min-height: var(--min-touch-target);
}

.collapsible-card summary::-webkit-details-marker {
  display: none;
}

.collapsible-card summary::marker {
  display: none;
  content: "";
}

.collapsible-card summary :is(h3, h4) {
  margin: 0;
  flex: 1;
}

.collapsible-card:not([open]) .details-chevron-icon {
  transform: rotate(180deg);
}

.collapsible-card[open] .details-chevron-icon {
  transform: rotate(0deg);
}

.collapsible-card[open] summary {
  border-bottom: 1px solid var(--border);
}

.collapsible-card summary:focus-visible {
  outline: var(--focus-outline);
  outline-offset: var(--focus-offset);
  border-radius: var(--border-radius-sm);
}

.collapsible-card-content {
  padding: var(--space-sm);
}

.collapsible-card-content p:last-child,
.collapsible-card-content ul:last-child,
.collapsible-card-content ol:last-child {
  margin-bottom: 0;
}

/* ========================================
   Map Embed
   ======================================== */

.map-embed-wrapper {
  position: relative;
  width: 100%;
  padding-bottom: 75%;
  margin: var(--space-xs) 0;
  border-radius: var(--radius, 8px);
  overflow: hidden;
}

.map-embed-wrapper iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* ========================================
   Test Cards (Inside Assessments & Tests)
   ======================================== */

.test-card {
  background-color: var(--bg-surface);
  border: 1px solid var(--glass-border);
  border-radius: var(--border-radius-sm);
  padding: var(--space-sm);
  margin-bottom: var(--space-xs);
  box-shadow: var(--shadow-sm);
}

.test-card h4 {
  margin-top: 0;
  margin-bottom: var(--space-2xs);
}

.test-card p {
  margin-bottom: 0;
  color: var(--text-secondary);
}

/* ========================================
   FAQ Items (Using <details>/<summary>)
   ======================================== */

.faq-list {
  margin-top: var(--space-xs);
  margin-bottom: var(--space-sm);
  background-color: var(--bg-surface);
  border: 1px solid var(--glass-border);
  border-radius: var(--border-radius-sm);
  padding: 0 var(--space-sm);
  box-shadow: var(--shadow-sm);
}

.faq-item {
  border-bottom: 1px solid var(--border);
}

.faq-item:last-child {
  border-bottom: none;
}

.faq-item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-sm) 0;
  cursor: pointer;
  font-weight: 600;
  list-style: none;
  min-height: var(--min-touch-target);
  color: var(--text);
}

/* Remove default marker */
.faq-item summary::-webkit-details-marker {
  display: none;
}

.faq-item summary::marker {
  display: none;
  content: "";
}

.faq-item .details-chevron {
  --details-chevron-size: 14px;
}

.faq-item:not([open]) .details-chevron-icon {
  transform: rotate(180deg);
}

.faq-item[open] .details-chevron-icon {
  transform: rotate(0deg);
}

.faq-item summary:hover {
  color: var(--link);
}

.faq-item summary:focus-visible {
  outline: var(--focus-outline);
  outline-offset: var(--focus-offset);
  border-radius: var(--border-radius-sm);
}

.faq-item p,
.faq-item div {
  padding-bottom: var(--space-sm);
  color: var(--text);
}

.faq-item div > p {
  margin: 0;
  padding-bottom: var(--space-xs);
}

.faq-item div > ul {
  margin-top: var(--space-xs);
  margin-bottom: var(--space-xs);
  padding-left: var(--space-md);
}

.faq-item div > p:last-child {
  padding-bottom: 0;
}

.disclaimer {
  font-size: var(--font-size-sm);
  color: var(--text-muted);
  font-style: italic;
  margin-top: var(--space-sm);
}

/* ========================================
   Error & Loading States
   ======================================== */

.section-loading,
.load-error {
  text-align: center;
  color: var(--text-muted);
  font-style: italic;
  padding: var(--space-md) var(--space-sm);
}

/* -------- Skeleton placeholders + content reveal (smoothness pass) --------
   While a section's JSON is in flight the body shows shimmer bars instead of
   the old "Loading content..." sentence - placeholders read as "arriving",
   not "empty". The bars are decorative (aria-hidden) with an sr-only text
   fallback; the nomodule / slow-boot watchdogs in index.template.html write
   their honest message via textContent on .section-loading, which replaces
   the bars wholesale - that path needs no changes here. */
.skeleton-bar {
  display: block;
  position: relative;
  overflow: hidden;
  height: 0.875rem;
  width: 100%;
  margin: 0 auto 0.75rem;
  border-radius: var(--border-radius-sm);
  background: var(--skeleton-bar);
}

.skeleton-bar--w85 { width: 85%; }
.skeleton-bar--w70 { width: 70%; }

@media (prefers-reduced-motion: no-preference) {
  .skeleton-bar::after {
    content: "";
    position: absolute;
    inset: 0;
    transform: translateX(-100%);
    background: linear-gradient(90deg, transparent, var(--skeleton-sheen), transparent);
    animation: skeleton-sweep 1.6s ease-in-out infinite;
  }
}

@keyframes skeleton-sweep {
  to { transform: translateX(100%); }
}

/* When a section's real content lands (render.js adds .is-filled after the
   innerHTML swap), it rises in softly instead of popping - one animation per
   section container, not per child, so a full-page load stays at ~15 cheap
   compositor animations. One-shot for real: render.js removes the class on
   animationend, because a matching element that goes display:none ->
   rendered again (tab switches, WebKit renderer re-attach when a nearby
   details toggles) restarts the animation and flashes the whole section. */
@media (prefers-reduced-motion: no-preference) {
  .accordion-body.is-filled {
    animation: content-reveal-in var(--transition-normal);
  }
}

@keyframes content-reveal-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
}

/* Expanding surfaces get the same soft entrance: the chevron already eases,
   but the revealed body used to pop in the same frame - a visible mismatch.
   These all go display:none -> rendered, which restarts the animation on
   each open. Close stays instant (iOS convention). Print kills all
   animation (utilities.css) so beforeprint's open-everything never
   snapshots a mid-fade frame.
   Excluded: .flow-step and .subsection. accordion.js drives those through
   a close-sibling-then-smooth-scroll sequence; a fade running while the
   page travels reads as a top-of-page flicker on iOS Safari (Alvin,
   Steps page, 2026-07-23).
   Simple opens (FAQ, inline details, support cards) keep the reveal. */
@media (prefers-reduced-motion: no-preference) {
  details[open]:not(.flow-step):not(.subsection) > *:not(summary),
  .team-tile.is-active .team-tile__expanded,
  .test-tile.is-active .test-tile__expanded,
  .zone-detail:not([hidden]),
  .zone-flow-content:not([hidden]) {
    animation: content-reveal-in var(--transition-normal);
  }
}

.map-loading {
  text-align: center;
  color: var(--text-muted);
  padding: var(--space-xl);
}

/* ========================================
   Footer
   ======================================== */

/* Brand Book skyline strip (brochure footer motif): lime silhouettes
   standing directly on the footer's top rule. Decorative only. */
.footer-skyline {
  display: block;
  width: 100%;
  max-width: var(--max-width);
  height: auto;
  margin: var(--space-lg) auto 0;
  padding: 0 var(--space-xs);
  fill: var(--brand-primary);
}

.footer-skyline + .site-footer {
  /* The skyline supplies the visual gap; buildings sit on the rule. */
  margin-top: 0;
}

@media (min-width: 481px) {
  .footer-skyline {
    /* Track the .site-footer container padding step-up (base.css). */
    padding: 0 var(--space-sm);
  }
}

.site-footer {
  margin-top: var(--space-md);
  padding-top: var(--space-md);
  padding-bottom: var(--space-lg);
  border-top: 1px solid var(--glass-border);
}

.footer-content {
  text-align: center;
}

.footer-updated {
  font-size: var(--font-size-sm);
  color: var(--text-muted);
  margin-bottom: var(--space-xs);
}

.footer-disclaimer {
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
  margin-bottom: var(--space-xs);
}

.footer-security {
  font-size: var(--font-size-sm);
  color: var(--text-muted);
}

.footer-feedback {
  font-size: var(--font-size-sm);
  margin-top: var(--space-xs);
  margin-bottom: 0;
}

.footer-feedback-link {
  color: var(--link);
  text-decoration: underline;
}

.footer-feedback-link:hover {
  color: var(--link-hover);
}

/* ========================================
   App Update Banner
   ======================================== */

.app-update-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  max-width: var(--max-width);
  margin: 0 auto;
  padding: var(--space-sm);
  background-color: var(--bg-surface);
  border-bottom: 1px solid var(--glass-border);
}

.app-update-banner[hidden] {
  display: none;
}

.app-update-message {
  margin-bottom: 0;
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
}

.site-status-banner {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: var(--space-sm);
  border-bottom: 1px solid var(--glass-border);
  font-size: var(--font-size-sm);
}

.site-status-banner-info {
  background-color: var(--section-blue);
  color: var(--text);
}

.site-status-banner-warning {
  background-color: var(--section-yellow);
  color: var(--text);
}

.update-refresh-btn {
  border: 1px solid var(--border);
  /* Brand primary button: lime surface, charcoal label */
  background-color: var(--brand-primary);
  color: var(--text-on-brand);
  border-radius: var(--border-radius-sm);
  min-height: var(--min-touch-target);
  padding: 0 var(--space-sm);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.update-refresh-btn:focus-visible {
  outline: var(--focus-outline);
  outline-offset: var(--focus-offset);
}

.update-refresh-btn:disabled {
  opacity: 0.7;
  cursor: progress;
}

/* Removed: .feedback-unavailable - no element carries it (render.js builds
   the feedback card's unavailable state from other classes). */

/* ========================================
   Flow Steps (Process Flow in How the ED Works)
   ======================================== */

.flow-steps {
  list-style: none;
  padding: 0;
  margin: 0;
}

.flow-steps > li {
  position: relative;
}

.flow-step {
  border: 1px solid var(--glass-border);
  border-radius: var(--border-radius);
  background-color: var(--bg-surface);
  box-shadow: var(--shadow-sm);
  overflow-anchor: none;
  scroll-margin-top: var(--space-sm);
}

.flow-step summary {
  display: flex;
  align-items: center;
  cursor: pointer;
  padding: var(--space-sm);
  min-height: var(--min-touch-target);
  list-style: none;
  gap: var(--space-sm);
}

.flow-step summary::-webkit-details-marker {
  display: none;
}

.flow-step summary::marker {
  display: none;
  content: "";
}

.flow-step-number {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  min-width: 32px;
  border-radius: 50%;
  background-color: var(--flow-step-bg, var(--brand-primary));
  /* Falls back to --text-on-brand, not --text: the default bg is the lime,
     where the deep charcoal is the AAA (8.27:1) pairing. */
  color: var(--flow-step-text, var(--text-on-brand));
  font-weight: 700;
  font-size: var(--font-size-base);
  flex-shrink: 0;
  box-shadow: 0 2px 8px var(--brand-primary-shadow, rgba(118, 176, 67, 0.3));
}

.flow-step summary h3 {
  margin: 0;
  flex: 1;
}

.flow-step .details-chevron {
  --details-chevron-size: 16px;
}

.flow-step:not([open]) .details-chevron-icon {
  transform: rotate(180deg);
}

.flow-step[open] .details-chevron-icon {
  transform: rotate(0deg);
}

.flow-step summary:focus-visible {
  outline: var(--focus-outline);
  outline-offset: var(--focus-offset);
  border-radius: var(--border-radius);
}

.flow-step[open] summary {
  border-bottom: 1px solid var(--border);
}

.flow-step-content {
  padding: var(--space-sm);
}

/* Flow arrows between steps */
.flow-arrow {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 4px 0;
}

.flow-arrow::before {
  content: "";
  display: block;
  width: 2px;
  height: 10px;
  background-color: var(--text-muted, #999);
}

.flow-arrow::after {
  content: "";
  display: block;
  width: 0;
  height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 6px solid var(--text-muted, #999);
}

/* Inline details (urgency levels nested toggle) */
.inline-details {
  border: 1px solid var(--glass-border);
  border-radius: var(--border-radius-sm);
  margin: var(--space-sm) 0;
}

.inline-details summary {
  display: flex;
  align-items: center;
  cursor: pointer;
  padding: var(--space-xs) var(--space-sm);
  list-style: none;
  font-weight: 600;
  color: var(--text-secondary);
  min-height: var(--min-touch-target);
}

.inline-details summary::-webkit-details-marker {
  display: none;
}

.inline-details summary::marker {
  display: none;
  content: "";
}

.inline-details .details-chevron {
  --details-chevron-size: 14px;
}

.inline-details:not([open]) .details-chevron-icon {
  transform: rotate(180deg);
}

.inline-details[open] .details-chevron-icon {
  transform: rotate(0deg);
}

.inline-details summary:focus-visible {
  outline: var(--focus-outline);
  outline-offset: var(--focus-offset);
  border-radius: var(--border-radius-sm);
}

.inline-details > :not(summary) {
  padding: var(--space-sm);
  padding-top: var(--space-sm);
}

.inline-details ul,
.inline-details ol {
  margin-top: 0;
  margin-bottom: var(--space-sm);
}

.inline-details li {
  margin-bottom: var(--space-2xs);
}

.inline-details li:last-child {
  margin-bottom: 0;
}

/* The CTAS triage badge styles that used to live here (.ctas-badge, .ctas-1
   through .ctas-5) were removed by the 2026-07-29 audit: nothing on this site
   emits those classes. The iOS redesign renders triage levels through
   .ios-urgency-item[data-level="N"] .ios-urgency-badge in screens.css, whose
   colours were deepened to clear AAA 7:1 - the old badge palette here still
   held the pre-AAA hues (#0072C6, #D32F2F, ...), so a future reader could
   reasonably have taken them for the live values. The frozen /classic/
   snapshot was the last consumer of .ctas-* and was deleted 2026-08-02, so
   these rules are now unused - safe to drop in a future cleanup. */

/* ========================================
   Zone Selector (Interactive Zone Picker)
   ======================================== */

.zone-selector {
  margin: var(--space-sm) 0;
}

.zone-selector-intro {
  margin-bottom: var(--space-sm);
}

.zone-selector-grid {
  display: grid;
  /* minmax(0, 1fr), not 1fr: a bare `1fr` means `minmax(auto, 1fr)`, so each
     column refuses to shrink below its content's min-content width. At the
     larger text sizes that floor exceeds the container and the grid pushes
     the whole page into horizontal scrolling - on exactly the accessibility
     path that needs it least. minmax(0, ...) lets the text wrap instead.
     (screens.css `.zone-grid` already had this right.) */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--space-xs);
  margin-bottom: var(--space-sm);
}

@media (max-width: 359px) {
  .zone-selector-grid {
    grid-template-columns: 1fr;
  }
}

.zone-btn {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
  padding: var(--space-sm);
  min-height: var(--min-touch-target);
  border: 1px solid var(--glass-border);
  border-left: 4px solid var(--zone-color, var(--border));
  border-radius: var(--border-radius-sm);
  background-color: var(--zone-bg, var(--bg-surface));
  cursor: pointer;
  font-family: inherit;
  font-size: var(--font-size-base);
  color: var(--text-primary);
  width: 100%;
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--transition-normal), border-color var(--transition-normal), transform var(--transition-normal);
}

.zone-btn:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-1px);
}

.zone-btn:focus-visible {
  outline: var(--focus-outline);
  outline-offset: var(--focus-offset);
}

.zone-btn-name {
  font-weight: 600;
}

.zone-btn-alt {
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
  font-weight: 400;
}

.zone-btn.active .zone-btn-alt {
  margin-left: var(--space-sm);
}

/* Zone color definitions */
.zone-btn[data-zone="red"] {
  --zone-color: #FF3B30;
  --zone-bg: rgba(255, 59, 48, 0.1);
}
.zone-btn[data-zone="blue"] {
  --zone-color: #4A90E2;
  --zone-bg: rgba(74, 144, 226, 0.1);
}
.zone-btn[data-zone="pink"] {
  --zone-color: #FF9CCF;
  --zone-bg: rgba(255, 156, 207, 0.1);
}
.zone-btn[data-zone="green"] {
  --zone-color: #34C759;
  --zone-bg: rgba(52, 199, 89, 0.1);
}
.zone-btn[data-zone="raz"] {
  --zone-color: #FFE066;
  --zone-bg: rgba(255, 224, 102, 0.1);
}
.zone-btn[data-zone="yellow"] {
  --zone-color: #FFF59D;
  --zone-bg: rgba(255, 245, 157, 0.1);
}
.zone-btn[data-zone="purple"] {
  --zone-color: #8E7CF0;
  --zone-bg: rgba(142, 124, 240, 0.1);
}
.zone-btn[data-zone="cyez"] {
  --zone-color: #00CFE8;
  --zone-bg: rgba(0, 207, 232, 0.1);
}

/* Dark mode: increase tint opacity. Keyed to the resolved in-app theme
   ([data-theme], stamped by preferences.js) - not prefers-color-scheme -
   so a user who picks Light on an OS-dark phone gets light-mode tints,
   matching every other themed surface (see the convention note in ios.css). */
[data-theme="dark"] .zone-btn[data-zone="red"] { --zone-bg: rgba(255, 59, 48, 0.15); }
[data-theme="dark"] .zone-btn[data-zone="blue"] { --zone-bg: rgba(74, 144, 226, 0.15); }
[data-theme="dark"] .zone-btn[data-zone="pink"] { --zone-bg: rgba(255, 156, 207, 0.15); }
[data-theme="dark"] .zone-btn[data-zone="green"] { --zone-bg: rgba(52, 199, 89, 0.15); }
[data-theme="dark"] .zone-btn[data-zone="raz"] { --zone-bg: rgba(255, 224, 102, 0.15); }
[data-theme="dark"] .zone-btn[data-zone="yellow"] { --zone-bg: rgba(255, 245, 157, 0.15); }
[data-theme="dark"] .zone-btn[data-zone="purple"] { --zone-bg: rgba(142, 124, 240, 0.15); }
[data-theme="dark"] .zone-btn[data-zone="cyez"] { --zone-bg: rgba(0, 207, 232, 0.15); }

.zone-btn-arrow {
  display: none;
  width: var(--arrow-size);
  height: var(--arrow-size);
  border-right: var(--arrow-border-width) solid var(--text-secondary);
  border-bottom: var(--arrow-border-width) solid var(--text-secondary);
  transform: rotate(-45deg);
  transition: transform var(--transition-fast);
  flex-shrink: 0;
  margin-left: auto;
}

.zone-btn.active {
  border-left-width: 6px;
  cursor: pointer;
  grid-column: 1 / -1;
  flex-direction: row;
  align-items: center;
  scroll-margin-top: var(--space-sm);
  box-shadow: var(--shadow-md), var(--glass-inner-glow);
}

.zone-btn.active .zone-btn-arrow {
  display: block;
  transform: rotate(-135deg);
}

.zone-btn[hidden] {
  display: none;
}

/* Zone detail panel (expanded zone content) */
.zone-detail {
  padding: 0;
}

.zone-detail[hidden] {
  display: none;
}

.zone-detail-rooms {
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
  font-weight: 600;
  margin-bottom: var(--space-xs);
}

.zone-detail-description {
  margin-bottom: var(--space-sm);
  color: var(--text-secondary);
}

.zone-bridge-link {
  display: block;
  margin-top: var(--space-sm);
  padding-top: var(--space-sm);
  border-top: 1px solid var(--border);
  color: var(--link);
  font-weight: 600;
}

.zone-after-note {
  font-size: var(--font-size-base);
  color: var(--text-muted);
  font-style: italic;
}

/* ========================================
   Language Selection Modal (First Visit)
   ======================================== */

.language-modal-overlay {
  position: fixed;
  inset: 0;
  /* Above the dock (ios.css z-index 9001) and the page-transition ghost
     (9100): a modal dialog must cover ALL navigation - the dock was floating
     over the backdrop, visibly and tappably, letting patients navigate away
     under an open modal. */
  z-index: 9300;
  background-color: var(--bg-overlay);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-sm);
  opacity: 0;
  transition: opacity var(--transition-normal);
}

.language-modal-overlay.active {
  opacity: 1;
}

.language-modal {
  background-color: var(--glass-bg-heavy);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border);
  border-radius: var(--border-radius);
  width: 100%;
  max-width: 400px;
  max-height: 85vh;
  display: flex;
  flex-direction: column;
  box-shadow: var(--glass-shadow), var(--glass-inner-glow);
  overflow: hidden;
  opacity: 0;
  transform: scale(0.95);
  transition: opacity var(--transition-normal), transform var(--transition-normal);
}

.language-modal-overlay.active .language-modal {
  opacity: 1;
  transform: scale(1);
}

.language-modal:focus {
  outline: none;
}

.language-modal-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  padding: var(--space-sm);
  gap: var(--space-xs);
}

.language-modal-title {
  margin: 0;
  font-size: var(--font-size-xl);
  font-weight: 700;
  color: var(--text);
  line-height: var(--line-height-tight);
  flex: 1;
}

/* Text button, not an icon: "Continue in English" must be readable at a
   glance by the users least fluent with web conventions. */
.language-modal-close {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--min-touch-target);
  padding: 0.375rem 0.75rem;
  border: 1px solid var(--border);
  background: var(--bg-surface);
  border-radius: var(--border-radius-sm);
  cursor: pointer;
  color: var(--text);
  font-size: var(--font-size-base);
  font-weight: 600;
  /* May wrap to two lines on 320px phones - shrinking beats overflowing
     the modal (the header row clipped at 320px with nowrap behavior). */
  min-width: 0;
  text-align: center;
}

.language-modal-close:hover {
  background-color: var(--bg-surface);
}

.language-modal-close:focus-visible {
  outline: var(--focus-outline);
  outline-offset: var(--focus-offset);
}

/* Where-the-words-go disclosure (REVIEW-BACKLOG item 2, ruled 2026-08-20):
   sits between the header and the language list, always rendered. Quiet but
   readable - it is a privacy fact, not a warning. flex-shrink 0 so the
   scrolling list can never squash it. */
.language-modal-note {
  flex-shrink: 0;
  margin: 0 var(--space-sm) var(--space-xs);
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
}

/* Active-language strip under the header (only rendered when a language is
   selected): checkmark + native name + English name, for the patient and any
   staff helping them. flex-shrink 0 so the list can never squash it. */
.language-modal-current {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  margin: 0 var(--space-sm) var(--space-xs);
  padding: 0.75rem 1rem;
  background: var(--bg-surface);
  border: 1px solid var(--primary, #B2D235);
  border-radius: var(--border-radius-sm);
}

.language-modal-current__label {
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
}

.language-modal-current__value {
  font-size: var(--font-size-lg);
  font-weight: 700;
  color: var(--text);
}

.language-modal-body {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 0 var(--space-sm) var(--space-sm);
}

.language-modal-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.language-modal-btn {
  width: 100%;
  min-height: var(--min-touch-target);
  padding: var(--space-xs) var(--space-sm);
  border: none;
  background: none;
  cursor: pointer;
  font-family: var(--font-family);
  font-size: var(--font-size-base);
  color: var(--text);
  text-align: left;
  border-radius: var(--border-radius-sm);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 0.5rem;
}

/* English gloss after the native name, for staff who cannot read the script. */
.language-modal-btn__english {
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
}

/* The active language, marked in the list as well as the header strip. */
.language-modal-btn.is-current {
  background-color: var(--bg-surface);
  font-weight: 700;
}

.language-modal-btn.is-current .language-modal-btn__native::before {
  content: "\2713\00a0";
  color: var(--primary, #B2D235);
}

.language-modal-btn:hover {
  background-color: var(--glass-bg-medium);
}

/* List rows flash their background on press (iOS list convention) rather
   than scaling - instant, and equally present under reduced motion. */
.language-modal-btn:active {
  background-color: var(--glass-bg-medium);
}

.language-modal-btn:focus-visible {
  outline: var(--focus-outline);
  outline-offset: var(--focus-offset);
}

.language-modal-btn-featured {
  font-size: var(--font-size-lg);
  font-weight: 500;
}

.language-modal-separator {
  height: 1px;
  background-color: var(--border);
  margin: var(--space-xs) 0;
}

/* ========================================
   Staffing Indicator
   ======================================== */

.staffing-indicator {
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--text-secondary);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--border-radius-sm);
  padding: var(--space-xs) var(--space-sm);
  margin-bottom: var(--space-sm);
}

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
  .language-modal-overlay,
  .language-modal {
    transition: none;
  }

  .details-chevron-icon {
    transition: none;
  }
}


/* ================================================================
   Hub redesign (While You Wait + After Your Visit hub pages
   and their subpages). Uses the global iOS green accent
   (--ios-accent / --ios-accent-soft / --ios-accent-strong)
   throughout, matching Home / Process / FAQ. The data-color
   "orange" / "yellow" attributes still exist on the section
   shells for any future use, but no visual orange/yellow chrome
   is rendered - the page palette is cream + green like the
   rest of the site.
   ================================================================ */

/* ----------------------------------------------------------------
   Feature card (top "Right now in your zone" card)
   Cream surface matching the stacked-card pattern on Process / Home -
   no gradient, no left accent bar. Distinguished from a regular
   stacked-card only by its content (pulsing dot + kicker + stat tiles).
   ---------------------------------------------------------------- */
.feature-card {
  margin: 0 var(--space-xs) var(--space-sm);
  border-radius: var(--radius-card);
  padding: 1.25rem;
  background: var(--ios-bg-card);
  border: 1px solid var(--ios-border);
  box-shadow: var(--shadow-card);
  position: relative;
}
.feature-card__kicker {
  font-size: var(--type-kicker);
  font-weight: 700;
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--ios-accent-strong);
  margin: 0 0 0.625rem;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}
.feature-card__dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--ios-accent);
  box-shadow: 0 0 0 4px var(--ios-accent-soft);
  animation: feature-pulse 1.8s ease-in-out infinite;
}
@keyframes feature-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.4; transform: scale(0.7); }
}
.feature-card__title {
  margin: 0 0 0.625rem;
  font-size: 1.375rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ios-ink);
  line-height: 1.2;
}
.feature-card__body {
  margin: 0 0 var(--space-sm);
  color: var(--ios-ink);
  font-size: 1rem;
  line-height: 1.5;
}
.feature-card__stats {
  display: grid;
  /* minmax(0, 1fr), not 1fr: a bare `1fr` means `minmax(auto, 1fr)`, so each
     column refuses to shrink below its content's min-content width. At the
     larger text sizes that floor exceeds the container and the grid pushes
     the whole page into horizontal scrolling - on exactly the accessibility
     path that needs it least. minmax(0, ...) lets the text wrap instead.
     (screens.css `.zone-grid` already had this right.) */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 0.625rem;
  margin: 0 0 0.5rem;
  align-items: stretch;
}
.feature-card__stat {
  background: var(--ios-accent-soft);
  border: 1px solid var(--ios-border);
  border-radius: 14px;
  padding: 0.625rem 0.75rem;
  display: flex;
  flex-direction: column;
  height: 100%;
}
.feature-card__stat-num {
  font-size: 1.25rem;
  font-weight: 800;
  color: var(--ios-accent-strong);
  letter-spacing: -0.02em;
  line-height: 1;
  margin: 0 0 0.25rem;
  /* Deliberately NOT `white-space: nowrap`. Values like "3-10+ hours" already
     sit on one line at every size that fits, so nowrap bought nothing - but it
     made the string unshrinkable, which set the grid column's min-content floor
     and pushed the page into horizontal scrolling at the larger text sizes.
     Letting it wrap only ever takes effect when it genuinely cannot fit. */
  min-width: 0;
}
.feature-card__stat-label {
  font-size: 0.875rem;
  color: var(--ios-muted);
  line-height: 1.3;
  margin: 0;
}
.feature-card__foot {
  margin: 0.625rem 0 0;
  color: var(--ios-ink);
  font-size: 0.9375rem;
  line-height: 1.5;
}

/* ----------------------------------------------------------------
   Action grid (subpage tiles) - reuses .ios-tile from ios.css
   ---------------------------------------------------------------- */
.action-grid {
  display: grid;
  /* minmax(0, 1fr), not 1fr: a bare `1fr` means `minmax(auto, 1fr)`, so each
     column refuses to shrink below its content's min-content width. At the
     larger text sizes that floor exceeds the container and the grid pushes
     the whole page into horizontal scrolling - on exactly the accessibility
     path that needs it least. minmax(0, ...) lets the text wrap instead.
     (screens.css `.zone-grid` already had this right.) */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 0.625rem;
  padding: 0 var(--space-xs);
  margin-bottom: 0.75rem;
}
/* Wide variant: icon LEFT, title RIGHT of the icon (vertically centered),
   subtitle below spanning full width - mirrors `.team-tile__head` + preview
   pattern (Doctors / Nurses tiles) so the AYV "Admission or transfer" tile
   reads like a peer of the team tiles. Specificity bump (`.ios-tile.ios-tile--wide`,
   0,2,0) wins over the base `.ios-tile { flex-direction: column }` rule
   (0,1,0) which loads later in ios.css. */
.ios-tile.ios-tile--wide {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 0.625rem;
  row-gap: 0.25rem;
  align-items: center;
  min-height: 0;
  padding: 0.875rem 1rem 1.5rem;
}
.ios-tile.ios-tile--wide .ios-tile__icon {
  grid-column: 1;
  grid-row: 1;
  flex-shrink: 0;
}
.ios-tile.ios-tile--wide .ios-tile__body {
  display: contents;
}
.ios-tile.ios-tile--wide .ios-tile__title {
  grid-column: 2;
  grid-row: 1;
  margin: 0;
}
.ios-tile.ios-tile--wide .ios-tile__subtitle {
  grid-column: 1 / -1;
  grid-row: 2;
  margin: 0;
}

/* ----------------------------------------------------------------
   Team scroller (horizontal expand-in-place tiles). Mirrors the
   .test-scroller pattern so "Who is looking after you" reads as
   peer with "Tests you may have".
   ---------------------------------------------------------------- */
.team-scroller-wrap {
  margin: 0 0 var(--space-xs);
  position: relative;
}
/* Inline-end edge fade hints there's more content to scroll to. Hidden when
   a tile is expanded so it doesn't overlap the active card. The gradient
   direction is overridden under [dir="rtl"] so RTL users see the fade on
   the correct edge. */
.team-scroller-wrap::after {
  content: "";
  position: absolute;
  top: 0; bottom: 0;
  inset-inline-end: 0;
  width: 28px;
  pointer-events: none;
  background: linear-gradient(to right, transparent, var(--ios-bg-body));
  opacity: 1;
  transition: opacity 200ms ease;
}
[dir="rtl"] .team-scroller-wrap::after {
  background: linear-gradient(to left, transparent, var(--ios-bg-body));
}
.team-scroller-wrap:has(.team-scroller.has-active)::after { opacity: 0; }
.team-scroller {
  display: flex;
  gap: 0.5rem;
  /* Inline-start padding aligns the first tile's left edge with the
     action-grid tiles above (e.g. "Prepare while waiting"), which sit at
     16px from the viewport via `.action-grid { padding: 0 var(--space-xs) }`.
     Also gives the prev arrow 8px of breathing room before it overlaps tile
     content at scrollLeft=0. RTL: padding-inline-start flips automatically.
     `scroll-padding-inline-start` matches the padding so scroll-snap counts
     the padding as the snap origin - without it, mandatory snapping pulls
     scrollLeft to the first tile's offsetLeft (8px), which makes the prev
     arrow appear on first load and visually "scrolls past" the padding. */
  padding: 0.25rem 0 0.5rem;
  padding-inline-start: var(--space-xs);
  scroll-padding-inline-start: var(--space-xs);
  overflow-x: auto;
  /* Proximity (not mandatory) so prev/next arrow `scrollBy({ behavior: 'smooth' })`
     animates cleanly. Mandatory snap forces an instant snap to the nearest
     snap point on the destination side, which Safari treats as a jump rather
     than a smooth animation. Proximity still snaps on manual swipe end when
     the scroll comes to rest near a tile, which is the only place where the
     snap behavior is user-visible. */
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.team-scroller::-webkit-scrollbar { display: none; }
.team-scroller::after {
  content: "";
  flex: 0 0 0.25rem;
}
.team-tile {
  /* Sized so the next tile is partially visible on phones (peek affordance);
     capped at 200px so tablet/desktop don't get oversized cards. */
  flex: 0 0 calc(60% - 0.25rem);
  max-width: 200px;
  scroll-snap-align: start;
  background: var(--ios-bg-card);
  border: 1px solid var(--ios-border);
  border-radius: var(--radius-tile);
  padding: 0.875rem;
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: inherit;
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  transition: background var(--transition-fast), border-color var(--transition-fast),
    transform var(--transition-fast);
}
.team-tile.is-active {
  border-color: var(--ios-accent);
  flex: 1 1 100%;
  /* Override the collapsed-state cap so the active tile fills the scroller. */
  max-width: none;
  min-width: 0;
  position: relative;
}
/* Chevron affordance in the head row: down when collapsed, rotates 180deg
   to up when active. Replaces the previous "X close" badge so there is one
   consistent indicator that signals "this tile is tappable" in both states. */
.team-tile__chev {
  margin-left: auto;
  width: 24px; height: 24px;
  border-radius: 50%;
  background: var(--ios-divider);
  color: var(--ios-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: transform var(--transition-normal);
}
.team-tile__chev svg { width: 14px; height: 14px; stroke-width: 2.5; flex: none; }
.team-tile.is-active .team-tile__chev { transform: rotate(180deg); }
/* Hide non-active siblings instantly when a tile expands. Matches the
   zone-btn pattern on the Process page (siblings get [hidden]) - clean
   snap, no flex-basis collapse animation. */
.team-scroller.has-active .team-tile:not(.is-active) { display: none; }
/* Trailing spacer is irrelevant when only the active tile is rendered;
   collapse it so the active card fills the scroller width edge-to-edge. */
.team-scroller.has-active::after { display: none; }
.team-tile__head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
/* The head row is the tile's <button> (expanded content must not live
   inside a button for AT); reset UA button chrome so the card visuals are
   unchanged. The whole tile stays clickable via delegation. */
.team-tile__head,
.test-tile__head {
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  width: 100%;
}
.team-tile__icon {
  width: 28px; height: 28px;
  border-radius: 8px;
  background: var(--ios-accent-soft);
  color: var(--ios-accent);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.team-tile__icon svg { width: 16px; height: 16px; stroke-width: 1.75; flex: none; }
.team-tile__title {
  margin: 0;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--ios-ink);
}
.team-tile__count {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--ios-accent-strong);
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}
.team-tile__count-text { display: inline; }
.team-tile__count-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--ios-accent);
  box-shadow: 0 0 0 3px var(--ios-accent-soft);
  animation: feature-pulse 1.8s ease-in-out infinite;
  flex-shrink: 0;
}
.team-tile__preview {
  font-size: var(--type-kicker);
  color: var(--ios-muted);
  margin: 0;
  line-height: 1.35;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Expanded bullet list inside an active team tile. The tile itself becomes
   a single card containing icon + title + (count + preview) + bullets,
   matching the zone-tile pattern (no separate detail panel below that
   repeats the title).

   Animated open/close via the grid-template-rows 0fr -> 1fr trick: the
   Body shows/hides instantly to match the zone-btn pattern - no
   slide-down. When a tile is active, the divider + spacing appear with
   the body content. */
.team-tile__expanded { display: none; }
.team-tile.is-active .team-tile__expanded {
  display: block;
  margin-top: 0.625rem;
  padding-top: 0.625rem;
  border-top: 1px solid var(--ios-divider);
}
.team-tile__expanded-list {
  margin: 0;
  padding-left: 1.125rem;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--ios-ink);
  list-style: disc;
}
.team-tile__expanded-list li { margin-bottom: 0.4rem; }
.team-tile__expanded-list li:last-child { margin-bottom: 0; }
.team-tile__expanded-list li ::marker,
.team-tile__expanded-list li::marker {
  color: var(--ios-muted);
}
.team-tile__expanded-list strong {
  color: var(--ios-ink);
  font-weight: 600;
}

/* ----------------------------------------------------------------
   Test scroller (horizontal expand-in-place tiles)
   ---------------------------------------------------------------- */
.test-scroller-wrap {
  margin: 0 0 var(--space-xs);
  position: relative;
}
.test-scroller-wrap::after {
  content: "";
  position: absolute;
  top: 0; bottom: 0;
  inset-inline-end: 0;
  width: 28px;
  pointer-events: none;
  background: linear-gradient(to right, transparent, var(--ios-bg-body));
  opacity: 1;
  transition: opacity 200ms ease;
}
[dir="rtl"] .test-scroller-wrap::after {
  background: linear-gradient(to left, transparent, var(--ios-bg-body));
}
.test-scroller-wrap:has(.test-scroller.has-active)::after { opacity: 0; }
.test-scroller {
  display: flex;
  gap: 0.5rem;
  /* See .team-scroller above - same inline-start padding + scroll-padding for
     action-grid alignment and snap-aware "start" position. */
  padding: 0.25rem 0 0.5rem;
  padding-inline-start: var(--space-xs);
  scroll-padding-inline-start: var(--space-xs);
  overflow-x: auto;
  /* See .team-scroller above - proximity instead of mandatory so arrow-click
     smooth scroll animates instead of jumping. */
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.test-scroller::-webkit-scrollbar { display: none; }
.test-scroller::after {
  content: "";
  flex: 0 0 0.25rem;
}
.test-tile {
  /* Sized so the next tile is partially visible on phones (peek affordance);
     capped at 200px so tablet/desktop don't get oversized cards. */
  flex: 0 0 calc(60% - 0.25rem);
  max-width: 200px;
  scroll-snap-align: start;
  background: var(--ios-bg-card);
  border: 1px solid var(--ios-border);
  border-radius: var(--radius-tile);
  padding: 0.875rem;
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: inherit;
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  transition: background var(--transition-fast), border-color var(--transition-fast),
    transform var(--transition-fast);
}
.test-tile.is-active {
  border-color: var(--ios-accent);
  flex: 1 1 100%;
  max-width: none;
  min-width: 0;
  position: relative;
}
/* Chevron affordance in the head row: down when collapsed, rotates 180deg
   to up when active. Replaces the previous "X close" badge. Mirrors
   .team-tile__chev so both scrollers feel consistent. */
.test-tile__chev {
  margin-left: auto;
  width: 24px; height: 24px;
  border-radius: 50%;
  background: var(--ios-divider);
  color: var(--ios-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: transform var(--transition-normal);
}
.test-tile__chev svg { width: 14px; height: 14px; stroke-width: 2.5; flex: none; }
.test-tile.is-active .test-tile__chev { transform: rotate(180deg); }
/* Hide non-active siblings instantly when a tile expands - matches the
   zone-btn pattern. Mirrors .team-scroller.has-active. */
.test-scroller.has-active .test-tile:not(.is-active) { display: none; }
.test-scroller.has-active::after { display: none; }
.test-tile__head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.test-tile__icon {
  width: 28px; height: 28px;
  border-radius: 8px;
  background: var(--ios-accent-soft);
  color: var(--ios-accent);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.test-tile__icon svg { width: 16px; height: 16px; stroke-width: 1.75; flex: none; }
.test-tile__title {
  margin: 0;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--ios-ink);
}
.test-tile__time {
  font-size: 0.875rem;
  color: var(--ios-muted);
  margin: 0;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.test-tile__preview {
  font-size: var(--type-kicker);
  color: var(--ios-muted);
  margin: 0;
  line-height: 1.35;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Body shows/hides instantly to match the zone-btn pattern - no
   slide-down. Mirrors .team-tile__expanded. */
.test-tile__expanded { display: none; }
.test-tile.is-active .test-tile__expanded {
  display: block;
  margin-top: 0.625rem;
  padding-top: 0.625rem;
  border-top: 1px solid var(--ios-divider);
}
.test-tile__expanded-body {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--ios-ink);
}
.test-tile__expanded-body strong {
  color: var(--ios-ink);
  font-weight: 600;
}
/* Hide the truncated preview text when expanded (the full body below
   contains the same content unabridged). */
.test-tile.is-active .test-tile__preview { display: none; }
.test-disclaimer {
  margin: 0 var(--space-sm) 0.75rem;
  font-size: var(--type-kicker);
  color: var(--ios-muted);
  line-height: 1.4;
}
.test-disclaimer strong {
  color: var(--ios-ink);
  font-weight: 600;
}

/* ----------------------------------------------------------------
   Scroller controls: chevron arrows + pagination dots
   POR Apr 28: improve discoverability of horizontal scrolling on
   .team-scroller and .test-scroller (Who is looking after you /
   Tests you may have on While You Wait). Both wraps are
   position: relative so arrows can absolute-position over the edges.
   Visibility wired in hub-interactions.js based on scroll position
   and the .has-active expand state.
   ---------------------------------------------------------------- */
.scroller-arrow {
  position: absolute;
  top: calc(50% - 0.25rem);
  /* Account for the scroller's 0.5rem bottom padding so the arrow centers
     on the visible tile band, not the full wrap. */
  transform: translateY(-50%);
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 1px solid var(--ios-border);
  background: rgba(255, 255, 255, 0.92);
  color: var(--ios-ink);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font: inherit;
  padding: 0;
  box-shadow: var(--shadow-sm);
  z-index: 2;
  /* Sit slightly inset so the arrow ring isn't clipped by the scroller wrap. */
  transition: opacity var(--transition-fast), background var(--transition-fast),
    transform var(--transition-fast);
}
.scroller-arrow svg {
  width: 16px;
  height: 16px;
  stroke-width: 2.5;
  flex: none;
}
.scroller-arrow:hover {
  background: rgba(255, 255, 255, 1);
}
.scroller-arrow:focus-visible {
  outline: var(--focus-outline);
  outline-offset: var(--focus-offset);
}
/* Invisible hit-area extension to the 44px touch-target floor (the ring
   renders 32px). */
.scroller-arrow::after {
  content: '';
  position: absolute;
  inset: -6px;
  border-radius: 50%;
}
.scroller-arrow--prev { inset-inline-start: 0; }
.scroller-arrow--next { inset-inline-end: 0; }
.scroller-arrow[hidden] { display: none; }

/* When a tile is expanded, no scrolling is possible/needed - hide arrows. */
.team-scroller-wrap:has(.team-scroller.has-active) .scroller-arrow,
.test-scroller-wrap:has(.test-scroller.has-active) .scroller-arrow {
  display: none;
}

/* Dark mode: tint the arrow background so it remains visible against the
   darker page background. Uses [data-theme="dark"] (set by preferences.js
   based on the in-app Appearance setting) rather than
   @media (prefers-color-scheme: dark) so the arrows track the page theme,
   not the OS preference. */
[data-theme="dark"] .scroller-arrow {
  background: rgba(40, 40, 40, 0.92);
  color: var(--ios-ink);
  border-color: var(--ios-border);
}
[data-theme="dark"] .scroller-arrow:hover { background: rgba(50, 50, 50, 1); }

@media (prefers-reduced-motion: reduce) {
  .scroller-arrow { transition: none; }
}

/* ----------------------------------------------------------------
   List card (icon + title + desc rows)
   ---------------------------------------------------------------- */
.list-card {
  background: var(--ios-bg-card);
  border: 1px solid var(--ios-border);
  border-radius: var(--radius-card);
  margin: 0 var(--space-xs) 0.75rem;
  padding: 0.25rem 0;
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.list-card__row {
  display: flex;
  gap: 0.875rem;
  padding: 0.875rem 1rem;
  align-items: flex-start;
  border-bottom: 1px solid var(--ios-divider);
}
.list-card__row:last-child { border-bottom: none; }
.list-card__icon {
  width: 32px; height: 32px;
  border-radius: 10px;
  background: var(--ios-accent-soft);
  color: var(--ios-accent);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  margin-top: 1px;
}
.list-card__icon svg { width: 18px; height: 18px; stroke-width: 1.75; flex: none; }
.list-card__body { flex: 1; }
.list-card__title {
  margin: 0 0 0.125rem;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.25;
  color: var(--ios-ink);
}
.list-card__desc {
  margin: 0;
  font-size: 0.875rem;
  color: var(--ios-muted);
  line-height: 1.4;
}
.list-card__desc a {
  color: var(--ios-accent-strong);
  font-weight: 600;
}
.list-card__desc strong {
  color: var(--ios-ink);
  font-weight: 600;
}
.list-card__desc ul {
  margin: 0.375rem 0 0;
  padding-left: 1.125rem;
  list-style: disc;
}
.list-card__desc ul li {
  margin: 0.125rem 0;
  line-height: 1.4;
}

/* ----------------------------------------------------------------
   Do / Don't list (vertically stacked horizontal cards)
   Was a 2-col grid; switched to a single column so each card spans
   the full content width with body-sized type. The cramped 13px
   side-by-side layout failed legibility on phones and the smaller
   font fell below the practical AA readability floor.
   ---------------------------------------------------------------- */
.dodont {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
  padding: 0 var(--space-xs);
  margin-bottom: 0.75rem;
}
.dodont__col {
  background: var(--ios-bg-card);
  border: 1px solid var(--ios-border);
  border-radius: var(--radius-tile);
  padding: 1rem;
}
.dodont__head {
  display: flex; align-items: center; gap: 0.5rem;
  margin-bottom: 0.625rem;
  font-size: 1.0625rem;
  font-weight: 700;
  color: var(--ios-ink);
}
.dodont__marker {
  width: 22px; height: 22px;
  border-radius: 6px;
  display: flex; align-items: center; justify-content: center;
  color: white;
  /* Sits in a flex row beside a heading that grows in every translation; the
     other icon wrappers on the page already pin themselves this way. */
  flex: none;
}
.dodont__marker svg { flex: none; }
/* Do = brand dark green; Don't keeps a semantic red (no brand-palette
   equivalent carries the "avoid" meaning). White glyphs pass AA on both. */
.dodont__col--do .dodont__marker { background: var(--brand-secondary); }
.dodont__col--dont .dodont__marker { background: #C44848; }
.dodont__list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.dodont__list li {
  display: flex;
  gap: 0.625rem;
  align-items: flex-start;
  font-size: 1rem;
  line-height: 1.45;
  padding: 0.3125rem 0;
  color: var(--ios-ink);
}
.dodont__list li::before {
  content: "";
  flex-shrink: 0;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--ios-muted);
  margin-top: 0.55rem;
}

/* ----------------------------------------------------------------
   ED screen mock - intentionally NOT themed (mocks the real
   waiting-room screens which use fixed colors).

   The FRAME around it is the exception, and is themed on purpose: it
   is the site talking about the picture, not part of the picture. A
   hospital vice-president opened this page on 2026-08-07 and reported
   the wait-time clock as "displaying the wrong time" - the frozen
   example date read as a broken live screen. The italic caveat in the
   content above it is real, and was read past: at a phone width the
   picture fills the screen on its own, so the caveat is off-screen by
   the time the date is on it. The stamp and the note below travel with
   the picture at any scroll position.
   ---------------------------------------------------------------- */
.ed-screen-mock {
  margin: 0 var(--space-xs) 0.75rem;
}
.ed-screen-frame {
  border: 2px dashed var(--ios-muted);
  border-radius: var(--radius-card);
  /* No side padding on purpose. The zone pill wraps with
     `overflow-wrap: anywhere` so that a name with no break point cannot clip
     the mock on a 320px phone - which means any width the frame takes comes
     straight out of the picture and breaks "Green/Pink Zone" mid-word. The
     stamp and the note carry their own inset instead. */
  padding: 0 0 0.6rem;
  /* The negative side margins give the border its 2px back, so the picture is
     exactly as wide as it was before the frame existed. Four pixels sounds
     like nothing and is not: at 390px it is the difference between the zone
     pill reading "Green/Pink Zone" and "Green/Pin k Zone". */
  margin: 0.5rem -2px 0;
}
.ed-screen-frame__tag {
  /* Stored in sentence case and upper-cased here: a screen reader reads
     "Example", not "E X A M P L E". */
  text-transform: uppercase;
  letter-spacing: 0.09em;
  font-size: 0.75rem;
  font-weight: 700;
  /* 9.3:1 light (#414042 on #F3F3F3), 12.0:1 dark (#E5E5E5 on #262626). */
  color: var(--ios-ink);
  background: var(--ios-bg-nested);
  text-align: center;
  margin: 0;
  padding: 0.3rem 0.5rem;
  border-radius: 6px 6px 0 0;
}
.ed-screen-frame__note {
  /* 7.8:1 light on the page surface, 10.3:1 dark. */
  color: var(--ios-muted);
  font-size: 0.8125rem;
  line-height: 1.35;
  text-align: center;
  margin: 0.6rem 0.5rem 0;
}
.ed-tabs {
  display: flex;
  gap: 0.375rem;
  padding: 0.125rem;
  background: var(--ios-divider);
  border-radius: var(--radius-pill);
  margin: 0.5rem auto 0.75rem;
  width: fit-content;
}
.ed-tab {
  appearance: none;
  border: none;
  background: transparent;
  font: inherit;
  font-size: 0.75rem;
  font-weight: 600;
  /* Darker than var(--ios-muted) to clear the AAA 7:1 contrast threshold
     against the .ed-tabs background (var(--ios-divider) composites to
     ~#E1E2E3). #454446 hits ~7.5:1. The active-tab color (--ios-ink) is
     already strong enough on its lighter active-state background. */
  color: #454446;
  padding: 0.4rem 0.85rem;
  border-radius: var(--radius-pill);
  cursor: pointer;
  /* Scoped, not `all`: `all` silently catches any future layout property
     and turns a class toggle into per-frame layout work. */
  transition: background var(--transition-fast), color var(--transition-fast),
    box-shadow var(--transition-fast), transform var(--transition-fast);
}
.ed-tab.is-active {
  background: var(--ios-bg-card);
  color: var(--ios-ink);
  box-shadow: var(--shadow-sm);
}
/* Dark mode: revert to the muted token (--ios-muted, #C0C0C0 in dark) which
   has enough contrast on the darker tab-list background. The hard-coded
   #454446 above is light-mode only. */
[data-theme="dark"] .ed-tab:not(.is-active) {
  color: var(--ios-muted);
}
.ed-screen-stack { position: relative; }
.ed-screen {
  margin: 0 0 0.5rem;
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
  border: 1px solid var(--ios-border);
  font-family: "Helvetica Neue", Arial, sans-serif;
}
.ed-screen__banner {
  background: #c8e26b;
  color: #1f2a16;
  font-weight: 700;
  text-align: center;
  font-size: 0.6875rem;
  padding: 0.4rem 0.5rem;
  letter-spacing: 0.01em;
  line-height: 1.25;
}
.ed-screen__banner em {
  font-style: normal;
  background: #fff7d1;
  color: inherit;
  padding: 0 0.2rem;
  border-radius: 3px;
}
.ed-clock {
  display: grid;
  grid-template-columns: 1fr 1.1fr 1fr;
  background: #f4f6fb;
}
.ed-clock__col {
  /* Grid items default to min-width auto; without 0 the fixed-width gauge
     forces the 3-column mock wider than a 320px phone and it clips. */
  min-width: 0;
  padding: 0.75rem 0.5rem;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  min-height: 165px;
}
@media (max-width: 349px) {
  .ed-clock__col {
    padding-inline: 0.25rem;
  }
}

/* Mock colours hold AAA (7:1) text contrast: full-strength white on the
   purple (7.38:1 - no opacity fades, they composited down to ~5.8:1),
   #5F3790 purple text on the pale zone column (7.97:1). */
.ed-clock__col--purple { background: #6b3fa0; color: #fff; }
.ed-clock__col--mid    { background: #e9eef9; color: #1a1a1a; }
.ed-clock__col--zone   { background: #f4f6fb; color: #5F3790; }
.ed-clock__time-label  { font-size: 0.6875rem; }
.ed-clock__time        { font-size: 1.5rem; font-weight: 700; line-height: 1; letter-spacing: -0.01em; }
.ed-clock__divider     { width: 70%; height: 1px; background: rgba(255, 255, 255, 0.25); margin: 0.25rem 0; }
.ed-clock__waiting-lead { font-size: 0.6875rem; line-height: 1.2; }
.ed-clock__waiting-num { font-size: 1.5rem; font-weight: 800; line-height: 1; }
.ed-clock__waiting-foot { font-size: 0.625rem; line-height: 1.2; }
.ed-clock__date { font-size: 0.875rem; font-weight: 700; line-height: 1.15; }
.ed-clock__busy-q { font-size: 0.625rem; line-height: 1.2; color: #4C4C4E; margin-top: 0.25rem; }
.ed-clock__zone-pill {
  background: #6cd66c;
  /* Dark text on bright green is ~6.7:1 contrast (vs ~1.83:1 for white-on-green
     which fails axe color-contrast). The bg color is editor-overridable from
     wait-screens.json `zoneColor`, so dark text is the safer default - keeps
     legibility on any reasonably bright zoneColor an editor might set. */
  color: #0d3a0d;
  font-weight: 800;
  font-size: 0.875rem;
  padding: 0.4rem 0.6rem;
  border-radius: 6px;
  line-height: 1.05;
  margin-bottom: 0.25rem;
  /* Editor-supplied zone names ("Green/Pink Zone") have no space to break at
     the slash; without these the pill's min-content width clips the mock on
     320px phones. */
  max-width: 100%;
  overflow-wrap: anywhere;
}

@media (max-width: 349px) {
  .ed-clock__zone-pill {
    font-size: 0.8125rem;
    padding-inline: 0.4rem;
  }
}
.ed-clock__zone-num { font-size: 2.25rem; font-weight: 800; line-height: 1; }
.ed-clock__zone-label { font-size: 0.625rem; line-height: 1.2; }

.ed-gauge {
  /* Shrinks with its column on narrow phones; labels are %-positioned so
     they scale with it. */
  width: min(110px, 100%);
  aspect-ratio: 110 / 60;
  height: auto;
  position: relative;
}
.ed-gauge svg { width: 100%; height: 100%; display: block; }
.ed-gauge__labels {
  position: absolute;
  inset: 0;
  font-size: 0.5625rem;
  font-weight: 700;
  pointer-events: none;
  color: #1a1a1a;
}
.ed-gauge__labels span {
  position: absolute;
  transform: translate(-50%, -50%);
  white-space: nowrap;
}

/* The corner labels (Low first, Extreme last) sit at 10%/92%; center-anchored
   they always overhang the gauge box, which clipped the mock on 320px phones.
   Anchor them by their inner edge instead so they stay inside at any size. */
.ed-gauge__labels span:first-child {
  transform: translate(0, -50%);
}

.ed-gauge__labels span:last-child {
  transform: translate(-100%, -50%);
}

.ed-list { background: #f4f6fb; }
.ed-list__bar {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: stretch;
  background: #6b3fa0;
  color: #fff;
}
.ed-list__zone-block {
  background: #6cd66c;
  /* See .ed-clock__zone-pill for rationale - dark text for contrast on the
     editor-supplied bright-green zone bg. */
  color: #0d3a0d;
  font-weight: 800;
  font-size: 0.6875rem;
  padding: 0.5rem 0.4rem;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  line-height: 1.05;
  min-width: 56px;
}
.ed-list__center {
  text-align: center;
  padding: 0.4rem 0.25rem;
  font-weight: 700;
  font-size: 0.75rem;
  line-height: 1.2;
}
.ed-list__center small {
  display: block;
  font-weight: 500;
  opacity: 0.85;
  font-size: 0.625rem;
  margin-top: 0.1rem;
}
.ed-list__legend {
  background: #c8e26b;
  color: #1f2a16;
  font-size: 0.625rem;
  font-weight: 700;
  padding: 0.3rem 0.5rem;
  text-align: left;
  line-height: 1.2;
}
.ed-list__rows {
  padding: 0.5rem 0.625rem 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.ed-list__row {
  font-size: 0.8125rem;
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  color: #111;
}
.ed-list__row strong { font-weight: 800; letter-spacing: 0.01em; }
.ed-list__row--you {
  background: #fff5b8;
  padding: 0.2rem 0.35rem;
  border-radius: 4px;
  box-shadow: inset 0 0 0 1px #f1d65a;
}
.ed-list__row-muted { color: #555; font-weight: 500; }
.ed-list__row-you-tag {
  margin-left: auto;
  font-weight: 700;
  color: #8b6900;
}

/* ----------------------------------------------------------------
   ios-list-card: opt-in card wrapper for plain `<ul>` / `<ol>`
   blocks. Set `"cls": "ios-list-card"` on a list block in JSON to
   render it inside a cream card with iOS-style padding, shadow,
   and themed colors. Used by Amenities (WYW), the prepare-tips
   list, and the Specialist referrals list.
   ---------------------------------------------------------------- */
ul.ios-list-card,
ol.ios-list-card {
  background: var(--ios-bg-card);
  border: 1px solid var(--ios-border);
  border-radius: var(--radius-card);
  margin: 0 var(--space-xs) 0.75rem;
  padding: 1rem 1.125rem 1rem 2.25rem;
  box-shadow: var(--shadow-sm);
  list-style: disc;
  color: var(--ios-ink);
}
ol.ios-list-card { list-style: decimal; }
ul.ios-list-card li,
ol.ios-list-card li {
  margin-bottom: 0.625rem;
  font-size: var(--type-body);
  line-height: 1.5;
  color: var(--ios-ink);
}
ul.ios-list-card li:last-child,
ol.ios-list-card li:last-child {
  margin-bottom: 0;
}
ul.ios-list-card li strong,
ol.ios-list-card li strong {
  color: var(--ios-ink);
  font-weight: 600;
}
ul.ios-list-card li a,
ol.ios-list-card li a {
  color: var(--ios-accent-strong);
  font-weight: 600;
}
ul.ios-list-card li ::marker,
ol.ios-list-card li ::marker {
  color: var(--ios-muted);
}

/* ----------------------------------------------------------------
   Reduced motion
   ---------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .feature-card__dot,
  .team-tile__count-dot {
    animation: none;
  }
  .team-tile,
  .team-tile__chev,
  .test-tile,
  .test-tile__chev,
  .ed-tab {
    transition: none;
  }
}

/* -------- Press feedback (2026-07-23 smoothness pass) --------
   Every tappable surface acknowledges touch the instant the finger lands,
   before its handler runs - the single cheapest perceived-latency win.
   Mirrors the .ios-tile / .ios-pill press pattern in ios.css. Transform
   presses sit behind the reduced-motion gate; rows and pills flash their
   background instead (see .language-modal-btn:active), which reads under
   reduced motion too. The scroller arrow composes its press with the
   translateY(-50%) that positions it - a bare scale() would teleport it. */
@media (prefers-reduced-motion: no-preference) {
  .team-tile:active,
  .test-tile:active {
    transform: scale(0.97);
  }

  .scroller-arrow:active {
    transform: translateY(-50%) scale(0.9);
  }

  .theme-choice__btn:active,
  .ed-tab:active {
    transform: scale(0.96);
  }
}

/* ============================================================
   Emergency broadcast banner (Decision #158)

   The one thing on this site that is edited under time pressure, and the
   only content Corporate Communications will realistically publish: a code
   orange notice - ambulances diverted, department closed to walk-ins - in
   front of patients already in the waiting room.

   COLOUR. Neither existing alert pair clears WCAG AAA in both themes with
   the body text colour: --section-red measures 6.38:1 in light, and
   --section-yellow 6.96:1 in dark, both under the 7:1 floor. So the banner
   carries its own pair, computed rather than eyeballed:

     light  #414042 on #FFD5D5  =  7.72:1     accent #B3261E vs bg 5.14:1
     dark   #E5E5E5 on #5C2828  =  9.32:1     accent #FF8A80 vs bg 6.10:1

   The accent is the left edge and the icon - non-text, so the 3:1 floor of
   WCAG 1.4.11 applies, and both clear it against the banner and the page.
   Urgency is carried by the edge bar and the icon rather than by a saturated
   background, which is what lets the text stay AAA.
   ============================================================ */

.emergency-banner {
  display: flex;
  align-items: flex-start;
  gap: var(--space-sm);
  max-width: var(--max-width);
  margin: 0 auto;
  padding: var(--space-sm);
  border-left: 4px solid var(--emergency-accent);
  background-color: var(--emergency-bg);
  color: var(--text);
}

.emergency-banner[hidden] {
  display: none;
}

.emergency-banner__icon {
  flex: 0 0 auto;
  width: 1.25em;
  height: 1.25em;
  margin-top: 0.1em;
  border-radius: 50%;
  background-color: var(--emergency-accent);
  /* The exclamation mark is drawn, not typed: a text glyph here would be
     picked up by Google Translate and by the readability linter, and read
     aloud as punctuation by a screen reader that already has the message. */
  -webkit-mask: var(--emergency-icon) center / 0.75em 0.75em no-repeat;
  mask: var(--emergency-icon) center / 0.75em 0.75em no-repeat;
}

.emergency-banner__message {
  flex: 1 1 auto;
  margin-bottom: 0;
  font-weight: 600;
}

.emergency-banner__dismiss {
  flex: 0 0 auto;
  padding: var(--space-xs) var(--space-sm);
  /* Full-size target rather than a small x: this is dismissed one-handed, on
     a phone, by someone who is unwell. */
  min-height: 44px;
  border: 1px solid var(--emergency-accent);
  border-radius: var(--border-radius-sm);
  background: transparent;
  color: var(--text);
  font-size: var(--font-size-sm);
  cursor: pointer;
}

.emergency-banner__dismiss:hover {
  background-color: var(--emergency-bg-hover);
}

/* ---------------------------------------------------------------------------
   Practice-copy banner
   ---------------------------------------------------------------------------
   Shipped on the sandbox only. The markup is emitted by buildIndexHtml when
   CMS_REPO points at a *-sandbox repo, so on production this rule matches
   nothing - it lives here rather than in an inline <style> so the two
   deployments keep byte-identical stylesheets and the drift check stays
   meaningful.

   Added 2026-08-03 after Alvin mistook the sandbox for the live site three
   times in one day: hunting a button that only production had, reporting
   sign-in broken, and checking a published map edit against the wrong site.
   Both sites are pixel-identical and a phone truncates the address bar to
   "...e-sandbox.pages.dev".

   Static, not fixed: it scrolls away like a masthead instead of permanently
   taxing the small screen this site is built for. Seeing it once on load is
   the job.
--------------------------------------------------------------------------- */
.practice-copy {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  padding: 10px max(14px, env(safe-area-inset-left)) 10px max(14px, env(safe-area-inset-right));
  /* Not a brand colour, on purpose - this must not read as part of the design
     being practised on. 8.6:1 on the body ink below. */
  background: #4B2E05;
  color: #FFF4E0;
  font-size: 15px;
  line-height: 1.35;
}

.practice-copy strong {
  letter-spacing: 0.06em;
  font-weight: 700;
}

.practice-copy a {
  color: #FFF4E0;
  text-decoration: underline;
}
