/* ═══════════════════════════════════════════════════════════════════════════
   style-scroll.css — TikTok-style vertical scroll view for Anatase
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Body reset for scroll mode ──────────────────────────────────────────── */
.scroll-body {
  margin: 0;
  padding: 0;
  overflow: hidden;
  /* svh (small viewport). Locks the layout to the URL-bar-visible size so
     nothing resizes when the bar animates in/out. Any sliver of viewport
     revealed when the bar hides is filled by html { background: #0a0a0a }
     below — invisible instead of a bright flash or a next-post peek. */
  height: 100vh;
  min-height: 100vh;
  height: 100svh;
  min-height: 100svh;
  background: #0a0a0a;
  /* Belt-and-suspenders against the mobile URL bar hiding at all: no
     overscroll chain out to the browser UI, no non-vertical touch gesture
     for the browser to interpret as "hide the bar". The stack itself
     overrides touch-action to pan-y so vertical scroll still works. */
  overscroll-behavior: none;
  touch-action: pan-y;
}
html:has(> body.scroll-body) {
  background: #0a0a0a;
  overscroll-behavior: none;
  /* Locks the top-level document so Chrome/MIUI can't hide the URL bar via
     a phantom document scroll while the reader flings the inner stack. */
  height: 100svh;
  overflow: hidden;
}

/* ── Header ──────────────────────────────────────────────────────────────── */
.scroll-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  /* ONE uniform translucent themed surface for the WHOLE header (tab row +
     rail-toggle) so there's no seam between them. The rail-toggle itself is
     transparent (it just sits on this backdrop), and the catalog uses the
     same value so header + catalog read as one continuous translucent panel
     whether the rail is collapsed or expanded. */
  background: color-mix(in srgb, var(--bg) 34%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  pointer-events: none;
}
.scroll-header > * { pointer-events: auto; }
.scroll-header-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
}

.scroll-back {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--bg-post) 80%, transparent);
  border: 1px solid var(--border);
  color: var(--text);
  text-decoration: none;
  flex-shrink: 0;
  transition: background .15s;
  box-shadow: 0 2px 10px rgba(0,0,0,.12);
}
.scroll-back:hover { background: var(--bg-post); color: var(--accent); }
.scroll-back svg { width: 20px; height: 20px; }

.scroll-header-info {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  flex: 1;
}
.scroll-board-tag {
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  flex-shrink: 0;
}
/* Second row of the header: a long, transparent bar with just an arrow --
   not a labeled button mixed in with the board tag/tabs. The shape and
   position alone (a full-width strip directly below the tabs) is the
   signal that something slides out from there. */
