/* ==========================================================================
   notes-study.css — styles for /notes/sample/ ONLY.
   ==========================================================================

   Loaded by exactly one page. Every selector is prefixed `ns` (or scoped under
   .page-notes-study) so nothing here can reach a live notes URL even by
   accident — that isolation is the point of the sample.

   Motion policy: everything decorative is inside the reduced-motion guard at
   the bottom of the file. The page must remain fully usable — filters, modal,
   timer, tour, bot — with all animation off. None of the interaction depends
   on a transition completing.
   ========================================================================== */

.page-notes-study {
  --ns-glow: 0 0 0 1px rgb(240 198 74 / 0.28), 0 18px 60px -18px rgb(240 198 74 / 0.34);
  --ns-line: rgb(255 255 255 / 0.09);
  --ns-card: rgb(255 255 255 / 0.035);
  --ns-card-2: rgb(255 255 255 / 0.06);
  --ns-veil: rgb(6 6 8 / 0.72);
  --ns-pane: rgb(18 18 22 / 0.95);
  /* NO overflow-x on the body. `overflow: clip` (or hidden) on an ancestor
     CLIPS fixed-position descendants — it broke the PDF modal on every notes
     page, which rendered inline in the flow with its close button off-screen
     instead of as an overlay. The clip belongs on the elements that actually
     overflow (the 3D art stages), not on the page. */
}

/* LIGHT THEME.
   The page asks layout_start() for dark, but a saved yc_theme cookie
   overrides it — so a returning student on light gets this page whatever it
   requested. Every surface above is a white overlay, which on a light
   background is invisible: the cards lost their borders entirely. These are
   the same tokens re-derived from black. */
.theme-light .page-notes-study,
.theme-light.page-notes-study,
html.theme-light .page-notes-study {
  --ns-line: rgb(15 18 26 / 0.13);
  --ns-card: rgb(15 18 26 / 0.028);
  --ns-card-2: rgb(15 18 26 / 0.05);
  --ns-veil: rgb(20 22 30 / 0.55);
  --ns-pane: rgb(255 255 255 / 0.97);
}
.theme-light .atmos__aurora { opacity: 0.55; }
.theme-light .atmos__grid {
  background-image:
    linear-gradient(rgb(15 18 26 / 0.06) 1px, transparent 1px),
    linear-gradient(90deg, rgb(15 18 26 / 0.06) 1px, transparent 1px);
}
.theme-light .atmos__motes { opacity: 0.35; }
.theme-light .nsBar__spark i,
.theme-light .nsRing__bg,
.theme-light .nsTimer__bg { stroke: rgb(15 18 26 / 0.12); }
.theme-light .nsBar__spark i { background: rgb(15 18 26 / 0.1); }
.theme-light .nsFilter span { background: rgb(15 18 26 / 0.08); }
.theme-light .nsMsg--bot p { background: rgb(15 18 26 / 0.06); }
.theme-light .nsBot__form input { background: rgb(15 18 26 / 0.04); }
.theme-light .nsBot__nudge button { background: rgb(15 18 26 / 0.08); }
.theme-light .nsCard__facts li { border-color: var(--ns-line); }
.theme-light .nsDeck__card {
  background: linear-gradient(155deg, rgb(255 255 255 / 0.9), rgb(255 255 255 / 0.55) 58%);
  box-shadow: 0 26px 60px -28px rgb(15 18 26 / 0.5);
}
.theme-light .nsModal__body { background: rgb(15 18 26 / 0.06); }

.sample-flag {
  margin: 0;
  padding: var(--s-3) var(--s-5);
  background: rgb(240 198 74 / 0.1);
  border-bottom: 1px solid rgb(240 198 74 / 0.28);
  color: var(--text-mid);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  text-align: center;
}
.sample-flag a { color: var(--y-yellow); }

/* ── ATMOSPHERE ─────────────────────────────────────────────────────────── */
/* Fixed, behind everything, pointer-events none. `position: fixed` rather than
   a tall absolute layer so it costs one composite regardless of page length. */
.atmos {
  position: fixed; inset: 0; z-index: 0;
  pointer-events: none; overflow: hidden;
}
.atmos__aurora {
  position: absolute; inset: -30%;
  background:
    radial-gradient(38% 44% at 22% 28%, rgb(240 198 74 / 0.16), transparent 62%),
    radial-gradient(34% 38% at 78% 22%, rgb(120 140 255 / 0.14), transparent 64%),
    radial-gradient(44% 40% at 60% 84%, rgb(255 110 160 / 0.10), transparent 66%);
  filter: blur(38px);
  animation: nsDrift 34s ease-in-out infinite alternate;
}
@keyframes nsDrift {
  0%   { transform: translate3d(-3%, -2%, 0) scale(1); }
  50%  { transform: translate3d(3%, 2%, 0) scale(1.08); }
  100% { transform: translate3d(-2%, 3%, 0) scale(1.02); }
}
/* A perspective floor. transform on a pseudo-element keeps the parent
   un-transformed so it does not become a containing block for the fixed layer. */
.atmos__grid {
  position: absolute; inset: 42% -60% -30% -60%;
  background-image:
    linear-gradient(rgb(255 255 255 / 0.05) 1px, transparent 1px),
    linear-gradient(90deg, rgb(255 255 255 / 0.05) 1px, transparent 1px);
  background-size: 62px 62px;
  transform: perspective(340px) rotateX(58deg);
  transform-origin: 50% 0;
  mask-image: linear-gradient(to bottom, black, transparent 72%);
  animation: nsFloor 18s linear infinite;
}
@keyframes nsFloor { to { background-position: 0 62px, 0 0; } }

.atmos__motes {
  position: absolute; inset: 0;
  background-image:
    radial-gradient(1.5px 1.5px at 12% 22%, rgb(255 255 255 / 0.5), transparent),
    radial-gradient(1.5px 1.5px at 68% 14%, rgb(255 255 255 / 0.4), transparent),
    radial-gradient(2px 2px   at 42% 76%, rgb(240 198 74 / 0.5), transparent),
    radial-gradient(1.5px 1.5px at 86% 62%, rgb(255 255 255 / 0.35), transparent),
    radial-gradient(1.5px 1.5px at 26% 54%, rgb(255 255 255 / 0.3), transparent);
  animation: nsMotes 22s ease-in-out infinite alternate;
}
@keyframes nsMotes {
  from { transform: translate3d(0, 0, 0); opacity: 0.7; }
  to   { transform: translate3d(0, -26px, 0); opacity: 1; }
}

/* Everything real sits above the atmosphere. */
.page-notes-study .section,
.nsHero, .nsBar { position: relative; z-index: 1; }

