/* styles.css — "Vital" design system for Nurse CNE */

:root {
  /* light theme — bone & jade */
  --bg:        oklch(0.985 0.004 90);
  --bg-2:      oklch(0.965 0.005 90);
  --surface:   #ffffff;
  --surface-2: oklch(0.975 0.004 90);
  --border:    oklch(0.91 0.005 90);
  --border-strong: oklch(0.85 0.006 90);
  --fg:        oklch(0.20 0.015 70);
  --fg-2:      oklch(0.45 0.012 70);
  --fg-3:      oklch(0.62 0.010 70);
  --primary:        oklch(0.42 0.06 175);
  --primary-ink:    #ffffff;
  --primary-soft:   oklch(0.92 0.025 175);
  --primary-soft-2: oklch(0.97 0.012 175);
  --accent:        oklch(0.68 0.10 50);
  --accent-soft:   oklch(0.94 0.04 50);
  --success: oklch(0.62 0.10 150);
  --warning: oklch(0.78 0.13 80);
  --danger:  oklch(0.58 0.16 25);

  --shadow-sm: 0 1px 2px rgba(20, 20, 14, 0.04);
  --shadow:    0 2px 6px rgba(20, 20, 14, 0.05), 0 1px 2px rgba(20, 20, 14, 0.04);
  --shadow-lg: 0 14px 32px -10px rgba(20, 20, 14, 0.18), 0 6px 14px -6px rgba(20, 20, 14, 0.10);

  --radius-sm: 8px;
  --radius:    14px;
  --radius-lg: 20px;
  --radius-xl: 28px;

  --font-sans:  'Geist', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-serif: 'Geist', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono:  'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  --pad: 18px;       /* density-controlled */
  --gap: 14px;
}

[data-theme='dark'] {
  --bg:        oklch(0.16 0.01 70);
  --bg-2:      oklch(0.20 0.012 70);
  --surface:   oklch(0.22 0.012 70);
  --surface-2: oklch(0.25 0.012 70);
  --border:    oklch(0.30 0.008 70);
  --border-strong: oklch(0.40 0.008 70);
  --fg:        oklch(0.96 0.004 90);
  --fg-2:      oklch(0.72 0.008 70);
  --fg-3:      oklch(0.55 0.008 70);
  --primary:        oklch(0.72 0.08 175);
  --primary-ink:    oklch(0.18 0.02 175);
  --primary-soft:   oklch(0.30 0.04 175);
  --primary-soft-2: oklch(0.24 0.02 175);
  --accent:        oklch(0.78 0.10 50);
  --accent-soft:   oklch(0.30 0.05 50);
  --shadow:    0 2px 6px rgba(0,0,0, 0.3), 0 1px 2px rgba(0,0,0, 0.2);
  --shadow-lg: 0 14px 32px -10px rgba(0,0,0, 0.5);
}

[data-theme='ocean'] {
  --primary:        oklch(0.45 0.09 240);
  --primary-soft:   oklch(0.93 0.03 240);
  --primary-soft-2: oklch(0.97 0.015 240);
  --accent:        oklch(0.68 0.11 30);
  --accent-soft:   oklch(0.94 0.04 30);
}

[data-theme='dusk'] {
  --primary:        oklch(0.45 0.09 320);
  --primary-soft:   oklch(0.94 0.03 320);
  --primary-soft-2: oklch(0.97 0.015 320);
  --accent:        oklch(0.72 0.10 70);
  --accent-soft:   oklch(0.94 0.04 70);
}

[data-density='compact'] { --pad: 14px; --gap: 10px; }
[data-density='comfy']   { --pad: 22px; --gap: 18px; }

/* ─────────────────── base ─────────────────── */
* { box-sizing: border-box; }
/* The document must NOT scroll — only inner .scroll containers do.
 * In Capacitor's WKWebView the outer scrollView is also disabled
 * (ios.scrollEnabled=false in capacitor.config.json), but locking
 * html/body here means the same constraints hold in the dev browser
 * and as a defence-in-depth on iOS. `overscroll-behavior: none` kills
 * rubber-band bounce on any descendant that does scroll. */
html, body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
  -webkit-overflow-scrolling: auto;
  position: fixed;
}
body {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-sans);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

.app {
  width: 100%;
  height: 100%;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-sans);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* ─────────────────── Page stack (tab ↔ detail overlay) ───────────────────
 * The tab screens (Home/Discover/Record/Profile) stay mounted whether or
 * not a course detail is open — the detail layer is positioned over the
 * top of them. Keeping the tab in the DOM is what preserves the user's
 * scroll position on back navigation without any save/restore logic.
 * ──────────────────────────────────────────────────────────────────── */
.page-stack {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.page-layer {
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.page-layer--tab {
  flex: 1;
}
.page-layer--tab.is-hidden {
  /* Hide visually without unmounting — scrollTop on inner .scroll
   * elements is preserved while the detail layer sits on top. */
  visibility: hidden;
  pointer-events: none;
}
.page-layer--detail {
  position: absolute;
  inset: 0;
  background: var(--bg);
  z-index: 5;
  animation: page-slide-in 220ms cubic-bezier(0.2, 0.7, 0.1, 1);
}
@keyframes page-slide-in {
  from { transform: translateX(6px); opacity: 0; }
  to   { transform: translateX(0);   opacity: 1; }
}

.scroll {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.scroll::-webkit-scrollbar { display: none; }

/* ─────────────────── typography ─────────────────── */
.serif { font-family: var(--font-serif); font-weight: 500; letter-spacing: -0.012em; }
.mono  { font-family: var(--font-mono);  letter-spacing: -0.01em; }
.eyebrow {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--fg-3);
  font-weight: 500;
}
.h-greet { font-size: 13px; color: var(--fg-2); font-weight: 400; }
.h-screen {
  font-family: var(--font-serif);
  font-size: 32px;
  line-height: 1.08;
  letter-spacing: -0.018em;
  font-weight: 500;
  color: var(--fg);
}
.h-section {
  font-family: var(--font-serif);
  font-size: 20px;
  font-weight: 500;
  letter-spacing: -0.012em;
  color: var(--fg);
  line-height: 1.15;
}
.h-row {
  font-size: 15px;
  font-weight: 500;
  color: var(--fg);
  line-height: 1.3;
  text-wrap: pretty;
}
.muted   { color: var(--fg-2); }
.muted-2 { color: var(--fg-3); }

/* ─────────────────── status bar shim ─────────────────── */
.bar { padding: 0 20px; }

/* ─────────────────── top header ─────────────────── */
.top {
  padding: 56px 20px 8px;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
}
.top.compact { padding-top: 56px; padding-bottom: 4px; }

.icon-btn {
  width: 38px; height: 38px;
  border-radius: 12px;
  border: 0.5px solid var(--border);
  background: var(--surface);
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--fg);
  cursor: pointer;
  transition: transform .12s ease, background .12s ease;
}
.icon-btn:hover { background: var(--surface-2); }
.icon-btn:active { transform: scale(0.96); }
.icon-btn .dot {
  position: absolute; top: 8px; right: 8px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent);
  border: 1.5px solid var(--surface);
}

