diff --git a/frontend/AGENTS.md b/frontend/AGENTS.md
index 8e23a94..2843206 100644
--- a/frontend/AGENTS.md
+++ b/frontend/AGENTS.md
@@ -81,6 +81,7 @@ frontend/src/
│ ├── contactMerge.ts # Merge WS contact updates into list
│ ├── localLabel.ts # Local label (text + color) in localStorage
│ ├── radioPresets.ts # LoRa radio preset configurations
+│ ├── fontScale.ts # Browser-local relative font scale persistence/application
│ └── theme.ts # Theme switching helpers
├── components/
│ ├── StatusBar.tsx
@@ -110,7 +111,7 @@ frontend/src/
│ ├── settings/
│ │ ├── settingsConstants.ts # Settings section type, ordering, labels
│ │ ├── SettingsRadioSection.tsx # Name, keys, advert interval, max contacts, radio preset, freq/bw/sf/cr, txPower, lat/lon, reboot, mesh discovery
-│ │ ├── SettingsLocalSection.tsx # Browser-local settings: theme, local label, reopen last conversation
+│ │ ├── SettingsLocalSection.tsx # Browser-local settings: theme, relative font scale, local label, reopen last conversation
│ │ ├── SettingsFanoutSection.tsx # Fanout integrations: MQTT, bots, config CRUD
│ │ ├── SettingsDatabaseSection.tsx # DB size, cleanup, auto-decrypt, local label
│ │ ├── SettingsStatisticsSection.tsx # Read-only mesh network stats
diff --git a/frontend/src/components/settings/SettingsLocalSection.tsx b/frontend/src/components/settings/SettingsLocalSection.tsx
index 5b08952..2a7d6d8 100644
--- a/frontend/src/components/settings/SettingsLocalSection.tsx
+++ b/frontend/src/components/settings/SettingsLocalSection.tsx
@@ -17,6 +17,14 @@ import {
setSavedDistanceUnit,
} from '../../utils/distanceUnits';
import { useDistanceUnit } from '../../contexts/DistanceUnitContext';
+import {
+ DEFAULT_FONT_SCALE,
+ FONT_SCALE_SLIDER_STEP,
+ MAX_FONT_SCALE,
+ MIN_FONT_SCALE,
+ getSavedFontScale,
+ setSavedFontScale,
+} from '../../utils/fontScale';
export function SettingsLocalSection({
onLocalLabelChange,
@@ -31,6 +39,29 @@ export function SettingsLocalSection({
);
const [localLabelText, setLocalLabelText] = useState(() => getLocalLabel().text);
const [localLabelColor, setLocalLabelColor] = useState(() => getLocalLabel().color);
+ const [fontScale, setFontScale] = useState(getSavedFontScale);
+ const [fontScaleSlider, setFontScaleSlider] = useState(getSavedFontScale);
+ const [fontScaleInput, setFontScaleInput] = useState(() => String(getSavedFontScale()));
+
+ const commitFontScale = (nextScale: number) => {
+ const normalized = setSavedFontScale(nextScale);
+ setFontScale(normalized);
+ setFontScaleSlider(normalized);
+ setFontScaleInput(String(normalized));
+ };
+
+ const restoreFontScaleInput = () => {
+ setFontScaleInput(String(fontScale));
+ };
+
+ const handleSliderChange = (nextScale: number) => {
+ setFontScaleSlider(nextScale);
+ setFontScaleInput(String(nextScale));
+ };
+
+ const handleSliderCommit = (nextScale: number) => {
+ commitFontScale(nextScale);
+ };
const handleToggleReopenLastConversation = (enabled: boolean) => {
setReopenLastConversation(enabled);
@@ -89,6 +120,85 @@ export function SettingsLocalSection({
+
+
+
+
+ Scales the app's typography for this browser only. The slider moves in 5% steps;
+ the number field accepts any value from 25% to 400%.
+
+
+
+
+