/* ── HERO ───────────────────────────────────────────────────────────────── */
.nsHero { padding-block: clamp(var(--s-10), 7vw, var(--s-16)) clamp(var(--s-8), 5vw, var(--s-12)); }
.nsHero__in {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  gap: clamp(var(--s-8), 5vw, var(--s-14));
  align-items: center;
}
@media (max-width: 62rem) {
  .nsHero__in { grid-template-columns: 1fr; }
  .nsDeck { order: -1; }
}

.nsHero__eyebrow { margin-top: var(--s-4); }

.nsHero__h1 {
  font-size: clamp(2.3rem, 1.2rem + 4.6vw, 4.4rem);
  line-height: 1.02;
  letter-spacing: -0.035em;
  margin: var(--s-3) 0 var(--s-5);
  text-wrap: balance;
}
/* Word-level reveal. The span wrappers are injected by JS; without JS the
   heading is simply plain text, which is why no opacity is set on the h1. */
.nsHero__h1 .w { display: inline-block; overflow: hidden; vertical-align: bottom; }
.nsHero__h1 .w > i {
  display: inline-block; font-style: inherit;
  transform: translateY(105%);
  animation: nsWordUp 0.85s var(--ease-out, cubic-bezier(.22,1,.36,1)) forwards;
  animation-delay: calc(var(--wi, 0) * 55ms);
}
@keyframes nsWordUp { to { transform: translateY(0); } }

.nsHero__sub {
  color: var(--text-mid); font-size: var(--fs-lg);
  max-width: 46ch; line-height: var(--lh-snug);
}

.nsHero__meta { display: flex; flex-wrap: wrap; gap: var(--s-2); margin: var(--s-6) 0 var(--s-7); }
.nsChip {
  display: inline-flex; align-items: center; gap: 0.4ch;
  padding: 0.42rem 0.8rem;
  border: 1px solid var(--ns-line);
  border-radius: 999px;
  background: var(--ns-card);
  font-size: var(--fs-sm); color: var(--text-mid);
  backdrop-filter: blur(6px);
}
.nsChip strong { color: var(--text-hi); font-variant-numeric: tabular-nums; }
.nsChip--code { font-family: var(--font-mono); color: var(--y-yellow); border-color: rgb(240 198 74 / 0.32); }
.nsChip--free { border-color: rgb(120 220 160 / 0.35); color: rgb(150 235 190); }

.nsHero__cta { display: flex; flex-wrap: wrap; gap: var(--s-3); }

/* ── THE DECK (3D fanned stack) ─────────────────────────────────────────── */
.nsDeck {
  position: relative;
  height: clamp(19rem, 34vw, 27rem);
  perspective: 1400px;
  perspective-origin: 50% 45%;
}
.nsDeck__card {
  position: absolute; left: 50%; top: 50%;
  width: min(15.5rem, 62%); aspect-ratio: 3 / 4;
  margin: 0;
  border-radius: var(--radius-lg);
  border: 1px solid var(--ns-line);
  background:
    linear-gradient(155deg, rgb(255 255 255 / 0.11), rgb(255 255 255 / 0.02) 58%),
    var(--surface-1);
  box-shadow: 0 26px 70px -26px rgb(0 0 0 / 0.85);
  display: grid; align-content: center; justify-items: center; gap: var(--s-2);
  backdrop-filter: blur(8px);
  /* Fanned by default so the shape reads before any interaction. The custom
     properties are what JS animates on hover — never `transform` directly, so
     the two cannot fight over the same declaration. */
  --rot: calc((var(--i) - 1.5) * 9deg);
  --tx:  calc((var(--i) - 1.5) * 3.1rem);
  --ty:  calc(var(--i) * -0.5rem);
  --tz:  calc(var(--i) * -34px);
  transform:
    translate(-50%, -50%)
    translate3d(var(--tx), var(--ty), var(--tz))
    rotateY(var(--rot)) rotateX(6deg);
  transition: transform 0.7s cubic-bezier(.22,1,.36,1), box-shadow 0.5s;
  z-index: calc(10 - var(--i));
}
.nsDeck:hover .nsDeck__card {
  --tx: calc((var(--i) - 1.5) * 4.6rem);
  --rot: calc((var(--i) - 1.5) * 13deg);
  --tz: calc(var(--i) * -14px);
}
.nsDeck__card:hover { box-shadow: var(--ns-glow), 0 30px 80px -24px rgb(0 0 0 / 0.9); }
.nsDeck__n {
  font-family: var(--font-display);
  font-size: clamp(2.4rem, 1.4rem + 3vw, 3.6rem); line-height: 1;
  color: var(--y-yellow); font-variant-numeric: tabular-nums;
}
.nsDeck__l {
  font-size: var(--fs-sm); color: var(--text-mid);
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
}
.nsDeck__glow {
  position: absolute; left: 50%; top: 58%; translate: -50% -50%;
  width: 74%; aspect-ratio: 1; border-radius: 50%;
  background: radial-gradient(circle, rgb(240 198 74 / 0.22), transparent 62%);
  filter: blur(26px); z-index: 0;
}

/* ── MISSION BAR ────────────────────────────────────────────────────────── */
.nsBar {
  position: sticky; top: var(--nav-h, 4.5rem);
  z-index: 20;
  border-block: 1px solid var(--ns-line);
  background: rgb(13 13 15 / 0.72);
  backdrop-filter: blur(14px) saturate(1.3);
  transform: translateY(-100%); opacity: 0;
  transition: transform 0.45s cubic-bezier(.22,1,.36,1), opacity 0.35s;
  pointer-events: none;
}
.nsBar.is-on { transform: none; opacity: 1; pointer-events: auto; }
.theme-light .nsBar { background: rgb(255 255 255 / 0.8); }

.nsBar__in {
  display: flex; align-items: center; gap: var(--s-5);
  padding-block: var(--s-3);
}
.nsBar__prog { display: flex; align-items: center; gap: var(--s-3); position: relative; }
.nsRing { width: 2.6rem; height: 2.6rem; transform: rotate(-90deg); flex: none; }
.nsRing__bg, .nsRing__fg {
  fill: none; stroke-width: 3.4; stroke-linecap: round;
}
.nsRing__bg { stroke: rgb(255 255 255 / 0.12); }
.nsRing__fg {
  stroke: var(--y-yellow);
  stroke-dasharray: 119.4;          /* 2πr, r = 19 */
  stroke-dashoffset: 119.4;
  transition: stroke-dashoffset 0.6s cubic-bezier(.22,1,.36,1);
  filter: drop-shadow(0 0 6px rgb(240 198 74 / 0.55));
}
.nsBar__pct {
  position: absolute; left: 1.3rem; top: 50%; translate: -50% -50%;
  font-size: 0.62rem; font-variant-numeric: tabular-nums; color: var(--text-hi);
}
.nsBar__lbl { font-size: var(--fs-sm); color: var(--text-mid); white-space: nowrap; }
.nsBar__lbl strong { color: var(--text-hi); }

