/* ==============================================================================
   Smart Study AI — Professional Dark Theme
   Simple, clean design. No decorative elements. Focus on clarity and usability.
   ============================================================================== */

/* --------------------------------------------------------------------------
   DESIGN TOKENS
   -------------------------------------------------------------------------- */

:root {
  --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue",
    Helvetica, Arial, sans-serif;

  /* White, not a tinted near-black — the app was dark-themed with a
     toggle at one point; the toggle's gone and this is the one background
     that's left. Purple is the secondary/accent colour below, not the base. */
  --bg: #ffffff;
  /* Solid, not translucent: the page is white and a surface is a quiet grey
     panel on top of it. Nothing here is see-through any more. */
  --surface: #f5f4f8;
  --surface-alt: #faf9fb;
  --border: rgba(0, 0, 0, 0.12);

  --text: #14121a;
  --text-muted: #55535e;
  --text-subtle: #79767f;

  --accent: #7c3aed;
  --accent-hover: #8b5cf6;
  --accent-soft: rgba(124, 58, 237, 0.12);
  /* Second accent for gradients (buttons, progress fill) — gold against the
     violet --accent, echoing the starfield's own colour. */
  --accent-2: #fbbf24;
  --on-accent: #241a3a;

  --correct: #059669;
  --correct-soft: rgba(52, 211, 153, 0.14);
  --wrong: #e11d48;
  --wrong-soft: rgba(244, 63, 94, 0.14);

  /* Logo wordmark. "Smart Study AI" is the logo, so it gets a colour ramp of
     its own rather than reusing --accent: violet at the S, through magenta,
     to gold by the I. Both places the name appears — the landing hero and
     the header brand — walk this same range, so editing it here moves both.
     The end hue runs past 360 on purpose: that's what carries the sweep
     through magenta and red rather than backwards through blue and green. */
  --logo-hue-start: 258;
  --logo-hue-end: 406;
  /* Lower saturation and lightness than the app's --accent on purpose — the
     wordmark reads as matte/muted rather than glossy or neon. */
  --logo-sat: 42%;
  --logo-light: 56%;

  /* Light shadows: these were tuned for the old dark theme, where a heavy
     black bloom disappeared into the background. On white it read as a grey
     smudge under every card. */
  --shadow: 0 4px 16px rgba(20, 18, 26, 0.08);
  --shadow-lifted: 0 8px 28px rgba(20, 18, 26, 0.12);

  --radius: 12px;
  --radius-large: 18px;

  --ease: cubic-bezier(0.4, 0, 0.2, 1);

  --font-scale: 1;
  --header-height: 56px;
  --content-width: 980px;
}

/* --------------------------------------------------------------------------
   RESET / BASE
   -------------------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  font-family: var(--font);
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
}

body {
  background-color: var(--bg);
  color: var(--text);
  line-height: 1.5;
  overflow-x: hidden;
}

button {
  font: inherit;
  cursor: pointer;
  border: none;
  background: none;
}

input,
textarea,
select {
  font: inherit;
  color: inherit;
  background: transparent;
}

[hidden] {
  display: none !important;
}

/* --------------------------------------------------------------------------
   TYPOGRAPHY
   -------------------------------------------------------------------------- */

h1,
h2,
h3,
h4 {
  line-height: 1.2;
  font-weight: 600;
  letter-spacing: -0.02em;
}

h1 {
  font-size: calc(2.5rem * var(--font-scale));
  margin-bottom: 0.5rem;
}

h2 {
  font-size: calc(1.875rem * var(--font-scale));
  margin-bottom: 0.5rem;
}

h3 {
  font-size: calc(1.25rem * var(--font-scale));
  margin-bottom: 0.5rem;
}

p {
  font-size: calc(1rem * var(--font-scale));
  margin-bottom: 1rem;
}

small,
.text-small {
  font-size: calc(0.875rem * var(--font-scale));
}

/* --------------------------------------------------------------------------
   MENU / HEADER
   -------------------------------------------------------------------------- */

/* No line under the header. The bar itself is frosted rather than solid, so
   what scrolls underneath blurs through it instead of hitting a hard edge —
   that blur is what separates the header from the page now. */
.menu {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  /* The notch eats the top-left corner in landscape, and the home indicator
     sits over the bottom of the screen. Both are reported by env(); they are
     0 on every device without them, so these cost nothing elsewhere. */
  height: calc(var(--header-height) + env(safe-area-inset-top));
  padding-top: env(safe-area-inset-top);
  padding-left: max(1.5rem, env(safe-area-inset-left));
  padding-right: max(1.5rem, env(safe-area-inset-right));
  background-color: rgba(255, 255, 255, 0.72);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0 1.5rem;
  z-index: 100;
  font-size: calc(0.95rem * var(--font-scale));
}

.menu__brand {
  font-weight: 700;
  letter-spacing: -0.02em;
  margin-right: auto;
  white-space: nowrap;
}

/* Per-letter, not one clipped gradient — matches .landing__title .letter
   below for the same reason that one gives: the fly-in transforms each
   span individually, and a background-clip: text gradient breaks across
   transformed children. Colored the same way whether or not it's about to
   fly in, so the header logo looks right immediately, before js/ui.js ever
   adds "is-entering". */
.menu__brand .letter {
  display: inline-block;
  color: hsl(
    calc(
      var(--logo-hue-start) +
      var(--letter-index) * (var(--logo-hue-end) - var(--logo-hue-start)) / 13
    )
    var(--logo-sat) var(--logo-light)
  );
}

/* Added once by js/ui.js, the first time a session reaches the chat screen
   — a signed-in visitor skips the landing page's own version of this
   entrance (see ui.js's auto-redirect past it) and would otherwise never
   see it at all. Same letterFly keyframes and stagger the landing page's
   wordmark uses, just at header size. */
.menu__brand.is-entering .letter {
  animation: letterFly 0.6s var(--ease) backwards;
  animation-delay: calc(var(--letter-index) * 0.08s);
}

/* Liquid glass: a translucent pill that blurs whatever passes under it,
   with a bright top edge and a soft drop shadow, so it reads as a raised
   piece of glass rather than a flat button. The sheen is the gradient —
   lighter at the top, thinner at the bottom, the way light falls on a
   curved surface. */
.menu__item,
.menu__sizer button {
  position: relative;
  color: var(--text-muted);
  border-radius: 999px;
  border: none;
  background-image: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.92),
    rgba(255, 255, 255, 0.55)
  );
  backdrop-filter: blur(12px) saturate(180%);
  -webkit-backdrop-filter: blur(12px) saturate(180%);
  box-shadow:
    0 1px 2px rgba(20, 18, 26, 0.06),
    0 4px 12px rgba(20, 18, 26, 0.05),
    inset 0 1px 0 rgba(255, 255, 255, 0.9);
  transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease),
    color 0.2s var(--ease);
}

/* The violet-to-gold rim. A gradient can't be a border-color, and the
   padding-box/border-box trick the feature cards use would tint the glass
   itself, since the fill here is see-through. So this paints the gradient
   over the whole pill and masks out everything but the 1.5px ring: two
   masks, one the full pill and one its inside, subtracted from each other. */
.menu__item::before,
.menu__sizer button::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  mask-composite: exclude;
  pointer-events: none;
}

.menu__item {
  padding: 0.45rem 1rem;
}

.menu__item:active,
.menu__sizer button:active {
  transform: translateY(1px);
  box-shadow:
    0 1px 2px rgba(20, 18, 26, 0.08),
    inset 0 1px 3px rgba(20, 18, 26, 0.08);
}

.menu__item:hover,
.menu__sizer button:hover {
  color: var(--text);
  transform: translateY(-1px);
  box-shadow:
    0 2px 4px rgba(20, 18, 26, 0.07),
    0 8px 20px rgba(20, 18, 26, 0.08),
    inset 0 1px 0 rgba(255, 255, 255, 1);
}

/* The current tab keeps the same rim, tinted inside so it reads as selected. */
.menu__item[aria-current="page"] {
  color: var(--accent);
  background-image: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.92),
    var(--accent-soft)
  );
}

.menu__sizer {
  display: flex;
  gap: 0.4rem;
}

/* --------------------------------------------------------------------------
   ACCOUNT MENU — signing in and out, and the text size. The button is the
   same liquid glass as the nav pills; the panel under it is a heavier sheet
   of the same material.
   -------------------------------------------------------------------------- */

.menu__account-wrap {
  position: relative;
  margin-left: auto;
}

.menu__account {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  max-width: 12rem;
}

.menu__account span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.menu__account[aria-expanded="true"] .menu__account-caret {
  transform: rotate(180deg);
}

.menu__account-caret {
  flex-shrink: 0;
  transition: transform 0.2s var(--ease);
}

.menu__dropdown {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  z-index: 120;
  min-width: 15rem;
  padding: 0.4rem;
  display: flex;
  flex-direction: column;
  border-radius: 14px;
  background-color: rgba(255, 255, 255, 0.82);
  backdrop-filter: blur(24px) saturate(180%);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  border: 1px solid rgba(20, 18, 26, 0.08);
  box-shadow:
    0 12px 32px rgba(20, 18, 26, 0.14),
    inset 0 1px 0 rgba(255, 255, 255, 0.9);
}

.menu__dropdown[hidden] {
  display: none;
}

.menu__dropdown-email {
  padding: 0.5rem 0.65rem 0.35rem;
  font-size: calc(0.78rem * var(--font-scale));
  color: var(--text-subtle);
  overflow: hidden;
  text-overflow: ellipsis;
}

.menu__dropdown-item {
  text-align: left;
  padding: 0.5rem 0.65rem;
  border-radius: 8px;
  color: var(--text);
  font-size: calc(0.9rem * var(--font-scale));
  transition: background-color 0.15s var(--ease), color 0.15s var(--ease);
}

.menu__dropdown-item:hover {
  background-color: var(--accent-soft);
  color: var(--accent);
}

.menu__dropdown-sep {
  height: 1px;
  margin: 0.35rem 0.3rem;
  background-color: var(--border);
}

.menu__dropdown-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.35rem 0.65rem 0.4rem;
  font-size: calc(0.9rem * var(--font-scale));
  color: var(--text);
}

.menu__sizer button {
  padding: 0.35rem 0.7rem;
  font-size: 0.9rem;
  font-weight: 500;
}



/* --------------------------------------------------------------------------
   MAIN CONTENT
   -------------------------------------------------------------------------- */

main {
  margin-top: calc(var(--header-height) + env(safe-area-inset-top));
  perspective: 1200px;
  perspective-origin: left center;
}

.screen {
  display: none;
  min-height: calc(100vh - var(--header-height));
}