.scroll-rail-toggle {
  width: 100%;
  height: 28px;
  border: none;
  /* Transparent: it sits on the header's single translucent backdrop, so it
     doesn't create a second band with a different opacity (the "seam"). */
  background: transparent;
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.scroll-rail-toggle:hover,
.scroll-rail-toggle:active { color: var(--accent); }
/* Wide, flat, semi-transparent chevron (no framing chip). */
.scroll-rail-toggle svg {
  width: 46px; height: 24px; stroke: currentColor; stroke-width: 2.2;
  opacity: .65;
}
.scroll-rail-toggle:hover svg, .scroll-rail-toggle:active svg { opacity: 1; }
.scroll-rail-toggle[hidden] { display: none; }
.scroll-thread-title {
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 500;
  color: #fff;
  opacity: .8;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.scroll-header-right { flex-shrink: 0; display: flex; align-items: center; gap: 8px; }
/* ── Tabs ────────────────────────────────────────────────────────────────── */
.scroll-tabs {
  display: flex;
  gap: 2px;
  background: color-mix(in srgb, var(--bg-post) 70%, transparent);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 2px;
}
.scroll-tab {
  display: inline-block;
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 600;
  padding: 5px 12px;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  transition: all .15s;
  text-transform: uppercase;
  letter-spacing: .03em;
  text-decoration: none;
}
.scroll-tab:hover:not(.disabled):not(:disabled) { color: var(--text); }
.scroll-tab.active { background: var(--accent); color: #fff; }
.scroll-tab:disabled,
.scroll-tab.disabled { opacity: .3; cursor: not-allowed; pointer-events: none; }

/* Drill-down nav (Posts / Thread / Board / Explore) -- replaces the tabs. */
.scroll-nav {
  display: flex;
  gap: 2px;
  background: color-mix(in srgb, var(--bg-post) 70%, transparent);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 2px;
}
.scroll-nav-btn {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 600;
  padding: 5px 12px;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  transition: color .15s, background .15s;
  text-transform: uppercase;
  letter-spacing: .03em;
}
.scroll-nav-btn:hover { color: var(--text); }
.scroll-nav-btn.active { background: var(--accent); color: #fff; }

/* Desktop-only up/down card-nav arrows (hidden on mobile, which uses swipes). */
.scroll-card-nav { display: none; }
@media (min-width: 901px) {
  .scroll-card-nav {
    display: flex; flex-direction: column; gap: 14px;
    position: fixed; z-index: 60; top: 50%; right: 40px;
    transform: translateY(-50%);
    transition: right .3s;
  }
  body.scroll-body.scs-open .scroll-card-nav { right: 460px; }   /* clear the comments panel */

  /* The card-nav arrows (up/down) stay at their default top: 50% 
     since they are fixed navigation elements that naturally overlap scrolling content. */

  .scroll-card-nav-btn {
    width: 44px; height: 44px; padding: 0; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: color-mix(in srgb, var(--bg-post) 70%, transparent);
    border: 1px solid var(--border); color: var(--text-dim); cursor: pointer;
    backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
    transition: color .15s, border-color .15s;
  }
  .scroll-card-nav-btn:hover { color: var(--accent); border-color: var(--accent); }
  .scroll-card-nav-btn svg { width: 22px; height: 22px; }
  /* Select-mode launcher — pencil/checkbox between the ↑↓ arrows. Simple
     bordered state when active (user asked for "solo borde marcado, simple"). */
  .scroll-card-nav-btn.mrail-toggle.active {
    color: var(--accent);
    border-color: var(--accent);
    border-width: 2px;
  }
}

/* ── Select mode: while active, posts render their bulk-selection checkbox on
   the left, so shift the content over 28px to keep everything aligned. Very
   light-touch in Fase 1 — Fase 2 will render the checkbox itself + the rail. */
body[data-select-mode] .scroll-card,
body[data-select-mode] .post-container,
body[data-select-mode] .post {
  transition: padding-left .15s ease;
}

/* Sub-board expand control on a board catalog tile (two-click-area boards): a
   full-width accent bar across the bottom ~20% of the thumb, clearly tappable. */
.scroll-catalog-tile.has-expand .scroll-catalog-tile-thumb { position: relative; }
.scroll-catalog-tile-expand {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  height: 30%; min-height: 20px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: none; border-top: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 0 0 9px 9px;
  background: color-mix(in srgb, var(--accent) 60%, transparent);
  color: #fff; cursor: pointer;
  box-shadow: 0 -1px 5px rgba(0,0,0,.35);
  transition: filter .18s, background .18s;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.scroll-catalog-tile-expand svg {
  width: 14px; height: 14px; stroke: #fff; stroke-width: 2.4;
  transition: transform .18s;
  filter: drop-shadow(0 1px 3px rgba(0,0,0,0.9));
}
.scroll-catalog-tile-expand:hover { filter: brightness(1.12); background: color-mix(in srgb, var(--accent) 80%, transparent); }
.scroll-catalog-tile-expand.open svg { transform: rotate(180deg); }

/* Source-board chip (shown on Explore cards to mark the post's origin board) */
.scroll-src-board {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  color: rgba(255,255,255,.7);
  background: rgba(0,0,0,.3);
  padding: 1px 6px;
  border-radius: 4px;
  text-decoration: none;
  margin-left: 6px;
}
.scroll-src-board:hover { color: #fff; background: rgba(0,0,0,.5); }
.scroll-card-text .scroll-src-board {
  color: var(--accent, currentColor);
  background: color-mix(in srgb, var(--bg-post) 70%, transparent);
}

/* Empty feed state */
.scroll-empty {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255,255,255,.5);
  font-family: var(--sans);
  font-size: 15px;
  pointer-events: none;
}

/* Brief dim while the feed is swapped client-side (Explore <-> Board). */
.scroll-switching .scroll-stack { opacity: .45; transition: opacity .12s; pointer-events: none; }

/* ── Card stack ──────────────────────────────────────────────────────────── */
.scroll-stack {
  /* svh (small viewport height, locked to bar-visible size). Everything
     stays a fixed pixel height across URL-bar transitions so scrollTop
     never falls between two snap positions. Any extra area the URL bar
     surrenders is dark (see .scroll-body / html above), not a next-post
     peek and not a bright flash. Previous versions used dvh + a JS
     scrollTop scale on visualViewport.resize; that fought Chrome's own
     scroll anchoring and produced the flicker + drift-to-previous-card
     the user reported on Xiaomi/MIUI. */
  height: 100svh;
  overflow-y: scroll;
  scroll-snap-type: y mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  -ms-overflow-style: none;
  /* Keep the scroll gesture from chaining out to the browser chrome; that
     chain is what MIUI/Chrome read as "user wants me to hide the URL bar".
     touch-action: pan-y still lets the reader scroll vertically inside the
     stack. */
  overscroll-behavior: contain;
  touch-action: pan-y;
}
.scroll-stack::-webkit-scrollbar { display: none; }

/* ── Card ─────────────────────────────────────────────────────────────────── */
.scroll-card {
  position: relative;
  height: 100svh;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--bg);
  border-bottom: 1px solid rgba(255,255,255,.06);
}
.scroll-gap { height: 0; overflow: hidden; pointer-events: none; }

/* ── End-of-thread card (InThread only) ────────────────────────────────────── */
/* Was unstyled: the message floated top-left, tiny, behind the header. Center
   it as a proper full-card panel, clear of the header/footer. */
.scroll-card-end-feed { background: var(--bg); }
.scroll-end-feed-inner {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 80px 28px calc(28px + var(--sfoot, 56px));
  text-align: center;
}
.scroll-end-feed-inner svg {
  width: 56px; height: 56px;
  color: var(--accent);
  opacity: .9;
}
.scroll-end-feed-text {
  font-family: var(--sans);
  font-size: 17px;
  font-weight: 600;
  color: var(--text);
  max-width: 340px;
}
.scroll-end-feed-btn {
  display: inline-block;
  padding: 11px 22px;
  border-radius: 10px;
  background: var(--accent);
  color: #fff;
  font-family: var(--sans);
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
  box-shadow: 0 3px 14px rgba(0,0,0,.25);
}
.scroll-end-feed-btn:hover { filter: brightness(1.08); }

/* ── Media area ──────────────────────────────────────────────────────────── */
.scroll-card-media-area {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #0a0a0a;
}
/* Subtle darkening so post content stands out from media */
.scroll-card-media::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,.15);
  pointer-events: none;
  z-index: 1;
}

.scroll-video-wrap,
.scroll-img-wrap {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.scroll-video {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: transparent;
}
.scroll-img {
  position: relative;
  z-index: 1;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

/* Blurred self-fill behind contained media: softens the hard black
   letterbox bands when the image/video doesn't fill the card. */
.scroll-img-wrap[style*="--mbg"]::before,
.scroll-video-wrap[style*="--mbg"]::before,
.scroll-gallery-slide[style*="--mbg"]::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image: var(--mbg);
  background-size: cover;
  background-position: center;
  filter: blur(34px) brightness(.5) saturate(1.15);
  transform: scale(1.18);
  pointer-events: none;
}
/* The custom player wrapper paints a solid black background (style-media.css)
   and sizes to the video, covering the blurred self-fill backdrop for any
   video that doesn't fill the card (square / portrait / 4:5 / bright). Force it
   to fill the card, transparent, with the video letterboxed inside -- so the
   blur shows through the transparent letterbox for EVERY ratio, not just 16:9. */
.scroll-video-wrap .cmp-video-wrap,
.scroll-gallery-slide .cmp-video-wrap {
  background: transparent !important;
  border: none !important;
  width: 100% !important;
  height: auto !important;
  max-width: 100% !important;
}
.scroll-video-wrap .cmp-video-wrap video,
.scroll-gallery-slide .cmp-video-wrap video {
  width: 100% !important;
  height: 100% !important;
  object-fit: contain !important;
}

/* ── Spoiler: layered (blurred real image behind, crisp icon on top) ────── */
.scroll-spoiler-wrap {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  overflow: hidden;
}
.scroll-spoiler-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: blur(28px) brightness(.45) saturate(1.1);
  transform: scale(1.08);
  transition: filter .3s, transform .3s;
}
.scroll-spoiler-icon {
  position: relative;
  z-index: 2;
  max-width: 230px;
  max-height: 230px;
  width: 62%;
  height: auto;
  object-fit: contain;
  filter: drop-shadow(0 2px 8px rgba(0,0,0,.5));
}
.scroll-spoiler-wrap.revealed .scroll-spoiler-bg {
  filter: none;
  transform: scale(1);
  object-fit: contain;
}
.scroll-spoiler-wrap.revealed .scroll-spoiler-icon {
  display: none;
}
/* Hero video/audio spoiler: neutral dark backdrop behind the spoiler icon,
   real media injected on reveal (built + simplified by _revealScrollMedia). */
.scroll-spoiler-media {
  background: #0a0a0a;
}
.scroll-spoiler-media.revealed {
  cursor: default;
}
.scroll-spoiler-media.revealed video {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
/* Audio spoiler placeholder isn't a fixed-height slide (audio-only hero flows
   in normal layout), so give it a sensible box; drop the dark fill. */
.scroll-spoiler-media-audio {
  background: transparent;
  min-height: 84px;
  border-radius: 12px;
}
.scroll-spoiler-media-audio .scroll-spoiler-icon {
  max-height: 72px;
  width: auto;
}
.scroll-spoiler-media-audio.revealed {
  min-height: 0;
  display: block;
}

/* ── Gallery (horizontal swipe for multi-image posts) ────────────────────── */
.scroll-gallery {
  width: 100%;
  height: 100%;
  position: relative;
  background: #0a0a0a;
}
.scroll-gallery-track {
  display: flex;
  width: 100%;
  height: 100%;
  overflow-x: scroll;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.scroll-gallery-track::-webkit-scrollbar { display: none; }
.scroll-gallery-slide {
  position: relative;
  flex: 0 0 100%;
  width: 100%;
  height: 100%;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #0a0a0a;
  overflow: hidden;
}
.scroll-gallery-slide .scroll-img,
.scroll-gallery-slide .scroll-video {
  position: relative;
  z-index: 1;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

/* Gallery arrows (smart: hidden at edges by JS, visible on desktop) */
.scroll-gallery-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  border: none;
  border-radius: 50%;
  background: rgba(0,0,0,.3);
  color: rgba(255,255,255,.75);
  cursor: pointer;
  z-index: 16;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background .15s, opacity .15s;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
/* In feeds that show the tall thread/board chip stack, lift the gallery arrows
   (flex+15% or top: 40%) so the right arrow clears the chips. */
body.scroll-body[data-scroll-mode="explore"] .scroll-gallery-arrow,
body.scroll-body[data-scroll-mode="inboard"] .scroll-gallery-arrow,
body.scroll-body[data-scroll-mode="saved"] .scroll-gallery-arrow {
  top: 40%;
  bottom: auto;
  transform: translateY(-50%);
}

.scroll-gallery-arrow:hover {
  background: rgba(0,0,0,.5);
  color: #fff;
}
.scroll-gallery-arrow svg { width: 20px; height: 20px; }
.scroll-gallery-prev { left: 8px; }
.scroll-gallery-next { right: 8px; }

/* Gallery dots */
.scroll-gallery-dots {
  position: absolute;
  bottom: calc(12px + var(--sfoot, 56px));   /* clear the footer bar */
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 6px;
  z-index: 15;
  padding: 4px 8px;
  border-radius: 10px;
  background: rgba(0,0,0,.3);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.scroll-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(255,255,255,.35);
  transition: all .2s;
}
.scroll-dot.active {
  background: #fff;
  transform: scale(1.3);
}

/* ── Poll / Dice extra pages (dot-navigable, over the card media) ── */
.scroll-extra-page {
  position: absolute; inset: 0; z-index: 8;
  background: var(--bg);
  display: flex; flex-direction: column;
  padding: 90px 76px calc(118px + var(--sfoot, 56px)) 16px;
  box-sizing: border-box;
}
.scroll-extra-page[hidden] { display: none; }   /* class display:flex ties [hidden] */
.scroll-extra-scroll { flex: 1; display: flex; flex-direction: column; min-height: 0; }
.scroll-extra-body { flex: 1; overflow-y: auto; }
/* The board poll/dice widgets already carry their own chrome; just make them
   fit the themed page. */
.scroll-extra-body .poll-block, .scroll-extra-body .dice-block { margin: 0 0 10px; }
.scroll-extra-body .dice-separator { display: none; }
.scroll-extra-pager {
  display: flex; align-items: center; justify-content: center; gap: 14px; padding-top: 10px;
}
.scroll-extra-pager[hidden] { display: none; }
.scroll-extra-pg {
  background: var(--bg-post); border: 1px solid var(--border); color: var(--text);
  width: 38px; height: 32px; border-radius: 8px; font-size: 17px; cursor: pointer;
}
.scroll-extra-pg:disabled { opacity: .4; cursor: default; }
.scroll-extra-pg-ind { font-family: var(--sans); font-size: 12px; color: var(--text-dim); min-width: 44px; text-align: center; }
/* Content/Poll/Dice dots */
.scroll-extra-dots {
  position: absolute; left: 50%; transform: translateX(-50%);
  bottom: calc(12px + var(--sfoot, 56px));
  display: flex; gap: 6px; z-index: 16;
  background: rgba(0,0,0,.32); padding: 4px 9px; border-radius: 14px;
  backdrop-filter: blur(8px);
}
.scroll-extra-dot {
  background: none; border: none; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  line-height: 1; padding: 0 2px; color: #fff; opacity: .55;
}
.scroll-extra-dot.active { opacity: 1; transform: scale(1.12); }
.scroll-extra-dot svg { width: 16px; height: 16px; stroke: currentColor; }
.scroll-extra-dot-content-dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: currentColor;
}

/* ── Translation toggle bar (Ver original / Ver traducción + ↺ retranslate) ── */
.scroll-tr-bar {
  display: flex; align-items: center; gap: 8px;
  margin: 4px 0 2px;
}
.scroll-tr-toggle {
  background: none; border: none; padding: 0; cursor: pointer;
  color: var(--accent); font-size: 12px; font-weight: 600;
  font-family: var(--sans);
}
.scroll-tr-toggle:hover { text-decoration: underline; }
.scroll-tr-re {
  background: none; border: none; padding: 0 2px; cursor: pointer;
  color: var(--text-dim); font-size: 14px; line-height: 1;
}
.scroll-tr-re:hover { color: var(--accent); }
/* Inside comments the bar is a touch smaller. */
.sc-content + .scroll-tr-bar { margin-top: 2px; }
.scroll-tr-bar .scroll-tr-toggle { font-size: 11.5px; }

/* ── Subtle video seek bar (sits just below the dots) ──
   Deliberately low-contrast so it doesn't grab attention; a small draggable
   circle scrubs the currently-playing video. Built by _buildCardSeek(). */
.scroll-seek {
  position: absolute;
  left: 18px; right: 18px;
  bottom: calc(2px + var(--sfoot, 56px));
  z-index: 14;
  height: 16px;
  display: flex; align-items: center;
  cursor: pointer;
  touch-action: none;
}
/* Override specificity conflict: [hidden] uses display:none but .scroll-seek
   sets display:flex, which wins without this rule. Hidden when card is inactive,
   restored in onCardActive — prevents the bar bleeding into adjacent cards. */
.scroll-seek[hidden] { display: none; }
.scroll-seek-track {
  position: relative;
  width: 100%; height: 3px;
  background: rgba(255,255,255,.15);
  border-radius: 2px;
}
.scroll-seek-fill {
  position: absolute; left: 0; top: 0; height: 100%; width: 0;
  background: rgba(255,255,255,.5);
  border-radius: 2px;
}
.scroll-seek-thumb {
  position: absolute; top: 50%; left: 0;
  width: 11px; height: 11px; border-radius: 50%;
  background: rgba(255,255,255,.82);
  transform: translate(-50%, -50%);
  box-shadow: 0 0 3px rgba(0,0,0,.45);
  pointer-events: none;
}

/* ── Text-only cards ─────────────────────────────────────────────────────── */
/* Styled after the board's own .post chrome (border + bg-post) instead of
   floating bare text on the theme background — gives it the same "card"
   weight a media post gets from its image. (The accent bars top/bottom that
   used to bookend this were uncomfortable and buggy — removed; see
   .scroll-title-card below for the one place accent now appears: a left
   bar, only on the OP-title chip, only when there is one.) */
.scroll-card-text { background: var(--bg); }
.scroll-text-hero {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 70px 24px 120px;
  background: var(--bg);
}
.scroll-text-hero-group {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  width: 100%;
  max-width: 600px;
}
.scroll-text-content {
  position: relative;
  font-family: var(--serif);
  font-size: clamp(16px, 3.4vw, 22px);
  line-height: 1.6;
  color: var(--text);
  text-align: center;
  max-width: 600px;
  /* Use the full card minus the hero's own padding (70 + 120) plus a little
     breathing room. 60vh was leaving three-embed raw posts squeezed into
     ~30% of the viewport with the play buttons too small to tap; this lets
     the content card grow to almost the whole card before falling back to
     internal scroll for extreme walls of text. */
  max-height: calc(100dvh - 210px);
  overflow-y: auto;
  overscroll-behavior: contain;
  word-break: break-word;
  background: var(--bg-post);
  border: 1px solid var(--border);
  border-radius: var(--cmp-radius, 8px);
  padding: 22px 22px 18px;
  box-shadow: 0 4px 20px rgba(0,0,0,.18);
}
.scroll-text-content .greentext { color: var(--greentext); }
.scroll-text-content .pinktext { color: var(--pinktext); }
/* Font-size tiers — auto-scaled server-side from the post's plain-text
   length (see _scroll_card.ejs::_heroSizeClass) so a one-liner reads big
   and a wall of text shrinks to a still-legible minimum instead of both
   using the same fixed size. */
.scroll-text-content.hero-size-xl { font-size: clamp(24px, 5.5vw, 32px); }
.scroll-text-content.hero-size-lg { font-size: clamp(19px, 4.2vw, 25px); }
.scroll-text-content.hero-size-sm { font-size: clamp(14px, 2.8vw, 18px); }
.scroll-text-content.hero-size-xs { font-size: clamp(13px, 2.4vw, 16px); }

/* ── OP/thread title card (raw cards only — see .scroll-op-title-top for
   the media-card equivalent). Sized independently from the body content
   below it (own length-based tier), since a long title can pair with very
   short content (or vice versa) and forcing them to share one scale looks
   wrong either way. Only this chip gets accent — a left bar — the content
   card itself stays plain. */
.scroll-title-card {
  width: 100%;
  background: var(--bg-post);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--cmp-radius, 8px);
  padding: 10px 16px;
  font-family: var(--sans);
  font-weight: 700;
  color: var(--accent);
  text-align: center;
  word-break: break-word;
  box-shadow: 0 2px 10px rgba(0,0,0,.14);
}
.scroll-title-card.title-size-lg { font-size: clamp(20px, 5.5vw, 26px); }
.scroll-title-card.title-size-md { font-size: clamp(16px, 4.4vw, 20px); }
.scroll-title-card.title-size-sm {
  font-size: clamp(13px, 3.2vw, 16px);
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ── Embed-only card (YouTube/TikTok/X) ───────────────────────────────────
   A CONTAINED box, not edge-to-edge fullscreen -- that covered the action
   sidebar/poster row/board chip entirely, leaving nothing tappable. Margin
   on all sides keeps the rest of the card's chrome reachable.
   URL + toggle are pulled OUT of the box (negative top offset escaping
   upward into the empty header-margin space above it) instead of sitting
   inside/under it, so they're never visually buried by the bottom overlay
   or the embed content itself -- no overflow:hidden on the box itself for
   exactly this reason; each embed element gets its own border-radius. */
.scroll-embed-hero {
  position: absolute;
  top: 17%;
  left: 8%;
  right: 8%;
  bottom: 20%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #000;
  border-radius: 14px;
  box-shadow: 0 8px 30px rgba(0,0,0,.5);
}
.scroll-embed-hero .ytembed,
.scroll-embed-hero .ttembed,
.scroll-embed-hero .twtembed {
  position: relative;
  width: 100%;
  height: 100%;
  margin: 0;
}
.scroll-embed-hero .yt-url,
.scroll-embed-hero .tt-url,
.scroll-embed-hero .twt-url {
  position: absolute;
  top: -36px;
  left: 0;
  z-index: 20;
  max-width: 72%;
  background: rgba(0,0,0,.55);
  padding: 5px 9px;
  border-radius: 6px;
  font-size: 11px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.scroll-embed-hero .yt-toggle,
.scroll-embed-hero .tt-toggle,
.scroll-embed-hero .twt-toggle {
  position: absolute;
  top: -36px;
  right: 0;
  z-index: 20;
}
.scroll-embed-hero .yt-thumb,
.scroll-embed-hero .yt-frame,
.scroll-embed-hero .tt-thumb,
.scroll-embed-hero .tt-frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  border: none;
  border-radius: 14px;
  aspect-ratio: auto;
  overflow: hidden;
}
.scroll-embed-hero .twt-mount {
  width: 100%;
  max-width: 100%;
  height: 100%;
  overflow-y: auto;
  zoom: 1;
  margin: 0;
  border-radius: 14px;
}

/* Audio file paired with image/video in the same gallery — centers the
   native player over the blurred backdrop slide. */
.scroll-gallery-slide-audio {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.scroll-text-content img,
.scroll-text-content .inline-file img,
.scroll-text-content a.inline-file img {
  max-width: 70%;
  max-height: 20vh;
  width: auto !important;
  height: auto !important;
  border-radius: 6px;
  display: inline-block;
  margin: 6px auto;
}
.scroll-text-content a.inline-file {
  width: auto !important;
  max-width: 70%;
  display: inline-block;
}

/* ── Bottom overlay ──────────────────────────────────────────────────────── */
.scroll-card-overlay {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 14px 76px 16px 16px;
  background: linear-gradient(to top, rgba(0,0,0,.78) 0%, rgba(0,0,0,.42) 55%, rgba(0,0,0,.12) 80%, transparent 100%);
  pointer-events: none;
  z-index: 10;
}
.scroll-card-overlay > * { pointer-events: auto; }
/* NOTE: .scroll-card-overlay above is position:absolute (it pins the
   poster-row/meta footer to the card's bottom edge). Do NOT add
   `position: relative` (or anything else that overrides `position`) on a
   more-specific .scroll-card-overlay selector below — that silently took
   it out of flow-anchored-absolute and put it back in normal document
   flow, which made the poster row render at the TOP of the card (first
   in-flow child, since the media area is itself absolutely positioned)
   instead of the bottom. Cost a very confusing bug once already. */
.scroll-card-text .scroll-card-overlay {
  /* Match the card's own bg (var(--bg)) -- var(--bg-post) is a different shade
     on some themes and read as a strange white band under the name/ID. */
  background: linear-gradient(to top, var(--bg) 0%, var(--bg) 40%, transparent 100%);
  border-top: 1px solid var(--border);
  /* Breathing room below the top divider line -- the poster name/ID was glued
     to it (esp. on mobile, where the base overlay padding-top is 0). Higher
     specificity than the mobile `.scroll-card-overlay{padding:0 ...}` reset. */
  padding-top: 20px;
}

/* ── Poster row (name + gem) ─────────────────────────────────────────────── */
.scroll-poster-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
}
.scroll-poster-name {
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 600;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0,0,0,.6);
}
.scroll-card-text .scroll-poster-name {
  color: var(--text);
  text-shadow: none;
}
/* OP/thread title — its own line below the identifier row (gem + name),
   never squeezed between them (that crowded the gem badge and truncated
   it). The thread's actual subject, accent-colored, exactly like
   .post-header .subject does in the normal board view. Only rendered for
   the post that IS the thread's OP and only when a real subject was set. */
.scroll-op-title-row { margin-bottom: 6px; }
.scroll-op-title {
  font-family: var(--sans);
  font-size: 15px;
  font-weight: 700;
  line-height: 1.3;
  color: var(--accent);
  text-shadow: 0 1px 3px rgba(0,0,0,.6);
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.scroll-card-text .scroll-op-title { text-shadow: none; }
/* Floating title above the media, white/no background, cleared below the
   fixed header (.scroll-header) so it's always readable regardless of what
   the image looks like underneath. Media cards only — raw cards show their
   title inside the card itself (.scroll-title-card). Centered across the
   full card width (symmetric margins — the action sidebar lives further
   down, not up here, so nothing to dodge on the right). */
.scroll-op-title-top {
  position: absolute;
  top: 54px; /* fallback before JS centers it -- see positionOpTitle() */
  left: 16px;
  right: 16px;
  transform: translateY(-50%);
  z-index: 12;
  font-family: var(--sans);
  font-weight: 800;
  font-size: 28px;
  line-height: 1.3;
  color: #fff;
  text-shadow: 0 1px 4px rgba(0,0,0,.7), 0 0 14px rgba(0,0,0,.5);
  text-align: center;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  pointer-events: none;
}

/* ── Post-0 board intro header (synthetic first slide of InBoard) ───────── */
.scroll-intro-header {
  position: absolute;
  top: 88px;   /* clear the fixed header + rail-toggle (was overlapping) */
  left: 16px;
  right: 16px;
  z-index: 12;
  display: flex;
  align-items: center;
  gap: 12px;
  background: rgba(0,0,0,.42);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-radius: 10px;
  padding: 10px 14px;
  box-shadow: 0 2px 14px rgba(0,0,0,.28);
}
.scroll-intro-chip {
  flex: 0 0 auto;
  width: 46px;
  height: 46px;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255,255,255,.1);
  background-size: cover;
  background-position: center;
}
.scroll-intro-chip-text {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  color: #fff;
}
.scroll-intro-text { min-width: 0; flex: 1 1 auto; }
.scroll-intro-name {
  font-family: var(--sans);
  font-weight: 800;
  font-size: 16px;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0,0,0,.6);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.scroll-intro-desc {
  font-family: var(--sans);
  font-size: 12px;
  color: rgba(255,255,255,.78);
  margin-top: 2px;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.scroll-card-text .scroll-intro-header { background: color-mix(in srgb, var(--bg-post) 85%, transparent); }
.scroll-card-text .scroll-intro-chip-text,
.scroll-card-text .scroll-intro-name { color: var(--text); text-shadow: none; }
.scroll-card-text .scroll-intro-desc { color: var(--text-dim); }

.scroll-gem {
  font-size: 11px;
  padding: 2px 8px;
  border-radius: 4px;
}

/* ── Post text (paginated) ───────────────────────────────────────────────── */
.scroll-card-text-below { margin-bottom: 6px; position: relative; }
.scroll-post-content {
  font-family: var(--serif);
  font-size: 14px;
  line-height: 1.5;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0,0,0,.5);
  max-height: 4.5em;
  overflow: hidden;
  word-break: break-word;
  position: relative;
}
.scroll-post-content.expanded {
  max-height: 40vh;
  overflow-y: auto;
  /* Without this, a touch-scroll gesture that bottoms out inside this
     inner scroll area can "chain" into the outer .scroll-stack's
     scroll-snap container, nudging the card itself out of the
     IntersectionObserver's active threshold -- which paused whatever
     audio/video/embed was playing just from scrolling to read text. */
  overscroll-behavior: contain;
}
.scroll-card-text .scroll-post-content {
  color: var(--text);
  text-shadow: none;
  background: var(--bg-post);
  padding: 12px 16px;
  border-radius: 8px;
  margin-bottom: 8px;
}
.scroll-post-content a,
.scroll-text-content a {
  color: var(--link);
  pointer-events: auto;
  text-decoration: underline;
}
.scroll-post-content a:hover,
.scroll-text-content a:hover { color: var(--link-hover); }
/* Plain hyperlinks: small bump only on the overlay's small text (14px base).
   Text-hero links used to inherit the post's own font-size -- harmless
   while that was a fixed clamp(18-28px), but once the body text itself got
   length-based auto-scaling (.hero-size-xl etc, up to ~40px for a one-
   liner), an inherited link inflated right along with it. Links read the
   same size regardless of how big/small the surrounding post text is. */
.scroll-post-content a:not(.postref):not(.inline-file) {
  font-size: 1.1em;
}
.scroll-text-content a:not(.postref):not(.inline-file) {
  font-size: 16px;
}
/* Quotes/citations (>>123): inherit the post's font size instead of the small global rem */
.scroll-post-content .postref,
.scroll-text-content .postref {
  color: var(--link);
  font-size: inherit;
}
/* Expandable media links (YouTube/TikTok/Twitch/X — the ones with a ▾ toggle
   button) ship a fixed 11px var(--mono) style (style-media.css) meant for
   the normal, full-width post column. In the overlay's narrow 14px column
   that monospace face reads visibly larger/heavier than the sans-serif
   plain links next to it, even after the 1.1em bump above. Force them to
   match plain links exactly: same font, same size. (Raw/text-hero cards
   are untouched — they already read fine at the inherited hero size.) */
.scroll-post-content .yt-url,
.scroll-post-content .tt-url,
.scroll-post-content .tw-url,
.scroll-post-content .twt-url {
  font-family: inherit !important;
  font-size: 1.1em !important;
}
/* ════════════════════════════════════════════════════════════════════════
   Per-context embed sizing -- every embed type (YouTube/Shorts, TikTok,
   Twitch, X) scaled to a fixed target percentage OF THE WRAPPER, not just
   the thumb/frame inside it -- that's the part that actually fixes "the
   container is bigger (or smaller) than its own thumbnail": .yt-thumb/
   .yt-frame/.tt-thumb/.tt-frame/etc ship an explicit pixel width
   (320-640px, style-media.css) which still counts as the element's
   preferred/intrinsic size and can pull a shrink-to-fit container
   (.scroll-text-content has no width of its own, just max-width, inside a
   flex column that doesn't stretch it) wider than intended -- the embed
   ends up driving the box's width instead of the other way around
   (confirmed live: a portrait TikTok/Shorts thumb at its old "fill the
   wrapper" 100% rendered as a roughly 9:16 box that swallowed nearly the
   whole screen, since width:100% of a fairly wide text column at a tall
   aspect-ratio computes to a LOT of height). Setting the WRAPPER itself to
   a fixed percentage (not just max-width) -- then having the thumb/frame
   fill 100% of that already-correctly-sized wrapper -- is what makes the
   container "extend exactly as much as its thumbnail": both end up the
   same final pixel size, by construction, regardless of the platform's
   own intrinsic aspect ratio.

   The two contexts deliberately use DIFFERENT targets: a description is a
   small supporting blurb under an image/video, not where you're meant to
   watch a full TikTok (50%) -- raw is the post's own full-screen text, a
   bit more generous but still nowhere near "this embed takes over the
   screen" (70%). Strip (gallery slides, which fill their slide at 100% by
   design) and fullscreen (.scroll-embed-hero, ~90% effective via its own
   existing top/left/right/bottom margins) are untouched -- both already
   size exactly to their container on their own terms.
   ════════════════════════════════════════════════════════════════════════ */
/* The WRAPPER stays full column width -- only the thumb/frame (the
   actual visual embed box) gets the per-context size reduction. Scaling
   the whole wrapper down (a previous attempt) squeezed the URL text +
   toggle button into that same narrow width too, forcing the toggle to
   wrap onto its own line below the link instead of sitting flush right
   on the same line -- the URL+toggle row needs the FULL text column to
   lay out exactly like any other line of text, with the toggle landing
   at the right edge of whatever space is actually available. */
.scroll-post-content .ytembed,
.scroll-post-content .ttembed,
.scroll-post-content .twembed,
.scroll-post-content .twtembed,
.scroll-text-content .ytembed,
.scroll-text-content .ttembed,
.scroll-text-content .twembed,
.scroll-text-content .twtembed {
  display: block;
  margin: 8px 0;
}
/* Description text reads left-aligned like any normal post body -- the
   embed box itself should land where a left-aligned reader expects it
   (flush left, same as the text above/below it), not centered just
   because it's a block element. Raw's box stays centered because raw's
   OWN text is already text-align:center -- that's the one case where
   centering actually matches the surrounding text instead of fighting
   it. */
.scroll-post-content .yt-thumb,
.scroll-post-content .yt-frame,
.scroll-post-content .tt-thumb,
.scroll-post-content .tt-frame,
.scroll-post-content .tw-thumb,
.scroll-post-content .tw-frame {
  width: 50% !important;
  max-width: 50%;
  margin: 0 !important;
}
.scroll-text-content .yt-thumb,
.scroll-text-content .yt-frame,
.scroll-text-content .tt-thumb,
.scroll-text-content .tt-frame,
.scroll-text-content .tw-thumb,
.scroll-text-content .tw-frame {
  width: 70% !important;
  max-width: 70%;
  margin: 0 auto !important;
}
/* X/Twitter's official widget requests its own fixed 500px + zoom:0.8
   (style-media.css) -- same per-context percentage as the thumb/frame
   boxes above (the wrapper itself stays full-width, see comment there),
   zoom reset to 1 since the width percentage is now the only scaling
   mechanism needed. */
.scroll-post-content .twt-mount {
  width: 50%;
  max-width: 50%;
  margin: 0;
  zoom: 1;
}
.scroll-text-content .twt-mount {
  width: 70%;
  max-width: 70%;
  margin: 0 auto;
  zoom: 1;
}

/* Generic per-context image sizing (below) targets EVERY <img> inside
   these containers by class+tag, which at equal CSS specificity ties
   with -- and, by simply loading later, wins against -- .yt-thumb img /
   .tw-thumb img's own board-view rule (style-media.css: width:100%;
   height:auto / height:100%;object-fit:cover). That's what was actually
   shrinking the YouTube/Twitch preview image down to a small inline-image
   size INSIDE an otherwise-correctly-sized box -- the box was right, the
   picture inside it wasn't filling it. Restored here with higher
   specificity (two classes beats one) so the platform preview image
   genuinely covers its own thumb box, cropping any aspect-ratio mismatch
   via object-fit instead of leaving empty space or a tiny inset photo. */
.scroll-post-content .yt-thumb img,
.scroll-post-content .tw-thumb img,
.scroll-text-content .yt-thumb img,
.scroll-text-content .tw-thumb img {
  width: 100% !important;
  height: 100% !important;
  max-width: 100% !important;
  max-height: 100% !important;
  object-fit: cover;
  margin: 0 !important;
}
/* TikTok has no real preview image to begin with (style-media.css: just
   a "TikTok" wordmark pinned near the top + a centered play icon, on a
   plain black box) -- fine at the board view's larger fixed 320px width,
   but the wordmark's fixed top:14px offset reads as "stuck in the
   corner of an empty box" once that box is a narrower, taller fraction
   of a phone-width column. Centered vertically (matching the play icon
   it sits above) and sized up slightly so it actually registers as the
   box's content instead of a small label in the corner. */
.scroll-post-content .tt-brand,
.scroll-text-content .tt-brand {
  top: 50% !important;
  transform: translateY(-50%);
  font-size: 26px;
}
.scroll-post-content .tt-thumb .yt-play,
.scroll-text-content .tt-thumb .yt-play {
  top: 68%;
}

.scroll-post-content .greentext { color: var(--greentext); }
.scroll-post-content .pinktext { color: var(--pinktext); }
/* Moe markup inside a scroll DESCRIPTION sits over the media (a dark image),
   where .scroll-post-content forces white text. The base .moe paints its glyphs
   in var(--text) (dark on most themes) with white sparkles — over dark media
   that reads as "only the sparkles show, the words vanish". Here we repaint the
   glyph fill white so the words are legible, and recolor the sparkles gold/amber
   so they still register against the now-white letters (white-on-white was
   invisible). Only over-media descriptions are affected; the raw-card variant
   (which sits on --bg-post with normal --text) is restored just below. */
.scroll-post-content .moe {
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M16 4L17.7 14.3 28 16 17.7 17.7 16 28 14.3 17.7 4 16 14.3 14.3Z' fill='%23ffd24a'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M16 6L17.4 14.6 26 16 17.4 17.4 16 26 14.6 17.4 6 16 14.6 14.6Z' fill='%23f5a623'/%3E%3C/svg%3E"),
    linear-gradient(#fff, #fff);
}
.scroll-card-text .scroll-post-content .moe {
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M16 4L17.7 14.3 28 16 17.7 17.7 16 28 14.3 17.7 4 16 14.3 14.3Z' fill='%23ffffff'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M16 6L17.4 14.6 26 16 17.4 17.4 16 26 14.6 17.4 6 16 14.6 14.6Z' fill='%23ffe6a8'/%3E%3C/svg%3E"),
    linear-gradient(var(--text, #e8eaed), var(--text, #e8eaed));
}
/* Inline (in-text) video: simple play/pause overlay + expand button (like the
   comments player) instead of the full native/cmp controls. */
.sc-inline-vid { position: relative; display: inline-block; line-height: 0; }
.sc-inline-vid video { display: block; max-width: 100%; border-radius: 4px; }
/* Native/cmp controls are stripped in JS -- hard-hide any residual bar too. */
.sc-inline-vid video::-webkit-media-controls { display: none !important; }
/* Only two controls, both semi-transparent: a GIANT play arrow (no bar) and a
   small expand button. */
.sc-inline-vid-play {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: 52px; color: rgba(255,255,255,.82);
  text-shadow: 0 2px 12px rgba(0,0,0,.6);
  background: none; cursor: pointer;
}
.sc-inline-vid-fs {
  position: absolute; bottom: 6px; right: 6px;
  width: 26px; height: 26px; border-radius: 6px;
  background: rgba(0,0,0,.32); color: rgba(255,255,255,.85); border: none; cursor: pointer;
  font-size: 13px; line-height: 1; display: flex; align-items: center; justify-content: center;
}
.sc-inline-vid-fs:hover { background: rgba(0,0,0,.6); color: #fff; }
/* Inline gem markup (.anatase-wrap): only cap the wrapper to the column width
   so a long gem can't push the post wider. The SVG keeps its own intrinsic
   size (constraining it distorted the gem) -- a rare over-long gem may clip at
   the edge, but normal gems render exactly as before. */
.scroll-post-content .anatase-wrap,
.scroll-text-content .anatase-wrap,
.sc-content .anatase-wrap { max-width: 100%; }
/* Spoilers: reveal legibly on ANY theme. The base .spoiler:hover forces
   color:white, which is invisible on light themes (Glaze/Hispa/Light/etc).
   Reveal by going fully transparent + the theme's own text colour so the text
   always contrasts its background, whether the theme is light or dark. */
.scroll-card .spoiler:hover, .scroll-card .spoiler:focus,
.scroll-comments-sheet .spoiler:hover, .scroll-comments-sheet .spoiler:focus {
  background: transparent !important;
  /* `inherit` = the surrounding text colour: white over media/fullscreen-strip
     overlays (.scroll-post-content is #fff there), theme text on raw cards and
     comments. Always legible, light or dark theme. */
  color: inherit !important;
}
/* Inline images/files inside scroll "description" text. The markup emits the
   author's chosen size as `width:Npx` on the .inline-file wrapper -- HONOR it
   (only cap to the column so nothing overflows). The previous
   `width:auto !important` forced every inline image to a fixed thumbnail,
   which is what broke inline-image resizing in descriptions. */
.scroll-post-content .inline-file,
.scroll-post-content a.inline-file {
  /* Honor authored width, but cap it: bigger than the comment thumbnails,
     yet not the full column (which read as too large in descriptions). */
  max-width: 58%;
  display: inline-block;
  vertical-align: middle;
}
.scroll-post-content .inline-file img,
.scroll-post-content a.inline-file img {
  width: 100%;
  height: auto;
  max-width: 100%;
  max-height: 210px;
  object-fit: contain;
  border-radius: 4px;
  display: block;
  margin: 0;
}
/* Bare inline images with no wrapper/authored size: same cap. */
.scroll-post-content > img,
.scroll-post-content p > img {
  max-width: 58%;
  max-height: 210px;
  height: auto;
  border-radius: 4px;
  vertical-align: middle;
  margin: 2px 4px;
}

/* Text controls (more button + page indicator) */
.scroll-text-controls {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 2px;
}
.scroll-text-controls[hidden] { display: none; }

.scroll-read-more {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 600;
  color: #fff;
  background: none;
  border: none;
  cursor: pointer;
  padding: 4px 0;
  opacity: .85;
  text-shadow: 0 1px 2px rgba(0,0,0,.5);
  transition: opacity .15s;
}
.scroll-read-more:hover { opacity: 1; }
.scroll-read-more svg {
  width: 16px;
  height: 16px;
  transition: transform .2s;
}
.scroll-read-more.expanded svg { transform: rotate(180deg); }
.scroll-card-text .scroll-read-more {
  color: var(--accent);
  text-shadow: none;
}

/* ── Meta line ───────────────────────────────────────────────────────────── */
.scroll-card-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--mono);
  font-size: 11px;
  color: rgba(255,255,255,.5);
}
.scroll-card-text .scroll-card-meta { color: var(--text-dim); }
/* "more" moved onto the meta line (time/No. left, more right) instead of
   its own row below the description -- claws back a full extra line of
   visible text, and lands right where a right thumb already rests near
   the action buttons. */
.scroll-card-meta .scroll-text-controls { margin-left: auto; margin-top: 0; }

/* ── Action sidebar ──────────────────────────────────────────────────────── */
.scroll-actions {
  position: absolute;
  right: 10px;
  bottom: 90px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  z-index: 20;
}
.scroll-action-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border: none;
  border-radius: 50%;
  background: rgba(0,0,0,.3);
  color: #fff;
  cursor: pointer;
  transition: all .15s;
  position: relative;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.scroll-card-text .scroll-action-btn {
  background: color-mix(in srgb, var(--bg-post) 80%, transparent);
  color: var(--text);
  backdrop-filter: none;
}
.scroll-action-btn:hover {
  background: rgba(0,0,0,.5);
  transform: scale(1.06);
}
.scroll-card-text .scroll-action-btn:hover {
  background: var(--bg-hover);
}
.scroll-action-btn svg {
  width: 22px;
  height: 22px;
  stroke: var(--accent);
}
/* Active state: accent fill for watch/bookmark toggles */
.scroll-btn-watch.active,
.scroll-btn-bookmark.active {
  background: color-mix(in srgb, var(--accent) 18%, rgba(0,0,0,.35));
}
.scroll-btn-watch.active svg,
.scroll-btn-bookmark.active svg {
  fill: color-mix(in srgb, var(--accent) 30%, transparent);
}

/* Action count badge — default: below the icon */
.scroll-action-count {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 600;
  color: #fff;
  margin-top: 2px;
  line-height: 1;
  text-shadow: 0 1px 2px rgba(0,0,0,.5);
}
.scroll-action-count.hidden { display: none; }

/* Comments button: quote count inside the SVG bubble, reply count below */
.sac-icon-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 0;
}
/* Quote count overlaid inside the chat bubble SVG */
.sac-q {
  position: absolute;
  top: 43%;
  left: 48%;
  transform: translate(-50%, -50%);
  font-family: var(--sans);
  font-size: 9px;
  font-weight: 800;
  color: var(--accent);
  line-height: 1;
  text-shadow: 0 0 4px rgba(0,0,0,.9), 0 0 4px rgba(0,0,0,.9);
  pointer-events: none;
}
/* Reply count below the icon (always shown alongside quote count, all feed modes) */
.sac-r {
  font-family: var(--sans);
  font-size: 10px;
  font-weight: 600;
  color: rgba(255,255,255,.7);
  line-height: 1;
  margin-top: 2px;
  text-shadow: 0 1px 2px rgba(0,0,0,.5);
}
.scroll-card-text .sac-r {
  color: var(--text-dim);
  text-shadow: none;
}

/* Jump button icon rotates 180° when at the last post (→ "go to first") */
.scroll-btn-jump svg { transition: transform 0.22s ease; }
.scroll-btn-jump.atend svg { transform: rotate(180deg); }
.scroll-card-text .scroll-action-count {
  color: var(--text-dim);
  text-shadow: none;
}

/* ── Thread stack: board chip + thread card (jump-to-source-thread) ───────── */
.scroll-thread-stack {
  position: absolute;
  right: 10px;
  /* Cleared above the whole action column, which grew ~70px taller once the
     audio chip (disc + name) became its bottom-most item. Measured: the
     comments button (topmost action) was overlapping the thread chip by ~65px
     before this. Mobile has its own values in the max-width:900px block. */
  bottom: 336px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 5px;
  z-index: 20;
}
/* OP cards include the bell button — one row taller, push it up further. */
.scroll-card-op .scroll-thread-stack {
  bottom: 396px;
}
/* Board chip: same size as the action buttons (.scroll-action-btn — 46px/
   42px), but square with soft corners like the rail's own board tile
   (.br-item, border-radius:6px in _boards_rail.ejs) — not circular. */
.scroll-board-chip {
  width: 46px;
  height: 46px;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0,0,0,.4);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 2px 10px rgba(0,0,0,.28);
  background-size: cover;
  background-position: center;
  text-decoration: none;
  cursor: pointer;
  transition: transform .15s, background-color .15s;
}
.scroll-board-chip:hover { transform: scale(1.06); }
.scroll-board-chip-text {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  color: rgba(255,255,255,.85);
  line-height: 1.1;
  text-align: center;
}
.scroll-card-text .scroll-board-chip:not(.has-logo) {
  background-color: color-mix(in srgb, var(--bg-post) 85%, transparent);
}
.scroll-card-text .scroll-board-chip-text { color: var(--text); }

.scroll-thread-card {
  width: 64px;
  display: flex;
  flex-direction: column;
  border-radius: 8px;
  overflow: hidden;
  background: rgba(0,0,0,.32);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 2px 12px rgba(0,0,0,.28);
  text-decoration: none;
  cursor: pointer;
  transition: transform .15s, background .15s;
}
.scroll-thread-card:hover { transform: scale(1.04); background: rgba(0,0,0,.46); }
.scroll-thread-card-thumb {
  width: 100%;
  aspect-ratio: 1 / 1;
  background: rgba(255,255,255,.08);
}
.scroll-thread-card-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.scroll-thread-card-body {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 4px 5px 5px;
  min-width: 0;
}
.scroll-thread-card-title {
  font-family: var(--sans);
  font-size: 9.5px;
  font-weight: 600;
  line-height: 1.2;
  color: #fff;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.scroll-thread-card-meta {
  font-family: var(--sans);
  font-size: 8px;
  color: rgba(255,255,255,.6);
  white-space: nowrap;
}
.scroll-card-text .scroll-thread-card {
  background: color-mix(in srgb, var(--bg-post) 85%, transparent);
  box-shadow: 0 2px 12px rgba(0,0,0,.12);
}
.scroll-card-text .scroll-thread-card:hover {
  background: color-mix(in srgb, var(--bg-post) 98%, transparent);
}
.scroll-card-text .scroll-thread-card-title { color: var(--text); }
.scroll-card-text .scroll-thread-card-meta { color: var(--text-dim); }

/* ── Catalog overlay (re-tap the active tab) ───────────────────────────────
   Shared shell for all three pickers: InThread filmstrip, InBoard
   filmstrip, Explore two-row board drill-down. */
/* A rail glued to the bottom of the header, overlapping the card currently
   in view (no dimming/blurring the rest of the screen — the post stays
   fully visible underneath). z-index sits BELOW the header (100) so the
   tabs stay on top and clickable while the rail is open: tapping the same
   tab again always re-opens it directly, no "closes the rail, needs a
   second tap to actually hit the tab" issue from a full-screen backdrop. */
.scroll-catalog {
  position: fixed;
  top: 72px;
  left: 0;
  right: 0;
  z-index: 90;
  /* Same translucent value as the header so the two read as one continuous
     panel (the "flexible box" that grows when the rail expands). */
  background: color-mix(in srgb, var(--bg) 48%, transparent);
  backdrop-filter: blur(9px);
  -webkit-backdrop-filter: blur(9px);
  box-shadow: 0 8px 24px rgba(0,0,0,.18);
  padding: 6px 8px 4px;
}
.scroll-catalog[hidden] { display: none; }
.scroll-catalog-close {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: rgba(255,255,255,.12);
  border: none;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.scroll-catalog-close:hover { background: rgba(255,255,255,.22); }
.scroll-catalog-close svg { width: 13px; height: 13px; stroke: currentColor; }
/* El panel ocupa todo el ancho de la ventana, pero el contenido iba topado a
   520px — unas 6 fichas de 76px+8 — así que en pantallas anchas la mitad del
   espacio quedaba vacío y había que arrastrar el carrusel sin necesidad. El
   tope sube por tramos: mantiene la medida cómoda en móvil y deja entrar más
   fichas según hay sitio. */
.scroll-catalog-body {
  width: 100%;
  max-width: 520px;
  margin: 0 auto;
  padding-right: 30px;
}
@media (min-width: 901px)  { .scroll-catalog-body { max-width: min(94vw, 880px); } }
@media (min-width: 1280px) { .scroll-catalog-body { max-width: min(94vw, 1180px); } }
@media (min-width: 1700px) { .scroll-catalog-body { max-width: min(94vw, 1520px); } }
.scroll-catalog-loading {
  text-align: center;
  color: rgba(255,255,255,.6);
  font-family: var(--sans);
  font-size: 13px;
  padding: 20px 0;
}
.scroll-catalog-search {
  margin-bottom: 6px;
  padding: 0 2px;
}
.scroll-catalog-search input {
  width: 100%;
  /* El cuerpo del panel se ensancha en pantallas grandes; el buscador no tiene
     por qué seguirle hasta los 1500px. */
  max-width: 520px;
  display: block;
  margin: 0 auto;
  padding: 5px 10px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--bg-post);
  color: var(--text);
  font-family: var(--sans);
  font-size: 12px;
  outline: none;
  box-sizing: border-box;
}
.scroll-catalog-search input:focus {
  border-color: var(--accent);
}
.scroll-catalog-jump-row {
  display: flex;
  justify-content: space-between;
  margin-bottom: 4px;
}
.scroll-catalog-jump-btn {
  background: var(--bg-post);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 3px 9px;
  border-radius: 5px;
  font-family: var(--sans);
  font-size: 10px;
  font-weight: 600;
  cursor: pointer;
}
.scroll-catalog-jump-btn:hover { background: var(--accent); color: #fff; border-color: var(--accent); }
.scroll-catalog-row {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding: 2px 2px 8px;
  scroll-snap-type: x proximity;
  scrollbar-width: thin;
  /* Un tablero con 3 hilos dejaba las fichas pegadas a la izquierda de un rail
     ancho. `safe center` las centra cuando sobra sitio y vuelve al inicio en
     cuanto desbordan — sin `safe`, centrar dejaría las primeras fichas fuera
     del área desplazable. La declaración previa es el respaldo para navegadores
     que no entiendan la palabra clave. */
  justify-content: flex-start;
  justify-content: safe center;
}
.scroll-catalog-row + .scroll-catalog-row { margin-top: 2px; }
.scroll-catalog-tile {
  flex: 0 0 auto;
  width: 76px;
  cursor: pointer;
  scroll-snap-align: center;
}
.scroll-catalog-tile-thumb {
  width: 76px;
  height: 76px;
  border-radius: 10px;
  background: var(--bg-post);
  overflow: hidden;
  border: 1px solid var(--border);   /* visible on light themes too */
  display: flex;
  align-items: center;
  justify-content: center;
}
.scroll-catalog-tile.current .scroll-catalog-tile-thumb,
.scroll-catalog-tile.armed .scroll-catalog-tile-thumb {
  border-color: var(--accent);
}
.scroll-catalog-tile-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Text fallback shown inside the thumbnail square when there's nothing to
   show a picture of: board chips with no logo get the legible /board/ id,
   text-only posts/threads get a snippet of their own raw content. */
.scroll-catalog-tile-board-id {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  color: var(--text);
  text-align: center;
  padding: 0 2px;
}
.scroll-catalog-tile-snippet {
  font-family: var(--sans);
  font-size: 10px;
  line-height: 1.3;
  color: var(--text-dim);
  text-align: center;
  padding: 6px;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 5;
  -webkit-box-orient: vertical;
}
.scroll-catalog-tile-label {
  font-family: var(--sans);
  font-size: 10px;
  font-weight: 600;
  color: var(--text);
  text-align: center;
  margin-top: 5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.scroll-catalog-tile-meta {
  font-family: var(--sans);
  font-size: 9px;
  color: var(--text-dim);
  text-align: center;
}

/* ═══════════════════════════════════════════════════════════════════════════
   Responsive: Mobile (<= 900px)
   ═══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 900px) {
  .scroll-header-row { padding: 6px 8px; }
  .scroll-tab { font-size: 10px; padding: 4px 8px; }
  /* Don't shrink the rail arrow on phones -- it should be at least as large as
     on desktop (was 18px/15px, too small to tap/see). */
  .scroll-rail-toggle { height: 30px; }
  .scroll-rail-toggle svg { width: 48px; height: 26px; }
  .scroll-catalog { top: 56px; padding: 8px 10px 12px; }
  .scroll-catalog-tile { width: 66px; }
  .scroll-catalog-tile-thumb { width: 66px; height: 66px; }
  /* Bottom padding lifts the centered raw text up out of the audio-chip zone
     (bottom-right) and into the free space at the top — it was sitting too low
     and overlapping the chip even when there was room above. */
  .scroll-text-hero { padding: 52px 14px 150px; }
  .scroll-text-content { font-size: clamp(15px, 4vw, 19px); padding: 18px 16px 14px; }
  .scroll-text-content.hero-size-xl { font-size: clamp(21px, 6.5vw, 27px); }
  .scroll-text-content.hero-size-lg { font-size: clamp(17px, 5vw, 21px); }
  .scroll-text-content.hero-size-sm { font-size: clamp(13px, 3.4vw, 16px); }
  .scroll-text-content.hero-size-xs { font-size: clamp(12px, 2.8vw, 14px); }
  .scroll-title-card { padding: 8px 12px; }
  .scroll-title-card.title-size-lg { font-size: clamp(17px, 6.5vw, 22px); }
  .scroll-title-card.title-size-md { font-size: clamp(14px, 5vw, 17px); }
  .scroll-title-card.title-size-sm { font-size: clamp(12px, 4vw, 14px); }
  .scroll-op-title-top { top: 48px; left: 12px; right: 12px; font-size: 22px; }
  .scroll-intro-header { top: 82px; left: 10px; right: 10px; padding: 8px 10px; gap: 9px; }
  .scroll-intro-chip { width: 38px; height: 38px; }
  .scroll-intro-name { font-size: 14px; }
  .scroll-intro-desc { font-size: 11px; }
  /* Right padding widened so the meta line's más/menos (read-more) button
     clears the audio chip (disc + name) stacked at the bottom of the action
     column — they were overlapping. */
  .scroll-card-overlay { right: 0; padding: 0 84px 12px 12px; }
  /* Raised to clear the audio-chip-taller action column on phones (the chip
     pushed the comments button up into the old 214/260 thread-stack zone). */
  .scroll-thread-stack { right: 6px; bottom: 296px; }
  .scroll-card-op .scroll-thread-stack { bottom: 344px; }
  .scroll-thread-card { width: 52px; }
  .scroll-board-chip { width: 42px; height: 42px; }
  .scroll-actions { right: 6px; bottom: 70px; gap: 4px; }
  .scroll-action-btn { width: 42px; height: 42px; }
  .scroll-action-btn svg { width: 20px; height: 20px; }
  .scroll-gallery-arrow { display: none !important; }
}

/* Desktop media query moved to the end of file */

/* ═══════════════════════════════════════════════════════════════════════════
   Comments bottom sheet (.scroll-comments-sheet)
   z-index: 95 — above cards (20) and catalog (90), below header (100)
   ═══════════════════════════════════════════════════════════════════════════ */
.scroll-comments-sheet {
  position: fixed;
  inset: 0;
  z-index: 95;
  pointer-events: none;
}
.scroll-comments-sheet:not([hidden]) {
  pointer-events: auto;
}

/* Semi-transparent backdrop */
.scs-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,.5);
  opacity: 0;
  transition: opacity .25s;
}
.scroll-comments-sheet.open .scs-backdrop {
  opacity: 1;
}

/* Sliding panel */
.scs-panel {
  position: absolute;
  left: 0; right: 0; bottom: var(--sfoot);   /* sit above the always-on footer */
  height: 72vh;
  border-radius: 16px 16px 0 0;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transform: translateY(100%);
  transition: transform .3s cubic-bezier(.32,0,.67,0);
  box-shadow: 0 -4px 32px rgba(0,0,0,.35);
}
.scroll-comments-sheet.open .scs-panel {
  transform: translateY(0);
}

/* Drag handle hint */
.scs-panel::before {
  content: '';
  display: block;
  width: 40px;
  height: 4px;
  border-radius: 2px;
  background: rgba(255,255,255,.2);
  margin: 10px auto 0;
  flex-shrink: 0;
}

/* Header */
.scs-header {
  display: flex;
  align-items: center;
  padding: 10px 16px 12px;
  border-bottom: 1px solid rgba(255,255,255,.07);
  flex-shrink: 0;
}
.scs-title {
  flex: 1;
  font-size: 15px;
  font-weight: 600;
}
.scs-close {
  background: none;
  border: none;
  color: inherit;
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  padding: 0 0 0 12px;
  opacity: .7;
}
.scs-close:hover { opacity: 1; }

/* Scrollable body */
.scs-body {
  flex: 1;
  overflow-y: auto;
  padding: 0 14px 8px;
  overscroll-behavior: contain;
  position: relative;
}

/* Section divider */
.scs-divider {
  height: 2px;
  background: rgba(255,255,255,.15);
  margin: 12px -14px;
}

/* "Load earlier" button */
.scs-load-earlier {
  display: block;
  width: 100%;
  padding: 7px 0;
  margin: 6px 0;
  background: none;
  border: 1px solid rgba(255,255,255,.12);
  border-radius: 8px;
  color: var(--accent);
  font-size: 13px;
  cursor: pointer;
  text-align: center;
}
.scs-load-earlier:hover {
  background: rgba(255,255,255,.04);
}
/* Same [hidden]-vs-class specificity trap as .sc-files-arrow / .sc-expand:
   display:block above ties [hidden]'s specificity and wins on source order,
   so the button showed even when the JS (earlier.hidden = !data.hasMore)
   correctly determined there was nothing left to load. */
.scs-load-earlier[hidden] { display: none; }

/* Loading spinner text */
.scs-loading {
  text-align: center;
  padding: 16px;
  color: rgba(255,255,255,.4);
  font-size: 13px;
}
.scs-empty-replies {
  text-align: center;
  padding: 16px;
  color: rgba(255,255,255,.35);
  font-size: 13px;
}

/* Collapsible "Ver citas" separator: sits BELOW the totals, loads on demand. */
.scs-quotes-wrap {
  margin: 10px -14px 0;
  border-top: 2px solid rgba(255,255,255,.12);
}
.scs-quotes-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  padding: 10px 0;
  background: none;
  border: none;
  color: var(--accent);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  letter-spacing: .02em;
}
.scs-quotes-toggle:hover { background: rgba(255,255,255,.03); }
.scs-qt-caret { transition: transform .18s; font-size: 11px; }
.scs-quotes-wrap.open .scs-qt-caret { transform: rotate(180deg); }
.scs-quotes-section { padding: 0 14px 4px; }
.scs-quotes-section[hidden] { display: none; }
.scs-quotes-empty {
  text-align: center;
  padding: 10px;
  color: rgba(255,255,255,.35);
  font-size: 12px;
}

/* ── Individual comment (.scroll-comment) ─── */
.scroll-comment {
  padding: 8px 0;
  border-bottom: 1px solid rgba(255,255,255,.05);
}
.scroll-comment:last-child {
  border-bottom: none;
}
/* The current post is hidden from its own totals list (you're already looking
   at it as the card). Hidden, not removed, so the shared per-thread list can be
   reused across posts without re-fetching -- just re-hidden per card. */
.scroll-comment.sc-deduped { display: none; }

/* Direct replies (quotes) visual differentiation */
.scs-quotes-section .scroll-comment {
  border-left: 3px solid var(--accent);
  padding-left: 10px;
  margin-left: -14px;
  padding-right: 14px;
  background: linear-gradient(90deg, rgba(255,255,255,0.03) 0%, transparent 100%);
}
.sc-header {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  /* Theme text (id/timestamp) -- was hardcoded white, invisible on light themes. */
  color: var(--text-dim);
  margin-bottom: 4px;
  flex-wrap: wrap;
}
.sc-name {
  font-weight: 600;
  color: var(--text);
}
.sc-capcode {
  font-size: 10px;
  font-weight: 700;
  color: var(--accent);
  letter-spacing: .04em;
}
/* Capcode type colors — match board's .capcode-* CSS vars */
.sc-capcode-op      { color: var(--capcode-op,    #5c7ec4) !important; }
.sc-capcode-mod     { color: var(--capcode-mod,   #2a8a3a) !important; }
.sc-capcode-admin   { color: var(--danger)                 !important; }
.sc-capcode-bo      { color: var(--capcode-bo,    #c47a1a) !important; }
.sc-capcode-monitor { color: var(--accent-deep,   #5a4c20) !important; }
/* Staff capcodes (admin/mod): hide the gem ID suffix so only the gem name shows */
.sc-gem.sc-gem-staff .gem-suffix { display: none; }

/* When a consecutive run of posts has the same poster, hide the repeated
   gem badge, name — keep the post number, timestamp and quote button. */
.sc-grouped .sc-gem,
.sc-grouped .sc-name { display: none; }
.sc-grouped .sc-no { display: inline-block !important; }
/* When the timestamp text also matches the previous post, hide it too */
.sc-grouped.sc-grouped-time .sc-time { display: none; }
/* Tighten the top gap between grouped posts */
.sc-grouped { padding-top: 1px; border-top: none; }

@keyframes scTargetFlash {
  0% { background-color: color-mix(in srgb, var(--accent) 30%, transparent); }
  100% { background-color: transparent; }
}
.sc-target-flash {
  animation: scTargetFlash 2s ease-out;
}
/* Keep the header row present on EVERY post even when grouped -- only the
   identity bits (gem/name/no/time) collapse, never the ↩/⋯ action buttons.
   Otherwise a post buried in a same-poster burst couldn't be replied to or
   reported, which removes the only per-post self-defense/communication path.
   The row collapses to a thin right-aligned button cluster, no real gap. */
.sc-grouped .sc-header { min-height: 0; padding-bottom: 0; margin-bottom: 0; }

.sc-no {
  font-size: 11px;
}
.sc-time {
  font-size: 11px;
}
.sc-quote-btn {
  margin-left: auto;
  background: none;
  border: none;
  color: var(--accent);
  cursor: pointer;
  font-size: 15px;
  padding: 0 2px;
  line-height: 1;
  flex-shrink: 0;
}
.sc-more-btn {
  background: none;
  border: none;
  color: var(--text-dim);
  cursor: pointer;
  font-size: 17px;
  padding: 0 4px;
  line-height: 1;
  flex-shrink: 0;
}
.sc-more-btn:hover { color: var(--text); }
/* Comment chips linking to the post's Poll/Dice card page. */
.sc-extra-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.sc-extra-chip {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--border));
  color: var(--accent);
  border-radius: 14px; padding: 4px 10px;
  font-family: var(--sans); font-size: 12px; font-weight: 600; cursor: pointer;
}
.sc-extra-chip:hover { background: var(--accent); color: #fff; }
.sc-gem {
  font-size: 11px;
  padding: 1px 5px;
  border-radius: 4px;
  line-height: 1.4;
}
.sc-content {
  font-size: 14px;
  line-height: 1.55;
  overflow-wrap: break-word;
  word-break: break-word;
  /* -webkit-line-clamp clips at an exact rendered line count instead of an
     em-based max-height guess -- the guess drifted whenever an inline child
     (quote refs, greentext, etc.) used different font metrics than the
     body text, clamping short posts that had no real overflow. This clips
     precisely, so the JS overflow check (scrollHeight vs clientHeight) is
     comparing two numbers the browser computed the same way, not a
     measured height against an estimated one. */
  display: -webkit-box;
  -webkit-line-clamp: 5;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.sc-body.expanded .sc-content {
  display: block;
  -webkit-line-clamp: unset;
  overflow: visible;
}
/* Keep greentext/quote colors from the markup renderer */
.sc-content .greentext { color: var(--greentext, #789922); }
.sc-content .postref   { color: var(--accent); text-decoration: none; }

.sc-expand {
  display: block;
  width: 100%;
  background: none;
  border: none;
  color: var(--accent);
  font-size: 12px;
  cursor: pointer;
  padding: 2px 0 0;
  text-align: right;
  opacity: .75;
}
/* Same trap as .sc-files-arrow: [hidden] and .sc-expand are both specificity
   (0,1,0), so this class's display:block was winning on source order alone
   and the button showed on EVERY post regardless of what the JS overflow
   check (btn.hidden = ...) actually decided -- toggling a DOM property that
   had no visual effect. */
.sc-expand[hidden] { display: none; }
.sc-expand:hover { opacity: 1; }

/* ── Comment file strip ──────────────────────────────────────────────────────
   Multi-image: mirrors .files.multi (900px+ board) — one unwrapped flex row.
   All images share a fixed max-height ceiling; each width adapts to its own
   aspect ratio so portrait images stay narrow and landscape images stay wide.
   flex:0 1 auto + min-width:0 lets items shrink proportionally when needed.
   max-width:100% !important (like the board) lets the image track the shrinking
   flex item without overflow or cropping.

   Single image: floats left so the post text wraps around it, mirroring
   .files.single (900px+ board). ── */

/* ── Multi-image strip ── */
.sc-files-wrap {
  position: relative;
  margin: 4px 0 8px;
  overflow: hidden;
}
.sc-files {
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  gap: 6px;
  max-width: 100%;
  overflow-x: auto;
  overflow-y: visible;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.sc-files::-webkit-scrollbar { display: none; }

/* Transparent scroll arrows — revealed by JS based on scroll position */
.sc-files-arrow {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 32px;
  border: none;
  color: #fff;
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  pointer-events: auto;
  z-index: 2;
}
.sc-files-arrow-left {
  left: 0;
  background: linear-gradient(to left, transparent 0%, rgba(0,0,0,.55) 100%);
  justify-content: flex-start;
  padding-left: 4px;
}
.sc-files-arrow-right {
  right: 0;
  background: linear-gradient(to right, transparent 0%, rgba(0,0,0,.55) 100%);
  justify-content: flex-end;
  padding-right: 4px;
}
/* [hidden] and .sc-files-arrow both have specificity (0,1,0); the class rule
   above wins on source order alone unless we re-assert [hidden] here. */
.sc-files-arrow[hidden] { display: none; }
.sc-file-link,
.sc-file-vid,
.sc-file-aud { flex: 0 1 auto; min-width: 0; }
.sc-file-link { display: block; line-height: 0; }

/* ALL imgs inside any .thumb anchor: covers original sc-file-img,
   revealed images (new <img> with no class), and re-spoilered placeholders.
   !important beats any inline style that app-media.js might restore. */
.sc-files .thumb img {
  display: block;
  max-height: 110px;
  max-width: 100% !important;
  width: auto !important;
  height: auto !important;
  border-radius: 6px;
}
/* Keep .sc-file-img working for non-thumb cases (shouldn't exist, but safe) */
.sc-file-img {
  display: block;
  max-height: 110px;
  max-width: 100% !important;
  width: auto;
  height: auto;
  border-radius: 6px;
}

/* Override global .thumb.spoilered min-width/height inside the strip
   so spoiler tiles don't add extra space and flex sizing works cleanly */
.sc-files .thumb.spoilered,
.sc-files .thumb.revealed { min-width: 0; min-height: 0; }

/* Overflow chip — 6th slot when post has more than 5 strip files.
   align-self:stretch makes it match the tallest sibling thumbnail height. */
.sc-files-overflow-chip {
  display: flex;
  align-items: center;
  justify-content: center;
  align-self: stretch;
  min-height: 48px;
  min-width: 48px;
  padding: 0 10px;
  background: rgba(255,255,255,.1);
  border: 1px solid rgba(255,255,255,.18);
  border-radius: 6px;
  color: inherit;
  text-decoration: none;
  font-size: 13px;
  font-weight: 600;
  flex-shrink: 0;
}
.sc-files-overflow-chip:hover { background: rgba(255,255,255,.18); }

/* ── Mini video player (single-file comment video) ── */
.sc-vid-mini {
  position: relative;
  display: block;
  border-radius: 8px;
  overflow: hidden;
  background: #000;
}
.sc-vid-mini video {
  display: block;
  width: 100%;
  height: auto;
}
.sc-vid-mini-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.sc-vid-play-btn {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  border: none;
  background: rgba(0,0,0,.55);
  color: #fff;
  font-size: 20px;
  cursor: pointer;
  pointer-events: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background .15s;
}
.sc-vid-play-btn:hover { background: rgba(0,0,0,.75); }
.sc-vid-expand-btn {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 26px;
  height: 26px;
  background: rgba(0,0,0,.4);
  border-radius: 5px;
  color: #fff;
  text-decoration: none;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  opacity: .7;
  transition: opacity .15s;
}
.sc-vid-expand-btn:hover { opacity: 1; }

/* Strip-sized variant: video is one of several file thumbs in a row, so it
   caps at the same max-height the image thumbs use instead of stretching
   to 100% width. */
.sc-vid-mini-strip {
  flex-shrink: 0;
  max-height: 110px;
}
.sc-vid-mini-strip video {
  max-height: 110px;
  width: auto;
  height: auto;
}
.sc-vid-mini-strip .sc-vid-play-btn {
  width: 34px;
  height: 34px;
  font-size: 14px;
}
.sc-vid-mini-strip .sc-vid-expand-btn {
  top: 4px;
  right: 4px;
  width: 20px;
  height: 20px;
  font-size: 11px;
}

/* ── Single image: float left, text wraps right ── */
.sc-files.sc-files-single {
  display: block;
  float: left;
  margin: 2px 10px 6px 0;
  max-width: 160px;
}
.sc-files.sc-files-single .thumb img,
.sc-files.sc-files-single .sc-file-img {
  max-width: 100% !important;
  max-height: 200px;
  border-radius: 6px;
}

/* sc-body: overflow:hidden creates a BFC so it contains the single floating
   image (sc-files-single). Text truncation itself lives on .sc-content via
   -webkit-line-clamp (see above), not on this element -- a fixed max-height
   here would re-introduce the mismatch that clamped short posts. */
.sc-body {
  font-size: 14px;
  overflow: hidden;
}

/* ── Video / audio in strip ── */
.sc-file-vid {
  border-radius: 6px;
  overflow: hidden;
  max-width: 200px;
}
.sc-file-vid .cmp-video-wrap { border-radius: 6px; }
.sc-file-vid video {
  display: block;
  max-width: 200px;
  max-height: 130px;
  width: auto;
  height: auto;
}
.sc-file-aud {
  background: rgba(255,255,255,.06);
  border-radius: 8px;
  padding: 4px 6px;
  display: flex;
  align-items: center;
}
.sc-file-aud audio {
  display: block;
  width: 200px;
  max-width: 100%;
  border-radius: 6px;
}
/* Native <audio controls>/<video controls> render light/system-themed by
   default, which clashes hard with the dark scroll UI (a bright white pill
   floating on black). color-scheme:dark tells Chromium/WebKit to paint the
   built-in controls in their dark variant instead of building a custom
   player -- keeps them "simple, transparent" per spec while still fitting
   the theme. Scoped broadly (not just .sc-file-aud) so inline audio embedded
   in comment/card post text (markup.js's .inline-audio, untouched by
   app-media-player.js inside scroll containers) is covered too. */
.scroll-comments-sheet audio,
.scroll-card audio {
  color-scheme: dark;
}

/* ── Simple custom audio player (replaces native controls) ──
   Big play/pause button + plain progress bar (click to seek) + time. No
   volume, no options menu. Built by _simplifyAudio() in app-scroll.js. */
.sc-audio {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  max-width: 360px;
  margin: 0 auto;
  padding: 8px 14px;
  box-sizing: border-box;
  border-radius: 30px;
  background: color-mix(in srgb, var(--accent, #e0679b) 14%, transparent);
}
.sc-audio-play {
  flex: 0 0 auto;
  width: 42px; height: 42px;
  border: none; border-radius: 50%;
  background: var(--accent, #e0679b);
  color: #fff;
  font-size: 16px; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  padding: 0;
}
.sc-audio-play .sc-audio-ic-play { margin-left: 2px; }
.sc-audio-play .sc-audio-ic-pause { font-size: 13px; letter-spacing: -1px; }
.sc-audio-bar {
  flex: 1 1 auto;
  height: 6px;
  border-radius: 3px;
  background: color-mix(in srgb, var(--accent, #e0679b) 28%, transparent);
  cursor: pointer;
  overflow: hidden;
}
.sc-audio-fill {
  height: 100%;
  width: 0%;
  border-radius: 3px;
  background: var(--accent, #e0679b);
}
.sc-audio-time {
  flex: 0 0 auto;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim, rgba(255,255,255,.7));
  white-space: nowrap;
}
/* Audio-only card centers the pill in its media area. */
.scroll-gallery-slide-audio .sc-audio { margin-top: 8px; }
/* When the custom pill is present, drop the comment wrapper's own bg/padding
   so it doesn't double up. */
.sc-file-aud:has(.sc-audio) { background: none; padding: 0; width: 100%; }

/* ── Reply form ─── */
.scs-reply-form {
  flex-shrink: 0;
  padding: 0;
  border-top: 1px solid rgba(255,255,255,.07);
  display: flex;
  flex-direction: column;
}
.scs-input-row {
  display: flex;
  align-items: flex-end;
  gap: 8px;
}
.scs-textarea {
  flex: 1;
  background: rgba(255,255,255,.07);
  border: none;
  border-radius: 10px;
  color: inherit;
  font-size: 14px;
  font-family: inherit;
  padding: 8px 12px;
  resize: none;
  min-height: 38px;
  max-height: 120px;
  overflow-y: auto;
  line-height: 1.4;
}
.scs-textarea:focus {
  outline: none;
  background: rgba(255,255,255,.1);
}
.scs-send {
  flex-shrink: 0;
  background: var(--accent);
  border: none;
  border-radius: 20px;
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  padding: 7px 16px;
  cursor: pointer;
  white-space: nowrap;
  transition: opacity .15s;
}
.scs-send:disabled { opacity: .5; cursor: default; }
.scs-send:hover:not(:disabled) { opacity: .88; }

/* ── Reply widget — parked (not rendered), moved into the active sheet on open ── */
/* display:none means offsetHeight=0 while parked, so the ResizeObserver baseline
   is captured fresh the first time the widget is shown inside a real sheet. */
#scroll-reply-park { display: none; }

/* When #reply-widget is inside .scs-reply-form, cancel float-widget positioning */
.scs-reply-form #reply-widget {
  position: static !important;
  display: block !important;
  visibility: visible !important;
  pointer-events: auto !important;
  width: 100% !important;
  max-width: none !important;
  transform: none !important;   /* cancel slide-in animation from .reply-widget base CSS */
  transition: none !important;
}
/* The compact chat bar should fill the full reply-form width */
.scs-reply-form .ce-chat-bar {
  width: 100% !important;
  box-sizing: border-box !important;
}
/* Gallery file rail sits above the chat line */
.scs-reply-form .gallery-wrap {
  width: 100%;
  max-height: 100px;
  overflow-x: auto;
}
/* Char counter centered in the free space between the name chip and the
   toolbar buttons (see _openSheet). */
.scr-counter-center { display: flex; align-items: center; justify-content: center; font-size: 11px; color: var(--text-dim); margin-left: 4px; }
/* Name chip: show more characters (no longer clipped to a few). */
.scs-reply-form .ccb-name { max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Send arrow: a clearly visible circular accent button, always shown in the
   scroll reply bar (the base rule hides it >=900px). */
.scs-reply-form .ccb-send {
  display: inline-flex !important;
  align-items: center; justify-content: center;
  width: 34px; height: 34px; padding: 0;
  border: 1.5px solid var(--accent); border-radius: 50%;
  color: var(--accent); background: transparent; font-size: 13px;
  flex: 0 0 auto;
}
.scs-reply-form .ccb-send:hover { background: var(--accent); color: #fff; }

/* ═══════════════════════════════════════════════════════════════════════════
   ⋯ action menu (.scroll-action-menu) — bottom sheet of post actions
   z-index: 98 — above the comments sheet (95) since it can be opened from
   inside a comment, below the header (100).
   ═══════════════════════════════════════════════════════════════════════════ */
.scroll-action-menu {
  position: fixed;
  inset: 0;
  z-index: 98;
}
.scam-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,.5);
  opacity: 0;
  transition: opacity .2s;
}
.scroll-action-menu.open .scam-backdrop { opacity: 1; }
.scam-panel {
  position: absolute;
  left: 0; right: 0; bottom: var(--sfoot, 56px);   /* sit above the always-on footer */
  background: var(--bg);
  border-radius: 16px 16px 0 0;
  box-shadow: 0 -4px 32px rgba(0,0,0,.4);
  padding: 8px 8px 12px;
  transform: translateY(calc(100% + var(--sfoot, 56px)));
  transition: transform .28s cubic-bezier(.32,0,.67,0);
}
.scroll-action-menu.open .scam-panel { transform: translateY(0); }
.scam-panel::before {
  content: '';
  display: block;
  width: 40px;
  height: 4px;
  border-radius: 2px;
  background: rgba(255,255,255,.2);
  margin: 6px auto 10px;
}
.scam-item {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 14px 16px;
  background: none;
  border: none;
  border-radius: 12px;
  color: var(--text);
  font-family: var(--sans);
  font-size: 15px;
  text-align: left;
  cursor: pointer;
}
.scam-item:hover, .scam-item:active { background: rgba(255,255,255,.07); }
.scam-item.scam-danger { color: #ff6b6b; }
.scam-ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  flex-shrink: 0;
}
.scam-ico svg { width: 20px; height: 20px; }
.scam-label { flex: 1; }

/* ═══════════════════════════════════════════════════════════════════════════
   Footer navigation bar (.scroll-footer) + Hilos view + Info sheet (Part D)
   Footer z-index 85: above cards (20), below catalog (90) / sheets (95) /
   header (100) so opening any of those covers it.
   ═══════════════════════════════════════════════════════════════════════════ */
.scroll-body { --sfoot: 56px; }
.scroll-footer {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  /* Topmost: the footer stays visible ON TOP of every overlay (Hilos, Crear,
     Info/Ajustes/Avisos, comments) so the user can switch pages fast. Every
     one of those overlays ends at `bottom: var(--sfoot)` so none cover it. */
  z-index: 130;
  display: flex;
  align-items: stretch;
  height: var(--sfoot);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: blur(8px);
  border-top: 1px solid rgba(255,255,255,.08);
}
/* Hide footer when comments are open on mobile to save space and avoid confusion */
@media (max-width: 900px) {
  body.scroll-body.scs-open .scroll-footer {
    display: none !important;
  }
  body.scroll-body.scs-open .scs-panel {
    bottom: 0 !important;
  }
}
.sfoot-btn {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  background: none;
  border: none;
  color: var(--text-dim);
  cursor: pointer;
  font-family: var(--sans);
  min-width: 0;
}
.sfoot-btn:hover, .sfoot-btn:active { color: var(--text); }
.sfoot-ico { display: inline-flex; }
.sfoot-ico svg { width: 22px; height: 22px; }
.sfoot-lbl { font-size: 10px; line-height: 1; }

/* Clear the footer: the poster/meta overlay text must not sit under it. */
.scroll-card-overlay { padding-bottom: calc(16px + var(--sfoot)); }
/* The custom video control bar sits at the card's bottom edge, which the
   footer covers -- lift it by the footer height on full-screen feed cards
   (comment-sheet / mini-strip players are outside .scroll-stack, untouched).
   Reset to 0 in native fullscreen, where the footer isn't on screen. */
.scroll-stack .cmp-bar { bottom: var(--sfoot); }
.cmp-video-wrap:fullscreen .cmp-bar,
.cmp-video-wrap:-webkit-full-screen .cmp-bar { bottom: 0; }

/* ── Fullscreen scrubber for scroll-card videos (double-tap to fullscreen) ──
   A subtle translucent bar with a clearly-visible thumb for seeking. */
.scroll-fs-scrub {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 22px 20px calc(20px + env(safe-area-inset-bottom, 0px));
  z-index: 30;
  background: linear-gradient(to top, rgba(0,0,0,.45), transparent);
}
.scroll-fs-scrub-track {
  position: relative;
  height: 5px;
  border-radius: 3px;
  background: rgba(255,255,255,.28);
  cursor: pointer;
  touch-action: none;
}
.scroll-fs-scrub-fill {
  position: absolute; left: 0; top: 0; bottom: 0;
  border-radius: 3px;
  background: rgba(255,255,255,.85);
}
.scroll-fs-scrub-thumb {
  position: absolute; top: 50%;
  width: 16px; height: 16px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 0 4px rgba(0,0,0,.25), 0 1px 4px rgba(0,0,0,.5);
  transform: translate(-50%, -50%);
  pointer-events: none;
}

/* ── Hilos view (full-screen board browser) ──
   z-index 110: ABOVE the scroll header (100) so it fully covers it -- otherwise
   the header's back arrow overlaps the view and there's no reachable close. */
.scroll-hilos {
  position: fixed;
  inset: 0;
  bottom: var(--sfoot);   /* end above the always-on footer */
  z-index: 110;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity .22s, transform .22s;
}
.scroll-hilos.open { opacity: 1; transform: translateY(0); }
/* [hidden] and the .scroll-hilos class both have (0,1,0) specificity; without
   this the class's display:flex wins on source order and the view is stuck
   visible on load. (Recurring style-scroll trap.) */
.scroll-hilos[hidden] { display: none; }
.scroll-hilos-head {
  display: flex;
  align-items: center;
  padding: 9px 16px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.scroll-hilos-title { flex: 1; font-size: 16px; font-weight: 600; font-family: var(--sans); }
.scroll-hilos-close,
.scroll-saved-close {
  background: none; border: none; color: var(--text-dim); cursor: pointer;
  display: inline-flex; padding: 4px;
}
.scroll-hilos-close:hover,
.scroll-saved-close:hover { color: var(--text); }
.scroll-hilos-close svg,
.scroll-saved-close svg { width: 22px; height: 22px; stroke: currentColor; }
.scroll-hilos-rail {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding: 8px 16px;
  flex-shrink: 0;
  border-bottom: 1px solid var(--border);
}
.shilos-board {
  flex: 0 0 auto;
  width: 56px; height: 56px;
  border-radius: 12px;
  border: 2px solid transparent;
  background: var(--bg-post) center/cover no-repeat;
  color: var(--text);
  font-family: var(--sans); font-size: 11px; font-weight: 600;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.shilos-board.active { border-color: var(--accent); }
/* Sub-board rail sits under the main rail, visually distinct (tighter, inset). */
.scroll-hilos-rail-sub { padding: 6px 16px; background: color-mix(in srgb, var(--bg-post) 40%, transparent); }
.scroll-hilos-rail-sub[hidden] { display: none; }
.scroll-hilos-rail-sub .shilos-board { width: 44px; height: 44px; font-size: 10px; }
/* Always-visible create bar (out of the scrolling grid so it never scrolls off). */
.scroll-hilos-createbar { flex-shrink: 0; padding: 8px 16px 6px; }
.scroll-hilos-createbar:empty { display: none; }
.scroll-hilos-createbar .shilos-create { margin: 0 auto; }
/* Thread search */
.scroll-hilos-search { padding: 8px 16px 2px; flex-shrink: 0; }
.scroll-hilos-search input {
  width: 100%; box-sizing: border-box;
  background: var(--bg-post); border: 1px solid var(--border);
  border-radius: 20px; color: var(--text);
  font-family: var(--sans); font-size: 14px; padding: 8px 14px;
}
/* Hilos covers the footer (z 110), so no --sfoot clearance is needed here. */
.scroll-hilos-body { flex: 1; overflow-y: auto; padding: 12px 12px 14px; }
.shilos-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);   /* exact 4 columns → 4x4 per page */
  gap: 8px;
}
/* Thread pager (prev / page / next) */
.scroll-hilos-pager {
  display: flex; align-items: center; justify-content: center; gap: 14px;
  padding: 8px 16px;
  border-top: 1px solid rgba(255,255,255,.06);
  flex-shrink: 0;
}
.scroll-hilos-pager[hidden] { display: none; }
.shilos-pg {
  background: var(--bg-post); border: 1px solid var(--border);
  color: var(--text); cursor: pointer;
  width: 40px; height: 34px; border-radius: 8px; font-size: 18px;
}
.shilos-pg:disabled { opacity: .4; cursor: default; }
.shilos-pg-ind { font-family: var(--sans); font-size: 13px; color: var(--text-dim); min-width: 54px; text-align: center; }
.shilos-tile {
  display: flex; flex-direction: column;
  background: var(--bg-post);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  text-decoration: none;
  color: var(--text);
}
.shilos-thumb {
  height: 84px;
  background: rgba(255,255,255,.04) center/cover no-repeat;
}
.shilos-thumb-text {
  padding: 6px; font-size: 10.5px; color: var(--text-dim);
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
}
.shilos-tile-sub {
  padding: 5px 6px 1px; font-size: 11px; font-weight: 600; line-height: 1.25;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.shilos-tile-meta { padding: 0 6px 6px; font-size: 10px; color: var(--text-dim); }
.shilos-loading, .shilos-empty { color: var(--text-dim); padding: 20px; text-align: center; }

/* ── Guardados (Saved) catalog ── */
.scroll-saved-tabs {
  display: flex; gap: 6px; padding: 8px 16px 2px; flex-shrink: 0;
}
.scroll-saved-tab {
  flex: 1; padding: 7px 4px; border: 1px solid var(--border); border-radius: 20px;
  background: transparent; color: var(--text-dim); font-size: 12px; font-weight: 600;
  cursor: pointer;
}
.scroll-saved-tab.active {
  background: var(--accent); border-color: var(--accent); color: #fff;
}
.saved-tile { position: relative; }
.saved-tile-thread { border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); }
.shilos-tile-meta .saved-tag {
  display: inline-block; font-size: 8.5px; font-weight: 700; letter-spacing: .04em;
  padding: 1px 5px; border-radius: 4px; background: var(--accent); color: #fff; margin-right: 5px;
}
.shilos-tile-meta .saved-tag-orphan { background: var(--text-dim); }
.shilos-tile-meta .saved-count { font-variant-numeric: tabular-nums; }
.saved-saveall {
  margin: 0 6px 6px; padding: 4px 8px; font-size: 10px; font-weight: 600;
  border: 1px solid var(--accent); border-radius: 14px;
  background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent);
  cursor: pointer;
}
.saved-saveall:disabled { opacity: .6; }
.saved-del {
  position: absolute; top: 5px; right: 5px; z-index: 3;
  width: 22px; height: 22px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: none; border-radius: 50%;
  background: rgba(0,0,0,.5); color: #fff; font-size: 12px; line-height: 1;
  cursor: pointer; opacity: .55;
}
.saved-del:hover { opacity: 1; background: var(--danger, #c0392b); }
.shilos-create {
  display: block;
  width: 100%;
  margin: 10px auto 2px;
  padding: 11px 18px;
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: 22px;
  font-family: var(--sans); font-weight: 600; font-size: 14px;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  max-width: 320px;
}

/* ── Info sheet content (reuses .scam-panel chrome) ── */
.scroll-info-sheet .sinfo-title {
  font-family: var(--sans); font-weight: 600; font-size: 15px;
  padding: 6px 10px 10px;
}
.sinfo-row {
  display: flex; gap: 10px; padding: 8px 10px;
  border-top: 1px solid rgba(255,255,255,.05);
  font-family: var(--sans); font-size: 14px;
}
.sinfo-k { color: var(--text-dim); flex: 0 0 84px; }
.sinfo-v { color: var(--text); flex: 1; word-break: break-word; }
.sinfo-legal {
  margin: 10px 10px 4px;
  padding-top: 10px;
  border-top: 1px solid rgba(255,255,255,.06);
  font-family: var(--sans);
  font-size: 11px;
  line-height: 1.5;
  color: var(--text-dim);
}
.sinfo-legal a { color: var(--accent); }

/* ── Ajustes / Avisos bottom sheets (scroll-native, reuse .scam-panel chrome) ── */
.scroll-settings-sheet .scam-panel,
.scroll-avisos-sheet .scam-panel { max-height: 82vh; overflow-y: auto; }
.sset-head {
  font-family: var(--sans); font-weight: 600; font-size: 16px;
  padding: 2px 10px 10px;
}
.sset-label {
  font-family: var(--sans); font-size: 11px; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: .05em;
  padding: 12px 10px 6px;
}
.scroll-settings-sheet .up-select {
  width: calc(100% - 20px); box-sizing: border-box; margin: 0 10px;
}
.scroll-settings-sheet .up-theme-grid { padding: 0 6px; }
.sset-check {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 10px 4px; font-family: var(--sans); font-size: 13px;
  color: var(--text); cursor: pointer;
}
.sset-check input { width: 17px; height: 17px; accent-color: var(--accent); flex: 0 0 auto; }
.savisos-host { padding: 4px 4px 10px; }
/* Hilos con notificación (watched threads) gallery inside the Avisos sheet */
.savisos-watches { border-top: 1px solid var(--border); margin-top: 6px; padding: 8px 6px 4px; }
.savisos-watches[hidden] { display: none; }
.savisos-watches-head {
  font-family: var(--sans); font-size: 11px; text-transform: uppercase;
  letter-spacing: .05em; color: var(--text-dim); padding: 2px 4px 8px;
}
.savisos-watch-grid.shilos-grid { grid-template-columns: repeat(2, 1fr); }
.savisos-watch-pager {
  display: flex; justify-content: center; align-items: center; gap: 12px; padding: 8px 0 2px;
}

/* ── Crear hilo (new-thread form) full-screen sheet ── */
.scroll-crear {
  position: fixed;
  inset: 0;
  bottom: var(--sfoot);   /* end above the always-on footer */
  z-index: 97;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity .22s, transform .22s;
}
.scroll-crear.open { opacity: 1; transform: translateY(0); }
.scroll-crear[hidden] { display: none; }   /* class display:flex would tie [hidden] otherwise */
.scroll-crear-head {
  display: flex; align-items: center;
  padding: 14px 16px;
  border-bottom: 1px solid rgba(255,255,255,.08);
  flex-shrink: 0;
}
.scroll-crear-title { flex: 1; font-size: 16px; font-weight: 600; font-family: var(--sans); }
.scroll-crear-close { background: none; border: none; color: var(--text); cursor: pointer; display: inline-flex; padding: 4px; }
.scroll-crear-close svg { width: 22px; height: 22px; }
/* Crear covers the footer + starts below the header (top set in JS), so no
   --sfoot clearance needed here. */
.scroll-crear-body { flex: 1; overflow-y: auto; padding: 14px 16px 24px; }
.scroll-crear .post-form-wrap { width: 100%; }
.scr-form { display: flex; flex-direction: column; gap: 9px; }
/* Rows: name / subject each full width */
.scr-field input {
  width: 100%; box-sizing: border-box;
  padding: 11px 12px; font-size: 15px;
  background: var(--bg-post); border: 1px solid var(--border);
  border-radius: 8px; color: var(--text);
}
/* Row: the three checkboxes */
.scr-checks {
  display: flex; flex-wrap: wrap; gap: 14px; align-items: center;
  font-family: var(--sans); font-size: 13px; color: var(--text);
  padding: 2px 0;
}
.scr-checks label { display: inline-flex; align-items: center; gap: 5px; cursor: pointer; }
.scr-checks .translate-subject-opt span { color: var(--text-dim); }
/* Row: capcode */
.scr-capcode { font-family: var(--sans); font-size: 13px; display: flex; align-items: center; gap: 6px; }
.scr-capcode select { padding: 5px 8px; border-radius: 6px; background: var(--bg-post); color: var(--text); border: 1px solid var(--border); }
/* Big, always-visible file dropzone (the gallery's "+" chip). */
.scroll-crear .editor-gallery-wrap { width: 100%; }
.scroll-crear .gallery-add {
  width: 96px !important; height: 96px !important;
  display: flex !important; align-items: center; justify-content: center;
  border: 2px dashed var(--border-strong, rgba(255,255,255,.25)) !important;
  border-radius: 10px !important; background: var(--bg-post) !important;
}
.scroll-crear .gallery-add .add-icon { font-size: 40px; line-height: 1; color: var(--accent); }
/* Char counter, lifted into the chat controls row (see _openCrear). */
.scr-counter { margin-left: auto; font-size: 11px; color: var(--text-dim); font-family: var(--sans); }
/* Big publish button (override wireNewThreadEditor's inline display:none). */
.scr-submit {
  display: block !important;
  width: 100%; box-sizing: border-box;
  padding: 14px; margin-top: 6px;
  background: var(--accent); color: #fff; border: none; border-radius: 10px;
  font-family: var(--sans); font-weight: 700; font-size: 16px; cursor: pointer;
}
.scr-submit:hover { filter: brightness(1.06); }
.scr-preview-btn {
  flex: 0 0 auto;
  padding: 9px 18px;
  background: var(--bg-post); color: var(--accent);
  border: 1.5px solid var(--accent); border-radius: 10px;
  font-family: var(--sans); font-weight: 700; font-size: 14px; cursor: pointer;
}
.scr-preview-btn:hover { background: var(--accent); color: #fff; }

/* ── Preview overlay: a read-only full-screen scroll card ── */
.scroll-preview {
  position: fixed;
  inset: 0;
  z-index: 120;   /* above Crear (97), below the footer (130) is fine; cover all */
  background: #000;
  display: flex;
  flex-direction: column;
  opacity: 0;
  transition: opacity .22s;
}
.scroll-preview.open { opacity: 1; }
.scroll-preview[hidden] { display: none; }
.scroll-preview-head {
  position: absolute; top: 0; left: 0; right: 0; z-index: 5;
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px;
  background: linear-gradient(to bottom, rgba(0,0,0,.55), transparent);
  pointer-events: none;
}
.scroll-preview-head > * { pointer-events: auto; }
.scroll-preview-close {
  display: inline-flex; align-items: center; gap: 4px;
  background: rgba(0,0,0,.4); border: 1px solid rgba(255,255,255,.25);
  color: #fff; border-radius: 20px; padding: 6px 12px 6px 8px;
  font-family: var(--sans); font-size: 13px; font-weight: 600; cursor: pointer;
  backdrop-filter: blur(8px);
}
.scroll-preview-close svg { width: 18px; height: 18px; }
.scroll-preview-tag {
  margin-left: auto;
  font-family: var(--sans); font-size: 12px; font-weight: 600;
  color: rgba(255,255,255,.85); background: rgba(0,0,0,.4);
  padding: 4px 10px; border-radius: 20px; backdrop-filter: blur(8px);
}
.scroll-preview-stack { flex: 1; position: relative; overflow: hidden; }
/* The preview card fills the stack like a real feed card. */
.scroll-preview-stack .scroll-card {
  position: absolute; inset: 0; height: 100%;
}

/* ── Crear form: FULL editor, mobile polish ──
   (Uses the full rich editor -- multi-line box, visible file gallery, dice/
   poll -- not the compact chat bar, which was hiding all of those.) */
.scr-checks, .scr-capcode { justify-content: center; }
/* Tall WHITE compose box (var(--bg-input) = white on light themes) with a
   clear accent-tinted border so it's obvious this is where you type. */
.scroll-crear .rich-editor {
  min-height: 11em !important;
  max-height: 46vh;
  overflow-y: auto;
  background: var(--bg-input, #fff) !important;
  color: var(--text) !important;
  border: 1.5px solid color-mix(in srgb, var(--accent) 45%, var(--border)) !important;
  border-radius: 8px !important;
  padding: 10px 12px !important;
}
.scroll-crear .rich-editor:focus { border-color: var(--accent) !important; }
/* Match the name/subject fields to the same white so the writable areas read
   as one consistent set of inputs. */
.scr-field input { background: var(--bg-input, #fff); }
/* Remove crudo/live toggle + language selector -- they don't belong in scroll. */
.scroll-crear .editor-live-toggle,
.scroll-crear .editor-lang-sel { display: none !important; }
/* Bigger, easily tappable toolbar buttons. */
.scroll-crear .sel-tb-btn { min-height: 34px; padding: 6px 10px; font-size: 0.9rem; }
/* One publish button: hide the editor's own inline submit; keep .scr-submit. */
.scroll-crear .editor-actions { display: none !important; }
.scr-counter { font-size: 11px; color: var(--text-dim); font-family: var(--sans); }
/* Dados / Encuesta toggle bar centered; each opens its own panel already. */
.scroll-crear .reply-extras-bar { display: flex !important; justify-content: center !important; gap: 12px; margin: 8px 0; }
/* Gallery: taller + wider chips so the delete ✕ / spoiler are easy to hit. */
.scroll-crear .editor-gallery { display: flex; flex-wrap: wrap; gap: 10px; }
.scroll-crear .gallery-chip { min-height: 120px; min-width: 116px; }
.scroll-crear .gallery-del { width: 26px; height: 26px; font-size: 15px; }
/* Spell out "Spoiler" instead of just "S" (the "S" text node is a shared JS
   literal, so zero it and relabel here -- scoped to Crear, board unaffected). */
.scroll-crear .gallery-spoiler { font-size: 0; display: inline-flex; align-items: center; gap: 4px; }
.scroll-crear .gallery-spoiler input { font-size: 13px; }
.scroll-crear .gallery-spoiler::after { content: 'Spoiler'; font-size: 11px; color: var(--text-dim); }

/* ═══════════════════════════════════════════════════════════════════════════
   Responsive: Desktop (> 900px) - Unified Block
   ═══════════════════════════════════════════════════════════════════════════ */
@media (min-width: 901px) {
  /* Allow body to push content when comments open */
  body.scroll-body {
    transition: padding-right 0.3s cubic-bezier(0.32, 0, 0.67, 0);
  }
  body.scroll-body.scs-open {
    padding-right: 420px;
  }

  .scroll-stack {
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
    transition: max-width 0.3s;
  }
  .scroll-header {
    max-width: 1200px;
    width: 100%;
    left: 50%;
    transform: translateX(-50%);
    right: auto;
    border-radius: 0 0 12px 12px;
    transition: left 0.3s, transform 0.3s;
  }
  body.scroll-body.scs-open .scroll-header {
    left: calc(50% - 210px);
  }

  .scroll-catalog {
    max-width: 1200px;
    width: 100%;
    left: 50%;
    transform: translateX(-50%);
    right: auto;
    border-radius: 0 0 12px 12px;
    transition: left 0.3s, transform 0.3s;
  }
  body.scroll-body.scs-open .scroll-catalog {
    left: calc(50% - 210px);
  }

  /* Redefine comments sheet as a fixed right sidebar */
  .scs-backdrop {
    display: none !important;
  }
  .scroll-comments-sheet {
    right: 0 !important;
    left: auto !important;
    bottom: 0 !important;
    top: 0 !important;
    width: 420px !important;
    height: 100vh !important;
  }
  .scs-panel {
    position: absolute !important;
    top: 0 !important;
    right: 0 !important;
    left: auto !important;
    bottom: 0 !important;
    width: 420px !important;
    max-width: 420px !important;
    height: 100% !important;
    margin: 0 !important;
    border-radius: 0 !important;
    transform: translateX(100%);
    box-shadow: -4px 0 32px rgba(0,0,0,0.35);
  }
  .scroll-comments-sheet.open .scs-panel {
    transform: translateX(0);
  }
  .scs-panel::before {
    display: none !important; /* Hide drag handle */
  }

  /* Bottom sheets on desktop: center them in the viewport explicitly (left:50%
     + translateX) instead of margin:auto, which drifted off-center once the
     scroll column was offset. The three scroll-native sheets get a wider box so
     they don't look cramped ("no se extienden bien"). */
  .scam-panel {
    left: 50%; right: auto;
    width: min(560px, 94vw);
    max-width: none;
    margin: 0;
    transform: translateX(-50%) translateY(calc(100% + var(--sfoot, 56px)));
  }
  .scroll-action-menu.open .scam-panel {
    transform: translateX(-50%) translateY(0);
  }
  .scroll-info-sheet .scam-panel,
  .scroll-settings-sheet .scam-panel,
  .scroll-avisos-sheet .scam-panel {
    width: min(680px, 94vw);
  }

  /* Single media in the side comments panel: block (not floated), but NOT
     full-width -- a full-width, near-fullscreen image dominated the narrow
     reply panel. Cap both dimensions to a modest size (reduced ~30% from
     the previous 280×260 so single-file images/videos don't dominate the
     comment card). */
  .sc-files.sc-files-single {
    float: none !important;
    display: block !important;
    max-width: 196px !important;
    margin: 0 0 12px 0 !important;
  }
  .sc-files.sc-files-single .thumb img,
  .sc-files.sc-files-single .sc-file-img,
  .sc-files.sc-files-single .sc-file-vid,
  .sc-files.sc-files-single .sc-vid-mini,
  .sc-files.sc-files-single .sc-vid-mini video {
    max-width: 196px !important;
    max-height: 182px !important;
    width: auto !important;
    margin: 0 !important;
    display: block !important;
  }
  
  /* Media container should center */
  .sc-files-wrap {
    display: flex;
    justify-content: center;
  }

  /* Footer and overlays */
  .scroll-footer {
    max-width: 1200px;
    width: 100%;
    left: 50%; right: auto;
    transform: translateX(-50%);
    border-radius: 12px 12px 0 0;
    border-left: 1px solid rgba(255,255,255,.08);
    border-right: 1px solid rgba(255,255,255,.08);
    transition: left 0.3s, transform 0.3s;
  }
  body.scroll-body.scs-open .scroll-footer {
    left: calc(50% - 210px);
  }

  .scroll-hilos, .scroll-crear {
    max-width: 1200px;
    width: 100%;
    left: 50%; right: auto;
    transform: translateX(-50%);
    transition: left 0.3s, transform 0.3s;
  }
  .scroll-hilos.open, .scroll-crear.open { 
    transform: translateX(-50%); 
  }
  body.scroll-body.scs-open .scroll-hilos,
  body.scroll-body.scs-open .scroll-crear {
    left: calc(50% - 210px);
  }
  /* Bottom sheets (⋯ menu, Info/Ajustes/Avisos, edit) are centered on the
     feed column, so they must shift with it when the comments panel opens --
     otherwise they stay at viewport center and drift off the visible feed. */
  body.scroll-body.scs-open .scam-panel {
    left: calc(50% - 210px);
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
   Dice Layout in Scroll Mode
   ═══════════════════════════════════════════════════════════════════════════ */
.scroll-dice-page .scroll-extra-body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: stretch;
  padding: 20px;
  gap: 20px;
  height: 100%;
}

.scroll-dice-page .dice-block-mount {
  width: 100%;
  margin: 0;
}

.scroll-dice-page .dice-block {
  display: flex;
  flex-direction: column;
  gap: 12px;
  background: rgba(0,0,0,0.4);
  padding: 20px;
  border-radius: 12px;
}

.scroll-dice-page .dice-results {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.scroll-dice-page .dice-pill {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 2rem;
  padding: 12px 24px;
  border-radius: 12px;
  border: 1px solid var(--border-strong);
}

.scroll-dice-page .dice-pill-lbl {
  font-size: 1.6rem;
  opacity: 0.8;
}

.scroll-dice-page .dice-pill-eq {
  display: none;
}

.scroll-dice-page .dice-pill-val {
  font-size: 2.5rem;
  font-weight: 900;
  color: var(--accent, #d0b86a);
}

.scroll-dice-page .dice-hist-table {
  font-size: 1.2rem;
}
.scroll-dice-page .dice-hist-table th, 
.scroll-dice-page .dice-hist-table td {
  padding: 6px 12px;
}
/* ── SCROLL CARD THEMES (Auto-generated) ── */
.scroll-theme-amber {
  /* ── Fondos principales ── */
  --bg:            #0c0800;
  --bg-panel:      #150f00;
  --bg-post:       #1c1500;
  --bg-op:         #221a00;
  --bg-admin:      #080500;

  /* ── Fondos extendidos ── */
  --bg-reply:          #181200;
  --bg-thread-preview: #120e00;
  --bg-card:           #150f00;
  --bg-input:          #080500;
  --bg-warn:           #1e1800;
  --bg-hover:          #2a2000;

  /* ── Bordes ── */
  --border:        #3a2800;
  --border-strong: #5a3c00;

  /* ── Texto ── */
  --text:          #e8d8b0;
  --text-dim:      #a08a60;

  /* ── Links y acento ── */
  --link:          #ffcc40;
  --link-hover:    #ffe080;
  --accent:        #ffb000;
  --accent-deep:   #a07000;
  --accent-deeper: #c08800;

  /* ── Markup ── */
  --greentext:     #d0a000;
  --pinktext:      #ff8040;
  --redtext:       #ff4020;
  --keeplang-color:#ffcc40;
  --moe-color:     #ff9040;

  /* ── Estados ── */
  --warn:          #ffcc40;
  --danger:        #ff4020;
  --spoiler-bg:    #000000;

  /* ── Editor toolbar ── */
  --bg-toolbar:        #181000;
  --border-toolbar:    #0a0800;
  --bg-toolbar-hover:  #2a2000;
  --bg-toolbar-danger: #280800;
  --toolbar-clear:     #ff6040;
  --toolbar-prefix:    #ffcc40;
  --toolbar-settings:  #ffb000;
}
.scroll-theme-anatase {
  --bg:            #2b2d31;
  --bg-panel:      #232428;
  --bg-post:       #2e3035;
  --bg-op:         #35373d;
  --bg-admin:      #1a1b1e;

  --bg-reply:          #2b2d32;
  --bg-thread-preview: #2a2c31;
  --bg-card:           #2e3035;
  --bg-input:          #1e1f22;
  --bg-warn:           #2a2410;
  --bg-hover:          #35373d;

  --border:        #3c3e44;
  --border-strong: #4e505a;

  --text:          #e8eaed;
  --text-dim:      #8d9099;

  --link:          #c8a858;
  --link-hover:    #e0c478;
  --accent:        #b89848;
  --accent-deep:   #5a4c20;
  --accent-deeper: #7a6830;

  --greentext:     #909048;
  --pinktext:      #b08870;
  --redtext:       #bc4838;
  --keeplang-color:#c8a858;
  --moe-color:     #a87848;

  --warn:          #c8a858;
  --danger:        #bc4838;
  --spoiler-bg:    #111214;

  --bg-toolbar:        #252628;
  --border-toolbar:    #1a1b1e;
  --bg-toolbar-hover:  #36342a;
  --bg-toolbar-danger: #2a1208;
  --toolbar-clear:     #a87860;
  --toolbar-prefix:    #c8a858;
  --toolbar-settings:  #b89848;

  --an-gold-hi:  #e0c478;
  --an-gold-mid: #b89848;
  --an-gold-dim: #5a4c20;
}
.scroll-theme-bloodline {
  /* Fondos — grafito oscuro neutro, NO marrón */
  --bg:            #111114;
  --bg-panel:      #0e0e11;
  --bg-post:       #18181c;
  --bg-op:         #1e1e23;
  --bg-admin:      #0a0a0d;

  --bg-reply:          #161619;
  --bg-thread-preview: #151518;
  --bg-card:           #18181c;
  --bg-input:          #0c0c0f;
  --bg-warn:           #1a1010;
  --bg-hover:          #222228;

  /* Bordes — gris frío, legibles */
  --border:        #2c2c34;
  --border-strong: #3e3e4a;

  /* Texto — blanco roto / gris claro — legible */
  --text:          #dcdce8;
  --text-dim:      #7878a0;

  /* Links — gris azulado frío */
  --link:          #9090c0;
  --link-hover:    #b8b8e0;

  /* Acento — rojo sangre como único color vivo */
  --accent:        #8a1a1a;
  --accent-deep:   #3a0808;
  --accent-deeper: #550f0f;

  /* Paleta interna */
  --bl-red:        #a01c1c;
  --bl-red-hi:     #cc2222;
  --bl-red-dim:    #601010;
  --bl-white:      #dcdce8;
  --bl-grey:       #8888a8;
  --bl-grey-dim:   #4a4a62;

  /* Markup */
  --greentext:     #6a9060;
  --pinktext:      #b06070;
  --redtext:       #cc2020;
  --keeplang-color:#9090c0;
  --moe-color:     #a060a0;

  --warn:          #b84040;
  --danger:        #cc2020;
  --spoiler-bg:    #050507;

  /* Toolbar */
  --bg-toolbar:        #0e0e11;
  --border-toolbar:    #0a0a0d;
  --bg-toolbar-hover:  #222228;
  --bg-toolbar-danger: #180808;
  --toolbar-clear:     #cc2020;
  --toolbar-prefix:    #9090c0;
  --toolbar-settings:  #7878a0;
}
.scroll-theme-dark {
  /* ── Fondos principales ── */
  --bg:            #15181d;
  --bg-panel:      #1e232b;
  --bg-post:       #21262e;
  --bg-op:         #262c35;
  --bg-admin:      #0e1116;

  /* ── Fondos extendidos ── */
  --bg-reply:          #1e2430;
  --bg-thread-preview: #1a1f27;
  --bg-card:           #1e232b;
  --bg-input:          #12151a;
  --bg-warn:           #2a2010;
  --bg-hover:          #2a3040;

  /* ── Bordes ── */
  --border:        #353c47;
  --border-strong: #4a5462;

  /* ── Texto ── */
  --text:          #d7dde5;
  --text-dim:      #8b94a1;

  /* ── Links y acento ── */
  --link:          #6fa8ff;
  --link-hover:    #93c0ff;
  --accent:        #6fa8ff;
  --accent-deep:   #3a5a9a;
  --accent-deeper: #4a6aaa;

  /* ── Markup ── */
  --greentext:     #7bb05a;
  --pinktext:      #d07bd0;
  --redtext:       #ff6680;
  --keeplang-color:#c8a840;
  --moe-color:     #ff7ab8;

  /* ── Estados ── */
  --warn:          #ffb04a;
  --danger:        #ff5577;
  --spoiler-bg:    #0a0a0a;

  /* ── Editor toolbar — en dark se aclara un poco para mayor contraste ── */
  --bg-toolbar:        #1e2638;
  --border-toolbar:    #0f1520;
  --bg-toolbar-hover:  #3a4a62;
  --bg-toolbar-danger: #5a1818;
  --toolbar-clear:     #ff9999;
  --toolbar-prefix:    #88ccff;
  --toolbar-settings:  #ffc844;
}
.scroll-theme-forest {
  /* ── Fondos principales ── */
  --bg:            #0f1a0f;
  --bg-panel:      #162416;
  --bg-post:       #1a2c1a;
  --bg-op:         #1e3420;
  --bg-admin:      #0a130a;

  /* ── Fondos extendidos ── */
  --bg-reply:      #162a18;
  --bg-thread-preview: #122014;
  --bg-card:           #162416;
  --bg-input:          #0a1208;
  --bg-warn:           #1a1800;
  --bg-hover:          #22381e;

  /* ── Bordes ── */
  --border:        #2a402a;
  --border-strong: #3a5c3a;

  /* ── Texto ── */
  --text:          #c8dcc0;
  --text-dim:      #80b070;

  /* ── Links y acento ── */
  --link:          #58c878;
  --link-hover:    #80e090;
  --accent:        #58c878;
  --accent-deep:   #2a7840;
  --accent-deeper: #3a9858;

  /* ── Markup ── */
  --greentext:     #70d060;
  --pinktext:      #d07898;
  --redtext:       #f07060;
  --keeplang-color:#c8b040;
  --moe-color:     #e068a8;

  /* ── Estados ── */
  --warn:          #e0b840;
  --danger:        #f07060;
  --spoiler-bg:    #050a04;

  /* ── Editor toolbar ── */
  --bg-toolbar:    #102010;
  --border-toolbar:#080e08;
  --bg-toolbar-hover:  #1e3420;
  --bg-toolbar-danger: #200e0a;
  --toolbar-clear:     #f09080;
  --toolbar-prefix:    #80e090;
  --toolbar-settings:  #e0b840;
}
.scroll-theme-glaze {
  /* Fondos — papel blanco limpio */
  --bg:            #f2f4f0;
  --bg-panel:      #e8ece6;
  --bg-post:       #ffffff;
  --bg-op:         #f8fffe;
  --bg-admin:      #dde4e0;

  --bg-reply:          #fafafa;
  --bg-thread-preview: #f5f7f4;
  --bg-card:           #ffffff;
  --bg-input:          #ffffff;
  --bg-warn:           #fffbe6;
  --bg-hover:          #e4f7f4;

  /* Bordes — negro/gris oscuro duro */
  --border:        #b0bcb8;
  --border-strong: #5a6e68;

  /* Texto — negro puro */
  --text:          #0e1a18;
  --text-dim:      #4a6660;

  /* Aguamarina saturado */
  --link:          #009980;
  --link-hover:    #00c8a8;
  --accent:        #00a892;
  --accent-deep:   #007a6a;
  --accent-deeper: #005548;

  /* Paleta interna */
  --gz-aqua:       #00c8b4;
  --gz-aqua-deep:  #009980;
  --gz-gold:       #c8900a;
  --gz-gold-hi:    #e8b020;
  --gz-black:      #0e1a18;
  --gz-crack:      rgba(0,200,180,0.55);

  /* Markup */
  --greentext:     #2a8c5a;
  --pinktext:      #c0306a;
  --redtext:       #c01830;
  --keeplang-color:#c8900a;
  --moe-color:     #9030a0;

  --warn:          #c8900a;
  --danger:        #c01830;
  --spoiler-bg:    #0e1a18;

  /* Toolbar */
  --bg-toolbar:        #dde4e0;
  --border-toolbar:    #b0bcb8;
  --bg-toolbar-hover:  #c8e8e4;
  --bg-toolbar-danger: #fad8dc;
  --toolbar-clear:     #c01830;
  --toolbar-prefix:    #00a892;
  --toolbar-settings:  #c8900a;
}
.scroll-theme-hexcraft {
  /* Fondos — violeta oscuro desaturado */
  --bg:            #0d0a18;
  --bg-panel:      #0a0814;
  --bg-post:       #130f22;
  --bg-op:         #181430;
  --bg-admin:      #070510;

  --bg-reply:          #100d1e;
  --bg-thread-preview: #0f0c1c;
  --bg-card:           #130f22;
  --bg-input:          #07050f;
  --bg-warn:           #161008;
  --bg-hover:          #1e1838;

  /* Bordes — violeta frío */
  --border:        #2a2248;
  --border-strong: #3e3068;

  /* Texto */
  --text:          #e0d5f2;
  --text-dim:      #8878b0;

  /* Acento dorado místico */
  --link:          #c8a040;
  --link-hover:    #e8c060;
  --accent:        #7050b8;
  --accent-deep:   #3a2870;
  --accent-deeper: #503890;

  /* Internos hexcraft */
  --hx-gold:       #c8a040;
  --hx-gold-hi:    #e8c860;
  --hx-violet:     #6040a8;
  --hx-violet-hi:  #8060c8;
  --hx-violet-dim: #3a2870;

  /* Markup */
  --greentext:     #6880b0;
  --pinktext:      #c060a8;
  --redtext:       #c04878;
  --keeplang-color:#c8a040;
  --moe-color:     #c070b8;

  --warn:          #c8a040;
  --danger:        #c04878;
  --spoiler-bg:    #040308;

  /* Toolbar */
  --bg-toolbar:    #0f0c20;
  --border-toolbar:#07050f;
  --bg-toolbar-hover: #1e1838;
  --bg-toolbar-danger:#1a0818;
  --toolbar-clear: #c04878;
  --toolbar-prefix:#c8a040;
  --toolbar-settings:#7050b8;
}
.scroll-theme-highcontrast {
  /* ── Fondos principales ── */
  --bg:            #ffffff;
  --bg-panel:      #f0f0f0;
  --bg-post:       #f8f8f8;
  --bg-op:         #e8e8e8;
  --bg-admin:      #ffffff;

  /* ── Fondos extendidos ── */
  --bg-reply:          #f4f4f4;
  --bg-thread-preview: #f8f8f8;
  --bg-card:           #f8f8f8;
  --bg-input:          #ffffff;
  --bg-warn:           #fffce0;
  --bg-hover:          #e0e0e0;

  /* ── Bordes ── */
  --border:        #000000;
  --border-strong: #000000;

  /* ── Texto ── */
  --text:          #000000;
  --text-dim:      #333333;

  /* ── Links y acento ── */
  --link:          #0000cc;
  --link-hover:    #0000ff;
  --accent:        #0000cc;
  --accent-deep:   #000099;
  --accent-deeper: #0000aa;

  /* ── Markup ── */
  --greentext:     #006600;
  --pinktext:      #880088;
  --redtext:       #cc0000;
  --keeplang-color:#886600;
  --moe-color:     #cc0066;

  /* ── Estados ── */
  --warn:          #885500;
  --danger:        #cc0000;
  --spoiler-bg:    #000000;

  /* ── Editor toolbar ── */
  --bg-toolbar:        #e8e8e8;
  --border-toolbar:    #000000;
  --bg-toolbar-hover:  #d0d0d0;
  --bg-toolbar-danger: #ffcccc;
  --toolbar-clear:     #cc0000;
  --toolbar-prefix:    #0000cc;
  --toolbar-settings:  #886600;
}
.scroll-theme-hispa {
  /* ── Fondos principales ── */
  --bg:            #ffffee;
  --bg-panel:      #f0e8d8;
  --bg-post:       #fefefe;
  --bg-op:         #f8f0e0;
  --bg-admin:      #fff8ee;

  /* ── Fondos extendidos ── */
  --bg-reply:          #f4f0e8;
  --bg-thread-preview: #faf8f2;
  --bg-card:           #f8f4ec;
  --bg-input:          #ffffff;
  --bg-warn:           #fff8cc;
  --bg-hover:          #f0e8d4;

  /* ── Bordes ── */
  --border:        #d9c8a8;
  --border-strong: #b89870;

  /* ── Texto ── */
  --text:          #222222;
  --text-dim:      #888070;

  /* ── Links y acento ── */
  --link:          #aa1111;
  --link-hover:    #cc2222;
  --accent:        #aa1111;
  --accent-deep:   #660808;
  --accent-deeper: #881010;

  /* ── Markup ── */
  --greentext:     #789922;
  --pinktext:      #e00070;
  --redtext:       #cc1111;
  --keeplang-color:#886600;
  --moe-color:     #cc0055;

  /* ── Estados ── */
  --warn:          #886600;
  --danger:        #cc1111;
  --spoiler-bg:    #111111;

  /* ── Editor toolbar ── */
  --bg-toolbar:        #ede0cc;
  --border-toolbar:    #c8b090;
  --bg-toolbar-hover:  #e0ceb0;
  --bg-toolbar-danger: #ffdddd;
  --toolbar-clear:     #cc1111;
  --toolbar-prefix:    #aa1111;
  --toolbar-settings:  #886600;
}
.scroll-theme-light {
  /* ── Fondos principales ── */
  --bg:            #dde4ed;
  --bg-panel:      #c8d3e0;
  --bg-post:       #f5f8fb;
  --bg-op:         #eaf0f8;
  --bg-admin:      #232a36;

  /* ── Fondos extendidos ── */
  --bg-reply:          #edf2f8;
  --bg-thread-preview: #f0f4f9;
  --bg-card:           #f5f8fb;
  --bg-input:          #ffffff;
  --bg-warn:           #fff8e8;
  --bg-hover:          #e0e8f4;

  /* ── Bordes ── */
  --border:        #9aaabb;
  --border-strong: #6a7f96;

  /* ── Texto ── */
  --text:          #1a1a1a;
  --text-dim:      #5a6573;

  /* ── Links y acento ── */
  --link:          #2255a0;
  --link-hover:    #1a469e;
  --accent:        #2255a0;
  --accent-deep:   #1a3f7a;
  --accent-deeper: #224e90;

  /* ── Markup ── */
  --greentext:     #5a8c3a;
  --pinktext:      #b85cb8;
  --redtext:       #d8002b;
  --keeplang-color:#a07820;
  --moe-color:     #d05090;

  /* ── Estados ── */
  --warn:          #b85c00;
  --danger:        #c41e3a;
  --spoiler-bg:    #1a1a1a;

  /* ── Editor toolbar ── */
  --bg-toolbar:        #dce5f0;
  --border-toolbar:    #b0bfce;
  --bg-toolbar-hover:  #c4d0e0;
  --bg-toolbar-danger: #f5d0d4;
  --toolbar-clear:     #c41e3a;
  --toolbar-prefix:    #2255a0;
  --toolbar-settings:  #a07820;
}
.scroll-theme-midnight {
  /* ── Fondos principales ── */
  --bg:            #000000;
  --bg-panel:      #080808;
  --bg-post:       #0f0f0f;
  --bg-op:         #161616;
  --bg-admin:      #040404;

  /* ── Fondos extendidos ── */
  --bg-reply:          #0c0c0c;
  --bg-thread-preview: #080808;
  --bg-card:           #090909;
  --bg-input:          #000000;
  --bg-warn:           #150e00;
  --bg-hover:          #181828;

  /* ── Bordes ── */
  --border:        #2a2a2a;
  --border-strong: #3c3c3c;

  /* ── Texto ── */
  --text:          #e8e8e8;
  --text-dim:      #787878;

  /* ── Links y acento ── */
  --link:          #a060ff;
  --link-hover:    #c090ff;
  --accent:        #a060ff;
  --accent-deep:   #6030c0;
  --accent-deeper: #7840d8;

  /* ── Markup ── */
  --greentext:     #60c860;
  --pinktext:      #e060c0;
  --redtext:       #ff5060;
  --keeplang-color:#d0a030;
  --moe-color:     #ff60a0;

  /* ── Estados ── */
  --warn:          #ffb020;
  --danger:        #ff3050;
  --spoiler-bg:    #000000;

  /* ── Editor toolbar ── */
  --bg-toolbar:        #0e0e1e;
  --border-toolbar:    #000000;
  --bg-toolbar-hover:  #1e1e32;
  --bg-toolbar-danger: #280010;
  --toolbar-clear:     #ff8090;
  --toolbar-prefix:    #c090ff;
  --toolbar-settings:  #ffb020;
}
.scroll-theme-ocean {
  /* ── Fondos principales ── */
  --bg:            #0d1b2a;
  --bg-panel:      #112236;
  --bg-post:       #142840;
  --bg-op:         #183050;
  --bg-admin:      #091422;

  /* ── Fondos extendidos ── */
  --bg-reply:          #122440;
  --bg-thread-preview: #0f1e34;
  --bg-card:           #112236;
  --bg-input:          #091420;
  --bg-warn:           #1a1400;
  --bg-hover:          #1e3858;

  /* ── Bordes ── */
  --border:        #1e3a58;
  --border-strong: #2a5080;

  /* ── Texto ── */
  --text:          #c8dff0;
  --text-dim:      #6a94b8;

  /* ── Links y acento ── */
  --link:          #4ab8e8;
  --link-hover:    #72ccf4;
  --accent:        #4ab8e8;
  --accent-deep:   #2070a0;
  --accent-deeper: #2e88be;

  /* ── Markup ── */
  --greentext:     #40b888;
  --pinktext:      #c070d0;
  --redtext:       #f06080;
  --keeplang-color:#d0a840;
  --moe-color:     #e070b0;

  /* ── Estados ── */
  --warn:          #f0b040;
  --danger:        #f06080;
  --spoiler-bg:    #040c14;

  /* ── Editor toolbar ── */
  --bg-toolbar:        #0e2038;
  --border-toolbar:    #071018;
  --bg-toolbar-hover:  #1a3858;
  --bg-toolbar-danger: #280e18;
  --toolbar-clear:     #f09aaa;
  --toolbar-prefix:    #72ccf4;
  --toolbar-settings:  #f0b040;
}
.scroll-theme-rose {
  /* ── Fondos principales ── */
  --bg:            #fff5f7;
  --bg-panel:      #fce8ed;
  --bg-post:       #f9dde4;
  --bg-op:         #f5cfd8;
  --bg-admin:      #fffbfc;

  /* ── Fondos extendidos ── */
  --bg-reply:          #fde8ee;
  --bg-thread-preview: #fef0f4;
  --bg-card:           #f9dde4;
  --bg-input:          #ffffff;
  --bg-warn:           #fff8e8;
  --bg-hover:          #f5d0da;

  /* ── Bordes ── */
  --border:        #e8b8c4;
  --border-strong: #d89aaa;

  /* ── Texto ── */
  --text:          #3a1828;
  --text-dim:      #8a5068;

  /* ── Links y acento ── */
  --link:          #b83060;
  --link-hover:    #d04878;
  --accent:        #c04870;
  --accent-deep:   #8a2048;
  --accent-deeper: #a03060;

  /* ── Markup ── */
  --greentext:     #3a7a50;
  --pinktext:      #a83898;
  --redtext:       #c02040;
  --keeplang-color:#906820;
  --moe-color:     #c040a0;

  /* ── Estados ── */
  --warn:          #c07020;
  --danger:        #c02040;
  --spoiler-bg:    #2a0818;

  /* ── Editor toolbar ── */
  --bg-toolbar:        #fce0e8;
  --border-toolbar:    #e8b0c0;
  --bg-toolbar-hover:  #f8c8d8;
  --bg-toolbar-danger: #ffd8dc;
  --toolbar-clear:     #c02040;
  --toolbar-prefix:    #b83060;
  --toolbar-settings:  #906820;
}
.scroll-theme-sepia {
  /* ── Fondos principales ── */
  --bg:            #f4efe6;
  --bg-panel:      #ede5d8;
  --bg-post:       #e8dece;
  --bg-op:         #ddd3c0;
  --bg-admin:      #f9f4ed;

  /* ── Fondos extendidos ── */
  --bg-reply:          #ede3d3;
  --bg-thread-preview: #f2ece2;
  --bg-card:           #e8dece;
  --bg-input:          #faf6f0;
  --bg-warn:           #f8f0d8;
  --bg-hover:          #d8ccb4;

  /* ── Bordes ── */
  --border:        #c8b99a;
  --border-strong: #a89070;

  /* ── Texto ── */
  --text:          #3d2e1e;
  --text-dim:      #7a6248;

  /* ── Links y acento ── */
  --link:          #7a4e28;
  --link-hover:    #a06030;
  --accent:        #8b5e3c;
  --accent-deep:   #5e3c20;
  --accent-deeper: #724a2a;

  /* ── Markup ── */
  --greentext:     #4a7a3a;
  --pinktext:      #9a5080;
  --redtext:       #c03040;
  --keeplang-color:#8a6820;
  --moe-color:     #b04880;

  /* ── Estados ── */
  --warn:          #c08020;
  --danger:        #c03040;
  --spoiler-bg:    #2a1e10;

  /* ── Editor toolbar ── */
  --bg-toolbar:        #e4d8c4;
  --border-toolbar:    #c0a880;
  --bg-toolbar-hover:  #d4c4a8;
  --bg-toolbar-danger: #f0d0c8;
  --toolbar-clear:     #c03040;
  --toolbar-prefix:    #7a4e28;
  --toolbar-settings:  #8a6820;
}
.scroll-theme-slate {
  /* ── Fondos principales ── */
  --bg:            #1a1f28;
  --bg-panel:      #222830;
  --bg-post:       #262d38;
  --bg-op:         #2c3440;
  --bg-admin:      #141820;

  /* ── Fondos extendidos ── */
  --bg-reply:          #222c3a;
  --bg-thread-preview: #1e2430;
  --bg-card:           #222830;
  --bg-input:          #12161e;
  --bg-warn:           #28200e;
  --bg-hover:          #2e3848;

  /* ── Bordes ── */
  --border:        #38404e;
  --border-strong: #4a5468;

  /* ── Texto ── */
  --text:          #ced4dc;
  --text-dim:      #7c8898;

  /* ── Links y acento ── */
  --link:          #88aadd;
  --link-hover:    #aac8f0;
  --accent:        #88aadd;
  --accent-deep:   #4a6a9a;
  --accent-deeper: #5c7eb0;

  /* ── Markup ── */
  --greentext:     #78b878;
  --pinktext:      #c878c8;
  --redtext:       #f07080;
  --keeplang-color:#c8a840;
  --moe-color:     #e07ab0;

  /* ── Estados ── */
  --warn:          #f0b850;
  --danger:        #f05070;
  --spoiler-bg:    #0a0c10;

  /* ── Editor toolbar ── */
  --bg-toolbar:        #1e2638;
  --border-toolbar:    #10141c;
  --bg-toolbar-hover:  #2e3c50;
  --bg-toolbar-danger: #381420;
  --toolbar-clear:     #f09aaa;
  --toolbar-prefix:    #aac8f0;
  --toolbar-settings:  #f0b850;
}

/* ═══════════════════════════════════════════════════════════════════════════
   Scroll audio chip — bottom-right, below the ⋯ action sidebar
   ═══════════════════════════════════════════════════════════════════════════ */
/* The chip is the LAST item of the .scroll-actions column (a flex column),
   so it sits directly under the ⋯ button: disc on top, name pill below. This
   keeps it clear of the video seek bar (which lives near the footer) and gives
   the reader a real, tappable target instead of a tiny badge in a dead zone. */
.scroll-audio-chip {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  margin-top: 2px;
  pointer-events: auto;
}
/* Disc: cover art or a music-note placeholder, sized like the action buttons.
   Spins slowly while playing. */
.sac-disc {
  position: relative;
  flex-shrink: 0;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 2px solid rgba(255,255,255,.5);
  background: rgba(0,0,0,.3) center/cover no-repeat;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 2px 10px rgba(0,0,0,.3);
}
.sac-disc svg { width: 20px; height: 20px; }
/* Hide ONLY the direct music-note placeholder when a cover is set — NOT the
   nested pause-overlay svg (a descendant selector was hiding the ⏸ too, so a
   covered disc showed just a dark square when paused). */
.sac-disc.has-cover > svg { display: none; }
.scroll-audio-chip.playing .sac-disc {
  animation: sac-spin 7s linear infinite;
  border-color: var(--accent, #88aadd);
}
@keyframes sac-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .scroll-audio-chip.playing .sac-disc { animation: none; }
}
/* Paused overlay: a clear ⏸ filling the disc, so the paused state is obvious
   (before, a tiny sound-off corner badge left users unsure a tap did anything).
   Shown only when the ambient is muted/paused; hidden while playing. */
.sac-pause-overlay {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: rgba(0,0,0,.55);
  display: none;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(1px);
}
.sac-pause-overlay svg { width: 24px; height: 24px; color: #fff; fill: #fff; }
.scroll-audio-chip.muted .sac-pause-overlay,
.scroll-audio-chip.paused .sac-pause-overlay { display: flex; }
.scroll-audio-chip.muted .sac-disc,
.scroll-audio-chip.paused .sac-disc { animation: none; }

/* Name: a translucent pill below the disc, with a marquee that scrolls only
   when the text overflows (JS toggles .sac-scroll). Idle = truncated. Slightly
   wider than the disc so a few chars are legible; centered under it. */
.sac-name {
  min-width: 0;
  max-width: 76px;
  height: 20px;
  padding: 0 8px;
  border: none;
  border-radius: 10px;
  background: rgba(0,0,0,.55);
  color: #fff;
  font-family: var(--sans);
  font-size: 10.5px;
  font-weight: 600;
  cursor: pointer;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 8px rgba(0,0,0,.3);
}
.scroll-audio-empty .sac-name { opacity: .82; font-weight: 500; }
.sac-marquee {
  display: block;
  width: 100%;
  overflow: hidden;
  white-space: nowrap;
}
.sac-marquee-txt {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: bottom;
}
/* When JS measures overflow it adds .sac-scroll → the text animates: a 1s
   pause, then a slow slide, then repeat (per plan §4C). The keyframes live in
   style.css (`mq-slide`) so the boards audio bar shares this exact motion;
   style.css is loaded here too. */
.sac-name.sac-scroll .sac-marquee-txt {
  max-width: none;
  text-overflow: clip;
  animation: mq-slide 9s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .sac-name.sac-scroll .sac-marquee-txt { animation: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Scroll audio drawer — bottom sheet (gallery / vote / upload)
   ═══════════════════════════════════════════════════════════════════════════ */
.scroll-audio-drawer {
  position: fixed;
  inset: 0;
  z-index: 130;
  display: flex;
  align-items: flex-end;
}
/* Same [hidden]-vs-class specificity trap as the other scroll sheets. */
.scroll-audio-drawer[hidden] { display: none; }
.sad-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,.5);
}
.sad-panel {
  position: relative;
  width: 100%;
  max-height: 82vh;
  margin: 0 auto;
  max-width: 620px;
  background: var(--bg);
  border-top-left-radius: 16px;
  border-top-right-radius: 16px;
  border: 1px solid var(--border);
  border-bottom: none;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-shadow: 0 -8px 30px rgba(0,0,0,.4);
  animation: sad-rise .22s ease;
}
@keyframes sad-rise { from { transform: translateY(20px); opacity: .6; } to { transform: translateY(0); opacity: 1; } }
.sad-head {
  display: flex;
  align-items: center;
  padding: 10px 16px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.sad-title { flex: 1; font-family: var(--sans); font-weight: 600; font-size: 16px; color: var(--text); }
.sad-close {
  background: none; border: none; color: var(--text-dim);
  font-size: 26px; line-height: 1; cursor: pointer; padding: 0 4px;
}
.sad-close:hover { color: var(--text); }

/* Current winner banner + playback bar */
.sad-current {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 16px;
  background: var(--bg-post);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.sad-current[hidden] { display: none; }
.sad-cur-top { display: flex; align-items: center; gap: 10px; }
.sad-cur-disc {
  width: 38px; height: 38px; border-radius: 50%;
  background: var(--bg-hover) center/cover no-repeat;
  border: 1px solid var(--border); flex-shrink: 0;
}
.sad-cur-name { font-family: var(--sans); font-weight: 600; font-size: 14px; color: var(--text); }
.sad-cur-sub { font-size: 11px; color: var(--text-dim); font-family: var(--sans); }
.sad-override { color: var(--warn, #f0b850); font-weight: 700; letter-spacing: .04em; }

/* Playback bar */
.sad-playbar { display: flex; align-items: center; gap: 8px; }
.sadpb-btn {
  flex-shrink: 0; border: none; background: none; cursor: pointer;
  color: var(--text); font-size: 14px; line-height: 1; padding: 4px;
}
.sadpb-btn:hover { color: var(--accent); }
.sadpb-play { font-size: 15px; }
.sadpb-ico-pause { display: none; }
.sadpb-play.playing .sadpb-ico-play { display: none; }
.sadpb-play.playing .sadpb-ico-pause { display: inline; }
.sadpb-cur, .sadpb-dur {
  font-family: var(--mono); font-size: 11px; color: var(--text-dim);
  flex-shrink: 0; min-width: 32px; text-align: center;
}
.sadpb-track {
  flex: 1; height: 6px; border-radius: 3px;
  background: var(--bg-hover); cursor: pointer; position: relative; touch-action: none;
}
/* La barra tiene hasta cuatro zonas cuando el post recorta el track:
   rojo apagado (descartado antes del inicio) · acento (reproducido) ·
   fondo (pendiente dentro del fragmento) · rojo vivo (descartado tras el fin).
   Sin recorte solo quedan las dos del medio. */
.sadpb-track { overflow: hidden; }
.sadpb-fill {
  position: absolute; top: 0; bottom: 0; left: 0; width: 0;
  border-radius: 3px; background: var(--accent); z-index: 3;
}
.sadpb-pre, .sadpb-post {
  position: absolute; top: 0; bottom: 0; width: 0;
  z-index: 1; display: none; pointer-events: none;
  background: var(--danger, #bc4838);
}
.sadpb-pre, .sadpb-post { opacity: .5; }
.sadpb-pre { border-radius: 3px 0 0 3px; }
.sadpb-post { border-radius: 0 3px 3px 0; }
.sadpb-track.has-range .sadpb-pre,
.sadpb-track.has-range .sadpb-post { display: block; }

/* Sort chips */
.sad-sorts { display: flex; gap: 6px; padding: 6px 16px 0; flex-shrink: 0; }
.sad-sort {
  padding: 4px 12px; border: 1px solid var(--border); border-radius: 12px;
  background: var(--bg-post); color: var(--text-dim);
  font-family: var(--sans); font-size: 12px; font-weight: 600; cursor: pointer;
}
.sad-sort.active { background: var(--accent); color: #fff; border-color: var(--accent); }

/* Load-more */
.sad-more {
  display: block; width: 100%; margin: 8px 0 4px; padding: 9px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--bg-post); color: var(--text);
  font-family: var(--sans); font-size: 13px; font-weight: 600; cursor: pointer;
}
.sad-more:hover { border-color: var(--accent); color: var(--accent); }

/* Scope tabs */
.sad-tabs {
  display: flex;
  gap: 6px;
  padding: 10px 16px 6px;
  flex-shrink: 0;
}
.sad-tab {
  flex: 1;
  padding: 7px 6px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg-post);
  color: var(--text-dim);
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.sad-tab.active { background: var(--accent); color: #fff; border-color: var(--accent); }

/* Role selector */
.sad-role {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  padding: 4px 16px 8px;
  flex-shrink: 0;
}
.sad-role[hidden] { display: none; }
.sad-role-lbl { font-size: 12px; color: var(--text-dim); font-family: var(--sans); margin-right: 2px; }
.sad-role-btn {
  padding: 4px 10px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--bg-post);
  color: var(--text-dim);
  font-family: var(--mono);
  font-size: 12px;
  cursor: pointer;
}
.sad-role-btn.active { background: var(--accent-deep, var(--accent)); color: #fff; border-color: var(--accent); }

/* Search */
.sad-search { padding: 2px 16px 8px; flex-shrink: 0; }
.sad-search-input {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg-input, var(--bg-post));
  color: var(--text);
  font-family: var(--sans);
  font-size: 14px;
}

/* List */
.sad-list {
  flex: 1;
  overflow-y: auto;
  padding: 4px 10px 8px;
  min-height: 80px;
}
.sad-loading, .sad-empty {
  text-align: center; color: var(--text-dim);
  font-family: var(--sans); font-size: 13px; padding: 24px 12px;
}
.sad-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 8px;
  border-radius: 10px;
}
.sad-item + .sad-item { border-top: 1px solid var(--border); }
.sad-item.winner { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.sad-prev {
  flex-shrink: 0;
  width: 32px; height: 32px; border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--bg-post); color: var(--text);
  cursor: pointer; font-size: 12px;
}
.sad-item.previewing .sad-prev { background: var(--accent); color: #fff; border-color: var(--accent); }
.sad-disc {
  width: 36px; height: 36px; border-radius: 6px;
  background: var(--bg-hover) center/cover no-repeat;
  border: 1px solid var(--border); flex-shrink: 0;
}
.sad-meta { flex: 1; min-width: 0; }
.sad-name {
  font-family: var(--sans); font-size: 14px; font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sad-nsfw {
  font-size: 9px; font-weight: 700; color: var(--danger, #cc2020);
  border: 1px solid currentColor; border-radius: 3px; padding: 0 3px; vertical-align: middle;
}
.sad-sub { font-size: 11px; color: var(--text-dim); font-family: var(--mono); }
.sad-winner-tag { color: var(--accent); font-weight: 700; }
.sad-item-actions { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.sad-edit, .sad-del {
  width: 28px; height: 28px; flex-shrink: 0;
  border: 1px solid var(--border); border-radius: 6px;
  background: var(--bg-post); color: var(--text-dim);
  cursor: pointer; font-size: 13px; line-height: 1;
  display: flex; align-items: center; justify-content: center;
}
.sad-edit:hover { color: var(--text); }
.sad-del:hover { color: var(--danger, #cc2020); border-color: var(--danger, #cc2020); }
.sad-vote {
  flex-shrink: 0;
  padding: 6px 14px;
  border: 1px solid var(--accent);
  border-radius: 8px;
  background: transparent;
  color: var(--accent);
  font-family: var(--sans); font-size: 13px; font-weight: 600;
  cursor: pointer;
}
.sad-vote.mine { background: var(--accent); color: #fff; }
.sad-vote.locked {
  border-color: var(--border);
  color: var(--text-dim);
  cursor: not-allowed;
  opacity: .7;
}
.sad-vote[disabled] { cursor: default; }
/* Anon assignment lock display */
.sad-lock-sub { color: var(--text-dim); font-style: italic; }
.sad-lock-badge { color: var(--warn, #f0b850); font-weight: 600; }
.sad-reset-lock {
  margin-left: auto;
  flex-shrink: 0;
  padding: 4px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: transparent;
  color: var(--text-dim);
  font-family: var(--sans); font-size: 11px; font-weight: 600;
  cursor: pointer;
  align-self: flex-start;
}
.sad-reset-lock:hover { color: var(--accent); border-color: var(--accent); }
.sad-up-title { font-family: var(--sans); font-size: 13px; font-weight: 700; color: var(--accent); }
.sad-up-btns { display: flex; gap: 8px; }
.sad-up-btns .sad-up-submit { flex: 1; }
.sad-up-cancel {
  padding: 9px 16px; border: 1px solid var(--border); border-radius: 8px;
  background: transparent; color: var(--text-dim);
  font-family: var(--sans); font-size: 14px; cursor: pointer;
}

/* Upload */
.sad-upload {
  border-top: 1px solid var(--border);
  padding: 10px 16px calc(10px + env(safe-area-inset-bottom, 0px));
  flex-shrink: 0;
}
.sad-upload-toggle {
  width: 100%;
  padding: 9px;
  border: 1px dashed var(--border-strong, var(--border));
  border-radius: 8px;
  background: transparent;
  color: var(--text-dim);
  font-family: var(--sans); font-size: 13px; font-weight: 600;
  cursor: pointer;
}
.sad-upload-form {
  display: flex; flex-direction: column; gap: 5px; margin-top: 10px;
  background: var(--bg-post);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px;
}
.sad-upload-form[hidden] { display: none; }
.sad-up-lbl {
  font-family: var(--sans); font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em;
  color: var(--text-dim); margin-top: 4px;
}
.sad-up-req { color: var(--accent); }
.sad-up-name {
  padding: 9px 12px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--bg-input, var(--bg)); color: var(--text);
  font-family: var(--sans); font-size: 14px;
}
.sad-up-name:focus, .sad-search-input:focus {
  outline: none; border-color: var(--accent);
}
/* Custom file input: hide the native control, style the label as a button, and
   show the chosen/current filename beside it. */
.sad-up-field { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.sad-up-filebtn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 14px;
  border: 1px solid var(--accent);
  border-radius: 8px;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent);
  font-family: var(--sans); font-size: 13px; font-weight: 600;
  cursor: pointer; flex-shrink: 0;
}
.sad-up-filebtn:hover { background: color-mix(in srgb, var(--accent) 24%, transparent); }
.sad-up-filebtn input[type="file"] {
  position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; pointer-events: none;
}
.sad-up-fileinfo {
  font-family: var(--sans); font-size: 12px; color: var(--text);
  min-width: 0; word-break: break-word; flex: 1;
}
.sad-up-fileinfo.current { color: var(--text-dim); font-style: italic; }
.sad-up-hint { font-family: var(--sans); font-size: 11px; color: var(--text-dim); margin-top: -1px; }
.sad-up-coverprev {
  position: relative;
  width: 48px; height: 48px;
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid var(--border);
  flex-shrink: 0;
}
.sad-up-coverprev[hidden] { display: none; }
.sad-up-coverprev img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sad-up-coverclear {
  position: absolute; top: 1px; right: 1px;
  width: 18px; height: 18px; border-radius: 50%;
  border: none; background: rgba(0,0,0,.7); color: #fff;
  font-size: 13px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.sad-up-submit {
  padding: 10px; border: none; border-radius: 8px;
  background: var(--accent); color: #fff;
  font-family: var(--sans); font-size: 14px; font-weight: 700; cursor: pointer;
}
.sad-up-submit:disabled { opacity: .6; cursor: default; }
.sad-up-msg { font-family: var(--sans); font-size: 12px; color: var(--text-dim); margin-top: 2px; }
.sad-up-msg.err { color: var(--danger, #cc2020); }
  
  /* Dice and Poll scaling specifically for the scroll view */
  .scroll-extra-body .poll-block,
  .scroll-extra-body .dice-block {
    width: 85%;
    max-width: 380px;
    margin: 0 auto;
    transform: scale(1.3);
    transform-origin: center;
  }

  .scroll-extra-body .dice-block {
    background: var(--bg-op, #1c1c1c);
    border: 1px solid var(--border, #333);
    border-radius: 8px;
    padding: 12px 16px 16px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.4);
    max-width: 360px;
  }

  .scroll-extra-body .poll-block {
    box-shadow: 0 8px 24px rgba(0,0,0,0.4);
  }

  @media (min-width: 900px) {
    .scroll-extra-body .poll-block,
    .scroll-extra-body .dice-block {
      transform: scale(1.5);
    }
  }
/* Scroll Mode: Form (Questionnaire) Integration */
.scroll-extra-quiz {
  display: flex;
  align-items: center; /* horizontally center */
  justify-content: flex-start; /* don't vertically center to avoid cutoff */
  padding: 40px 10px; /* add top padding instead */
}
.scroll-extra-quiz .quiz-block-mount {
  width: 100%;
  max-width: 600px;
  display: flex;
  flex-direction: column;
}
.scroll-extra-quiz .post-quiz-panel {
  position: static !important;
  width: 100% !important;
  max-width: none !important;
  height: 100% !important;
  max-height: none !important;
  margin: 0 !important;
  box-shadow: none !important;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: none !important;
  background: transparent !important;
}
.scroll-extra-quiz .post-quiz-panel .qz-head {
  display: none !important;
}
.scroll-extra-quiz .post-quiz-panel .qz-list {
  flex-grow: 1;
  overflow-y: auto;
  overflow-x: hidden;
}
.scroll-extra-quiz .post-quiz-panel .qz-close {
  display: none !important; /* hide the close button since it's a slide */
}

.scroll-gallery-dots:has(.scroll-dot:only-child) { display: none !important; }

.scroll-card.is-extra-slide .scroll-card-overlay { display: none !important; }
.scroll-card.is-extra-slide .scroll-extra-page { padding-bottom: calc(14px + var(--sfoot, 56px)) !important; }

.scroll-extra-quiz .post-quiz-panel .qz-card {
  background: var(--bg-op, #1c1c1c) !important;
  border: 1px solid var(--border, #333) !important;
  padding: 16px !important;
  border-radius: 8px !important;
  box-shadow: 0 8px 24px rgba(0,0,0,0.4) !important;
  margin-bottom: 0 !important;
}
.scroll-extra-quiz .post-quiz-panel .qz-item-title { font-size: 1.15em; color: var(--accent, #4ade80); margin-bottom: 12px; }

.scroll-extra-quiz .post-quiz-panel .qz-cover { min-height: 200px; }

.post-quiz-panel.in-scroll { padding: 0 !important; border: none !important; background: transparent !important; }