.nsBar__spark { display: flex; gap: 3px; flex: 1; min-width: 0; overflow: hidden; }
.nsBar__spark i {
  flex: 1 1 0; min-width: 2px; max-width: 14px; height: 1.5rem;
  border-radius: 2px; background: rgb(255 255 255 / 0.1);
  transition: background 0.4s, transform 0.4s;
}
.nsBar__spark i.is-on {
  background: linear-gradient(to top, var(--y-yellow), rgb(255 226 140));
  transform: scaleY(1.18);
}
@media (max-width: 52rem) { .nsBar__spark, .nsBar__lbl { display: none; } }

.nsBar__acts { display: flex; gap: var(--s-2); margin-left: auto; }
.nsBar__btn {
  display: inline-flex; align-items: center; gap: 0.5ch;
  padding: 0.5rem 0.85rem; border-radius: 999px;
  border: 1px solid var(--ns-line); background: var(--ns-card);
  color: var(--text-hi); font-size: var(--fs-sm); cursor: pointer;
  font-variant-numeric: tabular-nums;
  transition: border-color 0.25s, background 0.25s, transform 0.25s;
}
.nsBar__btn:hover { border-color: rgb(240 198 74 / 0.5); transform: translateY(-1px); }
.nsBar__btn--ghost { color: var(--text-mid); }
@media (max-width: 42rem) { .nsBar__btn--ghost { display: none; } }

/* ── HEADINGS ───────────────────────────────────────────────────────────── */
.nsHead { margin-bottom: clamp(var(--s-6), 3vw, var(--s-9)); }
.nsHead h2 {
  font-size: clamp(1.7rem, 1.1rem + 2.2vw, 2.7rem);
  letter-spacing: -0.028em; margin: 0 0 var(--s-2);
}
.nsHead p { color: var(--text-mid); margin: 0; }

/* ── FILTERS ────────────────────────────────────────────────────────────── */
.nsFilters {
  display: flex; flex-wrap: wrap; gap: var(--s-2);
  margin-bottom: clamp(var(--s-6), 3vw, var(--s-8));
}
.nsFilter {
  display: inline-flex; align-items: center; gap: 0.5ch;
  padding: 0.5rem 0.95rem; border-radius: 999px;
  border: 1px solid var(--ns-line); background: var(--ns-card);
  color: var(--text-mid); font-size: var(--fs-sm); cursor: pointer;
  transition: color 0.25s, border-color 0.25s, background 0.25s, transform 0.2s;
}
.nsFilter span {
  font-size: 0.7rem; padding: 0.1rem 0.42rem; border-radius: 999px;
  background: rgb(255 255 255 / 0.1); font-variant-numeric: tabular-nums;
}
.nsFilter:hover { color: var(--text-hi); transform: translateY(-1px); }
.nsFilter.is-on {
  color: #0d0d0f; background: var(--y-yellow); border-color: var(--y-yellow);
  box-shadow: 0 8px 24px -8px rgb(240 198 74 / 0.6);
}
.nsFilter.is-on span { background: rgb(0 0 0 / 0.18); }

/* ── SHELVES + CARDS ────────────────────────────────────────────────────── */
/* Shelves need real air between them, and the gap must come from padding on
   the shelf rather than margin on the heading: a one-card shelf leaves the
   grid short, and with margins the next heading collapsed against the card
   above it. Padding does not collapse, so the rhythm holds regardless of how
   many cards a shelf happens to have. A separator line makes the boundary
   legible even mid-scroll. */
.nsShelf { padding-block: clamp(var(--s-8), 4vw, var(--s-12)); }
.nsShelf + .nsShelf { border-top: 1px solid var(--ns-line); }
.nsShelf:first-of-type { padding-top: 0; }
.nsShelf:last-of-type { padding-bottom: 0; }
.nsShelf[hidden] { display: none; }
/* With a filter on, the visible shelf is the only one — drop the rule that
   would otherwise hang off a hidden sibling. */
.nsShelf[hidden] + .nsShelf { border-top: 0; }

.nsShelf__head {
  display: flex; gap: var(--s-4); align-items: center;
  margin-bottom: clamp(var(--s-5), 2.5vw, var(--s-7));
}
.nsShelf__head h3 {
  display: flex; align-items: center; gap: var(--s-3);
  font-size: clamp(1.15rem, 1rem + 0.7vw, 1.5rem); margin: 0 0 2px;
}
.nsShelf__head p { color: var(--text-lo); font-size: var(--fs-sm); margin: 0; }
.nsShelf__c {
  font-size: 0.72rem; padding: 0.12rem 0.5rem; border-radius: 999px;
  background: rgb(240 198 74 / 0.16); color: var(--y-yellow);
  font-variant-numeric: tabular-nums;
}
.nsShelf__icon {
  flex: none; width: 3rem; height: 3rem;
  border-radius: 50%;
  border: 1px solid rgb(240 198 74 / 0.3);
  background:
    radial-gradient(circle at 32% 28%, rgb(240 198 74 / 0.22), transparent 62%),
    var(--ns-card);
  display: grid; place-items: center;
  box-shadow: 0 0 0 4px rgb(240 198 74 / 0.06);
}
/* Icons drawn in CSS rather than shipped as files — four glyphs is not worth a
   sprite request on a sample page. */
.nsShelf__icon::after {
  content: ''; width: 1.05rem; height: 1.05rem;
  background: var(--y-yellow);
  mask-repeat: no-repeat; mask-size: contain; mask-position: center;
}
.nsShelf__icon--book::after  { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M4 4h7a3 3 0 0 1 3 3v13a2.5 2.5 0 0 0-2.5-2.5H4z'/%3E%3Cpath d='M20 4h-7a3 3 0 0 0-3 3v13a2.5 2.5 0 0 1 2.5-2.5H20z'/%3E%3C/svg%3E"); }
.nsShelf__icon--paper::after { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z'/%3E%3Cpath d='M14 2v6h6M8 13h8M8 17h5'/%3E%3C/svg%3E"); }
.nsShelf__icon--pen::after   { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M12 20h9M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4z'/%3E%3C/svg%3E"); }
.nsShelf__icon--flask::after { mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M9 2v7L4 19a2 2 0 0 0 1.7 3h12.6A2 2 0 0 0 20 19L15 9V2M8 2h8M7.5 14h9'/%3E%3C/svg%3E"); }

.nsGrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 17.5rem), 1fr));
  gap: clamp(var(--s-4), 2vw, var(--s-5));
}

