/* ─── FLOW SCHOOL — the member Video Library ─────────────────────────────────
   Shared by library.html, library-category.html, collection.html, video.html.
   Loaded AFTER global.css; everything here is built from its tokens.

   The design intent: the interface disappears behind the content. Artwork
   and typography carry the page — cards have no boxes, shelves have no
   chrome, and the only borders are hairlines doing real separating work.  */

/* ── the page ── */
.lib-page { max-width: 1280px; margin: 0 auto; padding: 40px 28px 120px; }
@media (max-width: 640px) { .lib-page { padding: 20px 16px 100px; } }
/* the search band rides above the hero in its own slice of the column;
   the body slice picks up below the hero */
.lib-page-top { padding-bottom: 0; }
.lib-page-top .explore { margin-bottom: 0; }
.lib-page-body { padding-top: 12px; }

/* ── access states (admin-only phase + signed-out) ── */
.lib-denied { max-width: 460px; margin: 120px auto; text-align: center; }
.lib-denied .material-symbols-sharp { font-size: 40px; color: var(--text-3); }
.lib-denied h1 { font-size: var(--fs-h5); font-weight: var(--weight-medium); margin: 14px 0 8px; }
.lib-denied p { color: var(--text-3); font-size: var(--text-body-sm); }

/* ── skeletons: the layout holds its shape while artwork arrives ── */
.lib-skel { border-radius: var(--r); background: rgba(var(--ink-rgb), .06);
  animation: libpulse 1.4s ease-in-out infinite; }
@keyframes libpulse { 0%,100% { opacity: .5 } 50% { opacity: 1 } }
@media (prefers-reduced-motion: reduce) { .lib-skel { animation: none; opacity: .6; } }

/* ═══ THE HERO ═══════════════════════════════════════════════════════════════
   An editorial carousel, not a row of cards. It lives OUTSIDE .lib-page and
   spans the whole content area edge to edge; --hgut aligns the first slide
   (and the dots) with the page column below, so full-bleed never reads as
   misregistered. Scroll-snap does the moving; on desktop the next feature
   peeks in from the right, which IS the affordance — the arrows only appear
   for people who hover looking for them. Nothing advances by itself and
   nothing plays by itself.                                                */
.hero { position: relative; margin: 24px 0 8px;
  --hgut: max(28px, calc((100% - 1224px) / 2)); }