.avatar {
  width: 38px; height: 38px;
  border-radius: 50%;
  background: var(--primary-soft);
  color: var(--primary);
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-sans);
  font-size: 13px; font-weight: 600;
  letter-spacing: 0.01em;
  border: 0.5px solid var(--border);
}

/* ─────────────────── chips ─────────────────── */
.chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0;
  background: var(--surface-2);
  color: var(--fg-2);
  border: 0.5px solid var(--border);
  white-space: nowrap;
}
.chip.solid {
  background: var(--primary);
  color: var(--primary-ink);
  border-color: transparent;
}
.chip.ghost { background: transparent; }
.chip.lg { padding: 6px 12px; font-size: 12px; }

.filter-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 13px;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 500;
  background: var(--surface);
  color: var(--fg-2);
  border: 0.5px solid var(--border);
  cursor: pointer;
  white-space: nowrap;
  transition: all .12s;
}
.filter-chip:hover { color: var(--fg); }
.filter-chip.on {
  background: var(--fg);
  color: var(--bg);
  border-color: var(--fg);
}

/* ─────────────────── cards ─────────────────── */
.card {
  background: var(--surface);
  border: 0.5px solid var(--border);
  border-radius: var(--radius);
  padding: var(--pad);
}

.card.flush { padding: 0; overflow: hidden; }

.card-row {
  display: flex; gap: 14px; align-items: stretch;
  padding: 14px var(--pad);
  border-bottom: 0.5px solid var(--border);
  cursor: pointer;
  transition: background .12s;
}
.card-row:last-child { border-bottom: 0; }
.card-row:hover { background: var(--surface-2); }

/* ─────────────────── buttons ─────────────────── */
.btn {
  appearance: none;
  border: 0;
  font-family: inherit;
  font-size: 15px;
  font-weight: 500;
  padding: 13px 18px;
  border-radius: 12px;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  transition: transform .12s, background .12s, opacity .12s;
}
.btn:active { transform: scale(0.985); }

.btn-primary {
  background: var(--primary);
  color: var(--primary-ink);
}
.btn-primary:hover { opacity: 0.92; }

.btn-ghost {
  background: var(--surface);
  color: var(--fg);
  border: 0.5px solid var(--border);
}
.btn-ghost:hover { background: var(--surface-2); }

.btn-fill {
  display: flex;
  width: 100%;
}

/* ─────────────────── tab bar ─────────────────── */
.tab-bar {
  position: relative;
  /* Visible portion was 86px which left ~33px of empty bar background
     below the icons (the perceived "gap above the home indicator").
     60px is closer to Apple HIG (49pt + design padding) and pulls the
     icons down toward the user's thumb. The safe-area-inset-bottom
     override below adds the home-indicator clearance separately. */
  height: 60px;
  flex-shrink: 0;
  background: color-mix(in oklch, var(--surface) 75%, transparent);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  backdrop-filter: blur(20px) saturate(180%);
  border-top: 0.5px solid var(--border);
  display: flex;
  /* center (not flex-start) so the icons sit in the middle of the
     visible bar instead of hugging the top with empty bar beneath. */
  align-items: center;
  padding: 0 6px;
}
.tab {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
  padding-top: 6px;
  gap: 3px;
  cursor: pointer;
  color: var(--fg-3);
  background: transparent;
  border: 0;
  font-family: inherit;
  transition: color .12s;
}
.tab span {
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.01em;
}
.tab.on { color: var(--primary); }
.tab.fab {
  flex: 0 0 64px;
}
.tab .fab-circle {
  width: 50px; height: 50px;
  border-radius: 50%;
  background: var(--fg);
  color: var(--bg);
  display: flex; align-items: center; justify-content: center;
  margin-top: -10px;
  box-shadow: var(--shadow-lg);
}

/* ─────────────────── progress ─────────────────── */
.progress-bar {
  height: 6px;
  background: var(--bg-2);
  border-radius: 999px;
  overflow: hidden;
}
.progress-bar > div {
  height: 100%;
  background: var(--primary);
  border-radius: 999px;
  transition: width .4s ease;
}

/* ─────────────────── divider ─────────────────── */
.hr { height: 0.5px; background: var(--border); margin: 0; border: 0; }

/* ─────────────────── topic tint utilities ─────────────────── */
.topic-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0;
}
.topic-pill::before {
  content: '';
  width: 6px; height: 6px; border-radius: 50%;
  background: currentColor;
  opacity: 0.55;
}

/* ─────────────────── points wallet hero ─────────────────── */
.wallet {
  position: relative;
  background: var(--surface);
  border: 0.5px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 22px;
  overflow: hidden;
}
.wallet::after {
  content: '';
  position: absolute;
  right: -40px; top: -40px;
  width: 160px; height: 160px;
  border-radius: 50%;
  background: radial-gradient(circle at 30% 30%, var(--primary-soft) 0%, transparent 70%);
  pointer-events: none;
}
.wallet-num {
  font-family: var(--font-serif);
  font-size: 56px;
  line-height: 0.95;
  letter-spacing: -0.028em;
  color: var(--fg);
  font-weight: 500;
  font-feature-settings: 'tnum';
  font-variant-numeric: tabular-nums;
}
.wallet-num .of {
  font-size: 28px;
  color: var(--fg-3);
  margin-left: 6px;
}