.nsCard { margin: 0; perspective: 900px; }
.nsCard[hidden] { display: none; }
.nsCard__in {
  position: relative; height: 100%;
  display: flex; flex-direction: column; gap: var(--s-2);
  padding: var(--s-5);
  border-radius: var(--radius-lg);
  border: 1px solid var(--ns-line);
  background: linear-gradient(160deg, var(--ns-card-2), var(--ns-card));
  overflow: hidden;
  /* Driven by data-tilt in notes-study.js via custom properties, so a GSAP
     reveal writing to `transform` on the parent cannot cancel the tilt — the
     bug that broke the avatar cards on /ai/avatar/. */
  transform: rotateX(var(--tx, 0deg)) rotateY(var(--ty, 0deg)) translateZ(0);
  transition: transform 0.35s cubic-bezier(.22,1,.36,1),
              border-color 0.3s, box-shadow 0.4s;
  will-change: transform;
}
.nsCard:hover .nsCard__in {
  border-color: rgb(240 198 74 / 0.42);
  box-shadow: var(--ns-glow);
}
.nsCard__sheen {
  position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background: radial-gradient(360px circle at var(--mx, 50%) var(--my, 50%),
              rgb(255 255 255 / 0.13), transparent 62%);
  transition: opacity 0.35s;
}
.nsCard:hover .nsCard__sheen { opacity: 1; }

.nsCard__top { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); }
.nsCard__kind {
  font-family: var(--font-mono); font-size: 0.66rem;
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
  color: var(--text-lo);
}
.nsCard__seen {
  font-size: 0.64rem; padding: 0.14rem 0.5rem; border-radius: 999px;
  background: rgb(120 220 160 / 0.16); color: rgb(150 235 190);
  border: 1px solid rgb(120 220 160 / 0.3);
}
.nsCard__title {
  font-size: var(--fs-base); line-height: var(--lh-snug);
  margin: 0; color: var(--text-hi);
  /* Titles in this catalogue run to 60+ characters. Clamping keeps the grid
     even without truncating so hard the title stops identifying the file. */
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  line-clamp: 3; overflow: hidden;
}
.nsCard__desc {
  color: var(--text-lo); font-size: var(--fs-sm); margin: 0;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  line-clamp: 2; overflow: hidden;
}
.nsCard__facts {
  display: flex; flex-wrap: wrap; gap: var(--s-2);
  list-style: none; padding: 0; margin: auto 0 0;
}
.nsCard__facts li {
  font-size: 0.68rem; color: var(--text-lo);
  padding: 0.16rem 0.5rem; border-radius: 999px;
  border: 1px solid var(--ns-line);
}
.nsCard__acts { display: flex; gap: var(--s-2); margin-top: var(--s-3); }
.nsCard__go, .nsCard__out {
  flex: 1; text-align: center;
  padding: 0.52rem 0.7rem; border-radius: var(--radius);
  font-size: var(--fs-sm); cursor: pointer; border: 1px solid transparent;
  transition: transform 0.2s, background 0.25s, border-color 0.25s;
}
.nsCard__go { background: var(--y-yellow); color: #0d0d0f; font-weight: 500; }
.nsCard__out { border-color: var(--ns-line); color: var(--text-mid); }
.nsCard__go:hover, .nsCard__out:hover { transform: translateY(-2px); }
.nsCard__out:hover { border-color: rgb(240 198 74 / 0.45); color: var(--text-hi); }

.nsEmpty { color: var(--text-lo); text-align: center; padding: var(--s-10) 0; }

/* ── NEXT ───────────────────────────────────────────────────────────────── */
.nsNext__row {
  display: grid; gap: var(--s-4);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
}
.nsNext__card {
  display: grid; gap: var(--s-2); padding: var(--s-6);
  border-radius: var(--radius-lg); border: 1px solid var(--ns-line);
  background: var(--ns-card); color: inherit; text-decoration: none;
  transform: rotateX(var(--tx, 0deg)) rotateY(var(--ty, 0deg));
  transition: transform 0.35s cubic-bezier(.22,1,.36,1), border-color 0.3s, box-shadow 0.4s;
}
.nsNext__card:hover { border-color: rgb(240 198 74 / 0.42); box-shadow: var(--ns-glow); }
.nsNext__k {
  font-family: var(--font-mono); font-size: 0.66rem; color: var(--y-yellow);
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
}
.nsNext__card strong { font-size: var(--fs-lg); color: var(--text-hi); }
.nsNext__go { color: var(--text-mid); font-size: var(--fs-sm); }

/* ── PREVIEW MODAL ──────────────────────────────────────────────────────── */
.nsModal {
  border: none; padding: 0; background: transparent;
  max-width: min(64rem, 94vw); width: 100%;
  max-height: 92vh;
  color: inherit;
}
.nsModal::backdrop { background: var(--ns-veil); backdrop-filter: blur(6px); }
.nsModal__card {
  display: flex; flex-direction: column; max-height: 92vh;
  border-radius: var(--radius-lg);
  border: 1px solid var(--ns-line);
  background: var(--surface-1);
  box-shadow: 0 40px 120px -30px rgb(0 0 0 / 0.9);
  overflow: hidden;
  animation: nsPop 0.36s cubic-bezier(.22,1,.36,1);
}
@keyframes nsPop {
  from { opacity: 0; transform: translateY(14px) scale(0.97); }
}
.nsModal__head {
  display: flex; align-items: center; gap: var(--s-4);
  padding: var(--s-5) var(--s-6); border-bottom: 1px solid var(--ns-line);
}
.nsModal__head h3 { margin: 0; font-size: var(--fs-lg); flex: 1; min-width: 0; }
.nsModal__x, .nsTimer__x, .nsBot__x {
  flex: none; width: 2rem; height: 2rem; border-radius: 50%;
  border: 1px solid var(--ns-line); background: transparent;
  color: var(--text-mid); font-size: 1.3rem; line-height: 1; cursor: pointer;
  transition: color 0.2s, border-color 0.2s, transform 0.2s;
}
.nsModal__x:hover, .nsTimer__x:hover, .nsBot__x:hover {
  color: var(--text-hi); border-color: rgb(240 198 74 / 0.5); transform: rotate(90deg);
}
.nsModal__body { flex: 1; min-height: 24rem; background: rgb(0 0 0 / 0.28); }
.nsModal__body iframe { width: 100%; height: 100%; min-height: 60vh; border: 0; display: block; }
.nsModal__note { padding: var(--s-10) var(--s-6); text-align: center; color: var(--text-mid); }
.nsModal__foot {
  display: flex; gap: var(--s-3); justify-content: flex-end;
  padding: var(--s-4) var(--s-6); border-top: 1px solid var(--ns-line);
}

/* ── STUDY TIMER ────────────────────────────────────────────────────────── */
/* Bottom-LEFT, deliberately. Yuna's panel occupies the bottom-right corner and
   is 22rem wide; a timer anchored on the same side is simply hidden behind her
   the moment a student opens the chat — which is exactly when they are most
   likely to want to see how long is left. Opposite corners is the only
   arrangement where both can be open at once. */
.nsTimer {
  position: fixed; left: clamp(1rem, 3vw, 2rem); bottom: clamp(1rem, 3vw, 2rem);
  z-index: 60; width: min(19rem, calc(100vw - 2rem));
}
.nsTimer[hidden] { display: none; }
.nsTimer__card {
  padding: var(--s-5);
  border-radius: var(--radius-lg); border: 1px solid var(--ns-line);
  background: var(--ns-pane); backdrop-filter: blur(16px);
  box-shadow: 0 30px 80px -24px rgb(0 0 0 / 0.9);
  animation: nsPop 0.34s cubic-bezier(.22,1,.36,1);
}
.nsTimer__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--s-4); }
.nsTimer__dial { position: relative; width: 11rem; margin: 0 auto var(--s-4); }
.nsTimer__dial svg { width: 100%; transform: rotate(-90deg); display: block; }
.nsTimer__bg, .nsTimer__fg { fill: none; stroke-width: 7; stroke-linecap: round; }
.nsTimer__bg { stroke: rgb(255 255 255 / 0.1); }
.nsTimer__fg {
  stroke: var(--y-yellow);
  stroke-dasharray: 326.7;         /* 2πr, r = 52 */
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 0.95s linear, stroke 0.4s;
  filter: drop-shadow(0 0 8px rgb(240 198 74 / 0.5));
}
.nsTimer.is-break .nsTimer__fg { stroke: rgb(120 220 160); filter: drop-shadow(0 0 8px rgb(120 220 160 / 0.5)); }
.nsTimer__read {
  position: absolute; inset: 0; display: grid; place-content: center; text-align: center; gap: 2px;
}
.nsTimer__read strong {
  font-family: var(--font-display); font-size: 2.1rem; line-height: 1;
  font-variant-numeric: tabular-nums; color: var(--text-hi);
}
.nsTimer__read span {
  font-family: var(--font-mono); font-size: 0.66rem; color: var(--text-lo);
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
}
.nsTimer__acts { display: flex; gap: var(--s-2); }
.nsTimer__acts .btn { flex: 1; }
.nsTimer__note { margin: var(--s-4) 0 0; font-size: var(--fs-xs); color: var(--text-lo); text-align: center; }
.nsTimer__note strong { color: var(--y-yellow); }

