/* ── Reset & Variables ─────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
/* Stops mobile Safari/Chrome from silently bumping font-size on some
   elements and not others (its auto text-inflation heuristic), which is
   what was throwing pixel-tuned rows like Chrono's input bar out of
   vertical alignment on phones despite matching on desktop. */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
a, button, [role='button'], .btn, input[type='color'], .cal-event, .cal-row, .year-day:not(.blank), .year-month, .view-tab, .list-item, select, [onclick], .nav-link, .context-menu-item, .zeno-suggestion { cursor: pointer; }
input[type='text'], input[type='email'], input[type='password'], input[type='url'], input[type='search'], textarea, [contenteditable] { cursor: text; }

:root {
  color-scheme: light;
  --bg:           #F7F7F2;
  --surface:      #FFFFFF;
  --surface2:     #F3F4F6;
  --surface3:     #EAECF0;
  --border:       #E5E7EB;
  --border2:      #D1D5DB;
  --primary:      #14213D;
  --primary-dim:  #0f1a2e;
  --primary-glow: rgba(20,33,61,0.06);
  --accent:       #2A9D8F;
  --accent-dim:   #228176;
  --text:         #111827;
  --text-muted:   #6B7280;
  --text-dim:     #9CA3AF;
  --red:          #930101;
  --amber:        #F59E0B;
  --green:        #22C55E;
  /* Separate from --red on purpose: --red is tuned dark for legible text/
     borders on a light background (delete buttons, error copy), but that
     same near-maroon tone reads muddy as a solid gradient fill -- .study-
     mode-btn wants the same lighter red in both themes, so this matches
     dark mode's --red/--study-red value exactly rather than re-deriving it. */
  --study-red:    #F87171;

  --font: -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', system-ui, sans-serif;
  --radius: 0.75rem;
  --radius-sm: 0.375rem;
  --radius-md: 0.625rem;
  --radius-lg: 1rem;
  --ease: cubic-bezier(0.25, 1, 0.5, 1);
  --ease-spring: cubic-bezier(0.32, 0.72, 0, 1);
  --ring: 0 0 0 0.2188rem color-mix(in srgb, var(--accent) 38%, transparent);
  --shadow: 0 0.5rem 2rem rgba(0,0,0,0.08);
  --shadow-sm: 0 0.125rem 0.5rem rgba(0,0,0,0.04);
  --glass-shadow: inset 0 1px 0 rgba(255,255,255,0.75), 0 0.125rem 0.625rem rgba(0,0,0,0.06);
  --glass-shadow-hover: inset 0 1px 0 rgba(255,255,255,0.85), 0 0.25rem 0.875rem rgba(0,0,0,0.08);
  --sidebar-bg: #14213D;
  --zeno-accent: #C8962E;
  --zeno-accent-light: #D4A94A;
  --zeno-accent-dim: #B8862A;
  --zeno-surface: #D4C8A0;
}

/* The whole app scales with the window, so it has the same proportions on
   every screen: every size in these stylesheets is in rem (only hairlines
   and the @media breakpoints stay in px), so this one rule grows or shrinks
   text, spacing, panels and the calendar together, the way browser zoom
   would, without zoom's side effects on 100vh layouts and on the
   drag/resize math (see the 2026-09-09 revert).
   19.4px on a 1440x900 laptop (about 790px of window under the browser's
   bars) -- a fifth larger than the 16px it was drawn at; whichever of
   width and height runs out first sets it, so a wide but short window
   does not grow past what fits. Never below 15.4px, and up to 48px for 4K.
   Phones, tablets and anything touch-first: 17.6px, a tenth over the 16px
   their px breakpoints were drawn for. */
html { font-size: clamp(15.4px, min(100vw / 74.4, 100vh / 40.9), 48px); }
@media (max-width: 1023px), (pointer: coarse) { html { font-size: 17.6px; } }

html, body { height: 100%; overflow: hidden; overscroll-behavior-x: none; }

/* Apple-style focus ring — visible for keyboard navigation only */
button:focus-visible, select:focus-visible,
input[type="checkbox"]:focus-visible, [tabindex="0"]:focus-visible,
.academic-chip:focus-visible, .cal-event:focus-visible,
.year-day:focus-visible {
  outline: none;
  box-shadow: var(--ring);
}

body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  font-size: 0.9375rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overscroll-behavior: none;
}

/* ── Loading screen ────────────────────────────────────────────────────────── */
#screen-loading {
  position: fixed;
  inset: 0;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.5rem;
  z-index: 999;
}

.loading-logo {
  display: flex; flex-direction: column; align-items: center; gap: 0.25rem;
  font-size: 2rem;
  font-weight: 800;
  color: var(--primary);
  letter-spacing: -1px;
  animation: pulse 1.5s ease-in-out infinite;
}

.loading-spinner {
  width: 2rem;
  height: 2rem;
  border: 0.1875rem solid rgba(20,33,61,0.15);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.4; }
}

/* ── Auth screen ───────────────────────────────────────────────────────────── */
#screen-auth {
  display: flex;
  /* A card taller than the window scrolls from its top instead of being
     cut off above and below: centred by its own margins while it fits. */
  align-items: flex-start;
  justify-content: center;
  height: 100vh;
  overflow-y: auto;
  padding: 1.5rem 0;
  background: linear-gradient(135deg, #eef2f7 0%, var(--bg) 60%);
}

.auth-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 1.25rem;
  padding: 2.25rem 2.5rem;
  width: 26.25rem;
  box-shadow: var(--shadow);
  margin: auto 0;
}

.auth-logo    { display: flex; flex-direction: column; align-items: center; font-size: 2.5rem; font-weight: 700; letter-spacing: -0.5px; color: var(--primary); text-align: center; margin-bottom: 0.5rem; }
.auth-tagline { font-size: 0.8125rem; color: var(--text-muted); margin-bottom: 2.625rem; /* room for the providers bubble over the key tab */ text-align: center; }

.auth-tabs {
  display: flex;
  gap: 0.25rem;
  background: var(--surface2);
  border-radius: var(--radius);
  padding: 0.25rem;
  margin-bottom: 1.375rem;
  position: relative;
}

.auth-tab-indicator {
  position: absolute;
  top: 0.25rem; bottom: 0.25rem; left: 0.25rem; width: 0;
  background: var(--surface);
  border-radius: var(--radius-sm);
  box-shadow: 0 1px 0.25rem rgba(0,0,0,0.1);
  transition: left 0.24s var(--ease), width 0.24s var(--ease);
  z-index: 0;
}

.auth-consent {
  display: flex; align-items: flex-start; gap: 0.5rem; margin: 0.25rem 0 0.5rem;
  font-size: 0.75rem; line-height: 1.45; color: var(--text-muted); cursor: pointer;
}
.auth-consent input { margin: 0.15rem 0 0; flex-shrink: 0; width: 1rem; height: 1rem; accent-color: var(--primary); }
.auth-consent a, .auth-consent-note a { color: inherit; text-decoration: underline; text-underline-offset: 0.125rem; }
.auth-consent-note { margin: 0.5rem 0 0; font-size: 0.6875rem; line-height: 1.45; color: var(--text-dim); text-align: center; }
.age-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; }
#form-age .auth-confirm-icon { margin-left: auto; margin-right: auto; }
.age-row select, .age-country { width: 100%; }
.age-month:disabled, .age-year:disabled, .age-country:disabled { opacity: 0.7; cursor: not-allowed; }
.age-parent { animation: fadeIn 0.2s var(--ease); }
.age-parent-hint { margin: 0.375rem 0 0; font-size: 0.6875rem; line-height: 1.45; color: var(--text-dim); }
#form-age .auth-confirm-title { text-align: center; }
#form-age .auth-confirm-desc { text-align: center; margin-bottom: 1rem; }
.parent-wait-status { min-height: 1rem; margin: 0.25rem 0 0.5rem; font-size: 0.75rem; color: var(--text-muted); text-align: center; }
.parent-wait-links { display: flex; justify-content: center; gap: 1rem; margin-bottom: 0.75rem; }
#parent-wait-change { margin: 0.5rem 0; }
.auth-social { display: flex; flex-direction: column; gap: 0.5rem; animation: fadeIn 0.2s var(--ease); }
.btn-social {
  display: flex; align-items: center; justify-content: center; gap: 0.625rem;
  width: 100%; padding: 0.75rem 1rem; border-radius: var(--radius);
  border: 1px solid var(--border); background: var(--surface2);
  color: var(--text); font-size: 0.875rem; font-weight: 600; font-family: var(--font);
  cursor: pointer; transition: background 0.12s, border-color 0.12s, box-shadow 0.12s, transform 0.12s var(--ease);
}
.btn-social:hover { background: var(--surface); border-color: var(--border2); box-shadow: var(--shadow-sm); }
.btn-social:active { transform: scale(0.98); }
.btn-social svg { flex-shrink: 0; }

#verification-sent, #forgot-sent {
  animation: fadeIn 0.3s var(--ease);
}
.auth-confirm { text-align: center; padding: 1.25rem 0; }
.auth-confirm-icon {
  width: 3.5rem; height: 3.5rem; margin: 0 auto 0.875rem;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%; background: rgba(42,157,143,0.12); color: var(--accent);
}
.auth-confirm-icon svg { width: 1.75rem; height: 1.75rem; }

.modal-lead-icon {
  width: 3rem; height: 3rem; margin: 0 auto;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%; background: rgba(42,157,143,0.12); color: var(--accent);
}
.modal-lead-icon svg { width: 1.5rem; height: 1.5rem; }
.modal-lead-icon.warning { background: rgba(245,158,11,0.14); color: var(--amber); }
.auth-confirm-title { font-size: 1rem; font-weight: 600; margin-bottom: 0.375rem; }
.auth-confirm-desc { font-size: 0.8125rem; color: var(--text-muted); margin: 0 0 1rem; line-height: 1.5; }

.auth-link {
  background: none; border: none; padding: 0;
  color: var(--accent); font-size: 0.75rem; font-weight: 500;
  cursor: pointer; font-family: var(--font);
}
.auth-link:hover { text-decoration: underline; }

.resend-verify {
  animation: fadeIn 0.3s ease;
}

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(0.25rem); }
  to   { opacity: 1; transform: translateY(0); }
}

.auth-tab {
  flex: 1; padding: 0.5rem; text-align: center;
  border-radius: var(--radius-sm); cursor: pointer;
  font-size: 0.8125rem; font-weight: 500; color: var(--text-muted);
  transition: color 0.16s var(--ease); border: none; background: none;
  position: relative; z-index: 1;
}
.auth-tab.active { color: var(--text); }

.auth-tab-icon { flex: 0 0 auto; width: 2.25rem; margin-right: 0.5rem; padding: 0.25rem 0; display: flex; align-items: center; justify-content: center; }
.auth-tab-icon svg { width: 1.125rem; height: 1.375rem; }
/* A key icon alone reads as "password/API key", not "sign in with Google/
   Microsoft instead" -- this custom bubble (on top of the native title
   tooltip, which is slow and easy to miss) makes that explicit the moment
   you hover or focus the tab, instead of only after clicking it. */
.auth-tab-tooltip {
  position: absolute; bottom: calc(100% + 0.5rem); right: -0.25rem;
  transform: translateY(0.25rem);
  background: #1F2430; color: #fff;
  font-size: 0.6875rem; font-weight: 600; white-space: nowrap;
  padding: 0.375rem 0.625rem; border-radius: var(--radius-sm);
  box-shadow: 0 0.25rem 0.875rem rgba(0,0,0,0.22);
  opacity: 0; pointer-events: none;
  transition: opacity 0.14s var(--ease), transform 0.14s var(--ease);
  z-index: 5;
}
/* Right-aligned over the key rather than centred on it: the key is the last
   tab, so a centred bubble ran past the card's edge on a phone. */
.auth-tab-tooltip::after {
  content: ''; position: absolute; top: 100%; right: 0.9375rem;
  border: 0.3125rem solid transparent; border-top-color: #1F2430;
}
.auth-tab-icon:hover .auth-tab-tooltip,
.auth-tab-icon:focus-visible .auth-tab-tooltip,
.auth-tab-icon.show-hint .auth-tab-tooltip {
  opacity: 1; transform: translateY(0);
}
/* Shown on its own when the page opens, so nobody has to find the key by
   hovering; it bobs gently until the first click or key press puts it away. */
.auth-tab-icon.show-hint .auth-tab-tooltip { animation: auth-hint-bob 2.4s ease-in-out 0.4s infinite; }
@keyframes auth-hint-bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-0.1875rem); }
}

/* ── Forms ─────────────────────────────────────────────────────────────────── */
.form-group { margin-bottom: 0.875rem; }
.form-group label { display: block; font-size: 0.75rem; font-weight: 600; color: var(--text-muted); margin-bottom: 0.375rem; }

/* Event modal's Calendar picker -- a closed dropdown button (same footprint
   as a normal <select>) that opens a checkbox panel, so it can still hold
   MORE than one calendar at once (the actual fix) without permanently
   taking up the vertical space an always-open checkbox list would. */
.event-cal-dropdown { position: relative; }
.event-cal-dropdown-btn {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
  background: var(--surface2); border: 1px solid var(--border);
  border-radius: var(--radius); color: var(--text);
  padding: 0.6875rem 0.8125rem; font-size: 0.875rem; font-family: var(--font);
  cursor: pointer; text-align: left; transition: border-color 0.15s;
}
.event-cal-dropdown-btn span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.event-cal-dropdown-btn svg { flex-shrink: 0; color: var(--text-muted); transition: transform 0.15s ease; }
.event-cal-dropdown-btn.open svg { transform: rotate(180deg); }
.event-cal-dropdown-panel {
  position: absolute; top: calc(100% + 0.25rem); left: 0; right: 0; z-index: 20;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 0.25rem 1rem rgba(0,0,0,0.18);
  padding: 0.375rem; max-height: 12.5rem; overflow-y: auto;
}
.event-calendar-list { display: flex; flex-direction: column; gap: 0.125rem; }
.event-cal-check-row {
  display: flex; align-items: center; gap: 0.75rem; font-size: 0.8125rem; color: var(--text);
  cursor: pointer; padding: 0.5rem 0.625rem; border-radius: 0.25rem;
}
.event-cal-check-row:hover { background: var(--surface2); }
.event-cal-check-row input[type="checkbox"] { width: auto; flex-shrink: 0; margin: 0; }

input, select, textarea {
  width: 100%; background: var(--surface2); border: 1px solid var(--border);
  border-radius: var(--radius); color: var(--text); padding: 0.6875rem 0.8125rem;
  font-size: 0.875rem; font-family: var(--font); outline: none; transition: border-color 0.15s;
}

.password-wrap { position: relative; }
.password-wrap input { padding-right: 2.25rem; }
.password-toggle {
  position: absolute; right: 0.375rem; top: 50%; transform: translateY(-50%);
  background: none; border: none; cursor: pointer; padding: 0.25rem;
  color: var(--text-muted); display: flex; align-items: center; justify-content: center;
  transition: color 0.15s; border-radius: 0.375rem;
}
.password-toggle:hover { color: var(--text); background: rgba(0,0,0,0.04); }
.password-toggle svg { width: 1.125rem; height: 1.125rem; display: block; }
input:focus, select:focus, textarea:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 0.2188rem color-mix(in srgb, var(--primary) 12%, transparent);
}
input::placeholder { color: var(--text-dim); }
select option { background: var(--surface); color: var(--text); }
textarea { resize: vertical; min-height: 2.5rem; }

/* Language picker -- a custom dropdown, not a native <select>, because
   <option> elements can only ever render plain text: the flag "icons" have
   to be real inline SVGs (not the emoji flags they replace, which some
   platforms -- Windows in particular -- render as bare two-letter country
   codes instead of pictures) and no browser will draw markup inside an
   <option> to show them. */
.lang-picker { position: relative; }
.lang-picker-btn {
  width: 100%; display: flex; align-items: center; gap: 0.5rem;
  background: var(--surface2); border: 1px solid var(--border);
  border-radius: var(--radius); color: var(--text);
  padding: 0.6875rem 0.8125rem; font-size: 0.875rem; font-family: var(--font);
  cursor: pointer; transition: border-color 0.15s;
}
.lang-picker-btn:hover { border-color: var(--border2); }
.lang-picker-btn[aria-expanded="true"] {
  border-color: var(--primary);
  box-shadow: 0 0 0 0.2188rem color-mix(in srgb, var(--primary) 12%, transparent);
}
.lang-picker-name { flex: 1; text-align: left; }
.lang-picker-caret { flex-shrink: 0; color: var(--text-muted); transition: transform 0.15s; }
.lang-picker-btn[aria-expanded="true"] .lang-picker-caret { transform: rotate(180deg); }
.lang-flag {
  flex-shrink: 0; width: 1.25rem; height: 0.875rem; border-radius: 0.125rem; overflow: hidden;
  display: inline-flex; box-shadow: 0 0 0 1px rgba(0,0,0,0.15);
}
.lang-flag svg { width: 100%; height: 100%; display: block; }

/* position: fixed (not absolute) and placed via JS -- the picker lives
   inside .settings-panes, which scrolls (overflow-y: auto), so an
   absolutely-positioned menu got clipped to that pane instead of floating
   over the rest of the modal. z-index above .modal-overlay's 100 so it
   still shows on top of everything else in the modal. */
.lang-picker-menu {
  position: fixed; z-index: 200;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); max-height: 16.25rem; overflow-y: auto; padding: 0.25rem;
}
.lang-picker-option {
  display: flex; align-items: center; gap: 0.5rem; width: 100%;
  padding: 0.5rem 0.5625rem; border-radius: 0.5rem; border: none; background: none;
  color: var(--text); font-size: 0.875rem; font-family: var(--font); cursor: pointer; text-align: left;
}
.lang-picker-option:hover { background: var(--surface2); }
.lang-picker-option.selected { font-weight: 700; }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.375rem;
  padding: 0.625rem 1.125rem; border-radius: var(--radius); border: none;
  font-size: 0.8125rem; font-weight: 600; font-family: var(--font);
  cursor: pointer; touch-action: manipulation;
  /* Named properties, not `all` -- `.btn`'s many variants only ever change
     background/border-color/box-shadow/color on :hover and transform on
     :active; transitioning `all` makes the browser watch every animatable
     property (including ones that never change here) on every hover across
     every button in the app, which is needless work on a very hot path. */
  transition-property: background, border-color, box-shadow, color, transform;
  transition-duration: 0.12s;
  transition-timing-function: var(--ease);
  text-decoration: none; /* also used on <a class="btn"> (e.g. grades's "Manage" links) */
}
.btn:active { transform: scale(0.97); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; pointer-events: none; }
.btn-primary {
  background: linear-gradient(135deg, rgba(20,33,61,0.88), rgba(15,26,46,0.88));
  color: #fff; border: 1px solid rgba(20,33,61,0.25);
  -webkit-backdrop-filter: blur(0.75rem) saturate(160%);
  backdrop-filter: blur(0.75rem) saturate(160%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.18), 0 0.125rem 0.625rem rgba(20,33,61,0.12);
}
.btn-primary:hover {
  background: linear-gradient(135deg, rgba(20,33,61,0.97), rgba(15,26,46,0.97));
  /* The same hairline lift the landing page's buttons have. Without it the
     app's buttons sit dead under the cursor while the site's respond. */
  transform: translateY(-1px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.18), 0 0.375rem 1.125rem rgba(20,33,61,0.18);
}
.btn-primary:active { transform: translateY(0) scale(0.97); }
.btn-ghost {
  background: rgba(255,255,255,0.65); color: #35383F;
  border: 1px solid rgba(0,0,0,0.06);
  -webkit-backdrop-filter: blur(0.75rem) saturate(160%);
  backdrop-filter: blur(0.75rem) saturate(160%);
  box-shadow: var(--glass-shadow);
}
.btn-ghost:hover { background: rgba(255,255,255,0.9); color: var(--text); box-shadow: var(--glass-shadow-hover); }
/* Portal rows between zenow <-> Grades: one shared shape, each themed
   with the other product's color, so the two read as a matched pair. Both
   sidebars (zenow's own, and Grades' reuse of it) share the same dark
   --sidebar-bg regardless of which app's page you're on, so this is a
   plain row -- no colored pill/card background, no border -- styled like
   the rest of the sidebar (hover = neutral light overlay, like
   .academic-chip), just with a colored mark + label -- a notch bigger than
   a regular link, not a full section with its own separator (that read as
   too heavy). */
.sidebar-portal-link {
  display: flex; align-items: center; gap: 0.5rem;
  margin: 0.375rem 0.375rem 0.5rem; padding: 0.4375rem 0.5rem;
  border-radius: var(--radius-sm);
  font-size: 0.84375rem; font-weight: 700;
  text-decoration: none;
  transition: background 0.15s var(--ease);
}
.sidebar-portal-link:hover { background: rgba(255,255,255,0.07); }
.sidebar-portal-link:active { transform: scale(0.98); }
/* Two portal links back to back (Grades + Curriculum) otherwise stack
   each one's own standalone-entry margin (meant to separate a single
   portal link from the list below it), doubling into a gap that reads as
   a lot of dead space between two items that should sit together like a
   small list. The last link in the group keeps the full bottom margin
   (still needs to separate the group from the Academic section below);
   only the join between two portal links themselves collapses. */
.sidebar-portal-link:has(+ .sidebar-portal-link) { margin-bottom: 0; }
.sidebar-portal-link + .sidebar-portal-link { margin-top: 0; }
.sidebar-portal-mark {
  width: 1.4375rem; height: 1.4375rem; border-radius: 0.4375rem; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; overflow: hidden;
}
.sidebar-portal-mark img { width: 100%; height: 100%; object-fit: cover; }
.sidebar-portal-mark svg { width: 0.9375rem; height: 0.9375rem; }
.sidebar-portal-chevron { margin-left: auto; flex-shrink: 0; opacity: 0.75; width: 1.0625rem; height: 1.0625rem; }

/* Grades entry point (in zenow's own sidebar): always blue in both
   themes (hardcoded, not a theme token) since it's the portal into a
   visually distinct sibling product. */
.sidebar-grades-link { color: #7EB6FF; }
/* Same gradient + glossy sheen + bottom shading as the real logomark
   (grades.html's SVG defs) -- layered CSS backgrounds standing in for
   the SVG's radialGradient/linearGradient overlays, so the sidebar entry
   point isn't just a flat color chip. */
.sidebar-grades-link .sidebar-portal-mark {
  background:
    radial-gradient(circle at 30% 22%, rgba(255,255,255,0.6) 0%, rgba(255,255,255,0.1) 55%, rgba(255,255,255,0) 100%),
    linear-gradient(to bottom, rgba(4,24,79,0) 55%, rgba(4,24,79,0.28) 100%),
    linear-gradient(135deg, #BFE4FF 0%, #4A86E8 45%, #15398F 100%);
}

/* Curriculum planner entry point -- a distinct violet, hardcoded like
   Grades' blue above, so the two portal links read as separate products
   at a glance rather than needing the label to tell them apart. */
.sidebar-curriculum-link { color: #C9AEFF; }
.sidebar-curriculum-link .sidebar-portal-mark {
  background:
    radial-gradient(circle at 30% 22%, rgba(255,255,255,0.5) 0%, rgba(255,255,255,0.08) 55%, rgba(255,255,255,0) 100%),
    linear-gradient(135deg, #D9C6FF 0%, #8B5CF6 55%, #4C1D95 100%);
}

/* Grades wordmark -- a blue gradient with a subtle shadow. Shared between
   the main app's sidebar link and the standalone Grades page (header +
   loading screen) so the brand renders identically everywhere. Used to be
   a two-tone split across "Next"/"grade" spans back when the product was
   called Nextgrade; a single word has no natural second span to split, so
   this is now one continuous gradient across the whole wordmark instead. */
.grades-wordmark { font-weight: 800; letter-spacing: -0.5px; color: #1F4FC4; }
:root[data-theme="dark"] .grades-wordmark { color: #6FA0FF; }

/* Same recipe as the landing page's gold "Achieve it" slogan: a tonal
   gradient fill (light -> dark) reads as an embossed/lit-from-above
   surface, then a soft color-matched drop-shadow (not a hard offset
   text-shadow) seats it with depth -- drop-shadow blurs only the shadow
   halo, never the glyph itself, so it stays crisp while looking "shadowed
   from the inside." Reserved for .grades-wordmark-hero (big, prominent
   placements only: the loading screen, the page header) -- the flat solid
   color above is what renders everywhere else, since gradient-clipped text
   reads blurry at small sizes (poor anti-aliasing on a thin glyph). */
.grades-wordmark-hero {
  letter-spacing: -0.03em;
  background-image: linear-gradient(135deg, #C7E6FF 0%, #6FB4FF 35%, #2E7FE0 65%, #17399A 100%);
  background-clip: text; -webkit-background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
  text-shadow: none;
  filter: drop-shadow(0 0.375rem 1rem rgba(47,111,237,0.30));
}

/* Full logo lockup: mark + wordmark side by side, used wherever the brand
   needs actual presence (loading screen, page header) rather than just a
   label. */
.grades-logo-lockup { display: flex; align-items: center; gap: 0.4em; }
.grades-logomark {
  flex-shrink: 0;
  filter: drop-shadow(0 0.125rem 0.25rem rgba(8,20,56,0.3)) drop-shadow(0 0.375rem 1rem rgba(47,111,237,0.45));
}
.btn-secondary {
  background: rgba(255,255,255,0.65); color: #35383F;
  border: 1px solid rgba(0,0,0,0.06);
  -webkit-backdrop-filter: blur(0.75rem) saturate(160%);
  backdrop-filter: blur(0.75rem) saturate(160%);
  box-shadow: var(--glass-shadow);
}
.btn-secondary:hover { background: rgba(255,255,255,0.9); color: var(--text); box-shadow: var(--glass-shadow-hover); }
/* Small buttons ("Add step", "Choose image", "Plan again", "Delete") sit
   inline in flat form/list content, not over background texture worth
   blurring -- the frosted-glass treatment that reads right on a full-size
   button just looks washed out at btn-sm scale, so the blur comes off.
   What replaces it is the landing page's own outline button: a clean
   surface, a real border, and a hairline lift on hover. A grey fill with
   muted text was the other way to drop the glass, and it read as disabled
   rather than as a button. Excludes .sidebar, which has its own look. */
.btn-ghost.btn-sm:not(.sidebar *), .btn-secondary.btn-sm:not(.sidebar *) {
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border);
  -webkit-backdrop-filter: none; backdrop-filter: none;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.7), 0 1px 0.125rem rgba(17,24,39,0.04);
}
.btn-ghost.btn-sm:not(.sidebar *):hover, .btn-secondary.btn-sm:not(.sidebar *):hover {
  background: var(--surface); color: var(--text);
  border-color: var(--border2);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.7), 0 0.1875rem 0.5rem rgba(17,24,39,0.07);
  transform: translateY(-1px);
}
.btn-ghost.btn-sm:not(.sidebar *):active, .btn-secondary.btn-sm:not(.sidebar *):active {
  transform: translateY(0) scale(0.97);
}
  .btn-danger {
    background: #DC2626; color: #fff;
    border: 1px solid rgba(185,28,28,0.9);
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.12), 0 0.125rem 0.625rem rgba(220,38,38,0.18);
}
/* A modal's own Undo action: the same quiet glass as the buttons beside
   it; only the curved arrow carries a soft amber hint that it reverses. */
.btn-undo {
  background: rgba(255,255,255,0.65); color: #35383F;
  border: 1px solid rgba(0,0,0,0.06);
  -webkit-backdrop-filter: blur(0.75rem) saturate(160%);
  backdrop-filter: blur(0.75rem) saturate(160%);
  box-shadow: var(--glass-shadow);
}
.btn-undo:hover { background: rgba(255,255,255,0.9); color: var(--text); box-shadow: var(--glass-shadow-hover); }
.btn-undo svg, .undo-btn svg { color: #C2761B; }
.btn-undo svg { width: 0.875rem; height: 0.875rem; flex-shrink: 0; }

.btn-danger:hover { background: #C01C22; }
.btn-full { width: 100%; }
.btn-connect-row { justify-content: flex-start; gap: 0.625rem; font-weight: 600; }
/* The student's own school's registry. Ringed rather than tinted -- it is
   the same kind of thing as the rows under it, just the one that is theirs. */
.btn-connect-row.is-school {
  border-color: color-mix(in srgb, var(--accent) 55%, var(--border));
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 22%, transparent);
}
.registry-row-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Real, but not set up on THIS server. Dimmed rather than absent: the
   student learns the difference between "we don't support it" and "ask
   whoever runs this to add the credentials". */
.btn-connect-row.is-unconfigured { opacity: 0.55; cursor: not-allowed; }
.registry-off {
  margin-left: auto; flex-shrink: 0;
  font-size: 0.5625rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em;
  color: var(--text-dim); background: var(--surface2);
  border-radius: 62.4375rem; padding: 0.0625rem 0.375rem;
}
.registry-mine {
  margin-left: auto; flex-shrink: 0;
  font-size: 0.5625rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent);
  border-radius: 62.4375rem; padding: 0.0625rem 0.375rem;
}
/* Searches every provider in every country, which is what replaced the old
   "Other countries" button -- a control that revealed a second list, where
   this one just finds the thing. */
/* Its own breathing room above the list. At 2px the box and the first row
   read as one control, and the row looked like a dropdown hanging off the
   input rather than the first of several things to choose between. */
.registry-search {
  width: 100%; margin-bottom: 0.5rem;
  font-size: 0.8125rem;
}
/* The line under a capped list. Muted and centred so it reads as a note
   about the list rather than as another row in it. */
.registry-more {
  font-size: 0.75rem; color: var(--text-muted); text-align: center;
  padding: 0.5rem 0.25rem 0.125rem;
}
/* Sits at the far end of the row so the provider's name still reads first:
   it is a caveat, not a headline. */
.registry-beta {
  margin-left: auto; font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.02em;
  color: var(--text-muted); border: 0.0625rem solid var(--border);
  border-radius: 0.375rem; padding: 0.0625rem 0.3125rem;
}
.settings-divider { height: 0.0625rem; background: var(--border); margin: 0.875rem 0; }
.btn-sm { padding: 0.3125rem 0.6875rem; font-size: 0.75rem; }
.btn-xs { padding: 0.125rem 0.375rem; font-size: 0.6875rem; background: none; border: none; color: var(--text-muted); cursor: pointer; text-decoration: none; }
.btn-xs:hover { color: var(--text); }
#btn-forgot-password {
  background: none; border: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: none;
  color: var(--text-muted); padding: 0.125rem 0.375rem;
}
#btn-forgot-password:hover { color: var(--text); }

.error-msg { color: #930101; font-size: 0.75rem; margin-top: 0.375rem; display: none; text-align: center;}
.error-msg.show { display: block; }

/* ── App layout ────────────────────────────────────────────────────────────── */
#screen-app {
  display: flex;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  position: relative;
}
.sidebar {
  width: var(--sidebar-w, 16rem); min-width: 16rem;
  background: var(--sidebar-bg);
  border-right: none;
  display: flex; flex-direction: column; overflow: hidden;
  position: relative;
}

.streak-flame {
  position: relative;
  width: 1.0625rem; height: 1.0625rem;
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  filter: drop-shadow(0 0 0.3125rem rgba(255,120,20,0.7));
  transform-origin: 50% 90%;
  animation: streakFlicker 2.6s ease-in-out infinite, streakSway 3.9s ease-in-out infinite;
}
.streak-flame svg { width: 100%; height: 100%; }

/* Two independent transform properties (scale + rotate) on different,
   non-multiple durations, so the combined motion doesn't visibly repeat
   for ~7.8s -- a single synced loop read as a mechanical pulse/wobble
   rather than an irregular flicker. */
@keyframes streakFlicker {
  0%, 100% { scale: 1 1; }
  15%      { scale: 0.95 1.06; }
  34%      { scale: 1.05 0.94; }
  52%      { scale: 0.97 1.05; }
  71%      { scale: 1.04 0.96; }
  88%      { scale: 0.98 1.03; }
}
@keyframes streakSway {
  0%, 100% { rotate: 0deg; }
  30%      { rotate: -2deg; }
  65%      { rotate: 1.4deg; }
}

.streak-fullscreen {
  position: fixed; inset: 0; z-index: 300;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0.875rem;
  background: radial-gradient(circle at 50% 32%, rgba(255,120,20,0.22), rgba(10,8,10,0.97) 62%);
  -webkit-backdrop-filter: blur(0.375rem);
  backdrop-filter: blur(0.375rem);
  animation: fadeIn 0.25s var(--ease);
}
.streak-fullscreen.hidden { display: none; }

.streak-fullscreen-close {
  position: absolute; top: 1.25rem; right: 1.25rem;
  width: 2.25rem; height: 2.25rem; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.16);
  color: #fff; cursor: pointer; transition: background 0.15s;
}
.streak-fullscreen-close:hover { background: rgba(255,255,255,0.18); }

.streak-fullscreen-nav { display: flex; align-items: center; gap: 1.25rem; }
.streak-fullscreen-arrow {
  flex-shrink: 0;
  width: 2.5rem; height: 2.5rem; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.16);
  color: #fff; cursor: pointer; transition: background 0.15s, opacity 0.15s;
}
.streak-fullscreen-arrow:hover { background: rgba(255,255,255,0.18); }

/* The count used to live inside .streak-fullscreen-flame, so its own
   flicker/sway transform dragged the number along with it. Split into a
   static positioning wrapper (this element) + the animated flame as its
   child, with the count as a sibling -- the number no longer inherits
   the flame's transform. */
.streak-fullscreen-flame-wrap {
  position: relative;
  width: 16.25rem; height: 16.25rem;
  display: flex; align-items: center; justify-content: center;
}
.streak-fullscreen-flame {
  width: 16.25rem; height: 16.25rem;
  display: flex; align-items: center; justify-content: center;
  filter: drop-shadow(0 0 3.375rem rgba(255,120,20,0.55));
  transform-origin: 50% 90%;
  animation: streakFlicker 6.2s ease-in-out infinite, streakSway 8.6s ease-in-out infinite;
}
.streak-fullscreen-flame svg { width: 100%; height: 100%; }
.streak-fullscreen-count {
  position: absolute; top: 64%; left: 50%; transform: translate(-50%, -50%);
  font-size: 3.375rem; font-weight: 900; color: #fff;
  letter-spacing: -1px;
  -webkit-text-stroke: 0.25rem #000;
  paint-order: stroke fill;
  text-shadow: 0 0.125rem 0.875rem rgba(0,0,0,0.55);
}

.streak-fullscreen-label {
  font-size: 0.9375rem; font-weight: 600; color: rgba(255,255,255,0.78);
  letter-spacing: 0.2px;
}

.streak-fullscreen-share { margin-top: 0.875rem; }
.streak-fullscreen-share .btn {
  background: linear-gradient(135deg, #FF9142, #EF4444);
  border: none; color: #fff;
  padding: 0.75rem 1.75rem;
  border-radius: 62.4375rem;
  font-weight: 700;
  letter-spacing: 0.2px;
  box-shadow: 0 0.375rem 1.25rem rgba(239,68,68,0.35), inset 0 1px 0 rgba(255,255,255,0.25);
  transition: transform 0.15s var(--ease), box-shadow 0.15s var(--ease), background 0.15s var(--ease);
}
.streak-fullscreen-share .btn svg { transform: rotate(-8deg); }
.streak-fullscreen-share .btn:hover {
  background: linear-gradient(135deg, #FFA35C, #F45B5B);
  box-shadow: 0 0.5rem 1.625rem rgba(239,68,68,0.45), inset 0 1px 0 rgba(255,255,255,0.3);
  transform: translateY(-1px);
}
.streak-fullscreen-share .btn:active { transform: scale(0.96); }

.sidebar-header {
  height: 4.625rem; box-sizing: border-box; padding: 0 1.125rem;
  border-bottom: 1px solid rgba(255,255,255,0.1);
  display: flex; align-items: center; justify-content: space-between;
}
.logo { display: flex; align-items: center; gap: 0.5rem; font-size: 1.25rem; font-weight: 800; color: #FFFFFF; letter-spacing: -0.5px; }
.logo img { flex-shrink: 0; object-fit: contain; aspect-ratio: 1 / 1; }

/* Clips the transparent padding baked into logo.png */
.logo-clip {
  width: 9.375rem;
  height: 9.375rem;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.logo-clip img { flex-shrink: 0; }

/* Pull "zenow" text closer to the actual circle (eats PNG bottom padding) */
.auth-logo .logo-clip { margin-bottom: -0.625rem; }

/* Children now manage their own scrolling, so this no longer scrolls as one unit. */
.sidebar-scroll { flex: 1; overflow: hidden; display: flex; flex-direction: column; }

.sidebar-section { padding: 1rem 1.125rem; }
#academic-section { border-bottom: none; }

#academic-section, #ng-academic-section {
  min-height: 4rem;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.sidebar-section-title {
  font-size: 0.75rem; font-weight: 600;
  letter-spacing: -0.1px; color: rgba(255,255,255,0.45); margin-bottom: 0.875rem;
  display: flex; align-items: center; justify-content: space-between;
}

/* The "+" and the filter sit together at the right end of the section title.
   Both are drawn on the same 1.375rem square and centre their glyph in it, so
   the two boxes are the same height and the icons share one optical centre --
   no nudge, because a nudge is only ever right for one font at one size. */
.sidebar-section-actions { display: flex; align-items: center; gap: 0.25rem; }
.sidebar-section-actions .academic-filter-btn,
.sidebar-section-actions .add-btn {
  display: grid; place-items: center;
  width: 1.375rem; height: 1.375rem;
  padding: 0; margin: 0;
  background: none; border: none; cursor: pointer;
  color: rgba(255,255,255,0.6); transition: color 0.15s;
}
.sidebar-section-actions .academic-filter-btn { position: relative; }
.sidebar-section-actions .academic-filter-btn:hover,
.sidebar-section-actions .add-btn:hover { color: #FFFFFF; }
.sidebar-section-actions .add-btn { font: inherit; font-size: 1.125rem; line-height: 1; }
/* A dot, not a count: the point is only "you are not seeing everything".
   Sits just outside the icon's own top-right, not the button's, so it stays on
   the glyph now that the button is a fixed square. --accent, NOT --primary: in
   light mode --primary is #14213D, the exact navy of --sidebar-bg, so a
   --primary dot would be invisible on the one background this button sits on. */
.academic-filter-btn.is-filtering::after {
  content: ''; position: absolute; top: 0.1875rem; right: 0.1875rem;
  width: 0.3125rem; height: 0.3125rem; border-radius: 50%;
  background: var(--accent);
}

.academic-filter-menu {
  position: fixed; z-index: 1000;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 0.5rem; box-shadow: var(--shadow);
  padding: 0.25rem; min-width: 10.5rem; max-width: 15rem;
  max-height: 70vh; overflow-y: auto;
  user-select: none;
}
.af-group-label {
  font-size: 0.625rem; font-weight: 700; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--text-muted);
  padding: 0.375rem 0.5rem 0.25rem;
}
.af-opt {
  display: flex; align-items: center; gap: 0.375rem; width: 100%;
  background: none; border: none; border-radius: 0.375rem;
  padding: 0.375rem 0.5rem; font: inherit; font-size: 0.8125rem;
  color: var(--text); text-align: left; cursor: pointer;
}
.af-opt:hover { background: var(--surface2); }
.af-opt.is-on { color: var(--primary); font-weight: 600; }
/* Fixed-width so the labels line up whether or not a row is ticked. */
.af-tick { flex: 0 0 0.75rem; font-size: 0.75rem; line-height: 1; }
.af-sep { height: 1px; margin: 0.25rem 0.25rem; background: var(--border); }
.af-reset { color: var(--text-muted); }

.academic-list { display: flex; flex-direction: column; gap: 0.375rem; flex: 1; overflow-y: auto; }
/* The scrollbar lives in the section's own right margin, not on the chips:
   the list reaches 0.625rem past their edge and gives that strip back as
   padding, so the chips keep their width and line up with the + above, and
   a bar -- macOS draws it over the content -- has a lane of its own. On the
   navy panel it is a light, quiet thumb rather than the page's grey one. */
.academic-list {
  margin-right: -0.625rem; padding-right: 0.625rem;
  scrollbar-width: thin; scrollbar-color: rgba(255,255,255,0.18) transparent;
}
.academic-list::-webkit-scrollbar { width: 0.3125rem; }
.academic-list::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.18); border-radius: 0.375rem; }
.academic-list::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.3); }

.academic-chip {
  background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.12);
  border-radius: var(--radius); padding: 0.625rem 0.75rem;
  cursor: pointer; transition: border-color 0.15s, background 0.15s;
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
}
/* Homework and exams/deadlines are two peers of one list, switched rather
   than stacked: the two tabs sit where the section title used to be, at the
   same weight and size, with the peer's filter and + beside them. The word
   showing is lit and underlined in the panel's soft green -- the same green
   in light and dark, since the panel is navy in both (--primary was navy in
   light mode, and vanished). The line is drawn, not bordered: it takes no
   room, so the words stay on the 1.375rem line of the + and filter and all
   of them share one centre. Each tab is only as wide as its own word, so the
   line measures the label. */
.af-peer-head { gap: 0.5rem; }
.af-peer-tabs { display: flex; align-items: center; gap: 0.875rem; min-width: 0; }
.af-tab {
  position: relative;
  flex: 0 1 auto; min-width: 0; height: 1.375rem; padding: 0;
  display: flex; align-items: center; line-height: 1;
  background: none; border: none;
  color: rgba(255,255,255,0.45); font: inherit; letter-spacing: inherit;
  cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  transition: color 0.15s;
}
.af-tab::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0;
  height: 0.125rem; border-radius: 1px; background: #A5E0A4;
  opacity: 0; transform: scaleX(0.6); transition: opacity 0.18s, transform 0.18s;
}
.af-tab:hover { color: rgba(255,255,255,0.7); }
.af-tab.is-active { color: rgba(255,255,255,0.9); }
.af-tab.is-active::after { opacity: 1; transform: none; }
.af-tab:focus-visible { outline: 0.125rem solid rgba(255,255,255,0.5); outline-offset: 0.125rem; border-radius: 0.25rem; }
@media (prefers-reduced-motion: reduce) { .af-tab::after { transition: none; } }
.academic-chip.type-deadline { cursor: pointer; }
.academic-date-tag {
  font-size: 0.625rem; font-weight: 700; padding: 0.0625rem 0.375rem; border-radius: 62.4375rem;
  color: #f5b544; background: rgba(245,181,68,0.14);
}
.academic-chip.type-assignment, .academic-chip.type-deadline, .academic-chip.type-project, .academic-chip.type-exam { background: rgba(219,234,254,0.08); border-color: rgba(219,234,254,0.16); }
.academic-chip:hover { border-color: rgba(255,255,255,0.25); background: rgba(255,255,255,0.12); }
.academic-chip.selected {
  outline: 0.125rem solid var(--primary);
  outline-offset: -0.125rem;
}
.academic-chip-top { display: flex; align-items: flex-start; gap: 0.5rem; margin-bottom: 0.25rem; }
.academic-chip-title {
  font-size: 0.8125rem; font-weight: 500; color: rgba(255,255,255,0.9); line-height: 1.35;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}

.academic-chip-meta { font-size: 0.6875rem; line-height: 1; color: rgba(255,255,255,0.5); display: flex; align-items: center; gap: 0.3125rem; }
.subject-dot { width: 0.375rem; height: 0.375rem; border-radius: 50%; flex-shrink: 0; cursor: pointer; }
.subject-dot:hover { opacity: 0.8; }
.academic-chip-flags { display: flex; align-items: center; gap: 0.3125rem; margin-left: auto; flex-shrink: 0; }
.academic-chip-subject { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; }
.academic-chip-subject:hover { color: rgba(255,255,255,0.8); }

.due-badge { margin-left: auto; font-size: 0.625rem; font-weight: 600; flex-shrink: 0; }
.due-badge.urgent { color: #FCA5A5; }
.due-badge.soon   { color: #FDE68A; }
.due-badge.ok     { color: rgba(255,255,255,0.4); }

.academic-chip.ignored {
  opacity: 0.45;
}
.academic-chip.ignored .academic-chip-title {
  color: rgba(255,255,255,0.5);
}
.ignored-badge {
  font-size: 0.5625rem;
  line-height: 1;
  color: rgba(255,255,255,0.35);
  background: rgba(255,255,255,0.08);
  padding: 0.0625rem 0.3125rem;
  border-radius: 0.375rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.3px;
}
.stale-sync-badge {
  font-size: 0.5625rem;
  line-height: 1;
  color: var(--amber, #F59E0B);
  background: rgba(245,158,11,0.14);
  padding: 0.0625rem 0.3125rem;
  border-radius: 0.375rem;
  font-weight: 600;
  cursor: pointer;
}
.stale-sync-badge:hover { background: rgba(245,158,11,0.24); }

/* Small status lamp on Grades' own subject-grid cards (public/js/grades.js
   renderSubjectGrid) -- unrelated to the sidebar's Subject Status/focus
   section below, but sharing the same three status colors. It reuses the
   theme's --green/--amber/--red tokens so the dot and the card's trend
   arrow speak one palette (the stock-board look), saturated rather than
   pastel, and the soft halo keeps the tiny dot legible on any surface. */
.load-dot { width: 0.5rem; height: 0.5rem; border-radius: 50%; flex-shrink: 0; }
.load-dot.ok      { background: var(--green); box-shadow: 0 0 0 0.1875rem color-mix(in srgb, var(--green) 18%, transparent); }
.load-dot.warning { background: var(--amber); box-shadow: 0 0 0 0.1875rem color-mix(in srgb, var(--amber) 18%, transparent); }
.load-dot.risk    { background: var(--red);   box-shadow: 0 0 0 0.1875rem color-mix(in srgb, var(--red)   18%, transparent); }

.load-list { display: flex; flex-direction: column; gap: 0.1875rem; flex: 1; overflow-y: auto; }
/* Flat row, not a card -- a left sideline in the SUBJECT's own identity
   color (set inline per row, arbitrary user-picked hex) for who this is,
   the message text's own color (risk/warning/ok, below) for how urgent it
   is. Two separate signals, kept visually separate rather than doubled up
   on one element. */
.focus-item {
  display: flex; flex-direction: column; gap: 0.125rem;
  padding: 0.3125rem 0.5rem;
  border-left: 0.1875rem solid transparent;
  border-radius: 0.25rem;
  /* --subject-color is set inline per row (app.js's renderLoadSignals,
     same value as the border-left-color next to it) -- color-mix tints the
     background a slight touch of the subject's own identity color instead
     of a flat neutral wash, falling back to the old flat tint if the
     variable is somehow missing. */
  background: color-mix(in srgb, var(--subject-color, transparent) 10%, rgba(255,255,255,0.025));
  cursor: pointer;
  transition: background 0.12s ease, opacity 0.12s ease;
}
.focus-item:hover { background: color-mix(in srgb, var(--subject-color, transparent) 18%, rgba(255,255,255,0.06)); }
.focus-item.ok      { opacity: 0.6; }
.focus-item.ok:hover { opacity: 1; }
.focus-subject { font-weight: 600; font-size: 0.75rem; color: rgba(255,255,255,0.88); }
.focus-next { font-size: 0.6875rem; line-height: 1.3; color: rgba(255,255,255,0.72); font-variant-numeric: tabular-nums; }
.focus-next.today { color: #86EFAC; font-weight: 600; }

/* ── Timetable strip (sidebar, below Subjects) ──────────────────────────────
   Deliberately not a .sidebar-section: it's a collapsible footer-ish strip
   pinned under the scrolling Subjects list, not another section competing
   for the same vertical space. Lives on the sidebar's fixed dark surface,
   so rgba-white values here rather than the theme vars the modal below
   uses. */
/* The section itself is only ever its header row tall. Opening it doesn't
   grow it downwards -- the day flies OUT to the right of the sidebar, over
   the calendar, so reading tomorrow never costs the Subjects list above it
   any room. (That also retires the drag-to-resize handle this section used
   to need: it no longer competes with anything for height.) */
.tt-section {
  flex-shrink: 0;
  border-top: 1px solid rgba(255,255,255,0.08);
  padding: 0.5rem 1.125rem 0.625rem;
  position: relative;
  display: flex; flex-direction: column;
  height: auto; min-height: 0;
}
/* Title row mirrors .sidebar-section-title above it: label on the left, its
   one action pinned right -- the same place Academic keeps its "+". */
.tt-head-row { display: flex; align-items: center; gap: 0.375rem; flex-shrink: 0; }
.tt-head {
  display: flex; align-items: center; gap: 0.375rem; flex: 1; min-width: 0;
  background: none; border: none; padding: 0.125rem 0; cursor: pointer;
  color: rgba(255,255,255,0.45); font-size: 0.75rem; font-weight: 600;
  font-family: inherit; letter-spacing: -0.1px; text-align: left;
}
.tt-head:hover { color: rgba(255,255,255,0.7); }
.tt-chevron { flex-shrink: 0; transition: transform 0.18s var(--ease, ease); }
/* Open flips it to point back at the sidebar: the same arrow that offered
   the panel now offers to put it away. */
.tt-section:not(.collapsed) .tt-chevron { transform: rotate(180deg); }
.tt-head-label { flex-shrink: 0; }
.tt-head-action {
  flex-shrink: 0;
  background: none; border: none; padding: 0.0625rem 0.125rem; cursor: pointer;
  font-family: inherit; font-size: 0.6875rem; font-weight: 600;
  color: rgba(255,255,255,0.9); transition: color 0.15s ease;
}
.tt-head-action:hover { color: rgba(255,255,255,1); }
/* Fixed, not absolute: .sidebar is overflow:hidden, so anything positioned
   inside it would simply be clipped at its edge. ttSetCollapsed measures the
   header and sets left/bottom, which also keeps the panel glued to the
   sidebar when it's dragged wider. */
/* Reads as the sidebar carrying on past its own edge rather than a card
   parked next to it: no left border, no rounding on the side that meets
   the sidebar, and the shadow thrown only rightwards, over the calendar.
   ttPositionFlyout butts it up against the sidebar with no gap. */
.tt-body {
  position: fixed; z-index: 40;
  width: 17rem; max-height: min(28rem, 70vh);
  display: flex; flex-direction: column;
  padding: 0.75rem 0.875rem;
  background: var(--sidebar-bg);
  border: 1px solid rgba(255,255,255,0.12);
  border-left: none;
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  box-shadow: 0.375rem 0 1.75rem rgba(0,0,0,0.32);
  animation: tt-flyout 0.16s var(--ease, ease);
}
@keyframes tt-flyout {
  from { opacity: 0; transform: translateX(-0.375rem); }
  to   { opacity: 1; transform: none; }
}
.tt-section.collapsed .tt-body { display: none; }
.tt-list { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 0.5rem; overflow-y: auto; }
.tt-group { display: flex; flex-direction: column; gap: 0.125rem; }
.tt-group-label {
  font-size: 0.6875rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.5px; color: rgba(255,255,255,0.35);
  padding-left: 0.125rem; margin-bottom: 0.125rem;
}
.tt-group-label.is-today { color: #86EFAC; }
/* Time in a fixed column so the subjects line up down the list -- the whole
   reason the day is a heading above rather than repeated per row. No filled
   background: five tinted blocks directly under the Subjects cards (which
   ARE filled) turned the bottom of the sidebar into a wall of boxes. The
   colour bar alone is enough to tie a row to its subject. */
/* Wide enough for a 12-hour "11:00 AM" without wrapping -- the column is
   fixed so the subjects line up, which means it has to fit the longest
   time the locale can produce, not the shortest. */
.tt-row {
  display: grid; grid-template-columns: 4.25rem 1fr; align-items: baseline;
  gap: 0.375rem; padding: 0.1875rem 0 0.1875rem 0.5rem;
  border-left: 0.1875rem solid var(--subject-color, rgba(255,255,255,0.2));
  font-size: 0.75rem;
}
.tt-row-time {
  color: rgba(255,255,255,0.45); font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.tt-row-subject {
  color: rgba(255,255,255,0.85); font-weight: 500;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tt-empty { font-size: 0.75rem; line-height: 1.45; color: rgba(255,255,255,0.7); padding: 0.5rem 0; }

/* Read-only timetable modal (Grades/Curriculum) */
.ng-tt-table { display: flex; flex-direction: column; gap: 0.375rem; }
.ng-tt-row {
  display: flex; align-items: center; gap: 0.75rem;
  padding: 0.5rem 0.625rem; border-radius: 0.375rem;
  background: rgba(255,255,255,0.04); border-left: 0.1875rem solid;
}
.ng-tt-dow { font-size: 0.75rem; font-weight: 600; min-width: 6rem; color: rgba(255,255,255,0.8); }
.ng-tt-time { font-size: 0.75rem; font-variant-numeric: tabular-nums; color: rgba(255,255,255,0.5); min-width: 3.5rem; }
.ng-tt-subj { font-size: 0.8125rem; color: rgba(255,255,255,0.9); }

/* ── Timetable modal (the actual weekly grid) ───────────────────────────── */
/* Doubled-up selector on purpose: this block sits above .modal's own
   `width: 30rem` in the file, so a bare .tt-modal would lose the tie and
   the week would fold into two columns. will-change keeps the entrance
   (a transform on a very wide, blurred-overlay layer) on the compositor. */
.modal.tt-modal { width: min(72rem, 97vw); max-width: 100%; will-change: transform; }
/* The GRID owns scrolling now, so .tt-modal-body no longer clips: the grid
   below is capped in height and scrolls both ways, keeping its headers. */
/* A calendar day view: one column per day plus a time gutter, every class
   positioned against the axis and sized by its duration, so a double period
   reads as twice the single next to it. The column count is set inline by
   renderTimetableGrid rather than left to auto-fit: auto-fit wraps the
   overflow onto a second row, which puts Friday underneath Monday and reads
   as a different week. Scrolling keeps the days in one line. */
.tt-grid { display: grid; gap: 0.375rem; overflow: auto; max-height: min(68vh, 46rem); padding-bottom: 0.25rem; }
.tt-day {
  display: flex; flex-direction: column; min-width: 0;
}
/* Pinned to the top of the scroll region: the axis and day headers hold
   their place while a long day scrolls beneath them. */
.tt-day-name {
  position: sticky; top: 0; z-index: 5;
  display: flex; align-items: center; justify-content: space-between; gap: 0.25rem;
  font-size: 0.6875rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.4px; color: var(--text-muted);
  height: 1.375rem; padding-bottom: 0.25rem; flex-shrink: 0;
  border-bottom: 1px solid var(--border2);
  background: var(--surface);
}
/* The hour ticks sit against the same origin as the class blocks next to
   them, offset by their own line height so a label reads as belonging to the
   rule it names rather than hanging below it. */
.tt-axis { display: flex; flex-direction: column; min-width: 0; }
/* The axis pins to the left edge of the scroll region so hour labels stay
   visible no matter how far right the week is scrolled. Its solid card
   background keeps day columns from peeking through underneath. */
.tt-axis {
  position: sticky; left: 0; z-index: 4; background: var(--surface);
  display: flex; flex-direction: column; min-width: 0;
}
.tt-axis .tt-day-name { border-bottom-color: transparent; }
.tt-axis-body { position: relative; height: var(--tt-body-h); }
.tt-axis-hour {
  position: absolute; right: 0.375rem; transform: translateY(-0.4em);
  font-size: 0.625rem; color: var(--text-muted);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* Hour rules as a background rather than elements: one gradient beats a
   dozen absolutely positioned divs per day, and it stays put when the axis
   range changes. */
.tt-day-body {
  position: relative; height: var(--tt-body-h);
  border-left: 1px solid var(--border2);
  background-image: repeating-linear-gradient(
    to bottom,
    var(--border2) 0, var(--border2) 1px,
    transparent 1px, transparent var(--tt-hour)
  );
}
/* The week is ALWAYS Mon-Sun, so there is no add/remove-day +. Instead a
   centred + / - pair stretches or shrinks the HOUR axis downwards, one row
   at a time; the - can only ever take back hours the + added, never the ones
   classes occupy. It sits BELOW the grid, outside the scroll region, so the
   sticky headers can never cover it. */
.tt-hours-ctl {
  display: flex; align-items: center; justify-content: center;
  gap: 0.5rem; padding-top: 0.375rem; flex-shrink: 0;
}
.tt-hours-ctl button {
  flex: none; width: 2.25rem; height: 1.375rem;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 1px dashed var(--border2); border-radius: var(--radius-sm);
  color: var(--text-muted); cursor: pointer; font-family: inherit;
  font-size: 0.8125rem; line-height: 1; padding: 0;
  transition: color 0.12s, border-color 0.12s;
}
.tt-hours-ctl button:hover:not(:disabled) { color: var(--text); border-color: var(--border); }
.tt-hours-ctl button:disabled { opacity: 0.4; cursor: default; }
.tt-class {
  position: absolute; overflow: hidden;
  display: flex; flex-direction: column; gap: 0.0625rem;
  text-align: left; cursor: pointer;
  background: var(--surface2); border: 1px solid var(--border2);
  border-left: 0.1875rem solid var(--subject-color, var(--border2));
  border-radius: var(--radius-sm); padding: 0.1875rem 0.3125rem;
  font-family: inherit; color: var(--text);
  transition: border-color 0.12s ease, background 0.12s ease;
}
.tt-class:hover { background: var(--surface); border-color: var(--border); z-index: 2; }
.tt-class-subject {
  font-size: 0.75rem; font-weight: 600; line-height: 1.2;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tt-class-meta {
  font-size: 0.625rem; color: var(--text-muted); line-height: 1.2;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* A short slot is still drawn true to its length -- it just can't carry both
   lines, so it keeps the one that identifies it. */
.tt-class.is-tight { justify-content: center; padding-block: 0.0625rem; }
.tt-class.is-tight .tt-class-meta { display: none; }
/* Click To Add: hovering an empty hour band under a day ghost-presents the
   exact one-hour slot a click will fill -- the hour band the pointer lands
   in, not the minute under the cursor. */
.tt-day-hover {
  position: absolute; top: 0; left: 0; right: 0; height: var(--tt-hour);
  display: flex; align-items: center; justify-content: center;
  color: var(--primary, #2563EB); font-size: 0.875rem; line-height: 1;
  border: 1px dashed var(--primary, #2563EB); border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--primary, #2563EB) 8%, transparent);
  pointer-events: none; opacity: 0; will-change: transform; transition: opacity 0.12s ease;
}
.tt-day-hover::before { content: '+'; font-weight: 600; }
.tt-day-hover.active { opacity: 1; }
/* Editing panel under the grid, not inside a day column -- six fields in a
   ~7.5rem column meant every one of them was clipped or stacked. Full width
   lets them sit in a row that wraps, each properly labelled. The class being
   edited stays visible in the grid above, marked with .is-editing. */
.tt-edit {
  background: var(--surface2); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 0.75rem; margin-top: 0.75rem;
}
.tt-edit-fields {
  display: grid; gap: 0.5rem;
  grid-template-columns: repeat(auto-fit, minmax(6.5rem, 1fr));
}
/* Subject is the field people actually type in, so it gets the room. */
.tt-edit-subject { grid-column: span 2; }
.tt-edit-field { display: flex; flex-direction: column; gap: 0.125rem; min-width: 0; }
.tt-edit-field > span {
  font-size: 0.625rem; font-weight: 600; letter-spacing: 0.2px;
  text-transform: uppercase; color: var(--text-muted);
}
.tt-edit input, .tt-edit select {
  font-size: 0.75rem; padding: 0.3125rem 0.375rem; width: 100%; min-width: 0;
}
.tt-edit-actions { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 0.625rem; }
.tt-edit-actions .btn { padding: 0.3125rem 0.875rem; font-size: 0.75rem; }
/* Opens upward. The editor is the last thing in the modal body, which is
   itself a scroll container, so a dropdown hanging below the subject field
   gets clipped by .tt-modal-body's own overflow.
   Doubled-up selector: .edu-combo-results sets `top` and sits LOWER in this
   file, so a bare .tt-combo-up loses the tie and ends up with both top and
   bottom pinned -- which collapses the box to nothing and renders as a
   dropdown that opens but can't be seen. */
.edu-combo-results.tt-combo-up { top: auto; bottom: calc(100% + 0.25rem); max-height: 11rem; }
/* The subject's colour, so the list reads like the coloured classes in the
   grid above rather than plain text. */
.tt-combo-dot {
  width: 0.5rem; height: 0.5rem; border-radius: 50%;
  flex-shrink: 0; align-self: center;
}
/* Ties the panel back to the cell it's editing. */
.tt-class.is-editing {
  border-color: var(--accent, #2563EB);
  box-shadow: 0 0 0 1px var(--accent, #2563EB);
}
.tt-modal-footer { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-top: 1rem; }
.tt-upload-btn { display: inline-flex; align-items: center; justify-content: center; padding: 0; width: 2rem; height: 2rem; }
.tt-footer-right { display: flex; gap: 0.5rem; }
.tt-modal-status { font-size: 0.75rem; color: var(--text-muted); margin-top: 0.75rem; text-align: center; }
.tt-modal-status.error { color: var(--danger, #DC2626); }
.tt-modal.drag-over { outline: 0.125rem dashed var(--accent, #2563EB); outline-offset: 0.25rem; }
.tt-grid-empty { font-size: 0.8125rem; color: var(--text-muted); text-align: center; padding: 2rem 1rem; line-height: 1.5; }

/* Lettered tile for a registry with no logo anyone may reuse. Sized and
   positioned like the brand SVGs in the same row, so the list reads level. */
.registry-mark {
  /* One knob, so a surface that needs a bigger mark sets the size and the
     corner radius, the letter and the artwork inside all follow. The ratios
     below reproduce the original 18px tile exactly (11px glyph, 14px
     favicon), so changing this variable is the only thing that ever moves. */
  --registry-mark-size: 1.125rem;
  display: grid; place-content: center; flex-shrink: 0;
  width: var(--registry-mark-size); height: var(--registry-mark-size);
  border-radius: calc(var(--registry-mark-size) * 0.2778);
  color: #fff; font-size: calc(var(--registry-mark-size) * 0.5556);
  font-weight: 700; line-height: 1;
}
/* A real logo sits in the same tile as a lettered one, so a provider with a
   published mark and one without still read as the same kind of row. */
.registry-mark.is-logo svg {
  display: block;
  /* Overrides the width/height on the SVG itself, which is written for
     the default tile size. */
  width: calc(var(--registry-mark-size) * 0.6111);
  height: calc(var(--registry-mark-size) * 0.6111);
}
/* A favicon fetched from the provider's own site. Its artwork usually
   carries the brand colour already, so the tile goes white and lets it --
   a red mark on a red tile would disappear. Inset slightly so a square
   favicon does not touch the tile's rounded corners. */
.registry-mark.is-favicon {
  background: #fff !important; box-shadow: inset 0 0 0 1px var(--border);
  /* The image is the tile now, so it has to be clipped to the same rounded
     corners rather than overhanging them. */
  overflow: hidden;
}
/* Fills the tile rather than sitting inset inside it. A favicon is drawn to
   its own square with its own padding baked in, and shrinking it further left
   some marks floating in white -- worst on the ones whose artwork already had
   generous margins. object-fit stays `contain` so a non-square favicon keeps
   its proportions instead of being stretched to fit. */
.registry-mark.is-favicon img {
  display: block; object-fit: contain;
  width: 100%; height: 100%;
}

/* Back arrow in a modal header that has one. Mirrors .modal-close opposite
   it so the two ends of the header balance. */
.modal-back {
  width: 1.75rem; height: 1.75rem; display: grid; place-content: center;
  margin-right: 0.125rem; flex-shrink: 0;
  background: none; border: none; border-radius: 0.5rem; cursor: pointer;
  color: var(--text-muted); transition: background 0.15s, color 0.15s;
}
.modal-back:hover { background: var(--surface2); color: var(--text); }
.modal-back.hidden { display: none; }

/* A broken registry on the Integrations row. Same red the manage panel uses
   for the same reason: a silently failing sync is homework that never
   arrives, and this line may be the only place it ever shows. */
.settings-row-sub.is-error { color: var(--danger, #DC2626); }
/* The row's sync button spins while every connected account runs. */
.settings-icon-btn.is-spinning svg { animation: spin 0.8s linear infinite; }
/* Top-aligned, not centred: a registry whose status wrapped to two lines
   (an error message does) left the mark and the buttons floating halfway down
   a taller row, lined up with nothing. */
.cal-card[data-registry] .cal-card-head { align-items: flex-start; }
.cal-card[data-registry] .cal-card-head > div:last-child { margin-top: -0.125rem; }
/* Bigger here than in the picker, and not because this surface is special:
   the picker's row is a single line of text, this card is two (name over
   sync status) plus buttons, so the tile that reads level with a row reads
   lost against a card twice its height. It spans both text lines instead. */
.cal-card[data-registry] .cal-card-head > .registry-mark {
  --registry-mark-size: 1.75rem;
  margin-top: 0.0625rem;
}
.registry-status { display: block; font-size: 0.71875rem; color: var(--text-muted); line-height: 1.3; }
/* A registry that stopped working is the one thing on this card worth
   shouting about -- a silently failing sync is homework that never arrives. */
.registry-status.is-error { color: var(--danger, #DC2626); }
.cal-sync-failing { color: var(--danger, #DC2626); }
/* Whose account this is, along the bottom of the card, opposite the
   auto-sync toggle. It was on a full-width line of its own, which gave a
   school username a whole row to itself and made every card taller than it
   needed to be -- and an email still wrapped onto two. Here it takes only the
   room that is left and gives up the rest gracefully: one line, ellipsis, and
   the full value in the tooltip for the cases that don't fit. */
.registry-foot {
  display: flex; align-items: center;
  gap: 0.75rem; margin-top: 0.5rem; min-width: 0;
}
/* The account on the right, the toggle on the left -- the same side the
   connected calendar cards put their address on, so the two managed-account
   lists read the same way.

   It takes what it needs and no more, rather than a fixed share of the row.
   Claiming half meant "PAOLO NAVAT…" beside a checkbox label with room to
   spare -- a short name clipped for nothing. Only a genuinely long one, an
   email, now hits the ellipsis, which is the case this was for. */
.registry-who {
  min-width: 0; flex: 0 1 auto; margin-left: auto; text-align: right;
  font-size: 0.6875rem; line-height: 1.35; color: var(--text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.registry-auto {
  display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0;
  font-size: 0.75rem; color: var(--text-muted); cursor: pointer;
}
/* On a phone the toggle's own label fills the row on its own, so sharing it
   clips a name that would otherwise fit easily. One line each instead: the
   card grows by a line rather than hiding something it had room for. */
@media (max-width: 30rem) {
  .registry-foot { flex-direction: column; align-items: stretch; gap: 0.375rem; }
  .registry-who { max-width: 100%; margin-left: 0; }
}
.registry-empty { font-size: 0.75rem; color: var(--text-muted); padding: 0.125rem 0; line-height: 1.45; }
.registry-privacy {
  font-size: 0.71875rem; color: var(--text-muted); line-height: 1.5;
  background: var(--surface2); border: 1px solid var(--border2);
  border-radius: var(--radius-sm); padding: 0.625rem 0.75rem; margin-top: 0.25rem;
}

/* ── Country picker ───────────────────────────────────────────────────────── */
/* Geometry, colours and behaviour copied from .lang-picker above rather than
   invented: they are the same control for the same reason, and two dropdowns
   that nearly match is worse than one that does. */
.country-pick-native { display: none; }
.country-pick { position: relative; }
.country-pick-btn {
  width: 100%; display: flex; align-items: center; gap: 0.5rem;
  background: var(--surface2); border: 1px solid var(--border);
  border-radius: var(--radius); color: var(--text);
  padding: 0.6875rem 0.8125rem; font-size: 0.875rem; font-family: var(--font);
  cursor: pointer; transition: border-color 0.15s;
}
.country-pick-btn:hover { border-color: var(--border2); }
.country-pick-btn[aria-expanded="true"] {
  border-color: var(--primary);
  box-shadow: 0 0 0 0.2188rem color-mix(in srgb, var(--primary) 12%, transparent);
}
.country-pick-face { display: flex; align-items: center; gap: 0.5rem; flex: 1; min-width: 0; }
.country-pick-name { flex: 1; text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.country-pick-caret { flex-shrink: 0; color: var(--text-muted); transition: transform 0.15s; }
.country-pick-btn[aria-expanded="true"] .country-pick-caret { transform: rotate(180deg); }
/* A flag is a picture of a rectangle: without a hairline the mostly-white
   ones (Japan, Poland) dissolve into the row and read as a failed image. */
.country-flag {
  flex-shrink: 0; width: 1.25rem; height: 0.875rem; border-radius: 0.125rem;
  object-fit: cover; display: inline-block; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15);
}
.country-flag-blank { background: var(--surface); }
/* position: fixed and placed from JS, for the same reason the language
   picker's menu is: this sits inside .settings-panes, which scrolls, and an
   absolutely-positioned menu is clipped to that pane instead of floating
   over the modal. */
.country-pick-menu {
  position: fixed; z-index: 200;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 0.25rem;
}
.country-pick-list { max-height: 13.75rem; overflow-y: auto; }
/* The list holds focus so it can take type-ahead keys, but it is the row
   highlight that shows where you are -- a ring around the whole box would
   read as an error. */
.country-pick-list:focus, .country-pick-list:focus-visible { outline: none; }
.country-pick-row {
  display: flex; align-items: center; gap: 0.5rem; width: 100%;
  padding: 0.5rem 0.5625rem; border-radius: 0.5rem; border: none; background: none;
  color: var(--text); font-size: 0.875rem; font-family: var(--font); cursor: pointer; text-align: left;
}
.country-pick-row > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.country-pick-row:hover, .country-pick-row.is-active { background: var(--surface2); }
.country-pick-row[aria-selected="true"] { font-weight: 700; }

/* ── Urgent registry homework ─────────────────────────────────────────────── */
/* Reuses .study-time-prompt-card's geometry -- same corner, same size, same
   entrance -- so the app has one "something needs your attention right now"
   shape rather than two that nearly match. Only what's inside differs. */
.registry-alert-card { border-left: 0.1875rem solid var(--amber, #F59E0B); }
.registry-alert-head { display: flex; align-items: center; gap: 0.5rem; margin: 0 1.75rem 0.75rem 0; }
.registry-alert-title { font-size: 0.9375rem; font-weight: 650; color: var(--text); line-height: 1.3; }
.registry-alert-list { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 1.125rem; }
/* More than a couple and the card would run off the screen -- the rest are
   in the sidebar like any other assignment, which is where they belong. */
.registry-alert-more { font-size: 0.75rem; color: var(--text-muted); padding-left: 0.625rem; }
/* The two actions split the card's full width rather than huddling at one
   end. Doubled-up selector because .study-time-prompt-row's own
   `.generate-btn { width: auto; flex-shrink: 0 }` sits LOWER in this file and
   would otherwise win the tie and shrink it back. */
/* The two actions split the card's full width rather than huddling at one
   end. A two-column grid, not flex:1 — the buttons come from different
   families with different borders and padding, so equal flex GROWTH still
   left them a few pixels apart. 1fr 1fr is exact whatever the box model.
   Doubled-up selector because .study-time-prompt-row's own
   `.generate-btn { width: auto; flex-shrink: 0 }` sits LOWER in this file and
   would otherwise win the tie and shrink it back. */
.study-time-prompt-row.registry-alert-row {
  display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem;
}
.study-time-prompt-row.registry-alert-row .btn,
.study-time-prompt-row.registry-alert-row .generate-btn {
  width: 100%; min-width: 0; margin-left: 0; justify-content: center;
}

/* ── Connected calendar cards ────────────────────────────────────────────── */
.cal-card {
  border: 1px solid var(--border); border-radius: 0.625rem;
  padding: 0.625rem 0.75rem;
}
.cal-card-head { display: flex; align-items: center; gap: 0.625rem; }
/* The account's email, on its own line along the bottom of the card. It used
   to sit on the title line, boxed in between a swatch and two buttons, where
   anything longer than about twenty characters was cut off.
   break-word isn't enough here: an address is a single unbroken token, so it
   needs break-all to wrap at all rather than overflowing its box. */
.cal-card-sub {
  margin-top: 0.375rem;
  font-size: 0.6875rem; line-height: 1.35; color: var(--text-muted);
  word-break: break-all;
  /* Right, under the card's actions: the left column says what the account
     is, so the address closes the right one rather than adding a third line
     under the title. Its own line still, not the meta row -- there the space
     left between a sync time and two buttons is about 120px, and an address
     clipped to 120px identifies no account at all. */
  text-align: right;
}
/* Inside the Lists modal the card has its own padding on the header row and
   a bordered body below, so the address is indented to line up with the
   title rather than with the card's edge. */
.cal-manage > .cal-card-sub { margin: -0.25rem 0 0; padding: 0 0.75rem 0.5rem; }
/* The card's border carries the calendar's colour -- the one set in the Lists
   modal -- instead of a swatch beside it. A 14px dot is a detail you have to
   go looking for; the card's own edge is already in view, and two Google
   accounts in different colours stop being two identical rows.

   color-mix against the border colour rather than a fixed hex, so one rule
   holds in both themes and the edge stays an edge: at full strength every
   card would read as selected, or as an error. A little more of the colour
   than before, since a 2px edge at 45% looked muddier than a 1px one did.

   The glow is the same colour again, wide and weak. It is there to make the
   border look deliberate rather than like a stray outline -- not to light the
   card up, which is what a tighter or stronger shadow does. */
.cal-card[data-account] {
  border-width: 0.125rem;
  border-color: color-mix(in srgb, var(--cal-color, var(--border)) 60%, var(--border));
  box-shadow: 0 0.0625rem 0.625rem color-mix(in srgb, var(--cal-color, transparent) 20%, transparent);
}

/* Says whose colour is sitting in the swatch next to it. Only rendered while
   a subject is actually picked -- with none, there's no name to give. */
.event-color-label {
  display: inline-flex; align-items: center; gap: 0.375rem;
  font-size: 0.75rem; color: var(--text-muted); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.event-color-label.hidden { display: none; }
.event-color-dot {
  width: 0.5rem; height: 0.5rem; border-radius: 50%; flex-shrink: 0;
}

/* ── Repeating events ───────────────────────────────────────────────────── */
/* The custom rule builder, shown under the Repeats select only when Custom is
   picked -- a student setting "every week" should never have to walk past an
   interval box and a weekday row to do it. */
.repeat-panel {
  background: var(--surface2); border: 1px solid var(--border2);
  border-radius: var(--radius-sm); padding: 0.625rem 0.75rem;
  margin: -0.25rem 0 0.875rem; display: flex; flex-direction: column; gap: 0.5rem;
}
.repeat-panel.hidden { display: none; }
.repeat-row { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.repeat-row.hidden { display: none; }
.repeat-label {
  font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.2px;
  text-transform: uppercase; color: var(--text-muted); flex-shrink: 0;
}
.repeat-panel select { font-size: 0.8125rem; padding: 0.3125rem 0.375rem; width: auto; }
.repeat-interval { width: 4rem; font-size: 0.8125rem; padding: 0.3125rem 0.375rem; flex-shrink: 0; }
.repeat-interval.hidden, .repeat-panel input[type="date"].hidden, .repeat-label.hidden { display: none; }
.repeat-panel input[type="date"] { font-size: 0.8125rem; padding: 0.3125rem 0.375rem; width: auto; }
.repeat-days { display: flex; gap: 0.25rem; flex-wrap: wrap; }
/* Two letters, not one: several languages share a first letter across two
   weekdays, and a row of ambiguous initials is worse than a slightly wider
   chip. */
.repeat-day {
  min-width: 2rem; padding: 0.25rem 0.375rem;
  background: none; border: 1px solid var(--border2); border-radius: var(--radius-sm);
  color: var(--text-muted); cursor: pointer; font-family: inherit;
  font-size: 0.6875rem; font-weight: 600; text-transform: uppercase;
  transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.repeat-day:hover { color: var(--text); border-color: var(--border); }
.repeat-day.on {
  background: var(--accent, #2563EB); border-color: var(--accent, #2563EB); color: #fff;
}
/* Says back what the rule actually means, so a wrong interval or a forgotten
   weekday is visible before saving rather than after the first wrong reminder. */
.repeat-summary { font-size: 0.6875rem; color: var(--text-muted); line-height: 1.4; }
/* On an occurrence of an existing series the rule is edited through the scope
   picker, not here -- see openEventModal. */
.repeat-panel.is-locked { opacity: 0.55; pointer-events: none; }
/* The little loop on a calendar event that belongs to a series. */
.event-repeat-mark {
  display: inline-block; margin-left: 0.25rem; opacity: 0.65;
  vertical-align: -0.0625rem; flex-shrink: 0;
}
.scope-choices { display: flex; flex-direction: column; gap: 0.5rem; }
.scope-choice {
  display: flex; flex-direction: column; gap: 0.1875rem; text-align: left;
  background: var(--surface2); border: 1px solid var(--border2);
  border-radius: var(--radius-sm); padding: 0.625rem 0.75rem;
  cursor: pointer; font-family: inherit; color: var(--text);
  transition: background 0.12s, border-color 0.12s;
}
.scope-choice:hover { background: var(--surface); border-color: var(--accent, #2563EB); }
.scope-choice-title { font-size: 0.8125rem; font-weight: 600; }
.scope-choice-desc { font-size: 0.6875rem; color: var(--text-muted); line-height: 1.35; }

/* Subject Focus modal (Subject Status row click) -- a subject's own
   breakdown: status, hours-needed/coverage/item-count stats, then the
   items themselves. Runs in the normal light/dark modal theme (var(...)),
   NOT the sidebar's fixed-dark surface the classes above use -- .due-badge
   is reused for each item's due text, but its own .ok variant is a
   hardcoded light-on-dark color tuned for that sidebar, so it's overridden
   here to stay legible on a light modal background too. */
.sf-status {
  font-size: 0.8125rem; font-weight: 500; margin-bottom: 0.75rem;
  padding: 0.5rem 0.625rem; border-radius: 0.375rem;
  display: flex; flex-direction: column; gap: 0.3125rem;
}
/* The deadline and the coverage verdict are separate claims, so each gets
   its own line rather than being run together into one sentence. */
.sf-status-line { display: flex; align-items: center; gap: 0.4375rem; }
.sf-status-line svg { width: 0.875rem; height: 0.875rem; flex-shrink: 0; }
.sf-status.risk    { background: rgba(220,38,38,0.1);  color: #DC2626; }
.sf-status.warning { background: rgba(180,83,9,0.1);   color: #B45309; }
.sf-status.ok      { background: rgba(21,128,61,0.1);  color: #15803D; }

.sf-stats {
  display: flex; gap: 1.25rem; margin-bottom: 1rem;
  padding-bottom: 0.875rem; border-bottom: 1px solid var(--border);
}
.sf-stat { display: flex; flex-direction: column; }
.sf-stat-value { font-size: 1.125rem; font-weight: 700; line-height: 1.2; }
.sf-stat-label { font-size: 0.625rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.03em; }

/* Graph section: browsable via arrows between different chart FORMATS of
   the same subject's real grade data (history line, category bars) --
   same array+index paging pattern as the streak fullscreen's granularity
   arrows (navigateStreakGranularity), styled for this modal's normal
   light/dark surface instead of that view's fixed-dark fullscreen. */
.sf-graph { margin-bottom: 1rem; padding-bottom: 0.875rem; border-bottom: 1px solid var(--border); }
.sf-graph-nav { display: flex; align-items: center; justify-content: center; gap: 0.75rem; margin-bottom: 0.375rem; }
.sf-graph-arrow {
  flex-shrink: 0; width: 1.75rem; height: 1.75rem; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface2); border: 1px solid var(--border); color: var(--text-muted);
  cursor: pointer; transition: background 0.12s ease, color 0.12s ease;
}
.sf-graph-arrow:hover { background: var(--surface3); color: var(--text); }
.sf-graph-format-label { font-size: 0.75rem; font-weight: 600; color: var(--text-muted); min-width: 6rem; text-align: center; }
.sf-graph-canvas { display: flex; justify-content: center; }
.sf-graph-canvas svg { max-width: 100%; }
.sf-graph-axis { stroke: var(--border); stroke-width: 1; }
.sf-graph-axis-label { font-size: 0.4375rem; fill: var(--text-muted); font-family: inherit; }
.sf-graph-grid { stroke: var(--border); stroke-width: 0.5; opacity: 0.4; }
.sf-graph-target { stroke: var(--text-muted); stroke-width: 1; stroke-dasharray: 3,3; }
.sf-graph-bar-label { font-size: 0.375rem; fill: var(--text-muted); }
.sf-graph-empty { padding: 1.25rem 0; font-size: 0.75rem; }

.sf-items { display: flex; flex-direction: column; gap: 0.375rem; max-height: 17.5rem; overflow-y: auto; }
.sf-item {
  display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
  padding: 0.5rem 0.625rem; border-radius: 0.375rem; cursor: pointer;
  background: var(--surface2);
}
.sf-item:hover { background: var(--surface3); }
.sf-item-title { font-size: 0.8125rem; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
:is(#sf-modal-body, #ng-sf-modal-body) .due-badge.ok { color: var(--text-muted); }
:is(#sf-modal-body, #ng-sf-modal-body) .due-badge.urgent { color: var(--red); }
:is(#sf-modal-body, #ng-sf-modal-body) .due-badge.soon { color: color-mix(in srgb, var(--amber) 75%, var(--text)); }

.upgrade-banner {
  margin: 0.75rem; padding: 0.75rem;
  /* Quiet, in the sidebar's own tones: an offer, not an alarm. */
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.08); border-radius: var(--radius); font-size: 0.75rem;
}
.upgrade-banner strong { display: block; margin-bottom: 0.25rem; color: rgba(255,255,255,0.88); font-size: 0.8125rem; font-weight: 600; }
.upgrade-banner p { color: rgba(255,255,255,0.5); margin-bottom: 0.625rem; line-height: 1.4; }

.sidebar-footer {
  padding: 0.875rem 1.125rem; border-top: 1px solid rgba(255,255,255,0.08);
  display: flex; align-items: center; justify-content: space-between; flex-shrink: 0;
}
.user-info { font-size: 0.6875rem; color: rgba(255,255,255,0.5); }
.user-email { font-size: 0.6875rem; color: rgba(255,255,255,0.5); max-width: 8.75rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-plan { font-size: 0.5625rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; display: block; margin-top: 0.0625rem; }
.plan-free { color: rgba(255,255,255,0.35); }
.plan-plus { color: var(--accent); }
.plan-pro  { color: #FDE68A; }
.plan-family { color: #FDE68A; }

/* sidebar icon buttons — topbar glass family */
.sidebar .btn-ghost {
  padding: 0.375rem 0.75rem;
  border-radius: var(--radius);
  background: rgba(255,255,255,0.1);
  color: rgba(255,255,255,0.75);
  border: 1px solid rgba(255,255,255,0.16);
  -webkit-backdrop-filter: blur(0.75rem) saturate(160%);
  backdrop-filter: blur(0.75rem) saturate(160%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.12), 0 1px 0.25rem rgba(0,0,0,0.10);
  flex-shrink: 0;
      transition: background 0.15s, color 0.15s, border-color 0.15s, box-shadow 0.12s var(--ease), transform 0.12s var(--ease);
}
.sidebar .btn-ghost:hover {
  background: rgba(255,255,255,0.17);
  color: #fff;
  border-color: rgba(255,255,255,0.28);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.2), 0 0.125rem 0.375rem rgba(0,0,0,0.14);
}
.sidebar .btn-ghost:active {
  transform: translateY(0) scale(0.97);
}

/* ── Main area ─────────────────────────────────────────────────────────────── */
.main {
  flex: 1;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--bg);
}
.topbar {
  display: flex; align-items: center; gap: 0.875rem;
  padding: 1rem 1.5rem; border-bottom: 1px solid var(--border); flex-shrink: 0;
  background: var(--surface);
}
.topbar-nav {
  display: flex; align-items: center; gap: 0.125rem;
  background: var(--surface2); border-radius: var(--radius); padding: 0.25rem;
}

.nav-arrow {
  background: none; border: none; border-radius: 0.375rem;
  color: var(--text-muted); cursor: pointer; width: 1.625rem; height: 1.625rem;
  display: flex; align-items: center; justify-content: center;
  transition: background 0.12s var(--ease), color 0.12s var(--ease), box-shadow 0.12s var(--ease);
}
.nav-arrow svg { flex-shrink: 0; }
.nav-arrow:hover { background: var(--surface); color: var(--text); box-shadow: var(--shadow-sm); }

.today-btn {
  height: 1.625rem; padding: 0 0.75rem; border: none; border-radius: 0.375rem;
  background: none; color: var(--text-muted); cursor: pointer;
  font-size: 0.8125rem; font-weight: 500; font-family: var(--font);
  transition: background 0.12s var(--ease), color 0.12s var(--ease), box-shadow 0.12s var(--ease);
}
.today-btn:hover { background: var(--surface); color: var(--text); box-shadow: var(--shadow-sm); }

/* Plan | Calendar: a floating glass capsule over the bottom of the view,
   out of the header (which already has the zoom tabs). A round thumb slides
   between the two icons; buttons and thumb share one size and one gap so
   the thumb lands exactly on each icon. */
.main { position: relative; }
/* The dock: a handle at rest, the switch when opened. Both sit in the same
   grid cell so one grows out of where the other was. On desktop the handle
   is a tab rising out of the bottom edge; with the pointer near (.is-near,
   app.js) it stands a little taller with one small bounce and a soft
   light behind it. */
.mode-dock {
  position: absolute; left: 50%; bottom: 0; z-index: 30; transform: translateX(-50%);
  display: grid; place-items: end center;
}
.mode-dock > * { grid-area: 1 / 1; }
.mode-handle {
  position: relative; display: grid; place-items: center;
  width: 3.75rem; height: 1.375rem; padding: 0 0 0.0625rem; cursor: pointer; -webkit-tap-highlight-color: transparent;
  border-radius: 0.875rem 0.875rem 0 0;
  color: var(--text-muted);
  background: color-mix(in srgb, var(--surface) 80%, transparent);
  -webkit-backdrop-filter: blur(0.875rem) saturate(170%); backdrop-filter: blur(0.875rem) saturate(170%);
  border: 1px solid color-mix(in srgb, var(--border) 85%, transparent); border-bottom: 0;
  box-shadow: 0 -0.25rem 0.875rem rgba(15,26,46,0.07);
  transform-origin: 50% 100%;
  transition: height 0.32s cubic-bezier(0.34, 1.56, 0.64, 1), color 0.2s ease, box-shadow 0.25s ease, opacity 0.2s ease, transform 0.3s ease;
  animation: mode-dock-in 0.55s 0.35s cubic-bezier(0.22, 1, 0.36, 1) both;
}
/* The energy: a soft light behind the tab, only a hint of the accent. */
.mode-handle::before {
  content: ''; position: absolute; left: -1.25rem; right: -1.25rem; top: -1rem; bottom: 0; z-index: -1; pointer-events: none;
  border-radius: 62.4375rem 62.4375rem 0 0;
  background: radial-gradient(60% 90% at 50% 100%, color-mix(in srgb, var(--accent) 7%, rgba(255,255,255,0.18)), transparent 75%);
  filter: blur(0.5rem); opacity: 0; transition: opacity 0.3s ease;
}
.mode-handle svg { width: 1rem; height: 1rem; transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); }
.mode-handle .mode-handle-left { display: none; }
.mode-dock.is-near .mode-handle, .mode-handle:hover, .mode-handle:focus-visible {
  height: 1.875rem; color: color-mix(in srgb, var(--text) 75%, var(--text-muted));
  box-shadow: 0 -0.3125rem 1rem rgba(15,26,46,0.08), 0 -1px 0.375rem color-mix(in srgb, var(--accent) 5%, transparent);
}
.mode-dock.is-near .mode-handle::before, .mode-handle:hover::before { opacity: 0.7; }
.mode-dock.is-near .mode-handle svg { animation: mode-handle-bounce 0.6s cubic-bezier(0.3, 0, 0.3, 1) both; }
.mode-handle:focus-visible { outline: 0.125rem solid var(--primary); outline-offset: 0.125rem; }
@keyframes mode-handle-bounce {
  0% { transform: translateY(0); } 35% { transform: translateY(-0.25rem); } 60% { transform: translateY(0); }
  80% { transform: translateY(-1.5px); } 100% { transform: translateY(0); }
}
@keyframes mode-dock-in { from { transform: translateY(100%); } to { transform: none; } }
.mode-dock.is-open .mode-handle { opacity: 0; transform: translateY(100%); pointer-events: none; animation: none; }

.mode-switch {
  --ms-size: 2.75rem; --ms-gap: 0.375rem;
  position: relative;
  display: inline-flex; align-items: center; gap: var(--ms-gap);
  padding: 0.375rem; border-radius: 62.4375rem;
  transform-origin: 50% 100%;
  opacity: 0; transform: translateY(0.75rem) scale(0.55); filter: blur(0.375rem); pointer-events: none;
  transition: opacity 0.2s ease, transform 0.42s cubic-bezier(0.34, 1.4, 0.64, 1), filter 0.25s ease;
  background: color-mix(in srgb, var(--surface) 80%, transparent);
  -webkit-backdrop-filter: blur(0.875rem) saturate(170%);
  backdrop-filter: blur(0.875rem) saturate(170%);
  border: 1px solid color-mix(in srgb, var(--border) 80%, transparent);
  box-shadow: 0 0.625rem 1.75rem rgba(15,26,46,0.16), 0 0.125rem 0.375rem rgba(15,26,46,0.08);
}
.mode-dock.is-open .mode-switch { opacity: 1; transform: none; filter: none; pointer-events: auto; }
.mode-dock .mode-switch { margin-bottom: 1rem; }
.mode-switch-thumb {
  position: absolute; top: 0.375rem; left: 0.375rem;
  width: var(--ms-size); height: var(--ms-size); border-radius: 50%;
  background: linear-gradient(135deg, rgba(42,157,143,0.95), rgba(34,129,118,0.95));
  box-shadow: 0 0.125rem 0.5rem rgba(42,157,143,0.4), inset 0 1px 0 rgba(255,255,255,0.3);
  transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.mode-switch[data-mode="calendar"] .mode-switch-thumb { transform: translateX(calc(var(--ms-size) + var(--ms-gap))); }
.mode-btn {
  position: relative; z-index: 1; flex-shrink: 0;
  width: var(--ms-size); height: var(--ms-size); padding: 0; margin: 0;
  display: grid; place-items: center;
  border: none; background: none; border-radius: 50%; cursor: pointer;
  color: var(--text-muted); transition: color 0.2s ease;
}
.mode-btn:hover { color: var(--text); }
.mode-btn.active { color: #fff; }
.mode-btn svg { display: block; width: 1.25rem; height: 1.25rem; }
.mode-btn:focus-visible { outline: 0.125rem solid var(--primary); outline-offset: 0.125rem; }
/* The calendar's own zoom levels mean nothing to the list. */
#screen-app.mode-plan .view-tabs,
#screen-app.mode-plan .mobile-bottom-nav { display: none !important; }
.view-tabs { position: relative; display: flex; background: var(--surface2); border-radius: var(--radius); padding: 0.25rem; gap: 0.1875rem; }
/* Sliding pill under whichever tab is active, same track+pill pattern as
   .auth-tab-indicator/.study-timer-mode-pill -- left/width set in px by
   positionViewTabPill() off the active tab's own offsetLeft/offsetWidth. */
.view-tab-pill {
  position: absolute; top: 0.25rem; bottom: 0.25rem; left: 0.25rem; width: 0;
  background: var(--surface); border-radius: 0.375rem; box-shadow: var(--shadow-sm);
  transition: left 0.24s var(--ease), width 0.24s var(--ease);
  will-change: left, width;
  z-index: 0;
}
.view-tab {
  position: relative; z-index: 1;
  padding: 0.375rem 0.875rem; border-radius: 0.375rem; border: none; background: none;
  color: var(--text-muted); font-size: 0.8125rem; font-weight: 500; font-family: var(--font);
  cursor: pointer; transition: color 0.12s var(--ease);
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
}
.view-tab.active { color: var(--primary); font-weight: 600; }

.generate-btn {
  display: flex; align-items: center; gap: 0.375rem; padding: 0.5rem 1rem;
  margin-left: auto; height: 2.25rem;
  background: linear-gradient(135deg, rgba(42,157,143,0.85), rgba(34,129,118,0.85));
  border: 1px solid rgba(42,157,143,0.35); border-radius: var(--radius);
  color: #fff; font-size: 0.8125rem; font-weight: 600; font-family: var(--font);
  cursor: pointer;
  transition: background 0.15s, box-shadow 0.15s, border-color 0.15s, transform 0.15s;
  -webkit-backdrop-filter: blur(0.75rem) saturate(160%);
  backdrop-filter: blur(0.75rem) saturate(160%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.25), 0 0.125rem 0.625rem rgba(42,157,143,0.18);
}
.generate-btn:hover {
  background: linear-gradient(135deg, rgba(42,157,143,0.96), rgba(34,129,118,0.96));
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.3), 0 0.25rem 0.875rem rgba(42,157,143,0.25);
  animation: gen-aura 1.6s steps(4, jump-none) infinite,
             gen-quake 1.6s steps(8, jump-none) infinite;
}
@keyframes gen-aura {
  0%   { box-shadow: inset 0 1px 0 rgba(255,255,255,0.3), 0 0.25rem 1.125rem rgba(116,208,255,0.4), 0 0 0.875rem rgba(255,213,79,0.4); }
  25%  { box-shadow: inset 0 1px 0 rgba(255,255,255,0.3), 0 0.25rem 0.875rem rgba(42,157,143,0.25), 0 0 0 rgba(255,213,79,0); }
  100% { box-shadow: inset 0 1px 0 rgba(255,255,255,0.3), 0 0.25rem 0.875rem rgba(42,157,143,0.25), 0 0 0 rgba(255,213,79,0); }
}
@keyframes gen-quake {
  0%    { transform: translate(0.4px, -0.4px); }
  12.5% { transform: translate(-0.4px, 0.4px); }
  25%   { transform: translate(0, 0); }
  100%  { transform: translate(0, 0); }
}
.generate-btn:active { transform: translateY(1px); }
.generate-btn svg {
  width: 0.9375rem; height: 0.9375rem; transform-origin: 50% 50%;
}
.generate-btn .gen-spark { stroke: #D7F6FF; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.generate-btn .gen-dot { fill: #D7F6FF; }
.generate-btn .gen-spark, .generate-btn .gen-dot { opacity: 0; }
.generate-btn:hover .gen-spark, .generate-btn:hover .gen-dot,
.generate-btn:active .gen-spark, .generate-btn:active .gen-dot {
  animation: gen-crackle 1.6s steps(4, jump-none) infinite;
}
@keyframes gen-crackle {
  0%  { opacity: 1; }
  25% { opacity: 0; }
  100% { opacity: 0; }
}
.generate-btn:hover svg, .generate-btn:active svg {
  animation: gen-hum 1.6s steps(2, jump-none) infinite;
}
@keyframes gen-hum {
  0%   { transform: translate(0, 0) rotate(0); }
  50%  { transform: translate(0.35px, -0.35px) rotate(1.6deg); }
}
.generate-btn:hover .gen-bolt, .generate-btn:active .gen-bolt {
  animation: gen-flash 1.6s steps(4, jump-none) infinite;
}
@keyframes gen-flash {
  0%   { color: #FFD54F; filter: drop-shadow(0 0 0.375rem rgba(255,213,79,0.85)); }
  25%  { color: #FFFFFF; filter: drop-shadow(0 0 0 rgba(255,213,79,0)); }
  100% { color: #FFFFFF; filter: drop-shadow(0 0 0 rgba(255,213,79,0)); }
}

@property --angle { syntax: '<angle>'; initial-value: 130deg; inherits: false; }
@property --s { syntax: '<length>'; initial-value: -0.625rem; inherits: false; }

#btn-add-event {
  height: 2.25rem; padding: 0 0.875rem;
  display: inline-flex; align-items: center; gap: 0.375rem;
  --angle: 130deg; --s: -0.625rem;
  /* 1px, not 1.5px -- .generate-btn/.study-mode-btn (the two buttons this
     one sits between) both use a clean 1px border. All three share the
     same explicit height:2.25rem under border-box, so a fractional border
     here doesn't change the actual box height, but it does round
     differently at some zoom/DPR combinations than the other two's clean
     1px, which is the most plausible source of a barely-visible mismatch
     between them. */
  border: 1px solid transparent;
  background:
    linear-gradient(160deg, rgba(255,255,255,0.45), rgba(255,255,255,0.2) 55%, rgba(255,255,255,0.32)) padding-box,
    linear-gradient(var(--angle),
      rgba(255,255,255,0.85) 0%,
      rgba(255,255,255,0.98) 14%,
      rgba(255,255,255,0.4) 32%,
      rgba(255,255,255,0.3) 55%,
      rgba(255,255,255,0.6) 78%,
      rgba(23,32,54,0.2) 100%) border-box;
  color: #2f343d;
  border-radius: var(--radius);
  -webkit-backdrop-filter: blur(0.625rem) saturate(170%) brightness(1.06);
  backdrop-filter: blur(0.625rem) saturate(170%) brightness(1.06);
    box-shadow: inset 0 0 0.1875rem 1.5px rgba(255,255,255,0.95), inset 0 0 0.375rem 0.4375rem rgba(255, 255, 255, 0.55), inset var(--s) var(--s) 1.375rem -0.25rem rgba(255, 255, 255, 0.75), inset 0 -0.4375rem 0.875rem rgba(255, 255, 255, 0.08), 0 0 0 1px rgba(147, 146, 146, 0.45), 0 0.375rem 0.875rem rgba(3, 3, 3, 0.1);
  position: relative;
  transition:
    box-shadow 0.3s ease,
    transform 0.7s linear(0, 0.01 0.9%, 0.037 1.8%, 0.148 3.8%, 0.762 11%, 0.985 14.2%, 1.062 15.7%, 1.125 17.3%, 1.167 18.9%, 1.191 20.5%, 1.199 22.5%, 1.185 24.8%, 1.012 35.7%, 0.979 39%, 0.963 42.4%, 0.963 47%, 0.997 57.7%, 1.007 64%, 1),
    --angle 0.7s ease,
    --s 0.3s ease;
}
#btn-add-event::before {
  content: '';
  position: absolute; inset: 0;
  border-radius: inherit;
  background:
    radial-gradient(90% 130% at 50% -40%, rgba(255,255,255,0.5), rgba(255,255,255,0) 62%),
    radial-gradient(26% 42% at calc(50% + var(--s)) 16%, rgba(255,255,255,0.4), rgba(255,255,255,0) 72%);
  pointer-events: none; z-index: 0;
}
@supports (filter: url(#liquid-distortion)) {
  #btn-add-event::before {
    -webkit-filter: url(#liquid-distortion) contrast(1.4);
    filter: url(#liquid-distortion) contrast(1.4);
  }
}
#btn-add-event::after {
  content: '';
  position: absolute; inset: 0;
  border-radius: inherit;
  background: radial-gradient(closest-side, transparent 58%, rgba(23,32,54,0.05) 90%, rgba(23,32,54,0.09));
  pointer-events: none; z-index: 0;
}
#btn-add-event svg, #btn-add-event span { position: relative; z-index: 1; }
#btn-add-event svg {
  width: 0.875rem; height: 0.875rem; flex-shrink: 0;
  filter: drop-shadow(0 1px 1px rgba(255,255,255,0.4));
  transition: transform 0.25s ease;
}
#btn-add-event:hover {
  --angle: 100deg;
  box-shadow:
    inset 0 0 0.1875rem 1.5px rgba(255,255,255,1),
    inset 0 0 0.375rem 0.4375rem rgba(255,255,255,0.4),
    inset var(--s) var(--s) 1.375rem -0.25rem rgba(255,255,255,0.6),
    inset 0 -0.4375rem 0.875rem rgba(23,32,54,0.12),
    0 0 0 1px rgba(255,255,255,0.45),
    0 0.4375rem 1rem rgba(20,33,61,0.18);
  transform: translateY(-1px);
}
#btn-add-event:hover svg { transform: scale(1.1); }
#btn-add-event:active {
  --angle: 30deg;
  --s: 0.625rem;
  transform: perspective(18.75rem) rotateX(14deg) scale(0.94) translateY(1px);
  transition:
    box-shadow 0.1s ease-out,
    transform 0.14s ease-out,
    --angle 0.7s ease,
    --s 0.28s ease;
  box-shadow:
    inset 0 0.125rem 0.3125rem rgba(23,32,54,0.16),
    inset 0.4375rem 0.625rem 1rem rgba(255,255,255,0.22),
    inset 0 0.375rem 0.75rem rgba(23,32,54,0.13),
    0 0 0 1px rgba(255,255,255,0.3),
    0 1px 0.125rem rgba(20,33,61,0.08);
}
#btn-add-event:active svg { transform: scale(0.85) translateY(1px); }

.undo-btn {
  display: none; align-items: center; gap: 0.25rem; padding: 0.5rem 0.75rem;
  margin-left: 0.375rem;
  background: rgba(255,255,255,0.65); border: 1px solid rgba(0,0,0,0.06);
  border-radius: var(--radius);
  color: var(--text); font-size: 0.8125rem; font-weight: 500; font-family: var(--font);
  cursor: pointer; transition: background 0.15s, box-shadow 0.15s; white-space: nowrap;
  -webkit-backdrop-filter: blur(0.75rem) saturate(160%);
  backdrop-filter: blur(0.75rem) saturate(160%);
  box-shadow: var(--glass-shadow);
}
.undo-btn.visible { display: flex; }
.undo-btn:hover { background: rgba(255,255,255,0.9); box-shadow: var(--glass-shadow-hover); }
.undo-btn svg { width: 0.875rem; height: 0.875rem; flex-shrink: 0; }
.undo-timer { font-size: 0.6875rem; color: var(--text-muted); margin-left: 0.25rem; }

/* ── Calendar views ─────────────────────────────────────────────────────────── */
.calendar-view { flex: 1; min-height: 0; overflow: hidden; display: none; flex-direction: column; }
.calendar-view.active { display: flex; }

/* ── Plan view ──────────────────────────────────────────────────────────
   The week as a calm list: a card per day, the work in it as rows, and what
   is due that day as its own card on top. No times -- the plan is about the
   day. Generous width and air; colour only where it means something (the
   subject's ring, today's name, a deadline). */
#view-plan {
  overflow-y: auto; overscroll-behavior: contain;
  /* The page scrolls up and down only: a sideways swipe on it is nobody's,
     so the browser can't read it as "back". The exams row slides on its own. */
  touch-action: pan-y pinch-zoom;
  --plan-hair: color-mix(in srgb, var(--text) 8%, transparent);
  --plan-card: var(--surface);
  --plan-card-shadow: 0 0 0 1px color-mix(in srgb, var(--text) 5%, transparent), 0 1px 0.125rem rgba(16,24,40,0.04), 0 0.375rem 1.25rem rgba(16,24,40,0.035);
  --plan-due: #F59E0B;
  --plan-due-ink: #B45309;
  --plan-pad: 1.25rem;
  --plan-lead: 1.5rem;
  --plan-gap: 1rem;
}
:root[data-theme="dark"] #view-plan {
  --plan-due: #FBBF24; --plan-due-ink: #F59E0B;
  --plan-card-shadow: 0 0 0 1px rgba(255,255,255,0.06);
}
.plan-head, .plan-days { max-width: 54rem; width: 100%; margin: 0 auto; box-sizing: border-box; padding-left: 2.5rem; padding-right: 2.5rem; }
.plan-head { padding-top: 2.75rem; }
.plan-range { font-size: 2rem; line-height: 1.15; font-weight: 700; letter-spacing: -0.03em; color: var(--text); white-space: nowrap; }
@media (max-width: 560px) { .plan-range { font-size: 1.625rem; } }
.plan-days { display: flex; flex-direction: column; gap: 2.5rem; padding-top: 2.25rem; padding-bottom: 8rem; }

.plan-day { display: flex; flex-direction: column; gap: 0.75rem; transition: opacity 0.2s ease; }
.plan-day-head { display: flex; align-items: baseline; gap: 0.5rem; padding: 0 0.25rem; }
.plan-day-name { margin: 0; font-size: 1.1875rem; font-weight: 700; letter-spacing: -0.018em; color: var(--text); text-transform: capitalize; }
.plan-day.is-today .plan-day-name { color: var(--accent); }
.plan-day-date { font-size: 0.9375rem; color: var(--text-muted); }
/* As tall as the date beside it: a mark on the line, not a button above it. */
.plan-day-hours { align-self: center; display: inline-flex; align-items: center; justify-content: center; width: 1.125rem; height: 1.125rem; padding: 0; border: 0; border-radius: 62.4375rem;
  background: color-mix(in srgb, var(--accent) 12%, transparent); color: var(--accent); font: inherit; font-size: 0.75rem; font-weight: 600; font-variant-numeric: tabular-nums; cursor: pointer; transition: background .15s, opacity .15s; }
.plan-day-hours:hover { background: color-mix(in srgb, var(--accent) 20%, transparent); }
.plan-day-hours.is-excluded { background: var(--surface2); color: var(--text-muted); }
.plan-day-hours > svg { width: 0.6875rem; height: 0.6875rem; }
.plan-day-note { margin-left: auto; font-size: 0.9375rem; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.plan-day.is-empty .plan-day-note { color: var(--text-dim); }
.plan-day-blocked { display: none; margin-left: auto; font-size: 0.8125rem; font-weight: 600; color: var(--red); }
.plan-day.is-past { opacity: 0.5; }

.plan-dues, .plan-group { background: var(--plan-card); border-radius: 1.125rem; box-shadow: var(--plan-card-shadow); overflow: hidden; }
.plan-dues {
  background: color-mix(in srgb, var(--plan-due) 7%, var(--plan-card));
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--plan-due) 22%, transparent);
}
.plan-group.is-empty:not(.has-ph) { display: none; }

/* A row: the ring, what and which subject, how long, and -- today -- Start.
   A study row carries its content in an inner layer so a swipe can slide it
   over the edit/delete actions behind (the Lists gesture). */
.plan-row { position: relative; display: block; overflow: hidden; touch-action: pan-y; cursor: pointer;
  -webkit-tap-highlight-color: transparent; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
  transition: transform 0.25s ease; }
.plan-row-inner, .plan-due {
  position: relative; display: flex; align-items: center; gap: var(--plan-gap);
  width: 100%; min-height: 4.25rem; padding: 0.875rem var(--plan-pad); box-sizing: border-box;
  background: transparent; border: 0; margin: 0; text-align: left;
  font-family: inherit; color: var(--text); cursor: pointer;
  -webkit-tap-highlight-color: transparent; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
  transition: background 0.15s ease, transform 0.25s ease;
}
.plan-group > :not(.plan-placeholder):not(.plan-chip-slot) + :not(.plan-placeholder):not(.plan-chip-slot)::before,
.plan-dues > * + *::before {
  content: ''; position: absolute; top: 0; right: 0; z-index: 2;
  left: calc(var(--plan-pad) + var(--plan-lead) + var(--plan-gap));
  height: 1px; background: var(--plan-hair);
}
.plan-row-inner { z-index: 1; background: var(--plan-card, var(--surface)); transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1), background 0.15s ease; }
.plan-row.swiping .plan-row-inner, .plan-row.swiping .swipe-action { transition: none; }
.plan-row.swipe-revealed .swipe-action-right { opacity: 1; pointer-events: auto; cursor: pointer; }
.plan-row:hover .plan-row-inner, .plan-due:hover { background: color-mix(in srgb, var(--text) 3%, var(--plan-card, var(--surface))); }
.plan-row:active .plan-row-inner { background: color-mix(in srgb, var(--text) 5%, var(--plan-card, var(--surface))); }
.plan-row:focus-visible .plan-row-inner, .plan-due:focus-visible { outline: none; box-shadow: inset 0 0 0 0.125rem color-mix(in srgb, var(--accent) 70%, transparent); }
.plan-row.is-pressed { transform: scale(0.985); }
.plan-row.is-pressed .plan-row-inner { background: color-mix(in srgb, var(--text) 5%, var(--plan-card, var(--surface))); }

.plan-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.1875rem; }
.plan-title { font-size: 1rem; font-weight: 550; line-height: 1.3; letter-spacing: -0.008em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A task in the plan says all of itself, on as many lines as it needs. */
.plan-row .plan-title { white-space: normal; overflow: visible; text-overflow: clip; overflow-wrap: anywhere; }
.plan-sub { font-size: 0.8125rem; line-height: 1.3; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.plan-late { color: var(--red); font-weight: 600; }
.plan-min { flex-shrink: 0; font-size: 0.9375rem; color: var(--text-muted); font-variant-numeric: tabular-nums; }
/* Tappable: the length (or time) opens its length control. */
button.plan-min.is-editable {
  font-family: var(--font); line-height: 1.2; cursor: pointer;
  padding: 0.25rem 0.5rem; margin: -0.25rem -0.125rem; border-radius: 0.5rem;
  border: none; background: transparent; transition: background .15s ease, color .15s ease;
}
button.plan-min.is-editable:hover, button.plan-min.is-editable:focus-visible {
  background: color-mix(in srgb, var(--subject, var(--accent)) 12%, transparent); color: var(--text);
}
.plan-len-pop {
  position: fixed; z-index: 1200; width: 17rem; padding: 0.75rem;
  border-radius: 1rem; border: 1px solid var(--border);
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  -webkit-backdrop-filter: blur(1.25rem) saturate(180%); backdrop-filter: blur(1.25rem) saturate(180%);
  box-shadow: 0 0.75rem 2.25rem rgba(15,26,46,0.16), 0 0.125rem 0.375rem rgba(15,26,46,0.06);
  animation: plan-len-in .18s cubic-bezier(.2, 1.1, .4, 1);
}
@keyframes plan-len-in { from { opacity: 0; transform: translateY(-0.1875rem) scale(.98); } }
.plan-len-row { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.625rem; }
.plan-len-val {
  font: 700 1.125rem/1.2 var(--font); color: var(--text); font-variant-numeric: tabular-nums;
  border: none; background: none; padding: 0.125rem 0.375rem; border-radius: 0.375rem; cursor: text;
}
button.plan-len-val:hover { color: var(--red); }
/* Tapped: the digits become the field, same size, as on the Study timer. */
.plan-len-input {
  width: 6ch; min-width: 0; text-align: center; color: var(--red);
  border: none; border-bottom: 1.5px solid color-mix(in srgb, var(--red) 45%, transparent); border-radius: 0;
}
.plan-len-input:focus { outline: none; box-shadow: none; border-color: transparent; border-bottom-color: color-mix(in srgb, var(--red) 55%, transparent); }
.plan-len-step {
  width: 2.25rem; height: 2.25rem; border-radius: 50%; border: 1px solid var(--border);
  background: var(--surface2); color: var(--text); font: 600 1.125rem/1 var(--font); cursor: pointer;
  display: grid; place-items: center; transition: background .15s ease, transform .1s ease;
}
.plan-len-step:hover { background: color-mix(in srgb, var(--accent) 12%, var(--surface2)); }
.plan-len-step:active { transform: scale(.94); }
.plan-len-step:disabled { opacity: .4; cursor: default; }
.plan-len-chips { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.375rem; }
.plan-len-chip {
  padding: 0.375rem 0; border-radius: 0.5rem; border: 1px solid var(--border);
  background: transparent; color: var(--text-muted); font: 600 0.75rem/1.2 var(--font); cursor: pointer;
  font-variant-numeric: tabular-nums; white-space: nowrap; transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.plan-len-chip:hover { background: var(--surface2); color: var(--text); }
.plan-len-chip.is-on { background: var(--accent); border-color: var(--accent); color: #fff; }

/* The ring is the subject's colour; ticked, it fills and the row goes quiet. */
.plan-check {
  flex-shrink: 0; position: relative; width: var(--plan-lead); height: var(--plan-lead); padding: 0;
  display: grid; place-items: center; border-radius: 50%; cursor: pointer;
  background: transparent; border: 0.125rem solid var(--subject); color: #fff;
  transition: background 0.2s ease, transform 0.12s ease;
}
.plan-check::after { content: ''; position: absolute; inset: -0.5rem; border-radius: 50%; }
.plan-check:hover { background: color-mix(in srgb, var(--subject) 14%, transparent); }
.plan-check:active { transform: scale(0.88); }
.plan-check svg { display: block; width: 0.875rem; height: 0.875rem; opacity: 0; transform: scale(0.5); transition: opacity 0.15s ease, transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1); }
.plan-row.is-done .plan-check { background: var(--subject); }
.plan-row.is-done .plan-check svg { opacity: 1; transform: none; }
.plan-row.is-done .plan-title, .plan-row.is-done .plan-sub, .plan-row.is-done .plan-min { color: var(--text-dim); }

/* Due: a round mark with the flag dead centre, and a quiet "Due". Liquid glass:
   the bubble is a lit sphere rather than a flat disc -- a bright meniscus where
   the light lands top-left, a darker pool bottom-right, a rim to catch the edge,
   and a soft contact shadow so it sits above the row instead of on it.
   The tint is mixed toward black, never white: white ink on the raw hue is only
   2.5:1 in light and 2.1:1 in dark, and at 60% it is 6.1:1 / 5.2:1. */
.plan-due-icon {
  --bubble: color-mix(in srgb, var(--plan-due) 85%, #000);
  flex-shrink: 0; width: var(--plan-lead); height: var(--plan-lead); border-radius: 50%;
  display: grid; place-items: center; color: #fff;
  background:
    radial-gradient(120% 120% at 30% 22%, color-mix(in srgb, var(--plan-due) 34%, #fff) 0%, transparent 58%),
    radial-gradient(140% 140% at 74% 82%, color-mix(in srgb, var(--bubble) 72%, #000) 0%, transparent 62%),
    linear-gradient(158deg, color-mix(in srgb, var(--bubble) 88%, #fff) 0%, var(--bubble) 46%, color-mix(in srgb, var(--bubble) 84%, #000) 100%);
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, #fff 26%, transparent),
    inset 0 1px 1px color-mix(in srgb, #fff 34%, transparent),
    inset 0 -0.125rem 0.1875rem color-mix(in srgb, #000 34%, transparent),
    0 1px 0.125rem color-mix(in srgb, var(--plan-due) 30%, transparent);
}
/* No shadow on the mark itself. Its ink is already centred on the viewBox to
   three decimals (bbox 1.303..14.697, centre 8.000) and its centroid sits only
   0.244u -- 0.213px -- above centre, which is sub-pixel at this size; a
   directional shadow would do more to unbalance it than the glyph ever was. */
.plan-due-icon svg { display: block; width: 0.875rem; height: 0.875rem; }
.plan-due-tag { flex-shrink: 0; font-size: 0.8125rem; font-weight: 600; color: var(--plan-due-ink); }

/* A row with a time shows it; one placed by day and order, its length. */
.plan-row.is-timed .plan-min { color: var(--text); font-weight: 500; }

/* Catch up: sessions from earlier days whose work is still owed. */
.plan-catchup { display: flex; flex-direction: column; gap: 0.75rem; transition: opacity 0.2s ease; }
.plan-days.is-dragging .plan-catchup { opacity: 0.45; }
.plan-catchup .plan-day-name { text-transform: none; }
.plan-day.is-all-done .plan-day-note { color: var(--accent); font-weight: 600; }

/* Done: a quiet pill beside the week's title opens what got ticked off. */
.plan-head { display: flex; align-items: center; gap: 1rem; }
.plan-done-pill {
  margin-left: auto; display: inline-flex; align-items: center; gap: 0.4375rem; flex-shrink: 0;
  height: 2rem; padding: 0 0.875rem 0 0.6875rem; border-radius: 62.4375rem; cursor: pointer;
  font: inherit; font-size: 0.8125rem; font-weight: 600;
  color: var(--text); background: color-mix(in srgb, var(--text) 5%, transparent);
  border: 0;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.12s ease;
}
.plan-done-pill .done-report-icon { width: 1rem; height: 1rem; color: var(--accent); }
.plan-done-pill:hover { background: color-mix(in srgb, var(--text) 9%, transparent); color: var(--text); }
.plan-done-pill:active { transform: scale(0.96); }
/* A tick just landed here. */
.plan-done-pill.is-receiving, .study-fold-toggle.is-receiving { animation: done-receive .55s cubic-bezier(.3, 1.6, .5, 1); }
@keyframes done-receive {
  0% { transform: scale(1); }
  35% { transform: scale(1.1); background: color-mix(in srgb, var(--accent) 16%, transparent); }
  100% { transform: scale(1); }
}
.plan-done-pill.hidden { display: none; }
/* Picked with Ctrl/Cmd: a ring in the accent, the way calendar events show it. */
#plan-days .plan-row.selected .plan-row-inner, #plan-days .plan-row.selected:hover .plan-row-inner { box-shadow: inset 0 0 0 0.125rem color-mix(in srgb, var(--accent) 70%, transparent); background: color-mix(in srgb, var(--accent) 7%, var(--plan-card, var(--surface))); }
.plan-progress-pill + .plan-done-pill { margin-left: 0; }
/* The week's pills sit together as one group, close, apart from the title. */
.plan-head > .plan-done-pill:not(.hidden) ~ .plan-done-pill { margin-left: -0.625rem; }
@media (max-width: 560px) {
  .plan-progress-pill { padding: 0; width: 2rem; justify-content: center; }
  .plan-progress-pill > span { display: none; }
}

/* Set by fitPlanHead() (app.js) only when the week and its pills would
   not fit on one line (a long week in German, a narrow phone). */
.plan-head.is-tight .plan-range { font-size: 1.375rem; letter-spacing: -0.025em; }
.plan-head.is-tighter .plan-range { font-size: 1.1875rem; letter-spacing: -0.02em; }

/* The goal, read where it matters (public/js/goal.js): on target in green,
   the distance in the plain ink of a fact -- a gap is something to know,
   not an alarm. */
.goal-state { font-size: 0.75rem; font-weight: 600; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.goal-state.is-on { color: #15803D; }
:root[data-theme="dark"] .goal-state.is-on { color: #4ADE80; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .goal-state.is-on { color: #4ADE80; } }

.plan-done-modal .modal-body { padding-top: 0.5rem; }
.plan-done-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.625rem; margin-bottom: 1.25rem; }
.plan-done-stat {
  display: flex; flex-direction: column; gap: 0.125rem; padding: 0.875rem 1rem; border-radius: 0.875rem;
  background: color-mix(in srgb, var(--accent) 8%, var(--surface));
}
.plan-done-num { font-size: clamp(1.0625rem, 4.4vw, 1.375rem); white-space: nowrap; font-weight: 700; letter-spacing: -0.02em; color: var(--text); font-variant-numeric: tabular-nums; }
.plan-done-cap { font-size: 0.75rem; color: var(--text-muted); }
.plan-done-day { margin: 1rem 0 0.375rem; padding: 0 0.125rem; font-size: 0.75rem; font-weight: 600; letter-spacing: 0.02em; text-transform: uppercase; color: var(--text-dim); }
.plan-done-day:first-of-type { margin-top: 0; }
.plan-done-list { display: flex; flex-direction: column; }
.plan-done-item {
  display: flex; align-items: center; gap: 0.875rem; padding: 0.625rem 0.125rem;
  border-top: 1px solid var(--plan-hair, var(--border));
  transition: opacity 0.18s ease, transform 0.18s ease;
}
.plan-done-list .plan-done-item:first-child { border-top: 0; }
.plan-done-item.is-leaving { opacity: 0; transform: translateX(0.75rem); }
/* A real checkbox: ticked, and un-ticking it is how a row comes back. */
.plan-done-tick {
  flex-shrink: 0; position: relative; width: 1.375rem; height: 1.375rem; padding: 0; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer;
  background: var(--subject); color: #fff; border: 0.125rem solid var(--subject);
  transition: background 0.2s ease, transform 0.12s ease;
}
.plan-done-tick::after { content: ''; position: absolute; inset: -0.5rem; border-radius: 50%; }
.plan-done-tick:hover { filter: brightness(1.06); }
.plan-done-tick:active { transform: scale(0.88); }
.plan-done-tick svg { width: 0.75rem; height: 0.75rem; transition: opacity 0.15s ease, transform 0.2s ease; }
.plan-done-item.is-unchecking .plan-done-tick { background: transparent; }
.plan-done-item.is-unchecking .plan-done-tick svg { opacity: 0; transform: scale(0.5); }
.plan-done-item .plan-title { font-size: 0.9375rem; color: var(--text-muted); }
.plan-done-empty { margin: 1rem 0; text-align: center; color: var(--text-muted); font-size: 0.875rem; }

/* Start: tinted, round; the next thing today gets the full button. */
.plan-start {
  flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; gap: 0.375rem;
  width: 2.125rem; height: 2.125rem; padding: 0; border: 0; border-radius: 62.4375rem; cursor: pointer;
  font-family: inherit; font-size: 0.875rem; font-weight: 600; letter-spacing: -0.005em;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent);
  transition: background 0.15s ease, transform 0.12s ease, box-shadow 0.15s ease;
}
.plan-start svg { display: block; width: 0.8125rem; height: 0.8125rem; }
.plan-start:hover { background: color-mix(in srgb, var(--accent) 20%, transparent); }
.plan-start:active { transform: scale(0.93); }
.plan-start.is-primary {
  width: auto; padding: 0 1rem 0 0.875rem; color: #fff; background: var(--accent);
  box-shadow: 0 1px 0.125rem rgba(16,24,40,0.08), 0 0.25rem 0.875rem color-mix(in srgb, var(--accent) 30%, transparent);
}
.plan-start.is-primary:hover { background: color-mix(in srgb, var(--accent) 88%, #000); }
/* Started homework: the same quiet button, with the word, in the same place. */
.plan-start.is-resume { width: auto; padding: 0 0.875rem 0 0.75rem; font-size: 0.8125rem; }

/* Dragging. The row lifts off the list; a slot opens where it will land. */
.plan-ghost {
  position: fixed !important; left: 0; top: 0; z-index: 900; margin: 0; pointer-events: none;
  background: var(--surface); border-radius: 0.875rem;
  box-shadow: 0 0 0 1px rgba(16,24,40,0.05);
  --plan-pad: 1.25rem; --plan-lead: 1.5rem; --plan-gap: 1rem;
  transition: scale 0.2s ease, box-shadow 0.2s ease; will-change: transform;
}
.plan-ghost::before { display: none; }
.plan-ghost .swipe-action { display: none; }
.plan-ghost .plan-row-inner { background: transparent; }
.plan-ghost.is-lifted { scale: 1.025; box-shadow: 0 1.25rem 3rem rgba(16,24,40,0.18), 0 0.25rem 0.75rem rgba(16,24,40,0.08); }
.plan-ghost.is-blocked { box-shadow: 0 0 0 0.125rem color-mix(in srgb, var(--red) 65%, transparent), 0 1.25rem 3rem rgba(16,24,40,0.18); }
.plan-ghost.is-settling { transition: transform 0.22s cubic-bezier(0.2, 0.8, 0.2, 1), scale 0.22s ease, box-shadow 0.22s ease; }
:root[data-theme="dark"] .plan-ghost.is-lifted { box-shadow: 0 0 0 1px rgba(255,255,255,0.08), 0 1.25rem 3rem rgba(0,0,0,0.5); }
.plan-placeholder { position: relative; height: 0; overflow: hidden; transition: height 0.22s cubic-bezier(0.2, 0.8, 0.2, 1); }
.plan-placeholder::after {
  content: ''; position: absolute; inset: 0.375rem 0.5rem; border-radius: 0.75rem;
  background: color-mix(in srgb, var(--accent) 7%, transparent);
  border: 1.5px dashed color-mix(in srgb, var(--accent) 40%, transparent);
}
.plan-row.is-source { display: none; }
.plan-days.is-dragging .plan-row:hover .plan-row-inner { background: var(--plan-card, var(--surface)); }
.plan-days.is-dragging .plan-day.is-blocked { opacity: 0.4; }
.plan-days.is-dragging .plan-day.is-after-due .plan-day-note { display: none; }
.plan-days.is-dragging .plan-day.is-after-due .plan-day-blocked { display: inline; }
body.plan-dragging, body.plan-dragging * { cursor: grabbing !important; }

/* The row menu: Time opens its choices in place. */
.plan-menu { min-width: 13rem; }
.plan-menu-more, .plan-menu-back { display: flex !important; align-items: center; gap: 0.5rem; }
.plan-menu-more svg { margin-left: auto; color: var(--text-dim); }
.plan-menu-back { font-weight: 600; }
.plan-menu-back svg { color: var(--text-dim); }
/* Move to…: an invisible date field where the menu was, there only so the
   system's date picker opens at that spot. */
.plan-move-picker {
  position: fixed; width: 1px; height: 1px; padding: 0; border: 0; margin: 0;
  opacity: 0; pointer-events: none;
}

.plan-empty { text-align: center; padding: 4rem 1.5rem; display: flex; flex-direction: column; align-items: center; gap: 0.5rem; }
.plan-empty-title { font-size: 1.0625rem; font-weight: 700; color: var(--text); margin: 0; }
.plan-empty-desc { font-size: 0.875rem; color: var(--text-muted); margin: 0; max-width: 24rem; }

/* A homework dragged in from the list: a preview row opens where it will
   land, dashed in its subject's colour, and pulses while the day is laid
   out around it. */
.plan-chip-slot { position: relative; height: 0; overflow: hidden; transition: height 0.22s cubic-bezier(0.2, 0.8, 0.2, 1); }
.plan-chip-slot-row {
  display: flex; align-items: center; gap: var(--plan-gap); box-sizing: border-box;
  min-height: 4.25rem; margin: 0.375rem 0.5rem; padding: 0.5rem calc(var(--plan-pad) - 0.5rem);
  border-radius: 0.875rem; border: 1.5px dashed color-mix(in srgb, var(--subject) 60%, transparent);
  background: color-mix(in srgb, var(--subject) 7%, var(--plan-card, var(--surface)));
}
.plan-chip-slot-ring { flex-shrink: 0; width: var(--plan-lead); height: var(--plan-lead); border-radius: 50%; border: 0.125rem solid var(--subject); box-sizing: border-box; opacity: 0.7; }
.plan-chip-slot .plan-title { color: var(--text); }
.plan-chip-slot-min { flex-shrink: 0; margin-left: auto; font: 600 0.75rem/1 var(--font); color: var(--text-muted); font-variant-numeric: tabular-nums; }
/* A calendar drop waiting on its length: the preview stays, solid. */
.chip-drop-held { transition: height 0.18s cubic-bezier(0.2, 0.8, 0.2, 1); }
.chip-drop-held .cdp-sub { display: none; }

/* How much of a dropped homework goes on this day. Same glass, stepper and
   chips as a Plan row's length, with the checklist under it. */
.drop-amt { width: 18.5rem; padding: 0.875rem; }
.drop-amt-head { display: flex; align-items: flex-start; gap: 0.625rem; margin-bottom: 0.75rem; }
.drop-amt-dot { flex-shrink: 0; width: 0.625rem; height: 0.625rem; margin-top: 0.3rem; border-radius: 50%; background: var(--subject); }
.drop-amt-head-text { min-width: 0; }
.drop-amt-title { font: 650 0.875rem/1.3 var(--font); color: var(--text); overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.drop-amt-sub { margin-top: 0.125rem; font: 500 0.75rem/1.3 var(--font); color: var(--text-muted); font-variant-numeric: tabular-nums; }
.drop-amt .plan-len-chip { padding: 0.4375rem 0; }
.drop-amt-note { margin-top: 0.5rem; font: 500 0.6875rem/1.3 var(--font); color: var(--text-muted); text-align: center; }
.drop-amt-steps-head {
  display: flex; justify-content: space-between; align-items: baseline; margin: 0.875rem 0 0.375rem;
  font: 600 0.6875rem/1.2 var(--font); color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em;
}
.drop-amt-count { text-transform: none; letter-spacing: 0; font-variant-numeric: tabular-nums; }
.drop-amt-steps { max-height: 9.5rem; overflow-y: auto; margin: 0 -0.25rem; padding: 0 0.25rem; overscroll-behavior: contain; }
.drop-amt-step {
  display: flex; align-items: flex-start; gap: 0.5rem; padding: 0.375rem 0.375rem; border-radius: 0.5rem; cursor: pointer;
  font: 500 0.8125rem/1.35 var(--font); color: var(--text-muted); transition: background 0.15s ease, color 0.15s ease;
}
.drop-amt-step:hover { background: var(--surface2); }
.drop-amt-step.is-on { color: var(--text); }
.drop-amt-step input { position: absolute; opacity: 0; pointer-events: none; }
.drop-amt-tick {
  flex-shrink: 0; position: relative; width: 1rem; height: 1rem; margin-top: 0.0625rem; border-radius: 0.3125rem;
  border: 1.5px solid var(--border-strong, var(--border)); transition: background 0.15s ease, border-color 0.15s ease;
}
.drop-amt-step.is-on .drop-amt-tick { background: var(--subject); border-color: var(--subject); }
.drop-amt-step.is-on .drop-amt-tick::after {
  content: ''; position: absolute; left: 0.28rem; top: 0.1rem; width: 0.25rem; height: 0.5rem;
  border: solid #fff; border-width: 0 0.125rem 0.125rem 0; transform: rotate(45deg);
}
.drop-amt-step input:focus-visible + .drop-amt-tick { box-shadow: 0 0 0 0.1875rem color-mix(in srgb, var(--subject) 30%, transparent); }
.drop-amt-step-text { min-width: 0; overflow-wrap: anywhere; }
.drop-amt-actions { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 0.875rem; }
.drop-amt-actions .btn-primary { min-width: 6.5rem; }
/* Phone: a sheet from the bottom over a dim. */
.drop-amt-scrim { position: fixed; inset: 0; z-index: 1199; background: rgba(17,24,39,0.35); animation: drop-amt-fade 0.2s ease; }
@keyframes drop-amt-fade { from { opacity: 0; } }
.drop-amt.is-sheet {
  left: 0; right: 0; bottom: 0; top: auto; width: auto; border-radius: 1.25rem 1.25rem 0 0; border-bottom: none;
  padding: 1rem 1rem calc(1rem + env(safe-area-inset-bottom)); background: var(--surface);
  animation: drop-amt-up 0.28s cubic-bezier(0.2, 0.9, 0.3, 1);
}
@keyframes drop-amt-up { from { transform: translateY(100%); } }
.drop-amt.is-sheet .plan-len-step { width: 2.75rem; height: 2.75rem; }
.drop-amt.is-sheet .plan-len-chip { padding: 0.5625rem 0; font-size: 0.8125rem; }
.drop-amt.is-sheet .drop-amt-steps { max-height: 38vh; }
.drop-amt.is-sheet .drop-amt-step { padding: 0.5rem 0.375rem; font-size: 0.875rem; }
.drop-amt.is-sheet .drop-amt-actions .btn { flex: 1; padding: 0.625rem; font-size: 0.875rem; }
.plan-chip-slot.is-saving .plan-chip-slot-row { animation: plan-slot-pulse 1s ease-in-out infinite; }
@keyframes plan-slot-pulse { 50% { opacity: 0.55; } }
.plan-group.is-empty.has-insert { display: block; }
.plan-day.chip-drop-late .plan-chip-slot-row { border-color: color-mix(in srgb, var(--red) 60%, transparent); background: color-mix(in srgb, var(--red) 6%, var(--plan-card, var(--surface))); }
.plan-day.chip-drop-late .plan-day-name { color: var(--red); }
.plan-day.chip-drop-blocked { opacity: 0.4; }
body.chip-dragging #view-plan .plan-row:hover .plan-row-inner { background: var(--plan-card, var(--surface)); }

/* Calendar: a session placed by day and order, not yet at a time. */
.cal-event.is-untimed .ev-time { font-style: italic; opacity: 0.8; }

/* Calendar: days a dragged homework block can't go (after its due date). */
.week-col.col-after-due, .day-col.col-after-due {
  background-image: repeating-linear-gradient(135deg, color-mix(in srgb, var(--red) 7%, transparent) 0 0.375rem, transparent 0.375rem 0.875rem);
}
/* Overdue work may go anywhere; the days it would be late on are tinted. */
.week-col.col-late, .day-col.col-late, .month-cell.chip-drop-late, .week-col.chip-drop-late, .day-col.chip-drop-late {
  background-color: color-mix(in srgb, var(--red) 6%, transparent);
}
.plan-days.is-dragging .plan-day.is-late .plan-group,
.plan-days.is-dragging .plan-day.is-late .plan-dues { box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--red) 45%, transparent); }
.plan-days.is-dragging .plan-day.is-late .plan-day-name { color: var(--red); }
.plan-days.is-dragging .plan-day.is-late .plan-placeholder::after {
  background: color-mix(in srgb, var(--red) 8%, transparent);
  border-color: color-mix(in srgb, var(--red) 45%, transparent);
}
.cal-event.drop-blocked { outline: 0.125rem solid color-mix(in srgb, var(--red) 70%, transparent); outline-offset: 1px; opacity: 0.6 !important; }
.month-cell.chip-drop-blocked, .week-col.chip-drop-blocked, .day-col.chip-drop-blocked {
  background-image: repeating-linear-gradient(135deg, color-mix(in srgb, var(--red) 8%, transparent) 0 0.375rem, transparent 0.375rem 0.875rem);
  cursor: not-allowed;
}

.mode-dock { left: auto; right: 0; bottom: 1.5rem; transform: none; place-items: center end; }
/* Everywhere, phone or desktop: a "<" tab of liquid glass on the right
   edge of the view, and the switch opens leftwards. Opening, the tab
   slides away into the edge and the switch springs out of it; closing, the switch slides back in and the tab
   springs out again. No glow, no idle bounce. */
.mode-handle, .mode-switch {
  background: linear-gradient(160deg, rgba(255,255,255,0.42), rgba(255,255,255,0.14));
  -webkit-backdrop-filter: blur(1.375rem) saturate(190%); backdrop-filter: blur(1.375rem) saturate(190%);
  border: 1px solid rgba(255,255,255,0.55);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.7), inset 0 -1px 0 rgba(255,255,255,0.18), 0 0.375rem 1.25rem rgba(15,26,46,0.12);
}
:root[data-theme="dark"] .mode-handle, :root[data-theme="dark"] .mode-switch {
  background: linear-gradient(160deg, rgba(255,255,255,0.14), rgba(255,255,255,0.04));
  border-color: rgba(255,255,255,0.16);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.18), 0 0.375rem 1.25rem rgba(0,0,0,0.35);
}
.mode-handle {
  width: 1.625rem; height: 3.25rem; padding: 0; border-radius: 1rem 0 0 1rem; border-right: 0;
  color: var(--text); animation: none;
  transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) 0.12s, opacity 0.2s ease 0.12s;
}
.mode-handle::before { display: none; }
.mode-handle .mode-handle-up { display: none; }
.mode-handle .mode-handle-left { display: block; }
.mode-dock.is-near .mode-handle, .mode-handle:hover { height: 3.25rem; box-shadow: inset 0 1px 0 rgba(255,255,255,0.7), 0 0.375rem 1.25rem rgba(15,26,46,0.12); }
.mode-dock.is-near .mode-handle svg { animation: none; }
.mode-dock.is-open .mode-handle {
  opacity: 0; transform: translateX(110%);
  transition: transform 0.24s cubic-bezier(0.4, 0, 1, 1), opacity 0.18s ease;
}
.mode-dock .mode-switch {
  margin: 0 0.75rem 0 0; filter: none; transform-origin: 100% 50%;
  transform: translateX(calc(100% + 1rem)) scale(0.92);
  transition: transform 0.26s cubic-bezier(0.4, 0, 1, 1), opacity 0.2s ease;
}
.mode-dock.is-open .mode-switch {
  transform: none;
  transition: transform 0.56s cubic-bezier(0.34, 1.56, 0.64, 1) 0.06s, opacity 0.18s ease 0.06s;
}
/* The thumb slides to the picked mode, on desktop and phone alike. */
.mode-switch-thumb { transition: transform 0.34s cubic-bezier(0.34, 1.56, 0.64, 1); }
@media (prefers-reduced-motion: reduce) { .mode-switch-thumb { transition: none; } }

@media (max-width: 480px) {
  /* Phones: bottom-right, sitting on top of the view tabs' bar (which is
     hidden in Plan, so there it drops to the bar's place). */
  .mode-dock {
    position: fixed; left: auto; right: 0; transform: none; place-items: center end;
    bottom: calc(0.75rem + env(safe-area-inset-bottom, 0rem) + 3.75rem + 0.5rem);
  }
  #screen-app.mode-plan .mode-dock { bottom: calc(0.75rem + env(safe-area-inset-bottom, 0rem)); }
  #screen-app.chrono-quick-open .mode-dock { opacity: 0; pointer-events: none; }
  #view-plan { --plan-pad: 1rem; --plan-gap: 0.8125rem; }
  .plan-head, .plan-days { padding-left: 1rem; padding-right: 1rem; }
  .plan-head { padding-top: 1.625rem; }
  .plan-range { font-size: 1.625rem; }
  .plan-days { gap: 2rem; padding-top: 1.625rem; padding-bottom: 6.5rem; }
  .plan-row-inner, .plan-due { min-height: 3.875rem; padding-top: 0.75rem; padding-bottom: 0.75rem; }
  .plan-start.is-primary { padding: 0 0.8125rem 0 0.75rem; font-size: 0.8125rem; }
}

/* Week view */
.week-header {
  display: grid; grid-template-columns: 3.25rem repeat(7, 1fr);
  border-bottom: 1px solid var(--border); flex-shrink: 0; background: var(--surface);
  padding-right: var(--sbw, 0rem);
}
.week-header-gutter { }
.week-header-day {
  padding: 0.875rem 0.375rem; text-align: center;
  border-left: 1px solid var(--border); cursor: pointer;
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
}
.week-header-day:hover { background: var(--surface2); }
.week-day-name { font-size: 0.6875rem; font-weight: 500; color: var(--text-muted); margin-bottom: 0.25rem; }
.week-day-num { font-size: 1.375rem; font-weight: 700; color: var(--text); }
.week-header-day.today .week-day-num {
  background: var(--primary); color: #fff;
  width: 2.25rem; height: 2.25rem; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  margin: 0 auto;
}

.week-body { flex: 1; min-height: 0; overflow-y: auto; position: relative; background: var(--bg); }

.week-grid { display: grid; grid-template-columns: 3.25rem repeat(7, 1fr); position: relative; }

.time-gutter { position: relative; }
.time-label {
  position: absolute; left: 0; width: 3rem; text-align: right;
  font-size: 0.625rem; color: var(--text-dim); padding-right: 0.375rem;
  transform: translateY(-0.4375rem); pointer-events: none; user-select: none;
}

.week-col { border-left: 1px solid var(--border); position: relative; user-select: none; background: var(--surface); }
.week-grid, .day-col { user-select: none; }

.hour-line { position: absolute; left: 0; right: 0; border-top: 1px solid var(--border); pointer-events: none; }
.hour-line.half { border-top-style: dashed; border-color: var(--surface3); }

/* Calendar event blocks — light palette */
.cal-event {
      position: absolute; left: 0.125rem; right: 0.125rem; border-radius: 0.375rem;
      padding: 0.1875rem 0.4375rem; font-size: 0.75rem; font-weight: 600; cursor: pointer;
      font-variant-numeric: tabular-nums;
      -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
  /* manipulation keeps panning but drops the browser's double-tap-to-zoom,
     which would otherwise swallow the second tap of the double-tap-to-edit
     gesture (see handleMobileEventTap in app.js) before our handler sees it. */
  touch-action: manipulation;
  /* overflow: clip (not hidden) + overflow-clip-margin lets the study-block
     task markers below bleed slightly past the padding edge, into where
     the border-left itself is painted, instead of getting clipped right at
     its inner edge -- see those rules for why that matters. */
  overflow: clip; overflow-clip-margin: 0.25rem;
  z-index: 1; transition: filter 0.1s, box-shadow 0.15s; line-height: 1.35;
  border-left: 0.25rem solid rgba(0,0,0,0.12);
}
.cal-event:hover { filter: brightness(0.95); box-shadow: var(--shadow-sm); }
/* nowrap matters: in a squeezed week column "08:30 - 09:15" is wider than the
   block and used to wrap onto a second line, pushing the title down past the
   bottom edge. It is a fixed-format string, so clipping it beats reflowing
   everything under it -- and it keeps the one-time-line assumption in
   eventBoxMetrics() true. */
.cal-event .ev-time {
  font-size: 0.6875rem; opacity: 0.7; display: block;
  white-space: nowrap; overflow: hidden; overflow-clip-margin: 0; text-overflow: ellipsis;
}

/* The title gets its own box so it clips at the block's padding edge instead
   of inheriting .cal-event's overflow-clip-margin, which exists for the task
   markers on the border and would otherwise let the text bleed 4px out of the
   event rectangle on every side. --ev-title-lines is set per event by
   eventTitleHtml() to however many lines fit under the time line; when none
   fit it renders no title element at all. */
.cal-event .ev-title {
  /* The -webkit-box trio, not the newer line-clamp shorthand: the shorthand
     also resets display, so declaring both leaves the winner down to source
     order. This form is the one every current engine implements. */
  display: -webkit-box; -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--ev-title-lines, 1);
  overflow: hidden; overflow-clip-margin: 0;
  overflow-wrap: anywhere; min-width: 0;
}

/* Study block task markers (see studyBlockTaskBandsHtml): one liquid-glass
   pill or bubble per checklist step scheduled into that block, sitting
   right ON the block's own colored left border (border-left-color, set
   per type/ev.color right above) instead of beside it. left:-2px +
   translateX(-50%) centers each marker on the border's own midline (the
   4px border occupies the 2px just outside .cal-event's padding edge, so
   -2px is its center); overflow-clip-margin on .cal-event above is what
   keeps that negative offset from being clipped away. width:3px (border-
   box, so the 1px border above included) is deliberately narrower than
   the 4px border it sits on, so it reads as a marker on the line, not a
   wider band replacing it. Glass = a light translucent gradient + blur +
   a soft inset highlight, which reads the same "wet highlight" whether
   the border underneath is green, blue, or a custom ev.color, and in
   both themes. */
.study-block-task-line {
  position: absolute; left: -0.125rem; width: 0.1875rem; pointer-events: auto;
  transform: translateX(-50%);
  border-radius: 62.4375rem;
  background: linear-gradient(155deg, rgba(255,255,255,0.65), rgba(255,255,255,0.18));
  -webkit-backdrop-filter: blur(0.125rem) saturate(180%);
  backdrop-filter: blur(0.125rem) saturate(180%);
  border: 1px solid rgba(255,255,255,0.45);
  /* Last shadow is the only non-inset one -- kept blur-less (0, not 2px)
     so it can't bleed past the 4px box and read as wider than the border
     line the marker sits on; the inset pair does all the "glass" shine. */
  box-shadow: inset 0 1px 1px rgba(255,255,255,0.7), inset 0 -0.125rem 0.1875rem rgba(0,0,0,0.06), 0 1px 0 rgba(0,0,0,0.12);
}
:root[data-theme="dark"] .study-block-task-line {
  background: linear-gradient(155deg, rgba(255,255,255,0.32), rgba(255,255,255,0.06));
  border-color: rgba(255,255,255,0.22);
  box-shadow: inset 0 1px 1px rgba(255,255,255,0.3), inset 0 -0.125rem 0.1875rem rgba(0,0,0,0.2), 0 1px 0 rgba(0,0,0,0.35);
}

/* A step with no duration of its own has no span to draw a pill from --
   just a small round bubble marking the moment, same glass treatment. */
.study-block-task-dot {
  position: absolute; left: -0.125rem; width: 0.1875rem; height: 0.1875rem; border-radius: 50%;
  pointer-events: auto;
  transform: translate(-50%, -50%);
  background: linear-gradient(155deg, rgba(255,255,255,0.7), rgba(255,255,255,0.2));
  -webkit-backdrop-filter: blur(0.125rem) saturate(180%);
  backdrop-filter: blur(0.125rem) saturate(180%);
  border: 1px solid rgba(255,255,255,0.5);
  box-shadow: inset 0 1px 1px rgba(255,255,255,0.75), inset 0 -1px 0.125rem rgba(0,0,0,0.08), 0 1px 0 rgba(0,0,0,0.15);
}
:root[data-theme="dark"] .study-block-task-dot {
  background: linear-gradient(155deg, rgba(255,255,255,0.38), rgba(255,255,255,0.08));
  border-color: rgba(255,255,255,0.25);
  box-shadow: inset 0 1px 1px rgba(255,255,255,0.35), inset 0 -1px 0.125rem rgba(0,0,0,0.2), 0 1px 0 rgba(0,0,0,0.35);
}

.ev-resize-handle { position: absolute; left: 0; right: 0; height: 0.4375rem; cursor: ns-resize; z-index: 3; }
.ev-resize-handle.ev-resize-top    { top: 0; }
.ev-resize-handle.ev-resize-bottom { bottom: 0; }
.ev-resize-handle::after {
  content: ''; position: absolute; left: 50%; top: 50%;
  width: 1.625rem; height: 0.1875rem; border-radius: 0.125rem; background: currentColor;
  opacity: 0; transform: translate(-50%, -50%); transition: opacity 0.12s;
}
.cal-event:hover .ev-resize-handle::after { opacity: 0.3; }
.ev-resize-handle:hover::after { opacity: 0.65; }

.cal-event.type-school      { background: #EDE9FE; color: #4C1D95; border-left-color: #7C3AED; }
.cal-event.type-personal    { background: #DBEAFE; color: #1E40AF; border-left-color: #3B82F6; }
.cal-event.type-sport       { background: #FED7AA; color: #9A3412; border-left-color: #F97316; }
.cal-event.type-study_block { background: #D8F3DC; color: #166534; border-left-color: #22C55E; }
.cal-event.type-exam        { background: #FDE68A; color: #92400E; border-left-color: #F59E0B; }
.cal-event.type-other       { background: #E5E7EB; color: #374151; border-left-color: #9CA3AF; }

.current-time-line {
  position: absolute; left: 0; right: 0; height: 0.125rem;
  background: var(--accent); z-index: 5; pointer-events: none;
}
.current-time-line::before {
  content: ''; position: absolute; left: -0.25rem; top: -0.25rem;
  width: 0.625rem; height: 0.625rem; border-radius: 50%; background: var(--accent);
}

.cal-event.type-study_window {
  left: 0; right: 0; z-index: 0;
  background: rgba(42,157,143,0.08);
  border: 1.5px dashed rgba(42,157,143,0.5);
  border-left: 0.25rem solid var(--accent);
  color: var(--accent-dim);
  border-radius: 0.375rem;
  cursor: pointer;
  font-size: 0.6875rem;
  font-style: italic;
  transition: background 0.15s, border-color 0.15s;
}
.cal-event.type-study_window:hover {
  background: rgba(42,157,143,0.14);
  border-color: rgba(42,157,143,0.7);
}

.drag-selection {
  position: absolute; left: 0.125rem; right: 0.125rem; z-index: 8;
  border-radius: 0.375rem; pointer-events: none;
  font-size: 0.75rem; font-weight: 600; padding: 0.1875rem 0.4375rem; user-select: none;
  box-shadow: var(--shadow-sm);
}
.drag-selection.drag-selection-window {
  background: rgba(42,157,143,0.14); border-left: 0.25rem solid var(--accent);
  color: var(--accent-dim);
}

.drag-choice-card {
  display: flex; align-items: center; gap: 0.875rem;
  width: 100%; padding: 1rem 1.125rem;
  background: rgba(255,255,255,0.55); border: 1px solid rgba(255,255,255,0.7);
  -webkit-backdrop-filter: blur(0.75rem) saturate(160%);
  backdrop-filter: blur(0.75rem) saturate(160%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.7), 0 0.25rem 0.875rem rgba(20,33,61,0.05);
  border-radius: 0.75rem; color: var(--text);
  font-family: var(--font); cursor: pointer;
  text-align: left;
  transition: background 0.12s var(--ease), border-color 0.12s var(--ease), transform 0.12s var(--ease);
}
.drag-choice-card:hover { background: rgba(255,255,255,0.8); border-color: rgba(42,157,143,0.3); transform: translateY(-1px); }
.drag-choice-card-danger:hover { border-color: rgba(239,68,68,0.4); }
/* A mode that's guaranteed to fail right now (no study windows exist yet)
   is disabled rather than left clickable-but-doomed -- see the has-study-
   windows check wired in app.js's modal-open handler. pointer-events:none
   already makes :hover unreachable by mouse, in both themes, so no
   separate light/dark :disabled:hover override is needed. */
.drag-choice-card:disabled { opacity: 0.45; cursor: not-allowed; pointer-events: none; }
.sched-card-title { font-weight: 600; font-size: 0.9375rem; }
.sched-card-desc  { font-size: 0.8125rem; color: var(--text-muted); margin-top: 0.25rem; line-height: 1.4; }

/* ── Multi-select ────────────────────────────────────────────────────────── */
.cal-event.selected {
  outline: 0.125rem solid var(--primary);
  outline-offset: -0.125rem;
  z-index: 3;
}
.month-event.selected {
  outline: 0.125rem solid var(--primary);
  outline-offset: -1px;
  border-radius: 0.375rem;
  z-index: 2;
}
.week-header-day.selected { background: var(--primary-glow); }
.week-header-day.selected .week-day-num { color: var(--primary); }
.week-header-day.today.selected .week-day-num { color: #fff; }
.month-cell.selected { background: var(--primary-glow); }
.month-cell.selected .month-cell-num { background: var(--primary); color: #fff; }
.year-day.selected { background: var(--primary-glow); color: var(--primary); font-weight: 700; }
.year-day.selected.today { background: var(--primary); color: #fff; }
.rubber-band {
  position: absolute;
  border: 1.5px solid var(--primary);
  background: rgba(20,33,61,0.06);
  z-index: 10;
  pointer-events: none;
  border-radius: 0.375rem;
}
.multi-select-bar {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  z-index: 200;
  background: var(--primary);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.625rem 1rem;
  padding-bottom: max(0.625rem, env(safe-area-inset-bottom));
  transform: translateY(100%);
  transition: transform 0.25s ease;
  box-shadow: 0 -0.25rem 1.25rem rgba(0,0,0,0.2);
}
.multi-select-bar.visible {
  transform: translateY(0);
}
.msb-count {
  font-size: 0.8125rem;
  font-weight: 600;
}
.msb-actions {
  display: flex;
  gap: 0.625rem;
}
.msb-btn {
  background: rgba(255,255,255,0.15);
  border: none;
  color: #fff;
  padding: 0.5rem 1rem;
  border-radius: 0.375rem;
  font-size: 0.75rem;
  font-weight: 600;
  font-family: var(--font);
  cursor: pointer;
  transition: background 0.15s;
}
.msb-btn:hover { background: rgba(255,255,255,0.25); }
.msb-btn-danger { background: rgba(255,255,255,0.15); color: #FCA5A5; }
.msb-btn-danger:hover { background: rgba(153,27,27,0.4); }
.msb-btn-done { background: none; color: rgba(255,255,255,0.6); padding: 0.5rem 0.625rem; }
.msb-btn-done:hover { color: #fff; }

/* Month view */
.month-grid-header {
  display: grid; grid-template-columns: repeat(7, 1fr);
  border-bottom: 1px solid var(--border); flex-shrink: 0; background: var(--surface);
}
.month-day-label {
padding: 0.75rem; text-align: center; font-size: 0.6875rem; font-weight: 600;
color: var(--text-dim);
}

.month-body { flex: 1; min-height: 0; overflow-y: auto; background: var(--bg); }
.month-grid { display: grid; grid-template-columns: repeat(7, 1fr); grid-auto-rows: minmax(6.875rem, 1fr); }

.month-cell {
  border-right: 1px solid var(--border); border-bottom: 1px solid var(--border);
  padding: 0.5rem; cursor: pointer; transition: background 0.1s; overflow: hidden;
  background: var(--surface);
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
}
.month-cell:hover { background: var(--surface2); }
.month-cell.other-month { opacity: 0.35; }
.month-cell.today { background: var(--primary-glow); }

.month-cell-num {
  font-size: 0.8125rem; font-weight: 600; margin-bottom: 0.25rem;
  width: 1.5rem; height: 1.5rem; display: flex; align-items: center; justify-content: center; border-radius: 50%;
}
.month-cell.today .month-cell-num { background: var(--primary); color: #fff; }

.month-event {
  font-size: 0.6875rem; padding: 0.125rem 0.375rem; border-radius: 0.375rem; margin-bottom: 0.1875rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  cursor: pointer; font-weight: 600;
  border-left: 0.1875rem solid rgba(0,0,0,0.12);
  touch-action: manipulation;
}
.month-event.type-school      { background: #EDE9FE; color: #4C1D95; border-left-color: #7C3AED; }
.month-event.type-personal    { background: #DBEAFE; color: #1E40AF; border-left-color: #3B82F6; }
.month-event.type-sport       { background: #FED7AA; color: #9A3412; border-left-color: #F97316; }
.month-event.type-study_block { background: #D8F3DC; color: #166534; border-left-color: #22C55E; }
.month-event.type-exam        { background: #FDE68A; color: #92400E; border-left-color: #F59E0B; }
.month-event.type-other       { background: #E5E7EB; color: #374151; border-left-color: #9CA3AF; }
.month-more { font-size: 0.625rem; color: var(--text-dim); padding: 0.0625rem 0.1875rem; }

/* Year view */
.year-grid {
  flex: 1; overflow-y: auto; align-content: start;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.875rem;
  padding: 1rem 1.5rem; background: var(--bg);
}
.year-month { background: var(--surface); border: 1px solid var(--border); border-radius: 0.75rem; padding: 0.625rem; cursor: pointer; }
.year-month:hover { border-color: var(--accent); }
.year-month-name { font-size: 0.8125rem; font-weight: 700; color: var(--text); text-align: center; margin-bottom: 0.5rem; cursor: pointer; }
.year-month.current .year-month-name { color: var(--accent); }
.year-days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0.125rem 0; pointer-events: none; }
.year-weekday { font-size: 0.5625rem; font-weight: 600; color: var(--text-dim); text-align: center; padding: 0.125rem 0; }
.year-day {
  font-size: 0.625rem; text-align: center; padding: 0.1875rem 0; border-radius: 0.375rem;
  cursor: pointer; display: flex; flex-direction: column; align-items: center; gap: 0.125rem;
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
  pointer-events: auto;
}
.year-day:hover { background: var(--surface2); }
.year-day.blank { cursor: default; }
.year-day.today { background: var(--primary); color: #fff; font-weight: 700; }
.year-day.today:hover { background: var(--primary); }
.year-dots { display: flex; gap: 0.0625rem; }
.year-dot { width: 0.1875rem; height: 0.1875rem; border-radius: 50%; }
.year-more { font-size: 0.4375rem; color: var(--text-dim); line-height: 1; }
.year-dot.type-school      { background: #7C3AED; }
.year-dot.type-personal    { background: #3B82F6; }
.year-dot.type-sport       { background: #F97316; }
.year-dot.type-study_block { background: #22C55E; }
.year-dot.type-exam        { background: #F59E0B; }
.year-dot.type-other       { background: #9CA3AF; }
.year-dot.type-study_window { background: var(--accent); }

/* Day view */
.day-header { padding: 1.125rem 1.5rem; border-bottom: 1px solid var(--border); flex-shrink: 0; background: var(--surface); }
.day-header-title { font-size: 1.25rem; font-weight: 700; color: var(--text); }
.day-header-sub   { font-size: 0.8125rem; color: var(--text-muted); margin-top: 0.25rem; }
.day-body { flex: 1; min-height: 0; overflow-y: auto; display: grid; grid-template-columns: 3.25rem 1fr; background: var(--bg); position: relative; }
.day-col { position: relative; border-left: 1px solid var(--border); background: var(--surface); }

/* ── Modals ────────────────────────────────────────────────────────────────── */
.modal-overlay { position: fixed; inset: 0; background: rgba(17,24,39,0.35); backdrop-filter: blur(0.25rem); z-index: 100; display: flex; align-items: center; justify-content: center; padding: 1.25rem; animation: overlay-in 0.28s var(--ease); }
.modal-overlay.hidden { display: none; }

.modal {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
  width: 30rem; max-width: 100%; max-height: 90vh; overflow-y: auto; box-shadow: var(--shadow);
  animation: modal-in 0.36s var(--ease-spring);
}

@keyframes overlay-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-in {
  from { opacity: 0; transform: translateY(1rem) scale(0.965); }
  to   { opacity: 1; transform: none; }
}

/* A little room under the header, so the ✕ never sits on its edge. */
.modal-header { display: flex; align-items: center; justify-content: space-between; padding: 1.5rem 1.75rem 0.5rem; }
.modal-title { font-size: 1rem; font-weight: 700; color: var(--text); }
/* A long title wraps well before the x, not under it. */
.modal-header .modal-title { min-width: 0; padding-right: 1.5rem; overflow-wrap: anywhere; }
.modal-header .modal-close { flex-shrink: 0; }
.modal-close, .zeno-close, #zeno-image-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border-radius: 50%;
  background: linear-gradient(160deg, #E5534B, #B42318);
  border: 1px solid rgba(255, 255, 255, 0.45);
  color: #fff;
  cursor: pointer;
  flex-shrink: 0;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5), 0 0.1875rem 0.75rem rgba(147, 1, 1, 0.18);
  -webkit-backdrop-filter: blur(0.875rem) saturate(180%);
  backdrop-filter: blur(0.875rem) saturate(180%);
  transition-property: background, color, transform, box-shadow;
  transition-duration: 0.25s;
  transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.modal-close:hover, .zeno-close:hover, #zeno-image-remove:hover {
  background: linear-gradient(160deg, #EF4444, #991B1B);
  color: #fff;
  transform: scale(1.08);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.55), 0 0.3125rem 1rem rgba(147, 1, 1, 0.35);
}

.modal-body { padding: 1.25rem 1.75rem; }
.modal-footer { display: flex; justify-content: space-between; gap: 0.5rem; padding: 0 1.75rem 1.5rem; }

.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; }

/* ── Two-Factor Authentication setup modal ─────────────────────────────── */
.twofa-pane { display: none; }
.twofa-pane.active { display: block; }
.twofa-hint { margin: 0 0 0.875rem; font-size: 0.8125rem; color: var(--text-muted); line-height: 1.55; text-align: center; }
.twofa-qr-wrap {
  display: flex; align-items: center; justify-content: center;
  padding: 0.75rem; background: #fff; border-radius: var(--radius);
  border: 1px solid var(--border); width: fit-content; margin: 0 auto 0.875rem;
}
.twofa-qr-wrap img { width: 11.25rem; height: 11.25rem; display: block; }
.twofa-manual-key {
  text-align: center; font-family: ui-monospace, 'SF Mono', 'Cascadia Code', monospace;
  font-size: 0.9375rem; font-weight: 600; letter-spacing: 0.05em; color: var(--text);
  background: var(--surface2); border-radius: var(--radius-sm); padding: 0.625rem;
  word-break: break-all;
}
.twofa-codes-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem;
  background: var(--surface2); border-radius: var(--radius); padding: 0.875rem;
}
.twofa-code {
  font-family: ui-monospace, 'SF Mono', 'Cascadia Code', monospace;
  font-size: 0.9375rem; font-weight: 600; color: var(--text); text-align: center;
  padding: 0.375rem 0; letter-spacing: 0.03em;
}
.twofa-ack-row {
  display: flex; align-items: center; gap: 0.5rem; margin-top: 0.875rem;
  font-size: 0.8125rem; color: var(--text-muted); cursor: pointer;
}
.twofa-ack-row input { width: auto; margin: 0; }

/* ── Report-a-bug screenshot attach (#modal-report-bug/#ng-modal-report-bug) */
.report-bug-image-row { display: flex; }
.report-bug-image-preview {
  display: flex; align-items: center; gap: 0.5rem; margin-top: 0.5rem;
  padding: 0.375rem 0.5rem; border-radius: var(--radius-sm); background: var(--surface2);
}
.report-bug-image-preview img { width: 2.5rem; height: 2.5rem; object-fit: cover; border-radius: 0.375rem; flex-shrink: 0; }
.report-bug-image-preview span { flex: 1; min-width: 0; font-size: 0.75rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.report-bug-image-remove {
  flex-shrink: 0; border: none; background: none; cursor: pointer; padding: 0.25rem;
  color: var(--text-muted); display: flex; align-items: center; justify-content: center;
  border-radius: 0.375rem; transition: color 0.12s, background 0.12s;
}
.report-bug-image-remove:hover { color: var(--red); background: color-mix(in srgb, var(--red) 10%, transparent); }

/* Upgrade */
.upgrade-modal { max-width: 26.25rem; }
.plan-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 0.625rem; margin-bottom: 0.5rem; }
.plan-card {
  background: var(--surface2); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 1rem; cursor: pointer; transition: border-color 0.15s;
}
.plan-card:hover { border-color: var(--primary); }
.plan-card .plan-name  { font-size: 0.875rem; font-weight: 700; color: var(--text); margin-bottom: 0.25rem; }
.plan-card .plan-price { font-size: 1.375rem; font-weight: 800; color: var(--accent); margin-bottom: 0.5rem; }
.plan-card .plan-price span { font-size: 0.75rem; font-weight: 400; color: var(--text-muted); }
.plan-card .plan-features { list-style: none; display: grid; gap: 0.5rem; font-size: 0.75rem; color: var(--text); }
.plan-card .plan-features li { display: flex; align-items: center; gap: 0.5rem; line-height: 1.3; }
.plan-card .plan-features svg { flex: none; width: 1rem; height: 1rem; color: var(--accent); }

/* Schedule mode modal */
.schedule-mode-body {
  display: flex; flex-direction: column; gap: 0.875rem; padding-top: 0.75rem;
}

/* One choice, three rows -- the same shape the registry picker uses, so a
   pick in this app looks like a pick anywhere else in it. A name and a mark,
   no second line: whichever is selected is shown by the row itself. */
.sched-modes { display: flex; flex-direction: column; gap: 0.375rem; }
.sched-mode {
  display: flex; align-items: center; gap: 0.625rem; width: 100%;
  padding: 0.6875rem 0.8125rem; cursor: pointer; text-align: left;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius);
  font-size: 0.875rem; font-weight: 600; font-family: var(--font);
  transition: border-color 0.15s, background 0.15s;
}
.sched-mode svg { width: 1.125rem; height: 1.125rem; flex-shrink: 0; color: var(--text-muted); }
.sched-mode:hover { border-color: var(--border2); }
.sched-mode.selected {
  border-color: var(--amber);
  background: color-mix(in srgb, var(--amber) 8%, var(--surface));
}
.sched-mode.selected svg { color: var(--amber); }
.sched-mode:disabled { opacity: 0.45; cursor: not-allowed; }

/* A hairline and a small label instead of a tinted, icon-headed card each.
   Stacked, those boxes read as three separate things to decide; this is one
   short form with three parts. */
.sched-section { border-top: 1px solid var(--border); padding-top: 0.75rem; }
.sched-section-label {
  font-size: 0.75rem; font-weight: 600; color: var(--text-muted); margin-bottom: 0.5rem;
}
#sched-notes-input { resize: vertical; min-height: 2.75rem; font-size: 0.8125rem; }

/* Auto-Schedule is its own step, not another settings sheet -- but it was
   saying so by flooding the entire panel in deep green. Everything inside
   then had to be white-on-green glass, which meant the three modes, the
   strategy toggle, the notes field and Run Schedule all came out as the
   same murky rectangle at slightly different opacities. Nothing had weight
   and nothing looked clickable; the one button that matters read exactly
   like the textarea above it.

   The green is concentrated into a header band instead. The panel keeps
   the identity at a glance, the body goes back to the app's ordinary
   surface -- where every component already has its own contrast, in both
   themes, with no overrides -- and Run Schedule becomes the very button
   that opened the modal, which gives the sheet one clear place to look. */
#modal-schedule-mode .modal {
  box-shadow: 0 1.5rem 3.75rem rgba(12, 40, 36, 0.28), var(--shadow);
}
/* The band rounds its own top corners rather than the panel clipping them.
   .modal needs to keep overflow-y:auto -- windows mode adds enough sections
   to run past 90vh, and clipping it would cut the Run button off instead of
   letting the sheet scroll. */
#modal-schedule-mode .modal-header {
  position: relative;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  padding: 1.125rem 1.25rem 1.125rem 1.375rem;
  background:
    radial-gradient(120% 180% at 12% -40%, rgba(255,255,255,0.28), rgba(255,255,255,0) 60%),
    linear-gradient(115deg, #2FA695 0%, #248A7D 52%, #1E7469 100%);
  color: #fff;
}
/* A slow breath of electric blue along the band's lower edge: the
   Auto-Schedule button's own flash, scaled to a surface. Enough that the
   panel never sits dead, not so much that it competes with the content. */
#modal-schedule-mode .modal-header::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: linear-gradient(90deg, rgba(255,213,79,0) 0%, rgba(255,213,79,0.55) 30%, rgba(116,208,255,0.75) 70%, rgba(116,208,255,0) 100%);
  animation: sched-band-glint 3.4s ease-in-out infinite;
}
@keyframes sched-band-glint { 0%, 100% { opacity: 0.35; } 50% { opacity: 1; } }

#modal-schedule-mode .modal-title {
  display: flex; align-items: center; gap: 0.5rem;
  color: #fff; font-size: 1rem; letter-spacing: -0.01em;
}
/* The bolt, in gold, so the band is recognisably the Auto-Schedule button's
   -- and so the amber that used to ring the whole panel still has somewhere
   to live. It reads better here than as a border: one warm mark against the
   green instead of a frame fighting it. */
#modal-schedule-mode .modal-title::before {
  content: ''; flex-shrink: 0; width: 1.625rem; height: 1.625rem; border-radius: 50%;
  background: rgba(255,213,79,0.22) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill='%23FFD54F' fill-rule='evenodd' d='M11.3 1.046A1 1 0 0112 2v5h4a1 1 0 01.82 1.573l-7 10A1 1 0 018 18v-5H4a1 1 0 01-.82-1.573l7-10a1 1 0 011.12-.38z' clip-rule='evenodd'/%3E%3C/svg%3E") center / 0.8125rem no-repeat;
  box-shadow: inset 0 0 0 1px rgba(255,213,79,0.45);
}
/* Every ✕ that closes a sheet: red at full strength, one mark the same
   everywhere (translucent read muddy on colour and washed out on white). */
.modal-close, #zeno-close {
  background: linear-gradient(160deg, #E5534B, #B42318);
  border-color: rgba(255, 255, 255, 0.45);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), 0 0.1875rem 0.625rem rgba(90, 10, 10, 0.28);
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
.modal-close:hover, #zeno-close:hover {
  background: linear-gradient(160deg, #EF4444, #991B1B);
}
#modal-schedule-mode .schedule-mode-body { border: none; padding-top: 1.125rem; }

/* The picked mode keeps the amber it always had. Against the ordinary
   surface it finally reads as a selection instead of a yellow tint lost in
   green, and it answers the gold bolt at the top of the sheet. */
#modal-schedule-mode .sched-mode.selected {
  background: color-mix(in srgb, var(--amber) 13%, transparent);
  border-color: var(--amber);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--amber) 35%, transparent);
}
#modal-schedule-mode .sched-mode.selected svg { color: var(--amber); }
#modal-schedule-mode .sched-mode.selected span { font-weight: 650; }

/* Run Schedule IS the Auto-Schedule button (.generate-btn, same markup), so
   it flashes the same way on hover. Only its size differs: full width. */
#modal-schedule-mode #btn-run-schedule {
  width: 100%; height: 2.875rem; margin-left: 0;
  justify-content: center; gap: 0.5rem; font-size: 0.9375rem;
}
#modal-schedule-mode #btn-run-schedule svg { width: 1rem; height: 1rem; }
#modal-schedule-mode #btn-run-schedule:disabled {
  background: var(--surface2); border-color: var(--border); color: var(--text-dim);
  box-shadow: none; cursor: not-allowed; transform: none; animation: none;
}
#modal-schedule-mode #btn-run-schedule:disabled svg,
#modal-schedule-mode #btn-run-schedule:disabled .gen-bolt { opacity: 0.4; animation: none; }
#modal-schedule-mode #btn-run-schedule:disabled :is(.gen-spark, .gen-dot) { animation: none; opacity: 0; }

/* Settings / grouped-list panels (Settings modal, Lists modal) — Apple System
   Settings style: a small caption sits above a rounded card, the card groups
   related rows behind a shared background with hairline dividers between
   them, so every panel in the app reads as one consistent system instead of
   ad-hoc inline-styled rows. */
.settings-section { margin-bottom: 1.375rem; }
.settings-section:last-child { margin-bottom: 0; }
.settings-section-title {
  font-size: 0.75rem; font-weight: 600; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: 0.04em;
  margin: 0 0.25rem 0.5rem;
}

/* Settings modal: sidebar nav + content panes, macOS System Settings style.
   #ng-modal-settings is Grades' and Curriculum's own copy of this exact
   modal (same markup/classes, different id) -- listed alongside
   #modal-settings so all three apps stay the same width instead of Grades/
   Curriculum silently falling back to .modal's generic 30rem. */
#modal-settings .modal, #ng-modal-settings .modal { width: 40rem; }
.settings-body {
  display: flex; align-items: stretch; padding: 0;
  height: 28.75rem; max-height: 66vh;
}
.settings-nav {
  position: relative;
  isolation: isolate;
  width: 10.625rem; flex-shrink: 0;
  border-right: 1px solid var(--border);
  padding: 0.875rem 0.625rem;
  display: flex; flex-direction: column; gap: 0.125rem;
  overflow-y: auto;
}
.settings-nav-indicator {
  position: absolute;
  top: 0; left: 0;
  width: 0; height: 0;
  border-radius: 0.5rem;
  background: var(--surface2);
  box-shadow: 0 1px 0.1875rem rgba(0,0,0,0.08);
  /* Position moves via transform (GPU-composited, matches the auth-tab
     indicator's smoothness) instead of animating top/left directly --
     those force a layout reflow every frame, which read as jerky/snapping
     especially since a pane swap reflows the whole modal at the same time. */
  transform: translate(0, 0);
  /* Only transform animates: it runs on the compositor, so the pane being
     laid out at the same moment cannot make it stutter. Width and height
     are the same for every item and are set without a transition. */
  transition: transform 0.2s cubic-bezier(0.2, 0.8, 0.2, 1);
  will-change: transform;
  pointer-events: none;
  z-index: 0;
}
.settings-nav-item {
  position: relative;
  z-index: 1;
  /* Its own layer, like the pill's: Safari on iPhone otherwise paints the
     pill (a composited layer, will-change) over the active item's icon in
     the scrolling row, whatever the z-index says. */
  transform: translateZ(0);
  display: flex; align-items: center; gap: 0.5625rem;
  width: 100%; padding: 0.5rem 0.625rem; border: none; border-radius: 0.5rem; background: none;
  font-family: var(--font); font-size: 0.8125rem; font-weight: 500; color: var(--text-muted);
  text-align: left; cursor: pointer; transition: background 0.12s var(--ease), color 0.12s var(--ease);
}
.settings-nav-item svg { width: 1rem; height: 1rem; flex-shrink: 0; }
/* Hover only on the others: on the active one it would double the pill. The
   active label keeps its weight, so it does not reflow as the pill lands. */
.settings-nav-item:not(.active):hover { background: color-mix(in srgb, var(--surface2) 60%, transparent); color: var(--text); }
.settings-nav-item.active { color: var(--primary); }
.settings-panes { flex: 1; min-width: 0; padding: 1.25rem 1.375rem; overflow-y: auto; }
.settings-pane { display: none; }
.settings-pane.active { display: block; }
.settings-pane .settings-section:last-child { margin-bottom: 0; }

/* .settings-body is padding:0 (its fixed-height two-pane layout manages
   its own internal padding), so unlike other modals it contributes no
   bottom breathing room before .modal-footer -- add it back just for the
   footer that follows this specific body. */
#modal-settings .modal-footer, #ng-modal-settings .modal-footer { padding-top: 1rem; }

@media (max-width: 640px) {
  #modal-settings .modal, #ng-modal-settings .modal { width: 100%; }
  .settings-body { height: auto; max-height: none; flex-direction: column; }
  .settings-nav {
    width: 100%;
    flex-direction: row;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    gap: 0.375rem;
    padding: 0.625rem 0.75rem;
    border-right: none;
    border-bottom: 1px solid var(--border);
  }
  .settings-nav::-webkit-scrollbar { display: none; }
  .settings-nav-item {
    flex-direction: column;
    flex-shrink: 0;
    width: auto;
    gap: 0.1875rem;
    padding: 0.4375rem 0.9375rem;
    border-radius: 0.625rem;
  }
  .settings-nav-item svg { width: 1.125rem; height: 1.125rem; }
  .settings-nav-item span { font-size: 0.65625rem; white-space: nowrap; }
  .settings-panes { overflow-y: visible; padding: 1.125rem; }
}

.settings-card {
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
/* Integrations pane stacks Tasks/Calendars, Export and Webhooks cards
   directly (no .settings-section wrapper between them), so give the group
   boundary its own breathing room instead of the bare 8px title margin. */
.settings-card + .settings-section-title { margin-top: 1.375rem; }
.settings-card + .settings-card { margin-top: 0.75rem; }
.settings-card-pad { padding: 0.875rem; }
.settings-card-pad .form-group:last-child { margin-bottom: 0; }
.settings-card-pad .form-row + .form-group { margin-top: 0.875rem; }
/* Inputs/select default to the same --surface2 as the card itself —
   override so they read as inset fields on the grouped card instead of
   blending into it. (.theme-picker is its own already-layered track+pill
   component and must NOT be re-parented onto --surface2, or its active
   segment — which is --surface, matching a plain page background — loses
   its contrast; it stays unwrapped, directly on the section.) */
.settings-card-pad input, .settings-card-pad select {
  background-color: var(--surface);
}
/* A lone number under its own line of explanation (the retention minimum):
   the plain full-width field would read as a form to fill in rather than as
   one value on a row. */
.settings-card-pad .retention-min-row { margin-top: 0.75rem; margin-bottom: 0; max-width: 12rem; }

.settings-row {
  display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
  padding: 0.75rem 0.875rem;
}
.settings-row + .settings-row { border-top: 1px solid var(--border); }
/* "Your week": three settings in one card, each with room to breathe. */
.settings-week-card .settings-row { padding: 0.875rem 1rem; min-height: 3.5rem; }
.settings-week-card .settings-row-sub { margin-top: 0.1875rem; }
.settings-row-icon {
  width: 1.875rem; height: 1.875rem; border-radius: 0.5rem; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--primary) 12%, transparent);
  color: var(--primary);
}
.settings-row-main { min-width: 0; flex: 1; }
.settings-row-label { font-size: 0.8125rem; font-weight: 600; color: var(--text); line-height: 1.3; }
.settings-row-sub { font-size: 0.75rem; color: var(--text-muted); margin-top: 0.0625rem; line-height: 1.3; }
/* A row says what it is in its label. The line under it is only for live
   state (synced at, codes left, unavailable here) and takes no room when
   there is none. */
.settings-row-sub:empty, .settings-credits-sub:empty, #ics-form-hint:empty { display: none; }
.settings-row-actions { display: flex; align-items: center; gap: 0.375rem; flex-shrink: 0; }
/* Match Manage's pill height/radius to the Sync icon button below so the
   two sit level and share the same corner language instead of Manage's
   generic .btn-sm size (shorter, more rounded) looking mismatched next
   to Sync's fixed 30px/8px square. */
.settings-row-actions .btn { height: 1.875rem; border-radius: 0.5rem; }
/* Toggle switch for boolean settings rows (e.g. Notifications) -- same
   shape/behavior as Grades' .ng-toggle, ported here since this pane
   (index.html) doesn't load grades.css. */
.settings-toggle { position: relative; display: inline-block; width: 2.5rem; height: 1.5rem; flex-shrink: 0; }
.settings-toggle input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.settings-toggle-slider {
  position: absolute; inset: 0; background: var(--border2); border-radius: 62.4375rem;
  transition: background 0.15s var(--ease); pointer-events: none;
}
.settings-toggle-slider::before {
  content: ''; position: absolute; width: 1.125rem; height: 1.125rem; left: 0.1875rem; top: 0.1875rem;
  background: #fff; border-radius: 50%; transition: transform 0.15s var(--ease);
  box-shadow: 0 1px 0.1875rem rgba(0,0,0,0.2);
}
.settings-toggle input:checked + .settings-toggle-slider { background: var(--primary); }
.settings-toggle input:checked + .settings-toggle-slider::before { transform: translateX(1rem); }
.settings-toggle input:disabled + .settings-toggle-slider { opacity: 0.4; cursor: not-allowed; }
/* Compact icon-only action (Sync) sitting next to a text button (Manage)
   inside a settings row -- flat, not another glass pill competing for
   attention. Background uses --surface (not --surface2) for the same
   nested-contrast reason as .settings-card-pad inputs above. */
.settings-icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.875rem; height: 1.875rem; flex-shrink: 0;
  padding: 0; border: none; border-radius: 0.5rem;
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
  transition: background 0.15s var(--ease), color 0.15s var(--ease), transform 0.1s var(--ease);
}
.settings-icon-btn svg { width: 0.9375rem; height: 0.9375rem; }
.settings-icon-btn:hover { background: var(--border); color: var(--text); }
.settings-icon-btn:active { transform: scale(0.92); }
.settings-icon-btn:disabled { opacity: 0.55; cursor: not-allowed; }

/* ── Webhooks modal ─────────────────────────────────────────────────────────
   "Your webhooks" cards + the "Add a webhook" form's event checklist. Was
   all raw inline styles before (including native, unstyled checkboxes for
   the event list -- inconsistent size/baseline against their label text
   across browsers, which read as "misaligned") -- reuses .cl-check (the
   same custom checkbox already used for checklist steps) and the app's
   existing settings-card/-row language instead. ────────────────────────── */
.webhook-card-list { display: flex; flex-direction: column; gap: 0.625rem; }
.webhook-card {
  display: flex; flex-direction: column; gap: 0.625rem;
  padding: 0.75rem 0.875rem; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface2);
}
.webhook-card-top { display: flex; align-items: flex-start; gap: 0.625rem; }
.webhook-card-icon {
  width: 1.875rem; height: 1.875rem; border-radius: 0.5rem; flex-shrink: 0; margin-top: 0.0625rem;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--primary) 12%, transparent);
  color: var(--primary);
}
.webhook-card-main { min-width: 0; flex: 1; }
.webhook-card-url { font-size: 0.78125rem; font-weight: 600; color: var(--text); line-height: 1.35; word-break: break-all; }
.webhook-card-events { font-size: 0.71875rem; color: var(--text-muted); margin-top: 0.1875rem; }
.webhook-card-footer {
  display: flex; align-items: center; justify-content: space-between; gap: 0.625rem;
  padding-top: 0.625rem; border-top: 1px solid var(--border);
}
.webhook-card-status { display: inline-flex; align-items: center; gap: 0.375rem; font-size: 0.6875rem; color: var(--text-dim); min-width: 0; }
.webhook-card-status-dot { width: 0.375rem; height: 0.375rem; border-radius: 50%; flex-shrink: 0; background: var(--text-dim); }
.webhook-card-status.ok { color: var(--green); }
.webhook-card-status.ok .webhook-card-status-dot { background: var(--green); }
.webhook-card-status.error { color: var(--red); }
.webhook-card-status.error .webhook-card-status-dot { background: var(--red); }
.webhook-card-actions { display: flex; gap: 0.375rem; flex-shrink: 0; }

.webhook-add-card { display: flex; flex-direction: column; gap: 0.625rem; }
.webhook-events-label { font-size: 0.6875rem; font-weight: 700; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.03em; margin-top: 0.125rem; }
.webhook-events-list {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  overflow: hidden;
}
.webhook-event-row {
  display: flex; align-items: center; gap: 0.625rem;
  padding: 0.5625rem 0.75rem; cursor: pointer;
  transition: background 0.12s var(--ease);
}
.webhook-event-row:hover { background: color-mix(in srgb, var(--text) 5%, transparent); }
.webhook-event-row + .webhook-event-row { border-top: 1px solid var(--border); }
.webhook-event-row span { font-size: 0.8125rem; color: var(--text); }
.webhook-event-row .cl-check { background: var(--surface2); }

/* A row that behaves like a full-width tappable action (Log Out, Reset
   Password, Manage Billing…) rather than a status row with a trailing
   button — flat, no border, just a hover wash like a native list cell. */
.settings-link-row {
  display: flex; align-items: center; justify-content: space-between; gap: 0.625rem;
  width: 100%; padding: 0.75rem 0.875rem; border: none; background: none;
  font-family: var(--font); font-size: 0.8125rem; font-weight: 600; color: var(--text);
  text-align: left; cursor: pointer; transition: background 0.12s var(--ease);
  text-decoration: none; /* also used on <a> rows (e.g. "Manage calendars in zenow") */
}
.settings-link-row + .settings-link-row { border-top: 1px solid var(--border); }
.settings-link-row .settings-link-row-external { flex-shrink: 0; width: 0.875rem; height: 0.875rem; opacity: 0.6; }
/* Separator for the "Manage calendars in zenow" row -- it follows plain
   .settings-row siblings, not another .settings-link-row, so the general
   adjacent-sibling rule above never fires for it. */
#ng-lists-calendars-container .settings-link-row,
.settings-pane[data-settings-pane="integrations"] .settings-link-row { border-top: 1px solid var(--border); }
.settings-link-row:hover { background: color-mix(in srgb, var(--text) 4%, transparent); }
.settings-link-row.danger { color: var(--red); }
.settings-link-row.accent { color: var(--accent); }
.settings-link-row.accent:hover { background: color-mix(in srgb, var(--accent) 8%, transparent); }

/* Help/bug-report -- bottom-left of the Settings modal footer. A single "?"
   button opens a drop-up menu (FAQ links out to the standalone /faq page;
   Report a bug opens #modal-report-bug, which files a GitHub issue via
   POST /api/feedback -- see routes/feedback.js) -- .settings-help-btn keeps
   the same flat icon-button language as .settings-icon-btn (the
   Integrations tab's Sync buttons); the FAQ search/accordion itself now
   lives in faq.html's own inline styles, not here, since it's a real page,
   not a modal. */
.settings-help-wrap { position: relative; display: flex; }
.settings-help-btn {
  width: 1.875rem; height: 1.875rem; border-radius: 0.5rem; flex-shrink: 0;
  border: none; background: var(--surface2);
  color: var(--text-muted);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; text-decoration: none;
  transition: background 0.15s var(--ease), color 0.15s var(--ease), transform 0.1s var(--ease);
}
.settings-help-btn svg { width: 1.0625rem; height: 1.0625rem; }
.settings-help-btn:hover, .settings-help-btn.active { background: var(--border); color: var(--text); }
.settings-help-btn:active { transform: scale(0.92); }

.help-menu-dropup {
  position: absolute; bottom: calc(100% + 0.5rem); left: 0; z-index: 20;
  min-width: 13.125rem; padding: 0.375rem; border-radius: var(--radius);
  background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);
  display: flex; flex-direction: column; gap: 0.125rem;
}
.help-menu-dropup.hidden { display: none; }
.help-menu-item {
  display: flex; align-items: center; gap: 0.625rem; padding: 0.5625rem 0.625rem;
  width: 100%; border: none; background: none; text-align: left; cursor: pointer;
  border-radius: var(--radius-sm); color: var(--text); text-decoration: none;
  font-family: var(--font); font-size: 0.8125rem; font-weight: 600; transition: background 0.12s var(--ease);
}
.help-menu-item svg { width: 1rem; height: 1rem; flex-shrink: 0; color: var(--text-muted); }
.help-menu-item:hover { background: var(--surface2); }

.settings-subsection-label {
  font-size: 0.6875rem; font-weight: 600; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: 0.05em;
  padding: 0.625rem 0.875rem 0.375rem;
}
.settings-subsection-label:first-child { padding-top: 0.75rem; }

/* A card that holds .list-item rows (Lists modal: subjects, event types) —
   horizontal padding only, since .list-item already handles its own
   vertical rhythm and divider between rows. */
.settings-card-list { padding: 0 0.875rem; }
/* .list-item-name/.list-item-due default to the same --surface2 the page
   background used to be for this component — override to --surface so they
   still contrast once nested in the new grouped card. */
.settings-card-list .list-item-name:focus { background: var(--surface); }
.settings-card-list .list-item-due { background: var(--surface); }

/* Trailing "+ Add …" action row at the bottom of a grouped card — same
   family as .settings-link-row but accent-colored, iOS "add row" style. */
.settings-add-row {
  display: flex; align-items: center; gap: 0.375rem;
  width: 100%; padding: 0.625rem 0.125rem;
  border: none; border-top: 1px solid var(--border); background: none;
  font-family: var(--font); font-size: 0.8125rem; font-weight: 600; color: var(--accent);
  text-align: left; cursor: pointer; transition: background 0.12s var(--ease);
}
.settings-add-row:hover { background: color-mix(in srgb, var(--accent) 7%, transparent); }

.settings-plan-info { font-size: 0.8125rem; color: var(--text-muted); padding: 0.75rem 0.875rem; border-bottom: 1px solid var(--border); }

/* Today's AI allowance. The number carries it -- a count with a bar under it
   reads at a glance, which is the whole point of putting it somewhere other
   than inside the modal that spends it. The bar is what is LEFT, so it
   empties as the day goes, and turns amber then red as it runs down. */
.settings-credits { display: flex; flex-direction: column; gap: 0.5rem; }
.settings-credits-head { display: flex; align-items: baseline; gap: 0.4375rem; }
.settings-credits-value {
  font-size: 1.375rem; font-weight: 700; color: var(--text); line-height: 1;
  font-variant-numeric: tabular-nums;
}
.settings-credits-note { font-size: 0.75rem; color: var(--text-muted); }
.settings-credits-bar {
  height: 0.25rem; border-radius: 62.4375rem; overflow: hidden;
  background: color-mix(in srgb, var(--text) 10%, transparent);
}
.settings-credits-bar > span {
  display: block; height: 100%; border-radius: 62.4375rem;
  background: var(--accent); transition: width 0.3s var(--ease), background 0.3s var(--ease);
}
.settings-credits.is-low .settings-credits-bar > span { background: var(--amber); }
.settings-credits.is-empty .settings-credits-bar > span { background: var(--red); }
.settings-credits.is-empty .settings-credits-value { color: var(--red); }
.settings-credits-sub { font-size: 0.6875rem; color: var(--text-dim); line-height: 1.4; }
/* Nothing to measure -- no key on the server, or the call failed. The bar
   would be a zero that looks like an empty allowance, which is a different
   and more alarming thing than not knowing. */
.settings-credits.is-unknown .settings-credits-bar { display: none; }

/* Education settings: school autocomplete. Same shape as Grades'
   .ng-school-* combobox (public/css/grades.css) -- duplicated rather than
   shared because the two pages load separate stylesheets with no build
   step between them. */
.edu-combo { position: relative; }
.edu-combo-results {
  position: absolute; top: calc(100% + 0.25rem); left: 0; right: 0;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow);
  max-height: 13.75rem; overflow-y: auto; z-index: 20;
}
.edu-combo-result {
  padding: 0.5rem 0.75rem; cursor: pointer; font-size: 0.8125rem;
  display: flex; align-items: baseline; gap: 0.375rem;
}
.edu-combo-result-country { color: var(--text-muted); font-size: 0.71875rem; }
.edu-combo-result:hover, .edu-combo-result.active { background: var(--surface2); }
.edu-combo-result-empty { padding: 0.5rem 0.75rem; font-size: 0.8125rem; color: var(--text-muted); }
.edu-hint { font-size: 0.75rem; color: var(--text-muted); line-height: 1.45; margin-bottom: 0.75rem; }
.form-group .edu-hint { margin: 0.375rem 0 0; }

/* ── Toast ─────────────────────────────────────────────────────────────────── */
.toast-container {
  position: fixed; bottom: 1.25rem; right: 1.25rem; z-index: 310;
  display: flex; flex-direction: column; gap: 0.375rem;
  pointer-events: none;
}
.toast {
  background: var(--surface); border: 1px solid var(--border2); border-radius: var(--radius);
  padding: 0.625rem 0.875rem; font-size: 0.8125rem; color: var(--text); box-shadow: 0 0.25rem 1rem rgba(0,0,0,0.12);
  animation: slideIn 0.2s var(--ease); min-width: 13.75rem;
  display: flex; align-items: center; gap: 0.5rem;
  pointer-events: auto;
}
.toast.success { border-color: #BBF7D0; background: #F0FDF4; color: #166534; }
.toast-action {
  margin-left: auto; padding: 0.25rem 0.625rem; border-radius: var(--radius-sm);
  background: none; border: 1px solid currentColor; color: inherit; cursor: pointer;
  font-family: inherit; font-size: 0.75rem; font-weight: 700;
}
.toast-action:hover { background: color-mix(in srgb, currentColor 10%, transparent); }
.toast.error   { border-color: #FECACA; background: #FEF2F2; color: #991B1B; }
.toast-icon { flex-shrink: 0; width: 1rem; height: 1rem; display: flex; }
.toast-icon svg { width: 100%; height: 100%; }
.toast:not(.success):not(.error) .toast-icon { color: var(--accent); }
.toast.success .toast-icon { color: #16A34A; }
.toast.error .toast-icon { color: #DC2626; }
@keyframes slideIn { from { transform: translateX(1.25rem); opacity: 0; } to { transform: translateX(0); opacity: 1; } }

/* ── Utils ──────────────────────────────────────────────────────────────────── */
::selection { background: color-mix(in srgb, var(--accent) 28%, transparent); }
::-webkit-scrollbar { width: 0.3125rem; height: 0.3125rem; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--border2) 70%, transparent); border-radius: 0.375rem; }
::-webkit-scrollbar-thumb:hover { background: var(--border2); }

/* Respect the system reduced-motion setting */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

.spinner { width: 1rem; height: 1rem; border: 0.125rem solid rgba(127,127,127,0.25); border-top-color: currentColor; border-radius: 50%; animation: spin 0.6s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

.empty-state { text-align: center; padding: 1rem 0.5rem; color: var(--text-dim); font-size: 0.75rem; }

.hidden { display: none !important; }

/* ── Loading states ──────────────────────────────────────────────────────────── */
#loading-overlay {
  position: fixed;
  inset: 0;
  background: var(--bg);
  z-index: 1000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.25rem;
  transition: opacity 0.25s ease;
}
#loading-overlay.fade-out { opacity: 0; pointer-events: none; }
#loading-overlay.hidden   { display: none; }

.loading-spinner {
  width: 1.75rem; height: 1.75rem;
  border: 0.1875rem solid rgba(20,33,61,0.15);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}

.btn-loading {
  position: relative;
  color: transparent !important;
  pointer-events: none;
}
.btn-loading::after {
  content: '';
  position: absolute;
  width: 0.9375rem; height: 0.9375rem;
  border: 0.125rem solid rgba(255,255,255,0.25);
  border-top-color: #fff;
  border-radius: 50%;
  animation: spin 0.6s linear infinite;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
}

.calendar-loading {
  pointer-events: none;
  opacity: 0.45;
  transition: opacity 0.1s;
}

/* Loading: a thin line running along the header's bottom edge. It takes
   no room in the row, so nothing in the header moves while it shows. */
.topbar { position: relative; }
.topbar-spinner {
  position: absolute; left: 0; right: 0; bottom: -1px; height: 0.125rem; z-index: 2;
  overflow: hidden; pointer-events: none; background: transparent;
}
.topbar-spinner::before {
  content: ''; position: absolute; top: 0; bottom: 0; left: 0; width: 35%;
  border-radius: 0.125rem;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  animation: topbar-progress 1.1s cubic-bezier(0.45, 0, 0.55, 1) infinite;
}
@keyframes topbar-progress { from { transform: translateX(-100%); } to { transform: translateX(290%); } }

input:disabled, select:disabled, textarea:disabled { opacity: 0.5; cursor: not-allowed; }
/* Group headings in a list (the event type's Normal / Academic): upright,
   not the browser's bold italic. */
optgroup { font-style: normal; font-weight: 600; }
optgroup option { font-weight: 400; }

/* ── Responsive ─────────────────────────────────────────────────────────────── */

/* Hamburger — hidden on desktop */
.btn-hamburger {
  display: none;
  background: none; border: none; color: var(--text-muted);
      cursor: pointer; padding: 0.5625rem; border-radius: var(--radius-sm);
  align-items: center; justify-content: center; flex-shrink: 0;
  transition: background 0.15s, color 0.15s;
}
.btn-hamburger:hover { background: var(--surface2); color: var(--text); }

/* Sidebar backdrop — hidden by default */
.sidebar-backdrop {
  display: none;
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.35);
  z-index: 49;
  backdrop-filter: blur(0.125rem);
}
.sidebar-backdrop.visible { display: block; }

/* Mobile bottom nav — hidden on desktop */
.mobile-bottom-nav { display: none; }

/* ── Tablet (≤ 768px) ── */
@media (max-width: 768px) {
  /* Resize handles are desktop-only */
  .resize-handle { display: none; }
  /* Sections scroll naturally on mobile. min-height:0 is what makes that
     true: without it the flex item refuses to shrink below its content,
     the sidebar (overflow:hidden) grows past the viewport, and Timetable
     and the footer get pushed off the bottom of the screen. With it they
     stay pinned exactly as on desktop and the Subjects list scrolls. */
  .sidebar-scroll { overflow-y: auto; min-height: 0; }
  #academic-section { flex: none; height: auto; overflow: visible; }
  .academic-list { flex: none; overflow-y: visible; max-height: none; margin-right: 0; padding-right: 0; }
  /* A flyout to the right needs a right to fly out to. On a phone the
     sidebar IS the screen, so the day opens in place instead -- same
     content, the only direction there's room for. It scrolls inside its
     own bounded height so a long day can never push the footer away. */
  .tt-body {
    position: static; width: auto;
    max-height: 42vh; overflow-y: auto;
    padding: 0.5rem 0 0; background: none; border: none;
    box-shadow: none; border-radius: 0; animation: none;
  }
  .academic-list, .tt-list { flex: none; overflow-y: visible; max-height: none; }
  .academic-list { margin-right: 0; padding-right: 0; }
  /* Tomorrow matters more on a phone, where nobody is looking at a week
     grid: the row gets its own tinted shelf and a full-strength label
     instead of the muted section heading it wears on desktop. */
  .tt-section {
    background: rgba(255,255,255,0.05);
    border-top: 1px solid rgba(255,255,255,0.14);
    padding: 0.6875rem 1.125rem 0.8125rem;
  }
  .tt-head { font-size: 0.875rem; color: rgba(255,255,255,0.82); }
  .tt-head .tt-chevron { width: 0.8125rem; height: 0.8125rem; }
  .tt-head-action { font-size: 0.75rem; }
  .tt-row { font-size: 0.8125rem; grid-template-columns: 4.5rem 1fr; }
  .tt-group-label { font-size: 0.75rem; }

  /* Show hamburger */
  .btn-hamburger { display: flex; }

  /* Sidebar becomes slide-in overlay */
  .sidebar {
    position: fixed;
    left: 0; top: 0; bottom: 0;
    z-index: 50;
    transform: translateX(-100%);
    transition: transform 0.25s ease;
    /* Room for both tabs whole beside the diary, filter and +. */
    width: 18.5rem; min-width: 0;
    max-width: 88vw;
  }
  .af-peer-tabs { gap: 0.75rem; }
  .sidebar.open {
    transform: translateX(0);
    box-shadow: 0.25rem 0 2rem rgba(0,0,0,0.18);
  }

  /* Main fills full width */
  #screen-app { position: relative; }

  /* Modals slide up from bottom */
  .modal-overlay { align-items: flex-end; padding: 0; }
  .modal {
    width: 100%; max-width: 100%;
    border-radius: 1.25rem 1.25rem 0 0;
    max-height: 92vh;
  }

  /* Year view: two columns */
  .year-grid { grid-template-columns: repeat(2, 1fr); gap: 0.75rem; padding: 0.75rem 1rem; }

  /* Auth card fluid */
  .auth-card { width: calc(100% - 2rem); max-width: 26.25rem; }

  /* Topbar tighter */
  .topbar { padding: 0.625rem 0.75rem; gap: 0.5rem; }
}

/* ── Mobile (≤ 480px) ── */
@media (max-width: 480px) {
  /* Auth: full screen card */
  #screen-auth { align-items: flex-start; padding: 0; }
  .auth-card {
    width: 100%; max-width: 100%;
    min-height: 100dvh;
    border-radius: 0; border: none;
    padding: 2.5rem 1.5rem 2rem;
    display: flex; flex-direction: column; justify-content: center;
  }
  /* Match img to container so circle is never clipped */
  .logo-clip { width: 7.5rem; height: 7.5rem; }
  .logo-clip img { width: 7.5rem !important; height: 7.5rem !important; }

  /* Hide desktop view tabs — replaced by bottom nav */
  .view-tabs { display: none; }

  /* Hide "Today" button to save space */
  .today-btn { display: none; }

  /* Generate/Event/Study-mode btns: icon only, all three pinned to the same
     width so they line up evenly instead of drifting with each icon's own
     natural size. */
  .generate-label { display: none; }
  #btn-add-event span { display: none; }
  .generate-btn, .study-mode-btn, #btn-add-event {
    height: 1.875rem; width: 2.125rem; padding: 0; justify-content: center;
  }
  /* .study-mode-btn's own base rule (below, later in the file) sets a fixed
     2.75x2.25rem size at equal specificity, so it wins the cascade over the
     rule above on every screen size unless out-specified here too. */
  .topbar .study-mode-btn { height: 1.875rem; width: 2.125rem; }
  /* .study-mode-icon is 1.375rem at desktop size, dwarfing the ~0.9rem
     icons in the other two buttons above once all three boxes are pinned
     to the same size -- shrink it to match so the button doesn't read as
     bigger than its neighbors. */
  .study-mode-icon { width: 0.9375rem; height: 0.9375rem; }

  /* Chrono btn: icon only */
  .chrono-topbar-btn { padding: 0.25rem; gap: 0; min-width: 1.625rem; justify-content: center; }
  .chrono-topbar-btn::before { margin: 0; }
  .chrono-topbar-btn span.chrono-label { display: none; }
  #ng-btn-ask-chrono-review, #ng-btn-ask-chrono-goals { padding: 0.375rem 0.875rem 0.375rem 0.5625rem; gap: 0.4375rem; min-width: 0; justify-content: flex-start; }
  #ng-btn-ask-chrono-review span.chrono-label, #ng-btn-ask-chrono-goals span.chrono-label { display: inline; }

  /* Nav arrows: bigger tap target */
  .nav-arrow { width: 1.875rem; height: 1.875rem; }
  .nav-arrow svg { width: 1rem; height: 1rem; }

  /* Topbar compact */
  .topbar { padding: 0.5rem 0.5rem; gap: 0.25rem; }

  /* Week view: seven columns do not fit a phone, so the grid is wider than
     the screen and scrolls sideways. That was already true; what was missing
     is what makes it usable.

     The snap this comment has always promised is now actually declared, so a
     swipe lands on a day boundary instead of halfway through Wednesday. */
  #view-week {
    overflow-x: auto; -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity; scroll-padding-left: 3.25rem;
  }
  .week-header, .week-body { min-width: 30rem; }
  .week-grid { min-width: 30rem; }
  .week-header-day { min-width: 3.75rem; }
  .week-col, .week-header-day { scroll-snap-align: start; }
  /* The hour gutter is the first grid column, so scrolling right used to
     carry the times off-screen with it -- a wall of blocks with nothing to
     read them against.
     Sticky alone could not fix it: .week-body has overflow-y:auto, which
     makes it the gutter's scroll container, and .week-body never scrolls
     horizontally (it and its content are both 30rem) -- so `left: 0` had no
     horizontal scroll to react to. Both axes move onto #view-week instead,
     which makes IT the scrollport the gutter sticks within, and the day
     header pins to the top the way it did when .week-body owned the
     vertical scroll. */
  #view-week { overflow: auto; }
  .week-body { overflow: visible; min-height: 0; }
  .week-header { position: sticky; top: 0; z-index: 4; }
  .week-grid .time-gutter, .week-header .week-header-gutter {
    position: sticky; left: 0; z-index: 3;
    background: var(--bg);
    box-shadow: 1px 0 0 var(--border);
  }
  .week-header .week-header-gutter { background: var(--surface); }
  .cal-event { font-size: 0.625rem; }
  .cal-event .ev-time { display: none; }

  /* The bottom nav floats over the calendar (fixed, ~3.75rem tall including
     its offset), and every scroll area ended flush against the viewport --
     so the last hour of the day, and the last row of the month, sat under it
     permanently with no way to scroll them clear. */
  .week-body, .day-body, .month-grid, #view-year {
    padding-bottom: calc(4.5rem + env(safe-area-inset-bottom, 0rem));
  }

  /* The day header was a 1.25rem bold title with 1.5rem of padding and a
     sub-line under it: "Saturday, September 26, 2026" wrapped to two lines
     and took a fifth of the screen before a single hour was visible. */
  .day-header { padding: 0.75rem 1rem; }
  .day-header-title { font-size: 1rem; line-height: 1.25; }
  .day-header-sub { font-size: 0.75rem; margin-top: 0.125rem; }

  /* Same complaint in week view: a 1.375rem date over a 2.25rem "today"
     disc gave the day names a tenth of the screen before any hour showed.
     Now that the strip is sticky it is on screen the whole time, which is
     more reason for it to be a strip and not a banner. */
  .week-header-day { padding: 0.5rem 0.25rem; }
  .week-day-name { font-size: 0.625rem; margin-bottom: 0.125rem; }
  .week-day-num { font-size: 1.0625rem; }
  .week-header-day.today .week-day-num { width: 1.75rem; height: 1.75rem; }

  /* Stack form rows */
  .form-row { grid-template-columns: 1fr; }

  /* Stack plan cards */
  .plan-cards { grid-template-columns: 1fr; }

  /* Tighter modal padding on mobile */
  .modal-body { padding: 0.875rem 1rem; }
  .modal-header { padding: 1rem 1rem 0.5rem; }
  .modal-footer { padding: 0 1rem 1rem; }

  /* Month view cells taller */
  .month-grid { grid-auto-rows: minmax(4.375rem, 1fr); }
  .month-cell { padding: 0.1875rem; }
  .month-cell-num { width: 1.125rem; height: 1.125rem; font-size: 0.625rem; }
  .month-event { font-size: 0.5rem; padding: 0.0625rem 0.1875rem; margin-bottom: 0.0625rem; }

  /* Year view: single column */
  .year-grid { grid-template-columns: 1fr; gap: 0.625rem; padding: 0.625rem; }
  .year-month { padding: 0.5rem; }
  .year-day { padding: 0.25rem 0; }

  /* Mobile bottom nav — floating liquid glass */
  .mobile-bottom-nav {
    display: flex; align-items: stretch;
    position: fixed;
    left: 0.75rem; right: 0.75rem;
    bottom: calc(0.75rem + env(safe-area-inset-bottom, 0rem));
    padding: 0.75rem 0.5rem;
    border-radius: 62.4375rem;
    background: none;
    -webkit-backdrop-filter: blur(0.125rem) saturate(115%);
    backdrop-filter: blur(0.125rem) saturate(115%);
    box-shadow:
      inset 0 0 0 0.5px rgba(255,255,255,0.09),
      inset 0 1px 0 rgba(255,255,255,0.06),
      inset 0 -1px 1px rgba(255,255,255,0.04),
      0 0 0 0.5px rgba(20,33,61,0.05),
      0 1.125rem 2.75rem rgba(20,33,61,0.10);
    z-index: 40;
    touch-action: pan-y;
    -webkit-touch-callout: none;
  }
  .mobile-bottom-nav::before {
    content: '';
    position: absolute; inset: 0;
    border-radius: inherit;
    background: radial-gradient(150% 130% at 50% -30%, rgba(255,255,255,0.045), rgba(255,255,255,0) 60%);
    pointer-events: none; z-index: 0;
  }
  .mobile-bottom-nav::after {
    content: '';
    position: absolute; inset: 0;
    border-radius: inherit;
    background: radial-gradient(closest-side, transparent 62%, rgba(20,33,61,0.018) 96%);
    pointer-events: none; z-index: 0;
  }
  /* Quick Ask docks at this exact same bottom-of-screen spot on mobile --
     without this the nav pill peeks out from behind the (shorter) bar. */
  #screen-app.chrono-quick-open .mobile-bottom-nav {
    opacity: 0; pointer-events: none; transition: opacity 0.2s ease;
  }
  .mobile-nav-bubble {
    position: absolute; top: 0.375rem; bottom: 0.375rem; left: 0;
    width: calc((100% - 1rem) / 4 * 0.78);
    border-radius: 1.5rem;
    background: none;
    z-index: 4;
    -webkit-backdrop-filter: blur(0.375rem) saturate(140%);
    backdrop-filter: blur(0.375rem) saturate(140%);
    box-shadow:
      inset 0 0 0 0.5px rgba(255,255,255,0.05),
      inset 0 1px 0 rgba(255,255,255,0.04),
      inset 0 -1px 1px rgba(255,255,255,0.02),
      0 0 0 0.5px rgba(20,33,61,0.03),
      0 0.875rem 1.875rem rgba(20,33,61,0.08);
    opacity: 0;
    pointer-events: none;
    will-change: transform, width;
    transform: translateX(calc(0.11 * (100% - 1rem) / 4));
  }
  .mobile-nav-lens {
    position: absolute; top: 0.375rem; bottom: 0.375rem; left: 0;
    width: 4rem;
    border-radius: 1.5rem;
    overflow: hidden;
    background: #edf1f9;
    -webkit-mask-image: radial-gradient(ellipse at center, rgba(0,0,0,0.22) 38%, rgba(0,0,0,1) 66%);
    mask-image: radial-gradient(ellipse at center, rgba(0,0,0,0.22) 38%, rgba(0,0,0,1) 66%);
    box-shadow:
      inset 1px 0 0 0 rgba(255,70,90,0.09),
      inset 0 1px 0 0 rgba(255,70,90,0.06),
      inset -1px 0 0 0 rgba(60,140,255,0.08),
      inset 0 -1px 0 0 rgba(60,140,255,0.06),
      inset 0 0 0 0.5px rgba(255,255,255,0.05),
      inset 0 1px 0 rgba(255,255,255,0.04),
      inset 0 -1px 1px rgba(255,255,255,0.02),
      0 0 0 0.5px rgba(20,33,61,0.03),
      0 0.875rem 1.875rem rgba(20,33,61,0.08);
    opacity: 0;
    pointer-events: none;
    z-index: 2;
    will-change: transform, width;
    transition: opacity 0.18s ease;
  }
  .mobile-nav-lens-inner {
    position: absolute; top: 0; left: 0;
    display: flex;
    background: #edf1f9;
    -webkit-filter: blur(0.25rem) saturate(130%) brightness(1.12);
    filter: blur(0.25rem) saturate(130%) brightness(1.12);
    will-change: transform;
  }
  .mobile-nav-lens-inner .mobile-nav-tab::after { display: none; }
  .mobile-nav-lens::after {
    content: '';
    position: absolute; inset: 0;
    border-radius: inherit;
    pointer-events: none; z-index: 3;
    background:
      radial-gradient(14% 34% at var(--refl-x, 50%) 92%, rgba(255,255,255,0.18), rgba(255,255,255,0) 100%),
      radial-gradient(50% 100% at var(--glow-x, 50%) 0%, rgba(255,255,255,0.18), rgba(255,255,255,0));
  }
  .mobile-bottom-nav:has(.mobile-nav-tab[data-view="week"].active) .mobile-nav-bubble { transform: translateX(calc(1.11 * (100% - 1rem) / 4)); }
  .mobile-bottom-nav:has(.mobile-nav-tab[data-view="month"].active) .mobile-nav-bubble { transform: translateX(calc(2.11 * (100% - 1rem) / 4)); }
  .mobile-bottom-nav:has(.mobile-nav-tab[data-view="year"].active) .mobile-nav-bubble { transform: translateX(calc(3.11 * (100% - 1rem) / 4)); }
  .mobile-nav-tab::after {
    content: '';
    position: absolute; top: -0.3125rem; bottom: -0.3125rem; left: 7%; right: 7%;
    border-radius: 1.5rem;
    background:
      radial-gradient(150% 130% at 50% -30%, rgba(255,255,255,0.04), rgba(255,255,255,0) 60%),
      radial-gradient(closest-side, transparent 54%, rgba(20,33,61,0.025) 94%, rgba(20,33,61,0.012));
    box-shadow:
      inset 0 0 0 0.5px rgba(255,255,255,0.05),
      inset 0 1px 0 rgba(255,255,255,0.04),
      inset 0 -1px 1px rgba(255,255,255,0.02),
      0 0 0 0.5px rgba(20,33,61,0.03),
      0 0.875rem 1.875rem rgba(20,33,61,0.08);
    opacity: 0;
    pointer-events: none;
    z-index: 0;
  }
  .mobile-nav-tab.active::after { opacity: 1; }
  .mobile-bottom-nav.mb-active .mobile-nav-tab::after { opacity: 0; }
  .mobile-nav-bubble::before {
    content: '';
    position: absolute; top: 0.125rem; left: 0.5rem; right: 0.5rem; height: 42%;
    border-radius: 1.25rem;
    background:
      radial-gradient(14% 34% at var(--refl-x, 50%) 92%, rgba(255,255,255,0.10), rgba(255,255,255,0) 100%),
      radial-gradient(50% 100% at var(--glow-x, 50%) 0%, rgba(255,255,255,0.10), rgba(255,255,255,0));
    pointer-events: none;
  }
  .mobile-nav-bubble::after {
    content: '';
    position: absolute; inset: 0;
    border-radius: inherit;
    background: radial-gradient(closest-side, transparent 54%, rgba(20,33,61,0.05) 94%, rgba(20,33,61,0.02));
    pointer-events: none;
  }
  .mobile-nav-tab {
    position: relative; z-index: 1;
    flex: 1; display: flex; align-items: center; justify-content: center;
    background: none; border: none; cursor: pointer; padding: 0.6875rem 0.125rem;
    color: var(--text-muted);
    transition: color 0.35s ease;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
  }
  .mobile-nav-tab svg,
  .mobile-nav-tab .mobile-nav-label {
    position: relative; z-index: 1;
    width: 1.375rem; height: 1.375rem;
    stroke: currentColor;
    transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
  }
  .mobile-nav-tab .mobile-nav-label {
    width: auto; height: auto;
    font-size: 0.875rem; font-weight: 600; letter-spacing: 0.02em;
    line-height: 1;
  }
  .mobile-nav-tab.active { color: var(--primary); }
  .mobile-nav-tab.active .mobile-nav-label { transform: scale(1.08); }
  .mobile-nav-tab:active .mobile-nav-label { transform: scale(0.92); }
  .mobile-nav-tab:active { color: var(--primary); }

  /* Dark theme: tone the white inset highlights down so the bubble
     doesn't show bright edges against the dark bar */
  :root[data-theme="dark"] .mobile-nav-bubble {
    box-shadow:
      inset 0 0 0 0.5px rgba(255,255,255,0.025),
      inset 0 1px 0 rgba(255,255,255,0.02),
      inset 0 -1px 1px rgba(255,255,255,0.015),
      0 0 0 0.5px rgba(0,0,0,0.4),
      0 0.875rem 1.875rem rgba(0,0,0,0.35);
  }
  :root[data-theme="dark"] .mobile-nav-bubble::after {
    background: radial-gradient(closest-side, transparent 54%, rgba(0,0,0,0.18) 94%, rgba(0,0,0,0.08));
  }
  :root[data-theme="dark"] .mobile-nav-lens {
    background: #262c38;
    box-shadow:
      inset 1px 0 0 0 rgba(255,70,90,0.05),
      inset 0 1px 0 0 rgba(255,70,90,0.035),
      inset -1px 0 0 0 rgba(60,140,255,0.05),
      inset 0 -1px 0 0 rgba(60,140,255,0.035),
      inset 0 0 0 0.5px rgba(255,255,255,0.03),
      inset 0 1px 0 rgba(255,255,255,0.02),
      inset 0 -1px 1px rgba(255,255,255,0.015),
      0 0 0 0.5px rgba(0,0,0,0.4),
      0 0.875rem 1.875rem rgba(0,0,0,0.35);
  }
  :root[data-theme="dark"] .mobile-nav-lens-inner { background: #262c38; }
  :root[data-theme="dark"] .mobile-nav-lens::after {
    background:
      radial-gradient(14% 34% at var(--refl-x, 50%) 92%, rgba(255,255,255,0.07), rgba(255,255,255,0) 100%),
      radial-gradient(50% 100% at var(--glow-x, 50%) 0%, rgba(255,255,255,0.07), rgba(255,255,255,0));
  }
  :root[data-theme="dark"] .mobile-nav-tab::after {
    background:
      radial-gradient(150% 130% at 50% -30%, rgba(255,255,255,0.02), rgba(255,255,255,0) 60%),
      radial-gradient(closest-side, transparent 54%, rgba(0,0,0,0.12) 94%, rgba(0,0,0,0.06));
    box-shadow:
      inset 0 0 0 0.5px rgba(255,255,255,0.025),
      inset 0 1px 0 rgba(255,255,255,0.02),
      inset 0 -1px 1px rgba(255,255,255,0.015),
      0 0 0 0.5px rgba(0,0,0,0.4),
      0 0.875rem 1.875rem rgba(0,0,0,0.3);
  }

  /* Modals full height on very small screens */
  .modal { max-height: 96vh; }

  /* Context menu as bottom sheet (mobile) */
  .context-menu.ctx-bottom,
  #day-context-menu.ctx-bottom,
  #scope-context-menu.ctx-bottom {
    left: 0;
    right: 0;
    top: auto;
    bottom: 0;
    width: 100%;
    border-radius: 1rem 1rem 0 0;
    box-shadow: 0 -0.25rem 1.5rem rgba(0,0,0,0.15);
    padding: 0.5rem 0.5rem max(0.5rem, env(safe-area-inset-bottom));
    transform: translateY(100%);
    transition: transform 0.25s ease;
    display: block;
    visibility: visible;
  }
  .context-menu.ctx-bottom.ctx-visible,
  #day-context-menu.ctx-bottom.ctx-visible,
  #scope-context-menu.ctx-bottom.ctx-visible {
    transform: translateY(0);
  }
  .ctx-scope-label { font-size: 0.625rem; }
  .ctx-item { padding: 0.625rem 0.75rem; font-size: 0.875rem; }
  .ctx-divider { margin: 0.25rem 0.5rem; }

  /* Toast centered at bottom */
  .toast-container {
    right: 50%;
    transform: translateX(50%);
    bottom: calc(5.25rem + env(safe-area-inset-bottom, 0rem));
    text-align: center;
  }
  .toast {
    min-width: auto;
    width: calc(100vw - 2rem);
    max-width: 22.5rem;
  }

  /* Modals respect safe area bottom */
  .modal {
    padding-bottom: env(safe-area-inset-bottom, 0rem);
  }
}

/* ── Context Menu ─────────────────────────────────────────────────────────── */
.context-menu {
  position: fixed;
  z-index: 1000;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0.5rem;
  box-shadow: var(--shadow);
  padding: 0.25rem;
  min-width: 8.75rem;
  user-select: none;
}
.ctx-item {
  display: block;
  width: 100%;
  padding: 0.5rem 0.875rem;
  text-align: left;
  background: none;
  border: none;
  border-radius: 0.375rem;
  cursor: pointer;
  font-size: 0.8125rem;
  color: var(--text);
}
.ctx-item:hover { background: var(--surface2); }
.ctx-item.ctx-danger { color: var(--red); }
.ctx-item.ctx-disabled { opacity: .4; pointer-events: none; }
.ctx-item.ctx-chrono { color: var(--zeno-accent); font-weight: 700; }
.ctx-item.ctx-chrono:hover { background: rgba(200,150,46,0.12); }
/* "Completed" tick: a green-check glyph (a ✅-style bullet) so the commonest
   action in this menu is the one you can find at a glance. Always reads as
   the positive action even on an item already done. */
#ctx-complete, #ng-ctx-complete { display: flex; align-items: center; gap: 0.4rem; }
.ctx-complete-tick { flex-shrink: 0; }
.ctx-divider { height: 0.0625rem; background: var(--border); margin: 0.25rem 0; }

.ctx-scope-label {
padding: 0.3125rem 0.75rem 0.1875rem;
font-size: 0.6875rem;
font-weight: 600;
color: var(--muted);
pointer-events: none;
}

/* Retention toggle in schedule modal */
.sched-retention-list {
  display: flex; flex-direction: column; gap: 0.25rem;
  max-height: 11.25rem; overflow-y: auto;
}
.sched-retention-list::-webkit-scrollbar { width: 0.25rem; }
.sched-retention-list::-webkit-scrollbar-thumb { background: var(--border2); border-radius: 0.375rem; }

.retention-item {
  display: flex; align-items: center; gap: 0.625rem;
  padding: 0.625rem 0.75rem; border-radius: 0.5rem;
  background: rgba(255,255,255,0.55); border: 1px solid rgba(245,158,11,0.18);
  -webkit-backdrop-filter: blur(0.625rem) saturate(160%);
  backdrop-filter: blur(0.625rem) saturate(160%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.7);
  font-size: 0.8125rem; cursor: pointer; transition: background 0.12s, border-color 0.12s;
}
.retention-item:hover { background: rgba(255,255,255,0.8); border-color: rgba(245,158,11,0.3); }
.retention-item .ret-title {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.retention-item .ret-due {
  font-size: 0.6875rem; color: var(--text-dim);
  background: var(--surface2); padding: 0.0625rem 0.375rem; border-radius: 0.375rem;
  white-space: nowrap;
}
.retention-item input[type="checkbox"] {
  margin: 0; width: 0.9375rem; height: 0.9375rem; flex-shrink: 0;
  accent-color: var(--primary); cursor: pointer;
}
.cal-check {
  margin: 0; width: 0.9375rem; height: 0.9375rem; flex-shrink: 0;
  accent-color: var(--primary); cursor: pointer;
}
.cal-row { display: flex; align-items: center; gap: 0.625rem; padding: 0.25rem 0; font-size: 0.8125rem; line-height: 1.3; cursor: pointer; }
.retention-item .subject-dot { width: 0.5rem; height: 0.5rem; border-radius: 50%; flex-shrink: 0; }

/* The retention-program gate in the schedule modal: a labelled switch with
   an arrow that opens the program modal. Asks, because running with distant
   work unspaced is the thing the feature exists to stop. */
.sched-retention-row { display: flex; align-items: center; gap: 0.75rem; }
.sched-retention-row-label { flex: 1; min-width: 0; }
.sched-retention-row-label .sched-section-label { margin-bottom: 0.125rem; }
.sched-retention-row-actions { display: flex; align-items: center; gap: 0.625rem; flex-shrink: 0; }
.sched-retention-manage {
  display: flex; align-items: center; justify-content: center;
  width: 1.75rem; height: 1.75rem; border-radius: 0.5rem;
  border: 1px solid var(--border); background: var(--surface);
  color: var(--text-dim); cursor: pointer; transition: color 0.12s, border-color 0.12s;
}
.sched-retention-manage:hover { color: var(--accent); border-color: var(--accent); }
.sched-retention-manage.disabled { opacity: 0.35; pointer-events: none; }

/* The event modal's "busy all day" row. Same shape as the retention row:
   the explanation sits under the label rather than in a tooltip, because
   what the switch does is not guessable from its name. */
.event-blocking-row { display: flex; align-items: center; gap: 0.75rem; }
.event-blocking-label { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.125rem; }
.event-blocking-note { font-size: 0.6875rem; color: var(--text-muted); line-height: 1.35; }

.switch { position: relative; display: inline-block; width: 2.25rem; height: 1.3125rem; flex-shrink: 0; }
.switch input { opacity: 0; width: 0; height: 0; }
.switch .slider {
  position: absolute; inset: 0; border-radius: 62.4375rem;
  background: var(--border2); cursor: pointer; transition: background 0.15s;
}
.switch .slider::before {
  content: ''; position: absolute; width: 0.9375rem; height: 0.9375rem;
  border-radius: 50%; background: #fff; left: 0.1875rem; top: 0.1875rem;
  box-shadow: 0 1px 0.125rem rgba(0,0,0,0.25); transition: transform 0.15s;
}
.switch input:checked + .slider { background: var(--primary); }
.switch input:checked + .slider::before { transform: translateX(0.9375rem); }
.switch input:focus-visible + .slider { outline: 0.125rem solid var(--primary); outline-offset: 0.125rem; }

/* The program modal itself: chart on top, then the two groups (homeworks /
   exams) as plain option lists. */
.rp-chart-box {
  border: 1px solid var(--border); border-radius: 0.625rem;
  padding: 0.625rem 0.75rem 0.5rem; margin-bottom: 0.9rem;
  background: var(--surface);
}
.rp-chart-box .sched-section-label { margin-bottom: 0.35rem; }
.rp-chart-legend {
  display: flex; align-items: center; justify-content: center;
  gap: 0.5rem; font-size: 0.6875rem; color: var(--text-dim); margin-top: 0.375rem;
}
.rp-leg { width: 0.75rem; height: 0.1875rem; border-radius: 62.4375rem; }
.rp-leg-with { background: var(--accent); }
.rp-leg-without { background: var(--text-dim); }
.rp-group { margin-bottom: 0.9rem; }
.rp-item input[type="checkbox"] { accent-color: var(--primary); }

/* Day override indicator */
.week-header-day { position: relative; }
.week-header-day.day-excluded { opacity: .5; }
.month-cell { position: relative; }
/* A day with its own hours: a clock in the bottom-right corner that opens them. */
.cal-day-hours {
  position: absolute; right: 0.3125rem; bottom: 0.3125rem; z-index: 2;
  display: grid; place-items: center; width: 1.5rem; height: 1.5rem; padding: 0; border: 0; border-radius: 50%;
  color: var(--primary); background: color-mix(in srgb, var(--primary) 12%, var(--surface)); cursor: pointer;
  transition: background .15s, transform .12s;
}
.cal-day-hours:hover { background: color-mix(in srgb, var(--primary) 22%, var(--surface)); }
.cal-day-hours:active { transform: scale(0.92); }
.cal-day-hours > svg { width: 0.9375rem; height: 0.9375rem; }
:root[data-theme="dark"] .cal-day-hours { color: var(--accent); background: color-mix(in srgb, var(--accent) 16%, var(--surface)); }
@media (max-width: 640px) {
  .cal-day-hours { right: 0.1875rem; bottom: 0.1875rem; width: 1.25rem; height: 1.25rem; }
  .cal-day-hours > svg { width: 0.8125rem; height: 0.8125rem; }
}
.month-cell.day-excluded { opacity: .5; }

/* Schedule result */
.schedule-summary { font-size: 0.8125rem; line-height: 1.6; text-align: center; padding: 0.5rem 0; }
.schedule-summary .stat { font-weight: 600; color: var(--primary); }
.schedule-summary .warning { color: var(--orange, #f59e0b); font-weight: 500; }
.schedule-actions { display: flex; gap: 0.5rem; margin-top: 1rem; }
.schedule-actions .btn { flex: 1; }

/* Shared by every schedule-result variant (success, need-more-time,
   no-study-windows, resolved-with-AI) -- was four copies of the same
   handful of inline font-size/margin declarations, one per variant,
   hand-tuned separately and drifting slightly out of sync with each
   other. One set of rules now, referenced by class. */
.schedule-result-title { font-size: 1.0625rem; font-weight: 700; letter-spacing: -0.01em; margin-bottom: 0.25rem; color: var(--text); }

/* Auto-Schedule's "Your hours": what Settings > Scheduling says, read-only,
   as a small grouped list with an Edit link to where it is changed. */
.sched-hours-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.375rem; }
.sched-hours-edit {
  display: inline-flex; align-items: center; gap: 0.125rem; padding: 0.125rem 0.25rem; margin-right: -0.25rem;
  border: none; background: transparent; color: var(--primary); font: inherit; font-size: 0.8125rem; font-weight: 600; cursor: pointer; border-radius: 0.375rem;
}
.sched-hours-edit:hover { background: color-mix(in srgb, var(--primary) 8%, transparent); }
.sched-hours-edit svg { width: 0.75rem; height: 0.75rem; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.sched-hours-card { background: var(--surface2); border: 1px solid var(--border); border-radius: 0.75rem; overflow: hidden; }
.sched-hours-row { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; padding: 0.5625rem 0.875rem; font-size: 0.8125rem; color: var(--text-muted); }
.sched-hours-row + .sched-hours-row { border-top: 1px solid var(--border); }
.sched-hours-row span:last-child { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; text-align: right; }
.sched-hours-row span.is-muted { color: var(--text-muted); font-weight: 500; }
.sched-hours + .sched-note, #sched-hours .sched-note { margin-top: 0.4375rem; }

/* The time found, as an agenda: a calendar leaf per day, then each session
   with its homework, subject colour and hours. */
.found-list {
  list-style: none; margin: 0.875rem 0 0; padding: 0; text-align: left;
  background: var(--surface2); border: 1px solid var(--border); border-radius: 0.875rem;
  max-height: min(16rem, 38vh); overflow-y: auto; overscroll-behavior: contain;
}
.found-day { display: flex; gap: 0.875rem; padding: 0.75rem 0.875rem; }
.found-day + .found-day { border-top: 1px solid var(--border); }
.found-leaf {
  flex-shrink: 0; width: 2.75rem; align-self: flex-start;
  display: flex; flex-direction: column; align-items: center;
  padding: 0.3125rem 0 0.375rem; border-radius: 0.625rem;
  background: var(--surface); border: 1px solid var(--border);
  box-shadow: 0 1px 0.125rem rgba(0,0,0,0.04);
}
.found-leaf-wd { font-size: 0.5625rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--red); line-height: 1.2; }
.found-leaf-dn { font-size: 1.125rem; font-weight: 700; color: var(--text); line-height: 1.1; font-variant-numeric: tabular-nums; }
.found-leaf-mo { font-size: 0.5625rem; font-weight: 500; color: var(--text-dim); line-height: 1.2; text-transform: lowercase; }
.found-sessions { list-style: none; margin: 0; padding: 0; flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.found-session { position: relative; display: flex; align-items: center; gap: 0.75rem; padding-left: 0.6875rem; min-height: 2.25rem; }
.found-session::before {
  content: ''; position: absolute; left: 0; top: 0.125rem; bottom: 0.125rem;
  width: 0.1875rem; border-radius: 0.125rem; background: var(--subj);
}
.found-what { flex: 1; min-width: 0; }
.found-title { font-size: 0.8125rem; font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.found-meta { display: flex; align-items: center; gap: 0.3125rem; margin-top: 0.125rem; font-size: 0.75rem; color: var(--text-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.found-adjust { flex-shrink: 0; display: inline-flex; gap: 0.25rem; }
.found-step {
  width: 1.625rem; height: 1.625rem; padding: 0; border-radius: 50%; display: grid; place-items: center; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface2); color: var(--text-muted);
  transition: background .15s ease, color .15s ease, transform .1s ease;
}
.found-step svg { width: 0.625rem; height: 0.625rem; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; }
.found-step:hover:not(:disabled) { color: var(--text); background: color-mix(in srgb, var(--accent) 10%, var(--surface2)); }
.found-step:active:not(:disabled) { transform: scale(.92); }
.found-step:disabled { opacity: .35; cursor: default; }
.found-session.is-saving .found-meta { opacity: .5; }
/* "Don't plan this", a bin: quiet, after the row's own controls, red only when
   reached for. With a mouse it waits for the row's hover. */
.rs-drop {
  flex-shrink: 0; width: 1.625rem; height: 1.625rem; margin-left: -0.25rem; padding: 0; border: 0; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer; background: transparent; color: var(--text-dim);
  transition: opacity .15s ease, color .15s ease, background .15s ease, transform .1s ease;
}
.rs-drop svg { width: 0.875rem; height: 0.875rem; }
.rs-drop:hover { color: var(--red); background: color-mix(in srgb, var(--red) 10%, transparent); }
.rs-drop:active { transform: scale(.92); }
.rs-drop:focus-visible { outline: 0.125rem solid color-mix(in srgb, var(--red) 55%, transparent); outline-offset: 1px; }
@media (hover: hover) and (pointer: fine) {
  .found-session .rs-drop, .short-row .rs-drop { opacity: 0; }
  .found-session:hover .rs-drop, .short-row:hover .rs-drop, .rs-drop:focus-visible { opacity: 1; }
}
.rs-dropped {
  display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
  margin: 0.75rem 0 0; padding: 0.5rem 0.5rem 0.5rem 0.875rem; border-radius: 0.75rem;
  background: var(--surface2); border: 1px solid var(--border);
  font-size: 0.8125rem; color: var(--text-muted); text-align: left;
  animation: rs-dropped-in .22s cubic-bezier(.2, .8, .3, 1);
}
.rs-dropped span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rs-dropped-undo {
  flex-shrink: 0; padding: 0.3125rem 0.625rem; border: 0; border-radius: 0.5rem; background: transparent; cursor: pointer;
  font: inherit; font-weight: 600; color: var(--accent); transition: background .15s ease;
}
.rs-dropped-undo:hover { background: color-mix(in srgb, var(--accent) 10%, transparent); }
.rs-dropped-undo:disabled { opacity: .5; cursor: default; }
@keyframes rs-dropped-in { from { opacity: 0; transform: translateY(-0.25rem); } }
@media (prefers-reduced-motion: reduce) { .rs-dropped { animation: none; } }
.found-meta { overflow: hidden; }
.found-len { overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 480px) {
  #schedule-result-body .found-session { gap: 0.5rem; }
  #schedule-result-body .found-adjust { gap: 0.25rem; }
  #schedule-result-body .found-step { width: 1.75rem; height: 1.75rem; }
  #schedule-result-body .rs-drop { width: 1.5rem; margin-left: -0.125rem; }
  #schedule-result-body .short-row { gap: 0.625rem; }
  #schedule-result-body .found-day { gap: 0.625rem; padding-right: 0.625rem; }
  #schedule-result-body .found-meta { font-size: 0.75rem; gap: 0.25rem; }
}
.short-row.is-saving, .found-session.is-saving { pointer-events: none; }
.short-row.is-saving .short-main { opacity: .5; }
:root[data-theme="dark"] .found-leaf { box-shadow: none; }

/* What doesn't fit: one row per homework, its subject colour down the
   side, how much is covered as a thin bar, and its estimate as a stepper
   the student can correct on the spot. */
.short-head { padding-bottom: 0.25rem; }
.short-head .schedule-result-desc { margin-bottom: 0.25rem; }
.short-section-title { font-size: 0.8125rem; font-weight: 600; color: var(--text); margin: 0 0 0.5rem; }
.short-list {
  list-style: none; margin: 0.75rem 0 0; padding: 0; text-align: left;
  background: var(--surface2); border: 1px solid var(--border); border-radius: 0.875rem;
  max-height: min(18rem, 45vh); overflow-y: auto; overscroll-behavior: contain;
}
.short-row { position: relative; display: flex; align-items: center; gap: 0.75rem; padding: 0.75rem 0.75rem 0.75rem 1.125rem; }
.short-row + .short-row { border-top: 1px solid var(--border); }
.short-row::before {
  content: ''; position: absolute; left: 0.5rem; top: 0.8125rem; bottom: 0.8125rem;
  width: 0.1875rem; border-radius: 0.125rem; background: var(--subj);
}
.short-main { flex: 1; min-width: 0; }
.short-title { font-size: 0.875rem; font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.short-meta { font-size: 0.75rem; color: var(--text-muted); margin-top: 0.0625rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.short-meta .is-late { color: var(--red); font-weight: 500; }
.short-bar { height: 0.25rem; margin-top: 0.5rem; border-radius: 0.125rem; overflow: hidden; background: color-mix(in srgb, var(--text) 9%, transparent); }
.short-bar span { display: block; height: 100%; border-radius: inherit; background: var(--subj); transition: width .3s ease; }
.short-missing { font-size: 0.6875rem; font-weight: 600; color: #B45309; margin-top: 0.3125rem; font-variant-numeric: tabular-nums; }
.short-row.is-fit .short-missing { color: #15803D; }
.short-stepper {
  display: flex; align-items: center; padding: 0.125rem;
  background: var(--surface); border: 1px solid var(--border); border-radius: 62.4375rem;
}
.short-step {
  display: flex; align-items: center; justify-content: center;
  width: 1.75rem; height: 1.75rem; padding: 0; border: none; border-radius: 50%;
  background: transparent; color: var(--text); cursor: pointer; transition: background .15s ease;
}
.short-step svg { width: 0.75rem; height: 0.75rem; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; }
.short-step:hover:not(:disabled) { background: var(--surface2); }
.short-step:disabled { opacity: .3; cursor: default; }
.short-val { min-width: 3.75rem; text-align: center; font-size: 0.8125rem; font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; white-space: nowrap; }
.short-row.is-edited .short-val { color: var(--primary); }
:root[data-theme="dark"] .short-missing { color: var(--amber); }
:root[data-theme="dark"] .short-row.is-fit .short-missing { color: var(--green); }
@media (max-width: 480px) {
  .short-val { min-width: 3.25rem; font-size: 0.75rem; }
  .short-step { width: 1.625rem; height: 1.625rem; }
}
.schedule-result-desc { font-size: 0.8125rem; color: var(--text-muted); margin-bottom: 0.75rem; line-height: 1.5; }
.schedule-result-desc:last-child { margin-bottom: 0; }
.schedule-result-desc-tight { margin-bottom: 0.25rem; }
.schedule-result-note { font-size: 0.75rem; font-weight: 500; margin: 0.25rem 0 0; color: var(--text-muted); line-height: 1.45; }
.schedule-result-credits { font-size: 0.75rem; color: var(--text-dim); margin-bottom: 0.75rem; }
.schedule-result-slots {
  font-size: 0.75rem; color: var(--text-muted); margin: 0 0 0.5rem;
  padding-left: 1.125rem; line-height: 1.7; text-align: left; list-style: none;
}
.schedule-result-slots li { margin-bottom: 0.25rem; }
.schedule-result-slots li:last-child { margin-bottom: 0; }
/* What moved, and where to: the title on one line, the before/after under it. */
.schedule-result-slots li.moved {
  display: flex; flex-direction: column; gap: 0.0625rem;
  margin-bottom: 0.4375rem; line-height: 1.45;
}
.schedule-result-slots li.moved span { opacity: 0.75; }

.schedule-result-icon {
  width: 2.5rem; height: 2.5rem; margin: 0 auto 0.75rem;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%; background: rgba(42,157,143,0.12); color: var(--accent);
}
.schedule-result-icon svg { width: 1.375rem; height: 1.375rem; }
.schedule-result-icon.warning { background: rgba(245,158,11,0.14); color: var(--amber); }
.schedule-result-icon.sparkle { background: rgba(42,157,143,0.12); color: var(--accent); }
.schedule-result-icon.neutral { background: var(--surface2); color: var(--text-muted); }
.result-stats {
  display: flex; gap: 0.5rem; justify-content: center; margin: 1rem 0;
}
.result-stat-card {
  flex: 1; min-width: 0; text-align: center; padding: 0.75rem 0.375rem;
  background: var(--surface2); border: 1px solid var(--border);
  border-radius: var(--radius);
}
.result-stat-card .stat-num {
      font-size: 1.25rem; font-weight: 700; color: var(--primary); line-height: 1.2;
      font-variant-numeric: tabular-nums;
    }
.result-stat-card .stat-label {
font-size: 0.6875rem; color: var(--text-muted);
margin-top: 0.125rem;
}

/* A hint, not a notice. It had a panel and a coloured bar, which is the
   treatment for something that needs acting on -- this only says what
   already happens. Centred under the two time pickers it belongs to, rather
   than ranged left under the left-hand one as though it were that field's. */
.sched-note {
  font-size: 0.6875rem; color: var(--text-muted); line-height: 1.5;
  margin-top: 0.5rem; text-align: center;
}

/* ── Lists Modal ──────────────────────────────────────────────────────────── */
.list-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.375rem 0;
  border-bottom: 1px solid var(--border);
  position: relative;
  overflow: hidden;
  touch-action: pan-y;
  transition: opacity 0.25s ease;
}
.list-item-inner {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex: 1;
  min-width: 0;
  padding-right: 0.75rem;
  position: relative;
  z-index: 1;
  transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}
.list-item.swiping { transition: none; }
.list-item.swiping .list-item-inner { transition: none; }
.list-item:last-child { border-bottom: none; }
.list-item > * { position: relative; z-index: 1; }
.list-item.swiping * { -webkit-user-select: none; user-select: none; }
.swipe-action {
  /* The slot the row slides away from. Clear itself: what shows is a small
     circle that swells in with the swipe (--sxr / --sxl,
     0..1, set in attachSwipeActions) and gives one soft bounce once it's
     fully out. */
  --tint: 200, 150, 46;
  --ink: #A67B25;
  position: absolute;
  top: 0; bottom: 0;
  display: grid;
  place-items: center;
  width: 4.75rem;
  color: var(--ink);
  pointer-events: none;
  z-index: 0;
  opacity: 0;
  transition: opacity 0.2s ease;
}
.swipe-action::before {
  content: '';
  position: absolute;
  top: 50%; margin-top: -1.3125rem;
  width: 2.625rem; height: 2.625rem;
  border-radius: 50%;
  /* A plain circle, the icon in its colour: no glass. */
  background: color-mix(in srgb, var(--ink) 13%, var(--surface));
  transform: scale(calc(0.5 + var(--sx, 0) * 0.5));
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.swipe-action svg {
  position: absolute;
  top: 50%; margin-top: -0.5625rem;
  width: 1.125rem; height: 1.125rem;
  transform: scale(calc(0.6 + var(--sx, 0) * 0.4));
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.list-item.swiping .swipe-action,
.list-item.swiping .swipe-action::before,
.list-item.swiping .swipe-action svg,
.plan-row.swiping .swipe-action::before,
.plan-row.swiping .swipe-action svg { transition: none; }
.swipe-action-left {
  left: 0;
  /* Anchored to the edge the row slides off, so the bubble peeks in from
     there rather than hiding under the part still covering its slot. */
  --edge: 1.0625rem;
  --sx: var(--sxr, 0);
  opacity: min(1, calc(var(--sxr, 0) * 1.6));
}
.swipe-action-right {
  right: 0;
  width: 5.25rem;
  --edge: 1.3125rem;
  --tint: 220, 70, 60;
  --ink: #C4453A;
  --sx: var(--sxl, 0);
  opacity: min(1, calc(var(--sxl, 0) * 1.6));
}
.swipe-action-left::before { left: var(--edge); }
.swipe-action-left svg { left: calc(var(--edge) + 0.75rem); }
.swipe-action-right::before { right: var(--edge); }
.swipe-action-right svg { right: calc(var(--edge) + 0.75rem); }
:root[data-theme="dark"] .swipe-action { --ink: #E3B65C; }
:root[data-theme="dark"] .swipe-action-right { --ink: #F08A80; }
/* Fully out: the bubble settles with a small wobble. */
.list-item.swipe-revealed .swipe-action-right,
.plan-row.swipe-revealed .swipe-action-right { --sx: 1; }
.list-item.swipe-revealed .swipe-action-right::before,
.plan-row.swipe-revealed .swipe-action-right::before { animation: swipe-bubble 0.55s cubic-bezier(0.3, 0, 0.3, 1) both; }
.swipe-action-right:active::before { transform: scale(0.9); }
@keyframes swipe-bubble {
  0% { transform: scale(0.85); } 40% { transform: scale(1.08, 0.94); } 65% { transform: scale(0.97, 1.03); } 100% { transform: scale(1); }
}
.list-item.swipe-revealed .list-item-inner { transform: translateX(-5.25rem); }
/* Study Mode steps on a phone (studyTaskSwipeEl): the step slides, the
   bubbles wait under it, and the trash can on the row gives way to them. */
.study-task-swipe { position: relative; overflow: hidden; border-radius: 0.75rem; }
.study-task-swipe > .study-task-row { position: relative; z-index: 1; background: var(--surface); transition: transform 0.25s var(--ease); }
.study-task-swipe.swiping > .study-task-row { transition: none; }
.study-task-swipe.swiping .swipe-action, .study-task-swipe.swiping .swipe-action::before, .study-task-swipe.swiping .swipe-action svg { transition: none; }
.study-task-swipe .study-task-remove { display: none; }
.study-task-swipe.swipe-revealed .swipe-action-right { --sx: 1; opacity: 1; pointer-events: auto; cursor: pointer; }
.study-task-swipe.swipe-revealed .swipe-action-right::before { animation: swipe-bubble 0.55s cubic-bezier(0.3, 0, 0.3, 1) both; }
.list-item.swipe-revealed .swipe-action-right {
  opacity: 1;
  pointer-events: auto;
  cursor: pointer;
}
@media (max-width: 768px) {
  .list-item { padding: 0.8125rem 0; }
}
.list-item-color {
  width: 1.75rem; height: 1.75rem;
  border: none; border-radius: 50%;
  padding: 0.125rem; cursor: pointer;
  flex-shrink: 0;
  background: none;
}
/* Every native color picker is a circle, never a square. The element rule
   rounds the frame; the engine-specific rules round the actual swatch so the
   white square some browsers draw inside the frame can't peek through. */
input[type='color'] { border-radius: 50%; }
input[type='color']::-webkit-color-swatch-wrapper { padding: 0; }
input[type='color']::-webkit-color-swatch { border: none; border-radius: 50%; }
input[type='color']::-moz-color-swatch { border: none; border-radius: 50%; }
.list-item-name {
  flex: 1;
  border: 1px solid transparent;
  border-radius: 0.375rem;
  padding: 0.25rem 0.5rem;
  font-size: 0.8125rem;
  background: none;
  color: var(--text);
}
.list-item-name:focus {
  outline: none;
  border-color: var(--border2);
  background: var(--surface2);
}
/* Grades/Curriculum's read-only calendar rows, drawn like zenow's own cards. */
.ng-cal-card { display: flex; align-items: center; gap: 0.625rem; padding: 0.5rem 0.75rem; border: 1px solid var(--border); border-radius: 0.625rem; }
.ng-cal-swatch { width: 1.375rem; height: 1.375rem; border-radius: 50%; flex-shrink: 0; }
.ng-cal-main { flex: 1; min-width: 0; }
.ng-cal-title { font-size: 0.8125rem; font-weight: 600; line-height: 1.25; }
.ng-cal-sub { font-size: 0.7188rem; color: var(--text-muted); line-height: 1.3; }

.list-item-due {
  font-size: 0.6875rem;
  color: var(--text-muted);
  white-space: nowrap;
  padding: 0.125rem 0.375rem;
  background: var(--surface2);
  border-radius: 0.75rem;
}
.list-item-edit,
.list-item-delete {
  opacity: 0;
  transform: translateX(0.5rem);
}
.list-item:hover .list-item-edit,
.list-item:hover .list-item-delete,
.list-item:focus-within .list-item-edit,
.list-item:focus-within .list-item-delete {
  opacity: 1;
  transform: translateX(0);
}
.list-item-edit,
.list-item-delete {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.125rem;
  height: 2.125rem;
  padding: 0;
  border: none;
  border-radius: 0.5625rem;
  background: none;
  color: var(--text-dim);
  cursor: pointer;
  flex-shrink: 0;
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.list-item-edit svg,
.list-item-delete svg { width: 1.0625rem; height: 1.0625rem; }
.list-item-edit:hover { background: var(--surface2); color: var(--text); }
.list-item-delete:hover { background: color-mix(in srgb, var(--red) 12%, transparent); color: var(--red); }
.list-item-edit:active { background: var(--border); }
.list-item-delete:active { background: color-mix(in srgb, var(--red) 20%, transparent); }

@media (hover: none), (max-width: 480px) {
  .list-item-edit,
  .list-item-delete { display: none; }
}

/* ── Chrono AI Panel ──────────────────────────────────────────────────────── */
.chrono-topbar-btn {
  display: flex;
  align-items: center;
  gap: 0.4375rem;
  padding: 0.375rem 0.875rem 0.375rem 0.5625rem;
  background: linear-gradient(135deg, rgba(200,150,46,0.78), rgba(166,123,37,0.82));
  border: 1px solid rgba(255,240,200,0.35);
  border-radius: 1.5rem;
  cursor: pointer;
  font-size: 0.8125rem;
  font-weight: 600;
  color: #fff;
  font-family: var(--font);
  -webkit-backdrop-filter: blur(0.875rem) saturate(170%);
  backdrop-filter: blur(0.875rem) saturate(170%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), 0 0.25rem 1rem rgba(139,105,20,0.25);
  /* padding/gap included so collapsing to the icon-only Quick Ask/Study
     Mode state (below) shrinks smoothly in step with it, instead of
     snapping to its final size the instant the state class lands while
     everything else keeps easing. */
  transition-property: background, border-color, transform, box-shadow, padding, gap;
  transition-duration: 0.25s;
  transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);
  flex-shrink: 0;
}
.chrono-topbar-btn::before {
  content: '';
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 40% 60% 45% 55% / 55% 45% 55% 45%;
  background: radial-gradient(circle at 35% 30%, #FFF9E6 0%, #FDE68A 42%, var(--zeno-accent-light) 72%, rgba(212,169,74,0) 100%);
  box-shadow: inset 0 -1px 0.125rem rgba(139,105,20,0.25), 0 0 0.625rem rgba(227,183,62,0.45);
  flex-shrink: 0;
  animation: orbBreathe 2.6s ease-in-out infinite;
  will-change: transform;
}
.chrono-topbar-btn:hover {
  background: linear-gradient(135deg, rgba(212,169,74,0.88), rgba(184,134,42,0.9));
  border-color: rgba(255,240,200,0.5);
  transform: translateY(-1px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.4), 0 0.375rem 1.25rem rgba(139,105,20,0.35);
}
#ng-btn-ask-chrono-review::before, #ng-btn-ask-chrono-goals::before {
  content: none;
}
#screen-app.chrono-open .chrono-topbar-btn {
  display: none;
}
#screen-app.chrono-open .topbar {
  gap: 0.625rem;
  padding: 0.75rem 1rem;
}

.chrono-topbar-avatar { display: none; }

/* Same pill shape/size as .generate-btn (Auto-Schedule) -- height, radius,
   font -- just red instead of teal. Icon-only always (no label), so it's
   pinned to the same fixed width the other two topbar buttons use once
   they're minimized down to icon-only too, rather than sizing itself off
   its own padding+icon. */
.study-mode-btn {
  display: flex; align-items: center; justify-content: center; width: 2.75rem; height: 2.25rem;
  background: linear-gradient(135deg, color-mix(in srgb, var(--study-red) 85%, transparent), color-mix(in srgb, var(--study-red) 65%, black));
  border: 1px solid color-mix(in srgb, var(--study-red) 35%, transparent); border-radius: var(--radius);
  color: #fff; font-size: 0.8125rem; font-weight: 600; font-family: var(--font);
  cursor: pointer;
  transition: filter 0.15s, box-shadow 0.15s, border-color 0.15s, transform 0.15s;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.25), 0 0.125rem 0.625rem color-mix(in srgb, var(--study-red) 18%, transparent);
}
.study-mode-btn:hover { filter: brightness(1.08); }
/* A session is still running with the panel closed: a live dot says the
   button is the way back to it, with the tasks still open in it. */
.study-mode-btn { position: relative; }
.study-mode-badge { display: none; }
.study-mode-btn.is-return .study-mode-badge {
  display: flex; align-items: center; justify-content: center;
  position: absolute; top: -0.25rem; right: -0.25rem;
  box-sizing: border-box; min-width: 0.875rem; height: 0.875rem; padding: 0; border-radius: 62.4375rem;
  background: #fff; border: 0.125rem solid var(--study-red);
  color: var(--study-red); font: 700 0.625rem/1 var(--font); font-variant-numeric: tabular-nums;
  text-align: center; letter-spacing: 0;
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--study-red) 45%, transparent);
  animation: study-return-pulse 1.8s ease-out infinite;
}
/* With a number: a circle for one digit, a pill for more, the digits set
   in a line box exactly the height of the inside so they sit in the middle. */
.study-mode-btn.is-return .study-mode-badge.has-count {
  min-width: 1.125rem; height: 1.125rem; padding: 0 0.1875rem; top: -0.4375rem; right: -0.4375rem;
  line-height: calc(1.125rem - 0.25rem);
}
@keyframes study-return-pulse {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--study-red) 45%, transparent); }
  70%, 100% { box-shadow: 0 0 0 0.4375rem transparent; }
}
@media (prefers-reduced-motion: reduce) { .study-mode-btn.is-return .study-mode-badge { animation: none; } }
.study-mode-btn:active { transform: translateY(1px); }
/* The icon itself is the hand-drawn page-turn asset (studymode.webp) --
   not a CSS simulation of one. Resting state shows a static poster frame
   (studymode-poster.png, extracted from the webp's own first frame) so
   nothing plays until hovered; JS in app.js swaps the src to the animated
   webp on mouseenter (and resets it on every hover so it restarts from
   frame 1 instead of possibly resuming mid-loop), then swaps back to the
   poster on mouseleave. */
.study-mode-icon {
  width: 1.375rem; height: 1.375rem;
  object-fit: contain;
}
.study-mode-btn.anim-playing .study-mode-icon { display: none; }
.study-mode-btn.anim-playing .study-mode-icon-anim { display: block; }
/* Same as Chrono's own toggle button hiding while its panel is open --
   the panel has its own visible close (X), so a second toggle in the
   header is redundant once it's showing. */
#screen-app.study-open #btn-study-mode { display: none; }
/* Same icon-only squeeze as chrono-open above, for the same reason -- the
   study panel takes the same width out of the main area. */


.zeno-bubble {
  display: none;
  width: 3.125rem;
  height: 3.125rem;
  background: var(--primary);
  color: #fff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 0.25rem 1.25rem rgba(0,0,0,0.2);
  z-index: 300;
  transition: transform .15s, box-shadow .15s;
  border: none;
}
.zeno-bubble:hover { transform: scale(1.07); box-shadow: 0 0.375rem 1.75rem rgba(0,0,0,0.26); }

.zeno-panel {
  flex: 0 0 0;
  overflow: hidden;
  transition: width .22s ease;
}

#screen-app.chrono-open .zeno-panel {
  flex-basis: var(--zeno-w, 21.25rem);
}
#screen-app.chrono-open .zeno-panel-inner {
  box-shadow: -0.25rem 0 1.5rem rgba(0,0,0,0.06);
}

.zeno-panel-inner {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  background: linear-gradient(180deg, #FDF8EE 0%, #FCF6E6 100%);
  border-left: 1px solid #E8D5A0;
  overflow: hidden;
}

/* ── Panel resize handles ──────────────────────────────────────────────────── */
.resize-handle {
  position: absolute;
  top: 0; bottom: 0;
  width: 0.5rem;
  cursor: col-resize;
  touch-action: none;
  z-index: 60;
}
.resize-handle::after {
  content: '';
  position: absolute;
  top: 0; bottom: 0;
  left: 50%;
  width: 0.0625rem;
  transform: translateX(-50%);
  background: rgba(20,33,61,0);
  transition: background 0.15s ease;
}
.resize-handle:hover::after,
#screen-app.resizing .resize-handle::after,
#ng-app.resizing .resize-handle::after,
#cp-app.resizing .resize-handle::after {
  background: rgba(20,33,61,0.18);
}
#resize-sidebar { left: var(--sidebar-w, 16rem); transform: translateX(-50%); }
#ng-resize-sidebar { left: var(--sidebar-w, 16rem); transform: translateX(-50%); }
#resize-zeno { right: var(--zeno-w, 21.25rem); transform: translateX(50%); }
#screen-app:not(.chrono-open) #resize-zeno { display: none; }
#ng-resize-zeno, #cp-resize-zeno { right: var(--zeno-w, 21.25rem); transform: translateX(50%); }
#ng-app:not(.chrono-open) #ng-resize-zeno, #cp-app:not(.chrono-open) #cp-resize-zeno,
#ng-app.chrono-max #ng-resize-zeno, #cp-app.chrono-max #cp-resize-zeno { display: none; }
:is(#ng-app, #cp-app).resizing .zeno-panel { transition: none; }
:is(#ng-app, #cp-app).resizing, :is(#ng-app, #cp-app).resizing * { user-select: none; -webkit-user-select: none; }
#resize-study { right: var(--study-w, 18.75rem); transform: translateX(50%); }
#screen-app:not(.study-open) #resize-study,
#screen-app.study-max #resize-study, :is(#screen-app, #ng-app, #cp-app).chrono-max #resize-zeno { display: none; }
#screen-app.resizing .study-panel { transition: none; }
#screen-app.resizing { cursor: col-resize; }
#ng-app.resizing { cursor: col-resize; }
#cp-app.resizing { cursor: col-resize; }
#screen-app.resizing .zeno-panel { transition: none; }
#screen-app.resizing, #screen-app.resizing * { user-select: none; -webkit-user-select: none; }
#ng-app.resizing, #ng-app.resizing * { user-select: none; -webkit-user-select: none; }
#cp-app.resizing, #cp-app.resizing * { user-select: none; -webkit-user-select: none; }

.zeno-header {
  display: flex;
  flex-direction: column;
  border-bottom: 1px solid #E8D5A0;
  background: linear-gradient(180deg, #FDF5E0, #FBF3DA);
  flex-shrink: 0;
  position: relative;
}

.chrono-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.3);
  z-index: 299;
}

/* The bar is wide enough on desktop (22rem, growing from btn-chrono's own
   spot in the topbar) to sit on top of -- and half-cover -- whichever
   topbar buttons are just to its left, so those hide while it's open.
   Desktop-only: on mobile the bar docks to the bottom of the screen
   instead, nowhere near these topbar buttons, so there's nothing to hide. */


/* ── Chrono Quick Ask -- the Chrono button itself extending into an input
   bar, not a separate dropdown appearing under it: same gold pill, same
   height, right edge pinned to the button's own right edge (JS-positioned
   in openChronoQuick/positionChronoQuickBar), growing leftward in place.
   #btn-chrono fades out underneath as this grows over it so the two read
   as one continuous shape. The mobile media query below overrides this
   with a fixed bottom-of-screen dock instead. ───────────────────────────── */
.chrono-quick-bar {
  position: fixed;
  z-index: 250;
  display: flex; align-items: center; gap: 0.25rem;
  height: 2.1875rem;
  width: 22rem; max-width: calc(100vw - 1.5rem);
  /* Right padding clears the orb's own 34px footprint (it sits pinned to
     this same right edge, elevated above the bar -- see
     .chrono-topbar-btn.chrono-quick-active) plus 4px, so send and the orb
     read as one pair at the bar's end rather than send floating mid-bar
     with a hole between them. 4px is the smallest gap that still keeps the
     elevated orb off the send button's hit area. Mobile overrides this back
     down since the orb isn't anywhere near the bottom-docked bar there. */
  padding: 0 2.375rem 0 1rem;
  background: linear-gradient(135deg, rgba(200,150,46,0.92), rgba(166,123,37,0.94));
  border: 1px solid rgba(255,240,200,0.35);
  border-radius: 1.5rem;
  -webkit-backdrop-filter: blur(0.875rem) saturate(170%);
  backdrop-filter: blur(0.875rem) saturate(170%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), 0 0.25rem 1rem rgba(139,105,20,0.25);
  transform-origin: right center;
  /* transform is in here too, not just width/opacity, so the mobile
     variant's scale+translateY entrance (and its reverse on close) both
     animate instead of one of the two snapping. */
  transition: width 0.28s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.2s ease, transform 0.28s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.chrono-quick-bar.hidden { display: none; }
.chrono-quick-bar.chrono-quick-entering { width: 2.5rem; opacity: 0; }
.chrono-quick-input {
  flex: 1; min-width: 0;
  border: none; background: none; outline: none;
  font-family: var(--font); font-size: 0.8125rem; font-weight: 600; color: #fff;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  -webkit-tap-highlight-color: transparent;
}
/* Overrides the app-wide input:focus ring (further up this file) -- a
   faint box-shadow meant for the app's light-surface form fields, which
   read as a stray translucent contour against this gold pill. */
.chrono-quick-input:focus { border-color: transparent; box-shadow: none; }
.chrono-quick-input::placeholder { color: rgba(255,255,255,0.65); font-weight: 400; }
.chrono-quick-icon-btn {
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  width: 1.75rem; height: 1.75rem;
  border: none; border-radius: 50%;
  background: rgba(255,255,255,0.16); color: #fff;
  cursor: pointer; transition: background 0.15s ease;
  -webkit-tap-highlight-color: transparent;
}
.chrono-quick-icon-btn:hover { background: rgba(255,255,255,0.28); }
/* Goes DARKER than the bar rather than lighter. Matching the bar's own
   mid-gold made the button disappear into it, but a near-white circle read
   as a foreign element dropped on Chrono's gold -- a deep brown-gold stays
   in the same family while still separating from the fill behind it. The
   pale rim + inset highlight, not the fill contrast alone, are what draw
   the button's edge. A whisper of bubble: a soft specular sheen and a hint
   of bottom inner shade, so it reads as a raised round button rather than
   a flat disc -- nothing like the glass bead it used to be. */
.chrono-quick-send-btn {
  position: relative;
  background: linear-gradient(135deg, #D4A94A, #C8962E);
  color: #FFF9E6;
  border: 1px solid rgba(255,249,230,0.5);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.3),
    inset 0 -0.125rem 0.3125rem -0.125rem rgba(104,76,10,0.22),
    0 1px 0.25rem rgba(139,105,20,0.3);
  transition: background 0.2s, box-shadow 0.2s, border-color 0.2s;
}
.chrono-quick-send-btn::before {
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  pointer-events: none; z-index: 0;
  background: radial-gradient(130% 130% at 30% 16%, rgba(255,255,255,0.26), rgba(255,255,255,0) 56%);
  opacity: 0.75;
  transition: opacity 0.2s ease;
}
.chrono-quick-send-btn > svg { position: relative; z-index: 1; }
.chrono-quick-send-btn:hover {
  background: linear-gradient(135deg, #C8962E, #B8862A);
  border-color: rgba(255,249,230,0.65);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.35),
    inset 0 -0.125rem 0.3125rem -0.125rem rgba(104,76,10,0.26),
    0 0.125rem 0.5rem rgba(139,105,20,0.4);
}
.chrono-quick-send-btn:hover::before { opacity: 1; }
.chrono-quick-send-btn:disabled {
  background: rgba(107,79,13,0.35);
  color: rgba(255,243,214,0.5);
  cursor: not-allowed;
  box-shadow: none;
  border-color: rgba(255,240,200,0.2);
}
.chrono-quick-send-btn:disabled::before { opacity: 0; }
/* Overrides the app-wide teal focus ring (button:focus-visible further up
   this file) -- it landed on the send button (and the orb) after a click,
   which read as a stray green box against Chrono's own gold/cream theme.
   A dark gold-brown instead of the app's usual light ring, since these
   buttons already sit on a light cream fill against a mid-tone gold bar --
   a light ring would barely register against either. */
.chrono-quick-bar button:focus-visible,
#btn-chrono.chrono-quick-active:focus-visible,
#ng-btn-chrono.chrono-quick-active:focus-visible {
  box-shadow: 0 0 0 0.1875rem rgba(122,94,18,0.55);
}
/* Stays visible and clickable (not faded/pointer-events:none) while Quick
   Ask is open -- with outside-click and Escape both already able to close
   it, tapping the orb again now promotes to the full chat instead (see
   the click handler in wireEvents). Collapses to icon-only and sits above
   the bar so on desktop, where the bar's right edge is pinned under it,
   it still reads as the bar's own rounded end rather than a separate
   control. */
.chrono-topbar-btn.chrono-quick-active {
  position: relative;
  z-index: 251;
  padding: 0.375rem;
  gap: 0;
  justify-content: center;
}
.chrono-topbar-btn.chrono-quick-active .chrono-label { display: none; }

/* Speech-bubble: Quick Ask's own reply is otherwise invisible -- this is
   the one place it surfaces, and only when there's something to flag. */
.chrono-quick-bubble {
  position: fixed; z-index: 250;
  max-width: 20rem;
  padding: 0.625rem 0.875rem;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border2); border-radius: var(--radius);
  box-shadow: 0 0.75rem 1.75rem rgba(0,0,0,0.16);
  font-size: 0.8125rem; line-height: 1.45;
  /* Closed by default via opacity/transform/pointer-events, not display --
     show/hideChronoQuickBubble toggle .visible rather than .hidden, so
     this can actually transition instead of just snapping. */
  opacity: 0;
  transform: scale(0.94) translateY(0.25rem);
  pointer-events: none;
  transition: opacity 0.16s ease, transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.chrono-quick-bubble.visible {
  opacity: 1;
  transform: scale(1) translateY(0);
  pointer-events: auto;
}
.chrono-quick-bubble::after {
  content: ''; position: absolute; top: -0.375rem; right: 1.25rem;
  width: 0.75rem; height: 0.75rem; background: inherit;
  border-left: 1px solid var(--border2); border-top: 1px solid var(--border2);
  transform: rotate(45deg);
}

.zeno-header-row {
  display: flex;
  align-items: center;
  padding: 0.5rem 0.75rem;
}

.zeno-header-actions {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  margin-left: auto;
}

.zeno-title {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 1.125rem;
  font-weight: 600;
  color: #7A5E12;
}

/* The title is now a button (opens the chat switcher below it) -- reset
   away the native button chrome, keep .zeno-title's own look. */
.zeno-title-btn {
  border: none; background: none; padding: 0; margin: 0;
  font-family: inherit; cursor: pointer; min-width: 0;
}
.zeno-chat-title-text {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 10rem;
}
.zeno-chat-caret { flex-shrink: 0; opacity: 0.6; transition: transform 0.18s ease; }
.zeno-title-btn[aria-expanded="true"] .zeno-chat-caret { transform: rotate(180deg); }

/* Chat switcher: a dropdown of saved chats, anchored under the header.
   Reuses .list-item/.settings-add-row wholesale (same rows/swipe-to-delete
   gesture as the Lists modal) rather than inventing new row styling --
   just recolored to Chrono's own gold/cream palette instead of the app's
   generic surface tokens, so it reads as part of the Chrono panel. */
.zeno-chat-switcher {
  position: absolute; top: 100%; left: 0.75rem; right: 0.75rem;
  z-index: 5; margin-top: 0.375rem;
  background: linear-gradient(180deg, #FDF8EE 0%, #FCF6E6 100%);
  border: 1px solid #E8D5A0;
  border-radius: var(--radius); box-shadow: 0 0.75rem 1.75rem rgba(139,105,20,0.18);
  padding: 0.375rem 0.75rem;
  max-height: 60vh; overflow-y: auto;
  /* Closed by default via opacity/transform/pointer-events, not display --
     openChatSwitcher/closeChatSwitcher toggle .open rather than .hidden,
     so this can actually transition instead of just snapping. */
  opacity: 0;
  transform: scale(0.96) translateY(-0.25rem);
  transform-origin: top right;
  pointer-events: none;
  transition: opacity 0.16s ease, transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.zeno-chat-switcher.open {
  opacity: 1;
  transform: scale(1) translateY(0);
  pointer-events: auto;
}
.zeno-chat-switcher-list .list-item { border-bottom-color: rgba(200,150,46,0.2); }
.zeno-chat-switcher-list .list-item:last-child { border-bottom: none; }
/* No swipe gesture here (rename swaps the title for an input, which
   doesn't fit the Lists modal's swipe-to-focus-an-always-present-input
   pattern) -- so unlike Lists, these stay visible without a hover/swipe to
   reveal them, since a touch screen has no hover and needs some way in.
   transform: none cancels .list-item-edit/-delete's own default (a
   translateX(8px) resting offset meant to animate in on hover) -- left in
   place, that offset only ever resolved on :hover, so the buttons visibly
   *shifted sideways* on hover instead of just changing color. */
.zeno-chat-switcher-list .list-item-edit,
.zeno-chat-switcher-list .list-item-delete {
  position: static; opacity: 1; transform: none; flex-shrink: 0;
  color: #B89E5A;
}
.zeno-chat-switcher-list .list-item-edit:hover {
  background: rgba(200,150,46,0.16); color: #7A5E12;
}
.zeno-chat-switcher-list .list-item-edit:active { background: rgba(200,150,46,0.26); }
.zeno-chat-switcher-row-title {
  flex: 1; min-width: 0; text-align: left;
  border: none; background: none; padding: 0.25rem 0.5rem; margin: 0;
  font-family: inherit; font-size: 0.8125rem; color: #5C4A1E;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer;
}
.zeno-chat-switcher-row-title.active { font-weight: 700; color: #7A5E12; }
.zeno-chat-switcher-empty { padding: 0.75rem 0.25rem; font-size: 0.8125rem; color: #B89E5A; }
.zeno-chat-switcher .settings-add-row {
  border-top-color: rgba(200,150,46,0.2); color: var(--zeno-accent-dim);
}
.zeno-chat-switcher .settings-add-row:hover { background: rgba(200,150,46,0.1); }

.zeno-usage-bar {
  width: 100%;
  height: 0.1875rem;
  background: rgba(200,150,46,0.12);
  flex-shrink: 0;
}
.zeno-usage-fill {
  height: 100%;
  min-width: 0;
  background: linear-gradient(90deg, var(--zeno-accent), #FDE68A);
  transition: width 0.35s ease;
}

.zeno-avatar {
  width: 2.5rem;
  height: 2.5rem;
  flex-shrink: 0;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

.zeno-orb {
  width: 1.625rem;
  height: 1.625rem;
  background: radial-gradient(circle at 35% 30%, #FFF9E6 0%, #FDE68A 38%, var(--zeno-accent) 60%, #8B6914 82%, rgba(139,105,20,0) 100%);
  border-radius: 42% 58% 48% 52% / 52% 46% 54% 48%;
  animation: orbBreathe 2.4s ease-in-out infinite;
  position: absolute;
  z-index: 2;
  will-change: transform;
  backface-visibility: hidden;
}

.zeno-orb-ring {
  width: 2.25rem;
  height: 2.25rem;
  border: 1.5px solid rgba(200, 150, 46, 0.25);
  border-radius: 50%;
  position: absolute;
  animation: orbSpin 5s linear infinite;
  z-index: 1;
}

.zeno-orb-ring::before {
  content: '';
  position: absolute;
  width: 0.3125rem;
  height: 0.3125rem;
  background: #FDE68A;
  border-radius: 50%;
  top: -0.15625rem;
  left: 50%;
  margin-left: -0.15625rem;
  box-shadow: 0 0 0.625rem rgba(253, 230, 138, 1);
}

@keyframes orbBreathe {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.09); }
}

@keyframes orbSpin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

.zeno-badge {
  font-size: 0.75rem;
  font-weight: 700;
  background: linear-gradient(135deg, var(--zeno-accent), #A67B25);
  color: #fff;
  padding: 0.125rem 0.4375rem;
  border-radius: 0.75rem;
  letter-spacing: .06em;
}

.zeno-disclaimer {
  display: flex;
  align-items: flex-start;
  gap: 0.3125rem;
  padding: 0.3125rem 0.75rem;
  font-size: 0.625rem;
  color: #8B7355;
  background: #FCF4E0;
  border-bottom: 1px solid #E8D5A0;
  flex-shrink: 0;
  line-height: 1.4;
}

.zeno-messages {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: 0.875rem;
  display: flex;
  flex-direction: column;
  gap: 0.6875rem;
}
/* A message never shrinks to fit: Safari squeezes the children of a column
   scroller instead of letting them overflow, and then nothing scrolls. */
.zeno-messages > * { flex-shrink: 0; }
.zeno-messages::-webkit-scrollbar { width: 0.25rem; }
.zeno-messages::-webkit-scrollbar-track { background: transparent; }
.zeno-messages::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, #E8D5A0, #D4B86A);
  border-radius: 0.375rem;
}
.zeno-messages::-webkit-scrollbar-thumb:hover { background: var(--zeno-accent); }

.zeno-msg {
  max-width: 88%;
  padding: 0.625rem 0.8125rem;
  border-radius: var(--radius-lg);
  font-size: 0.875rem;
  line-height: 1.55;
  word-break: break-word;
  white-space: pre-wrap;
}
.zeno-msg em { font-style: italic; opacity: .8; }
.zeno-msg p { margin: 0; }
.zeno-msg p + p { margin-top: 0.5rem; }
.zeno-msg ul, .zeno-msg ol { margin: 0.375rem 0 0; padding-left: 1.125rem; }
.zeno-msg p + ul, .zeno-msg p + ol { margin-top: 0.5rem; }
.zeno-msg li + li { margin-top: 0.125rem; }
.zeno-msg strong { font-weight: 700; }
.zeno-msg h3, .zeno-msg h4, .zeno-msg h5 { font-weight: 700; line-height: 1.3; margin: 0.75rem 0 0.25rem; }
.zeno-msg h3:first-child, .zeno-msg h4:first-child, .zeno-msg h5:first-child { margin-top: 0; }
.zeno-msg h3 { font-size: 1rem; }
.zeno-msg h4 { font-size: 0.9375rem; }
.zeno-msg h5 { font-size: 0.8125rem; text-transform: uppercase; letter-spacing: 0.03em; }

.zeno-msg-assistant {
  background: linear-gradient(160deg, #FEF9EC, #F8ECD0 85%);
  color: #5C4A1E;
  align-self: flex-start;
  border-bottom-left-radius: 0.25rem;
  border: 1px solid rgba(200, 150, 46, 0.14);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.9),
    0 1px 0.1875rem rgba(92,74,30,0.08);
}

.zeno-msg-user {
  background: linear-gradient(160deg, var(--zeno-accent-light), var(--zeno-accent-dim));
  color: #fff;
  align-self: flex-end;
  border-bottom-right-radius: 0.25rem;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.28),
    0 0.125rem 0.375rem rgba(139,105,20,0.28);
}

.zeno-msg-image {
  max-width: 80%;
  align-self: flex-end;
}
.zeno-msg-image img {
  max-width: 100%;
  border-radius: 0.5rem;
  display: block;
}

/* A single word ("Thinking", "Adding"...) with an animated ellipsis
   (see zenoShowTyping/classifyChronoLoadingWordKey), not the old plain
   3-dot bounce -- so max-width fits a short word/phrase now, not just
   three tiny circles. */
.zeno-typing {
  display: flex;
  align-items: center;
  padding: 0.625rem 0.8125rem;
  max-width: 12rem;
  background: linear-gradient(160deg, #FEF9EC, #F8ECD0 85%);
  border: 1px solid rgba(200, 150, 46, 0.14);
  border-radius: var(--radius-lg);
  border-bottom-left-radius: 0.25rem;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.9),
    0 1px 0.1875rem rgba(92,74,30,0.08);
}
.zeno-typing-word { font-weight: 400; }

/* "Ask Chrono" on something: a chip naming what the question is about,
   above the input while it waits and above the student's bubble once sent. */
.chrono-ref-strip { display: flex; padding: 0.5rem 0.75rem 0; flex-shrink: 0; }
.chrono-ref {
  display: inline-flex; align-items: center; gap: 0.375rem; max-width: 100%;
  padding: 0.25rem 0.375rem 0.25rem 0.5rem; border-radius: 62.4375rem;
  font-size: 0.75rem; font-weight: 600; line-height: 1.2; color: var(--zeno-accent-dim, #8B6914);
  background: color-mix(in srgb, var(--zeno-accent, #C8962E) 12%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--zeno-accent, #C8962E) 30%, transparent);
}
.chrono-ref-icon { flex-shrink: 0; width: 0.875rem; height: 0.875rem; }
.chrono-ref-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chrono-ref-x {
  flex-shrink: 0; width: 1.125rem; height: 1.125rem; padding: 0; border: 0; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer; color: inherit; background: transparent; opacity: 0.7;
}
.chrono-ref-x:hover { opacity: 1; background: color-mix(in srgb, var(--zeno-accent, #C8962E) 18%, transparent); }
.zeno-msg-ref { align-self: flex-end; max-width: 88%; display: flex; justify-content: flex-end; margin-bottom: -0.125rem; }
:root[data-theme="dark"] .chrono-ref { color: var(--zeno-accent-light, #E8C66A); }

.zeno-image-strip {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.375rem 0.75rem;
  border-top: 1px solid #E8D5A0;
  background: #FCF4E0;
  flex-shrink: 0;
}
.zeno-image-strip img {
  height: 2.5rem;
  width: 2.5rem;
  object-fit: cover;
  border-radius: 0.375rem;
  flex-shrink: 0;
}
/* Shown instead of the <img> thumbnail for a non-image attachment (PDF,
   text file) -- there's nothing to preview visually, just a generic file
   glyph in the same slot so the strip's layout doesn't jump between the
   two cases. */
.zeno-file-icon {
  height: 2.5rem; width: 2.5rem; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  border-radius: 0.375rem;
  background: rgba(184,158,90,0.15); color: #B89E5A;
}
.zeno-file-icon svg { width: 1.25rem; height: 1.25rem; }
.zeno-image-strip button {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 0.8125rem;
  color: var(--text-muted);
  padding: 0.125rem 0.25rem;
  flex-shrink: 0;
}
.zeno-image-strip button:hover { color: #FFD7D2; transform: scale(1.08); }

.zeno-input-row {
  display: flex;
  align-items: flex-end;
  gap: 0.625rem;
  padding: 0.75rem 0.875rem;
  border-top: 1px solid #E8D5A0;
  background: #FDF5E0;
  flex-shrink: 0;
}

.zeno-attach-btn {
  cursor: pointer;
  color: #B89E5A;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 0.75rem;
  border: 1px solid rgba(184,158,90,0.25);
  -webkit-backdrop-filter: blur(0.75rem) saturate(160%);
  backdrop-filter: blur(0.75rem) saturate(160%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.7), 0 0.125rem 0.5rem rgba(139,105,20,0.08);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color .15s, background .15s;
}
.zeno-attach-btn:hover { color: var(--zeno-accent); background: rgba(255,255,255,0.85); }

.zeno-textarea {
  flex: 1;
  /* Resting single-line height matched to the 40px attach/send buttons
     beside it -- .zeno-input-row aligns its children to the bottom
     (align-items:flex-end, so the buttons stay put as the textarea grows
     for multi-line input), and this textarea's own natural rows="1" height
     used to come out a few px taller than 40px, throwing the attach and
     send buttons visibly out of line with it. JS (see the 'input' handler)
     takes over height from here once typing starts, growing it for
     multiple lines up to max-height below.
  */
  height: 2.5rem;
  min-height: 0;
  box-sizing: border-box;
  border: 1px solid #E8D5A0;
  border-radius: 0.75rem;
  padding: 0.5rem 0.8125rem;
  font-size: 0.875rem;
  font-family: var(--font);
  resize: none;
  max-height: 6.875rem;
  overflow-y: auto;
  background: #FDFAF0;
  color: #5C4A1E;
  /* Pinned to an exact pixel value, not line-height:1.5 (~1.3125rem) -- browsers
     round that fractional line box inconsistently, which was enough to push
     this box's total rendered height a px or two past the attach/send
     buttons' plain height:2.5rem. 1.375rem content + 1rem padding + 0.125rem border
     resolves to exactly 2.5rem every time, matching them pixel-for-pixel. */
  line-height: 1.375rem;
}
.zeno-textarea:focus { outline: none; border-color: var(--zeno-accent); box-shadow: 0 0 0 0.125rem rgba(200, 150, 46, 0.12); }
.zeno-textarea::placeholder { color: #B89E5A; }

/* Ghost-text suggestion overlaid on the empty textarea, Tab-to-accept.
   Sits on top of the (empty) textarea with pointer-events:none, so clicks/
   typing pass straight through; hidden the instant real text exists. */
.zeno-textarea-wrap { position: relative; flex: 1; min-width: 0; }
/* display:block (a textarea is inline-block by default) -- otherwise the
   wrap's height includes the inline line box's descender space below the
   textarea, a few px taller than the textarea itself, which pushed it out
   of line with the attach/send buttons beside it (most visible on mobile,
   where text-inflation made the gap larger still). */
.zeno-textarea-wrap .zeno-textarea { display: block; width: 100%; }
.zeno-ghost {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  padding: 0.5rem 0.8125rem; font-size: 0.875rem; font-family: var(--font); line-height: 1.375rem;
  color: #B89E5A; overflow: hidden;
  display: flex; align-items: baseline; gap: 0.375rem;
}
.zeno-ghost.hidden { display: none; }
/* Never wraps to a second line -- a long suggestion just runs past the
   visible edge on its own single line instead of pushing the Tab hint
   down/off; min-width:0 lets it actually shrink inside the flex row rather
   than forcing the row to overflow. */
.zeno-ghost-text {
  white-space: nowrap; overflow-x: auto; min-width: 0; flex: 1;
  scrollbar-width: none;
}
.zeno-ghost-text::-webkit-scrollbar { display: none; }
.zeno-ghost-tab-hint {
  flex-shrink: 0; font-size: 0.625rem; font-weight: 700; opacity: 0.75;
  border: 1px solid currentColor; border-radius: 0.25rem; padding: 0.0625rem 0.3125rem; line-height: 1.4;
}

.zeno-send-btn {
  width: 2.5rem;
  height: 2.5rem;
  background: linear-gradient(135deg, rgba(200,150,46,0.9), rgba(166,123,37,0.9));
  color: #fff;
  border: 1px solid rgba(139,105,20,0.4);
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: background .2s, box-shadow .2s, border-color .2s;
  -webkit-backdrop-filter: blur(0.75rem) saturate(160%);
  backdrop-filter: blur(0.75rem) saturate(160%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), 0 1px 0.25rem rgba(139,105,20,0.2);
}
.zeno-send-btn:hover { background: linear-gradient(135deg, var(--zeno-accent-light), var(--zeno-accent-dim)); box-shadow: inset 0 1px 0 rgba(255,255,255,0.4), 0 0.125rem 0.5rem rgba(139,105,20,0.3); }
.zeno-send-btn:disabled { background: var(--zeno-surface); cursor: not-allowed; box-shadow: none; border-color: rgba(139,105,20,0.2); }

@media (max-width: 768px) {
  .zeno-panel {
    position: fixed;
    top: 0; right: 0; bottom: 0;
    left: 0;
    z-index: 300;
    transition: transform 0.25s ease;
    transform: translateX(100%);
    width: 100%;
  }
  #screen-app.chrono-open .zeno-panel {
    width: 100%;
    transform: translateX(0);
  }
  #screen-app.chrono-open .zeno-panel-inner {
    box-shadow: none;
  }
  .zeno-panel-inner {
    width: 100%;
    border-left: none;
  }

  .chrono-topbar-btn span.chrono-label { display: none; }
  .chrono-topbar-btn { justify-content: center; padding: 0.375rem; gap: 0; }
  #ng-btn-ask-chrono-review, #ng-btn-ask-chrono-goals { padding: 0.375rem 0.875rem 0.375rem 0.5625rem; gap: 0.4375rem; justify-content: flex-start; }
  #ng-btn-ask-chrono-review span.chrono-label, #ng-btn-ask-chrono-goals span.chrono-label { display: inline; }
  #chrono-backdrop {
    opacity: 0;
    transition: opacity 0.25s ease;
    pointer-events: none;
    display: block;
  }
  #screen-app.chrono-open #chrono-backdrop {
    opacity: 1;
    pointer-events: auto;
  }

  /* Quick Ask docks to the bottom of the screen on mobile instead of
     dropping from the button -- same bar, same style, just repositioned;
     the JS positioning function skips setting top/right below this width
     so this is the only rule deciding where it sits. */
  .chrono-quick-bar {
    left: 0.75rem; right: 0.75rem; bottom: calc(0.75rem + env(safe-area-inset-bottom, 0px));
    width: auto; max-width: none;
    /* The orb stays up in the topbar here, nowhere near this bottom-docked
       bar, so send doesn't need the desktop clearance for it. */
    padding-right: 0.25rem;
    border-radius: 1.5rem;
    transform-origin: bottom center;
  }
  .chrono-quick-bar.chrono-quick-entering { width: auto; opacity: 0; transform: scale(0.92) translateY(0.375rem); }
  /* Sits just above the bottom-docked bar instead of the desktop position
     (positionChronoQuickBubble() skips setting top/right below this width,
     same as the bar above) -- pointing its little triangle down at the bar
     instead of up, since the bubble is now above it, not below. */
  .chrono-quick-bubble {
    left: 0.75rem; right: 0.75rem; max-width: none;
    top: auto;
    bottom: calc(0.75rem + env(safe-area-inset-bottom, 0px) + 2.1875rem + 0.5rem);
  }
  .chrono-quick-bubble::after {
    top: auto; right: auto; left: 1.5rem; bottom: -0.375rem;
    border-left: none; border-top: none;
    border-right: 1px solid var(--border2); border-bottom: 1px solid var(--border2);
  }
}

/* Study Mode -- minimal right-side task panel for the current study block,
   same flex-slot shape as .zeno-panel above and mutually exclusive with it
   (opening either one closes the other, in app.js): Study Mode takes the
   sidebar slot exactly like Chrono's own panel would, no separate floating
   "widget" form. Neutral surface tokens with a red accent touch (icon,
   subject label, checkmarks, header wash/seam) -- calm and focused, not a
   full red repaint. Its own topbar button hides while open, same as
   Chrono's toggle button already does while its panel is open. */
.study-panel {
  flex: 0 0 0;
  overflow: hidden;
  transition: width .22s ease;
}
#screen-app.study-open .study-panel { flex-basis: var(--study-w, 18.75rem); }
#screen-app.study-open .study-panel-inner { box-shadow: -0.25rem 0 1.5rem rgba(0,0,0,0.06); }
/* The panel scrolls as one page, header pinned on top. With only the task
   list scrolling, an open timer on a phone left the list a sliver at the
   bottom that could not be scrolled at all. */
.study-panel-inner {
  width: 100%; height: 100%;
  display: flex; flex-direction: column;
  background: var(--surface);
  border-left: 1px solid color-mix(in srgb, var(--red) 20%, var(--border));
  overflow-x: hidden; overflow-y: auto;
  overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
}
.study-panel-inner > * { flex-shrink: 0; }
.study-header {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 0.5rem;
  padding: 1.25rem 1.25rem 0.875rem;
  border-bottom: 1px solid color-mix(in srgb, var(--red) 25%, var(--border));
  background: color-mix(in srgb, var(--red) 4%, var(--surface));
  flex-shrink: 0;
  position: sticky; top: 0; z-index: 3;
}
.study-header-main { min-width: 0; flex: 1; }
/* What is left of the sitting: the minutes, on the line of the buttons. It is
   also the way to more time. */
.study-remaining {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  min-width: 1.75rem; height: 1.75rem; padding: 0 0.4375rem; margin-right: 0.125rem;
  border: none; border-radius: 0.5rem; background: transparent; cursor: pointer;
  color: var(--red); font-family: var(--font); transition: background .15s ease, transform .1s ease;
}
.study-remaining:hover { background: color-mix(in srgb, var(--red) 9%, transparent); }
.study-remaining:active { transform: scale(.96); }
.study-remaining-min {
  font-size: 0.6875rem; font-weight: 600; line-height: 1; color: var(--text-muted);
  font-variant-numeric: tabular-nums; white-space: nowrap; pointer-events: none;
}
.study-remaining.is-over .study-remaining-min { color: var(--red); }

/* "More time": any number of minutes, not a fixed step. */
.study-more-pop {
  position: fixed; z-index: 1200; width: 17rem; padding: 0.875rem;
  border-radius: 1rem; border: 1px solid var(--border);
  background: color-mix(in srgb, var(--surface) 90%, transparent);
  -webkit-backdrop-filter: blur(1.25rem) saturate(180%); backdrop-filter: blur(1.25rem) saturate(180%);
  box-shadow: 0 0.75rem 2.25rem rgba(15,26,46,0.16), 0 0.125rem 0.375rem rgba(15,26,46,0.06);
  animation: plan-len-in .18s cubic-bezier(.2, 1.1, .4, 1);
}
.study-more-head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.625rem; }
.study-more-title { font-size: 0.8125rem; font-weight: 700; color: var(--text); }
.study-more-ends { font-size: 0.6875rem; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.study-more-pop .plan-len-step:hover { background: color-mix(in srgb, var(--red) 10%, var(--surface2)); }
.study-more-pop .plan-len-chip.is-on { background: var(--red); border-color: var(--red); }
.study-more-note { margin: 0.625rem 0 0; font-size: 0.6875rem; line-height: 1.35; color: var(--text-muted); }
.study-more-add {
  width: 100%; margin-top: 0.75rem; padding: 0.5625rem; border: none; border-radius: 0.625rem; cursor: pointer;
  color: #fff; font: 600 0.8125rem/1.2 var(--font);
  background: linear-gradient(135deg, var(--red), color-mix(in srgb, var(--red) 70%, black));
  box-shadow: 0 1px 0.375rem color-mix(in srgb, var(--red) 35%, transparent), inset 0 1px 0 rgba(255,255,255,.25);
  transition: filter .15s ease, transform .1s ease;
}
.study-more-add:hover { filter: brightness(1.08); }
.study-more-add:active { transform: scale(.98); }
.study-more-add:disabled { opacity: .6; cursor: default; }
/* Taking time off: the same controls in a quieter, neutral tone. */
.study-more-pop .plan-len-val.is-cut { color: var(--text-muted); }
.study-more-pop .plan-len-chip.is-cut.is-on { background: var(--text-muted); border-color: var(--text-muted); color: var(--surface); }
.study-more-add.is-cut {
  color: var(--text); background: var(--surface2);
  box-shadow: inset 0 0 0 1px var(--border);
}


/* The session is ending: finish the homework, or move on. */
.study-end-card {
  margin: 0.875rem 1.25rem 1rem; padding: 0.75rem 0.75rem 0.75rem 0.875rem; border-radius: 0.875rem;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  border: 1px solid color-mix(in srgb, var(--red) 30%, var(--border));
  box-shadow: 0 1px 0.125rem rgba(15,26,46,0.04), 0 0.5rem 1.375rem rgba(15,26,46,0.07);
  animation: study-end-in .32s cubic-bezier(.2, 1.2, .4, 1);
}
@keyframes study-end-in { from { opacity: 0; transform: translateY(-0.25rem) scale(.98); } }
.study-end-head { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.625rem; }
.study-end-title { flex: 1; min-width: 0; font-size: 0.8125rem; font-weight: 700; color: var(--text); }
.study-end-card.is-over .study-end-title { color: var(--red); }
.study-end-x {
  flex-shrink: 0; width: 1.375rem; height: 1.375rem; border-radius: 50%; border: none; padding: 0;
  display: grid; place-content: center; background: transparent; color: var(--text-dim); cursor: pointer;
}
.study-end-x:hover { background: var(--surface2); color: var(--text); }
.study-end-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.study-end-btn {
  flex: 1 1 9rem; min-width: 0; display: inline-flex; align-items: center; justify-content: center; gap: 0.375rem;
  padding: 0.5rem 0.625rem; border-radius: 0.625rem; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface2); color: var(--text);
  font: 600 0.75rem/1.2 var(--font); transition: filter .15s ease, background .15s ease, transform .1s ease;
}
.study-end-btn:active { transform: scale(.98); }
.study-end-btn:hover { background: color-mix(in srgb, var(--text) 6%, var(--surface2)); }
.study-end-btn.is-complete {
  border-color: transparent; color: #fff;
  background: linear-gradient(135deg, var(--red), color-mix(in srgb, var(--red) 70%, black));
  box-shadow: 0 1px 0.375rem color-mix(in srgb, var(--red) 35%, transparent), inset 0 1px 0 rgba(255,255,255,.25);
}
.study-end-btn.is-complete:hover { filter: brightness(1.08); background: linear-gradient(135deg, var(--red), color-mix(in srgb, var(--red) 70%, black)); }
.study-end-btn.is-complete:disabled { filter: none; opacity: .55; cursor: default; }
/* Still on it? The same card, calmer: a nudge, not an alarm -- no red edge. */
.study-focus-card { border-color: var(--border); }
.study-focus-card .study-end-head { margin-bottom: 0.25rem; }
.study-focus-sub { margin: 0 0 0.625rem; font-size: 0.75rem; line-height: 1.45; color: var(--text-muted); overflow-wrap: anywhere; }
.study-end-btn.is-primary { border-color: transparent; color: #fff; background: var(--red); }
.study-end-btn.is-primary:hover { background: color-mix(in srgb, var(--red) 88%, black); }
.study-end-next-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.study-header-subject { font-size: 0.8125rem; font-weight: 600; color: var(--red); letter-spacing: -0.005em; margin-bottom: 0.1875rem; }
.study-header-title {
  font-size: 0.9375rem; font-weight: 700; color: var(--text); line-height: 1.3;
  /* Up to two lines, then "...": a sentence cut after three words reads
     as broken. */
  min-width: 0; overflow: hidden; overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
/* ── Study Timer ──────────────────────────────────────────────────────────
   Two states of the same widget: a slim one-line bar (collapsed) and a full
   card with a circular progress ring (expanded). Only one is ever in the
   DOM's visible flow at a time (.hidden on whichever isn't current). */
.study-timer { flex-shrink: 0; }

/* Collapsed state reads as a banner (full-bleed strip, flush with the
   panel's own edges) rather than a floating box -- no side margins/border/
   corner-rounding, just a bottom rule like a divider. Sits with zero gap
   directly under .study-header -- no border-top of its own either, since
   the header's own border-bottom already draws that seam; a second line
   right under it would just double up. Content padding matches .study-
   header's own 1.25rem so the label/time still line up with everything
   else in the panel despite the background spanning wider. */
.study-timer-collapsed {
  width: 100%; display: flex; align-items: center; gap: 0.5rem;
  margin-top: 0;
  padding: 0.625rem 1.25rem; border-radius: 0;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  border: none;
  border-bottom: 1px solid var(--border);
  -webkit-backdrop-filter: blur(1rem) saturate(180%);
  backdrop-filter: blur(1rem) saturate(180%);
  cursor: pointer; font-family: var(--font); text-align: left;
  transition: background .15s ease, border-color .15s ease;
}
.study-timer-collapsed:hover { background: var(--surface); border-color: color-mix(in srgb, var(--red) 30%, var(--border)); }
.study-timer-collapsed-dot {
  width: 0.5rem; height: 0.5rem; border-radius: 50%; flex-shrink: 0;
  background: var(--red); box-shadow: 0 0 0 0.1875rem color-mix(in srgb, var(--red) 18%, transparent);
}
.study-timer-collapsed.on-break .study-timer-collapsed-dot { background: var(--primary); box-shadow: 0 0 0 0.1875rem color-mix(in srgb, var(--primary) 18%, transparent); }
.study-timer-collapsed.running .study-timer-collapsed-dot { animation: studyTimerDotPulse 1.8s ease-in-out infinite; }
@keyframes studyTimerDotPulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
.study-timer-collapsed-label { font-size: 0.75rem; font-weight: 600; color: var(--text-muted); }
.study-timer-collapsed-time {
  margin-left: auto; font-size: 0.9375rem; font-weight: 700; color: var(--text);
  font-variant-numeric: tabular-nums; letter-spacing: -0.01em;
}
.study-timer-chevron { color: var(--text-dim); flex-shrink: 0; }

.study-timer-expanded {
  /* The task list's own side margin, so the card and the steps under it
     share both edges. */
  margin: 0.875rem 0.875rem 0;
  padding: 1rem 1rem 0.875rem; border-radius: 1rem;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  border: 1px solid var(--border);
  -webkit-backdrop-filter: blur(1rem) saturate(180%);
  backdrop-filter: blur(1rem) saturate(180%);
  box-shadow: 0 1px 0.125rem rgba(15,26,46,0.04), 0 0.625rem 1.75rem rgba(15,26,46,0.06);
}
.study-timer-top-row { display: flex; align-items: center; gap: 0.5rem; margin: 0 -0.375rem 0.875rem; }

/* iOS-style segmented control: a sliding pill behind whichever button is
   active, driven purely by CSS (3 equal segments, translateX by index). */
.study-timer-modes {
  position: relative; flex: 1; min-width: 0; display: flex; gap: 0.125rem;
  padding: 0.1875rem; border-radius: 0.625rem; background: var(--surface2);
}
/* left/width set in px by JS (studyTimerPositionPill), measured from the
   active button's own offsetLeft/offsetWidth -- precise regardless of
   padding/gap/font metrics, rather than guessed via calc(). */
.study-timer-mode-pill {
  position: absolute; top: 0.1875rem; height: calc(100% - 0.375rem);
  border-radius: 0.5rem; background: var(--surface);
  box-shadow: 0 1px 0.1875rem rgba(15,26,46,0.14), 0 1px 1px rgba(15,26,46,0.06);
  transition: left .28s cubic-bezier(0.34, 1.2, 0.64, 1), width .28s cubic-bezier(0.34, 1.2, 0.64, 1);
}
.study-timer-mode {
  position: relative; z-index: 1; flex: 1; padding: 0.3125rem 0.25rem; border: none;
  border-radius: 0.5rem; background: transparent; color: var(--text-muted);
  font-size: 0.6875rem; font-weight: 600; font-family: var(--font); cursor: pointer;
  transition: color .2s ease; white-space: nowrap;
}
.study-timer-mode.active { color: var(--text); }
/* Minimize: a small handle centred under the controls -- folds the card
   up into the banner above, the way the banner's own chevron unfolds it. */
.study-timer-collapse-btn {
  display: flex; align-items: center; justify-content: center;
  width: 2.5rem; height: 1.125rem; margin: 0.875rem auto -0.25rem; padding: 0;
  border-radius: 62.4375rem; border: none;
  background: color-mix(in srgb, var(--surface2) 70%, transparent);
  color: var(--text-dim); cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.study-timer-collapse-btn:hover { background: var(--surface2); color: var(--text); }
/* Sized by their labels and allowed to shrink, so the control always fits
   the card: without min-width:0 on the control itself, a long label
   ("Personalizzato") pushed it out past the card's right edge. */
.study-timer-mode { flex: 1 1 auto; min-width: 0; padding-left: 0.25rem; padding-right: 0.25rem; overflow: hidden; text-overflow: ellipsis; }

.study-timer-repeat-row {
  display: flex; align-items: center; gap: 0.4375rem; margin-bottom: 0.75rem;
  font-size: 0.75rem; color: var(--text-muted);
}
.study-timer-repeat-row input {
  width: 2.75rem; padding: 0.25rem 0.375rem; border-radius: var(--radius-sm);
  border: 1px solid var(--border); font-size: 0.8125rem; font-weight: 600;
  text-align: center; background: var(--surface2); color: var(--text);
}

.study-timer-segments { margin-bottom: 0.875rem; }
.study-timer-segments-list {
  display: flex; flex-direction: column; gap: 0.375rem; margin-bottom: 0.5rem;
  max-height: 12rem; overflow-y: auto; overscroll-behavior: contain;
  padding-right: 0.125rem;
}
.study-timer-segment-row { display: flex; align-items: center; gap: 0.375rem; }
.study-timer-segment-row .study-timer-segment-dot { width: 0.5rem; height: 0.5rem; border-radius: 50%; flex-shrink: 0; background: var(--red); }
.study-timer-segment-row.odd .study-timer-segment-dot { background: var(--primary); }
.study-timer-segment-label {
  flex: 1; min-width: 0; padding: 0.3125rem 0.5rem; border-radius: var(--radius-sm);
  border: 1px solid var(--border); font-size: 0.8125rem; background: var(--surface2); color: var(--text);
}
/* Pomodoro's stage names are fixed (Work/Break) -- a plain label, not an
   input, so it doesn't invite editing that wouldn't do anything. */
.study-timer-segment-label.static {
  display: flex; align-items: center; border-color: transparent; background: transparent;
  color: var(--text-muted); font-weight: 600;
}
.study-timer-segment-minutes {
  width: 3.25rem; padding: 0.3125rem 0.375rem; border-radius: var(--radius-sm);
  border: 1px solid var(--border); font-size: 0.8125rem; text-align: center;
  background: var(--surface2); color: var(--text);
}
.study-timer-segment-remove {
  flex-shrink: 0; width: 1.5rem; height: 1.5rem; border-radius: 50%; border: none;
  background: transparent; color: var(--text-dim); font-size: 1rem; line-height: 1;
  cursor: pointer; display: flex; align-items: center; justify-content: center;
  transition: background .15s ease, color .15s ease;
}
.study-timer-segment-remove:hover { background: var(--surface2); color: var(--red); }
.study-timer-segment-remove:disabled { opacity: .3; cursor: default; pointer-events: none; }
.study-timer-segment-link {
  flex-shrink: 0; width: 1.5rem; height: 1.5rem; border-radius: 50%; border: none;
  background: transparent; color: var(--text-dim); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background .15s ease, color .15s ease;
}
.study-timer-segment-link:hover { background: var(--surface2); color: var(--red); }
/* Active = this stage is the one currently accepting linked tasks (click
   task rows, or drag one here, to link it). */
.study-timer-segment-link.active { color: #fff; background: var(--red); }
.context-menu .ctx-head { padding: 0.375rem 0.75rem 0.25rem; font-size: 0.6875rem; font-weight: 600; color: var(--text-dim); letter-spacing: 0.02em; }
.ctx-stage { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.ctx-stage-min { color: var(--text-dim); font-variant-numeric: tabular-nums; font-size: 0.75rem; }
.ctx-stage.is-active { font-weight: 600; }
.study-timer-segment-row.drag-over { outline: 0.125rem dashed var(--red); outline-offset: 1px; border-radius: 0.5rem; }
/* Reordering custom stages: a grip at the row's start, dragged up or down. */
.study-timer-segment-grip {
  flex-shrink: 0; width: 1rem; height: 1.75rem; margin-right: -0.125rem; padding: 0; border: none;
  border-radius: 0.375rem; background: transparent; color: var(--text-dim); opacity: .55;
  display: flex; align-items: center; justify-content: center;
  cursor: grab; touch-action: none; transition: opacity .15s ease, color .15s ease;
}
.study-timer-segment-row:hover .study-timer-segment-grip, .study-timer-segment-grip:focus-visible { opacity: 1; }
.study-timer-segment-grip:hover { color: var(--text-muted); }
@media (hover: none) { .study-timer-segment-grip { opacity: .8; } }
.study-timer-segments-list.is-sorting { user-select: none; -webkit-user-select: none; cursor: grabbing; }
.study-timer-segments-list.is-sorting .study-timer-segment-grip { cursor: grabbing; }
.study-timer-segments-list.is-sorting .study-timer-segment-row { transition: transform .18s cubic-bezier(.2, .8, .3, 1); }
.study-timer-segments-list.is-sorting .study-timer-segment-row.is-dragging {
  position: relative; z-index: 2; transition: none;
  border-radius: 0.625rem; background: var(--surface); box-shadow: 0 0.375rem 1.125rem rgba(0,0,0,.18);
}
/* The stage the clock is on, while a session is under way. */
.study-timer-segment-row.is-live .study-timer-segment-dot { box-shadow: 0 0 0 0.1875rem color-mix(in srgb, var(--red) 25%, transparent); }
.study-timer-segment-row.odd.is-live .study-timer-segment-dot { box-shadow: 0 0 0 0.1875rem color-mix(in srgb, var(--primary) 25%, transparent); }
.study-timer-segment-row.is-live .study-timer-segment-label { font-weight: 600; }
@media (prefers-reduced-motion: reduce) {
  .study-timer-segments-list.is-sorting .study-timer-segment-row { transition: none; }
}
.study-timer-add-segment {
  width: 100%; padding: 0.375rem; border-radius: var(--radius-sm); border: 1px dashed var(--border);
  background: transparent; color: var(--text-muted); font-size: 0.75rem; font-weight: 600;
  font-family: var(--font); cursor: pointer; transition: background .15s ease, border-color .15s ease;
}
.study-timer-add-segment:hover { background: var(--surface2); border-color: var(--red); color: var(--red); }
.study-timer-seg-actions { display: flex; gap: 0.375rem; }
.study-timer-seg-actions .study-timer-add-segment { flex: 1 1 0; min-width: 0; }
.study-timer-seg-actions .study-timer-add-segment.hidden { display: none; }

.study-timer-ring-wrap { position: relative; width: 8rem; height: 8rem; margin: 0.25rem auto 0.5rem; }
.study-timer-ring { transform: rotate(-90deg); }
.study-timer-ring-bg, .study-timer-ring-fg { fill: none; stroke-width: 6; }
.study-timer-ring-bg { stroke: var(--border); }
.study-timer-ring-fg {
  stroke: var(--red); stroke-linecap: round;
  stroke-dasharray: 326.726; stroke-dashoffset: 0;
  transition: stroke-dashoffset .4s linear, stroke .3s ease;
}
.study-timer-ring-fg.break { stroke: var(--primary); }
.study-timer-ring-fg.stopwatch { stroke: var(--text-dim); }
.study-timer-ring-center {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 0.125rem;
}
.study-timer-phase {
  font-size: 0.625rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--red);
  /* A stage can be named after a task: kept inside the ring's inner width. */
  max-width: 5.75rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.study-timer-phase.break { color: var(--primary); }
.study-timer-phase.stopwatch { color: var(--text-dim); }
.study-timer-display { font-size: 1.75rem; font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; color: var(--text); line-height: 1.15; cursor: pointer; border-radius: 0.25rem; }
.study-timer-display:hover { color: var(--red); }
/* Deliberately matches .study-timer-display's box as closely as possible --
   same font metrics, no border/background/padding of its own -- so swapping
   to the input on click reads as "these digits became editable", not as a
   different, bigger element appearing in its place. width is in ch (~character
   count of "88:88") rather than a guessed rem value, since that's what
   actually tracks the text it's replacing. padding:0 and the :focus overrides
   below undo the generic input, select, textarea rule's own padding/
   border-color/box-shadow -- those apply to every bare <input> including
   this one, and are exactly what shows up as an unwanted box the moment
   this one gets focus (i.e. the moment it's clicked into edit). */
.study-timer-display-input {
  width: 5ch; text-align: center; font: inherit; font-size: 1.75rem; font-weight: 700;
  font-variant-numeric: tabular-nums; letter-spacing: -0.02em; color: var(--red);
  background: transparent; border: none; border-radius: 0; padding: 0; line-height: 1.15;
}
.study-timer-display-input:focus { outline: none; border-color: transparent; box-shadow: none; }
.study-timer-cycles { text-align: center; font-size: 0.6875rem; color: var(--text-dim); margin-bottom: 0.75rem; }

.study-timer-controls { display: flex; align-items: center; justify-content: center; gap: 0.75rem; }
.study-timer-icon-btn {
  width: 2.25rem; height: 2.25rem; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface2); border: 1px solid var(--border); color: var(--text-muted);
  cursor: pointer; transition: background .15s ease, transform .1s ease;
}
.study-timer-icon-btn:hover { background: var(--surface); color: var(--text); }
.study-timer-icon-btn:active { transform: scale(0.94); }
.study-timer-icon-btn:disabled { opacity: .4; cursor: default; pointer-events: none; }
.study-timer-icon-btn.primary {
  background: linear-gradient(135deg, var(--red), color-mix(in srgb, var(--red) 80%, black));
  border-color: transparent; color: #fff;
}
.study-timer-icon-btn.primary:hover { filter: brightness(1.08); }
#study-timer-start svg { margin-left: 1px; } /* optically center the play triangle -- pause's icon is symmetric and doesn't need it */
.study-task-list { flex: 0 0 auto; padding: 0.625rem 0.875rem; display: flex; flex-direction: column; gap: 0.375rem; }
/* The list takes its own height and study help sits right under it; the
   add-a-task row keeps its place at the bottom of the panel. */
#study-panel .study-add-row { margin-top: auto; }
/* Card-row treatment matching .cl-row (checklist editor) for visual
   consistency across the app, with the red accent swapped in for study's
   own identity -- was a flat, borderless list before, which read as
   unfinished next to the rest of the UI's glassy card language. */
.study-task-row {
  display: flex; align-items: center; gap: 0.5625rem;
  padding: 0.1875rem 0.4375rem 0.1875rem 0.5625rem;
  border-radius: 0.75rem;
  background: linear-gradient(135deg, rgba(255,255,255,0.075), rgba(255,255,255,0.028));
  border: 1px solid var(--border);
  -webkit-backdrop-filter: blur(0.875rem) saturate(170%);
  backdrop-filter: blur(0.875rem) saturate(170%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.10), 0 1px 0.3125rem rgba(15,26,46,0.06);
  transition: border-color .18s ease, box-shadow .18s ease;
}
.study-task-row:hover {
  border-color: color-mix(in srgb, var(--red) 40%, var(--border));
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.16), 0 0.1875rem 0.75rem rgba(15,26,46,0.09);
}
/* Linked to a stage of the CURRENTLY selected timer mode -- a step linked
   to some other mode's stage doesn't get this (it isn't "current" right
   now), same reasoning as why it sorts as unmapped in that view too. */
/* While a stage's "link tasks" mode is active, the row's own controls go
   inert (pointer-events:none on the children) so a click anywhere on the
   row toggles its link instead of hitting the checkbox/text/etc underneath. */
.study-task-row.picking { cursor: pointer; }
.study-task-row.picking > * { pointer-events: none; opacity: .55; }
.study-task-row.picking.picked {
  background: color-mix(in srgb, var(--red) 16%, transparent);
  border-color: var(--red);
}
.study-task-row.picking.picked > * { opacity: 1; }
.study-task-row:focus-within {
  border-color: color-mix(in srgb, var(--red) 60%, var(--border));
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.18), 0 0 0 0.1875rem color-mix(in srgb, var(--red) 13%, transparent), 0 0.1875rem 0.75rem rgba(15,26,46,0.09);
}
.study-task-row.done { opacity: .72; }
.study-task-row.done .study-task-text { color: var(--text-dim); text-decoration: line-through; text-decoration-color: rgba(127,127,127,.7); }
.study-task-check {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  width: 1.375rem; height: 1.375rem; aspect-ratio: 1 / 1; flex: 0 0 1.375rem; margin: 0; padding: 0;
  border-radius: 50%; cursor: pointer;
  background: rgba(127,127,127,0.10);
  border: 1.5px solid var(--border);
  display: grid; place-content: center;
  transition: background .18s, border-color .18s, box-shadow .18s, transform .12s;
}
.study-task-check:hover { border-color: color-mix(in srgb, var(--red) 55%, var(--border2)); transform: scale(1.1); }
.study-task-check:checked {
  background: linear-gradient(135deg, var(--red), color-mix(in srgb, var(--red) 65%, black));
  border-color: transparent;
  box-shadow: 0 1px 0.375rem color-mix(in srgb, var(--red) 40%, transparent), inset 0 1px 0 rgba(255,255,255,.35);
}
.study-task-check::before {
  content: '';
  width: 0.6875rem; height: 0.6875rem;
  background: #fff;
  clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
  transform: scale(0);
  transition: transform .16s cubic-bezier(.2, 1.4, .4, 1);
}
.study-task-check:checked::before { transform: scale(1); }
.study-task-text {
  flex: 1; min-width: 0; border: none; background: none; font-size: 0.8125rem; color: var(--text);
  font-family: var(--font); padding: 0.5rem 0.25rem; line-height: 1.4;
  /* All of it, wrapped: a textarea that grows with the task (app.js). */
  display: block; resize: none; overflow: hidden; white-space: pre-wrap; overflow-wrap: anywhere; field-sizing: content; min-height: 0;
}
/* The row itself lights up while editing (:focus-within above); the
   app-wide input focus ring on top of that drew a second, grey box. */
.study-task-text:focus { outline: none; border-color: transparent; box-shadow: none; }
.study-task-remove {
  flex-shrink: 0; width: 1.375rem; height: 1.375rem;
  display: grid; place-content: center;
  border: none; border-radius: 0.5rem; cursor: pointer;
  background: transparent; color: var(--text-dim);
  opacity: 0;
  transition: opacity .15s, color .15s, background .15s;
}
.study-task-row:hover .study-task-remove, .study-task-remove:focus-visible { opacity: 1; }
.study-task-remove:hover { color: var(--red); background: color-mix(in srgb, var(--red) 12%, transparent); }
/* No hover on touch -- without this the remove button is permanently
   invisible (and untappable) on phones/tablets, same fix as .cl-remove. */
@media (hover: none) { .study-task-remove { opacity: 1; } }
/* Reordering: a grip at the row's start, the timer stages' own. With a
   mouse it shows on the row's hover; on touch it is always there, quiet. */
.study-task-row.is-sortable { padding-left: 0.25rem; }
.study-task-grip {
  flex-shrink: 0; width: 1rem; height: 1.75rem; margin-right: -0.3125rem; padding: 0; border: none;
  border-radius: 0.375rem; background: transparent; color: var(--text-dim); opacity: 0;
  display: flex; align-items: center; justify-content: center;
  cursor: grab; touch-action: none; transition: opacity .15s ease, color .15s ease;
}
.study-task-row:hover .study-task-grip, .study-task-grip:focus-visible { opacity: .9; }
.study-task-grip:hover { color: var(--text-muted); }
@media (hover: none) { .study-task-grip { opacity: .6; } }
.is-sorting { user-select: none; -webkit-user-select: none; cursor: grabbing; }
.is-sorting .study-task-grip { cursor: grabbing; opacity: .9; }
.is-sorting > .study-task-row, .is-sorting > .study-task-swipe { transition: transform .18s cubic-bezier(.2, .8, .3, 1); }
.is-sorting > .is-dragging { position: relative; z-index: 2; transition: none; }
.is-sorting > .study-task-row.is-dragging, .is-sorting > .is-dragging > .study-task-row {
  background: var(--surface); border-color: color-mix(in srgb, var(--red) 40%, var(--border));
  box-shadow: 0 0.5rem 1.375rem rgba(15,26,46,.18), 0 1px 0.1875rem rgba(15,26,46,.08);
}
.is-sorting > .study-task-swipe.is-dragging { overflow: visible; }
@media (prefers-reduced-motion: reduce) {
  .is-sorting > .study-task-row, .is-sorting > .study-task-swipe { transition: none; }
}

/* Clock button: picks WHEN in the active block/window this step should
   happen (see openStudyTimePicker in app.js), not how long it takes -- that
   estimate lives on .cl-duration in the academic-item modal instead. Hidden
   like .study-task-remove until the row is hovered (unset state is just an
   affordance, not information worth showing at rest). Once a time IS set it
   becomes a small "2:30 PM" pill that stays visible -- that's actual data,
   not an action button. Same tinted-background hover treatment as
   .study-task-remove, but green (study blocks' own accent color) instead of
   red, since setting a time isn't a destructive action. */
.study-task-duration {
  flex-shrink: 0; height: 1.375rem; padding: 0 0.375rem; min-width: 1.375rem;
  display: flex; align-items: center; justify-content: center;
  border: none; border-radius: 0.5rem; cursor: pointer;
  background: transparent; color: var(--text-dim); font-size: 0.6875rem; font-weight: 600;
  font-family: var(--font); font-variant-numeric: tabular-nums;
  opacity: 0;
  transition: opacity .15s, background .15s, color .15s;
}
.study-task-row:hover .study-task-duration, .cl-row:hover .study-task-duration, .study-task-duration:focus-visible, .study-task-duration.set { opacity: 1; }
.study-task-duration:hover { color: var(--green); background: color-mix(in srgb, var(--green) 12%, transparent); }
.study-task-duration.set { background: var(--surface2); color: var(--text-muted); }
.study-task-duration.set:hover { color: var(--green); background: color-mix(in srgb, var(--green) 14%, transparent); }
.study-task-duration:disabled { cursor: default; pointer-events: none; }
@media (hover: none) { .study-task-duration { opacity: 1; } }

/* Popover opened by the clock button above: a slider constrained to the
   active block/window's own start-end range, so a step can only be scheduled
   to a time that's actually inside the session it belongs to. */
.study-time-picker {
  position: fixed; z-index: 1000;
  width: 12.5rem;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 0.625rem; box-shadow: var(--shadow);
  padding: 0.75rem 0.875rem 0.625rem;
}
.study-time-picker-value {
  text-align: center; font-size: 0.9375rem; font-weight: 700; color: var(--text);
  margin-bottom: 0.5rem; font-variant-numeric: tabular-nums;
}
.study-time-picker-slider {
  -webkit-appearance: none; appearance: none;
  display: block; width: 100%; height: 0.3125rem; border-radius: 62.4375rem;
  background: var(--surface2); outline: none; cursor: pointer; margin: 0.25rem 0;
}
.study-time-picker-slider::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 1rem; height: 1rem; border-radius: 50%;
  background: var(--primary); cursor: pointer; box-shadow: 0 1px 0.1875rem rgba(0,0,0,.25);
}
.study-time-picker-slider::-moz-range-thumb {
  width: 1rem; height: 1rem; border-radius: 50%; border: none;
  background: var(--primary); cursor: pointer; box-shadow: 0 1px 0.1875rem rgba(0,0,0,.25);
}
.study-time-picker-slider::-moz-range-track { background: var(--surface2); height: 0.3125rem; border-radius: 62.4375rem; }
.study-time-picker-range {
  display: flex; justify-content: space-between;
  font-size: 0.6875rem; color: var(--text-dim); margin-top: 0.125rem;
}
.study-time-picker-clear {
  display: block; width: 100%; margin-top: 0.5rem;
  padding: 0.3125rem; border: none; border-radius: 0.375rem;
  background: transparent; color: var(--text-muted); font-size: 0.75rem; font-weight: 600;
  cursor: pointer; text-align: center; font-family: var(--font);
  transition: background .15s, color .15s;
}
.study-time-picker-clear:hover { color: var(--red); background: color-mix(in srgb, var(--red) 12%, transparent); }

/* Add-task input, same glass-card family as the rows above it so it reads
   as part of the list rather than a bare underlined input; the leading "+"
   is a real clickable submit affordance (was Enter-only before, with no
   visual cue that typing there did anything). */
.study-add-row {
  display: flex; align-items: center; gap: 0.5rem;
  margin: 0.25rem 0.875rem 0.875rem; padding: 0.1875rem 0.5625rem 0.1875rem 0.6875rem;
  border-radius: 0.75rem;
  background: linear-gradient(135deg, rgba(255,255,255,0.075), rgba(255,255,255,0.028));
  border: 1px solid var(--border);
  -webkit-backdrop-filter: blur(0.875rem) saturate(170%);
  backdrop-filter: blur(0.875rem) saturate(170%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.10), 0 1px 0.3125rem rgba(15,26,46,0.06);
  transition: border-color .18s ease, box-shadow .18s ease;
  flex-shrink: 0;
}
.study-add-row:focus-within {
  border-color: color-mix(in srgb, var(--red) 55%, var(--border));
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.16), 0 0 0 0.1875rem color-mix(in srgb, var(--red) 13%, transparent), 0 0.1875rem 0.75rem rgba(15,26,46,0.09);
}
.study-add-icon {
  flex-shrink: 0; width: 1.375rem; height: 1.375rem; border-radius: 0.5rem;
  display: grid; place-content: center; padding: 0;
  border: none; background: none; color: var(--text-dim); cursor: pointer;
  transition: color .15s, background .15s;
}
.study-add-icon:hover { color: var(--red); background: color-mix(in srgb, var(--red) 12%, transparent); }
.study-add-row:focus-within .study-add-icon, .study-add-row.has-text .study-add-icon { color: var(--red); }
.study-add-row input {
  flex: 1; min-width: 0; border: none; background: none; font-size: 0.8125rem; color: var(--text);
  font-family: var(--font); padding: 0.5rem 0;
}
.study-add-row input::placeholder { color: var(--text-dim); opacity: .75; }
.study-add-row input:focus { outline: none; border-color: transparent; box-shadow: none; }
/* Floating card, deliberately outside .study-panel's own layout/scroll --
   see the HTML comment at its markup. Bottom-left (toasts already own
   bottom-right) so it doesn't compete with them for the same corner. */
/* "Study now?" -- the piece of work it suggests, under the free-time line. */
/* The walkthrough owns the screen while it is open. */
body.ob-open #study-now-card, body.ob-open #registry-alert-card, body.ob-open #spotlight-card { display: none; }
/* A sheet open over the app has the stage; the suggestion waits behind it
   (and never sits on the sheet's own controls). */
body:has(.modal-overlay:not(.hidden)) #study-now-card,
body:has(.modal-overlay:not(.hidden)) #registry-alert-card,
body:has(.modal-overlay:not(.hidden)) #spotlight-card,
body:has(.iv-overlay:not(.hidden)) #spotlight-card,
html.oral-open #spotlight-card { display: none; }
#study-now-start { white-space: nowrap; }

.study-time-prompt-card {
  position: fixed; left: 1.25rem; bottom: 1.25rem; z-index: 300;
  width: 25rem; max-width: calc(100vw - 2.5rem);
  padding: 1.5rem 1.625rem; border-radius: var(--radius-lg);
  background: color-mix(in srgb, var(--accent) 7%, color-mix(in srgb, var(--surface) 82%, transparent));
  -webkit-backdrop-filter: blur(1.375rem) saturate(170%); backdrop-filter: blur(1.375rem) saturate(170%);
  border: 1px solid color-mix(in srgb, var(--accent) 20%, var(--border));
  box-shadow: var(--shadow);
  animation: studyTimePromptIn 0.25s var(--ease);
}
@keyframes studyTimePromptIn { from { transform: translateX(-1.25rem); opacity: 0; } to { transform: none; opacity: 1; } }
.study-time-prompt-close {
  position: absolute; top: 0.75rem; right: 0.75rem;
  width: 1.875rem; height: 1.875rem; display: grid; place-content: center;
  border: none; border-radius: 0.5rem; cursor: pointer;
  background: transparent; color: var(--text-dim);
  transition: background .15s, color .15s;
}
.study-time-prompt-close svg { width: 0.8125rem; height: 0.8125rem; }
.study-time-prompt-close:hover { background: var(--surface2); color: var(--text); }
.study-time-prompt-label { font-size: 0.9375rem; color: var(--text-muted); margin: 0 1.5rem 1.125rem 0; line-height: 1.45; }
.study-time-prompt-row { display: flex; align-items: center; gap: 0.75rem; }
.study-time-prompt-row input {
  flex: 1; min-width: 0; padding: 0.75rem 0.875rem; border-radius: var(--radius-sm);
  border: 1px solid var(--border); font-size: 0.9375rem; background: var(--surface2); color: var(--text);
}
/* Pins the button back to its full icon+label footprint regardless of the
   ≤480px icon-only squeeze that otherwise targets every bare .generate-btn
   (meant for the cramped topbar, not a card with its own dedicated space) --
   two classes here beats that rule's one on specificity alone. */
.study-time-prompt-row .generate-btn {
  flex-shrink: 0; margin-left: 0;
  width: auto; height: 2.75rem; padding: 0.625rem 1.25rem; justify-content: center;
  font-size: 0.875rem;
}
.study-time-prompt-row .generate-btn svg { width: 1.0625rem; height: 1.0625rem; flex-shrink: 0; }
.study-empty { text-align: center; padding: 1.875rem 1rem; font-size: 0.8125rem; color: var(--text-dim); }
.study-empty.study-stage-free { padding: 1.25rem 1rem; }

/* Suggested steps. Deliberately the Auto-Schedule prompts' vocabulary --
   accent badge, bolt, ghost-then-generate pair -- because it is the same
   kind of offer: the app has worked something out and is asking before it
   touches anything. Inline in the panel rather than a floating card, since
   it is about the list it sits above. */
.study-suggest-card {
  margin: 1.125rem 1.25rem 0.25rem; padding: 0.875rem 0.875rem 0.875rem 1rem;
  border-radius: 1rem; background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: 0 1px 0.125rem rgba(15,26,46,0.04), 0 0.625rem 1.75rem rgba(15,26,46,0.06);
  animation: studySuggestIn 0.22s var(--ease);
}
@keyframes studySuggestIn { from { transform: translateY(-0.375rem); opacity: 0; } to { transform: none; opacity: 1; } }
.study-suggest-head { display: flex; align-items: center; gap: 0.625rem; margin-bottom: 0.75rem; }
.study-suggest-badge {
  display: grid; place-content: center; flex-shrink: 0;
  width: 1.75rem; height: 1.75rem; border-radius: 50%;
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  color: var(--accent);
}
.study-suggest-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.0625rem; }
.study-suggest-title { font-size: 0.8125rem; font-weight: 700; color: var(--text); line-height: 1.3; }
.study-suggest-count { font-size: 0.75rem; color: var(--text-muted); }
.study-suggest-x {
  flex-shrink: 0; align-self: flex-start; width: 1.5rem; height: 1.5rem; padding: 0;
  display: grid; place-items: center; border: none; border-radius: 50%;
  background: transparent; color: var(--text-dim); cursor: pointer;
}
.study-suggest-x:hover { background: var(--surface2); color: var(--text); }
.study-suggest-row { display: flex; align-items: center; gap: 0.5rem; }
.study-suggest-row > * { flex: 1 1 0; min-width: 0; }
/* "See steps" is as wide as its words; the green button takes the rest. */
.study-suggest-row .btn {
  flex: 0 0 auto; height: 2.125rem; padding: 0 0.75rem; font-size: 0.75rem; white-space: nowrap;
}
/* Carries #screen-app.study-open so it outranks the topbar's icon-only
   squeeze (`#screen-app.study-open .generate-btn { width: 2.75rem; padding: 0 }`),
   which is written for the two buttons in the header and would otherwise
   crop this one's label -- the study panel is inside #screen-app, unlike
   the floating prompt cards that escape the rule by being siblings of it. */
#screen-app.study-open .study-suggest-row .generate-btn,
.study-suggest-row .generate-btn {
  flex: 1 1 auto; min-width: 0; margin-left: 0;
  width: auto; height: 2.125rem; padding: 0 0.875rem; justify-content: center;
  font-size: 0.8125rem; white-space: nowrap;
}
.study-suggest-row .generate-btn svg { width: 0.875rem; height: 0.875rem; flex-shrink: 0; }
.study-suggest-card.busy { opacity: 0.55; pointer-events: none; }

/* The full list lives in a modal so the panel stays about the timer and the
   tasks. Above Study Mode's panel, which floats at z-index 300 on smaller
   windows. */
.study-steps-overlay { z-index: 600; }
/* Auto-Schedule's answer can land in the same moment Study Mode opens for a
   session starting now; on a phone that panel is full screen, and the
   answer must not end up hidden under it. */
#modal-schedule-result { z-index: 600; }
.study-steps-overlay #study-steps-accept {
  background: linear-gradient(135deg, rgba(42,157,143,0.9), rgba(34,129,118,0.9));
  border: 1px solid rgba(42,157,143,0.35); color: #fff;
}
.study-steps-overlay #study-steps-accept:hover { background: linear-gradient(135deg, rgba(42,157,143,1), rgba(34,129,118,1)); }
.study-steps-for { font-size: 0.75rem; color: var(--text-muted); margin-top: 0.125rem; }
.study-steps-list {
  list-style: none; margin: 0; padding: 0; counter-reset: step;
  display: flex; flex-direction: column; gap: 0.5rem;
  max-height: min(24rem, 55vh); overflow-y: auto;
}
.study-steps-list li {
  counter-increment: step; display: flex; gap: 0.625rem; align-items: flex-start;
  padding: 0.625rem 0.75rem; border-radius: 0.75rem;
  background: var(--surface2); font-size: 0.8125rem; line-height: 1.45; color: var(--text);
}
.study-steps-list li::before {
  content: counter(step); flex-shrink: 0;
  width: 1.25rem; height: 1.25rem; border-radius: 50%; display: grid; place-items: center;
  font-size: 0.6875rem; font-weight: 700;
  background: color-mix(in srgb, var(--accent) 16%, transparent); color: var(--accent);
}

/* Chrono's topbar button drops its "Chrono" label down to just the orb
   while Study Mode owns the header, but keeps the same footprint (height,
   min-width) as the other topbar buttons (.generate-btn/.study-mode-btn)
   -- only the shape goes compact/icon-only, not the overall size. It's
   still a plain toggle for its own normal flex-slot panel (see openZeno's
   mutual-exclusivity check), not a separate floating widget. */


@media (max-width: 768px) {
  .study-panel {
    position: fixed;
    top: 0; right: 0; bottom: 0; left: 0;
    z-index: 300;
    transition: transform 0.25s ease;
    transform: translateX(100%);
    width: 100%;
  }
  #screen-app.study-open .study-panel { width: 100%; transform: translateX(0); }
  #screen-app.study-open .study-panel-inner { box-shadow: none; }
  .study-panel-inner { width: 100%; border-left: none; }
  #study-backdrop { opacity: 0; transition: opacity 0.25s ease; pointer-events: none; display: block; }
  #screen-app.study-open #study-backdrop { opacity: 1; pointer-events: auto; }
}

/* ── Dark theme ────────────────────────────────────────────────────────────── */
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg:           #0E1116;
  --surface:      #171B22;
  --surface2:     #1E232C;
  --surface3:     #262C38;
  --border:       #2A313D;
  --border2:      #3B4453;
  --primary:      #A5E0A4;
  --primary-dim:  #C0EDBE;
  --primary-glow: rgba(165,224,164,0.12);
  --accent:       #3FBFAF;
  --accent-dim:   #35A896;
  --text:         #E6E9EF;
  --text-muted:   #9AA4B5;
  --text-dim:     #6E788A;
  --red:          #F87171;
  --amber:        #FBBF24;
  --green:        #4ADE80;
  --shadow: 0 0.5rem 2rem rgba(0,0,0,0.5);
  --shadow-sm: 0 0.125rem 0.5rem rgba(0,0,0,0.35);
  --sidebar-bg: #15233F;
}

/* zenow wordmark — logo-background green on loading/auth screens, white in the app shell */
:root[data-theme="dark"] .loading-logo,
:root[data-theme="dark"] .auth-logo { color: #A5E0A4; }

:root[data-theme="dark"] .logo { color: #FFFFFF; }

/* zenow-green accent: dark ink instead of white on filled chips/buttons */
:root[data-theme="dark"] .week-header-day.today .week-day-num,
:root[data-theme="dark"] .week-header-day.today.selected .week-day-num,
:root[data-theme="dark"] .month-cell.selected .month-cell-num,
:root[data-theme="dark"] .month-cell.today .month-cell-num,
:root[data-theme="dark"] .year-day.selected.today,
:root[data-theme="dark"] .year-day.today,
:root[data-theme="dark"] .zeno-bubble { color: #14213D; }

:root[data-theme="dark"] #screen-auth {
  background: linear-gradient(135deg, #1A2030 0%, var(--bg) 60%);
}

/* The ring on the page's own background: a faint track, the accent arc,
   and nothing filled in behind it. */
:root[data-theme="dark"] .loading-spinner {
  background: transparent;
  border-color: rgba(255,255,255,0.12);
  border-top-color: var(--primary);
}

:root[data-theme="dark"] .password-toggle:hover { background: rgba(255,255,255,0.08); }

:root[data-theme="dark"] .btn-danger {
  background: rgba(220,38,38,0.16);
  border-color: rgba(220,38,38,0.35);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.1), 0 0.125rem 0.625rem rgba(220,38,38,0.05);
}

/* Glass buttons */
:root[data-theme="dark"] .btn-ghost,
:root[data-theme="dark"] .btn-secondary,
:root[data-theme="dark"] .undo-btn {
  background: rgba(255,255,255,0.07);
  border-color: rgba(255,255,255,0.12);
  color: var(--text);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.07), 0 0.125rem 0.625rem rgba(0,0,0,0.4);
}
:root[data-theme="dark"] .btn-ghost:hover,
:root[data-theme="dark"] .btn-secondary:hover,
:root[data-theme="dark"] .undo-btn:hover {
  background: rgba(255,255,255,0.13);
  color: var(--text);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.1), 0 0.25rem 0.875rem rgba(0,0,0,0.5);
}
:root[data-theme="dark"] .btn-undo {
  background: rgba(255,255,255,0.07); border-color: rgba(255,255,255,0.12); color: var(--text);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.07), 0 0.125rem 0.625rem rgba(0,0,0,0.4);
}
:root[data-theme="dark"] .btn-undo:hover {
  background: rgba(255,255,255,0.13); color: var(--text);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.1), 0 0.25rem 0.875rem rgba(0,0,0,0.5);
}
:root[data-theme="dark"] .btn-undo svg, :root[data-theme="dark"] .undo-btn svg { color: #E9B566; }
/* Same shape as light: a clean surface, a real border, a hairline lift.
   The white inner highlight light mode uses would be a glare here, so the
   depth comes from a plain shadow instead. */
:root[data-theme="dark"] .btn-ghost.btn-sm:not(.sidebar *),
:root[data-theme="dark"] .btn-secondary.btn-sm:not(.sidebar *) {
  background: var(--surface2);
  border-color: var(--border);
  color: var(--text);
  box-shadow: 0 1px 0.125rem rgba(0,0,0,0.25);
}
:root[data-theme="dark"] .btn-ghost.btn-sm:not(.sidebar *):hover,
:root[data-theme="dark"] .btn-secondary.btn-sm:not(.sidebar *):hover {
  background: var(--surface2);
  border-color: var(--border2);
  color: var(--text);
  box-shadow: 0 0.25rem 0.75rem rgba(0,0,0,0.35);
}

/* +Event — dark glass (light mode keeps the original bright glass) */
:root[data-theme="dark"] #btn-add-event {
  background:
    linear-gradient(160deg, rgba(255,255,255,0.14), rgba(255,255,255,0.06) 55%, rgba(255,255,255,0.1)) padding-box,
    linear-gradient(var(--angle),
      rgba(255,255,255,0.3) 0%,
      rgba(255,255,255,0.35) 14%,
      rgba(255,255,255,0.12) 32%,
      rgba(255,255,255,0.09) 55%,
      rgba(255,255,255,0.2) 78%,
      rgba(23,32,54,0.5) 100%) border-box;
  color: #fff;
  box-shadow: inset 0 0 0.1875rem 1.5px rgba(255,255,255,0.3), inset 0 0 0.375rem 0.4375rem rgba(255, 255, 255, 0.15), inset var(--s) var(--s) 1.375rem -0.25rem rgba(255, 255, 255, 0.22), inset 0 -0.4375rem 0.875rem rgba(23, 32, 54, 0.2), 0 0 0 1px rgba(0,0,0,0.35), 0 0.375rem 0.875rem rgba(3, 3, 3, 0.2);
}
:root[data-theme="dark"] #btn-add-event::before {
  background:
    radial-gradient(90% 130% at 50% -40%, rgba(255,255,255,0.12), rgba(255,255,255,0) 62%),
    radial-gradient(26% 42% at calc(50% + var(--s)) 16%, rgba(255,255,255,0.08), rgba(255,255,255,0) 72%);
}
:root[data-theme="dark"] #btn-add-event::after {
  background: radial-gradient(closest-side, transparent 58%, rgba(0,0,0,0.25) 90%, rgba(0,0,0,0.4));
}
:root[data-theme="dark"] #btn-add-event svg { filter: drop-shadow(0 1px 1px rgba(0,0,0,0.35)); }
:root[data-theme="dark"] #btn-add-event:hover {
  box-shadow:
    inset 0 0 0.1875rem 1.5px rgba(255,255,255,0.35),
    inset 0 0 0.375rem 0.4375rem rgba(255,255,255,0.18),
    inset var(--s) var(--s) 1.375rem -0.25rem rgba(255,255,255,0.25),
    inset 0 -0.4375rem 0.875rem rgba(23,32,54,0.25),
    0 0 0 1px rgba(255,255,255,0.22),
    0 0.4375rem 1rem rgba(0,0,0,0.4);
}
:root[data-theme="dark"] #btn-add-event:active {
  box-shadow:
    inset 0 0.125rem 0.3125rem rgba(23,32,54,0.3),
    inset 0.4375rem 0.625rem 1rem rgba(255,255,255,0.08),
    inset 0 0.375rem 0.75rem rgba(23,32,54,0.25),
    0 0 0 1px rgba(255,255,255,0.14),
    0 1px 0.125rem rgba(0,0,0,0.3);
}

/* Calendar events — dark palette */
:root[data-theme="dark"] .cal-event.type-school      { background: rgba(124,58,237,0.22); color: #C4B5FD; border-left-color: #8B5CF6; }
:root[data-theme="dark"] .cal-event.type-personal    { background: rgba(59,130,246,0.22); color: #93C5FD; border-left-color: #60A5FA; }
:root[data-theme="dark"] .cal-event.type-sport       { background: rgba(249,115,22,0.22); color: #FDBA74; border-left-color: #FB923C; }
:root[data-theme="dark"] .cal-event.type-study_block { background: rgba(34,197,94,0.2);  color: #86EFAC; border-left-color: #4ADE80; }
:root[data-theme="dark"] .cal-event.type-exam        { background: rgba(245,158,11,0.22); color: #FCD34D; border-left-color: #FBBF24; }
:root[data-theme="dark"] .cal-event.type-other       { background: rgba(156,163,175,0.2); color: #CBD5E1; border-left-color: #94A3B8; }
:root[data-theme="dark"] .cal-event:hover { filter: brightness(1.1); }
:root[data-theme="dark"] .cal-event.type-study_window {
  background: rgba(42,157,143,0.16);
  border-color: rgba(42,157,143,0.5);
  color: var(--accent);
}
:root[data-theme="dark"] .cal-event.type-study_window:hover {
  background: rgba(42,157,143,0.22);
  border-color: rgba(42,157,143,0.7);
}

:root[data-theme="dark"] .rubber-band { background: rgba(165,224,164,0.12); }

:root[data-theme="dark"] .drag-choice-card {
  background: rgba(255,255,255,0.06);
  border-color: rgba(255,255,255,0.12);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.06), 0 0.25rem 0.875rem rgba(0,0,0,0.4);
}
:root[data-theme="dark"] .drag-choice-card:hover {
  background: rgba(255,255,255,0.1);
  border-color: rgba(63,191,175,0.4);
}
:root[data-theme="dark"] .drag-choice-card-danger:hover {
  border-color: rgba(248,113,113,0.5);
}

/* The dark theme's own copy of the green felt, gone for the same reason as
   the light one: the panel now carries its identity in the header band, and
   the body is the ordinary dark surface, where every control already has the
   contrast it was designed with. Only the band is deepened a touch so it
   does not glare against a dark page. */
:root[data-theme="dark"] #modal-schedule-mode .modal-header {
  background:
    radial-gradient(120% 180% at 12% -40%, rgba(255,255,255,0.18), rgba(255,255,255,0) 60%),
    linear-gradient(115deg, #248A7D 0%, #1C6F64 52%, #17594F 100%);
}
:root[data-theme="dark"] #modal-schedule-mode .modal {
  box-shadow: 0 1.5rem 3.75rem rgba(0,0,0,0.55), var(--shadow);
}

:root[data-theme="dark"] .retention-item {
  background: rgba(255,255,255,0.06);
  border-color: rgba(255,255,255,0.12);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.06);
}
:root[data-theme="dark"] .retention-item:hover {
  background: rgba(255,255,255,0.1);
  border-color: rgba(245,158,11,0.4);
}

:root[data-theme="dark"] .toast.success {
  border-color: rgba(74,222,128,0.4);
  background: rgba(34,197,94,0.15);
  color: #86EFAC;
}
:root[data-theme="dark"] .toast.error {
  border-color: rgba(248,113,113,0.4);
  background: rgba(239,68,68,0.15);
  color: #FCA5A5;
}

:root[data-theme="dark"] .multi-select-bar { background: #14213D; }

/* Chrono AI panel — dark warm brown */
:root[data-theme="dark"] .zeno-panel-inner {
  background: linear-gradient(180deg, #453B28 0%, #382F20 100%);
  border-left-color: #6B5A38;
}
:root[data-theme="dark"] .zeno-header {
  background: linear-gradient(180deg, #4A4029, #403724);
  border-bottom-color: #6B5A38;
}
:root[data-theme="dark"] .zeno-title { color: #E6CD97; }
/* .chrono-quick-bar intentionally has no dark override -- same theme-
   independent gold gradient as .chrono-topbar-btn itself, which it's
   extending from. */
:root[data-theme="dark"] #screen-app.chrono-open .zeno-panel-inner {
  box-shadow: -0.25rem 0 1.5rem rgba(0,0,0,0.5);
}
:root[data-theme="dark"] .zeno-disclaimer {
  color: #C9AC7A;
  background: #4A4029;
  border-bottom-color: #6B5A38;
}
:root[data-theme="dark"] .zeno-messages::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, #6B5A38, #8A7444);
}
:root[data-theme="dark"] .zeno-msg-assistant,
:root[data-theme="dark"] .zeno-typing {
  background: linear-gradient(160deg, #4A3F28, #423823 85%);
  color: #E6CD97;
  border-color: rgba(200,150,46,0.35);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.07),
    0 1px 0.1875rem rgba(0,0,0,0.35);
}
:root[data-theme="dark"] .zeno-msg-user {
  background: linear-gradient(160deg, #8A6A1F, #6E5315);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.15),
    0 0.125rem 0.375rem rgba(0,0,0,0.4);
}
:root[data-theme="dark"] .zeno-image-strip {
  background: #4A4029;
  border-top-color: #6B5A38;
}
:root[data-theme="dark"] .zeno-file-icon {
  background: rgba(212,184,106,0.15); color: #D4B86A;
}
:root[data-theme="dark"] .zeno-input-row {
  border-top-color: #6B5A38;
  background: #3E3523;
}
:root[data-theme="dark"] .zeno-attach-btn {
  color: #D4B86A;
  border-color: rgba(200,150,46,0.25);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.06), 0 0.125rem 0.5rem rgba(0,0,0,0.3);
}
:root[data-theme="dark"] .zeno-attach-btn:hover {
  color: #E8C35E;
  background: rgba(255,255,255,0.1);
}
:root[data-theme="dark"] .zeno-textarea {
  border-color: #6B5A38;
  background: #332B1C;
  color: #E6CD97;
}
:root[data-theme="dark"] .zeno-textarea:focus {
  border-color: var(--zeno-accent);
  box-shadow: 0 0 0 0.125rem rgba(200,150,46,0.15);
}
:root[data-theme="dark"] .zeno-textarea::placeholder { color: #9C8357; }
:root[data-theme="dark"] .zeno-ghost { color: #9C8357; }
:root[data-theme="dark"] .zeno-chat-switcher {
  background: linear-gradient(160deg, #4A3F28, #423823 85%);
  border-color: rgba(200,150,46,0.35);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.07), 0 0.75rem 1.75rem rgba(0,0,0,0.4);
}
:root[data-theme="dark"] .zeno-chat-switcher-list .list-item { border-bottom-color: rgba(200,150,46,0.22); }
:root[data-theme="dark"] .zeno-chat-switcher-list .list-item-edit,
:root[data-theme="dark"] .zeno-chat-switcher-list .list-item-delete { color: #9C8357; }
:root[data-theme="dark"] .zeno-chat-switcher-list .list-item-edit:hover {
  background: rgba(212,184,106,0.16); color: #E8C35E;
}
:root[data-theme="dark"] .zeno-chat-switcher-list .list-item-edit:active { background: rgba(212,184,106,0.26); }
:root[data-theme="dark"] .zeno-chat-switcher-row-title { color: #E6CD97; }
:root[data-theme="dark"] .zeno-chat-switcher-row-title.active { color: #E8C35E; }
:root[data-theme="dark"] .zeno-chat-switcher-empty { color: #9C8357; }
:root[data-theme="dark"] .zeno-chat-switcher .settings-add-row { border-top-color: rgba(200,150,46,0.22); color: #E8C35E; }
:root[data-theme="dark"] .zeno-chat-switcher .settings-add-row:hover { background: rgba(212,184,106,0.12); }

/* Theme picker (settings modal) */
.theme-picker {
  position: relative;
  display: flex;
  gap: 0.25rem;
  background: var(--surface2);
  border-radius: var(--radius);
  padding: 0.25rem;
}
/* Same track+pill pattern as .auth-tab-indicator/.view-tab-pill -- left/
   width set in px by positionThemePickerPill() off the active option's own
   offsetLeft/offsetWidth. */
.theme-picker-pill {
  position: absolute; top: 0.25rem; bottom: 0.25rem; left: 0.25rem; width: 0;
  background: var(--surface); border-radius: var(--radius-sm);
  box-shadow: 0 1px 0.25rem rgba(0,0,0,0.1);
  transition: left 0.24s var(--ease), width 0.24s var(--ease);
  z-index: 0;
}
.theme-opt {
  position: relative; z-index: 1;
  flex: 1;
  padding: 0.5rem;
  text-align: center;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-muted);
  transition: color 0.12s var(--ease);
  border: none;
  background: none;
  font-family: var(--font);
}
.theme-opt.active {
  color: var(--text);
  font-weight: 600;
}

/* -- checklist editor (academic modal) + sidebar progress -- */
.checklist-editor { display: flex; flex-direction: column; gap: 0.4375rem; }
.checklist-editor:empty { display: none; }
.cl-row {
  display: flex; align-items: center; gap: 0.5625rem;
  padding: 0.1875rem 0.4375rem 0.1875rem 0.5625rem;
  border-radius: 0.75rem;
  background: linear-gradient(135deg, rgba(255,255,255,0.075), rgba(255,255,255,0.028));
  border: 1px solid var(--border);
  -webkit-backdrop-filter: blur(0.875rem) saturate(170%);
  backdrop-filter: blur(0.875rem) saturate(170%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.10), 0 1px 0.3125rem rgba(15,26,46,0.06);
  transition: border-color .18s ease, box-shadow .18s ease, background .18s ease;
}
.cl-row:hover {
  border-color: rgba(125,155,215,0.42);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.16), 0 0.1875rem 0.75rem rgba(15,26,46,0.09);
}
.cl-row:focus-within {
  border-color: rgba(125,155,215,0.62);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.18), 0 0 0 0.1875rem rgba(125,155,215,0.13), 0 0.1875rem 0.75rem rgba(15,26,46,0.09);
}
.cl-check {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  width: 1.0625rem; height: 1.0625rem; flex-shrink: 0; margin: 0;
  border-radius: 0.375rem; cursor: pointer;
  background: rgba(127,127,127,0.10);
  border: 1.5px solid var(--border);
  display: grid; place-content: center;
  transition: background .18s, border-color .18s, box-shadow .18s, transform .12s;
}
.cl-check:hover { border-color: rgba(125,155,215,.55); transform: scale(1.1); }
.cl-check:checked {
  background: linear-gradient(135deg, var(--accent), #34b3a2);
  border-color: transparent;
  box-shadow: 0 1px 0.375rem rgba(63,191,175,.40), inset 0 1px 0 rgba(255,255,255,.35);
}
.cl-check::before {
  content: '';
  width: 0.5625rem; height: 0.5625rem;
  background: #fff;
  clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
  transform: scale(0);
  transition: transform .16s cubic-bezier(.2, 1.4, .4, 1);
}
.cl-check:checked::before { transform: scale(1); }
.cl-text {
  flex: 1; min-width: 0;
  font-size: 0.8125rem; padding: 0.5rem 0.25rem;
  background: transparent; border: none;
  color: var(--text); font-family: var(--font);
  transition: color .18s;
}
.cl-text::placeholder { color: var(--text-dim); opacity: .75; }
.cl-text:focus { outline: none; }
.cl-remove {
  flex-shrink: 0; width: 1.375rem; height: 1.375rem; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  border: none; border-radius: 0.5rem; cursor: pointer;
  background: transparent; color: var(--text-dim); font-size: 0.9375rem;
  opacity: .55;
  transition: opacity .15s, color .15s, background .15s;
}
.cl-row:hover .cl-remove, .cl-remove:focus-visible { opacity: 1; }
.cl-remove:hover { color: var(--red); background: rgba(239,68,68,0.12); }
@media (hover: none) { .cl-remove { opacity: 1; } }
.cl-row.done { opacity: .72; }

/* Toggles whether a REAL (non-shadow) assignment's task belongs to THIS
   specific study block -- a private shadow's whole checklist is implicitly
   "this block's" already, so it never gets this control (see
   isPrivateShadowItem). Round, not the softer squircle the other row
   buttons use, so it reads as a distinct kind of control (inclusion, not
   an action on the task itself) at a glance. */
.cl-assign-toggle {
  flex-shrink: 0; width: 1.375rem; height: 1.375rem;
  display: flex; align-items: center; justify-content: center;
  border: 1.5px dashed var(--border); border-radius: 50%; cursor: pointer;
  background: transparent; color: var(--text-dim);
  transition: background .15s, color .15s, border-color .15s;
}
.cl-assign-toggle:hover { border-color: var(--green); color: var(--green); border-style: solid; }
.cl-assign-toggle.assigned {
  border: 1.5px solid var(--green); color: var(--green);
  background: color-mix(in srgb, var(--green) 18%, transparent);
}
.cl-assign-toggle.assigned:hover { background: color-mix(in srgb, var(--green) 28%, transparent); border-color: var(--red); color: var(--red); }
/* Unassigned tasks read as "not part of this session" -- comes after
   .cl-row.done above on purpose so it wins when a task is both done AND
   unassigned (rare, but "not part of this block" is the stronger signal). */
.cl-row.unassigned { opacity: .45; }
.cl-row.unassigned:hover { opacity: .7; }

/* Duration button: an hourglass icon until a duration is set, then a small
   "25m"-style pill. Amber hover (not red) since setting a duration isn't
   a destructive action. */
.cl-duration {
  flex-shrink: 0; height: 1.375rem; padding: 0 0.375rem; min-width: 1.375rem;
  display: flex; align-items: center; justify-content: center;
  border: none; border-radius: 0.5rem; cursor: pointer;
  background: transparent; color: var(--text-dim); font-size: 0.6875rem; font-weight: 600;
  font-family: var(--font); font-variant-numeric: tabular-nums;
  transition: background .15s, color .15s;
}
.cl-duration:hover { color: var(--amber); background: color-mix(in srgb, var(--amber) 12%, transparent); }
.cl-duration.set { background: var(--surface2); color: var(--text-muted); }
.cl-duration.set:hover { color: var(--amber); background: color-mix(in srgb, var(--amber) 14%, transparent); }
.cl-duration-input {
  flex-shrink: 0; width: 2.75rem; height: 1.375rem; padding: 0 0.25rem;
  border: 1px solid var(--red); border-radius: 0.5rem; font-size: 0.6875rem; font-weight: 600;
  text-align: center; background: var(--surface2); color: var(--text); font-family: var(--font);
}
.cl-duration-input:focus { outline: none; }
.cl-row.done .cl-text { text-decoration: line-through; text-decoration-color: rgba(127,127,127,.7); color: var(--text-dim); }
.cl-count {
      font-size: 0.6875rem; font-weight: 700; letter-spacing: .02em;
      font-variant-numeric: tabular-nums;
      padding: 0.09375rem 0.5rem; border-radius: 62.4375rem;
  background: rgba(125,155,215,0.13); color: var(--text-dim);
  border: 1px solid rgba(125,155,215,0.22);
  transition: background .2s, color .2s, border-color .2s;
}
.cl-count.complete {
  background: linear-gradient(135deg, rgba(63,191,175,.24), rgba(63,191,175,.12));
  color: var(--accent); border-color: rgba(63,191,175,.38);
}
.academic-check-badge {
  font-size: 0.625rem; line-height: 1; font-weight: 700;
  padding: 0.0625rem 0.4375rem; border-radius: 62.4375rem;
  background: rgba(255,255,255,0.1); color: rgba(255,255,255,0.65);
}
.academic-check-badge.all-done { color: #A5E0A4; }
:root[data-theme="dark"] .academic-check-badge { background: rgba(255,255,255,0.12); }

/* -- cookie consent banner -- */
.cookie-banner {
  position: fixed; left: 50%; bottom: 1.125rem; transform: translate(-50%, 1.5rem);
  z-index: 10000; display: flex; align-items: center; gap: 0.875rem;
  max-width: min(37.5rem, calc(100vw - 2rem)); padding: 0.8125rem 1.125rem;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: 0 1rem 3rem rgba(0,0,0,0.22); font-size: 0.8125rem; line-height: 1.5;
  color: var(--text-muted); opacity: 0; pointer-events: none;
  transition: opacity 0.3s, transform 0.3s;
}
.cookie-banner.show { opacity: 1; pointer-events: auto; transform: translate(-50%, 0); }
.cookie-banner a { color: var(--accent); text-decoration: none; font-weight: 600; }
.cookie-banner a:hover { text-decoration: underline; }
.cookie-banner button {
  flex-shrink: 0; border: none; cursor: pointer; padding: 0.5rem 1rem;
  border-radius: 62.4375rem; font-size: 0.75rem; font-weight: 700; font-family: var(--font);
  background: var(--accent); color: #fff; transition: background 0.15s;
}
.cookie-banner button:hover { background: var(--accent-dim); }
@media (max-width: 480px) { .cookie-banner { flex-direction: column; align-items: stretch; text-align: center; } }

/* -- legal links (settings modal) -- */
.settings-legal-row { padding: 0.625rem 0.875rem; font-size: 0.6875rem; white-space: nowrap; }
.settings-legal-row a { color: var(--text-muted); text-decoration: none; transition: color 0.15s; }
.settings-legal-row a:hover { color: var(--primary); text-decoration: underline; }

/* -- drop overlay: image → Chrono -- */
.drop-overlay {
  position: fixed; inset: 0; z-index: 500;
  display: flex; align-items: center; justify-content: center;
  background: rgba(20,33,61,0.35);
  -webkit-backdrop-filter: blur(0.1875rem); backdrop-filter: blur(0.1875rem);
  opacity: 0; pointer-events: none; transition: opacity 0.15s;
}
.drop-overlay.visible { opacity: 1; }
.drop-overlay-card {
  display: flex; flex-direction: column; align-items: center; gap: 0.625rem;
  padding: 2.125rem 2.875rem; border-radius: 1.125rem; text-align: center;
  border: 0.125rem dashed var(--primary);
  background: var(--surface); color: var(--primary);
  box-shadow: 0 1.5rem 4rem rgba(0,0,0,0.3);
}
.drop-overlay-card svg { opacity: 0.9; }
.drop-title { font-size: 1.0625rem; font-weight: 800; color: var(--text); letter-spacing: 0.2px; }
:root[data-theme="dark"] .drop-overlay { background: rgba(6,8,12,0.55); }

/* ── First-run walkthrough ────────────────────────────────────────────────
   Deliberately not a .modal-overlay. A modal is something you dismiss to get
   back to what you were doing; this is the first thing a new student sees,
   so it owns the whole screen and the only way past it is a decision --
   answer the step, skip the step, or skip the introduction. Everything here
   is built from the theme variables, so dark mode needs no rules of its
   own. */
.ob-overlay {
  position: fixed; inset: 0; z-index: 120;
  display: flex; align-items: center; justify-content: center;
  padding: 1.5rem;
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  backdrop-filter: blur(0.375rem);
  animation: ob-fade 0.24s var(--ease, ease);
}
/* A section's introduction: over the panel or layer it opened in. */
.ob-overlay.is-top { z-index: 2100; }
.ob-overlay.hidden { display: none; }
/* Nothing behind the walkthrough should scroll away under it. */
body.ob-open { overflow: hidden; }
@keyframes ob-fade { from { opacity: 0; } to { opacity: 1; } }

.ob-card {
  width: min(38rem, 100%);
  max-height: min(46rem, calc(100dvh - 3rem));
  display: flex; flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  overflow: hidden;
}

/* Progress rail: one segment per step, filled up to where the student is.
   A bar rather than "3 of 7" because the exact number is not the point --
   how much is left is. */
.ob-head {
  display: flex; align-items: center; gap: 1rem;
  padding: 0.875rem 1.25rem;
  border-bottom: 1px solid var(--border);
}
.ob-rail { flex: 1; display: flex; gap: 0.25rem; min-width: 0; }
.ob-rail-seg {
  flex: 1; height: 0.1875rem; border-radius: 62.4375rem;
  background: var(--surface3);
  transition: background 0.3s var(--ease, ease);
}
.ob-rail-seg.done { background: var(--accent); }
.ob-skip-all {
  flex-shrink: 0;
  background: none; border: none; padding: 0.125rem;
  font-family: inherit; font-size: 0.75rem; font-weight: 500;
  color: var(--text-dim); cursor: pointer;
  transition: color 0.15s ease;
}
.ob-skip-all:hover { color: var(--text-muted); }

.ob-body {
  flex: 1; min-height: 0; overflow-y: auto;
  padding: 1.75rem 1.75rem 1.5rem;
}
/* Each step swaps the whole body, so it re-enters rather than jumping. */
.ob-step { animation: ob-step-in 0.26s var(--ease, ease); }
@keyframes ob-step-in {
  from { opacity: 0; transform: translateY(0.5rem); }
  to   { opacity: 1; transform: none; }
}
.ob-eyebrow {
  font-size: 0.6875rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.08em; color: var(--accent); margin-bottom: 0.5rem;
}
.ob-title {
  font-size: 1.5rem; font-weight: 700; line-height: 1.2;
  letter-spacing: -0.02em; color: var(--text); margin-bottom: 0.5rem;
}
.ob-lede {
  font-size: 0.875rem; line-height: 1.55; color: var(--text-muted);
  margin-bottom: 1.25rem;
}
.ob-lede:last-child { margin-bottom: 0; }
.ob-fields { display: flex; flex-direction: column; gap: 1rem; }
.ob-field { display: flex; flex-direction: column; gap: 0.375rem; }
.ob-field > label {
  font-size: 0.75rem; font-weight: 600; color: var(--text-muted);
}
.ob-field-note { font-size: 0.75rem; line-height: 1.45; color: var(--text-dim); }
.ob-row { display: flex; gap: 0.75rem; }
.ob-row > * { flex: 1; min-width: 0; }
/* A value and its scale stay side by side, even on a phone. */
.ob-row.ob-row-keep > select { flex: 0 1 11rem; }

/* A choice grid: the level picker, the session-length presets, the tour's
   own cards. One rule because they are the same object at different sizes --
   a tile you pick, which says what it is and what picking it means. */
.ob-choices { display: grid; gap: 0.5rem; }
.ob-choices.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.ob-choice {
  display: flex; flex-direction: column; gap: 0.1875rem;
  padding: 0.75rem 0.875rem; text-align: left;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-md); cursor: pointer;
  font-family: inherit; color: var(--text);
  transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
}
.ob-choice:hover { border-color: var(--border2); background: var(--surface2); }
.ob-choice.selected {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, var(--surface));
  box-shadow: inset 0 0 0 1px var(--accent);
}
.ob-choice-title { font-size: 0.8125rem; font-weight: 600; }
.ob-choices.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ob-choice.ob-choice-sm { padding: 0.5rem 0.625rem; align-items: center; text-align: center; }

/* Days of the week as toggles: days off, and the days a commitment repeats. */
.ob-days { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 0.3125rem; }
.ob-day {
  padding: 0.4375rem 0; border-radius: var(--radius-sm);
  background: var(--surface); border: 1px solid var(--border);
  font-family: inherit; font-size: 0.75rem; font-weight: 600; color: var(--text-muted);
  cursor: pointer; text-transform: capitalize;
  transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
}
.ob-day:hover { border-color: var(--border2); color: var(--text); }
.ob-day.selected {
  border-color: var(--accent); color: var(--text);
  background: color-mix(in srgb, var(--accent) 12%, var(--surface));
}
.ob-choice-note { font-size: 0.75rem; line-height: 1.4; color: var(--text-muted); }

/* How you study: toggle chips, and the student's own ways as removable ones. */
.sm-sub { margin-bottom: 0.625rem; }
.sm-chips { display: flex; flex-wrap: wrap; gap: 0.375rem; }
.sm-chip {
  display: inline-flex; align-items: center; gap: 0.375rem; min-height: 2rem;
  padding: 0.3125rem 0.75rem 0.3125rem 0.5rem; border-radius: 62.4375rem;
  border: 1px solid var(--border); background: var(--surface);
  font: 500 0.8125rem/1.2 var(--font); color: var(--text); cursor: pointer;
  transition: background .15s ease, border-color .15s ease, color .15s ease, transform .1s ease;
}
.sm-chip:hover { border-color: var(--border2); background: var(--surface2); }
.sm-chip:active { transform: scale(.97); }
.sm-chip-check {
  width: 1rem; height: 1rem; border-radius: 50%; flex-shrink: 0;
  border: 1.5px solid var(--border2); background: transparent; position: relative;
  transition: background .15s ease, border-color .15s ease;
}
.sm-chip.is-on { border-color: color-mix(in srgb, var(--accent) 55%, var(--border)); background: color-mix(in srgb, var(--accent) 10%, var(--surface)); }
.sm-chip.is-on .sm-chip-check { background: var(--accent); border-color: var(--accent); }
.sm-chip.is-on .sm-chip-check::after {
  content: ''; position: absolute; left: 0.28rem; top: 0.14rem; width: 0.25rem; height: 0.45rem;
  border: solid #fff; border-width: 0 1.5px 1.5px 0; transform: rotate(45deg);
}
.sm-chip.is-custom { cursor: default; padding-right: 0.5rem; }
.sm-chip-x {
  background: none; border: none; padding: 0 0.125rem; margin-left: 0.125rem; cursor: pointer;
  font: 400 1rem/1 var(--font); color: var(--text-dim);
}
.sm-chip-x:hover { color: var(--text); }
.sm-add { display: flex; gap: 0.375rem; margin-top: 0.625rem; }
.sm-add input { flex: 1; min-width: 0; height: 2.125rem; border-radius: 62.4375rem; padding: 0 0.875rem; font-size: 0.8125rem; }
.sm-add-btn {
  width: 2.125rem; height: 2.125rem; flex-shrink: 0; border-radius: 50%; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface2); color: var(--text);
  font: 500 1.125rem/1 var(--font);
}
.sm-add-btn:hover { background: color-mix(in srgb, var(--accent) 12%, var(--surface2)); }

/* Your steps: one small card per kind of work, each step with its place. */
.sh-kind { padding: 0.75rem 0 0.875rem; }
.sh-kind + .sh-kind { border-top: 1px solid var(--border); }
.sh-kind:first-child { padding-top: 0.125rem; }
.sh-head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.75rem; margin-bottom: 0.5rem; }
.sh-name { font-size: 0.875rem; font-weight: 600; color: var(--text); }
.sh-src { font-size: 0.75rem; color: var(--text-dim); white-space: nowrap; }
.sh-reset { background: none; border: 0; padding: 0; font: inherit; color: var(--accent); cursor: pointer; }
.sh-reset:hover { text-decoration: underline; }
.sh-steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.375rem; }
.sh-step { display: flex; align-items: center; gap: 0.5rem; }
.sh-at {
  flex-shrink: 0; min-width: 4.75rem; height: 1.875rem; padding: 0 0.625rem; border-radius: 62.4375rem; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface2); color: var(--text-muted);
  font: 600 0.6875rem/1 var(--font); letter-spacing: 0.01em; transition: background .15s ease, color .15s ease;
}
.sh-at:hover { color: var(--text); background: color-mix(in srgb, var(--accent) 10%, var(--surface2)); }
.sh-text { flex: 1; min-width: 0; height: 1.875rem; border-radius: 0.5rem; padding: 0 0.625rem; font-size: 0.8125rem; }
.sh-remove {
  flex-shrink: 0; width: 1.875rem; height: 1.875rem; display: grid; place-items: center; border: 0; border-radius: 50%;
  background: transparent; color: var(--text-dim); cursor: pointer; transition: color .15s ease, background .15s ease;
}
.sh-remove:hover { color: var(--red); background: color-mix(in srgb, var(--red) 10%, transparent); }
.sh-none, .sh-empty { margin: 0; font-size: 0.8125rem; color: var(--text-dim); line-height: 1.5; }
.sh-add { margin-top: 0.5rem; }
.sh-more { margin-top: 0.75rem; width: 100%; }

/* Subject chips the student is building up on the subjects step. */
.ob-chips { display: flex; flex-wrap: wrap; gap: 0.375rem; }
.ob-chip {
  display: inline-flex; align-items: center; gap: 0.375rem;
  padding: 0.3125rem 0.5rem 0.3125rem 0.625rem;
  background: var(--surface2); border: 1px solid var(--border);
  border-radius: 62.4375rem; font-size: 0.75rem; font-weight: 500; color: var(--text);
}
.ob-chip-dot { width: 0.5rem; height: 0.5rem; border-radius: 50%; flex-shrink: 0; }
.ob-chip-x {
  background: none; border: none; padding: 0; cursor: pointer;
  font-family: inherit; font-size: 0.875rem; line-height: 1;
  color: var(--text-dim);
}
.ob-chip-x:hover { color: var(--text); }
.ob-chip-empty { font-size: 0.75rem; color: var(--text-dim); }
.ob-suggest { display: flex; flex-wrap: wrap; gap: 0.375rem; margin-top: 0.5rem; }
.ob-suggest-btn {
  padding: 0.25rem 0.625rem; border-radius: 62.4375rem;
  background: none; border: 1px dashed var(--border2);
  font-family: inherit; font-size: 0.75rem; color: var(--text-muted); cursor: pointer;
}
.ob-suggest-btn:hover { border-style: solid; color: var(--text); background: var(--surface2); }

/* Tour: one explainer at a time, with its own little diagram above the
   words. Dots rather than a second progress rail -- the rail at the top is
   about the walkthrough, these are about the tour inside this one step. */
.ob-tour-figure {
  display: flex; align-items: center; justify-content: center;
  height: 8.5rem; margin-bottom: 1.125rem;
  background: var(--surface2); border: 1px solid var(--border);
  border-radius: var(--radius-md); overflow: hidden;
}
.ob-tour-figure svg { width: 100%; height: 100%; }
.ob-tour-dots { display: flex; gap: 0.375rem; justify-content: center; margin-top: 1.25rem; }
.ob-tour-dot {
  width: 0.4375rem; height: 0.4375rem; border-radius: 50%; padding: 0;
  background: var(--surface3); border: none; cursor: pointer;
  transition: background 0.2s ease, transform 0.2s ease;
}
.ob-tour-dot.active { background: var(--accent); transform: scale(1.2); }

/* Integrations: a row per thing you can connect, with its state on the
   right. Connecting leaves the page (OAuth) or opens the real modal, so
   these are links into the app proper, not a second implementation. */
.ob-connect { display: flex; flex-direction: column; gap: 0.5rem; }
.ob-connect-row {
  display: flex; align-items: center; gap: 0.75rem;
  padding: 0.75rem 0.875rem;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.ob-connect-mark {
  width: 2rem; height: 2rem; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--radius-sm);
  background: var(--surface2); color: var(--text-muted);
}
.ob-connect-mark svg { width: 1.0625rem; height: 1.0625rem; }
.ob-connect-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.125rem; }
.ob-connect-title { font-size: 0.8125rem; font-weight: 600; color: var(--text); }
.ob-connect-note { font-size: 0.75rem; line-height: 1.4; color: var(--text-muted); }
.ob-connect-done {
  flex-shrink: 0; display: inline-flex; align-items: center; gap: 0.25rem;
  font-size: 0.75rem; font-weight: 600; color: var(--green);
}

/* Recap on the last step: what the walkthrough actually set. */
.ob-recap { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 1.25rem; }
.ob-recap-row {
  display: flex; align-items: baseline; gap: 0.625rem;
  font-size: 0.8125rem; color: var(--text);
}
.ob-recap-check { color: var(--green); flex-shrink: 0; font-weight: 700; }
.ob-recap-label { color: var(--text-muted); }

.ob-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
  padding: 0.875rem 1.25rem;
  border-top: 1px solid var(--border);
  background: var(--surface);
}
.ob-foot-right { display: flex; align-items: center; gap: 1rem; }
/* Skipping is a way past, not an alternative worth weighing: as a second
   button beside Continue it read like a choice between two things. Quiet
   text, the same register as "Skip introduction" in the header, and a
   wider gap so the eye lands on the primary action first. */
.ob-skip-step {
  background: none; border: none; padding: 0.25rem 0.125rem; cursor: pointer;
  font-family: inherit; font-size: 0.8125rem; font-weight: 500;
  color: var(--text-dim);
  transition: color 0.15s ease;
}
.ob-skip-step:hover { color: var(--text-muted); text-decoration: underline; text-underline-offset: 0.1875rem; }
.ob-skip-step:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--radius-sm); }
/* Back is invisible on the first step but still occupies its corner, so the
   footer's other buttons don't slide sideways between steps. */
.ob-back.is-hidden { visibility: hidden; }
.ob-foot .hidden { display: none; }

/* ── Spotlight ───────────────────────────────────────────────────────────
   On the tour the card leaves the middle of the screen and stands beside
   the thing it is describing, while everything else dims around it. The
   dimming is one element's enormous box-shadow rather than a mask: the
   shadow paints outwards from the ring, so the target keeps the real,
   unfiltered app inside it. The blur goes here for the same reason. */
.ob-overlay.is-spotlight {
  background: none; backdrop-filter: none;
  display: block; padding: 0;
}
/* The drawing still earns its place beside a lit element -- it says what
   kind of thing this is at a glance, which a ring alone does not -- but at
   a size that keeps the card a card rather than a poster. */
.ob-overlay.is-spotlight .ob-tour-figure { height: 6.5rem; margin-bottom: 0.875rem; }
.ob-overlay.is-spotlight .ob-card {
  /* Above the ring: both are children of the overlay, and the ring's scrim
     is what paints the rest of the screen down -- without this it paints
     the card down along with it. */
  position: fixed; z-index: 2;
  /* Tall enough that a card carrying both a drawing and its paragraph says
     all of it: at 26rem the last line was being cut off mid-sentence, with
     only a silent scrollbar to say so. */
  width: 22rem; max-height: min(32rem, calc(100dvh - 2rem));
  transition: top 0.34s var(--ease, ease), left 0.34s var(--ease, ease);
}
/* The same near-black the modals dim with, rather than the walkthrough's
   own pale wash: over a light app a pale scrim greys everything to the
   same flatness, and the whole point here is that one thing is not. */
.ob-spot {
  position: fixed; z-index: 1; pointer-events: none;
  border-radius: var(--radius-md);
  box-shadow:
    0 0 0 100vmax rgba(17,24,39,0.5),
    0 0 0 0.125rem var(--accent),
    0 0 0 0.375rem color-mix(in srgb, var(--accent) 28%, transparent);
  transition: top 0.34s var(--ease, ease), left 0.34s var(--ease, ease),
              width 0.34s var(--ease, ease), height 0.34s var(--ease, ease);
}
.ob-spot.hidden { display: none; }

/* ── The tour on a phone ────────────────────────────────────────────────
   No room to stand beside anything, so the card is a sheet along the
   bottom and the real control it describes is ringed above it. When that
   control would sit under the sheet, the screen is simply dimmed. */
.ob-overlay.is-sheet { display: block; padding: 0; background: none; -webkit-backdrop-filter: none; backdrop-filter: none; }
.ob-overlay.is-sheet.is-sheet-dim { background: rgba(17,24,39,0.5); }
.ob-overlay.is-sheet .ob-card {
  position: fixed; z-index: 2;
  left: 0.5rem; right: 0.5rem; bottom: calc(0.5rem + env(safe-area-inset-bottom));
  width: auto; height: auto; max-height: 64dvh;
  border: 1px solid var(--border); border-radius: 1.25rem;
  box-shadow: 0 -0.625rem 2.5rem rgba(17,24,39,0.25);
  animation: ob-sheet-in 0.32s var(--ease, ease);
}
.ob-overlay.is-sheet .ob-head { padding: 0.75rem 1rem; }
.ob-overlay.is-sheet .ob-body { padding: 1rem 1.125rem 0.5rem; }
.ob-overlay.is-sheet .ob-tour-figure { height: 6.75rem; margin-bottom: 0.875rem; }
.ob-overlay.is-sheet .ob-title { font-size: 1.1875rem; }
.ob-overlay.is-sheet .ob-tour-dots { margin-top: 0.875rem; }
.ob-overlay.is-sheet .ob-foot { padding: 0.625rem 1rem 0.75rem; }
/* When the thing described sits along the bottom edge, the sheet takes the
   top instead, so the ring is never under it. */
.ob-overlay.is-sheet.is-sheet-top .ob-card {
  top: calc(0.5rem + env(safe-area-inset-top)); bottom: auto;
  box-shadow: 0 0.625rem 2.5rem rgba(17,24,39,0.25);
  animation-name: ob-sheet-in-top;
}
@keyframes ob-sheet-in { from { transform: translateY(1.5rem); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes ob-sheet-in-top { from { transform: translateY(-1.5rem); opacity: 0; } to { transform: none; opacity: 1; } }

/* ── The tour's drawings, animated ───────────────────────────────────────
   Every loop is 3.6s; each drawing's resting state (what reduced motion
   shows) is its finished one. */
.obf * { transform-box: fill-box; }
.obf-plan .obf-tick-fill { transform-origin: center; animation: obf-tick-fill 3.6s ease infinite; }
.obf-plan .obf-tick { stroke-dasharray: 12; animation: obf-tick-draw 3.6s ease infinite; }
.obf-plan .obf-done-text { animation: obf-done-text 3.6s ease infinite; }
@keyframes obf-tick-fill { 0%, 22% { transform: scale(0); } 32%, 82% { transform: scale(1); } 92%, 100% { transform: scale(0); } }
@keyframes obf-tick-draw { 0%, 30% { stroke-dashoffset: 12; } 40%, 82% { stroke-dashoffset: 0; } 92%, 100% { stroke-dashoffset: 12; } }
@keyframes obf-done-text { 0%, 30% { opacity: 0.45; } 40%, 82% { opacity: 0.15; } 92%, 100% { opacity: 0.45; } }

.obf-modes .obf-mode-pill { animation: obf-pill 3.6s cubic-bezier(.5,0,.2,1) infinite; }
.obf-modes .obf-mode-list { animation: obf-fade-out 3.6s ease infinite; }
.obf-modes .obf-mode-grid { animation: obf-fade-in 3.6s ease infinite; }
@keyframes obf-pill { 0%, 35% { transform: none; } 45%, 85% { transform: translateX(2.875rem); } 95%, 100% { transform: none; } }
@keyframes obf-fade-out { 0%, 35% { opacity: 1; } 45%, 85% { opacity: 0; } 95%, 100% { opacity: 1; } }
@keyframes obf-fade-in { 0%, 35% { opacity: 0; } 45%, 85% { opacity: 1; } 95%, 100% { opacity: 0; } }

.obf-homework .obf-chip { animation: obf-chip-in 3.6s ease infinite; }
.obf-homework .obf-chip-1 { animation-delay: 0.25s; }
.obf-homework .obf-chip-2 { animation-delay: 0.5s; }
.obf-homework .obf-chip-3 { animation-delay: 0.9s; }
@keyframes obf-chip-in { 0% { opacity: 0; transform: translateX(-0.75rem); } 12%, 85% { opacity: 1; transform: none; } 95%, 100% { opacity: 0; } }

.obf-drag .obf-ghost { animation: obf-ghost 3.6s cubic-bezier(.45,0,.25,1) infinite; }
.obf-drag .obf-drop { transform-origin: top; animation: obf-drop 3.6s ease infinite; }
@keyframes obf-ghost {
  0%, 10% { transform: none; opacity: 1; }
  52% { transform: translate(9.5rem, 1.625rem); opacity: 1; }
  58%, 100% { transform: translate(9.5rem, 1.625rem); opacity: 0; }
}
@keyframes obf-drop { 0%, 54% { transform: scaleY(0); opacity: 0; } 62%, 88% { transform: scaleY(1); opacity: 0.85; } 96%, 100% { opacity: 0; } }

.obf-auto .obf-auto-btn { transform-origin: center; animation: obf-press 3.6s ease infinite; }
.obf-auto .obf-pop { transform-origin: center; animation: obf-pop 3.6s ease infinite; }
.obf-auto .obf-pop-1 { animation-delay: 0.3s; }
.obf-auto .obf-pop-2 { animation-delay: 0.6s; }
.obf-auto .obf-pop-3 { animation-delay: 0.9s; }
@keyframes obf-press { 0%, 6% { transform: none; } 11% { transform: scale(0.93); } 16%, 100% { transform: none; } }
@keyframes obf-pop { 0%, 18% { transform: scale(0.5); opacity: 0; } 26%, 84% { transform: none; opacity: 1; } 94%, 100% { opacity: 0; } }

.obf-menu .obf-cursor { animation: obf-cursor 3.6s ease infinite; }
.obf-menu .obf-pop-menu, .obf-hold .obf-pop-menu { transform-origin: top left; animation: obf-menu 3.6s ease infinite; }
@keyframes obf-cursor { 0% { transform: translate(-3.75rem, 3.125rem); } 24%, 100% { transform: none; } }
@keyframes obf-menu { 0%, 30% { transform: scale(0.85); opacity: 0; } 36%, 84% { transform: none; opacity: 1; } 92%, 100% { opacity: 0; } }

.obf-hold .obf-finger { animation: obf-finger 3.6s ease infinite; }
.obf-hold .obf-press { transform-origin: center; animation: obf-ripple 3.6s ease-out infinite; }
@keyframes obf-finger { 0% { opacity: 0; } 8%, 36% { opacity: 0.35; } 44%, 100% { opacity: 0; } }
@keyframes obf-ripple { 0%, 8% { transform: scale(0.4); opacity: 0.4; } 34% { transform: scale(1.5); opacity: 0; } 100% { opacity: 0; } }

.obf-swipe .obf-swipe-row { animation: obf-swipe 3.6s cubic-bezier(.45,0,.25,1) infinite; }
@keyframes obf-swipe {
  0%, 8% { transform: none; } 20%, 36% { transform: translateX(4.375rem); } 46%, 54% { transform: none; }
  66%, 82% { transform: translateX(-4.375rem); } 92%, 100% { transform: none; }
}

.obf-study .obf-ring { animation: obf-ring 3.6s linear infinite; }
/* The Daily 3: a snap, three cards dealt, the flame. */
.obf-daily .obf-snap { animation: obf-daily-snap 4s ease infinite; transform-origin: 3.6875rem 4.375rem; }
.obf-daily .obf-card { opacity: 0; animation: obf-daily-card 4s ease infinite; }
.obf-daily .obf-card-1 { animation-delay: .25s; }
.obf-daily .obf-card-2 { animation-delay: .5s; }
.obf-daily .obf-flame { opacity: 0; transform-origin: 17.5625rem 2.875rem; animation: obf-daily-flame 4s ease infinite; }
@keyframes obf-daily-snap { 0%, 100% { transform: scale(1); } 8% { transform: scale(.94); } 14% { transform: scale(1); } }
@keyframes obf-daily-card { 0%, 18% { opacity: 0; transform: translateX(-0.625rem); } 30%, 88% { opacity: 1; transform: none; } 100% { opacity: 0; } }
@keyframes obf-daily-flame { 0%, 55% { opacity: 0; transform: scale(.5); } 65%, 88% { opacity: 1; transform: scale(1); } 100% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .obf-daily .obf-card, .obf-daily .obf-flame { opacity: 1; animation: none; } .obf-daily .obf-snap { animation: none; } }
.obf-study .obf-step-dot { transform-origin: center; animation: obf-step 3.6s ease infinite; }
.obf-study .obf-step-1 .obf-step-dot { animation-delay: 0.9s; }
.obf-study .obf-step-2 .obf-step-dot { animation-name: obf-step-late; }
@keyframes obf-ring { from { stroke-dashoffset: 276.5; } to { stroke-dashoffset: 0; } }
@keyframes obf-step { 0%, 18% { transform: scale(0); } 26%, 86% { transform: scale(1); } 96%, 100% { transform: scale(0); } }
@keyframes obf-step-late { 0%, 100% { transform: scale(0); } }

.obf-chrono .obf-ask { animation: obf-ask 3.6s ease infinite; }
.obf-chrono .obf-typing { animation: obf-typing 3.6s ease infinite; }
.obf-chrono .obf-dot { animation: obf-bounce 0.9s ease-in-out infinite; }
.obf-chrono .obf-dot-1 { animation-delay: 0.15s; }
.obf-chrono .obf-dot-2 { animation-delay: 0.3s; }
.obf-chrono .obf-reply { transform-origin: top left; animation: obf-reply 3.6s ease infinite; }
@keyframes obf-ask { 0% { opacity: 0; transform: translateY(0.5rem); } 10%, 88% { opacity: 1; transform: none; } 96%, 100% { opacity: 0; } }
@keyframes obf-typing { 0%, 14% { opacity: 0; } 18%, 42% { opacity: 1; } 46%, 100% { opacity: 0; } }
@keyframes obf-bounce { 0%, 100% { transform: none; } 50% { transform: translateY(-0.25rem); } }
@keyframes obf-reply { 0%, 44% { opacity: 0; transform: scale(0.94); } 52%, 88% { opacity: 1; transform: none; } 96%, 100% { opacity: 0; } }

.obf-add .obf-grow { transform-origin: top; animation: obf-grow 3.6s ease infinite; }
.obf-add .obf-grow-label { animation: obf-label 3.6s ease infinite; }
.obf-add .obf-cursor-down { animation: obf-cursor-down 3.6s ease infinite; }
@keyframes obf-grow { 0%, 10% { transform: scaleY(0); opacity: 0.8; } 50%, 86% { transform: scaleY(1); opacity: 0.8; } 96%, 100% { opacity: 0; } }
@keyframes obf-label { 0%, 52% { opacity: 0; } 60%, 86% { opacity: 0.85; } 96%, 100% { opacity: 0; } }
@keyframes obf-cursor-down { 0%, 10% { transform: none; opacity: 1; } 50% { transform: translateY(3.75rem); opacity: 1; } 60%, 100% { transform: translateY(3.75rem); opacity: 0; } }

.obf-more .obf-line { animation: obf-line 3.6s ease infinite; }
.obf-more .obf-pt { transform-origin: center; animation: obf-pop 3.6s ease infinite; }
.obf-more .obf-pt-1 { animation-delay: 0.25s; }
.obf-more .obf-pt-2 { animation-delay: 0.5s; }
.obf-more .obf-pt-3 { animation-delay: 0.75s; }
.obf-more .obf-pt-4 { animation-delay: 1s; }
@keyframes obf-line { 0%, 8% { stroke-dashoffset: 240; } 60%, 88% { stroke-dashoffset: 0; } 98%, 100% { stroke-dashoffset: 240; } }

.obf-settings .obf-gear { transform-origin: center; animation: obf-spin 7.2s linear infinite; }
.obf-settings .obf-knob { animation: obf-knob 3.6s ease infinite; }
.obf-settings .obf-toggle { animation: obf-toggle 3.6s ease infinite; }
.obf-settings .obf-knob-1, .obf-settings .obf-toggle-1 { animation-delay: 0.4s; }
.obf-settings .obf-knob-2, .obf-settings .obf-toggle-2 { animation-delay: 0.8s; }
@keyframes obf-spin { to { transform: rotate(360deg); } }
@keyframes obf-knob { 0%, 15% { transform: none; } 25%, 80% { transform: translateX(1rem); } 90%, 100% { transform: none; } }
@keyframes obf-toggle { 0%, 15% { fill: var(--surface3); } 25%, 80% { fill: var(--accent); } 90%, 100% { fill: var(--surface3); } }

@media (prefers-reduced-motion: reduce) {
  .obf, .obf * { animation: none !important; }
  .ob-overlay.is-sheet .ob-card { animation: none; }
}

/* Demo mode: the card is explaining a real window that is open behind it.
   The walkthrough's own backdrop and blur go away -- the point is that the
   student is looking at the actual screen, not a screenshot of it -- and the
   overlay stops swallowing clicks so the window underneath is live. The card
   itself stays interactive and steps aside to a corner, since modals centre
   themselves and the two would otherwise sit on top of each other. */
.ob-overlay.is-demo {
  background: none;
  -webkit-backdrop-filter: none; backdrop-filter: none;
  pointer-events: none;
  align-items: flex-end; justify-content: flex-start;
  padding: 1.25rem;
}
.ob-overlay.is-demo .ob-card {
  pointer-events: auto;
  width: min(23rem, 100%);
  max-height: min(30rem, calc(100dvh - 2.5rem));
  box-shadow: 0 1.5rem 3.75rem rgba(17,24,39,0.28), var(--shadow);
}
/* The figure is redundant when the real thing is on screen behind it. */
.ob-overlay.is-demo .ob-tour-figure { display: none; }
.ob-overlay.is-demo .ob-spot { display: none; }
/* On a phone there is no "beside": the card takes the bottom of the screen
   and the window it describes sits above it. */
@media (max-width: 768px) {
  .ob-overlay.is-demo { align-items: flex-end; justify-content: center; padding: 0.75rem; }
  .ob-overlay.is-demo .ob-card { width: 100%; max-height: 45dvh; }
}

@media (max-width: 768px) {
  .ob-overlay { padding: 0; }
  .ob-card {
    width: 100%; max-width: 100%; height: 100dvh; max-height: 100dvh;
    border: none; border-radius: 0;
  }
  .ob-body { padding: 1.25rem 1.125rem 1.5rem; }
  .ob-title { font-size: 1.3125rem; }
  .ob-row { flex-direction: column; gap: 0.75rem; }
  .ob-row.ob-row-keep { flex-direction: row; gap: 0.5rem; }
  .ob-choices.cols-2 { grid-template-columns: 1fr; }
  .ob-tour-figure { height: 7rem; }
  /* Thumb-reachable and unambiguous: the primary action fills the width it
     can, and Back keeps its corner. */
  .ob-foot { padding: 0.75rem 1.125rem calc(0.75rem + env(safe-area-inset-bottom)); }
  .ob-foot-right { flex: 1; justify-content: flex-end; }
  /* There is nowhere for a card to stand beside anything on a phone, so
     the spotlight never turns on here -- but if the viewport is resized
     across the breakpoint mid-tour, this puts the card back. */
  .ob-overlay.is-spotlight { display: flex; }
  .ob-overlay.is-spotlight .ob-card {
    position: static; width: 100%; max-height: 100dvh;
  }
}

/* ── Upgrade window ───────────────────────────────────────────────────────
   The paywall is a sales page a student lands on mid-task, so it has to
   answer three things without being read: why am I here, what can I have
   for nothing, and what do the two tiers cost. In that order down the
   card. */
.upgrade-reason {
  padding: 0.625rem 0.75rem; margin-bottom: 0.875rem;
  background: color-mix(in srgb, var(--amber) 12%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--amber) 38%, transparent);
  border-radius: var(--radius-md);
  font-size: 0.8125rem; line-height: 1.5; color: var(--text);
}
.upgrade-reason.hidden { display: none; }
.upgrade-lede { font-size: 0.8125rem; color: var(--text-muted); margin-bottom: 1rem; line-height: 1.55; }

/* The trial sits above the prices, because a free fortnight is a better
   answer to "not now" than a cheaper monthly rate. */
.upgrade-trial {
  display: flex; align-items: center; gap: 0.875rem;
  padding: 0.875rem; margin-bottom: 1rem;
  background: color-mix(in srgb, var(--accent) 9%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--accent) 34%, transparent);
  border-radius: var(--radius-md);
}
.upgrade-trial.hidden { display: none; }
.upgrade-trial-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.125rem; }
.upgrade-trial-text strong { font-size: 0.875rem; color: var(--text); }
.upgrade-trial-text span { font-size: 0.75rem; color: var(--text-muted); }

/* Same sliding pill as the theme and level pickers elsewhere, so the
   control reads as one the student has already used. */
.upgrade-period {
  position: relative; display: flex; gap: 0.25rem; margin-bottom: 1rem;
  padding: 0.1875rem; background: var(--surface2);
  border: 1px solid var(--border); border-radius: 62.4375rem;
}
.upgrade-period-pill {
  position: absolute; top: 0.1875rem; bottom: 0.1875rem;
  background: var(--surface); border-radius: 62.4375rem;
  box-shadow: var(--shadow-sm);
  transition: left 0.22s var(--ease, ease), width 0.22s var(--ease, ease);
}
.upgrade-period-opt {
  position: relative; z-index: 1; flex: 1;
  padding: 0.4375rem 0.625rem; border: none; background: none; cursor: pointer;
  font-family: inherit; font-size: 0.75rem; font-weight: 600;
  color: var(--text-muted); white-space: nowrap;
  transition: color 0.15s ease;
}
.upgrade-period-opt.active { color: var(--text); }
.plan-price-note { font-size: 0.6875rem; font-weight: 500; color: var(--text-muted); margin-top: 0.125rem; }

/* A running trial is a countdown, not a tier: amber rather than the paid
   badge's colour, so it never reads as something already bought. */
.user-plan.plan-trial {
  background: color-mix(in srgb, var(--amber) 22%, transparent);
  color: #F5C451;
}

@media (max-width: 768px) {
  .upgrade-trial { flex-direction: column; align-items: stretch; gap: 0.625rem; }
  .upgrade-period-opt { font-size: 0.6875rem; padding: 0.4375rem 0.375rem; }
}

/* ── The parent / tutor link, in Settings > Account ──────────────────────── */
/* A short list -- an account can have five of these at most -- so the rows
   are laid out to be read rather than scanned, with the one thing that
   matters (when it was last opened) on the second line. */
.share-list { display: flex; flex-direction: column; gap: 0.625rem; }
.share-empty { font-size: 0.8125rem; color: var(--text-dim); }
.share-row {
  display: flex; align-items: center; gap: 0.75rem;
  padding: 0.75rem 0.875rem; border-radius: 0.75rem;
  background: var(--surface); border: 1px solid var(--border);
}
.share-row-main { flex: 1; min-width: 0; }
.share-row-label { font-size: 0.8125rem; font-weight: 600; overflow-wrap: anywhere; }
.share-row-sub { font-size: 0.6875rem; color: var(--text-dim); margin-top: 0.125rem; }
.btn-ghost.btn-sm.share-revoke { flex-shrink: 0; color: var(--red); }

/* The URL is shown once, so it is shown whole -- wrapped over as many lines
   as it takes rather than truncated with an ellipsis a student might copy. */
.share-url-box {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.625rem 0.75rem; border-radius: 0.625rem;
  background: var(--surface); border: 1px solid var(--border);
}
.share-url {
  flex: 1; min-width: 0; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.75rem; line-height: 1.5; overflow-wrap: anywhere; user-select: all;
}

/* ── Exam seasons ───────────────────────────────────────────────────────── */
.es-intro { font-size: 0.8125rem; line-height: 1.6; color: var(--text-muted); margin: 0 0 1.5rem; }
.es-list { display: flex; flex-direction: column; gap: 0.625rem; margin-bottom: 1.5rem; }
.es-empty { font-size: 0.8125rem; color: var(--text-dim); }
.es-row {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.625rem 0.75rem; border-radius: 0.625rem;
  background: var(--surface); border: 1px solid var(--border);
}
.es-row-main { flex: 1; min-width: 0; }
.es-row-label { font-size: 0.8125rem; font-weight: 600; overflow-wrap: anywhere; }
.es-row-sub { font-size: 0.6875rem; color: var(--text-dim); margin-top: 0.125rem; }
.btn-ghost.btn-sm.es-delete { color: var(--red); flex-shrink: 0; }
.es-new { padding-top: 1.25rem; border-top: 1px solid var(--border); }

/* What the last plan did. The per-exam split is the part worth reading:
   it is where a student sees the plan disagreeing with them about which
   exam needs the most work, which is the whole point of weighting it. */
.es-result { margin-top: 1.5rem; padding-top: 1.25rem; border-top: 1px solid var(--border); }
.es-result-head { font-size: 0.8125rem; font-weight: 600; margin-bottom: 0.875rem; }
.es-result-row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 0.75rem; font-size: 0.75rem; padding: 0.4375rem 0;
}
.es-result-subject { color: var(--text); overflow-wrap: anywhere; }
.es-result-hours { color: var(--text-muted); flex-shrink: 0; font-variant-numeric: tabular-nums; }
.es-why { font-size: 0.75rem; line-height: 1.6; color: var(--text-muted); margin: 0.5rem 0 0; }

/* ── Syllabus and past papers ────────────────────────────────────────────── */
.mat-intro { font-size: 0.8125rem; line-height: 1.6; color: var(--text-muted); margin: 0 0 1.5rem; }
.mat-status { font-size: 0.75rem; margin-top: 0.5rem; min-height: 1rem; color: var(--text-muted); }
.mat-status.is-error { color: var(--red); }
.mat-status.is-ok { color: var(--accent); }
.mat-status.is-busy { color: var(--text-muted); }

/* The review list. Everything read is shown, ticked, and droppable — the
   student confirms what goes into their revision before any of it is kept. */
.mat-review { margin-top: 1.5rem; padding-top: 1.25rem; border-top: 1px solid var(--border); }
.mat-review-head { font-size: 0.8125rem; font-weight: 600; margin-bottom: 0.875rem; }
.mat-topics { max-height: 15rem; overflow-y: auto; display: flex; flex-direction: column; gap: 0.125rem; }
.mat-topic {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.3125rem 0.375rem; border-radius: 0.375rem; cursor: pointer; font-size: 0.8125rem;
}
.mat-topic:hover { background: var(--surface2); }
.mat-topic input { flex-shrink: 0; margin: 0; }
.mat-topic-name { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.mat-topic-unit { font-size: 0.6875rem; color: var(--text-dim); flex-shrink: 0; }

.mat-saved { margin-top: 1.5rem; display: flex; flex-direction: column; gap: 0.625rem; }
.mat-empty { font-size: 0.8125rem; color: var(--text-dim); }
.mat-row {
  display: flex; align-items: center; gap: 0.75rem;
  padding: 0.75rem 0.875rem; border-radius: 0.75rem;
  background: var(--surface); border: 1px solid var(--border);
}
.mat-row-main { flex: 1; min-width: 0; }
.mat-row-label { font-size: 0.8125rem; font-weight: 600; overflow-wrap: anywhere; }
.mat-row-sub { font-size: 0.6875rem; color: var(--text-dim); margin-top: 0.125rem; }
.btn-ghost.btn-sm.mat-delete { color: var(--red); flex-shrink: 0; }

/* The ranking. The reason beside each topic is the part that earns its
   place: a bare order tells a student nothing about why. */
.mat-ranked { margin-top: 1.5rem; padding-top: 1.25rem; border-top: 1px solid var(--border); }
.mat-ranked-head { font-size: 0.8125rem; font-weight: 600; margin-bottom: 0.875rem; }
.mat-rank-row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 0.75rem; font-size: 0.75rem; padding: 0.4375rem 0;
}
.mat-rank-name { overflow-wrap: anywhere; }
.mat-rank-why { color: var(--text-dim); flex-shrink: 0; font-size: 0.6875rem; }
/* Reading the ranking and acting on it are two things; space them. */
#mat-ranked .form-group { margin-top: 1.25rem; }

/* Auto-schedule strategy: top up vs rebuild. A segmented pair rather than a
   dropdown -- there are two, and which one is selected has to be readable
   at a glance before pressing Run. */
.sched-strategy { padding-top: 0.75rem; }
/* Same sliding track+pill as .view-tabs -- the pill rides underneath the
   labels; positionSchedStrategyPill() in app.js keeps it under whichever
   of the two is active, offsetLeft/offsetWidth so it glides the gap. */
.sched-strategy-row {
  position: relative;
  display: flex; gap: 0.25rem; padding: 0.1875rem; background: var(--surface2); border-radius: var(--radius-md);
}
.sched-strategy-pill {
  position: absolute; top: 0.1875rem; bottom: 0.1875rem; left: 0.1875rem; width: 0;
  background: var(--surface); border-radius: calc(var(--radius-md) - 0.1875rem);
  box-shadow: var(--shadow-sm);
  transition: left 0.26s var(--ease), width 0.26s var(--ease);
  z-index: 0;
}
.sched-strategy-btn {
  position: relative; z-index: 1;
  flex: 1; padding: 0.4375rem 0.5rem; font-size: 0.8125rem; font-weight: 600;
  color: var(--text-muted); background: none; border: 0;
  border-radius: calc(var(--radius-md) - 0.1875rem); cursor: pointer;
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.sched-strategy-btn:hover { color: var(--text); }
.sched-strategy-btn.is-active { background: none; color: var(--text); box-shadow: none; }

/* ── The Auto-Schedule sheet ────────────────────────────────────────────
   Settings for the button, not a form before each run: what it does, the
   hours of each day, what else counts. Grouped rows, iOS-settings style. */
.as-body { display: flex; flex-direction: column; gap: 1rem; }
.as-body .sched-section.as-first { border-top: none; padding-top: 0; }
.as-body .sched-note { text-align: left; }
.as-body .sched-note.is-warn { color: var(--red); }
.as-notes textarea { width: 100%; margin-top: 0.5rem; }
.as-row, .as-extra-row { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; }
.as-row-main { min-width: 0; }
.as-row-label { font-size: 0.875rem; font-weight: 600; color: var(--text); }
.as-row-sub { font-size: 0.75rem; color: var(--text-muted); line-height: 1.4; margin-top: 0.0625rem; }
#as-week { margin-top: 0.75rem; }
#as-week.is-off { margin-top: 0; }
.as-seg { display: flex; gap: 0.25rem; padding: 0.1875rem; background: var(--surface2); border-radius: var(--radius-md); margin-bottom: 0.75rem; }
.as-seg-btn {
  flex: 1; padding: 0.375rem 0.5rem; border: 0; border-radius: calc(var(--radius-md) - 0.1875rem);
  background: none; color: var(--text-muted); font: inherit; font-size: 0.75rem; font-weight: 600; cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.as-seg-btn.is-active { background: var(--surface); color: var(--text); box-shadow: var(--shadow-sm); }
.as-times { display: flex; align-items: center; gap: 0.5rem; }
.as-times.is-bad .as-time, .as-dayrow.is-bad .as-time { border-color: var(--red); }
.as-time { flex: 1; min-width: 0; font-variant-numeric: tabular-nums; }
.as-dash { color: var(--text-dim); flex-shrink: 0; }
.as-days { display: flex; gap: 0.3125rem; margin-top: 0.625rem; }
.as-day {
  flex: 1; min-width: 0; padding: 0.4375rem 0; border-radius: 62.4375rem;
  border: 1px solid var(--border); background: var(--surface); color: var(--text-muted);
  font: inherit; font-size: 0.75rem; font-weight: 600; cursor: pointer; text-transform: capitalize;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.as-day.is-on { background: var(--accent); border-color: var(--accent); color: #fff; }
:root[data-theme="dark"] .as-day.is-on { color: #14213D; }
.as-byday { display: flex; flex-direction: column; background: var(--surface2); border: 1px solid var(--border); border-radius: 0.75rem; overflow: hidden; }
.as-dayrow { display: flex; align-items: center; gap: 0.5rem; padding: 0.4375rem 0.625rem; min-height: 2.75rem; }
.as-dayrow + .as-dayrow { border-top: 1px solid var(--border); }
.as-dayrow .as-day { flex: 0 0 3.25rem; padding: 0.3125rem 0; }
.as-dayrow .as-time { padding-top: 0.3125rem; padding-bottom: 0.3125rem; }
.as-off-label { font-size: 0.75rem; color: var(--text-dim); }
.as-card { background: var(--surface2); border: 1px solid var(--border); border-radius: 0.75rem; }
.as-row-link {
  display: flex; flex-direction: column; align-items: flex-start; flex: 1; min-width: 0;
  padding: 0; border: 0; background: none; font: inherit; text-align: left; color: inherit; cursor: pointer;
}
.as-row-link:disabled { cursor: default; }
.as-row-link .as-row-label { display: inline-flex; align-items: center; gap: 0.25rem; }
.as-row-link svg { width: 0.75rem; height: 0.75rem; fill: none; stroke: var(--text-dim); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.as-row-link:hover:not(:disabled) .as-row-label { color: var(--primary); }
#as-windows-note { margin-top: 0.5rem; }
.as-extra-row { padding: 0.625rem 0.875rem; }
.as-extra-row + .as-extra-row { border-top: 1px solid var(--border); }
.as-done { width: 100%; }
/* Specific dates: a month, the day picked, its own hours or a day off. */
/* Under the hours, as quiet as a footnote. */
.as-dates-link {
  display: inline-flex; align-items: center; gap: 0.375rem; margin: 0.75rem 0 0 -0.25rem; padding: 0.25rem 0.375rem;
  border: 0; border-radius: 0.5rem; background: none; font: inherit; font-size: 0.75rem; font-weight: 600;
  color: var(--text-muted); cursor: pointer; transition: color 0.15s ease, background 0.15s ease;
}
.as-dates-link:hover { color: var(--text); background: var(--surface2); }
.as-dates-link svg { width: 0.8125rem; height: 0.8125rem; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.asd-cal { padding: 0.125rem 0 0.25rem; }
.asd-cal .qa-cal-nav:disabled { opacity: 0.35; cursor: default; background: none; }
.asd-day { position: relative; }
.asd-day:disabled { cursor: default; background: none; }
.asd-day.is-usual-off:not(.is-on) { color: var(--text-dim); }
/* Its own hours: a dot under the date. A day off: the date struck through. */
.asd-day.is-custom::after {
  content: ''; position: absolute; left: 50%; bottom: 0.1875rem; width: 0.25rem; height: 0.25rem;
  margin-left: -0.125rem; border-radius: 50%; background: var(--accent);
}
.asd-day.is-custom.is-on::after { background: #fff; }
.asd-day.is-off:not(.is-on) { color: var(--text-dim); text-decoration: line-through; text-decoration-thickness: 1.5px; }
.asd-hint { margin: 0.75rem 0 0; font-size: 0.8125rem; color: var(--text-muted); text-align: center; }
.asd-editor { margin-top: 0.875rem; padding-top: 0.875rem; border-top: 1px solid var(--border); }
.asd-date { font-size: 0.9375rem; font-weight: 650; color: var(--text); margin-bottom: 0.625rem; }
.asd-date::first-letter { text-transform: uppercase; }
.asd-usual { font-size: 0.8125rem; color: var(--text-muted); padding: 0.125rem 0.125rem 0; }
.asd-list-title { margin: 1.125rem 0 0.375rem; font-size: 0.6875rem; font-weight: 650; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-dim); }
.asd-list { background: var(--surface2); border: 1px solid var(--border); border-radius: 0.75rem; overflow: hidden; }
.asd-item { display: flex; align-items: center; }
.asd-item + .asd-item { border-top: 1px solid var(--border); }
.asd-item-main {
  flex: 1; min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
  padding: 0.5625rem 0.25rem 0.5625rem 0.875rem; border: 0; background: none; font: inherit; color: inherit; cursor: pointer; text-align: left;
}
.asd-item-date { font-size: 0.8125rem; font-weight: 600; color: var(--text); }
.asd-item-date::first-letter { text-transform: uppercase; }
.asd-item-val { font-size: 0.8125rem; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.asd-item-val.is-off { color: var(--text-dim); }
.asd-item-x {
  flex: none; width: 2.25rem; height: 2.25rem; margin-right: 0.25rem; border: 0; border-radius: 50%;
  background: none; color: var(--text-dim); display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
}
.asd-item-x:hover { background: var(--surface3); color: var(--text); }

/* Dragging an assignment onto the calendar. Pointer-based (the app blocks
   native drag-and-drop), so the ghost and the preview are drawn by hand. */
.academic-chip.is-dragging { opacity: 0.4; }
body.chip-dragging { cursor: grabbing; user-select: none; }
body.chip-dragging .academic-chip { cursor: grabbing; }
.chip-drag-ghost {
  position: fixed; top: 0; left: 0; z-index: 2000; pointer-events: none;
  max-width: 13rem; padding: 0.375rem 0.625rem;
  font-size: 0.75rem; font-weight: 600; color: #fff;
  background: var(--primary); border-radius: var(--radius-sm);
  box-shadow: var(--shadow); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Same shape as the calendar's own drag selection, in the accent colour, so
   the preview reads as "this is where it will go" rather than as an event
   that already exists. */
.chip-drop-preview, .chip-drop-held {
  background: color-mix(in srgb, var(--accent) 22%, transparent) !important;
  border: 1.5px dashed var(--accent) !important;
  color: var(--accent-dim) !important;
  pointer-events: none;
}
.month-cell.chip-drop-target { outline: 0.125rem dashed var(--accent); outline-offset: -0.125rem; }

/* The whole header turns into a drop zone while a chip is being dragged:
   slide it up there to fit it into free time rather than to a set slot.
   Same green felt as the Auto-Schedule button, so it reads as that action. */
.chip-fit-drop {
  position: fixed; top: 0; left: 0; right: 0; z-index: 1900;
  display: flex; align-items: center; justify-content: center; gap: 0.5rem;
  min-height: 4.25rem;
  background: linear-gradient(135deg, rgba(42,157,143,0.92), rgba(34,129,118,0.92));
  border-bottom: 1px solid rgba(42,157,143,0.5);
  color: #fff; font-size: 0.9375rem; font-weight: 700; font-family: var(--font);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.25), 0 0.25rem 1.125rem rgba(42,157,143,0.35);
  -webkit-backdrop-filter: blur(0.75rem) saturate(160%);
  backdrop-filter: blur(0.75rem) saturate(160%);
  opacity: 0; transform: translateY(-100%);
  transition: opacity 0.18s ease, transform 0.18s ease;
  pointer-events: none;
  -webkit-user-select: none; user-select: none;
}
.chip-fit-drop svg { width: 1.125rem; height: 1.125rem; flex-shrink: 0; }
body.chip-dragging .chip-fit-drop { opacity: 1; transform: translateY(0); pointer-events: auto; }
body.chip-dragging .chip-fit-drop.is-over {
  background: linear-gradient(135deg, rgba(34,129,118,1), rgba(27,103,94,1));
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.3), 0 0.25rem 1.5rem rgba(42,157,143,0.5);
}

/* Full-screen loader for the drop itself -- placing is the slow part (and
   the reason dragging used to feel like it was doing nothing). */
.chip-drop-loading {
  position: fixed; inset: 0; z-index: 2100;
  display: flex; align-items: center; justify-content: center;
  background: rgba(13, 17, 23, 0.6);
}
.chip-drop-loading-inner {
  display: flex; align-items: center; gap: 0.75rem;
  padding: 1rem 1.5rem;
  background: var(--surface); border-radius: var(--radius);
  box-shadow: var(--shadow);
  color: var(--text); font-size: 0.875rem; font-weight: 600; font-family: var(--font);
  border: 0.125rem solid var(--amber);
}
.chip-drop-loading .spinner { color: var(--accent); }

/* Auto-Schedule as a split button: the bolt runs a top-up in the usual
   hours straight away; the chevron opens the full sheet. */
.generate-split { display: flex; align-items: stretch; margin-left: auto; border-radius: var(--radius); }
.generate-split .generate-btn { margin-left: 0; border-top-right-radius: 0; border-bottom-right-radius: 0; border-right-width: 0; }
.generate-more {
  display: grid; place-items: center; width: 1.75rem; height: auto; padding: 0; cursor: pointer;
  color: #fff; font-family: var(--font);
  background: linear-gradient(135deg, rgba(38,145,132,0.9), rgba(30,118,108,0.9));
  border: 1px solid rgba(42,157,143,0.35); border-left: 1px solid rgba(255,255,255,0.28);
  border-radius: 0 var(--radius) var(--radius) 0;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.22), 0 0.125rem 0.625rem rgba(42,157,143,0.18);
  -webkit-backdrop-filter: blur(0.75rem) saturate(160%); backdrop-filter: blur(0.75rem) saturate(160%);
  transition: background 0.15s, transform 0.15s;
}
.generate-btn.is-busy { justify-content: center; overflow: hidden; }
.generate-btn.is-busy .spinner { flex-shrink: 0; width: 0.875rem; height: 0.875rem; border-color: rgba(255,255,255,0.35); border-top-color: #fff; }
.generate-btn.is-busy .generate-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.generate-more svg { width: 0.875rem; height: 0.875rem; transition: transform 0.2s ease; }
.generate-more:hover { background: linear-gradient(135deg, rgba(42,157,143,1), rgba(34,129,118,1)); }
.generate-more:hover svg { transform: translateY(1px); }
.generate-more:active { transform: translateY(1px); }
.generate-more:disabled, .generate-split .generate-btn:disabled { opacity: 0.6; cursor: default; }
.topbar.tb-5 .generate-more { width: 1.5rem; }

/* ── The topbar at any width ─────────────────────────────────────────────
   The topbar's room depends on more than the window (the sidebar, Chrono's
   panel and Study Mode's panel all take from it) and its content on more
   than the layout (the language, which buttons are showing). So instead of
   guessing breakpoints, fitTopbar() in app.js measures it and adds these
   stages one at a time until everything sits on one row: labels become
   icons, then Today and Chrono's label go, then the view tabs tighten and
   turn to initials, then the buttons themselves get smaller. Nothing in it
   ever shrinks below its own size -- a squeezed button is an egg. */
.topbar { flex-wrap: wrap; row-gap: 0.5rem; }
.topbar > * { flex-shrink: 0; }
/* Whatever Quick Ask's bar sits on top of steps aside while it is open
   (worked out in JS from where the bar really lands -- markUnderQuickBar). */
.topbar > .under-quick { opacity: 0 !important; pointer-events: none; transition: opacity 0.15s ease; }

.topbar.tb-1 .generate-label, .topbar.tb-1 #btn-add-event span, .topbar.tb-1 .undo-label { display: none; }
.topbar.tb-1 #btn-generate, .topbar.tb-1 #btn-add-event { width: 2.5rem; padding: 0; justify-content: center; }
.topbar.tb-2 .today-btn { display: none; }
.topbar.tb-2 .chrono-topbar-btn { padding: 0.25rem; gap: 0; min-width: 2.25rem; justify-content: center; }
.topbar.tb-2 .chrono-topbar-btn span.chrono-label { display: none; }
.topbar.tb-3 .view-tab { padding: 0.375rem 0.5625rem; font-size: 0.75rem; }
.topbar.tb-4 .view-tab[data-short] { font-size: 0; padding: 0.375rem 0.5625rem; }
.topbar.tb-4 .view-tab[data-short]::after { content: attr(data-short); font-size: 0.75rem; }
.topbar.tb-5 #btn-generate, .topbar.tb-5 #btn-add-event, .topbar.tb-5 .study-mode-btn { width: 2.125rem; height: 2rem; }
.topbar.tb-5 .nav-arrow { width: 1.5rem; }
.topbar.tb-5 { gap: 0.375rem; padding-left: 0.625rem; padding-right: 0.625rem; }
.topbar.tb-6 { gap: 0.25rem; padding-left: 0.5rem; padding-right: 0.5rem; }
.topbar.tb-6 .view-tab[data-short] { padding: 0.375rem 0.4375rem; }

/* ── Side panels on mid-size windows ─────────────────────────────────────
   Chrono's panel and Study Mode's panel sit beside the calendar when there
   is room for both. Below ~1150px, docking one next to the sidebar leaves
   the calendar (and its header) under ~550px -- a calendar you can't read
   and a header that can't hold its buttons. There they float over the
   calendar instead, as they already do on phones, at their own width. */
@media (min-width: 769px) and (max-width: 1150px) {
  .zeno-panel, .study-panel {
    position: fixed; top: 0; right: 0; bottom: 0; z-index: 300;
    flex: none; transition: transform 0.25s ease; transform: translateX(100%);
  }
  .zeno-panel { width: var(--zeno-w, 21.25rem); }
  .study-panel { width: var(--study-w, 18.75rem); }
  :is(#screen-app, #ng-app, #cp-app).chrono-open .zeno-panel,
  #screen-app.study-open .study-panel { transform: translateX(0); }
  :is(#screen-app, #ng-app, #cp-app).chrono-open .zeno-panel-inner,
  #screen-app.study-open .study-panel-inner { box-shadow: -0.5rem 0 2rem rgba(0,0,0,0.14); }
  #chrono-backdrop, #study-backdrop, #ng-chrono-backdrop, #cp-chrono-backdrop {
    display: block; opacity: 0; pointer-events: none; transition: opacity 0.25s ease;
    background: rgba(17,24,39,0.18);
  }
  #screen-app.chrono-open #chrono-backdrop, #ng-app.chrono-open #ng-chrono-backdrop, #cp-app.chrono-open #cp-chrono-backdrop,
  #screen-app.study-open #study-backdrop { opacity: 1; pointer-events: auto; }
  #resize-zeno, #ng-resize-zeno, #cp-resize-zeno { display: none; }
}

/* ── Study Mode and Chrono, full screen ───────────────────────────────────
   The panel takes the main area, under the topbar, beside the sidebar --
   the place a view has -- so the header keeps working and the Plan /
   Calendar switch is still where it always is. Switching views, closing
   the panel or Esc puts it back at the side. Desktop and tablet only: on
   a phone the panels are full screen already. */
.panel-max-btn .pm-shrink { display: none; }
/* Full screen is not a destructive action: white glass, not the red of close. */
.zeno-close.panel-max-btn {
  background: linear-gradient(160deg, rgba(255,255,255,0.95), rgba(244,245,247,0.88));
  border: 1px solid var(--border); color: var(--text-muted);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.9), 0 0.125rem 0.5rem rgba(15,26,46,0.08);
}
.zeno-close.panel-max-btn:hover {
  background: #fff; color: var(--text);
  box-shadow: inset 0 1px 0 #fff, 0 0.25rem 0.75rem rgba(15,26,46,0.14);
}
:root[data-theme="dark"] .zeno-close.panel-max-btn {
  background: linear-gradient(160deg, rgba(255,255,255,0.16), rgba(255,255,255,0.08));
  border-color: rgba(255,255,255,0.18); color: rgba(255,255,255,0.85);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.18), 0 0.125rem 0.5rem rgba(0,0,0,0.25);
}
:root[data-theme="dark"] .zeno-close.panel-max-btn:hover { background: rgba(255,255,255,0.24); color: #fff; }
#screen-app.study-max #study-max .pm-expand,
:is(#screen-app, #ng-app, #cp-app).chrono-max .zeno-panel .panel-max-btn .pm-expand { display: none; }
#screen-app.study-max #study-max .pm-shrink,
:is(#screen-app, #ng-app, #cp-app).chrono-max .zeno-panel .panel-max-btn .pm-shrink { display: block; }
.study-header-actions { display: flex; align-items: center; gap: 0.375rem; flex-shrink: 0; }
@media (max-width: 768px) { .panel-max-btn { display: none !important; } }

#screen-app.study-max .study-panel,
:is(#screen-app, #ng-app, #cp-app).chrono-max .zeno-panel {
  position: fixed; z-index: 25; flex: none; transform: none; transition: none;
  top: var(--panel-max-top, 3.5rem); left: var(--panel-max-left, 16rem); right: 0; bottom: 0;
  width: auto;
}
#screen-app.study-max .main > :not(.topbar):not(.mode-dock),
:is(#screen-app, #ng-app, #cp-app).chrono-max .main > :not(.topbar):not(.mode-dock),
:is(#ng-app, #cp-app).chrono-max .ng-content > :not(header) { visibility: hidden; }
#screen-app.study-max #study-backdrop,
:is(#screen-app, #ng-app, #cp-app).chrono-max .chrono-backdrop { display: none; }
#screen-app.study-max .study-panel-inner,
:is(#screen-app, #ng-app, #cp-app).chrono-max .zeno-panel-inner { border-left: none; box-shadow: none; }
/* Chrono full screen goes over Study Mode too -- which stays open behind it,
   just as it was, for when Chrono is made small again. */
#screen-app.chrono-max .zeno-panel { z-index: 40; }
#screen-app.chrono-max .study-panel { visibility: hidden; }

/* Study Mode: the same panel, just bigger -- its content in a readable
   column down the middle, the header across the top. */
#screen-app.study-max .study-panel-inner > :not(.study-header) {
  width: min(42rem, 100% - 2rem); margin-left: auto; margin-right: auto;
}
/* The minimized timer is a band under the header, edge to edge like the
   header itself; only what is in it lines up with the column. */
#screen-app.study-max .study-panel-inner > .study-timer:has(> .study-timer-collapsed:not(.hidden)) {
  width: 100%; margin-left: 0; margin-right: 0;
}
#screen-app.study-max .study-timer-collapsed {
  width: 100%; margin-left: 0; margin-right: 0;
  padding-left: max(1.25rem, calc((100% - 42rem) / 2));
  padding-right: max(1.25rem, calc((100% - 42rem) / 2));
}

/* Chrono full screen: a chat, as in a messaging app -- a readable column
   down the middle, the student's bubbles on its right and Chrono's on its
   left, each as wide as what it says (never the whole column). */
:is(#screen-app, #ng-app, #cp-app).chrono-max .zeno-messages {
  padding-left: max(1.25rem, calc((100% - 48rem) / 2));
  padding-right: max(1.25rem, calc((100% - 48rem) / 2));
}
:is(#screen-app, #ng-app, #cp-app).chrono-max .zeno-msg { max-width: min(78%, 40rem); }
:is(#screen-app, #ng-app, #cp-app).chrono-max .zeno-msg-user { max-width: min(70%, 32rem); }
:is(#screen-app, #ng-app, #cp-app).chrono-max .zeno-input-row,
:is(#screen-app, #ng-app, #cp-app).chrono-max .zeno-image-strip {
  width: 100%; max-width: 48rem; margin-left: auto; margin-right: auto;
}

/* A drop that only partly fits before a class: amber, labelled "30 of
   90 min". Dropped onto a class: red, and refused. */
.chip-drop-preview.is-partial {
  background: color-mix(in srgb, var(--amber) 20%, transparent) !important;
  border-color: var(--amber) !important;
  color: color-mix(in srgb, var(--amber) 70%, var(--text)) !important;
}
.chip-drop-preview.is-busy {
  background: color-mix(in srgb, var(--red) 12%, transparent) !important;
  border-color: var(--red) !important;
  color: var(--red) !important;
}

.chip-drop-preview.is-partial { overflow: hidden; line-height: 1.2; }
.chip-drop-preview .cdp-time, .chip-drop-preview .cdp-sub, .chip-drop-held .cdp-time { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chip-drop-preview .cdp-sub { font-size: 0.6875rem; font-weight: 600; opacity: .85; }

/* ── Ticking off ─────────────────────────────────────────────────────────
   The check lands (a small pop), the row stays a moment, then folds away
   while a tick flies to Done. */
.plan-row.is-completing .plan-title { text-decoration: line-through; text-decoration-color: color-mix(in srgb, var(--text-dim) 70%, transparent); }
@keyframes check-pop { 0% { transform: scale(.8); } 50% { transform: scale(1.18); } 100% { transform: scale(1); } }
/* The checkmark, everywhere something is ticked off: the mark inside the
   circle bounces (tickAnim in itemview.js adds .tick-anim for one run, so a
   list re-rendered with things already done stays still). The circle
   itself does not move. */
@keyframes tick-bounce { 0% { transform: scale(0.4); } 45% { transform: scale(1.35); } 70% { transform: scale(0.88); } 85% { transform: scale(1.06); } 100% { transform: scale(1); } }
.tick-anim > svg:not(:has(circle)), .tick-anim > svg:has(circle) path:last-of-type, .tick-anim::before { animation: tick-bounce .5s cubic-bezier(.3, 1.4, .5, 1); transform-origin: center; transform-box: fill-box; }
.plan-row.is-completing .plan-check svg { animation: tick-bounce .5s cubic-bezier(.3, 1.4, .5, 1); }
.plan-row.is-leaving {
  height: 0 !important; opacity: 0; transform: translateX(0.75rem);
  transition: height .34s cubic-bezier(.4, 0, .2, 1), opacity .24s ease, transform .3s ease;
}
.fly-check {
  position: fixed; z-index: 3000; width: 1.375rem; height: 1.375rem; border-radius: 50%; pointer-events: none;
  display: grid; place-items: center;
  background: var(--fly, var(--accent)); box-shadow: 0 0.25rem 0.875rem rgba(15,26,46,0.22);
}
.fly-check svg { width: 0.8125rem; height: 0.8125rem; }

/* Study Mode: a ticked task stays a moment, then folds into Done. */
.study-task-row.is-completing .study-task-text { color: var(--text-dim); text-decoration: line-through; text-decoration-color: rgba(127,127,127,.7); }
.study-task-row.is-leaving {
  height: 0 !important; min-height: 0; margin-top: 0 !important; margin-bottom: -0.375rem !important;
  padding-top: 0; padding-bottom: 0; border-width: 0; opacity: 0; transform: translateX(0.75rem); overflow: hidden;
  transition: height .32s cubic-bezier(.4, 0, .2, 1), padding .32s ease, margin .32s ease, opacity .22s ease, transform .3s ease;
}
.study-task-row.is-arriving { animation: study-arrive .36s cubic-bezier(.2, 1.1, .4, 1); }
@keyframes study-arrive { from { opacity: 0; transform: translateY(0.375rem) scale(.98); } }
/* Done, and in a stage, Other tasks: folds side by side above the list. */
.study-folds { margin-bottom: 0.25rem; }
.study-folds.is-open { margin-bottom: 0.5rem; padding-bottom: 0.5rem; border-bottom: 1px solid var(--border); }
.study-folds-bar { display: flex; flex-wrap: wrap; gap: 0.375rem; }
.study-fold-toggle {
  display: inline-flex; align-items: center; gap: 0.375rem;
  padding: 0.3125rem 0.6875rem 0.3125rem 0.5625rem; border-radius: 62.4375rem; border: 0;
  background: color-mix(in srgb, var(--text) 5%, transparent); color: var(--text-muted); cursor: pointer;
  font: 600 0.75rem/1.2 var(--font); transition: background .15s ease, color .15s ease;
}
.study-fold-toggle .done-report-icon { color: var(--red); width: 0.875rem; height: 0.875rem; }
.study-fold-toggle .study-other-icon { color: var(--text-dim); }
.study-fold-toggle:hover, .study-fold-toggle.is-open { background: color-mix(in srgb, var(--text) 9%, transparent); color: var(--text); }
.study-fold-count {
  min-width: 1.125rem; padding: 0 0.3125rem; border-radius: 62.4375rem; background: var(--surface2);
  color: var(--text-muted); font-size: 0.6875rem; line-height: 1.125rem; text-align: center;
  font-variant-numeric: tabular-nums;
}
.study-fold-toggle:hover .study-fold-count, .study-fold-toggle.is-open .study-fold-count { background: var(--surface); }
.study-done-chevron { transition: transform .2s ease; }
.study-fold-toggle.is-open .study-done-chevron { transform: rotate(180deg); }
.study-done-list { display: flex; flex-direction: column; gap: 0.375rem; margin-top: 0.5rem; }
.study-done-list + .study-done-list { padding-top: 0.5rem; border-top: 1px solid var(--border); }
.study-done-list .study-task-row.done { opacity: .8; }
@media (prefers-reduced-motion: reduce) {
  .plan-row.is-completing .plan-check, .study-task-row.is-arriving { animation: none; }
  .tick-anim > svg, .tick-anim::before, .tick-anim svg path, .plan-row.is-completing .plan-check svg { animation: none; }
}

/* ── Rich answers (md.js) ────────────────────────────────────────────────
   What Chrono can write beyond paragraphs and lists: tables, code, task
   lists, callouts, highlights -- and charts. Scoped to message bubbles
   (.zeno-msg) and anything else rendering markdown with .md-rich. */
.zeno-msg { white-space: normal; }
.zeno-msg p, .zeno-msg li { white-space: pre-wrap; }
.zeno-msg strong { font-weight: 650; }
.zeno-msg mark, .md-rich mark {
  background: linear-gradient(transparent 55%, color-mix(in srgb, #F5C542 55%, transparent) 55%);
  color: inherit; padding: 0 0.0625rem;
}
.zeno-msg hr { border: 0; border-top: 1px solid color-mix(in srgb, currentColor 16%, transparent); margin: 0.75rem 0; }
.zeno-msg a { color: inherit; text-decoration: underline; text-decoration-color: color-mix(in srgb, currentColor 40%, transparent); text-underline-offset: 0.125rem; }
.zeno-msg code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.8125em;
  padding: 0.0625rem 0.3125rem; border-radius: 0.3125rem; background: color-mix(in srgb, currentColor 9%, transparent);
}
.zeno-msg pre.md-code {
  position: relative; margin: 0.5rem 0 0; padding: 0.75rem 0.875rem; border-radius: 0.625rem; overflow-x: auto;
  background: #1d1a14; color: #f3ead7; font-size: 0.8125rem; line-height: 1.5; white-space: pre;
}
.zeno-msg pre.md-code code { background: none; padding: 0; font-size: inherit; color: inherit; }
.zeno-msg pre.md-code[data-lang]::before {
  content: attr(data-lang); position: absolute; top: 0.3125rem; right: 0.5rem;
  font: 600 0.625rem/1 var(--font); letter-spacing: 0.04em; text-transform: uppercase; opacity: .55;
}
.zeno-msg blockquote {
  margin: 0.5rem 0 0; padding: 0.125rem 0 0.125rem 0.75rem;
  border-left: 0.1875rem solid color-mix(in srgb, currentColor 22%, transparent); opacity: .92;
}
.md-table { margin: 0.5rem 0 0; overflow-x: auto; border-radius: 0.625rem; border: 1px solid color-mix(in srgb, currentColor 12%, transparent); }
.md-table table { width: 100%; border-collapse: collapse; font-size: 0.8125rem; font-variant-numeric: tabular-nums; }
.md-table th, .md-table td { padding: 0.4375rem 0.625rem; text-align: left; border-top: 1px solid color-mix(in srgb, currentColor 9%, transparent); white-space: nowrap; }
.md-table thead th { border-top: 0; font-weight: 650; background: color-mix(in srgb, currentColor 5%, transparent); }
.md-table tbody tr:hover td { background: color-mix(in srgb, currentColor 4%, transparent); }
ul.md-tasks { list-style: none; padding-left: 0.125rem; }
.md-task { display: flex; align-items: flex-start; gap: 0.5rem; }
.md-box {
  flex-shrink: 0; width: 0.9375rem; height: 0.9375rem; margin-top: 0.1875rem; border-radius: 0.3125rem;
  border: 1.5px solid color-mix(in srgb, currentColor 40%, transparent);
}
.md-task.is-done .md-box { background: var(--accent, #2a9d8f); border-color: transparent; position: relative; }
.md-task.is-done .md-box::after {
  content: ''; position: absolute; inset: 0; background: #fff;
  clip-path: polygon(22% 50%, 12% 61%, 42% 88%, 90% 28%, 79% 18%, 41% 66%);
}
.md-task.is-done { opacity: .6; text-decoration: line-through; }

/* Callouts: "> [!TIP]" and friends. */
.md-callout {
  --cl: #2a78d6;
  margin: 0.5rem 0 0; padding: 0.5625rem 0.75rem 0.625rem; border-radius: 0.625rem;
  background: color-mix(in srgb, var(--cl) 9%, transparent);
  border: 1px solid color-mix(in srgb, var(--cl) 22%, transparent);
}
.md-callout.md-tip { --cl: #1baf7a; }
.md-callout.md-important { --cl: #4a3aa7; }
.md-callout.md-warning { --cl: #d98a00; }
.md-callout-title { display: flex; align-items: center; gap: 0.375rem; font-weight: 700; font-size: 0.8125rem; margin-bottom: 0.1875rem; }
.md-callout-icon { width: 0.875rem; height: 0.875rem; border-radius: 50%; background: var(--cl); flex-shrink: 0; position: relative; }
.md-callout-icon::after { content: 'i'; position: absolute; inset: 0; display: grid; place-items: center; color: #fff; font: 700 0.5625rem/1 var(--font); }
.md-tip .md-callout-icon::after { content: '✓'; }
.md-warning .md-callout-icon::after, .md-important .md-callout-icon::after { content: '!'; }
.md-callout > :last-child { margin-bottom: 0; }

/* Charts. The categorical slots in fixed order; dark mode has its own steps. */
.md-chart {
  --c1: #2a78d6; --c2: #eb6834; --c3: #1baf7a; --c4: #eda100;
  --c5: #e87ba4; --c6: #008300; --c7: #4a3aa7; --c8: #e34948;
  --md-surface: #FEF9EC; --md-grid: color-mix(in srgb, currentColor 12%, transparent);
  margin: 0.625rem 0 0; padding: 0.75rem 0.75rem 0.5rem; border-radius: 0.75rem;
  background: color-mix(in srgb, #fff 55%, transparent);
  border: 1px solid color-mix(in srgb, currentColor 10%, transparent);
  white-space: normal;
}
:root[data-theme="dark"] .md-chart {
  --c1: #3987e5; --c2: #d95926; --c3: #199e70; --c4: #c98500;
  --c5: #d55181; --c6: #008300; --c7: #9085e9; --c8: #e66767;
  --md-surface: #1f1c16; background: color-mix(in srgb, #000 18%, transparent);
}
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) .md-chart {
    --c1: #3987e5; --c2: #d95926; --c3: #199e70; --c4: #c98500;
    --c5: #d55181; --c6: #008300; --c7: #9085e9; --c8: #e66767;
    --md-surface: #1f1c16;
  }
}
.md-chart .s1 { --c: var(--c1); } .md-chart .s2 { --c: var(--c2); } .md-chart .s3 { --c: var(--c3); } .md-chart .s4 { --c: var(--c4); }
.md-chart .s5 { --c: var(--c5); } .md-chart .s6 { --c: var(--c6); } .md-chart .s7 { --c: var(--c7); } .md-chart .s8 { --c: var(--c8); }
.md-chart-title { font-size: 0.8125rem; font-weight: 700; margin: 0 0 0.5rem; }
.md-legend { display: flex; flex-wrap: wrap; gap: 0.25rem 0.75rem; margin-top: 0.5rem; font-size: 0.75rem; opacity: .9; }
.md-legend-item { display: inline-flex; align-items: center; gap: 0.3125rem; }
.md-legend-item b { font-weight: 650; font-variant-numeric: tabular-nums; }
.md-sw { width: 0.625rem; height: 0.625rem; border-radius: 0.1875rem; background: var(--c); display: inline-block; }
.md-chart-data { margin-top: 0.375rem; font-size: 0.75rem; }
.md-chart-data summary { cursor: pointer; opacity: .6; width: max-content; list-style: none; }
.md-chart-data summary::-webkit-details-marker { display: none; }
.md-chart-data summary::before { content: '▸ '; }
.md-chart-data[open] summary::before { content: '▾ '; }

/* Horizontal bars and progress rows. */
.md-hbars { position: relative; display: flex; flex-direction: column; gap: 0.4375rem; }
.md-hbar-row { display: grid; grid-template-columns: minmax(3.5rem, 28%) 1fr; align-items: center; gap: 0.5rem; }
.md-hbar-label { font-size: 0.75rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; opacity: .85; }
.md-hbar-bars { display: flex; flex-direction: column; gap: 0.125rem; }
.md-hbar-track { --vw: 3rem; display: flex; align-items: center; gap: 0.375rem; min-width: 0; }
.md-hbar-track.is-progress { --vw: 4.5rem; position: relative; }
.md-hbar-track.is-progress::before {
  content: ''; position: absolute; left: 0; right: var(--vw); height: 0.625rem; border-radius: 0 0.25rem 0.25rem 0;
  background: var(--md-grid);
}
.md-hbar {
  position: relative; flex: none; height: 0.625rem; width: calc((100% - var(--vw)) * var(--f, 0)); min-width: 0.125rem;
  background: var(--c); border-radius: 0 0.25rem 0.25rem 0;
  animation: md-grow .7s cubic-bezier(.2, .8, .2, 1) both; animation-delay: var(--d, 0ms);
}
.md-hbar-val { font-size: 0.6875rem; font-weight: 600; font-variant-numeric: tabular-nums; opacity: .85; white-space: nowrap; }
.md-hbar-track { position: relative; }
.md-hbar-tgt {
  position: absolute; top: -0.125rem; bottom: -0.125rem; width: 0; left: calc((100% - var(--vw)) * var(--x));
  border-left: 1px dashed color-mix(in srgb, currentColor 55%, transparent); z-index: 1; pointer-events: none;
}
.md-chart-note { display: flex; align-items: center; gap: 0.375rem; margin-top: 0.4375rem; font-size: 0.6875rem; opacity: .75; }
.md-tgt-key { width: 0; height: 0.75rem; border-left: 1px dashed currentColor; display: inline-block; }
@keyframes md-grow { from { width: 0; } }

/* Columns, lines, donut. */
.md-plot { display: block; width: 100%; height: auto; overflow: visible; }
.md-grid { stroke: var(--md-grid); stroke-width: 1; }
.md-target { stroke: currentColor; stroke-opacity: .45; stroke-width: 1; stroke-dasharray: 3 3; }
.md-tick, .md-end { fill: currentColor; font: 500 0.5625rem var(--font); opacity: .65; }
.md-end { font-weight: 700; opacity: .9; }
.md-col {
  fill: var(--c); transform-box: fill-box; transform-origin: 50% 100%;
  animation: md-rise-col .6s cubic-bezier(.2, .8, .2, 1) both; animation-delay: var(--d, 0ms);
  transition: opacity .15s ease;
}
.md-plot:hover .md-col:not(:hover) { opacity: .55; }
@keyframes md-rise-col { from { transform: scaleY(0); } }
.md-line { fill: none; stroke: var(--c); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1; animation: md-draw 1s cubic-bezier(.4, 0, .2, 1) both; }
@keyframes md-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
.md-area { fill: var(--c); opacity: .1; animation: md-fade .8s ease .3s both; }
.md-dot {
  fill: var(--c); stroke: var(--md-surface); stroke-width: 2; transform-box: fill-box; transform-origin: center;
  animation: md-pop .35s cubic-bezier(.3, 1.6, .5, 1) both; animation-delay: var(--d, 0ms); cursor: default;
}
.md-dot:hover { r: 5.5; }
@keyframes md-pop { from { transform: scale(0); } }
@keyframes md-fade { from { opacity: 0; } }
.md-donut-wrap { display: flex; justify-content: center; }
.md-donut { width: 9rem; height: 9rem; }
.md-seg { fill: none; stroke: var(--c); stroke-width: 14; animation: md-fade .6s ease both; animation-delay: var(--d, 0ms); transition: stroke-width .15s ease; }
.md-seg:hover { stroke-width: 17; }
.md-donut-total { fill: currentColor; font: 700 0.8125rem var(--font); }

/* A new answer comes in block by block rather than all at once. */
.md-anim > * { animation: md-in .42s cubic-bezier(.2, .8, .2, 1) both; animation-delay: calc(min(var(--i, 0), 12) * 60ms); }
@keyframes md-in { from { opacity: 0; transform: translateY(0.375rem); } }
.zeno-msg-assistant.is-new { animation: md-bubble .32s cubic-bezier(.2, 1.1, .4, 1) both; }
@keyframes md-bubble { from { opacity: 0; transform: translateY(0.5rem) scale(.985); } }
@media (prefers-reduced-motion: reduce) {
  .md-anim > *, .zeno-msg-assistant.is-new, .md-hbar, .md-col, .md-line, .md-area, .md-dot, .md-seg { animation: none !important; }
}

/* Chrono is thinking: its gold warms a little towards amber and breathes
   slowly -- a calm "working on it", not an alarm. Same in the topbar
   (Quick Ask) and in the panel's header. */
.chrono-topbar-btn.is-thinking::before {
  background: radial-gradient(circle at 35% 30%, #FFF7E6 0%, #FCD9A0 40%, #E8A34A 72%, rgba(200,130,40,0) 100%);
  box-shadow: inset 0 -1px 0.125rem rgba(140,85,20,0.25), 0 0 0.625rem rgba(232,163,74,0.4);
  animation: orbThink 2.2s ease-in-out infinite;
}
#zeno-panel.is-thinking .zeno-orb, .zeno-panel.is-thinking .zeno-orb {
  background: radial-gradient(circle at 35% 30%, #FFF7E6 0%, #FCD9A0 36%, #E8A34A 60%, #8F5A14 84%, rgba(143,90,20,0) 100%);
  animation: orbThink 2.2s ease-in-out infinite;
  filter: drop-shadow(0 0 0.25rem rgba(232,163,74,0.35));
}
#zeno-panel.is-thinking .zeno-orb-ring, .zeno-panel.is-thinking .zeno-orb-ring { border-color: rgba(232,163,74,0.3); animation-duration: 3.4s; }
#zeno-panel.is-thinking .zeno-orb-ring::before, .zeno-panel.is-thinking .zeno-orb-ring::before { background: #FCD9A0; box-shadow: 0 0 0.5rem rgba(232,163,74,0.7); }
.chrono-topbar-btn::before, .zeno-orb { transition: background .6s ease, box-shadow .6s ease, filter .6s ease; }
@keyframes orbThink {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.06); }
}
@media (prefers-reduced-motion: reduce) {
  .chrono-topbar-btn.is-thinking::before, #zeno-panel.is-thinking .zeno-orb, .zeno-panel.is-thinking .zeno-orb { animation: none; }
}

/* A study row's time, beside its subject: plain text, no colour or dot. */
.plan-time { font-variant-numeric: tabular-nums; }

/* Phones asking for less motion: the mode switch fades, it does not travel. */
@media (max-width: 480px) and (prefers-reduced-motion: reduce) {
  .mode-handle, .mode-dock.is-open .mode-handle,
  .mode-dock .mode-switch, .mode-dock.is-open .mode-switch { transform: none; transition: opacity 0.15s ease; }
}

/* Event editor: the two date-time fields share the row instead of the
   wider one pushing past the modal's edge. */
#modal-event .form-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
#modal-event #event-start, #modal-event #event-end { width: 100%; min-width: 0; box-sizing: border-box; padding-left: 0.625rem; padding-right: 0.5rem; font-size: 0.875rem; }

.plan-steps-pop .drop-amt-steps { max-height: 14rem; }
.plan-steps-pop .drop-amt-step.is-done .drop-amt-step-text { color: var(--text-dim); }

/* Homework estimate: a full-width field like its neighbours, − left, + right. */
.est-inline { display: block; }
.est-inline-row {
  display: flex; align-items: center; gap: 0.25rem; width: 100%; box-sizing: border-box; padding: 0.25rem;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface2);
}
.est-inline-step {
  flex: none; width: 2.25rem; height: 2.125rem; border: none; border-radius: calc(var(--radius) - 0.25rem); background: transparent;
  color: var(--text-muted); font: 500 1.0625rem/1 var(--font); cursor: pointer; display: grid; place-items: center;
}
.est-inline-step:hover:not(:disabled) { background: var(--surface); color: var(--text); }
.est-inline-step:disabled { opacity: .35; cursor: default; }
.est-inline-val {
  flex: 1; min-width: 0; padding: 0.375rem; border: none; background: none; border-radius: 0.375rem;
  color: var(--text); font: 500 0.875rem/1.3 var(--font); text-align: center; font-variant-numeric: tabular-nums; cursor: text;
}
.est-inline-row .est-inline-input { width: auto; flex: 1; min-width: 0; padding: 0.375rem; border: none; outline: none; background: none; box-shadow: none; border-radius: 0; }
.est-inline-row:focus-within { border-color: var(--primary); box-shadow: 0 0 0 0.2188rem color-mix(in srgb, var(--primary) 12%, transparent); }
/* A test or deadline with no study time: one quiet button to give it some. */
.est-inline-add {
  flex: 1; min-width: 0; height: 2.125rem; border: none; border-radius: calc(var(--radius) - 0.25rem); background: none;
  color: var(--text-muted); font: 500 0.875rem/1 var(--font); cursor: pointer;
}
.est-inline-add:hover { background: var(--surface); color: var(--text); }
.est-inline-none {
  flex: none; width: 1.75rem; height: 1.75rem; margin-left: 0.125rem; border: none; border-radius: 50%; background: none;
  color: var(--text-dim); font: 500 1rem/1 var(--font); cursor: pointer; display: grid; place-items: center;
}
.est-inline-none:hover { background: var(--surface); color: var(--red); }

/* Auto-Schedule result: one title, one line of facts, then the lists. */
.rs-head { text-align: center; padding: 0.25rem 0 1rem; }
.rs-head .schedule-result-icon { margin-bottom: 0.625rem; }
.rs-head .schedule-result-title { margin-bottom: 0.125rem; }
.rs-facts { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 0.375rem; margin: 0; font-size: 0.8125rem; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.rs-dot { color: var(--text-dim); }
.rs-note { margin: 0.75rem 0 0; font-size: 0.8125rem; color: var(--text-muted); text-align: center; }
.rs-head + .rs-note { margin: -0.75rem 0 1rem; }
.short-cols { display: flex; justify-content: space-between; align-items: baseline; margin: 0 0.25rem 0.5rem; font-size: 0.75rem; font-weight: 600; color: var(--text-muted); }
.short-cols span:first-child { color: #B45309; }
.short-freed { margin: 0.625rem 0.25rem 0; font-size: 0.8125rem; font-weight: 600; color: #15803D; }
:root[data-theme="dark"] .short-freed { color: #4ADE80; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .short-freed { color: #4ADE80; } }
.short-section { margin-top: 1rem; }
.short-meta { display: flex; align-items: center; gap: 0.3125rem; }
.short-meta .short-missing { margin: 0; }
.short-bar { margin-top: 0.4375rem; }
:root[data-theme="dark"] .short-cols span:first-child { color: var(--amber); }
.short-val { min-width: 4.5rem; }
#schedule-result-body .schedule-actions .btn { white-space: nowrap; }
@media (max-width: 480px) {
  #schedule-result-body .schedule-actions .btn { font-size: 0.8125rem; padding-left: 0.5rem; padding-right: 0.5rem; }
}

/* ── Auto-Schedule sheet, calmer ─────────────────────────────────────────
   The green Auto-Schedule band on top; groups separated by space and a
   hairline, not boxes; days as light chips; fields at the size of text. */
#modal-schedule-mode .schedule-mode-body { padding-top: 0.875rem; }
.as-body { gap: 0; }
.as-body > .sched-section { border-top: 1px solid var(--border); padding: 1rem 0 0; margin-top: 1rem; }
.as-body > .sched-section.as-first { border-top: none; padding-top: 0; margin-top: 0; }
.as-body .sched-note { margin-top: 0.4375rem; }
#as-week { margin-top: 0.625rem; }
.as-seg { margin-bottom: 0.625rem; }
.as-time { padding: 0.375rem 0.625rem; font-size: 0.875rem; min-height: 0; height: 2.25rem; }
.as-days { gap: 0.25rem; margin-top: 0.5rem; }
.as-day {
  padding: 0.3125rem 0; border: 1px solid var(--border); background: transparent; color: var(--text-dim);
  font-size: 0.75rem; font-weight: 600;
}
.as-day:hover { color: var(--text); }
.as-day.is-on { background: color-mix(in srgb, var(--accent) 14%, transparent); border-color: transparent; color: var(--accent-dim, var(--accent)); }
:root[data-theme="dark"] .as-day.is-on { color: var(--accent); }
.as-byday { background: none; border: none; border-radius: 0; gap: 0.25rem; }
.as-dayrow { padding: 0; min-height: 2.25rem; }
.as-dayrow + .as-dayrow { border-top: none; }
.as-dayrow .as-day { flex: 0 0 3rem; padding: 0.3125rem 0; }
.as-dayrow .as-time { height: 2rem; padding-top: 0.25rem; padding-bottom: 0.25rem; }
.as-dayrow.is-off .as-off-label { padding-left: 0.25rem; }
#as-extra .as-extra-row { padding: 0; }
.as-done { margin-top: 1.25rem; padding-top: 0.625rem; padding-bottom: 0.625rem; }

/* ── Room to breathe: Auto-Schedule sheet and result ─────────────────── */
#modal-schedule-mode .modal-header { padding: 1.25rem 1.5rem 1.25rem 1.75rem; }
#modal-schedule-mode .schedule-mode-body { padding: 1.5rem 1.75rem 1.75rem; }
.as-body > .sched-section { padding-top: 1.375rem; margin-top: 1.375rem; }
#modal-schedule-mode .sched-strategy-btn { padding: 0.625rem 0.5rem; font-size: 0.875rem; }
.as-seg { margin-bottom: 0.875rem; }
.as-seg-btn { padding: 0.5625rem 0.5rem; font-size: 0.8125rem; }
#as-week { margin-top: 1rem; }
.as-times { gap: 0.625rem; }
.as-time { height: 2.5rem; font-size: 0.9375rem; padding: 0.4375rem 0.75rem; }
.as-days { gap: 0.375rem; margin-top: 0.75rem; }
.as-day { padding: 0.5rem 0; font-size: 0.8125rem; }
.as-byday { gap: 0.5rem; }
.as-dayrow { gap: 0.625rem; min-height: 2.5rem; }
.as-dayrow .as-day { flex: 0 0 3.25rem; padding: 0.4375rem 0; }
.as-dayrow .as-time { height: 2.375rem; }
.as-row-label { font-size: 0.9375rem; }
.as-done { margin-top: 1.75rem; padding-top: 0.75rem; padding-bottom: 0.75rem; }
.as-notes textarea { margin-top: 0.75rem; }

#modal-schedule-result .modal-header { padding: 1.5rem 1.75rem 0.5rem; }
#modal-schedule-result .modal-body { padding: 1.25rem 1.75rem 0.5rem; }
.rs-head { padding: 0.5rem 0 1.5rem; }
.rs-head .schedule-result-icon { margin-bottom: 0.875rem; }
.rs-head .schedule-result-title { font-size: 1.1875rem; margin-bottom: 0.25rem; }
.rs-facts { font-size: 0.875rem; }
.found-list { margin-top: 0; max-height: min(20rem, 42vh); }
.found-day { gap: 1rem; padding: 1rem 1.125rem; }
.found-sessions { gap: 0.875rem; }
.found-session { padding-left: 0.875rem; gap: 1rem; }
.found-title { font-size: 0.875rem; }
.found-meta { margin-top: 0.1875rem; font-size: 0.8125rem; }
.found-adjust { gap: 0.375rem; }
.found-step { width: 1.875rem; height: 1.875rem; }
.short-section { margin-top: 1.5rem; }
.short-cols { margin: 0 0.375rem 0.625rem; font-size: 0.8125rem; }
.short-row { padding: 1rem 1.125rem 1rem 1.375rem; gap: 1rem; }
.short-meta { margin-top: 0.1875rem; }
.short-bar { margin-top: 0.625rem; }
#schedule-result-body .schedule-actions { margin-top: 1.5rem; gap: 0.625rem; }
@media (max-width: 480px) {
  #modal-schedule-mode .modal-header { padding: 1rem 1.125rem 1rem 1.25rem; }
  #modal-schedule-result .modal-header { padding: 1.25rem 1.25rem 0.5rem; }
  #modal-schedule-mode .schedule-mode-body { padding: 1.25rem 1.25rem 1.5rem; }
  #modal-schedule-result .modal-body { padding: 1rem 1.25rem 0.5rem; }
  .found-day { padding: 0.875rem; gap: 0.75rem; }
  .short-row { padding: 0.875rem 0.875rem 0.875rem 1.125rem; }
  .as-day { font-size: 0.75rem; }
}
/* The result says what happened in its own title; the header keeps only ✕. */
#modal-schedule-result .modal-title { visibility: hidden; }
#modal-schedule-result .modal-body { padding-top: 0; }
#schedule-result-footer { padding-top: 1rem; }
#modal-schedule-mode .modal { width: 31.25rem; }
#modal-schedule-result .modal { width: 32.5rem; }

/* Homework inside the corner cards ("Study now", new or unplanned work):
   one tile, the subject's colour as a bar, title over subject and due. */
/* A homework, in a card (Study now?, new from the registry): clear glass
   with only a breath of its subject's colour in one corner -- the colour
   itself is the thin bar at the start. */
.card-item {
  display: flex; align-items: stretch; gap: 0.75rem; min-width: 0;
  padding: 0.6875rem 0.875rem 0.6875rem 0.75rem; border-radius: 0.75rem;
  background:
    radial-gradient(130% 160% at 0% 0%, color-mix(in srgb, var(--subject-color, var(--accent)) 7%, transparent), transparent 55%),
    linear-gradient(160deg, color-mix(in srgb, var(--surface) 72%, transparent), color-mix(in srgb, var(--surface2) 50%, transparent));
  -webkit-backdrop-filter: blur(1rem) saturate(170%); backdrop-filter: blur(1rem) saturate(170%);
  border: 1px solid color-mix(in srgb, var(--subject-color, var(--accent)) 8%, var(--border));
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.6), 0 1px 0.1875rem rgba(15,26,46,0.04);
}
:root[data-theme="dark"] .card-item { box-shadow: inset 0 1px 0 rgba(255,255,255,0.07), 0 1px 0.1875rem rgba(0,0,0,0.2); }
.card-item::before {
  content: ''; flex: none; width: 0.25rem; border-radius: 6.1875rem;
  background: var(--subject-color, var(--accent));
}
.card-item-body { display: flex; flex-direction: column; gap: 0.1875rem; min-width: 0; }
.card-item-title {
  font-size: 0.875rem; font-weight: 600; color: var(--text); line-height: 1.35;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.card-item-meta { font-size: 0.75rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.study-now-item { margin: 0.75rem 0 1.125rem; }
.registry-alert-list { gap: 0.5rem; }
.registry-alert-more { padding-left: 0.25rem; }

/* Homework modal: the rest of the fields, one tap away. A quiet row under a
   hairline -- label left, what is inside (estimate, steps) read back right. */
.acad-more-toggle {
  display: flex; align-items: center; gap: 0.5rem; width: 100%;
  margin: 0.125rem 0 0; padding: 0.875rem 0.125rem 0.875rem 0;
  border: none; border-top: 1px solid var(--border); background: none; cursor: pointer;
  color: var(--text-muted); font: 600 0.8125rem/1.3 var(--font); text-align: left;
  transition: color 0.15s;
}
.acad-more-toggle:hover { color: var(--text); }
.acad-more-sum { margin-left: auto; font-weight: 500; color: var(--text-dim); font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.acad-more-chev { flex: none; transition: transform 0.2s var(--ease); }
.acad-more-toggle[aria-expanded="true"] { margin-bottom: 0.5rem; }
.acad-more-toggle[aria-expanded="true"] .acad-more-chev { transform: rotate(180deg); }
.acad-more-toggle[aria-expanded="true"] .acad-more-sum { display: none; }
.acad-more { display: block; }
.acad-more.is-open { display: block; }
@keyframes acadMoreIn { from { opacity: 0; transform: translateY(-0.25rem); } to { opacity: 1; transform: none; } }

/* An empty week says what to do next: one button, one quiet link under it. */
.plan-empty-actions { display: flex; flex-direction: column; align-items: center; gap: 0.75rem; margin-top: 1.125rem; }
.plan-empty-btn { display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.6875rem 1.25rem; }
.plan-empty-btn svg { flex: none; }
.plan-empty-link {
  border: none; background: none; cursor: pointer; padding: 0.25rem 0.5rem;
  color: var(--text-muted); font: 600 0.8125rem/1.3 var(--font); transition: color 0.15s;
}
.plan-empty-link:hover { color: var(--text); }

/* Setup: one switch among the choices -- a plain row, the same toggle as Settings. */
.ob-switch-row {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 0.875rem 1rem; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface2); cursor: pointer;
}
.ob-switch-text { display: flex; flex-direction: column; gap: 0.1875rem; min-width: 0; }
.ob-switch-title { font-size: 0.875rem; font-weight: 600; color: var(--text); }
.ob-switch-note { font-size: 0.75rem; line-height: 1.4; color: var(--text-muted); }
.acad-subject-new { width: 100%; }

/* ── A calmer pass ───────────────────────────────────────────────────────
   Small things that each added a little noise. */

/* Study timer: the phase list waits behind its own button. */
#study-timer-expanded:not(.phases-open) .study-timer-segments,
#study-timer-expanded:not(.phases-open) .study-timer-repeat-row { display: none !important; }
.study-timer-phases-btn {
  /* A square exactly as tall as the mode control beside it (1.8125rem):
     a stretched flex item ignores aspect-ratio, so the width is set. */
  flex: none; align-self: center; width: 1.8125rem; height: 1.8125rem; display: grid; place-items: center; padding: 0;
  border: none; border-radius: 0.625rem; background: var(--surface2); color: var(--text-dim); cursor: pointer;
  transition: color 0.15s, background 0.15s;
}
.study-timer-phases-btn:hover { color: var(--text); background: var(--surface3); }
.study-timer-phases-btn[aria-expanded="true"] { color: var(--text); background: var(--surface3); }
.study-timer-phases-btn svg { width: 0.9375rem; height: 0.9375rem; }
#study-timer-expanded:not(.phases-open) .study-timer-ring-wrap { margin-top: 0.5rem; }

/* Calendar: hours ruled, half hours only hinted. */
.hour-line.half { border-top-style: solid; border-color: color-mix(in srgb, var(--border) 45%, transparent); }

/* Plan: a run of empty days reads as one quiet stretch, not a list of gaps. */
.plan-days:not(.is-dragging) .plan-day.is-empty:not(:has(.plan-due)) + .plan-day.is-empty:not(:has(.plan-due)) { margin-top: -1.125rem; }
.plan-day.is-empty .plan-day-note { font-size: 0.875rem; }

/* A test or deadline: tinted, without a ring around it. */
.plan-dues { box-shadow: 0 0 0 1px color-mix(in srgb, var(--plan-due) 13%, transparent); }

/* Sidebar: "Ignored" said quietly, in the case it is written in. */
.ignored-badge { text-transform: none; letter-spacing: 0; font-size: 0.625rem; font-weight: 500; background: none; padding: 0; color: rgba(255,255,255,0.32); }

/* Start: the next thing today keeps its word (Start / Resume), on a flat
   filled pill the height of the round buttons beside it -- no glow, so it
   leads the list without competing with the header. */
.plan-start.is-primary { width: auto; padding: 0 0.9375rem 0 0.8125rem; color: #fff; background: var(--accent); box-shadow: none; font-size: 0.8125rem; }
.plan-start.is-primary:hover { background: color-mix(in srgb, var(--accent) 88%, #000); }

/* ── Detail pass: things that didn't match their neighbours ──────────── */

/* Top bar: one height and one corner for every control in it. The date arrows and view tabs were a
   pixel or two short, and Event's label a size smaller than the rest.
   Chrono keeps its own pill: it is also the quick-chat bar, and its shape
   and glow are that bar's. */
@media (min-width: 769px) {
  .topbar-nav, .view-tabs { height: 2.25rem; box-sizing: border-box; }
}
#btn-add-event { font-size: 0.8125rem; }
#btn-add-event { box-shadow: inset 0 0 0.1875rem 1.5px rgba(255,255,255,0.95), inset 0 0 0.375rem 0.4375rem rgba(255,255,255,0.55), inset var(--s) var(--s) 1.375rem -0.25rem rgba(255,255,255,0.75), inset 0 -0.4375rem 0.875rem rgba(255,255,255,0.08), 0 0 0 1px rgba(147,146,146,0.3), 0 0.25rem 0.625rem rgba(3,3,3,0.06); }

/* Today is teal wherever it appears -- the Plan already says so; the
   calendar's week, month and year said it in navy, and the year in a
   square. */
.week-header-day.today .week-day-num,
.month-cell.today .month-cell-num { background: var(--accent); color: #fff; }
.year-day.today, .year-day.today:hover, .year-day.selected.today { background: var(--accent); color: #fff; border-radius: 50%; }
:root[data-theme="dark"] .week-header-day.today .week-day-num,
:root[data-theme="dark"] .month-cell.today .month-cell-num,
:root[data-theme="dark"] .year-day.today, :root[data-theme="dark"] .year-day.selected.today { background: var(--accent); color: #0B1F1C; }
.week-day-num { font-weight: 600; }
.week-header-day.today .week-day-num { font-weight: 700; }

/* Event blocks: the subject's colour for the bar and the tint, a deeper
   shade of it for the words -- sky blue on sky blue was hard to read. */
.cal-event .ev-title, .month-event-t { color: color-mix(in srgb, currentColor 58%, var(--text)); }
.cal-event .ev-time { color: color-mix(in srgb, currentColor 70%, var(--text-muted)); }

/* One chevron for every dropdown: the browser's own was a heavy black
   arrow beside the app's soft one on the language picker. */
select:not([multiple]):not([size]) {
  -webkit-appearance: none; appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%238A919C' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 8l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 0.75rem center; background-size: 0.875rem 0.875rem;
  padding-right: 2.25rem;
}
.tt-edit select:not([multiple]), .repeat-panel select:not([multiple]) { padding-right: 1.625rem; background-position: right 0.4375rem center; background-size: 0.75rem 0.75rem; }

/* A test or deadline: a flat amber disc, like every other mark in the list
   -- it was the one glossy, lit object on the page. */
.plan-due-icon { background: color-mix(in srgb, var(--plan-due) 80%, #000); box-shadow: none; }

/* Timetable row: the action quieter than the thing it belongs to. */
.tt-head-action { color: rgba(255,255,255,0.55); font-weight: 500; }
.tt-head-action:hover { color: #fff; }

/* Study header: the time left reads beside the subject, not among the
   window buttons. */
/* What the goal asks of this exam (renderStudyGoal), quietly under the title. */
.study-header-meta { display: flex; align-items: center; gap: 0.625rem; min-width: 0; margin-bottom: 0.1875rem; }
.study-header-meta .study-header-subject { margin-bottom: 0; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.study-header-meta .study-remaining { height: auto; min-width: 0; padding: 0.125rem 0.3125rem; margin: 0 0 0 -0.3125rem; border-radius: 0.375rem; flex: none; }

/* Auto-Schedule result: something urgent didn't fit while a session runs. */
.rs-switch { display: flex; flex-direction: column; gap: 0.625rem; margin: 0 0 1.25rem; padding: 1rem; border-radius: 1rem;
  background: color-mix(in srgb, var(--accent) 6%, var(--surface)); border: 1px solid color-mix(in srgb, var(--accent) 18%, var(--border)); }
.rs-switch-lead { margin: 0; font-size: 0.8125rem; font-weight: 600; color: var(--text); }
.rs-switch .card-item { background: var(--surface); }
.rs-switch-btn { align-self: stretch; }
.rs-switch-note { margin: 0; font-size: 0.75rem; color: var(--text-muted); text-align: center; }

/* ── A session's share ─────────────────────────────────────────────────────
   "Not now" sits beside delete and behaves like it -- quiet until the row is
   hovered -- but in the calm accent: sending a step on is not a loss. */
.study-task-later {
  flex-shrink: 0; width: 1.375rem; height: 1.375rem;
  display: grid; place-content: center;
  border: none; border-radius: 0.5rem; cursor: pointer;
  background: transparent; color: var(--text-dim);
  opacity: 0;
  transition: opacity .15s, color .15s, background .15s;
}
.study-task-row:hover .study-task-later, .study-task-later:focus-visible { opacity: 1; }
.study-task-later:hover { color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
@media (hover: none) { .study-task-later { opacity: 1; } }

.study-share-done {
  margin: 0.75rem 0.25rem; padding: 1.125rem 1rem 1rem;
  border-radius: 0.875rem; background: var(--surface2);
  text-align: center;
}
.study-share-done-title { font-size: 0.875rem; font-weight: 600; color: var(--text); }
.study-share-done-sub { margin-top: 0.1875rem; font-size: 0.75rem; color: var(--text-muted); }
.study-share-done-actions { margin-top: 0.875rem; display: flex; gap: 0.5rem; justify-content: center; flex-wrap: wrap; }

/* Add step · Suggest steps, side by side under a homework's list. */
.cl-actions { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.5rem; flex-wrap: wrap; }
.cl-suggest { display: inline-flex; align-items: center; gap: 0.375rem; }
.cl-suggest svg { color: var(--accent); flex-shrink: 0; }
.cl-suggest.is-busy { pointer-events: none; }
.cl-suggest.is-busy svg { animation: cl-suggest-pulse 1s ease-in-out infinite; }
@keyframes cl-suggest-pulse { 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) { .cl-suggest.is-busy svg { animation: none; } }
.settings-card-pad .steps-mode-sub { margin: 0.5rem 0.125rem 0; }

/* ── Smoothness: background blur only where it can be seen ─────────────────
   backdrop-filter re-blurs everything behind an element on every frame in
   which anything behind it changes -- a scroll, a fade, a modal sliding in.
   Measured at 2x (a Retina screen): with it, opening a modal fell to ~12 fps
   and scrolling inside Settings ran at ~15 fps; without it, both hold 60.
   Most of it sat on things over a flat, opaque surface (buttons, rows, the
   inside of a modal), where the blur has nothing to show and only costs;
   and two full-screen drop overlays, invisible at rest, kept blurring the
   whole window all the time. The glass stays where something moves behind
   it: the Plan | Calendar handle, the phone's bottom bar, popovers, Quick Ask. */
.btn-primary, .btn-ghost, .btn-secondary, .btn-undo, .sidebar .btn-ghost,
.generate-btn, .generate-more, #btn-add-event, .undo-btn,
.modal-close, .zeno-close, #zeno-image-remove, .panel-max-btn,
.chrono-topbar-btn, .zeno-attach-btn, .zeno-send-btn,
.study-timer-collapsed, .study-timer-expanded, .study-task-row, .study-add-row,
.cl-row, .retention-item, .chip-fit-drop, .card-item, .drag-choice-card,
.study-block-task-line, .study-block-task-dot, .swipe-action::before {
  -webkit-backdrop-filter: none !important; backdrop-filter: none !important;
}
/* A modal is an opaque sheet: nothing inside it needs to see through. */
.modal, .modal * { -webkit-backdrop-filter: none !important; backdrop-filter: none !important; }
/* Full-screen dims: a touch darker instead of blurred. */
.modal-overlay { -webkit-backdrop-filter: none; backdrop-filter: none; background: rgba(17,24,39,0.44); }
:root[data-theme="dark"] .modal-overlay { background: rgba(0,0,0,0.55); }
.sidebar-backdrop { -webkit-backdrop-filter: none; backdrop-filter: none; background: rgba(0,0,0,0.4); }
.drop-overlay {
  -webkit-backdrop-filter: none; backdrop-filter: none; background: rgba(20,33,61,0.5);
  visibility: hidden; transition: opacity 0.15s, visibility 0s linear 0.15s;
}
.drop-overlay.visible { visibility: visible; transition: opacity 0.15s, visibility 0s; }

/* ── Readiness ──────────────────────────────────────────────────────────────
   One number per test. The ring fills to the number; the colour says where
   it stands -- red below half, amber below three quarters, green above. */
.ready-chip, .ready-big { --lvl: var(--green); }
.ready-chip.lvl-low, .ready-big.lvl-low { --lvl: #EF4444; }
.ready-chip.lvl-mid, .ready-big.lvl-mid { --lvl: var(--amber); }
.ready-chip {
  flex-shrink: 0; display: inline-flex; align-items: center; gap: 0.3125rem;
  font-size: 0.75rem; font-weight: 700; font-variant-numeric: tabular-nums; color: inherit;
}
.ready-ring {
  --size: 0.875rem; width: var(--size); height: var(--size); border-radius: 50%; flex-shrink: 0;
  background: conic-gradient(var(--lvl) calc(var(--r) * 1%), color-mix(in srgb, currentColor 16%, transparent) 0);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 0.1875rem), #000 calc(100% - 0.1562rem));
          mask: radial-gradient(farthest-side, transparent calc(100% - 0.1875rem), #000 calc(100% - 0.1562rem));
}
.academic-chip .ready-chip { color: rgba(255,255,255,0.85); font-size: 0.6875rem; }
.academic-chip .ready-ring { --size: 0.75rem; }
.plan-due .ready-chip { font-size: 0.8125rem; color: var(--text); }

.ready-big { position: relative; display: grid; place-items: center; width: 3.25rem; height: 3.25rem; flex-shrink: 0; color: var(--text); }
.ready-big .ready-ring { --size: 3.25rem; position: absolute; inset: 0;
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 0.3125rem), #000 calc(100% - 0.2812rem));
          mask: radial-gradient(farthest-side, transparent calc(100% - 0.3125rem), #000 calc(100% - 0.2812rem)); }
.ready-big b { font-size: 0.875rem; font-weight: 700; font-variant-numeric: tabular-nums; }

.ready-panel {
  display: flex; flex-direction: column; gap: 0.625rem; margin-bottom: 1rem; padding: 0.875rem 1rem;
  border-radius: var(--radius-md); background: var(--surface2); border: 1px solid var(--border);
}
.ready-head { display: flex; align-items: center; gap: 0.75rem; }
.ready-head-text { display: flex; flex-direction: column; gap: 0.125rem; min-width: 0; }
.ready-title { font-size: 0.875rem; font-weight: 600; color: var(--text); }
.ready-sub { font-size: 0.75rem; color: var(--text-muted); line-height: 1.4; }
.ready-weak-label { font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-dim); }
.ready-weak { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.25rem; }
.ready-weak li { display: flex; justify-content: space-between; gap: 0.75rem; font-size: 0.8125rem; color: var(--text); }
.ready-weak-score { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.ready-check-btn { align-self: flex-start; }

/* The check itself */
.recall-modal { max-width: 34rem; }
.recall-modal .modal-body { padding-top: 0.25rem; }
.recall-for { font-size: 0.8125rem; color: var(--text-muted); margin-top: 0.125rem; }
.recall-lede { margin: 0 0 0.875rem; font-size: 0.875rem; line-height: 1.5; color: var(--text); }
.recall-page {
  display: flex; align-items: center; gap: 0.625rem; padding: 0.6875rem 0.875rem; cursor: pointer;
  border-radius: 0.875rem; border: 1px dashed var(--border2); color: var(--text-muted);
  transition: border-color 0.15s, background 0.15s, color 0.15s;
}
.recall-page:hover { border-color: var(--accent); color: var(--text); background: color-mix(in srgb, var(--accent) 5%, transparent); }
.recall-page-ico { display: grid; place-items: center; width: 2rem; height: 2rem; flex-shrink: 0; border-radius: 0.625rem; color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.recall-page-btn { font-size: 0.8125rem; font-weight: 600; }
.recall-page.is-added { border-style: solid; border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); color: var(--text); }
.recall-actions { display: flex; align-items: center; gap: 0.5rem; width: 100%; justify-content: flex-end; }
.recall-hint { margin-right: auto; font-size: 0.75rem; color: var(--text-dim); }
.recall-spinner { width: 0.875rem; height: 0.875rem; border-radius: 50%; border: 0.125rem solid var(--border2); border-top-color: var(--accent); animation: recall-spin 0.8s linear infinite; flex-shrink: 0; }
@keyframes recall-spin { to { transform: rotate(360deg); } }

/* The three questions: a card each, numbered, the answer box growing with
   what is written. Drawn as empty cards while they are being written. */
.recall-qs { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.625rem; }
.recall-card {
  display: flex; flex-direction: column; gap: 0.5rem; padding: 0.875rem 0.9375rem 0.9375rem;
  border-radius: 0.875rem; background: var(--surface); border: 1px solid var(--border);
  animation: recall-in 0.28s var(--ease, ease) both;
}
.recall-card:nth-child(2) { animation-delay: 0.05s; } .recall-card:nth-child(3) { animation-delay: 0.1s; }
@keyframes recall-in { from { opacity: 0; transform: translateY(0.375rem); } }
.recall-card:focus-within { border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); }
.recall-meta { display: flex; align-items: baseline; gap: 0.125rem; font-size: 0.75rem; font-weight: 600; color: var(--text-dim); font-variant-numeric: tabular-nums; min-width: 0; }
.recall-n { color: var(--accent); font-weight: 800; }
.recall-topic { margin-left: 0.5rem; padding-left: 0.5rem; border-left: 1px solid var(--border2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-muted); }
.recall-q-text { font-size: 0.9688rem; line-height: 1.45; font-weight: 600; color: var(--text); }
.recall-a {
  width: 100%; box-sizing: border-box; resize: none; min-height: 2.625rem; max-height: 12.5rem; padding: 0.5625rem 0.75rem;
  font: inherit; font-size: 0.875rem; line-height: 1.45; color: var(--text);
  border-radius: 0.625rem; border: 1px solid var(--border); background: var(--surface2);
  transition: border-color 0.15s, box-shadow 0.15s, background 0.15s;
}
.recall-a:focus { outline: none; background: var(--surface); border-color: var(--accent); box-shadow: 0 0 0 0.1875rem color-mix(in srgb, var(--accent) 16%, transparent); }
.recall-card.is-ghost { gap: 0.625rem; }
.recall-bar { display: block; height: 0.625rem; border-radius: 0.3125rem; background: var(--surface2); position: relative; overflow: hidden; }
.recall-bar.is-q { height: 0.875rem; }
.recall-bar.is-box { width: 100%; height: 2.625rem; border-radius: 0.625rem; }
.recall-bar::after { content: ''; position: absolute; inset: 0; transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--surface) 70%, transparent), transparent); animation: recall-shine 1.3s ease-in-out infinite; }
@keyframes recall-shine { to { transform: translateX(100%); } }
.recall-wait-text { display: flex; align-items: center; justify-content: center; gap: 0.5rem; margin: 0.875rem 0 0.25rem; font-size: 0.8125rem; color: var(--text-muted); }

/* Marked: the score, how ready the test is now, and each answer with its
   verdict and the full answer -- open where it was not right. */
.recall-top { display: flex; align-items: center; gap: 0.875rem; margin-bottom: 0.875rem; }
.recall-top .pt-score { min-width: 0; padding: 0.875rem 1.125rem 0.75rem; border-radius: 1.25rem; }
.recall-top .pt-score-n { font-size: 2.25rem; }
.recall-ready { flex: 1; min-width: 0; display: flex; align-items: center; gap: 0.75rem; padding: 0.625rem 0.75rem; border-radius: 1rem; background: var(--surface2); }
.recall-ready .ready-head-text { display: flex; flex-direction: column; gap: 0.125rem; min-width: 0; }
.recall-ready .ready-title { font-size: 0.875rem; font-weight: 700; color: var(--text); }
.recall-ready .ready-sub { font-size: 0.75rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.recall-delta { font-size: 0.75rem; font-weight: 700; padding: 0.0625rem 0.375rem; border-radius: 62.4375rem; }
.recall-delta.up { color: #15803D; background: rgba(34,197,94,0.14); }
.recall-delta.down { color: #B91C1C; background: rgba(239,68,68,0.12); }
.recall-qs.is-marked .recall-card { animation: none; }
.recall-score { font-size: 1.25rem; font-weight: 700; color: var(--text); margin-bottom: 0.75rem; }
.recall-qs.is-marked .rv-given.is-empty { color: var(--text-muted); font-style: italic; }
@media (max-width: 480px) {
  .recall-top { gap: 0.625rem; }
  .recall-top .pt-score { padding: 0.75rem 0.875rem 0.625rem; }
  .recall-top .pt-score-n { font-size: 1.875rem; }
}

/* A card at the top of the Plan: the coach's, the Daily 3, the review. It is
   one of the Plan's own cards -- the same corner, shadow and padding as a
   day's rows, its icon in the rows' ring column so the titles line up, and
   its actions the rows' Start pill. */
.plan-recall {
  position: relative; display: flex; align-items: center; gap: var(--plan-gap, 1rem);
  min-height: 4.25rem; margin-bottom: -0.5rem; padding: 0.875rem var(--plan-pad, 1.25rem); box-sizing: border-box;
  border-radius: 1.125rem; background: var(--plan-card, var(--surface)); box-shadow: var(--plan-card-shadow, var(--shadow-sm));
}
/* The card's icon: a tile in one of Apple's system colours, lit from above,
   with a filled glyph (public/js/glyphs.js). 34px over the rows' 24px ring
   column -- the negative margins keep it centred on that column, so the
   card's title still starts where the rows' titles do. */
.plan-recall-icon {
  --t1: #5FCFC2; --t2: #2A9D8F;
  width: 2.125rem; height: 2.125rem; margin: 0 -0.3125rem; flex-shrink: 0; display: grid; place-items: center;
  border-radius: 0.6875rem; color: #fff; font-size: 0.9375rem; font-weight: 700; font-variant-numeric: tabular-nums;
  --tile-cut: color-mix(in srgb, var(--t1) 45%, var(--t2));
  background: linear-gradient(180deg, var(--t1), var(--t2));
  box-shadow: inset 0 0.5px 0 rgba(255,255,255,0.3), 0 0.5px 1px rgba(16,24,40,0.08);
}
.plan-recall-icon svg { display: block; width: 1.1875rem; height: 1.1875rem; filter: drop-shadow(0 0.5px 0.5px rgba(0,0,0,0.12)); }
.plan-recall-icon > b { text-shadow: 0 0.5px 0.5px rgba(0,0,0,0.12); }
.plan-recall-icon .g-cut { fill: var(--tile-cut); }
.plan-recall-icon .g-cut-s { fill: none; stroke: var(--tile-cut); stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.plan-recall-icon.is-blue   { --t1: #5AB0FF; --t2: #007AFF; }
.plan-recall-icon.is-indigo { --t1: #8C8AF5; --t2: #5856D6; }
.plan-recall-icon.is-orange { --t1: #FFC05A; --t2: #FF9500; }
.plan-recall-icon.is-purple { --t1: #D394F2; --t2: #AF52DE; }
.plan-recall-icon.is-green  { --t1: #6EDD8C; --t2: #30B652; }
.plan-recall-icon.is-red    { --t1: #FF7B73; --t2: #FF3B30; }
.plan-recall-icon.is-teal   { --t1: #5FCFC2; --t2: #2A9D8F; }
.plan-recall .plan-main { flex: 1 1 14rem; min-width: 0; }
.plan-recall .plan-title, .plan-recall .plan-sub { white-space: normal; overflow: visible; text-overflow: clip; }
.plan-recall .plan-sub { line-height: 1.4; }
.plan-card-actions { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; margin-left: auto; }
.pill-btn {
  display: inline-flex; align-items: center; justify-content: center; height: 2.125rem; padding: 0 0.9375rem;
  border: 0; border-radius: 62.4375rem; cursor: pointer; white-space: nowrap;
  font-family: inherit; font-size: 0.8125rem; font-weight: 600; letter-spacing: -0.005em;
  color: #fff; background: var(--accent); transition: background 0.15s ease, transform 0.12s ease;
}
.pill-btn:hover { background: color-mix(in srgb, var(--accent) 88%, #000); }
.pill-btn:active { transform: scale(0.96); }
.pill-btn.is-quiet { color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.pill-btn.is-quiet:hover { background: color-mix(in srgb, var(--accent) 20%, transparent); }
.pill-btn:focus-visible, .plan-card-x:focus-visible { outline: 0.125rem solid color-mix(in srgb, var(--accent) 55%, transparent); outline-offset: 0.125rem; }
.pill-btn:disabled { opacity: 0.55; cursor: default; }
/* Not now: a quiet round button at the end of the actions. */
.plan-card-x {
  width: 2.125rem; height: 2.125rem; flex-shrink: 0; display: grid; place-items: center; padding: 0;
  border: 0; border-radius: 50%; background: transparent; color: var(--text-dim); cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.plan-card-x svg { width: 0.75rem; height: 0.75rem; }
.plan-card-x:hover { background: color-mix(in srgb, var(--text) 6%, transparent); color: var(--text); }
@media (max-width: 560px) {
  /* A phone: a short card stays one line like a row; when the actions don't
     fit beside the words they go under them, on the right, and Not now moves
     to the corner. */
  .plan-recall { flex-wrap: wrap; row-gap: 0.75rem; }
  .plan-recall .plan-main { flex-basis: 10.5rem; }
  /* Long words: the icon stays by the title, as on the week card. */
  .plan-recall-icon { align-self: flex-start; }
  .plan-card-actions { align-self: center; }
  .plan-recall:has(.plan-card-x) .plan-main { padding-right: 1.75rem; }
  .plan-card-x { position: absolute; top: 0.625rem; right: 0.625rem; width: 1.75rem; height: 1.75rem; }
}
:root[data-theme="dark"] .recall-delta.up { color: #4ADE80; }
:root[data-theme="dark"] .recall-delta.down { color: #F87171; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .recall-delta.up { color: #4ADE80; }
  :root:not([data-theme="light"]) .recall-delta.down { color: #F87171; }
}
@media (prefers-reduced-motion: reduce) { .recall-spinner { animation: none; } }

/* ── The tutor in Study Mode ────────────────────────────────────────────────
   One topic at a time, in the panel's own column: Learn, Practice, Check.
   The panel can be narrow (18.75rem), so everything stacks. */
.tutor-hidden { display: none !important; }
.study-topic { padding: 1rem 1rem 1.25rem; display: flex; flex-direction: column; gap: 0.75rem; }
.tutor-head { display: flex; align-items: center; gap: 0.5rem; }
.tutor-back {
  flex-shrink: 0; width: 1.75rem; height: 1.75rem; display: grid; place-items: center; border-radius: 50%;
  border: 1px solid var(--border); background: var(--surface); color: var(--text-muted); cursor: pointer;
}
.tutor-back:hover { color: var(--text); background: var(--surface2); }
.tutor-title { flex: 1; min-width: 0; font-size: 0.9375rem; font-weight: 650; color: var(--text); line-height: 1.3; overflow-wrap: anywhere; }
.tutor-stages { display: flex; gap: 0.25rem; padding: 0.1875rem; border-radius: 62.4375rem; background: var(--surface2); }
.tutor-stage {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 0.3125rem;
  padding: 0.375rem 0.25rem; border: 0; border-radius: 62.4375rem; background: transparent; cursor: pointer;
  font: 600 0.75rem/1 var(--font); color: var(--text-muted); white-space: nowrap;
}
.tutor-stage.is-active { background: var(--surface); color: var(--text); box-shadow: var(--shadow-sm); }
.tutor-material { display: flex; flex-wrap: wrap; align-items: center; gap: 0.3125rem; font-size: 0.75rem; }
.tutor-src {
  display: inline-flex; align-items: center; gap: 0.25rem; max-width: 100%;
  padding: 0.1875rem 0.25rem 0.1875rem 0.5rem; border-radius: 62.4375rem; background: var(--surface2); color: var(--text);
}
.tutor-src-ico { flex-shrink: 0; display: grid; place-items: center; color: var(--text-muted); }
.tutor-src-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 500 0.75rem/1.3 var(--font); color: var(--text); }
button.tutor-src-name { border: 0; padding: 0; background: none; cursor: pointer; text-align: left; }
button.tutor-src-name:hover, button.tutor-src-name:focus-visible { color: var(--accent); text-decoration: underline; text-underline-offset: 0.125rem; outline: none; }
.tutor-src-x { border: 0; background: transparent; color: var(--text-dim); cursor: pointer; font-size: 0.875rem; line-height: 1; padding: 0 0.25rem; }
.tutor-src-x:hover { color: var(--text); }
.tutor-paste textarea {
  width: 100%; box-sizing: border-box; padding: 0.5rem 0.625rem; font: inherit; font-size: 0.8125rem;
  border-radius: var(--radius-sm); border: 1px solid var(--border2); background: var(--surface); color: var(--text);
}
.tutor-paste textarea:focus { outline: none; box-shadow: var(--ring); border-color: var(--accent); }
.tutor-row-end { display: flex; align-items: center; justify-content: flex-end; gap: 0.5rem; margin-top: 0.5rem; flex-wrap: wrap; }
.tutor-body { display: flex; flex-direction: column; gap: 0.625rem; }
.tutor-explain { font-size: 0.875rem; line-height: 1.6; color: var(--text); }
.tutor-explain p, .tutor-qa-a p { margin: 0 0 0.5rem; }
.tutor-explain ul, .tutor-explain ol, .tutor-qa-a ul { margin: 0 0 0.5rem; padding-left: 1.125rem; }
.tutor-explain h1, .tutor-explain h2, .tutor-explain h3, .tutor-explain h4 { font-size: 0.875rem; margin: 0.625rem 0 0.25rem; }
.tutor-explain code, .tutor-qa-a code { font-size: 0.8125rem; padding: 0 0.25rem; border-radius: 0.25rem; background: var(--surface2); }
.tutor-kp-label { font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-dim); }
.tutor-kp { margin: 0; padding: 0.625rem 0.75rem 0.625rem 1.75rem; border-radius: var(--radius-md); background: var(--surface2); font-size: 0.8125rem; line-height: 1.5; color: var(--text); }
.tutor-kp li + li { margin-top: 0.25rem; }
.tutor-qa { display: flex; flex-direction: column; gap: 0.5rem; }
.tutor-qa-q { align-self: flex-end; max-width: 85%; padding: 0.5rem 0.8125rem; border-radius: 1rem 1rem 0.3125rem 1rem; background: var(--primary); color: #fff; font-size: 0.875rem; line-height: 1.5; }
.tutor-qa-a { font-size: 0.875rem; line-height: 1.55; color: var(--text); }
.tutor-qa-wait { color: var(--text-muted); display: inline-flex; align-items: baseline; }
.tutor-wait-word { display: inline-block; }
.tutor-wait-word.is-swap { animation: tutor-wait-swap .38s cubic-bezier(.2,.8,.2,1); }
.tutor-wait-dots { display: inline-flex; width: 1.1em; }
.tutor-wait-dots i { font-style: normal; opacity: 0; animation: tutor-wait-d1 1.6s infinite; }
.tutor-wait-dots i:nth-child(2) { animation-name: tutor-wait-d2; }
.tutor-wait-dots i:nth-child(3) { animation-name: tutor-wait-d3; }
/* They count up -- one, two, three -- then start again, as Chrono's do. */
@keyframes tutor-wait-d1 { 0%, 18% { opacity: 0; } 25%, 90% { opacity: 1; } 100% { opacity: 0; } }
@keyframes tutor-wait-d2 { 0%, 43% { opacity: 0; } 50%, 90% { opacity: 1; } 100% { opacity: 0; } }
@keyframes tutor-wait-d3 { 0%, 68% { opacity: 0; } 75%, 90% { opacity: 1; } 100% { opacity: 0; } }
@keyframes tutor-wait-swap { from { opacity: 0; transform: translateY(0.25rem); filter: blur(0.125rem); } to { opacity: 1; transform: none; filter: none; } }
@media (prefers-reduced-motion: reduce) {
  .tutor-wait-word.is-swap { animation: none; }
  .tutor-wait-dots i { animation: none; opacity: 1; }
}
.tutor-pq-meta { font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-dim); }
.tutor-pq { font-size: 0.9375rem; line-height: 1.45; color: var(--text); }
.tutor-model { font-size: 0.8125rem; line-height: 1.5; padding: 0.5rem 0.625rem; border-radius: var(--radius-sm); background: color-mix(in srgb, var(--accent) 9%, transparent); color: var(--text); }
.tutor-self-label { font-size: 0.75rem; color: var(--text-muted); }
.tutor-self { display: flex; gap: 0.375rem; width: 100%; }
.tutor-self-btn {
  flex: 1; padding: 0.5rem 0.25rem; border-radius: var(--radius-sm); cursor: pointer;
  font: 600 0.8125rem/1.2 var(--font); border: 1px solid var(--border2); background: var(--surface); color: var(--text);
}
.tutor-self-btn.is-missed:hover, .tutor-self-btn.is-missed:focus-visible { border-color: #EF4444; color: #DC2626; }
.tutor-self-btn.is-partly:hover, .tutor-self-btn.is-partly:focus-visible { border-color: var(--amber); color: #B45309; }
.tutor-self-btn.is-right:hover, .tutor-self-btn.is-right:focus-visible { border-color: var(--green); color: #15803D; }
.tutor-done { padding: 0.875rem; border-radius: var(--radius-md); background: var(--surface2); }
.tutor-done-title { font-size: 0.9375rem; font-weight: 650; color: var(--text); }
.tutor-done-sub { font-size: 0.8125rem; color: var(--text-muted); margin-top: 0.25rem; }
.tutor-lede { margin: 0; font-size: 0.8125rem; line-height: 1.5; color: var(--text-muted); }
.tutor-green { padding: 0.5rem 0.625rem; border-radius: var(--radius-sm); font-size: 0.8125rem; font-weight: 600; color: #15803D; background: rgba(34,197,94,0.12); }
.tutor-fallback { display: flex; flex-direction: column; gap: 0.5rem; }
.tutor-notes { font-size: 0.8125rem; line-height: 1.5; white-space: pre-wrap; padding: 0.5rem 0.625rem; border-radius: var(--radius-sm); background: var(--surface2); color: var(--text); }
.tutor-card { padding: 1rem; border-radius: var(--radius-md); border: 1px solid var(--border); background: var(--surface2); display: flex; flex-direction: column; gap: 0.625rem; min-height: 6rem; }
.tutor-card-hint { font-size: 0.75rem; color: var(--text-dim); }
.tutor-summary-head { font-size: 0.8125rem; color: var(--text-muted); margin-bottom: 0.625rem; }
.tutor-summary { list-style: none; margin: 0 0 0.75rem; padding: 0; display: flex; flex-direction: column; gap: 0.375rem; }
.tutor-summary li { display: flex; justify-content: space-between; gap: 0.75rem; padding: 0.5rem 0.75rem; border-radius: var(--radius-sm); background: var(--surface2); font-size: 0.875rem; color: var(--text); }
.tutor-summary-move { font-variant-numeric: tabular-nums; color: var(--text-muted); white-space: nowrap; }
.tutor-summary-move b { color: var(--text); }
.tutor-summary-green { color: var(--green); font-size: 0.625rem; vertical-align: middle; }
:root[data-theme="dark"] .tutor-green, :root[data-theme="dark"] .tutor-self-btn.is-right:hover { color: #4ADE80; }
:root[data-theme="dark"] .tutor-qa-q { background: var(--accent-dim); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .tutor-green { color: #4ADE80; }
  :root:not([data-theme="light"]) .tutor-qa-q { background: var(--accent-dim); }
}
.tutor-hints { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.tutor-hint { display: flex; gap: 0.625rem; padding: 0.625rem 0; font-size: 0.8125rem; line-height: 1.55; color: var(--text); }
.tutor-hint + .tutor-hint { border-top: 1px solid var(--border); }
.tutor-hint .md-body { flex: 1; min-width: 0; }
.tutor-hint p { margin: 0 0 0.375rem; }
.tutor-hint p:last-child { margin-bottom: 0; }
.tutor-hint-n {
  flex-shrink: 0; width: 1.25rem; height: 1.25rem; margin-top: 0.0625rem; border-radius: 50%; display: grid; place-items: center;
  font: 600 0.6875rem/1 var(--font); color: var(--text-muted); background: var(--surface2);
}
.tutor-fineprint { margin: 0; font-size: 0.6875rem; line-height: 1.45; color: var(--text-dim); }
.tutor-ex-result { padding: 0.75rem 0.875rem; border-radius: 0.875rem; font-size: 0.875rem; line-height: 1.5; color: var(--text); background: var(--surface2); display: flex; flex-direction: column; gap: 0.25rem; }
.tutor-ex-result ul { margin: 0; padding-left: 1.125rem; }
.tutor-ex-result.mark-right { background: color-mix(in srgb, var(--green) 9%, var(--surface)); }
.tutor-ex-result.mark-partly { background: color-mix(in srgb, var(--amber) 10%, var(--surface)); }
.tutor-ex-result.mark-wrong { background: color-mix(in srgb, #EF4444 8%, var(--surface)); }
.tutor-next { display: flex; align-items: flex-start; gap: 0.5rem; font-size: 0.875rem; line-height: 1.5; color: var(--text-muted); }
.tutor-next svg { flex-shrink: 0; margin-top: 0.25rem; color: var(--accent); }
.tutor-next-text { min-width: 0; overflow-wrap: anywhere; }
.tutor-next-text .katex-display { margin: 0.25rem 0; overflow-x: auto; }
.tutor-explain-back { display: flex; flex-direction: column; gap: 0.5rem; padding-top: 0.75rem; border-top: 1px solid var(--border); }
.tutor-explain-input { position: relative; }
.tutor-explain-input .recall-a { padding-right: 2.5rem; }
.tutor-mic {
  position: absolute; right: 0.375rem; top: 0.375rem; width: 1.875rem; height: 1.875rem; border-radius: 50%;
  display: grid; place-items: center; border: 1px solid var(--border); background: var(--surface); color: var(--text-muted); cursor: pointer;
}
.tutor-mic.is-on { color: #fff; background: #EF4444; border-color: #EF4444; animation: tutor-pulse 1.4s ease-in-out infinite; }
@keyframes tutor-pulse { 50% { box-shadow: 0 0 0 0.375rem rgba(239,68,68,0.15); } }
@media (prefers-reduced-motion: reduce) { .tutor-mic.is-on { animation: none; } }

/* Sources and Study Search inside a topic */
.tutor-sources { display: flex; flex-direction: column; gap: 0.5rem; padding-top: 0.75rem; border-top: 1px solid var(--border); }
.tutor-sources-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; min-height: 1.75rem; }
.tutor-res-list { display: flex; flex-direction: column; gap: 0.25rem; }
.tutor-res {
  display: flex; align-items: center; gap: 0.625rem; width: 100%; padding: 0.5rem 0.625rem; text-align: left; cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); font: inherit;
  transition: border-color 0.15s, background 0.15s;
}
.tutor-res:hover, .tutor-res:focus-visible { border-color: color-mix(in srgb, var(--accent) 45%, transparent); background: color-mix(in srgb, var(--accent) 4%, var(--surface)); }
.tutor-res-icon { flex-shrink: 0; width: 1.75rem; height: 1.75rem; border-radius: 0.5rem; display: grid; place-items: center; background: var(--surface2); color: var(--text-muted); }
.tutor-res-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.0625rem; }
.tutor-res-title { font-size: 0.8125rem; font-weight: 600; line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tutor-res-host { font-size: 0.75rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tutor-res-go { flex-shrink: 0; color: var(--text-dim); }
.tutor-res-label { font-size: 0.6875rem; color: var(--text-dim); margin-top: 0.25rem; }
.tutor-search { position: relative; }
.tutor-search .tutor-search-icon { position: absolute; left: 0.625rem; top: 50%; transform: translateY(-50%); color: var(--text-dim); pointer-events: none; }
.tutor-search input { padding-left: 1.875rem; }
.tutor-search input::-webkit-search-cancel-button { display: none; }
.tutor-search-answer { font-size: 0.8125rem; line-height: 1.6; color: var(--text); padding: 0.625rem 0.75rem; border-radius: var(--radius-md); background: var(--surface2); }
.tutor-search-answer p { margin: 0 0 0.5rem; }
.tutor-search-answer p:last-child { margin-bottom: 0; }
.tutor-search-answer ul, .tutor-search-answer ol { margin: 0 0 0.5rem; padding-left: 1.125rem; }
#tutor-search-out { display: flex; flex-direction: column; gap: 0.375rem; }
#tutor-search-out:empty { display: none; }
.tutor-link { display: flex; gap: 0.375rem; }
.tutor-link.hidden { display: none; }
.tutor-link input {
  flex: 1; min-width: 0; padding: 0.5rem 0.625rem; font: inherit; font-size: 0.8125rem;
  border-radius: var(--radius-sm); border: 1px solid var(--border2); background: var(--surface); color: var(--text);
}
.tutor-link input:focus { outline: none; box-shadow: var(--ring); border-color: var(--accent); }

/* The reader: a source, read inside Zenow, with Chrono beside it */
.reader-overlay { z-index: 650; }
.reader-modal { width: 64rem; height: min(52rem, 90vh); max-height: 90vh; display: flex; flex-direction: column; overflow: hidden; }
.reader-head { gap: 0.75rem; padding: 1rem 1.25rem 0.875rem; border-bottom: 1px solid var(--border); }
.reader-head-text { flex: 1; min-width: 0; }
.reader-site { font-size: 0.75rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.reader-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.reader-open { flex-shrink: 0; text-decoration: none; }
.reader-main { flex: 1; min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr) 19rem; }
.reader-body { overflow-y: auto; padding: 1.5rem 2rem 2.5rem; font-size: 1rem; line-height: 1.7; color: var(--text); }
.reader-body > * { max-width: 40rem; margin-left: auto; margin-right: auto; }
.reader-body p { margin: 0 auto 0.875rem; }
.reader-body h3 { font-size: 1.0625rem; line-height: 1.35; margin: 1.5rem auto 0.5rem; }
.reader-body h3:first-child { margin-top: 0; }
.reader-body .reader-li { padding-left: 1rem; position: relative; margin-bottom: 0.375rem; }
.reader-body .reader-li::before { content: ''; position: absolute; left: 0.25rem; top: 0.72em; width: 0.3125rem; height: 0.3125rem; border-radius: 50%; background: var(--text-dim); }
.reader-body blockquote { margin: 0 auto 0.875rem; padding: 0.25rem 0 0.25rem 0.875rem; border-left: 0.1875rem solid var(--border2); color: var(--text-muted); }
.reader-body pre { white-space: pre-wrap; font-size: 0.8125rem; line-height: 1.5; padding: 0.75rem; border-radius: var(--radius-sm); background: var(--surface2); overflow-x: auto; }
.reader-video { position: relative; width: 100%; aspect-ratio: 16 / 9; border-radius: var(--radius-md); overflow: hidden; background: #000; }
.reader-video iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.reader-empty { display: flex; flex-direction: column; align-items: center; gap: 1rem; padding: 3rem 1rem; text-align: center; color: var(--text-muted); font-size: 0.9375rem; }
.reader-empty p { margin: 0; max-width: 26rem; }
.reader-side { overflow-y: auto; padding: 1.25rem; border-left: 1px solid var(--border); background: var(--surface2); display: flex; flex-direction: column; gap: 0.625rem; }
.reader-side:empty { display: none; }
.reader-actions { display: flex; flex-direction: column; gap: 0.375rem; padding-bottom: 0.75rem; border-bottom: 1px solid var(--border); }
.reader-actions .btn { width: 100%; justify-content: center; }
.reader-actions .tutor-fineprint { margin-top: 0.125rem; }
.reader-side .tutor-ask input { background: var(--surface); }
.reader-main:has(.reader-side:empty) { grid-template-columns: minmax(0, 1fr); }
@media (max-width: 760px) {
  .reader-overlay { padding: 0; align-items: stretch; }
  .reader-modal { width: 100%; height: 100%; max-height: none; border-radius: 0; border: 0; }
  .reader-main { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) auto; }
  .reader-body { padding: 1.125rem 1rem 1.5rem; font-size: 0.9375rem; }
  .reader-side { border-left: 0; border-top: 1px solid var(--border); max-height: 42vh; padding: 0.875rem 1rem calc(0.875rem + env(safe-area-inset-bottom)); }
  .reader-open { padding-left: 0.5rem; padding-right: 0.5rem; }
}

/* The weekly email on a parent / tutor link */
.share-row-actions { display: flex; align-items: center; gap: 0.25rem; flex-shrink: 0; }
.share-row-email { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.375rem; margin-top: 0.25rem; font-size: 0.6875rem; color: var(--text-muted); overflow-wrap: anywhere; }
.share-row-alerts { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.5rem; font-size: 0.75rem; line-height: 1.35; color: var(--text); cursor: pointer; }
.share-row-alert-last { margin-top: 0.25rem; font-size: 0.6875rem; color: var(--text-dim); }

/* The rows and the sheet that makes a link (shareSettings.js). */
.share-row { align-items: flex-start; }
.share-row-actions { padding-top: 0.0625rem; }
.share-row-sub + .share-row-sub { margin-top: 0; }
.btn.share-icon-btn { width: 1.875rem; height: 1.875rem; padding: 0; display: inline-grid; place-items: center; color: var(--text-muted); }
.btn.share-icon-btn:hover { color: var(--text); }
.share-row-tag {
  display: inline-flex; align-items: center; gap: 0.25rem; vertical-align: 0.0625rem;
  font-size: 0.625rem; font-weight: 700; letter-spacing: 0.03em; text-transform: uppercase;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent);
  padding: 0.0625rem 0.4375rem; border-radius: 999px;
}
.share-email-add-link {
  margin-top: 0.375rem; padding: 0; border: 0; background: none; cursor: pointer;
  font: inherit; font-size: 0.6875rem; font-weight: 600; color: var(--accent);
}
.share-email-add-link:hover { text-decoration: underline; text-underline-offset: 0.125rem; }
.share-empty { padding: 0.25rem 0 0.125rem; }
.share-empty-title { font-size: 0.8125rem; font-weight: 600; color: var(--text); }
.share-empty-text { font-size: 0.75rem; line-height: 1.55; color: var(--text-muted); margin-top: 0.1875rem; }

.share-sheet .modal { animation: share-sheet-in 0.32s var(--ease); }
@keyframes share-sheet-in { from { opacity: 0; transform: translateY(0.5rem) scale(0.985); } to { opacity: 1; transform: none; } }
.share-sheet-body { padding-top: 0.25rem; }
.share-sheet-lede { font-size: 0.8125rem; line-height: 1.6; color: var(--text-muted); margin: 0 0 1rem; }
.share-sheet-chips { display: flex; flex-wrap: wrap; gap: 0.375rem; margin-top: 0.5rem; }
.share-sheet-chip {
  font: inherit; font-size: 0.75rem; font-weight: 600; color: var(--text-muted); cursor: pointer;
  background: var(--surface2); border: 1px solid transparent; border-radius: 999px; padding: 0.25rem 0.75rem;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.share-sheet-chip:hover { color: var(--text); }
.share-sheet-chip.is-on { background: var(--primary-glow); border-color: var(--primary); color: var(--primary); }
.share-sheet-what { margin: 0.25rem 0 1rem; border: 1px solid var(--border); border-radius: 0.75rem; overflow: hidden; }
.share-sheet-heading {
  font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-dim);
  padding: 0.625rem 0.875rem 0.375rem;
}
.share-sheet-opt {
  display: flex; align-items: center; justify-content: space-between; gap: 0.875rem;
  padding: 0.625rem 0.875rem; border-top: 1px solid var(--border); cursor: pointer;
}
.share-sheet-heading + .share-sheet-opt { border-top: none; }
.share-sheet-opt.is-fixed { cursor: default; }
.share-sheet-opt-text { min-width: 0; }
.share-sheet-opt-text b { display: block; font-size: 0.8125rem; font-weight: 600; color: var(--text); }
.share-sheet-opt-text small { display: block; font-size: 0.6875rem; line-height: 1.45; color: var(--text-muted); margin-top: 0.0625rem; }
.share-sheet-always { font-size: 0.6875rem; font-weight: 600; color: var(--text-dim); white-space: nowrap; }
.share-sheet-hint { font-size: 0.6875rem; line-height: 1.5; color: var(--text-dim); margin: 0.375rem 0 0; }
.share-sheet-actions { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 1.125rem; }
.share-sheet-done .share-url-box { margin-bottom: 0.625rem; }
.share-sheet-done-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.share-sheet-done-actions .btn { display: inline-flex; align-items: center; gap: 0.375rem; }
.share-sheet-done .share-sheet-hint { margin-top: 0.75rem; }

/* Settings > Account, Family plan: whether a member shares with the payer. */
.settings-family-share { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; padding: 0.625rem 0 0.125rem; font-size: 0.75rem; line-height: 1.45; color: var(--text); cursor: pointer; }
.settings-family-share small { display: block; color: var(--text-muted); font-size: 0.6875rem; margin-top: 0.0625rem; }
.settings-family-status { font-size: 0.6875rem; color: var(--text-dim); margin-top: 0.0625rem; }
.settings-family-status.is-shared { color: var(--accent); font-weight: 600; }
.settings-family-open { display: inline-flex; align-items: center; gap: 0.375rem; text-decoration: none; }
.share-email-stop { border: 0; padding: 0; background: none; font: inherit; color: var(--accent); cursor: pointer; text-decoration: underline; text-underline-offset: 0.125rem; }
.btn-ghost.btn-sm.share-email-add { color: var(--accent); }

/* The Family plan: a wide row under Plus and Pro, and its Settings block */
.plan-card.plan-card-wide { grid-column: 1 / -1; display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.plan-card-wide .plan-price { margin-bottom: 0; text-align: right; white-space: nowrap; }
.plan-wide-main { min-width: 0; }
.plan-wide-sub { font-size: 0.75rem; line-height: 1.45; color: var(--text-muted); }
.settings-family { display: flex; flex-direction: column; gap: 0.375rem; padding: 0.75rem 0.875rem; border-top: 1px solid var(--border); }
.settings-family.hidden { display: none; }
.settings-family-head { font-size: 0.75rem; font-weight: 600; color: var(--text); }
.settings-family-row { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; }
.settings-family-name { font-size: 0.8125rem; color: var(--text); min-width: 0; overflow-wrap: anywhere; }
.settings-family-invite { align-self: flex-start; }
.settings-family-seats { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; padding: 0.25rem 0; }
.settings-family-seats-label { font-size: 0.8125rem; color: var(--text); }
.settings-family-seats-ctl { display: inline-flex; align-items: center; gap: 0.125rem; padding: 0.125rem; border: 1px solid var(--border); border-radius: 999px; background: var(--surface2); }
.settings-family-step { display: inline-flex; align-items: center; justify-content: center; width: 1.75rem; height: 1.75rem; border: 0; border-radius: 50%; background: transparent; color: var(--text); cursor: pointer; transition: background 0.15s; }
.settings-family-step:hover:not(:disabled) { background: var(--surface3); }
.settings-family-step:disabled { color: var(--text-dim); cursor: default; opacity: 0.5; }
.settings-family-seats-n { min-width: 1.5rem; text-align: center; font-size: 0.875rem; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--text); }
.settings-family-note { font-size: 0.6875rem; color: var(--text-dim); line-height: 1.45; }
.family-join-text { font-size: 0.875rem; line-height: 1.6; color: var(--text-muted); margin: 0 0 1rem; }
.family-join-actions { display: flex; justify-content: flex-end; gap: 0.5rem; }
@media (max-width: 640px) {
  .plan-card.plan-card-wide { flex-direction: column; align-items: flex-start; }
  .plan-card-wide .plan-price { text-align: left; }
}

/* Material: chips under the header, added from its + */
.tutor-src { max-width: 100%; overflow: hidden; }
.tutor-src > :not(.tutor-src-x) { min-width: 0; }
.tutor-add-wrap { position: relative; flex-shrink: 0; }
.tutor-add-menu {
  position: absolute; right: 0; top: calc(100% + 0.375rem); z-index: 20; min-width: 13.5rem; padding: 0.3125rem;
  border-radius: 0.75rem; border: 1px solid var(--border); background: var(--surface); box-shadow: var(--shadow);
  display: flex; flex-direction: column;
}
.tutor-add-menu.hidden { display: none; }
.tutor-add-item {
  display: flex; align-items: center; gap: 0.625rem; width: 100%; padding: 0.5625rem 0.625rem; border: 0; border-radius: 0.5rem;
  background: transparent; color: var(--text); font: 500 0.8125rem/1.2 var(--font); text-align: left; cursor: pointer;
}
.tutor-add-item svg { flex-shrink: 0; color: var(--text-muted); }
.tutor-add-item:hover, .tutor-add-item:focus-visible { background: var(--surface2); outline: none; }

/* Your phone's camera, from a computer */
.snap-modal { max-width: 22rem; }
.snap-body { display: flex; flex-direction: column; align-items: center; gap: 0.75rem; text-align: center; }
.snap-qr { width: 13.5rem; height: 13.5rem; padding: 0.625rem; border-radius: 1rem; background: #fff; border: 1px solid var(--border); display: grid; place-items: center; }
.snap-qr svg { width: 100%; height: 100%; display: block; }
/* Two ways in: the app on the phone opens the page by itself, or the code. */
.snap-way { align-self: stretch; display: flex; align-items: center; gap: 0.75rem; padding: 0.75rem 0.875rem; border-radius: 0.875rem; background: var(--surface2); text-align: left; }
.snap-way-ico { flex-shrink: 0; width: 2.25rem; height: 2.25rem; border-radius: 0.625rem; display: grid; place-items: center; background: var(--surface); color: var(--accent); }
.snap-way-text { display: flex; flex-direction: column; gap: 0.125rem; min-width: 0; }
.snap-way-text b { font-size: 0.875rem; font-weight: 600; color: var(--text); }
.snap-way-text span { font-size: 0.8125rem; line-height: 1.4; color: var(--text-muted); }
.snap-or { align-self: stretch; display: flex; align-items: center; gap: 0.75rem; font-size: 0.75rem; font-weight: 600; color: var(--text-muted); text-transform: lowercase; }
.snap-or::before, .snap-or::after { content: ''; flex: 1; height: 1px; background: var(--border); }
.snap-scan { margin: 0; font-size: 0.875rem; font-weight: 600; color: var(--text); }
.snap-lede { margin: 0; font-size: 0.875rem; line-height: 1.5; color: var(--text-muted); }
.snap-status { font-size: 0.8125rem; font-weight: 600; color: var(--accent); min-height: 1.2em; }
.snap-body .tutor-row-end { align-self: stretch; }
/* With a mouse, the row's own controls take no room until they are wanted,
   so the step's name gets the whole row. Set times stay visible. */
@media (hover: hover) and (pointer: fine) {
  .study-task-row:not(:hover):not(:focus-within) .study-task-remove,
  .study-task-row:not(:hover):not(:focus-within) .study-task-later,
  .study-task-row:not(:hover):not(:focus-within) .study-task-duration:not(.set) { display: none; }
}
.tutor-add-menu { min-width: 15rem; }
.tutor-add-item span { white-space: nowrap; }
.tutor-stage { min-width: 0; overflow: hidden; text-overflow: ellipsis; flex: 1 1 auto; }

/* Study help, one way in: a crimson pill in the panel's header, beside the
   full-screen and close buttons -- the books and one word. Which step it is
   about is chosen inside. */
.study-help-entry {
  display: inline-flex; align-items: center; gap: 0.375rem; flex-shrink: 0;
  height: 1.75rem; padding: 0 0.8125rem 0 0.5625rem; border: 0; border-radius: 62.4375rem; cursor: pointer;
  color: #fff; font-family: var(--font); font-size: 0.75rem; font-weight: 650; letter-spacing: -0.005em; white-space: nowrap;
  /* Liquid glass in crimson: a tinted body light passes through, a bright
     specular cap on top, a soft caustic glow pooling at the bottom, and a
     hairline rim lit from above. Flat on the outside, no bubble shadow. */
  --glass-tint: linear-gradient(180deg, rgba(212,44,54,0.80) 0%, rgba(160,20,28,0.88) 100%);
  background:
    radial-gradient(130% 70% at 50% -18%, rgba(255,255,255,0.50) 0%, rgba(255,255,255,0.10) 52%, rgba(255,255,255,0) 64%),
    radial-gradient(80% 60% at 50% 125%, rgba(255,150,150,0.42) 0%, rgba(255,150,150,0) 70%),
    var(--glass-tint);
  text-shadow: 0 0.5px 1px rgba(90,0,8,0.35);
  box-shadow:
    inset 0 0.75px 0 rgba(255,255,255,0.75),
    inset 0 -0.75px 0 rgba(255,255,255,0.22),
    inset 0 0 0 0.75px rgba(255,255,255,0.20),
    0 1px 0.125rem rgba(110,8,16,0.16);
  -webkit-backdrop-filter: blur(0.625rem) saturate(180%); backdrop-filter: blur(0.625rem) saturate(180%);
  transition: filter .16s ease, transform .1s ease, box-shadow .16s ease;
}
.study-help-entry.hidden { display: none; }
.study-help-entry:active { transform: scale(.96); }
.study-help-entry:focus-visible { outline: 0.125rem solid rgba(196,43,51,0.55); outline-offset: 0.125rem; }
.study-help-icon { display: grid; place-items: center; width: 1rem; height: 1rem; }
.study-help-icon svg { width: 1rem; height: 1rem; }
.study-help-entry.tutor-hidden { display: none; }
/* The best help in the room says so: the sparkle and the word, wherever
   the panel is. */
:root[data-theme="dark"] .study-help-entry { --glass-tint: linear-gradient(180deg, rgba(226,58,68,0.72) 0%, rgba(168,24,34,0.82) 100%); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .study-help-entry { --glass-tint: linear-gradient(180deg, rgba(226,58,68,0.72) 0%, rgba(168,24,34,0.82) 100%); }
}
@media (prefers-reduced-motion: reduce) { .study-help-entry { transition: none; } }

/* Inside study help: the steps (or a test's topics) and the whole of it,
   one row to move between them. */
/* Which step: the title opens a list of them, the whole homework first. */
.tutor-head { position: relative; }
.tutor-title-btn {
  display: inline-flex; align-items: center; gap: 0.3125rem; flex: 1; min-width: 0;
  margin: -0.25rem 0 -0.25rem -0.375rem; padding: 0.25rem 0.375rem; border: 0; border-radius: 0.5rem;
  background: none; font: inherit; font-size: 0.9375rem; font-weight: 650; color: var(--text); text-align: left; cursor: pointer;
  transition: background .15s ease;
}
.tutor-title-btn:hover, .tutor-title-btn.is-open { background: var(--surface2); }
.tutor-title-btn:focus-visible { outline: none; box-shadow: var(--ring); }
.tutor-title-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tutor-title-chev { flex: none; color: var(--text-dim); transition: transform .18s var(--ease); }
.tutor-title-btn.is-open .tutor-title-chev { transform: rotate(180deg); }
.tutor-step-menu {
  position: absolute; z-index: 5; top: calc(100% + 0.375rem); left: 2.25rem; right: 0;
  max-height: 16rem; overflow-y: auto; overscroll-behavior: contain;
  padding: 0.3125rem; border-radius: 0.875rem; background: var(--surface); border: 1px solid var(--border);
  box-shadow: 0 1rem 2.5rem rgba(17,24,39,0.16), 0 0.125rem 0.375rem rgba(17,24,39,0.06);
  animation: qa-pop-in 0.16s var(--ease);
}
.tutor-step-menu.hidden { display: none; }
.tutor-step-opt {
  display: flex; align-items: center; gap: 0.5rem; width: 100%; min-height: 2.25rem; padding: 0.375rem 0.625rem;
  border: 0; border-radius: 0.5625rem; background: none; color: var(--text); font: inherit; font-size: 0.8125rem; text-align: left; cursor: pointer;
}
.tutor-step-opt:hover, .tutor-step-opt:focus-visible { background: var(--surface2); outline: none; }
.tutor-step-opt.is-active { font-weight: 650; }
.tutor-step-opt.is-whole { border-bottom: 1px solid var(--border); border-radius: 0.5625rem 0.5625rem 0 0; margin-bottom: 0.1875rem; }
.tutor-step-opt.is-done .tutor-step-label { color: var(--text-muted); }
.tutor-step-label { flex: 1; min-width: 0; line-height: 1.35; overflow-wrap: anywhere; }
.tutor-step-mark { flex: none; width: 0.875rem; height: 0.875rem; color: var(--red); }
.tutor-step-mark svg { width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.tutor-step-on { flex: none; color: var(--red); }

/* Chrono's words: whatever Chrono wrote carries its gold, so it is never
   mistaken for the page or the student's own notes. */
.chrono-card {
  padding: 0.875rem 1.125rem 1rem; border-radius: var(--radius-md);
  background: color-mix(in srgb, #E9C46A 16%, var(--surface));
  border: 1px solid color-mix(in srgb, #C8962E 32%, transparent);
  font-size: 0.9375rem; line-height: 1.65; color: var(--text);
}
.chrono-card .md-body ul, .chrono-card .md-body ol { margin: 0 0 0.5rem; padding-left: 1.25rem; }
.chrono-card .md-body li + li { margin-top: 0.25rem; }
.chrono-card .md-body h1, .chrono-card .md-body h2, .chrono-card .md-body h3 { font-size: 0.9375rem; margin: 0.75rem 0 0.25rem; }
.chrono-card .md-math-display { margin: 0.5rem 0; overflow-x: auto; }
.chrono-card-head { display: flex; align-items: center; gap: 0.375rem; margin-bottom: 0.375rem; font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: #A97A1E; }
.chrono-card .md-body p { margin: 0 0 0.5rem; }
.chrono-card .md-body p:last-child { margin-bottom: 0; }
.tutor-qa-a.chrono-says { align-self: flex-start; max-width: 92%; box-sizing: border-box; padding: 0.625rem 0.875rem; border-radius: 1rem 1rem 1rem 0.3125rem; background: color-mix(in srgb, #E9C46A 13%, var(--surface)); border: 1px solid color-mix(in srgb, #C8962E 18%, transparent); }
:root[data-theme="dark"] .chrono-card-head { color: #E9C46A; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .chrono-card-head { color: #E9C46A; } }

/* The search window */
.search-overlay { z-index: 640; align-items: flex-start; padding-top: max(8vh, 1.25rem); }
.search-modal { width: min(44rem, calc(100vw - 2rem)); max-width: none; max-height: min(48rem, 88vh); display: flex; flex-direction: column; overflow: hidden; }
.search-bar { display: flex; align-items: center; gap: 0.625rem; padding: 0.875rem 1rem 0.875rem 1.125rem; border-bottom: 1px solid var(--border); }
.search-bar-icon { color: var(--text-dim); display: grid; flex-shrink: 0; }
.search-bar-icon svg { width: 1.0625rem; height: 1.0625rem; }
.search-modal .search-bar input {
  flex: 1; min-width: 0; height: auto; margin: 0; padding: 0.25rem 0; border: 0; border-radius: 0; box-shadow: none;
  background: transparent; font: 400 1.0625rem/1.4 var(--font); color: var(--text); -webkit-appearance: none; appearance: none;
}
.search-modal .search-bar input:focus { outline: none; box-shadow: none; border: 0; }
.search-modal .search-bar input::placeholder { color: var(--text-dim); }
.search-bar input::-webkit-search-cancel-button { display: none; }
.search-cancel { flex-shrink: 0; border: 0; background: transparent; padding: 0.25rem 0.125rem; cursor: pointer; font: 500 0.875rem/1 var(--font); color: var(--accent); }
.search-cancel:hover { opacity: 0.75; }
.search-body { flex: 1; min-height: 0; overflow-y: auto; padding: 1.125rem 1.25rem 1.5rem; display: flex; flex-direction: column; gap: 1rem; }
/* Nothing in the window shrinks to fit: the window scrolls instead. */
.search-body > *, .search-sources > * { flex-shrink: 0; }
.search-label { font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-dim); margin-top: 0.25rem; }
.search-sources { display: flex; flex-direction: column; gap: 0.5rem; padding-top: 0.5rem; }
.search-sources-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
@media (max-width: 640px) {
  .search-overlay { padding: 0; align-items: stretch; }
  .search-modal { width: 100%; max-height: none; height: 100%; border-radius: 0; border: 0; }
}

/* The reader showing the page itself */
.reader-modes { display: flex; padding: 0.1875rem; border-radius: 62.4375rem; background: var(--surface2); flex-shrink: 0; }
.reader-modes.hidden { display: none; }
.reader-modes button { border: 0; background: transparent; padding: 0.3125rem 0.75rem; border-radius: 62.4375rem; cursor: pointer; font: 600 0.75rem/1 var(--font); color: var(--text-muted); }
.reader-modes button.is-active { background: var(--surface); color: var(--text); box-shadow: var(--shadow-sm); }
.reader-body.is-frame { padding: 0; overflow: hidden; display: flex; flex-direction: column; }
.reader-body.is-frame > * { max-width: none; margin: 0; }
.reader-frame { flex: 1; width: 100%; min-height: 0; border: 0; background: #fff; }
.reader-frame-note { padding: 0.375rem 1rem; font-size: 0.75rem; color: var(--text-dim); border-top: 1px solid var(--border); }

/* Formulas */
.md-math-display { overflow-x: auto; overflow-y: hidden; margin: 0.5rem 0; padding: 0.125rem 0; }
.katex { font-size: 1.05em; }
.md-math { font-size: 0.875em; }

/* The topic, quietly: round icon buttons in the header, one composer per
   task (the field, its tools and its action in one box), no captions. */
.tutor-icon-btn {
  flex-shrink: 0; width: 1.75rem; height: 1.75rem; padding: 0; border-radius: 50%; display: grid; place-items: center; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface); color: var(--text-muted);
  transition: color .15s ease, background .15s ease, border-color .15s ease;
}
.tutor-icon-btn:hover, .tutor-icon-btn:focus-visible, .tutor-icon-btn[aria-expanded="true"] { color: var(--text); border-color: var(--border2); background: var(--surface2); }
.tutor-icon-btn.is-flat { border-color: transparent; background: transparent; width: 1.75rem; height: 1.75rem; }
.tutor-icon-btn.is-flat:hover, .tutor-icon-btn.is-flat:focus-visible { background: var(--surface2); border-color: transparent; }
.tutor-head .tutor-add-wrap { display: grid; }
.tutor-stage { gap: 0; }
.tutor-composer {
  display: flex; flex-direction: column; border-radius: 0.875rem; border: 1px solid var(--border2); background: var(--surface);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.tutor-composer:focus-within { border-color: color-mix(in srgb, var(--accent) 60%, var(--border2)); box-shadow: 0 0 0 0.1875rem color-mix(in srgb, var(--accent) 12%, transparent); }
.tutor-composer textarea {
  display: block; width: 100%; box-sizing: border-box; resize: none; min-height: 4.5rem; margin: 0; padding: 0.75rem 0.875rem 0.375rem;
  border: 0; border-radius: 0.875rem 0.875rem 0 0; background: transparent; box-shadow: none;
  font: 400 0.875rem/1.55 var(--font); color: var(--text);
}
.tutor-composer textarea:focus { outline: none; box-shadow: none; }
.tutor-composer textarea::placeholder { color: var(--text-dim); }
.tutor-composer-bar { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; padding: 0.375rem 0.5rem 0.5rem 0.5rem; }
.tutor-composer-tools { display: flex; align-items: center; gap: 0.125rem; min-width: 0; }
.tutor-composer-bar .btn { flex-shrink: 0; }
.tutor-attached {
  display: inline-flex; align-items: center; gap: 0.3125rem; min-width: 0; padding: 0.1875rem 0.25rem 0.1875rem 0.5rem;
  border-radius: 62.4375rem; background: var(--surface2); font: 500 0.75rem/1.2 var(--font); color: var(--text);
}
.tutor-attached svg { flex-shrink: 0; color: var(--text-muted); }
.tutor-ask { position: relative; display: flex; }
.tutor-ask input {
  flex: 1; min-width: 0; height: 2.375rem; box-sizing: border-box; margin: 0; padding: 0 2.75rem 0 0.875rem;
  border-radius: 62.4375rem; border: 1px solid var(--border2); background: var(--surface); box-shadow: none;
  font: 400 0.8125rem/1 var(--font); color: var(--text);
}
.tutor-ask input:focus { outline: none; border-color: var(--accent); box-shadow: var(--ring); }
.tutor-ask input::placeholder { color: var(--text-dim); }
.tutor-send {
  position: absolute; right: 0.3125rem; top: 50%; transform: translateY(-50%); width: 1.75rem; height: 1.75rem; padding: 0;
  border: 0; border-radius: 50%; display: grid; place-items: center; cursor: pointer; background: var(--accent); color: #fff;
  transition: opacity .15s ease, background .15s ease;
}
.tutor-send:hover:not(:disabled) { background: color-mix(in srgb, var(--accent) 88%, #000); }
.tutor-ask input:placeholder-shown + .tutor-send { opacity: 0.35; }
.tutor-rebuild {
  align-self: flex-start; display: inline-flex; align-items: center; gap: 0.375rem; padding: 0.3125rem 0.625rem; cursor: pointer;
  border-radius: 62.4375rem; border: 1px solid var(--border); background: var(--surface); color: var(--accent); font: 600 0.75rem/1 var(--font);
}
.tutor-rebuild:hover { background: var(--surface2); }
/* Sources read as one grouped list, not a stack of cards. */
.tutor-res-list { gap: 0; border: 1px solid var(--border); border-radius: var(--radius-md); overflow: hidden; background: var(--surface); }
.tutor-res-list .tutor-res { border: 0; border-radius: 0; background: transparent; }
.tutor-res-list .tutor-res + .tutor-res { box-shadow: inset 0 1px 0 var(--border); }
.tutor-res-list .tutor-res:hover, .tutor-res-list .tutor-res:focus-visible { background: var(--surface2); outline: none; }
:root[data-theme="dark"] .tutor-composer .btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .tutor-composer .btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; } }
/* Site icons: shown once loaded, over the generic glyph. */
img.fav { display: none; flex-shrink: 0; width: 1rem; height: 1rem; border-radius: 0.1875rem; object-fit: contain; }
.has-fav > img.fav { display: block; }
.tutor-res-icon.has-fav { background: #fff; box-shadow: inset 0 0 0 1px var(--border); }
.tutor-res-icon.has-fav > svg { display: none; }
.reader-site { display: flex; align-items: center; gap: 0.375rem; }
.reader-site > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.reader-site img.fav { width: 0.875rem; height: 0.875rem; }

/* The pages Chrono's summary drew on, as small site chips under it. */
.chrono-sources { display: flex; flex-wrap: wrap; gap: 0.375rem; margin-top: 0.75rem; padding-top: 0.625rem; border-top: 1px solid color-mix(in srgb, #C8962E 22%, transparent); }
.chrono-src {
  display: inline-flex; align-items: center; gap: 0.375rem; max-width: 100%; height: 1.75rem; padding: 0 0.625rem; cursor: pointer;
  border-radius: 62.4375rem; border: 1px solid color-mix(in srgb, #C8962E 24%, transparent); background: var(--surface);
  font: 500 0.75rem/1 var(--font); color: var(--text);
}
.chrono-src:hover, .chrono-src:focus-visible { border-color: color-mix(in srgb, #C8962E 50%, transparent); outline: none; }
.chrono-src-ico { display: none; }
.chrono-src-ico.has-fav { display: grid; }
.chrono-src-ico img.fav { width: 0.875rem; height: 0.875rem; }
.chrono-src-host { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Quiz me on this, in the reader's side panel */
.reader-side .recall-qs { margin: 0.25rem 0 0; }
.reader-side .recall-a { background: var(--surface); }
.reader-quiz-back {
  align-self: flex-start; display: inline-flex; align-items: center; gap: 0.125rem; margin: 0 0 0 -0.25rem; padding: 0.25rem 0.375rem 0.25rem 0.125rem;
  border: 0; border-radius: 62.4375rem; background: none; cursor: pointer; font: 600 0.8125rem/1 var(--font); color: var(--accent);
}
.reader-quiz-back:hover, .reader-quiz-back:focus-visible { background: color-mix(in srgb, var(--accent) 10%, transparent); outline: none; }

/* Full-screen Study Mode with Chrono beside it: the study panel makes room. */
#screen-app.study-max.chrono-open .study-panel { right: var(--zeno-w, 21.25rem); }
#screen-app.study-max.chrono-open .study-panel-inner { border-right: 1px solid var(--border); }

/* Homework help, Understand: three ways in, then a conversation. */
.tutor-starters { display: flex; flex-wrap: wrap; gap: 0.375rem; }
.tutor-starter {
  padding: 0.5rem 0.8125rem; border-radius: 62.4375rem; border: 0; background: color-mix(in srgb, var(--text) 5%, transparent);
  font: 500 0.8125rem/1.2 var(--font); color: var(--text); cursor: pointer; text-align: left;
  transition: background .15s ease, transform .12s ease;
}
.tutor-starter:hover, .tutor-starter:focus-visible { background: color-mix(in srgb, var(--text) 9%, transparent); outline: none; }
.tutor-starter:active { transform: scale(0.97); }

/* The conversation about a task is Chrono's (studytutor.js, "The
   conversation is Chrono's"): its name over it, in Chrono's gold, and a
   way into Chrono's own panel. */
.tutor-chrono { display: flex; flex-direction: column; gap: 0.625rem; }
.tutor-chrono-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; min-height: 1.75rem; }
.tutor-chrono-name {
  display: inline-flex; align-items: center; gap: 0.375rem;
  font-size: 0.8125rem; font-weight: 600; letter-spacing: -0.005em; color: #A97A1E;
}
.tutor-chrono-open {
  display: inline-flex; align-items: center; gap: 0.3125rem; flex-shrink: 0;
  height: 1.875rem; padding: 0 0.75rem; border-radius: 62.4375rem; cursor: pointer;
  border: 0;
  background: color-mix(in srgb, #E9C46A 16%, var(--surface)); color: #8A6316;
  font: 600 0.75rem/1 var(--font); transition: background .15s ease, border-color .15s ease;
}
.tutor-chrono-open:hover, .tutor-chrono-open:focus-visible {
  background: color-mix(in srgb, #E9C46A 26%, var(--surface)); outline: none;
}
/* The student's side of it looks as it does in Chrono. */
.tutor-chrono .tutor-qa-q {
  background: linear-gradient(160deg, var(--zeno-accent-light), var(--zeno-accent-dim)); color: #fff;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.22), 0 1px 0.125rem rgba(139,105,20,0.18);
}
:root[data-theme="dark"] .tutor-chrono .tutor-qa-q { background: linear-gradient(160deg, #8A6A1F, #6E5315); box-shadow: inset 0 1px 0 rgba(255,255,255,0.15), 0 0.125rem 0.375rem rgba(0,0,0,0.4); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .tutor-chrono .tutor-qa-q { background: linear-gradient(160deg, #8A6A1F, #6E5315); box-shadow: inset 0 1px 0 rgba(255,255,255,0.15), 0 0.125rem 0.375rem rgba(0,0,0,0.4); }
}
.tutor-chrono-away {
  align-items: flex-start; gap: 0.5rem; padding: 1rem 1.0625rem; border-radius: 0.875rem;
  background: color-mix(in srgb, #E9C46A 12%, var(--surface)); border: 1px solid color-mix(in srgb, #C8962E 18%, transparent);
}
.tutor-chrono-away p { margin: 0 0 0.25rem; font-size: 0.875rem; line-height: 1.5; color: var(--text-muted); }
:root[data-theme="dark"] .tutor-chrono-name, :root[data-theme="dark"] .tutor-chrono-open { color: #E9C46A; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .tutor-chrono-name, :root:not([data-theme="light"]) .tutor-chrono-open { color: #E9C46A; }
}
/* On a phone both panels fill the screen: Chrono, opened from a task,
   comes over it, and closing it is the way back. */
@media (max-width: 768px) {
  #screen-app.study-open.chrono-open .zeno-panel { z-index: 310; }
}

/* Progress: what studying changed, per subject (public/js/progress.js). */
.progress-modal .modal-body { display: flex; flex-direction: column; gap: 0.875rem; padding-top: 0.25rem; }
.prog-seg { align-self: flex-start; display: inline-flex; padding: 0.1875rem; border-radius: 62.4375rem; background: var(--surface2); }
.prog-seg button {
  border: 0; background: transparent; padding: 0.375rem 0.875rem; border-radius: 62.4375rem; cursor: pointer;
  font: 600 0.8125rem/1 var(--font); color: var(--text-muted);
}
.prog-seg button.on { background: var(--surface); color: var(--text); box-shadow: var(--shadow-sm); }
/* Where it is all heading (public/js/goal.js), above the period switch:
   the same quiet tile as the Plan's cards, read-only, with Grades one tap
   away to set or change it. */
.prog-goal { display: flex; align-items: center; gap: 0.75rem; padding: 0.75rem 0.875rem; border-radius: 0.875rem; background: var(--surface2); }
.prog-goal-tile {
  --t1: #8C8AF5; --t2: #5856D6; --tile-cut: color-mix(in srgb, var(--t1) 45%, var(--t2));
  flex-shrink: 0; width: 2rem; height: 2rem; display: grid; place-items: center; border-radius: 0.625rem; color: #fff;
  background: linear-gradient(180deg, var(--t1), var(--t2)); box-shadow: inset 0 0.5px 0 rgba(255,255,255,0.3), 0 0.5px 1px rgba(16,24,40,0.08);
}
.prog-goal-tile svg { width: 1.0625rem; height: 1.0625rem; display: block; }
.prog-goal-tile .g-cut { fill: var(--tile-cut); }
.prog-goal.is-empty .prog-goal-tile { --t1: color-mix(in srgb, var(--text) 30%, transparent); --t2: color-mix(in srgb, var(--text) 42%, transparent); }
.prog-goal-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.125rem; }
.prog-goal-title { font-size: 0.9375rem; font-weight: 650; letter-spacing: -0.01em; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.prog-goal.is-empty .prog-goal-title { font-weight: 600; font-size: 0.875rem; }
.prog-goal-sub { display: flex; flex-wrap: wrap; gap: 0 0.5rem; font-size: 0.75rem; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.prog-goal-link { flex-shrink: 0; display: inline-flex; align-items: center; gap: 0.125rem; font-size: 0.8125rem; font-weight: 600; color: var(--accent); text-decoration: none; }
.prog-goal-link svg { width: 0.875rem; height: 0.875rem; }
.prog-goal-link:hover { text-decoration: underline; }
.prog-goal-line { display: flex; flex-wrap: wrap; gap: 0 0.5rem; font-size: 0.75rem; color: var(--text-muted); line-height: 1.4; font-variant-numeric: tabular-nums; }
/* The four numbers as one grouped card, split by hairlines, not four
   loose boxes; the lists below are inset groups in the same surface. */
.prog-tiles {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1px;
  border-radius: 0.875rem; overflow: hidden; background: var(--border); border: 1px solid var(--border);
}
.prog-tile { display: flex; flex-direction: column; gap: 0.1875rem; padding: 0.8125rem 0.875rem 0.75rem; background: var(--surface2); min-width: 0; }
/* The number fits its tile: it shrinks with a narrow tile, and a time too
   long even then breaks between hours and minutes -- never cut off. */
.prog-tile { container-type: inline-size; }
.prog-tile-v { font-size: clamp(1rem, 20cqi, 1.375rem); line-height: 1.1; font-weight: 700; letter-spacing: -0.025em; color: var(--text); font-variant-numeric: tabular-nums; overflow-wrap: normal; }
.prog-tile-l { font-size: 0.75rem; font-weight: 500; color: var(--text-muted); line-height: 1.25; overflow-wrap: break-word; hyphens: auto; }
.prog-tile-n { font-size: 0.6875rem; color: var(--text-dim); line-height: 1.25; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.prog-label { margin: 0.375rem 0 -0.375rem 0.875rem; font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-dim); }
.prog-subjs, .prog-moves {
  list-style: none; margin: 0; padding: 0 0.875rem; display: flex; flex-direction: column;
  border-radius: 0.875rem; background: var(--surface2);
}
.prog-subj { display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto; align-items: center; column-gap: 0.75rem; padding: 0.75rem 0; border-bottom: 1px solid var(--border); }
.prog-subj:last-child { border-bottom: 0; }
.prog-dot { width: 0.5rem; height: 0.5rem; border-radius: 50%; align-self: start; margin-top: 0.375rem; }
.prog-subj-main { min-width: 0; display: flex; flex-direction: column; gap: 0.125rem; }
.prog-subj-name { font-size: 0.9375rem; font-weight: 600; letter-spacing: -0.01em; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.prog-subj-facts, .prog-test { font-size: 0.75rem; color: var(--text-muted); line-height: 1.35; }
.prog-test { color: var(--text-dim); }
.prog-spark { width: 4.5rem; height: auto; }
.prog-subj.is-unscored .prog-subj-num { grid-column: 3 / 5; }
.prog-subj-num { display: flex; flex-direction: column; align-items: flex-end; gap: 0.25rem; min-width: 3.5rem; }
.prog-subj-num b { font-size: 1.0625rem; font-weight: 700; letter-spacing: -0.02em; line-height: 1; font-variant-numeric: tabular-nums; color: var(--text); }
.prog-unscored { font-size: 0.75rem; color: var(--text-dim); }
.prog-delta { font-size: 0.6875rem; font-weight: 650; line-height: 1.35; padding: 0 0.375rem; border-radius: 62.4375rem; font-variant-numeric: tabular-nums; }
.prog-delta.up { color: #15803D; background: color-mix(in srgb, #16A34A 13%, transparent); }
.prog-delta.down { color: #B91C1C; background: color-mix(in srgb, #DC2626 11%, transparent); }
.prog-delta.flat { color: var(--text-dim); background: var(--surface); }
:root[data-theme="dark"] .prog-delta.up { color: #4ADE80; }
:root[data-theme="dark"] .prog-delta.down { color: #F87171; }
.prog-move { display: flex; align-items: center; gap: 0.75rem; padding: 0.625rem 0; border-bottom: 1px solid var(--border); }
.prog-move:last-child { border-bottom: 0; }
.prog-move-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.0625rem; }
.prog-move-topic { font-size: 0.875rem; font-weight: 500; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.prog-move-subj { font-size: 0.75rem; color: var(--text-dim); }
.prog-move-nums { flex-shrink: 0; font-size: 0.8125rem; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.prog-move-nums b { font-weight: 650; color: #15803D; }
.is-slipping .prog-move-nums b { color: #B45309; }
:root[data-theme="dark"] .prog-move-nums b { color: #4ADE80; }
:root[data-theme="dark"] .is-slipping .prog-move-nums b { color: #FBBF24; }
.prog-empty { padding: 1.5rem 0.5rem 1rem; text-align: center; }
.prog-empty-title { font-size: 0.9375rem; font-weight: 650; color: var(--text); margin-bottom: 0.375rem; }
.prog-empty-text { margin: 0; font-size: 0.8125rem; line-height: 1.5; color: var(--text-muted); }
.prog-foot { margin: 0.25rem 0 0; font-size: 0.75rem; line-height: 1.5; color: var(--text-dim); }
.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 (max-width: 560px) {
  .prog-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .prog-spark { display: none; }
  .prog-subj { grid-template-columns: auto minmax(0, 1fr) auto; }
  .prog-subj.is-unscored .prog-subj-num { grid-column: auto; }
}

/* The coach's cards on the Plan (public/js/coach.js): the shared card above,
   amber only for study that slipped, like a deadline. */
/* The week ahead: what it holds, and a bar per day. */
.plan-coach-week { align-items: flex-start; }
.coach-tests { list-style: none; margin: 0.625rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.375rem; }
.coach-tests li { display: flex; align-items: center; gap: 0.5rem; font-size: 0.8125rem; min-width: 0; }
.coach-test-name { font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.coach-test-when { color: var(--text-muted); white-space: nowrap; }
.coach-test-ready { flex-shrink: 0; padding: 0.0625rem 0.4375rem; border-radius: 62.4375rem; font-size: 0.6875rem; font-weight: 600; font-variant-numeric: tabular-nums;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.coach-test-ready.is-unchecked { color: var(--text-muted); background: color-mix(in srgb, var(--text) 6%, transparent); }
.coach-week { flex-shrink: 0; align-self: center; display: flex; align-items: flex-end; gap: 0.375rem; }
.coach-day { display: flex; flex-direction: column; align-items: center; gap: 0.3125rem; }
.coach-bar { width: 0.5rem; border-radius: 0.1875rem; background: var(--accent); }
.coach-day.is-off .coach-bar { background: color-mix(in srgb, var(--text) 12%, transparent); }
.coach-dlabel { font-size: 0.625rem; font-weight: 600; color: var(--text-dim); text-transform: uppercase; }
/* A day with a test: its letter in the deadline colour. */
.coach-day.has-test .coach-dlabel { color: var(--plan-due-ink, #B45309); }
.plan-coach-week .plan-card-actions { align-self: center; margin-left: 0.25rem; }
/* The week, opened: the total, a bar a day, the tests. */
.cw { display: flex; flex-direction: column; gap: 1.25rem; }
.cw-head { display: flex; flex-direction: column; gap: 0.125rem; }
.cw-total { font-size: 2rem; font-weight: 800; letter-spacing: -0.02em; line-height: 1.1; color: var(--text); font-variant-numeric: tabular-nums; }
.cw-heavy { font-size: 0.8125rem; color: var(--text-muted); }
.cw-chart { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 0.375rem; padding: 0.875rem 0.75rem 0.75rem; border-radius: 1rem; background: var(--surface2); }
.cw-day { display: flex; flex-direction: column; align-items: center; gap: 0.25rem; min-width: 0; }
.cw-time { height: 1rem; font-size: 0.625rem; font-weight: 700; color: var(--text-muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
.cw-col { position: relative; display: flex; align-items: flex-end; justify-content: center; width: 100%; height: 6.5rem; }
.cw-bar { width: min(1.75rem, 70%); border-radius: 0.5rem 0.5rem 0.3125rem 0.3125rem; background: color-mix(in srgb, var(--accent) 55%, transparent); transition: height 0.4s var(--ease); }
.cw-day.is-heavy .cw-bar { background: var(--accent); }
.cw-day.is-off .cw-col::after { content: ''; width: 0.375rem; height: 0.375rem; border-radius: 50%; background: color-mix(in srgb, var(--text) 14%, transparent); }
.cw-name { margin-top: 0.25rem; font-size: 0.6875rem; font-weight: 600; color: var(--text-muted); text-transform: capitalize; }
.cw-date { font-size: 0.8125rem; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.cw-day.is-today .cw-date { display: inline-grid; place-items: center; min-width: 1.5rem; height: 1.5rem; border-radius: 50%; background: var(--text); color: var(--surface); }
.cw-test { width: 0.375rem; height: 0.375rem; border-radius: 50%; background: var(--plan-due-ink, #B45309); }
.cw-test.is-none { background: transparent; }
.cw-tests { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.cw-test-row { display: flex; align-items: center; gap: 0.75rem; padding: 0.75rem 0; border-top: 1px solid var(--border); min-width: 0; }
.cw-test-row:first-child { border-top: 0; padding-top: 0; }
.cw-test-dot { flex-shrink: 0; width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--plan-due-ink, #B45309); }
.cw-test-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.0625rem; }
.cw-test-name { font-size: 0.9375rem; font-weight: 600; color: var(--text); overflow-wrap: anywhere; }
.cw-test-when { font-size: 0.8125rem; color: var(--text-muted); text-transform: capitalize; }
@media (max-width: 560px) {
  .coach-week { display: none; }
  /* The test's name on its own line, its day and readiness under it. */
  .coach-tests { gap: 0.5rem; }
  .coach-tests li { flex-wrap: wrap; row-gap: 0.125rem; }
  .coach-test-name { flex-basis: 100%; }
}
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .prog-delta.up { color: #4ADE80; }
  :root:not([data-theme="light"]) .prog-delta.down { color: #F87171; }
  :root:not([data-theme="light"]) .prog-move-nums b { color: #4ADE80; }
  :root:not([data-theme="light"]) .is-slipping .prog-move-nums b { color: #FBBF24; }
}

/* "Photograph your diary instead", at the top of a new homework form. */
.academic-photo-link { display: flex; align-items: center; gap: 0.75rem; width: 100%; margin: 0 0 1rem; padding: 0.75rem 0.875rem; border-radius: 0.75rem;
  border: 1px dashed var(--border); background: transparent; color: var(--text); text-align: left; cursor: pointer; font: inherit;
  transition: border-color .15s ease, background .15s ease; }
.academic-photo-link:hover { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 6%, transparent); }
.academic-photo-link > svg { flex-shrink: 0; color: var(--accent); }
.academic-photo-text { display: flex; flex-direction: column; gap: 0.125rem; min-width: 0; }
.academic-photo-text b { font-size: 0.875rem; font-weight: 600; }
.academic-photo-text span { font-size: 0.7812rem; color: var(--text-muted); }

/* Homework, ready when it is opened (studytutor.js homeworkPrepHtml): the
   exercise photo first, then the exercise itself and what was said in class. */
.tutor-need { display: flex; flex-direction: column; gap: 0.875rem; padding: 1rem 1.0625rem; border-radius: 0.875rem;
  background: color-mix(in srgb, var(--accent) 7%, var(--surface)); border: 1px solid color-mix(in srgb, var(--accent) 14%, transparent); }
.tutor-need-text { display: flex; flex-direction: column; gap: 0.25rem; }
.tutor-need-text b { font-size: 0.9375rem; font-weight: 600; letter-spacing: -0.01em; color: var(--text); }
.tutor-need-text span { font-size: 0.8125rem; line-height: 1.45; color: var(--text-muted); }
.tutor-need-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.tutor-need-actions .pill-btn { gap: 0.4375rem; padding-left: 0.8125rem; }
.tutor-need-actions .pill-btn svg { width: 1rem; height: 1rem; }
.tutor-exercise, .tutor-class { border: 1px solid var(--border); border-radius: 0.75rem; background: var(--surface); }
.tutor-exercise > summary, .tutor-class > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: 0.5rem;
  padding: 0.625rem 0.875rem; font-size: 0.8125rem; font-weight: 600; color: var(--text); }
.tutor-exercise > summary::-webkit-details-marker, .tutor-class > summary::-webkit-details-marker { display: none; }
.tutor-exercise > summary::after, .tutor-class > summary::after { content: ''; margin-left: auto; width: 0.4375rem; height: 0.4375rem; flex-shrink: 0;
  border-right: 1.6px solid var(--text-muted); border-bottom: 1.6px solid var(--text-muted); transform: rotate(45deg) translateY(-0.125rem); transition: transform .15s ease; }
.tutor-exercise[open] > summary::after, .tutor-class[open] > summary::after { transform: rotate(225deg) translateY(-1px); }
.tutor-exercise-body { padding: 0 0.875rem 0.75rem; font-size: 0.875rem; line-height: 1.55; max-height: 22rem; overflow: auto; }
.tutor-class-tag { flex-shrink: 0; padding: 1px 0.4375rem; border-radius: 62.4375rem; font-size: 0.6875rem; font-weight: 700; letter-spacing: .02em;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.tutor-class-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tutor-class-day { flex-shrink: 0; font-weight: 500; color: var(--text-muted); }
.tutor-class-notes { margin: 0; padding: 0 0.875rem 0.75rem 2rem; font-size: 0.8125rem; line-height: 1.5; color: var(--text-muted); }

/* What you've covered: a subject's notebook, in its window (app.js
   renderNotebook). Lessons and material newest first, nothing to file. */
.sf-notebook { display: flex; flex-direction: column; gap: 0.625rem; margin-top: 1.125rem; padding-top: 1rem; border-top: 1px solid var(--border); }
.sf-teacher { display: flex; align-items: center; gap: 0.625rem; margin: 0 0 0.75rem; padding: 0.375rem 0.625rem; border-radius: 0.625rem; background: var(--surface2); cursor: text; }
.sf-teacher-label { flex-shrink: 0; font-size: 0.6875rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted); }
.sf-teacher input { flex: 1; min-width: 0; border: 0; background: none; padding: 0.125rem 0; font: inherit; font-size: 0.875rem; font-weight: 600; color: var(--text); text-align: right; }
.sf-teacher input::placeholder { font-weight: 500; color: var(--text-dim); }
.sf-teacher input:focus { outline: none; }
.sf-teacher:focus-within { box-shadow: 0 0 0 0.125rem color-mix(in srgb, var(--accent) 35%, transparent); }
.sf-nb-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.sf-nb-title { font-size: 0.6875rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted); }
.sf-nb-add-wrap { position: relative; }
.sf-nb-add { border: 0; background: none; padding: 0.25rem 0.375rem; font: inherit; font-size: 0.8125rem; font-weight: 600; color: var(--accent); cursor: pointer; border-radius: 0.5rem; }
.sf-nb-add:hover { background: color-mix(in srgb, var(--accent) 10%, transparent); }
.sf-nb-menu { position: absolute; right: 0; top: calc(100% + 0.25rem); z-index: 5; min-width: 11rem; display: flex; flex-direction: column; padding: 0.25rem;
  border-radius: 0.625rem; border: 1px solid var(--border); background: var(--surface); box-shadow: 0 0.625rem 1.75rem rgba(15, 23, 42, 0.14); }
.sf-nb-opt { display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem 0.625rem; border: 0; background: none; border-radius: 0.4375rem;
  font: inherit; font-size: 0.8125rem; color: var(--text); text-align: left; cursor: pointer; }
.sf-nb-opt:hover { background: var(--surface2); }
.sf-nb-paste { display: flex; flex-direction: column; gap: 0.5rem; }
.sf-nb-paste textarea { width: 100%; box-sizing: border-box; resize: vertical; font: inherit; font-size: 0.8125rem; padding: 0.5rem 0.625rem;
  border-radius: 0.625rem; border: 1px solid var(--border); background: var(--bg); color: var(--text); }
.sf-nb-paste-bar { display: flex; justify-content: flex-end; gap: 0.375rem; }
.sf-nb-list { display: flex; flex-direction: column; border: 1px solid var(--border); border-radius: 0.75rem; overflow: hidden; background: var(--surface); }
.sf-nb-row { display: flex; align-items: center; gap: 0.625rem; width: 100%; padding: 0.5625rem 0.75rem; border: 0; background: none;
  font: inherit; color: var(--text); text-align: left; cursor: pointer; transition: background .12s ease; }
.sf-nb-row + .sf-nb-row { border-top: 1px solid var(--border); }
.sf-nb-row:hover { background: var(--surface2); }
.sf-nb-ico { flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; width: 1.75rem; height: 1.75rem; border-radius: 0.5rem;
  color: var(--text-muted); background: var(--surface2); }
.sf-nb-ico.is-lesson { color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.sf-nb-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.sf-nb-name { font-size: 0.8125rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sf-nb-sub { font-size: 0.75rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sf-nb-day { flex-shrink: 0; font-size: 0.75rem; color: var(--text-muted); }
.sf-nb-more { align-self: flex-start; border: 0; background: none; padding: 0.125rem 0; font: inherit; font-size: 0.8125rem; font-weight: 600; color: var(--accent); cursor: pointer; }
.sf-nb-mistakes { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; padding: 0.625rem 0.75rem; border-radius: 0.75rem;
  font-size: 0.8125rem; color: var(--text); background: color-mix(in srgb, #F59E0B 10%, transparent); border: 1px solid color-mix(in srgb, #F59E0B 28%, transparent); }
.sf-nb-empty { margin: 0; font-size: 0.8125rem; line-height: 1.5; color: var(--text-muted); }
.nb-source-modal { max-width: 35rem; }
.nb-source-body { max-height: 70vh; overflow: auto; font-size: 0.9375rem; line-height: 1.6; }
.sf-nb-body { display: flex; flex-direction: column; gap: 0.5rem; }

/* Checking step by step (studytutor.js): their lines, right up to the
   first one that goes wrong; then the cleanest way, once it is right; and
   the homework back from the teacher. */
.tutor-lines { list-style: none; margin: 0; padding: 0.375rem 0; border-radius: 0.75rem; border: 1px solid var(--border); background: var(--surface); font-size: 0.875rem; }
.tutor-lines li { display: flex; align-items: baseline; gap: 0.5rem; padding: 0.3125rem 0.75rem; }
.tutor-line-mark { flex: 0 0 1rem; text-align: center; font-weight: 700; font-size: 0.75rem; }
.tutor-lines li.is-ok .tutor-line-mark { color: #16A34A; }
.tutor-lines li.is-wrong { background: color-mix(in srgb, #DC2626 8%, transparent); }
.tutor-lines li.is-wrong .tutor-line-mark { color: #DC2626; }
.tutor-lines li:not(.is-ok):not(.is-wrong) { color: var(--text-muted); }
.tutor-line-text { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.tutor-line-here { flex-shrink: 0; font-size: 0.75rem; font-weight: 600; color: #DC2626; }
.tutor-saved { display: flex; align-items: flex-start; gap: 0.375rem; margin-top: 0.25rem; font-size: 0.75rem; line-height: 1.45; color: var(--text-muted); }
.tutor-saved svg { flex-shrink: 0; margin-top: 0.0625rem; color: var(--accent); }
.tutor-corrected-link { align-self: flex-start; display: inline-flex; align-items: center; gap: 0.4375rem; padding: 0.375rem 0.625rem 0.375rem 0.5rem; margin-left: -0.5rem;
  border-radius: 62.4375rem; font-size: 0.8125rem; color: var(--text-muted); cursor: pointer; transition: background .15s ease, color .15s ease; }
.tutor-corrected-link svg { width: 0.9375rem; height: 0.9375rem; flex-shrink: 0; }
.tutor-corrected-link:hover { color: var(--text); background: color-mix(in srgb, var(--text) 5%, transparent); }
.tutor-corrected-link.is-busy { cursor: progress; text-decoration: none; }
.tutor-correction { display: flex; flex-direction: column; gap: 0.375rem; padding: 0.875rem 1rem; border-radius: 0.875rem; border: 1px solid var(--border); background: var(--surface); font-size: 0.875rem; line-height: 1.5; }
.tutor-correction-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.tutor-correction-grade { padding: 1px 0.5rem; border-radius: 62.4375rem; font-weight: 700; font-size: 0.8125rem; background: var(--surface2); }
.tutor-correction-marks { margin: 0; padding-left: 1.125rem; }
.tutor-correction-focus { font-size: 0.8125rem; color: var(--text-muted); }
.tutor-msg-cleanest .md-body :is(ol, ul) { margin: 0.25rem 0; padding-left: 1.375rem; }

/* Homework help: one conversation (studytutor.js, "Homework: one
   conversation"). Hints and checks are messages in the thread; the
   composer asks, asks for a hint, or has the working checked. */
.tutor-talk-lede { margin: 0; font-size: 0.8125rem; line-height: 1.5; color: var(--text-muted); }
.tutor-msg-ask { display: inline-flex; align-items: center; gap: 0.375rem; }
.tutor-msg-work.is-text { font-variant-numeric: tabular-nums; display: flex; flex-direction: column; gap: 0.125rem; }
.tutor-msg-work:not(.is-text) { display: inline-flex; align-items: center; gap: 0.375rem; }
.tutor-msg-work svg, .tutor-msg-ask svg { flex-shrink: 0; opacity: 0.9; }
.tutor-qa-a .md-body p { margin: 0 0 0.375rem; }
.tutor-qa-a .md-body p:last-child { margin-bottom: 0; }
/* What a message is, over it: a word with its mark, in sentence case. */
.tutor-msg-tag { display: flex; align-items: center; gap: 0.375rem; margin-bottom: 0.3125rem; font-size: 0.75rem; font-weight: 600; color: var(--text); }
.tutor-msg-tag svg { flex-shrink: 0; }
.tutor-msg-tag.is-hint, .tutor-msg-tag.is-cleanest { color: #A97A1E; }
:root[data-theme="dark"] .tutor-msg-tag.is-hint, :root[data-theme="dark"] .tutor-msg-tag.is-cleanest { color: #E9C46A; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .tutor-msg-tag.is-hint, :root:not([data-theme="light"]) .tutor-msg-tag.is-cleanest { color: #E9C46A; } }
.tutor-msg-dot { width: 0.5rem; height: 0.5rem; border-radius: 50%; flex-shrink: 0; background: var(--amber); }
.mark-right .tutor-msg-dot { background: var(--green); }
.mark-wrong .tutor-msg-dot { background: #EF4444; }
.tutor-msg-check { display: flex; flex-direction: column; gap: 0.25rem; }
.tutor-msg-check .tutor-msg-tag { margin-bottom: 0.125rem; }
.tutor-msg-check .tutor-lines { margin: 0.25rem 0 0.375rem; }
.tutor-check-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 0.5rem; margin-top: 0.5rem; }
.tutor-check-actions .pill-btn { height: 2rem; }
.tutor-talk-composer textarea { min-height: 3.25rem; }
.tutor-talk-composer .tutor-attached { margin: 0.5rem 0.625rem 0; align-self: flex-start; }
.tutor-talk-actions { display: flex; align-items: center; gap: 0.375rem; flex-shrink: 0; }
.tutor-talk-actions .tutor-send { position: static; transform: none; width: 2rem; height: 2rem; }
/* Hint and Check my work: tinted pills, the composer's own. */
.tutor-act {
  display: inline-flex; align-items: center; gap: 0.3125rem; height: 2rem; padding: 0 0.75rem;
  border-radius: 62.4375rem; border: 0; background: color-mix(in srgb, var(--text) 6%, transparent); color: var(--text);
  font: 600 0.75rem/1 var(--font); cursor: pointer; white-space: nowrap;
  transition: background .15s ease, transform .12s ease;
}
.tutor-act:hover:not(:disabled), .tutor-act:focus-visible { background: color-mix(in srgb, var(--text) 10%, transparent); outline: none; }
.tutor-act:active:not(:disabled) { transform: scale(0.96); }
.tutor-act:disabled, .tutor-talk-actions .tutor-send:disabled { opacity: 0.45; cursor: default; }
#tutor-act-hint svg { color: #A97A1E; }
#tutor-act-check svg { color: var(--green); }
@media (max-width: 400px) { .tutor-talk-actions .tutor-act > span { display: none; } .tutor-act { padding: 0; width: 2rem; justify-content: center; } }
/* The panel can be narrow on a wide screen too (Study Mode beside the
   calendar): the hint and check buttons go to icons by the composer's own
   width, before the attach icon and the send button run into them. */
.tutor-talk-composer { container-type: inline-size; }
@container (max-width: 26rem) {
  .tutor-talk-actions .tutor-act > span { display: none; }
  .tutor-talk-actions .tutor-act { padding: 0; width: 2rem; justify-content: center; }
}

/* ── Centred on the capitals ──────────────────────────────────────────────
   A label or a digit is centred by its line box, and every font sits its
   glyphs a little high or low in it (the 3 in a circle rode a pixel up).
   Trimmed to cap height and baseline, the letters themselves are what is
   centred, as Apple centres them. Where text-box isn't supported nothing
   changes. */
.plan-recall-icon > b, .pill-btn > span, .plan-start > span, .plan-done-pill:not(.plan-progress-pill) > span,
.tutor-act > span, .dz-btn > span, .dz-streak > b {
  display: block; text-box: trim-both cap alphabetic;
}
.plan-recall-icon > b { font-weight: inherit; }

/* ── Glass or plain: decided by where a control sits ─────────────────────
   Apple's rule (iOS 26): glass is the layer that floats over content --
   bars, popovers, the things content scrolls under -- because there is
   something behind it to show. A control inside the content (a card's
   action, a row's Start, the chips in a conversation) is plain: a solid
   fill when it is the thing to do, a tint when it is the other choice.
   So here:
   - glass: the top bar, the Plan | Calendar dock and the cards floating
     over the Plan (free time, urgent homework), each with its own styles;
   - plain: everything inside the Plan's cards and rows, the Plan's header
     pills, and study help.
   What every button keeps is the press: a quick spring back. That is
   motion, not gloss. No backdrop blur on buttons (see "Smoothness"). */
:root { --lg-spring: cubic-bezier(0.34, 1.56, 0.64, 1); }

/* Plain, with a spring: every button in the content. */
.pill-btn, .plan-start, .tutor-send, .plan-done-pill, .tutor-act, .tutor-starter, .tutor-chrono-open {
  transition: transform 0.45s var(--lg-spring), background 0.15s ease, color 0.15s ease;
}
.pill-btn:active, .plan-start:active, .tutor-send:active:not(:disabled), .plan-done-pill:active,
.tutor-act:active:not(:disabled), .tutor-starter:active, .tutor-chrono-open:active {
  transform: scale(0.94); transition-duration: 0.1s;
}

@media (prefers-reduced-motion: reduce) {
  .pill-btn, .plan-start, .tutor-send, .plan-done-pill, .tutor-act, .tutor-starter, .tutor-chrono-open { transition: none; }
}

/* Study help's filled glyphs (glyphs.js): the bulb in Chrono's gold, the
   check in green with its tick cut out of the button behind it. */
.tutor-act svg, .tutor-msg-tag svg, .tutor-msg-ask svg { width: 0.9375rem; height: 0.9375rem; flex-shrink: 0; }
.tutor-act .g-cut-s, .tutor-msg-tag .g-cut-s { fill: none; stroke: var(--surface); stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.tutor-need-head { display: flex; align-items: center; gap: 0.875rem; }
.tutor-need-head .plan-recall-icon { margin: 0; }
.tutor-need-actions { padding-left: 3rem; }
@media (max-width: 400px) { .tutor-need-actions { padding-left: 0; } }

/* Date and time fields in the app's language (public/js/dateLocal.js): at
   rest the value is drawn in the field's background, so the native text --
   in the device's language -- hides. With focus it comes back. */
input.dlz-on::-webkit-datetime-edit { opacity: 0; }
input.dlz-on::-webkit-date-and-time-value { opacity: 0; }
@supports (-moz-appearance: none) { input.dlz-on { color: transparent; } }

/* Auto-Schedule result: what moved, under the time it found. */
.rs-moved-head { margin: 1.25rem 0 0; font-size: 0.8125rem; font-weight: 600; color: var(--text); text-align: left; }
.rs-moved-list { margin-top: 0.5rem; }
.rs-was { overflow: hidden; text-overflow: ellipsis; }

/* ── Quick add (quickadd.js) ──────────────────────────────────────────────────
   One line near the top of the screen, Spotlight-like: it stays clear of a
   phone's keyboard, and what was understood sits right under it as chips. */
.qa-overlay {
  /* Above the corner cards (300), below the toasts (310) that report on it. */
  position: fixed; inset: 0; z-index: 305;
  display: flex; justify-content: center; align-items: flex-start;
  padding: max(12vh, 4.5rem) 1rem 1rem;
  background: rgba(17,24,39,0.28);
  animation: overlay-in 0.22s var(--ease);
}
.qa-overlay.hidden { display: none; }
.qa-sheet {
  width: 38rem; max-width: 100%;
  background: var(--surface); border: 1px solid var(--border); border-radius: 1.125rem;
  box-shadow: 0 1.5rem 4rem rgba(17,24,39,0.18), 0 0.125rem 0.5rem rgba(17,24,39,0.06);
  padding: 0.5rem 0.5rem 0.625rem;
  animation: modal-in 0.32s var(--ease-spring);
}
.qa-line { display: flex; align-items: center; gap: 0.25rem; }
.qa-input {
  flex: 1; min-width: 0;
  font: inherit; font-size: 1.125rem; font-weight: 500; color: var(--text);
  background: transparent; border: 0; outline: 0;
  padding: 0.75rem 0.75rem 0.625rem;
}
.qa-input::placeholder { color: var(--text-dim); font-weight: 400; }
.qa-field { position: relative; flex: 1; min-width: 0; display: flex; }
/* What the line was read as: a tint on the words themselves, drawn on a
   copy of the line laid over it. A tap on one keeps it as plain words. */
.qa-hl {
  position: absolute; inset: 0; pointer-events: none;
  overflow: hidden; white-space: pre; color: transparent;
}
.qa-mark {
  pointer-events: auto; cursor: pointer; border-radius: 0.3125rem;
  background: color-mix(in srgb, var(--accent) 15%, transparent);
  box-shadow: 0 0 0 0.125rem color-mix(in srgb, var(--accent) 15%, transparent);
  transition: background 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
.qa-mark:hover {
  background: color-mix(in srgb, var(--accent) 24%, transparent);
  box-shadow: 0 0 0 0.125rem color-mix(in srgb, var(--accent) 24%, transparent);
}
.qa-mark.is-off {
  background: transparent; box-shadow: none;
  text-decoration: underline dotted var(--text-dim); text-decoration-thickness: 1.5px; text-underline-offset: 0.3em;
}
.qa-mark.is-off:hover { text-decoration-color: var(--text-muted); }
.qa-photo {
  flex: none; width: 2.5rem; height: 2.5rem; border-radius: 0.75rem;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 0; color: var(--text-muted);
  transition: background 0.18s var(--ease), color 0.18s var(--ease);
}
.qa-photo:hover { background: var(--surface2); color: var(--text); }
.qa-chips {
  /* One row while it fits; a chip that would run off the sheet goes on to
     the next line, and only that one. */
  display: flex; flex-wrap: wrap; gap: 0.3125rem; padding: 0.125rem 0.625rem 0.5rem;
}
.qa-chips > .qa-chip { max-width: 100%; }
.qa-chips .qa-chip-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.qa-chips::-webkit-scrollbar { display: none; }
.qa-chips > .qa-chip { flex: none; }
.qa-chip {
  position: relative; display: inline-flex; align-items: center; gap: 0.375rem;
  height: 1.875rem; padding: 0 0.625rem; border-radius: 62.4375rem;
  background: var(--surface2); color: var(--text);
  font-size: 0.8125rem; font-weight: 600; white-space: nowrap;
  transition: background 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
.qa-chip { cursor: pointer; user-select: none; -webkit-user-select: none; }
.qa-chip:hover, .qa-chip.is-open { background: var(--surface3); }
.qa-chip:focus-visible { outline: none; box-shadow: var(--ring); }
.qa-chev { flex: none; color: var(--text-dim); margin-right: -0.125rem; transition: transform 0.18s var(--ease); }
.qa-chip.is-open .qa-chev { transform: rotate(180deg); }
.qa-ico { flex: none; color: var(--text-muted); }
.qa-chip.hidden { display: none; }
.qa-chip.is-empty { color: var(--text-muted); font-weight: 500; }
/* A day taken from the timetable rather than from what was typed. */
.qa-chip.is-guess { color: var(--accent-dim); }
/* ── The chips' menus (quickadd.js): drawn by the app, not the system ── */
.qa-sheet { position: relative; }
.qa-pop {
  position: absolute; z-index: 2; min-width: 12rem; max-width: calc(100% - 1rem);
  max-height: 16.5rem; overflow-y: auto; overscroll-behavior: contain;
  padding: 0.3125rem; border-radius: 0.875rem;
  background: var(--surface); border: 1px solid var(--border);
  box-shadow: 0 1rem 2.5rem rgba(17,24,39,0.16), 0 0.125rem 0.375rem rgba(17,24,39,0.06);
  animation: qa-pop-in 0.16s var(--ease);
}
.qa-pop.hidden { display: none; }
@keyframes qa-pop-in { from { opacity: 0; transform: translateY(-0.25rem) scale(0.98); } to { opacity: 1; transform: none; } }
.qa-opt {
  display: flex; align-items: center; gap: 0.5rem; width: 100%;
  min-height: 2.25rem; padding: 0 0.625rem; border: 0; border-radius: 0.5625rem;
  background: none; color: var(--text); font: inherit; font-size: 0.875rem; text-align: left; cursor: pointer;
}
.qa-opt:hover, .qa-opt:focus-visible { background: var(--surface2); outline: none; }
.qa-opt.is-on { font-weight: 600; }
.qa-opt-text { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.qa-opt-tick { flex: none; color: var(--accent); }
.qa-pop-item { width: 18rem; }
.qa-opt-item { min-height: 2.75rem; padding-top: 0.375rem; padding-bottom: 0.375rem; }
.qa-opt-item .qa-opt-text { display: flex; flex-direction: column; gap: 0.0625rem; }
.qa-opt-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.qa-opt-sub { font-size: 0.75rem; font-weight: 400; color: var(--text-muted); }
.qa-chip-item .qa-chip-text { max-width: 9rem; overflow: hidden; text-overflow: ellipsis; }
.qa-pop-time { min-width: 9rem; }
.qa-pop-empty { padding: 0.625rem; font-size: 0.8125rem; color: var(--text-muted); }
/* The day: Today and Tomorrow first, then the month. */
.qa-pop-date { width: 17.5rem; max-height: none; padding: 0.625rem; }
.qa-cal-quick { display: grid; grid-template-columns: 1fr 1fr; gap: 0.375rem; margin-bottom: 0.625rem; }
.qa-cal-chip {
  height: 2rem; border: 0; border-radius: 0.625rem; background: var(--surface2); color: var(--text);
  font: inherit; font-size: 0.8125rem; font-weight: 600; cursor: pointer;
}
.qa-cal-chip:hover { background: var(--surface3); }
.qa-cal-chip.is-on { background: var(--accent); color: #fff; }
.qa-cal-head { display: flex; align-items: center; gap: 0.25rem; margin: 0 0.125rem 0.375rem 0.25rem; }
.qa-cal-title { flex: 1; font-size: 0.8125rem; font-weight: 650; color: var(--text); }
.qa-cal-title::first-letter { text-transform: uppercase; }
.qa-cal-nav {
  display: inline-flex; align-items: center; justify-content: center; width: 1.75rem; height: 1.75rem;
  border: 0; border-radius: 50%; background: none; color: var(--text-muted); cursor: pointer;
}
.qa-cal-nav:hover { background: var(--surface2); color: var(--text); }
.qa-cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0.125rem; }
.qa-cal-wd { text-align: center; font-size: 0.6875rem; font-weight: 600; color: var(--text-dim); padding: 0.25rem 0; text-transform: uppercase; }
.qa-cal-day {
  aspect-ratio: 1; border: 0; border-radius: 50%; background: none; color: var(--text);
  font: inherit; font-size: 0.8125rem; font-variant-numeric: tabular-nums; cursor: pointer;
}
.qa-cal-day:hover { background: var(--surface2); }
.qa-cal-day.is-past { color: var(--text-dim); }
.qa-cal-day.is-today { color: var(--accent); font-weight: 700; }
.qa-cal-day.is-on { background: var(--accent); color: #fff; font-weight: 700; }
.qa-dot { width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--border2); flex: none; }
.qa-chip-subject.is-empty .qa-dot { display: none; }
.qa-chip.qa-nudge { animation: qa-nudge 0.42s var(--ease); box-shadow: var(--ring); }
@keyframes qa-nudge { 20% { transform: translateX(-0.1875rem); } 45% { transform: translateX(0.1875rem); } 70% { transform: translateX(-0.125rem); } }
.qa-foot {
  display: flex; align-items: center; justify-content: flex-end; gap: 0.5rem;
  padding: 0.5rem 0.375rem 0; border-top: 1px solid var(--border);
}
.qa-more { margin-right: auto; color: var(--text-muted); }
.qa-add { min-width: 5.5rem; }
.qa-add .spinner { display: inline-block; vertical-align: middle; width: 0.9375rem; height: 0.9375rem; border-color: rgba(255,255,255,0.35); border-top-color: #fff; }
@media (max-width: 600px) {
  .qa-overlay { padding-top: max(env(safe-area-inset-top), 0.75rem); }
  .qa-sheet { border-radius: 1rem; }
  .qa-input { font-size: 1.0625rem; }
}
@media (prefers-reduced-motion: reduce) { .qa-sheet, .qa-overlay, .qa-chip.qa-nudge { animation: none; } }

/* The line is the sheet's own surface, not a field inside it: no box, no
   ring (the app-wide input:focus above would draw both). */
.qa-sheet .qa-input, .qa-sheet .qa-input:focus { border: 0; box-shadow: none; background: transparent; outline: none; width: auto; }

/* ── Exams ahead (recall.js) ──────────────────────────────────────────────────
   The top of the Plan: one card per exam in the next two weeks, in a row
   that slides. The ring is how ready; Check me and the guess are what to do
   about it.

   Two cards fit a computer's column; on a phone one, with the edge of the
   next showing so it is plain there is more, and the row runs to the
   screen's edges. Each slide stops on a card. The arrows are for a mouse;
   a finger swipes. A card says three things: the exam, when, and how
   ready -- the rest is in the exam's own view, a tap away. */
.plan-exams { display: flex; flex-direction: column; gap: 0.625rem; container-type: inline-size; }
.pe-head { display: flex; flex-wrap: wrap; align-items: center; gap: 0.125rem 0.5rem; padding: 0 0.25rem; min-height: 1.875rem; }
.pe-heading { white-space: nowrap; margin: 0; font-size: 1.1875rem; font-weight: 700; letter-spacing: -0.018em; color: var(--text); }
.pe-score { margin-left: auto; font-size: 0.8125rem; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.pe-nav { display: none; gap: 0.375rem; margin-left: auto; }
.pe-score + .pe-nav { margin-left: 0.625rem; }
.plan-exams.is-scrollable .pe-nav { display: flex; }
.pe-arrow {
  /* Quiet: a bare chevron in the header's grey, a soft disc only on hover. */
  display: grid; place-items: center; width: 1.75rem; height: 1.75rem; padding: 0;
  border: 0; border-radius: 50%; cursor: pointer; color: var(--text-muted);
  background: transparent; box-shadow: none;
  transition: opacity 0.15s var(--ease), transform 0.1s var(--ease), background 0.15s var(--ease), color 0.15s var(--ease);
}
.pe-arrow svg { width: 0.8125rem; height: 0.8125rem; }
.pe-arrow:hover:not(:disabled) { background: color-mix(in srgb, var(--text) 7%, transparent); color: var(--text); }
.pe-arrow:active:not(:disabled) { transform: scale(0.9); }
.pe-arrow:focus-visible { outline: none; box-shadow: var(--ring); }
.pe-arrow:disabled { opacity: 0.3; cursor: default; }
.pe-track {
  --pe-gap: 0.75rem; --pe-per: 2; --pe-bleed: 0.375rem;
  display: flex; gap: var(--pe-gap);
  overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory;
  touch-action: pan-x pan-y pinch-zoom;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
  /* Room for the cards' shadow, which the sliding box would cut off. */
  margin: calc(-1 * var(--pe-bleed)) calc(-1 * var(--pe-bleed)) -0.75rem;
  padding: var(--pe-bleed) var(--pe-bleed) 0.75rem;
  scroll-padding-inline: var(--pe-bleed);
}
.pe-track::-webkit-scrollbar { display: none; }
.pe-track > .pe-card { flex: 0 0 calc((100% - (var(--pe-per) - 1) * var(--pe-gap)) / var(--pe-per)); scroll-snap-align: start; }
@container (max-width: 28rem) { .pe-track > .pe-card { flex-basis: calc(100% - 2.5rem); } .pe-track > .pe-card:only-child { flex-basis: 100%; } }
@media (hover: none) { .plan-exams.is-scrollable .pe-nav { display: none; } }
@media (max-width: 480px) { .pe-track { --pe-bleed: 1rem; } }
.pe-card {
  display: flex; flex-direction: column; gap: 0.875rem; min-width: 0;
  padding: 0.9375rem 1rem 0.875rem; border-radius: 1.125rem;
  background: var(--plan-card, var(--surface));
}
/* No outline: a soft glow in the subject's colour. */
.pe-card[style*="--subject"] {
  box-shadow: 0 1px 2px color-mix(in srgb, var(--subject) 6%, transparent), 0 4px 14px -6px color-mix(in srgb, var(--subject) 16%, transparent);
}
.pe-open {
  display: flex; align-items: center; gap: 0.875rem; min-width: 0; width: 100%;
  padding: 0; border: 0; background: none; text-align: left; font: inherit; color: inherit; cursor: pointer;
}
.pe-ring.is-unknown .ready-ring { background: color-mix(in srgb, currentColor 14%, transparent); }
.pe-ring.is-unknown b { color: var(--text-dim); }
.pe-text { display: flex; flex-direction: column; gap: 0.125rem; min-width: 0; }
.pe-title { font-size: 0.9375rem; font-weight: 650; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pe-when { font-size: 0.8125rem; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-transform: capitalize; }
/* One row: Check me, and what the student and Zenow expect at its end. */
.pe-actions { display: flex; align-items: center; gap: 0.5rem; min-width: 0; }
.pe-actions > .pe-vs, .pe-actions > .pe-guess { margin-left: auto; min-width: 0; }
.pe-btn {
  display: inline-flex; align-items: center; gap: 0.375rem; height: 1.875rem; padding: 0 0.8125rem;
  border: 0; border-radius: 62.4375rem; cursor: pointer; white-space: nowrap;
  font: inherit; font-size: 0.8125rem; font-weight: 600;
  color: var(--accent-dim); background: color-mix(in srgb, var(--accent) 12%, transparent);
  transition: background 0.15s ease, transform 0.12s ease;
}
.pe-btn:hover { background: color-mix(in srgb, var(--accent) 19%, transparent); }
.pe-btn:active { transform: scale(0.96); }
.pe-btn.pe-guess { color: var(--text); background: var(--surface2); }
/* An oral's Interrogami: Chrono's gold, the colour of the oral everywhere. */
.pe-btn.pe-oral { color: #8A6418; background: color-mix(in srgb, #C8962E 16%, transparent); }
.pe-btn.pe-oral:hover { background: color-mix(in srgb, #C8962E 24%, transparent); }
:root[data-theme="dark"] .pe-btn.pe-oral { color: #E9C46A; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .pe-btn.pe-oral { color: #E9C46A; } }
.pe-btn.pe-guess:hover { background: var(--surface3); }
.pe-btn.is-primary { color: #fff; background: var(--accent); }
.pe-btn:disabled { opacity: 0.6; cursor: default; }
.pe-vs {
  border: 0; background: none; padding: 0 0.25rem; cursor: pointer; font: inherit;
  font-size: 0.8125rem; font-weight: 600; color: var(--text-muted); font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pe-vs:hover { color: var(--text); }
.pe-vs-sep { color: var(--text-dim); margin: 0 0.125rem; }
.pe-guess-form { display: flex; align-items: center; gap: 0.5rem; width: 100%; }
.pe-guess-form .pe-guess-input { flex: 1; min-width: 0; height: 1.875rem; padding: 0 0.75rem; border-radius: 62.4375rem; font-size: 0.8125rem; }
.pe-guess-form .pe-guess-input.is-bad { border-color: var(--red); }
.pe-guess-x, .iv-guess-x {
  flex: none; display: inline-grid; place-items: center; width: 1.875rem; height: 1.875rem; padding: 0;
  border: 0; border-radius: 50%; cursor: pointer; color: var(--text-muted); background: var(--surface2);
  transition: background 0.15s ease, color 0.15s ease, transform 0.12s ease;
}
.iv-guess-x { width: 2rem; height: 2rem; }
.pe-guess-x:hover, .iv-guess-x:hover { color: var(--text); background: color-mix(in srgb, var(--text) 10%, var(--surface2)); }
.pe-guess-x:active, .iv-guess-x:active { transform: scale(0.94); }
.pe-result .plan-sub { white-space: normal; }
@media (max-width: 600px) { .pe-nav { order: 1; } .pe-score + .pe-nav { margin-left: auto; } .pe-score { order: 2; margin-left: 0; width: 100%; } }

.session-length-custom { margin-top: 0.75rem; }
.session-length-custom.hidden { display: none; }

/* ── A homework or an exam, opened (itemview.js) ─────────────────────────────
   Not a form: the thing itself. The title, the day, the steps and the notes
   read as text and are edited where they are; nothing has a box until it is
   touched. Shared by Zenow, Grades and Curriculum. */
.iv-overlay {
  /* Over the corner cards and an open sidebar (300), under the toasts (310). */
  position: fixed; inset: 0; z-index: 305;
  display: flex; align-items: center; justify-content: center; padding: 1.25rem;
  background: rgba(17,24,39,0.44);
  animation: overlay-in 0.24s var(--ease);
}
:root[data-theme="dark"] .iv-overlay { background: rgba(0,0,0,0.55); }
.iv-overlay.hidden { display: none; }
body:has(.iv-overlay:not(.hidden)) #study-now-card { display: none; }
.iv-sheet {
  display: flex; flex-direction: column; gap: 1.375rem;
  width: 34rem; max-width: 100%; max-height: min(88vh, 50rem); overflow-y: auto; overscroll-behavior: contain;
  padding: 1.25rem 1.5rem 1.5rem;
  background: var(--surface); border: 1px solid var(--border); border-radius: 1.25rem;
  box-shadow: 0 1.5rem 4rem rgba(17,24,39,0.18), 0 0.125rem 0.5rem rgba(17,24,39,0.06);
  animation: modal-in 0.34s var(--ease-spring);
}
.iv-head { position: relative; display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; min-height: 1.75rem; }
.iv-kind {
  display: inline-flex; align-items: center; gap: 0.5rem; min-width: 0;
  font-size: 0.8125rem; font-weight: 600; color: var(--text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.iv-dot { flex: none; width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--text-dim); }
.iv-dim { color: var(--text-dim); font-weight: 400; }
/* What kind it is, said quietly: the subject is what the eye looks for. */
.iv-kind-type { color: var(--text-dim); font-weight: 500; }
.iv-head-actions { display: flex; align-items: center; gap: 0.375rem; flex: none; }
.iv-more {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.75rem; height: 1.75rem; padding: 0; border: 0; border-radius: 50%;
  background: var(--surface2); color: var(--text-muted); cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.iv-more:hover, .iv-more[aria-expanded="true"] { background: var(--surface3); color: var(--text); }
.iv-menu {
  position: absolute; top: 2.25rem; right: 0; z-index: 2; min-width: 11.5rem;
  display: flex; flex-direction: column; padding: 0.3125rem;
  background: var(--surface); border: 1px solid var(--border); border-radius: 0.875rem;
  box-shadow: 0 0.75rem 2rem rgba(17,24,39,0.16), 0 1px 0.1875rem rgba(17,24,39,0.06);
  animation: modal-in 0.2s var(--ease);
}
.iv-menu.hidden { display: none; }
.iv-menu button {
  text-align: left; padding: 0.5rem 0.75rem; border: 0; border-radius: 0.5625rem;
  background: none; font: inherit; font-size: 0.875rem; color: var(--text); cursor: pointer;
}
.iv-menu button:hover { background: var(--surface2); }
.iv-menu .iv-menu-done { display: flex; align-items: center; gap: 0.5rem; }
.iv-menu .is-danger { color: var(--red); }
.iv-menu .is-chrono { color: var(--zeno-accent); font-weight: 700; }
.iv-menu .is-chrono:hover { background: rgba(200,150,46,0.12); }
.iv-menu .is-danger.is-armed { background: color-mix(in srgb, var(--red) 11%, transparent); font-weight: 600; }

/* Text that is edited where it is: no box until it has the cursor. */
.iv-sheet .iv-title, .iv-sheet .iv-notes, .iv-sheet .iv-add-step { cursor: text; }
.iv-sheet textarea.iv-title {
  display: block; width: calc(100% + 0.75rem); margin: -0.25rem -0.375rem 0; padding: 0.25rem 0.375rem;
  min-height: 0; resize: none; overflow: hidden;
  font-size: 1.375rem; font-weight: 700; letter-spacing: -0.02em; line-height: 1.25; color: var(--text);
  background: transparent; border: 0; border-radius: 0.5rem; box-shadow: none;
  transition: background 0.15s ease;
}
.iv-sheet textarea.iv-title:hover { background: color-mix(in srgb, var(--surface2) 60%, transparent); }
.iv-sheet textarea.iv-title:focus { background: var(--surface2); box-shadow: none; }

.iv-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 0.625rem 0.5rem; margin-top: -0.5rem; }
/* The Auto-Schedule button, folded to its bolt, beside the ⋯: plans what
   is left of this item. Same glass and teal as the one in the header. */
.iv-plan {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 1.75rem; height: 1.75rem; padding: 0; border-radius: 50%; cursor: pointer; color: #fff;
  background: linear-gradient(135deg, rgba(42,157,143,0.85), rgba(34,129,118,0.85));
  border: 1px solid rgba(42,157,143,0.35);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.25), 0 0.125rem 0.625rem rgba(42,157,143,0.18);
  transition: background 0.15s ease, box-shadow 0.15s ease, transform 0.12s ease;
}
.iv-plan:hover {
  background: linear-gradient(135deg, rgba(42,157,143,0.96), rgba(34,129,118,0.96));
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.3), 0 0.25rem 0.875rem rgba(42,157,143,0.25), 0 0 0.75rem rgba(255,213,79,0.3);
}
.iv-plan:active { transform: scale(0.94); }
/* On hover it crackles exactly like the header's Auto-Schedule button. */
.iv-plan svg { transform-origin: 50% 50%; overflow: visible; }
.iv-plan .gen-spark { stroke: #D7F6FF; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.iv-plan .gen-dot { fill: #D7F6FF; }
.iv-plan .gen-spark, .iv-plan .gen-dot { opacity: 0; }
.iv-plan:hover { animation: gen-aura 1.6s steps(4, jump-none) infinite, gen-quake 1.6s steps(8, jump-none) infinite; }
.iv-plan:hover .gen-spark, .iv-plan:hover .gen-dot { animation: gen-crackle 1.6s steps(4, jump-none) infinite; }
.iv-plan:hover svg { animation: gen-hum 1.6s steps(2, jump-none) infinite; }
.iv-plan:hover .gen-bolt { animation: gen-flash 1.6s steps(4, jump-none) infinite; }
@media (prefers-reduced-motion: reduce) { .iv-plan:hover, .iv-plan:hover svg, .iv-plan:hover .gen-bolt, .iv-plan:hover .gen-spark, .iv-plan:hover .gen-dot { animation: none; } }
.iv-plan:focus-visible { outline: none; box-shadow: var(--ring); }
.iv-due {
  position: relative; display: inline-flex; align-items: center; gap: 0.4375rem;
  height: 2.25rem; padding: 0 0.875rem; border: 0; border-radius: 0.75rem;
  background: var(--surface2); color: var(--text);
  font: inherit; font-size: 0.8125rem; font-weight: 600; white-space: nowrap; cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, transform 0.12s ease;
}
.iv-due:hover { background: var(--surface3); }
.iv-due svg { color: var(--text-muted); }
.iv-due > span { display: inline-block; }
.iv-due > span::first-letter { text-transform: uppercase; }
.iv-due.is-late { color: var(--red); background: color-mix(in srgb, var(--red) 10%, transparent); }
.iv-due.is-late svg { color: currentColor; }
/* The due day opens the same month card as the Add sheet. */
.iv-due-wrap { position: relative; display: inline-flex; }
.iv-due:focus-visible { outline: none; box-shadow: var(--ring); }
.iv-due.is-open { background: var(--surface3); }
.iv-due-pop { top: calc(100% + 0.375rem); left: 0; z-index: 6; }
/* Done: the tick beside the title, as on every Plan row. */
.iv-title-row { display: flex; align-items: flex-start; gap: 0.75rem; }
.iv-title-row textarea.iv-title { flex: 1; min-width: 0; }
.iv-check {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 1.625rem; height: 1.625rem; margin-top: 0.0625rem; padding: 0; border-radius: 50%;
  border: 0.125rem solid var(--text-dim); background: none; color: transparent; cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease, transform 0.12s ease;
}
.iv-check svg { width: 0.875rem; height: 0.875rem; }
.iv-check:hover { border-color: var(--accent); color: color-mix(in srgb, var(--accent) 55%, transparent); }
.iv-check:active { transform: scale(0.9); }
.iv-check.is-on { background: var(--accent); border-color: var(--accent); color: #fff; }
.iv-title-row:has(.iv-check.is-on) .iv-title { color: var(--text-muted); }
/* Where the item's header ends and its contents begin. */
.iv-rule { flex: none; height: 1px; margin: 0; border: 0; background: var(--border); }
.iv-label { font-size: 0.75rem; font-weight: 600; letter-spacing: 0.01em; color: var(--text-muted); margin-bottom: 0.25rem; }

/* Study time: the time it takes, a pill like the date, opening a small card. */
.iv-len-wrap { position: relative; display: inline-flex; }
.iv-len {
  display: inline-flex; align-items: center; gap: 0.4375rem;
  height: 2.25rem; padding: 0 0.875rem; border: 0; border-radius: 0.75rem;
  background: var(--surface2); color: var(--text);
  font: inherit; font-size: 0.8125rem; font-weight: 600; white-space: nowrap; cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, transform 0.12s ease;
}
.iv-len:hover, .iv-len[aria-expanded="true"] { background: var(--surface3); }
.iv-len:active { transform: scale(0.96); }
.iv-len svg { color: var(--text-muted); }
.iv-len.is-empty { color: var(--text-muted); font-weight: 500; }
.iv-len-pop {
  position: absolute; top: calc(100% + 0.375rem); left: 0; z-index: 3; width: 15.5rem;
  display: flex; flex-direction: column; gap: 0.625rem; padding: 0.75rem;
  background: var(--surface); border: 1px solid var(--border); border-radius: 0.875rem;
  box-shadow: 0 0.75rem 2rem rgba(17,24,39,0.16), 0 1px 0.1875rem rgba(17,24,39,0.06);
  animation: modal-in 0.2s var(--ease);
}
.iv-len-pop.hidden { display: none; }
.iv-len-title { font-size: 0.75rem; font-weight: 600; color: var(--text-muted); }
.iv-len-row { display: flex; align-items: center; gap: 0.375rem; }
.iv-len-step {
  flex: 0 0 2.25rem; height: 2.25rem; border: 0; border-radius: 0.625rem;
  background: var(--surface2); color: var(--text); font: inherit; font-size: 1.0625rem; font-weight: 600; cursor: pointer;
  transition: background 0.15s ease;
}
.iv-len-step:hover:not(:disabled) { background: var(--surface3); }
.iv-len-step:disabled { opacity: 0.35; cursor: default; }
.iv-len-val {
  flex: 1; min-width: 0; height: 2.25rem; border: 0; border-radius: 0.625rem;
  background: none; color: var(--text); font: inherit; font-size: 0.9375rem; font-weight: 700;
  font-variant-numeric: tabular-nums; text-align: center; cursor: text;
}
.iv-len-val:hover { background: var(--surface2); }
.iv-sheet .iv-len-val.is-typing { background: var(--surface2); box-shadow: var(--ring); padding: 0 0.5rem; }
.iv-len-presets { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.3125rem; }
.iv-len-preset {
  height: 1.875rem; padding: 0; border: 0; border-radius: 62.4375rem;
  background: var(--surface2); color: var(--text); font: inherit; font-size: 0.75rem; font-weight: 600; white-space: nowrap; cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.iv-len-preset:hover { background: var(--surface3); }
.iv-len-preset.is-on { background: var(--accent); color: #fff; }
.iv-len-none {
  align-self: flex-start; padding: 0.25rem 0.125rem; border: 0; background: none;
  font: inherit; font-size: 0.8125rem; color: var(--text-muted); cursor: pointer;
}
.iv-len-none:hover { color: var(--red); }

.iv-block { display: flex; flex-direction: column; gap: 0.25rem; }
.iv-block.is-loading { border-radius: 0.875rem; background: var(--surface2); opacity: 0.55; }
.iv-sessions.is-loading { min-height: 2.75rem; }
.iv-ready.is-loading { min-height: 7.25rem; }
.iv-muted { font-size: 0.875rem; color: var(--text-muted); }

.iv-ready { gap: 0.75rem; padding: 0.875rem 1rem; border-radius: 1rem; background: var(--surface2); }
.iv-ready-head { display: flex; align-items: center; gap: 0.875rem; }
.iv-ready-text { font-size: 0.875rem; line-height: 1.4; color: var(--text); }
.iv-ready .ready-big.is-unknown .ready-ring { background: color-mix(in srgb, currentColor 14%, transparent); }
.iv-ready .ready-big.is-unknown b { color: var(--text-dim); }
.iv-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 0.5rem; }
.iv-btn {
  display: inline-flex; align-items: center; gap: 0.375rem; height: 2rem; padding: 0 0.875rem;
  border: 0; border-radius: 62.4375rem; cursor: pointer; white-space: nowrap;
  font: inherit; font-size: 0.8125rem; font-weight: 600;
  color: var(--accent-dim); background: color-mix(in srgb, var(--accent) 12%, transparent);
  transition: background 0.15s ease, transform 0.12s ease;
}
.iv-btn:hover { background: color-mix(in srgb, var(--accent) 19%, transparent); }
.iv-btn:active { transform: scale(0.96); }
.iv-btn.is-primary { color: #fff; background: var(--accent); }
.iv-btn.is-primary:hover { background: color-mix(in srgb, var(--accent) 88%, #000); }
.iv-btn:disabled { opacity: 0.6; cursor: default; }
/* The ways to be tested, side by side, each in its own colour with its
   own mark: the quick check (the main one, filled), the mock test, the
   oral. Same height, title and subtitle on one line each. */
#iv-ready-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; }
/* The first is the main one, across the row: the quick check, or for an
   oral, being questioned out loud. */
#iv-ready-actions > :first-child { grid-column: 1 / -1; }
/* Narrow (a phone, a slim panel): one under the other, nothing cut. */
.iv-ready { container-type: inline-size; }
@container (max-width: 22rem) { #iv-ready-actions { grid-template-columns: 1fr; } }
.iv-act {
  --c: var(--accent);
  display: flex; align-items: center; gap: 0.625rem; min-width: 0; height: 3.5rem; padding: 0 0.75rem 0 0.5rem;
  border: 0; border-radius: 0.875rem; cursor: pointer; text-align: left; font: inherit; color: var(--text);
  background: var(--surface); box-shadow: 0 0 0 1px var(--border);
  transition: box-shadow 0.15s ease, transform 0.12s ease, background 0.15s ease;
}
.iv-act:hover { box-shadow: 0 0 0 1px color-mix(in srgb, var(--c) 55%, var(--border)), 0 0.25rem 0.75rem color-mix(in srgb, var(--c) 14%, transparent); transform: translateY(-1px); }
.iv-act:active { transform: scale(0.97); }
.iv-act:focus-visible { outline: 2px solid var(--c); outline-offset: 2px; }
.iv-act-ico {
  flex: none; display: grid; place-items: center; width: 2.5rem; height: 2.5rem; border-radius: 0.75rem;
  color: var(--c); background: color-mix(in srgb, var(--c) 14%, transparent);
}
.iv-act-text { display: flex; flex-direction: column; gap: 0.125rem; min-width: 0; line-height: 1.2; }
.iv-act-text b, .iv-act-text small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.iv-act-text b { font-size: 0.875rem; font-weight: 650; }
.iv-act-text small { font-size: 0.6875rem; font-weight: 550; color: var(--text-muted); }
#iv-ready-actions > .iv-act:first-child { background: color-mix(in srgb, var(--c) 9%, var(--surface)); box-shadow: 0 0 0 1px color-mix(in srgb, var(--c) 35%, transparent); }
#iv-ready-actions > .iv-act:first-child .iv-act-ico { color: #fff; background: var(--c); box-shadow: 0 0.25rem 0.625rem color-mix(in srgb, var(--c) 35%, transparent); }
.iv-act.is-practice { --c: #4A63C9; }
.iv-act.is-oral { --c: var(--zeno-accent, #C8962E); }
.iv-act.is-oral .iv-act-ico { background: radial-gradient(circle at 35% 30%, color-mix(in srgb, #FDE68A 45%, transparent), color-mix(in srgb, var(--c) 16%, transparent) 70%); }
:root[data-theme="dark"] .iv-act.is-practice { --c: #8EA2F0; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .iv-act.is-practice { --c: #8EA2F0; } }
/* Your guess: lighter, under the three -- a number of your own, not a test. */
.iv-guess-row { display: flex; }
.iv-guess-btn {
  display: inline-flex; align-items: center; gap: 0.4375rem; padding: 0.4375rem 0.875rem 0.4375rem 0.625rem;
  border: 1px dashed color-mix(in srgb, var(--text) 22%, transparent); border-radius: 62.4375rem; background: none; cursor: pointer;
  font: inherit; font-size: 0.8125rem; font-weight: 600; color: var(--text-muted); transition: color 0.15s ease, border-color 0.15s ease;
}
.iv-guess-btn svg { width: 1rem; height: 1rem; }
.iv-guess-btn:hover { color: var(--text); border-color: color-mix(in srgb, var(--text) 40%, transparent); }
.iv-guess-row .iv-guess { width: 100%; }
.iv-ready .iv-btn:not(.is-primary) { background: var(--surface); color: var(--text); box-shadow: 0 0 0 1px var(--border); }
.iv-vs {
  border: 0; background: none; padding: 0 0.25rem; cursor: pointer; font: inherit;
  font-size: 0.8125rem; font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums;
}
.iv-guess { display: flex; align-items: center; gap: 0.5rem; width: 100%; }
.iv-sheet .iv-guess input { flex: 1; min-width: 0; height: 2rem; padding: 0 0.875rem; border-radius: 62.4375rem; font-size: 0.8125rem; background: var(--surface); }
.iv-sheet .iv-guess input.is-bad { border-color: var(--red); }

.iv-sessions { gap: 0.625rem; }
.iv-session {
  display: flex; align-items: center; gap: 0.75rem; min-height: 3.375rem;
  padding: 0.5rem 0.5rem 0.5rem 1rem; border-radius: 1rem; background: var(--surface2);
}
.iv-session-when { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.125rem; }
.iv-session-when b { font-size: 0.875rem; font-weight: 650; line-height: 1.3; color: var(--text); overflow-wrap: anywhere; }
.iv-session-when b::first-letter { text-transform: uppercase; }
.iv-session-sub { font-size: 0.8125rem; line-height: 1.3; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.iv-session .iv-btn:not(.is-primary) { background: var(--surface); color: var(--text); box-shadow: 0 0 0 1px var(--border); }
.iv-sessions-empty {
  display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; min-height: 3.375rem;
  padding: 0.5rem 0.5rem 0.5rem 1rem; border-radius: 1rem; background: var(--surface2);
}

.iv-steps { gap: 0; }
.iv-step { display: flex; align-items: flex-start; gap: 0.75rem; padding: 0.5rem 0; }
.iv-tick {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 1.25rem; height: 1.25rem; margin-top: 0.0625rem; padding: 0; border-radius: 50%;
  border: 1.6px solid var(--text-dim); background: none; color: transparent; cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease, transform 0.12s ease;
}
.iv-tick:hover { border-color: var(--accent); }
.iv-tick:active { transform: scale(0.9); }
.iv-step.is-done .iv-tick { background: var(--accent); border-color: var(--accent); color: #fff; }
.iv-step-text { flex: 1; min-width: 0; font-size: 0.9375rem; line-height: 1.4; color: var(--text); overflow-wrap: anywhere; }
.iv-step.is-done .iv-step-text { color: var(--text-muted); }
.iv-step-x {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 1.75rem; height: 1.75rem; margin: -0.25rem -0.25rem -0.25rem 0; padding: 0; border: 0; border-radius: 50%;
  background: none; color: var(--text-dim); cursor: pointer; opacity: 0;
  transition: opacity 0.15s ease, background 0.15s ease, color 0.15s ease;
}
.iv-step:hover .iv-step-x, .iv-step-x:focus-visible { opacity: 1; }
.iv-step-x:hover { background: color-mix(in srgb, var(--red) 10%, transparent); color: var(--red); }
@media (hover: none) { .iv-step-x { opacity: 0.6; } }
.iv-sheet input.iv-add-step {
  width: 100%; padding: 0.5rem 0 0.5rem 2rem; border: 0; border-radius: 0; background: transparent; box-shadow: none;
  font-size: 0.9375rem; color: var(--text);
}
.iv-sheet input.iv-add-step:focus { box-shadow: none; }
.iv-sheet textarea.iv-notes {
  display: block; width: 100%; min-height: 2.75rem; resize: none; overflow: hidden;
  padding: 0.6875rem 0.875rem; border: 0; border-radius: 0.875rem; background: var(--surface2); box-shadow: none;
  font-size: 0.9375rem; line-height: 1.45; color: var(--text);
}
.iv-sheet textarea.iv-notes:focus { box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--accent) 45%, transparent); }

@media (max-width: 768px) {
  .iv-overlay { align-items: flex-end; padding: 0; }
  /* A phone gets the room a thumb needs: more air between the parts, and
     taller targets. */
  .iv-sheet {
    width: 100%; max-height: 92vh; border-radius: 1.5rem 1.5rem 0 0; border-bottom: 0;
    gap: 1.625rem; padding: 1.125rem 1.375rem calc(1.75rem + env(safe-area-inset-bottom));
  }
  .iv-meta { gap: 0.75rem 0.625rem; margin-top: -0.625rem; }
  .iv-sessions { gap: 0.75rem; }
  .iv-session { min-height: 3.75rem; padding: 0.625rem 0.625rem 0.625rem 1.125rem; }
  .iv-due, .iv-len { height: 2.5rem; padding: 0 1rem; font-size: 0.875rem; }
  .iv-session .iv-btn { height: 2.25rem; padding: 0 1rem; }
  .iv-step { padding: 0.625rem 0; gap: 0.875rem; }
  .iv-sheet input.iv-add-step { padding: 0.625rem 0 0.625rem 2.125rem; }
  .iv-sheet textarea.iv-notes { min-height: 3.5rem; }
}
@media (prefers-reduced-motion: reduce) { .iv-overlay, .iv-sheet, .iv-menu { animation: none; } }

/* A setting that cannot be saved as typed (settingsLive.js). */
input[aria-invalid="true"], input[aria-invalid="true"]:focus { border-color: var(--red); box-shadow: 0 0 0 0.2188rem color-mix(in srgb, var(--red) 12%, transparent); }


/* ── Plan cards, round 2 ──────────────────────────────────────────────────
   Two lines at most for a card's title and its line; the rest is a tap away
   ("Show more", app.js planCardsFit) in a sheet. Not now always sits in the
   card's top-right corner, clear of the actions. */
.plan-recall .plan-title, .plan-recall .plan-sub {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2;
  overflow: hidden; white-space: normal; text-overflow: clip;
}
.plan-more {
  align-self: flex-start; margin-top: 0.25rem; padding: 0; border: 0; background: none; cursor: pointer;
  font: inherit; font-size: 0.75rem; font-weight: 600; color: var(--accent);
}
.plan-more:hover { text-decoration: underline; }
.plan-recall .plan-main { display: flex; flex-direction: column; }
.plan-recall:has(.plan-card-x) { padding-right: calc(var(--plan-pad, 1.25rem) + 1.5rem); }
.plan-recall .plan-card-x { position: absolute; top: 0.5rem; right: 0.5rem; width: 1.75rem; height: 1.75rem; }
.plan-recall:has(.plan-card-x) .plan-main { padding-right: 0; }
/* The week card: its icon level with the middle of what it says. */
/* The sheet: everything the card had, and its buttons. */
.plan-card-full { display: flex; flex-direction: column; gap: 0.5rem; font-size: 0.9375rem; line-height: 1.5; color: var(--text); }
.plan-card-full .plan-sub { display: block; white-space: normal; color: var(--text-muted); }
.plan-card-full-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 0.5rem; margin-top: 1.25rem; }

/* Descriptions as spaced pieces, not a string of dots: the subject leads
   with its colour, a status reads as a soft tag. */
.plan-bit + .plan-bit { margin-left: 0.625rem; }
.plan-sub .plan-late { display: inline-block; padding: 0 0.375rem; border-radius: 62.4375rem; background: color-mix(in srgb, var(--red) 12%, transparent); font-size: 0.6875rem; line-height: 1.25rem; font-weight: 600; }
.rs-facts { gap: 0.875rem; }
.found-meta { gap: 0.5rem; }
.found-len, .short-due, .rs-was { padding: 0 0.375rem; border-radius: 62.4375rem; background: color-mix(in srgb, var(--text-muted) 12%, transparent); font-size: 0.6875rem; line-height: 1.125rem; }
.short-meta { gap: 0.5rem; }
.short-due.is-late { color: var(--red); background: color-mix(in srgb, var(--red) 12%, transparent); font-weight: 500; }
@media (max-width: 560px) {
  /* A card taller than one line: the icon stays beside the title, and the
     buttons take the full width under both, so nothing leaves a hole under
     the icon. */
  .plan-recall { display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: var(--plan-gap, 1rem); row-gap: 0.875rem; align-items: start; }
  .plan-recall > .plan-recall-icon { grid-column: 1; grid-row: 1; align-self: start; }
  .plan-recall > :not(.plan-recall-icon) { grid-column: 2; min-width: 0; }
  .plan-recall > .plan-card-actions { grid-column: 1 / -1; margin-left: 0; }
  .plan-recall > .plan-card-actions > :not(.plan-card-x) { flex: 1 1 0; justify-content: center; }
  .plan-recall:has(.plan-card-x) { padding-right: var(--plan-pad, 1.25rem); }
  .plan-recall:has(.plan-card-x) > .plan-main { padding-right: 1.75rem; }
}

/* What a card keeps for its "Show more" sheet (the week's tests). */
.plan-recall .plan-card-extra { display: none; }
.plan-recall > .plan-card-actions:has(> .plan-card-x:only-child) { display: contents; }
#plan-card-modal-body .coach-week { display: flex; justify-content: center; margin-top: 1.25rem; }
/* Each homework on a line of its own: its subject's colour, the title
   wrapping as long as it needs, the time it still asks for at the end. */
.coach-items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.coach-item { display: flex; align-items: flex-start; gap: 0.75rem; padding: 0.75rem 0; }
.coach-item + .coach-item { border-top: 0.5px solid var(--border, rgba(0,0,0,0.08)); }
.coach-item-dot { flex: none; width: 0.5rem; height: 0.5rem; margin-top: 0.4375rem; border-radius: 50%; background: var(--subject, var(--text-dim)); }
.coach-item-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.125rem; }
.coach-item-title { font-size: 0.9375rem; font-weight: 600; line-height: 1.4; color: var(--text); overflow-wrap: anywhere; }
.coach-item-sub { font-size: 0.8125rem; color: var(--text-muted); }
.coach-item-len { flex: none; margin-top: 0.125rem; padding: 0 0.5rem; border-radius: 62.4375rem; font-size: 0.75rem; line-height: 1.375rem; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--text-muted); background: color-mix(in srgb, var(--text-muted) 12%, transparent); }
#plan-card-modal-body > :first-child { margin-top: 0; padding-top: 0; border-top: 0; }
#plan-card-modal-body .coach-items:first-child .coach-item:first-child { padding-top: 0.25rem; }
#plan-card-modal-body .coach-tests { display: flex; margin: 1.25rem 0 0; padding-top: 1rem; border-top: 0.5px solid var(--border, rgba(0,0,0,0.08)); }
.plan-coach-week { align-items: center; }

/* Auto-Schedule result: sessions picked up and put elsewhere. */
#schedule-result-body .found-session.can-drag { cursor: grab; touch-action: pan-y; -webkit-user-select: none; user-select: none; }
#schedule-result-body.rs-dragging, #schedule-result-body.rs-dragging * { cursor: grabbing !important; }
#schedule-result-body .found-day.is-empty { display: none; }
#schedule-result-body.rs-dragging .found-day.is-empty { display: flex; opacity: 0.55; }
#schedule-result-body.rs-dragging .found-day.is-empty .found-sessions { min-height: 2.25rem; border-radius: 0.625rem; border: 1px dashed var(--border); }
.found-session.is-lifted { opacity: 0.35; }
.found-session.is-lifted > * { visibility: hidden; }
.found-session.is-lifted::after { content: ''; position: absolute; inset: 0; border-radius: 0.625rem; background: color-mix(in srgb, var(--accent) 10%, transparent); border: 1px dashed color-mix(in srgb, var(--accent) 45%, transparent); }
.rs-ghost {
  position: fixed; left: 0; top: 0; z-index: 10000; pointer-events: none; margin: 0; list-style: none;
  padding: 0.5rem 0.75rem 0.5rem 1.125rem; border-radius: 0.75rem; background: var(--surface);
  box-shadow: 0 0.75rem 2rem rgba(16,24,40,0.18), 0 0.125rem 0.375rem rgba(16,24,40,0.08);
  display: flex; align-items: center; gap: 0.75rem; box-sizing: border-box;
}
.rs-ghost::before { content: ''; position: absolute; left: 0.5rem; top: 0.625rem; bottom: 0.625rem; width: 0.1875rem; border-radius: 0.125rem; background: var(--subj); }
.rs-ghost .found-adjust, .rs-ghost .rs-drop { display: none; }
.rs-drag-hint { margin: 0.75rem 0 0; text-align: center; font-size: 0.75rem; color: var(--text-dim); }

/* The result sheet: header and footer stay put, only the list scrolls, so
   Undo and Done are always one tap away however long the result is. */
#modal-schedule-result .modal { display: flex; flex-direction: column; overflow: hidden; }
#modal-schedule-result .modal-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
#schedule-result-footer { flex-shrink: 0; align-items: center; padding: 0.875rem 1.75rem 1.25rem; border-top: 0.5px solid var(--border); }
/* Undo: a quiet pill with its arrow, plainly a way back, not another Close. */
.rs-undo {
  display: inline-flex; align-items: center; gap: 0.4375rem; padding: 0.5rem 0.875rem 0.5rem 0.75rem; border-radius: 62.4375rem;
  border: 0; background: color-mix(in srgb, var(--text) 6%, transparent); color: var(--text); font-weight: 600;
  box-shadow: none; transition: background .15s ease, transform .1s ease;
}
.rs-undo svg { width: 0.9375rem; height: 0.9375rem; flex-shrink: 0; color: var(--text-muted); }
.rs-undo:hover { background: color-mix(in srgb, var(--text) 10%, transparent); }
.rs-undo:active { transform: scale(0.97); }
.rs-undo .spinner { width: 0.9375rem; height: 0.9375rem; }
@media (max-width: 560px) {
  #schedule-result-footer { padding: 0.75rem 1.25rem calc(1rem + env(safe-area-inset-bottom, 0px)); }
}
#schedule-result-footer .btn { height: 2.5rem; border-radius: 62.4375rem; }
#btn-close-schedule-result { padding: 0 1.375rem; }

/* Item view: steps picked up and put in a new order. */
.iv-step { cursor: grab; -webkit-user-select: none; user-select: none; }
.iv-dragging, .iv-dragging * { cursor: grabbing !important; -webkit-user-select: none !important; user-select: none !important; }
.iv-step.is-lifted { position: relative; }
.iv-step.is-lifted > * { visibility: hidden; }
.iv-step.is-lifted::after { content: ''; position: absolute; inset: 0.1875rem 0; border-radius: 0.625rem; background: color-mix(in srgb, var(--accent) 10%, transparent); border: 1px dashed color-mix(in srgb, var(--accent) 45%, transparent); }
.iv-step-ghost {
  position: fixed; z-index: 10001; pointer-events: none; box-sizing: border-box; margin: 0;
  padding: 0.5rem 0.75rem; border-radius: 0.75rem; background: var(--surface);
  box-shadow: 0 0.75rem 2rem rgba(16,24,40,0.18), 0 0.125rem 0.375rem rgba(16,24,40,0.08);
}
.iv-step-ghost .iv-step-x { display: none; }

/* ── Inside study help, calmer ────────────────────────────────────────
   One line on top: back, which step, and three quiet tools. Then the
   stages, then the page -- each thing once, nothing boxed that need not be. */
.study-topic { padding: 1rem 1.125rem 1.5rem; gap: 0.875rem; }
.tutor-head { gap: 0.25rem; margin: -0.25rem -0.375rem 0; }
.tutor-back { width: 2rem; height: 2rem; border: 0; background: transparent; color: var(--text-muted); }
.tutor-back:hover { background: var(--surface2); }
.tutor-head .tutor-title { font-size: 1rem; font-weight: 650; letter-spacing: -0.01em; }
.tutor-head .tutor-title:not(.tutor-title-btn) { padding: 0 0.375rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tutor-head .tutor-title-btn { flex: 0 1 auto; margin-right: auto; }
.tutor-head-tools { display: flex; align-items: center; gap: 0.125rem; flex-shrink: 0; margin-left: auto; }
.tutor-head-tools .ready-chip { margin-right: 0.25rem; }
.tutor-head .tutor-icon-btn { width: 2rem; height: 2rem; border-color: transparent; background: transparent; }
.tutor-head .tutor-icon-btn:hover, .tutor-head .tutor-icon-btn:focus-visible, .tutor-head .tutor-icon-btn[aria-expanded="true"] { border-color: transparent; background: var(--surface2); }
.tutor-stages { border-radius: var(--radius-md); }
.tutor-stage { border-radius: calc(var(--radius-md) - 0.1875rem); padding: 0.4375rem 0.25rem; }
/* The exercise to photograph: one line and its buttons, side by side. */
.tutor-need { gap: 0.75rem; padding: 0.875rem 1rem; text-align: left; align-items: stretch; }
.tutor-need-actions { justify-content: flex-start; padding-left: 0; }
.tutor-need-text b { font-size: 0.875rem; }
.tutor-need-actions .pill-btn { flex: 0 0 auto; }
/* Chrono: a quiet link under the conversation. */
.tutor-chrono-head { justify-content: flex-end; min-height: 0; }
.tutor-chrono-open { height: auto; padding: 0.25rem 0.375rem; background: none; color: var(--text-muted); font-weight: 600; border-radius: 0.5rem; }
.tutor-chrono-open:hover, .tutor-chrono-open:focus-visible { background: var(--surface2); color: var(--text); }
:root[data-theme="dark"] .tutor-chrono-open { color: var(--text-muted); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .tutor-chrono-open { color: var(--text-muted); } }
/* Start over: on the left, quiet; red while it asks to be sure. */
.tutor-chrono-head:has(.tutor-chrono-reset) { justify-content: space-between; }
.tutor-chrono-reset.is-asking, .tutor-chrono-reset.is-asking:hover { color: var(--red); background: color-mix(in srgb, var(--red) 10%, transparent); }
/* Buttons inside the page are the app's pills, not form buttons. */
.study-topic .btn { height: 2.125rem; padding: 0 0.9375rem; border-radius: 62.4375rem; font-size: 0.8125rem; }
.tutor-starters { gap: 0.375rem; }
.tutor-starter { font-size: 0.8125rem; padding: 0.4375rem 0.75rem; }
@media (max-width: 560px) {
  .study-topic { padding: 0.875rem 1rem 1.5rem; }
  .tutor-explain, .tutor-qa-a, .tutor-qa-q { font-size: 0.9375rem; }
}

/* Study header: the time left reads at the subject's size, and the title
   stops well short of the buttons beside it. */
.study-header-meta .study-remaining-min { font-size: 0.8125rem; }
.study-header-main { padding-right: 0.75rem; }

/* A duplicate on its way: the copy sits under the original, faded and
   shimmering, with a small spinner, until the server has placed it. */
.plan-row.is-pending { pointer-events: none; animation: plan-pending-in .22s ease-out both; }
.plan-row.is-pending > :not(.plan-pending-spin) { opacity: .45; }
.plan-row.is-pending .swipe-action { display: none; }
.plan-row.is-pending .plan-main ~ *, .plan-row.is-pending .plan-time { visibility: hidden; }
.plan-pending-spin { z-index: 1; }
.plan-row.is-pending::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(100deg, transparent 20%, color-mix(in srgb, var(--subject, var(--accent)) 14%, transparent) 50%, transparent 80%);
  background-size: 220% 100%; animation: plan-pending-sheen 1.1s linear infinite;
}
.plan-pending-spin {
  position: absolute; right: 1.75rem; top: 50%; width: 1.125rem; height: 1.125rem; margin-top: -0.5625rem; border-radius: 50%;
  border: 0.125rem solid color-mix(in srgb, var(--subject, var(--accent)) 25%, transparent);
  border-top-color: var(--subject, var(--accent)); animation: spin .7s linear infinite;
}
@keyframes plan-pending-in { from { opacity: 0; transform: translateY(-0.375rem); } to { opacity: 1; transform: none; } }
@keyframes plan-pending-sheen { from { background-position: 120% 0; } to { background-position: -120% 0; } }

/* Study help on hover: a light sweeps across the pill, the big sparkle
   turns a quarter and the small one twinkles, and the glass lights up. */
.study-help-entry { position: relative; overflow: hidden; isolation: isolate;
  transition: filter .2s ease, transform .18s cubic-bezier(.3,1.4,.5,1), box-shadow .25s ease; }
.study-help-entry::after {
  content: ''; position: absolute; inset: -1px; z-index: -1; pointer-events: none;
  background: linear-gradient(115deg, transparent 32%, rgba(255,255,255,0.32) 47%, rgba(255,255,255,0.06) 55%, transparent 68%);
  transform: translateX(-120%);
}
.study-help-icon svg path { transform-box: fill-box; transform-origin: center; transition: transform .45s cubic-bezier(.3,1.5,.5,1), opacity .2s ease; }
.study-help-entry:hover {
  filter: brightness(1.07) saturate(1.05);
  box-shadow:
    inset 0 0.75px 0 rgba(255,255,255,0.9),
    inset 0 -0.75px 0 rgba(255,255,255,0.3),
    inset 0 0 0 0.75px rgba(255,255,255,0.3),
    inset 0 0 0.625rem rgba(255,190,190,0.22),
    0 0.125rem 0.5rem rgba(110,8,16,0.18);
}
.study-help-entry:hover::after { transform: translateX(120%); transition: transform .7s cubic-bezier(.4,0,.2,1); }
.study-help-entry:hover .study-help-icon svg path:first-child { transform: rotate(90deg) scale(1.08); }
.study-help-entry:hover .study-help-icon svg path:last-child { animation: study-help-twinkle .9s ease-in-out .1s 2; }
.study-help-entry:active { transform: scale(.96); }
@keyframes study-help-twinkle { 0%, 100% { transform: scale(1); opacity: .85; } 50% { transform: scale(1.5) rotate(45deg); opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .study-help-entry, .study-help-icon svg path { transition: none; }
  .study-help-entry::after, .study-help-entry:hover .study-help-icon svg path { animation: none; transform: none; }
  .plan-row.is-pending, .plan-row.is-pending::after { animation: none; }
}

/* Something not understood, noticed and kept (models/gaps.js): a quiet line
   under the answer that noticed it, and in the search window the list of
   them, each one tap from a search. */
.tutor-gap-note {
  display: flex; align-items: flex-start; gap: 0.375rem; margin-top: 0.5rem; padding-top: 0.5rem;
  border-top: 1px dashed color-mix(in srgb, #C8962E 32%, transparent);
  font-size: 0.75rem; line-height: 1.45; color: var(--text-muted);
}
.tutor-gap-note svg { flex-shrink: 0; margin-top: 0.0625rem; color: #B7791F; }
:root[data-theme="dark"] .tutor-gap-note svg, :root[data-theme="dark"] .search-gap svg { color: #E9C46A; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .tutor-gap-note svg, :root:not([data-theme="light"]) .search-gap svg { color: #E9C46A; } }
.search-gap-list { display: flex; flex-wrap: wrap; gap: 0.375rem; }
.search-gap {
  display: inline-flex; align-items: center; gap: 0.3125rem; max-width: 100%; min-width: 0;
  padding: 0.375rem 0.75rem 0.375rem 0.625rem; border-radius: 62.4375rem; cursor: pointer;
  border: 1px solid color-mix(in srgb, #C8962E 30%, var(--border)); background: color-mix(in srgb, #E9C46A 12%, var(--surface));
  font: 600 0.8125rem/1.2 var(--font); color: var(--text); transition: background .15s ease, transform .1s ease;
}
.search-gap span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.search-gap svg { flex-shrink: 0; color: #B7791F; }
.search-gap:hover { background: color-mix(in srgb, #E9C46A 22%, var(--surface)); }
.search-gap:active { transform: scale(.97); }
.search-for-gaps { margin: 0 0 0.5rem; font-size: 0.75rem; line-height: 1.45; color: var(--text-muted); }

/* Study boxes in Chrono's answers (public/js/md.js): a definition, a
   formula, an example, the key point, the usual mistake -- each its own
   card, so the eye finds the thing it came for. A thin rule of the kind's
   colour on the left, what it is in small caps, then what it is about. */
.md-callout.md-study {
  --cl: #4a63c9;
  margin: 0.625rem 0 0; padding: 0; overflow: hidden; border-radius: 0.75rem;
  background: var(--surface, #fff);
  border: 1px solid color-mix(in srgb, var(--cl) 20%, var(--border, rgba(0,0,0,.08)));
  box-shadow: inset 0.1875rem 0 0 var(--cl), 0 1px 0.125rem rgba(15,26,46,0.04);
  color: var(--text, inherit);
}
.md-callout.md-study + .md-callout.md-study { margin-top: 0.5rem; }
.md-study .md-callout-title {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 0.25rem 0.5rem; margin: 0;
  padding: 0.5rem 0.75rem 0.375rem 0.875rem; font-size: 0.875rem;
}
.md-study .md-callout-icon { display: none; }
.md-study .md-callout-kind {
  font-size: 0.625rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--cl);
}
.md-study .md-callout-name { font-weight: 700; letter-spacing: -0.01em; color: var(--text, inherit); }
.md-study .md-callout-body { padding: 0 0.875rem 0.625rem 0.875rem; font-size: 0.875rem; line-height: 1.55; }
.md-study .md-callout-body > :first-child { margin-top: 0; }
.md-study .md-callout-body > :last-child { margin-bottom: 0; }
.md-study .md-callout-body p + p { margin-top: 0.375rem; }
.md-study .md-callout-body ul, .md-study .md-callout-body ol { margin: 0.25rem 0 0; padding-left: 1.125rem; }
.md-callout.md-definition { --cl: #4a63c9; }
.md-callout.md-formula { --cl: #0f8f86; background: color-mix(in srgb, var(--cl) 5%, var(--surface, #fff)); }
.md-formula .md-math-display { margin: 0.25rem 0; text-align: center; font-size: 1.0625rem; overflow-x: auto; }
.md-callout.md-example { --cl: #7a7f8c; background: color-mix(in srgb, var(--text, #000) 3%, var(--surface, #fff)); }
.md-callout.md-key { --cl: #1a9a68; background: color-mix(in srgb, var(--cl) 6%, var(--surface, #fff)); }
.md-callout.md-mistake { --cl: #d0532f; background: color-mix(in srgb, var(--cl) 6%, var(--surface, #fff)); }
:root[data-theme="dark"] .md-callout.md-definition { --cl: #8ea2ff; }
:root[data-theme="dark"] .md-callout.md-formula { --cl: #4fd1c5; }
:root[data-theme="dark"] .md-callout.md-example { --cl: #a3a9b6; }
:root[data-theme="dark"] .md-callout.md-key { --cl: #4ade80; }
:root[data-theme="dark"] .md-callout.md-mistake { --cl: #ff8a65; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .md-callout.md-definition { --cl: #8ea2ff; }
  :root:not([data-theme="light"]) .md-callout.md-formula { --cl: #4fd1c5; }
  :root:not([data-theme="light"]) .md-callout.md-example { --cl: #a3a9b6; }
  :root:not([data-theme="light"]) .md-callout.md-key { --cl: #4ade80; }
  :root:not([data-theme="light"]) .md-callout.md-mistake { --cl: #ff8a65; }
}
/* Inside the study-help bubble the boxes span its width, clear of the tint. */
.tutor-qa-a .md-callout.md-study { margin-left: 0; margin-right: 0; }
.tutor-qa-a .md-body h3, .tutor-qa-a .md-body h4 { font-size: 0.875rem; font-weight: 700; margin: 0.625rem 0 0.25rem; }
.tutor-qa-a .md-body h3:first-child, .tutor-qa-a .md-body h4:first-child { margin-top: 0; }
.tutor-qa-a .md-body ol { margin: 0 0 0.5rem; padding-left: 1.25rem; }
.tutor-qa-a .md-body li + li { margin-top: 0.1875rem; }
/* Chrono's chat: a little more air between the parts of an answer. */
.zeno-msg .md-callout.md-study + p, .zeno-msg .md-callout.md-study + ul, .zeno-msg .md-callout.md-study + ol { margin-top: 0.625rem; }
.zeno-msg h3 { font-size: 0.9375rem; letter-spacing: -0.01em; }
.md-callout.md-study + h3, .md-callout.md-study + h4 { margin-top: 0.875rem !important; }

/* The loader leaves once the first view is drawn underneath it. */
#screen-loading { transition: opacity .24s ease; }
#screen-loading.is-leaving { opacity: 0; pointer-events: none; }
@media (prefers-reduced-motion: reduce) { #screen-loading { transition: none; } }

/* Their page, read and marked (studytutor.js, "Their own page"). The photo
   they sent sits in their bubble; a check draws on it where it goes wrong,
   says what it read off it, and opens it full size on a tap. */
.tutor-msg-work.is-photos { display: flex; flex-wrap: wrap; gap: 0.375rem; padding: 0.375rem; background: color-mix(in srgb, var(--primary) 88%, #000); }
.tutor-photo-thumb { display: block; width: 4.5rem; height: 4.5rem; padding: 0; border: 0; border-radius: 0.625rem; overflow: hidden; cursor: zoom-in; background: rgba(255,255,255,.15); }
.tutor-photo-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.tutor-read-tag { display: flex; align-items: center; gap: 0.3125rem; margin-bottom: 0.25rem; font-size: 0.6875rem; font-weight: 600; opacity: 0.8; }
.tutor-read-tag svg { width: 0.8125rem; height: 0.8125rem; }
.tutor-marked { display: flex; flex-direction: column; gap: 0.5rem; margin: 0.375rem 0 0.25rem; }
.tutor-marked-fig {
  position: relative; display: block; width: 100%; max-width: 26rem; padding: 0; border: 1px solid var(--border); border-radius: 0.75rem;
  overflow: hidden; background: var(--surface); cursor: zoom-in; line-height: 0;
}
.tutor-marked-fig img { display: block; width: 100%; height: auto; }
.tutor-mark {
  position: absolute; box-sizing: border-box; border-radius: 0.5rem; pointer-events: none;
  border: 0.125rem solid #E5484D; background: color-mix(in srgb, #E5484D 10%, transparent);
  box-shadow: 0 0 0 1px rgba(255,255,255,.55);
}
.tutor-mark.is-ok { border-color: #16A34A; background: color-mix(in srgb, #16A34A 10%, transparent); }
.tutor-mark em {
  position: absolute; left: -0.125rem; bottom: calc(100% + 0.1875rem); max-width: 16rem; padding: 0.1875rem 0.4375rem; border-radius: 0.375rem;
  font: 600 0.6875rem/1.3 var(--font); font-style: normal; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: #fff; background: #D93D42; box-shadow: 0 0.125rem 0.375rem rgba(0,0,0,.18);
}
.tutor-mark em.is-below { bottom: auto; top: calc(100% + 0.1875rem); }
.tutor-mark.is-ok em { background: #15803D; }
.tutor-read { margin: 0.25rem 0 0.375rem; }
.tutor-read summary { cursor: pointer; font-size: 0.75rem; font-weight: 600; color: var(--text-muted); padding: 0.125rem 0; list-style-position: inside; }
.tutor-read summary:hover { color: var(--text); }
.tutor-read[open] summary { margin-bottom: 0.25rem; }
.tutor-read .tutor-lines li:not(.is-ok):not(.is-wrong) { color: var(--text); }
.tutor-read-why { font-weight: 400; color: var(--text-muted); }
.tutor-read-fix { margin-top: 0.375rem; height: 1.875rem; font-size: 0.75rem; }
.tutor-unsure {
  margin-top: 0.25rem; padding: 0.4375rem 0.625rem; border-radius: 0.625rem; font-size: 0.75rem; line-height: 1.45;
  color: var(--text); background: color-mix(in srgb, #F59E0B 10%, transparent); border: 1px solid color-mix(in srgb, #F59E0B 26%, transparent);
}
.tutor-zoom {
  position: fixed; inset: 0; z-index: 4000; display: flex; align-items: center; justify-content: center; padding: 3.5rem 1rem 1rem;
  background: rgba(10, 12, 16, 0.82); backdrop-filter: blur(0.375rem); -webkit-backdrop-filter: blur(0.375rem);
  animation: tutor-zoom-in .18s ease-out;
}
.tutor-zoom-inner { max-width: min(60rem, 100%); max-height: 100%; overflow: auto; border-radius: 0.875rem; }
.tutor-zoom-inner > img, .tutor-zoom-inner .tutor-marked-fig img { display: block; max-width: 100%; max-height: calc(100vh - 5rem); width: auto; margin: 0 auto; }
.tutor-zoom-inner .tutor-marked-fig { max-width: none; cursor: default; border: 0; display: inline-block; width: auto; }
.tutor-zoom-inner .tutor-mark em { font-size: 0.8125rem; }
.tutor-zoom-x { position: absolute; top: 0.875rem; right: 0.875rem; }
@keyframes tutor-zoom-in { from { opacity: 0; } to { opacity: 1; } }

/* Figures drawn to scale (public/js/figure.js): graphs, shapes, number
   lines, circuits. They sit in a chart card and take its palette; ink is
   the text colour, so they hold in both themes. */
.md-figure { color: var(--text); }
.md-figure .fig-svg { display: block; width: 100%; max-width: 30rem; height: auto; margin: 0 auto; overflow: visible; font-family: var(--font); }
.fig-grid { stroke: var(--md-grid); stroke-width: 1; fill: none; }
.fig-axis { stroke: color-mix(in srgb, currentColor 62%, transparent); stroke-width: 1.2; fill: none; }
.fig-axis-head { fill: color-mix(in srgb, currentColor 62%, transparent); }
.fig-label { font-size: 0.6875rem; fill: currentColor; font-weight: 550; paint-order: stroke; stroke: var(--md-label-halo, color-mix(in srgb, var(--surface) 88%, transparent)); stroke-width: 0.1875rem; stroke-linejoin: round; }
.fig-tick { font-size: 0.5938rem; font-weight: 450; fill: color-mix(in srgb, currentColor 62%, transparent); font-variant-numeric: tabular-nums; }
.fig-axis-name { font-size: 0.6875rem; font-style: italic; font-weight: 600; fill: color-mix(in srgb, currentColor 75%, transparent); }
.fig-curve { fill: none; stroke: var(--c); stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.fig-curve.is-dash, .fig-seg.is-dash, .fig-vec.is-dash { stroke-dasharray: 5 4; }
.fig-curve-label, .fig-vec-label { fill: var(--c); font-weight: 700; }
.fig-shade { fill: color-mix(in srgb, var(--c1) 18%, transparent); stroke: none; }
.fig-ref { stroke: color-mix(in srgb, currentColor 45%, transparent); stroke-width: 1.2; stroke-dasharray: 4 4; fill: none; }
.fig-ref-label { font-size: 0.625rem; fill: color-mix(in srgb, currentColor 70%, transparent); }
.fig-seg { stroke: currentColor; stroke-width: 1.8; fill: none; stroke-linecap: round; }
.fig-vec { stroke: var(--c); stroke-width: 2.4; fill: none; stroke-linecap: round; }
.fig-head { fill: currentColor; stroke: none; }
.fig-vec.fig-head { fill: var(--c); }
.fig-point { fill: var(--c2); stroke: var(--surface); stroke-width: 1.5; }
.fig-point.is-open { fill: var(--surface); stroke: var(--c2); stroke-width: 2; }
.fig-poly { fill: color-mix(in srgb, var(--c) 12%, transparent); stroke: currentColor; stroke-width: 1.8; stroke-linejoin: round; }
.fig-circle { fill: color-mix(in srgb, var(--c) 8%, transparent); stroke: var(--c); stroke-width: 1.8; }
.fig-angle { fill: none; stroke: var(--c2); stroke-width: 1.5; }
.fig-angle-label { fill: var(--c2); font-size: 0.6562rem; }
.fig-name { font-weight: 700; font-size: 0.75rem; font-style: italic; }
.fig-side { font-size: 0.6562rem; }
.fig-interval { stroke: var(--c); stroke-width: 4; stroke-linecap: round; fill: none; }
.fig-interval-head { fill: var(--c); }
.fig-end { fill: var(--c); stroke: var(--c); stroke-width: 2; }
.fig-end.is-open { fill: var(--surface); }
.fig-wire { stroke: currentColor; stroke-width: 1.6; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.fig-comp { stroke: currentColor; stroke-width: 1.8; fill: var(--surface); stroke-linejoin: round; }
.fig-comp.is-thick { stroke-width: 3.6; }
.fig-node { fill: currentColor; }
.fig-meter { font-size: 0.625rem; font-weight: 800; }
.fig-comp-label { font-size: 0.625rem; }
.fig-pole { font-size: 0.625rem; font-weight: 700; }

/* A plot to play with (figure.js livePlot): drag to move, zoom, full
   screen; sliders for its parameters, the equations reading their values,
   the family traced as it moves. */
.fig-live { position: relative; }
.fig-stage { position: relative; }
.fig-live .fig-svg { touch-action: pan-y; cursor: grab; user-select: none; -webkit-user-select: none; }
.fig-live.is-active .fig-svg { touch-action: none; }
.fig-live .fig-svg:active { cursor: grabbing; }
.fig-point.is-drag { cursor: ew-resize; stroke-width: 2.5; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.22)); }
.fig-trail { fill: none; stroke: var(--c); stroke-width: 1.1; opacity: 0.16; }
.fig-tools { position: absolute; top: 0.25rem; right: 0.25rem; display: flex; gap: 0.125rem; padding: 0.125rem; border-radius: 0.625rem; background: color-mix(in srgb, var(--surface) 86%, transparent); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); opacity: 0; transition: opacity .15s ease; }
.fig-live:hover .fig-tools, .fig-live.is-active .fig-tools, .fig-live.is-big .fig-tools, .fig-tools:focus-within { opacity: 1; }
@media (hover: none) { .fig-tools { opacity: 1; } }
.fig-tool { display: grid; place-items: center; width: 1.875rem; height: 1.875rem; border: 0; border-radius: 0.5rem; background: none; color: var(--text-muted); cursor: pointer; transition: background .15s ease, color .15s ease; }
.fig-tool:hover, .fig-tool:focus-visible { background: var(--surface2); color: var(--text); outline: none; }
.fig-tool[aria-pressed="true"] { color: var(--c1); background: color-mix(in srgb, var(--c1) 12%, transparent); }
.fig-eqs { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.25rem 0.875rem; margin: 0.375rem 0 0; }
.fig-eq { font-size: 0.875rem; font-weight: 600; font-style: italic; color: var(--c); font-variant-numeric: tabular-nums; white-space: nowrap; }
.fig-params { display: flex; flex-direction: column; gap: 0.375rem; margin: 0.625rem 0 0.125rem; padding-top: 0.625rem; border-top: 1px solid color-mix(in srgb, currentColor 9%, transparent); }
.fig-param { display: grid; grid-template-columns: minmax(1.5rem, auto) 1fr 3.25rem; align-items: center; gap: 0.625rem; }
.fig-param-name { display: flex; flex-direction: column; font-size: 0.9375rem; font-weight: 700; font-style: italic; line-height: 1.15; }
.fig-param-name small { font-size: 0.6875rem; font-weight: 500; font-style: normal; color: var(--text-muted); max-width: 7rem; }
.fig-param output { font-size: 0.875rem; font-weight: 600; text-align: right; font-variant-numeric: tabular-nums; }
.fig-param input[type="range"] { width: 100%; accent-color: var(--c1); margin: 0; height: 1.5rem; cursor: pointer; }
.fig-param-acts { display: flex; justify-content: flex-end; gap: 0.25rem; }
.fig-param-acts [data-fig-act="play"] { color: var(--c1); }
.fig-live.is-big {
  position: fixed; z-index: 5001; inset: 1.5rem; margin: 0; overflow: auto; display: flex; flex-direction: column;
  background: var(--surface); border: 0; box-shadow: 0 1.5rem 4rem rgba(0, 0, 0, 0.28); padding: 1rem 1.25rem;
  animation: fig-big-in .18s ease-out;
}
.fig-live.is-big .fig-stage { flex: 1; min-height: 0; display: flex; align-items: center; }
.fig-live.is-big .fig-svg { max-width: none; width: 100%; height: 100%; }
.fig-live.is-big .fig-eq { font-size: 1.0625rem; }
.fig-scrim { position: fixed; inset: 0; z-index: 5000; background: rgba(10, 12, 16, 0.55); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); animation: fig-big-in .18s ease-out; }
@keyframes fig-big-in { from { opacity: 0; } to { opacity: 1; } }
@media (max-width: 640px) { .fig-live.is-big { inset: 0; border-radius: 0; padding: 0.75rem 0.75rem calc(0.75rem + env(safe-area-inset-bottom)); } }
@media (prefers-reduced-motion: reduce) { .fig-live.is-big, .fig-scrim { animation: none; } }

/* Pictures in a conversation (public/js/pictures.js): a real one found,
   with where it is from; or a button to make one, asked first. */
.md-image-offer { margin: 0.625rem 0 0.25rem; display: flex; flex-direction: column; gap: 0.5rem; white-space: normal; }
.pic-figure { margin: 0; border-radius: 0.875rem; overflow: hidden; border: 1px solid color-mix(in srgb, currentColor 11%, transparent); background: var(--surface); max-width: 28rem; }
.pic-zoom { display: block; width: 100%; padding: 0; border: 0; background: #fff; cursor: zoom-in; line-height: 0; }
.pic-zoom img { display: block; width: 100%; max-height: 22rem; object-fit: contain; }
.pic-figure figcaption { display: flex; flex-direction: column; gap: 0.125rem; padding: 0.5rem 0.75rem 0.5625rem; font-size: 0.75rem; line-height: 1.4; }
.pic-caption { color: var(--text); font-weight: 550; }
.pic-credit { color: var(--text-muted); font-size: 0.6875rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pic-credit a { color: inherit; text-decoration: underline; text-underline-offset: 0.125rem; }
.pic-badge { display: inline-flex; align-items: center; gap: 0.25rem; font-weight: 600; color: #7C5BD9; }
:root[data-theme="dark"] .pic-badge { color: #B9A3FF; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .pic-badge { color: #B9A3FF; } }
.pic-loading, .pic-none { display: flex; align-items: center; gap: 0.5rem; padding: 0.625rem 0.75rem; border-radius: 0.75rem; font-size: 0.75rem; color: var(--text-muted);
  background: color-mix(in srgb, currentColor 4%, transparent); max-width: 28rem; }
.pic-shimmer { width: 2.25rem; height: 1.5rem; border-radius: 0.375rem; flex-shrink: 0;
  background: linear-gradient(90deg, color-mix(in srgb, currentColor 8%, transparent) 0%, color-mix(in srgb, currentColor 16%, transparent) 50%, color-mix(in srgb, currentColor 8%, transparent) 100%);
  background-size: 200% 100%; animation: pic-shimmer 1.2s linear infinite; }
.pic-allowance .pic-shimmer { width: 10rem; height: 0.875rem; }
@keyframes pic-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
.pic-offer { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.75rem; }
.pic-offer-why { font-size: 0.8125rem; color: var(--text-muted); }
.pic-make-btn {
  display: inline-flex; align-items: center; gap: 0.375rem; height: 2rem; padding: 0 0.875rem; border-radius: 62.4375rem; border: 0; cursor: pointer;
  font: 600 0.75rem/1 var(--font); color: #5B3FC4; background: color-mix(in srgb, #7C5BD9 13%, transparent);
  transition: background .15s ease, transform .12s ease;
}
.pic-make-btn:hover, .pic-make-btn:focus-visible { background: color-mix(in srgb, #7C5BD9 20%, transparent); outline: none; }
.pic-make-btn:active { transform: scale(0.96); }
:root[data-theme="dark"] .pic-make-btn { color: #CBB9FF; background: color-mix(in srgb, #9B7DFF 20%, transparent); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .pic-make-btn { color: #CBB9FF; background: color-mix(in srgb, #9B7DFF 20%, transparent); } }
.pic-more { font-size: 0.75rem; }
.pic-more summary { cursor: pointer; color: var(--text-muted); margin-bottom: 0.375rem; }
.pic-confirm { z-index: 3500; }
.pic-confirm textarea { width: 100%; box-sizing: border-box; resize: vertical; min-height: 5.5rem; font: inherit; font-size: 0.875rem; line-height: 1.45; padding: 0.625rem 0.75rem;
  border-radius: 0.75rem; border: 1px solid var(--border); background: var(--surface); color: var(--text); }
.pic-confirm-label { display: block; font-size: 0.75rem; font-weight: 600; color: var(--text-muted); margin: 0 0 0.375rem; }
.pic-confirm-src { display: block; max-width: 100%; max-height: 10rem; margin: 0 0 0.75rem; border-radius: 0.625rem; object-fit: contain; background: var(--surface2); }
.pic-confirm-warn { margin: 0 0 0.75rem; font-size: 0.8125rem; color: #B42318; }
.pic-allowance { margin-top: 0.625rem; font-size: 0.8125rem; line-height: 1.45; color: var(--text-muted); }
.pic-allowance b { color: var(--text); font-weight: 600; }
.pic-link { border: 0; background: none; padding: 0; font: inherit; font-weight: 600; color: var(--accent); cursor: pointer; }
.pic-err { margin-top: 0.375rem; color: #B42318; font-size: 0.75rem; }
.pic-spin { display: inline-block; width: 0.75rem; height: 0.75rem; margin-right: 0.375rem; border-radius: 50%; border: 0.125rem solid rgba(255,255,255,.45); border-top-color: #fff; animation: pic-spin .7s linear infinite; vertical-align: -1px; }
@keyframes pic-spin { to { transform: rotate(360deg); } }

/* Revising for a test (studytutor.js, "Practice" and "Check"): one question
   at a time, marked by Chrono with the reason; a marked test as a paper;
   "Not on my test" on every question; and the references it is all
   written from. */
.rv-card { display: flex; flex-direction: column; gap: 0.625rem; padding: 0.875rem 0.9375rem 0.9375rem; border-radius: 0.875rem;
  border: 1px solid var(--border); background: var(--surface); box-shadow: var(--shadow-sm); }
.rv-card.is-flagged { opacity: 0.72; }
.rv-card-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; min-width: 0; }
.rv-meta { min-width: 0; font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rv-q { font-size: 0.9375rem; line-height: 1.5; color: var(--text); font-weight: 500; }
.rv-input { min-height: 4.5rem; }
.rv-actions { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; }
.rv-given { font-size: 0.8125rem; line-height: 1.5; color: var(--text); padding: 0.5rem 0.625rem; border-radius: 0.625rem; background: var(--surface2); white-space: pre-wrap; }
.rv-verdict { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 0.5rem; padding: 0.5625rem 0.75rem; border-radius: 0.625rem; font-size: 0.8125rem; line-height: 1.5; }
.rv-verdict b { font-weight: 700; }
.rv-verdict .rv-dot { width: 0.5rem; height: 0.5rem; border-radius: 50%; flex-shrink: 0; align-self: center; }
.rv-verdict.is-right { background: color-mix(in srgb, #22C55E 11%, transparent); }
.rv-verdict.is-right .rv-dot { background: #22C55E; } .rv-verdict.is-right b { color: #15803D; }
.rv-verdict.is-partly { background: color-mix(in srgb, #F59E0B 12%, transparent); }
.rv-verdict.is-partly .rv-dot { background: #F59E0B; } .rv-verdict.is-partly b { color: #B45309; }
.rv-verdict.is-wrong { background: color-mix(in srgb, #EF4444 10%, transparent); }
.rv-verdict.is-wrong .rv-dot { background: #EF4444; } .rv-verdict.is-wrong b { color: #B91C1C; }
:root[data-theme="dark"] .rv-verdict.is-right b { color: #4ADE80; } :root[data-theme="dark"] .rv-verdict.is-partly b { color: #FBBF24; } :root[data-theme="dark"] .rv-verdict.is-wrong b { color: #F87171; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .rv-verdict.is-right b { color: #4ADE80; } :root:not([data-theme="light"]) .rv-verdict.is-partly b { color: #FBBF24; } :root:not([data-theme="light"]) .rv-verdict.is-wrong b { color: #F87171; } }
.rv-label { font-size: 0.6875rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-dim); margin-bottom: 0.25rem; }
.rv-answer { padding: 0.5625rem 0.75rem; border-radius: 0.625rem; background: color-mix(in srgb, var(--accent) 8%, transparent); font-size: 0.8125rem; line-height: 1.5; }
.rv-answer .md-body p { margin: 0 0 0.375rem; } .rv-answer .md-body p:last-child { margin: 0; }
.rv-answer-fold { margin-top: 0.25rem; font-size: 0.8125rem; }
.rv-answer-fold summary { cursor: pointer; font-weight: 600; color: var(--text-muted); width: max-content; }
.rv-answer-fold .md-body { margin-top: 0.25rem; padding: 0.5rem 0.625rem; border-radius: 0.5rem; background: color-mix(in srgb, var(--accent) 8%, transparent); }
.rv-flag {
  flex-shrink: 0; display: inline-flex; align-items: center; gap: 0.3125rem; height: 1.625rem; padding: 0 0.5625rem; border-radius: 62.4375rem; cursor: pointer;
  border: 1px solid transparent; background: transparent; color: var(--text-dim); font: 600 0.6875rem/1 var(--font);
  transition: color .15s ease, background .15s ease, border-color .15s ease;
}
.rv-flag:hover, .rv-flag:focus-visible { color: var(--text); background: var(--surface2); outline: none; }
.rv-flag.is-on { color: #B45309; background: color-mix(in srgb, #F59E0B 13%, transparent); }
:root[data-theme="dark"] .rv-flag.is-on { color: #FBBF24; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .rv-flag.is-on { color: #FBBF24; } }
.rv-flag-note { font-size: 0.8125rem; line-height: 1.45; color: var(--text-muted); }
.rv-progress { display: flex; gap: 0.25rem; justify-content: center; margin-top: 0.75rem; }
.rv-progress i { width: 1.375rem; height: 0.25rem; border-radius: 62.4375rem; background: var(--border2); }
.rv-progress i.is-now { background: var(--text-muted); }
.rv-progress i.is-right { background: #22C55E; } .rv-progress i.is-partly { background: #F59E0B; } .rv-progress i.is-wrong { background: #EF4444; }
.rv-progress i.is-flagged { background: transparent; border: 1px dashed var(--border2); }
.rv-done { display: flex; align-items: center; gap: 0.875rem; padding: 0.875rem 1rem; border-radius: 0.875rem; background: var(--surface2); margin-bottom: 0.75rem; }
.rv-score { display: flex; align-items: baseline; flex-shrink: 0; font-variant-numeric: tabular-nums; }
.rv-score-n { font-size: 2rem; font-weight: 750; line-height: 1; color: var(--text); letter-spacing: -0.02em; }
.rv-score-of { font-size: 1rem; font-weight: 600; color: var(--text-muted); margin-left: 0.125rem; }
.rv-done-text { min-width: 0; }
.rv-review { margin-bottom: 0.5rem; }
.rv-intro { display: flex; flex-direction: column; gap: 0.75rem; }
.rv-sizes { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.5rem; }
.rv-size { display: flex; flex-direction: column; align-items: center; gap: 0.125rem; padding: 0.625rem 0.5rem; border-radius: 0.75rem; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface); color: var(--text-muted); font: inherit; transition: border-color .15s ease, background .15s ease, color .15s ease; }
.rv-size b { font-size: 1.25rem; font-weight: 750; color: var(--text); font-variant-numeric: tabular-nums; }
.rv-size span { font-size: 0.6875rem; }
.rv-size.is-active { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--surface)); color: var(--text); box-shadow: 0 0 0 1px var(--accent) inset; }
.rv-paper .rv-paper-q { padding: 0.75rem 0.875rem; border-radius: 0.75rem; border: 1px solid var(--border); background: var(--surface); }
.rv-paper .rv-paper-q.is-flagged { opacity: 0.7; }

/* References: always one tap away in the header, open as a panel. */
.rv-refs-btn {
  display: inline-flex; align-items: center; gap: 0.3125rem; height: 2rem; padding: 0 0.625rem 0 0.5rem; border-radius: 62.4375rem; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface); color: var(--text); font: 600 0.75rem/1 var(--font);
  transition: background .15s ease, border-color .15s ease;
}
.rv-refs-btn svg { color: var(--accent); flex-shrink: 0; }
.rv-refs-btn b { min-width: 1.125rem; height: 1.125rem; padding: 0 0.3125rem; border-radius: 62.4375rem; display: inline-grid; place-items: center; font-size: 0.6875rem; background: var(--surface2); color: var(--text); }
.rv-refs-btn:hover, .rv-refs-btn.is-open { background: var(--surface2); }
@container (max-width: 22rem) { .rv-refs-btn-label { display: none; } }
.rv-refs { display: flex; flex-direction: column; gap: 0.625rem; padding: 0.875rem; border-radius: 0.875rem; border: 1px solid var(--border); background: var(--surface); }
.rv-refs-lede { margin: 0; font-size: 0.75rem; line-height: 1.45; color: var(--text-muted); }
.rv-refs-empty { margin: 0; font-size: 0.8125rem; color: var(--text-muted); }
.rv-ref-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.rv-ref { display: flex; align-items: flex-start; gap: 0.625rem; padding: 0.5625rem 0; border-top: 1px solid var(--border); }
.rv-ref:first-child { border-top: 0; padding-top: 0.125rem; }
.rv-ref-ico { flex-shrink: 0; width: 1.75rem; height: 1.75rem; border-radius: 0.5rem; display: grid; place-items: center; background: var(--surface2); color: var(--text-muted); }
.rv-ref-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.1875rem; }
.rv-ref-top { display: flex; align-items: baseline; gap: 0.5rem; min-width: 0; }
.rv-ref-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 600 0.8125rem/1.35 var(--font); color: var(--text); border: 0; background: none; padding: 0; text-align: left; }
.rv-ref-name.is-link { cursor: pointer; color: var(--accent); }
.rv-ref-scope { flex-shrink: 0; max-width: 45%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.6875rem; color: var(--text-dim); }
.rv-ref-note { display: flex; align-items: flex-start; gap: 0.3125rem; border: 0; background: none; padding: 0; cursor: pointer; text-align: left;
  font: 0.75rem/1.45 var(--font); color: var(--text-muted); }
.rv-ref-note svg { flex-shrink: 0; margin-top: 0.125rem; opacity: 0.6; }
.rv-ref-note.is-empty { color: var(--text-dim); font-style: italic; }
.rv-ref-note:hover { color: var(--text); }
.rv-ref-note-edit textarea { width: 100%; box-sizing: border-box; font: inherit; font-size: 0.8125rem; padding: 0.4375rem 0.5625rem; border-radius: 0.5rem; border: 1px solid var(--border); background: var(--bg); color: var(--text); resize: vertical; }
.rv-scope { display: flex; flex-wrap: wrap; align-items: center; gap: 0.375rem; font-size: 0.75rem; color: var(--text-muted); }
.rv-scope-opt { max-width: 14rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; height: 1.625rem; padding: 0 0.625rem; border-radius: 62.4375rem; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface); color: var(--text-muted); font: 600 0.6875rem/1 var(--font); }
.rv-scope-opt.is-active { border-color: var(--accent); color: var(--text); background: color-mix(in srgb, var(--accent) 9%, var(--surface)); }
.rv-ref-add { display: flex; flex-wrap: wrap; gap: 0.375rem; }
.rv-ref-add-btn { display: inline-flex; align-items: center; gap: 0.375rem; height: 2rem; padding: 0 0.75rem; border-radius: 62.4375rem; cursor: pointer;
  border: 0; background: color-mix(in srgb, var(--text) 6%, transparent); color: var(--text); font: 600 0.75rem/1 var(--font); transition: background .15s ease; }
.rv-ref-add-btn:hover, .rv-ref-add-btn:focus-within { background: color-mix(in srgb, var(--text) 10%, transparent); }
.rv-ref-add-btn svg { color: var(--text-muted); }
#rv-ref-note-form input { width: 100%; box-sizing: border-box; margin-bottom: 0.375rem; font: inherit; font-size: 0.8125rem; padding: 0.4375rem 0.5625rem; border-radius: 0.5rem; border: 1px solid var(--border); background: var(--bg); color: var(--text); }

/* ── Exam Study Help (revising for a test) ──────────────────────────────── */
/* One calm column: where you are, the topic in full, how ready, three steps,
   then the work. Scoped to .is-revise so homework help keeps its own look. */
.study-topic.is-revise { gap: 1rem; padding-top: 0.75rem; }
.is-revise .rvx-head { display: flex; flex-direction: column; align-items: stretch; gap: 0.5rem; margin: 0; position: relative; }
.is-revise .rvx-bar { display: flex; align-items: center; gap: 0.25rem; margin: 0 -0.375rem; min-height: 2rem; }
.is-revise .rvx-bar .tutor-back { flex-shrink: 0; }
.rvx-crumb { flex: 1; min-width: 0; font-size: 0.6875rem; font-weight: 650; letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rvx-tools { display: flex; align-items: center; gap: 0.125rem; flex-shrink: 0; }
.rvx-tool { position: relative; width: 2rem; height: 2rem; display: grid; place-items: center; border: 0; border-radius: 0.625rem; background: transparent; color: var(--text-muted); cursor: pointer; padding: 0; transition: background .15s, color .15s; }
.rvx-tool:hover, .rvx-tool:focus-visible, .rvx-tool.is-open { background: var(--surface2); color: var(--text); outline: none; }
.rvx-tool.is-open { color: var(--accent); }
.rvx-badge { position: absolute; top: 0.125rem; right: 0.0625rem; min-width: 0.9375rem; height: 0.9375rem; padding: 0 0.25rem; border-radius: 62.4375rem; display: grid; place-items: center; font-size: 0.5625rem; font-weight: 750; background: var(--accent); color: #fff; box-shadow: 0 0 0 2px var(--surface); }
.is-revise .rvx-title { display: flex; align-items: flex-start; gap: 0.375rem; width: 100%; margin: 0; padding: 0; border: 0; background: none; text-align: left; font: 700 1.1875rem/1.28 var(--font); letter-spacing: -0.015em; color: var(--text); }
.is-revise button.rvx-title { cursor: pointer; border-radius: 0.5rem; padding: 0.125rem 0.375rem; margin: 0 -0.375rem; width: calc(100% + 0.75rem); }
.is-revise button.rvx-title:hover, .is-revise button.rvx-title.is-open { background: var(--surface2); }
.is-revise .rvx-title .tutor-title-text { white-space: normal; overflow: visible; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.is-revise .rvx-title .tutor-title-chev { margin-top: 0.4375rem; width: 0.875rem; height: 0.875rem; }
.is-revise .tutor-step-menu { position: static; margin: -0.25rem 0 0; width: auto; max-width: none; box-shadow: 0 0.5rem 1.5rem rgba(16,24,40,0.1); }
.rvx-ready { display: flex; align-items: center; gap: 0.625rem; --lvl: #22C55E; }
.rvx-ready.lvl-low { --lvl: #EF4444; } .rvx-ready.lvl-mid { --lvl: #F59E0B; } .rvx-ready.is-none { --lvl: var(--border2); }
.rvx-ready-track { flex: 1; height: 0.375rem; border-radius: 62.4375rem; background: var(--surface2); overflow: hidden; }
.rvx-ready-track i { display: block; height: 100%; border-radius: inherit; background: var(--lvl); transition: width .6s var(--ease); }
.rvx-ready-label { flex-shrink: 0; font-size: 0.75rem; font-weight: 650; color: var(--text-muted); font-variant-numeric: tabular-nums; display: inline-flex; align-items: center; gap: 0.375rem; }
.rvx-ready-label em { font-style: normal; font-size: 0.6875rem; font-weight: 700; padding: 0.0625rem 0.375rem; border-radius: 62.4375rem; }
.rvx-ready-label em.up { color: #15803D; background: color-mix(in srgb, #22C55E 14%, transparent); }
.rvx-ready-label em.down { color: #B45309; background: color-mix(in srgb, #F59E0B 14%, transparent); }

/* The three steps as a stepper: number, name, a tick once done. */
.is-revise .rvx-steps { display: grid; grid-template-columns: repeat(3, minmax(0, auto)); /* each label as wide as it needs, the rest shared */ gap: 0.25rem; padding: 0.25rem; border-radius: 0.875rem; background: var(--surface2); }
.is-revise .rvx-step { display: flex; align-items: center; justify-content: center; gap: 0.3125rem; min-width: 0; height: 2.125rem; padding: 0 0.25rem; border: 0; border-radius: 0.6875rem; background: transparent; color: var(--text-muted); font: 600 0.8125rem/1 var(--font); cursor: pointer; transition: background .18s, color .18s, box-shadow .18s; }
.is-revise .rvx-step:hover { color: var(--text); }
.is-revise .rvx-step.is-active { background: var(--surface); color: var(--text); box-shadow: 0 1px 2px rgba(16,24,40,0.06), 0 0 0 1px color-mix(in srgb, var(--text) 5%, transparent); }
.rvx-step-n { width: 1rem; height: 1rem; flex-shrink: 0; border-radius: 50%; display: grid; place-items: center; font-size: 0.6875rem; font-weight: 750; background: color-mix(in srgb, var(--text) 8%, transparent); color: var(--text-muted); }
.rvx-step.is-active .rvx-step-n { background: var(--accent); color: #fff; }
.rvx-step.is-done:not(.is-active) .rvx-step-n { background: color-mix(in srgb, #22C55E 18%, transparent); color: #15803D; }
.rvx-step-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Beside the page the panel is narrow: a size smaller, so the longest
   of the three still reads whole. */
@media (min-width: 769px) { #screen-app:not(.study-max) .is-revise .rvx-step { font-size: 0.75rem; padding: 0 0.125rem; } }

/* References: a card that reads top to bottom. */
.is-revise .rvx-refs { gap: 0.75rem; padding: 0.875rem 0.9375rem; border-radius: 0.875rem; animation: rvx-in .22s var(--ease); }
@keyframes rvx-in { from { opacity: 0; transform: translateY(-0.25rem); } to { opacity: 1; transform: none; } }
.rvx-refs-head { display: flex; flex-direction: column; gap: 0.125rem; }
.rvx-refs-head b { font-size: 0.875rem; font-weight: 700; color: var(--text); }
.rvx-refs-head > span { font-size: 0.75rem; line-height: 1.45; color: var(--text-muted); }
.rvx-refs-head:has(#rv-refs-lesson) { flex-direction: row; align-items: center; justify-content: space-between; gap: 0.5rem; }
.rvx-refs-head .tutor-rebuild { margin: 0; }
.tutor-rebuild.is-stale { color: var(--accent); }
.is-revise .rv-ref-scope { max-width: none; font-size: 0.6875rem; color: var(--text-dim); }
.is-revise .rv-ref-name { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.rvx-refs-add { display: flex; flex-direction: column; gap: 0.5rem; }
.rv-ref-list + .rvx-refs-add { padding-top: 0.75rem; border-top: 1px solid var(--border); }
.rvx-seg { display: flex; align-items: center; gap: 0.25rem; padding: 0.1875rem; border-radius: 62.4375rem; background: var(--surface2); width: max-content; max-width: 100%; }
.rvx-seg-label { font-size: 0.6875rem; font-weight: 600; color: var(--text-dim); padding: 0 0.375rem 0 0.5rem; white-space: nowrap; }
.is-revise .rvx-seg .rv-scope-opt { height: 1.625rem; border: 0; background: transparent; color: var(--text-muted); font: 600 0.75rem/1 var(--font); padding: 0 0.6875rem; }
.is-revise .rvx-seg .rv-scope-opt.is-active { background: var(--surface); color: var(--text); box-shadow: 0 1px 2px rgba(16,24,40,0.08); }
.is-revise .rvx-refs-add .rv-ref-add { display: grid; grid-template-columns: repeat(auto-fit, minmax(6.5rem, 1fr)); gap: 0.375rem; }
.is-revise .rv-ref-add-btn { justify-content: center; height: 2.125rem; padding: 0 0.625rem; border-radius: 0.625rem; font-size: 0.75rem; font-weight: 600; white-space: nowrap; }
.is-revise .rv-ref-add-btn.is-on { background: color-mix(in srgb, var(--accent) 12%, transparent); color: var(--text); }

/* Learn */
.rvx-label { font-size: 0.6875rem; font-weight: 650; letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-dim); margin-bottom: 0.4375rem; }
.rvx-lesson { display: flex; flex-direction: column; gap: 0.875rem; }
.is-revise .tutor-explain { font-size: 0.9375rem; line-height: 1.65; }
.rvx-remember { padding: 0.75rem 0.875rem; border-radius: 0.875rem; background: color-mix(in srgb, var(--accent) 7%, var(--surface)); border: 1px solid color-mix(in srgb, var(--accent) 16%, transparent); }
.rvx-remember .rvx-label { color: var(--accent-dim); }
.is-revise .rvx-remember .tutor-kp { padding: 0 0 0 1.125rem; background: none; font-size: 0.875rem; }
.rvx-ask { padding-top: 0.875rem; border-top: 1px solid var(--border); }
.rvx-foot { position: sticky; bottom: 0; z-index: 2; display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 0.5rem; margin: 0 -1.125rem -1.5rem; padding: 0.75rem 1.125rem calc(0.875rem + env(safe-area-inset-bottom, 0px)); background: linear-gradient(to bottom, color-mix(in srgb, var(--surface) 0%, transparent), var(--surface) 35%); }
.is-revise .rvx-go { gap: 0.25rem; padding-right: 0.75rem; }

/* Practice */
.rvx-practice-top { display: flex; align-items: center; gap: 0.75rem; }
.rvx-count { flex-shrink: 0; font-size: 0.75rem; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.rvx-count b { font-size: 0.875rem; color: var(--text); font-weight: 700; }
.rvx-progress { flex: 1; display: flex; gap: 0.25rem; }
.rvx-progress i { flex: 1; height: 0.3125rem; border-radius: 62.4375rem; background: var(--surface2); transition: background .25s; }
.rvx-progress i.is-now { background: var(--text-muted); }
.rvx-progress i.is-right { background: #22C55E; } .rvx-progress i.is-partly { background: #F59E0B; } .rvx-progress i.is-wrong { background: #EF4444; }
.rvx-progress i.is-flagged { background: transparent; box-shadow: inset 0 0 0 1px var(--border2); }
.is-revise .rvx-card { gap: 0.75rem; padding: 1rem 1rem 0.625rem; border-radius: 1rem; box-shadow: 0 1px 2px rgba(16,24,40,0.04), 0 0.375rem 1.25rem rgba(16,24,40,0.04); }
.rvx-card-meta { display: flex; align-items: center; gap: 0.4375rem; min-width: 0; }
.rvx-level { flex-shrink: 0; font-size: 0.625rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; padding: 0.125rem 0.4375rem; border-radius: 62.4375rem; }
.rvx-level.lvl-1 { color: #15803D; background: color-mix(in srgb, #22C55E 13%, transparent); }
.rvx-level.lvl-2 { color: #1D4ED8; background: color-mix(in srgb, #3B82F6 12%, transparent); }
.rvx-level.lvl-3 { color: #7C3AED; background: color-mix(in srgb, #8B5CF6 13%, transparent); }
.rvx-q-topic { min-width: 0; font-size: 0.6875rem; color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.is-revise .rv-q { font-size: 0.9375rem; line-height: 1.55; font-weight: 500; }
.rvx-hint { display: flex; gap: 0.5rem; align-items: flex-start; padding: 0.5625rem 0.75rem; border-radius: 0.625rem; font-size: 0.8125rem; line-height: 1.5; color: var(--text); background: color-mix(in srgb, #F59E0B 11%, transparent); animation: rvx-in .2s var(--ease); }
.rvx-hint svg { flex-shrink: 0; margin-top: 0.125rem; color: #B45309; }
.is-revise .rv-input { min-height: 5rem; font-size: 0.875rem; }
.rvx-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.rvx-spacer { display: none; }
.is-revise .rvx-actions .btn { flex: 1 1 0; min-width: max-content; justify-content: center; }
.is-revise .rvx-actions .btn.rvx-hint-btn { flex: 0 0 auto; }
.is-revise .rvx-hint-btn { gap: 0.3125rem; padding-left: 0.75rem; color: #B45309; }
.rvx-card-foot { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin: 0 -0.375rem; padding-top: 0.375rem; border-top: 1px solid var(--border); }
.rvx-card-foot .rv-flag { font-size: 0.6875rem; }
.rvx-kbd { font-size: 0.6875rem; color: var(--text-dim); white-space: nowrap; }
.is-revise .rv-verdict { flex-wrap: nowrap; align-items: flex-start; gap: 0.5625rem; padding: 0.625rem 0.75rem; }
.is-revise .rv-verdict .rv-dot { margin-top: 0.4375rem; align-self: flex-start; }
.is-revise .rv-verdict > div { display: flex; flex-direction: column; gap: 0.125rem; }
.rvx-verdict-mini { font-size: 0.6875rem; font-weight: 650; color: var(--text-dim); }
.rvx-verdict-mini.is-wrong { color: #B91C1C; } .rvx-verdict-mini.is-partly { color: #B45309; }

/* Results (a practice set, a check) */
.rvx-result { display: flex; align-items: center; gap: 1rem; padding: 1rem; border-radius: 1rem; background: var(--surface2); }
.rvx-ring { --p: 0; --lvl: #22C55E; flex-shrink: 0; width: 4.5rem; height: 4.5rem; border-radius: 50%; display: grid; place-items: center; background: conic-gradient(var(--lvl) calc(var(--p) * 1%), color-mix(in srgb, var(--text) 9%, transparent) 0); }
.rvx-ring.lvl-low { --lvl: #EF4444; } .rvx-ring.lvl-mid { --lvl: #F59E0B; }
.rvx-ring > span { width: 3.75rem; height: 3.75rem; border-radius: 50%; background: var(--surface2); display: flex; align-items: baseline; justify-content: center; padding-top: 1.125rem; box-sizing: border-box; font-variant-numeric: tabular-nums; }
.rvx-ring b { font-size: 1.25rem; font-weight: 750; color: var(--text); letter-spacing: -0.02em; }
.rvx-ring small { font-size: 0.75rem; font-weight: 600; color: var(--text-muted); }
.rvx-result-text { min-width: 0; display: flex; flex-direction: column; gap: 0.25rem; }
.rvx-result-title { font-size: 1rem; font-weight: 700; color: var(--text); }
.rvx-result-sub, .rvx-move { font-size: 0.8125rem; color: var(--text-muted); }
.rvx-move s { color: var(--text-dim); }
.rvx-move b { font-weight: 700; color: #15803D; } .rvx-move b.lvl-low { color: #B91C1C; } .rvx-move b.lvl-mid { color: #B45309; }
.rvx-next-up { display: flex; flex-direction: column; gap: 0.5rem; }
.rvx-next-up p { margin: 0; font-size: 0.8125rem; line-height: 1.5; color: var(--text-muted); }
.rvx-missed { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.375rem; }
.rvx-missed > li { border-radius: 0.75rem; border: 1px solid var(--border); background: var(--surface); --dot: #EF4444; }
.rvx-missed > li.is-partly { --dot: #F59E0B; } .rvx-missed > li.is-right { --dot: #22C55E; }
.rvx-missed summary { list-style: none; display: flex; gap: 0.625rem; align-items: flex-start; padding: 0.625rem 0.75rem; cursor: pointer; }
.rvx-missed summary::-webkit-details-marker { display: none; }
.rvx-missed-dot { flex-shrink: 0; width: 0.5rem; height: 0.5rem; margin-top: 0.4375rem; border-radius: 50%; background: var(--dot); }
.rvx-missed-q { min-width: 0; font-size: 0.8125rem; line-height: 1.5; color: var(--text); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.rvx-missed details[open] .rvx-missed-q { display: block; -webkit-line-clamp: unset; }
.rvx-missed-body { display: flex; flex-direction: column; gap: 0.5rem; padding: 0 0.75rem 0.625rem 1.875rem; }
.rvx-missed-fb { margin: 0; font-size: 0.8125rem; line-height: 1.5; color: var(--text-muted); }
.rvx-missed-body .rvx-card-foot { margin: 0; border-top: 0; padding-top: 0; justify-content: flex-start; }
.rvx-saved { font-size: 0.75rem; }

/* Check */
.rvx-rules { margin: 0; padding: 0 0 0 1.125rem; display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.75rem; line-height: 1.5; color: var(--text-muted); }

@media (prefers-reduced-motion: reduce) {
  .rvx-refs, .rvx-hint { animation: none; }
}
:root[data-theme="dark"] .rvx-level.lvl-1, :root[data-theme="dark"] .rvx-step.is-done:not(.is-active) .rvx-step-n, :root[data-theme="dark"] .rvx-ready-label em.up, :root[data-theme="dark"] .rvx-move b { color: #4ADE80; }
:root[data-theme="dark"] .rvx-level.lvl-2 { color: #93C5FD; }
:root[data-theme="dark"] .rvx-level.lvl-3 { color: #C4B5FD; }
:root[data-theme="dark"] .rvx-hint svg, :root[data-theme="dark"] .is-revise .rvx-hint-btn, :root[data-theme="dark"] .rvx-ready-label em.down, :root[data-theme="dark"] .rvx-move b.lvl-mid { color: #FBBF24; }
:root[data-theme="dark"] .rvx-move b.lvl-low { color: #F87171; }
.is-revise .rvx-foot .btn { flex: 1 1 auto; justify-content: center; }
.is-revise .rvx-foot .btn-primary { flex-basis: 100%; }

/* What to focus on: the whole test, or a few of its references. */
.rvx-focus { display: flex; flex-direction: column; gap: 0.0625rem; }
.rvx-focus-chips { display: flex; flex-wrap: wrap; gap: 0.375rem; }
.rvx-chip { display: inline-flex; align-items: center; gap: 0.375rem; max-width: 100%; min-height: 2rem; padding: 0.3125rem 0.75rem; border-radius: 62.4375rem; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface); color: var(--text); font: 600 0.75rem/1.25 var(--font); text-align: left;
  transition: background .15s ease, border-color .15s ease, color .15s ease, box-shadow .15s ease; }
.rvx-chip:hover { border-color: color-mix(in srgb, var(--text) 22%, var(--border)); }
.rvx-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.rvx-chip.is-on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, var(--surface)); color: var(--text); box-shadow: inset 0 0 0 1px var(--accent); }
.rvx-chip-ico { display: inline-grid; place-items: center; color: var(--text-muted); flex-shrink: 0; }
.rvx-chip.is-on .rvx-chip-ico { color: var(--accent); }
.rvx-chip-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 14rem; }
/* A row of chips that scrolls sideways (studytutor.js chipCarousel): one
   line, snapping to a chip, the edges fading where there is more, and an
   arrow on each end on a wide screen. */
.cc { position: relative; min-width: 0; }
.cc > .cc-track {
  display: flex; flex-wrap: nowrap; gap: 0.375rem; overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x proximity; scroll-padding-inline: 0.25rem; scrollbar-width: none;
  padding: 0.125rem 0.0625rem 0.25rem;
  -webkit-mask: linear-gradient(to right, transparent 0, #000 1.75rem, #000 calc(100% - 1.75rem), transparent 100%);
  mask: linear-gradient(to right, transparent 0, #000 1.75rem, #000 calc(100% - 1.75rem), transparent 100%);
}
.cc-track::-webkit-scrollbar { display: none; }
.cc-track > * { flex: none; scroll-snap-align: start; }
.cc.is-start .cc-track { -webkit-mask: linear-gradient(to right, #000 calc(100% - 1.75rem), transparent 100%); mask: linear-gradient(to right, #000 calc(100% - 1.75rem), transparent 100%); }
.cc.is-end .cc-track { -webkit-mask: linear-gradient(to right, transparent 0, #000 1.75rem); mask: linear-gradient(to right, transparent 0, #000 1.75rem); }
.cc.is-start.is-end .cc-track, .cc.is-static .cc-track { -webkit-mask: none; mask: none; }
.cc-arrow {
  position: absolute; top: 50%; z-index: 1; display: grid; place-items: center; width: 1.75rem; height: 1.75rem; margin-top: -0.9375rem;
  border: 0; border-radius: 50%; cursor: pointer; color: var(--text);
  background: var(--surface); box-shadow: 0 0 0 1px var(--border), 0 0.25rem 0.75rem rgba(0,0,0,0.12);
  opacity: 0; pointer-events: none; transition: opacity 0.15s ease, transform 0.15s ease;
}
.cc-prev { left: -0.25rem; }
.cc-next { right: -0.25rem; }
.cc-arrow:active { transform: scale(0.92); }
@media (hover: hover) {
  .cc:hover:not(.is-start) .cc-prev, .cc:hover:not(.is-end) .cc-next { opacity: 1; pointer-events: auto; }
}
.cc.is-static .cc-arrow { display: none; }
.cc .rvx-chip-text { max-width: 12rem; }
.rvx-focus-tip { margin: 0.375rem 0 0; font-size: 0.75rem; line-height: 1.45; color: var(--text-dim); }

/* No references yet: the one thing to do first. */
.rvx-empty { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 0.25rem 0.75rem; padding: 0.875rem 0.875rem 0.75rem; border-radius: 0.875rem;
  border: 1px dashed color-mix(in srgb, var(--accent) 45%, var(--border)); background: color-mix(in srgb, var(--accent) 5%, var(--surface)); }
.rvx-empty-ico { width: 2.25rem; height: 2.25rem; border-radius: 0.625rem; display: grid; place-items: center; color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); }
.rvx-empty-ico svg { width: 1.125rem; height: 1.125rem; }
.rvx-empty-text { display: flex; flex-direction: column; gap: 0.1875rem; font-size: 0.8125rem; line-height: 1.45; color: var(--text-muted); }
.rvx-empty-text b { font-size: 0.875rem; color: var(--text); }
.rvx-empty-actions { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 0.375rem; margin-top: 0.5rem; }
.rvx-empty-actions .btn { display: inline-flex; align-items: center; gap: 0.375rem; }

/* A lesson, practice or mock test not yet written: what it will be, and
   the one button that writes it -- nothing is spent before that. */
.rvx-offer { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 0.375rem; padding: 1.5rem 1.125rem 1.125rem; border-radius: 1rem;
  border: 1px solid var(--border); background: radial-gradient(120% 90% at 50% 0%, color-mix(in srgb, var(--accent) 9%, var(--surface)) 0%, var(--surface) 62%); }
.rvx-offer.is-loading { min-height: 13rem; background: linear-gradient(100deg, var(--surface) 30%, var(--surface2) 50%, var(--surface) 70%); background-size: 300% 100%; animation: rvx-shimmer 1.4s ease-in-out infinite; }
@keyframes rvx-shimmer { from { background-position: 100% 0; } to { background-position: 0 0; } }
.rvx-offer-ico { width: 2.75rem; height: 2.75rem; border-radius: 0.875rem; display: grid; place-items: center; color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); margin-bottom: 0.25rem; }
.rvx-offer-title { font-size: 1.0625rem; font-weight: 750; letter-spacing: -0.01em; color: var(--text); }
.rvx-offer-on { max-width: 100%; font-size: 0.8125rem; font-weight: 600; color: var(--accent); overflow-wrap: anywhere; }
.rvx-offer-body { margin: 0.125rem 0 0; max-width: 26rem; font-size: 0.8125rem; line-height: 1.55; color: var(--text-muted); }
.rvx-offer-tip { margin: 0.25rem 0 0; max-width: 26rem; font-size: 0.75rem; line-height: 1.45; color: var(--text-dim); padding: 0.4375rem 0.625rem; border-radius: 0.625rem; background: var(--surface2); }
.rvx-offer .btn.rvx-offer-go { margin-top: 0.625rem; min-width: 12rem; height: 2.625rem; justify-content: center; }
.rvx-offer-note { font-size: 0.6875rem; color: var(--text-dim); }
.rvx-sim-points { list-style: none; margin: 0.375rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.375rem; text-align: left; max-width: 24rem; width: 100%; }
.rvx-sim-points li { position: relative; padding-left: 1.5rem; font-size: 0.8125rem; line-height: 1.45; color: var(--text); }
.rvx-sim-points li::before { content: ''; position: absolute; left: 0.25rem; top: 0.375rem; width: 0.5rem; height: 0.3125rem; border-left: 2px solid var(--accent); border-bottom: 2px solid var(--accent); transform: rotate(-45deg); }

/* Homework: the theory behind it, one tap from the conversation. */
.tutor-theory-btn { display: inline-flex; align-items: center; gap: 0.3125rem; height: 1.875rem; padding: 0 0.625rem; border-radius: 62.4375rem; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface); color: var(--text); font: 600 0.75rem/1 var(--font); transition: background .15s ease, border-color .15s ease; }
.tutor-theory-btn svg { color: var(--accent); }
.tutor-theory-btn:hover { background: var(--surface2); }
.tutor-theory-btn.is-on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, var(--surface)); }
.tutor-hw-lesson { display: flex; flex-direction: column; gap: 0.875rem; }
.tutor-hw-lesson .rvx-foot { margin: 0; padding-left: 0; padding-right: 0; }
@media (max-width: 420px) { .tutor-theory-btn span { display: none; } .tutor-theory-btn { width: 1.875rem; padding: 0; justify-content: center; } }
/* Beside the page the panel is narrow: the button is its icon, and the
   step's name gets the room. */
@media (min-width: 769px) {
  #screen-app:not(.study-max) .tutor-theory-btn span { display: none; }
  #screen-app:not(.study-max) .tutor-theory-btn { width: 1.875rem; padding: 0; justify-content: center; }
}
.is-revise .rvx-foot .rvx-go { flex-basis: auto; flex-grow: 0; }

/* The homework or test, opened: what it is about beyond its title. */
.iv-refs { display: flex; flex-direction: column; gap: 0.5rem; }
.iv-refs-empty { margin: 0; font-size: 0.8125rem; line-height: 1.5; color: var(--text-muted); }
.iv-refs-loading { height: 1.25rem; border-radius: 0.5rem; background: var(--surface2); }
.iv-ref-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.25rem; }
.iv-ref { display: flex; align-items: center; gap: 0.625rem; padding: 0.375rem 0.25rem 0.375rem 0; border-radius: 0.5rem; }
.iv-ref-ico { flex-shrink: 0; width: 1.75rem; height: 1.75rem; border-radius: 0.5rem; display: grid; place-items: center; background: var(--surface2); color: var(--text-muted); }
.iv-ref-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.iv-ref-name { font-size: 0.8125rem; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.iv-ref-note { font-size: 0.75rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.iv-ref .iv-step-x { opacity: 0; }
.iv-ref:hover .iv-step-x, .iv-ref .iv-step-x:focus-visible { opacity: 1; }
@media (hover: none) { .iv-ref .iv-step-x { opacity: 0.7; } }
.iv-ref-add { display: flex; flex-wrap: wrap; gap: 0.375rem; }
.iv-ref-btn { display: inline-flex; align-items: center; gap: 0.375rem; height: 1.875rem; padding: 0 0.6875rem; border: 1px solid var(--border); border-radius: 62.4375rem; background: var(--surface); color: var(--text); font: 600 0.75rem/1 var(--font); cursor: pointer; transition: background .15s, border-color .15s; }
.iv-ref-btn svg { color: var(--text-muted); }
.iv-ref-btn:hover, .iv-ref-btn:focus-within { background: var(--surface2); }
.iv-ref-btn.is-on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 9%, var(--surface)); }
.iv-ref-btn.is-busy { opacity: 0.7; pointer-events: none; }
.iv-ref-form { display: flex; gap: 0.375rem; align-items: center; }
.iv-ref-form.is-note { flex-direction: column; align-items: stretch; }
.iv-ref-form.is-note .iv-btn { align-self: flex-end; }
.iv-ref-form input, .iv-ref-form textarea { flex: 1; min-width: 0; box-sizing: border-box; font: inherit; font-size: 0.8125rem; padding: 0.4375rem 0.625rem; border-radius: 0.625rem; border: 1px solid var(--border); background: var(--bg); color: var(--text); resize: vertical; }
.iv-ref-form input:focus, .iv-ref-form textarea:focus { outline: none; border-color: var(--accent); box-shadow: var(--ring); }

/* The lesson as a deck of cards. */
.rvx-deck { display: flex; flex-direction: column; gap: 0.625rem; }
.rvx-deck-track { display: flex; gap: 0.75rem; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; overscroll-behavior-x: contain; outline: none; }
.rvx-deck-track::-webkit-scrollbar { display: none; }
.rvx-slide { flex: 0 0 100%; box-sizing: border-box; scroll-snap-align: start; display: flex; flex-direction: column; gap: 0.625rem; min-height: 13rem; padding: 1.125rem 1.125rem 1rem; border-radius: 1rem; border: 1px solid var(--border); background: var(--surface); box-shadow: 0 1px 2px rgba(16,24,40,0.04), 0 0.375rem 1.25rem rgba(16,24,40,0.04); }
.rvx-slide-title { margin: 0; font-size: 1.0625rem; font-weight: 700; letter-spacing: -0.01em; line-height: 1.3; color: var(--text); }
.rvx-slide-points { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 0.5rem; }
.rvx-slide-points li { position: relative; padding-left: 1rem; font-size: 0.9375rem; line-height: 1.45; color: var(--text); }
.rvx-slide-points li::before { content: ''; position: absolute; left: 0.125rem; top: 0.5625rem; width: 0.375rem; height: 0.375rem; border-radius: 50%; background: var(--accent); }
.rvx-slide-ex { margin-top: auto; padding: 0.5625rem 0.75rem; border-radius: 0.625rem; font-size: 0.8125rem; line-height: 1.5; color: var(--text); background: var(--surface2); border-left: 0.1875rem solid var(--accent); }
.rvx-slide.is-remember { background: color-mix(in srgb, var(--accent) 7%, var(--surface)); border-color: color-mix(in srgb, var(--accent) 18%, transparent); }
.rvx-slide.is-remember .rvx-slide-title { color: var(--accent-dim); }
.rvx-deck-nav { display: flex; align-items: center; gap: 0.625rem; }
.rvx-deck-dots { flex: 1; display: flex; justify-content: center; gap: 0.3125rem; }
.rvx-deck-dots i { width: 0.375rem; height: 0.375rem; border-radius: 62.4375rem; background: var(--border2); transition: width .25s var(--ease), background .25s; }
.rvx-deck-dots i.is-on { width: 1.125rem; background: var(--accent); }
.rvx-deck-n { font-size: 0.75rem; font-weight: 650; color: var(--text-dim); font-variant-numeric: tabular-nums; min-width: 2rem; text-align: right; }
.rvx-deck-btn { width: 2rem; height: 2rem; flex-shrink: 0; display: grid; place-items: center; border-radius: 50%; border: 1px solid var(--border); background: var(--surface); color: var(--text); cursor: pointer; transition: background .15s, opacity .15s; }
.rvx-deck-btn:hover:not(:disabled) { background: var(--surface2); }
.rvx-deck-btn:disabled { opacity: 0.35; cursor: default; }
.rvx-deck-btn.is-next:not(:disabled) { background: var(--primary); border-color: var(--primary); color: #fff; }
:root[data-theme="dark"] .rvx-deck-btn.is-next:not(:disabled) { background: var(--text); color: var(--bg); border-color: var(--text); }

/* Study Help's answers: one even rhythm. Every block sits the same small
   step below the one before; a heading takes a little more air above it;
   lists stay inside the bubble and nested ones hug their parent. */
:is(.tutor-qa-a.md-body, .tutor-qa-a .md-body) > * { margin: 0; }
:is(.tutor-qa-a.md-body, .tutor-qa-a .md-body) > * + * { margin-top: 0.5rem; }
:is(.tutor-qa-a.md-body, .tutor-qa-a .md-body) > :is(h2, h3, h4, h5):not(:first-child) { margin-top: 0.875rem; }
:is(.tutor-qa-a.md-body, .tutor-qa-a .md-body) > :is(h2, h3, h4, h5) + * { margin-top: 0.25rem; }
:is(.tutor-qa-a.md-body, .tutor-qa-a .md-body) :is(h2, h3) { font-size: 0.9375rem; font-weight: 700; line-height: 1.35; letter-spacing: -0.01em; }
:is(.tutor-qa-a.md-body, .tutor-qa-a .md-body) :is(h4, h5) { font-size: 0.875rem; font-weight: 700; line-height: 1.4; }
:is(.tutor-qa-a.md-body, .tutor-qa-a .md-body) :is(ul, ol) { padding-left: 1.25rem; }
:is(.tutor-qa-a.md-body, .tutor-qa-a .md-body) li + li { margin-top: 0.1875rem; }
:is(.tutor-qa-a.md-body, .tutor-qa-a .md-body) li > :is(ul, ol) { margin: 0.1875rem 0 0; }
:is(.tutor-qa-a.md-body, .tutor-qa-a .md-body) li > p { margin: 0; }
:is(.tutor-qa-a.md-body, .tutor-qa-a .md-body) > hr { border: 0; height: 1px; background: color-mix(in srgb, currentColor 14%, transparent); margin: 0.75rem 0; }
:is(.tutor-qa-a.md-body, .tutor-qa-a .md-body) > hr + * { margin-top: 0; }
:is(.tutor-qa-a.md-body, .tutor-qa-a .md-body) blockquote { padding: 0.125rem 0 0.125rem 0.75rem; border-left: 3px solid color-mix(in srgb, #C8962E 40%, transparent); color: var(--text-muted); }
:is(.tutor-qa-a.md-body, .tutor-qa-a .md-body) blockquote > * { margin: 0; }
:is(.tutor-qa-a.md-body, .tutor-qa-a .md-body) > .md-math-display { padding: 0.25rem 0; }
:is(.tutor-qa-a.md-body, .tutor-qa-a .md-body) > :is(.md-table, .md-callout, .md-math-display, pre) + * { margin-top: 0.625rem; }
:is(.tutor-qa-a.md-body, .tutor-qa-a .md-body) > * + :is(.md-table, .md-callout, .md-math-display, pre) { margin-top: 0.625rem; }
:is(.tutor-qa-a.md-body, .tutor-qa-a .md-body) > .md-callout.md-study + .md-callout.md-study { margin-top: 0.5rem; }

/* Reply to a passage: the button over a selection, the passage pinned
   above the box, and the passage at the top of the sent question. */
.qr-pill {
  position: fixed; z-index: 2000; display: inline-flex; align-items: center; gap: 0.375rem;
  padding: 0.4375rem 0.75rem; border: 0; border-radius: 999px; cursor: pointer;
  background: var(--primary); color: #fff; font: 600 0.8125rem/1 var(--font);
  box-shadow: 0 6px 20px rgba(0,0,0,.18), 0 1px 3px rgba(0,0,0,.12);
  animation: qr-in .16s cubic-bezier(.2,.8,.2,1);
}
.qr-pill[hidden] { display: none; }
.qr-pill svg { width: 0.875rem; height: 0.875rem; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
@keyframes qr-in { from { opacity: 0; transform: translateY(4px) scale(.96); } }
.qr-chip {
  display: flex; align-items: center; gap: 0.5rem; margin: 0 0 0.375rem; padding: 0.375rem 0.375rem 0.375rem 0.625rem;
  border-radius: 0.625rem; background: color-mix(in srgb, #E9C46A 14%, var(--surface));
  font-size: 0.8125rem; line-height: 1.4; color: var(--text-muted); min-width: 0;
}
.qr-chip-bar { flex: none; align-self: stretch; width: 3px; border-radius: 2px; background: #C8962E; }
.qr-chip-text { flex: 1; min-width: 0; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.qr-chip-x { flex: none; width: 1.5rem; height: 1.5rem; border: 0; border-radius: 50%; background: transparent; color: var(--text-dim); font-size: 1.125rem; line-height: 1; cursor: pointer; }
.qr-chip-x:hover { background: color-mix(in srgb, currentColor 10%, transparent); }
.qr-sent { display: block; }
.qr-sent-q { display: block; margin-bottom: 0.3125rem; padding-left: 0.5rem; border-left: 2px solid rgba(255,255,255,.55); opacity: .8; font-size: 0.8125rem; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; }
.zeno-msg-user blockquote { margin: 0 0 0.3125rem; padding-left: 0.5rem; border-left: 2px solid currentColor; opacity: .8; font-size: 0.8125rem; }
.zeno-msg-user blockquote p { margin: 0; }

/* Maths in the homework box: formulas drawn in the text, and a visual
   editor above it (mathkeys.js). */
.mk-compose { position: relative; display: block; width: 100%; box-sizing: border-box; min-height: 3.25rem; max-height: 14rem; overflow-y: auto; margin: 0; padding: 0.75rem 0.875rem 0.375rem;
  border-radius: 0.875rem 0.875rem 0 0; font: 400 0.875rem/1.55 var(--font); color: var(--text); white-space: pre-wrap; overflow-wrap: anywhere; outline: none; cursor: text; }
.mk-compose.is-empty::before { content: attr(data-placeholder); color: var(--text-dim); pointer-events: none; position: absolute; }
.mk-compose[aria-disabled="true"] { opacity: 0.6; cursor: default; }
.mk-chip { display: inline-block; vertical-align: middle; margin: 0 0.0625rem; padding: 0.0625rem 0.3125rem; border-radius: 0.375rem; cursor: pointer; user-select: none; white-space: nowrap;
  background: color-mix(in srgb, var(--accent) 9%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 22%, transparent); transition: background .15s ease; }
.mk-chip:hover { background: color-mix(in srgb, var(--accent) 16%, transparent); }
.mk-chip .katex { font-size: 1.02em; }
.mk-panel { margin: 0.5rem 0.5rem 0; padding: 0.5rem; border-radius: 0.75rem; border: 1px solid var(--border); background: var(--bg); display: flex; flex-direction: column; gap: 0.5rem; }
.mk-panel[hidden] { display: none; }
.mk-field-wrap { min-height: 3rem; border-radius: 0.625rem; background: var(--surface); border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--border)); display: flex; align-items: center; }
.mk-field { display: block; width: 100%; min-height: 3rem; padding: 0.375rem 0.625rem; box-sizing: border-box; font-size: 1.25rem; border: 0; border-radius: inherit; background: transparent; color: var(--text);
  --caret-color: var(--accent); --selection-background-color: color-mix(in srgb, var(--accent) 22%, transparent); --contains-highlight-background-color: transparent; --primary: var(--accent); outline: none; }
.mk-field::part(menu-toggle), .mk-field::part(virtual-keyboard-toggle) { display: none; }
.mk-loading { padding: 0 0.75rem; font-size: 0.8125rem; color: var(--text-dim); }
.mk-loading.is-error { color: var(--danger, #DC2626); }
.mk-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 0.375rem; }
.mk-tip { flex: 1 1 14rem; min-width: 0; font-size: 0.6875rem; line-height: 1.35; color: var(--text-dim); }
.mk-toggle.is-on { color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.mk-toggle svg { width: 1.0625rem; height: 1.0625rem; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.mk-row { display: flex; gap: 0.25rem; overflow-x: auto; scrollbar-width: none; }
.mk-row::-webkit-scrollbar { display: none; }
.mk-key {
  flex: none; min-width: 2.25rem; height: 2.125rem; padding: 0 0.5rem; border: 1px solid var(--border); border-radius: 0.5rem;
  background: var(--surface); color: var(--text); font: 500 0.875rem/1 'Cambria Math', 'STIX Two Math', Georgia, serif; cursor: pointer;
  display: inline-grid; place-items: center;
}
.mk-key:hover { background: color-mix(in srgb, var(--accent) 8%, var(--surface)); border-color: color-mix(in srgb, var(--accent) 30%, var(--border)); }
.mk-key:active { transform: scale(.96); }
.mk-key sup, .mk-key sub { font-size: 0.625rem; }
.mk-frac { display: inline-flex; flex-direction: column; align-items: center; font-size: 0.6875rem; line-height: 1; }
.mk-frac i { font-style: normal; padding: 0 0.125rem; }
.mk-frac i:first-child { border-bottom: 1px solid currentColor; padding-bottom: 1px; }

/* References: a file or picture held over the panel. */
.rv-refs.is-drop, .iv-refs.is-drop { outline: 2px dashed color-mix(in srgb, var(--accent) 60%, transparent); outline-offset: 4px; border-radius: 0.75rem; background: color-mix(in srgb, var(--accent) 5%, transparent); }

/* The lesson, taught: a mind map first, then cards that explain -- each
   card as tall as it needs, a small label for what kind of card it is. */
.rvx-deck-track { align-items: flex-start; overflow-y: hidden; transition: height .28s cubic-bezier(.2,.8,.2,1); }
.rvx-slide.is-rich { gap: 0.5rem; padding: 1.125rem 1.25rem 1.25rem; }
.rvx-slide-kind { align-self: flex-start; display: inline-flex; align-items: center; gap: 0.375rem; font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--kc, var(--accent)); }
.rvx-slide-kind::before { content: ''; width: 0.4375rem; height: 0.4375rem; border-radius: 50%; background: currentColor; }
.rvx-slide-kind.is-definition { --kc: #4a63c9; }
.rvx-slide-kind.is-formula { --kc: #0f8f86; }
.rvx-slide-kind.is-example { --kc: #7a7f8c; }
.rvx-slide-kind.is-steps { --kc: #4a3aa7; }
.rvx-slide-kind.is-compare { --kc: #b0682a; }
.rvx-slide-kind.is-trap { --kc: #d0453a; }
.rvx-slide-kind.is-map { --kc: #1a9a68; }
.rvx-slide-body { font-size: 0.9375rem; line-height: 1.6; color: var(--text); }
.rvx-slide-body > * { margin: 0; }
.rvx-slide-body > * + * { margin-top: 0.625rem; }
.rvx-slide-body :is(ul, ol) { padding-left: 1.25rem; }
.rvx-slide-body li + li { margin-top: 0.25rem; }
.rvx-slide-body li::marker { color: var(--accent); }
.rvx-slide-body :is(h2, h3, h4) { font-size: 0.9375rem; font-weight: 700; }
.rvx-slide-body > * + :is(.md-callout, .md-table, .md-math-display, .md-figure, .md-image-offer, figure) { margin-top: 0.75rem; }
.rvx-slide-body strong { font-weight: 650; }

.rvx-mm { display: flex; flex-direction: column; align-items: center; padding-top: 0.25rem; }
.rvx-mm-center {
  position: relative; z-index: 1; padding: 0.625rem 1.125rem; border-radius: 999px; text-align: center;
  background: var(--primary); color: #fff; font-weight: 700; font-size: 1rem; letter-spacing: -0.01em;
  box-shadow: 0 4px 14px rgba(16,24,40,.14);
}
.rvx-mm-branches {
  position: relative; width: 100%; margin-top: 1.25rem; display: grid; gap: 0.625rem;
  grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
}
/* The trunk from the centre down to the branches. */
.rvx-mm-branches::before { content: ''; position: absolute; left: 50%; top: -1.25rem; width: 2px; height: 1.25rem; background: var(--border); transform: translateX(-1px); }
.rvx-mm-branch {
  --hue: calc(var(--b) * 57 + 150);
  --bc: hsl(var(--hue) 55% 45%);
  padding: 0.625rem 0.75rem 0.6875rem; border-radius: 0.75rem;
  background: color-mix(in srgb, var(--bc) 7%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--bc) 22%, transparent);
  border-top: 3px solid var(--bc);
}
.rvx-mm-label { font-weight: 700; font-size: 0.875rem; line-height: 1.3; color: color-mix(in srgb, var(--bc) 70%, var(--text)); }
.rvx-mm-branch ul { margin: 0.375rem 0 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 0.25rem; }
.rvx-mm-branch li { position: relative; padding-left: 0.75rem; font-size: 0.8125rem; line-height: 1.4; color: var(--text); }
.rvx-mm-branch li::before { content: ''; position: absolute; left: 0; top: 0.5rem; width: 0.3125rem; height: 2px; border-radius: 1px; background: var(--bc); }

/* The references count: a small dot on the book's corner, not over it. */
.rvx-tool .rvx-badge { top: -0.1875rem; right: -0.25rem; min-width: 0.75rem; height: 0.75rem; padding: 0 0.1875rem; font-size: 0.5rem; line-height: 1; box-shadow: 0 0 0 1.5px var(--surface); }
#rv-refs-toggle svg { width: 1.375rem; height: 1.375rem; }
#rv-refs-toggle .rvx-badge { top: 0.0625rem; right: 0.0625rem; }

/* The lesson as a presentation: each card says which chapter it is in
   (the map branch's colour), what kind of card, and where in the deck. */
.rvx-slide-head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; min-height: 1.25rem; }
.rvx-slide-section {
  --hue: calc(var(--b, 0) * 57 + 150); --bc: hsl(var(--hue) 55% 42%);
  display: inline-flex; align-items: center; max-width: 60%; padding: 0.1875rem 0.5625rem; border-radius: 999px;
  font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--bc); background: color-mix(in srgb, var(--bc) 11%, transparent);
}
.rvx-slide-head .rvx-slide-kind { font-size: 0.625rem; }
.rvx-slide-of { margin-left: auto; font-size: 0.6875rem; font-weight: 600; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.rvx-slide.is-rich .rvx-slide-title { font-size: 1.1875rem; margin-top: 0.125rem; }
.rvx-slide-kind.is-timeline { --kc: #8a5a1f; }
/* Tables in a card wrap, so a narrow panel never scrolls sideways. */
.rvx-slide-body .md-table th, .rvx-slide-body .md-table td { white-space: normal; vertical-align: top; line-height: 1.4; }
.rvx-slide-body .md-table table { font-size: 0.8125rem; }
/* Nothing wider than the slide: long words break, wide tables, formulas
   and code scroll inside it, pictures shrink to fit. */
.rvx-slide { min-width: 0; }
.rvx-slide > *, .rvx-slide-body > * { min-width: 0; max-width: 100%; }
.rvx-slide-title, .rvx-slide-body, .rvx-recall { overflow-wrap: anywhere; }
.rvx-slide-body :is(.md-math-display, .katex-display, pre, .md-scheme, .md-figure) { max-width: 100%; overflow-x: auto; overflow-y: hidden; }
.rvx-slide-body pre { white-space: pre-wrap; }
.rvx-slide-body img, .rvx-slide-body svg { max-width: 100%; height: auto; }
.rvx-slide-body .md-table { max-width: 100%; }
.rvx-slide-body .md-table :is(th, td) { overflow-wrap: normal; word-break: normal; hyphens: auto; min-width: 5.5rem; }

/* "Mettiti alla prova": each question, then its answer on a tap. */
.rvx-slide.is-recall { background: color-mix(in srgb, var(--accent) 5%, var(--surface)); }
.rvx-slide-kind.is-recall { --kc: var(--accent); }
.rvx-slide-kind.is-intro { --kc: #c2410c; }
.rvx-slide-kind.is-summary { --kc: #7c3aed; }
.rvx-recall { margin: 0.25rem 0 0; padding: 0; list-style: none; counter-reset: rq; display: flex; flex-direction: column; gap: 0.625rem; }
.rvx-recall > li { counter-increment: rq; border-radius: 0.875rem; background: var(--surface); border: 1px solid var(--border); }
.rvx-recall details > summary { display: flex; flex-direction: column; gap: 0.375rem; padding: 0.75rem 0.875rem 0.75rem 2.5rem; position: relative; cursor: pointer; list-style: none; }
.rvx-recall details > summary::-webkit-details-marker { display: none; }
.rvx-recall details > summary::before { content: counter(rq); position: absolute; left: 0.75rem; top: 0.75rem; width: 1.25rem; height: 1.25rem; border-radius: 50%; display: grid; place-items: center; font-size: 0.6875rem; font-weight: 700; color: #fff; background: var(--accent); }
.rvx-recall-q { font-size: 0.9375rem; font-weight: 600; line-height: 1.45; color: var(--text); }
.rvx-recall-show { align-self: flex-start; font-size: 0.75rem; font-weight: 650; color: var(--accent-dim); }
.rvx-recall details[open] .rvx-recall-show { display: none; }
.rvx-recall-a { padding: 0 0.875rem 0.875rem 2.5rem; font-size: 0.9063rem; line-height: 1.55; color: var(--text); animation: rvx-reveal .22s var(--ease); }
@keyframes rvx-reveal { from { opacity: 0; transform: translateY(-0.25rem); } to { opacity: 1; transform: none; } }
.rvx-deck.is-fullscreen .rvx-recall-q { font-size: 1em; }
.rvx-deck.is-fullscreen .rvx-recall-a { font-size: 0.95em; }
.rvx-slide-body .md-table thead th { background: color-mix(in srgb, var(--accent) 9%, var(--surface)); }
.rvx-slide-body .pic-figure img { border-radius: 0.625rem; }

/* Schemes (md.js renderScheme): flow, cycle, timeline, tree. */
.md-scheme { margin: 0.75rem 0 0; padding: 0.75rem 0.875rem 0.875rem; border-radius: 0.875rem; background: color-mix(in srgb, var(--accent) 5%, var(--surface)); border: 1px solid color-mix(in srgb, var(--accent) 16%, transparent); }
.md-scheme-title { font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--accent); margin-bottom: 0.5rem; }
.md-scheme ol, .md-scheme ul { margin: 0; padding: 0; list-style: none; }
/* A flow: numbered steps joined by arrows. */
.md-flow ol { display: flex; flex-direction: column; gap: 1.125rem; }
.md-flow li { position: relative; display: flex; align-items: flex-start; gap: 0.625rem; padding: 0.5rem 0.625rem; border-radius: 0.625rem; background: var(--surface); border: 1px solid var(--border); box-shadow: 0 1px 2px rgba(16,24,40,.04); }
.md-flow li + li::before { content: ''; position: absolute; left: 1.3125rem; top: -1.125rem; width: 2px; height: 1.125rem; background: color-mix(in srgb, var(--accent) 45%, transparent); }
.md-flow li + li::after { content: ''; position: absolute; left: calc(1.3125rem - 4px); top: -0.4375rem; border: 5px solid transparent; border-top-color: color-mix(in srgb, var(--accent) 60%, transparent); border-bottom: 0; }
.md-flow-n { flex: none; width: 1.5rem; height: 1.5rem; border-radius: 50%; display: grid; place-items: center; font-size: 0.75rem; font-weight: 700; color: #fff; background: var(--accent); }
.md-flow-body { display: flex; flex-direction: column; gap: 0.0625rem; min-width: 0; font-size: 0.875rem; line-height: 1.4; }
.md-flow-body b { font-weight: 650; }
.md-flow-body span { font-size: 0.8125rem; color: var(--text-muted); }
.md-flow.is-cycle { position: relative; }
.md-flow-back { margin-top: 0.375rem; text-align: center; font-size: 1.125rem; line-height: 1; color: var(--accent); }
/* A timeline: dates on a rail. */
.md-timeline ol { position: relative; padding-left: 1rem; }
.md-timeline ol::before { content: ''; position: absolute; left: 0.25rem; top: 0.375rem; bottom: 0.375rem; width: 2px; background: color-mix(in srgb, var(--accent) 30%, transparent); }
.md-timeline li { position: relative; display: flex; flex-direction: column; padding: 0.25rem 0 0.5rem 0.5rem; }
.md-timeline li::before { content: ''; position: absolute; left: -0.9375rem; top: 0.5rem; width: 0.625rem; height: 0.625rem; border-radius: 50%; background: var(--surface); border: 2px solid var(--accent); }
.md-tl-date { font-size: 0.75rem; font-weight: 700; color: var(--accent); font-variant-numeric: tabular-nums; }
.md-tl-body { display: flex; flex-direction: column; font-size: 0.875rem; line-height: 1.4; }
.md-tl-body b { font-weight: 650; }
.md-tl-body span { font-size: 0.8125rem; color: var(--text-muted); }
/* A tree: a classification, branches indented on guide lines. */
.md-tree ul ul { margin-left: 0.75rem; padding-left: 0.75rem; border-left: 2px solid color-mix(in srgb, var(--accent) 25%, transparent); }
.md-tree li { margin-top: 0.375rem; }
.md-tree-node { display: inline-block; padding: 0.25rem 0.625rem; border-radius: 0.5rem; background: var(--surface); border: 1px solid var(--border); font-size: 0.8125rem; line-height: 1.35; }
.md-tree > ul > li > .md-tree-node { background: var(--accent); color: #fff; border-color: transparent; font-weight: 700; }
.md-tree ul ul > li > .md-tree-node { font-weight: 600; }
.md-tree ul ul ul > li > .md-tree-node { font-weight: 400; color: var(--text-muted); }
.rvx-slide-head .rvx-slide-kind { align-self: center; }

/* Homework the registry dropped (registryMissing.js): the choice. */
.regmiss-overlay { z-index: 900; display: flex; align-items: center; justify-content: center; animation: regmiss-in .16s ease; }
.regmiss-overlay.is-leaving { opacity: 0; transition: opacity .16s; }
@keyframes regmiss-in { from { opacity: 0; } }
.regmiss { max-width: 23rem; width: calc(100vw - 2rem); }
.regmiss-body { display: flex; flex-direction: column; gap: 0.75rem; padding-top: 0.25rem; }
.regmiss-item { display: flex; flex-direction: column; align-items: center; gap: 0.125rem; text-align: center; }
.regmiss-item b { font-size: 0.9375rem; font-weight: 650; color: var(--text); line-height: 1.3; }
.regmiss-item span { font-size: 0.75rem; color: var(--text-dim); }
.regmiss-desc { margin: 0; font-size: 0.8125rem; line-height: 1.45; color: var(--text-muted); text-align: center; }
.regmiss-opt { font-weight: 600; font-size: 0.875rem; }
.regmiss-opt-sub { font-size: 0.75rem; color: var(--text-dim); margin-top: 0.0625rem; }
.regmiss .drag-choice-card { text-align: left; }
.regmiss .drag-choice-card:disabled { opacity: .6; cursor: progress; }
.stale-sync-badge[data-regmiss]:focus-visible { outline: 2px solid var(--amber, #F59E0B); outline-offset: 1px; }

/* The full solution, on request: a calm sheet that teaches, not a dump. */
.sol-overlay { position: fixed; inset: 0; z-index: 950; display: flex; align-items: center; justify-content: center; padding: 1rem; background: rgba(15,23,42,.42); backdrop-filter: blur(3px); animation: sol-fade .18s ease; }
.sol-overlay.is-leaving { opacity: 0; transition: opacity .18s; }
@keyframes sol-fade { from { opacity: 0; } }
@keyframes sol-rise { from { opacity: 0; transform: translateY(10px) scale(.985); } }
.sol { width: min(36rem, 100%); max-height: min(88vh, 52rem); display: flex; flex-direction: column; border-radius: 1.25rem; background: var(--surface); border: 1px solid var(--border); box-shadow: 0 24px 64px rgba(15,23,42,.28); animation: sol-rise .22s cubic-bezier(.2,.8,.2,1); overflow: hidden; }
.sol:not(.is-full) { width: min(26rem, 100%); }
.sol-head { display: flex; align-items: flex-start; gap: 0.75rem; padding: 1.125rem 1.25rem 0.875rem; border-bottom: 1px solid var(--border); }
.sol-head-text { flex: 1; min-width: 0; }
.sol-eyebrow { font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--accent); }
.sol-head h2 { margin: 0.125rem 0 0; font-size: 1.1875rem; font-weight: 700; letter-spacing: -0.01em; color: var(--text); }
.sol-part { margin-top: 0.125rem; font-size: 0.8125rem; color: var(--text-muted); line-height: 1.4; }
.sol-x { flex: none; width: 2rem; height: 2rem; border: 0; border-radius: 50%; display: grid; place-items: center; background: var(--surface2); color: var(--text-muted); cursor: pointer; }
.sol-x:hover { color: var(--text); }
.sol-body { overflow-y: auto; padding: 1.125rem 1.25rem 1.375rem; display: flex; flex-direction: column; gap: 1rem; }
.sol-ask p { margin: 0; font-size: 0.9375rem; line-height: 1.55; color: var(--text); }
.sol-actions { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 1rem; flex-wrap: wrap; }
.sol-actions .btn { display: inline-flex; align-items: center; gap: 0.375rem; }
.sol-actions .btn svg { width: 1rem; height: 1rem; }
.sol-wait { display: flex; align-items: center; gap: 0.625rem; padding: 1.5rem 0; justify-content: center; color: var(--text-muted); font-size: 0.875rem; }
.sol-spin { width: 1.125rem; height: 1.125rem; border-radius: 50%; border: 2px solid color-mix(in srgb, var(--accent) 25%, transparent); border-top-color: var(--accent); animation: sol-turn .8s linear infinite; }
@keyframes sol-turn { to { transform: rotate(360deg); } }
.sol-error { font-size: 0.875rem; color: var(--text-muted); text-align: center; padding-top: 0.5rem; }
.sol-unsure { padding: 0.625rem 0.75rem; border-radius: 0.75rem; font-size: 0.8125rem; line-height: 1.45; color: #8a5a00; background: rgba(245,158,11,.12); border: 1px solid rgba(245,158,11,.28); }
.sol-summary { margin: 0; font-size: 0.9375rem; line-height: 1.55; color: var(--text); }
.sol-steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.sol-step { position: relative; display: flex; gap: 0.75rem; padding-bottom: 1rem; }
.sol-step:not(:last-child)::before { content: ''; position: absolute; left: 0.8125rem; top: 1.75rem; bottom: 0.125rem; width: 2px; background: color-mix(in srgb, var(--accent) 20%, transparent); }
.sol-n { flex: none; width: 1.625rem; height: 1.625rem; border-radius: 50%; display: grid; place-items: center; font-size: 0.75rem; font-weight: 700; color: #fff; background: var(--accent); }
.sol-step-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.375rem; padding-top: 0.125rem; }
.sol-step-title { font-size: 0.9375rem; font-weight: 650; color: var(--text); line-height: 1.35; }
.sol-work { padding: 0.625rem 0.75rem; border-radius: 0.75rem; background: var(--surface2); font-size: 0.9375rem; line-height: 1.6; color: var(--text); overflow-x: auto; }
.sol-work > * { margin: 0; } .sol-work > * + * { margin-top: 0.375rem; }
.sol-work .md-math-display { margin: 0.25rem 0; }
.sol-why { font-size: 0.8125rem; line-height: 1.5; color: var(--text-muted); }
.sol-why span { font-weight: 700; color: var(--accent); }
.sol-label { font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; margin-bottom: 0.375rem; }
.sol-final { padding: 0.875rem 1rem; border-radius: 0.875rem; background: color-mix(in srgb, var(--accent) 9%, var(--surface)); border: 1.5px solid color-mix(in srgb, var(--accent) 35%, transparent); }
.sol-final .sol-label { color: var(--accent); }
.sol-final .md-body { font-size: 1rem; font-weight: 600; color: var(--text); line-height: 1.55; }
.sol-final .md-body > * { margin: 0; }
.sol-graph .sol-label { color: var(--text-muted); }
.sol-graph .md-figure { margin-top: 0; }
.sol-box { padding: 0.75rem 0.875rem; border-radius: 0.75rem; font-size: 0.875rem; line-height: 1.5; color: var(--text); }
.sol-box .md-body > * { margin: 0; }
.sol-box ul { margin: 0; padding-left: 1.125rem; } .sol-box li + li { margin-top: 0.25rem; }
.sol-box.is-check { background: color-mix(in srgb, #1a9a68 7%, var(--surface)); border: 1px solid color-mix(in srgb, #1a9a68 22%, transparent); }
.sol-box.is-check .sol-label { color: #1a9a68; }
.sol-box.is-trap { background: color-mix(in srgb, #d0453a 6%, var(--surface)); border: 1px solid color-mix(in srgb, #d0453a 20%, transparent); }
.sol-box.is-trap .sol-label { color: #d0453a; }
.tutor-act.is-quiet { opacity: .85; }
@media (max-width: 640px) {
  .sol-overlay { align-items: flex-end; padding: 0; }
  .sol, .sol:not(.is-full) { width: 100%; max-height: 92vh; border-radius: 1.25rem 1.25rem 0 0; }
}

/* The Daily 3's streak, on its own card: what keeping it today keeps. */
.dz-streak-bit { display: inline-flex; align-items: center; gap: 0.25rem; color: var(--accent); font-weight: 600; }
.dz-streak-bit .dz-flame { width: 0.8125rem; height: 0.8125rem; }
.dz-title-row { display: flex; align-items: center; gap: 0.5rem; }
.dz-streak-badge { display: inline-flex; align-items: center; gap: 0.1875rem; height: 1.25rem; padding: 0 0.4375rem; border-radius: 62.4375rem;
  font-size: 0.6875rem; font-weight: 700; color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); font-variant-numeric: tabular-nums; }
.dz-streak-badge .dz-flame { width: 0.75rem; height: 0.75rem; }
.plan-recall .dz-sub { display: flex; flex-wrap: wrap; align-items: center; column-gap: 0.625rem; row-gap: 0.125rem; }
.dz-sub-subject { display: inline-flex; align-items: center; gap: 0.3125rem; }
.dz-sub-subject::before { content: ''; width: 0.4375rem; height: 0.4375rem; border-radius: 50%; background: var(--subject); }

/* The lesson: full screen to study from, and downloads (lessonExport.js). */
.lx-tools { display: flex; justify-content: flex-end; gap: 0.375rem; }
.lx-wrap { position: relative; }
.lx-btn { display: inline-flex; align-items: center; gap: 0.3125rem; height: 1.875rem; padding: 0 0.6875rem; border-radius: 62.4375rem; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface); color: var(--text-muted); font: 600 0.75rem/1 var(--font); transition: background .15s ease, color .15s ease; }
.lx-btn:hover, .lx-btn[aria-expanded="true"] { background: var(--surface2); color: var(--text); }
.lx-menu { position: absolute; right: 0; top: calc(100% + 0.375rem); z-index: 30; min-width: 15rem; padding: 0.3125rem; border-radius: 0.875rem; border: 1px solid var(--border); background: var(--surface);
  box-shadow: 0 0.75rem 2rem rgba(16,24,40,0.14), 0 0.125rem 0.375rem rgba(16,24,40,0.06); display: flex; flex-direction: column; }
.lx-menu[hidden] { display: none; }
.lx-item { display: flex; flex-direction: column; align-items: flex-start; gap: 0.125rem; padding: 0.5rem 0.625rem; border: 0; border-radius: 0.625rem; background: none; cursor: pointer; text-align: left; color: var(--text); font: inherit; }
.lx-item:hover, .lx-item:focus-visible { background: var(--surface2); outline: none; }
.lx-item b { font-size: 0.8125rem; font-weight: 650; }
.lx-item span { font-size: 0.6875rem; color: var(--text-dim); }
.rvx-deck.is-exporting { cursor: progress; }
.rvx-deck.is-exporting .lx-btn { opacity: 0.6; pointer-events: none; }
/* Full screen: one slide, large, in the middle; the controls under it. */
.rvx-deck:fullscreen, .rvx-deck.is-full { box-sizing: border-box; padding: 1.25rem clamp(1rem, 6vw, 5rem) 1.5rem; background: var(--bg); overflow-y: auto; justify-content: center; }
.rvx-deck.is-full { position: fixed; inset: 0; z-index: 1000; }
.rvx-deck.is-fullscreen .lx-tools { position: sticky; top: 0; z-index: 2; }
.rvx-deck.is-fullscreen .lx-tools, .rvx-deck.is-fullscreen .rvx-deck-track, .rvx-deck.is-fullscreen .rvx-deck-nav { width: 100%; max-width: 56rem; margin: 0 auto; }
.rvx-deck.is-fullscreen .rvx-slide { padding: clamp(1.25rem, 3vw, 2.5rem); font-size: 1.125rem; }
.rvx-deck.is-fullscreen .rvx-slide-title { font-size: 1.75rem; }
.rvx-deck.is-fullscreen .rvx-slide-body { font-size: 1.0625rem; line-height: 1.65; }
.rvx-deck.is-fullscreen .rvx-deck-btn { width: 2.75rem; height: 2.75rem; }
/* Full screen is a presentation: the slide fills the screen, its text
   grows with it, and a long one scrolls inside the slide. */
.rvx-deck.is-fullscreen { display: flex; flex-direction: column; height: 100vh; height: 100dvh; padding: 1rem clamp(1rem, 4vw, 3rem) 1.25rem; gap: 0.875rem; }
.rvx-deck.is-fullscreen .lx-tools, .rvx-deck.is-fullscreen .rvx-deck-track, .rvx-deck.is-fullscreen .rvx-deck-nav { max-width: 80rem; }
.rvx-deck.is-fullscreen .rvx-deck-track { flex: 1 1 auto; min-height: 0; height: auto !important; align-items: stretch; }
.rvx-deck.is-fullscreen .rvx-slide { height: 100%; overflow-y: auto; justify-content: safe center; padding: clamp(1.5rem, 4vw, 3.5rem) clamp(1.5rem, 6vw, 5.5rem); font-size: clamp(1.125rem, 1.45vw, 1.4375rem); }
.rvx-deck.is-fullscreen .rvx-slide-title { font-size: clamp(1.75rem, 2.6vw, 2.625rem); }
.rvx-deck.is-fullscreen .rvx-slide-body, .rvx-deck.is-fullscreen .rvx-recall { font-size: 1em; line-height: 1.65; }
.rvx-deck.is-fullscreen .rvx-slide-body .md-table table { font-size: 0.875em; }
.rvx-deck.is-fullscreen .rvx-slide-kind { font-size: 0.75rem; }
.lx-print-frame { position: fixed; right: 0; bottom: 0; width: 0; height: 0; border: 0; visibility: hidden; }
/* Printed (Save as PDF): every slide on its own page. */
.lx-print { margin: 0; padding: 0; background: #fff; }
.lx-print-title { font: 750 1.5rem/1.2 var(--font); margin: 0 0 1rem; color: #111; }
.lx-print .rvx-slide { break-inside: avoid; page-break-inside: avoid; break-after: page; box-shadow: none; margin: 0 0 1rem; min-height: 0; }
.lx-print .rvx-slide:last-child { break-after: auto; }
@media print { @page { margin: 14mm; } .lx-print { -webkit-print-color-adjust: exact; print-color-adjust: exact; } }

/* Practice: overrule a marking, and talk a question through. */
.rv-accept { align-self: flex-start; display: inline-flex; align-items: center; gap: 0.3125rem; height: 1.75rem; padding: 0 0.625rem; border-radius: 62.4375rem; cursor: pointer;
  border: 1px dashed color-mix(in srgb, #16A34A 45%, var(--border)); background: transparent; color: #15803D; font: 600 0.75rem/1 var(--font); transition: background .15s ease; }
.rv-accept:hover { background: color-mix(in srgb, #22C55E 10%, transparent); }
:root[data-theme="dark"] .rv-accept { color: #4ADE80; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .rv-accept { color: #4ADE80; } }
.rv-talk { margin-top: 0.25rem; }

/* A session's time, set in place (app.js openPlanTime). */
.plan-time-pop { display: flex; flex-direction: column; gap: 0.5rem; min-width: 13rem; }
.plan-time-field { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.6875rem; font-weight: 650; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-dim); }
.plan-time-input { height: 2.25rem; padding: 0 0.625rem; border-radius: 0.625rem; border: 1px solid var(--border2); background: var(--surface); color: var(--text); font: 600 1rem/1 var(--font); font-variant-numeric: tabular-nums; text-transform: none; letter-spacing: 0; }
.plan-time-input:focus { outline: none; border-color: var(--accent); box-shadow: var(--ring); }
.plan-time-foot { display: flex; justify-content: flex-end; }

/* The quick view's steps: the same Suggest steps as the full form. */
.iv-label-row { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.iv-suggest { display: inline-flex; align-items: center; gap: 0.3125rem; height: 1.625rem; padding: 0 0.625rem; border-radius: 62.4375rem; cursor: pointer;
  border: 0; background: color-mix(in srgb, var(--accent) 11%, transparent); color: var(--accent-dim); font: 600 0.71875rem/1 var(--font); letter-spacing: 0; transition: background .15s ease; }
.iv-suggest:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); }
.iv-suggest svg { width: 0.8125rem; height: 0.8125rem; }
.iv-suggest.is-busy { opacity: 0.6; cursor: progress; }
.iv-suggest.is-busy .gen-bolt { animation: iv-pulse 0.9s ease-in-out infinite; }
@keyframes iv-pulse { 50% { opacity: 0.35; } }

/* ── "Room made: plan again?" (app.js offerReplan) ──
   A bubble hanging from Auto-Schedule, and the button breathing a soft
   ring until the question is answered. */
.is-calling { position: relative; animation: replan-ring 1.8s var(--ease) infinite; }
@keyframes replan-ring {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent); }
  70% { box-shadow: 0 0 0 0.625rem color-mix(in srgb, var(--accent) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 transparent; }
}
.replan-tip { position: fixed; z-index: 950; width: min(19rem, calc(100vw - 1.5rem)); box-sizing: border-box; padding: 1rem 1rem 0.875rem;
  background: var(--surface); border: 1px solid var(--border); border-radius: 1rem;
  box-shadow: 0 0.75rem 2rem rgba(15, 23, 42, 0.18), 0 0.125rem 0.375rem rgba(15, 23, 42, 0.08);
  opacity: 0; transform: translateY(-0.375rem) scale(0.97); transform-origin: var(--arrow-x, 50%) 0;
  transition: opacity .18s var(--ease), transform .28s var(--ease-spring); }
.replan-tip.is-in { opacity: 1; transform: none; }
.replan-tip-arrow { position: absolute; top: -0.4375rem; left: var(--arrow-x, 50%); width: 0.75rem; height: 0.75rem; margin-left: -0.375rem;
  background: var(--surface); border-left: 1px solid var(--border); border-top: 1px solid var(--border); transform: rotate(45deg); border-radius: 0.1875rem 0 0 0; }
.replan-tip-title { margin: 0 0 0.25rem; font-size: 0.9375rem; font-weight: 700; color: var(--text); letter-spacing: -0.01em; }
.replan-tip-body { margin: 0; font-size: 0.8125rem; line-height: 1.45; color: var(--text-muted); }
.replan-tip-actions { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 0.875rem; }
@media (prefers-reduced-motion: reduce) { .is-calling { animation: none; box-shadow: 0 0 0 0.1875rem color-mix(in srgb, var(--accent) 45%, transparent); } }

/* The phone, while the computer waits for its photos (app.js watchPhoneSnap). */
.phone-snap { position: fixed; inset: 0; z-index: 9000; background: var(--bg); animation: phoneSnapIn 0.28s cubic-bezier(0.2, 0.8, 0.2, 1); }
.phone-snap iframe { width: 100%; height: 100%; border: 0; display: block; }
.phone-snap-x { position: absolute; top: calc(0.875rem + env(safe-area-inset-top)); right: 1rem; width: 2.25rem; height: 2.25rem; border-radius: 50%; border: 0; display: grid; place-items: center; background: color-mix(in srgb, var(--text) 8%, transparent); color: var(--text); cursor: pointer; }
@keyframes phoneSnapIn { from { transform: translateY(1.5rem); opacity: 0; } to { transform: none; opacity: 1; } }

/* Study time on a piece of work: done, planned, of what it needs. */
.academic-chip-hours { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.4375rem; }
.ach-bar { flex: 1; display: flex; height: 0.1875rem; border-radius: 62.4375rem; overflow: hidden; background: rgba(255,255,255,0.1); }
.ach-bar i { display: block; height: 100%; }
.ach-done { background: var(--subj, #A5E0A4); }
.ach-plan { background: color-mix(in srgb, var(--subj, #A5E0A4) 38%, transparent); }
.ach-text { flex: none; font-size: 0.625rem; font-weight: 600; font-variant-numeric: tabular-nums; color: rgba(255,255,255,0.5); }
.academic-chip-hours.is-done .ach-text { color: #A5E0A4; }
/* In the homework's editing modal, on the light surface. */
#academic-progress .academic-chip-hours { margin-top: 0.5rem; }
#academic-progress .ach-bar { height: 0.3125rem; background: var(--surface2); }
#academic-progress .ach-text { font-size: 0.75rem; color: var(--text-muted); }
#academic-progress .academic-chip-hours.is-done .ach-text { color: var(--success, #2A9D8F); }

/* A test's tasks, one tap from its revision: each helped like homework. */
.rvx-task-pick { flex: none; display: inline-flex; align-items: center; gap: 0.25rem; height: 1.75rem; padding: 0 0.625rem 0 0.75rem; border: 0; border-radius: 62.4375rem; cursor: pointer;
  font: inherit; font-size: 0.75rem; font-weight: 650; color: var(--text-muted); background: color-mix(in srgb, var(--text) 6%, transparent); transition: background 0.15s ease, color 0.15s ease; }
.rvx-task-pick:hover, .rvx-task-pick.is-open { color: var(--text); background: color-mix(in srgb, var(--text) 10%, transparent); }
.rvx-task-pick .tutor-title-chev { transition: transform 0.2s ease; }
.rvx-task-pick.is-open .tutor-title-chev { transform: rotate(180deg); }

/* Upgrade sheet: the yearly saving as its own line, not in the switch. */
.upgrade-year-banner { display: flex; align-items: center; justify-content: center; gap: 0.4375rem; margin: -0.25rem auto 0.875rem; width: max-content; max-width: 100%; padding: 0.3125rem 0.8125rem; border-radius: 62.4375rem; font-size: 0.78125rem; font-weight: 600; color: #8A6414; background: rgba(227,183,62,0.14); border: 1px solid rgba(200,150,46,0.25); }
[data-theme="dark"] .upgrade-year-banner { color: #E9C46A; background: rgba(227,183,62,0.12); }

/* ── The top of the Plan: banners, not rows ───────────────────────────────
   What the coach or the Daily 3 has to say sits on a soft tint of its own
   colour, with no card shadow: it reads as a note pinned above the plan,
   never as one more thing in it. */
.plan-recall {
  --b: #2A9D8F;
  background: linear-gradient(120deg, color-mix(in srgb, var(--b) 13%, var(--surface)) 0%, color-mix(in srgb, var(--b) 5%, var(--surface)) 70%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--b) 16%, transparent);
  margin-bottom: 0.25rem;
}
.plan-recall:has(> .plan-recall-icon.is-indigo) { --b: #5856D6; }
.plan-recall:has(> .plan-recall-icon.is-blue) { --b: #007AFF; }
.plan-recall:has(> .plan-recall-icon.is-orange) { --b: #FF9500; }
.plan-recall:has(> .plan-recall-icon.is-purple) { --b: #AF52DE; }
.plan-recall:has(> .plan-recall-icon.is-green) { --b: #30B652; }
.plan-recall:has(> .plan-recall-icon.is-red) { --b: #FF3B30; }
/* A banner's button is tinted, not filled: the banner offers, the plan's
   own Start is the one filled button in the list. */
.plan-recall .pill-btn { color: color-mix(in srgb, var(--b) 82%, var(--text)); background: color-mix(in srgb, var(--b) 15%, transparent); box-shadow: none; }
.plan-recall .pill-btn:hover { background: color-mix(in srgb, var(--b) 23%, transparent); }
.plan-recall .pill-btn.is-quiet { color: color-mix(in srgb, var(--b) 80%, var(--text)); background: color-mix(in srgb, var(--b) 14%, transparent); }
:root[data-theme="dark"] .plan-recall {
  background: linear-gradient(120deg, color-mix(in srgb, var(--b) 20%, var(--surface)) 0%, color-mix(in srgb, var(--b) 8%, var(--surface)) 70%);
}

/* The Daily 3: its questions as three marks under the title. */
.plan-daily .plan-main { gap: 0.375rem; }
.dz-pips { display: flex; gap: 0.25rem; }
.dz-pip { display: block; flex: none; width: 1.375rem; height: 0.25rem; border-radius: 62rem; background: color-mix(in srgb, var(--b) 22%, transparent); }
.dz-pip.is-done { background: var(--b); }
@media (max-width: 560px) {
  /* Short enough for one line on a phone too: Start stays at its side. */
  .plan-recall.plan-daily { display: flex; align-items: center; }
  .plan-recall.plan-daily > .plan-card-actions { margin-left: auto; }
  .plan-recall.plan-daily > .plan-card-actions > .pill-btn { flex: none; }
}

/* Study Mode's title opens in full when tapped (app.js). */
#study-title { cursor: pointer; border-radius: 0.375rem; }
#study-title:focus-visible { outline: 0.125rem solid color-mix(in srgb, var(--accent) 55%, transparent); outline-offset: 0.125rem; }
.study-title-full { margin: 0; font-size: 1.125rem; font-weight: 650; line-height: 1.45; color: var(--text); overflow-wrap: anywhere; }

/* ── Progress, read at a glance (progress.js) ─────────────────────────── */
.prog-wait { display: flex; align-items: baseline; justify-content: center; padding: 2rem 0; font-size: 0.875rem; color: var(--text-muted); }
.prog-dots { display: inline-flex; gap: 0.1875rem; margin-left: 0.1875rem; }
.prog-dots i { width: 0.25rem; height: 0.25rem; border-radius: 50%; background: currentColor; animation: progDot 1.2s ease-in-out infinite; }
.prog-dots i:nth-child(2) { animation-delay: 0.15s; }
.prog-dots i:nth-child(3) { animation-delay: 0.3s; }
@keyframes progDot { 0%, 70%, 100% { opacity: 0.25; transform: none; } 35% { opacity: 1; transform: translateY(-0.1875rem); } }
@media (prefers-reduced-motion: reduce) { .prog-dots i { animation: none; opacity: 0.6; } }

.pg-hero { display: flex; flex-direction: column; gap: 0.5rem; padding: 1rem 1rem 0.875rem; border-radius: 1rem; background: var(--surface2); }
.pg-hero-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap; }
.pg-hero-v { font-size: 2rem; font-weight: 800; letter-spacing: -0.03em; line-height: 1; color: var(--text); font-variant-numeric: tabular-nums; }
.pg-hero-l { margin-top: 0.25rem; font-size: 0.8125rem; color: var(--text-muted); }
.pg-hero .prog-delta { font-size: 0.75rem; padding: 0.125rem 0.5rem; }
.pg-chart { display: block; width: 100%; height: auto; overflow: visible; }
.pg-grid { stroke: color-mix(in srgb, var(--text) 9%, transparent); stroke-width: 1; }
.pg-axis { font-size: 9px; fill: var(--text-dim); font-family: var(--font); font-variant-numeric: tabular-nums; }
.pg-area { fill: color-mix(in srgb, var(--accent) 14%, transparent); }
.pg-line { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.pg-end { fill: var(--accent); stroke: var(--surface2); stroke-width: 2; }
.pg-x { display: flex; justify-content: space-between; padding-left: 1.875rem; font-size: 0.6875rem; color: var(--text-dim); }
.pg-note { margin: 0.125rem 0 0; font-size: 0.75rem; line-height: 1.45; color: var(--text-muted); }

.pg-tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 420px) { .pg-tiles { grid-template-columns: 1fr; } .pg-tiles .prog-tile { flex-direction: row; align-items: baseline; flex-wrap: wrap; column-gap: 0.5rem; } }
.pg-tiles .prog-tile-n { white-space: normal; }

/* A subject: name and how ready on one line, the bar under them. */
.prog-subjs .prog-subj { display: flex; flex-direction: column; align-items: stretch; gap: 0.375rem; }
.pg-subj-top { display: flex; align-items: center; gap: 0.5rem; min-width: 0; }
.pg-subj-top .prog-dot { align-self: center; margin: 0; flex-shrink: 0; }
.pg-subj-top .prog-subj-name { flex: 1; min-width: 0; }
.pg-subj-v { display: inline-flex; align-items: center; gap: 0.375rem; flex-shrink: 0; }
.pg-subj-v b { font-size: 1rem; font-weight: 700; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; color: var(--text); }
.pg-bar { position: relative; height: 0.5rem; border-radius: 62rem; background: color-mix(in srgb, var(--text) 8%, transparent); }
.pg-bar-fill { position: absolute; inset: 0 auto 0 0; border-radius: inherit; background: var(--c); }
.pg-bar-was { position: absolute; top: -0.1875rem; bottom: -0.1875rem; width: 2px; margin-left: -1px; border-radius: 1px; background: var(--text); opacity: 0.45; }

/* "+ Add subject" in place of the picker (subjectAdd.js): the field takes the
   select's own room, the tick and the cross sit inside its right edge. */
.subj-add { position: relative; display: flex; align-items: center; }
.subj-add-input { width: 100%; padding-right: 4.25rem !important; }
.subj-add-btn {
  position: absolute; top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.75rem; height: 1.75rem; padding: 0; border: 0; border-radius: 0.5rem;
  background: transparent; color: var(--text-muted); cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.subj-add-btn svg { width: 1rem; height: 1rem; }
.subj-add-btn.is-ok { right: 2.25rem; color: var(--accent); }
.subj-add-btn:not(.is-ok) { right: 0.375rem; }
.subj-add-btn:hover { background: var(--surface2, rgba(0,0,0,.05)); }
.subj-add.is-busy { opacity: .6; pointer-events: none; }

/* Ignoring homework with sessions booked: keep them or take them off. */
.ignore-sessions-text { margin: 0; font-size: 0.875rem; line-height: 1.5; color: var(--text-muted); }
#modal-ignore-sessions .modal-footer { justify-content: flex-end; }
/* "+ Add subject" at the end of the quick sheet's subject list. */
.qa-opt-add { color: var(--accent); font-weight: 600; margin-top: 0.125rem; }
.qa-opt-plus { flex: none; }
.qa-opt-new {
  display: flex; align-items: center; gap: 0.5rem; min-height: 2.25rem; margin-top: 0.125rem;
  padding: 0 0.625rem; border-radius: 0.5625rem; background: var(--surface2); color: var(--accent);
}
.qa-opt-new input { flex: 1; min-width: 0; height: auto; padding: 0 !important; border: 0 !important; box-shadow: none !important; outline: none; background: none !important; color: var(--text); font: inherit; font-size: 0.875rem; }
.qa-opt-new.is-busy { opacity: .6; }

/* The spotlight's way in (app.js maybeSpotlight): filled in the colour that
   kind of practice has everywhere -- Chrono's gold for the oral, the mock
   test's blue, the quick check's teal. */
.spotlight-go {
  --c: var(--accent);
  flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
  height: 2.75rem; padding: 0 1.25rem; margin-left: auto; border: 0; border-radius: var(--radius-sm, 0.625rem);
  font: inherit; font-size: 0.875rem; font-weight: 650; color: #fff; cursor: pointer; white-space: nowrap;
  background: var(--c);
  box-shadow: 0 0.375rem 1rem color-mix(in srgb, var(--c) 30%, transparent), inset 0 1px 0 rgba(255,255,255,0.18);
  transition: transform .15s var(--ease), box-shadow .15s ease, filter .15s ease;
}
.spotlight-go:hover { transform: translateY(-1px); filter: brightness(1.05); }
.spotlight-go:active { transform: scale(0.97); }
.spotlight-go[data-kind="oral"] { --c: #C8962E; background: linear-gradient(160deg, #D4A94A, #B8862A); }
.spotlight-go[data-kind="practice"] { --c: #4A63C9; }
/* Study help: the crimson of its pill in the panel's header. */
.spotlight-go[data-kind="help"] { --c: #C42B33; background: linear-gradient(180deg, #D42C36, #A0141C); }
.spotlight-go-ico svg { width: 1rem; height: 1rem; }
.spotlight-go-ico { display: grid; place-items: center; }

/* The list's diary, filter and + (academicFilter.js) are there when the
   list is pointed at or a filter is on -- at rest the sidebar is the work
   itself. Touch screens keep them shown. */
@media (hover: hover) and (pointer: fine) {
  .af-peer-head .sidebar-section-actions > * { opacity: 0; transition: opacity .18s ease; }
  #academic-section:hover .af-peer-head .sidebar-section-actions > *,
  .af-peer-head .sidebar-section-actions > :focus-visible,
  .af-peer-head .sidebar-section-actions > .is-filtering,
  .af-peer-head .sidebar-section-actions > [aria-expanded="true"] { opacity: 1; }
}

/* Beside the page, full screen is there when the header is pointed at:
   at rest the header holds what the session is and the way to help. */
@media (hover: hover) and (pointer: fine) {
  #screen-app:not(.study-max) #study-max { opacity: 0; width: 0; margin-left: -0.375rem; overflow: hidden; transition: opacity .18s ease, width .18s ease, margin .18s ease; }
  #screen-app:not(.study-max) .study-header:hover #study-max,
  #screen-app:not(.study-max) #study-max:focus-visible { opacity: 1; width: 1.75rem; margin-left: 0; }
}


/* ── Today, on top of the Plan (renderPlanView in app.js) ───────────────────
   The day at a glance, and the day itself: a ring that fills as today's
   rows are ticked, the greeting and what is left, the day as a line, and
   today's rows right in it -- the first with the one filled Start on the
   screen. Calm surface, generous space -- the first thing seen every day. */
.plan-today {
  --today-pad: 1.375rem;
  margin: 0; padding: 1.25rem var(--today-pad); border-radius: var(--radius-lg);
  background: var(--surface); box-shadow: 0 0 0 1px var(--border), 0 0.375rem 1.25rem rgba(16,24,40,0.04);
}
.today-head { display: flex; align-items: center; gap: 0.875rem; min-width: 0; }
.today-ring { position: relative; flex: none; width: 3rem; height: 3rem; display: grid; place-items: center; color: var(--accent); }
.today-ring svg:not(.today-ring-tick) { position: absolute; inset: 0; width: 100%; height: 100%; transform: rotate(-90deg); }
.today-ring circle { fill: none; stroke-width: 3.2; }
.today-ring-bg { stroke: color-mix(in srgb, var(--accent) 14%, transparent); }
.today-ring-fg { stroke: var(--accent); stroke-linecap: round; stroke-dasharray: var(--p) 100; transition: stroke-dasharray .6s var(--ease); }
.today-ring.is-empty .today-ring-fg { opacity: 0; }
.today-ring b { position: relative; font-size: 0.6875rem; font-weight: 700; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.today-ring.is-full { color: #fff; }
.today-ring.is-full::before { content: ''; position: absolute; inset: 0.25rem; border-radius: 50%; background: var(--accent); animation: todayPop .5s cubic-bezier(.34,1.56,.64,1); }
.today-ring-tick { position: relative; width: 1.125rem; height: 1.125rem; animation: todayPop .5s .08s cubic-bezier(.34,1.56,.64,1) both; }
@keyframes todayPop { from { transform: scale(.4); opacity: 0; } to { transform: none; opacity: 1; } }
.today-text { display: flex; flex-direction: column; gap: 0.125rem; min-width: 0; flex: 1; }
.today-hello { font-size: 0.8125rem; font-weight: 550; color: var(--text-muted); }
.today-title { font-size: 1.1875rem; font-weight: 700; letter-spacing: -0.015em; color: var(--text); line-height: 1.25; }
/* What is left, after the words: the same line, a step quieter. */
.today-title-dim { color: var(--text-muted); font-weight: 600; }
.today-streak {
  flex: none; display: inline-flex; align-items: center; gap: 0.25rem; height: 1.875rem; padding: 0 0.6875rem 0 0.5625rem;
  border-radius: 62.4375rem; color: #E8590C; background: color-mix(in srgb, #F59F00 14%, transparent);
  font-size: 0.8125rem; font-variant-numeric: tabular-nums;
}
.today-streak svg { width: 0.9375rem; height: 0.9375rem; }
:root[data-theme="dark"] .plan-today { box-shadow: 0 0 0 1px var(--border); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .plan-today { box-shadow: 0 0 0 1px var(--border); } }
@media (max-width: 480px) {
  .plan-today { --today-pad: 1rem; padding: 1rem var(--today-pad); }
  .today-title { font-size: 1.0625rem; }
}
@media (prefers-reduced-motion: reduce) { .today-ring.is-full::before { animation: none; } .today-ring-fg { transition: none; } }
/* Today's rows are the card's own lower part: edge to edge, under a
   hairline, the card's corners at the bottom -- no card inside a card. */
.plan-today { padding-bottom: 0; }
.plan-today .today-head { padding: 0; }
.plan-today > .today-line { margin: 1rem 0 0; }
.plan-today > .plan-group, .plan-today > .plan-dues {
  /* Edge to edge: as far out as the card's own padding, whatever it is. */
  margin: 1.125rem calc(-1 * var(--today-pad)) 0; border-radius: 0; box-shadow: none; background: transparent;
  border-top: 1px solid var(--plan-hair, var(--border));
}
.plan-today > .plan-dues + .plan-group { margin-top: 0; }
.plan-today > .plan-group:last-child { border-radius: 0 0 var(--radius-lg) var(--radius-lg); }
.plan-today > .plan-group.is-empty:not(.has-ph):not(.has-insert) { display: block; border: 0; margin-top: 0; height: 1.25rem; }
.plan-today .plan-row-inner { background: var(--surface); }
/* Today is read at a glance: a long title stops at two lines (the whole
   of it is a tap away), so one task cannot fill the phone's screen. */
.plan-today .plan-row .plan-title { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; }

/* Auto-Schedule's sheet, calmer: the ordinary white header of every other
   sheet, its bolt in a teal tile as the one mark of whose sheet it is --
   no band, no moving glint. */
#modal-schedule-mode .modal-header { background: var(--surface); color: var(--text); padding: 1.25rem 1.25rem 0.5rem 1.375rem; }
#modal-schedule-mode .modal-header::after { content: none; }
#modal-schedule-mode .modal-title { color: var(--text); font-size: 1.0625rem; }
#modal-schedule-mode .modal-title::before {
  width: 1.75rem; height: 1.75rem; border-radius: 0.5rem; box-shadow: none;
  background: var(--accent) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill='%23fff' fill-rule='evenodd' d='M11.3 1.046A1 1 0 0112 2v5h4a1 1 0 01.82 1.573l-7 10A1 1 0 018 18v-5H4a1 1 0 01-.82-1.573l7-10a1 1 0 011.12-.38z' clip-rule='evenodd'/%3E%3C/svg%3E") center / 0.875rem no-repeat;
}
#modal-schedule-mode .modal { box-shadow: var(--shadow-lg, 0 1.5rem 3.75rem rgba(16,24,40,0.18)); }
/* The week's sheet: what the seven days behind came to, above the week ahead. */
.cw-past {
  display: flex; align-items: baseline; justify-content: space-between; gap: 0.75rem;
  margin-bottom: 1rem; padding: 0.75rem 0.875rem; border-radius: var(--radius);
  background: color-mix(in srgb, var(--accent) 8%, var(--surface2));
}
.cw-past-label { font-size: 0.75rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--accent-dim); }
.cw-past-value { font-size: 0.875rem; font-weight: 650; color: var(--text); text-align: right; }
/* The corner card with nothing to point at (keeping Zenow close): the line
   and the two buttons. */
.spotlight-card .study-now-item.hidden { display: none; }

/* ── The corner cards: their two buttons ──────────────────────────────────
   Every card in the corner (study now, the test spotlight, study help, new
   registry work, keeping Zenow close) ends on the same pair: "Not now" and
   the action, side by side, the same height and the same rounded shape --
   one quiet, one filled -- never one pushed off to the far edge. The
   message reads as the headline; what it is about sits under it. */
.study-time-prompt-card .study-time-prompt-row.registry-alert-row {
  display: grid; grid-template-columns: 1fr 1fr; gap: 0.625rem;
}
.study-time-prompt-card .study-time-prompt-row.registry-alert-row > .btn,
.study-time-prompt-card .study-time-prompt-row.registry-alert-row > .generate-btn,
.study-time-prompt-card .study-time-prompt-row.registry-alert-row > .spotlight-go {
  width: 100%; min-width: 0; height: 2.75rem; margin: 0; padding: 0 1rem;
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
  border-radius: 0.875rem; font-size: 0.875rem; font-weight: 650; white-space: nowrap;
  box-sizing: border-box;
}
.study-time-prompt-card .study-time-prompt-row.registry-alert-row > .btn.btn-ghost {
  color: var(--text); background: var(--surface); border: 1px solid var(--border);
  box-shadow: 0 1px 0.125rem rgba(16,24,40,0.05);
}
.study-time-prompt-card .study-time-prompt-row.registry-alert-row > .btn.btn-ghost:hover { background: var(--surface2); }
.study-time-prompt-card .study-time-prompt-row.registry-alert-row > .generate-btn,
.study-time-prompt-card .study-time-prompt-row.registry-alert-row > .spotlight-go {
  border: 1px solid transparent; color: #fff;
}
.study-time-prompt-card .study-time-prompt-row.registry-alert-row > .spotlight-go[data-kind] { background: var(--c); box-shadow: 0 0.25rem 0.75rem color-mix(in srgb, var(--c) 28%, transparent); }
.study-time-prompt-card .spotlight-go svg, .study-time-prompt-card .generate-btn svg { width: 1rem; height: 1rem; flex: none; }
.study-time-prompt-card .study-time-prompt-row > * > span { overflow: hidden; text-overflow: ellipsis; }

.study-time-prompt-card .generate-btn:hover { animation: none; }
/* A phone: "Not now" as wide as its word, the action takes the rest. */
@media (max-width: 480px) {
  .study-time-prompt-card .study-time-prompt-row.registry-alert-row { grid-template-columns: auto minmax(0, 1fr); }
  .study-time-prompt-card .study-time-prompt-row.registry-alert-row > .btn.btn-ghost { padding: 0 1.125rem; }
}

/* Today's line (todayLineHtml): the day's study hours end to end, each
   session where it falls in its subject's colour, a dot for now. */
.today-line { display: flex; align-items: center; gap: 0.625rem; margin-top: 1rem; }
.tl-edge { flex: none; font-size: 0.6875rem; font-weight: 600; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.tl-track { position: relative; flex: 1; height: 0.625rem; border-radius: 62.4375rem; background: var(--surface2); }
.tl-seg {
  position: absolute; top: 0; bottom: 0; border-radius: 62.4375rem;
  background: var(--subject); box-shadow: 0 0 0 1.5px var(--surface);
  transition: opacity .3s ease;
}
.tl-seg.is-done { opacity: 0.32; }
.tl-now {
  position: absolute; top: 50%; width: 0.75rem; height: 0.75rem; margin: -0.375rem 0 0 -0.375rem; border-radius: 50%;
  background: var(--surface); box-shadow: 0 0 0 2px var(--text), 0 1px 0.25rem rgba(16,24,40,.2);
}
/* The day done: a burst of dots from the ring. */
.today-ring { overflow: visible; }
.today-burst { position: absolute; left: 50%; top: 50%; width: 0; height: 0; pointer-events: none; }
.today-burst i {
  position: absolute; width: 0.4375rem; height: 0.4375rem; margin: -0.21875rem; border-radius: 50%;
  animation: todayBurst 0.9s cubic-bezier(0.2, 0.7, 0.3, 1) both;
}
@keyframes todayBurst {
  0% { transform: translate(0, 0) scale(0.4); opacity: 1; }
  70% { opacity: 1; }
  100% { transform: translate(var(--x), var(--y)) scale(1); opacity: 0; }
}

/* Tests ahead, foldable (recall.js): a section heading like the days'
   ("Tomorrow", "Monday"), not a row -- the title, how many, and a chevron.
   Folded by default; open, the cards follow. */
.pe-head { flex-wrap: nowrap; }
.pe-fold {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: 0.5rem;
  padding: 0.25rem 0.25rem 0.25rem 0; margin: -0.25rem 0; border: 0; border-radius: 0.625rem; cursor: pointer;
  text-align: left; font: inherit; color: var(--text); background: none;
}
.pe-fold-ico { display: none; }
.pe-fold .pe-heading { font-size: 1.1875rem; font-weight: 700; letter-spacing: -0.018em; }
.pe-count {
  flex: none; min-width: 1.375rem; height: 1.375rem; padding: 0 0.4375rem; border-radius: 62.4375rem;
  display: inline-grid; place-items: center; font-size: 0.75rem; font-weight: 700; font-variant-numeric: tabular-nums;
  color: var(--text-muted); background: var(--surface2);
}
.pe-chev { flex: none; color: var(--text-dim); transition: transform .25s var(--ease), color .15s ease; }
.plan-exams.is-folded .pe-chev { transform: rotate(-90deg); }
.pe-fold:hover .pe-chev { color: var(--text); }
.plan-exams.is-folded .pe-nav { display: none; }

/* ── The corner card, one shape ─────────────────────────────────────────────
   Every card that asks for a moment sits in the bottom-left corner, where
   it always has: an opaque card, a coloured icon
   tile, a title, one line under it, and the two buttons side by side. The
   same for study now, a test coming, study help, new registry work, more
   time and keeping Zenow close. */
.study-time-prompt-card {
  left: 1.25rem; bottom: 1.25rem;
  padding: 1rem 1rem 1rem 1rem; border-radius: 1.25rem;
  background: var(--surface); border: 1px solid var(--border);
  -webkit-backdrop-filter: none; backdrop-filter: none;
  box-shadow: 0 1rem 2.5rem rgba(16,24,40,0.12), 0 0.125rem 0.5rem rgba(16,24,40,0.05);
  animation: cornerIn 0.34s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes cornerIn { from { transform: translateY(0.75rem); opacity: 0; } to { transform: none; opacity: 1; } }
.registry-alert-card { border-left: 1px solid var(--border); }
.study-time-prompt-card .study-time-prompt-close { top: 0.75rem; right: 0.75rem; width: 1.625rem; height: 1.625rem; border-radius: 50%; }
.cc-head { display: flex; align-items: flex-start; gap: 0.75rem; margin: 0 1.75rem 0.875rem 0; min-width: 0; }
.cc-icon {
  --c: var(--accent);
  flex: none; display: grid; place-items: center; width: 2.25rem; height: 2.25rem; border-radius: 0.75rem;
  color: #fff; background: var(--c);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.22), 0 0.25rem 0.625rem color-mix(in srgb, var(--c) 28%, transparent);
}
.cc-icon svg { width: 1.125rem; height: 1.125rem; }
.cc-text { display: flex; flex-direction: column; gap: 0.125rem; min-width: 0; padding-top: 0.0625rem; }
.cc-title { font-size: 0.9375rem; font-weight: 650; line-height: 1.3; color: var(--text); letter-spacing: -0.005em; overflow-wrap: anywhere; }
.cc-sub { display: block; font-size: 0.8125rem; line-height: 1.4; color: var(--text-muted); overflow-wrap: anywhere; }
.cc-dot { display: inline-block; width: 0.4375rem; height: 0.4375rem; margin-right: 0.375rem; border-radius: 50%; background: var(--subject-color, var(--accent)); vertical-align: 0.0625rem; }
.cc-sep { margin: 0 0.3125rem; color: var(--text-dim); }
/* The buttons: the action's icon is the tile's; the button says the word. */
.corner-card .generate-btn svg { display: none; }
.corner-card .study-time-prompt-row.registry-alert-row > .spotlight-go,
.corner-card .study-time-prompt-row.registry-alert-row > .generate-btn { background: var(--c, var(--accent)); box-shadow: none; }
.study-now-card .study-time-prompt-row.registry-alert-row > .generate-btn { --c: var(--accent); }
/* The other two (new registry work, more time) in the same type. */
.study-time-prompt-card .registry-alert-title, .study-time-prompt-card .study-time-prompt-label { font-size: 0.9375rem; font-weight: 650; color: var(--text); }
:root[data-theme="dark"] .study-time-prompt-card { box-shadow: 0 1rem 2.5rem rgba(0,0,0,0.45); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .study-time-prompt-card { box-shadow: 0 1rem 2.5rem rgba(0,0,0,0.45); } }
@media (max-width: 768px) {
  .study-time-prompt-card { left: 0.75rem; right: 0.75rem; width: auto; max-width: none; bottom: calc(0.75rem + env(safe-area-inset-bottom, 0px)); }
}
@media (prefers-reduced-motion: reduce) { .study-time-prompt-card { animation: none; } }
/* A day with nothing in it: its name and date, quieter, and close to the next. */
.plan-day.is-empty:not(.is-today):not(:has(.plan-due)) .plan-day-name { font-size: 1rem; color: var(--text-muted); }
.plan-day.is-empty:not(.is-today):not(:has(.plan-due)) .plan-day-date { font-size: 0.875rem; color: var(--text-dim); }

/* After a test: its grade asked for in the card itself, then the receipt
   with the student's own line under it. */
.pe-ask-form { flex-wrap: nowrap; }
.pe-ask-form .pe-guess-input { width: 5.5rem; height: 2.125rem; padding: 0 0.875rem; border-radius: 62.4375rem; font-size: 0.875rem; text-align: center; }
.pe-ask-form .pe-guess-input.is-bad { border-color: var(--red); }
@media (max-width: 600px) { .pe-ask-form .pe-guess-input { flex: 1 1 auto; width: auto; } }
.pe-result-line { display: block; margin-top: 0.25rem; font-size: 0.8125rem; font-weight: 600; color: var(--accent-dim, var(--accent)); }

/* Progress: the tests sat, each from how ready to what it got. */
.pg-rc-line {
  margin: 0 0 0.5rem; padding: 0.75rem 0.875rem; border-radius: var(--radius);
  font-size: 0.875rem; font-weight: 600; color: var(--text);
  background: color-mix(in srgb, var(--accent) 9%, var(--surface2));
}
.pg-rcs { list-style: none; margin: 0 0 1.25rem; padding: 0 0.875rem; display: flex; flex-direction: column; border-radius: 0.875rem; background: var(--surface2); }
.pg-rc { display: flex; align-items: center; gap: 0.75rem; padding: 0.625rem 0; border-top: 1px solid var(--border); }
.pg-rc:first-child { border-top: 0; }
.pg-rc-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.0625rem; }
.pg-rc-title { font-size: 0.875rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pg-rc-facts { font-size: 0.75rem; color: var(--text-muted); }
.pg-rc-nums { flex: none; display: inline-flex; align-items: baseline; gap: 0.375rem; font-variant-numeric: tabular-nums; }
.pg-rc-ready { font-size: 0.8125rem; font-weight: 600; color: var(--text-muted); }
.pg-rc-arrow { color: var(--text-dim); font-size: 0.75rem; }
.pg-rc-nums b { font-size: 1rem; font-weight: 750; color: var(--text); }

/* A test sat, waiting for its grade (recall.js awaitingCardHtml): the grade
   typed in, the marks already in Grades it could be, or none coming. */
.pe-ask-form.pe-actions { gap: 0.375rem; }
.pe-ask-form.pe-actions .pe-guess-input { flex: 1 1 3.5rem; width: auto; min-width: 3rem; height: 1.875rem; padding: 0 0.75rem; text-align: left; }
.pe-ask-form .pe-none { flex: none; color: var(--text-muted); }
.pe-links { display: flex; align-items: center; flex-wrap: wrap; gap: 0.375rem; min-width: 0; font-size: 0.75rem; color: var(--text-muted); }
.plan-recall .pe-links { margin-top: 0.375rem; }
.pe-links-label { font-weight: 600; }
.pe-link {
  display: inline-flex; align-items: baseline; gap: 0.3125rem; height: 1.625rem; padding: 0 0.625rem; border-radius: 62.4375rem;
  border: 1px solid var(--border); background: var(--surface); color: var(--text-muted); cursor: pointer; font: inherit; font-size: 0.75rem;
  align-items: center; transition: border-color .15s ease, background .15s ease;
}
.pe-link b { font-size: 0.8125rem; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.pe-link:hover { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 7%, var(--surface)); }
.pe-link:disabled { opacity: 0.55; cursor: default; }
.pe-card.is-awaiting .pe-ring b { font-size: 0.75rem; }
.pe-card.is-awaiting .pe-when { text-transform: none; }

/* ── The end of a sitting (recall.js sessionDoneHtml) ──────────────────────
   Today's ring, larger, filling by what was just done -- the tick and the
   burst when the day is complete -- the count and the time beside it, and
   the next sitting under them. */
.sd-hero { display: flex; align-items: center; gap: 1rem; margin: 0 0 0.875rem; }
.sd-ring { width: 3.75rem; height: 3.75rem; }
.sd-ring b { font-size: 0.8125rem; color: var(--text); }
.sd-ring .today-ring-fg { transition: stroke-dasharray 0.9s cubic-bezier(0.2, 0.7, 0.3, 1); }
.sd-ring .today-ring-tick { width: 1.375rem; height: 1.375rem; }
.sd-text { display: flex; flex-direction: column; gap: 0.1875rem; min-width: 0; }
.sd-title { font-size: 1.125rem; font-weight: 700; letter-spacing: -0.015em; color: var(--text); }
.sd-line { font-size: 0.875rem; color: var(--text-muted); }
.sd-next {
  display: flex; align-items: center; gap: 0.5rem; margin: 0 0 1rem; padding: 0.625rem 0.875rem; border-radius: 0.75rem;
  font-size: 0.875rem; font-weight: 600; color: var(--text); background: var(--surface2);
}
.sd-next svg { flex: none; color: var(--accent); }
.sd-next span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (prefers-reduced-motion: reduce) { .sd-ring .today-ring-fg { transition: none; } }

/* The evening card: tomorrow, ready; one tap closes the day. */
.plan-tomorrow { transition: opacity .25s ease, transform .25s ease; }
.plan-tomorrow.is-leaving { opacity: 0; transform: translateY(-0.375rem) scale(0.98); }

/* ── The class (classmates.js) ──────────────────────────────────────────────
   In the sidebar under Grades and Curriculum, in its own teal; its sheet:
   the invitation, the work classmates have, the people, the one switch. */
button.sidebar-portal-link { width: calc(100% - 0.75rem); border: 0; background: none; font-family: inherit; text-align: left; cursor: pointer; }
.sidebar-class-link { color: #6EE7D8; }
.sidebar-class-link .sidebar-portal-mark {
  background:
    radial-gradient(circle at 30% 22%, rgba(255,255,255,0.5) 0%, rgba(255,255,255,0.08) 55%, rgba(255,255,255,0) 100%),
    linear-gradient(135deg, #A7F3E4 0%, #14B8A6 50%, #0F5F57 100%);
}
/* Its glyph (two people) fills its square more than the others' do. */
.sidebar-class-link .sidebar-portal-mark svg { width: 0.6875rem; height: 0.6875rem; }
/* The page you are on, in every sidebar: the same three links, this one lit. */
.sidebar-portal-link.is-current { background: rgba(255,255,255,0.08); }
.sidebar-portal-link.is-current .sidebar-portal-chevron { opacity: 0; }
.sidebar-class-badge {
  min-width: 1.125rem; height: 1.125rem; padding: 0 0.3125rem; margin-left: auto; border-radius: 62.4375rem;
  display: inline-grid; place-items: center; font-size: 0.6875rem; font-weight: 700; color: #0B3B36; background: #6EE7D8;
}
.sidebar-class-badge.hidden { display: none; }
.sidebar-class-badge:not(.hidden) + .sidebar-portal-chevron { margin-left: 0.25rem; }

.class-modal { max-width: 30rem; }
.class-lede { margin: 0 0 1rem; font-size: 0.9375rem; line-height: 1.5; color: var(--text-muted); }
.class-form { margin: 0 0 1rem; }
.class-label { display: block; margin-bottom: 0.375rem; font-size: 0.8125rem; font-weight: 650; color: var(--text); }
.class-row { display: flex; gap: 0.5rem; }
.class-row input { flex: 1; min-width: 0; }
.class-row .btn { flex: none; min-width: 5.5rem; justify-content: center; }
.class-note { display: flex; gap: 0.5rem; align-items: flex-start; margin: 0.25rem 0 0; font-size: 0.8125rem; line-height: 1.45; color: var(--text-muted); }
.class-note svg { flex: none; margin-top: 0.125rem; color: var(--text-dim); }
.class-actions { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 1.25rem; }
/* The code, in one quiet strip with its two ways to pass it on. */
.class-invite { display: flex; align-items: center; gap: 0.375rem; padding: 0.375rem 0.375rem 0.375rem 0.875rem; border-radius: 0.875rem; background: var(--surface2); }
.class-invite-code { flex: 1; min-width: 0; font-size: 0.9375rem; font-weight: 650; letter-spacing: 0.08em; color: var(--text); font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.class-invite .class-icon-btn { width: 2rem; height: 2rem; background: var(--surface); }
.class-invite .class-icon-btn:hover, .class-invite .class-icon-btn.is-on { background: #0EA5A4; }
.class-qr { display: flex; flex-direction: column; align-items: center; gap: 0.625rem; margin-top: 0.625rem; padding: 1rem; border-radius: 0.875rem; background: var(--surface2); }
.class-qr-code { width: min(15rem, 70vw); aspect-ratio: 1; padding: 0.5rem; border-radius: 0.75rem; background: #fff; box-sizing: border-box; }
.class-qr-code svg { display: block; width: 100%; height: 100%; }
.class-qr-code.is-loading { background: color-mix(in srgb, var(--text) 6%, var(--surface)); }
.class-section { margin: 1.25rem 0 0.375rem; font-size: 0.75rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-dim); }
.class-people { list-style: none; margin: 0; padding: 0 0.875rem; border-radius: 0.875rem; background: var(--surface2); }
.class-person { display: flex; align-items: center; gap: 0.625rem; padding: 0.625rem 0; border-top: 1px solid var(--border); }
.class-person:first-child { border-top: 0; }
.class-avatar {
  flex: none; width: 1.875rem; height: 1.875rem; border-radius: 50%; display: grid; place-items: center;
  font-size: 0.6875rem; font-weight: 700; color: #0B3B36; background: color-mix(in srgb, #14B8A6 22%, var(--surface));
}
.class-person.is-me .class-avatar { color: #fff; background: #0EA5A4; }
.class-person-name { flex: 1; min-width: 0; font-size: 0.875rem; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.class-dim { font-weight: 500; color: var(--text-muted); }
.class-tag { flex: none; padding: 0.125rem 0.5rem; border-radius: 62.4375rem; font-size: 0.6875rem; font-weight: 600; color: var(--text-muted); background: var(--surface); }
.class-tag.is-off { color: var(--text-dim); }
.class-x {
  flex: none; width: 1.75rem; height: 1.75rem; display: grid; place-items: center; padding: 0; border: 0; border-radius: 50%;
  color: var(--text-dim); background: transparent; cursor: pointer;
}
.class-x:hover { color: var(--text); background: color-mix(in srgb, var(--text) 7%, transparent); }
.class-switch { display: flex; align-items: center; gap: 1rem; margin: 0.875rem 0 0.25rem; cursor: pointer; font-size: 0.875rem; font-weight: 600; }
.class-switch > span { flex: 1; display: flex; flex-direction: column; gap: 0.125rem; font-size: 0.875rem; }
.class-switch > span .class-dim { font-size: 0.8125rem; }
.class-switch input {
  appearance: none; -webkit-appearance: none; flex: none; position: relative; width: 2.75rem; height: 1.625rem; margin: 0;
  border-radius: 62.4375rem; background: color-mix(in srgb, var(--text) 18%, transparent); cursor: pointer; transition: background .2s ease;
}
.class-switch input::after {
  content: ''; position: absolute; top: 0.1875rem; left: 0.1875rem; width: 1.25rem; height: 1.25rem; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 3px rgba(16,24,40,.25); transition: transform .2s var(--ease);
}
.class-switch input:checked { background: #0EA5A4; }
.class-switch input:checked::after { transform: translateX(1.125rem); }
.class-foot { display: flex; justify-content: space-between; gap: 0.75rem; margin-top: 1.25rem; padding-top: 0.875rem; border-top: 1px solid var(--border); }
.class-link-btn { border: 0; background: none; padding: 0.25rem 0; font: inherit; font-size: 0.8125rem; font-weight: 600; color: var(--text-muted); cursor: pointer; }
.class-link-btn:hover { color: var(--text); }
.class-link-btn.is-danger { color: var(--red, #DC2626); }

/* The class's orals: one row per subject, opened on a tap. */
.class-head { display: flex; align-items: center; justify-content: space-between; margin: 1.25rem 0 0.5rem; font-size: 0.9375rem; font-weight: 700; color: var(--text); }
.class-icon-btn {
  flex: none; display: grid; place-items: center; width: 2.25rem; height: 2.25rem; border-radius: 62.4375rem; border: 0;
  color: #0D8F86; background: color-mix(in srgb, #14B8A6 14%, var(--surface)); cursor: pointer;
}
.class-icon-btn:hover, .class-icon-btn.is-on { color: #fff; background: #0EA5A4; }
.class-orals { list-style: none; margin: 0; padding: 0; border-radius: 0.875rem; background: var(--surface2); overflow: hidden; }
.class-oral + .class-oral { border-top: 1px solid var(--border); }
.class-oral-head {
  display: flex; align-items: center; gap: 0.625rem; width: 100%; min-height: 3rem; padding: 0.5rem 0.875rem;
  border: 0; background: none; font: inherit; text-align: left; color: var(--text); cursor: pointer;
}
.class-oral-subject { flex: 1; min-width: 0; font-size: 0.9375rem; font-weight: 650; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.class-faces { display: flex; flex: none; }
.class-face {
  display: grid; place-items: center; width: 1.5rem; height: 1.5rem; margin-left: -0.375rem; border-radius: 50%;
  font-size: 0.5625rem; font-weight: 700; color: #0B3B36; background: color-mix(in srgb, #14B8A6 22%, var(--surface));
  box-shadow: 0 0 0 2px var(--surface2);
}
.class-face:first-child { margin-left: 0; }
.class-face.is-more { color: var(--text-muted); background: var(--surface); }
.class-status { flex: none; padding: 0.1875rem 0.5rem; border-radius: 62.4375rem; font-size: 0.6875rem; font-weight: 700; }
.class-status.is-high { color: #92400E; background: color-mix(in srgb, #F59E0B 22%, var(--surface)); }
.class-status.is-medium { color: #0D8F86; background: color-mix(in srgb, #14B8A6 14%, var(--surface)); }
.class-status.is-done { display: grid; place-items: center; width: 1.375rem; height: 1.375rem; padding: 0; color: var(--text-dim); background: var(--surface); }
:root[data-theme="dark"] .class-status.is-high { color: #FCD34D; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .class-status.is-high { color: #FCD34D; } }
.class-oral-more { padding: 0 0.875rem 0.625rem; }
.class-q { margin: 0 0 0.375rem; padding-left: 0.625rem; border-left: 2px solid color-mix(in srgb, #14B8A6 45%, var(--border)); font-size: 0.8125rem; line-height: 1.45; color: var(--text); }
/* Who was questioned, on what, and when: the name first, the rest quieter. */
.class-oral-row { display: flex; align-items: center; gap: 0.5rem; min-height: 2rem; margin-top: 0.125rem; font-size: 0.8125rem; }
.class-oral-row:first-of-type, .class-q + .class-oral-row { margin-top: 0.5rem; }
.class-oral-who { flex: none; font-weight: 600; color: var(--text); }
.class-oral-topic { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-muted); }
.class-oral-day { flex: none; font-size: 0.75rem; color: var(--text-dim); text-transform: capitalize; }
.class-oral-row .class-x { width: 1.5rem; height: 1.5rem; margin-right: -0.25rem; }
@media (hover: hover) { .class-oral-row .class-x { opacity: 0; transition: opacity .15s ease; } .class-oral-row:hover .class-x, .class-oral-row .class-x:focus-visible { opacity: 1; } }
.class-oral-form { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 0.5rem; padding: 0.75rem; border-radius: 0.875rem; background: var(--surface2); }
.class-oral-form input, .class-oral-form select, .class-oral-form textarea { width: 100%; min-width: 0; box-sizing: border-box; }
.class-oral-form textarea { resize: vertical; }
.class-oral-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; }
.class-oral-form .class-actions { margin-top: 0.125rem; }
.class-empty {
  display: flex; align-items: center; justify-content: center; gap: 0.5rem; width: 100%; padding: 0.875rem;
  border: 1px dashed color-mix(in srgb, #14B8A6 40%, var(--border)); border-radius: 0.875rem; background: none;
  font: inherit; font-size: 0.875rem; font-weight: 600; color: #0D8F86; cursor: pointer;
}
.class-people-toggle {
  display: flex; align-items: center; gap: 0.625rem; width: 100%; margin-top: 1rem; padding: 0.5rem 0; border: 0; background: none;
  font: inherit; font-size: 0.8125rem; cursor: pointer;
}
.class-people-toggle .class-face { box-shadow: 0 0 0 2px var(--surface); width: 1.75rem; height: 1.75rem; font-size: 0.625rem; }
.class-people-count { font-weight: 600; color: var(--text-muted); }
.class-people-chev { margin-left: auto; color: var(--text-dim); transition: transform .2s var(--ease); }
.class-people-toggle[aria-expanded="true"] .class-people-chev { transform: rotate(180deg); }
.class-people-toggle:hover .class-people-count, .class-people-toggle:hover .class-people-chev { color: var(--text); }

/* The upgrade window's pass, the price it sits against, and asking a
   parent to pay. */
.plan-card-pass { border-style: dashed; }
.plan-card-pass.hidden { display: none; }
.upgrade-anchor { margin: 0.875rem 0 0; font-size: 0.8125rem; font-weight: 600; text-align: center; color: var(--text-muted); }
.upgrade-ask {
  display: flex; align-items: center; justify-content: center; gap: 0.5rem; width: 100%; margin-top: 0.75rem; padding: 0.75rem 1rem;
  border: 1px solid var(--border); border-radius: 0.875rem; background: var(--surface); color: var(--text);
  font: inherit; font-size: 0.875rem; font-weight: 650; cursor: pointer; transition: background .15s ease;
}
.upgrade-ask:hover { background: var(--surface2); }
.upgrade-ask.hidden { display: none; }
.upgrade-ask svg { color: var(--accent); }

/* ── The flame (Today's header) ─────────────────────────────────────────────
   A button to its full screen. Waiting -- nothing studied yet today -- it
   is unlit: grey, until the first thing done lights it, with a jump. */
.today-streak { border: 0; cursor: pointer; font: inherit; font-weight: 700; transition: background .2s ease, color .2s ease, transform .15s ease; }
.today-streak:hover { transform: scale(1.04); }
.today-streak:active { transform: scale(0.96); }
.today-streak.is-waiting { color: var(--text-dim); background: var(--surface2); }
.today-streak.is-waiting svg { opacity: 0.55; filter: grayscale(1); }
.today-streak.is-up { animation: flameUp .7s cubic-bezier(.34,1.56,.64,1); }
.today-streak.is-up svg { animation: flameLit .9s ease-out; }
@keyframes flameUp { 0% { transform: scale(.7); } 45% { transform: scale(1.18); } 100% { transform: none; } }
@keyframes flameLit { 0% { filter: grayscale(1) brightness(1.6); } 100% { filter: none; } }

/* A golden day: the burst in gold, a little wider. */
.today-burst.is-gold i { box-shadow: 0 0 0.375rem rgba(232,180,60,.65); }

/* The flame's full screen: how the streak keeps, and a milestone. */
.streak-fullscreen-note { max-width: 20rem; padding: 0 1.25rem; text-align: center; font-size: 0.8125rem; line-height: 1.45; color: rgba(255,255,255,0.6); }
.streak-fullscreen-note.hidden { display: none; }
.streak-fullscreen.is-milestone .streak-fullscreen-label { font-size: 1.25rem; font-weight: 750; color: #fff; text-align: center; padding: 0 1.25rem; }
.streak-fullscreen.is-milestone .streak-fullscreen-flame-wrap { animation: milestoneIn .9s cubic-bezier(.34,1.56,.64,1) both; }
.streak-fullscreen.is-milestone .streak-fullscreen-flame-wrap .today-burst i { width: 0.625rem; height: 0.625rem; margin: -0.3125rem; }
@keyframes milestoneIn { from { transform: scale(.4); opacity: 0; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .today-streak.is-up, .today-streak.is-up svg, .streak-fullscreen.is-milestone .streak-fullscreen-flame-wrap { animation: none; }
}
.streak-fullscreen.is-milestone .streak-fullscreen-arrow { visibility: hidden; }

/* Dark: Today's empty ring was barely there. */
:root[data-theme="dark"] .today-ring-bg { stroke: color-mix(in srgb, var(--accent) 26%, transparent); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .today-ring-bg { stroke: color-mix(in srgb, var(--accent) 26%, transparent); } }

/* ── Admission test simulations (public/js/prep.js) ──────────────────────
   A screen of its own: the real thing is two hours long. One column, the
   question big; a reading passage beside it on a wide screen. */
.prep-sheet { position: fixed; inset: 0; z-index: 900; background: var(--bg); color: var(--text); overflow-y: auto; -webkit-overflow-scrolling: touch; }
.prep-sheet.hidden { display: none; }
.prep-frame { min-height: 100%; display: flex; flex-direction: column; }
.prep-top { position: sticky; top: 0; z-index: 2; display: flex; align-items: center; gap: 0.75rem; padding: 0.875rem 1.25rem; background: color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border-bottom: 1px solid var(--border); }
.prep-top-title { flex: 1; min-width: 0; font-size: 0.9375rem; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.prep-top-title span { font-weight: 500; color: var(--text-muted); }
.prep-pick { flex: 0 1 auto; max-width: 70%; margin-right: auto; padding: 0.5rem 2rem 0.5rem 0.75rem; border-radius: 0.625rem; border: 1px solid var(--border); background: var(--surface); font: inherit; font-size: 0.875rem; font-weight: 600; color: var(--text); }
.prep-x { flex: none; width: 2.25rem; height: 2.25rem; display: grid; place-items: center; border: 0; border-radius: 50%; background: var(--surface2); color: var(--text-muted); cursor: pointer; transition: background 0.15s, color 0.15s; }
.prep-x:hover { background: var(--surface3); color: var(--text); }
.prep-clock { font-variant-numeric: tabular-nums; font-size: 1.0625rem; font-weight: 700; padding: 0.375rem 0.75rem; border-radius: 0.5rem; background: var(--surface2); transition: background 0.3s, color 0.3s; }
.prep-clock.is-low { background: color-mix(in srgb, #DC2626 14%, transparent); color: #DC2626; }
.prep-main { width: 100%; max-width: 40rem; margin: 0 auto; padding: 2rem 1.25rem 4rem; flex: 1; }
.prep-label { font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 0.5rem; }
.prep-label-n { float: right; letter-spacing: 0; text-transform: none; font-weight: 600; }
.prep-h { font-size: 1.875rem; line-height: 1.15; font-weight: 800; letter-spacing: -0.02em; margin: 0 0 0.75rem; }
.prep-sub { font-size: 0.9375rem; color: var(--text-muted); margin: 0.25rem 0 0; line-height: 1.5; }
.prep-meta { font-size: 0.8125rem; color: var(--text-muted); margin: 0.625rem 0 0; }
.prep-note { font-size: 0.875rem; color: var(--text-muted); margin: 1rem 0; line-height: 1.5; }
.prep-source { margin-top: 2rem; font-size: 0.75rem; line-height: 1.5; color: var(--text-dim); }
.prep-last { display: flex; align-items: flex-end; gap: 0.25rem; margin-top: 0.5rem; }
.prep-last-n { font-size: 3.25rem; line-height: 1; font-weight: 800; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
.prep-last-of { font-size: 1.25rem; font-weight: 700; color: var(--text-dim); padding-bottom: 0.3rem; }
.prep-spark { display: flex; align-items: flex-end; gap: 0.1875rem; height: 2.25rem; margin-left: auto; padding-bottom: 0.3rem; }
.prep-spark i { width: 0.4375rem; border-radius: 0.125rem; background: color-mix(in srgb, var(--accent) 55%, transparent); }
.prep-spark i:last-child { background: var(--accent); }
.prep-start { margin: 1.75rem 0 2.25rem; }
.prep-btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.375rem; min-height: 2.75rem; padding: 0 1.375rem; border-radius: 0.75rem; border: 0; font: inherit; font-size: 0.9375rem; font-weight: 700; cursor: pointer; transition: transform 0.12s var(--ease), background 0.15s, opacity 0.15s; }
.prep-btn:active { transform: scale(0.97); }
.prep-btn:disabled { opacity: 0.45; cursor: default; }
.prep-btn-primary { background: var(--primary); color: #fff; }
.prep-start .prep-btn-primary { width: 100%; min-height: 3.25rem; font-size: 1rem; }
.prep-btn-ghost { background: var(--surface2); color: var(--text); }
.prep-link { border: 0; background: none; padding: 0.25rem 0; font: inherit; font-size: 0.8125rem; font-weight: 600; color: var(--text-muted); cursor: pointer; text-decoration: underline; text-underline-offset: 0.2em; }
.prep-block { margin-top: 1.75rem; }
.prep-cov { border-top: 1px solid var(--border); }
.prep-cov:last-of-type { border-bottom: 1px solid var(--border); }
.prep-cov summary { display: grid; grid-template-columns: 1fr auto; grid-template-areas: "name n" "meta meta" "bar bar"; gap: 0.25rem 0.75rem; padding: 0.875rem 0; cursor: pointer; list-style: none; }
.prep-cov summary::-webkit-details-marker { display: none; }
.prep-cov-name { grid-area: name; font-weight: 700; font-size: 0.9375rem; }
.prep-cov-name em { font-style: normal; font-weight: 500; color: var(--text-dim); font-size: 0.8125rem; }
.prep-cov-n { grid-area: n; font-size: 0.8125rem; font-weight: 600; color: var(--text-muted); }
.prep-cov-meta { grid-area: meta; font-size: 0.75rem; color: var(--text-dim); }
.prep-cov-bar { grid-area: bar; display: block; height: 0.3125rem; border-radius: 1rem; background: var(--surface3); overflow: hidden; margin-top: 0.25rem; }
.prep-cov-bar i { display: block; height: 100%; border-radius: inherit; background: var(--accent); transition: width 0.6s var(--ease); }
.prep-cov ul { list-style: none; margin: 0 0 0.875rem; padding: 0; }
.prep-cov li { display: flex; justify-content: space-between; gap: 1rem; padding: 0.375rem 0; font-size: 0.8438rem; }
.prep-cov li b { font-weight: 600; white-space: nowrap; color: var(--text-muted); }
.prep-cov li.is-good b { color: #15803D; }
.prep-cov li.is-weak b { color: #B45309; }
.prep-cov li.is-new b { color: var(--text-dim); font-weight: 500; }
.prep-weak { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5rem; }
.prep-weak li { padding: 0.75rem 0.875rem; border-radius: 0.75rem; background: color-mix(in srgb, #F59E0B 10%, var(--surface)); display: flex; flex-direction: column; gap: 0.125rem; }
.prep-weak li span { font-weight: 600; font-size: 0.9063rem; }
.prep-weak li small { font-size: 0.75rem; color: var(--text-muted); }
.prep-wait { flex: 1; display: grid; place-items: center; }
.prep-dots { display: inline-flex; gap: 0.3125rem; }
.prep-dots i { width: 0.4375rem; height: 0.4375rem; border-radius: 50%; background: var(--accent); animation: prepDot 1.2s infinite ease-in-out; }
.prep-dots i:nth-child(2) { animation-delay: 0.15s; }
.prep-dots i:nth-child(3) { animation-delay: 0.3s; }
@keyframes prepDot { 0%, 80%, 100% { opacity: 0.25; transform: translateY(0); } 40% { opacity: 1; transform: translateY(-0.1875rem); } }
@media (prefers-reduced-motion: reduce) { .prep-dots i { animation: none; opacity: 0.7; } }
.prep-gate { padding-top: 3.5rem; }
.prep-gate .prep-btn-primary { margin-top: 2rem; width: 100%; min-height: 3.25rem; }
.prep-steps { display: flex; gap: 0.375rem; margin-bottom: 1.75rem; }
.prep-steps i { flex: 1; height: 0.25rem; border-radius: 1rem; background: var(--surface3); }
.prep-steps i.done { background: var(--accent); }
.prep-steps i.now { background: var(--primary); }
.prep-writing { display: flex; gap: 0.875rem; align-items: flex-start; margin-top: 2rem; padding: 1rem 1.125rem; border-radius: 0.875rem; background: var(--surface); border: 1px solid var(--border); }
.prep-writing .prep-dots { margin-top: 0.4375rem; }
.prep-writing b { font-size: 0.9375rem; }
.prep-writing p { margin: 0.25rem 0 0; font-size: 0.8125rem; color: var(--text-muted); line-height: 1.5; }
.prep-nav { display: flex; gap: 0.3125rem; padding: 0.625rem 1.25rem; overflow-x: auto; scrollbar-width: none; border-bottom: 1px solid var(--border); background: var(--bg); }
.prep-nav::-webkit-scrollbar { display: none; }
.prep-dot { flex: none; width: 1.875rem; height: 1.875rem; border-radius: 0.5rem; border: 1px solid var(--border); background: var(--surface); font: inherit; font-size: 0.75rem; font-weight: 600; color: var(--text-muted); cursor: pointer; font-variant-numeric: tabular-nums; }
.prep-dot.done { background: color-mix(in srgb, var(--accent) 16%, var(--surface)); border-color: color-mix(in srgb, var(--accent) 40%, transparent); color: var(--text); }
.prep-dot.now { border-color: var(--primary); box-shadow: inset 0 0 0 1px var(--primary); color: var(--text); }
.prep-run { padding-top: 1.75rem; }
.prep-run.has-passage { max-width: 72rem; display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: 2rem; align-items: start; }
.prep-passage { position: sticky; top: 7.5rem; max-height: calc(100vh - 9rem); overflow-y: auto; padding: 1.25rem 1.375rem; border-radius: 0.875rem; background: var(--surface); border: 1px solid var(--border); font-size: 0.9375rem; line-height: 1.7; }
.prep-passage p { margin: 0 0 0.875rem; }
.prep-stem { font-size: 1.125rem; line-height: 1.6; margin: 0.625rem 0 1.375rem; }
.prep-options { display: grid; gap: 0.5rem; }
.prep-opt { display: flex; align-items: flex-start; gap: 0.75rem; width: 100%; text-align: left; padding: 0.875rem 1rem; border-radius: 0.75rem; border: 1px solid var(--border); background: var(--surface); font: inherit; font-size: 0.9688rem; line-height: 1.5; color: var(--text); cursor: pointer; transition: border-color 0.15s, background 0.15s, transform 0.12s var(--ease); }
.prep-opt:hover { border-color: var(--border2); }
.prep-opt:active { transform: scale(0.99); }
.prep-opt-l { flex: none; width: 1.625rem; height: 1.625rem; border-radius: 50%; display: grid; place-items: center; font-size: 0.75rem; font-weight: 700; background: var(--surface2); color: var(--text-muted); transition: background 0.15s, color 0.15s; }
.prep-opt.is-on { border-color: var(--primary); background: color-mix(in srgb, var(--primary) 5%, var(--surface)); box-shadow: inset 0 0 0 1px var(--primary); }
.prep-opt.is-on .prep-opt-l { background: var(--primary); color: #fff; }
.prep-opt-t { padding-top: 0.0625rem; min-width: 0; }
.prep-type { width: 100%; padding: 0.875rem 1rem; border-radius: 0.75rem; border: 1px solid var(--border); background: var(--surface); font: inherit; font-size: 1.0625rem; color: var(--text); }
.prep-q-foot { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-top: 1.5rem; }
.prep-hint { font-size: 0.75rem; color: var(--text-dim); }
.prep-arrows { display: flex; gap: 0.5rem; margin-left: auto; }
.prep-arrows .prep-btn-ghost[data-prep="prev"] { width: 2.75rem; padding: 0; }
.prep-end-now { display: block; margin: 2rem auto 0; }
.prep-score { display: flex; align-items: flex-end; gap: 0.25rem; }
.prep-score .prep-last-n { font-size: 4rem; }
.prep-high .prep-last-n { color: #15803D; }
.prep-mid .prep-last-n { color: #B45309; }
.prep-low .prep-last-n { color: #DC2626; }
.prep-res { list-style: none; margin: 1.75rem 0 0; padding: 0; display: grid; gap: 1rem; }
.prep-res-row { display: grid; gap: 0.375rem; }
.prep-res-row .prep-cov-bar { grid-area: auto; margin-top: 0; }
.prep-res-row.is-unscored { opacity: 0.7; }
.prep-res-head { display: flex; justify-content: space-between; gap: 1rem; font-size: 0.9375rem; font-weight: 600; }
.prep-res-head b { font-variant-numeric: tabular-nums; }
.prep-res-head small { color: var(--text-dim); font-weight: 600; }
.prep-res-row > small { font-size: 0.75rem; color: var(--text-muted); }
.prep-result > .prep-label { margin-top: 2rem; }
.prep-review { border-top: 1px solid var(--border); }
.prep-review:last-of-type { border-bottom: 1px solid var(--border); }
.prep-review summary { display: flex; justify-content: space-between; gap: 1rem; padding: 0.875rem 0; cursor: pointer; list-style: none; font-weight: 600; font-size: 0.9375rem; }
.prep-review summary::-webkit-details-marker { display: none; }
.prep-review summary small { font-weight: 500; color: var(--text-muted); font-size: 0.8125rem; }
.prep-review ol { margin: 0 0 1rem; padding-left: 1.25rem; display: grid; gap: 1rem; }
.prep-rq { padding-left: 0.375rem; }
.prep-rq::marker { color: var(--text-dim); font-weight: 700; font-size: 0.8125rem; }
.prep-rq.is-wrong::marker { color: #DC2626; }
.prep-rq.is-right::marker { color: #15803D; }
.prep-rq-stem { font-size: 0.9375rem; line-height: 1.55; margin-bottom: 0.5rem; }
.prep-rq-line { display: flex; align-items: baseline; gap: 0.5rem; font-size: 0.875rem; line-height: 1.5; padding: 0.375rem 0.625rem; border-radius: 0.5rem; background: color-mix(in srgb, #DC2626 8%, transparent); margin-top: 0.25rem; }
.prep-rq-line.is-key { background: color-mix(in srgb, #16A34A 10%, transparent); }
.prep-rq-line > span { flex: none; font-weight: 700; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); padding-top: 0.125rem; }
.prep-rq-why { font-size: 0.8438rem; line-height: 1.55; color: var(--text-muted); margin-top: 0.5rem; }
body.prep-open { overflow: hidden; }
@media (max-width: 760px) {
  .prep-run.has-passage { display: block; }
  .prep-passage { position: static; max-height: none; margin-bottom: 1.5rem; }
  .prep-main { padding: 1.5rem 1rem 3rem; }
  .prep-top { padding: 0.75rem 1rem; }
  .prep-h { font-size: 1.625rem; }
  .prep-stem { font-size: 1.0625rem; }
  .prep-top-run .prep-top-title span { display: none; }
}
:root[data-theme="dark"] .prep-btn-primary { background: #E5E7EB; color: #0F1420; }
:root[data-theme="dark"] .prep-opt.is-on .prep-opt-l { background: #E5E7EB; color: #0F1420; }
:root[data-theme="dark"] .prep-opt.is-on { border-color: #E5E7EB; box-shadow: inset 0 0 0 1px #E5E7EB; background: rgba(255,255,255,0.05); }
:root[data-theme="dark"] .prep-dot.now { border-color: #E5E7EB; box-shadow: inset 0 0 0 1px #E5E7EB; }
:root[data-theme="dark"] .prep-steps i.now { background: #E5E7EB; }
:root[data-theme="dark"] .prep-cov li.is-good b, :root[data-theme="dark"] .prep-high .prep-last-n { color: #4ADE80; }
:root[data-theme="dark"] .prep-cov li.is-weak b, :root[data-theme="dark"] .prep-mid .prep-last-n { color: #FBBF24; }
:root[data-theme="dark"] .prep-low .prep-last-n { color: #F87171; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .prep-btn-primary { background: #E5E7EB; color: #0F1420; }
  :root:not([data-theme="light"]) .prep-opt.is-on .prep-opt-l { background: #E5E7EB; color: #0F1420; }
  :root:not([data-theme="light"]) .prep-opt.is-on { border-color: #E5E7EB; box-shadow: inset 0 0 0 1px #E5E7EB; background: rgba(255,255,255,0.05); }
  :root:not([data-theme="light"]) .prep-dot.now { border-color: #E5E7EB; box-shadow: inset 0 0 0 1px #E5E7EB; }
  :root:not([data-theme="light"]) .prep-steps i.now { background: #E5E7EB; }
  :root:not([data-theme="light"]) .prep-cov li.is-good b, :root:not([data-theme="light"]) .prep-high .prep-last-n { color: #4ADE80; }
  :root:not([data-theme="light"]) .prep-cov li.is-weak b, :root:not([data-theme="light"]) .prep-mid .prep-last-n { color: #FBBF24; }
  :root:not([data-theme="light"]) .prep-low .prep-last-n { color: #F87171; }
}

/* "Which of these came up?" (recall.js outcomeCardHtml): a list of the
   predicted questions, each a tap. */
.pe-out { align-items: flex-start; }
.pe-out .plan-sub { white-space: normal; }
.pe-out-list { display: flex; flex-direction: column; gap: 0.375rem; margin-top: 0.75rem; }
.pe-out-q { display: flex; align-items: center; gap: 0.75rem; padding: 0.5rem 0.5rem 0.5rem 0.875rem; border-radius: 0.75rem; border: 1px solid var(--border); background: var(--surface); font-size: 0.875rem; line-height: 1.45; transition: border-color 0.15s, background 0.15s; }
.pe-out-q.is-on { border-color: color-mix(in srgb, #5856D6 40%, transparent); background: color-mix(in srgb, #5856D6 6%, var(--surface)); }
.pe-out-t { flex: 1; min-width: 0; }
.pe-out-pills { flex: none; display: flex; gap: 0.25rem; padding: 0.1875rem; border-radius: 62rem; background: var(--surface2); }
.pe-out-pill { border: 0; background: transparent; padding: 0.3125rem 0.6875rem; border-radius: 62rem; font: inherit; font-size: 0.75rem; font-weight: 700; color: var(--text-muted); cursor: pointer; transition: background 0.15s, color 0.15s, transform 0.12s var(--ease); }
.pe-out-pill:active { transform: scale(0.96); }
.pe-out-pill.is-on { background: #5856D6; color: #fff; }
.pe-out-pill[data-pe-out-lv="similar"].is-on { background: color-mix(in srgb, #5856D6 70%, var(--surface)); }
@media (max-width: 600px) {
  .pe-out-q { flex-direction: column; align-items: stretch; gap: 0.5rem; padding: 0.625rem 0.75rem; }
  .pe-out-pills { align-self: flex-start; }
}
.pe-out-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin-top: 0.75rem; }
.pe-out-skip { margin-left: auto; border: 0; background: none; padding: 0.25rem 0; font: inherit; font-size: 0.8125rem; font-weight: 600; color: var(--text-muted); cursor: pointer; }
.pe-out-wait { display: block; margin-top: 0.75rem; }
.pe-out-dots { display: inline-flex; gap: 0.3125rem; }
.pe-out-dots i { width: 0.375rem; height: 0.375rem; border-radius: 50%; background: #5856D6; animation: prepDot 1.2s infinite ease-in-out; }
.pe-out-dots i:nth-child(2) { animation-delay: 0.15s; }
.pe-out-dots i:nth-child(3) { animation-delay: 0.3s; }

/* First run, the test step: what it is on, and how to start
   (onboarding.js obRenderExam). */
.ob-exam-topic[aria-invalid="true"], #ob-exam-subject[aria-invalid="true"], #ob-exam-day[aria-invalid="true"] { border-color: var(--amber); box-shadow: 0 0 0 0.1875rem color-mix(in srgb, var(--amber) 22%, transparent); }
.ob-exam-mode { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; margin-top: 0.375rem; }
.ob-mode { display: flex; flex-direction: column; align-items: flex-start; gap: 0.125rem; padding: 0.75rem 0.875rem; text-align: left; border-radius: 0.75rem; border: 1px solid var(--border); background: var(--surface); font: inherit; color: var(--text); cursor: pointer; transition: border-color 0.15s, background 0.15s, box-shadow 0.15s; }
.ob-mode b { font-size: 0.875rem; }
.ob-mode span { font-size: 0.75rem; color: var(--text-muted); line-height: 1.4; }
.ob-mode.is-on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 7%, var(--surface)); box-shadow: inset 0 0 0 1px var(--accent); }
.ob-exam-mode.hidden, .ob-exam-topic.hidden { display: none; }

/* Waiting on a save the student asked for (app.js busyStart): a thin bar
   along the top, and what they touched breathing until it is done. */
#busy-bar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 10000; height: 2px; overflow: hidden;
  pointer-events: none; opacity: 0; transition: opacity .2s ease;
}
#busy-bar.is-on { opacity: 1; }
#busy-bar::before {
  content: ''; position: absolute; top: 0; bottom: 0; left: 0; width: 35%;
  background: linear-gradient(90deg, transparent, var(--accent, #0EA5A4), transparent);
  animation: busy-run 1.1s cubic-bezier(.4, 0, .2, 1) infinite;
}
@keyframes busy-run { from { transform: translateX(-100%); } to { transform: translateX(300%); } }
.is-busy { animation: busy-breathe .9s ease-in-out infinite alternate; pointer-events: none; }
@keyframes busy-breathe { from { opacity: 1; } to { opacity: .45; } }
@media (prefers-reduced-motion: reduce) {
  #busy-bar::before { animation-duration: 2.4s; }
  .is-busy { animation: none; opacity: .6; }
}
.class-oral-form input[list]::-webkit-calendar-picker-indicator { opacity: 0; }