/* ─────────────────── timeline ─────────────────── */
.timeline {
  position: relative;
  padding-left: 22px;
}
.timeline::before {
  content: '';
  position: absolute;
  left: 6px; top: 6px; bottom: 6px;
  width: 1px;
  background: var(--border);
}
.tl-item {
  position: relative;
  padding: 0 0 18px 0;
}
.tl-item::before {
  content: '';
  position: absolute;
  left: -22px; top: 6px;
  width: 13px; height: 13px;
  border-radius: 50%;
  background: var(--surface);
  border: 2px solid var(--border-strong);
}
.tl-item.done::before {
  background: var(--primary);
  border-color: var(--primary);
}
.tl-item.up::before {
  background: var(--accent);
  border-color: var(--accent);
}

/* ─────────────────── bottom sheet (modal) ─────────────────── */
.sheet-backdrop {
  position: absolute; inset: 0;
  background: rgba(20, 20, 14, 0.36);
  z-index: 100;
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  animation: fadeIn .2s;
}
.sheet {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  background: var(--bg);
  border-top-left-radius: 28px;
  border-top-right-radius: 28px;
  box-shadow: 0 -10px 40px rgba(0,0,0,0.18);
  z-index: 101;
  max-height: 90%;
  display: flex; flex-direction: column;
  animation: slideUp .28s cubic-bezier(.18,.7,.2,1);
  overflow: hidden;
}
.sheet-handle {
  width: 38px; height: 5px; border-radius: 3px;
  background: var(--border-strong);
  margin: 8px auto 0;
  flex-shrink: 0;
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes slideUp { from { transform: translateY(100%); } to { transform: translateY(0); } }

/* ─────────────────── form fields ─────────────────── */
.field {
  display: flex; flex-direction: column; gap: 6px;
}
.field-label {
  font-size: 12px;
  color: var(--fg-2);
  font-weight: 500;
}
.field-input {
  appearance: none;
  background: var(--surface);
  border: 0.5px solid var(--border);
  border-radius: 12px;
  padding: 13px 14px;
  font-family: inherit;
  /* 16px floor avoids iOS WKWebView auto-zoom on focus. */
  font-size: 16px;
  color: var(--fg);
  outline: none;
  transition: border-color .12s, background .12s;
}
.field-input:focus {
  border-color: var(--primary);
  background: var(--surface);
}
.field-input::placeholder { color: var(--fg-3); }

.search-bar {
  position: relative;
  display: flex; align-items: center;
  background: var(--surface);
  border: 0.5px solid var(--border);
  border-radius: 12px;
  padding: 0 12px;
  height: 42px;
}
.search-bar input {
  appearance: none;
  border: 0;
  background: transparent;
  flex: 1;
  outline: none;
  font-family: inherit;
  /* 16px floor avoids iOS WKWebView auto-zoom on focus. The search
     used to be 14px and was the worst offender (smaller starting size
     → larger relative zoom kicked in by iOS, blowing the layout). */
  font-size: 16px;
  color: var(--fg);
  margin-left: 8px;
}
.search-bar input::placeholder { color: var(--fg-3); }

/* ─────────────────── Pills row (no-scroll-bar) ─────────────────── */
.scroll-x {
  display: flex; gap: 10px;
  overflow-x: auto;
  -ms-overflow-style: none;
  scrollbar-width: none;
  padding: 4px 20px 8px;
  margin: 0 -20px;
  scroll-padding: 20px;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}
.scroll-x::-webkit-scrollbar { display: none; }

/* ─────────────────── Course card (large list) ─────────────────── */
.course-card {
  background: var(--surface);
  border: 0.5px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
  cursor: pointer;
  display: flex; flex-direction: column; gap: 10px;
  transition: transform .15s ease, border-color .12s;
}
.course-card:hover { border-color: var(--border-strong); }
.course-card:active { transform: scale(0.99); }

/* Expired courses dim slightly so they read as historical without disappearing. */
.course-card.is-ended {
  opacity: 0.72;
  background: var(--surface-2);
}
.course-card.is-ended h4 { color: var(--fg-2); }

.course-card .row {
  display: flex; align-items: center; gap: 8px;
  flex-wrap: wrap;
}
.course-card h4 {
  margin: 0;
  font-size: 16px;
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: -0.003em;
  color: var(--fg);
  text-wrap: pretty;
}
.course-card .meta {
  font-size: 12.5px;
  color: var(--fg-2);
}
.course-card .pts {
  font-family: var(--font-serif);
  font-size: 26px;
  font-weight: 500;
  line-height: 1;
  color: var(--fg);
  letter-spacing: -0.022em;
  font-variant-numeric: tabular-nums;
}
.course-card .pts-label {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--fg-3);
  margin-top: 2px;
}