/* ── YUNA — DOUBT BOT ───────────────────────────────────────────────────── */
.nsBot { position: fixed; right: clamp(1rem, 3vw, 2rem); bottom: clamp(1rem, 3vw, 2rem); z-index: 70; }
.nsBot[hidden] { display: none; }

.nsBot__bubble {
  position: relative; display: grid; place-items: center;
  width: 4rem; height: 4rem; padding: 0;
  border-radius: 50%; border: 2px solid rgb(240 198 74 / 0.55);
  background: var(--surface-1); cursor: pointer;
  box-shadow: 0 14px 40px -10px rgb(0 0 0 / 0.7);
  transition: transform 0.35s cubic-bezier(.34,1.56,.64,1), box-shadow 0.3s;
}
.nsBot__bubble:hover { transform: scale(1.08) translateY(-2px); }
/* Yuna's source is a FULL-BODY studio portrait, 776×1200, with her head
   occupying roughly the top quarter. Dropped into a 64px circle at scale 1 her
   face renders about 25px across and the bubble reads as an empty dark disc —
   which is exactly how it looked before this rule. object-position centres the
   crop on her face; the scale then fills the circle with it. */
.nsBot__bubble img {
  /* ABSOLUTE, not width/height:100%. The button is `display:grid;
     place-items:center`, which makes the image a centred grid item sized to
     its own content — so `height:100%` never resolved and the box came out
     56x87 instead of square. object-fit:cover then had nothing to crop, the
     full-length portrait was shown at full length, and her head sat clipped
     against the top edge. `inset` gives a genuinely square box, which is what
     both the crop and the centring maths below assume. */
  position: absolute; inset: 2px;
  width: auto; height: auto; border-radius: 50%;
  /* Geometry, not guesswork. Source is 776x1200; a square cover-crop shows
     776px of height. With object-position at the top, her face centre (y≈240
     in the source) lands at 240/776 ≈ 31% down the crop. Scaling 1.7x about an
     origin of 18% maps that to 18 + (31-18)*1.7 ≈ 40% — head in the upper
     third, shoulders and blazer below it, which is a portrait rather than a
     face swab. An origin ON the face would pin it in place, not move it. */
  object-fit: cover; object-position: 50% 0%;
  transform: scale(1.7);
  transform-origin: 50% 18%;
}
/* A conic ring behind the photo, so the bubble reads as a deliberate icon
   rather than a cropped photograph sitting in a circle. */
.nsBot__bubble {
  background:
    conic-gradient(from 210deg,
      rgb(240 198 74 / .95), rgb(120 220 160 / .8),
      rgb(120 160 255 / .8), rgb(240 198 74 / .95));
  padding: 2px;
  border-color: transparent;
  /* MUST clip: the photo is scaled 2.15x to fill the circle with her face, and
     an unclipped scaled image spills out over the page as a rectangle. */
  overflow: hidden;
}
.nsBot__bubble::before {
  content: ''; position: absolute; inset: 2px;
  border-radius: 50%; background: var(--surface-1); z-index: 0;
}
.nsBot__bubble img { position: relative; z-index: 1; }

/* The ping rings were child <span>s, which `overflow: hidden` above would
   clip to nothing — the whole point of a ping is that it expands PAST the
   element. Drawn as an animated box-shadow instead: it escapes the clip, and
   it is one composited property rather than two extra nodes. */
.nsBot__ring { display: none; }
.nsBot__bubble {
  animation: nsPing2 2.8s cubic-bezier(0, 0, .2, 1) infinite;
}
@keyframes nsPing2 {
  0%   { box-shadow: 0 0 0 0 rgb(240 198 74 / .5), 0 14px 40px -10px rgb(0 0 0 / .7); }
  70%  { box-shadow: 0 0 0 14px rgb(240 198 74 / 0), 0 14px 40px -10px rgb(0 0 0 / .7); }
  100% { box-shadow: 0 0 0 0 rgb(240 198 74 / 0), 0 14px 40px -10px rgb(0 0 0 / .7); }
}
@media (prefers-reduced-motion: reduce) { .nsBot__bubble { animation: none; } }
.nsBot__head img {
  object-position: 50% 0%; transform: scale(1.7); transform-origin: 50% 18%;
}
/* The header avatar needs its own clipping context once the image is scaled,
   or the zoom spills over the adjacent text. */
.nsBot__head img { border-radius: 50%; overflow: hidden; }
.nsBot__ring {
  position: absolute; inset: -2px; border-radius: 50%;
  border: 2px solid rgb(240 198 74 / 0.6);
  animation: nsPing 2.6s cubic-bezier(0,0,.2,1) infinite;
}
.nsBot__ring--2 { animation-delay: 1.3s; }
@keyframes nsPing {
  0%   { transform: scale(1);   opacity: 0.75; }
  70%  { transform: scale(1.7); opacity: 0; }
  100% { transform: scale(1.7); opacity: 0; }
}
.nsBot__dot {
  position: absolute; right: 2px; bottom: 2px;
  width: 0.85rem; height: 0.85rem; border-radius: 50%;
  background: rgb(80 220 140); border: 2px solid var(--surface-1);
}

