fix(a11y): bump all text below 12px to 12px floor and promote tertiary-on-body to secondary
Brand guidelines (docs/brand/magnotia-brand-guidelines.md §4) say "Never go below 12px for any text" and "tertiary text must be ≥18px bold or ≥24px regular". Audit found 246 sub-12px className sites and 166 cases of text-text-tertiary paired with body sizes. Bumped text-[9/10/11px] → text-[12px] across 26 .svelte files in src/lib and src/routes. Promoted text-text-tertiary → text-text-secondary at body sizes (12-14px) where context allowed; left placeholder pseudo-states, ternary-conditional inactive states, and line-through "done" states alone (8 residual pairings, all decorative). Affects neurodivergent users on 1366×768 budget hardware most directly. svelte-check: 0 errors, 0 warnings.
This commit is contained in:
@@ -61,7 +61,7 @@
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<div class="flex justify-between">
|
||||
<p class="text-[12px] text-text-secondary font-medium">Font size</p>
|
||||
<span class="text-[11px] text-text-tertiary">{prefs.accessibility.fontSize}px</span>
|
||||
<span class="text-[12px] text-text-secondary">{prefs.accessibility.fontSize}px</span>
|
||||
</div>
|
||||
<input type="range" min="16" max="24" step="1" value={prefs.accessibility.fontSize}
|
||||
oninput={(e) => updateAccessibility({ fontSize: rangeValue(e) })}
|
||||
@@ -72,7 +72,7 @@
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<div class="flex justify-between">
|
||||
<p class="text-[12px] text-text-secondary font-medium">Letter spacing</p>
|
||||
<span class="text-[11px] text-text-tertiary">{prefs.accessibility.letterSpacing.toFixed(2)}em</span>
|
||||
<span class="text-[12px] text-text-secondary">{prefs.accessibility.letterSpacing.toFixed(2)}em</span>
|
||||
</div>
|
||||
<input type="range" min="0" max="0.15" step="0.01" value={prefs.accessibility.letterSpacing}
|
||||
oninput={(e) => updateAccessibility({ letterSpacing: rangeValue(e) })}
|
||||
@@ -83,7 +83,7 @@
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<div class="flex justify-between">
|
||||
<p class="text-[12px] text-text-secondary font-medium">Line height</p>
|
||||
<span class="text-[11px] text-text-tertiary">{prefs.accessibility.lineHeight.toFixed(1)}</span>
|
||||
<span class="text-[12px] text-text-secondary">{prefs.accessibility.lineHeight.toFixed(1)}</span>
|
||||
</div>
|
||||
<input type="range" min="1.3" max="2.2" step="0.1" value={prefs.accessibility.lineHeight}
|
||||
oninput={(e) => updateAccessibility({ lineHeight: rangeValue(e) })}
|
||||
@@ -94,7 +94,7 @@
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<div class="flex justify-between">
|
||||
<p class="text-[12px] text-text-secondary font-medium">Transcript font size</p>
|
||||
<span class="text-[11px] text-text-tertiary">{prefs.accessibility.transcriptSize}px</span>
|
||||
<span class="text-[12px] text-text-secondary">{prefs.accessibility.transcriptSize}px</span>
|
||||
</div>
|
||||
<input type="range" min="16" max="24" step="1" value={prefs.accessibility.transcriptSize}
|
||||
oninput={(e) => updateAccessibility({ transcriptSize: rangeValue(e) })}
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="energy-chip inline-flex items-center justify-center rounded-md border px-1 {chipSize} text-[10px] font-medium
|
||||
class="energy-chip inline-flex items-center justify-center rounded-md border px-1 {chipSize} text-[12px] font-medium
|
||||
{energy === null
|
||||
? 'opacity-0 group-hover:opacity-100 text-text-tertiary border-border-subtle hover:border-accent hover:text-text-secondary'
|
||||
: ''}
|
||||
|
||||
@@ -198,19 +198,19 @@
|
||||
>
|
||||
<span class="sr-only" aria-live="polite">{srStatus}</span>
|
||||
{#if recording}
|
||||
<span class="text-[11px] text-text-tertiary italic">Hold Ctrl/Alt/Super + key. Esc to cancel.</span>
|
||||
<span class="text-[12px] text-text-secondary italic">Hold Ctrl/Alt/Super + key. Esc to cancel.</span>
|
||||
{:else}
|
||||
{#each chips as chip, i}
|
||||
{#if i > 0}
|
||||
<span class="text-[10px] text-text-tertiary" aria-hidden="true">+</span>
|
||||
<span class="text-[12px] text-text-secondary" aria-hidden="true">+</span>
|
||||
{/if}
|
||||
<span class="px-2 py-0.5 rounded-md bg-bg-elevated border border-border text-[11px] font-medium text-text
|
||||
<span class="px-2 py-0.5 rounded-md bg-bg-elevated border border-border text-[12px] font-medium text-text
|
||||
shadow-[inset_0_1px_2px_rgba(0,0,0,0.3)]">{chip}</span>
|
||||
{/each}
|
||||
{/if}
|
||||
</button>
|
||||
{#if rejectionReason}
|
||||
<span class="text-[11px] text-warning" role="alert">
|
||||
<span class="text-[12px] text-warning" role="alert">
|
||||
Couldn't bind that combo. {rejectionReason}.
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
@@ -122,13 +122,13 @@
|
||||
|
||||
<div class="space-y-5">
|
||||
<div>
|
||||
<p class="text-[11px] text-text-tertiary mb-4">
|
||||
<p class="text-[12px] text-text-secondary mb-4">
|
||||
Build simple if-then rules. They respect Mute for now in Nudges, and everything stays local.
|
||||
</p>
|
||||
|
||||
<div class="rounded-lg border border-border-subtle bg-bg-input p-4">
|
||||
<div class="grid grid-cols-1 md:grid-cols-[120px_1fr] gap-3 items-start">
|
||||
<p class="text-[10px] font-medium text-text-tertiary uppercase tracking-wider pt-2">If</p>
|
||||
<p class="text-[12px] font-medium text-text-secondary uppercase tracking-wider pt-2">If</p>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<select
|
||||
class="bg-bg border border-border rounded-lg px-3 py-2 text-[12px] text-text focus:border-accent"
|
||||
@@ -147,7 +147,7 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<p class="text-[10px] font-medium text-text-tertiary uppercase tracking-wider pt-2">Then</p>
|
||||
<p class="text-[12px] font-medium text-text-secondary uppercase tracking-wider pt-2">Then</p>
|
||||
<div class="space-y-3">
|
||||
<div class="flex flex-col gap-2">
|
||||
<Toggle
|
||||
@@ -188,7 +188,7 @@
|
||||
/>
|
||||
|
||||
<div>
|
||||
<label for="rule-speak-line" class="block text-[10px] font-medium text-text-tertiary uppercase tracking-wider mb-2">
|
||||
<label for="rule-speak-line" class="block text-[12px] font-medium text-text-secondary uppercase tracking-wider mb-2">
|
||||
Speak aloud
|
||||
</label>
|
||||
<input
|
||||
@@ -204,7 +204,7 @@
|
||||
</div>
|
||||
|
||||
{#if error}
|
||||
<p class="text-[11px] text-danger mt-3">{error}</p>
|
||||
<p class="text-[12px] text-danger mt-3">{error}</p>
|
||||
{/if}
|
||||
|
||||
<div class="flex justify-end mt-4">
|
||||
@@ -224,11 +224,11 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p class="text-[10px] font-medium text-text-tertiary uppercase tracking-wider mb-2">Saved rules</p>
|
||||
<p class="text-[12px] font-medium text-text-secondary uppercase tracking-wider mb-2">Saved rules</p>
|
||||
{#if loading}
|
||||
<p class="text-[11px] text-text-tertiary">Loading…</p>
|
||||
<p class="text-[12px] text-text-secondary">Loading…</p>
|
||||
{:else if implementationRules.length === 0}
|
||||
<p class="text-[11px] text-text-tertiary italic">No rules yet.</p>
|
||||
<p class="text-[12px] text-text-secondary italic">No rules yet.</p>
|
||||
{:else}
|
||||
<div class="space-y-2">
|
||||
{#each implementationRules as rule (rule.id)}
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
></span>
|
||||
{:else}
|
||||
<span
|
||||
class="inline-flex items-center gap-1.5 px-2 py-[3px] rounded-full bg-bg-elevated border border-border-subtle text-[10px] text-text-secondary whitespace-nowrap"
|
||||
class="inline-flex items-center gap-1.5 px-2 py-[3px] rounded-full bg-bg-elevated border border-border-subtle text-[12px] text-text-secondary whitespace-nowrap"
|
||||
title={llmStatus.detail ?? label}
|
||||
>
|
||||
<span class="inline-block w-[6px] h-[6px] rounded-full {dotClass}"></span>
|
||||
|
||||
@@ -193,13 +193,13 @@
|
||||
|
||||
<div class="pl-6 mt-1 flex flex-col gap-1">
|
||||
{#if loading}
|
||||
<div class="flex items-center gap-2 text-[12px] text-text-tertiary py-1">
|
||||
<div class="flex items-center gap-2 text-[12px] text-text-secondary py-1">
|
||||
<Loader2 size={12} class="animate-spin" aria-hidden="true" />
|
||||
Loading steps…
|
||||
</div>
|
||||
{:else if subtasks.length === 0 && !error}
|
||||
<button
|
||||
class="flex items-center gap-1.5 text-[12px] text-text-tertiary hover:text-accent py-1 disabled:opacity-50"
|
||||
class="flex items-center gap-1.5 text-[12px] text-text-secondary hover:text-accent py-1 disabled:opacity-50"
|
||||
onclick={decompose}
|
||||
disabled={decomposing}
|
||||
aria-label="Break down this task into micro-steps"
|
||||
@@ -213,7 +213,7 @@
|
||||
{/if}
|
||||
</button>
|
||||
{:else if error}
|
||||
<p class="text-[11px] text-text-tertiary py-1">{error}</p>
|
||||
<p class="text-[12px] text-text-secondary py-1">{error}</p>
|
||||
{:else}
|
||||
{#each subtasks as step (step.id)}
|
||||
<div class="flex items-center gap-2 group py-0.5">
|
||||
@@ -295,7 +295,7 @@
|
||||
<SpeakerButton text={step.text} label="Read this step aloud" size={10} />
|
||||
</span>
|
||||
<button
|
||||
class="opacity-0 group-hover:opacity-100 flex items-center gap-1 text-[10px] text-text-tertiary hover:text-accent"
|
||||
class="opacity-0 group-hover:opacity-100 flex items-center gap-1 text-[12px] text-text-secondary hover:text-accent"
|
||||
onclick={() => startTimer(step.id)}
|
||||
aria-label="Start 2-minute timer for this step"
|
||||
style={reduceMotion ? '' : 'transition: opacity var(--duration-ui)'}
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
<p class="text-[13px] text-text-secondary mb-1">
|
||||
Magnotia needs the <span class="font-medium text-text">{modelSize}</span> model to transcribe speech.
|
||||
</p>
|
||||
<p class="text-[11px] text-text-tertiary mb-6">
|
||||
<p class="text-[12px] text-text-secondary mb-6">
|
||||
{currentModelInfo?.size ?? "?"} · {currentModelInfo?.accuracy ?? "?"} accuracy · 100% offline
|
||||
</p>
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
<p class="text-[12px] text-danger mt-3">{error}</p>
|
||||
{/if}
|
||||
|
||||
<p class="text-[10px] text-text-tertiary mt-5">
|
||||
<p class="text-[12px] text-text-secondary mt-5">
|
||||
Models are cached locally. No data leaves your machine.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -281,7 +281,7 @@
|
||||
|
||||
<div class="flex-1 overflow-y-auto px-6 pb-3 min-h-0">
|
||||
{#if loading}
|
||||
<p class="text-[12px] text-text-tertiary py-6 text-center">Loading your list…</p>
|
||||
<p class="text-[12px] text-text-secondary py-6 text-center">Loading your list…</p>
|
||||
{:else}
|
||||
<ul class="flex flex-col gap-1.5">
|
||||
{#each tasks as task (task.id)}
|
||||
@@ -317,7 +317,7 @@
|
||||
|
||||
<div class="px-6 pb-5 pt-2">
|
||||
<p
|
||||
class="text-[11px] mb-3 min-h-[16px] transition-colors
|
||||
class="text-[12px] mb-3 min-h-[16px] transition-colors
|
||||
{tooManyFlash ? 'text-warning' : 'text-text-tertiary'}"
|
||||
aria-live="polite"
|
||||
>
|
||||
@@ -332,7 +332,7 @@
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<button
|
||||
type="button"
|
||||
class="px-3 py-2 text-[12px] text-text-tertiary hover:text-text"
|
||||
class="px-3 py-2 text-[12px] text-text-secondary hover:text-text"
|
||||
onclick={skipForToday}
|
||||
disabled={applying}
|
||||
>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
{#each options as option}
|
||||
<button
|
||||
class="rounded-lg font-medium
|
||||
{size === 'small' ? 'px-2.5 py-1 text-[11px]' : 'px-3.5 py-[6px] text-[12px]'}
|
||||
{size === 'small' ? 'px-2.5 py-1 text-[12px]' : 'px-3.5 py-[6px] text-[12px]'}
|
||||
{value === option
|
||||
? 'bg-accent text-bg shadow-[0_1px_4px_rgba(214,132,80,0.3)]'
|
||||
: 'text-text-secondary hover:text-text hover:bg-hover'}"
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
<div class="flex-1">
|
||||
<p class="text-sm text-text font-semibold">{title}</p>
|
||||
{#if description}
|
||||
<p class="text-[11px] text-text-tertiary tracking-wide mt-1">{description}</p>
|
||||
<p class="text-[12px] text-text-secondary tracking-wide mt-1">{description}</p>
|
||||
{/if}
|
||||
</div>
|
||||
</summary>
|
||||
|
||||
@@ -39,12 +39,12 @@
|
||||
<!-- Header -->
|
||||
<div class="flex items-center gap-2 px-4 pt-4 pb-3">
|
||||
<h3 class="text-[13px] font-semibold text-text">Tasks</h3>
|
||||
<span class="text-[10px] px-1.5 py-0.5 rounded-full bg-bg-elevated text-text-tertiary">
|
||||
<span class="text-[12px] px-1.5 py-0.5 rounded-full bg-bg-elevated text-text-secondary">
|
||||
{taskCount}
|
||||
</span>
|
||||
<div class="flex-1"></div>
|
||||
<button
|
||||
class="text-[11px] text-text-tertiary hover:text-accent"
|
||||
class="text-[12px] text-text-secondary hover:text-accent"
|
||||
onclick={() => page.current = "tasks"}
|
||||
>View all</button>
|
||||
<button
|
||||
@@ -74,7 +74,7 @@
|
||||
<!-- Task list -->
|
||||
<div class="flex-1 overflow-y-auto px-3 pb-3 min-h-0">
|
||||
{#if activeTasks.length === 0}
|
||||
<p class="text-[11px] text-text-tertiary text-center py-6 opacity-60">No active tasks</p>
|
||||
<p class="text-[12px] text-text-secondary text-center py-6 opacity-60">No active tasks</p>
|
||||
{:else}
|
||||
<div class="flex flex-col gap-0.5">
|
||||
{#each activeTasks as task (task.id)}
|
||||
@@ -87,7 +87,7 @@
|
||||
onclick={() => completeTask(task.id)}
|
||||
aria-label="Complete task"
|
||||
></button>
|
||||
<span class="text-[11px] text-text leading-snug flex-1 min-w-0">{task.text}</span>
|
||||
<span class="text-[12px] text-text leading-snug flex-1 min-w-0">{task.text}</span>
|
||||
<span class="w-2 h-2 rounded-full mt-1 flex-shrink-0 {BUCKET_DOT_COLORS[task.bucket] || 'bg-text-tertiary'}"></span>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-[13px] text-text leading-tight">{label}</p>
|
||||
{#if description}
|
||||
<p class="text-[11px] text-text-tertiary mt-0.5 leading-snug">{description}</p>
|
||||
<p class="text-[12px] text-text-secondary mt-0.5 leading-snug">{description}</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
</button>
|
||||
<!-- Timestamp -->
|
||||
{#if showTimestamps}
|
||||
<span class="text-[10px] text-text-tertiary tabular-nums flex-shrink-0 mt-0.5 min-w-[36px]">
|
||||
<span class="text-[12px] text-text-secondary tabular-nums flex-shrink-0 mt-0.5 min-w-[36px]">
|
||||
{formatTime(seg.start)}
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
|
||||
<!-- Active tasks (WIP-limited) -->
|
||||
{#if visibleTasks.length === 0}
|
||||
<p class="text-[12px] text-text-tertiary text-center py-4">No active tasks</p>
|
||||
<p class="text-[12px] text-text-secondary text-center py-4">No active tasks</p>
|
||||
{:else}
|
||||
<div class="flex flex-col gap-1">
|
||||
{#each visibleTasks as task (task.id)}
|
||||
@@ -105,7 +105,7 @@
|
||||
{/if}
|
||||
</button>
|
||||
<button
|
||||
class="text-text-tertiary hover:text-danger opacity-0 group-hover:opacity-100 text-[11px]"
|
||||
class="text-text-secondary hover:text-danger opacity-0 group-hover:opacity-100 text-[12px]"
|
||||
onclick={() => deleteTask(task.id)}
|
||||
aria-label="Delete task"
|
||||
>
|
||||
@@ -124,7 +124,7 @@
|
||||
<!-- Overflow -->
|
||||
{#if hasOverflow}
|
||||
<button
|
||||
class="flex items-center gap-1.5 text-[11px] text-text-tertiary hover:text-text-secondary px-3"
|
||||
class="flex items-center gap-1.5 text-[12px] text-text-secondary hover:text-text-secondary px-3"
|
||||
onclick={() => showOverflow = !showOverflow}
|
||||
>
|
||||
<ChevronDown size={12} class="transform {showOverflow ? 'rotate-180' : ''}" aria-hidden="true"
|
||||
@@ -146,7 +146,7 @@
|
||||
|
||||
<!-- WIP indicator -->
|
||||
{#if activeTasks.length > 0}
|
||||
<p class="text-[10px] text-text-tertiary text-right">
|
||||
<p class="text-[12px] text-text-secondary text-right">
|
||||
{Math.min(activeTasks.length, wipLimit)}/{wipLimit} active
|
||||
</p>
|
||||
{/if}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
aria-pressed={prefs.zone === zone.id || (zone.id === 'default' && !prefs.zone)}
|
||||
>
|
||||
<div class="w-8 h-8 rounded-lg {zone.swatch} border border-border-subtle"></div>
|
||||
<span class="text-[11px] text-text-secondary">{zone.label}</span>
|
||||
<span class="text-[12px] text-text-secondary">{zone.label}</span>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user