/* ─────────────────── small course card (horizontal scroll) ─────────────────── */
.mini-card {
  flex: 0 0 232px;
  background: var(--surface);
  border: 0.5px solid var(--border);
  border-radius: var(--radius);
  padding: 13px 14px 12px;
  display: flex; flex-direction: column; gap: 10px;
  cursor: pointer;
  min-height: 158px;
  transition: border-color .12s ease, transform .15s ease;
  scroll-snap-align: start;
}
.mini-card:hover { border-color: var(--border-strong); }
.mini-card:active { transform: scale(0.99); }
.mini-card .mc-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-width: 0;
}
.mini-card .mc-date {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-3);
  white-space: nowrap;
  flex-shrink: 0;
}
.mini-card h5 {
  margin: 0;
  font-size: 14.5px;
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.005em;
  color: var(--fg);
  text-wrap: pretty;
  /* clamp to 2 lines so long English titles don't stretch the row */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  word-break: break-word;
  overflow-wrap: anywhere;
}
.mini-card .mc-foot {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 10px;
  margin-top: auto;
  padding-top: 10px;
  border-top: 0.5px solid var(--border);
}
.mini-card .mc-provider {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--fg-2);
  font-size: 11.5px;
  min-width: 0;
}
.mini-card .mc-provider-name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.mini-card .mc-pts {
  display: inline-flex;
  align-items: baseline;
  gap: 3px;
  flex-shrink: 0;
}
.mini-card .mc-pts-num {
  font-size: 20px;
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.mini-card .mc-pts-label {
  font-size: 9.5px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

/* ─────────────────── Detail screen ─────────────────── */
.detail-hero {
  padding: 0 20px 14px;
}
.detail-facts {
  margin: 0 20px;
  border: 0.5px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}
.fact-row {
  display: grid;
  grid-template-columns: 96px 1fr;
  align-items: start;
  padding: 12px 16px;
  border-bottom: 0.5px solid var(--border);
  font-size: 13.5px;
}
.fact-row:last-child { border-bottom: 0; }
.fact-row .k {
  color: var(--fg-3);
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  padding-top: 3px;
}
.fact-row .v {
  color: var(--fg);
  font-weight: 500;
  text-wrap: pretty;
}

/* ─────────────────── Stick CTA ─────────────────── */
.cta-bar {
  position: absolute;
  left: 0; right: 0; bottom: 86px;
  padding: 12px 20px 14px;
  background: color-mix(in oklch, var(--bg) 70%, transparent);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  backdrop-filter: blur(20px) saturate(180%);
  border-top: 0.5px solid var(--border);
  display: flex; gap: 10px;
  z-index: 30;
}
.cta-bar.detail { bottom: 0; }

/* ─────────────────── ring (segmented progress) ─────────────────── */
.ring-num {
  font-family: var(--font-sans);
  font-size: 38px;
  font-weight: 500;
  line-height: 1;
  color: var(--fg);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum', 'cv11';
}

/* ─────────────────── empty + states ─────────────────── */
.dot-status { width: 6px; height: 6px; border-radius: 50%; display: inline-block; }

/* ─────────────────── animation utility ─────────────────── */
/* Subtle entrance — translates rather than fades so screenshot tools
   (and reduced-motion users) still see content at frame 0. */
.fade-in {
  animation: vital-slide-in .25s cubic-bezier(.2,.7,.2,1);
}
@keyframes vital-slide-in {
  from { transform: translateY(6px); }
  to   { transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .fade-in { animation: none; }
}

/* ─────────────────── Vital brand lockup ─────────────────── */
.vital-brand {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}
.vital-brand-v {
  flex-direction: column;
  align-items: center;
  gap: 12px;
  text-align: center;
}
.vital-brand-mark {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--primary-soft);
  color: var(--primary);
  border-radius: 11px;
  flex-shrink: 0;
}
.vital-brand-text { min-width: 0; }
.vital-brand-name {
  font-size: 20px;
  font-weight: 500;
  letter-spacing: -0.018em;
  line-height: 1;
  color: var(--fg);
}
.vital-brand-v .vital-brand-name { font-size: 24px; }
.vital-brand-tag {
  font-size: 9px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--fg-3);
  margin-top: 3px;
}
.vital-brand-v .vital-brand-tag { font-size: 9.5px; letter-spacing: 0.20em; }

/* ─────────────────── Vital splash (loading) ─────────────────── */
.vital-splash {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  color: var(--fg);
  gap: 14px;
  z-index: 300;
}
.vital-splash-stage {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 96px;
  height: 96px;
  color: var(--primary);
  position: relative;
}
/* The ring breathes (a soft scale + opacity pulse) */
.vs-ring {
  transform-origin: center;
  transform-box: fill-box;
  animation: vs-breathe 2.4s ease-in-out infinite;
}
/* The heartbeat path is always visible at low opacity (so the screenshot /
   first frame always has shape). A second copy on top sweeps a bright pulse
   across via a CSS mask, giving the "alive" feel. */
.vs-pulse-bg {
  opacity: 0.25;
}
.vs-pulse {
  -webkit-mask: linear-gradient(90deg, transparent 0%, #000 40%, #000 60%, transparent 100%);
          mask: linear-gradient(90deg, transparent 0%, #000 40%, #000 60%, transparent 100%);
  -webkit-mask-size: 60% 100%;
          mask-size: 60% 100%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  animation: vs-sweep 2.4s ease-in-out infinite;
}
@keyframes vs-breathe {
  0%, 100% { opacity: 0.6; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.04); }
}
@keyframes vs-sweep {
  0%   { -webkit-mask-position: -60% 0; mask-position: -60% 0; }
  100% { -webkit-mask-position: 160% 0; mask-position: 160% 0; }
}
.vital-splash-name {
  font-size: 26px;
  letter-spacing: -0.022em;
  font-weight: 500;
  margin-top: 8px;
  color: var(--fg);
}
.vital-splash-label {
  font-size: 9.5px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--fg-3);
}
@media (prefers-reduced-motion: reduce) {
  .vs-ring  { animation: none; opacity: 1; }
  .vs-pulse { animation: none; -webkit-mask: none; mask: none; }
}

/* ─────────────────── Guest sign-in card (Profile, Home, Record) ─────── */
.guest-card {
  background: var(--surface);
  border: 0.5px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 26px 22px;
  position: relative;
  overflow: hidden;
}
.guest-card::after {
  content: '';
  position: absolute;
  right: -80px; top: -80px;
  width: 240px; height: 240px;
  border-radius: 50%;
  background: radial-gradient(circle at 30% 30%, var(--primary-soft) 0%, transparent 70%);
  pointer-events: none;
  z-index: 0;
}
.guest-card > * { position: relative; z-index: 1; }
.guest-card .gc-eyebrow {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--primary);
  font-weight: 500;
  margin-bottom: 12px;
}
.guest-card .gc-title {
  font-family: var(--font-serif);
  font-size: 26px;
  font-weight: 500;
  line-height: 1.12;
  letter-spacing: -0.022em;
  color: var(--fg);
  margin: 0 0 8px;
  text-wrap: balance;
}
.guest-card .gc-sub {
  font-size: 14px;
  line-height: 1.5;
  color: var(--fg-2);
  margin: 0 0 18px;
  text-wrap: pretty;
}
.guest-card .gc-cta {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

/* Guest-mode Record / locked screen */
.guest-lock {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 60px 28px;
  text-align: center;
  gap: 14px;
}
.guest-lock-icon {
  width: 56px; height: 56px;
  border-radius: 50%;
  background: var(--primary-soft);
  color: var(--primary);
  display: flex; align-items: center; justify-content: center;
}
.guest-lock-title {
  font-family: var(--font-serif);
  font-size: 24px;
  font-weight: 500;
  letter-spacing: -0.022em;
  margin: 0;
  text-wrap: balance;
}
.guest-lock-sub {
  color: var(--fg-2);
  font-size: 14px;
  max-width: 360px;
  text-wrap: pretty;
  margin: 0;
}

/* SideNav Sign-in CTA (replaces user card for guests) */
.sn-signin-btn {
  appearance: none;
  cursor: pointer;
  background: var(--primary);
  color: var(--primary-ink);
  border: 0;
  border-radius: 999px;
  padding: 0;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font: 500 13px var(--font-sans);
  margin: 0 auto;
  transition: opacity 120ms, transform 120ms;
}
.sn-signin-btn:hover { opacity: 0.92; }
@media (min-width: 1024px) {
  .sn-signin-btn {
    width: 100%;
    height: auto;
    padding: 11px 14px;
    border-radius: 12px;
    margin: 0;
  }
}

/* Auth overlay: full-screen modal carrying AuthRouter */
.auth-overlay {
  position: fixed;
  inset: 0;
  background: color-mix(in oklch, var(--bg) 96%, transparent);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  z-index: 400;
  display: flex;
  align-items: stretch;
  justify-content: center;
  animation: vital-fade-in .18s ease both;
}
@keyframes vital-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.auth-overlay > .auth-shell { background: transparent; }
/* Back-to-home button shown in the auth overlay only. Lives inside the
   .auth-top row (not absolute-positioned) so it shares the safe-area-inset
   handling already on .auth-top — no Dynamic Island overlap. */
.auth-top-left {
  display: flex;
  align-items: center;
  gap: 12px;
}
.auth-top-back {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 32px;
  padding: 0 12px 0 8px;
  border-radius: 10px;
  border: 0.5px solid var(--border);
  background: var(--surface);
  color: var(--fg);
  font: 500 13px var(--font-sans);
  letter-spacing: -0.005em;
  cursor: pointer;
  transition: background 120ms ease;
}
.auth-top-back:hover { background: var(--surface-2); }
.auth-top-back:active { transform: scale(0.98); }
@media (min-width: 768px) {
  .auth-overlay { padding: 28px; }
  .auth-overlay > .auth-shell {
    align-self: center;
    width: 100%;
    max-width: 480px;
    background: var(--surface);
    border: 0.5px solid var(--border);
    border-radius: 22px;
    box-shadow: var(--shadow-lg);
    height: auto;
    max-height: calc(100vh - 56px);
  }
  .auth-overlay > .auth-shell .auth-top    { padding-top: 30px; }
  .auth-overlay > .auth-shell .auth-body   { padding-top: 28px; }
}

/* lang toggle */
.lang-toggle {
  display: inline-flex;
  background: var(--bg-2);
  border-radius: 999px;
  padding: 3px;
  font-size: 11px;
  font-weight: 500;
  border: 0.5px solid var(--border);
}
.lang-toggle button {
  appearance: none;
  background: transparent;
  border: 0;
  padding: 4px 10px;
  border-radius: 999px;
  color: var(--fg-3);
  cursor: pointer;
  font-family: inherit;
}
.lang-toggle button.on {
  background: var(--surface);
  color: var(--fg);
  box-shadow: var(--shadow-sm);
}

/* ─────────────────── Detail floating topbar + menu + toast ─────────────────── */
.detail-topbar {
  position: absolute;
  top: 0; left: 0; right: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  /* Individual padding properties — NOT the shorthand. The shorthand
     resets padding-top and would re-cover the Dynamic Island. The back
     button is a 36×36 tappable icon-btn; it must clear the inset on
     6.7"+ devices or it becomes untappable under the status bar. */
  padding-top: max(14px, calc(env(safe-area-inset-top) + 6px));
  padding-right: 16px;
  padding-bottom: 14px;
  padding-left: 16px;
  z-index: 20;
  transition: background 200ms ease, backdrop-filter 200ms ease, border-bottom-color 200ms ease, padding 200ms ease;
  background: transparent;
  border-bottom: 0.5px solid transparent;
  pointer-events: none;
}
.detail-topbar > * { pointer-events: auto; }
.detail-topbar .icon-btn {
  background: rgba(255, 255, 255, 0.78);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  border-color: transparent;
  flex-shrink: 0;
}
.detail-topbar.is-scrolled {
  background: color-mix(in oklch, var(--bg) 82%, transparent);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  backdrop-filter: blur(14px) saturate(160%);
  border-bottom-color: var(--border);
  /* Compact state still has to clear the inset — the bar is floating
     over scrolled content, the Dynamic Island doesn't go away. */
  padding-top: max(10px, calc(env(safe-area-inset-top) + 4px));
  padding-bottom: 10px;
}
.detail-topbar-title {
  flex: 1;
  min-width: 0;
  font-size: 14px;
  font-weight: 500;
  color: var(--fg);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: center;
  opacity: 0;
  transition: opacity 200ms ease;
  pointer-events: none;
}
.detail-topbar.is-scrolled .detail-topbar-title { opacity: 1; }
[data-theme='dark'] .detail-topbar .icon-btn { background: rgba(40, 40, 36, 0.6); }

.detail-menu-wrap { position: relative; flex-shrink: 0; }
.detail-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 220px;
  background: var(--surface);
  border: 0.5px solid var(--border);
  border-radius: 14px;
  box-shadow: var(--shadow-lg);
  padding: 6px;
  z-index: 30;
  animation: vital-menu-in 140ms cubic-bezier(.18, .7, .2, 1) both;
}
@keyframes vital-menu-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
.detail-menu-item {
  appearance: none;
  background: transparent;
  border: 0;
  font: inherit;
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 9px;
  color: var(--fg);
  font-size: 13.5px;
  text-align: left;
  cursor: pointer;
  transition: background 100ms;
}
.detail-menu-item:hover { background: var(--surface-2); }
.detail-menu-item.danger { color: var(--danger); }
.detail-menu-divider {
  height: 0.5px;
  background: var(--border);
  margin: 6px 4px;
}

