Commit Graph

528 Commits

Author SHA1 Message Date
xRangerDE
63b04b6469 release: 4.6.107 storage stats table scope=col + aria-label
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:57:44 +02:00
xRangerDE
03b575cd1d a11y: scope=col + aria-label on storage stats table headers
The Storage card's per-streamer stats table was built without scope attributes on its <th> cells and the last column (the "Open" action column) had an empty header — screen readers couldn't tell which column a data cell belonged to once you tabbed into the rows, and the actions column had no announced name at all.

Fixes:
- All 6 column headers get scope="col" — explicit signal to screen readers that each <th> is a column header (the implicit <th>-inside-<thead> semantics work, but explicit scope is best practice for data tables and the de-facto standard for accessibility tooling validation)
- The empty actions header gets aria-label set from a new storageColumnActionsAria locale key (DE: "Aktionen", EN: "Actions") so screen readers announce "Aktionen, Spaltenkopf" for that column instead of skipping over an unnamed header.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:57:33 +02:00
xRangerDE
3748e25d1d release: 4.6.106 prefers-reduced-motion support
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:51:35 +02:00
xRangerDE
7dd6755392 a11y: respect prefers-reduced-motion — suppress all animations/transitions
The app had no @media (prefers-reduced-motion: reduce) rule, meaning users with the OS-level "Reduce motion" setting enabled still got the full animation set: the empty-state floating SVG (4s infinite), the btn-icon-spin on Refresh hover, the vod-bulk-bar slide-in, the storyboard fade-in, and the ~6 transition: all declarations scattered across button hover states.

For users with vestibular disorders this is real discomfort, not aesthetic preference. Windows 11 and macOS both expose the setting via Settings > Accessibility, and the media query is the standard way to honour it from CSS.

Added the conventional reduce-motion block at the bottom of styles.css:
- animation-duration: 0.01ms (effectively instant)
- animation-iteration-count: 1 (kills infinite loops)
- transition-duration: 0.01ms (state changes are immediate)
- scroll-behavior: auto (kills smooth-scroll)

All hover/state changes still happen — they just snap rather than animate. No feature is lost.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:51:23 +02:00
xRangerDE
02b61c7ea4 release: 4.6.105 .vod-btn focus-visible rings
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:46:42 +02:00
xRangerDE
5a4b054d9d a11y: focus-visible rings on .vod-btn (per-card action buttons)
Each VOD card renders 2-3 action buttons in its footer (.vod-btn — Trim, Queue, etc.). They had :hover states but no :focus-visible, so keyboard users tabbing through the VOD grid would land on each button without any visual focus indicator.

Added:
- .vod-btn:focus-visible — purple ring (covers the secondary variant which has a translucent grey bg)
- .vod-btn.primary:focus-visible — inner-white + outer-purple double-ring so the indicator stays visible against the button's own purple background (same pattern used for .btn-pill.primary and .btn-primary in 4.6.81/82)

Continues the per-area focus-visible pass — VOD-grid keyboard nav (already covered: card itself, checkbox; now: action buttons inside the card) is the final big interactive surface to get coverage.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:46:32 +02:00
xRangerDE
e73db55e29 release: 4.6.104 .modal-close + .queue-retry-btn focus-visible rings
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:42:32 +02:00
xRangerDE
9be864e614 a11y: focus-visible on .modal-close + .queue-retry-btn
Two more interactive buttons that had hover + active states but no keyboard focus indicator:

- .modal-close (the X-close button used by all 5 modals — update, clip-cutter, events viewer, chat viewer, template guide). Red-toned ring matching the hover colour family.

- .queue-retry-btn (per-item retry button on failed queue items). Purple ring matching the hover state's accent-purple feedback.

Continues the focus-visible pass started in 4.6.81/82/103. Closes the remaining shell-and-modal buttons that keyboard users could tab to without seeing where they were.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:42:21 +02:00
xRangerDE
03f3756523 release: 4.6.103 .lang-option focus-visible ring
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:37:49 +02:00
xRangerDE
91e4e65fa6 a11y: focus-visible ring on .lang-option (language picker)
The two language-picker buttons (Deutsch / English) had :hover and an
.active state but no :focus-visible — keyboard users tabbing into the
group couldn't see which button was focused unless it also happened to
be the active one. And even then, the active state uses a 1px soft
shadow which is easy to mistake for the hover border tweak.

