diff --git a/CLAUDE.md b/CLAUDE.md index 7d91e99..9f30a6a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -327,6 +327,24 @@ v2026.08.26.005 Fix the screen sleeping on a song (owner: "when I took away gig self-guards; `visibilitychange` re-requests unconditionally; `openCurrent()` and `startScroll()` re-assert. Dead `releaseWake()` and the orphaned gig-mode comment removed. Reproduced against a stubbed `wakeLock` first: 8 failing, then 11 passing. +v2026.09.07.001 Visual pass — one icon language, real type hierarchy, readable section headings, + decluttered rows. **No behaviour change; the sheet renderer is byte-identical** + across all six seed songs (verified pill-by-pill). (1) `#isprite` `` sheet + replaces OS emoji + text glyphs + one lone SVG. **Icon paint lives in CSS on + `.ico`, never as attributes on the sprite root** — `` clones inherit from the + *use site*, so `fill="none" stroke="currentColor"` on `#isprite` never reaches + them and every stroked icon renders as a black fill. `setIcon(el,name)` swaps + symbols where JS used to assign `textContent` (theme toggle, scroll play/pause, + stage button). (2) `--display` retargeted JetBrains Mono → **Fraunces** (already + self-hosted and precached, dormant since .07.04.003); mono is now data-only. + `.brand` pinned to `--mono` so the wordmark is untouched. (3) `.comment` section + headings → tracked accent small caps + hairline rule (were `.7em` grey italic, the + smallest text on screen). (4) Rows show title/subtitle/key; actions live in the + context menu via long-press **or a new `⋯` `.rowmore` button** (pointer devices + have no long-press). `openSetlistContext()` gives setlists the same treatment and + `install()` in the long-press IIFE now takes the opener as its 3rd argument. + Played = a `✓` in the `.num` slot only. Version tag moved to `#aboutLine` in the + ≡ sheet; see §9 for why `.brand small` must stay in the DOM. ``` > **Note:** the changelog comment at the top of `setlist69.html` is missing entries @@ -598,7 +616,7 @@ Globals: `transpose` (semitones, 0 on song open), `preferFlats` (bool), `fontSiz **Prev/next:** `nextSong()` / `prevSong()` — in a set (`curIndex>=0`) they walk `songIds`; opened standalone they walk the **library** in its rendered alphabetical order (`libraryIds()`, v2026.08.14.002), so swipe works everywhere and the dock shows "n/N" of whichever list applies. Swipe left/right triggers these (40px threshold, |dx|>1.8·|dy|, <700ms; resets on `touchcancel`). History: .003 shipped a "not in a setlist" toast for standalone swipes after the silent no-op burned two debug rounds; .002 of 08.14 replaced it with real library navigation. **🎲 `#spinSong`** (Songs header) opens a random song standalone, never repeating the previous one. **The swipe listener is bound on `document` in the CAPTURE phase, not on `#songView` — load-bearing (v2026.08.13.002).** WebKit multicol (the two-column sheet) can mis-target touches inside columned content, so a bubbling listener on `#songView` is not guaranteed to hear them; document-capture fires no matter what element the browser thinks was touched. It gates on `screen==="song"` and ignores gestures starting inside `.modal`, `.dock`, `#chordPop`, or `header`, so control-drags can't change songs. `#songView` also carries `touch-action:pan-y pinch-zoom` + `overflow-x:hidden` (v2026.08.13.001) — keep `pinch-zoom` in the value, plain `pan-y` would revoke the a11y zoom re-enabled in v2026.07.12.004. `-webkit-overflow-scrolling:touch` was deliberately REMOVED from `.screen` in .002 (legacy since iOS 13; its composited scroller is a gesture-claim suspect) — do not reintroduce it. -**Gesture debug overlay (v2026.08.13.002):** 5 quick taps on the version tag (`.brand small`) toggle `#gestureDbg`, a fixed, `pointer-events:none` readout of the last ~6 touch events seen at document level (type, target, dx/dy) plus screen name and rendered column count. Session-only, never persisted. Exists so a dead gesture on a real device can be reported with the actual event stream — ask the owner to 5-tap, swipe once, and read back the overlay. +**Gesture debug overlay (v2026.08.13.002):** 5 quick taps on the version line (`#aboutLine`, in the ≡ tools sheet — it was `.brand small` until v2026.09.07.001) toggle `#gestureDbg`, a fixed, `pointer-events:none` readout of the last ~6 touch events seen at document level (type, target, dx/dy) plus screen name and rendered column count. Session-only, never persisted. Exists so a dead gesture on a real device can be reported with the actual event stream — ask the owner to 5-tap, swipe once, and read back the overlay. **Wake lock (app-wide; sentinel trap fixed v2026.08.26.005):** acquired at `boot()`, re-requested on every `visibilitychange→visible` on ANY screen, and re-asserted by `openCurrent()` and `startScroll()`. The owner runs the app on a stand all night — it must not sleep anywhere. @@ -642,10 +660,18 @@ CSS custom properties define both themes. As of v2026.07.17.001 the palette is * Contrast: lyrics/ink high in both modes; keep new colors above WCAG AA (`--faint` is the deliberately dim tier, still kept ≥AA on the darkest bg it lands on). -Fonts (the "mono chrome, readable lyrics" split): `--display` **and** `--mono` are both JetBrains Mono — so the brand wordmark, header title, section headings, modal headings, song titles, chords and version tag are all monospace (the PileUp look). `--ui` Hanken Grotesk stays on **lyric bodies + subtitles/banter**, the text you actually read while playing. Fraunces is no longer referenced (its `@font-face` + precache entry are dormant; safe to remove in a future cleanup). +Fonts — three faces, three jobs (v2026.09.07.001): + +- `--display` **Fraunces** — song titles (`.svtitle`), screen headings (`.listhead h2`), the header set name (`.htitle`), modal headings (`.mhead h3`). A warm display serif is what separates this from a developer tool; it was dormant-but-precached for months before this pass switched it on, so it costs no extra download. +- `--ui` **Hanken Grotesk** — everything a person *reads*: lyric bodies, subtitles, banter, buttons, labels. +- `--mono` **JetBrains Mono** — **data only**: chords (`.chordpill`), keys (`.pill`, `.keypill`, `.capo-badge`), counts (`.count`, `.num`, `.pos`), the version line, the editor textarea, `#gestureDbg`. + +`.brand` is pinned to `--mono` explicitly so retargeting `--display` leaves the PileUp-family wordmark alone. **Don't put mono back on titles or headings** — that was the single biggest "unfinished" tell. **Brand wordmark** (`.brand`): uppercase, wide-tracked (`.16em`), amber, with a soft glow (`text-shadow`), echoing PileUp's `PILEUP` mark. The `` version tag inside it opts back out (`text-transform:none`). +**Icons (v2026.09.07.001):** every glyph is `` pointing into the `#isprite` `` sheet at the top of ``. **The paint (`fill:none;stroke:currentColor;stroke-width:1.75`) is set in CSS on `.ico`, not as attributes on the sprite root** — a `` clone inherits from the use site, so attributes on `#isprite` never reach it and icons render as solid black fills. Symbols that are meant to be solid (play/pause/prev/next, dots) carry their own `fill="currentColor" stroke="none"`, which beats the inherited CSS. When JS needs to change an icon, call `setIcon(el,name)` — assigning `textContent` would delete the `` child. + **Capo badge** (`.capo-badge`): monospaced, amber border, shown beneath the key pill in the song view header when `capoVal > 0`. ----- @@ -654,7 +680,8 @@ Fonts (the "mono chrome, readable lyrics" split): `--display` **and** `--mono` a ``` Storage: idbOpen idbGet idbSet persist flushPersist isValidState -Seed/init: seed boot uid newSongId applyTheme toast migrateBanter addShowcaseSong +Seed/init: seed boot uid newSongId applyTheme toast migrateBanter retireShowcase + upgradeShowcase setIcon Music core: transposeNote transposeChord looksChord isChordLine pitchClass keyColor cleanEmbeddedChords toNashville nashPill Chord diagrams: chordFamily chordFrets chordDiagramSVG showChordPop hideChordPop @@ -666,7 +693,8 @@ Song view: openSongInSet openSongStandalone openCurrent reRender library nextSong prevSong startScroll stopScroll updateScrollProg requestWake openDockSheet closeDockSheet nudgeFont Editor: openEditor closeEditor saveSong -Context/dialogs: openSongContext closeSongContext openAdder closeAdder showPrompt showConfirm +Context/dialogs: openSongContext openSetlistContext closeSongContext openAdder closeAdder + showPrompt showConfirm closeModal loadPlayed savePlayed Backup/share: saveJsonFile exportData shareApp shareSetlist restoreData mergeSetImport Song links: b64urlEnc b64urlDec streamBytes songToLink linkToSong shareSong diff --git a/README.md b/README.md index 01d14aa..20011b8 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@
[![CI](https://github.com/cdburgess75/SetList69/actions/workflows/check.yml/badge.svg)](https://github.com/cdburgess75/SetList69/actions/workflows/check.yml) -[![Version](https://img.shields.io/badge/version-2026.08.26.005-informational?style=flat-square)](#versioning) +[![Version](https://img.shields.io/badge/version-2026.09.07.001-informational?style=flat-square)](#versioning) [![PWA](https://img.shields.io/badge/PWA-installable-5A0FC8?style=flat-square)](#save-it-to-your-phone) [![Offline](https://img.shields.io/badge/offline-first-2ea043?style=flat-square)](#features) [![Runtime deps](https://img.shields.io/badge/runtime_dependencies-0-f5a623?style=flat-square)](#tech-stack) diff --git a/docs/screenshots/chord-diagram.png b/docs/screenshots/chord-diagram.png index 9fcfbe5..7e09310 100644 Binary files a/docs/screenshots/chord-diagram.png and b/docs/screenshots/chord-diagram.png differ diff --git a/docs/screenshots/editor.png b/docs/screenshots/editor.png index d28b61b..ad06e5b 100644 Binary files a/docs/screenshots/editor.png and b/docs/screenshots/editor.png differ diff --git a/docs/screenshots/home.png b/docs/screenshots/home.png index e0b8262..305eda9 100644 Binary files a/docs/screenshots/home.png and b/docs/screenshots/home.png differ diff --git a/docs/screenshots/played.png b/docs/screenshots/played.png index e1869b6..9219c33 100644 Binary files a/docs/screenshots/played.png and b/docs/screenshots/played.png differ diff --git a/docs/screenshots/song-light.png b/docs/screenshots/song-light.png index 6056220..ea08613 100644 Binary files a/docs/screenshots/song-light.png and b/docs/screenshots/song-light.png differ diff --git a/docs/screenshots/song.png b/docs/screenshots/song.png index 24268e7..cb64eba 100644 Binary files a/docs/screenshots/song.png and b/docs/screenshots/song.png differ diff --git a/docs/screenshots/twocol.png b/docs/screenshots/twocol.png index f997656..4d24659 100644 Binary files a/docs/screenshots/twocol.png and b/docs/screenshots/twocol.png differ diff --git a/setlist69.html b/setlist69.html index c254c0f..6dacb35 100644 --- a/setlist69.html +++ b/setlist69.html @@ -250,6 +250,30 @@ Also removed: dead releaseWake() (no call sites) and the orphaned gig-mode comment block. Reproduced with a stubbed wakeLock first - 8 failing assertions before, 11 passing after. + v2026.09.07.001 Visual pass (owner: "easier to use, easier to see, make it look like a high-end + app"). FOUR changes, no behaviour change. (1) ONE icon language: a + sprite (#isprite) replaces a mix of OS emoji (🎲 — rendered differently on every + device and could not follow the theme), text glyphs (≡ ☾ ✕ ⊕ › ✎ ▲▼ ↺ ⚙ ◀ ▶) + and one lone SVG that matched nothing. Paint lives in CSS on .ico, NOT as + attributes on the sprite root — clones inherit from the use site, so + fill/stroke on #isprite never reach the clone (every stroked icon rendered as a + black fill until this was found). setIcon() swaps symbols where JS used to + assign textContent. (2) Type hierarchy: --display retargeted from JetBrains Mono + to Fraunces (self-hosted + precached since .07.04.003, dormant until now) for + song titles, screen/modal headings; mono is now data only — chords, keys, + counts, version. .brand pinned to --mono so the wordmark is unaffected. + (3) Section headings ({c:} comments) go from .7em grey italic — the smallest + text on screen — to tracked accent small caps with a hairline rule. (4) Rows + carry title/subtitle/key only; ▲▼ ✎ ✕ ⊕ › moved into the context menu, reached + by long-press or a new ⋯ button (pointer devices have no long-press). New + openSetlistContext() gives setlists the same menu (settings/move/delete), and + the long-press installer takes the opener as an argument. "Played" is encoded + ONCE — a ✓ in the row-number slot — instead of dim + strikethrough + pill; the + pill was eating the width that truncated titles to "House of t...". Version tag + moves out of the header into the ≡ sheet (#aboutLine); .brand small is kept in + the DOM but display:none because CI greps it and APP_VERSION reads it, and the + 5-tap gesture-debug trigger moved onto #aboutLine with it. Sheet renderer + verified byte-identical across all six seed songs. --> @@ -273,7 +297,10 @@ --brand:#ff6f5c; /* header wordmark — coral, its own token so --accent stays amber */ --green:#AED8CA; --green-dim:#2E8B7A; /* "played" strike + tag (bright on dark) */ --ui:'Hanken Grotesk',system-ui,-apple-system,sans-serif; - --display:'JetBrains Mono',ui-monospace,Menlo,Consolas,monospace; + /* Fraunces (self-hosted + precached since .07.04.003, dormant until v2026.09.07.001) is the + DISPLAY face: song titles, screen headings, modal headings. Mono is for data only - + chords, keys, counts, positions, the version - never for words a singer reads. */ + --display:'Fraunces',Georgia,'Times New Roman',serif; --mono:'JetBrains Mono',ui-monospace,Menlo,Consolas,monospace; --radius:10px; } @@ -297,23 +324,30 @@ padding-top:max(.65rem,env(safe-area-inset-top)); background:var(--panel); border-bottom:1px solid var(--line);position:relative;z-index:20;} - .brand{font-family:var(--display);font-weight:700;font-size:1.02rem;display:flex;align-items:center;gap:.45rem; + .brand{font-family:var(--mono);font-weight:700;font-size:1.02rem;display:flex;align-items:center;gap:.45rem; text-transform:uppercase;letter-spacing:.16em;color:var(--brand);text-shadow:0 0 14px rgba(255,111,92,.5);} /* status light: green when running the latest version, red when an update is available */ .brand .dot{width:.5rem;height:.5rem;border-radius:50%;background:var(--ok);box-shadow:0 0 12px var(--ok);transition:background .3s,box-shadow .3s;} .brand .dot.behind{background:var(--red);box-shadow:0 0 12px var(--red);} - .brand small{font-family:var(--mono);font-size:.55rem;color:var(--faint);font-weight:500;letter-spacing:1px;align-self:flex-start;text-transform:none;text-shadow:none;} + .brand small{display:none;} /* kept in the DOM: CI + APP_VERSION read it. Visible copy is #aboutLine in the ≡ sheet. */ .spacer{flex:1;} + /* One icon language: every glyph is a into the #isprite sheet, stroked in currentColor + so icons inherit .iconbtn's colour states and the theme. Replaced a mix of OS emoji, text + glyphs and one lone SVG that never matched in weight or optical size. */ + .ico{width:1.25em;height:1.25em;display:block;flex-shrink:0; + fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round;} + .iconbtn .ico{width:21px;height:21px;} + .ctx-btn .ico,.ghostbtn .ico{width:18px;height:18px;} .iconbtn{width:2.2rem;height:2.2rem;border-radius:10px;display:grid;place-items:center;font-size:1rem; color:var(--muted);transition:.15s;border:1px solid transparent;} .iconbtn[hidden]{display:none;} /* the `hidden` attr must beat .iconbtn's display:grid */ /* header zoom pair: two glyphs in a button the flex row shrinks to ~28px on a narrow phone */ - .iconbtn.fontbtn{font-family:var(--mono);font-size:.82rem;font-weight:700;letter-spacing:-.02em; + .iconbtn.fontbtn{font-family:var(--ui);font-size:.95rem;font-weight:700;letter-spacing:-.02em; white-space:nowrap;} /* the flex row shrinks these below their glyph width — without this "A+" breaks onto two lines */ .iconbtn:hover{background:var(--panel2);color:var(--ink);} .back{display:flex;align-items:center;gap:.3rem;font-weight:600;font-size:.9rem;color:var(--muted);padding:.3rem .2rem;} .back:hover{color:var(--ink);} - .htitle{font-family:var(--display);font-weight:500;font-size:1.05rem;white-space:nowrap;overflow:hidden; + .htitle{font-family:var(--display);font-weight:600;font-size:1.12rem;white-space:nowrap;overflow:hidden; text-overflow:ellipsis;max-width:55vw;} main{flex:1;overflow:hidden;position:relative;background:var(--bg);} @@ -327,7 +361,7 @@ .screen.show{display:block;} .listhead{display:flex;align-items:center;gap:.6rem;margin-bottom:.9rem;} - .listhead h2{font-family:var(--display);font-weight:500;font-size:1.5rem;margin:0;} + .listhead h2{font-family:var(--display);font-weight:600;font-size:1.6rem;letter-spacing:-.01em;margin:0;} .count{font-family:var(--mono);font-size:.7rem;color:var(--faint);} .card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius); @@ -335,15 +369,19 @@ .card:active{transform:scale(.99);} .card:hover{border-color:var(--faint);} .card.is-current{border-color:var(--accent);box-shadow:inset 3px 0 0 var(--accent);} - /* "played" row: dim it, strike the title, add a small outlined ✓ pill (ham-radio "worked" style) */ + /* "played" is encoded ONCE: a green ✓ replaces the row number, and the row dims. It used to + be dim + strikethrough + an outlined pill - three signals for one bit, and the pill ate the + width that made titles truncate to "House of t...". */ .card.played{opacity:.62;} - .card.played .t{text-decoration:line-through;text-decoration-color:var(--green);text-decoration-thickness:2px;} - .wkd{display:inline-block;font-size:.6rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase; - padding:.12rem .4rem;border:1px solid var(--green-dim);border-radius:4px;color:var(--green); - white-space:nowrap;flex-shrink:0;} + .card.played .num{color:var(--green);opacity:1;} .set-toolbar{display:flex;align-items:center;gap:.5rem;margin-bottom:.75rem;flex-wrap:wrap;} .set-tr-label{font-size:.7rem;color:var(--faint);font-family:var(--mono);} - .stagebtn{padding:.38rem .85rem;border-radius:9px;font-size:.78rem;font-weight:700;background:var(--accent);color:#fff;font-family:var(--mono);text-transform:uppercase;letter-spacing:.06em;} + .stagebtn{padding:.42rem .9rem;border-radius:9px;font-size:.78rem;font-weight:700;background:var(--accent);color:#fff;font-family:var(--ui);text-transform:uppercase;letter-spacing:.07em;} + .stagebtn{display:inline-flex;align-items:center;gap:.4rem;} + .stagebtn .ico{width:15px;height:15px;} + .secbtn{display:flex;align-items:center;justify-content:center;gap:.5rem;} + .fab .ico{width:26px;height:26px;} + .back .ico{width:17px;height:17px;} .stagebtn:hover{background:var(--accent2);} /* stage mode: hide all editing chrome */ #setSongsScreen[data-stage] .drag-handle, @@ -355,20 +393,25 @@ #setSongsScreen[data-stage] #stageBtn{background:var(--panel2);color:var(--muted);border:1px solid var(--line);} #setSongsScreen[data-stage] .card{padding:1.15rem 1rem;cursor:pointer;} .card .meta{flex:1;min-width:0;} - .card .t{font-weight:600;font-size:1.05rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;} - .card .s{font-size:.78rem;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:.1rem;} + .card .t{font-weight:600;font-size:1.06rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;} + .card .s{font-size:.82rem;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:.1rem;} .chev{color:var(--faint);font-size:1.1rem;} .num{font-family:var(--mono);color:var(--faint);font-size:.85rem;min-width:1.3rem;text-align:right;} .pill{font-family:var(--mono);font-size:.72rem;font-weight:700;padding:.2rem .5rem;border-radius:7px; color:#fff;letter-spacing:.3px;white-space:nowrap;box-shadow:inset 0 0 0 1px #ffffff22;} - .ord{display:flex;flex-direction:column;line-height:1;} - .ord button{font-size:.68rem;color:var(--faint);padding:.05rem .35rem;} - .ord button:hover{color:var(--ink);} + /* Row actions live in the long-press menu (and the ⋯ button, for pointer devices), not on + every row. .rm is retained: the stage-mode rule below still references it. */ .rm{color:var(--faint);font-size:1.05rem;padding:.25rem .45rem;} .rm:hover{color:var(--red);} + .rowmore{color:var(--faint);width:2rem;height:2rem;border-radius:8px;display:grid;place-items:center;flex-shrink:0;} + .rowmore:hover{color:var(--ink);background:var(--panel2);} + /* Version line in the ≡ sheet - the header slot now holds the wordmark alone. Also the + 5-tap target for the gesture-debug overlay (moved off .brand small, which is display:none). */ + .about{font-family:var(--mono);font-size:.7rem;color:var(--faint);text-align:center; + padding:.7rem .2rem .2rem;letter-spacing:.5px;} .empty{text-align:center;color:var(--faint);padding:2.6rem 1rem;font-size:.9rem;line-height:1.6;} .empty .big{font-size:2.2rem;margin-bottom:.4rem;opacity:.55;} @@ -377,11 +420,12 @@ display:grid;place-items:center;z-index:15;box-shadow:0 6px 22px #0006,0 0 0 1px #ffffff14;transition:.15s;} .fab:hover{background:var(--accent2);transform:scale(1.05);} - .secbtn{width:100%;padding:.8rem;border-radius:12px;background:var(--accent);color:#fff;font-weight:700; - font-family:var(--mono);text-transform:uppercase;font-size:.82rem;margin-bottom:1rem;letter-spacing:.06em;} + .secbtn{width:100%;padding:.85rem;border-radius:12px;background:var(--accent);color:#fff;font-weight:700; + font-family:var(--ui);text-transform:uppercase;font-size:.82rem;margin-bottom:1rem;letter-spacing:.07em;} .secbtn:hover{background:var(--accent2);} - .ghostbtn{width:100%;padding:.7rem;border-radius:12px;background:var(--panel);border:1px solid var(--line); - color:var(--muted);font-weight:600;font-size:.85rem;margin-bottom:.6rem;} + .ghostbtn{width:100%;padding:.75rem;border-radius:12px;background:var(--panel);border:1px solid var(--line); + color:var(--muted);font-weight:600;font-size:.85rem;margin-bottom:.6rem; + display:flex;align-items:center;justify-content:center;gap:.5rem;} .ghostbtn:hover{color:var(--ink);} /* touch-action: horizontal pans belong to the app's swipe-between-songs handler, never the @@ -392,7 +436,7 @@ promise against any multicol overflow quirk. */ #songView{padding-bottom:calc(1.4rem + env(safe-area-inset-bottom));touch-action:pan-y pinch-zoom;overflow-x:hidden;} .svhead{display:flex;align-items:flex-start;gap:.7rem;margin-bottom:.4rem;} - .svtitle{font-family:var(--display);font-weight:600;font-size:1.7rem;line-height:1.05;flex:1;cursor:pointer;} + .svtitle{font-family:var(--display);font-weight:600;font-size:1.68rem;letter-spacing:-.015em;line-height:1.1;flex:1;cursor:pointer;} .svsub{color:var(--muted);font-size:.88rem;margin-top:.1rem;} /* Banter: a highlighted stage-note under the title — meant to be read at a glance, so it gets a highlighter-style tinted bar rather than fine print. */ @@ -438,7 +482,13 @@ .wgspace{display:inline-block;width:.32em;} /* breakable gap between word-groups */ .chorus{border-left:3px solid var(--accent);padding-left:.7rem;margin-left:-.1rem;} .tabline{font-family:var(--mono);font-size:.62em;color:var(--muted);white-space:pre;overflow-x:auto;line-height:1.35;} - .comment{color:var(--muted);font-style:italic;font-size:.7em;margin:.3rem 0 .5rem;font-family:var(--ui);} + /* Section headings (Verse/Chorus/solo cues). These are what a player scans for mid-song, so + they are set as tracked small caps in the accent with a hairline rule - was .7em grey + italic, the smallest text on the screen. Accent on bg clears AA in both themes. */ + .comment{font-family:var(--ui);font-style:normal;font-weight:700;font-size:.8em; + letter-spacing:.13em;text-transform:uppercase;color:var(--accent); + margin:.75em 0 .45em;padding-bottom:.22em;border-bottom:1px solid var(--line);} + .sect:first-child .comment{margin-top:.1em;} .swipehint{text-align:center;color:var(--faint);font-size:.7rem;font-family:var(--mono);margin-top:2rem;opacity:.6;transition:opacity .5s;} .modal.bottom{align-items:flex-end;} .modal.bottom .sheetwrap{border-radius:var(--radius) var(--radius) 0 0;border-left:1px solid var(--line);border-right:1px solid var(--line);max-height:55dvh;} @@ -503,7 +553,7 @@ border-left:1px solid var(--line);border-right:1px solid var(--line);} .mhead{display:flex;align-items:center;gap:.6rem;padding:.8rem 1rem;border-bottom:1px solid var(--line); padding-top:max(.8rem,env(safe-area-inset-top));} - .mhead h3{font-family:var(--display);font-weight:500;font-size:1.2rem;margin:0;flex:1;} + .mhead h3{font-family:var(--display);font-weight:600;font-size:1.25rem;margin:0;flex:1;} .mbody{flex:1;overflow-y:auto;padding:1rem;display:flex;flex-direction:column;gap:.7rem;} .field label{display:block;font-size:.72rem;color:var(--muted);text-transform:uppercase;letter-spacing:.6px; margin-bottom:.25rem;font-weight:600;} @@ -574,6 +624,36 @@ +
- -
SetList69v2026.08.26.005
+ +
SetList69v2026.09.07.001
- + - - - - + + + +
@@ -600,7 +680,7 @@

Setlists

@@ -623,12 +703,12 @@

Songs

±0
set key
- - + +
- +
@@ -644,10 +724,10 @@

Songs

‹ swipe to change song ›
-
-
+
+
3
- +
@@ -656,7 +736,7 @@

Songs