/* =====================================================================
   AskProf mobile app layer
   Implements design_handoff_askprof_mobile/: chat-first bottom-tab app
   chrome, slide-over history sheet, full-screen onboarding, bottom-sheet
   artifacts and the dark theme. Loaded AFTER styles.css on app pages;
   desktop (>900px) is intentionally untouched except for a handful of
   shared components marked "global" below.
   ===================================================================== */

/* ------------------------- Dark theme tokens -------------------------
   Derived from the sidebar navy #0e2233 (see handoff README 1k/1l), not a
   generic gray. Scoped to <=900px: the dark screens were only designed for
   the mobile app, and the Appearance control only exists in the mobile UI.
   Auto = no data-theme attribute -> the OS decides; the profile control
   forces 'light' or 'dark' via js/theme.js. */
@media (max-width: 900px) and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0b1a29;
    --surface: #12283a;
    --surface-2: #1a3348;
    --line: rgba(255, 255, 255, .09);
    --ink: #e9f1f9;
    --ink-soft: #b6c6d6;
    --muted: #7f95a9;
    --primary-soft: #1c3a57;
    --primary-700: #8fc2f7;
    --accent-soft: rgba(247, 144, 30, .16);
    --danger-soft: rgba(226, 59, 78, .16);
  }
}
@media (max-width: 900px) {
  :root[data-theme="dark"] {
    --bg: #0b1a29;
    --surface: #12283a;
    --surface-2: #1a3348;
    --line: rgba(255, 255, 255, .09);
    --ink: #e9f1f9;
    --ink-soft: #b6c6d6;
    --muted: #7f95a9;
    --primary-soft: #1c3a57;
    --primary-700: #8fc2f7;
    --accent-soft: rgba(247, 144, 30, .16);
    --danger-soft: rgba(226, 59, 78, .16);
  }
}

/* Dark fixups for hardcoded colours. .dark-ui is stamped on <html> by
   js/theme.js consumers?—no: it is pure CSS. We repeat the two selector forms
   because CSS variables cannot express "when dark". Keep this list short. */