/* Screens stack their content top-to-bottom. Without an explicit direction the
   flex default is `row`, which turns every heading and paragraph into a narrow
   side-by-side column. Any screen that genuinely wants a row has to say so. */
.screen:not([hidden]) {
  display: flex;
  flex-direction: column;
  position: relative;
  transform-origin: left center;
  backface-visibility: hidden;
  will-change: transform, opacity;
  animation: pageFlip 0.55s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Transform + opacity only — both run on the compositor, so the flip stays at
   60fps. Animating clip-path or filter here forces a repaint every frame and is
   what made the earlier version stutter. */
@keyframes pageFlip {
  from {
    /* The hinge (transform-origin, set on .screen below) is on the left, so
       a NEGATIVE rotateY here swings the right edge toward the viewer
       first — a page lifting up and toward you, which reads as turning
       BACK to a previous page. Positive is the fix: the right edge starts
       receded behind the spine and swings forward into place, the way the
       next page in a left-bound book actually arrives. */
    opacity: 0;
    transform: rotateY(26deg) translateZ(-40px);
  }
  to {
    opacity: 1;
    transform: rotateY(0deg) translateZ(0);
  }
}

@keyframes letterFly {
  0% {
    opacity: 0;
    transform: translateY(-40px) translateX(-20px) rotateZ(-10deg);
  }
  50% {
    opacity: 1;
    transform: translateY(-60px) translateX(10px) rotateZ(5deg);
  }
  100% {
    opacity: 1;
    transform: translateY(0) translateX(0) rotateZ(0);
  }
}

@keyframes slideUpFade {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes slideInRight {
  from {
    opacity: 0;
    transform: translateX(100px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

/* --------------------------------------------------------------------------
   SPLASH
   The whole opening: the wordmark flies in over the chat, then fades. There
   is no landing page any more — the app starts on Study, already built
   underneath this, so the only thing being waited on is the animation
   itself. js/ui.js fades it out and removes it.
   -------------------------------------------------------------------------- */

.splash {
  /* How long each letter waits behind the one before it. Everything else in
     the splash is timed off this, so slowing the intro down is one number. */
  --splash-step: 0.08s;
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  background-color: var(--bg);
  transition: opacity 0.4s var(--ease);
}

/* Already signed in: no intro at all, straight to the chat. Set by the head
   script in index.html. */
.has-session .splash {
  display: none;
}

.splash.is-leaving {
  opacity: 0;
  pointer-events: none;
}

.splash__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.25rem;
}

.splash__mark {
  margin: 0;
  /* One line, always. Each letter is its own element, so a line could
     otherwise break between any two of them — "Smart Study A / I" is what
     that looked like on a phone. The size follows the screen's width so it
     fits rather than wraps. */
  white-space: nowrap;
  font-size: min(calc(2.6rem * var(--font-scale)), 9vw);
  font-weight: 700;
  letter-spacing: -0.03em;
  text-align: center;
  /* Ties the per-letter colours below back into one object. */
  text-shadow: 0 0 20px
    hsl(calc((var(--logo-hue-start) + var(--logo-hue-end)) / 2)
        var(--logo-sat) var(--logo-light) / 0.15);
}

/* Same ramp and same stagger as the header's wordmark: violet at the S,
   through magenta, to gold by the I. */
.splash__mark .letter {
  display: inline-block;
  color: hsl(
    calc(
      var(--logo-hue-start) +
      var(--letter-index) * (var(--logo-hue-end) - var(--logo-hue-start)) / 13
    )
    var(--logo-sat) var(--logo-light)
  );
  animation: letterFly 0.6s var(--ease) backwards;
  animation-delay: calc(var(--letter-index) * var(--splash-step));
}

/* Lights up once the name has landed: the last letter starts at 13 steps
   and takes 0.6s, so this waits out both. */
.splash__bulb {
  display: block;
  width: 2.6rem;
  height: 2.6rem;
  animation: splashBulb 0.7s var(--ease) backwards;
  animation-delay: calc(13 * var(--splash-step) + 0.45s);
}

.splash__bulb svg {
  width: 100%;
  height: 100%;
}

@keyframes splashBulb {
  from {
    opacity: 0;
    transform: translateY(6px) scale(0.85);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* A phone gets a slightly slower reading of the same animation — at desktop
   speed it goes by before you've looked at it. */
@media (max-width: 600px) {
  .splash {
    --splash-step: 0.1s;
  }

  .splash__mark {
    font-size: min(calc(2.2rem * var(--font-scale)), 9.5vw);
  }

  .splash__mark .letter {
    animation-duration: 0.75s;
  }
}

/* Less motion asked for: the wordmark and the bulb, without the flight. */
@media (prefers-reduced-motion: reduce) {
  .splash__mark .letter,
  .splash__bulb {
    animation: none;
  }
}

/* --------------------------------------------------------------------------
   LANDING PAGE
   Kept for the auth screen's .link-button, and so the feature cards can come
   back on a marketing page later — the landing markup itself is gone.
   -------------------------------------------------------------------------- */

.landing {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 3rem 1.5rem;
  text-align: center;
  position: relative;
}

/* Nothing on this page but the wordmark and one button, so the hero is the
   page — centred, with room around it rather than a stack of copy under it.
   The feature cards and the sign-in prompt that used to live here are gone;
   creating an account is asked for when the free trial runs out instead. */
.landing__hero {
  max-width: 700px;
  /* The button owns the first screenful; the cards start below the fold, so
     scrolling is what reveals them. */
  min-height: calc(100vh - var(--header-height) - 9rem);
  min-height: calc(100dvh - var(--header-height) - 9rem);
  justify-content: center;
  margin-bottom: 3rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
}

.landing__title {
  font-weight: 700;
  letter-spacing: -0.03em;
  display: inline-block;
  /* Glow behind the wordmark — the colour below is per-letter, so a shadow on
     the h1 is what ties the letters back into one object. Taken from the middle
     of the ramp so it follows whatever the tokens are set to. Kept faint on
     purpose — a matte wordmark doesn't want a glossy halo undoing the effect. */
  text-shadow: 0 0 20px
    hsl(calc((var(--logo-hue-start) + var(--logo-hue-end)) / 2)
        var(--logo-sat) var(--logo-light) / 0.15);
}

.landing__title .letter {
  display: inline-block;
  /* Each letter takes one step along the ramp. Done per letter rather than with
     background-clip: text because the fly-in below transforms every span, and a
     clipped gradient breaks on transformed children. --letter-index is already
     on each span for the animation delay, so the sweep rides along for free.
     The 13 is the last letter's index — the divisor that lands the final glyph
     exactly on --logo-hue-end. */
  color: hsl(
    calc(
      var(--logo-hue-start) +
      var(--letter-index) * (var(--logo-hue-end) - var(--logo-hue-start)) / 13
    )
    var(--logo-sat) var(--logo-light)
  );
  animation: letterFly 0.6s var(--ease) backwards;
  animation-delay: calc(var(--letter-index) * 0.08s);
}

.landing__tagline {
  font-size: calc(1.1rem * var(--font-scale));
  color: var(--text-muted);
  max-width: 500px;
  line-height: 1.6;
  animation: slideUpFade 0.6s var(--ease) 0.2s backwards;
}

.btn.landing__start {
  margin-top: 1.5rem;
  padding: 1.05rem 2.5rem;
  font-size: calc(1.15rem * var(--font-scale));
  border-radius: 999px;
  box-shadow: 0 6px 20px rgba(124, 58, 237, 0.25);
  animation: slideUpFade 0.6s var(--ease) 0.35s backwards;
}

.btn.landing__start:hover {
  box-shadow: 0 10px 28px rgba(124, 58, 237, 0.32);
  transform: translateY(-1px);
}

.landing__cta {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  align-items: center;
  margin-top: 1rem;
  width: 100%;
  animation: slideUpFade 0.6s var(--ease) 0.4s backwards;
}

.landing__signin,
.landing__guest {
  font-size: calc(0.95rem * var(--font-scale));
  color: var(--text-muted);
  margin: 0;
}

.link-button {
  color: var(--accent);
  background: none;
  border: none;
  cursor: pointer;
  text-decoration: none;
  font-weight: 500;
  transition: color 0.2s var(--ease);
}

.link-button:hover {
  color: var(--accent-hover);
  text-decoration: underline;
}

.landing__below {
  max-width: 1100px;
  width: 100%;
}

.landing__features {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 2rem;
  list-style: none;
  margin-bottom: 2rem;
}

/* The border is the button gradient, not a grey hairline. Two backgrounds
   do it: the fill is clipped to the padding box, the violet-to-gold ramp to
   the border box, so the border itself is what the gradient paints. The
   border has to be transparent for the second layer to show through it. */
.feature {
  padding: 2rem;
  border: 1.5px solid transparent;
  border-radius: var(--radius-large);
  background-image:
    linear-gradient(var(--surface), var(--surface)),
    linear-gradient(135deg, var(--accent), var(--accent-2));
  background-origin: border-box;
  background-clip: padding-box, border-box;
  text-align: left;
  transition: box-shadow 0.2s var(--ease), transform 0.2s var(--ease);
}

/* Hovering can't recolour a border that's already a gradient, so the card
   lifts instead. */
.feature:hover {
  box-shadow: var(--shadow-lifted);
  transform: translateY(-2px);
}

.feature h3 {
  color: var(--text);
  margin-bottom: 0.75rem;
}

.feature p {
  font-size: calc(0.95rem * var(--font-scale));
  color: var(--text-muted);
  margin: 0;
  line-height: 1.6;
}

.landing__note {
  text-align: center;
  font-size: calc(0.9rem * var(--font-scale));
  color: var(--text-subtle);
  margin: 0;
}


/* --------------------------------------------------------------------------
   PAGES
   Plain white, edge to edge. The moving starfield that used to sit behind
   every screen is gone, so nothing here has to cover it any more — content
   is simply centred on white.
   -------------------------------------------------------------------------- */

.screen {
  position: relative;
  background-color: var(--bg);
}

.landing {
  padding-left: 3rem;
  padding-right: 3rem;
}

.screen:not(.landing) {
  padding-left: 2rem;
  padding-right: 2rem;
}

/* One centred column on every screen — Account, My Files and the quiz used
   to stretch edge to edge, which read as unfinished next to the chat. */
.screen:not(.landing):not(#screen-notes) > * {
  width: 100%;
  max-width: 1000px;
  margin-left: auto;
  margin-right: auto;
}

/* Notes use the full width, so the whole screen is the page. */
#screen-notes {
  background-image: none;
  background-color: var(--bg);
}

/* --------------------------------------------------------------------------
   BUTTONS
   -------------------------------------------------------------------------- */

.btn {
  padding: 0.75rem 1.5rem;
  border-radius: var(--radius);
  font-weight: 500;
  transition: all 0.2s var(--ease);
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  text-decoration: none;
  white-space: nowrap;
}

.btn--primary {
  /* Teal into gold, same two hues as the aurora background — the two
     accent tokens together, so a palette swap keeps this in sync for free. */
  background-image: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: var(--on-accent);
}

.btn--primary:hover {
  filter: brightness(1.08);
}

.btn--primary:active {
  transform: scale(0.98);
}

.btn--secondary {
  background-color: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}

.btn--secondary:hover {
  background-color: var(--accent);
  color: var(--on-accent);
}

.btn--large {
  padding: 0.875rem 2rem;
  font-size: calc(1.05rem * var(--font-scale));
  min-width: 180px;
}

.btn--small {
  padding: 0.5rem 0.75rem;
  font-size: calc(0.875rem * var(--font-scale));
}

.btn--danger {
  background-color: var(--wrong);
  color: white;
}

.btn--danger:hover {
  opacity: 0.9;
}

/* --------------------------------------------------------------------------
   FORMS
   -------------------------------------------------------------------------- */

.form-group {
  margin-bottom: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

label {
  font-weight: 500;
  font-size: calc(0.95rem * var(--font-scale));
  color: var(--text);
}

.field {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.field input,
.field textarea {
  padding: 0.75rem;
  background-color: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  transition: all 0.2s var(--ease);
}

.field input::placeholder,
.field textarea::placeholder {
  color: var(--text-muted);
}

.field input:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* --------------------------------------------------------------------------
   CHAT SCREEN
   -------------------------------------------------------------------------- */

.chat-screen {
  flex-direction: column;
  /* .screen only sets min-height, so .chat-shell's "height: 100%" below had
     nothing real to resolve against — the shell was sizing to its own
     content instead of the viewport, which left the composer sitting right
     under the greeting instead of pinned to the bottom like a chat UI.
     Two declarations on purpose: 100vh is sized as if the mobile browser's
     address bar is hidden, so on load (bar visible) the real viewport is
     shorter and the composer's bottom edge — and the send button — ends up
     behind the bar. 100dvh tracks the actual visible area instead; the vh
     line stays first as a fallback for browsers that don't know dvh, which
     ignore the second declaration rather than break on it. */
  height: calc(100vh - var(--header-height));
  height: calc(100dvh - var(--header-height));
  padding: 0;
}

.chat-shell {
  display: flex;
  flex-direction: column;
  height: 100%;
  max-width: 800px;
  margin: 0 auto;
  width: 100%;
}

.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.chat-message {
  display: flex;
  gap: 1rem;
  animation: fadeIn 0.3s var(--ease);
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.chat-message--assistant {
  align-self: flex-start;
  max-width: 85%;
}

.chat-message--user {
  align-self: flex-end;
  max-width: 85%;
}

.chat-avatar {
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  background-color: var(--surface-alt);
  flex-shrink: 0;
}

.chat-avatar svg {
  width: 19px;
  height: 19px;
}

/* A flex item's default min-width is auto, not 0 — without this, a long
   nowrap choice label (see .chat-choice below) forces the whole bubble,
   and the chat column itself, wider than the viewport instead of wrapping. */
.chat-message__body {
  min-width: 0;
}

.chat-message p {
  padding: 0.75rem 1rem;
  border-radius: 12px;
  margin: 0;
  word-wrap: break-word;
}

.chat-message--assistant p {
  background-color: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
}

.chat-message--user p {
  background-color: var(--accent);
  color: var(--on-accent);
}

.chat-choices {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

/* Some choice labels ("Outline — terms & definitions") are long enough that
   .btn's usual nowrap would push them past the viewport on narrow screens. */
.chat-choice {
  white-space: normal;
  text-align: left;
  max-width: 100%;
}

/* --------------------------------------------------------------------------
   QUIZ READY CARD
   The one moment in the chat that gets a Notion/Linear-quiet treatment
   instead of the usual bubbles and filled buttons — a hairline border, no
   fill, tight spacing. Everywhere else in the conversation is untouched.
   -------------------------------------------------------------------------- */

.quiz-ready-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  max-width: 85%;
  padding: 0.875rem 1.125rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  align-self: flex-start;
}

.quiz-ready-card__title {
  font-size: calc(0.9rem * var(--font-scale));
  font-weight: 500;
  color: var(--text);
}

.quiz-ready-card__actions {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-shrink: 0;
}

.quiz-ready-card__start {
  padding: 0.4rem 0.9rem;
  border-radius: 6px;
  background-color: var(--accent);
  color: var(--on-accent);
  font-size: calc(0.85rem * var(--font-scale));
  font-weight: 500;
  white-space: nowrap;
  transition: opacity 0.15s var(--ease);
}

.quiz-ready-card__start:hover {
  opacity: 0.85;
}

.quiz-ready-card__save {
  font-size: calc(0.85rem * var(--font-scale));
  color: var(--text-muted);
  white-space: nowrap;
  transition: color 0.15s var(--ease);
}

.quiz-ready-card__save:hover {
  color: var(--text);
}

.quiz-ready-card__save:disabled {
  cursor: default;
}

/* .chat-note and .chat-error had no rule at all until now — every "Sign in
   to save this quiz", "When should I show you the answers?", and inline
   error in the chat (see ui.js's withThinking and the save-button handler)
   was rendering as plain, undifferentiated body text. */
.chat-note {
  font-size: calc(0.85rem * var(--font-scale));
  color: var(--text-muted);
}

.chat-error {
  font-size: calc(0.85rem * var(--font-scale));
  color: var(--wrong);
}

/* Worked homework answers put each step on its own line. */
.chat-message p.chat-reply {
  white-space: pre-wrap;
}

/* --------------------------------------------------------------------------
   ANSWER KEY — a pasted quiz with every answer filled in, shown in the chat
   before it's offered as a practice quiz.
   -------------------------------------------------------------------------- */

.answer-key {
  list-style: none;
  counter-reset: key;
  display: flex;
  flex-direction: column;
  margin: 0.5rem 0 0.75rem;
  background-color: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.answer-key__item {
  counter-increment: key;
  position: relative;
  padding: 0.75rem 1rem 0.75rem 2.6rem;
}

.answer-key__item + .answer-key__item {
  border-top: 1px solid var(--border);
}

.answer-key__item::before {
  content: counter(key) ".";
  position: absolute;
  left: 1rem;
  top: 0.75rem;
  font-weight: 600;
  color: var(--text-subtle);
  font-variant-numeric: tabular-nums;
}

/* The bubble styling on `.chat-message p` is for message text, not rows. */
.chat-message .answer-key p {
  padding: 0;
  border: none;
  border-radius: 0;
  background: none;
}

.chat-message .answer-key .answer-key__question {
  color: var(--text);
  white-space: pre-wrap;
}

.chat-message .answer-key .answer-key__answer {
  margin-top: 0.3rem;
  font-weight: 600;
  color: var(--correct);
}

.answer-key__tag {
  margin-left: 0.5rem;
  padding: 0.05rem 0.45rem;
  border-radius: 999px;
  background-color: var(--surface);
  border: 1px solid var(--border);
  font-size: calc(0.7rem * var(--font-scale));
  font-weight: 500;
  color: var(--text-muted);
  vertical-align: middle;
}

.chat-message .answer-key .answer-key__why {
  margin-top: 0.25rem;
  font-size: calc(0.85rem * var(--font-scale));
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   PICTURE ATTACHMENTS
   -------------------------------------------------------------------------- */

.chat-attachments {
  flex-basis: 100%;
  order: -1;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.chat-attachment {
  position: relative;
  width: 64px;
  height: 64px;
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  background-color: var(--surface-alt);
}

.chat-attachment img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.chat-attachment__remove {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background-color: rgba(20, 18, 26, 0.75);
  color: #fff;
  font-size: 0.9rem;
  line-height: 20px;
}

.chat-attach {
  flex-shrink: 0;
  align-self: flex-end;
  width: 2.75rem;
  height: 2.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text-muted);
  transition: color 0.15s var(--ease), border-color 0.15s var(--ease);
}

.chat-attach:hover {
  color: var(--accent);
  border-color: var(--accent);
}

.chat-message__images {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.4rem;
  margin-top: 0.4rem;
}

.chat-message__images img {
  max-width: 180px;
  max-height: 180px;
  border: 1px solid var(--border);
  border-radius: 10px;
}

.chat-composer {
  /* Clears the home indicator, so a swipe-up doesn't land on Send. */
  padding: 1.5rem 1.5rem calc(1.5rem + env(safe-area-inset-bottom));
  border-top: 1px solid var(--border);
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: flex-end;
  /* A flex row's default overflow is visible — without this, the one bug
     below (missing min-width: 0) wouldn't just clip the textarea's own
     text, it'd push the send button past the screen edge entirely. Kept
     as a safeguard even with that fixed, since a plain-text paste with an
     unbroken run of characters can still force width past the container. */
  overflow-x: hidden;
}

#chat-input {
  flex: 1;
  /* A <textarea>'s default intrinsic minimum width (a flex item's
     min-width defaults to auto, not 0) is real and browser-specific —
     Safari and Chrome don't agree on it. Past a certain paste length or
     just on a narrow screen, that minimum could exceed the space flex:1
     actually had to give it, so the box (and the text inside it) rendered
     wider than its container instead of wrapping — this is what was
     cutting words off and, since .chat-composer holds the send button
     too, could shove that off-screen along with it. */
  min-width: 0;
  padding: 0.75rem;
  background-color: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  overflow-wrap: break-word;
  word-wrap: break-word;
  /* Matches the 160px cap js/ui.js's auto-resize actually grows this to —
     they'd fallen out of sync (this said 120px), so text between 120 and
     160px tall would go through both a resize animation to a JS-set
     height and then get its bottom clipped/scrolled by this shorter cap. */
  max-height: 160px;
  resize: vertical;
  transition: all 0.2s var(--ease);
}

#chat-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.chat-controls {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* Filled clockwise from the top by setting stroke-dashoffset in JS — see
   ui.js's renderGuestUsageRing(). circumference (2 * PI * r, r=15.5) is
   ~97.39; that's the dasharray both circles share, computed once here
   rather than duplicated as a magic number in the JS that sets the offset. */
.guest-usage-ring {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
}

.guest-usage-ring svg {
  width: 100%;
  height: 100%;
  transform: rotate(-90deg); /* start the fill at 12 o'clock, not 3 o'clock */
}

.guest-usage-ring__track,
.guest-usage-ring__fill {
  fill: none;
  stroke-width: 3;
  stroke-dasharray: 97.39;
}

.guest-usage-ring__track {
  stroke: var(--border);
}

.guest-usage-ring__fill {
  stroke: var(--accent);
  stroke-linecap: round;
  transition: stroke-dashoffset 0.4s var(--ease), stroke 0.4s var(--ease);
}

/* Warns before the trial actually runs out, not just at the exact moment it
   does — ui.js adds this once spend crosses 85% of the guest cap. */
.guest-usage-ring__fill.is-low {
  stroke: var(--wrong);
}

.chat-send {
  padding: 0.75rem 1rem;
  background-image: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: var(--on-accent);
  border-radius: var(--radius);
  flex-shrink: 0;
  transition: all 0.2s var(--ease);
}

.chat-send:hover:not(:disabled) {
  filter: brightness(1.08);
}

.chat-send:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.chat-context {
  padding: 0.75rem 1.5rem;
  background-color: var(--surface);
  border-top: 1px solid var(--border);
  font-size: calc(0.9rem * var(--font-scale));
  color: var(--text-muted);
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* --------------------------------------------------------------------------
   QUIZ SCREEN
   -------------------------------------------------------------------------- */

.quiz-shell {
  display: flex;
  flex-direction: column;
  gap: 2rem;
  max-width: 700px;
  margin: 0 auto;
  padding: 2rem 1.5rem;
}

.quiz__bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem;
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-large);
}

.quiz__bar-inner {
  flex: 1;
}

.progress-bar {
  height: 4px;
  background-color: var(--surface-alt);
  border-radius: 2px;
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background-image: linear-gradient(90deg, var(--accent), var(--accent-2));
  transition: width 0.3s var(--ease);
}

.qcard {
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-large);
  padding: 2rem;
}

.qcard__number {
  font-size: calc(0.85rem * var(--font-scale));
  color: var(--text-muted);
  margin-bottom: 0.5rem;
}

.qcard__text {
  font-size: calc(1.1rem * var(--font-scale));
  line-height: 1.6;
  color: var(--text);
  margin-bottom: 1.5rem;
}

.answer {
  display: flex;
  align-items: center;
  gap: 0.875rem;
  width: 100%;
  padding: 0.875rem 1rem;
  margin-bottom: 0.75rem;
  text-align: left;
  background-color: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  cursor: pointer;
  transition: all 0.2s var(--ease);
}

/* The A/B/C/D badge — was a bare <span> with no layout of its own, so it
   rendered flush against the option text ("ALin-Manuel Miranda"). A
   fixed-size circle keeps every option's text starting at the same x
   position regardless of the letter, which is what actually reads as a
   properly laid-out quiz rather than a wall of run-on text. */
.answer__letter {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background-color: var(--surface);
  border: 1px solid var(--border);
  font-size: calc(0.8rem * var(--font-scale));
  font-weight: 600;
  color: var(--text-muted);
}

.answer__text {
  flex: 1;
  line-height: 1.5;
}

.answer:hover {
  border-color: var(--accent);
  background-color: var(--accent-soft);
}

.answer.is-chosen .answer__letter {
  border-color: var(--accent);
  background-color: var(--accent);
  color: var(--on-accent);
}

/* Graded state wins over merely-chosen — otherwise a wrong pick keeps its
   accent-purple badge sitting on top of the row's red "wrong" tint. */
.answer.is-correct .answer__letter {
  border-color: var(--correct);
  background-color: var(--correct);
  color: white;
}

.answer.is-wrong .answer__letter {
  border-color: var(--wrong);
  background-color: var(--wrong);
  color: white;
}

.answer:disabled {
  cursor: default;
}

.answer.is-correct {
  border-color: var(--correct);
  background-color: var(--correct-soft);
  color: var(--text);
}

.answer.is-wrong {
  border-color: var(--wrong);
  background-color: var(--wrong-soft);
  color: var(--text);
}

/* "Select all that apply", "Fill in the blank", "Match each item" — a small
   label above the question so the student knows how to answer it. */
.qcard__kind {
  font-size: calc(0.78rem * var(--font-scale));
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 0.35rem;
}

/* Select-all choices are checkboxes, not radio-style letters: square badges
   say "more than one" at a glance. */
.answers--multi .answer__letter {
  border-radius: 5px;
}

.qcard__text--blanks {
  line-height: 2.2;
}

.blank {
  display: inline-block;
  width: 9rem;
  max-width: 100%;
  margin: 0 0.3rem;
  padding: 0.15rem 0.5rem;
  border: none;
  border-bottom: 2px solid var(--accent);
  background-color: var(--surface-alt);
  border-radius: 4px 4px 0 0;
  font-size: inherit;
  font-weight: 500;
  color: var(--text);
}

.blank:focus {
  outline: none;
  background-color: var(--accent-soft);
}

.blank.is-correct { border-bottom-color: var(--correct); background-color: var(--correct-soft); }
.blank.is-wrong { border-bottom-color: var(--wrong); background-color: var(--wrong-soft); }

.match {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}

.match__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 0.75rem;
  background-color: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.match__prompt {
  line-height: 1.4;
}

.match__select {
  width: 100%;
  padding: 0.45rem 0.5rem;
  background-color: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
}

.match__select.is-correct { border-color: var(--correct); background-color: var(--correct-soft); }
.match__select.is-wrong { border-color: var(--wrong); background-color: var(--wrong-soft); }

@media (max-width: 600px) {
  .match__row {
    grid-template-columns: 1fr;
    gap: 0.4rem;
  }
}

.qcard__images {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}

.qcard__images img {
  max-width: 100%;
  max-height: 360px;
  border: 1px solid var(--border);
  border-radius: 8px;
}

.qcard__check {
  margin-bottom: 0.5rem;
}

.quiz__actions {
  display: flex;
  gap: 1rem;
  justify-content: center;
  margin-top: 2rem;
  padding-bottom: env(safe-area-inset-bottom);
}

/* --------------------------------------------------------------------------
   RESULTS SCREEN
   -------------------------------------------------------------------------- */

.results-shell {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  max-width: 600px;
  margin: 0 auto;
  padding: 3rem 1.5rem;
  text-align: center;
}

.score {
  font-size: calc(3rem * var(--font-scale));
  font-weight: 700;
  color: var(--accent);
  margin-bottom: 0.5rem;
}

.score-label {
  font-size: calc(1rem * var(--font-scale));
  color: var(--text-muted);
  margin-bottom: 2rem;
}

.review {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin-top: 2rem;
}

.review__item {
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-large);
  padding: 1.5rem;
  text-align: left;
}

.review__question {
  font-weight: 500;
  color: var(--text);
  margin-bottom: 0.75rem;
}

.review__yours {
  font-size: calc(0.9rem * var(--font-scale));
  color: var(--text-muted);
  margin-bottom: 0.5rem;
}

.review__correct {
  font-size: calc(0.9rem * var(--font-scale));
  color: var(--correct);
  margin-bottom: 0.5rem;
}

.review__why {
  font-size: calc(0.9rem * var(--font-scale));
  color: var(--text-muted);
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border);
}

/* --------------------------------------------------------------------------
   NOTES SCREEN
   -------------------------------------------------------------------------- */

/* Three columns: where a note lives (rail), which note (list), and the note
   itself. Below 900px they fold into one drawer over the page — see the
   media query at the end of this file. */
.notes-shell {
  display: flex;
  position: relative;
  width: 100%;
  flex: 1;
  min-height: 0;
  background-color: var(--bg);
}

.notes-browser {
  display: flex;
  flex-shrink: 0;
  min-height: 0;
  background-color: var(--bg);
  border-right: 1px solid var(--border);
}

/* COLUMN 1 — search, every note, folders. */
.notes-rail {
  width: 230px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.85rem 0.6rem;
  overflow-y: auto;
  background-color: var(--surface-alt);
  border-right: 1px solid var(--border);
}

.notes-rail__search {
  width: 100%;
  margin-bottom: 0.6rem;
  padding: 0.45rem 0.7rem;
  background-color: var(--bg);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text);
  font-size: calc(0.85rem * var(--font-scale));
}

.notes-rail__search:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.notes-rail__item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.45rem 0.6rem;
  border-radius: 8px;
  color: var(--text);
  font-size: calc(0.9rem * var(--font-scale));
  text-align: left;
  cursor: pointer;
  transition: background-color 0.15s var(--ease);
}

.notes-rail__item:hover {
  background-color: var(--bg);
}

.notes-rail__item.is-active {
  background-color: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}

.notes-rail__icon {
  display: flex;
  flex-shrink: 0;
  color: currentColor;
}

.notes-rail__label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.notes-rail__count {
  flex-shrink: 0;
  font-size: calc(0.78rem * var(--font-scale));
  color: var(--text-subtle);
  font-variant-numeric: tabular-nums;
}

.notes-rail__item.is-active .notes-rail__count {
  color: var(--accent);
}

.notes-rail__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 1.1rem 0.6rem 0.35rem;
  font-size: calc(0.78rem * var(--font-scale));
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-subtle);
}

.notes-rail__add {
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 5px;
  font-size: 1.1rem;
  line-height: 1;
  color: var(--text-muted);
}

.notes-rail__add:hover {
  background-color: var(--bg);
  color: var(--accent);
}

.notes-rail__folders {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.notes-rail__folder.is-drop-target {
  background-color: var(--accent-soft);
  box-shadow: inset 0 0 0 2px var(--accent);
}

/* COLUMN 2 — the notes in whatever the rail has selected. */
.notes-list {
  width: 290px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  min-height: 0;
  background-color: var(--bg);
}

.notes-list__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.85rem 0.9rem 0.5rem;
}

.notes-list__title {
  margin: 0;
  font-size: calc(1.35rem * var(--font-scale));
  font-weight: 700;
  letter-spacing: -0.02em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.notes-list__tabs {
  display: flex;
  gap: 1rem;
  padding: 0 0.9rem;
  border-bottom: 1px solid var(--border);
}

.notes-list__tab {
  padding: 0.35rem 0;
  border-bottom: 2px solid transparent;
  color: var(--text-muted);
  font-size: calc(0.88rem * var(--font-scale));
  font-weight: 500;
}

.notes-list__tab:hover {
  color: var(--text);
}

.notes-list__tab.is-active {
  color: var(--accent);
  border-bottom-color: var(--accent);
  font-weight: 600;
}

.notes-list__items {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 0.5rem;
}

.note-row {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.55rem 0.6rem;
  border-radius: 10px;
  cursor: pointer;
  transition: background-color 0.15s var(--ease);
}

.note-row__body {
  flex: 1;
  min-width: 0;
}

/* Shown on phones, where the list is the whole screen and has room for it. */
.note-row__thumb {
  display: none;
  flex-shrink: 0;
  width: 58px;
  height: 78px;
  padding: 5px;
  overflow: hidden;
  background-color: var(--bg);
  border: 1px solid var(--border);
  border-radius: 4px;
  box-shadow: 0 1px 3px rgba(20, 18, 26, 0.08);
}

.note-row__thumb p {
  margin: 0;
  font-size: 4px;
  line-height: 1.7;
  color: var(--text-muted);
  word-break: break-word;
}

.note-row__folder {
  display: inline-block;
  margin-top: 0.3rem;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: calc(0.72rem * var(--font-scale));
  font-weight: 600;
  color: var(--text);
  background-color: var(--surface-alt);
}

.note-row__folder[data-color="violet"] { background-color: rgba(124, 58, 237, 0.14); color: #5b21b6; }
.note-row__folder[data-color="gold"]   { background-color: rgba(251, 191, 36, 0.2);  color: #92400e; }
.note-row__folder[data-color="rose"]   { background-color: rgba(225, 29, 72, 0.12);  color: #9f1239; }
.note-row__folder[data-color="teal"]   { background-color: rgba(13, 148, 136, 0.14); color: #0f766e; }
.note-row__folder[data-color="blue"]   { background-color: rgba(37, 99, 235, 0.12);  color: #1e40af; }
.note-row__folder[data-color="green"]  { background-color: rgba(5, 150, 105, 0.14);  color: #047857; }

.note-row:hover {
  background-color: var(--surface-alt);
}

.note-row.is-active {
  background-color: var(--accent-soft);
}

.note-row__top {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.note-row__title {
  flex: 1;
  min-width: 0;
  font-size: calc(0.92rem * var(--font-scale));
  font-weight: 600;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.note-row__star {
  display: flex;
  flex-shrink: 0;
  color: var(--accent-2);
}

.note-row__meta {
  margin-top: 0.15rem;
  font-size: calc(0.8rem * var(--font-scale));
  color: var(--text-subtle);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The empty state each tab gets when it has nothing to show. */
.notes-empty {
  padding: 2.5rem 1.25rem;
  text-align: center;
}

.notes-empty__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3.5rem;
  height: 3.5rem;
  margin-bottom: 0.85rem;
  border-radius: 50%;
  background-color: var(--surface-alt);
  color: var(--text-subtle);
}

.notes-empty__icon svg {
  width: 26px;
  height: 26px;
}

.notes-empty h3 {
  font-size: calc(1.05rem * var(--font-scale));
  color: var(--accent);
}

.notes-empty p {
  font-size: calc(0.85rem * var(--font-scale));
  color: var(--text-muted);
  line-height: 1.5;
}

.notes-scrim {
  position: absolute;
  inset: 0;
  z-index: 40;
  background-color: rgba(20, 18, 26, 0.18);
}

/* --------------------------------------------------------------------------
   NOTES LIST — subjects and the notes inside them. Built by js/notes.js's
   renderTree(), which rebuilds the whole list on any change — cheap at this
   scale, so every row below only describes how to look.
   -------------------------------------------------------------------------- */

.notes-tree {
  display: flex;
  flex-direction: column;
}

.note-class + .note-class {
  margin-top: 0.15rem;
}

.note-class__header {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0.4rem;
  border-radius: 8px;
  cursor: pointer;
  transition: background-color 0.15s var(--ease);
}

.note-class__header:hover {
  background-color: var(--surface-alt);
}

.note-class__header.is-drop-target {
  background-color: var(--accent-soft);
  box-shadow: inset 0 0 0 2px var(--accent);
}

.note-tree__chevron {
  flex-shrink: 0;
  width: 1rem;
  height: 1rem;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-subtle);
  transition: transform 0.15s var(--ease);
}

.note-tree__chevron.is-expanded {
  transform: rotate(90deg);
}

.note-color-dot {
  flex-shrink: 0;
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
}

.note-class__name {
  flex: 1;
  min-width: 0;
  font-size: calc(0.9rem * var(--font-scale));
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.note-class__header--unfiled .note-class__name {
  font-weight: 500;
  color: var(--text-muted);
}

.note-class__count {
  flex-shrink: 0;
  font-size: calc(0.75rem * var(--font-scale));
  color: var(--text-subtle);
  font-variant-numeric: tabular-nums;
}

/* The +/⋯ row buttons only need to be reachable, not always visible, so a
   list of subjects doesn't look cluttered with controls. */
.note-tree__icon-btn {
  flex-shrink: 0;
  width: 1.4rem;
  height: 1.4rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 5px;
  color: var(--text-subtle);
  opacity: 0;
  transition: opacity 0.15s var(--ease), background-color 0.15s var(--ease), color 0.15s var(--ease);
}

.note-class__header:hover .note-tree__icon-btn,
.note-doc:hover .note-tree__icon-btn,
.note-tree__icon-btn:focus-visible {
  opacity: 1;
}

/* A touchscreen has no hover to reveal these on. */
@media (hover: none) {
  .note-tree__icon-btn {
    opacity: 1;
  }
}

.note-tree__icon-btn:hover {
  background-color: var(--border);
  color: var(--text);
}

.note-class__children {
  display: flex;
  flex-direction: column;
  padding-left: 1.4rem;
}

.note-doc {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.35rem;
  padding: 0.3rem 0.4rem;
  border-radius: 8px;
  cursor: pointer;
  color: var(--text-muted);
  transition: background-color 0.15s var(--ease), color 0.15s var(--ease);
}

.note-doc__menu {
  flex-shrink: 0;
}

.note-doc:hover {
  background-color: var(--surface-alt);
  color: var(--text);
}

.note-doc.is-active {
  background-color: var(--accent-soft);
  color: var(--text);
}

.note-doc__title {
  flex: 1;
  min-width: 0;
  font-size: calc(0.87rem * var(--font-scale));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.note-doc__date {
  font-size: calc(0.75rem * var(--font-scale));
  color: var(--text-subtle);
  flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   INLINE RENAME / ADD FORMS — appear exactly where the row they replace or
   follow would be, rather than in a separate modal.
   -------------------------------------------------------------------------- */

.note-tree__rename-input,
.note-tree__add-input {
  flex: 1;
  min-width: 0;
  background-color: var(--surface-alt);
  border: 1px solid var(--accent);
  border-radius: 6px;
  padding: 0.25rem 0.5rem;
  color: var(--text);
  font-size: calc(0.87rem * var(--font-scale));
}

.note-tree__rename-input:focus,
.note-tree__add-input:focus {
  outline: none;
}

.note-tree__add-class-form {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 0.9rem;
  margin-bottom: 0.75rem;
  background-color: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.note-tree__add-actions {
  display: flex;
  gap: 0.5rem;
}

.note-color-swatches {
  display: flex;
  gap: 0.5rem;
}

.note-color-swatch {
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 50%;
  border: 2px solid transparent;
  cursor: pointer;
  transition: transform 0.1s var(--ease), border-color 0.1s var(--ease);
}

.note-color-swatch:hover {
  transform: scale(1.12);
}

.note-color-swatch.is-selected {
  border-color: var(--text);
}

.note-color-dot[data-color="violet"],
.note-color-swatch[data-color="violet"] { background-color: #8b5cf6; }
.note-color-dot[data-color="gold"],
.note-color-swatch[data-color="gold"] { background-color: #f59e0b; }
.note-color-dot[data-color="rose"],
.note-color-swatch[data-color="rose"] { background-color: #f43f5e; }
.note-color-dot[data-color="teal"],
.note-color-swatch[data-color="teal"] { background-color: #14b8a6; }
.note-color-dot[data-color="blue"],
.note-color-swatch[data-color="blue"] { background-color: #3b82f6; }
.note-color-dot[data-color="green"],
.note-color-swatch[data-color="green"] { background-color: #22c55e; }

/* --------------------------------------------------------------------------
   POPOVER MENU — the class/tab "⋯" menu and a note's right-click "Move
   to…" menu. Positioned in JS (fixed, near the click); this just styles it.
   -------------------------------------------------------------------------- */

/* The ⋯ on a My Files card. The menu it opens is .note-menu, shared with
   the one in Notes. */
.card-menu-btn {
  width: 2rem;
  height: 2rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  color: var(--text-muted);
  transition: background-color 0.15s var(--ease), color 0.15s var(--ease);
}

.card-menu-btn:hover {
  background-color: var(--surface-alt);
  color: var(--text);
}

.note-menu {
  position: fixed;
  z-index: 200;
  min-width: 200px;
  max-width: 280px;
  max-height: 60vh;
  overflow-y: auto;
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  padding: 0.35rem;
  display: flex;
  flex-direction: column;
}

.note-menu__heading {
  padding: 0.4rem 0.6rem 0.3rem;
  font-size: calc(0.75rem * var(--font-scale));
  font-weight: 600;
  color: var(--text-subtle);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.note-menu__item {
  text-align: left;
  padding: 0.45rem 0.6rem;
  border-radius: 6px;
  font-size: calc(0.87rem * var(--font-scale));
  color: var(--text);
}

.note-menu__item:hover:not(:disabled) {
  background-color: var(--accent-soft);
}

.note-menu__item:disabled {
  color: var(--text-subtle);
  cursor: default;
}

.note-menu__item--danger {
  color: var(--wrong);
}

.note-menu__sep {
  height: 1px;
  margin: 0.3rem 0.4rem;
  background-color: var(--border);
}

/* --------------------------------------------------------------------------
   CHART INSERT MODAL — the toolbar's "Chart" button. A basic version: type,
   a manually typed table of label/value rows, Insert renders it once and
   drops it into the note as an image (see js/notes.js's insertChart).
   -------------------------------------------------------------------------- */

.chart-modal {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: rgba(20, 15, 30, 0.45);
  padding: 1.5rem;
}

.chart-modal__dialog {
  width: 100%;
  max-width: 420px;
  max-height: 85vh;
  overflow-y: auto;
  background-color: #ffffff;
  border-radius: var(--radius-large);
  padding: 1.5rem;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
}

.chart-modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1rem;
}

.chart-modal__header h3 {
  margin: 0;
  font-size: calc(1.05rem * var(--font-scale));
}

.chart-modal__close {
  width: 1.75rem;
  height: 1.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
  font-size: 1.2rem;
  color: var(--text-muted);
}

.chart-modal__close:hover {
  background-color: var(--surface-alt);
  color: var(--text);
}

.chart-modal__field {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1rem;
}

.chart-modal__field label {
  font-size: calc(0.85rem * var(--font-scale));
  color: var(--text-muted);
}

.chart-modal__field select {
  flex: 1;
  padding: 0.4rem 0.6rem;
  border-radius: 6px;
  border: 1px solid var(--border);
  background-color: var(--surface-alt);
  color: var(--text);
}

.chart-modal__rows {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}

.chart-modal__row {
  display: flex;
  gap: 0.5rem;
  align-items: center;
}

.chart-modal__row input {
  padding: 0.45rem 0.6rem;
  border-radius: 6px;
  border: 1px solid var(--border);
  background-color: var(--surface-alt);
  color: var(--text);
  font-size: calc(0.9rem * var(--font-scale));
}

.chart-modal__row input[type="text"] {
  flex: 3;
  min-width: 0;
}

.chart-modal__row input[type="number"] {
  flex: 2;
  min-width: 0;
}

.chart-modal__row-remove {
  flex-shrink: 0;
  width: 1.75rem;
  height: 1.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
  color: var(--text-subtle);
}

.chart-modal__row-remove:hover {
  background-color: var(--surface-alt);
  color: var(--wrong);
}

.chart-modal__add-row {
  font-size: calc(0.85rem * var(--font-scale));
  color: var(--accent);
  font-weight: 500;
  padding: 0.3rem 0;
}

.chart-modal__error {
  font-size: calc(0.82rem * var(--font-scale));
  color: var(--wrong);
  margin: 0.5rem 0 0;
}

.chart-modal__actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
  margin-top: 1.25rem;
}

/* The toolbar on top, the page filling the rest, a quiet status line under
   it. */
.notes-editor-column {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
}

/* Not a card: the page is the screen. The writing column is capped so lines
   stay a readable length, with generous margins either side. */
.notes-page-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
  padding: 0.75rem 1.25rem 0.5rem;
}

/* Only needed once the columns fold into a drawer; on a wide screen the
   list is already on screen. */
.notes-page-head__drawer {
  display: none;
  align-items: center;
  gap: 0.25rem;
  height: 2.2rem;
  padding: 0 0.7rem 0 0.5rem;
  border-radius: 999px;
  background-color: var(--accent-soft);
  color: var(--accent);
  font-size: calc(0.9rem * var(--font-scale));
  font-weight: 600;
}

.notes-page-head__drawer:active {
  transform: scale(0.97);
}

.notes-page-head__title {
  margin: 0;
  font-size: calc(1.3rem * var(--font-scale));
  font-weight: 700;
  letter-spacing: -0.02em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.notes-editor {
  flex: 1;
  min-height: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  padding: 1.5rem max(1.5rem, calc((100% - 820px) / 2)) 2rem;
  background-color: var(--surface-alt);
}

/* Shown until a note is picked — the tab opens on the list now. */
.notes-editor__empty {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  text-align: center;
  color: var(--text-muted);
}

.notes-editor__empty[hidden] {
  display: none;
}

/* The paper: the typed text, with the pen layer on top of it.

   Pages behave the way they do in a handwriting app — a fixed height each,
   a hairline where one ends and the next begins, and always one empty page
   waiting after the last one you've written on. There are no separate page
   elements: the whole thing is one sheet whose height is a multiple of the
   page height, with the dividers painted on by a repeating gradient. That
   keeps the text flowing normally (a paragraph can straddle a break, as it
   does in the reference app) and keeps the ink canvas a single layer.

   --page-height is set by js/notes.js from the paper's own width, so a page
   keeps US Letter proportions whatever the screen. */
.notes-page {
  position: relative;
  --page-height: 100%;
  min-height: 100%;
  padding: 3rem;
  background-color: var(--bg);
  background-image: repeating-linear-gradient(
    to bottom,
    transparent 0,
    transparent calc(var(--page-height) - 1px),
    var(--border) calc(var(--page-height) - 1px),
    var(--border) var(--page-height)
  );
  border: 1px solid var(--border);
  border-radius: 6px;
  box-shadow: var(--shadow);
}

.notes-ink {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  /* Type mode: the canvas is a picture, and every click goes through it to
     the text underneath. */
  pointer-events: none;
}

/* Draw mode. touch-action: none is what stops Safari from turning an Apple
   Pencil stroke into a page scroll; a finger still scrolls, because
   js/notes.js turns finger drags back into scrolling by hand. */
.notes-page.is-drawing .notes-ink {
  pointer-events: auto;
  touch-action: none;
  cursor: crosshair;
}

/* Dragging a pencil across typed text would otherwise start an iPadOS text
   selection — the blue highlight, the grab handles and the magnifier — all
   fighting the stroke. */
.notes-page.is-drawing {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

.notes-page.is-drawing .ql-editor {
  caret-color: transparent;
}

/* --------------------------------------------------------------------------
   TOOLBAR — a Google-Docs-style bar above the page, built from Quill's own
   format controls (the ql-* elements) plus undo/redo (Quill's history
   module has no toolbar button of its own, so these two are plain buttons
   wired directly to quill.history in js/notes.js rather than ql-* controls).
   Quill injects its icons into the ql-* elements itself; this only handles
   layout and color, not the icons' own artwork.
   -------------------------------------------------------------------------- */

/* Modeled on Google Docs / Microsoft 365's toolbar: a light gray bar (not
   the app's usual translucent glass), bordered dropdown "chips" instead of
   bare text, and square icon buttons that pick up a light gray fill on
   hover — the office-suite look, not this app's own accent-colored one. */
.notes-toolbar.ql-toolbar.ql-snow {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.2rem;
  flex-shrink: 0;
  width: 100%;
  padding: 0.35rem 0.75rem;
  border: none;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  background-color: var(--bg);
}

/* Opens the drawer, and names the note that's open. */
.notes-toolbar.ql-snow .notes-toolbar__drawer {
  width: auto;
  max-width: 16rem;
  height: 1.85rem;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0 0.6rem 0 0.45rem;
  color: var(--text);
}

.notes-toolbar__current {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: calc(0.85rem * var(--font-scale));
  font-weight: 600;
}

.notes-toolbar__more-wrap {
  position: relative;
}

.notes-toolbar__more {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 0.2rem;
  padding: 0.35rem;
  background-color: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}

.notes-toolbar__more[hidden] {
  display: none !important;
}

.notes-toolbar__modes,
.notes-toolbar__group {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.2rem;
}

.notes-toolbar__modes {
  padding: 0.15rem;
  border-radius: 999px;
  background-color: var(--surface-alt);
}

/* Pen, highlighter, eraser and the two mode buttons all share one shape. */
.notes-toolbar.ql-snow .notes-tool {
  width: 1.95rem;
  height: 1.95rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  color: var(--text-muted);
}

.notes-toolbar.ql-snow .notes-tool.is-active {
  background-color: var(--bg);
  color: var(--accent);
  box-shadow: 0 1px 3px rgba(20, 18, 26, 0.12);
}

.notes-palette-wrap {
  position: relative;
  display: flex;
}

/* The button is the current colour. The swatches used to sit inline, which
   on a phone put them off the end of a scrolling toolbar — present, but
   invisible, so there was no way to find them. */
.notes-color__dot {
  width: 1.15rem;
  height: 1.15rem;
  border-radius: 50%;
  background-color: #14121a;
  box-shadow: inset 0 0 0 1px rgba(20, 18, 26, 0.2);
}

/* Fixed, not absolute, and placed by js/notes.js. The toolbar scrolls
   sideways, and an overflow container clips both axes — inside it this
   popover would be cut off exactly as the account menu once was. */
.notes-palette {
  position: fixed;
  z-index: 140;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 0.7rem;
  border-radius: 12px;
  background-color: var(--bg);
  border: 1px solid var(--border);
  box-shadow: 0 10px 28px rgba(20, 18, 26, 0.16);
}

.notes-palette[hidden] {
  display: none;
}

.notes-swatches {
  display: grid;
  grid-template-columns: repeat(3, auto);
  gap: 0.5rem;
}

.notes-swatch {
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 50%;
  border: 2px solid transparent;
  box-shadow: inset 0 0 0 1px rgba(20, 18, 26, 0.15);
  transition: transform 0.15s var(--ease);
}

.notes-swatch:hover {
  transform: scale(1.15);
}

.notes-swatch.is-selected {
  border-color: var(--accent);
  transform: scale(1.15);
}

.notes-size {
  width: 5.5rem;
  accent-color: var(--accent);
}

.notes-toolbar__divider {
  width: 1px;
  height: 1.1rem;
  align-self: center;
  margin: 0 0.25rem;
  background-color: var(--border);
}

/* File / Insert — plain-text controls living as the first two items in the
   toolbar itself (not a separate row above it), each opening the app's
   existing .note-menu popover (see openMenu in js/notes.js) anchored under
   the button. Sized to the same height as every other toolbar control so
   they read as part of the one bar, not a different kind of thing bolted
   onto it. */
.notes-toolbar.ql-snow .notes-toolbar__menu {
  width: auto;
  height: 1.85rem;
  padding: 0 0.65rem;
  border-radius: 6px;
  font-size: calc(0.85rem * var(--font-scale));
  font-weight: 500;
  color: var(--text);
}

.notes-toolbar.ql-snow .ql-picker {
  height: 1.85rem;
  flex-shrink: 0;
  color: var(--text);
}

.notes-toolbar.ql-snow button {
  width: 1.85rem;
  height: 1.85rem;
  flex-shrink: 0;
  border-radius: 6px;
}

.notes-toolbar.ql-snow .ql-picker-label {
  height: 1.85rem;
  display: flex;
  align-items: center;
  flex-shrink: 0;
  white-space: nowrap;
  gap: 0.4rem;
  padding: 0 0.55rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background-color: #ffffff;
  font-size: calc(0.85rem * var(--font-scale));
  font-weight: 500;
  color: var(--text);
}

.notes-toolbar.ql-snow button:hover {
  background-color: rgba(0, 0, 0, 0.06);
}

/* Undo/redo are the one pair of toolbar controls that can genuinely have
   nothing to do — offering a click that would do nothing (grayed out,
   hover-inert) is exactly the "this control is currently unavailable"
   affordance Word/Docs use rather than leaving them looking clickable at
   all times. */
.notes-toolbar.ql-snow button:disabled {
  opacity: 0.35;
  cursor: default;
  pointer-events: none;
}

/* A toggled-on format (bold/italic/underline/list while the cursor sits in
   one) gets a light accent fill of its own — distinct from a plain hover —
   the same "this is currently active" language Docs/Word use, rather than
   only recoloring the icon's stroke. */
.notes-toolbar.ql-snow button.ql-active {
  background-color: var(--accent-soft);
}

/* Icon pickers (align, text colour, highlight) are only ~28px wide; the text
   pickers' padding above squeezed their icons down to a few pixels. */
.notes-toolbar.ql-snow .ql-icon-picker .ql-picker-label,
.notes-toolbar.ql-snow .ql-color-picker .ql-picker-label {
  padding: 0 3px;
  justify-content: center;
}

.notes-toolbar.ql-snow .ql-icon-picker .ql-picker-label svg,
.notes-toolbar.ql-snow .ql-color-picker .ql-picker-label svg {
  width: 18px;
  height: 18px;
}

.notes-toolbar.ql-snow .ql-picker-label:hover,
.notes-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-label {
  border-color: rgba(0, 0, 0, 0.3);
}

.notes-toolbar.ql-snow button.ql-active .ql-stroke {
  stroke: var(--accent);
}

.notes-toolbar.ql-snow button.ql-active .ql-fill {
  fill: var(--accent);
}

/* The clean single-chevron swapped in for font/size/lineheight (see the
   icon-swap loop in js/notes.js) flips to point up while its list is open —
   the same affordance real Docs/Word picker carets give, which the
   two-stacked-triangle glyph Quill ships by default never bothered with. */
.notes-toolbar.ql-snow .ql-font .ql-picker-label svg,
.notes-toolbar.ql-snow .ql-size .ql-picker-label svg,
.notes-toolbar.ql-snow .ql-lineheight .ql-picker-label svg {
  position: static;
  width: 11px;
  margin-top: 0;
  transition: transform 0.15s ease;
}

.notes-toolbar.ql-snow .ql-font.ql-expanded .ql-picker-label svg,
.notes-toolbar.ql-snow .ql-size.ql-expanded .ql-picker-label svg,
.notes-toolbar.ql-snow .ql-lineheight.ql-expanded .ql-picker-label svg {
  transform: rotate(180deg);
}

/* Quill's own quill.snow.css only wires up content: attr(data-label) for
   the picker classes it ships (ql-font/ql-size) — a class it's never heard
   of, like our own ql-lineheight, gets no label text at all without this. */
.notes-toolbar.ql-snow .ql-picker.ql-lineheight .ql-picker-label::before,
.notes-toolbar.ql-snow .ql-picker.ql-lineheight .ql-picker-item::before {
  content: attr(data-label);
}

.notes-toolbar.ql-snow .ql-picker-options {
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.14);
  padding: 0.35rem;
  background-color: #ffffff;
}

.notes-toolbar.ql-snow .ql-picker-item {
  border-radius: 6px;
  padding: 0.35rem 0.65rem;
}

/* ql-align is an "icon picker" — Quill gives its dropdown items a fixed
   24x24 box (unlike the text pickers above, which size to their label
   text), and the generous text-picker padding above was eating almost all
   of that box, squeezing each option's SVG down to ~3px — invisible, and
   indistinguishable from its three siblings. A tighter, icon-picker-only
   padding is what actually leaves room for the icon to render at a size
   you can tell apart from the others. */
.notes-toolbar.ql-snow .ql-icon-picker .ql-picker-item {
  padding: 3px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.notes-toolbar.ql-snow .ql-icon-picker .ql-picker-item svg {
  width: 16px;
  height: 16px;
}

.notes-toolbar.ql-snow .ql-picker-item:hover {
  background-color: var(--accent-soft);
  color: var(--accent);
}

/* Quill mounts its own .ql-container.ql-snow classes directly onto this
   same element (#note-body-editor) rather than wrapping it in a new one —
   so this doubles as both the flex slot the page gives it AND an override
   of Quill's own container styling (the border, in particular; the page
   itself already has one). Only .ql-editor below is an actual child.
   The border reset needs the #id selector below — Quill's own rule is
   .ql-snow.ql-container (two classes), which outranks a single class like
   .notes-editor__quill regardless of source order. */
.notes-editor__quill {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  font-size: calc(1rem * var(--font-scale));
}

#note-body-editor.ql-container {
  border: none;
}

.notes-editor__quill .ql-editor {
  padding: 0.5rem 0;
  color: var(--text);
  line-height: 1.9;
}

.notes-editor__quill .ql-editor.ql-blank::before {
  color: var(--text-subtle);
  font-style: normal;
  left: 0;
}

/* Quill has no table blot of its own — a table inserted via the toolbar
   (see js/notes.js's insertTable) is plain HTML dropped into the doc, so it
   needs its own borders here; without this it would render borderless. */
.notes-editor__quill .ql-editor table {
  width: 100%;
  border-collapse: collapse;
  margin: 0.75rem 0;
}

.notes-editor__quill .ql-editor table td {
  border: 1px solid var(--border);
  padding: 0.5rem 0.6rem;
  min-width: 2rem;
  vertical-align: top;
}

/* Like Word's own status bar — a slim strip below the page, not printed on
   the white page itself. Word count on the left, save status on the right,
   same two-span layout it always had. */
.notes-status-bar {
  padding-bottom: calc(0.6rem + env(safe-area-inset-bottom));
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  flex-shrink: 0;
  width: 100%;
  max-width: 800px;
  margin: 0 auto;
  padding: 0.35rem 1.5rem 0.6rem;
  font-size: calc(0.78rem * var(--font-scale));
  color: var(--text-subtle);
  min-height: 1.2em;
}

@media (max-width: 900px) {
  /* Under 900px there isn't room for rail + list + page, so the first two
     slide in together over the page. */
  .notes-browser {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: 41;
    box-shadow: 8px 0 32px rgba(0, 0, 0, 0.12);
    transform: translateX(-105%);
    visibility: hidden;
    transition: transform 0.22s var(--ease), visibility 0s linear 0.22s;
  }

  .notes-browser.is-open {
    transform: none;
    visibility: visible;
    transition: transform 0.22s var(--ease), visibility 0s;
  }

  .notes-rail {
    width: 40vw;
    max-width: 200px;
  }

  .notes-list {
    width: 55vw;
    max-width: 280px;
  }

  .notes-page-head__drawer {
    display: flex;
  }

  .notes-editor {
    padding: 0.75rem;
  }

  .notes-page {
    padding: 1.75rem 1.25rem;
  }
}

/* --------------------------------------------------------------------------
   FILES SCREEN
   -------------------------------------------------------------------------- */

.files-section {
  margin-bottom: 2rem;
}

.files-section__title {
  /* Flush left, matching the "My Files" heading and subtitle above it —
     .file-list below still centers itself in its own 600px column (existing
     behavior, unchanged), so there's a small indent between a heading and
     its list, but that reads better than the heading itself appearing to
     float off-center relative to the page title above it. */
  font-size: calc(1.1rem * var(--font-scale));
  font-weight: 600;
  color: var(--text);
}

.file-list {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  list-style: none;
  max-width: 600px;
  margin: 1rem auto 0;
  padding: 0 1.5rem;
}

/* --------------------------------------------------------------------------
   STUDY GUIDE CONTENT
   Shared between the chat presenter (js/ui.js's presentStudyGuide) and a
   saved guide's "View" toggle in My Files — one rendering, two places it
   shows up.
   -------------------------------------------------------------------------- */

.study-guide {
  margin: 0.75rem 0;
}

.study-guide__heading {
  font-size: calc(0.95rem * var(--font-scale));
  font-weight: 600;
  color: var(--text);
  margin-top: 1rem;
}

.study-guide__heading:first-child {
  margin-top: 0;
}

.study-guide__list {
  list-style: none;
  margin: 0.4rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}

.study-guide__list li {
  font-size: calc(0.9rem * var(--font-scale));
  color: var(--text-muted);
  line-height: 1.5;
  padding-left: 0.9rem;
  position: relative;
}

.study-guide__list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.6em;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background-color: var(--text-subtle);
}

/* The inline "View" expansion inside a My Files card — a hairline separates
   it from the card's title/meta/actions above. */
.study-guide--card {
  width: 100%;
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border);
}

.file-card {
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-large);
  padding: 1.5rem;
  display: flex;
  /* Built for exactly two children (info, actions) side by side. A study
     guide or saved answer's "View" toggle appends a third — .study-guide--
     card's own width:100% is what sends it onto a line of its own instead
     of squeezing in next to the buttons. */
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  transition: all 0.2s var(--ease);
}

.file-card:hover {
  border-color: var(--accent);
  box-shadow: var(--shadow);
}

.file-card__info {
  flex: 1;
}

.file-card__title {
  font-weight: 500;
  color: var(--text);
  margin-bottom: 0.25rem;
}

.file-card__meta {
  font-size: calc(0.85rem * var(--font-scale));
  color: var(--text-muted);
}

.file-card__actions {
  display: flex;
  gap: 0.5rem;
}

/* --------------------------------------------------------------------------
   AUTH SCREENS
   -------------------------------------------------------------------------- */

.auth-shell {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: calc(100vh - var(--header-height));
  padding: 2rem 1.5rem;
}

/* Auth and Results are the two screens marked .screen--centered in the
   markup; .screen already sets flex-direction: column (see MAIN CONTENT
   above), so centering just needs these two axes. There was previously no
   rule for this class at all — both screens rendered flush left. */
.screen--centered {
  align-items: center;
  justify-content: center;
  text-align: center;
  padding-top: 3rem;
  padding-bottom: 3rem;
}

/* Same gap: used on .subtitle, .auth-switch, .auth-message, and
   .results__actions below — all present in the markup with no rule behind
   them, so this section fills in several missing pieces at once rather than
   one broken class in isolation. */
.subtitle {
  color: var(--text-muted);
  font-size: calc(1rem * var(--font-scale));
}

.auth-switch {
  font-size: calc(0.9rem * var(--font-scale));
  color: var(--text-muted);
}

.auth-message {
  padding: 0.75rem;
  border-radius: var(--radius);
  font-size: calc(0.9rem * var(--font-scale));
  margin-bottom: 0.5rem;
}

.auth-message--error {
  background-color: var(--wrong-soft);
  color: var(--wrong);
}

.auth-message--info {
  background-color: var(--correct-soft);
  color: var(--correct);
}

.results__actions {
  display: flex;
  gap: 1rem;
  justify-content: center;
  margin: 1.5rem 0;
}

.auth-card {
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-large);
  padding: 2.5rem;
  max-width: 400px;
  width: 100%;
  /* .screen--centered sets text-align: center on the whole screen so the
     card itself sits in the middle of the page; without this the labels and
     typed text inside the form would inherit that and center too. */
  text-align: left;
}

.auth-card h2 {
  margin-bottom: 1.5rem;
  text-align: center;
}

.auth-form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.form-error {
  background-color: var(--wrong-soft);
  color: var(--wrong);
  padding: 0.75rem;
  border-radius: var(--radius);
  font-size: calc(0.9rem * var(--font-scale));
}

.form-success {
  background-color: var(--correct-soft);
  color: var(--correct);
  padding: 0.75rem;
  border-radius: var(--radius);
  font-size: calc(0.9rem * var(--font-scale));
}

/* --------------------------------------------------------------------------
   ACCOUNT SCREEN
   -------------------------------------------------------------------------- */

.account-shell {
  max-width: 600px;
  margin: 2rem auto;
  padding: 0 1.5rem;
}

.account-section {
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-large);
  padding: 2rem;
  margin-bottom: 2rem;
}

.account-section h3 {
  margin-bottom: 1.5rem;
}

/* Generic glass panel — used on the Files and Account screens (guest/empty/
   signed-in states). Same treatment as .account-section and its siblings;
   there was previously no rule for it at all, so these panels rendered with
   no background, border, or padding. */
.card {
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-large);
  padding: 2rem;
  margin-bottom: 1.5rem;
}

.card h3 {
  margin-bottom: 0.75rem;
}

.text-muted {
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   RESPONSIVE
   -------------------------------------------------------------------------- */

@media (max-width: 600px) {
  .menu {
    padding: 0 1rem;
    gap: 0.5rem;
    font-size: calc(0.85rem * var(--font-scale));
  }

  /* No horizontal scroll strip here. It dates from when the header also
     carried the wordmark and the text-size buttons and nothing fit; those
     have since moved or gone, and the row fits on a 390px phone. It had to
     go regardless: overflow-x clips the OTHER axis too, so the account
     menu's dropdown was being cut off at the header's own 56px height. */
  .menu__item,
  .menu__sizer {
    flex-shrink: 0;
  }

  .menu__item {
    white-space: nowrap;
  }

  .menu__brand {
    font-size: calc(0.95rem * var(--font-scale));
  }

  .menu__item {
    padding: 0.4rem 0.75rem;
  }

  .menu__sizer {
    margin-left: 0.5rem;
  }

  h1 {
    font-size: calc(1.75rem * var(--font-scale));
  }

  h2 {
    font-size: calc(1.375rem * var(--font-scale));
  }

  .landing__hero {
    margin-bottom: 2rem;
  }

  .landing__tagline {
    font-size: calc(1rem * var(--font-scale));
  }

  .landing__features {
    grid-template-columns: 1fr;
  }


  /* The More button sits near the left edge once the toolbar wraps, so the
     panel opens rightwards and wraps instead of running off-screen. */
  .notes-toolbar__more {
    left: 0;
    right: auto;
    flex-wrap: wrap;
    width: max-content;
    max-width: 70vw;
  }

  /* Three buttons beside the message box left it a sliver wide, so on a
     phone the box takes the whole row and the buttons sit underneath. */
  .chat-composer {
    padding: 0.75rem 0;
    gap: 0.5rem;
  }

  #chat-input {
    flex-basis: 100%;
  }

  .chat-attach {
    width: 2.4rem;
    height: 2.4rem;
  }

  .chat-controls {
    margin-left: auto;
  }

  .chat-shell {
    max-width: 100%;
  }

  .chat-message--assistant,
  .chat-message--user {
    max-width: 95%;
  }

  .quiz-ready-card {
    max-width: 95%;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.75rem;
  }

  .auth-card {
    padding: 1.5rem;
  }

  .quiz-shell {
    padding: 1rem 1.5rem;
  }

  .qcard {
    padding: 1.5rem;
  }
  /* --- HEADER ---------------------------------------------------------
     Brand + three pills + the account menu is more than 390px of phone can
     hold, and "Sign in" was being pushed off the right edge. The wordmark
     goes (it's the one thing repeated on the page itself), and everything
     else tightens up. */
  .menu {
    padding: 0 0.6rem;
    gap: 0.3rem;
  }

  .menu__brand {
    display: none;
  }

  .menu__item {
    padding: 0.4rem 0.7rem;
    font-size: calc(0.85rem * var(--font-scale));
  }

  .menu__account {
    max-width: 7.5rem;
  }

  @media (max-width: 360px) {
    .menu {
      padding: 0 0.4rem;
      gap: 0.2rem;
    }

    .menu__item {
      padding: 0.35rem 0.55rem;
      font-size: calc(0.8rem * var(--font-scale));
    }
  }

  /* The nav sits left now that the brand is gone; the account menu keeps
     its own corner. */
  .menu__item[data-screen="notes"] {
    margin-left: 0;
  }

  /* The paper scrolls inside its own column, not by scrolling the whole
     window — otherwise the floating toolbar, which is anchored to the
     bottom of that column, ends up far below the screen. dvh tracks the
     visible area as Safari's address bar comes and goes. */
  #screen-notes {
    padding-left: 0;
    padding-right: 0;
    min-height: 0;
    height: calc(100vh - var(--header-height) - env(safe-area-inset-top));
    height: calc(100dvh - var(--header-height) - env(safe-area-inset-top));
    overflow: hidden;
  }

  .notes-shell,
  .notes-editor-column {
    min-height: 0;
  }

  .notes-editor {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }

  /* --- NOTES ----------------------------------------------------------
     Notability's phone shape: one thing at a time. The browser covers the
     whole screen, its folders become a scrolling row of chips above the
     list, and picking a note hands the screen to the page. */
  .notes-browser {
    width: 100%;
    max-width: 100%;
    flex-direction: column;
  }

  .notes-rail {
    width: 100%;
    max-width: none;
    flex-direction: row;
    align-items: center;
    flex-wrap: nowrap;
    gap: 0.4rem;
    overflow-x: auto;
    overflow-y: hidden;
    padding: 0.6rem 0.75rem;
    border-right: none;
    border-bottom: 1px solid var(--border);
    /* Stops a horizontal swipe on the chips from rubber-banding the page. */
    overscroll-behavior-x: contain;
  }

  .notes-rail__search {
    order: -1;
    width: 100%;
    margin-bottom: 0;
  }

  /* Each folder is a chip on one line, so the search box wraps above them. */
  .notes-rail {
    flex-wrap: wrap;
  }

  .notes-rail__folders {
    flex-direction: row;
    flex-wrap: nowrap;
    gap: 0.4rem;
    overflow-x: auto;
    padding-bottom: 0.15rem;
  }

  .notes-rail__item {
    width: auto;
    flex-shrink: 0;
    padding: 0.35rem 0.7rem;
    border-radius: 999px;
    background-color: var(--bg);
    border: 1px solid var(--border);
    font-size: calc(0.85rem * var(--font-scale));
  }

  .notes-rail__folders {
    order: 2;
    flex: 1;
    min-width: 0;
  }

  .notes-rail__head {
    order: 3;
    margin: 0;
  }

  /* "FOLDERS" is a column heading; in a row of chips the + speaks for
     itself. */
  .notes-rail__head > span {
    display: none;
  }

  .notes-rail__add {
    width: 1.9rem;
    height: 1.9rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    background-color: var(--bg);
  }

  /* Kept, not hidden: it is the only way to rename, recolour or delete a
     folder on a phone. */
  .notes-rail__item .note-tree__icon-btn {
    opacity: 1;
    margin-left: -0.15rem;
  }

  .notes-list {
    width: 100%;
    max-width: none;
    flex: 1;
  }

  /* One row of tools that scrolls sideways beats three stacked rows eating
     half the page. */
  .notes-toolbar.ql-toolbar.ql-snow {
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    padding: 0.35rem 0.5rem;
  }

  .notes-toolbar__group,
  .notes-toolbar__modes {
    flex-wrap: nowrap;
  }

  .notes-page-head {
    padding: 0.6rem 0.75rem 0.4rem;
  }

  .notes-page-head__title {
    font-size: calc(1.05rem * var(--font-scale));
  }

  .notes-editor {
    padding: 0.5rem;
  }

  /* The list is the whole screen, so it gets the reference app's shape: a
     big title, tabs under it, and rows with a thumbnail, the folder it's
     in, and the date. */
  .notes-list__title {
    font-size: calc(2rem * var(--font-scale));
    font-weight: 800;
    letter-spacing: -0.03em;
  }

  .notes-list__head {
    padding: 0.5rem 1rem 0.35rem;
  }

  .notes-list__tabs {
    gap: 1.1rem;
    padding: 0 1rem;
  }

  .notes-list__tab {
    padding: 0.4rem 0;
    font-size: calc(1rem * var(--font-scale));
    font-weight: 600;
  }

  .notes-list__items {
    padding: 0.25rem 0;
  }

  .note-row {
    align-items: center;
    gap: 0.9rem;
    padding: 0.75rem 1rem;
    border-radius: 0;
    border-bottom: 1px solid var(--border);
  }

  .note-row__thumb {
    display: block;
  }

  .note-row__title {
    font-size: calc(1.05rem * var(--font-scale));
    white-space: normal;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  .note-row__meta {
    font-size: calc(0.85rem * var(--font-scale));
  }

  /* --- THE OPEN NOTE ---------------------------------------------------
     The paper runs the full width; the controls float over it. Back at the
     top left, the note's name under it, and every tool in one pill at the
     bottom where a thumb can reach it. */
  .notes-editor-column {
    position: relative;
  }

  .notes-page-head {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.35rem;
    padding: 0.5rem 1rem 0.5rem;
  }

  .notes-page-head__drawer {
    height: 2.4rem;
    padding: 0 0.9rem 0 0.7rem;
    box-shadow: 0 2px 8px rgba(20, 18, 26, 0.12);
  }

  .notes-page-head__title {
    font-size: calc(1.6rem * var(--font-scale));
    font-weight: 800;
    letter-spacing: -0.03em;
    max-width: 100%;
  }

  /* At the top, above the paper — where a handwriting app puts it. It was
     briefly a floating pill at the bottom; on the page it reads as part of
     the app rather than something hovering over your writing. One row that
     scrolls sideways, so it never stacks and eats the page. */
  .notes-toolbar.ql-toolbar.ql-snow {
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    padding: 0.35rem 0.5rem;
  }

  .notes-editor {
    padding: 0.5rem 0 0;
  }

  .notes-page {
    padding: 1.25rem 1rem;
    border: none;
    border-radius: 0;
    box-shadow: none;
  }

  .notes-status-bar {
    display: none; /* the floating bar is already over the bottom of the page */
  }

}

/* --------------------------------------------------------------------------
   DARK MODE / REDUCED MOTION
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

@media (prefers-color-scheme: dark) {
  body {
    background-color: var(--bg);
    color: var(--text);
  }
}

/* Screen reader only */
.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;
}