/* Inline toast (used by Copy link confirmation) */
.vital-toast {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  background: color-mix(in oklch, var(--fg) 88%, transparent);
  color: var(--bg);
  font-size: 13px;
  padding: 10px 16px;
  border-radius: 999px;
  box-shadow: var(--shadow-lg);
  z-index: 500;
  animation: vital-toast-in 220ms cubic-bezier(.18, .7, .2, 1) both;
}
@keyframes vital-toast-in {
  from { opacity: 0; transform: translate(-50%, 12px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}

/* ─────────────────── Register dialog (two-step) ─────────────────── */
.register-dialog-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(20, 20, 14, 0.36);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  z-index: 450;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  animation: vital-fade-in .18s ease both;
}
.register-dialog {
  position: relative;
  background: var(--bg);
  width: 100%;
  max-width: 520px;
  border-radius: 22px;
  padding: 28px 22px 22px;
  box-shadow: var(--shadow-lg);
  animation: rd-pop .22s cubic-bezier(.18, .7, .2, 1) both;
}
@keyframes rd-pop {
  from { opacity: 0; transform: scale(0.97); }
  to   { opacity: 1; transform: scale(1); }
}
@media (min-width: 768px) {
  .register-dialog-backdrop { padding: 28px; }
}
.register-dialog-close {
  position: absolute;
  top: 14px; right: 14px;
  width: 32px; height: 32px;
  border-radius: 10px;
}
.register-dialog-eyebrow {
  font-size: 9.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--primary);
  font-weight: 500;
  margin-bottom: 8px;
}
.register-dialog-title {
  font-family: var(--font-serif);
  font-size: 22px;
  font-weight: 500;
  letter-spacing: -0.018em;
  color: var(--fg);
  margin: 0 36px 6px 0;
  text-wrap: balance;
  line-height: 1.2;
}
.register-dialog-sub {
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--fg-2);
  margin: 0;
  text-wrap: pretty;
}

