
:root {
  --bg: #12090b;
  --panel: #1a1014;
  --panel-2: #24151c;
  --text: #f4ecd9;
  --muted: #b39a9a;
  --gold: #c45c4a;
  --line: rgba(244, 236, 217, 0.12);
  --safe-t: env(safe-area-inset-top);
  --safe-b: env(safe-area-inset-bottom);
}
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; background: var(--bg); color: var(--text); }
body { font-family: Georgia, "Times New Roman", serif; overflow: hidden; }
button, a, .muted, .kicker, .credit, .tabs, .toggle, .fine, .chips {
  font-family: system-ui, -apple-system, sans-serif;
}
.skip { position: absolute; left: -999px; }
.app { height: 100%; display: flex; flex-direction: column; min-height: 0; }
.top {
  display: flex; justify-content: center;
  padding: calc(10px + var(--safe-t)) 16px 8px; z-index: 5;
}
.toggle {
  display: flex; background: var(--panel); border: 1px solid var(--line);
  border-radius: 999px; padding: 4px;
}
.toggle button {
  border: 0; background: transparent; color: var(--muted);
  padding: 8px 20px; border-radius: 999px; font-weight: 650; cursor: pointer;
}
.toggle button.on { background: #efe6d4; color: #1a1408; }
.feed {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  scroll-snap-type: y mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.feed::-webkit-scrollbar { display: none; }
.slide {
  height: 100%;
  min-height: 100%;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  display: flex;
  flex-direction: column;
  position: relative;
  background: #000;
}
.slide img { width: 100%; height: 42vh; object-fit: cover; object-position: center; background: #111; cursor: pointer; }
.panel {
  flex: 1; min-height: 0;
  background: linear-gradient(#151b30, #12090b);
  padding: 18px; border-top: 1px solid var(--line);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
}
.kicker { font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: #CC6E5F; margin: 0 0 8px; }
h1 { font-size: clamp(24px, 7vw, 32px); line-height: 1.12; margin: 0 0 12px; font-weight: 500; }
.extract { font-size: 17px; line-height: 1.45; color: #e8dfcc; margin: 0 0 14px; }
.credit { font-size: 12px; color: var(--muted); margin: 0 0 14px; line-height: 1.4; }
.actions { display: flex; gap: 8px; flex-wrap: wrap; }
.actions button, .actions a, .ghost, .chips button {
  background: var(--panel-2); color: var(--text); text-decoration: none;
  border: 1px solid var(--line); border-radius: 999px; padding: 10px 14px;
  cursor: pointer; font-size: 14px;
}
.actions .liked { color: #ff6b7a; border-color: #ff6b7a; }
.ghost { margin: 12px 0; }
body.watch .top { position: absolute; left: 0; right: 0; }
body.watch .slide img { height: 100%; width:100%; position: absolute; inset: 0; object-fit: contain; background:#000; }
body.watch .panel,
body.watch .media-hint,
body.watch .yt-note,
body.watch .credit { display: none !important; }
body.watch .extract { display: none; }
body.watch .slide { background:#000; }
body.watch .tabs { background: transparent; border-color: transparent; }
.tabs {
  display: grid; grid-template-columns: repeat(4, 1fr);
  background: #0e1426; border-top: 1px solid var(--line);
  padding-bottom: var(--safe-b);
  position: relative;
  z-index: 60;
  pointer-events: auto;
}
.tabs button { background: none; border: 0; color: var(--muted); padding: 6px 0 8px; cursor: pointer; font-weight: 600; display:flex; flex-direction:column; align-items:center; gap:2px; font-size:11px; }
.tabs button img { width:28px; height:28px; object-fit:contain; border-radius:0; background:transparent; filter:none; display:block; }
.tabs button img.ico-on { display:none; }
.tabs button.on { color: #D27A6E; } /* read44j: active tab label (Sean-approved, Artist pick, ~5.2:1 on navy) */
.tabs button.on img.ico-off { display:none; }
.tabs button.on img.ico-on { display:block; }
.tabs button.on img { filter:none; box-shadow:none; }
.screen { flex: 1; overflow-x: hidden; overflow-y: auto; padding: 22px 18px calc(24px + var(--safe-b)); }
.screen h2 { margin: 8px 0; }
.card { background: var(--panel); border: 1px solid var(--line); border-radius: 16px; padding: 16px; margin: 12px 0; }
.card h3 { margin: 14px 0 4px; font-size: 16px; font-family: system-ui, sans-serif; }
.card h3:first-child { margin-top: 0; }
.muted { color: var(--muted); font-size: 14px; line-height: 1.45; }
.brand-row { display: flex; gap: 12px; align-items: center; margin: 12px 0; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.chips button, .tags button, .tag, .empty, .card { overflow-wrap: anywhere; max-width: 100%; }
.chips button.on { background: #efe6d4; color: #1a1408; }
.empty { color: var(--muted); padding: 20px 0; }
.overlay {
  position: fixed; inset: 0; background: var(--bg); z-index: 200;
  display: flex; flex-direction: column;
  padding: calc(28px + var(--safe-t)) 22px calc(20px + var(--safe-b));
}
.overlay[hidden] { display: none !important; }
.overlay h2 { font-size: 34px; margin: 10px 0 12px; }
.overlay p { color: #d7ceb9; font-size: 18px; line-height: 1.4; }
.overlay-foot { margin-top: auto; }
.primary {
  width: 100%; border: 0; background: #efe6d4; color: #1a1408;
  border-radius: 999px; padding: 16px; font-size: 17px; font-weight: 700; cursor: pointer;
}
.fine { font-size: 12px; color: var(--muted); text-align: center; margin-top: 12px; }
.fine-left { text-align: left; }
.text-btn { background: none; border: 0; color: var(--muted); cursor: pointer; }
.skip-btn { align-self: flex-end; }
.brand { color: var(--gold); font-weight: 700; letter-spacing: .02em; font-family: system-ui, sans-serif; }
.point { display: grid; grid-template-columns: 36px 1fr; gap: 10px; margin: 12px 0; color: #d7ceb9; font-size: 16px; }
.point b { display: block; color: var(--text); }
.burst {
  position: fixed; left: 50%; top: 42%; transform: translate(-50%,-50%) scale(.4);
  font-size: 84px; color: #ff6b7a; pointer-events: none; z-index: 40;
  animation: pop .55s ease-out;
}
.burst[hidden] { display: none; }
@keyframes pop {
  0% { opacity: 0; transform: translate(-50%,-50%) scale(.3); }
  35% { opacity: 1; transform: translate(-50%,-50%) scale(1.15); }
  100% { opacity: 0; transform: translate(-50%,-60%) scale(1.3); }
}
.saved-card { cursor: pointer; }

.img-ph{width:100%;height:42vh;background:linear-gradient(180deg,#24151c,#12090b);}
body.watch .img-ph{height:100%;position:absolute;inset:0;}

.tags { display:flex; flex-wrap:wrap; gap:6px; margin: 0 0 12px; }
.tags button, .tag {
  background: transparent; color: var(--gold); border: 1px solid rgba(224,179,90,.35);
  border-radius: 999px; padding: 5px 10px; font-size: 12px; cursor: pointer;
}
.why { font-size: 12px; color: var(--muted); margin: 0 0 10px; font-family: system-ui, sans-serif; }

.top { position:relative; align-items:center; gap:8px; }
.feed-count{display:none;}
.sound-btn { margin-left:8px; flex:0 0 auto; }
.top{position:relative;}

.search { display:flex; flex-wrap:wrap; gap:8px; margin: 12px 0; }
.search input {
  flex:1 1 9rem; min-width:0; background: var(--panel); border:1px solid var(--line); color:var(--text);
  border-radius: 999px; padding: 12px 14px; font-size: 16px;
}
#searchForm {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  width: 100%;
  max-width: 100%;
  margin-bottom: 0;
}
#searchInput {
  display: block;
  flex: 1 1 auto;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
  -webkit-appearance: none;
  appearance: none;
  font-family: system-ui, -apple-system, sans-serif;
  font-size: 12px;
  letter-spacing: 0;
  padding-left: 10px;
  padding-right: 10px;
}
#searchInput::-webkit-search-decoration,
#searchInput::-webkit-search-cancel-button,
#searchInput::-webkit-search-results-button,
#searchInput::-webkit-search-results-decoration { display: none; }
#searchForm button { margin-top: 0; }
.search button { flex:0 0 auto; background:#efe6d4; color:#1a1408; border:0; border-radius:999px; padding:12px 16px; font-weight:700; }
.rail {
  position:absolute; right:10px; bottom: 22%; display:flex; flex-direction:column; gap:10px; z-index:4;
}
.rail button {
  width:auto; min-width:48px; height:auto; border-radius:16px; border:1px solid var(--line);
  background: rgba(11,16,32,.55); color: var(--text); backdrop-filter: blur(8px);
  font: 10px/1.1 system-ui, sans-serif; cursor:pointer;
  display:flex; flex-direction:column; align-items:center; gap:2px;
  padding:6px 7px 7px;
}
.rail-ico { font-size:16px; line-height:1; }
.rail-name { letter-spacing:.01em; }
.rail button.liked { color: var(--gold); border-color: var(--gold); }
.rail button.kept { color: var(--gold); }
body.watch .actions { display:none; }
.burst { color: var(--gold); font-size: 92px; }
.expand {
  position:fixed; inset:0; background: rgba(6,9,18,.96); z-index:80;
  overflow:auto; padding: calc(52px + var(--safe-t)) 18px calc(24px + var(--safe-b));
}
.expand[hidden] { display:none !important; }
.expand img { width:100%; max-height:36vh; object-fit:contain; background:#000; border-radius:12px; }
.expand .full-extract { white-space:pre-wrap; font-size:16px; line-height:1.5; color:#e8dfcc; }
.expand-close {
  position:fixed; top: calc(10px + var(--safe-t)); right:14px; z-index:120;
  background:#efe6d4; color:#1a1408; border:0; border-radius:999px; padding:8px 14px; font-weight:700;
  pointer-events:auto;
}
.hit { cursor:pointer; }

.rail { opacity:1; visibility:visible; transition: opacity .35s ease, visibility 0s linear 0s; }
/* Faded but still tappable for a moment; "off" (added by app.js 1s after the fade) stops taps. */
.rail.gone { opacity:0; transition: opacity .35s ease; }
.rail.gone.off { visibility:hidden; pointer-events:none; }
/* Sit the buttons on the picture (42vh tall) so they never cover the card's text. */
body:not(.watch) .rail { bottom: calc(100% - 42vh + 10px); }


.ytwrap { position:relative; width:100%; height:42vh; background:#000; }
body.watch .ytwrap { height:100%; position:absolute; inset:0; }
.ytwrap iframe { width:100%; height:100%; border:0; }
.play-tr {
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  background:#c45c4a; color:#fff; border:0; border-radius:999px; padding:12px 18px;
  font-weight:700; z-index:3; cursor:pointer;
}
.yt-note { font-size:12px; color:var(--muted); }

.media { position:relative; width:100%; height:42vh; overflow:hidden; background:#000; touch-action: pan-y; }
body.watch .media { height:100%; position:absolute; inset:0; }
.media-track { display:flex; width:100%; height:100%; transition: transform .25s ease; }
.media-track > .pane { height:100%; min-width:0; }
.media .ytwrap, .media .still, .media img { width:100%; height:100%; object-fit:cover; background:#000; }
.media-hint { position:static; margin:0; padding:8px 14px; background:#12090b; color:#efe6d4; font:13px/1.35 system-ui, sans-serif; pointer-events:none; }

.commons-av audio { position:absolute; left:12px; right:12px; bottom:36px; width:calc(100% - 24px); }
.commons-av video { width:100%; height:100%; object-fit:contain; background:#000; }

.feed-count { max-width:42%; text-align:right; font-size:11px; line-height:1.2; }

body.watch .panel, body.watch .rail { display:none !important; }
body.watch .watch-stage { position:absolute; inset:0; background:#000; }
body.watch .watch-stage iframe,
body.watch .watch-stage video { position:absolute; inset:0; width:100%; height:100%; border:0; background:#000; }
body.watch .yt-poster { position:absolute; inset:0; width:100%; height:100%; object-fit:contain; background:#000; }
body.watch-landscape .tabs { display:none !important; }
body.watch-landscape .app { height:100dvh; }
body.watch-landscape .feed, body.watch-landscape .slide, body.watch-landscape .watch-stage { height:100%; }

.sound-btn { background:transparent; color:var(--muted); border:1px solid var(--line); border-radius:999px; width:36px; height:36px; padding:0; font-size:16px; cursor:pointer; line-height:36px; }
.sound-btn.on { color:#efe6d4; border-color:#c45c4a; }

.to-read { position:absolute; top:12px; left:12px; z-index:8; background:rgba(0,0,0,.55); color:#efe6d4; border:1px solid rgba(255,255,255,.2); border-radius:999px; padding:8px 14px; font-size:14px; cursor:pointer; }
body.watch-landscape .to-read { top:8px; left:8px; }

img { background:#1a1014; }

#threadMsgs { display:flex; flex-direction:column; gap:8px; margin:12px 0; }

#tvChrome, #tvStatic, .watch-bar { display:none !important; pointer-events:none !important; }
/* Clip/Trailer only on the Watch feed. You, Find, Drop, and Kept stay clear. */
/* F: the feed no longer reserves the Clip | Trailer bar's 44px on every card (see F below). */
body.watch.screen-feed:not(.watch-both) #tvChrome { display:none !important; }
body.watch.screen-feed.watch-both #tvChrome {
  display:block !important; position:fixed; left:0; right:0; top:auto;
  bottom: calc(58px + var(--safe-b)); height:44px; z-index:55;
  pointer-events:none; background:#0e1426;
}
body.watch .tv-bezel { display: none; }
body.watch.screen-feed .watch-bar {
  position:relative; left:auto; right:auto; bottom:auto; z-index:2;
  display:flex !important; flex-wrap:nowrap; align-items:center; justify-content:center; gap:8px;
  height:44px; min-height:0; padding:0 8px; background:transparent; color:#efe6d4;
  font:12px/1.3 system-ui, sans-serif; pointer-events:none;
}
body.watch.screen-feed button.source-label {
  pointer-events:auto !important; cursor:pointer;
  position:relative; z-index:3;
  font:12px/1.3 system-ui, sans-serif;
  background:transparent; color:#b39a9a;
}
body.watch .source-label {
  border:1px solid rgba(244,236,217,.28); border-radius:999px; padding:4px 10px; color:#b39a9a;
}
body.watch #tvChrome.on-clip .label-clip,
body.watch #tvChrome.on-trailer .label-trailer {
  background:#efe6d4; color:#1a1408; border-color:#efe6d4; font-weight:700;
}
body.watch .watch-swipe-hint { display:none; flex-basis:100%; text-align:center; }
body.watch #tvChrome.has-both .watch-swipe-hint { display:none; }
body.watch .watch-stage { inset: 0; border-radius: 0; overflow: hidden; z-index: 1; }
body.watch .to-read { top: calc(58px + var(--safe-t)); left: 28px; }
body.watch .top { z-index:80; pointer-events:auto; }
body.watch-landscape.screen-feed #tvChrome { bottom: var(--safe-b); }
body.watch-landscape .watch-stage { inset:0; border-radius:0; }

.tv-static {
  position:fixed; inset:0; z-index:7; display:none;
  background:
    repeating-linear-gradient(180deg, rgba(255,255,255,.18) 0 1px, rgba(0,0,0,.25) 1px 3px),
    repeating-linear-gradient(90deg, rgba(255,255,255,.08) 0 1px, transparent 1px 2px);
  mix-blend-mode: screen;
  opacity:0;
  pointer-events:none;
}
body.watch .tv-static.on, body.watch .tv-static.hold { display:block; }
body.watch .tv-static.on { animation: snow 160ms steps(4) both; }
body.watch .tv-static.hold { opacity:.28; animation: snow-hold .4s steps(3) infinite; }
@keyframes snow {
  0% { opacity:.9; transform: translateY(0); }
  40% { opacity:.55; transform: translateY(-6px); }
  100% { opacity:0; transform: translateY(8px); }
}
@keyframes snow-hold {
  0% { background-position: 0 0, 0 0; }
  100% { background-position: 0 8px, 3px 0; }
}
.watch-stage.fault .tv-fault {
  position:absolute; left:10%; right:10%; top:42%; z-index:4;
  color:#efe6d4; text-align:center; font:15px Georgia, serif;
  text-shadow:0 1px 3px #000;
}
.watch-stage.fault::after {
  content:""; position:absolute; inset:0; z-index:3; pointer-events:none;
  background: repeating-linear-gradient(180deg, rgba(255,255,255,.12) 0 1px, rgba(0,0,0,.2) 1px 3px);
  opacity:.35; mix-blend-mode:screen;
}

#tabSaved { display:none; }

body:not(.watch) .tv-fault,
body:not(.watch) .watch-stage.fault::after { display:none !important; }
.tv-fault { pointer-events:none; }

.watch-track { display:flex; height:100%; width:100%; transition: transform .28s ease; }
.watch-stage[data-panes="2"] .watch-track { width:200%; }
.watch-pane { flex: 0 0 100%; height:100%; position:relative; }
.watch-stage[data-panes="2"] .watch-pane { flex-basis: 50%; }
.watch-pane .lore-clip, .watch-pane iframe, .watch-pane .yt-poster, .watch-pane video { position:absolute; inset:0; width:100%; height:100%; object-fit:contain; background:#000; border:0; }
.yt-fallback { position:absolute; left:0; right:0; bottom:0; z-index:45; padding:14px 16px 16px; background:rgba(18,9,11,.94); color:#efe6d4; text-align:center; font:14px/1.35 system-ui,sans-serif; pointer-events:auto; }
.yt-fallback p { margin:0; }
.yt-fallback a { color:#efe6d4; font-weight:700; display:inline-block; margin-top:8px; }
.watch-stage:not(.on-trailer) .yt-fallback { display:none; }
/* watch-credit-toasts §7-9 (signed Oct 17): fitted plate, 34px, 12px above the tabs (Watch: 6px above the bar, set in JS). */
.ls-note{
  position:fixed; left:50%; right:auto; z-index:260; box-sizing:border-box;
  width:max-content; max-width:calc(100% - 32px); min-height:32px; margin:0;
  display:flex; align-items:center; justify-content:center; gap:8px; padding:7px 14px; border-radius:10px;
  background:rgba(26,16,20,.97); color:#EFE6D4; border:1px solid rgba(244,236,217,.12);
  box-shadow:inset 0 1px 0 #8C313B, 0 6px 18px rgba(0,0,0,.45);
  font:500 13px/18px system-ui,-apple-system,sans-serif; letter-spacing:.005em; text-align:left;
  transform:translate(-50%,0); pointer-events:none;
  bottom:calc(60px + 12px + var(--safe-b));
}
.ls-note[hidden] { display:none !important; }
.ls-note-msg { margin:0; flex:none; }
.ls-note-ico{color:#C9675C; font-size:13px; line-height:18px; flex:none}
.ls-note-ico.muted{color:#B39A9A}
.ls-note.err{box-shadow:inset 0 1px 0 #CC6E5F, 0 6px 18px rgba(0,0,0,.45)}
.ls-note.has-url{width:calc(100% - 32px); flex-wrap:nowrap; padding:4px 4px 4px 14px; gap:10px}
.ls-note-url{pointer-events:auto; flex:1 1 auto; min-width:0; display:block; box-sizing:border-box; height:30px; margin:0; padding:0 10px; border-radius:7px;
  border:1px solid rgba(244,236,217,.12); background:#0f0a0c; color:#EFE6D4; font:13px/28px ui-monospace,monospace; text-overflow:ellipsis; user-select:all; -webkit-user-select:all}
.ls-note.has-undo{padding-right:0; gap:0}
.ls-note.has-undo .ls-note-ico{margin-right:8px}
.ls-note-undo{
  pointer-events:auto; position:relative; flex:none; box-sizing:border-box;
  min-width:44px; height:44px; margin:-6px 0 -6px 10px; padding:0 14px;
  display:flex; align-items:center; justify-content:center;
  background:none; border:0; border-left:1px solid rgba(244,236,217,.16); border-radius:0 10px 10px 0;
  color:#CC6E5F; font:600 13px/18px system-ui,-apple-system,sans-serif; letter-spacing:.02em; cursor:pointer;
  -webkit-tap-highlight-color:transparent;
}
.ls-note-undo:active{opacity:.7}
.ls-note-undo:focus-visible{outline:2px solid #CC6E5F; outline-offset:2px}
@keyframes lsNoteIn{from{opacity:0;transform:translate(-50%,8px)}to{opacity:1;transform:translate(-50%,0)}}
@keyframes lsNoteOut{from{opacity:1;transform:translate(-50%,0)}to{opacity:0;transform:translate(-50%,4px)}}
@keyframes lsNoteFade{from{opacity:0}to{opacity:1}}
.ls-note.in{animation:lsNoteIn 180ms cubic-bezier(.33,1,.68,1) both}
.ls-note.out{animation:lsNoteOut 160ms ease-in both}
@media (prefers-reduced-motion: reduce){
  .ls-note.in{animation:lsNoteFade 120ms linear both}
  .ls-note.out{animation:lsNoteFade 120ms linear reverse both}
}

.swipe-catch { position:absolute; left:0; right:0; top:0; bottom:48px; z-index:5; transform:none; touch-action:pan-y; }
.watch-stage .to-read, .back-clip { z-index:40; }
.back-clip { display:none; position:absolute; top:14px; left:14px; border:0; background:#1a120c; color:#efe6d4; font:12px Georgia,serif; padding:8px 12px; }
.watch-stage.on-trailer .back-clip { display:none !important; }

.why-name {
  display: inline;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  color: inherit;
  font: inherit;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
  vertical-align: baseline;
}
.shelf-quiet { margin-top: 22px; }
.shelf-quiet input { font-size: 14px; padding: 8px 12px; color: var(--muted); }
.shelf-quiet button {
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--line);
  font-weight: 600;
  font-size: 13px;
  padding: 8px 12px;
}
.auth-form { display: flex; flex-direction: column; gap: 10px; margin-top: 16px; }
.auth-form input {
  width: 100%;
  background: var(--panel);
  border: 1px solid var(--line);
  color: var(--text);
  border-radius: 999px;
  padding: 12px 14px;
  font-size: 16px;
}
.auth-choice {
  width: 100%;
  min-height: 48px;
  border-radius: 999px;
  padding: 16px;
  font-size: 17px;
  font-weight: 700;
  cursor: pointer;
  font-family: system-ui, -apple-system, sans-serif;
}
#authContinue { background: #efe6d4; color: #1a1408; border: 0; }
#authSkip.auth-choice { background: transparent; color: var(--text); border: 1px solid var(--line); }
/* Links on the You screen (Legal etc.): cream, not default blue on dark. */
#you a { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }

/* Watch: Keep and Send circles (position set by placeWatchRail in app.js). No labels, no
   plate behind them, no fade. Read keeps its own rail; this one exists only in Watch. */
.watch-rail { display:none; }
body.watch .watch-rail {
  display:flex; flex-direction:column; gap:12px;
  position:absolute; right:40px; bottom:56px; z-index:45; pointer-events:none;
}
body.watch .watch-rail button {
  pointer-events:auto; box-sizing:border-box;
  width:44px; height:44px; min-width:44px; padding:0; margin:0;
  border-radius:50%; border:1px solid #efe6d4;
  background: rgba(11,16,32,.55); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  color:#efe6d4; display:flex; align-items:center; justify-content:center; cursor:pointer;
  opacity:1; transition:none;
}
body.watch .watch-rail .rail-ico { font-size:18px; line-height:1; }
body.watch .watch-rail button.kept { color:#C9675C; }

/* Find results: a plain list directly under the field. Rows ~64px, full width, the whole row
   is the tap target, hairlines between rows. No cards, plates or chips. */
:root { --muted-cream: #a99f8c; } /* 7.5:1 on --bg */
#searchResults.find-list { margin: 8px -18px 0; max-height: min(60vh, 1280px); overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; }
.find-row {
  display: flex; align-items: center; gap: 12px; width: 100%; min-height: 64px; height: 64px;
  margin: 0; padding: 8px 18px; border: 0; background: none; color: var(--text);
  text-align: left; cursor: pointer; font: inherit; -webkit-tap-highlight-color: transparent;
}
.find-row + .find-row { border-top: 1px solid var(--line); }
.find-row:active { background: rgba(244, 236, 217, 0.05); }
.find-thumb { flex: 0 0 48px; width: 48px; height: 48px; object-fit: cover; border-radius: 4px; background: #1a1014; cursor: pointer; }
.find-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 2px; }
.find-title, .find-desc { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.find-title { font-family: Georgia, "Times New Roman", serif; font-size: 17px; line-height: 1.3; color: var(--text); }
.find-desc { font-family: system-ui, -apple-system, sans-serif; font-size: 13px; line-height: 1.35; color: var(--muted-cream); }
.find-clip { flex: 0 0 auto; font: 600 11px/1 system-ui, -apple-system, sans-serif; font-variant: small-caps; text-transform: lowercase; letter-spacing: .06em; color: var(--text); }
#searchResults.find-empty { margin: 10px 0 0; }
.find-none { margin: 0; font-size: 17px; line-height: 1.45; color: #e8dfcc; font-family: Georgia, "Times New Roman", serif; }

/* You: the Kept wall. 2 columns, 16px side margins, 12px gutter, 20px between rows (about
   173px square tiles at 390px), scaling with width. */
.kept-head { margin: 22px 0 12px; font-family: Georgia, "Times New Roman", serif; }
#youSaved.kept-wall { display: grid; align-items: start; grid-template-columns: 1fr 1fr; column-gap: 12px; row-gap: 20px; margin: 0 -2px; }
.kept-tile { position: relative; display: block; width: 100%; min-width: 0; margin: 0; padding: 0; border: 0; background: none; color: var(--text); text-align: left; cursor: pointer; -webkit-tap-highlight-color: transparent; font: inherit; }
.kept-photo { position: relative; display: block; width: 100%; aspect-ratio: 1 / 1; border-radius: 4px; overflow: hidden; background: #24151c; border: 0; box-shadow: none; }
.kept-photo img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: center 33%; border-radius: 0; background: #24151c; cursor: pointer; }
.kept-photo.no-photo::before { content: ""; position: absolute; inset: 6px; border: 1px solid rgba(244, 236, 217, 0.55); border-radius: 1px; pointer-events: none; }
.kept-diamond { position: absolute; left: 50%; top: 50%; width: 12px; height: 12px; background: #b87333; transform: translate(-50%, -50%) rotate(45deg); }
.kept-tile:active .kept-photo { filter: brightness(0.85); }
.kept-title { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; margin-top: 8px; font-family: Georgia, "Times New Roman", serif; font-size: 15px; line-height: 1.25; color: var(--text); overflow-wrap: anywhere; }
.kept-clip { position: absolute; top: 8px; right: 8px; font: 600 11px/1 system-ui, -apple-system, sans-serif; font-variant: small-caps; text-transform: lowercase; letter-spacing: .06em; color: var(--text); text-shadow: 0 1px 3px rgba(0, 0, 0, 0.75); pointer-events: none; }
.kept-none { margin: 0 0 8px; font-size: 17px; line-height: 1.45; color: #e8dfcc; font-family: Georgia, "Times New Roman", serif; }
#youShelfTabs[hidden], #shelfFormYou[hidden] { display: none !important; }

/* Read: the Watch half is inert on a card with neither a clip nor a trailer. */
.toggle button.inert { opacity: .45; cursor: default; }
/* Read: small-caps Clip mark on the lead picture when the card has a silent clip. */
.lead-clip { position: absolute; top: 8px; right: 8px; z-index: 3; font: 600 11px/1 system-ui, -apple-system, sans-serif; font-variant: small-caps; text-transform: lowercase; letter-spacing: .06em; color: var(--text); text-shadow: 0 1px 3px rgba(0, 0, 0, 0.75); pointer-events: none; }
body.watch .lead-clip { display: none; }

/* B. Candlelit paper (Artist concept 01). Static only: one 7 KB tiling grain image (cream,
   6% peak alpha), four foxing spots and a warm plum paper gradient on the card, a warm edge
   vignette over the card and a soft inner shadow on the photo. No blend modes, no filters,
   nothing animated here (the candle flicker lives with the motion rules). Nothing moves. */
.slide .panel {
  background-color: #12090b;
  background-image:
    url("paper.png?v=read31"),
    radial-gradient(circle at 18% 22%, rgba(160, 96, 44, .10) 0 3px, transparent 26px),
    radial-gradient(circle at 82% 64%, rgba(160, 96, 44, .09) 0 2px, transparent 34px),
    radial-gradient(circle at 64% 12%, rgba(160, 96, 44, .08) 0 2px, transparent 20px),
    radial-gradient(circle at 30% 88%, rgba(160, 96, 44, .09) 0 4px, transparent 40px),
    linear-gradient(#150a0d, #12090b);
  background-size: 128px 128px, auto, auto, auto, auto, auto;
}
.slide::after {
  content: ""; position: absolute; inset: 0; z-index: 3; pointer-events: none;
  background: radial-gradient(ellipse 120% 90% at 50% 45%, transparent 58%, rgba(30, 10, 4, .6) 100%);
}
.slide .media::after {
  content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  box-shadow: inset 0 0 38px 14px rgba(18, 9, 11, .9), inset 0 0 0 1px rgba(244, 236, 217, .07);
}
body.watch .slide::after, body.watch .slide .media::after { display: none; }

/* C. Seasonal accent: All Hallows #CC6E5F, folk horror #8FA36A, Christmas horror #8DB6D8.
   app.js sets --accent on each card from its own season tag (falling back to loreSeason()) and
   --season-accent on the page for the active chip. Label, rules, photo frame, active chip only. */
.slide .kicker { color: var(--accent, #CC6E5F); }
.slide .media::after {
  box-shadow: inset 0 0 38px 14px rgba(18, 9, 11, .9), inset 0 0 0 1px rgba(244, 236, 217, .07);
  box-shadow: inset 0 0 38px 14px rgba(18, 9, 11, .9), inset 0 0 0 1px color-mix(in srgb, var(--accent, #CC6E5F) 45%, transparent);
}
#filterChip { color: var(--season-accent, #CC6E5F); border-color: color-mix(in srgb, var(--season-accent, #CC6E5F) 55%, transparent); }
#topicList button.on { background: var(--season-accent, #CC6E5F); border-color: var(--season-accent, #CC6E5F); color: #12090b; }

/* D. Catalog plate: "No. NNNN · Category" in Courier Prime small caps (self-hosted subset,
   SIL OFL 1.1, fonts/CourierPrime-OFL.txt), with a thin accent rule above the title. The rule
   is absolutely positioned and the kicker's line box is pinned to its old 15px, so the title
   and extract do not move. */
@font-face {
  font-family: "Courier Prime";
  src: url("fonts/CourierPrime-Regular.woff2?v=read31") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
.slide .kicker {
  position: relative;
  font-family: "Courier Prime", "Courier New", Courier, ui-monospace, monospace;
  font-size: 13px; line-height: 15px; height: 15px; white-space: nowrap; overflow: visible;
  letter-spacing: .08em; text-transform: none; font-variant: small-caps;
}
.slide .kicker .no { color: #f4ecd9; opacity: .85; }
.slide .kicker::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -5px; height: 1px; pointer-events: none;
  background: linear-gradient(90deg, var(--accent, #CC6E5F) 0 62%, transparent);
}

/* E. Motion. Develop: opacity only (the photo sits on black), 900ms ease-out, started by app.js
   on the image's load event. Keep flare: transform/colour/text-shadow on one glyph. Candle
   flicker: opacity of the edge vignette on the visible card only, about +/-2% brightness at
   the edges, slow incommensurate steps; paused while the tab is hidden. */
@keyframes develop { from { opacity: 0; } to { opacity: 1; } }
@keyframes keepFlare {
  0% { transform: scale(1); color: inherit; text-shadow: none; }
  15% { transform: scale(1.6); color: #FFF3D0; text-shadow: 0 0 4px #FFF0C0, 0 0 12px #FFC46A, 0 0 22px rgba(204, 110, 95, .85); }
  45% { transform: scale(1.15); color: #F0A070; text-shadow: 0 0 8px rgba(204, 110, 95, .6); }
  100% { transform: scale(1); text-shadow: none; }
}
@keyframes candle {
  0% { opacity: 1; } 17% { opacity: .57; } 31% { opacity: .87; } 46% { opacity: .4; }
  60% { opacity: .79; } 74% { opacity: .49; } 88% { opacity: .96; } 100% { opacity: .61; }
}
@media (prefers-reduced-motion: no-preference) {
  .slide .media .still img.develop { animation: develop 900ms cubic-bezier(.33, 1, .68, 1) both; }
  .slide.lit::after { animation: candle 7.4s linear infinite alternate; will-change: opacity; }
  body.tab-hidden .slide.lit::after { animation-play-state: paused; }
  .rail-ico.flare { animation: keepFlare 600ms cubic-bezier(.33, 1, .68, 1) both; }
}
@media (prefers-reduced-motion: reduce) {
  .rail-ico.flare { color: inherit; }
}

/* F. Watch black band. The feed keeps one constant height in Watch, so snapping never jumps.
   Only a card with both a clip and a trailer gives up its bottom 44px to the Clip | Trailer
   bar; on single-source cards the player fills that space. The clip stays 9:16 (contain) and
   the spare space is #100607. Keep/Send are placed by the same frame rule (placeWatchRail). */
body.watch.screen-feed .slide .watch-stage[data-panes="2"] { bottom: 44px; }
body.watch .slide .watch-stage[data-panes="1"],
body.watch .slide .watch-stage[data-panes="1"] .watch-pane,
body.watch .slide .watch-stage[data-panes="1"] video { background: #100607; }

/* G. Trailer controls: embedded with controls=0 and driven by LoreScroll's tap (IFrame API).
   When the API fails the player is reloaded with YouTube's controls; taps then go to YouTube. */
body.watch .watch-stage.yt-native.on-trailer .swipe-catch { pointer-events: none; }

/* K. 31 Nights of Lore badge (Artist's spec): top bar, in the empty slot left of Read | Watch,
   left-aligned to the 16px margin, at least 44px tall and as wide as the slot (app.js sets the
   width). Small caps 11px, 0.08em, copper #C9675C, no plate, pill, border or icon. Pressed: 70%.
   Absolutely positioned, so the switch and the sound control do not move. */
@font-face {
  font-family: "LoreBadge";
  src: url("fonts/ArchivoNarrow-SemiBold-subset.woff2?v=read35") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
}
.night-badge {
  position: absolute; left: 16px; top: calc(var(--safe-t) + 10px); height: 44px; min-height: 44px;
  margin: 0; padding: 0; border: 0; background: none; box-shadow: none; cursor: pointer;
  display: flex; align-items: center; justify-content: flex-start; text-align: left;
  font: 600 11px/1 "LoreBadge", system-ui, -apple-system, sans-serif; letter-spacing: .08em;
  font-variant-caps: all-small-caps; white-space: nowrap; color: #C9675C;
  -webkit-tap-highlight-color: transparent; z-index: 6;
}
.night-badge[hidden] { display: none !important; }
.night-badge:active { opacity: .7; }
#nightList.night-list { margin: 8px -18px 0; max-height: none; }

/* Item 1 (read33): trailer controls never over YouTube's player. The trailer iframe fills only
   its own 16:9 box (app.js placeTrailerFrame sets --yt-*); on a Trailer the catcher is clipped
   around that box, so taps on the player go to YouTube and LoreScroll's controls live in the
   bands above and below it. */
body.watch .watch-pane.yt-pane iframe {
  left: var(--yt-l, 0); top: var(--yt-t, 0); right: auto; bottom: auto;
  width: var(--yt-w, 100%); height: var(--yt-h, 100%);
}
body.watch .watch-stage.on-trailer .swipe-catch { clip-path: var(--catch-clip, none); -webkit-clip-path: var(--catch-clip, none); }

/* Item 2 (read33): portrait letterbox bands around the 9:16 clip or the 16:9 trailer show the
   card's own Wikipedia photo, blurred and dimmed, behind the player. Landscape keeps #100607. */
.band-fill { display: none; }
body.watch .watch-stage.has-band .band-fill {
  display: block; position: absolute; inset: -40px; z-index: 0; pointer-events: none;
  background-color: #100607; background-size: cover; background-position: center;
  filter: blur(24px) brightness(.34) saturate(.8);
}
body.watch .watch-stage.has-band .watch-track { position: relative; z-index: 1; }
body.watch .slide .watch-stage.has-band[data-panes],
body.watch .slide .watch-stage.has-band[data-panes] .watch-pane,
body.watch .slide .watch-stage.has-band[data-panes] video,
body.watch .slide .watch-stage.has-band[data-panes] iframe { background: transparent; }
/* Fix (Beta, r33 loose ends): on a silent clip the band below the 9:16 frame showed the blurred
   photo as an empty grey strip. Silent clips keep the dark Watch background (#100607) around the
   frame; the blurred-photo bands stay for trailers. Taps there still reach the clip's stage. */
body.watch .watch-stage.has-band[data-lore^="silent/"]:not(.on-trailer) .band-fill { display: none; }
body.watch .slide .watch-stage.has-band[data-lore^="silent/"]:not(.on-trailer) { background: #100607; }
@media (orientation: landscape) {
  body.watch .watch-stage.has-band .band-fill { display: none; }
  body.watch .slide .watch-stage.has-band[data-panes] { background: #100607; }
}

/* Item 5 (read33): paused silent clip. A dark scrim over the clip with a play mark and the card's
   title. It never takes taps (the tap still resumes the clip) and never covers the end card. */
.clip-scrim { display: none; }
body.watch .clip-scrim.on {
  display: flex; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  flex-direction: column; align-items: center; justify-content: center; gap: 18px;
  background: rgba(12, 5, 6, .86); padding: 0 48px; text-align: center;
}
body.watch .clip-scrim .scrim-play {
  width: 0; height: 0; margin-left: 8px;
  border-left: 30px solid #f4ecd9; border-top: 18px solid transparent; border-bottom: 18px solid transparent;
  filter: drop-shadow(0 1px 6px rgba(0, 0, 0, .6));
}
body.watch .clip-scrim .scrim-title {
  font: 500 24px/1.2 Georgia, "Times New Roman", serif; color: #f4ecd9;
  text-shadow: 0 1px 8px rgba(0, 0, 0, .8); max-width: 100%; overflow-wrap: anywhere;
}

/* Item 8 (read33): transparent pictures (SVG, PNG with alpha) sit on a cream plate so dark line
   art stays readable: cards, Find thumbnails, Kept tiles, the article view and the night list. */
img.on-plate {
  background: #F4ECD9 !important; object-fit: contain !important; object-position: center !important;
  padding: 6%; box-sizing: border-box;
}
.slide .media .still img.on-plate { padding: 8% 10%; }
img.find-thumb.on-plate, #nightList img.on-plate { padding: 3px; }

/* Item 11 (read33): Watch hint. Read only: a card with media shows the Watch label in full cream
   with a 6px #CC6E5F play triangle; a card without media keeps the inert 45% label. The first card
   pulses the triangle once (1 -> 1.25 -> 1, 600ms), off under reduced motion. Switch position,
   Clip mark and tab bar are unchanged; the triangle takes no width when hidden. */
.toggle { position: relative; }
.toggle button .watch-tri { display: none; }
body:not(.watch) .toggle button#btnWatch.has-media { color: #f4ecd9; }
body:not(.watch) .toggle button#btnWatch.has-media .watch-tri {
  display: inline-block; width: 0; height: 0; margin: 0 6px 1px -12px; vertical-align: middle;
  border-left: 6px solid #CC6E5F; border-top: 3.5px solid transparent; border-bottom: 3.5px solid transparent;
}
body:not(.watch) .toggle button#btnWatch.has-media.pulse .watch-tri { animation: watchTriPulse 600ms ease-in-out 1; }
@keyframes watchTriPulse { 0% { transform: scale(1); } 50% { transform: scale(1.25); } 100% { transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { body .toggle button#btnWatch .watch-tri { animation: none !important; } }
.watch-note {
  position: absolute; left: 0; right: 0; top: calc(100% + 6px); margin: 0; text-align: center;
  font-size: 13px; line-height: 1.3; color: #b39a9a; pointer-events: none; white-space: nowrap;
  text-shadow: 0 1px 3px #000, 0 0 8px rgba(0,0,0,.85);
  opacity: 0; transition: opacity 160ms ease;
}
.watch-note.on { opacity: 1; }

/* Item 11 (read33): Watch attribution block (position set by placeAttrib in app.js). Archivo
   Narrow 10.5px / 13px, muted cream #CDBFB0 (well over 4.5:1 on the plum), over a soft plum
   gradient with no plate. Long titles ellipsize; the licence and the not-affiliated line never do.
   Tapping opens the Wikipedia article in a new tab; underline on press only. */
@font-face {
  font-family: "LoreAttrib";
  src: url("fonts/ArchivoNarrow-Medium-latin.woff2?v=read33") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
.watch-attrib { display: none; }
body.watch .watch-attrib:not([hidden]) {
  display: flex; flex-direction: column; justify-content: flex-end;
  position: absolute; z-index: 46; box-sizing: border-box; min-height: 34px; padding: 4px 0 4px 8px; margin: 0 0 0 -8px;
  font: 500 10.5px/13px "LoreAttrib", "Archivo Narrow", "Arial Narrow", system-ui, sans-serif;
  color: #CDBFB0; text-decoration: none; letter-spacing: .01em;
  background: radial-gradient(120% 140% at 0% 100%, rgba(18, 9, 11, .78) 0%, rgba(18, 9, 11, .5) 55%, rgba(18, 9, 11, 0) 100%);
  border-radius: 6px; -webkit-tap-highlight-color: transparent;
}
body.watch .watch-attrib .wa-l1 { display: flex; min-width: 0; white-space: nowrap; }
body.watch .watch-attrib .wa-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
body.watch .watch-attrib .wa-lic { flex: none; }
body.watch .watch-attrib .wa-l2 { white-space: nowrap; }
/* read40 (bug 2): a landscape clip's credit sits right against the frame's left edge. */
body.watch .watch-attrib.wa-side { text-align: right; }
body.watch .watch-attrib.wa-side .wa-l1 { justify-content: flex-end; }
body.watch .watch-attrib:active .wa-title, body.watch .watch-attrib:active .wa-lic, body.watch .watch-attrib:active .wa-l2 { text-decoration: underline; }

/* Item 7 (read33): 31 Nights mood. Every per-night value comes from runs.js via app.js:
   --night (A: OKLab ramp, gold on night 1 to blood red on the last), --vig (C: edge vignette
   .60 -> .75), --ink (C: darkness under the text, 0 -> .60), --photo-shadow (38 -> 50px). */
@font-face {
  font-family: "LoreOnum";
  src: url("fonts/CrimsonPro-Digits-onum.woff2?v=read33") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
html.night-run .night-badge { color: var(--night, #C9675C); gap: 3px; }
.night-badge .cg { flex: none; width: 10px; height: 14px; margin-top: -2px; }
@media (prefers-reduced-motion: no-preference) {
  .night-badge .cg .flame { transform-box: fill-box; transform-origin: 50% 100%; animation: candleFlick 2s ease-in-out infinite alternate; }
  @keyframes candleFlick { 0% { transform: scaleY(1); opacity: 1; } 40% { transform: scaleY(.92) skewX(-3deg); opacity: .9; } 100% { transform: scaleY(1.04) skewX(2deg); opacity: 1; } }
  body.tab-hidden .night-badge .cg .flame { animation-play-state: paused; }
}
.why.night { color: var(--why-c, var(--night, #C9675C)); }
html.night-run .slide::after {
  background: radial-gradient(ellipse 120% 90% at 50% 45%, transparent 58%, rgba(30, 10, 4, var(--vig, .6)) 100%);
}
html.night-run body:not(.watch) .slide .panel {
  background-image:
    radial-gradient(ellipse 110% 85% at 50% 45%, transparent 35%, rgba(6, 2, 2, var(--ink, 0)) 100%),
    url("paper.png?v=read31"),
    radial-gradient(circle at 18% 22%, rgba(160, 96, 44, .10) 0 3px, transparent 26px),
    radial-gradient(circle at 82% 64%, rgba(160, 96, 44, .09) 0 2px, transparent 34px),
    radial-gradient(circle at 64% 12%, rgba(160, 96, 44, .08) 0 2px, transparent 20px),
    radial-gradient(circle at 30% 88%, rgba(160, 96, 44, .09) 0 4px, transparent 40px),
    linear-gradient(#150a0d, #12090b);
  background-size: auto, 128px 128px, auto, auto, auto, auto, auto;
}
html.night-run .slide .media::after {
  box-shadow: inset 0 0 var(--photo-shadow, 38px) 14px rgba(18, 9, 11, .9), inset 0 0 0 1px color-mix(in srgb, var(--accent, #CC6E5F) 45%, transparent);
}
/* D: the night list ledger. Row geometry unchanged (64px, 48px thumbnail). */
#nightList .night-row .find-desc { font-size: 13px; line-height: 1.35; }
#nightList .night-row .no { font-family: "Courier Prime", ui-monospace, monospace; font-variant: small-caps; letter-spacing: .06em; color: #b39a9a; }
#nightList .night-row .num { font-family: "LoreOnum", Georgia, serif; font-variant-numeric: oldstyle-nums; font-feature-settings: "onum" 1; font-size: 17px; line-height: 0; color: #f4ecd9; margin-left: 2px; }
#nightList .night-row:not(.tonight):not(.sealed) .find-title { color: #f4ecd9; }
#nightList .night-row:not(.tonight):not(.sealed) .find-thumb:not(.on-plate) { filter: sepia(.25) saturate(.85) contrast(1.02); }
#nightList .night-row:not(.tonight):not(.sealed) .find-thumb { box-shadow: 0 0 0 1px rgba(244, 236, 217, .18); }
#nightList .night-row.tonight { background-image: radial-gradient(ellipse 140px 60px at 42px 50%, color-mix(in srgb, var(--row-c) 16%, transparent), transparent 70%); }
#nightList .night-row.tonight .find-thumb { box-shadow: 0 0 0 1px color-mix(in srgb, var(--row-c) 80%, transparent), 0 0 14px 3px color-mix(in srgb, var(--row-c) 45%, transparent); }
#nightList .night-row.tonight .find-desc, #nightList .night-row.tonight .no, #nightList .night-row.tonight .num { color: var(--row-c); }
#nightList .night-row.sealed { cursor: default; }
#nightList .night-row.sealed .find-title { color: #b39a9a; font-style: italic; }
#nightList .night-row .night-seal { flex: 0 0 48px; width: 48px; height: 48px; display: flex; align-items: center; justify-content: center; }
/* Item 3: the sealed card a future /n/<N>/ lands on. */
.slide.sealed-slide { display: flex; align-items: center; justify-content: center; background: radial-gradient(ellipse 90% 70% at 50% 42%, #1f0f15 0%, #12090b 75%); }
.sealed-card {
  display: flex; flex-direction: column; align-items: center; text-align: center; gap: 14px;
  padding: 32px 28px; max-width: 360px; color: #f4ecd9;
}
.sealed-card .seal { filter: drop-shadow(0 6px 18px rgba(0, 0, 0, .55)); }
.sealed-kicker { margin: 6px 0 0; font: 600 13px/1.2 "Albert Sans", system-ui, sans-serif; letter-spacing: .14em; text-transform: uppercase; color: var(--seal-c); }
.sealed-kicker .no { font-family: "Courier Prime", ui-monospace, monospace; font-variant: small-caps; text-transform: none; letter-spacing: .06em; }
.sealed-kicker .num { font-family: "LoreOnum", Georgia, serif; font-variant-numeric: oldstyle-nums; font-size: 17px; letter-spacing: 0; }
.sealed-title { margin: 0; font: 500 30px/1.15 Georgia, "Times New Roman", serif; color: #f4ecd9; }
.sealed-line { margin: 0; font-size: 15px; line-height: 1.45; color: #cdbfb0; }
.sealed-list {
  margin-top: 8px; min-height: 44px; padding: 10px 22px; border-radius: 999px; border: 0;
  background: #efe6d4; color: #1a1408; font-weight: 650; font-size: 15px; cursor: pointer;
}
.sealed-hint { margin: 18px 0 0; font-size: 13px; color: #b39a9a; }
/* A #/a/ link to a title with no article (or that could not load) keeps its place as a notice. */
.link-miss .sealed-wiki { margin-top: 6px; color: #efe6d4; font-weight: 650; font-size: 15px; min-height: 44px; display: inline-flex; align-items: center; }

/* Q1 (signed 6:18pm): soft-launch feedback row in You, directly under the Kept wall. Secondary
   dark pill: plum fill, 1px cream hairline at about 3:1 on the fill, cream 15px centred text,
   48px tall, 24px above and 24px before the New shelf form. No icon or badge. Pressed: 85%. */
.sl-row { margin: 24px 0; }
.sl-row[hidden] { display: none !important; }
.sl-btn {
  display: flex; align-items: center; justify-content: center; width: 100%; height: 48px; margin: 0; padding: 0 16px;
  background: #24151c; color: #f4ecd9; border: 1px solid #6F6360; border-radius: 999px;
  font: 500 15px/1 system-ui, -apple-system, sans-serif; text-align: center; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.sl-btn:active { opacity: .85; }
.sl-row + .shelf-quiet { margin-top: 0; }

/* Q3 (signed 6:29pm): night-card Send sheet. */
.night-sheet { position: fixed; inset: 0; z-index: 60; }
.night-sheet[hidden] { display: none !important; }
.ns-scrim { position: absolute; inset: 0; background: rgba(8, 3, 5, .55); opacity: 0; transition: opacity .18s ease; }
.ns-panel {
  position: absolute; left: 0; right: 0; bottom: 0; background: #24151c; border-top: 1px solid #8d2c2f;
  border-radius: 16px 16px 0 0; padding: 10px 16px calc(14px + var(--safe-b)); display: flex; flex-direction: column; gap: 12px;
  transform: translateY(100%); transition: transform .22s ease; max-width: 40rem; margin: 0 auto;
}
.night-sheet.open .ns-scrim { opacity: 1; }
.night-sheet.open .ns-panel { transform: none; }
.ns-grab { width: 36px; height: 4px; border-radius: 2px; background: rgba(244, 236, 217, .35); margin: 0 auto 6px; }
.ns-pill {
  display: flex; align-items: center; justify-content: center; gap: 10px; height: 48px; width: 100%; border-radius: 999px;
  font: 600 15px/1 system-ui, -apple-system, sans-serif; cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.ns-pill[hidden] { display: none; }
.ns-link { background: #f4ecd9; color: #1a1408; border: 0; }
.ns-story { background: #12090b; color: #f4ecd9; border: 1px solid #6F6360; }
.ns-candle { display: inline-flex; width: 10px; height: 14px; }
.ns-pill:active { opacity: .85; }
.ns-cancel { align-self: center; background: none; border: 0; color: rgba(244, 236, 217, .72); font: 500 15px/1 system-ui, -apple-system, sans-serif; padding: 12px 24px; cursor: pointer; }
@media (prefers-reduced-motion: reduce) { .ns-panel, .ns-scrim { transition: none; } }

/* Q5 (signed 8:51pm): not-in-catalog / no-signal link card, in the 404 style (plum, grain, red
   double frame, cream inner line, season-accent seal). The tab bar stays. */
@font-face { font-family: "LoreGelasio"; src: url("fonts/Gelasio-Medium-latin.woff2?v=read35") format("woff2"); font-weight: 500; font-display: swap; }
@font-face { font-family: "LoreLabel404"; src: url("fonts/ArchivoNarrow-SemiBold-404.woff2?v=read35") format("woff2"); font-weight: 600; font-display: swap; }
.slide.link-miss { display: flex; align-items: center; justify-content: center; padding: 18px; background: radial-gradient(ellipse 90% 70% at 50% 40%, #1c0d12 0%, #100607 70%); }
.lm-card {
  position: relative; width: 100%; max-width: 560px; padding: 40px 30px 32px; overflow: hidden; color: #f4ecd9;
  background-color: #12090b;
  background-image: url("paper.png"),
    radial-gradient(circle at 18% 22%, rgba(160, 96, 44, .10) 0 3px, transparent 26px),
    radial-gradient(circle at 82% 70%, rgba(160, 96, 44, .09) 0 2px, transparent 34px),
    linear-gradient(#150a0d, #12090b);
  background-size: 128px 128px, auto, auto, auto;
}
.lm-card::before { content: ""; position: absolute; inset: 0; border: 4px solid #8d2c2f; pointer-events: none; }
.lm-card::after { content: ""; position: absolute; inset: 0; pointer-events: none; background: radial-gradient(ellipse 120% 90% at 50% 45%, transparent 58%, rgba(30, 10, 4, .6) 100%); }
.lm-inner { position: absolute; inset: 11px; border: 1px solid rgba(235, 228, 214, .5); pointer-events: none; }
.lm-seal { display: block; width: 30px; height: 30px; margin: 0 0 18px; position: relative; z-index: 1; }
.lm-fail .lm-seal { opacity: .5; }
.lm-label { position: relative; z-index: 1; margin: 0 0 14px; font: 600 13px/15px "LoreLabel404", "Archivo Narrow", system-ui, sans-serif; letter-spacing: .16em; text-transform: uppercase; color: #CC6E5F; }
.lm-title {
  position: relative; z-index: 1; margin: 0 0 24px; font: 500 clamp(26px, 7.4vw, 36px)/1.12 "LoreGelasio", Georgia, "Times New Roman", serif; letter-spacing: -.005em;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; text-wrap: balance;
}
.lm-btns { position: relative; z-index: 2; display: flex; flex-direction: column; gap: 16px; }
.lm-pill {
  display: flex; align-items: center; justify-content: center; min-height: 48px; padding: 0 18px; border-radius: 999px; text-decoration: none;
  font: 650 16px/1 system-ui, -apple-system, sans-serif; white-space: nowrap; cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.lm-primary { background: #efe6d4; color: #1a1408; border: 0; }
.lm-ghost { background: #24151c; color: #f4ecd9; border: 1px solid #6F6360; }
.lm-pill:active { opacity: .85; }
.lm-pill:focus-visible { outline: 2px solid #CC6E5F; outline-offset: 3px; }

/* read35 (Q6 item 2): the version label wraps only at the " · " before the season. */
.version-label .vl-nw { white-space: nowrap; }

/* read35 (Q7, signed 9:13pm). A: the season mark in the badge slot outside a run (not tappable). */
@property --vig { syntax: "<number>"; inherits: true; initial-value: 0.6; }
@property --ink { syntax: "<number>"; inherits: true; initial-value: 0; }
.night-badge.season-mark { gap: 3px; cursor: default; pointer-events: none; }
.night-badge.season-mark:active { opacity: 1; }
/* Q8: after a run, the mark opens that run's ledger archive, with the badge's 70% pressed state. */
.night-badge.season-mark.tappable { cursor: pointer; pointer-events: auto; }
.night-badge.season-mark.tappable:active { opacity: .7; }
.night-badge .sg { flex: none; width: 10px; height: 14px; margin-top: -2px; }
.night-badge.glyph-only .nb-text { display: none; }
/* C: afterglow (once, the first Feed open in the week after the run). */
/* read41: the transition is armed (ag-ease) only after the peak levels have been applied, so the
   lift runs its full 2s from the peak instead of first easing up to it and being reversed. */
html.afterglow.ag-ease { transition: --vig 2s cubic-bezier(.2, .6, .2, 1), --ink 2s cubic-bezier(.2, .6, .2, 1); }
.night-badge.ag { position: absolute; }
.night-badge.ag > span { position: absolute; left: 0; top: 0; height: 44px; display: flex; align-items: center; gap: 3px; }
.night-badge.ag .ag-smoke, .night-badge.ag .ag-mark { opacity: 0; }
.night-badge.ag.ag-go .ag-candle { animation: agOut .5s ease forwards; }
.night-badge.ag.ag-go .ag-smoke { animation: agSmoke .8s ease .4s forwards; }
.night-badge.ag.ag-go .ag-mark { animation: agIn .6s ease 1.1s forwards; }
@keyframes agOut { to { opacity: 0; } }
@keyframes agSmoke { 0% { opacity: 0; } 40% { opacity: 1; } 100% { opacity: 0; } }
@keyframes agIn { to { opacity: 1; } }
/* B: the ledger archive. */
#nights .ledger-sub { color: rgba(215, 206, 185, .82); font-family: system-ui, -apple-system, sans-serif; }
#nightList.archive .night-row .no, #nightList.archive .night-row .num { color: var(--ink-c) !important; }
#nightList.archive .night-row.tonight { background-image: none; }
#nightList .night-row .ledger-smoke { display: inline-flex; vertical-align: -2px; margin-right: 5px; }
#nightList .night-row .ledger-smoke .cg { width: 10px; height: 14px; }
.ledger-close { margin: 22px 0 10px; text-align: center; font: italic 400 16px/1.4 Georgia, "Times New Roman", serif; color: #f4ecd9; opacity: .9; }
.ledger-close::before { content: ""; display: block; width: 56px; height: 1px; margin: 0 auto 16px; background: linear-gradient(90deg, transparent, rgba(244, 236, 217, .35), transparent); }
/* D: the reason line on a night card opens the night list. */
.why.night.why-link { cursor: pointer; -webkit-tap-highlight-color: transparent; }
.why.night.why-link .why-u { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; text-decoration-color: color-mix(in srgb, var(--why-c, #C9675C) 45%, transparent); }
.why.night.why-link .why-go { display: inline-block; opacity: .8; }
.why.night.why-link:active { opacity: .7; }

/* Q10 (signed Oct 11 9:13am; /workspace/all-souls/NOTES.md, mockups/). All Souls, Nov 1-2 only
   (html[data-season="souls"]). 2. Candlelight warmth: the edge vignette lighter and warmer with a
   faint amber glow from the bottom edge (body text 12.15:1 worst case on grain); it replaces the
   night-31 darkness on these days. No flicker (optional; not built). 3. Papel picado: a cut-paper
   strip (flowers and diamonds, no skulls) at 42% along the top edge of the text panel, just under
   the photo, inside the panel's top padding. Decorative only. 4. The seasonal reason line in
   marigold. Watch, the tab bar and positions are unchanged. */
html[data-season="souls"] body:not(.watch) .slide::after {
  background:
    radial-gradient(ellipse 120% 90% at 50% 45%, transparent 60%, rgba(52, 22, 6, .44) 100%),
    radial-gradient(ellipse 95% 24% at 50% 100%, rgba(232, 150, 58, .10) 0%, rgba(232, 150, 58, .035) 55%, transparent 80%);
}
html[data-season="souls"] body:not(.watch) .slide .media::after {
  box-shadow: inset 0 0 34px 12px rgba(30, 14, 8, .78), inset 0 0 0 1px color-mix(in srgb, var(--accent, #CC6E5F) 45%, transparent);
}
html[data-season="souls"] body:not(.watch) .slide .panel { position: relative; }
html[data-season="souls"] body:not(.watch) .slide .panel::before {
  content: ""; position: absolute; left: 0; right: 0; top: 1px; height: 15px; z-index: 4; pointer-events: none;
  background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='56' height='15' viewBox='0 0 56 15'%3E%3Cpath d='M0 1.2 Q14 2.6 28 1.2 T56 1.2' stroke='%23F4ECD9' stroke-width='.6' fill='none' opacity='.7'/%3E%3Cpath fill-rule='evenodd' fill='%23E8A23A' d='M3 1.8 H25 V10.8 Q22.25 14.4 19.50 10.8 Q16.75 14.4 14.00 10.8 Q11.25 14.4 8.50 10.8 Q5.75 14.4 3.00 10.8 Z M13.05 4.45 a0.95 0.95 0 1 0 1.9 0 a0.95 0.95 0 1 0 -1.9 0 M14.71 5.66 a0.95 0.95 0 1 0 1.9 0 a0.95 0.95 0 1 0 -1.9 0 M14.08 7.62 a0.95 0.95 0 1 0 1.9 0 a0.95 0.95 0 1 0 -1.9 0 M12.02 7.62 a0.95 0.95 0 1 0 1.9 0 a0.95 0.95 0 1 0 -1.9 0 M11.39 5.66 a0.95 0.95 0 1 0 1.9 0 a0.95 0.95 0 1 0 -1.9 0 M13.45 6.20 a0.55 0.55 0 1 0 1.1 0 a0.55 0.55 0 1 0 -1.1 0 M7.40 4.800000000000001 l1.2 1.4 l-1.2 1.4 l-1.2 -1.4 z M20.60 4.800000000000001 l1.2 1.4 l-1.2 1.4 l-1.2 -1.4 z M6.08 9.60 a0.42 0.42 0 1 0 0.84 0 a0.42 0.42 0 1 0 -0.84 0 M9.83 9.60 a0.42 0.42 0 1 0 0.84 0 a0.42 0.42 0 1 0 -0.84 0 M17.33 9.60 a0.42 0.42 0 1 0 0.84 0 a0.42 0.42 0 1 0 -0.84 0 M21.08 9.60 a0.42 0.42 0 1 0 0.84 0 a0.42 0.42 0 1 0 -0.84 0'/%3E%3Cpath fill-rule='evenodd' fill='%23F4ECD9' d='M31 1.8 H53 V10.8 Q50.25 14.4 47.50 10.8 Q44.75 14.4 42.00 10.8 Q39.25 14.4 36.50 10.8 Q33.75 14.4 31.00 10.8 Z M41.05 4.45 a0.95 0.95 0 1 0 1.9 0 a0.95 0.95 0 1 0 -1.9 0 M42.71 5.66 a0.95 0.95 0 1 0 1.9 0 a0.95 0.95 0 1 0 -1.9 0 M42.08 7.62 a0.95 0.95 0 1 0 1.9 0 a0.95 0.95 0 1 0 -1.9 0 M40.02 7.62 a0.95 0.95 0 1 0 1.9 0 a0.95 0.95 0 1 0 -1.9 0 M39.39 5.66 a0.95 0.95 0 1 0 1.9 0 a0.95 0.95 0 1 0 -1.9 0 M41.45 6.20 a0.55 0.55 0 1 0 1.1 0 a0.55 0.55 0 1 0 -1.1 0 M35.40 4.800000000000001 l1.2 1.4 l-1.2 1.4 l-1.2 -1.4 z M48.60 4.800000000000001 l1.2 1.4 l-1.2 1.4 l-1.2 -1.4 z M34.08 9.60 a0.42 0.42 0 1 0 0.84 0 a0.42 0.42 0 1 0 -0.84 0 M37.83 9.60 a0.42 0.42 0 1 0 0.84 0 a0.42 0.42 0 1 0 -0.84 0 M45.33 9.60 a0.42 0.42 0 1 0 0.84 0 a0.42 0.42 0 1 0 -0.84 0 M49.08 9.60 a0.42 0.42 0 1 0 0.84 0 a0.42 0.42 0 1 0 -0.84 0'/%3E%3C/svg%3E"); background-repeat: repeat-x; background-size: 56px 15px; background-position: center 0; opacity: .42;
}
.why.souls { color: #E8A23A; margin: 2px 0 10px; }
.why.souls .dot { opacity: .7; padding: 0 .1em; }
/* S3 (Q11): end of a hashtag's Find results, muted cream body style. */
#searchResults .find-end { margin: 14px 18px 18px; font-size: 15px; line-height: 1.45; color: #CDBFB0; font-family: Georgia, "Times New Roman", serif; }
/* S5 (Q11): ledger rows with no free photo (or faces: true) get the no-photo tile, as on the Kept wall. */
#nightList .night-nophoto { position: relative; display: block; flex: 0 0 48px; width: 48px; height: 48px; border-radius: 4px; background: #24151c; box-shadow: 0 0 0 1px rgba(244, 236, 217, .18); }
#nightList .night-nophoto::before { content: ""; position: absolute; inset: 5px; border: 1px solid rgba(244, 236, 217, 0.55); border-radius: 1px; }
#nightList .night-nophoto .kept-diamond { width: 9px; height: 9px; }
/* S4 (Q11): the Read link for a music video that does not play here. */
.yt-note.music-link a { color: inherit; text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; }

/* Q12 winter look (signed Oct 11 1:06pm; /workspace/winter-run/NOTES.md). Only runs with a
   vignetteTint (html.run-tint, winter #05080F since read40 V1) or the frost glyph get these; October is unchanged. */
html.night-run.run-tint .slide::after {
  background: radial-gradient(ellipse 120% 90% at 50% 45%, transparent 58%, rgba(var(--vig-rgb, 5, 8, 15), var(--vig, .6)) 100%);
}
html.night-run.run-tint body:not(.watch) .slide .panel {
  background-image:
    radial-gradient(ellipse 110% 85% at 50% 45%, transparent 35%, rgba(2, 4, 10, var(--ink, 0)) 100%),
    url("paper.png?v=read31"),
    radial-gradient(circle at 18% 22%, rgba(120, 140, 168, .09) 0 3px, transparent 26px),
    radial-gradient(circle at 82% 64%, rgba(120, 140, 168, .08) 0 2px, transparent 34px),
    radial-gradient(circle at 64% 12%, rgba(120, 140, 168, .07) 0 2px, transparent 20px),
    radial-gradient(circle at 30% 88%, rgba(120, 140, 168, .08) 0 4px, transparent 40px),
    linear-gradient(#150a0d, #12090b);
  background-size: auto, 128px 128px, auto, auto, auto, auto, auto;
}
/* Ledger: past nights in frozen ink with rime on the numeral (three speckle layers clipped to the
   old-style digits); tonight glows in frost a little stronger (20%). */
#nightList .night-row.frozen .no { color: var(--ink-c); }
#nightList .night-row.frozen .num {
  color: var(--ink-c);
  background-image:
    radial-gradient(circle, rgba(238, 244, 250, .75) 0 .6px, transparent .9px),
    radial-gradient(circle, rgba(238, 244, 250, .6) 0 .5px, transparent .8px),
    radial-gradient(circle, rgba(238, 244, 250, .55) 0 .5px, transparent .8px),
    linear-gradient(var(--ink-c), var(--ink-c));
  background-size: 3px 3px, 4px 4px, 5px 5px, auto;
  background-position: 0 0, 1px 2px, 2px 1px, 0 0;
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
  line-height: 1;
}
#nightList.frost .night-row.tonight { background-image: radial-gradient(ellipse 140px 60px at 42px 50%, color-mix(in srgb, var(--row-c) 20%, transparent), transparent 70%); }
/* Sealed card (a): plum in a red double frame with a cream inner line, cool vignette, frost seal. */
.slide.sealed-slide.sealed-frost { background: radial-gradient(ellipse 90% 70% at 50% 42%, #1f0f15 0%, #12090b 75%); }
/* The frame wraps the card itself (board mockup sealed-n12-dec15-proposed.png); the scroll hint sits below it. */
.frost-card {
  border: 4px solid #8d2c2f; width: min(380px, calc(100% - 40px)); max-width: none; box-sizing: border-box; padding: 30px 22px;
  background: radial-gradient(ellipse 100% 80% at 50% 40%, #241118 0%, #170b10 100%);
}
.frost-card::before { content: ""; position: absolute; inset: 8px; border: 1px solid rgba(235, 228, 214, .5); pointer-events: none; }
.frost-card .sealed-hint { position: absolute; left: 0; right: 0; top: calc(100% + 40px); margin: 0; }
.slide.sealed-slide.sealed-frost::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(ellipse 120% 90% at 50% 45%, transparent 58%, rgba(var(--vig-rgb, 5, 8, 15), .6) 100%);
}
.frost-card { position: relative; z-index: 1; gap: 12px; }
.frost-kicker { font: 600 15px/1.2 "Archivo Narrow", "Albert Sans", system-ui, sans-serif; letter-spacing: .14em; }
/* read40 (Artist winter look check, item 3): the kicker's glyph is the night's frost crystal (SVG),
   not U+2744, which some phones draw as a colour emoji. */
.frost-kicker { display: flex; align-items: center; justify-content: center; gap: 6px; }
.frost-kicker .fk-glyph { display: inline-flex; }
.frost-kicker .fk-glyph svg { width: 15px; height: 21px; margin-top: -3px; }
/* read40 (item 4): paper inside the frame with a cool inner vignette, as signed. */
.frost-card {
  background: url("paper.png?v=read31") 0 0 / 128px 128px, radial-gradient(ellipse 100% 80% at 50% 40%, #241118 0%, #170b10 100%);
}
.frost-card::after { content: ""; position: absolute; inset: 9px; pointer-events: none; background: radial-gradient(ellipse 120% 90% at 50% 45%, transparent 55%, rgba(10, 16, 28, .6) 100%); }
.frost-card > :not(.sealed-hint) { position: relative; z-index: 1; }
.frost-card .sealed-title { font-size: 28px; white-space: nowrap; }
.frost-card .sealed-run { margin: 0; font: 600 12px/1.2 "Albert Sans", system-ui, sans-serif; letter-spacing: .2em; color: #d7ceb9; }

/* E4 (read39): a Feed card whose fit is not known yet stays hidden until it is judged. */
.slide.fit-pending { display: none !important; }
/* Landscape phones: the framed winter sealed card fits between the top bar and the tab bar. */
@media (orientation: landscape) and (max-height: 520px) {
  .slide.sealed-slide.sealed-frost { box-sizing: border-box; padding: 64px 0 62px; }
  .frost-card { width: min(420px, calc(100% - 40px)); padding: 12px 20px; gap: 6px; }
  .frost-card::before { inset: 5px; }
  .frost-card .seal { width: 60px; height: 60px; }
  .frost-card .frost-kicker { margin: 0; font-size: 13px; }
  .frost-card .sealed-title { font-size: 22px; margin: 0; }
  .frost-card .sealed-line, .frost-card .sealed-hint { display: none; }
  .frost-card .sealed-list { margin: 2px 0 0; padding-top: 8px; padding-bottom: 8px; }
}

/* read42 (item C): the lead picture and its credit stay hidden until the author has resolved. */
.slide.credit-wait .media .pane:first-child .still img { visibility: hidden; }
.slide.credit-wait .img-credit, .slide.credit-missing .img-credit { visibility: hidden; }

/* ===== read44d: cold-deck look, items 1-2 (SIGNED Artist + App Genius, Oct 17 2026).
   Film and specimen plates in the Read photo box (cold-deck-look/after/proposal-plate.css, as signed).
   Only .ls-plate and .still.has-plate are matched, so nothing outside the photo box changes. ===== */
@font-face { font-family: "LoreGelasioItalic"; src: url("fonts/Gelasio-Italic-latin.woff2?v=read44d") format("woff2"); font-weight: 400; font-style: italic; font-display: swap; }
.slide .media .still.has-plate > img { visibility: hidden; }
.ls-plate {
  position: absolute; inset: 0; overflow: hidden; pointer-events: none;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; color: #F4ECD9; padding: 0 28px;
}
.slide .media .still.has-plate { position: relative; }
.ls-plate p { margin: 0; }

/* --- Specimen plate (any no-photo, non-film card) --- */
.ls-specimen {
  background-color: #100607;
  background-image:
    url("paper.png?v=read31"),
    radial-gradient(ellipse 70% 60% at 50% 38%, rgba(201, 103, 92, .13) 0%, rgba(201, 103, 92, .04) 45%, transparent 75%),
    radial-gradient(circle at 22% 78%, rgba(160, 96, 44, .10) 0 3px, transparent 30px),
    radial-gradient(circle at 81% 24%, rgba(160, 96, 44, .08) 0 2px, transparent 24px),
    linear-gradient(#160a0c, #100607);
  background-size: 128px 128px, auto, auto, auto, auto;
}
/* fine double frame rule */
.ls-specimen::before {
  content: ""; position: absolute; inset: 14px;
  border: 1px solid rgba(201, 103, 92, .55);
  box-shadow: inset 0 0 0 4px #100607, inset 0 0 0 5px rgba(244, 236, 217, .10);
}
/* corner brackets (engraved plate corners, not diamonds) */
.ls-specimen .lp-corner { position: absolute; width: 14px; height: 14px; border-color: #C9675C; border-style: solid; border-width: 0; }
.ls-specimen .lp-corner.tl { top: 22px; left: 22px; border-top-width: 1px; border-left-width: 1px; }
.ls-specimen .lp-corner.tr { top: 22px; right: 22px; border-top-width: 1px; border-right-width: 1px; }
.ls-specimen .lp-corner.bl { bottom: 22px; left: 22px; border-bottom-width: 1px; border-left-width: 1px; }
.ls-specimen .lp-corner.br { bottom: 22px; right: 22px; border-bottom-width: 1px; border-right-width: 1px; }
/* large dim initial, decorative */
.ls-specimen .lp-ghost {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -54%);
  font: 500 300px/1 "LoreGelasio", Georgia, serif; color: rgba(201, 103, 92, .075);
  letter-spacing: 0; user-select: none;
}
.ls-specimen .lp-label {
  position: absolute; top: 34px; left: 0; right: 0;
  font: 400 12px/1 "Courier Prime", "Courier New", monospace; font-variant: small-caps;
  letter-spacing: .22em; color: #D27A6E;
}
.ls-specimen .lp-title {
  position: relative; text-wrap: balance; font: 500 56px/1.02 "LoreGelasio", Georgia, serif; letter-spacing: .01em;
  color: #F4ECD9; text-shadow: 0 0 18px rgba(201, 103, 92, .28), 0 1px 0 rgba(0, 0, 0, .6);
}
.ls-plate[data-len="m"] .lp-title { font-size: 44px; }
.ls-plate[data-len="l"] .lp-title { font-size: 34px; line-height: 1.08; }
.ls-specimen .lp-rule {
  position: relative; display: block; width: 132px; height: 9px; margin: 14px 0 12px;
  background:
    linear-gradient(#C9675C, #C9675C) left 50% / 56px 1px no-repeat,
    linear-gradient(#C9675C, #C9675C) right 50% / 56px 1px no-repeat,
    radial-gradient(circle, #C9675C 0 2px, transparent 2.5px) center / 9px 9px no-repeat;
}
.ls-specimen .lp-desc {
  position: relative; max-width: 270px; text-wrap: balance;
  font: italic 400 16px/1.35 "LoreGelasioItalic", Georgia, serif; color: #D9CDB6;
}
.ls-specimen .lp-foot {
  position: absolute; bottom: 33px; left: 0; right: 0;
  font: 400 11px/1 "Courier Prime", "Courier New", monospace; font-variant: small-caps;
  letter-spacing: .22em; color: #A8968C;
}

/* --- Film plate: poster-less cinema title card --- */
.ls-film {
  background-color: #0D0607;
  background-image:
    url("paper.png?v=read31"),
    radial-gradient(ellipse 62% 55% at 50% 50%, rgba(244, 236, 217, .085) 0%, rgba(201, 103, 92, .045) 40%, transparent 72%),
    linear-gradient(#120809, #0D0607);
  background-size: 128px 128px, auto, auto;
}
.ls-film .lp-bar { position: absolute; left: 0; right: 0; height: 17%; background: #000; display: flex; align-items: center; padding: 0 22px; }
.ls-film .lp-bar.top { top: 0; border-bottom: 1px solid rgba(201, 103, 92, .55); justify-content: space-between; }
.ls-film .lp-bar.bot { bottom: 0; border-top: 1px solid rgba(201, 103, 92, .55); justify-content: space-between; }
.ls-film .lp-bar span {
  font: 400 12px/1 "Courier Prime", "Courier New", monospace; font-variant: small-caps; letter-spacing: .2em; color: #D27A6E;
}
.ls-film .lp-bar span.dim { color: #A8968C; }
/* projector gate: rounded film frame inside the bars */
.ls-film::before {
  content: ""; position: absolute; left: 16px; right: 16px; top: calc(17% + 12px); bottom: calc(17% + 12px);
  border: 1px solid rgba(244, 236, 217, .13); border-radius: 12px / 16px;
}
.ls-film .lp-pre {
  position: relative; font: 600 11px/1 "LoreAttrib", "Archivo Narrow", system-ui, sans-serif; text-transform: uppercase;
  letter-spacing: .32em; color: #D9CDB6; margin-bottom: 12px; padding-left: .32em;
}
.ls-film .lp-title {
  position: relative; text-wrap: balance; max-width: 100%; font: 500 42px/1.02 "LoreGelasio", Georgia, serif; text-transform: uppercase;
  letter-spacing: .14em; padding-left: .14em; color: #F4ECD9;
  text-shadow: 0 0 22px rgba(244, 236, 217, .18), 0 1px 0 #000;
}
.ls-film[data-len="m"] .lp-title { font-size: 34px; letter-spacing: .11em; }
.ls-film[data-len="l"] .lp-title { font-size: 26px; letter-spacing: .08em; line-height: 1.12; }
.ls-film .lp-year {
  position: relative; display: flex; align-items: center; gap: 12px; margin-top: 12px;
  font: 500 20px/1 "LoreOnum", "Crimson Pro", Georgia, serif; letter-spacing: .12em; color: #D27A6E;
}
.ls-film .lp-year::before, .ls-film .lp-year::after { content: ""; width: 28px; height: 1px; background: rgba(201, 103, 92, .7); }
/* lift the small engraved labels above the card's edge vignette (.media::after z2) so they keep full contrast */
.ls-plate .lp-label, .ls-plate .lp-foot, .ls-film .lp-bar span { z-index: 3; }
.ls-film .lp-bar span { position: relative; }
/* read44d: the markup wraps the centred lines (aria-hidden) and makes the trailer bar a real button,
   at least 44px tall (item 2), the only part of a plate that takes taps. */
.ls-plate .lp-body { position: relative; display: flex; flex-direction: column; align-items: center; max-width: 100%; }
.ls-film button.lp-bar.bot {
  pointer-events: auto; cursor: pointer; min-height: 44px; margin: 0; width: 100%; box-sizing: border-box;
  border: 0; border-top: 1px solid rgba(201, 103, 92, .55); border-radius: 0; background: #000; color: inherit;
  font: inherit; text-align: left; -webkit-tap-highlight-color: transparent; z-index: 3;
}
.ls-film button.lp-bar.bot:focus-visible { outline: 2px solid #D27A6E; outline-offset: -3px; }
/* read44d: phones in landscape (843x390 tested) give the photo box only ~164px, so both plates
   tighten there to keep every line clear of the 44px trailer bar and of each other. */
@media (orientation: landscape) and (max-height: 500px) {
  .ls-specimen::before { inset: 8px; }
  .ls-specimen .lp-corner.tl, .ls-specimen .lp-corner.tr { top: 14px; }
  .ls-specimen .lp-corner.bl, .ls-specimen .lp-corner.br { bottom: 14px; }
  .ls-specimen .lp-corner.tl, .ls-specimen .lp-corner.bl { left: 14px; }
  .ls-specimen .lp-corner.tr, .ls-specimen .lp-corner.br { right: 14px; }
  .ls-specimen .lp-ghost { font-size: 150px; }
  .ls-specimen .lp-label { top: 18px; font-size: 11px; }
  .ls-specimen .lp-foot { bottom: 16px; font-size: 10px; }
  .ls-specimen .lp-title, .ls-plate.ls-specimen[data-len="m"] .lp-title, .ls-plate.ls-specimen[data-len="l"] .lp-title { font-size: 30px; line-height: 1.05; }
  .ls-specimen .lp-rule { margin: 6px 0 5px; }
  .ls-specimen .lp-desc { max-width: 560px; font-size: 13px; line-height: 1.25; }
  .ls-film::before { top: calc(17% + 6px); bottom: 50px; }
  .ls-film .lp-body { margin-bottom: 16px; }
  .ls-film .lp-pre { margin-bottom: 5px; font-size: 10px; }
  .ls-film .lp-title, .ls-film[data-len="m"] .lp-title, .ls-film[data-len="l"] .lp-title { font-size: 26px; }
  .ls-film .lp-year { margin-top: 4px; font-size: 15px; }
}

/* ===== read44e: no-stall W1, W3, W5 (App Genius function spec + Artist look co-sign, Oct 17). ===== */
/* W1: a Feed card whose text is not ready is held out of view (like fit-pending). */
.slide.text-pending { display: none !important; }
/* W3: "Wikipedia is busy" reuses the NO SIGNAL card as is; only the label tone and the pills differ. */
.lm-busy .lm-label { color: #D9CDB6; }
.lm-busy .lm-busy-title { display: block; -webkit-line-clamp: unset; overflow: visible; }
/* Pills: 'Open on Wikipedia' takes the primary style (Retry's on the offline card) with its arrow;
   'Try again' the secondary outline. Side by side only when both labels fit at half width (fitPills). */
.lm-secondary, .lm-wiki { background: transparent; color: #f4ecd9; border: 1px solid rgba(244, 236, 217, .4); }
.lm-wiki, .lm-open { gap: 8px; }
.lm-pill .lm-ext { font: 600 15px/1 system-ui, -apple-system, sans-serif; transform: translateY(-1px); }
.lm-btns.ao-row { flex-direction: row; }
.lm-btns.ao-row .lm-pill { flex: 1 1 0; min-width: 0; }
/* W5: while a card loads its label slot stays empty with its height kept; the label fades in over
   150 ms when it arrives (instant with reduced motion), so nothing below it moves. */
.panel .kicker:empty::before { content: "\200b"; }
@media (prefers-reduced-motion: no-preference) {
  .slide.label-in .panel .kicker { animation: lsLabelIn 150ms ease-out both; }
}
@keyframes lsLabelIn { from { opacity: 0; } to { opacity: 1; } }
/* read44e: the busy card fits between the bars on a landscape phone (pills stay on screen). NO SIGNAL unchanged. */
@media (orientation: landscape) and (max-height: 500px) {
  .lm-busy .lm-card { padding: 24px 28px 26px; }
  .lm-busy .lm-seal { display: none; }
  .lm-busy .lm-label { margin: 0 0 8px; }
  .lm-busy .lm-title { font-size: 22px; margin: 0 0 14px; }
}
/* read44g (Beta, Oct 17): Keep/Send never covers the "Trailer in Watch ▸" bar. Portrait: the rail sits
   above the bar (17% of the 42vh photo box). Landscape phones: the rail is one row along the bottom of
   the photo box (above the bar on a trailer plate), so Mark is no longer under the top bar. */
body:not(.watch) .slide:has(.lp-trailer) .rail { bottom: calc(100% - 42vh + 7.14vh + 10px); }
@media (orientation: landscape) and (max-height: 500px) {
  body:not(.watch) .rail { flex-direction: row; }
  body:not(.watch) .slide:has(.lp-trailer) .rail { bottom: calc(100% - 42vh + 44px + 8px); }
}
/* read44i (Beta, read44g (d)): the same rule for engines without :has() (Safari < 15.4, Chrome < 105);
   app.js adds .lp-has-trailer to a slide holding the Trailer bar there. Kept as separate rules so an
   engine that can't parse :has() still applies these. */
body:not(.watch) .slide.lp-has-trailer .rail { bottom: calc(100% - 42vh + 7.14vh + 10px); }
@media (orientation: landscape) and (max-height: 500px) {
  body:not(.watch) .slide.lp-has-trailer .rail { bottom: calc(100% - 42vh + 44px + 8px); }
}
/* watch-credit-toasts §1-6 (signed Oct 17): Watch credit line, trailer plum band, WC4 wait. */
.watch-imgcredit{display:none}
body.watch .watch-imgcredit:not([hidden]){
  position:absolute; z-index:46; display:flex; align-items:center; box-sizing:border-box;
  height:16px; margin:0; padding:0; white-space:nowrap;
  font:500 10.5px/16px "LoreAttrib","Archivo Narrow","Arial Narrow",system-ui,sans-serif;
  letter-spacing:.02em; color:#B39A9A; text-decoration:none; -webkit-tap-highlight-color:transparent;
  opacity:1; transition:opacity 160ms ease;
}
body.watch .watch-imgcredit::before{content:"";position:absolute;inset:-4px}
body.watch .watch-imgcredit .wic-k, body.watch .watch-imgcredit .wic-l{flex:none}
body.watch .watch-imgcredit .wic-a{min-width:0; overflow:hidden; text-overflow:ellipsis}
body.watch .watch-imgcredit:active span{text-decoration:underline}
body.watch .watch-imgcredit.wic-off, body.watch .watch-imgcredit.wic-under-toast{opacity:0; pointer-events:none}
body.watch .watch-imgcredit.wic-on-band{background:rgba(16,6,7,.6); box-shadow:0 0 10px 6px rgba(16,6,7,.6); border-radius:4px}
@media (prefers-reduced-motion: reduce){ body.watch .watch-imgcredit{transition:none} }
body.watch .watch-attrib .wa-l3{white-space:nowrap; display:flex; min-width:0; color:#B39A9A}
body.watch .watch-attrib .wa-l3[hidden]{display:none}
body.watch .watch-attrib .wa-l3 .wic-a{min-width:0; overflow:hidden; text-overflow:ellipsis}
body.watch .watch-attrib .wa-l3 .wic-k, body.watch .watch-attrib .wa-l3 .wic-l{flex:none}
body.watch .watch-stage.on-trailer .band-fill{display:none !important}
body.watch .slide .watch-stage.on-trailer,
body.watch .slide .watch-stage.wic-wait{background:linear-gradient(180deg,#1A0B0F 0%,#100607 46%,#0B0405 100%) !important}
/* Read's image credit: only the author ellipsizes, the licence and "via" always show. */
.img-credit .ic-line{display:flex; min-width:0; color:inherit; text-decoration:none}
.img-credit .ic-k, .img-credit .ic-l{flex:none; white-space:pre}
.img-credit .ic-a{min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}

/* read44m (receiver-landing-spec R3, look signed by Artist): the next-night line on tonight's card only.
   Archivo Narrow 500 12/16, .04em, muted cream #A8968C, 4px under the reason line (its 10px margin less 6). */
.why-next { margin: -6px 0 10px; font: 500 12px/16px "LoreAttrib", "Archivo Narrow", "Arial Narrow", system-ui, sans-serif; letter-spacing: .04em; color: #A8968C; }
/* R1e-LOOK: the in-app browser hint, card 1 only, the last line of the text column, 10px under the
   Keep/Send row. A 16px copper hairline before it; fades in 200ms, out 160ms; no fade with reduced motion. */
.inapp-hint { display: flex; align-items: baseline; gap: 8px; margin: 10px 0 0; font: 500 12px/16px "LoreAttrib", "Archivo Narrow", "Arial Narrow", system-ui, sans-serif; letter-spacing: .02em; color: #D9CDB6; opacity: 0; transition: opacity 200ms ease-out; }
.inapp-hint .hair { flex: 0 0 16px; width: 16px; height: 1px; background: #8C313B; align-self: center; }
.inapp-hint.on { opacity: 1; }
.inapp-hint.off { opacity: 0; transition: opacity 160ms ease-in; }
body.watch .inapp-hint { display: none; }
@media (prefers-reduced-motion: reduce) { .inapp-hint, .inapp-hint.off { transition: none; } }
/* R1e first-screen look (r1e-first-screen-look, Artist, Oct 17 2026).
   The in-app hint becomes a catalogue slip pinned to the TOP EDGE of card 1's photo (.media),
   directly under the top bar. Portrait: left, on the text column's 18px line. Phone landscape:
   top-right corner, so it stays out of the left/centre toast fallback zones and the CLIP mark.
   Type, colour, hairline, copy and motion are the signed R1e look; only the box moves.
   The existing .inapp-hint rules (font, colour, .on/.off fades, reduced motion, body.watch hide) stay. */
.media > .inapp-hint.slip{
  position:absolute; top:0; left:0; right:auto; z-index:2;          /* under the rail (4) and CLIP mark (3) */
  box-sizing:border-box; width:max-content; max-width:calc(100% - 24px);
  margin:0; padding:6px 30px 6px 18px;                               /* text on the 18px column; 28px slip */
  background:linear-gradient(90deg,
    rgba(16,6,7,.86) 0, rgba(16,6,7,.86) calc(100% - 24px), rgba(16,6,7,0) 100%); /* tint fades out in the right padding only */
  pointer-events:none;                                               /* never blocks photo taps or the picture swipe */
}
@media (orientation: landscape) and (max-height: 500px){
  .media > .inapp-hint.slip{
    left:auto; right:0; padding:6px 44px 6px 14px;                  /* text ends 44px from the edge: 13px clear of CLIP */
    background:linear-gradient(270deg,
      rgba(16,6,7,.86) 0, rgba(16,6,7,.86) calc(100% - 14px), rgba(16,6,7,0) 100%); /* short 14px fade on the left */
  }
}

/* read44n: landscape Watch toast (live_r44l #7 / FD6; /workspace/landscape-toast-look, SIGNED by Artist and
   App Genius). Phones on their side only; portrait is untouched. notePlace -> noteGutterPlace sets the
   class and the custom properties. */
@media (orientation: landscape) and (max-height: 500px) {
  body.watch-landscape .ls-note.ls-note--gutter{
    left:var(--note-l); right:auto; top:auto; bottom:var(--note-b);
    max-width:var(--note-maxw); transform:translate(0,0);
    justify-content:flex-start;
  }
  body.watch-landscape .ls-note.ls-note--gutter .ls-note-msg,
  body.watch-landscape .ls-note.ls-note--top .ls-note-msg{flex:0 1 auto; min-width:0; white-space:normal; overflow-wrap:break-word}
  body.watch-landscape .ls-note.ls-note--gutter.has-undo,
  body.watch-landscape .ls-note.ls-note--top.has-undo{align-items:flex-start}
  body.watch-landscape .ls-note.ls-note--gutter.has-undo .ls-note-msg,
  body.watch-landscape .ls-note.ls-note--top.has-undo .ls-note-msg{margin:7px 0}
  body.watch-landscape .ls-note.ls-note--gutter.has-undo .ls-note-ico,
  body.watch-landscape .ls-note.ls-note--top.has-undo .ls-note-ico{margin-top:7px}
  body.watch-landscape .ls-note.ls-note--gutter .ls-note-undo,
  body.watch-landscape .ls-note.ls-note--top .ls-note-undo{align-self:flex-start}
  body.watch-landscape .ls-note.ls-note--gutter.in,
  body.watch-landscape .ls-note.ls-note--top.in{animation-name:lsNoteInG}
  body.watch-landscape .ls-note.ls-note--gutter.out,
  body.watch-landscape .ls-note.ls-note--top.out{animation-name:lsNoteOutG}
  /* Gutter under 220px: top-aligned 8px under the night badge, still in the gutter (up to 3 rows). */
  body.watch-landscape .ls-note.ls-note--top{
    left:var(--note-l); right:auto; top:var(--note-t); bottom:auto;
    max-width:var(--note-maxw); transform:translate(0,0); justify-content:flex-start;
  }
}
@keyframes lsNoteInG{from{opacity:0;transform:translate(0,8px)}to{opacity:1;transform:translate(0,0)}}
@keyframes lsNoteOutG{from{opacity:1;transform:translate(0,0)}to{opacity:0;transform:translate(0,4px)}}
@media (prefers-reduced-motion: reduce){
  body.watch-landscape .ls-note.ls-note--gutter.in,
  body.watch-landscape .ls-note.ls-note--top.in{animation:lsNoteFade 120ms linear both}
  body.watch-landscape .ls-note.ls-note--gutter.out,
  body.watch-landscape .ls-note.ls-note--top.out{animation:lsNoteFade 120ms linear reverse both}
}

/* ===== read44p C6 (r2-cold-visitor-spec addendum, App Genius SIGNED; look by Artist + App Genius):
   a Read photo that has not arrived shows the card's plate; when it loads the plate fades out over 200 ms,
   so the photo crossfades in. It never holds back the text. A picture still waiting in the image queue
   (data-lsrc, no src yet) draws nothing of its own. ===== */
.slide .media .still.ph-late { position: relative; }
.slide .media .still img[data-lsrc]:not([src]) { visibility: hidden; }
.slide .media .still.ph-late > .ls-plate.ph { opacity: 1; transition: opacity 200ms ease-out; }
.slide .media .still.ph-late.ph-in > .ls-plate.ph { opacity: 0; }
.slide.credit-wait .media .still.ph-late.ph-in > .ls-plate.ph { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .slide .media .still.ph-late > .ls-plate.ph { transition: none; } }

/* read44p: Read footer image-credit row (credit-loading-look, SIGNED Oct 17; after/proposal-credit.css verbatim). */
/* Read card footer: the image credit gets its own reserved 16px row (credit-loading-look, Artist, Oct 17 2026).
   The row exists from the first paint in every state (wait, resolved, missing, gave-up), so the footer and
   everything after it never move. The generic "Lead image from the Wikipedia article…" string is never shown:
   the row's text comes only from creditOk meta (the same gate as .img-credit and the Watch line).
   Type and colour = the signed Watch credit line: Archivo Narrow 500 10.5/16, .02em, #B39A9A, "Image: <Author> · <Licence>". */
.panel .credit .src-img{
  position:relative; display:flex; align-items:center; box-sizing:border-box;
  height:16px; margin:0 0 4px; padding:0; overflow:hidden; white-space:nowrap;
  font:500 10.5px/16px "LoreAttrib","Archivo Narrow","Arial Narrow",system-ui,sans-serif;
  letter-spacing:.02em; color:#B39A9A;
}
.src-img .si-k{flex:none; margin-right:4px}                         /* "Image:" is always true, so it shows from the start */
.src-img .si-v{position:relative; flex:1 1 auto; min-width:0; height:16px}
/* Placeholder: a quiet 96x2 hairline slip where the name will be. Breathes .9 ↔ .7 for 4 half-cycles (5.6 s), then rests at .9. */
.src-img .si-pl{position:absolute; inset:0; opacity:1; transition:opacity 100ms ease-in}     /* placeholder wrapper: fades out first */
.src-img .si-bar{position:absolute; left:0; top:11px; width:96px; height:2px; border-radius:1px; background:#A8968C; opacity:.9}  /* on the baseline: a catalogue-form blank, "Image: ____" */
.src-img .si-bar{animation:siBreath 1400ms ease-in-out 4 alternate both; animation-delay:var(--si-delay,0ms)}  /* app sets −(ms since the card first asked) on a re-render */
@keyframes siBreath{from{opacity:.9}to{opacity:.7}}
/* Resolved text sits on the bar's spot; only opacity changes. Only the author ellipsizes (Watch rule). */
.src-img .si-t{position:absolute; inset:0; display:flex; min-width:0; opacity:0; transition:opacity 200ms ease-out 100ms}  /* R1e's 200 ms fade, after the blank has gone */
.src-img .si-a{min-width:0; overflow:hidden; text-overflow:ellipsis}
.src-img .si-l{flex:none; white-space:pre}
.src-img.is-on .si-t, .src-img.is-missing .si-t, .src-img.is-gaveup .si-t{opacity:1}
.src-img.is-on .si-pl, .src-img.is-missing .si-pl, .src-img.is-gaveup .si-pl{opacity:0}
.src-img.is-missing .si-k{display:none}                               /* "Title card: no free lead image on Wikipedia." */
.src-img.now .si-t, .src-img.now .si-pl{transition:none}           /* credit already cached at render: no fade on a re-render */
@media (prefers-reduced-motion: reduce){
  .src-img .si-bar{animation:none !important}
  .src-img .si-t, .src-img .si-pl{transition:none !important}
}
/* read44p item 6 (FD6 exception, Read footer only): at 843x390 the row fades while a toast is up. */
.panel .credit .src-img{transition:opacity 200ms ease-out}
.panel .credit .src-img.si-under-toast{opacity:0}
@media (prefers-reduced-motion: reduce){ .panel .credit .src-img{transition:none} }

/* ==== read44q S1: Read feed text clamp (SIGNED Oct 24 by Artist + App Genius; text-clamp-look/after/proposal-clamp.css,
   applied as signed; app.js fitSlide() sets --ph / --ex-lines and the fit classes). ==== */
/* Read feed text clamp: one swipe, one card (S1). LoreScroll Artist, Oct 24 2026. Look only; positions flagged in NOTES.md "For App Genius".
   Scope: Read feed cards only (#feed > .slide.fit, set by the fit hook). Watch, the full reading view (#expand),
   the title ladder (plate 56/44/34, film 42/34/26, frost 28), the R1e strip, toasts and the tab bar are not touched.
   The fit hook (after/markup-notes.md §3) sets on each slide:
     --ph        photo box height in px (42vh cap; it yields down to 72px so body + footer fit)
     --ex-lines  body lines shown (≥3 portrait, ≥2 landscape phones)
     .fit-short  slide shorter than 500px (360x560, 320x560): chips + yt-note move to the full view, media hint compacts
     .rail-row   photo box under 240px: the Mark/Keep/Send rail goes to one row (the landscape rule)
     .ph-s       photo box under 160px: a plate keeps its title size but drops its small print
     .ex-clamped / .ex-full  text cut (fade + cue) / text fits (no fade, no cue, still tappable) */

/* 1. The panel stops being a scroller. The swipe belongs to the feed. */
body:not(.watch) #feed > .slide.fit .panel{
  display:flex; flex-direction:column; overflow:hidden;   /* no overscroll-behavior here: it would stop the swipe chaining to the feed */
  touch-action:pan-y;                 /* the vertical pan now reaches the feed's scroll-snap (no inner scroller to eat it) */
  padding:12px 18px 10px;             /* 18px text column kept; top 18→12, bottom 18→10 */
}
body:not(.watch) #feed > .slide.fit .panel > *{flex:none}
body:not(.watch) #feed > .slide.fit h1{margin-bottom:8px}            /* 12→8 */
body:not(.watch) #feed > .slide.fit .why{margin-bottom:8px}          /* 10→8 */

/* 2. Body: the tap target + the clamp box. */
body:not(.watch) #feed > .slide.fit .ex-wrap{
  --lh:24.65px; --cue-w:58px;         /* .extract 17px × 1.45 (type unchanged); cue box width */
  flex:1 1 0; min-height:44px; margin:0 0 8px; position:relative;
  cursor:pointer; -webkit-tap-highlight-color:transparent; outline:none; border-radius:4px;
}
body:not(.watch) #feed > .slide.fit .ex-wrap:focus-visible{box-shadow:0 0 0 2px rgba(210,122,110,.55)}
/* Clamp box: exactly N whole lines, N = --ex-lines from the fit rule. */
body:not(.watch) #feed > .slide.fit .ex-box{position:relative; overflow:hidden; height:calc(var(--ex-lines,3) * var(--lh))}
body:not(.watch) #feed > .slide.fit .ex-box .extract{margin:0}
/* Fade: 2 lines, transparent → the ground, over the last two clamped lines.
   Done as a mask so the text dissolves into the panel's own ground (#100607 plate under the paper grain,
   measured #140A0B–#170D0F on screen). A painted #100607 overlay left a visible 3–6-step seam at the box edge. */
body:not(.watch) #feed > .slide.fit.ex-clamped .ex-box .extract{
  -webkit-mask:linear-gradient(#000 calc(100% - 2 * var(--lh)), transparent 100%) top / 100% calc(var(--ex-lines,3) * var(--lh)) no-repeat;
          mask:linear-gradient(#000 calc(100% - 2 * var(--lh)), transparent 100%) top / 100% calc(var(--ex-lines,3) * var(--lh)) no-repeat;
}  /* sized to the clamp box (the <p> itself is taller than the box) */
/* The cue's slot: the last line's text clears out under the cue over a 24px soft edge (no painted plate). */
body:not(.watch) #feed > .slide.fit.ex-clamped .ex-box{
  -webkit-mask:linear-gradient(#000,#000) top / 100% calc(100% - var(--lh)) no-repeat,
               linear-gradient(to left, transparent 0 var(--cue-w), #000 calc(var(--cue-w) + 24px)) bottom / 100% var(--lh) no-repeat;
          mask:linear-gradient(#000,#000) top / 100% calc(100% - var(--lh)) no-repeat,
               linear-gradient(to left, transparent 0 var(--cue-w), #000 calc(var(--cue-w) + 24px)) bottom / 100% var(--lh) no-repeat;
}
/* Cue: the last line ends "… Read on". Archivo Narrow 500 12/16, #D27A6E (6.43:1 on #100607, AA; ≥5.8:1 on the measured ground). */
body:not(.watch) #feed > .slide.fit .ex-cue{display:none}
body:not(.watch) #feed > .slide.fit.ex-clamped .ex-cue{
  display:block; position:absolute; right:0; z-index:1; pointer-events:none; white-space:nowrap;
  top:calc((var(--ex-lines,3) - 1) * var(--lh) + (var(--lh) - 16px) / 2 + 1px);   /* centred on the last line box */
  font:500 12px/16px "LoreAttrib","Archivo Narrow","Arial Narrow",system-ui,sans-serif; letter-spacing:.02em; color:#D27A6E;
}
body:not(.watch) #feed > .slide.fit .ex-wrap:active .ex-cue{color:#F4ECD9}  /* press: the cue goes cream under the finger */

/* 3. Chips: one row in the feed (whole chips only); the rest live in the full view. */
body:not(.watch) #feed > .slide.fit .tags{flex-wrap:wrap; max-height:29px; overflow:hidden; margin:0 0 8px}
body:not(.watch) #feed > .slide.fit .tags:empty{display:none}
body:not(.watch) #feed > .slide.fit .yt-note{margin:0 0 8px}
body:not(.watch) #feed > .slide.fit p.credit:not(.img-credit){margin:0 0 8px}   /* footer: image row + Source, then actions */

/* 4. Short screens (slide < 500px: 360x560, 320x560). */
body:not(.watch) #feed > .slide.fit-short .tags,
body:not(.watch) #feed > .slide.fit-short .yt-note{display:none}               /* → full view (For App Genius) */
body:not(.watch) #feed > .slide.fit-short h1{display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2; overflow:hidden}  /* safety net for very long titles; none of the test cards wrap */
body:not(.watch) #feed > .slide.fit-short > .media-hint{padding:2px 14px; font-size:12px; line-height:16px}  /* 33.5→20px */
@media (max-width:340px){                                                       /* 320: keep Mark/Keep/Send/Wikipedia on one row */
  body:not(.watch) #feed > .slide.fit .actions{flex-wrap:nowrap; gap:6px}
  body:not(.watch) #feed > .slide.fit .actions button, body:not(.watch) #feed > .slide.fit .actions a{padding:10px 10px}
}

/* 5. The photo yields (42vh cap → 72px floor). The rail follows the photo's bottom edge. */
body:not(.watch) #feed > .slide.fit > .media,
body:not(.watch) #feed > .slide.fit > .media .still,
body:not(.watch) #feed > .slide.fit > .media img{height:var(--ph)}
body:not(.watch) #feed > .slide.fit .rail{bottom:calc(100% - var(--ph) + 10px)}
body:not(.watch) #feed > .slide.fit.lp-has-trailer .rail,
body:not(.watch) #feed > .slide.fit:has(.lp-trailer) .rail{bottom:calc(100% - var(--ph) * .83 + 10px)}
body:not(.watch) #feed > .slide.fit.rail-row .rail{flex-direction:row}   /* 3 stacked buttons need ~240px of photo */
body:not(.watch) #feed > .slide.fit.ph-s .ls-plate .lp-label,
body:not(.watch) #feed > .slide.fit.ph-s .ls-plate .lp-foot,
body:not(.watch) #feed > .slide.fit.ph-s .ls-plate .lp-desc,
body:not(.watch) #feed > .slide.fit.ph-s .ls-plate .lp-ghost,
body:not(.watch) #feed > .slide.fit.ph-s .ls-film .lp-pre,
body:not(.watch) #feed > .slide.fit.ph-s .ls-film .lp-year{display:none}       /* the year is in the h1 below; title keeps its ladder size; small print waits for the full view */

/* 6. Landscape phones (843x390): photo left, card right, so the footer fits beside the photo. */
@media (orientation:landscape) and (max-height:500px){
  body:not(.watch) #feed > .slide.fit{
    display:grid; grid-template-columns:minmax(0,40%) minmax(0,1fr); grid-template-rows:auto auto auto minmax(0,1fr);
  }
  body:not(.watch) #feed > .slide.fit > .media{grid-column:1; grid-row:1}
  body:not(.watch) #feed > .slide.fit > .img-credit{grid-column:1; grid-row:2}
  body:not(.watch) #feed > .slide.fit > .media-hint{grid-column:1; grid-row:3}
  body:not(.watch) #feed > .slide.fit > .panel{grid-column:2; grid-row:1 / -1; min-height:0; border-top:0; border-left:1px solid var(--line)}
  body:not(.watch) #feed > .slide.fit .rail{flex-direction:row; right:calc(60% + 10px)}
  body:not(.watch) #feed > .slide.fit .tags, body:not(.watch) #feed > .slide.fit .yt-note{display:none}
  body:not(.watch) #feed > .slide.fit .panel{padding-top:10px}
  body:not(.watch) #feed > .slide.fit h1{font-size:28px}            /* 7vw would give 32px on a phone on its side; 28 buys the 2nd body line */
  body:not(.watch) #feed > .slide.fit.fit-tight .ex-wrap{min-height:var(--lh)}   /* read44s F: one whole line, still the tap target */
  body:not(.watch) #feed > .slide.fit.fit-tight2 .why-next{display:none}
}
@media (prefers-reduced-motion: reduce){ body:not(.watch) #feed > .slide.fit .ex-cue{transition:none} }

/* read44q S1 build additions (not look changes): the visually hidden "Read on" label, the reserved hint row
   (item 6: height held from first paint, blank until a gallery arrives), the no-photo box following --ph,
   and the full view's new chips + YouTube disclosure (item 3). */
.ex-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.media-hint.mh-res{visibility:hidden}
body:not(.watch) #feed > .slide.fit > .media .img-ph{height:var(--ph)}
body:not(.watch) #feed > .slide.fit .panel{-webkit-overflow-scrolling:auto}
.expand .ex-tags{margin:6px 0 12px}
.expand .yt-note{margin:0 0 10px}

/* read44r yt-landscape-look (SIGNED Oct 24 + Artist addendum): landscape trailer disclosure line (after/proposal-yt.css as signed).
   The trailer line's spans are now separated by normal spaces; outside .wic-side the flex row drops them, so the
   old non-breaking gaps come back as generated content and portrait (and the attrib line 3) render as before. */
body.watch .wic-sp.wic-k::after{content:"\a0"}
body.watch .wic-sp.wic-l::before{content:"\a0"}
body.watch .watch-imgcredit.wic-side .wic-sp.wic-k::after,
body.watch .watch-imgcredit.wic-side .wic-sp.wic-l::before{content:none}
/* yt-landscape-look: landscape trailer disclosure when .watch-attrib is hidden (placeAttrib: band b.left < 174).
   Reuses the signed .watch-imgcredit element/type (Archivo Narrow 10.5/16, #B39A9A). JS sets left/top/width
   and toggles .wic-side (band beside player, wraps <=3 lines) or .wic-under (single line under player). */
@media (orientation: landscape) and (max-height: 500px){
  body.watch .watch-imgcredit.wic-side:not([hidden]){
    display:block; height:auto; max-height:48px; white-space:normal; overflow:hidden;
  }
  body.watch .watch-imgcredit.wic-side .wic-k,
  body.watch .watch-imgcredit.wic-side .wic-l{white-space:nowrap}
  body.watch .watch-imgcredit.wic-side .wic-a{
    display:inline-block; max-width:100%; vertical-align:top; white-space:nowrap;
    overflow:hidden; text-overflow:ellipsis;
  }
  body.watch .watch-imgcredit.wic-under:not([hidden]){display:flex}
}

/* read44s C: the chips row is held (invisible) while a card's text is still loading, so it does not move the card when it arrives. */
.tags.tags-res{visibility:hidden; pointer-events:none}

/* ===== read44y (nsfw-blur-switch.md, Artist look B1-B3, signed Oct 28): sensitive images ===== */
@font-face { font-family: "LoreSens"; src: url("fonts/ArchivoNarrow-SemiBold-subset.woff2?v=read35") format("woff2"); font-weight: 600; font-display: swap; }
/* B1: the blur is CSS on the real image (no extra request). html.sens-show lifts it everywhere. */
.sens { position: relative; overflow: hidden; }
.sens > img { transition: filter 260ms ease-out, transform 260ms ease-out; }
.sens.is-blur > img { filter: blur(28px) saturate(.4) brightness(.55); transform: scale(1.08); pointer-events: none; -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }
.slide .media .still.sens.is-blur > img.develop { animation: none; }
.sens-veil {
  position: absolute; inset: 0; z-index: 2; display: flex; flex-direction: column; align-items: center; justify-content: center;
  margin: 0; padding: 0; border: 0; border-radius: 0; width: 100%; background: rgba(16, 6, 7, .35); color: #F4ECD9;
  cursor: pointer; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; user-select: none;
  opacity: 1; transition: opacity 260ms ease-out;
}
.sens-veil::before { content: ""; position: absolute; inset: 8px; border: 1px solid #8C313B; pointer-events: none; }
.sens-k { font: 400 11px/16px "Courier Prime", ui-monospace, monospace; letter-spacing: .12em; text-transform: uppercase; color: #D27A6E; }
.sens-t { display: flex; align-items: center; justify-content: center; width: 100%; min-height: 44px; margin-top: 6px; margin-bottom: -14px; font: 600 15px/20px "LoreSens", "Archivo Narrow", system-ui, sans-serif; color: #F4ECD9; }
.sens:not(.is-blur) > .sens-veil, html.sens-show .sens > .sens-veil { opacity: 0; pointer-events: none; visibility: hidden; transition: opacity 260ms ease-out, visibility 0s linear 260ms; }
html.sens-show .sens > img { filter: none; transform: none; pointer-events: auto; -webkit-touch-callout: default; -webkit-user-select: auto; user-select: auto; }
/* Tiles under 120px: reason kicker only, 10/14. */
.sens-veil.sm::before { inset: 3px; }
.sens-veil.sm .sens-k { font-size: 10px; line-height: 14px; letter-spacing: .12em; max-width: 100%; overflow: hidden; }
.sens-box { position: relative; display: inline-block; overflow: hidden; flex: none; }
.sens-box.sb-find { flex: 0 0 48px; width: 48px; height: 48px; border-radius: 4px; }
.sens-box.sb-find > img.find-thumb { display: block; }
.ex-img.sens { margin: 0; }
.ex-img.sens > img { display: block; width: 100%; }
@media (prefers-reduced-motion: reduce) { .sens > img, .sens-veil, .sens:not(.is-blur) > .sens-veil, html.sens-show .sens > .sens-veil { transition: none; } }

/* B2: You > Sensitive images (52px row, existing row style). */
.sens-wrap { margin: 8px 0 16px; }
.sens-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; height: 52px; }
.sens-lab { flex: 1 1 auto; min-width: 0; font: 500 16px/22px "LoreGelasio", Georgia, serif; color: #F4ECD9; }
.sens-hint { margin: 2px 0 0; font: 400 12px/16px system-ui, -apple-system, sans-serif; color: #A8968C; }
.sens-seg { flex: none; display: inline-flex; border: 1px solid rgba(140, 49, 59, .6); border-radius: 999px; overflow: hidden; }
.sens-seg button {
  min-width: 64px; min-height: 44px; padding: 0 14px; margin: 0; border: 0; background: transparent; color: #D9CDB6;
  font: 600 14px/1 "LoreSens", "Archivo Narrow", system-ui, sans-serif; cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.sens-seg button + button { border-left: 1px solid rgba(140, 49, 59, .6); }
.sens-seg button.on { background: #C9675C; color: #100607; }

/* B3: the 18+ confirm (existing bottom-sheet style). */
.sens-sheet { position: fixed; inset: 0; z-index: 80; }
.sens-sheet[hidden] { display: none !important; }
.ss-scrim { position: absolute; inset: 0; background: rgba(8, 3, 5, .55); opacity: 0; transition: opacity .18s ease; }
.ss-panel {
  position: absolute; left: 0; right: 0; bottom: 0; max-width: 420px; margin: 0 auto; background: #1A0C0E;
  border-top: 1px solid rgba(140, 49, 59, .6); border-radius: 16px 16px 0 0; padding: 22px 18px calc(14px + var(--safe-b, 0px));
  display: flex; flex-direction: column; transform: translateY(100%); transition: transform .22s ease;
}
.sens-sheet.open .ss-scrim { opacity: 1; }
.sens-sheet.open .ss-panel { transform: none; }
.ss-text { margin: 0 0 18px; font: 500 19px/26px "LoreGelasio", Georgia, serif; color: #F4ECD9; }
.ss-show { width: 100%; height: 48px; border: 0; border-radius: 999px; background: #C9675C; color: #100607; font: 600 15px/1 "LoreSens", "Archivo Narrow", system-ui, sans-serif; cursor: pointer; }
.ss-cancel { align-self: stretch; height: 44px; margin-top: 8px; border: 0; background: none; color: #D9CDB6; font: 600 15px/1 "LoreSens", "Archivo Narrow", system-ui, sans-serif; cursor: pointer; }
.ss-show:active, .ss-cancel:active { opacity: .85; }
@media (prefers-reduced-motion: reduce) { .ss-panel, .ss-scrim { transition: none; } }