@media (max-width: 900px) {
  /* Brand "Ask" reads too dark on navy; use the existing sidebar value. */
  :root[data-theme="dark"] .brand-name .ask { color: #6db1f5; }
  :root[data-theme="dark"] .tabbar { background: #0e2233; }
  :root[data-theme="dark"] .msg .content pre { background: #0a1622; border: 1px solid var(--line); }
  :root[data-theme="dark"] .quiz-option.correct { background: rgba(24, 165, 88, .16); }
  :root[data-theme="dark"] .quiz-feedback.good { background: rgba(24, 165, 88, .16); color: #7fd7a8; }
  :root[data-theme="dark"] .quiz-feedback.bad { background: rgba(226, 59, 78, .16); color: #f2a1ab; }
  :root[data-theme="dark"] .alert-success { background: rgba(24, 165, 88, .16); color: #7fd7a8; border-color: rgba(24,165,88,.3); }
  :root[data-theme="dark"] .alert-error { background: rgba(226, 59, 78, .16); color: #f2a1ab; border-color: rgba(226,59,78,.3); }
  :root[data-theme="dark"] .followup-chip,
  :root[data-theme="dark"] .artifact-btn { background: rgba(31, 122, 224, .18); border-color: rgba(109, 177, 245, .35); }
  :root[data-theme="dark"] .oauth-btn img, :root[data-theme="dark"] .side-sponsor img,
  :root[data-theme="dark"] .sponsor-credit img { background: #fff; border-radius: 4px; }
}
@media (max-width: 900px) and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .brand-name .ask { color: #6db1f5; }
  :root:not([data-theme="light"]) .tabbar { background: #0e2233; }
  :root:not([data-theme="light"]) .msg .content pre { background: #0a1622; border: 1px solid var(--line); }
  :root:not([data-theme="light"]) .quiz-option.correct { background: rgba(24, 165, 88, .16); }
  :root:not([data-theme="light"]) .quiz-feedback.good { background: rgba(24, 165, 88, .16); color: #7fd7a8; }
  :root:not([data-theme="light"]) .quiz-feedback.bad { background: rgba(226, 59, 78, .16); color: #f2a1ab; }
  :root:not([data-theme="light"]) .alert-success { background: rgba(24, 165, 88, .16); color: #7fd7a8; border-color: rgba(24,165,88,.3); }
  :root:not([data-theme="light"]) .alert-error { background: rgba(226, 59, 78, .16); color: #f2a1ab; border-color: rgba(226,59,78,.3); }
  :root:not([data-theme="light"]) .followup-chip,
  :root:not([data-theme="light"]) .artifact-btn { background: rgba(31, 122, 224, .18); border-color: rgba(109, 177, 245, .35); }
  :root:not([data-theme="light"]) .oauth-btn img, :root:not([data-theme="light"]) .side-sponsor img,
  :root:not([data-theme="light"]) .sponsor-credit img { background: #fff; border-radius: 4px; }
}

/* ------------------------- Shared components (global) -------------------------
   Used on desktop too: the quiz progress strip, redesigned flashcards and the
   streak hero render inside existing pages/modals at every width. */

/* Quiz progress strip: one segment per question.
   done-good = answered correctly, done-bad = wrong, current, todo. */
.quiz-progress { display: flex; gap: 4px; margin: 0 0 16px; }
.quiz-progress span { flex: 1; height: 4px; border-radius: 99px; background: var(--surface-2); }
.quiz-progress span.done-good { background: var(--success); }
.quiz-progress span.done-bad { background: var(--danger); }
.quiz-progress span.current { background: var(--primary); }

/* Flashcards: stacked-deck card, progress dots, spaced-repetition actions. */
.flashcard-stack { position: relative; margin: 4px 0 0; }
.flashcard-stack::before {
  content: ''; position: absolute; inset: 10px -8px -8px 10px;
  background: var(--accent-soft); border-radius: 18px; transform: rotate(2.5deg);
}
.flashcard-stack.flipped::before { background: var(--primary-soft); transform: rotate(-2.5deg); }
.flashcard {
  position: relative; min-height: 220px; border-radius: 18px;
  border: 1px solid #c5ddf7; box-shadow: var(--shadow);
  padding: 30px;
}
.flashcard.flipped { border-color: var(--line); }
.flashcard-label {
  font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--primary); margin-bottom: 14px;
}
.flashcard.flipped .flashcard-label { color: var(--accent-600); }
.flashcard-side { font-family: var(--font-display); font-size: 19px; line-height: 1.4; font-weight: 600; }
.flashcard-dots { display: flex; justify-content: center; align-items: center; gap: 5px; margin: 20px 0 4px; flex-wrap: wrap; }
.flashcard-dots span { width: 6px; height: 6px; border-radius: 50%; background: var(--line); }
.flashcard-dots span.done { background: var(--primary); }
.flashcard-dots span.current { width: 18px; border-radius: 99px; background: var(--accent); }
.flashcard-actions { display: flex; gap: 12px; width: 100%; }
.flashcard-actions .btn { flex: 1; }
.btn-success { background: var(--success); color: #fff; }
.btn-success:hover { filter: brightness(.95); text-decoration: none; }
.flashcard-done { text-align: center; padding: 26px 0 10px; }
.flashcard-done .big { font-size: 42px; margin-bottom: 8px; }
/* "Still learning" / "Got it" split the footer half-and-half (design 1h). */
.flashcards-full .modal-foot .btn { flex: 1; }

/* Streak hero (progress page). */
.streak-hero {
  display: flex; align-items: center; gap: 14px;
  background: linear-gradient(120deg, var(--primary), var(--primary-700));
  border-radius: 16px; padding: 16px 18px; color: #fff;
  box-shadow: 0 8px 30px rgba(16, 32, 52, .18); margin-bottom: 18px;
}
/* The gradient must stay on-brand in dark mode, where --primary-700 becomes a
   pale text colour rather than a deep blue. */
:root[data-theme="dark"] .streak-hero { background: linear-gradient(120deg, #1f7ae0, #0f5099); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .streak-hero { background: linear-gradient(120deg, #1f7ae0, #0f5099); } }
.streak-hero .flame { font-size: 30px; }
.streak-hero .sh-num { font-family: var(--font-display); font-weight: 800; font-size: 22px; line-height: 1.25; color: #fff; }
.streak-hero .sh-sub { font-size: 12.5px; color: rgba(255, 255, 255, .85); }

/* Convo list date-group headers (chat sidebar / history sheet). */
.convo-group {
  font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: #6b8198; padding: 12px 8px 5px;
}

/* Reporting AI responses (Google Play AI-content requirement) — shared by
   desktop and mobile. Deliberately quieter than the thumbs: it sits in the
   same row but reads as a link, so it is discoverable without inviting
   accidental taps. */
.report-btn {
  background: none; border: none; cursor: pointer;
  padding: 3px 8px; border-radius: 999px; margin-left: 2px;
  font: 500 12.5px var(--font-body); color: var(--muted);
  transition: background .12s, color .12s;
}
.report-btn:hover { background: var(--danger-soft); color: var(--danger); }

.report-reasons { display: flex; flex-direction: column; gap: 8px; margin: 0 0 14px; }
.report-reason {
  display: flex; align-items: flex-start; gap: 11px; cursor: pointer;
  border: 1px solid var(--line); border-radius: 12px; padding: 11px 13px;
  transition: border-color .12s, background .12s;
}
.report-reason:hover { border-color: var(--primary); background: var(--primary-soft); }
.report-reason input { margin: 2px 0 0; flex: none; accent-color: var(--primary); }
.report-reason b { display: block; font-size: 14px; font-weight: 600; }
.report-reason small { display: block; font-size: 12px; color: var(--muted); line-height: 1.4; }
/* `.selected` is set by js/chat.js and is the load-bearing one; `:has()` is
   only progressive enhancement. Two reasons not to rely on :has() alone:
   Android WebView below Chrome 105 does not support it at all, and style
   invalidation is unreliable when `checked` is set programmatically rather
   than by a real tap — which left the chosen reason visually unmarked. */
.report-reason.selected,
.report-reason:has(input:checked) { border-color: var(--primary); background: var(--primary-soft); }

/* Photo the user attached, shown inside their own message bubble. Previously
   nothing was rendered, so a caption + photo looked like a plain text send. */
.msg-image {
  display: block; max-width: 100%; width: auto; max-height: 260px;
  border-radius: 12px; margin: 0 0 8px; border: 1px solid var(--line);
}
.msg-images { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; }
/* Several photos share the row, so cap each one rather than letting the first
   fill the bubble and push the rest onto their own lines. */
.msg-images .msg-image { margin: 0; max-width: 46%; max-height: 180px; }
.msg-images:has(.msg-image:only-child) .msg-image { max-width: 100%; max-height: 260px; }
.msg.user .content .msg-images { justify-content: flex-end; }

/* Composer thumbnail strip: horizontally scrollable so three photos never
   push the text box off screen on a narrow phone. */
.img-preview-wrap { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 4px; }
.img-preview-wrap.hidden { display: none; }
.img-preview-wrap .img-preview-inner { flex: none; }
.img-preview-wrap .img-preview-inner img { max-height: 92px; max-width: 120px; }
/* The image button while a large photo is decoding/re-encoding. */
.img-btn.busy { opacity: .5; pointer-events: none; }

/* "Add a photo" source sheet (native builds). */
.source-opt {
  display: flex; align-items: center; gap: 13px; width: 100%; text-align: left;
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
  padding: 14px 15px; margin-bottom: 10px; cursor: pointer;
  font-family: var(--font-body); color: var(--ink);
  transition: border-color .12s, background .12s;
}
.source-opt:hover { border-color: var(--primary); background: var(--primary-soft); }
.source-opt .source-ic {
  flex: none; width: 42px; height: 42px; border-radius: 11px; display: grid;
  place-items: center; background: var(--primary-soft); color: var(--primary-700);
}
.source-opt b { display: block; font-size: 15px; font-weight: 600; }
.source-opt small { display: block; font-size: 12.5px; color: var(--muted); }

/* Classes page (design 1i) — shared by desktop and mobile. */
.section-label {
  font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted); padding: 6px 4px 8px;
}
.class-tile {
  flex: none; width: 42px; height: 42px; border-radius: 11px;
  display: grid; place-items: center; font-family: var(--font-display);
  font-weight: 700; font-size: 14px; background: var(--primary-soft); color: var(--primary-700);
}
.class-tile.alt { background: var(--accent-soft); color: var(--accent-600); }
.enrolled-row { padding: 0; overflow: hidden; margin-bottom: 10px; }
.enrolled-main { display: flex; align-items: center; gap: 13px; padding: 15px 16px; cursor: pointer; }
.enrolled-info { flex: 1; min-width: 0; }
.enrolled-name { font-weight: 600; font-size: 14.5px; }
.enrolled-sub { font-size: 12px; color: var(--muted); }
.enrolled-chev { color: var(--muted); flex: none; transition: transform .15s; }
.enrolled-row.open .enrolled-chev { transform: rotate(90deg); }
.enrolled-actions { display: flex; align-items: center; gap: 8px; padding: 0 16px 14px; }
.create-class-row {
  display: block; width: 100%; border: 1px dashed var(--line); background: none;
  border-radius: 14px; padding: 13px; text-align: center; font: 600 13.5px var(--font-body);
  color: var(--primary); cursor: pointer; margin-bottom: 22px;
}
.create-class-row:hover { border-color: var(--primary); }

/* ------------------- Safe areas on tablets (>900px) -------------------
   styles.css scopes its safe-area padding to max-width:900px, on the
   assumption that "the app lives below 900px". A tablet breaks that: a 10"
   device is ~960dp, so it gets the DESKTOP layout while still being a real
   device with a status bar and gesture bar. The result was the sidebar brand
   rendering underneath the status bar.

   env(safe-area-inset-*) is 0 in a desktop browser, so every calc() here
   collapses to the value it already had — this changes nothing on desktop.
   These live in mobile.css (loaded after styles.css) so the padding-top wins
   over the `padding: 0` shorthand styles.css sets on a fresh chat's topbar. */
@media (min-width: 901px) {
  .chat-side .side-top { padding-top: calc(16px + env(safe-area-inset-top)); }
  .chat-topbar { padding-top: calc(10px + env(safe-area-inset-top)); }
  .chat-topbar:not(.has-actions) { padding-top: env(safe-area-inset-top); }
  .composer { padding-bottom: calc(14px + env(safe-area-inset-bottom)); }
  /* Only the LAST element in the sidebar takes the bottom inset — .side-user
     sits above .side-sponsor, so padding both would open a gap between them. */
  .side-sponsor { padding-bottom: calc(10px + env(safe-area-inset-bottom)); }
  .nav { padding-top: env(safe-area-inset-top); }
  .page { padding-top: calc(40px + env(safe-area-inset-top)); }
}

/* Utility: mobile-only chrome. */
.mobile-only { display: none; }
/* Mobile chrome that must never render on desktop, whatever classes it has. */
.tabbar { display: none; }
.onboard-flow { display: none; }

/* =====================================================================
   Mobile app chrome (<= 900px)
   ===================================================================== */
@media (max-width: 900px) {
  .mobile-only { display: block; }
  .desktop-only { display: none !important; }

  /* ------------------------- Bottom tab bar ------------------------- */
  .tabbar {
    display: flex; background: var(--surface); border-top: 1px solid var(--line);
    padding: 7px 8px calc(2px + env(safe-area-inset-bottom));
    z-index: 40;
  }
  .tabbar.tabbar-fixed { position: fixed; left: 0; right: 0; bottom: 0; }
  .tabbar .tab {
    flex: 1; display: flex; flex-direction: column; align-items: center; gap: 3px;
    padding: 4px 0 2px; font-size: 10.5px; font-weight: 600; color: var(--muted);
    text-decoration: none; border-radius: 10px;
  }
  .tabbar .tab:hover { text-decoration: none; }
  .tabbar .tab.active { color: var(--primary); }
  .tabbar .tab svg { width: 22px; height: 22px; }
  /* Pages with a fixed tab bar need the content to clear it. height:auto is
     load-bearing: styles.css sets body{height:100%}, which pins the body box
     (and therefore this padding) to viewport height while the content
     overflows past it — so the last panel scrolled in BEHIND the tab bar.
     Letting the body grow puts the padding after the real end of content. */
  body.has-tabbar {
    height: auto;
    min-height: 100%;
    padding-bottom: calc(76px + env(safe-area-inset-bottom));
  }
  /* In an active conversation the tab bar yields to the composer (design 1d). */
  body.in-conversation .tabbar { display: none; }

  /* ------------------------- Chat top bar ------------------------- */
  .chat-topbar { gap: 6px; padding-left: 14px; padding-right: 14px; }
  .topbar-icon {
    flex: none; width: 40px; height: 40px; display: grid; place-items: center;
    background: none; border: none; border-radius: 12px; color: var(--ink-soft);
    cursor: pointer; padding: 0;
  }
  .topbar-icon:active { background: var(--surface-2); }
  .topbar-center { flex: 1; min-width: 0; text-align: center; }
  .topbar-center .brand-name { font-size: 20px; }
  .topbar-title .t {
    font-family: var(--font-display); font-weight: 600; font-size: 14.5px; color: var(--ink);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 220px; margin: 0 auto;
  }
  .topbar-title .s { font-size: 11px; color: var(--muted); line-height: 1.3; }
  /* Balance the 40px history button on the left so the centered brand/title
     stays centered even when the right side has no visible action (fresh
     chat: the new-chat pen only appears once a conversation is open). */
  .chat-topbar .topbar-actions { margin-left: 0; min-width: 40px; justify-content: flex-end; }
  /* The old bordered hamburger chrome does not exist in this design. */
  .hamburger { border: none; font-size: 0; }
  /* Share becomes a 40px icon button (design 1d); the pill text is desktop-only. */
  .topbar-btn {
    width: 40px; height: 40px; padding: 0; justify-content: center;
    background: none; border: none; color: var(--ink-soft);
  }
  .topbar-btn:hover { background: var(--surface-2); }
  .share-txt { display: none; }
  /* The identity-row streak badge is a pill, not a block. */
  .side-user .streak-badge { display: inline-flex; }

  /* ------------------------- History sheet ------------------------- */
  /* The dark desktop sidebar becomes a light slide-over sheet (design 1e). */
  .chat-side {
    width: 82%; max-width: 330px; background: var(--surface); color: var(--ink);
    border-radius: 0 22px 22px 0; box-shadow: var(--shadow-lg);
  }
  .side-overlay { background: rgba(10, 20, 32, .45); }
  .chat-side .side-top {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    border-bottom: none; padding-bottom: 6px;
  }
  .chat-side .brand-name { color: var(--ink); font-size: 19px; }
  .chat-side .brand-name .ask { color: var(--primary); }
  .side-new {
    width: auto; margin-top: 0; border-radius: 999px; padding: 8px 15px;
    font-size: 13px; white-space: nowrap;
  }
  .side-search { padding: 4px 14px 8px; }
  .side-search-input {
    background: var(--surface-2); border: none; border-radius: 11px; padding: 9px 12px;
    color: var(--ink);
  }
  .side-search-input::placeholder { color: var(--muted); }
  .convo-group { color: var(--muted); }
  .convo-item { color: var(--ink-soft); border-radius: 11px; padding: 11px 12px; }
  .convo-item:hover { background: var(--surface-2); }
  .convo-item.active { background: var(--primary-soft); color: var(--primary-700); font-weight: 600; }
  .convo-del { color: var(--muted); opacity: .55; }
  .convo-del:hover { color: var(--ink); background: var(--surface-2); }
  .side-list .empty { color: var(--muted); }
  /* Progress lives in the tab bar now; the sheet keeps install + identity. */
  .side-progress-row { display: none; }
  .side-nav-row { color: var(--ink-soft); border-top: 1px solid var(--line); }
  .side-nav-row:hover { background: var(--surface-2); color: var(--ink); }
  .side-install { color: var(--success); }
  .side-user { border-top: 1px solid var(--line); padding: 12px 14px 10px 16px; }
  .side-user-main { color: var(--ink); }
  .side-user-main:hover { background: var(--surface-2); }
  .side-user-name { font-size: 13.5px; }
  .side-signout { color: var(--muted); }
  .side-signout:hover { background: var(--surface-2); color: var(--ink); }
  .streak-badge { background: rgba(247, 144, 30, .12); color: var(--accent-600); }
  .streak-badge b { color: var(--ink); }
  .side-sponsor { border-top: 1px solid var(--line); color: var(--muted); }
  .side-sponsor b { color: var(--ink-soft); }

  /* ------------------------- Chat welcome (home) ------------------------- */
  .messages { display: flex; flex-direction: column; }
  .welcome {
    flex: 1; display: flex; flex-direction: column; justify-content: center;
    padding: 20px 22px; margin: 0 auto; width: 100%;
  }
  .welcome img { width: 76px; margin-bottom: 12px; }
  .welcome h2 { font-size: 23px; margin: 0; }
  .welcome p { font-size: 14px; margin: 5px 0 24px; }
  .suggest { grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 0; }
  .suggest button { border-radius: 14px; padding: 13px 14px; }
  .suggest button b { font-size: 13.5px; margin-bottom: 2px; }
  .suggest button span { font-size: 12px; color: var(--muted); line-height: 1.45; display: block; }

  /* ------------------------- Composer ------------------------- */
  .composer { background: var(--bg); border-top: none; padding: 8px 0; }
  body.in-conversation .composer { padding-bottom: calc(14px + env(safe-area-inset-bottom)); }
  .composer .container { padding: 0 14px; }
  .composer-box {
    border-radius: 22px; padding: 8px 8px 8px 6px; gap: 6px;
    box-shadow: var(--shadow-sm);
  }
  .composer-box textarea { padding-left: 2px; }
  .img-btn, .mic-btn { width: 40px; height: 40px; padding: 0; flex: none; }
  .mic-btn {
    background: none; border: none; cursor: pointer; color: var(--muted);
    border-radius: 8px; display: grid; place-items: center;
    transition: color .15s, background .15s;
  }
  .mic-btn:hover { color: var(--primary); background: var(--primary-soft); }
  .send-btn { width: 40px; height: 40px; border-radius: 14px; }
  .composer .hint { display: none; }
  .track-bar { margin: 0 4px 8px; }
  .artifact-bar { margin: 0 4px 8px; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  .artifact-bar::-webkit-scrollbar { display: none; }
  .artifact-btn { white-space: nowrap; padding: 6px 12px; font-size: 12.5px; }

  /* ------------------------- Messages ------------------------- */
  .messages { padding: 12px 0; }
  .messages .container { padding: 0 16px; }
  .msg { gap: 10px; margin-bottom: 16px; }
  .msg .who { display: none; }
  .msg .body { padding-top: 0; font-size: 14.5px; }
  .msg .content { line-height: 1.62; }
  .msg.assistant .avatar { width: 30px; height: 30px; border-radius: 9px; padding: 3px; }
  .msg.user .avatar { display: none; }
  .msg.user .body { max-width: 80%; }
  .msg.user .content { padding: 11px 15px; border-radius: 18px 18px 5px 18px; font-size: 14.5px; line-height: 1.55; }
  /* Formula/code block: white card with brand-blue mono text (design 1d). */
  .msg .content pre {
    background: var(--surface); color: var(--primary-700);
    border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px;
  }
  .msg .content pre code { color: inherit; }
  .source-label { font-size: 11.5px; }
  .followup-chips { padding-left: 40px; }
  .followup-chip { font-size: 12.5px; padding: 7px 14px; }

  /* ------------------------- Bottom sheets (modals) ------------------------- */
  .modal-host { padding: 0; align-items: end; }
  .modal-host.show { display: flex; flex-direction: column; justify-content: flex-end; }
  .modal {
    max-width: none; width: 100%; max-height: 88dvh;
    border-radius: 22px 22px 0 0; padding-top: 6px;
    animation: sheet-up .25s ease;
  }
  .modal::before {
    content: ''; display: block; width: 38px; height: 5px; border-radius: 99px;
    background: var(--line); margin: 6px auto 2px;
  }
  .modal-head { border-bottom: none; padding: 10px 20px 6px; }
  .modal-body { padding: 10px 20px 16px; }
  .modal-foot {
    border-top: none; padding: 4px 20px calc(20px + env(safe-area-inset-bottom));
  }
  /* A sheet with no footer has nothing carrying the bottom inset, so its last
     row ends up under the gesture bar — seen on the "Add a photo" sheet, where
     "Choose from photos" was half-hidden behind the navigation buttons. */
  .modal-host .modal:not(:has(.modal-foot)) .modal-body {
    padding-bottom: calc(16px + env(safe-area-inset-bottom));
  }
  /* Same, without :has() — Android WebView below Chrome 105 ignores the rule
     above, and this sheet is native-only so old WebViews matter here. */
  #imgSourceModal .modal-body {
    padding-bottom: calc(16px + env(safe-area-inset-bottom));
  }
  .modal-foot .btn { border-radius: 999px; padding: 13px 20px; }
  @keyframes sheet-up { from { transform: translateY(40px); opacity: .6; } to { transform: translateY(0); opacity: 1; } }
  /* Flashcards go full screen rather than sheet (design 1h). */
  .modal-host.flashcards-full { align-items: stretch; }
  .modal-host.flashcards-full .modal {
    max-height: none; height: 100dvh; border-radius: 0;
    padding-top: calc(6px + env(safe-area-inset-top));
    display: flex; flex-direction: column;
  }
  .modal-host.flashcards-full .modal::before { display: none; }
  .modal-host.flashcards-full .modal-body {
    flex: 1; display: flex; flex-direction: column; justify-content: center; padding: 0 24px;
  }
  .modal-host.flashcards-full .flashcard { min-height: 280px; display: grid; place-items: center; text-align: center; }

  /* ------------------------- Auth (sign in / sign up) ------------------------- */
  .auth-wrap { display: flex; flex-direction: column; padding: 20px 28px; }
  .auth-card {
    background: none; border: none; box-shadow: none; padding: 0;
    max-width: 400px; margin: auto;
  }
  .auth-card .brand { display: block; text-align: center; }
  .auth-card .brand img { height: auto; width: 96px; margin: 0 auto 10px; }
  .auth-card h1 { text-align: center; font-size: 26px; font-weight: 800; margin: 0; }
  .auth-card .sub { text-align: center; font-size: 14px; margin: 4px 0 26px; }
  .auth-card .input { border-radius: 12px; padding: 13px 15px; background: var(--surface); }
  /* That shorthand resets the padding-right styles.css reserves for the
     show/hide toggle, which would leave typed text running under the icon.
     Higher specificity so it wins regardless of file order. */
  .auth-card .pw-wrap .input { padding-right: 46px; }
  .auth-card .btn-block {
    border-radius: 999px; padding: 14px; font-size: 15px;
    box-shadow: 0 8px 30px rgba(31, 122, 224, .25);
  }
  .oauth-row { flex-direction: row; }
  .oauth-btn { border-radius: 12px; padding: 12px; background: var(--surface); }
  .auth-sponsor { margin-top: auto; padding: 22px 0 6px; font-size: 11px; }

  /* ------------------------- Onboarding (full-screen, 3 steps) ------------------------- */
  .onboard-flow {
    position: fixed; inset: 0; z-index: 95; background: var(--bg);
    display: none; flex-direction: column;
    padding-top: calc(8px + env(safe-area-inset-top));
  }
  .onboard-flow.show { display: flex; }
  .ob-head { display: flex; align-items: center; gap: 12px; padding: 12px 20px 4px; }
  .ob-back { background: none; border: none; padding: 4px; cursor: pointer; color: var(--ink-soft); display: grid; place-items: center; }
  .ob-back.hidden-step { visibility: hidden; }
  .ob-pills { display: flex; gap: 5px; flex: 1; justify-content: center; }
  .ob-pills span { width: 22px; height: 5px; border-radius: 99px; background: var(--line); }
  .ob-pills span.on { background: var(--primary); }
  .ob-skip { background: none; border: none; font-size: 13px; font-weight: 600; color: var(--muted); cursor: pointer; font-family: var(--font-body); }
  .ob-body { flex: 1; min-height: 0; overflow: auto; padding: 22px 24px; }
  .ob-body h2 { font-size: 24px; line-height: 1.25; margin: 0; }
  .ob-body .ob-sub { font-size: 14px; color: var(--ink-soft); margin: 6px 0 20px; }
  .ob-cards { display: flex; flex-direction: column; gap: 10px; }
  .ob-card {
    display: flex; align-items: center; gap: 14px; text-align: left; width: 100%;
    background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
    padding: 15px 16px; cursor: pointer; font-family: var(--font-body); color: var(--ink);
  }
  .ob-card.selected { border: 2px solid var(--primary); padding: 14px 15px; box-shadow: 0 0 0 3px var(--primary-soft); }
  .ob-card .ob-ic {
    flex: none; width: 40px; height: 40px; border-radius: 10px;
    display: grid; place-items: center; font-family: var(--font-display);
    font-weight: 700; font-size: 12px; background: var(--surface-2); color: var(--ink-soft);
  }
  .ob-card.selected .ob-ic { background: var(--primary-soft); color: var(--primary-700); }
  .ob-card .ob-main { flex: 1; min-width: 0; }
  .ob-card .ob-title { font-weight: 600; font-size: 15px; }
  .ob-card .ob-note { font-size: 12.5px; color: var(--muted); }
  .ob-card .ob-check {
    flex: none; width: 22px; height: 22px; border-radius: 50%; background: var(--primary);
    display: none; place-items: center; color: #fff;
  }
  .ob-card.selected .ob-check { display: grid; }
  .ob-section-label { font-weight: 600; font-size: 13px; margin: 22px 0 8px; color: var(--ink-soft); }
  .ob-chips { display: flex; flex-wrap: wrap; gap: 8px; }
  .ob-chip {
    background: var(--surface); border: 1px solid var(--line); color: var(--ink-soft);
    border-radius: 999px; padding: 9px 16px; font-size: 13.5px; font-family: var(--font-body);
    cursor: pointer;
  }
  .ob-chip.selected { background: var(--primary-soft); border-color: var(--primary); color: var(--primary-700); font-weight: 600; }
  .ob-foot { padding: 10px 24px calc(18px + env(safe-area-inset-bottom)); }
  .ob-continue {
    width: 100%; background: var(--primary); color: #fff; border: none; border-radius: 999px;
    padding: 15px; font: 600 15px var(--font-body); cursor: pointer;
  }
  .ob-continue:disabled { opacity: .55; }

  /* ------------------------- Tab pages (progress/classes/profile) ------------------------- */
  .nav { display: none; }
  footer.site { display: none; }
  .page { padding: calc(10px + env(safe-area-inset-top)) 0 26px; }
  .page h1 { font-size: 24px; font-weight: 800; }
  .page .sub { font-size: 12.5px; color: var(--muted); margin-bottom: 16px; }
  .panel { border-radius: 14px; padding: 16px; margin-bottom: 12px; }
  .panel h2 { font-size: 15px; }
  .panel .panel-sub { font-size: 12px; margin-bottom: 12px; }

  /* Progress */
  .stat-cards { grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 12px; }
  .stat { border-radius: 14px; padding: 14px 16px; }
  .stat .k { font-size: 11px; }
  .stat .v { font-size: 26px; margin-top: 2px; }
  .stat-hint { display: none; }
  #weakQuizBtn { width: 100%; border-radius: 999px; padding: 12px; margin-top: 6px; }

  /* Classes: compact the teacher-card stats into the mini tiles (design 1i). */
  .join-code { font-size: 15px; padding: 7px 12px; border-radius: 9px; }
  .class-detail .stat-cards { display: flex; gap: 8px; margin: 12px 0; }
  .class-detail .stat {
    flex: 1; background: var(--surface-2); border: none; box-shadow: none;
    border-radius: 10px; padding: 10px; text-align: center;
  }
  .class-detail .stat .k { font-size: 10.5px; text-transform: none; letter-spacing: 0; }
  .class-detail .stat .v { font-size: 17px; margin-top: 0; }

  /* Profile */
  .profile-head { display: flex; align-items: center; gap: 14px; padding: 6px 4px 14px; }
  .profile-head .avatar-initials { width: 58px; height: 58px; font-size: 20px; }
  .profile-head .ph-name { font-family: var(--font-display); font-weight: 700; font-size: 19px; }
  .profile-head .ph-meta { font-size: 12.5px; color: var(--muted); }
  /* Collapsible panels: tapping the heading opens the body (grouped-list feel). */
  .panel.collapsible > h2 {
    display: flex; align-items: center; justify-content: space-between;
    cursor: pointer; margin: 0; user-select: none;
  }
  .panel.collapsible > h2::after {
    content: ''; width: 9px; height: 9px; flex: none;
    border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted);
    transform: rotate(-45deg); transition: transform .15s;
  }
  .panel.collapsible.open > h2::after { transform: rotate(45deg); }
  /* Only DIRECT children toggle; nested layout (flex tag rows etc.) inside the
     form keeps its own display untouched. */
  .panel.collapsible > *:not(h2) { display: none; }
  .panel.collapsible.open > *:not(h2) { display: block; }
  .panel.collapsible.open > h2 { margin-bottom: 10px; }
  .seg { display: inline-flex; background: var(--surface-2); border-radius: 999px; padding: 3px; }
  .seg button {
    border: none; background: none; padding: 5px 12px; border-radius: 999px;
    font: 600 11.5px var(--font-body); color: var(--muted); cursor: pointer;
  }
  .seg button.active { background: var(--surface); color: var(--primary-700); box-shadow: 0 1px 2px rgba(16, 32, 52, .1); }
  .profile-sponsor {
    display: flex; align-items: center; justify-content: center; gap: 7px;
    font-size: 11px; color: var(--muted); padding: 6px 0 0;
  }
  .profile-sponsor img { height: 15px; }
  .row-danger { color: var(--danger) !important; }
}