Added two rules:
- .lang-option:focus-visible — purple-accent ring matching the rest of
  the app's focus-visible convention
- .lang-option.active:focus-visible — combines the pressed-state border
  with the thicker 2px focus halo so focus and pressed state are both
  visible when they coincide

Continues the focus-visible pass started in 4.6.81 (btn-primary/secondary/
pill/close) and 4.6.82 (queue + top-bar + add-streamer buttons).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:37:37 +02:00
xRangerDE
9046344375 release: 4.6.102 centralize localStorage try/catch helpers
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:33:33 +02:00
xRangerDE
752a5b2556 cleanup: centralise localStorage try/catch in renderer-shared — safeLocalStorageGet/Set/Remove
Every renderer module that persists state was wrapping its localStorage.getItem/setItem/removeItem call in the same try/catch idiom — handling private-browsing quirks and other sandbox contexts where storage isn't writable. Three identical patterns repeated nine times across renderer-streamers (filter / sort / hide-downloaded state), renderer-updates (skipped-update version), and renderer.ts (active-tab persistence).

Introduced three helpers in renderer-shared.ts:
- safeLocalStorageGet(key, fallback = '') — wraps getItem with the try/catch + fallback
- safeLocalStorageSet(key, value) — wraps setItem
- safeLocalStorageRemove(key) — wraps removeItem (needed for clearSkippedUpdateVersion which actually deletes the entry rather than blanking it)

Refactored 9 callsites. Reduces the noise:before:
    try { return localStorage.getItem(KEY) ?? ''; } catch { return ''; }
    try { localStorage.setItem(KEY, value); } catch { /* localStorage may be unavailable */ }
after:
    return safeLocalStorageGet(KEY);
    safeLocalStorageSet(KEY, value);

Left the VOD scroll-positions persistence in renderer-streamers untouched — its surrounding try/catch wraps JSON.parse/stringify logic that doesn't fit the simple helper signature.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:33:23 +02:00
xRangerDE
cf76e37c22 release: 4.6.101 language-picker labelled button group
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:28:23 +02:00
xRangerDE
a7fbdd2fbf a11y: language-picker is now a labelled button group for screen readers
The language picker is a pair of <button aria-pressed=...> toggles (Deutsch / English) sitting inside a div, with a separate <label id="languageLabel">Sprache</label> directly above. Two issues:

- The <label> has no for= attribute because the actual control is a custom button-pair, not a single input. So the label was just floating text — present visually but not programmatically connected to the buttons it describes.

- The two buttons were a flat list with no group container, so a screen reader navigating button-by-button announced "Deutsch, pressed" / "English, not pressed" without any context that these are language alternatives.

Added role="group" and aria-labelledby="languageLabel" to the language-picker div. Screen readers now announce "Sprache, group, Deutsch button pressed" — the floating label becomes the group's accessible name and the relationship is exposed via the accessibility tree.

Kept the aria-pressed toggle pattern (rather than rewiring to role="radiogroup"+role="radio") because the JS state plumbing already aligns with the toggle semantics and the group label is enough to clarify the picker's intent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:28:13 +02:00
xRangerDE
d0de52de95 release: 4.6.100 remove dead .clip-template-lint + clip-template-wrap button margin
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:22:47 +02:00
xRangerDE
3e5bdb73d4 dead-code: remove .clip-template-lint orphan + extract clipTemplateGuideBtn margin
The .clip-template-lint CSS rule was documented as a no-op alias kept in case any external reference still used it (deprecated when the shared .template-lint class with .ok/.warn modifiers took over). Grep confirms zero external references — both .ts files and index.html only mention the new .template-lint class. Deleted the rule + its 5-line comment.