.register-dialog-card {
  appearance: none;
  width: 100%;
  background: var(--surface);
  border: 0.5px solid var(--border);
  border-radius: 14px;
  padding: 14px;
  display: flex;
  align-items: center;
  gap: 14px;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition: border-color 120ms, background 120ms, transform 120ms;
}
.register-dialog-card:hover:not(:disabled) {
  border-color: var(--border-strong);
  background: var(--surface-2);
}
.register-dialog-card:active:not(:disabled) { transform: scale(0.995); }
.rd-card-icon {
  width: 40px; height: 40px;
  border-radius: 12px;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.rd-card-body { flex: 1; min-width: 0; }
.rd-card-title {
  font-size: 14.5px;
  font-weight: 500;
  color: var(--fg);
  margin-bottom: 2px;
}
.rd-card-sub {
  font-size: 12.5px;
  color: var(--fg-2);
  line-height: 1.4;
}

.register-dialog-url {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 16px;
  padding: 10px 14px;
  background: var(--surface-2);
  border: 0.5px solid var(--border);
  border-radius: 10px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--fg-2);
  word-break: break-all;
  overflow: hidden;
}
.register-dialog-url > span {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1;
}
.register-dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 18px;
}
.register-dialog-kbd {
  font-family: var(--font-mono);
  font-size: 10.5px;
  background: rgba(255,255,255,0.18);
  color: inherit;
  padding: 2px 6px;
  border-radius: 5px;
  margin-left: 4px;
}

/* ─────────────────── Course detail — speakers + fees ─────────────────── */
.speaker-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 12px;
  background: var(--surface);
  border: 0.5px solid var(--border);
  border-radius: 12px;
}
.speaker-avatar {
  width: 32px; height: 32px;
  border-radius: 50%;
  background: var(--primary-soft);
  color: var(--primary);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: 13px;
  letter-spacing: -0.02em;
  flex-shrink: 0;
}
.fee-line {
  display: flex;
  justify-content: space-between;
  font-size: 12px;
  font-weight: 400;
  color: var(--fg-2);
  gap: 14px;
}
.fee-line .mono { font-size: 12px; color: var(--fg); font-variant-numeric: tabular-nums; }

/* ─────────────────── Change log / change history ─────────────────── */
.changelog {
  margin-top: 6px;
  border: 0.5px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}