.nsBot__nudge {
  position: absolute; right: 4.9rem; bottom: 1rem;
  margin: 0; padding: 0.55rem 2rem 0.55rem 0.9rem;
  border-radius: 999px; border: 1px solid var(--ns-line);
  background: var(--ns-pane); backdrop-filter: blur(10px);
  color: var(--text-mid); font-size: var(--fs-sm); white-space: nowrap;
  box-shadow: 0 12px 34px -12px rgb(0 0 0 / 0.8);
  animation: nsSlideIn 0.5s cubic-bezier(.22,1,.36,1) 1.4s both;
}
.nsBot__nudge[hidden] { display: none; }
.nsBot__nudge button {
  position: absolute; right: 0.45rem; top: 50%; translate: 0 -50%;
  width: 1.35rem; height: 1.35rem; border-radius: 50%;
  border: none; background: rgb(255 255 255 / 0.1);
  color: var(--text-mid); cursor: pointer; line-height: 1;
}
@keyframes nsSlideIn { from { opacity: 0; transform: translateX(14px); } }
@media (max-width: 34rem) { .nsBot__nudge { display: none; } }

.nsBot__panel {
  position: absolute; right: 0; bottom: 5rem;
  width: min(22rem, calc(100vw - 2rem));
  display: flex; flex-direction: column;
  border-radius: var(--radius-lg); border: 1px solid var(--ns-line);
  background: var(--ns-pane); backdrop-filter: blur(18px);
  box-shadow: 0 36px 90px -26px rgb(0 0 0 / 0.9);
  overflow: hidden;
  transform-origin: 90% 100%;
  animation: nsBotIn 0.42s cubic-bezier(.22,1,.36,1);
}
.nsBot__panel[hidden] { display: none; }
@keyframes nsBotIn {
  from { opacity: 0; transform: translateY(16px) scale(0.9) rotateX(14deg); }
}
.nsBot__head {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-4); border-bottom: 1px solid var(--ns-line);
}
.nsBot__head img { width: 2.5rem; height: 2.5rem; flex: none; border-radius: 50%; object-fit: cover; }
.nsBot__head div { flex: 1; min-width: 0; display: grid; }
.nsBot__head strong { color: var(--text-hi); }
.nsBot__head span { font-size: var(--fs-xs); color: var(--text-lo); display: flex; align-items: center; gap: 0.4ch; }
.nsBot__head span i { width: 0.45rem; height: 0.45rem; border-radius: 50%; background: rgb(80 220 140); }

.nsBot__log {
  flex: 1; min-height: 12rem; max-height: 46vh; overflow-y: auto;
  padding: var(--s-4); display: grid; gap: var(--s-3); align-content: start;
}
.nsMsg { display: flex; }
.nsMsg p {
  margin: 0; padding: 0.6rem 0.85rem; border-radius: var(--radius);
  font-size: var(--fs-sm); line-height: var(--lh-snug); max-width: 85%;
  animation: nsMsgIn 0.32s cubic-bezier(.22,1,.36,1);
}
@keyframes nsMsgIn { from { opacity: 0; transform: translateY(8px); } }
.nsMsg--bot p { background: rgb(255 255 255 / 0.07); color: var(--text-mid); border-bottom-left-radius: 4px; }
.nsMsg--me { justify-content: flex-end; }
.nsMsg--me p { background: var(--y-yellow); color: #0d0d0f; border-bottom-right-radius: 4px; }

/* Three-dot typing indicator. */
.nsTyping p { display: flex; gap: 4px; align-items: center; }
.nsTyping i {
  width: 5px; height: 5px; border-radius: 50%; background: var(--text-lo);
  animation: nsBlink 1.2s ease-in-out infinite;
}
.nsTyping i:nth-child(2) { animation-delay: 0.18s; }
.nsTyping i:nth-child(3) { animation-delay: 0.36s; }
@keyframes nsBlink { 0%,60%,100% { opacity: 0.25; transform: translateY(0); } 30% { opacity: 1; transform: translateY(-3px); } }

.nsBot__chips { display: flex; flex-wrap: wrap; gap: var(--s-2); padding: 0 var(--s-4) var(--s-3); }
.nsBot__chips button {
  padding: 0.34rem 0.7rem; border-radius: 999px;
  border: 1px solid var(--ns-line); background: transparent;
  color: var(--text-mid); font-size: var(--fs-xs); cursor: pointer;
  transition: color 0.2s, border-color 0.2s;
}
.nsBot__chips button:hover { color: var(--text-hi); border-color: rgb(240 198 74 / 0.5); }
.nsBot__chips[hidden] { display: none; }

.nsBot__form { display: flex; gap: var(--s-2); padding: var(--s-3) var(--s-4); border-top: 1px solid var(--ns-line); }
.nsBot__form input {
  flex: 1; min-width: 0; padding: 0.6rem 0.85rem;
  border-radius: 999px; border: 1px solid var(--ns-line);
  background: rgb(255 255 255 / 0.05); color: var(--text-hi); font: inherit;
  font-size: var(--fs-sm);
}
.nsBot__form input:focus-visible { outline: 2px solid var(--y-yellow); outline-offset: 1px; }
.nsBot__form button {
  flex: none; width: 2.4rem; height: 2.4rem; border-radius: 50%;
  border: none; background: var(--y-yellow); color: #0d0d0f;
  display: grid; place-items: center; cursor: pointer;
  transition: transform 0.2s;
}
.nsBot__form button:hover { transform: scale(1.08); }
.nsBot__demo { margin: 0; padding: 0 var(--s-4) var(--s-3); font-size: 0.64rem; color: var(--text-lo); text-align: center; }

/* ── GUIDED TOUR ────────────────────────────────────────────────────────── */
.nsTour { position: fixed; inset: 0; z-index: 90; }
.nsTour[hidden] { display: none; }
/* Transparent BY DESIGN. The darkening is done entirely by the spotlight's
   huge box-shadow below, which is what punches the hole. Giving this element a
   background too means the hole reveals the veil rather than the page, and the
   spotlight silently never appears — it only exists to swallow clicks on the
   rest of the page while the tour is open. */
.nsTour__veil { position: absolute; inset: 0; background: transparent; }
/* One spotlight element, moved and resized per step. The hole is a huge box
   shadow rather than a mask so it works without mask support. */
.nsTour__spot {
  position: absolute; border-radius: var(--radius-lg);
  box-shadow: 0 0 0 9999px var(--ns-veil), 0 0 0 2px rgb(240 198 74 / 0.9),
              0 0 40px rgb(240 198 74 / 0.4);
  transition: all 0.5s cubic-bezier(.22,1,.36,1);
  pointer-events: none;
}
.nsTour__pop {
  position: absolute; width: min(20rem, calc(100vw - 2rem));
  padding: var(--s-5);
  border-radius: var(--radius-lg); border: 1px solid rgb(240 198 74 / 0.35);
  background: var(--ns-pane); backdrop-filter: blur(14px);
  box-shadow: 0 30px 80px -22px rgb(0 0 0 / 0.9);
  transition: all 0.5s cubic-bezier(.22,1,.36,1);
}
.nsTour__step { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text-lo); }
.nsTour__step b { color: var(--y-yellow); }
.nsTour__pop h4 { margin: var(--s-2) 0 var(--s-2); font-size: var(--fs-lg); }
.nsTour__pop p { margin: 0 0 var(--s-4); color: var(--text-mid); font-size: var(--fs-sm); line-height: var(--lh-snug); }
.nsTour__acts { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); }
.nsTour__skip { border: none; background: none; color: var(--text-lo); font-size: var(--fs-sm); cursor: pointer; }
.nsTour__skip:hover { color: var(--text-mid); }
/* The arrow is a rotated square tucked under the popup edge; JS sets --ax/--ay
   and which edge it hangs off. */