.hero-track {
  display: flex; gap: 20px;
  overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none; -ms-overflow-style: none;
  padding: 0 var(--hgut);
  scroll-padding-left: var(--hgut);
}
.hero-track::-webkit-scrollbar { display: none; }
.hero-slide {
  position: relative; flex: 0 0 88%;
  scroll-snap-align: start;
  border-radius: var(--r); overflow: hidden;
  aspect-ratio: 21 / 9; background: var(--well-bg);
  color: #fff; display: flex; align-items: flex-end;
  cursor: pointer; text-decoration: none;
}
.hero-slide:hover { color: #fff; }
/* the peek exists to hint at a NEXT slide — a lone feature owns the band */
.hero-slide:only-child { flex-basis: 100%; }
.hero-slide img { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; will-change: transform;
  transition: transform 1.1s cubic-bezier(.16, 1, .3, 1); }
@media (hover: hover) { .hero-slide:hover img { transform: scale(1.03); } }
/* the scrim earns the type its legibility — it climbs well past the copy
   block and holds real darkness through it, so a bright studio wall can
   never wash the title out.
   inset -1px + translateZ: the zooming image lives on its own GPU layer,
   and without both, the scrim misregisters by a subpixel while the
   transform runs — a bright hairline of unshaded image at the bottom. */
.hero-slide::after { content: ''; position: absolute; inset: -1px;
  transform: translateZ(0);
  background: linear-gradient(to top, rgba(10,11,14,.88) 0%, rgba(10,11,14,.62) 38%, rgba(10,11,14,.22) 68%, rgba(10,11,14,.02) 100%); }
.hero-copy { position: relative; z-index: 1; padding: 32px 36px; max-width: 62ch;
  display: flex; flex-direction: column; align-items: flex-start; }
.hero-eyebrow { font-family: var(--font-mono); font-size: var(--fs-meta);
  letter-spacing: var(--ls-micro); text-transform: uppercase; color: rgba(255,255,255,.75);
  display: inline-flex; align-items: center; gap: 8px; }
.hero-eyebrow .material-symbols-sharp { font-size: 13px; }
.hero-title { font-size: clamp(24px, 3.4vw, 40px); font-weight: var(--weight-book);
  letter-spacing: var(--ls-heading); line-height: var(--lh-heading); margin: 10px 0 8px; }
.hero-desc { font-size: var(--text-body-sm); line-height: 1.5; color: rgba(255,255,255,.82);
  margin: 0 0 10px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.hero-meta { font-family: var(--font-mono); font-size: var(--fs-meta); color: rgba(255,255,255,.65); }
.hero-cta { display: inline-flex; align-items: center; gap: 8px; margin-top: 16px;
  font-size: var(--text-ui); font-weight: var(--weight-medium); color: #fff;
  transition: gap var(--transition-base); }
.hero-cta .material-symbols-sharp { font-size: var(--icon-md); }
@media (hover: hover) { .hero-slide:hover .hero-cta { gap: 12px; } }
/* the slide with no artwork yet — a quiet field, never a broken image */
.hero-slide.bare { background:
  radial-gradient(120% 160% at 85% 0%, rgba(var(--accent-rgb), .35), transparent 55%),
  linear-gradient(160deg, #23262e, #14161b); }
[data-theme="light"] .hero-slide.bare { background:
  radial-gradient(120% 160% at 85% 0%, rgba(var(--accent-rgb), .30), transparent 55%),
  linear-gradient(160deg, #3a3e48, #1d2026); }

/* the restrained controls: dots always, arrows on hover, desktop only */
.hero-nav { display: flex; align-items: center; gap: 12px; margin-top: 14px;
  padding: 0 var(--hgut); }
.hero-dots { display: flex; gap: 6px; }
.hero-dot { width: 6px; height: 6px; border-radius: 50%; border: 0; padding: 0;
  background: rgba(var(--ink-rgb), .18); cursor: pointer;
  transition: background var(--transition-base), transform var(--transition-base); }
.hero-dot.on { background: var(--accent); transform: scale(1.25); }
.hero-arrows { display: none; margin-left: auto; gap: 6px; }
@media (hover: hover) and (min-width: 900px) {
  .hero-arrows { display: flex; opacity: 0; transition: opacity var(--transition-base); }
  .hero:hover .hero-arrows, .hero:focus-within .hero-arrows { opacity: 1; }
}
.hero-arrow { display: grid; place-items: center; width: 34px; height: 34px;
  border: 1px solid var(--border-light); border-radius: 50%; background: none;
  color: var(--text-2); cursor: pointer;
  transition: color var(--transition-base), border-color var(--transition-base); }
.hero-arrow:hover { color: var(--text-1); border-color: rgba(var(--ink-rgb), .35); }
.hero-arrow .material-symbols-sharp { font-size: 16px; }
@media (max-width: 640px) {
  .hero { margin: 14px 0 0; --hgut: 16px; }
  .hero-track { gap: 12px; }
  .hero-slide { flex-basis: 92%; aspect-ratio: 4 / 3; }
  .hero-copy { padding: 18px 20px; }
  .hero-desc { display: none; }
}

/* ═══ SEARCH — the question, not a toolbar ═══════════════════════════════════
   A headline and an underlined field. The input is borderless because the
   page is quiet; the hairline wakes to the accent on focus.              */
.explore { margin: 0 0 44px; }
.explore-row { display: flex; align-items: center; gap: 14px;
  border-bottom: 1px solid var(--border); padding-bottom: 10px;
  transition: border-color var(--transition-base); }
.explore-row:focus-within { border-color: rgba(var(--ink-rgb), .60); }
.explore-row > .material-symbols-sharp { font-size: var(--icon-lg); color: var(--text-3); flex: none; }
.explore-input { flex: 1; min-width: 0; border: 0; background: none; outline: none;
  font-family: var(--font); font-size: var(--fs-h7); color: var(--text-1); padding: 6px 0; }
.explore-input::placeholder { color: var(--text-4); }
/* type="search" brings the browser's own ✕ — the app's clear button is the
   one true clear, so the native twin goes */
.explore-input::-webkit-search-cancel-button,
.explore-input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }
/* the quiet keycap that teaches the shortcut — pointer devices only, and
   it steps aside the moment the field is in use */
.explore-kbd { display: none; }
@media (hover: hover) {
  .explore-kbd { display: grid; place-items: center; flex: none;
    min-width: 22px; height: 22px; padding: 0 5px;
    border: 1px solid var(--border-light); border-radius: var(--rf);
    font-family: var(--font-mono); font-size: var(--fs-meta); color: var(--text-4); }
  .explore-row:focus-within .explore-kbd,
  .explore-row.has-q .explore-kbd { display: none; }
}
.explore-clear { display: none; border: 0; background: none; cursor: pointer;
  color: var(--text-3); padding: 6px; }
.explore-clear:hover { color: var(--text-1); }
.explore-clear .material-symbols-sharp { font-size: 16px; }
.explore-row.has-q .explore-clear { display: grid; place-items: center; }

/* the filter door sits with the search — one discovery instrument */
.filter-btn { display: inline-flex; align-items: center; gap: 8px; flex: none;
  border: 1px solid var(--border-light); border-radius: 999px;
  background: none; cursor: pointer; padding: 9px 16px;
  font-family: var(--font); font-size: var(--text-ui); color: var(--text-2);
  transition: color var(--transition-base), border-color var(--transition-base); }
.filter-btn:hover { color: var(--text-1); border-color: rgba(var(--ink-rgb), .35); }
.filter-btn .material-symbols-sharp { font-size: var(--icon-md); }
.filter-btn .n { font-family: var(--font-mono); font-size: var(--fs-meta);
  color: var(--accent); }
.filter-btn.on { color: var(--accent); border-color: var(--accent-border); }

/* active filters, readable and removable in place */
.active-filters { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.active-filters[hidden] { display: none; }   /* flex outranks the UA's [hidden] */
.filter-btn[hidden] { display: none; }       /* same trap — inline-flex outranks it too */
.af-chip { display: inline-flex; align-items: center; gap: 6px;
  border: 0; border-radius: 999px; cursor: pointer; padding: 6px 12px;
  background: var(--accent-dim); color: var(--accent);
  font-family: var(--font); font-size: var(--fs-label-1); }
.af-chip .material-symbols-sharp { font-size: 13px; }
.af-clear { border: 0; background: none; cursor: pointer; padding: 6px 4px;
  font-family: var(--font); font-size: var(--fs-label-1); color: var(--text-3); }
.af-clear:hover { color: var(--text-1); }

/* ── the filter panel: popover on desktop, sheet on touch ── */
.fil-veil { position: fixed; inset: 0; z-index: 300; background: rgba(0,0,0,.4);
  opacity: 0; transition: opacity var(--transition-base); }
.fil-veil.open { opacity: 1; }
.fil-panel { position: fixed; z-index: 301; background: var(--paper-solid);
  border: 1px solid var(--border-light); box-shadow: var(--shadow-float);
  display: flex; flex-direction: column; }
@media (min-width: 761px) {
  .fil-panel { top: 0; right: 0; bottom: 0; width: min(400px, 92vw);
    border-radius: 0; border-width: 0 0 0 1px; padding: 24px 26px;
    transform: translateX(8%); opacity: 0;
    transition: transform var(--transition-base), opacity var(--transition-base); }
  .fil-panel.open { transform: none; opacity: 1; }
}
@media (max-width: 760px) {
  .fil-panel { left: 0; right: 0; bottom: 0; max-height: 82vh;
    border-radius: var(--r) var(--r) 0 0; border-width: 1px 0 0 0; padding: 10px 20px 24px;
    transform: translateY(100%); transition: transform .3s ease; }
  .fil-panel.open { transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .fil-panel, .fil-veil { transition: opacity 90ms ease; transform: none !important; }
}
.fil-grabber { width: 36px; height: 4px; border-radius: 999px; margin: 4px auto 10px;
  background: rgba(var(--ink-rgb), .18); }
@media (min-width: 761px) { .fil-grabber { display: none; } }
.fil-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.fil-head h2 { font-size: var(--fs-h6); font-weight: var(--weight-medium); }
.fil-body { overflow-y: auto; flex: 1; padding-bottom: 8px; }
.fil-group { padding: 16px 0; border-bottom: 1px solid var(--border-light); }
.fil-group:last-child { border-bottom: 0; }
.fil-group-name { font-family: var(--font-mono); font-size: var(--fs-meta);
  letter-spacing: var(--ls-micro); text-transform: uppercase; color: var(--text-3);
  margin-bottom: 12px; }
.fil-opts { display: flex; flex-wrap: wrap; gap: 8px; }
.fil-opt { display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid rgba(var(--ink-rgb), .16); border-radius: 999px;
  background: none; cursor: pointer; padding: 8px 14px;
  font-family: var(--font); font-size: var(--fs-label-1); color: var(--text-2);
  transition: color var(--transition-base), border-color var(--transition-base),
              background var(--transition-base); }
.fil-opt:hover { color: var(--text-1); }
.fil-opt.on { background: var(--accent-dim); border-color: transparent; color: var(--accent); }
.fil-opt .material-symbols-sharp { font-size: 13px; }
.fil-actions { display: flex; gap: 10px; align-items: center; padding-top: 14px;
  border-top: 1px solid var(--border-light); }
.fil-actions .btn-primary { padding: 12px 22px; font-size: var(--text-ui); margin-left: auto; }

/* ── the library's view tabs: All · Continue watching · Saved ──
   The video page's tab grammar, promoted to the library. Sits tight under
   the search band; the count is a quiet mono whisper, not a badge. */
.lib-view { margin: 0 0 36px; }
/* .wtabs' display:flex outranks the UA's [hidden] rule — without this
   guard the row can never actually hide (search mode relies on it) */
.lib-view[hidden] { display: none; }
.wtab-n { font-family: var(--font-mono); font-size: var(--fs-meta);
  color: var(--text-3); margin-left: 7px; }

/* ═══ SHELVES ════════════════════════════════════════════════════════════════
   A shelf is a heading and a row of artwork. The row scrolls past the page
   gutter so motion feels free; a mask fades content at the edges instead
   of clipping it dead.                                                    */
.shelf { margin-bottom: 52px; }
.shelf-head { display: flex; align-items: baseline; gap: 16px; margin-bottom: 6px; }
.shelf-id { flex: 1; min-width: 0; }
/* no weight declared on purpose: the global heading rules own it, so the
   shelf name wears the same editorial book weight as every other headline
   ("What do you want to explore?", the hero title) — bigger-but-lighter */
/* 28px on desktop, easing to 23px on narrow screens — the viewport-
   tracking middle keeps the step continuous, never a jump */
.shelf-name { font-size: clamp(23px, 2.4vw, 28px); letter-spacing: var(--ls-heading); }
/* the supporting line: a step above body copy, a clear step under the name */
.shelf-sub { font-size: var(--fs-h7); font-weight: var(--weight-regular);
  color: var(--text-2); margin: 3px 0 0; line-height: var(--lh-tight);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.shelf-name a { color: inherit; text-decoration: none; }
.shelf-desc { font-size: var(--text-body-sm); color: var(--text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 1; }
.shelf-all { flex: none; font-size: var(--text-ui); color: var(--text-3);
  text-decoration: none; display: inline-flex; align-items: center; gap: 6px;
  transition: color var(--transition-base), gap var(--transition-base); }
.shelf-all .material-symbols-sharp { font-size: 14px; }
.shelf-all:hover { color: var(--text-1); gap: 9px; }
.shelf-row { display: flex; gap: 18px; overflow-x: auto;
  scroll-snap-type: x mandatory; scrollbar-width: none;
  margin: 0 -28px; padding: 20px 28px 8px; scroll-padding-left: 28px; }
.shelf-row::-webkit-scrollbar { display: none; }
.shelf-row > * { scroll-snap-align: start; }
@media (max-width: 640px) {
  .shelf { margin-bottom: 40px; }
  .shelf-row { margin: 0 -16px; padding: 20px 16px 8px; scroll-padding-left: 16px; gap: 12px; }
  .shelf-desc { display: none; }
}

/* ═══ CARDS ══════════════════════════════════════════════════════════════════
   No boxes. A card is its artwork, a title, and one mono line — the same
   anatomy for videos and collections, with the collection wearing a quiet
   stacked edge behind its art so "there is more inside" reads at a glance. */
.vcard { flex: 0 0 260px; min-width: 0; text-decoration: none; color: inherit;
  display: flex; flex-direction: column; gap: 10px; }
.vcard-grid .vcard { flex: initial; }
@media (max-width: 640px) { .shelf-row .vcard { flex-basis: 200px; } }
.vcard-art { position: relative; aspect-ratio: 16 / 9; border-radius: var(--rs);
  overflow: hidden; background: var(--well-bg); box-shadow: var(--well); }
/* a thumbnail that hasn't arrived is INVISIBLE (no broken-image glyph,
   no well hairlines) — the frame breathes like every other skeleton,
   then the image fades in on load */
.vcard-art img[data-mv-thumb], .vcard-art img[data-tf-thumb] {
  opacity: 0;
  /* opacity JOINS the artwork's transition list — this selector outranks
     .vcard-art img, so dropping transform/filter here would kill the
     slow-zoom easing on hover (it did, briefly) */
  transition: opacity .45s ease,
    transform .7s cubic-bezier(.16, 1, .3, 1),
    filter .7s cubic-bezier(.16, 1, .3, 1); }
.vcard-art img.mv-in { opacity: 1; }
.vcard-art:has(img[data-mv-thumb]:not(.mv-in))::before,
.vcard-art:has(img[data-tf-thumb]:not(.mv-in))::before {
  content: ''; position: absolute; inset: 0;
  background: rgba(var(--ink-rgb), .06);
  animation: libpulse 1.4s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  .vcard-art:has(img[data-mv-thumb]:not(.mv-in))::before,
  .vcard-art:has(img[data-tf-thumb]:not(.mv-in))::before { animation: none; opacity: .6; }
}
/* Hover is the ARTWORK's moment, not the type's: a slow zoom with a
   gentle brightening, like light falling on the thing you're reaching
   for. The title never changes — the content responds, the interface
   stays still. */
.vcard-art img { width: 100%; height: 100%; object-fit: cover; display: block;
  will-change: transform;
  transition: transform .7s cubic-bezier(.16, 1, .3, 1), filter .7s cubic-bezier(.16, 1, .3, 1); }
@media (hover: hover) {
  .vcard:hover .vcard-art img { transform: scale(1.04); filter: brightness(1.06); }
}
@media (prefers-reduced-motion: reduce) {
  .vcard-art img, .hero-slide img, .pl-thumb img { transition: none !important; transform: none !important; }
}
.vcard-art .bare-glyph { position: absolute; inset: 0; display: grid; place-items: center;
  color: var(--text-4); }
.vcard-art .bare-glyph .material-symbols-sharp { font-size: 22px; opacity: .5; }
.vcard-dur { position: absolute; right: 8px; bottom: 8px;
  font-family: var(--font-mono); font-size: var(--fs-meta); color: #fff;
  background: rgba(0,0,0,.6); padding: 2px 6px; border-radius: var(--rf); }
/* a member video with no published placement wears its lock top-left */
.mv-private { position: absolute; left: 8px; top: 8px; display: inline-flex;
  align-items: center; gap: 5px; font-family: var(--font-mono); font-size: var(--fs-meta);
  text-transform: uppercase; letter-spacing: .08em; white-space: nowrap;
  /* the duration badge's dress — white on smoke, readable over any artwork */
  color: #fff; background: rgba(0,0,0,.6); padding: 2px 6px; border-radius: var(--rf); }
.mv-private .material-symbols-sharp { font-size: 12px; }
/* a placed video wears the globe in the accent — solid, so the state
   reads over any artwork */
.mv-shared { color: var(--paper-solid); background: var(--accent); }
/* member-video cards speak their meta in caps, like the other libraries */
.mv-card .vcard-meta { text-transform: uppercase; letter-spacing: .04em; transition: color var(--transition-base); }
.mv-card:hover .vcard-meta { color: var(--text-1); }
/* where you are in a started video: a thin line along the artwork's foot.
   Accent because progress IS state; capped at 96% in JS so a nearly-done
   video still visibly has a sliver to go. */
.vcard-progress { position: absolute; left: 0; right: 0; bottom: 0; height: 3px;
  background: rgba(0,0,0,.45); }
.vcard-progress > span { display: block; height: 100%; background: var(--accent); }
/* ── the collection deck: REAL images stacked behind the cover ──
   Each sheet is an actual thumbnail from inside the collection, narrowed
   and lifted so a strip of it shows above the cover; a veil dims each
   step back so depth reads as depth. Sheets without art yet hold the
   quiet tinted edge until their signed still arrives. */
.vcard.is-collection .vcard-art { overflow: visible; border-radius: var(--rs); }
.vcard.is-collection .vcard-art > .vcard-art-in { position: absolute; inset: 0;
  border-radius: var(--rs); overflow: hidden;
  /* opaque paper under the translucent well — the sheets behind must never
     ghost through an art-less or still-loading cover */
  background: linear-gradient(var(--well-bg), var(--well-bg)) var(--paper-solid);
  box-shadow: 0 -3px 10px rgba(10, 11, 14, .22); }
.vcard-stack { position: absolute; inset: 0;
  border-radius: var(--rs) var(--rs) 0 0; overflow: hidden;
  background: rgba(var(--ink-rgb), .08);
  transform-origin: bottom center;
  transition: transform .7s cubic-bezier(.16, 1, .3, 1); }
.vcard-stack img { width: 100%; height: 100%; object-fit: cover; display: block; }
.vcard-stack::after { content: ''; position: absolute; inset: 0; }
.vcard-stack.vs-1 { transform: translateY(-6px) scaleX(.94); }
.vcard-stack.vs-1::after { background: rgba(10, 11, 14, .30); }
.vcard-stack.vs-2 { transform: translateY(-12px) scaleX(.88); }
.vcard-stack.vs-2::after { background: rgba(10, 11, 14, .48); }
/* the deck breathes on hover — the sheets fan a breath further while the
   cover does the cards' zoom */
@media (hover: hover) {
  .vcard.is-collection:hover .vcard-stack.vs-1 { transform: translateY(-9px) scaleX(.94); }
  .vcard.is-collection:hover .vcard-stack.vs-2 { transform: translateY(-17px) scaleX(.88); }
}
@media (prefers-reduced-motion: reduce) {
  .vcard-stack { transition: none !important; }
}
.vcard-title { font-size: var(--text-body-sm); font-weight: var(--weight-medium);
  line-height: var(--lh-tight); letter-spacing: var(--ls-ui);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.vcard-meta { font-family: var(--font-mono); font-size: var(--fs-meta); color: var(--text-3);
  display: inline-flex; align-items: center; gap: 6px; }
.vcard-meta .material-symbols-sharp { font-size: 12px; }

/* ── managing the personal galleries: one quiet control per card ──
   Rides .btn-icon for its tooltip and focus behavior; sized down and
   hover-revealed so the artwork stays the card. Touch gets it always —
   an affordance you must hover to find does not exist on a phone. */
.card-manage { position: absolute; top: 8px; right: 8px; z-index: 2;
  width: 30px; height: 30px; border: 0; border-radius: var(--rb);
  background: var(--paper-solid); color: var(--text-2); box-shadow: var(--shadow-float);
  opacity: 0; transition: opacity var(--transition-base), color var(--transition-base); }
.card-manage .material-symbols-sharp { font-size: 15px; }
.card-manage:hover { color: var(--text-1); background: var(--paper-solid); border: 0; }
.vcard:hover .card-manage, .card-manage:focus-visible { opacity: 1; }
@media (hover: none) { .card-manage { opacity: 1; } }

/* results / category grids */
.vcard-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 26px 18px; padding-top: 14px; }
@media (max-width: 640px) { .vcard-grid { grid-template-columns: repeat(2, 1fr); gap: 20px 12px; } }

/* results framing */
.results-head { display: flex; align-items: baseline; gap: 12px; margin: 0 0 18px; }
.results-head h2 { font-size: var(--fs-h6); font-weight: var(--weight-medium) !important; }
.results-count { font-family: var(--font-mono); font-size: var(--fs-meta); color: var(--text-3); }
.lib-empty { padding: 64px 20px; text-align: center; }
.lib-empty h3 { font-size: var(--fs-h6); font-weight: var(--weight-medium) !important; margin-bottom: 6px; }
.lib-empty p { font-size: var(--text-body-sm); color: var(--text-3); max-width: 44ch; margin: 0 auto; }

/* ═══ CATEGORY PAGE ══════════════════════════════════════════════════════════ */
.cat-hero { position: relative; border-radius: var(--r); overflow: hidden;
  margin-bottom: 20px; }
.cat-hero img { width: 100%; aspect-ratio: 21 / 7; object-fit: cover; display: block; }
@media (max-width: 640px) { .cat-hero img { aspect-ratio: 16 / 9; } }
.cat-title { font-size: clamp(28px, 4vw, 44px); font-weight: var(--weight-book);
  letter-spacing: var(--ls-heading); margin: 18px 0 10px; }
.cat-sub { font-size: clamp(17px, 1.8vw, 21px); font-weight: var(--weight-regular);
  color: var(--text-2); line-height: var(--lh-tight); max-width: 68ch; margin: -4px 0 16px; }
.cat-desc { font-size: var(--text-body); line-height: var(--lh-body); color: var(--text-2);
  max-width: 68ch; margin: 0 0 36px; white-space: pre-line; }
/* the way back is the site's glass bar (.post-bar, global.css) — the old
   inline .lib-crumb retired with v7.1.7 */
.lib-page-underbar { padding-top: 0; }

/* ═══ COLLECTION PAGE ════════════════════════════════════════════════════════ */
.col-hero { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: 36px; align-items: start; margin-bottom: 48px; }
@media (max-width: 860px) { .col-hero { grid-template-columns: 1fr; gap: 20px; } }
.col-hero-art { position: relative; aspect-ratio: 16 / 9; border-radius: var(--r);
  overflow: hidden; background: var(--well-bg); box-shadow: var(--well); }
.col-hero-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.col-hero-eyebrow { font-family: var(--font-mono); font-size: var(--fs-meta);
  letter-spacing: var(--ls-micro); text-transform: uppercase; color: var(--text-3);
  display: inline-flex; align-items: center; gap: 8px; }
.col-hero-eyebrow .material-symbols-sharp { font-size: 13px; }
.col-hero h1 { font-size: clamp(26px, 3.2vw, 38px); font-weight: var(--weight-book);
  letter-spacing: var(--ls-heading); line-height: var(--lh-heading); margin: 10px 0 10px; }
.col-hero-meta { font-family: var(--font-mono); font-size: var(--fs-meta); color: var(--text-3);
  margin-bottom: 14px; }
.col-hero-desc { font-size: var(--text-body-sm); line-height: var(--lh-body); color: var(--text-2);
  white-space: pre-line; margin-bottom: 20px; }
.col-hero-desc.rich-text { white-space: normal; }   /* rich markup draws its own breaks */
.col-start { display: inline-flex; align-items: center; gap: 10px; }
.col-start .btn-primary { display: inline-flex; align-items: center; gap: 8px;
  padding: 13px 24px; font-size: var(--text-ui); }
.col-start .btn-primary .material-symbols-sharp { font-size: var(--icon-md); }

/* what's inside */
.inside-h { font-size: var(--fs-h6); font-weight: var(--weight-medium) !important; margin: 0 0 18px; }
.pl-divider { font-family: var(--font-mono); font-size: var(--fs-meta);
  letter-spacing: var(--ls-micro); text-transform: uppercase; color: var(--text-3);
  margin: 26px 0 12px; display: flex; align-items: center; gap: 14px; }
.pl-divider::after { content: ''; flex: 1; height: 1px; background: var(--border-light); }
.pl-divider:first-child { margin-top: 0; }
.pl-row { display: flex; align-items: center; gap: 16px; padding: 10px 0;
  text-decoration: none; color: inherit; border-radius: var(--rs); }
.pl-row + .pl-row { border-top: 1px solid var(--border-light); }
.pl-num { font-family: var(--font-mono); font-size: var(--fs-meta); color: var(--text-3);
  width: 22px; text-align: right; flex: none; }
.pl-thumb { position: relative; width: 132px; aspect-ratio: 16 / 9; flex: none;
  border-radius: var(--rs); overflow: hidden; background: var(--well-bg); box-shadow: var(--well); }
.pl-thumb img { width: 100%; height: 100%; object-fit: cover; display: block;
  will-change: transform;
  transition: transform .7s cubic-bezier(.16, 1, .3, 1), filter .7s cubic-bezier(.16, 1, .3, 1); }
/* one hover grammar everywhere: the CONTENT responds, the type stays
   still — same zoom-and-brighten the cards use */
@media (hover: hover) {
  .pl-row:hover .pl-thumb img { transform: scale(1.04); filter: brightness(1.06); }
}
.pl-thumb .material-symbols-sharp { position: absolute; inset: 0; display: grid;
  place-items: center; font-size: 18px; color: var(--text-4); }
.pl-body { flex: 1; min-width: 0; }
.pl-title { font-size: var(--fs-h7); font-weight: var(--weight-medium);
  letter-spacing: var(--ls-ui);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pl-sub { font-family: var(--font-mono); font-size: var(--fs-meta); color: var(--text-3); margin-top: 3px;
  display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pl-dur { font-family: var(--font-mono); font-size: var(--fs-meta); color: var(--text-3); flex: none; }
/* watched: the check takes the number's seat, and the row steps back a
   little — done things go quiet, the next thing stays forward */
.pl-check { font-size: 14px; color: var(--text-3); }
.pl-row.done .pl-title { color: var(--text-2); }
.pl-row.done .pl-thumb { opacity: .75; }
@media (max-width: 640px) {
  .pl-thumb { width: 96px; }
  /* numbers yield to the tight row; the watched check is worth its space */
  .pl-num { display: none; }
  .pl-row.done .pl-num { display: block; width: auto; }
}

/* ═══ VIDEO PAGE ═════════════════════════════════════════════════════════════ */
.watch { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0 36px; }
/* the video owns the page: ~75% player, ~25% rail. The rail keeps just
   enough to stay readable; below that it drops to the fold instead. */
.watch.with-rail { grid-template-columns: minmax(0, 3fr) minmax(210px, 1fr); }
@media (max-width: 1040px) { .watch.with-rail { grid-template-columns: 1fr; } }
.player-well { position: relative; aspect-ratio: 16 / 9; border-radius: var(--r);
  overflow: hidden; background: #000; }
.player-well mux-player { width: 100%; height: 100%; --media-object-fit: contain; }
/* the big play control wears the dashboard seal's exact dress: translucent
   dark scrim, white glyph, deepening on hover — one play language site-wide */
mux-player::part(center play button) {
  background: rgba(0, 0, 0, .6);
  color: #fff;
  transition: background var(--transition-base);
}
mux-player::part(center play button):hover { background: rgba(0, 0, 0, .75); }
/* below Mux's small breakpoint (player < 484px) the center button collapses
   to a bare 40px glyph — no padding, no radius — so our scrim showed as a
   square smaller than the icon. Give it a real seal on phones too. */
.player-well { container-type: inline-size; }
@container (max-width: 483px) {
  mux-player::part(center play button) {
    width: 64px; height: 64px; padding: 18px; border-radius: 50%;
    box-sizing: border-box;
  }
}
.player-well .lib-skel { position: absolute; inset: 0; border-radius: 0; }
.player-msg { position: absolute; inset: 0; display: grid; place-items: center;
  color: rgba(255,255,255,.75); font-size: var(--text-body-sm); padding: 20px; text-align: center; }

.watch-head { display: flex; align-items: flex-start; gap: 16px; margin: 20px 0 6px; }
.watch-head h1 { font-size: clamp(20px, 2.4vw, 28px); font-weight: var(--weight-medium) !important;
  letter-spacing: var(--ls-heading); line-height: var(--lh-heading); flex: 1; min-width: 0; }
.watch-meta { font-family: var(--font-mono); font-size: var(--fs-meta); color: var(--text-3);
  margin-bottom: 20px; }
.watch-meta a { color: inherit; text-decoration: none; }
.watch-meta a:hover { color: var(--text-1); }
/* Save/Share are the app's own .btn-icon (global.css) — the bookmark fills
   via .saved, the tooltip names the glyph. No page-local button dialect. */
.watch-actions { display: flex; gap: 8px; flex: none; padding-top: 2px; }

/* ── chapters: a quiet strip riding under the player ──
   Mono times, plain names, the current one lit — a map you can touch
   without leaving the moment. Scrolls sideways past the frame edge. */
.chap-strip { display: flex; gap: 8px; overflow-x: auto; margin-top: 12px;
  padding-bottom: 4px; scrollbar-width: none; }
.chap-strip::-webkit-scrollbar { display: none; }
.chap-strip[hidden] { display: none; }   /* flex outranks the UA's [hidden] */
.chap-chip { display: inline-flex; align-items: baseline; gap: 8px; flex: none;
  max-width: 260px; border: 1px solid rgba(var(--ink-rgb), .28); border-radius: 999px;
  background: none; cursor: pointer; padding: 7px 14px;
  transition: color var(--transition-base), border-color var(--transition-base),
              background var(--transition-base); }
.chap-chip-time { font-family: var(--font-mono); font-size: var(--fs-meta);
  color: var(--text-3); flex: none; }
.chap-chip-name { font-family: var(--font); font-size: var(--fs-label-1);
  color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chap-chip:hover .chap-chip-name { color: var(--text-1); }
/* selected inverts to solid ink, like every selectable chip */
.chap-chip.on { background: var(--ink-solid); border-color: var(--ink-solid); }
.chap-chip.on .chap-chip-time, .chap-chip.on .chap-chip-name { color: var(--paper-solid); }

/* ── the collection rail (desktop) / fold (mobile) ── */
.rail { position: sticky; top: 20px; align-self: start;
  border-left: 1px solid var(--border-light); padding-left: 24px;
  display: flex; flex-direction: column; max-height: calc(100vh - 40px); }
.rail-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 4px; }
.rail-eyebrow { font-family: var(--font-mono); font-size: var(--fs-meta);
  letter-spacing: var(--ls-micro); text-transform: uppercase; color: var(--text-3); }
.rail-title { font-size: var(--fs-h7); font-weight: var(--weight-medium); margin: 2px 0 2px; }
.rail-title a { color: inherit; text-decoration: none; }
.rail-title a:hover { color: var(--accent); }
.rail-pos { font-family: var(--font-mono); font-size: var(--fs-meta); color: var(--text-3); }
.rail-toggle { margin-left: auto; border: 0; background: none; cursor: pointer;
  color: var(--text-3); padding: 4px; }
.rail-toggle:hover { color: var(--text-1); }
.rail-toggle .material-symbols-sharp { font-size: 16px; transition: transform var(--transition-base); }
.rail.closed .rail-toggle .material-symbols-sharp { transform: rotate(180deg); }
.rail-list { overflow-y: auto; margin-top: 12px; scrollbar-width: thin; }
.rail.closed .rail-list { display: none; }
.rail-div { font-family: var(--font-mono); font-size: var(--fs-meta);
  letter-spacing: var(--ls-micro); text-transform: uppercase; color: var(--text-3);
  margin: 16px 0 8px; }
.rail-div:first-child { margin-top: 0; }
.rail-item { display: flex; align-items: center; gap: 10px; padding: 8px 8px;
  margin: 0 -8px; border-radius: var(--rs); text-decoration: none; color: inherit;
  transition: background var(--transition-base); }
.rail-item:hover { background: rgba(var(--ink-rgb), .04); }
.rail-item.now { background: var(--accent-dim); }
.rail-item.now .ri-title { color: var(--accent); }
.ri-num { font-family: var(--font-mono); font-size: var(--fs-meta); color: var(--text-3);
  width: 18px; text-align: right; flex: none; }
.ri-title { flex: 1; min-width: 0; font-size: var(--text-ui);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ri-dur { font-family: var(--font-mono); font-size: var(--fs-meta); color: var(--text-3); flex: none; }
/* watched rail entries: the check sits where the number was, the title
   steps back — same grammar as the collection page's playlist */
.ri-check { font-size: 13px; color: var(--text-3); }
.rail-item.done .ri-title { color: var(--text-3); }

/* mobile collection fold under the player */
.fold { display: none; }
@media (max-width: 1040px) {
  .watch.with-rail .rail { display: none; }
  .fold { display: block; margin-top: 14px; border: 1px solid var(--border-light);
    border-radius: var(--r); overflow: hidden; }
  .fold-bar { display: flex; align-items: center; gap: 10px; width: 100%;
    padding: 12px 16px; border: 0; background: none; cursor: pointer;
    font-family: var(--font); font-size: var(--text-ui); color: var(--text-1); text-align: left; }
  .fold-bar .pos { font-family: var(--font-mono); font-size: var(--fs-meta); color: var(--text-3); flex: none; }
  .fold-bar .name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .fold-bar .material-symbols-sharp { font-size: 16px; color: var(--text-3);
    transition: transform var(--transition-base); }
  .fold.open .fold-bar .material-symbols-sharp { transform: rotate(180deg); }
  .fold-list { display: none; padding: 0 8px 8px; }
  .fold.open .fold-list { display: block; }
}

/* ── Up Next ── */
.upnext { position: absolute; inset: 0; z-index: 5; display: grid; place-items: center;
  background: rgba(8,9,12,.86); color: #fff; text-align: center; padding: 20px; }
.upnext[hidden] { display: none; }
.upnext-card { max-width: 360px; }
.upnext-cap { font-family: var(--font-mono); font-size: var(--fs-meta);
  letter-spacing: var(--ls-micro); text-transform: uppercase; color: rgba(255,255,255,.65); }
.upnext-thumb { width: 240px; aspect-ratio: 16/9; border-radius: var(--rs);
  overflow: hidden; margin: 12px auto; background: rgba(255,255,255,.08); }
.upnext-thumb img { width: 100%; height: 100%; object-fit: cover; }
.upnext-title { font-size: var(--fs-h7); font-weight: var(--weight-medium); margin-bottom: 2px; }
.upnext-dur { font-family: var(--font-mono); font-size: var(--fs-meta); color: rgba(255,255,255,.65); }
.upnext-actions { display: flex; align-items: center; justify-content: center; gap: 14px; margin-top: 16px; }
.upnext-play { display: inline-flex; align-items: center; gap: 8px;
  background: #fff; color: #111; border: 0; border-radius: var(--rb);
  padding: 11px 20px; cursor: pointer; font-family: var(--font);
  font-size: var(--text-ui); font-weight: var(--weight-medium); }
.upnext-play .material-symbols-sharp { font-size: var(--icon-md); }
.upnext-count { font-family: var(--font-mono); font-size: var(--fs-meta); color: rgba(255,255,255,.65); }
.upnext-auto { display: inline-flex; align-items: center; gap: 8px;
  border: 0; background: none; color: rgba(255,255,255,.75); cursor: pointer;
  font-family: var(--font); font-size: var(--fs-label-1); }
.upnext-auto .tog { width: 30px; height: 18px; border-radius: 999px;
  background: rgba(255,255,255,.25); position: relative; transition: background var(--transition-base); }
.upnext-auto .tog::after { content: ''; position: absolute; top: 2px; left: 2px;
  width: 14px; height: 14px; border-radius: 50%; background: #fff;
  transition: transform var(--transition-base); }
.upnext-auto.on .tog { background: var(--accent); }
.upnext-auto.on .tog::after { transform: translateX(12px); }
/* a phone's 16:9 well is ~220px tall — the stacked card cannot fit, so it
   lies down: thumb beside the words, actions on their own row, everything
   inside the frame including the player's own control bar */
@media (max-width: 640px) {
  .upnext { padding: 12px 14px 40px; }
  .upnext-card { max-width: none; width: 100%; text-align: left;
    display: grid; grid-template-columns: 96px minmax(0, 1fr);
    gap: 0 12px; align-items: center; }
  .upnext-cap { grid-column: 1 / -1; margin-bottom: 8px; }
  .upnext-thumb { width: 96px; margin: 0; grid-row: 2 / 4; }
  .upnext-title { font-size: var(--text-ui);
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .upnext-actions { grid-column: 1 / -1; justify-content: flex-start; margin-top: 12px; }
  .upnext-play { padding: 8px 14px; }
  .upnext-count { grid-column: 1 / -1; }
}

/* ═══ TABS — a hairline, not a toolbar ═══════════════════════════════════════ */
.wtabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border-light);
  margin: 8px 0 24px; overflow-x: auto; scrollbar-width: none; }
.wtabs::-webkit-scrollbar { display: none; }
/* a tab that is yours alone wears the lock (Notes here, Your Past
   Submissions on Teacher Practice) */
.wtab-lock { font-size: 13px; margin-right: 6px; vertical-align: -2px; }

/* ── Inspired: the flows members made from a sequence starter ───────────── */
.insp-strip { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  background: rgba(var(--ink-rgb), .045); border-radius: var(--r); padding: 14px 18px; margin: 0 0 24px; }
.insp-strip p { margin: 0; flex: 1; min-width: 220px; font-size: var(--text-body-sm); color: var(--text-2); }
.insp-strip p b { font-weight: var(--weight-medium); color: var(--text-1); }
.insp-strip .btn-primary, .insp-strip .btn-secondary { flex-shrink: 0; }
.insp-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 28px 20px; }
.insp-by { display: flex; align-items: center; gap: 8px; min-width: 0; margin-top: 10px; }
.insp-ava { width: 22px; height: 22px; border-radius: 50%; flex: none; overflow: hidden;
  background: rgba(var(--ink-rgb), .1); display: grid; place-items: center; font-size: 11px; color: var(--text-3); }
.insp-ava img { width: 100%; height: 100%; object-fit: cover; display: block; }
.insp-by-name { font-size: var(--fs-meta); color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.insp-note { text-transform: none; letter-spacing: 0; font-family: var(--font); font-size: var(--text-body-sm);
  color: var(--text-3); line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.insp-about { margin: 22px 0 0; font-size: var(--text-body-sm); }
.insp-about button { display: inline-flex; align-items: center; gap: 6px; border: 0; background: none; padding: 0;
  color: var(--text-1); font: inherit; cursor: pointer; text-decoration: underline; text-underline-offset: 3px; }
.insp-about button .material-symbols-sharp { font-size: 16px; text-decoration: none; }
.wtab { border: 0; background: none; cursor: pointer; padding: 10px 14px;
  font-family: var(--font); font-size: var(--text-ui); color: var(--text-3);
  border-bottom: 2px solid transparent; margin-bottom: -1px; white-space: nowrap;
  transition: color var(--transition-base), border-color var(--transition-base); }
.wtab:hover { color: var(--text-1); }
.wtab.on { color: var(--text-1); border-bottom-color: var(--accent); }
.wpane { max-width: 76ch; }
/* the Inspired pane is a grid, not a paragraph: it takes the whole column */
#pane-inspired { max-width: none; }
.wpane[hidden] { display: none; }
.wpane .about-desc { font-size: var(--text-body-sm); line-height: 1.65; color: var(--text-2);
  white-space: pre-line; }
/* rich descriptions bring their own structure — pre-line would double
   every break the markup already draws */
.wpane .about-desc.rich-text { white-space: normal; }
.rich-text p { margin: 0 0 12px; }
.rich-text p:last-child { margin-bottom: 0; }
.rich-text ul, .rich-text ol { margin: 0 0 12px; padding-left: 22px; }
.rich-text li { margin-bottom: 4px; }
.rich-text strong, .rich-text b { font-weight: var(--weight-medium); color: var(--text-1); }
.rich-text a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.rich-text a:hover { text-decoration: none; }
/* ── appears in: the collections that hold this video ── */
.appears-in { margin-top: 32px; }
.ai-head { font-family: var(--font-mono); font-size: var(--fs-meta);
  letter-spacing: var(--ls-micro); text-transform: uppercase; color: var(--text-3);
  margin-bottom: 14px; }
.appears-in .vcard-grid { grid-template-columns: repeat(auto-fill, minmax(220px, 260px)); }

.about-tags { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 20px; }
.about-tag { font-family: var(--font-mono); font-size: 10px; text-transform: uppercase; letter-spacing: .08em; color: var(--text-2); background: var(--sidebar-bg); border: 0; border-radius: var(--rf); padding: 4px 9px; white-space: nowrap; }

/* ── notes ── */
.note-composer { display: flex; flex-direction: column; gap: 10px; margin-bottom: 26px; }
/* the composers wear the app's own recessed well (.modal-input in the
   markup); this only adds the textarea-specific behavior on top */
textarea.note-input { min-height: 52px; resize: none; display: block; line-height: 1.6; }
.note-composer-row { display: flex; align-items: center; gap: 12px; }
.note-at { display: inline-flex; align-items: center; gap: 6px; border: 0; cursor: pointer;
  font-family: var(--font-mono); font-size: var(--fs-meta);
  border-radius: var(--rf); padding: 4px 8px;
  background: var(--accent-dim); color: var(--accent); }
.note-at.off { background: rgba(var(--ink-rgb), .06); color: var(--text-3);
  text-decoration: line-through; }
.note-save { margin-left: auto; }
.note-save .btn-secondary { padding: 9px 18px; font-size: var(--text-ui); }
.note { display: flex; gap: 14px; padding: 14px 0; border-bottom: 1px solid var(--border-light); }
.note-ts { flex: none; border: 0; background: none; cursor: pointer; padding: 0;
  font-family: var(--font-mono); font-size: var(--fs-meta); color: var(--accent); }
.note-ts:hover { text-decoration: underline; }
.note-ts.plain { color: var(--text-4); cursor: default; }
.note-ts.plain:hover { text-decoration: none; }
.note-body { flex: 1; min-width: 0; font-size: var(--text-body-sm); line-height: 1.6;
  color: var(--text-1); white-space: pre-line; }
.note-del { flex: none; opacity: 0; }
.note:hover .note-del, .note:focus-within .note-del { opacity: 1; }
@media (hover: none) { .note-del { opacity: 1; } }

/* ── discussion ── */
.disc-composer { display: flex; gap: 12px; margin-bottom: 28px; }
.disc-avatar { width: 32px; height: 32px; border-radius: 50%; flex: none; overflow: hidden;
  background: var(--accent-dim); color: var(--accent); display: grid; place-items: center;
  font-size: var(--fs-label-1); font-weight: var(--weight-medium); }
.disc-avatar img { width: 100%; height: 100%; object-fit: cover; }
.disc-composer .grow { flex: 1; min-width: 0; }
.disc-actions { display: flex; gap: 10px; margin-top: 8px; justify-content: flex-end; }
.disc-actions .btn-secondary { padding: 8px 16px; font-size: var(--text-ui); }
.comment { display: flex; gap: 12px; padding: 16px 0; }
.comment + .comment, .comment + .comment-thread { border-top: 1px solid var(--border-light); }
.comment-thread { padding-left: 44px; }
/* the comment a shared link points at: a brief wash, then nothing */
.comment.landed { background: var(--accent-dim); transition: background 1.2s ease 1s; border-radius: var(--rs); }
.comment-main { flex: 1; min-width: 0; }
.comment-by { display: flex; align-items: baseline; gap: 8px; margin-bottom: 3px; }
.comment-name { font-size: var(--text-ui); font-weight: var(--weight-medium); }
.comment-when { font-family: var(--font-mono); font-size: var(--fs-meta); color: var(--text-4); }
.comment-body { font-size: var(--text-body-sm); line-height: 1.6; color: var(--text-1);
  white-space: pre-line; }
.comment-tools { display: flex; align-items: center; gap: 14px; margin-top: 6px; }
.comment-tools button { border: 0; background: none; cursor: pointer; padding: 0;
  font-family: var(--font); font-size: var(--fs-label-1); color: var(--text-3); }
.comment-tools button:hover { color: var(--text-1); }

/* ── the heart: a person, not a metric ──────────────────────────────
   Outline until it means something; filled accent once YOU'VE hearted.
   Hover says WHO — the same little ink tooltip the rest of the app
   uses, fed by data-tooltip. */
.cmt-heart { display: inline-flex; align-items: center; gap: 5px; position: relative; }
.cmt-heart .material-symbols-sharp { font-size: 14px; transition: transform var(--transition-fast); }
.cmt-heart:active .material-symbols-sharp { transform: scale(1.2); }
@media (prefers-reduced-motion: reduce) { .cmt-heart .material-symbols-sharp { transition: none; } }
.cmt-heart .n { font-family: var(--font-mono); font-size: var(--fs-meta); }
.cmt-heart.on { color: var(--accent); }
.cmt-heart.on:hover { color: var(--accent); }
.cmt-heart.on .material-symbols-sharp svg { fill: currentColor; }
.cmt-heart[data-tooltip]::before {
  content: attr(data-tooltip);
  position: absolute; bottom: calc(100% + 7px); left: 0;
  transform: translateY(3px);
  white-space: nowrap; max-width: 320px; overflow: hidden; text-overflow: ellipsis;
  font-family: var(--font); font-size: 11px; font-weight: var(--weight-medium);
  color: var(--paper-solid); background: var(--ink-solid);
  border-radius: var(--rb); padding: 4px 8px;
  pointer-events: none; opacity: 0;
  transition: opacity var(--transition-fast), transform var(--transition-fast);
  z-index: 40;
}
.cmt-heart[data-tooltip]:hover::before,
.cmt-heart[data-tooltip]:focus-visible::before { opacity: 1; transform: translateY(0); }
.comment-reply-box { margin: 8px 0 4px 44px; }

/* ── resources: file chips with a folded corner ──────────────────────
   A resource reads as the FILE it is — a small raised tile with a
   dog-eared page corner in the accent, the download tray as the only
   other mark. The whole chip is the download button.                 */
.res-chips { display: flex; flex-wrap: wrap; gap: 12px; }
.res-chip {
  position: relative; display: flex; align-items: center; gap: 16px;
  max-width: 340px; padding: 14px 16px; text-align: left; cursor: pointer;
  border: 1px solid var(--border-light); border-radius: var(--rs);
  background: rgba(var(--ink-rgb), .045);
  box-shadow: none;
  font-family: var(--font); color: var(--text-1);
  /* the page-corner cut */
  clip-path: polygon(0 0, calc(100% - 18px) 0, 100% 18px, 100% 100%, 0 100%);
  transition: background var(--transition-base), border-color var(--transition-base);
}
.res-chip:hover { background: rgba(var(--ink-rgb), .07);
  border-color: rgba(var(--ink-rgb), .28); }
/* the fold itself — the flap the cut corner turned down */
.res-chip::after { content: ''; position: absolute; top: 0; right: 0;
  width: 18px; height: 18px;
  background: linear-gradient(to bottom left, transparent 49.5%, var(--accent) 50%);
  border-bottom-left-radius: 3px; }
.res-chip .res-title { flex: 1; min-width: 0; font-size: var(--text-ui);
  font-weight: var(--weight-medium); line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.res-chip .res-get { flex: none; color: var(--text-3); display: grid; place-items: center;
  transition: color var(--transition-base); }
.res-chip .res-get .material-symbols-sharp { font-size: var(--icon-lg); }
.res-chip:hover .res-get { color: var(--text-1); }
.res-chip:disabled { opacity: .55; cursor: default; }