.changelog[open] { background: var(--surface); }
.changelog-summary {
  appearance: none;
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 14px;
  font-size: 13px;
  color: var(--fg-2);
  font-weight: 500;
  user-select: none;
  transition: background 120ms;
}
.changelog-summary::-webkit-details-marker { display: none; }
.changelog-summary:hover { background: var(--surface-2); }
.changelog-summary-label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.changelog-summary-meta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--fg-3);
}
.changelog-count {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--bg-2);
  color: var(--fg-2);
  min-width: 22px;
  text-align: center;
}
.changelog[open] .changelog-summary svg:last-child {
  transform: rotate(180deg);
}
.changelog-summary svg:last-child {
  transition: transform 180ms ease;
}
.changelog-list {
  list-style: none;
  margin: 0;
  padding: 4px 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 0;
  border-top: 0.5px solid var(--border);
}
.changelog-item {
  position: relative;
  display: grid;
  grid-template-columns: 18px 1fr;
  gap: 12px;
  padding: 14px 0 14px 0;
}
.changelog-item + .changelog-item {
  border-top: 0.5px solid var(--border);
}
/* Vertical timeline line through the bullets */
.changelog-item::before {
  content: '';
  position: absolute;
  left: 8px;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--border);
}
.changelog-item:first-child::before { top: 22px; }
.changelog-item:last-child::before  { bottom: calc(100% - 22px); }
.changelog-bullet {
  position: relative;
  z-index: 1;
  margin-top: 7px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--surface);
  border: 1.5px solid var(--border-strong);
  align-self: start;
  justify-self: center;
}
.changelog-item:first-child .changelog-bullet {
  background: var(--primary);
  border-color: var(--primary);
}
.changelog-body {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.changelog-date {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--fg-3);
}
.changelog-changes {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.changelog-change {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.changelog-field {
  font-size: 13px;
  font-weight: 500;
  color: var(--fg);
  letter-spacing: -0.003em;
}
.changelog-diff {
  display: flex;
  flex-direction: column;
  gap: 4px;
  background: var(--surface-2);
  border: 0.5px solid var(--border);
  border-radius: 10px;
  padding: 8px 10px;
}
.changelog-diff-row {
  display: grid;
  grid-template-columns: 44px 1fr;
  gap: 10px;
  align-items: start;
  font-size: 12.5px;
  line-height: 1.45;
}
.changelog-diff-tag {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  padding: 2px 0;
  text-align: left;
  color: var(--fg-3);
  white-space: nowrap;
}
.changelog-diff-tag.was { color: var(--fg-3); }
.changelog-diff-tag.now { color: var(--primary); }
.changelog-diff-old {
  color: var(--fg-3);
  text-decoration: line-through;
  text-decoration-color: var(--border-strong);
  word-break: break-word;
  overflow-wrap: anywhere;
}
.changelog-diff-new {
  color: var(--fg);
  word-break: break-word;
  overflow-wrap: anywhere;
}


/* ═══════════════════════════════════════════════════════════════════════
   MOTION-KIT support styles
   Drop-in CSS for motion-kit.jsx. All values are derived from existing
   tokens; no new colors are introduced.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Stagger entrance (consumed by <Stagger>) ─────────────────────────── */
@keyframes vital-stagger-in {
  from { opacity: 0; transform: translateY(var(--vital-stagger-dist, 8px)); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ── Skeleton shimmer (consumed by <Skeleton>) ────────────────────────── */
.vital-skel {
  position: relative;
  overflow: hidden;
  background: var(--bg-2);
  isolation: isolate;
}
.vital-skel::before {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(
    90deg,
    transparent 0%,
    color-mix(in oklch, var(--surface) 60%, transparent) 50%,
    transparent 100%
  );
  animation: vital-skel-shimmer 1.6s ease-in-out infinite;
}
@keyframes vital-skel-shimmer {
  from { transform: translateX(-100%); }
  to   { transform: translateX(100%); }
}

/* ── Spinner (consumed by <Spinner> / <LoadingButton>) ────────────────── */
.vital-spinner {
  display: inline-block;
  width: 14px; height: 14px;
  border-radius: 50%;
  border: 1.6px solid color-mix(in oklch, currentColor 22%, transparent);
  border-top-color: currentColor;
  animation: vital-spin .7s linear infinite;
  vertical-align: -2px;
}
@keyframes vital-spin { to { transform: rotate(360deg); } }

/* ── Sheet exit (paired with the new 'is-closing' class in <Sheet>) ───── */
.sheet.is-closing         { animation: vital-slide-down .24s cubic-bezier(.4,0,.2,1) both; }
.sheet-backdrop.is-closing{ animation: vital-fade-out   .22s ease both; }
@keyframes vital-slide-down {
  from { transform: translateY(0);    opacity: 1; }
  to   { transform: translateY(100%); opacity: 0; }
}
@keyframes vital-fade-out { from { opacity: 1; } to { opacity: 0; } }

/* On tablet+ the sheet becomes a centered modal — exit needs its own
   keyframe because the base transform is translate(-50%, -50%). */
@media (min-width: 768px) {
  .sheet.is-closing {
    animation: vital-modal-out .22s cubic-bezier(.4,0,.2,1) both;
  }
  @keyframes vital-modal-out {
    from { transform: translate(-50%, -50%) scale(1);    opacity: 1; }
    to   { transform: translate(-50%, -50%) scale(0.96); opacity: 0; }
  }
}

/* ── Toast exit ───────────────────────────────────────────────────────── */
.vital-toast.is-out { animation: vital-toast-out .22s ease both; }
@keyframes vital-toast-out {
  from { opacity: 1; transform: translate(-50%, 0); }
  to   { opacity: 0; transform: translate(-50%, 8px); }
}
.vital-toast.is-danger  { background: color-mix(in oklch, var(--danger) 90%, transparent); }
.vital-toast.is-success { background: color-mix(in oklch, var(--success) 90%, transparent); }

/* ── Auth overlay exit ────────────────────────────────────────────────── */
.auth-overlay[data-anim-state="exit"] { animation: vital-fade-out .18s ease both; }

/* ── Safe-area handling (iOS notch + bottom indicator) ───────────────── */
/* The mobile bottom tab bar pads itself so its hit targets sit above the
   iOS home indicator. Equivalent of Tailwind's pb-safe. */
.tab-bar {
  padding-bottom: max(0px, env(safe-area-inset-bottom));
  height: calc(60px + env(safe-area-inset-bottom));
}
/* Sticky CTA bars (course detail "Register" / "Enrol" buttons) */
.cta-bar {
  padding-bottom: max(14px, calc(14px + env(safe-area-inset-bottom)));
}
/* Screen header should clear the iOS status bar / notch */
@supports (padding-top: env(safe-area-inset-top)) {
  .top { padding-top: max(56px, calc(env(safe-area-inset-top) + 18px)); }
  /* Auth / onboarding header — same status-bar clearance pattern as .top
     but kept distinct so design tweaks to one don't quietly affect the
     other. Was a hardcoded 22px before viewport-fit=cover was wired up. */
  .auth-top { padding-top: max(22px, calc(env(safe-area-inset-top) + 6px)); }
  .auth-foot { padding-bottom: max(26px, calc(env(safe-area-inset-bottom) + 12px)); }
  /* Bottom sheets slide up over the home indicator; keep inner padding
     above the indicator without inflating the sheet's own height. */
  .sheet { padding-bottom: env(safe-area-inset-bottom); }
}

/* ── Offline banner (Step 9) ────────────────────────────────────────────
   Shown when the device reports no connectivity OR the most recent
   course-catalogue fetch failed while cached data was on screen.
   Sits above all app content; pads itself for the iOS notch / Dynamic
   Island so the bilingual text never collides with the status bar. */
.offline-banner {
  position: relative;
  z-index: 50;
  flex-shrink: 0;
  padding: max(10px, calc(env(safe-area-inset-top) + 10px)) 16px 10px;
  background: color-mix(in oklch, #b45309 90%, transparent);
  color: #fff;
  font-size: 14px;
  line-height: 1.4;
  text-align: center;
  letter-spacing: 0.01em;
  font-weight: 500;
  -webkit-backdrop-filter: saturate(160%);
  backdrop-filter: saturate(160%);
}

/* Footer under OfflineCatalogueScreen — single "Try to reconnect" CTA.
   Padding-bottom respects the home-indicator safe area. */
.offline-footer {
  flex-shrink: 0;
  padding: 12px 20px max(14px, calc(env(safe-area-inset-bottom) + 12px));
  border-top: 0.5px solid var(--border);
  background: var(--surface);
  display: flex;
  justify-content: center;
}

/* ── Tap latency fix ────────────────────────────────────────────────────
   `touch-action: manipulation` tells WebKit it can fire `click` immediately
   instead of waiting ~300ms to see whether the user is double-tapping to
   zoom. Applied to interactive elements only — keeping it off scroll
   containers preserves pinch-to-zoom in places like image previews. */
button, a, label, summary, [role="button"],
.btn, .icon-btn, .tab, .pill, .filter-chip,
input, select, textarea {
  touch-action: manipulation;
}

/* ── iOS WKWebView auto-zoom prevention ────────────────────────────────
   When any focusable input renders text below 16px, iOS zooms the
   viewport on focus to "improve readability" and the page layout
   visibly breaks. Setting a 16px floor universally avoids this
   without disabling user-scalable zoom (which is an accessibility
   regression Apple explicitly discourages). Specific input classes
   above already declare 16px exactly; this is the safety net for any
   future input that forgets. */
input, textarea, select {
  font-size: max(16px, 1em);
}

/* ── Z-index stacking hygiene ─────────────────────────────────────────── */
/* These root scrollers each get their own stacking context so blurred
   backdrops and absolute children inside one screen can never bleed
   onto another (the original cause of "menu hides behind hero" bugs). */
.app, .scroll, .detail-shell, .sheet, .auth-overlay,
.register-dialog-backdrop, .detail-menu-wrap {
  isolation: isolate;
}

/* ── Spring-y tap on existing chrome (works alongside motion-kit) ─────── */
.btn {
  transition: transform .14s cubic-bezier(.5, .8, .35, 1.4),
              background .14s ease, opacity .14s ease, box-shadow .18s ease;
}
.btn:active:not([disabled]):not([aria-busy="true"]) { transform: scale(0.96); }
.btn[disabled],
.btn[aria-busy="true"] { cursor: not-allowed; }
.btn[aria-busy="true"] { opacity: .88; }

.icon-btn {
  transition: transform .14s cubic-bezier(.5,.8,.35,1.4),
              background .12s ease, color .12s ease;
}
.icon-btn:active { transform: scale(0.92); }

.filter-chip {
  transition: transform .14s cubic-bezier(.5,.8,.35,1.4),
              background .14s ease, color .14s ease, border-color .14s ease;
}
.filter-chip:active { transform: scale(0.96); }

/* Cards already have :hover/:active rules; layer a spring curve on top
   so the existing 'transform: scale(.99)' rule feels deliberate. */
.course-card,
.mini-card {
  transition: transform .18s cubic-bezier(.18,.7,.2,1),
              border-color .14s ease,
              box-shadow .2s ease,
              background .14s ease;
}
.course-card:hover,
.mini-card:hover { transform: translateY(-1px); box-shadow: var(--shadow); }

/* ── Focus-visible ring (keyboard a11y) ──────────────────────────────── */
*:focus { outline: none; }
*:focus-visible {
  outline: 2px solid color-mix(in oklch, var(--primary) 80%, transparent);
  outline-offset: 2px;
  border-radius: 8px;
}
/* Keep card focus rings flush with their border radius */
.card:focus-visible,
.course-card:focus-visible,
.mini-card:focus-visible,
.sheet:focus-visible { outline-offset: 3px; border-radius: var(--radius); }

/* ── Text-overflow defenses (utility classes) ─────────────────────────── */
.clamp-1 { display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; word-break: break-word; }
.clamp-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; word-break: break-word; }
.clamp-3 { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; word-break: break-word; }
.truncate { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* The course-card heading is the single most overflow-prone element.
   Clamp it to 2 lines so long bilingual titles never explode the row. */
.course-card h4 {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  word-break: break-word;
}

/* ── Empty state ──────────────────────────────────────────────────────── */
.vital-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 48px 24px;
  text-align: center;
  color: var(--fg-2);
}
.vital-empty .vital-empty-icon {
  width: 48px; height: 48px;
  border-radius: 50%;
  background: var(--primary-soft-2);
  color: var(--primary);
  display: flex; align-items: center; justify-content: center;
  margin-bottom: 4px;
}
.vital-empty .vital-empty-title {
  font-family: var(--font-serif);
  font-size: 17px;
  font-weight: 500;
  letter-spacing: -0.012em;
  color: var(--fg);
}
.vital-empty .vital-empty-sub {
  font-size: 13px;
  line-height: 1.5;
  max-width: 320px;
  text-wrap: pretty;
}

/* ── Reduced-motion master switch (last layer wins) ──────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .vital-skel::before { opacity: 0.35; animation: none !important; }
}
