/* player-dyn.css — dynamic player TEST SPACE styles (topic-test*.html, playlists.html).
   Shares the site's CSS variables (pages define :root). tier-premium remaps the accent
   to the canonical premium gold (text #B29234 / light #FBF5DC), mirroring the gold player
   skin on premium topic pages. */
.dyn-wrap.tier-premium { --accent: #B29234; --accent-light: #FBF5DC; --accent-mid: #C8A030; }

/* ── player chrome — copied from player.js's dyn topic player (round-8 item 6: the two
   players must be side-by-side indistinguishable). Scoped under .dyn-wrap. ── */
.dyn-wrap .dyn-player, .dyn-player { background: var(--surface); border: 0.5px solid var(--border); border-radius: var(--radius-lg); padding: 1.1rem 1.25rem 1rem; }
.dyn-mode { display: flex; gap: 2px; background: var(--bg); border: 0.5px solid var(--border-strong); border-radius: var(--radius-sm); padding: 2px; width: max-content; margin: 0 auto 0.9rem; }
.dyn-mode button { font-family: var(--font-ui); font-size: 12px; font-weight: 400; color: var(--text-secondary); background: none; border: none; border-radius: 4px; padding: 4px 10px; cursor: pointer; transition: background 0.15s, color 0.15s; white-space: nowrap; }
.dyn-mode button:hover { color: var(--text-primary); }
.dyn-mode button.on { background: var(--accent); color: #fff; font-weight: 500; }
.dyn-main { display: flex; align-items: center; gap: 12px; margin-bottom: 0.35rem; }
.dyn-play { width: 38px; height: 38px; border-radius: 50%; border: none; background: var(--accent); cursor: pointer; display: flex; align-items: center; justify-content: center; flex-shrink: 0; transition: background 0.15s; }
.dyn-play:hover { background: var(--accent-mid); }
.dyn-play svg { fill: #fff; width: 14px; height: 14px; margin-left: 2px; }
.dyn-skip { position: relative; width: 34px; height: 34px; border-radius: 50%; background: none; border: none; color: var(--text-secondary); cursor: pointer; display: flex; align-items: center; justify-content: center; flex-shrink: 0; transition: background 0.15s, color 0.15s; }
.dyn-skip:hover { background: var(--bg); color: var(--accent); }
.dyn-skip.dyn-sent svg { width: 30px; height: 30px; }
.dyn-topic-btn { width: 34px; height: 34px; }
.dyn-topic-btn svg { width: 14px; height: 14px; }
.dyn-scrubwrap { flex: 1; min-width: 0; }

.dyn-build { text-align: center; font-size: 13px; font-weight: 500; color: var(--accent); padding: 4px 0 8px; }
.dyn-dots { display: inline-block; width: 1.1em; text-align: left; }
.dyn-dots::after { content: '...'; display: inline-block; width: 0; overflow: hidden; vertical-align: bottom; animation: dyn-dots 1.2s steps(3, start) infinite; }
@keyframes dyn-dots { from { width: 0; } to { width: 1.05em; } }
#dyn-build-n, .dyn-build span:last-child { color: var(--text-tertiary); font-weight: 400; margin-left: 6px; }

/* scrubber — same track/fill/thumb as the player.js dyn scrubber (8px bar, 18px thumb) */
.dyn-seek { visibility: hidden; }
.dyn-seek-bar { width: 100%; height: 8px; border-radius: 4px; background: var(--border); cursor: pointer; position: relative; margin: 10px 0 5px; }
.dyn-seek-bar i { display: block; position: absolute; left: 0; top: 0; bottom: 0; width: 0; background: var(--accent); border-radius: 4px; transition: width 0.1s linear; }
.dyn-seek-bar i::after { content: ''; position: absolute; right: -9px; top: 50%; transform: translateY(-50%); width: 18px; height: 18px; border-radius: 50%; background: var(--accent); box-shadow: 0 1px 3px rgba(0,0,0,0.25); }
.dyn-seek-t { display: flex; justify-content: space-between; font-size: 11px; color: var(--text-tertiary); font-variant-numeric: tabular-nums; }

/* now-playing line — same typography as the player.js .now-playing strip */
.dyn-now { display: block; width: 100%; text-align: center; font-family: var(--font-ui); font-size: 12.5px; color: var(--text-secondary); background: none; border: none; cursor: pointer; padding: 4px 0; margin: 0.15rem 0 0.35rem; }
.dyn-now:hover { color: var(--accent); }
.dyn-slider { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 8px; font-size: 11.5px; color: var(--text-tertiary); }
.dyn-slider input[type=range] { width: 110px; accent-color: var(--accent); }
#dyn-pf-val { min-width: 34px; color: var(--text-secondary); font-weight: 500; }
.dyn-ctl-sep { color: var(--border-strong); }
.dyn-reps { display: inline-flex; gap: 3px; }
.dyn-rep-btn { width: 20px; height: 20px; border-radius: 5px; border: 0.5px solid var(--border-strong); background: var(--surface); color: var(--text-tertiary); font: 600 10.5px var(--font-ui); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; padding: 0; }
.dyn-rep-btn.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.dyn-en-lbl { display: inline-flex; align-items: center; gap: 4px; cursor: pointer; }
.dyn-en-lbl input { accent-color: var(--accent); margin: 0; width: 13px; height: 13px; }

.dyn-pills { display: flex; gap: 8px; margin: 1.25rem 0 0.9rem; }
.dyn-pills button { font-family: var(--font-ui); font-size: 12.5px; font-weight: 500; padding: 6px 14px; border-radius: 18px; border: 0.5px solid var(--border-strong); background: var(--surface); color: var(--text-secondary); cursor: pointer; }
.dyn-pills button.on { background: var(--accent); border-color: var(--accent); color: #fff; }

.dyn-list { display: flex; flex-direction: column; gap: 9px; margin-top: 0.9rem; }
.dyn-card { display: flex; align-items: center; gap: 12px; background: var(--surface); border: 0.5px solid var(--border); border-radius: var(--radius-md); padding: 0.8rem 0.95rem; transition: border-color 0.15s, background 0.15s, opacity 0.15s; }
.dyn-card .dyn-txt { flex: 1; cursor: pointer; min-width: 0; }
.dyn-th { font-family: var(--font-thai); font-size: 19px; line-height: 1.55; }
.dyn-tr { font-size: 12px; color: var(--text-tertiary); margin-top: 1px; }
.dyn-en { font-size: 13px; color: var(--text-secondary); margin-top: 2px; }
.dyn-card.playing { border-color: var(--accent); background: var(--accent-light); }
.dyn-card.off { opacity: 0.55; background: transparent; border-style: dashed; }
.dyn-card.off .dyn-txt { cursor: default; }
.dyn-card.off .dyn-th { text-decoration: line-through; text-decoration-color: rgba(0,0,0,0.35); }
.dyn-off-tag { display: inline-block; font-size: 10px; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-tertiary); border: 0.5px solid var(--border-strong); border-radius: 9px; padding: 1px 7px; margin-top: 4px; }
.dyn-btns { display: flex; gap: 7px; flex-shrink: 0; }
.dyn-x, .dyn-note { width: 30px; height: 30px; border-radius: 50%; border: 0.5px solid var(--border-strong); background: var(--surface); color: var(--text-tertiary); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
.dyn-x:hover, .dyn-note:hover { color: var(--accent); border-color: var(--accent); }
.dyn-x svg, .dyn-note svg { width: 14px; height: 14px; }
.dyn-empty { text-align: center; color: var(--text-tertiary); font-size: 13px; padding: 1.5rem 0; }

/* batch-remove tick mode (factory) */
.dyn-card .dyn-tick { display: inline-block; width: 20px; height: 20px; border-radius: 50%; border: 1.5px solid var(--border-strong); flex-shrink: 0; position: relative; cursor: pointer; }
.dyn-card .dyn-tick::before { content: ''; position: absolute; inset: -7px; }   /* generous tap target */
.dyn-card .dyn-tick.on { background: var(--accent); border-color: var(--accent); }
.dyn-card .dyn-tick.on::after { content: ''; position: absolute; left: 6px; top: 2.5px; width: 5px; height: 9px; border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg); }
.dyn-list.removing .dyn-btns { display: none; }
.dyn-list.removing .dyn-card { cursor: pointer; }
.dyn-list.removing .dyn-txt { cursor: pointer; }
#dyn-rm-bar { position: fixed; left: 0; right: 0; bottom: 0; background: var(--surface); border-top: 0.5px solid var(--border); padding: 10px 16px; display: none; align-items: center; justify-content: space-between; gap: 12px; z-index: 250; }
#dyn-rm-bar.show { display: flex; }
#dyn-rm-bar button { font-family: var(--font-ui); font-size: 13px; font-weight: 600; border-radius: 18px; padding: 8px 20px; cursor: pointer; }
#dyn-rm-bar .dyn-rm-done { color: #fff; background: #B03030; border: none; }
#dyn-rm-bar .dyn-rm-cancel { color: var(--text-secondary); background: var(--surface); border: 0.5px solid var(--border-strong); }
#dyn-rm-count { font-size: 13px; color: var(--text-secondary); font-weight: 500; }

/* prev/next topic (or playlist) footer nav — mirrors the topic pages' read-nav look */
.dyn-topicnav { display: flex; justify-content: space-between; gap: 1rem; margin-top: 2rem; padding-top: 1.25rem; border-top: 0.5px solid var(--border); }
.dyn-tn { display: inline-flex; flex-direction: column; gap: 2px; max-width: 46%; font-size: 13px; color: var(--accent); text-decoration: none; border: 0.5px solid var(--border-strong); border-radius: var(--radius-sm); padding: 7px 14px; transition: background 0.15s, border-color 0.15s; }
.dyn-tn:hover { background: var(--accent-light); border-color: var(--accent); }
.dyn-tn-r { text-align: right; align-items: flex-end; }
.dyn-tn-l { font-size: 11px; color: var(--text-tertiary); letter-spacing: 0.05em; text-transform: uppercase; }
.dyn-tn-n { color: var(--text-primary); font-weight: 500; }

/* add-to-playlist popup */
#dyn-pl-pop { position: fixed; inset: 0; background: rgba(20,15,45,0.45); z-index: 300; display: flex; align-items: center; justify-content: center; padding: 1.25rem; }
.dyn-pl-card { background: var(--surface); border-radius: var(--radius-lg); width: 100%; max-width: 380px; max-height: 70vh; display: flex; flex-direction: column; overflow: hidden; box-shadow: 0 12px 40px rgba(0,0,0,0.25); }
.dyn-pl-head { font-size: 15px; font-weight: 600; padding: 1rem 1.15rem 0.6rem; }
.dyn-pl-body { overflow-y: auto; padding: 0 0.6rem; }
.dyn-pl-empty { font-size: 13px; color: var(--text-secondary); padding: 1rem 0.6rem 1.4rem; line-height: 1.6; }
.dyn-pl-row { display: flex; align-items: center; gap: 11px; width: 100%; text-align: left; background: none; border: none; border-radius: var(--radius-md); padding: 0.65rem 0.6rem; cursor: pointer; font-family: var(--font-ui); }
.dyn-pl-row:hover { background: var(--accent-light); }
.dyn-pl-row.busy { opacity: 0.5; pointer-events: none; }
.dyn-pl-tick { width: 20px; height: 20px; border-radius: 6px; border: 1.5px solid var(--border-strong); flex-shrink: 0; position: relative; }
.dyn-pl-row.on .dyn-pl-tick { background: var(--accent); border-color: var(--accent); }
.dyn-pl-row.on.gold .dyn-pl-tick { background: #B29234; border-color: #B29234; }
.dyn-pl-row.on .dyn-pl-tick::after { content: ''; position: absolute; left: 6px; top: 2.5px; width: 5px; height: 9px; border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg); }
.dyn-pl-name { flex: 1; font-size: 14px; color: var(--text-primary); font-weight: 500; }
.dyn-pl-count { font-size: 12px; color: var(--text-tertiary); }
.dyn-pl-foot { padding: 0.7rem 1.15rem 1rem; text-align: right; border-top: 0.5px solid var(--border); }
.dyn-pl-done { font-family: var(--font-ui); font-size: 13px; font-weight: 600; color: #fff; background: var(--accent); border: none; border-radius: 18px; padding: 8px 22px; cursor: pointer; }
/* Secondary action in a two-button confirm (the leave-guard). The SAFE choice keeps the accent
   pill; the one that abandons work is the quiet outlined button, so the default reading of the
   dialog is "stay". Sits left of it — destructive-ish on the left, safe on the right. */
.dyn-pl-alt { background: var(--surface); color: var(--text-secondary); border: 0.5px solid var(--border-strong); margin-right: 8px; }

/* "＋ New playlist" — the first row of the add-to-playlist chooser (2026-08-09). Accent-coloured
   so it reads as an action among a list of destinations, and separated by a hairline so it does
   not look like one of the user's own playlists. */
.dyn-pl-new .dyn-pl-name { color: var(--accent); font-weight: 600; }
.dyn-pl-row.dyn-pl-new { border-bottom: 0.5px solid var(--border); border-radius: 0; margin-bottom: 4px; }
/* Name field for dynPrompt(). 16px is not a style choice: anything smaller makes iOS Safari zoom
   the whole page on focus, which throws the dialog off-centre and cannot be undone by the user. */
.dyn-pl-input { width: 100%; box-sizing: border-box; font-family: var(--font-ui); font-size: 16px;
  color: var(--text-primary); background: var(--bg); border: 0.5px solid var(--border-strong);
  border-radius: var(--radius-md); padding: 10px 12px; }
.dyn-pl-input:focus { outline: none; border-color: var(--accent); }

/* playlists page */
.pl-add { display: inline-flex; align-items: center; gap: 8px; font-family: var(--font-ui); font-size: 13.5px; font-weight: 600; color: #fff; background: var(--accent); border: none; border-radius: 20px; padding: 9px 20px; cursor: pointer; margin-bottom: 1.25rem; }
.pl-add:hover { background: var(--accent-mid); }
.pl-box { background: var(--surface); border: 0.5px solid var(--border); border-radius: var(--radius-lg); margin-bottom: 0.85rem; overflow: hidden; }
.pl-box-head { display: flex; align-items: center; gap: 12px; width: 100%; text-align: left; background: none; border: none; padding: 1rem 1.15rem; cursor: pointer; font-family: var(--font-ui); }
.pl-box-name { flex: 1; font-size: 15px; font-weight: 600; color: var(--text-primary); }
/* r85 — the state caption sits on its OWN LINE. Owner, 2026-08-01: the caption "jumps left" when
   it reads `· update available`. Cause: this row is [name flex:1][meta][control], so meta is
   anchored RIGHT and a longer caption grows leftward, shrinking the name — the position moved with
   the string length. Giving it a full-width basis drops it under the name, where it cannot compete
   for horizontal space and never moves. Also serves "the download interface looks like a
   centrepiece; it is just a function." */
.pl-box-head { flex-wrap: wrap; }
.pl-box-meta { font-size: 12.5px; color: var(--text-tertiary); flex: 1 0 100%; order: 3; margin-top: 2px; }
/* .pl-box-chev removed r31 — the whole .pl-box-head is a button, so the chevron was clutter that
   read as a sibling of the download circles/ticks. Its rules went with it. */
.pl-box-body { display: none; padding: 0 1.15rem 1.15rem; }
.pl-box.open .pl-box-body { display: block; }
/* "Remove sentences" (batch-remove entry) — quiet pill like .pl-del, accent-leaning */
.pl-remsent { font-family: var(--font-ui); font-size: 12px; color: var(--accent); background: none; border: 0.5px solid var(--accent); border-radius: 14px; padding: 4px 12px; cursor: pointer; margin-top: 1rem; margin-right: 8px; }
.pl-remsent:hover { background: var(--accent-light); }
/* "Rename playlist" — same quiet accent pill as .pl-remsent; it is an ordinary, reversible edit. */
.pl-rename { font-family: var(--font-ui); font-size: 12px; color: var(--accent); background: none; border: 0.5px solid var(--accent); border-radius: 14px; padding: 4px 12px; cursor: pointer; margin-top: 1rem; margin-right: 8px; }
.pl-rename:hover { background: var(--accent-light); }
/* "Delete playlist" — the only destructive action here, so it reads red rather than neutral grey. */
.pl-del { font-family: var(--font-ui); font-size: 12px; color: #B00020; background: none; border: 0.5px solid rgba(176,0,32,0.45); border-radius: 14px; padding: 4px 12px; cursor: pointer; margin-top: 1rem; }
.pl-del:hover { background: rgba(176,0,32,0.07); border-color: #B00020; }
.pl-del:hover { color: #B03030; border-color: #B03030; }
.pl-note { font-size: 13px; color: var(--text-secondary); line-height: 1.6; }