.nsTour__arrow {
  position: absolute; width: 0.85rem; height: 0.85rem;
  background: var(--ns-pane);
  border-left: 1px solid rgb(240 198 74 / 0.35);
  border-top: 1px solid rgb(240 198 74 / 0.35);
  left: var(--ax, 50%); top: var(--ay, -0.45rem);
  transform: translateX(-50%) rotate(45deg);
}
.nsTour__pop[data-side="above"] .nsTour__arrow {
  top: auto; bottom: -0.45rem; transform: translateX(-50%) rotate(225deg);
}

/* ── REDUCED MOTION ─────────────────────────────────────────────────────── */
/* Kills decoration, keeps function. Every interactive affordance above still
   works with all of this disabled. */
@media (prefers-reduced-motion: reduce) {
  .atmos__aurora, .atmos__grid, .atmos__motes,
  .nsBot__ring, .nsBot__nudge { animation: none; }
  .nsHero__h1 .w > i { animation: none; transform: none; }
  .nsDeck__card,
  .nsCard__in, .nsNext__card,
  .nsTour__spot, .nsTour__pop,
  .nsRing__fg, .nsTimer__fg { transition: none; }
  .nsDeck:hover .nsDeck__card { --tx: calc((var(--i) - 1.5) * 3.1rem); --rot: calc((var(--i) - 1.5) * 9deg); }
  .nsModal__card, .nsBot__panel, .nsTimer__card, .nsMsg p { animation: none; }
  .nsBar { transition: none; }
}

/* ── HERO ART ───────────────────────────────────────────────────────────────
   Replaces the sample's fixed card-deck. Hue, glyph, lattice and tilt all come
   from notes_hero_art() via inline custom properties, so every subject page
   looks different while staying identical between visits. Everything is
   decorative and aria-hidden — the counts it shows have real, clickable
   equivalents in the shelves below. */
.nsArt {
  position: relative; overflow: clip;
  min-height: clamp(19rem, 32vw, 27rem);
  perspective: 1500px;
  display: grid; place-items: center;
}
.nsArt__stage {
  position: relative; width: 100%; height: 100%;
  display: grid; place-items: center;
  transform: rotateX(var(--ax, 0deg)) rotateY(var(--ay, 0deg)) rotate(var(--tilt, 0deg));
  transform-style: preserve-3d;
  transition: transform .5s cubic-bezier(.22,1,.36,1);
}

/* Lattice — four variants, chosen by hash. */
.nsArt__lat {
  position: absolute; inset: 8%;
  border-radius: 28%;
  opacity: .5;
  background:
    radial-gradient(closest-side, hsl(var(--h) 80% 60% / .22), transparent 72%),
    radial-gradient(closest-side at 70% 30%, hsl(var(--h2) 80% 62% / .18), transparent 70%);
  filter: blur(6px);
  animation: nsArtPulse 9s ease-in-out infinite alternate;
}
.nsArt__lat--1 { border-radius: 50%; }
.nsArt__lat--2 { border-radius: 12%; transform: rotate(18deg); }
.nsArt__lat--3 { border-radius: 46% 54% 38% 62% / 52% 40% 60% 48%; }
@keyframes nsArtPulse { to { transform: scale(1.08) rotate(6deg); opacity: .72; } }

.nsArt__glyph {
  position: absolute;
  font-size: clamp(9rem, 20vw, 16rem); line-height: 1;
  font-family: var(--font-display);
  color: hsl(var(--h) 85% 68% / .16);
  text-shadow: 0 0 60px hsl(var(--h) 90% 60% / .3);
  transform: translateZ(-90px);
  user-select: none;
}

.nsArt__ring {
  position: absolute; border-radius: 50%;
  border: 1px solid hsl(var(--h) 80% 65% / .3);
}
.nsArt__ring--1 { inset: 12%; transform: rotateX(72deg) translateZ(20px); animation: nsSpin 22s linear infinite; }
.nsArt__ring--2 { inset: 22%; transform: rotateY(68deg) translateZ(10px); animation: nsSpin 30s linear infinite reverse; border-color: hsl(var(--h2) 80% 66% / .28); }
@keyframes nsSpin { to { rotate: 360deg; } }

/* The count chips orbit the glyph. --i spaces them; the hash tilt means two
   adjacent subjects never sit in the same arrangement. */
.nsArt__card {
  position: absolute;
  display: grid; gap: 2px; justify-items: center;
  padding: var(--s-3) var(--s-4);
  min-width: 6.5rem;
  border-radius: var(--radius);
  border: 1px solid hsl(var(--h) 60% 60% / .32);
  background: linear-gradient(150deg, hsl(var(--h) 40% 30% / .5), rgb(255 255 255 / .04));
  backdrop-filter: blur(10px);
  box-shadow: 0 18px 44px -18px rgb(0 0 0 / .8);
  transform:
    rotate(calc(var(--i) * 90deg + 20deg))
    translate(clamp(6rem, 13vw, 9.5rem))
    rotate(calc(var(--i) * -90deg - 20deg))
    translateZ(calc(var(--i) * 16px));
  animation: nsFloat 7s ease-in-out infinite alternate;
  animation-delay: calc(var(--i) * -1.4s);
}
.theme-light .nsArt__card {
  background: linear-gradient(150deg, hsl(var(--h) 70% 92% / .9), rgb(255 255 255 / .8));
}
@keyframes nsFloat { to { translate: 0 -12px; } }
.nsArt__n {
  font-family: var(--font-display); font-size: 1.6rem; line-height: 1;
  color: hsl(var(--h) 90% 72%); font-variant-numeric: tabular-nums;
}
.theme-light .nsArt__n { color: hsl(var(--h) 70% 38%); }
.nsArt__l {
  font-size: .6rem; color: var(--text-mid); text-align: center;
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
}