Same edit moves the clipTemplateGuideBtn's margin-top:8px from inline to a .clip-template-wrap .btn-secondary descendant rule. One inline style attribute gone, and the spacing now lives next to the .clip-template-wrap definition where future readers will look for it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:22:36 +02:00
xRangerDE
f3e7225011 release: 4.6.99 .section-header-actions + drop redundant inline style
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:17:18 +02:00
xRangerDE
8f6d7b2d9a cleanup: .section-header-actions class + drop redundant margin-top:0 on archiveTitle
The stats card header (Archiv-Statistik) had an inline-styled inner div grouping the "last scanned" label with the Aktualisieren button — display:flex; gap:8px; align-items:center;. Extracted that pattern to .section-header-actions, which has a real semantic role: it's the right-side action cluster inside a section-header that needs to stay together as a single flex item so the parent's justify-content:space-between can pin it to the right.

Same edit drops the inline style="margin-top:0;" from <h3 id="archiveTitle"> — the global * { margin: 0 } reset already zeroes it, so the inline declaration was a literal no-op that just added noise to the markup. Worth removing as it might mislead future readers into thinking the override does something.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:17:09 +02:00
xRangerDE
8b917bee77 release: 4.6.98 mergeDesc + versionInfo unify on .card-intro
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:12:18 +02:00
xRangerDE
f6bb5970c9 cleanup: mergeDesc + versionInfo reuse .card-intro — typography consistency
Two more inline-styled secondary paragraphs converted to the shared .card-intro class:

