/* =============================================================================
   SELF-HOSTED WEBFONTS
   Previously loaded from fonts.googleapis.com, which cost two extra DNS+TLS
   handshakes to a third party before any text could paint, and leaked every
   visitor's IP to Google. Same files, served from origin.
   font-display:swap keeps text visible during load rather than blank.
   ========================================================================== */
@font-face { font-family: "Bricolage Grotesque"; src: url("../fonts/bricolage-grotesque-latin-600-normal.woff2") format("woff2"); font-weight: 600; font-style: normal; font-display: swap; }
@font-face { font-family: "Bricolage Grotesque"; src: url("../fonts/bricolage-grotesque-latin-700-normal.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: swap; }
@font-face { font-family: "Bricolage Grotesque"; src: url("../fonts/bricolage-grotesque-latin-800-normal.woff2") format("woff2"); font-weight: 800; font-style: normal; font-display: swap; }
@font-face { font-family: "Hanken Grotesk"; src: url("../fonts/hanken-grotesk-latin-400-normal.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "Hanken Grotesk"; src: url("../fonts/hanken-grotesk-latin-500-normal.woff2") format("woff2"); font-weight: 500; font-style: normal; font-display: swap; }
@font-face { font-family: "Hanken Grotesk"; src: url("../fonts/hanken-grotesk-latin-600-normal.woff2") format("woff2"); font-weight: 600; font-style: normal; font-display: swap; }
@font-face { font-family: "Hanken Grotesk"; src: url("../fonts/hanken-grotesk-latin-700-normal.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: swap; }
@font-face { font-family: "JetBrains Mono"; src: url("../fonts/jetbrains-mono-latin-400-normal.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "JetBrains Mono"; src: url("../fonts/jetbrains-mono-latin-500-normal.woff2") format("woff2"); font-weight: 500; font-style: normal; font-display: swap; }

/* =============================================================================
   USMLE PULSE — main.css
   Design system: tokens, reset, base typography, shared components.
   Load order: main.css -> page CSS (landing/auth/dashboard).
   ========================================================================== */

/* ---------------------------------------------------------------------------
   1. DESIGN TOKENS
   The single source of truth for color, type, spacing, radius, shadow, motion.
   Change a brand color here and it cascades across the whole site.
--------------------------------------------------------------------------- */
:root {
  /* Brand palette */
  --ink:          #0c1a24;   /* near-black text / deep surfaces */
  --ink-2:        #142a3a;   /* raised dark surface */
  --ink-soft:     #3a4f5e;   /* secondary text on light */
  --paper:        #f7f6f3;   /* warm off-white page bg */
  --paper-2:      #ffffff;   /* cards on paper */
  --line:         #e7e3dc;   /* hairline borders on light */
  --line-dark:    #21384a;   /* hairline borders on dark */

  --brand:        #0f766e;   /* teal — trust / medical / primary */
  --brand-600:    #0c655e;
  --brand-700:    #0a544e;
  --brand-bright: #14b8a6;   /* teal highlight / illustration */
  --brand-tint:   #e3f3f1;   /* teal wash background */

  --pulse:        #ff5a4c;   /* coral — the heartbeat / CTA / accent */
  --pulse-600:    #ed4636;
  --pulse-tint:   #ffe9e6;

  --gold:         #f5b942;   /* sparing accent for ratings / highlights */
  --success:      #16a34a;
  --danger:       #dc2626;
  --info:         #2563eb;

  /* Text roles */
  --text:         var(--ink);
  --text-muted:   #5b6b77;
  --brand-text:   #0f766e;   /* teal for TEXT. 5.06:1 on light paper. */
  --text-invert:  #eaf2f1;
  --text-invert-muted: #9db4bf;

  /* Typography */
  --font-display: "Bricolage Grotesque", "Hanken Grotesk", system-ui, sans-serif;
  --font-body:    "Hanken Grotesk", system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
  --font-mono:    "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Fluid type scale (clamp = responsive without breakpoints) */
  --t-eyebrow: 0.78rem;
  --t-body:    clamp(1rem, 0.96rem + 0.2vw, 1.0625rem);
  --t-lead:    clamp(1.125rem, 1.05rem + 0.4vw, 1.3rem);
  --t-h3:      clamp(1.25rem, 1.1rem + 0.7vw, 1.6rem);
  --t-h2:      clamp(1.75rem, 1.4rem + 1.6vw, 2.6rem);
  --t-h1:      clamp(2.4rem, 1.8rem + 3vw, 4.2rem);

  /* Spacing scale */
  --sp-1: 0.25rem; --sp-2: 0.5rem; --sp-3: 0.75rem; --sp-4: 1rem;
  --sp-5: 1.5rem; --sp-6: 2rem; --sp-7: 3rem; --sp-8: 4rem; --sp-9: 6rem;

  /* Radius */
  --r-sm: 8px; --r-md: 14px; --r-lg: 22px; --r-xl: 32px; --r-pill: 999px;

  /* Shadows — soft, layered, premium */
  --shadow-sm: 0 1px 2px rgba(12,26,36,.06), 0 1px 3px rgba(12,26,36,.05);
  --shadow-md: 0 6px 16px -6px rgba(12,26,36,.14), 0 2px 6px rgba(12,26,36,.06);
  --shadow-lg: 0 24px 48px -18px rgba(12,26,36,.28), 0 8px 18px -10px rgba(12,26,36,.14);
  --shadow-glow: 0 0 0 1px rgba(255,90,76,.25), 0 10px 40px -10px rgba(255,90,76,.45);

  /* Layout */
  --maxw: 1180px;
  --maxw-narrow: 760px;
  --header-h: 72px;

  /* Motion */
  --ease: cubic-bezier(.22,.61,.36,1);
  --ease-out: cubic-bezier(.16,1,.3,1);
  --dur-fast: .15s; --dur: .28s; --dur-slow: .6s;

  /* -------------------------------------------------------------------------
     SEMANTIC LAYER — roles, not colors.
     Everything above is the PALETTE (what colors exist). Everything below is
     ROLES (what a color is for). Components should reference roles only.

     This split exists because --ink was doing two incompatible jobs: it was
     both "darkest brand color" (hero slab, footer, dark buttons — must stay
     dark in night mode) and "primary text color" (must invert in night mode).
     One token cannot do both, which is why night mode previously needed a
     hand-maintained patch list that grew with every new component.

     Night mode now overrides ONLY this block. Add a component using roles and
     it themes correctly with no extra work.
  ------------------------------------------------------------------------- */

  /* Surfaces */
  --surface-page:     var(--paper);    /* app/page background */
  --surface-raised:   var(--paper-2);  /* cards, panels, inputs */
  --surface-sunken:   #efece6;         /* wells, tracks, inset areas */
  --surface-inverse:  var(--ink);      /* deliberate dark slab — hero, footer */
  --surface-overlay:  var(--paper-2);  /* modals, dropdowns, popovers */
  --surface-hover:    rgba(12,26,36,.04);
  --surface-active:   rgba(12,26,36,.08);

  /* Content (text + icons) */
  --content-primary:    var(--ink);       /* headings, body */
  --content-secondary:  var(--ink-soft);  /* supporting copy */
  --content-muted:      var(--text-muted);/* captions, meta, placeholders */
  --content-brand:      var(--brand-text);
  --content-on-inverse: var(--text-invert);      /* on --surface-inverse */
  --content-on-inverse-muted: var(--text-invert-muted);
  --content-on-brand:   #ffffff;          /* on teal fills */
  --content-on-accent:  var(--ink);       /* on coral/gold fills — coral stays
                                             light in both themes, so this
                                             stays dark. 5.74:1 on coral. */

  /* Borders */
  --border-subtle:  var(--line);
  --border-default: var(--line);
  --border-strong:  var(--ink-soft);
  --border-focus:   var(--pulse);

  /* Feedback */
  --feedback-success: var(--success);
  --feedback-danger:  var(--danger);
  --feedback-warning: #e0a23c;
  --feedback-info:    var(--info);

  /* Breakpoints — reference values. Media queries can't read custom
     properties, so these document the scale that @media must match. */
  --bp-sm: 480px; --bp-md: 768px; --bp-lg: 1024px; --bp-xl: 1280px;
}

/* ---------------------------------------------------------------------------
   2. RESET & BASE
--------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  font-family: var(--font-body);
  font-size: var(--t-body);
  line-height: 1.6;
  color: var(--text);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  min-height: 100vh;
}

img, svg, video { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: none; }
ul { list-style: none; padding: 0; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.02em;
  color: var(--text);
}
h1 { font-size: var(--t-h1); font-weight: 800; }
h2 { font-size: var(--t-h2); }
h3 { font-size: var(--t-h3); }

/* Accessibility: visible focus + skip link + reduced motion */
:focus-visible { outline: 3px solid var(--pulse); outline-offset: 2px; border-radius: 4px; }
.skip-link {
  position: absolute; left: -999px; top: 8px; z-index: 200;
  background: var(--ink); color: #fff; padding: 10px 16px; border-radius: var(--r-sm);
}
.skip-link:focus { left: 12px; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; animation-iteration-count: 1 !important; }
}

/* ---------------------------------------------------------------------------
   3. LAYOUT HELPERS
--------------------------------------------------------------------------- */
.container { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--sp-5); }
.narrow { max-width: var(--maxw-narrow); }
.section { padding-block: clamp(3.5rem, 8vw, 7rem); }
.center { text-align: center; }
.stack > * + * { margin-top: var(--sp-4); }

.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--t-eyebrow);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--brand-text);
  display: inline-flex; align-items: center; gap: .5rem;
  font-weight: 500;
}
.eyebrow::before { content: ""; width: 22px; height: 1px; background: var(--brand); opacity: .6; }
.section-head { max-width: 640px; margin-bottom: var(--sp-7); }
.section-head.center { margin-inline: auto; }
.section-head h2 { margin-top: var(--sp-3); }
.section-head p { color: var(--text-muted); font-size: var(--t-lead); margin-top: var(--sp-3); }

/* ---------------------------------------------------------------------------
   4. BUTTONS
--------------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .55rem;
  font-family: var(--font-body); font-weight: 600; font-size: .98rem;
  padding: .82rem 1.4rem; border-radius: var(--r-pill);
  transition: transform var(--dur-fast) var(--ease), box-shadow var(--dur) var(--ease), background var(--dur) var(--ease);
  white-space: nowrap; line-height: 1; border: 1px solid transparent;
}
.btn:active { transform: translateY(1px) scale(.99); }
.btn-primary { background: var(--pulse); color: var(--content-on-accent); box-shadow: var(--shadow-md); }  /* dark ink: 5.74:1 on coral — white was 3.08:1 (fails AA) */
.btn-primary:hover { background: var(--pulse-600); box-shadow: var(--shadow-glow); transform: translateY(-1px); }
.btn-ghost { background: transparent; border-color: var(--line); color: var(--text); }
.btn-ghost:hover { border-color: var(--content-primary); background: rgba(12,26,36,.03); }
.btn-dark { background: var(--ink); color: #fff; }
.btn-dark:hover { background: var(--ink-2); transform: translateY(-1px); box-shadow: var(--shadow-md); }
.btn-brand { background: var(--brand); color: #fff; }
.btn-brand:hover { background: var(--brand-600); transform: translateY(-1px); box-shadow: var(--shadow-md); }
.btn-block { width: 100%; }
.btn-lg { padding: 1rem 1.7rem; font-size: 1.02rem; }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .55; pointer-events: none; }
.btn .spinner { width: 16px; height: 16px; border: 2px solid rgba(255,255,255,.4); border-top-color: #fff; border-radius: 50%; animation: spin .7s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------------------------------------------------------------------------
   5. CARDS / PILLS / BADGES
--------------------------------------------------------------------------- */
.card {
  background: var(--paper-2); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: var(--sp-6);
  box-shadow: var(--shadow-sm);
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.card-hover:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); border-color: transparent; }
.pill {
  display: inline-flex; align-items: center; gap: .4rem;
  font-family: var(--font-mono); font-size: .72rem; letter-spacing: .04em;
  padding: .35rem .7rem; border-radius: var(--r-pill);
  background: var(--brand-tint); color: var(--brand-700); font-weight: 500;
}
.badge { display:inline-flex; align-items:center; gap:.4rem; font-size:.78rem; font-weight:600; padding:.25rem .65rem; border-radius: var(--r-pill); }
.badge-active { background: rgba(22,163,74,.12); color: var(--success); }
.badge-pending { background: rgba(245,185,66,.18); color: #9a6b00; }
.badge-none { background: rgba(12,26,36,.07); color: var(--text-muted); }

/* ---------------------------------------------------------------------------
   6. FORMS
--------------------------------------------------------------------------- */
.field { display: flex; flex-direction: column; gap: .45rem; margin-bottom: var(--sp-4); }
.field label { font-weight: 600; font-size: .9rem; }
.field .hint { font-size: .82rem; color: var(--text-muted); }
.input, .input-wrap input {
  width: 100%; padding: .8rem 1rem; font-size: 1rem;
  background: var(--paper-2); border: 1.5px solid var(--line); border-radius: var(--r-md);
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.input:focus, .input-wrap input:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 4px var(--brand-tint); }
.input.is-invalid { border-color: var(--danger); }
.input-wrap { position: relative; display: flex; align-items: center; }
.input-wrap input { padding-right: 3rem; }
.input-wrap .toggle-pw {
  position: absolute; right: .5rem; padding: .4rem; color: var(--text-muted); border-radius: var(--r-sm);
}
.input-wrap .toggle-pw:hover { color: var(--text); }
.field-error { color: var(--danger); font-size: .82rem; min-height: 1.1em; }
.checkbox-row { display: flex; align-items: flex-start; gap: .6rem; font-size: .9rem; color: var(--text-muted); }
.checkbox-row input { margin-top: .2rem; accent-color: var(--brand); width: 18px; height: 18px; }
.divider-or { display: flex; align-items: center; gap: 1rem; color: var(--text-muted); font-size: .82rem; margin: var(--sp-5) 0; }
.divider-or::before, .divider-or::after { content: ""; flex: 1; height: 1px; background: var(--line); }

/* Password strength meter */
.pw-meter { height: 6px; border-radius: var(--r-pill); background: var(--line); overflow: hidden; margin-top: .4rem; }
.pw-meter > span { display: block; height: 100%; width: 0; transition: width var(--dur) var(--ease), background var(--dur) var(--ease); border-radius: inherit; }

/* ---------------------------------------------------------------------------
   7. HEADER / NAV (injected by components/layout.js)
--------------------------------------------------------------------------- */
.site-header {
  position: sticky; top: 0; z-index: 100; height: var(--header-h);
  display: flex; align-items: center;
  background: color-mix(in srgb, var(--paper) 82%, transparent);
  backdrop-filter: saturate(160%) blur(12px);
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.site-header.scrolled { border-bottom-color: var(--line); background: color-mix(in srgb, var(--paper) 92%, transparent); }
.site-header .container { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-5); }
.brand { display: inline-flex; align-items: center; gap: .6rem; font-family: var(--font-display); font-weight: 800; font-size: 1.18rem; letter-spacing: -.02em; }
.brand .mark { width: 30px; height: 30px; flex: none; }
.nav-menu { display: flex; align-items: center; gap: var(--sp-5); }
.nav-links { display: flex; align-items: center; gap: var(--sp-2); }
.nav-links { flex-wrap: nowrap; }
/* Multi-word tabs ("My plan", "Ask a Tutor", "Study Partners") were being
   squeezed below their content width and wrapping onto 2-3 lines, which
   made the header ragged and uneven in height. Keep each tab on one line
   and stop flex from shrinking them below their text. */
.nav-links a { padding: .5rem .8rem; border-radius: var(--r-sm); font-weight: 500; font-size: .95rem; color: var(--ink-soft); white-space: nowrap; flex: 0 0 auto; transition: color var(--dur-fast), background var(--dur-fast); }
.nav-links a:hover, .nav-links a[aria-current="page"] { color: var(--content-primary); background: rgba(12,26,36,.05); }
.nav-actions { display: flex; align-items: center; gap: var(--sp-3); }
.nav-toggle { display: none; width: 44px; height: 44px; border-radius: var(--r-sm); align-items: center; justify-content: center; }
.nav-toggle span, .nav-toggle span::before, .nav-toggle span::after { content:""; display:block; width:22px; height:2px; background: var(--ink); border-radius: 2px; position: relative; transition: transform var(--dur) var(--ease), opacity var(--dur-fast); }
.nav-toggle span::before { position:absolute; top:-7px; } .nav-toggle span::after { position:absolute; top:7px; }
body.nav-open .nav-toggle span { background: transparent; }
body.nav-open .nav-toggle span::before { transform: translateY(7px) rotate(45deg); }
body.nav-open .nav-toggle span::after { transform: translateY(-7px) rotate(-45deg); }


/* Between the hamburger cutoff and a roomy desktop the row is tight, especially
   for moderators (who carry an extra Admin item). Tighten spacing rather than
   letting tabs wrap or the header overflow. */
@media (min-width: 1024px) and (max-width: 1279px) {
  .site-header .container { gap: var(--sp-3); }
  .nav-menu { gap: var(--sp-3); }
  .nav-links { gap: 2px; }
  .nav-links a { padding: .5rem .55rem; font-size: .9rem; }
  .nav-actions { gap: var(--sp-2); }
}

@media (max-width: 1023px) {
  .nav-toggle { display: inline-flex; position: relative; z-index: 210; }
  .nav-menu {
    position: fixed; inset: 0; z-index: 200; background: var(--paper);
    flex-direction: column; align-items: stretch; justify-content: flex-start;
    padding: calc(var(--header-h) + var(--sp-4)) var(--sp-5) var(--sp-6);
    gap: var(--sp-2); overflow-y: auto; -webkit-overflow-scrolling: touch;
    transform: translateX(100%); transition: transform var(--dur) var(--ease); display: flex;
  }
  body.nav-open .nav-menu { transform: translateX(0); }
  body.nav-open { overflow: hidden; }
  .nav-links { flex-direction: column; align-items: stretch; gap: var(--sp-1); }
  .nav-links a { padding: .95rem 1rem; font-size: 1.08rem; border-radius: var(--r-md); }
  .nav-actions { flex-direction: column; align-items: stretch; gap: var(--sp-3); margin-top: var(--sp-4); }
  .nav-actions .btn { width: 100%; }
  /* backdrop-filter on the header makes it a containing block for the fixed
     menu, clipping it to header height — disable it on mobile so the overlay
     fills the screen and all tabs show. */
  .site-header { backdrop-filter: none; -webkit-backdrop-filter: none;
    background: color-mix(in srgb, var(--paper) 94%, transparent); }
}

/* ---------------------------------------------------------------------------
   8. FOOTER (injected)
--------------------------------------------------------------------------- */
.site-footer { background: var(--ink); color: var(--text-invert-muted); padding-block: var(--sp-8) var(--sp-6); margin-top: var(--sp-9); }
.site-footer a { color: var(--text-invert-muted); transition: color var(--dur-fast); }
.site-footer a:hover { color: #fff; }
.footer-grid { display: grid; grid-template-columns: 1.6fr repeat(3, 1fr); gap: var(--sp-6); padding-bottom: var(--sp-7); border-bottom: 1px solid var(--line-dark); }
.footer-brand .brand { color: #fff; }
.footer-brand p { margin-top: var(--sp-3); max-width: 32ch; font-size: .92rem; }
.footer-col h4 { color: #fff; font-family: var(--font-mono); font-size: .74rem; letter-spacing: .12em; text-transform: uppercase; font-weight: 500; margin-bottom: var(--sp-3); }
.footer-col ul { display: flex; flex-direction: column; gap: .6rem; font-size: .92rem; }
.footer-bottom { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); padding-top: var(--sp-5); font-size: .85rem; flex-wrap: wrap; }
.social-row { display: flex; gap: .5rem; }
.social-row a { width: 38px; height: 38px; border: 1px solid var(--line-dark); border-radius: var(--r-pill); display: grid; place-items: center; }
.social-row a:hover { border-color: var(--pulse); color: #fff; }
@media (max-width: 767px) { .footer-grid { grid-template-columns: 1fr 1fr; } .footer-brand { grid-column: 1 / -1; } }

/* ---------------------------------------------------------------------------
   9. TOAST (ui.js)
--------------------------------------------------------------------------- */
.toast-wrap { position: fixed; right: 1rem; bottom: 1rem; z-index: 300; display: flex; flex-direction: column; gap: .6rem; }
.toast {
  display: flex; align-items: center; gap: .7rem; background: var(--ink); color: #fff;
  padding: .85rem 1.1rem; border-radius: var(--r-md); box-shadow: var(--shadow-lg);
  font-size: .92rem; max-width: 360px; transform: translateY(10px); opacity: 0;
  animation: toast-in .35s var(--ease-out) forwards;
}
.toast.success { border-left: 3px solid var(--success); }
.toast.error { border-left: 3px solid var(--danger); }
.toast.info { border-left: 3px solid var(--info); }
@keyframes toast-in { to { transform: translateY(0); opacity: 1; } }

/* ---------------------------------------------------------------------------
   10. SCROLL REVEAL (ui.js adds .reveal then .in)
--------------------------------------------------------------------------- */
.reveal { opacity: 0; transform: translateY(18px); transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out); }
.reveal.in { opacity: 1; transform: none; }
.reveal[data-delay="1"] { transition-delay: .08s; }
.reveal[data-delay="2"] { transition-delay: .16s; }
.reveal[data-delay="3"] { transition-delay: .24s; }

/* The animated ECG / pulse line — the brand signature */
.pulse-line path { stroke-dasharray: 1400; stroke-dashoffset: 1400; animation: draw-pulse 3s var(--ease-out) forwards; }
@keyframes draw-pulse { to { stroke-dashoffset: 0; } }

/* ===== Floating chat widget ===== */
.chat-fab { position: fixed; right: 20px; bottom: 20px; z-index: 150; width: 56px; height: 56px; border-radius: 50%;
  border: 0; cursor: pointer; display: grid; place-items: center; color: #fff; background: var(--brand);
  box-shadow: 0 10px 26px rgba(15,118,110,.4); transition: transform .15s, box-shadow .15s; }
.chat-fab:hover { transform: translateY(-2px); box-shadow: 0 14px 32px rgba(15,118,110,.5); }
.chat-fab.is-open { background: var(--ink); }
.chat-badge { position: absolute; top: -4px; right: -4px; min-width: 20px; height: 20px; padding: 0 5px; border-radius: 10px;
  background: #e23b3b; color: #fff; font-size: 12px; font-weight: 800; line-height: 20px; text-align: center;
  box-shadow: 0 2px 6px rgba(0,0,0,.3); border: 2px solid var(--paper, #fff); box-sizing: content-box; }
.chat-fab.has-unread { animation: chat-pulse 1.6s ease-in-out infinite; }
@keyframes chat-pulse { 0%,100% { box-shadow: 0 10px 24px rgba(15,118,110,.4); } 50% { box-shadow: 0 10px 24px rgba(15,118,110,.4), 0 0 0 7px rgba(226,59,59,.18); } }
@media (prefers-reduced-motion: reduce) { .chat-fab.has-unread { animation: none; } }
.chat-panel { position: fixed; right: 20px; bottom: 88px; z-index: 150; width: min(360px, calc(100vw - 40px));
  height: min(520px, calc(100vh - 140px)); display: flex; flex-direction: column; overflow: hidden;
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: 0 20px 60px rgba(12,26,36,.25); }
.chat-head { display: flex; align-items: center; justify-content: space-between; padding: .9rem 1rem;
  background: var(--ink); color: #fff; }
.chat-head b { font-size: .98rem; }
.chat-x { background: none; border: 0; color: #fff; font-size: 1.5rem; line-height: 1; cursor: pointer; opacity: .8; }
.chat-x:hover { opacity: 1; }
.chat-body { flex: 1; overflow-y: auto; padding: 1rem; display: flex; flex-direction: column; gap: .5rem; }
.chat-empty { color: var(--text-muted); font-size: .9rem; text-align: center; margin: auto; }
.cmsg { max-width: 80%; padding: .55rem .8rem; border-radius: var(--r-md); font-size: .92rem; line-height: 1.45; }
.cmsg.in { align-self: flex-start; background: var(--paper-2); border: 1px solid var(--line); }
.cmsg.out { align-self: flex-end; background: var(--brand); color: #fff; }
.chat-foot { display: flex; gap: .5rem; padding: .7rem; border-top: 1px solid var(--line); align-items: center; }
.chat-foot .input { flex: 1; }
.chat-foot .btn { flex: none; padding: .6rem .8rem; }
@media (max-width: 479px) {
  .chat-panel { right: 10px; left: 10px; width: auto; bottom: 84px; }
  .chat-fab { right: 14px; bottom: 14px; }
}

/* Footer email subscribe */
.footer-newsletter { display: flex; gap: .5rem; margin-top: 1.1rem; max-width: 320px; }
.footer-newsletter .input { flex: 1; }
.footer-newsletter .btn { flex: none; }
@media (max-width: 479px) { .footer-newsletter { max-width: none; } }

/* Fix: [hidden] must win over the panel's display:flex (chat opened by default / wouldn't close) */
.chat-panel[hidden] { display: none !important; }
.chat-fab[hidden] { display: none !important; }

/* =============================== NIGHT MODE ===============================
   Overrides the SEMANTIC layer only. Because components reference roles, a new
   component themes itself correctly with no entry here. The long per-component
   patch list this replaced is gone.
   ========================================================================== */
[data-theme="dark"] {
  /* Palette shifts */
  --paper: #0c151c;        /* page background */
  --paper-2: #16242f;      /* cards / raised surfaces */
  --line: #28394a;         /* borders */
  --text: #e7eef1;         /* body text */
  --text-muted: #9fb3bf;
  --brand-text: #58c9be;   /* lighter teal — 7.1:1 on the dark card surface */
  --ink-soft: #9fb3bf;
  --brand-tint: #0d2826;
  --pulse-tint: #2c1714;
  --shadow-sm: 0 1px 2px rgba(0,0,0,.45);
  --shadow-md: 0 6px 16px -6px rgba(0,0,0,.55);
  --shadow-lg: 0 24px 48px -18px rgba(0,0,0,.7);

  /* Semantic roles. --surface-inverse and --content-on-accent deliberately do
     NOT flip: the hero slab stays dark and coral stays coral, so dark text on
     coral remains the accessible pairing in both themes. */
  --surface-sunken:  #0a1219;
  --surface-hover:   rgba(255,255,255,.06);
  --surface-active:  rgba(255,255,255,.10);

  --content-primary:   var(--text);
  --content-secondary: var(--text-muted);
  --border-strong:     #3d5266;

  --feedback-success: #4ade80;
  --feedback-danger:  #f87171;
  --feedback-warning: #f0c862;
  --feedback-info:    #60a5fa;
}
[data-theme="dark"] body { background: var(--surface-page); }
[data-theme="dark"] .input,
[data-theme="dark"] select.input,
[data-theme="dark"] textarea.input { background: var(--surface-raised); border-color: var(--border-default); color: var(--content-primary); }
[data-theme="dark"] .input::placeholder { color: var(--content-muted); }
/* Header chrome sits on the now-dark page. */
[data-theme="dark"] .nav-toggle span,
[data-theme="dark"] .nav-toggle span::before,
[data-theme="dark"] .nav-toggle span::after { background: var(--content-primary); }

/* Theme toggle button */
.theme-toggle { display: inline-grid; place-items: center; width: 40px; height: 40px; flex: none;
  border-radius: var(--r-pill); border: 1px solid var(--line); background: transparent; color: var(--text);
  cursor: pointer; transition: background .15s, border-color .15s; }
.theme-toggle:hover { background: color-mix(in srgb, var(--text) 8%, transparent); border-color: var(--text-muted); }
.nav-actions .theme-toggle { order: -1; }
@media (max-width: 1023px) { .nav-actions .theme-toggle { width: 100%; border-radius: var(--r-md); gap: .5rem; } .theme-toggle .tt-label { display: inline; } }
.theme-toggle .tt-label { display: none; margin-left: .5rem; font-weight: 600; }

/* Footer bottom legal links */
.footer-legal-links { display: flex; gap: 1rem; flex-wrap: wrap; }
.footer-legal-links a { color: var(--text-invert-muted); }
.footer-legal-links a:hover { color: #fff; }

/* -----------------------------------------------------------------------
   The HTML `hidden` attribute must ALWAYS win over component display rules.
   Without this, any `.thing { display:flex/grid }` overrides `[hidden]`
   (same specificity, author beats UA), so "hidden" elements still render.
   This one rule prevents that across every page. -------------------------- */
[hidden] { display: none !important; }

/* WhatsApp call-to-action button */
.btn-whatsapp { background: #25d366; color: #fff; display: inline-flex; align-items: center; justify-content: center; gap: .55rem; border: none; }
.btn-whatsapp:hover { background: #1eb858; color: #fff; }
.btn-whatsapp svg { flex: none; }

/* Protected pages: blank the output if someone tries to print/save-as-PDF */
@media print {
  body.pulse-protected { display: none !important; }
}
.pulse-wm { mix-blend-mode: multiply; }
[data-theme="dark"] .pulse-wm { mix-blend-mode: screen; }

/* ===== Mobile safety net: prevent any stray wide element from forcing the
   whole page into a zoomed-out "desktop" view on phones. ===== */
html, body { max-width: 100%; overflow-x: hidden; }
img, canvas, video, iframe { max-width: 100%; height: auto; }
svg { max-width: 100%; }
table { max-width: 100%; }
@media (max-width: 479px) {
  .container, main, .dash, .dash-main { min-width: 0; }
  /* tables that can't shrink should scroll inside their own box, not the page */
  .admin-table-wrap, .dash-table-wrap, .pkg-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }
}

/* ===== Extra mobile hardening for dense rows/inputs (defensive) ===== */
@media (max-width: 479px) {
  /* inputs paired with buttons must be able to shrink, not push the page wide */
  .promo-row .input, .form-row .input, .input-group .input { min-width: 0; }
  /* any flex row of controls wraps instead of overflowing */
  .field-row, .form-row, .btn-row { flex-wrap: wrap; }
  /* tall hero phones shouldn't dominate the first mobile screen */
  .hero-phones { max-width: 320px; }
}

/* Devices list + account danger actions (dashboard) */
.device-row { display: flex; align-items: center; justify-content: space-between; gap: .75rem;
  padding: .6rem .2rem; border-bottom: 1px solid var(--line, #e6e6e6); }
.device-row:last-child { border-bottom: 0; }
.device-badge { display: inline-block; font-size: .72rem; font-weight: 700; color: #0f766e;
  background: rgba(15,118,110,.12); border-radius: 999px; padding: .05rem .5rem; margin-left: .35rem; }
.danger-actions { display: flex; gap: .6rem; flex-wrap: wrap; }
.btn.danger { color: #c0392b; border-color: rgba(192,57,43,.4); }
.btn.danger:hover { background: rgba(192,57,43,.08); }

/* Live pricing sale display */
.price-old{text-decoration:line-through;opacity:.5;font-weight:600;margin-right:.35rem}
.price-new{color:var(--pulse,#ff5a4c);font-weight:800}


/* Duty picker — tick to transfer. Selection is by checkbox only, so task text
   stays copy-protected. */
.duty-picker{margin-top:.6rem;padding:.7rem;border:1px solid var(--line);border-radius:10px;background:var(--paper-2)}
.duty-picker-head{font-size:.8rem;font-weight:700;opacity:.75;margin-bottom:.5rem}
.duty-opt{display:flex;gap:.5rem;align-items:flex-start;padding:.4rem .3rem;border-radius:8px;font-size:.85rem;line-height:1.35;cursor:pointer;user-select:none;-webkit-user-select:none}
.duty-opt:hover{background:rgba(255,255,255,.04)}
.duty-opt input{margin-top:.15rem;flex:0 0 auto;min-width:18px;min-height:18px}
.duty-opt span{-webkit-user-select:none;user-select:none}
.duty-picker-actions{display:flex;gap:.5rem;margin-top:.6rem;flex-wrap:wrap}
.price-after{font-size:.85rem;font-weight:600;opacity:.7}

/* NBME form card: score sits where the reorder arrows normally are */
.m-score{display:flex;align-items:center;gap:.35rem;font-size:.72rem;font-weight:700;opacity:.8;white-space:nowrap;padding-right:.2rem}
.m-score input{width:52px;padding:.3rem .35rem;border:1px solid var(--line);border-radius:8px;background:var(--paper);color:var(--content-primary);font-size:.85rem;text-align:center;font-family:var(--font-mono,monospace)}
.m-score input:focus{outline:2px solid var(--brand);outline-offset:1px}
.acc-count{font-size:.82rem;font-weight:700;opacity:.7;white-space:nowrap;align-self:center}

/* A student's own tasks */
.mine-badge{display:inline-block;font-size:.62rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase;padding:.1rem .35rem;border-radius:999px;background:var(--brand-tint);color:var(--brand-text);vertical-align:middle;margin-left:.35rem}
.mine-add-wrap{padding:.4rem .2rem .2rem}
.mine-form{margin-top:.6rem;padding:.7rem;border:1px solid var(--line);border-radius:10px;background:var(--paper-2);display:grid;gap:.6rem}
.mine-l{display:grid;gap:.3rem;font-size:.8rem;font-weight:700;opacity:.8}
.mine-form textarea{resize:vertical;font-family:var(--font-body);line-height:1.4}
.mine-actions{display:flex;gap:.5rem;flex-wrap:wrap}

/* ===== Testimonials flipboard ============================================ */
.tm-wrap{max-width:760px;margin:0 auto;text-align:center}
.tm-head{margin-bottom:1.1rem}
.tm-title{font-family:var(--font-display);font-weight:800;font-size:clamp(1.5rem,3.4vw,2.1rem);margin:.3rem 0 0}
.tm-stage{position:relative;min-height:230px;perspective:1400px}
.tm-card{position:absolute;inset:0;background:var(--paper-2);border:1px solid var(--line);border-radius:16px;
  padding:1.4rem 1.3rem;box-shadow:var(--shadow-md);transform-origin:center top;backface-visibility:hidden;
  display:flex;align-items:center;justify-content:center}
.tm-face{width:100%}
.tm-body{font-size:1.02rem;line-height:1.6;margin:0 0 1rem;color:var(--text)}
.tm-shot{margin:0 0 .9rem;border-radius:12px;overflow:hidden;border:1px solid var(--line);background:var(--paper)}
.tm-shot img{display:block;width:100%;max-height:280px;object-fit:contain}
.tm-who{display:flex;align-items:center;justify-content:center;gap:.55rem;flex-wrap:wrap}
.tm-avatar{width:30px;height:30px;border-radius:50%;background:var(--brand-tint);color:var(--brand-text);
  display:grid;place-items:center;font-weight:800;font-size:.85rem;flex:none}
.tm-name{font-weight:700}
.tm-when{opacity:.55;font-size:.82rem}

/* the flip itself — the card turns over on its top edge, like a board */
@keyframes tmIn{from{transform:rotateX(-92deg);opacity:0}60%{opacity:1}to{transform:rotateX(0);opacity:1}}
@keyframes tmOut{from{transform:rotateX(0);opacity:1}to{transform:rotateX(88deg);opacity:0}}
@keyframes tmInRev{from{transform:rotateX(92deg);opacity:0}60%{opacity:1}to{transform:rotateX(0);opacity:1}}
@keyframes tmOutRev{from{transform:rotateX(0);opacity:1}to{transform:rotateX(-88deg);opacity:0}}
.tm-in{animation:tmIn .46s cubic-bezier(.2,.8,.25,1) both}
.tm-out{animation:tmOut .4s cubic-bezier(.6,0,.8,.3) both}
.tm-in-rev{animation:tmInRev .46s cubic-bezier(.2,.8,.25,1) both}
.tm-out-rev{animation:tmOutRev .4s cubic-bezier(.6,0,.8,.3) both}

.tm-controls{display:flex;align-items:center;justify-content:center;gap:.8rem;margin-top:1rem}
.tm-nav{width:38px;height:38px;border-radius:50%;border:1px solid var(--line);background:var(--paper-2);
  color:var(--text);font-size:1.2rem;line-height:1;cursor:pointer;transition:transform .15s,border-color .15s}
.tm-nav:hover{transform:scale(1.08);border-color:var(--brand-text)}
.tm-dots{display:flex;gap:.4rem}
.tm-dot{width:8px;height:8px;padding:0;border-radius:50%;border:0;background:var(--line);cursor:pointer;transition:all .25s}
.tm-dot.is-on{background:var(--pulse);width:22px;border-radius:999px}
.tm-cta{margin-top:.9rem}
.tm-form{margin-top:1rem;padding:1rem;border:1px solid var(--line);border-radius:14px;background:var(--paper-2);display:grid;gap:.7rem;text-align:left}
.tm-l{display:grid;gap:.3rem;font-size:.82rem;font-weight:700;opacity:.85}
.tm-actions{display:flex;gap:.5rem}
.tm-note{font-size:.82rem;opacity:.65;margin:.2rem 0 0}
@media (max-width: 767px){ .tm-stage{min-height:280px} .tm-card{padding:1.1rem .9rem} }
@media (prefers-reduced-motion: reduce){ .tm-in,.tm-out,.tm-in-rev,.tm-out-rev{animation:none} }

/* ===== Calendar button — it was a ghost among ghosts ====================== */
.cal-toggle{display:inline-flex;align-items:center;gap:.5rem;font-weight:700;font-size:.95rem;
  padding:.72rem 1.2rem;border-radius:var(--r-pill);border:1px solid transparent;
  background:var(--brand);color:#fff;cursor:pointer;box-shadow:var(--shadow-sm);
  transition:transform .16s cubic-bezier(.2,.8,.25,1),box-shadow .16s,filter .16s}
.cal-toggle:hover{transform:translateY(-2px);box-shadow:var(--shadow-md);filter:brightness(1.08)}
.cal-toggle:active{transform:translateY(0)}
.cal-toggle:focus-visible{outline:2px solid var(--brand-text);outline-offset:3px}
.cal-toggle .cal-ico{font-size:1.05rem;transition:transform .3s cubic-bezier(.2,.8,.25,1)}
.cal-toggle.is-open .cal-ico{transform:rotate(-12deg) scale(1.1)}
.cal-toggle .cal-chev{transition:transform .3s cubic-bezier(.2,.8,.25,1)}
.cal-toggle.is-open .cal-chev{transform:rotate(180deg)}
/* a soft pulse the first time, so it's findable without being a nuisance */
@keyframes calNudge{0%,100%{box-shadow:0 0 0 0 rgba(15,118,110,.45)}50%{box-shadow:0 0 0 10px rgba(15,118,110,0)}}
.cal-toggle.nudge{animation:calNudge 2.4s ease-out 3}
@keyframes calDrop{from{opacity:0;transform:translateY(-8px) scaleY(.97)}to{opacity:1;transform:none}}
.cal-panel-in{animation:calDrop .32s cubic-bezier(.2,.8,.25,1) both;transform-origin:top center}
@media (prefers-reduced-motion: reduce){ .cal-toggle,.cal-toggle .cal-ico,.cal-toggle .cal-chev{transition:none}
  .cal-toggle.nudge{animation:none} .cal-panel-in{animation:none} }

/* Testimonials — admin list */
.tm-admin-row{display:flex;gap:.8rem;justify-content:space-between;align-items:flex-start;padding:.7rem;border:1px solid var(--line);border-radius:10px;margin-bottom:.5rem}
.tm-admin-row.is-pending{border-color:var(--gold);background:color-mix(in srgb, var(--gold) 7%, transparent)}
.tm-admin-main{min-width:0}
.tm-admin-top{display:flex;gap:.5rem;align-items:center;flex-wrap:wrap}
.tm-admin-acts{display:flex;gap:.4rem;flex-wrap:wrap;flex:none}
.tm-tag{font-size:.66rem;font-weight:800;text-transform:uppercase;letter-spacing:.05em;padding:.12rem .4rem;border-radius:999px}
.tm-tag.ok{background:var(--brand-tint);color:var(--brand-text)}
.tm-tag.wait{background:color-mix(in srgb, var(--gold) 22%, transparent);color:var(--gold)}

/* ===== Button feedback ==================================================
   Every button should answer you the instant you touch it. Lift on hover,
   press down on click, and a ripple that starts where the pointer landed. */
.btn, .cal-toggle, .tm-nav, .admin-tab {
  position: relative; overflow: hidden;
  transition: transform .14s var(--ease-out), box-shadow .18s var(--ease-out), filter .18s var(--ease-out);
}
.btn:hover:not(:disabled), .tm-nav:hover { transform: translateY(-2px); }
.btn:active:not(:disabled), .cal-toggle:active, .tm-nav:active { transform: translateY(0) scale(.975); }
.btn:disabled { transform: none; filter: saturate(.6) opacity(.7); cursor: not-allowed; }

/* ripple */
.rip { position: absolute; border-radius: 50%; transform: scale(0); pointer-events: none;
  background: currentColor; opacity: .28; animation: rip .55s var(--ease-out) forwards; }
@keyframes rip { to { transform: scale(2.6); opacity: 0; } }

/* checkbox tick — a small pop when a task is completed */
@keyframes tickPop { 0% { transform: scale(1) } 45% { transform: scale(1.32) } 100% { transform: scale(1) } }
.task-check input:checked { animation: tickPop .28s var(--ease-out); }

/* cards lift slightly as you consider them */
.price-card { transition: transform .2s var(--ease-out), box-shadow .2s var(--ease-out); }
.price-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); }

@media (prefers-reduced-motion: reduce) {
  .btn, .cal-toggle, .tm-nav, .admin-tab, .price-card { transition: none }
  .btn:hover, .btn:active, .price-card:hover, .tm-nav:hover { transform: none }
  .rip { display: none }
  .task-check input:checked { animation: none }
}

/* ===== Library — Pulse Notes chapters ==================================== */
.lib-notes-head{grid-column:1/-1;margin-bottom:.2rem}
.lib-notes-head .lib-title{font-size:1.15rem}
.lib-ch-grid{grid-column:1/-1;display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:.7rem}
.lib-ch{display:flex;flex-direction:column;align-items:flex-start;gap:.25rem;text-align:left;
  padding:.9rem 1rem;border:1px solid var(--line);border-radius:12px;background:var(--paper-2);
  color:var(--text);cursor:pointer;transition:transform .16s var(--ease-out),border-color .16s,box-shadow .16s}
.lib-ch:hover{transform:translateY(-3px);border-color:var(--brand-text);box-shadow:var(--shadow-md)}
.lib-ch-name{font-weight:700;font-size:1rem}
.lib-ch-meta{font-size:.78rem;opacity:.6}
.lib-ch-go{margin-top:.35rem;font-size:.82rem;font-weight:700;color:var(--brand-text)}

/* ===== Avatars ========================================================== */
.pulse-avatar{display:inline-flex;align-items:center;justify-content:center;border-radius:50%;
  background-size:cover;background-position:center;background-repeat:no-repeat;
  color:#fff;font-weight:800;line-height:1;flex:none;user-select:none;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.08)}
.avatar-edit{display:flex;align-items:center;gap:1rem;margin-bottom:1.2rem}
.avatar-preview{width:76px;height:76px}
.avatar-edit-actions{display:flex;flex-direction:column;gap:.3rem;align-items:flex-start}
.avatar-edit-actions .btn{cursor:pointer}

/* ===== Direct messages ================================================== */
.dm-nav-badge{display:inline-flex;align-items:center;justify-content:center;min-width:16px;height:16px;
  padding:0 4px;margin-left:4px;border-radius:999px;background:var(--pulse);color:var(--content-on-accent);
  font-size:.65rem;font-weight:800;vertical-align:middle}
.dm-app{display:grid;grid-template-columns:300px 1fr;gap:1px;background:var(--line);
  border:1px solid var(--line);border-radius:16px;overflow:hidden;margin-top:var(--sp-4);
  min-height:520px;height:70vh}
.dm-list{background:var(--paper-2);display:flex;flex-direction:column;overflow:hidden}
.dm-list-head{display:flex;align-items:center;justify-content:space-between;gap:.5rem;
  padding:.9rem 1rem;border-bottom:1px solid var(--line)}
[data-dm-convos]{overflow-y:auto;flex:1}
.dm-convo{display:flex;align-items:center;gap:.7rem;width:100%;text-align:left;padding:.7rem 1rem;
  border:0;border-bottom:1px solid var(--line);background:transparent;color:var(--text);cursor:pointer;
  transition:background .15s}
.dm-convo:hover{background:var(--paper)}
.dm-convo.is-active{background:var(--brand-tint)}
.dm-convo-av{flex:none}
.dm-convo-main{min-width:0;flex:1;display:flex;flex-direction:column;gap:.1rem}
.dm-convo-name{font-weight:700;font-size:.92rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dm-convo-last{font-size:.8rem;opacity:.6;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dm-convo.has-unread .dm-convo-last{opacity:.9;font-weight:600}
.dm-convo-meta{display:flex;flex-direction:column;align-items:flex-end;gap:.25rem;flex:none}
.dm-convo-time{font-size:.72rem;opacity:.5}
.dm-badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;
  padding:0 5px;border-radius:999px;background:var(--pulse);color:var(--content-on-accent);font-size:.7rem;font-weight:800}
.dm-thread{background:var(--paper-2);display:flex;flex-direction:column;overflow:hidden}
.dm-empty{margin:auto;padding:2rem;text-align:center}
.dm-thread-head{display:flex;align-items:center;gap:.6rem;padding:.8rem 1rem;border-bottom:1px solid var(--line)}
.dm-thread-name{font-weight:700}
.dm-spacer{flex:1}
.dm-menu{position:relative}
.dm-menu-pop{position:absolute;right:0;top:100%;margin-top:.3rem;background:var(--paper-2);
  border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow-md);overflow:hidden;z-index:5}
.dm-menu-pop button{display:block;width:100%;text-align:left;padding:.6rem 1rem;border:0;background:transparent;
  color:var(--pulse);font-weight:600;cursor:pointer;white-space:nowrap}
.dm-menu-pop button:hover{background:var(--paper)}
.dm-messages{flex:1;overflow-y:auto;padding:1rem;display:flex;flex-direction:column;gap:.5rem}
.dm-msg{display:flex;flex-direction:column;max-width:78%}
.dm-msg.mine{align-self:flex-end;align-items:flex-end}
.dm-msg.theirs{align-self:flex-start;align-items:flex-start}
.dm-bubble{padding:.55rem .8rem;border-radius:14px;font-size:.92rem;line-height:1.4;word-break:break-word}
.dm-msg.mine .dm-bubble{background:var(--brand);color:#fff;border-bottom-right-radius:4px}
.dm-msg.theirs .dm-bubble{background:var(--paper);border:1px solid var(--line);border-bottom-left-radius:4px}
.dm-msg-meta{display:flex;align-items:center;gap:.4rem;font-size:.68rem;opacity:.5;margin-top:.15rem}
.dm-report{border:0;background:transparent;cursor:pointer;opacity:.5;font-size:.8rem}
.dm-report:hover{opacity:1}
.dm-composer{display:flex;gap:.5rem;align-items:flex-end;padding:.7rem;border-top:1px solid var(--line)}
.dm-composer textarea{flex:1;resize:none;border:1px solid var(--line);border-radius:12px;padding:.55rem .8rem;
  background:var(--paper);color:var(--text);font-family:var(--font-body);font-size:.92rem;line-height:1.4;max-height:140px}
.dm-blocked-note{padding:.9rem 1rem;border-top:1px solid var(--line);text-align:center;font-size:.85rem;opacity:.7}
@media (max-width: 767px){
  .dm-app{grid-template-columns:1fr;height:auto}
  .dm-list{max-height:38vh}
  .dm-thread{min-height:52vh}
}

/* ===== Community feed =================================================== */
.container-narrow{max-width:680px}
.feed-composer{padding:1rem;margin:var(--sp-4) 0 1rem}
.feed-composer textarea{width:100%;border:1px solid var(--line);border-radius:12px;padding:.7rem .9rem;
  background:var(--paper);color:var(--text);font-family:var(--font-body);font-size:.95rem;line-height:1.5;resize:vertical;min-height:56px}
.feed-composer-row{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;margin-top:.6rem}
.feed-mini{max-width:auto;padding:.4rem .6rem;font-size:.82rem;border-radius:8px}
.feed-spacer{flex:1}
.feed-img-preview{position:relative;margin-top:.6rem;display:inline-block}
.feed-img-preview img{max-height:200px;border-radius:10px;display:block}
.feed-img-preview button{position:absolute;top:6px;right:6px;width:26px;height:26px;border-radius:50%;border:0;
  background:rgba(0,0,0,.6);color:#fff;cursor:pointer}
.feed-filters{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}
.feed-list{display:flex;flex-direction:column;gap:1rem}
.feed-post{padding:1rem 1.1rem}
.feed-post-head{display:flex;align-items:center;gap:.65rem}
.feed-av{flex:none}
.feed-av.sm{width:28px;height:28px}
.feed-who{flex:1;min-width:0;display:flex;flex-direction:column;gap:.1rem}
.feed-name{background:0;border:0;padding:0;font-weight:700;font-size:.95rem;color:var(--text);cursor:pointer;text-align:left}
.feed-name:hover{color:var(--brand-text)}
.feed-time{font-size:.76rem;opacity:.55}
.feed-more-btn{border:0;background:transparent;font-size:1.2rem;cursor:pointer;opacity:.6;padding:0 .3rem}
.feed-more-btn:hover{opacity:1}
.feed-tags{display:flex;gap:.4rem;flex-wrap:wrap;margin:.6rem 0 .2rem}
.feed-tag{font-size:.7rem;font-weight:700;padding:.15rem .5rem;border-radius:999px;background:var(--brand-tint);color:var(--brand-text)}
.feed-tag.alt{background:var(--pulse-tint);color:var(--pulse)}
.feed-body{margin:.6rem 0;line-height:1.55;white-space:pre-wrap;word-break:break-word}
.feed-image{margin:.6rem 0;border-radius:12px;overflow:hidden;border:1px solid var(--line)}
.feed-image img{display:block;width:100%;max-height:460px;object-fit:cover}
.feed-actions{display:flex;gap:.3rem;flex-wrap:wrap;margin-top:.5rem;border-top:1px solid var(--line);padding-top:.5rem}
.feed-act{display:inline-flex;align-items:center;gap:.35rem;border:0;background:transparent;color:var(--text-muted);
  cursor:pointer;padding:.35rem .6rem;border-radius:8px;font-size:.85rem;font-weight:600;transition:background .15s,color .15s}
.feed-act:hover{background:var(--paper)}
.feed-act.on{color:var(--pulse)}
.feed-comments{margin-top:.7rem;border-top:1px solid var(--line);padding-top:.7rem}
.feed-comment-form{display:flex;gap:.5rem;margin-bottom:.7rem}
.feed-comment{display:flex;gap:.5rem;margin-bottom:.6rem}
.feed-comment.reply{margin-left:1.6rem}
.feed-comment-main{flex:1;min-width:0}
.feed-comment-bubble{background:var(--paper);border:1px solid var(--line);border-radius:12px;padding:.45rem .7rem;font-size:.9rem;line-height:1.45;word-break:break-word}
.feed-comment-meta{display:flex;gap:.7rem;align-items:center;font-size:.74rem;opacity:.6;margin-top:.2rem;padding-left:.3rem}
.feed-comment-meta button{border:0;background:0;color:inherit;cursor:pointer;font-size:.74rem;padding:0}
.feed-comment-meta button.on{color:var(--pulse);opacity:1}
.feed-replies{margin-top:.5rem}
.feed-skel-line{height:12px;border-radius:6px;background:linear-gradient(90deg,var(--line),var(--paper-2),var(--line));
  background-size:200% 100%;animation:feedSkel 1.3s infinite;margin:.5rem 0}
@keyframes feedSkel{0%{background-position:200% 0}100%{background-position:-200% 0}}
@media (prefers-reduced-motion: reduce){ .feed-skel-line{animation:none} }

/* ===== Public profile =================================================== */
.profile-card{padding:1.4rem;margin-top:var(--sp-4)}
.profile-top{display:flex;gap:1rem;align-items:center}
.profile-av{flex:none}
.profile-name{font-size:1.5rem;margin:0}
.profile-joined{font-size:.82rem;opacity:.6;margin:.2rem 0 .4rem}
.profile-tags{display:flex;gap:.4rem;flex-wrap:wrap}
.profile-msg{margin-top:1rem;width:100%}
.profile-bio{margin-top:1rem;line-height:1.6;white-space:pre-wrap}
.profile-edit{margin-top:.8rem;display:grid;gap:.6rem;padding:.9rem;border:1px solid var(--line);border-radius:12px;background:var(--paper-2)}
.profile-stats{display:flex;gap:2rem;margin-top:1.2rem;padding-top:1rem;border-top:1px solid var(--line)}
.profile-stats div{display:flex;flex-direction:column}
.profile-stats strong{font-size:1.3rem}
.profile-stats span{font-size:.8rem;opacity:.6}
.profile-section-title{font-size:1.1rem;margin:1.6rem 0 .8rem}

/* keep an element in the layout (so labels can trigger it) but invisible */
.visually-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* moderator: full-conversation view */
.rp-thread-modal{position:fixed;inset:0;background:rgba(0,0,0,.55);display:flex;align-items:center;justify-content:center;z-index:400;padding:1rem}
.rp-thread-inner{background:var(--paper-2);border:1px solid var(--line);border-radius:14px;padding:1.2rem;max-width:560px;width:100%;max-height:80vh;overflow-y:auto}

/* admin feature toggles */
.flag-row{display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:.8rem 0;border-bottom:1px solid var(--line)}
.flag-toggle{position:relative;width:48px;height:28px;border-radius:999px;border:0;cursor:pointer;flex:none;transition:background .18s}
.flag-toggle.on{background:var(--brand)}
.flag-toggle.off{background:var(--line)}
.flag-knob{position:absolute;top:3px;left:3px;width:22px;height:22px;border-radius:50%;background:#fff;transition:transform .18s}
.flag-toggle.on .flag-knob{transform:translateX(20px)}

/* ===== Notification bell =============================================== */
.notif-bell{position:relative;display:inline-flex}
.notif-btn{position:relative;border:0;background:transparent;font-size:1.15rem;cursor:pointer;padding:.3rem .4rem;border-radius:8px;line-height:1}
.notif-btn:hover{background:var(--paper-2)}
.notif-badge{position:absolute;top:0;right:0;min-width:16px;height:16px;padding:0 4px;border-radius:999px;
  background:var(--pulse);color:var(--content-on-accent);font-size:.62rem;font-weight:800;display:flex;align-items:center;justify-content:center}
.notif-pop{position:absolute;right:0;top:calc(100% + .4rem);width:300px;max-height:400px;overflow-y:auto;
  background:var(--paper-2);border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow-lg);z-index:120}
.notif-head{padding:.7rem .9rem;font-weight:700;font-size:.85rem;border-bottom:1px solid var(--line)}
.notif-item{display:flex;flex-direction:column;gap:.15rem;padding:.6rem .9rem;border-bottom:1px solid var(--line);
  color:var(--text);text-decoration:none}
.notif-item:hover{background:var(--paper)}
.notif-item b{font-size:.88rem}
.notif-item span{font-size:.8rem;opacity:.65;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* admin inbox unread markers */
.thread-item.has-unread{background:var(--brand-tint)}
.thread-unread{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;margin-left:.3rem;border-radius:999px;background:var(--pulse);color:var(--content-on-accent);font-size:.7rem;font-weight:800;vertical-align:middle}

/* subscription expiry notice in the bell */
.notif-sub-expired b{color:var(--pulse)}
.notif-sub-ending b{color:var(--gold)}

/* ===== Google sign-in ================================================== */
.auth-divider{display:flex;align-items:center;gap:.7rem;margin:1.1rem 0;color:var(--text-muted);font-size:.82rem}
.auth-divider::before,.auth-divider::after{content:"";flex:1;height:1px;background:var(--line)}
.btn-google{display:flex;align-items:center;justify-content:center;gap:.6rem;width:100%;
  background:var(--paper-2);border:1px solid var(--line);color:var(--text);font-weight:600;
  padding:.7rem 1rem;border-radius:12px;cursor:pointer;transition:background .15s,border-color .15s}
.btn-google:hover{background:var(--paper);border-color:var(--text-muted)}
.btn-google:disabled{opacity:.6;cursor:default}
.btn-google svg{flex:none}

/* =============================================================================
   FEEDBACK PRIMITIVES — skeletons, empty states, inline status
   Perceived speed is most of perceived quality. Every Supabase round-trip in
   this app previously rendered nothing until data landed; these give the UI
   something honest to show while it waits, and something useful to say when
   there is genuinely nothing to show.
   ========================================================================== */

/* --- Skeletons ---------------------------------------------------------- */
.skel {
  position: relative; overflow: hidden;
  background: var(--surface-sunken);
  border-radius: var(--r-sm);
}
.skel::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg,
    transparent,
    color-mix(in srgb, var(--surface-raised) 85%, transparent),
    transparent);
  transform: translateX(-100%);
  animation: skelSweep 1.4s var(--ease) infinite;
}
@keyframes skelSweep { to { transform: translateX(100%); } }

.skel-line { height: .75rem; margin-bottom: .55rem; }
.skel-line:last-child { margin-bottom: 0; }
.skel-line.w-40 { width: 40%; } .skel-line.w-60 { width: 60%; }
.skel-line.w-75 { width: 75%; } .skel-line.w-90 { width: 90%; }
.skel-title { height: 1.15rem; width: 45%; margin-bottom: .8rem; border-radius: var(--r-sm); }
.skel-card {
  border: 1px solid var(--border-subtle); border-radius: var(--r-lg);
  background: var(--surface-raised); padding: var(--sp-5);
}
.skel-avatar { width: 44px; height: 44px; border-radius: var(--r-pill); flex: none; }
.skel-row { display: flex; align-items: center; gap: .8rem; }

/* Respect reduced motion: hold a static tone rather than sweeping. */
@media (prefers-reduced-motion: reduce) {
  .skel::after { animation: none; opacity: .5; }
}

/* --- Empty states ------------------------------------------------------- */
.empty {
  display: grid; place-items: center; text-align: center;
  padding: var(--sp-7) var(--sp-5);
  border: 1px dashed var(--border-default); border-radius: var(--r-lg);
  background: var(--surface-raised);
}
.empty-ic {
  width: 48px; height: 48px; display: grid; place-items: center;
  border-radius: var(--r-pill); margin-bottom: var(--sp-4);
  background: var(--brand-tint); color: var(--content-brand);
}
.empty-ic svg { width: 24px; height: 24px; }
.empty h3 { font-size: 1.05rem; margin-bottom: var(--sp-2); }
.empty p { font-size: .9rem; color: var(--content-muted); max-width: 42ch; margin-inline: auto; }
.empty .btn { margin-top: var(--sp-5); }

/* Failure is not emptiness — it needs a different colour and a way out. */
.empty.is-error { border-color: color-mix(in srgb, var(--feedback-danger) 45%, transparent); border-style: solid; }
.empty.is-error .empty-ic { background: color-mix(in srgb, var(--feedback-danger) 14%, transparent); color: var(--feedback-danger); }

/* --- Inline status ------------------------------------------------------ */
.status {
  display: flex; align-items: flex-start; gap: .6rem;
  padding: .7rem .9rem; border-radius: var(--r-md);
  border: 1px solid var(--border-default); background: var(--surface-raised);
  font-size: .88rem; line-height: 1.45;
}
.status svg { width: 18px; height: 18px; flex: none; margin-top: .1rem; }
.status.is-success { border-color: color-mix(in srgb, var(--feedback-success) 45%, transparent); background: color-mix(in srgb, var(--feedback-success) 9%, var(--surface-raised)); color: var(--feedback-success); }
.status.is-error   { border-color: color-mix(in srgb, var(--feedback-danger) 45%, transparent);  background: color-mix(in srgb, var(--feedback-danger) 9%, var(--surface-raised));  color: var(--feedback-danger); }
.status.is-warning { border-color: color-mix(in srgb, var(--feedback-warning) 45%, transparent); background: color-mix(in srgb, var(--feedback-warning) 9%, var(--surface-raised)); color: var(--feedback-warning); }
.status.is-info    { border-color: color-mix(in srgb, var(--feedback-info) 45%, transparent);    background: color-mix(in srgb, var(--feedback-info) 9%, var(--surface-raised));    color: var(--feedback-info); }
.status b { color: var(--content-primary); display: block; }

/* --- Button busy state -------------------------------------------------- */
.btn.is-busy { position: relative; color: transparent !important; pointer-events: none; }
.btn.is-busy::after {
  content: ""; position: absolute; inset: 0; margin: auto;
  width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid currentColor; border-top-color: transparent;
  color: var(--content-on-accent);
  animation: btnSpin .6s linear infinite;
}
.btn-secondary.is-busy::after, .btn-ghost.is-busy::after { color: var(--content-primary); }
@keyframes btnSpin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .btn.is-busy::after { animation-duration: 2s; } }

/* Small layout helpers — used by JS-rendered markup so it needn't inline styles. */
.input-narrow { width: 140px; max-width: 100%; }
.mt-2 { margin-top: var(--sp-2); }
.mt-3 { margin-top: var(--sp-3); }
.mt-4 { margin-top: var(--sp-4); }

/* =============================================================================
   CHALLENGES WIDGET (challenges-ui.js) — shared across pages.
   Reuses the .chal-* progress language from the dashboard so the same object
   looks the same everywhere it appears.
   ========================================================================== */
.cui-head { margin: 0 0 .2rem; font-size: 1.2rem; }
.cui-sub { margin: 0 0 .8rem; font-size: .9rem; color: var(--content-muted); }
.cui-medals { display: flex; flex-wrap: wrap; gap: .9rem; margin-bottom: var(--sp-4); align-items: flex-start; }
.cui-card { padding: var(--sp-4); margin-bottom: .7rem; }
.cui-top { display: flex; justify-content: space-between; align-items: center; gap: .5rem; }
.cui-mods { font-size: .85rem; color: var(--content-muted); margin: .3rem 0 .1rem; }
.cui-mods.is-tight { font-size: .8rem; margin: .2rem 0 .5rem; }
.cui-note { font-size: .78rem; color: var(--content-muted); }
.cui-cta { margin-top: .5rem; }
.cui-bar { height: 10px; border-radius: var(--r-pill); background: var(--surface-sunken); overflow: hidden; }
.cui-bar > i { display: block; height: 100%; background: var(--pulse); transition: width .5s var(--ease-out), background .3s; }
.cui-card.is-earned .cui-bar > i { background: var(--brand); }
.cui-pct { font-size: .78rem; color: var(--content-muted); margin-top: .35rem; font-family: var(--font-mono); }

/* Full-width note inside the booking slot grid (was an inline grid-column). */
.bk-note-full { grid-column: 1 / -1; }