/* The aurora borrows the subject's hue so the whole page is tinted by it. */
.atmos__aurora[style*="--h"] {
  background:
    radial-gradient(38% 44% at 22% 28%, hsl(var(--h) 85% 60% / .16), transparent 62%),
    radial-gradient(34% 38% at 78% 22%, hsl(var(--h2) 85% 62% / .14), transparent 64%),
    radial-gradient(44% 40% at 60% 84%, rgb(240 198 74 / .08), transparent 66%);
}

@media (max-width: 62rem) { .nsArt { min-height: 16rem; } }
@media (prefers-reduced-motion: reduce) {
  .nsArt__lat, .nsArt__ring, .nsArt__card { animation: none; }
  .nsArt__stage { transition: none; }
}

/* Credit line on a resource card — legal text, so it must stay legible
   rather than being styled down to invisibility. */
.nsCard__credit {
  margin: var(--s-3) 0 0; font-size: .66rem; color: var(--text-lo);
  border-top: 1px solid var(--ns-line); padding-top: var(--s-2);
}
.nsCard__credit a { color: var(--text-mid); text-decoration: underline; }

/* ==========================================================================
   RESPONSIVE PASS
   ==========================================================================
   Checked at 1440 / 1024 / 834 / 768 / 430 / 390 / 360 / 320.

   The recurring failure on this page is not layout, it is FIXED FURNITURE:
   the mission bar, the timer, Yuna's bubble and the tour popup are all
   position:fixed or sticky, and on a 360px phone they collectively cover the
   content they are meant to support. Each rule below reclaims that space.
   ========================================================================== */

/* ── tablet ─────────────────────────────────────────────────────────────── */
@media (max-width: 64rem) {
  .nsHero { padding-block: var(--s-8) var(--s-6); }
  .nsArt { min-height: 15rem; order: -1; }
  .nsArt__glyph { font-size: clamp(6rem, 18vw, 10rem); }
  .nsArt__card { min-width: 5.5rem; padding: var(--s-2) var(--s-3); }
  .nsArt__n { font-size: 1.25rem; }
}

/* ── phone ──────────────────────────────────────────────────────────────── */
@media (max-width: 40rem) {
  /* The orbiting cards collide with each other below ~640px because the orbit
     radius cannot shrink past the card width. Below this the art becomes a
     backdrop only — the same counts are one screen down as real filter chips,
     so nothing is lost. */
  .nsArt__card { display: none; }
  .nsArt { min-height: 11rem; }
  .nsArt__glyph { font-size: 7rem; }
  .nsArt__ring--1 { inset: 20%; }
  .nsArt__ring--2 { inset: 30%; }

  .nsHero__h1 { font-size: clamp(2rem, 8vw, 2.6rem); }
  .nsHero__cta { display: grid; }
  .nsHero__cta .btn { width: 100%; justify-content: center; }

  /* Sticky bar: keep the ring and the actions, drop the sparkline. Two rows of
     furniture pinned to the top of a phone is most of the viewport. */
  .nsBar__in { gap: var(--s-3); padding-block: var(--s-2); }
  .nsBar__btn { padding: .42rem .6rem; font-size: .72rem; }

  .nsShelf__head { gap: var(--s-3); }
  .nsShelf__icon { width: 2.4rem; height: 2.4rem; }
  .nsShelf__icon::after { width: .9rem; height: .9rem; }

  .nsGrid { grid-template-columns: 1fr; }
  .nsCard__in { padding: var(--s-4); }

  /* Timer and Yuna both anchor to the bottom. On a phone the timer becomes a
     full-width sheet above the bubble rather than a floating card that would
     sit underneath it. */
  .nsTimer {
    left: var(--s-3); right: var(--s-3); bottom: var(--s-3);
    width: auto;
  }
  .nsTimer__dial { width: 8.5rem; }
  .nsTimer__read strong { font-size: 1.7rem; }

  .nsBot { right: var(--s-3); bottom: var(--s-3); }
  .nsBot__bubble { width: 3.4rem; height: 3.4rem; }
  .nsBot__panel {
    position: fixed; left: var(--s-3); right: var(--s-3); bottom: 4.6rem;
    width: auto;
  }
  .nsBot__log { max-height: 40vh; }

  /* The tour popup must never be wider than the screen or taller than the
     space left under the spotlight. */
  .nsTour__pop { width: calc(100vw - 1.5rem); padding: var(--s-4); }
  .nsTour__pop h4 { font-size: var(--fs-base); }

  .nsModal__card { max-height: 94vh; }
  .nsModal__body iframe { min-height: 70vh; }
  .nsModal__foot { flex-direction: column-reverse; }
  .nsModal__foot .btn { width: 100%; justify-content: center; }
}

/* ── small phone ────────────────────────────────────────────────────────── */
@media (max-width: 24rem) {
  .nsChip { padding: .34rem .6rem; font-size: .72rem; }
  .nsFilter { padding: .42rem .7rem; font-size: .72rem; }
  .nsBar__pct { display: none; }
  .nsShelf__head p { display: none; }   /* the shelf label already says it */
}

/* ── short viewports (landscape phone) ──────────────────────────────────── */
/* A 390x844 phone turned sideways is 390px TALL. A bottom sheet plus a sticky
   bar leaves nothing; the timer goes back to a compact card. */
@media (max-height: 32rem) and (orientation: landscape) {
  .nsTimer { left: auto; right: var(--s-3); width: min(15rem, 46vw); }
  .nsTimer__dial { width: 6rem; }
  .nsTimer__note, .nsTour__pop p { display: none; }
  .nsBot__panel { bottom: 4rem; }
  .nsBot__log { max-height: 30vh; }
}

/* Never let the page scroll sideways, whatever the art does. */
.page-notes-study { max-width: 100vw; }

/* ── PDF MODAL: above the nav ───────────────────────────────────────────────
   The modal ships at --z-modal (300) and the nav at --z-nav (100), so on
   paper the modal wins. In practice the sticky header creates its own
   stacking context that paints over it, which put the site nav across the
   modal's title bar and hid the close button behind it — the reader could see
   the PDF and had no obvious way out of it.

   Raised explicitly rather than by nudging --z-nav down: the nav's z-index is
   load-bearing for the dropdown menu on every other page, and this is the one
   component that genuinely must sit above everything. */
.page-notes-study .pdfmodal { z-index: 1000; }
/* Clear the header height so the bar and its × are never tucked under it. */
.page-notes-study .pdfmodal__panel { max-height: calc(100vh - var(--nav-h, 4.5rem) - 2rem); }
.page-notes-study .pdfmodal__x { position: relative; z-index: 2; }