- mergeDesc (Merge tab's intro paragraph): was color/margin-bottom:15px inline
- versionInfo (Updates card's "Version: v4.1.13" line): was color/margin-bottom:10px inline

Both sit below an h3 inside a settings-card — the same structural role as the 7 other .card-intro paragraphs. Converting unifies font-size (was browser-default ~14-16px, now the consistent 13px secondary-text size) and margin rhythm (12px) with the rest of the app's card intros. Visual delta is sub-perceptible (a few px in margin, ~1-3px in font-size) but the markup now reads its intent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:12:08 +02:00
xRangerDE
af38df2139 release: 4.6.97 .template-lint owns its own margin-top
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:06:13 +02:00
xRangerDE
38aadb6fb9 cleanup: .template-lint owns its own margin-top — unifies two divergent inline values
Both template-lint usages (clip-cutter modal at index.html:105 and Settings filename-template card at index.html:657) had different inline margin-top values — 4px vs 6px. The visual difference is essentially imperceptible but it's a pointless divergence: the same class, same context (a lint badge directly below a template input), spaced differently for no design reason.

Hoisted margin-top:6px into the .template-lint base class. Both usages now drop their inline override and pick up the same rhythm. Clip-cutter's lint shifts 2px down — visually identical.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:06:03 +02:00
xRangerDE
e728212981 release: 4.6.96 .settings-card.centered + .info-text + .stats-summary-grid
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:01:19 +02:00
xRangerDE
afbd09f507 cleanup: .settings-card.centered + .info-text + .stats-summary-grid
Three more inline-styled blocks moved into CSS classes:

- The Clips Info card had max-width:600px; margin:20px auto inline on the settings-card itself, plus color/line-height/white-space:pre-line inline on the info paragraph. Now .settings-card.centered (modifier for narrow-centred cards) and .info-text (multi-line description text with preserved authored line breaks).

- The Stats Summary KPI grid carried a 3-property grid declaration inline (display:grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap:12px). The layout is unique to this one container, but lifting it to .stats-summary-grid makes the markup self-documenting and matches the rest of the .stats-* class family.

Net: 3 inline style attributes gone, 3 new CSS rules.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 07:01:08 +02:00
xRangerDE
94a542b09a release: 4.6.95 .form-stack size modifiers + .input-narrow
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:56:40 +02:00
xRangerDE
3362138d1a cleanup: .form-stack size modifiers + .input-narrow — 5 inline width styles gone
Two related size-modifier patterns extracted:

1. .form-stack.size-sm (min-width:120px) and .form-stack.size-md (min-width:160px) — the Auto-Cleanup 3-up row carried three near-identical inline min-width declarations (120 / 160 / 160). They control where the row breaks to a new line on narrow widths, so the breakpoint metadata is logically a layout-modifier-class concern, not inline-style markup.

2. .input-narrow (width:90px) — the two Auto-VOD inputs (Poll-Intervall, Max. Alter) had their width inline because the values are 2-3 digits and a full-width input would look odd. Encoded once as a class, applied twice.

Net: 5 inline style attributes gone, 3 new CSS rules.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:56:31 +02:00
xRangerDE
562e92494b release: 4.6.94 .card-intro a colour + archive-search-summary uses .form-sublabel
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:51:22 +02:00
xRangerDE
2c0c7f6d00 cleanup: .card-intro a default colour + archive-search-summary uses .form-sublabel
The Twitch-API card's help-text paragraph contains one inline link (apiHelpLink → dev.twitch.tv/console/apps). It carried color/text-decoration/cursor inline — but text-decoration:underline and cursor:pointer are the browser defaults for <a href=...>, so only the accent colour was actually doing work. Hoisted that to a single .card-intro a descendant rule — any future inline link inside a card intro paragraph picks up the accent colour without ceremony.

Same edit converts the archiveSearchSummary div from inline (font-size:12px; color:var(--text-secondary)) to the existing .form-sublabel class — exact match.

Two more inline style attributes gone.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:51:13 +02:00
xRangerDE
d2a0f35265 release: 4.6.93 merge tab uses .merge-empty-state + cutter placeholder descendant rules
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:47:22 +02:00
xRangerDE
5931892320 cleanup: merge tab uses pre-existing .merge-empty-state class + clip-cutter placeholder gets descendant rules
The merge tab's empty state at index.html:400 was written as <div class="empty-state" style="padding: 40px 20px"> with two more inline-styled descendants (SVG opacity:0.3 and p margin-top:10px). A .merge-empty-state class with exactly those three properties has been sitting in styles.css since the original empty-state pass — the HTML just never picked it up. Switched to <div class="empty-state merge-empty-state"> + bare children. 3 inline styles gone.

Same pattern in the clip-cutter video preview placeholder at index.html:332-333 (svg opacity:0.3, p margin-top:10px). Added two descendant rules to the existing .video-preview .placeholder block so the styling lives in CSS. 2 more inline styles gone.

Net 5 inline style attributes gone, no visual change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:47:13 +02:00
xRangerDE
c6394fd411 release: 4.6.92 a11y — 14 more labels linked to inputs via for=
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:43:12 +02:00
xRangerDE
6946c34395 a11y: 14 more labels linked to their inputs via for=
Continuing the label-for pass from 4.6.79 + 4.6.83. The Settings tab, Twitch-API card, Discord card, Clips template guide, and the main cutter time-input row all had label elements sitting right next to their inputs/selects with no programmatic for=/id pairing — screen readers couldn't announce the label on focus, and clicking the label text didn't focus the control.

Fixed labels (label-id → target-input-id):
- themeLabel → themeSelect
- clientIdLabel → clientId
- clientSecretLabel → clientSecret
- storageLabel → downloadPath
- modeLabel → downloadMode
- partMinutesLabel → partMinutes
- parallelDownloadsLabel → parallelDownloads
- streamlinkQualityLabel → streamlinkQuality
- performanceModeLabel → performanceMode
- metadataCacheMinutesLabel → metadataCacheMinutes
- discordWebhookUrlLabel → discordWebhookUrl
- templateGuideTemplateLabel → templateGuideInput
- cutterStartLabel → startTime
- cutterEndLabel → endTime

Together with the prior passes (clip-cutter modal labels in 4.6.79, filename-template labels in 4.6.83), every plain label-above-input pair in static HTML now uses for=. Remaining unattached labels (languageLabel, vodHideDownloadedLabel) are intentional — the first targets a custom button-pair language picker, the second wraps its own checkbox via .inline-toggle.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:43:01 +02:00
xRangerDE
5c0378582e release: 4.6.91 aria-label on the 3 icon-only main-shell buttons
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:37:35 +02:00
xRangerDE
3ec88a7800 a11y: aria-label on the 3 icon-only buttons in the main shell
Three icon-only buttons in the always-visible UI had no programmatic accessible name:
- the "+" add-streamer button (no id, no title, no aria-label — entire button was unnamed)
- the bulk-remove X button next to the Streamer section title (had a localized title, but title is not a reliable accessible-name source — many screen readers don't expose it)
- the VOD-filter clear X button above the VOD grid (same — title-only)

For all three the visible text is just a glyph ("+", "x"), so the accessible name has to come from somewhere else. Added:
- new locale key static.streamerAddAriaLabel ("Streamer hinzufuegen" / "Add streamer") and an id on the "+" button so renderer-texts can localize it
- new setAriaLabel(id, value) helper in renderer-texts mirroring the existing setTitle/setPlaceholder pattern
- aria-label calls for all three buttons, in addition to the existing title (so the tooltip stays for sighted users)

The two existing X buttons reuse their existing title strings as aria-label — no new translation work, just exposing the already-present text via the right ARIA attribute.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:37:26 +02:00
xRangerDE
2df8d72a61 release: 4.6.90 .form-row.aligned + .form-sublabel reuse
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:31:49 +02:00
xRangerDE
b3d77040de cleanup: .form-row.aligned modifier + .form-sublabel reuse — 5 inline styles gone
Three Settings cards (Debug-Log, Auto-VOD-Download, Runtime Metrics) carried the identical inline style attribute on their action-row form-row:

    style="margin-bottom: 10px; align-items: center;"

Extracted into a single .form-row.aligned modifier — three duplicated inline declarations collapsed to one shared rule that pairs naturally with the existing .form-row.section-header pattern.

Two more inline styles converted to the existing .form-sublabel class:
- autoVodStatusLine: style="font-size:12px; color: var(--text-secondary);" — exact match for .form-sublabel
- storageSummary: same as above plus margin-bottom:8px (kept inline since margin is a one-off positioning concern, not part of the sublabel concept)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:31:40 +02:00
xRangerDE
61c71ebc7f release: 4.6.89 settings-card h4/hr defaults + .toggle-row reuse
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:27:15 +02:00
xRangerDE
ed20c44749 cleanup: settings-card h4 + hr defaults — and Auto-Cleanup label reuses .toggle-row
The Auto-Cleanup subsection inside the Storage card carries three inline-styled patterns that are good candidates to live in the cascade rather than the markup:

- <hr> with border:none; border-top:1px solid var(--border-soft); margin:16px 0
- <h4> with margin:0 0 8px 0; font-size:14px
- a checkbox <label> wrapping the "Auto-Cleanup aktivieren" toggle with the same display:flex; align-items:center; gap:8px pattern that the existing .toggle-row class already encodes

Hoisted the hr + h4 styling to default .settings-card descendant rules — any future subsection divider/heading inside a settings card now follows the same rhythm without ceremony — and the label reuses .toggle-row (margin-bottom:8px stays inline because the next sibling is a form-row, not another toggle-row, so the .toggle-row + .toggle-row sibling rule doesn't apply).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:27:05 +02:00
xRangerDE
c845be64cf release: 4.6.88 auto-updater lifecycle events go through appendDebugLog
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:21:42 +02:00
xRangerDE
a7f16d8cf8 observability: auto-updater lifecycle events go through appendDebugLog, not console.log
Four autoUpdater event handlers (checking-for-update, update-available, update-not-available, update-downloaded) were logging via raw console.log while the sibling 'error' handler already used appendDebugLog. Two consequences:

1. In a packaged build the user has no visible record of the update lifecycle — console.log streams to stderr which is invisible without DevTools. appendDebugLog writes to the timestamped debug log file that the user can inspect via the Live Debug-Log card in Settings.

2. Inconsistent — the existing 'auto-updater-error' tag in line 6479 was the only update-related event reaching the debug log. New tags ('auto-updater-checking', 'auto-updater-update-available', 'auto-updater-update-not-available', 'auto-updater-update-downloaded') give the full lifecycle a coherent grep-friendly prefix in the log.

The version info that was being printed inline ("Update available: 4.7.0") now lives in the structured details payload instead of a free-form message — easier to parse mechanically and matches the rest of the codebase's debug-log conventions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:21:35 +02:00
xRangerDE
d19e7ebc34 release: 4.6.87 .section-title flex layout + .section-title-label
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:17:23 +02:00
xRangerDE
e61940c108 cleanup: extract .section-title flex layout + .section-title-label
The sidebar's streamer section-title carried two inline flex containers:
- outer .section-title with display:flex; align-items:center; gap:6px; justify-content:space-between (so the bulk-remove X button can pin right while the title group stays left)
- inner span with display:flex; align-items:baseline; gap:8px (so the title text and the streamer counter share the same text-baseline rather than centring against each other)

.section-title is only used in this one spot, so the flex layout becomes part of the class definition (no risk of bleeding into other usages). The inner-span pattern moves to a dedicated .section-title-label class. Two inline style attributes gone.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:17:16 +02:00
xRangerDE
77aa04c894 release: 4.6.86 stats header consolidation + .card-intro.flush
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:12:19 +02:00
xRangerDE
35dc3201d8 cleanup: stats card header reuses .form-row.section-header + .card-intro.flush
The Statistics tab's "Archiv-Statistik" card had its own bespoke inline-styled flex header (display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:8px) plus an inline margin:0 on the h3 and an inline-styled intro paragraph with a different margin rhythm than the other 7 card intros (margin-top:8px; margin-bottom:0).

Two small additions reuse the existing classes:
- flex-wrap:wrap added to .form-row.section-header so the System-Check / Storage / now-Stats headers all wrap gracefully on narrow widths instead of overflowing. Strict improvement everywhere it's already used.
- .card-intro.flush modifier (margin-top:8px; margin-bottom:0) for intros that sit flush against the next block rather than spaced from it.

Three more inline style attributes gone, and the stats header now shares the same width-collapse behavior as the other section-header rows.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:12:10 +02:00
xRangerDE
67da6d4c58 release: 4.6.85 form-row.section-header + inline-toggle reuse
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:08:02 +02:00
xRangerDE
ccfff174ae cleanup: .form-row.section-header + reuse .inline-toggle — kill 6 inline styles
Two recurring inline-style patterns in Settings:

1. The "card title + right-aligned refresh button" header — used by the System-Check card and the Storage card. Both carried the identical 3-property inline style on the form-row plus an inline margin:0 on the h3 inside. Now expressed as .form-row.section-header (with a descendant h3 margin reset) — two cards, four inline attrs gone.

2. The "checkbox + Auto-Refresh label" pattern next to the debug-log and runtime-metrics action buttons — both were inline-styled with display:flex; align-items:center; gap:6px; font-size:13px; color:var(--text-secondary). The existing .inline-toggle class (already used by the VOD filter row's Hide-downloaded toggle) is the exact same pattern at 12px instead of 13px — close enough that unifying onto the shared class is the right move. 1px down beats keeping a third near-duplicate definition.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:07:51 +02:00
xRangerDE
3e591fac3d release: 4.6.84 .card-intro CSS class — 7 cards deduped
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:03:17 +02:00
xRangerDE
534f22b632 cleanup: extract .card-intro CSS class — kill 7 duplicated inline styles
Seven settings/feature cards (Archive, API help, Storage, Cleanup, Discord, Auto-VOD, Backup) each carry an intro paragraph with the exact same inline style attribute:

    style="color: var(--text-secondary); font-size:13px; margin-bottom:12px; line-height:1.5;"

That's the same 4-property declaration duplicated 7 times. Extracted into a single .card-intro class — HTML reads as semantic intent ("this is a card-intro paragraph") instead of repeated style soup, and any future tweak to intro-paragraph styling now lives in one place.

(statsIntro is similar but uses margin-top:8px; margin-bottom:0; — different rhythm because it sits above the stats grid, left as-is.)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 06:03:09 +02:00
xRangerDE
af0a27c01b release: 4.6.83 .filename-template-grid CSS class + label for= associations
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 05:58:51 +02:00
xRangerDE
0e313e8857 cleanup+a11y: .filename-template-grid CSS class + for= on the 3 template labels
The filename-templates 3-pair grid in Settings carried four inline style attributes:
- the wrapper div's display:grid; gap:8px; margin-top:8px
- three labels with the same font-size:13px; color:var(--text-secondary), with the 2nd and 3rd also having margin-top:4px

Extracted into a single .filename-template-grid class block (with descendant label styling + a :not(:first-child) margin-top rule). HTML drops from a noisy block of inline styles to a clean labelled grid.

Same edit added for= associations on the three labels (vodTemplateLabel → vodFilenameTemplate, partsTemplateLabel → partsFilenameTemplate, defaultClipTemplateLabel → defaultClipFilenameTemplate) — they were sitting right next to their inputs with no programmatic association. Continues the label-for a11y work from 4.6.79; clicking a label now focuses its input and screen readers announce the label when the input is focused.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 05:58:39 +02:00