Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions codec_audit.html
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,18 @@ <h1><a href="/" style="color:inherit;text-decoration:none">CODEC</a></h1>
function _ssDel(k){try{sessionStorage.removeItem(k)}catch(e){}}
</script>
<script>
/* Text size: small / medium / large. Default MEDIUM (1.15x) — the 14px base was
reported too small in the native app window. `zoom` scales every px-sized
rule on the page in one move, which a font-size variable alone would not.
Shared across surfaces via localStorage + the storage event. */
var _TEXT_SIZES={small:1,medium:1.15,large:1.3};
function _textSize(){var v=_lsGet('codec-text-size');return (v in _TEXT_SIZES)?v:'medium'}
function applyTextSize(){document.documentElement.style.zoom=String(_TEXT_SIZES[_textSize()]);var g=document.getElementById('textSizeGroup');if(g){Array.prototype.forEach.call(g.querySelectorAll('button'),function(b){b.classList.toggle('sel',b.getAttribute('data-size')===_textSize())})}}
function setTextSize(s){if(!(s in _TEXT_SIZES))return;_lsSet('codec-text-size',s);applyTextSize()}
window.addEventListener('storage',function(e){if(e.key==='codec-text-size')applyTextSize()});
applyTextSize();
</script>
<script>
function openSidePanel(){document.getElementById('sidePanel').classList.add('open');document.getElementById('sidePanelOverlay').classList.add('open')}
function closeSidePanel(){document.getElementById('sidePanel').classList.remove('open');document.getElementById('sidePanelOverlay').classList.remove('open')}
var _voiceOn=_lsGet('codec-voice')==='true';
Expand Down
12 changes: 12 additions & 0 deletions codec_auth.html
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,18 @@
function _ssDel(k){try{sessionStorage.removeItem(k)}catch(e){}}
</script>
<script>
/* Text size: small / medium / large. Default MEDIUM (1.15x) — the 14px base was
reported too small in the native app window. `zoom` scales every px-sized
rule on the page in one move, which a font-size variable alone would not.
Shared across surfaces via localStorage + the storage event. */
var _TEXT_SIZES={small:1,medium:1.15,large:1.3};
function _textSize(){var v=_lsGet('codec-text-size');return (v in _TEXT_SIZES)?v:'medium'}
function applyTextSize(){document.documentElement.style.zoom=String(_TEXT_SIZES[_textSize()]);var g=document.getElementById('textSizeGroup');if(g){Array.prototype.forEach.call(g.querySelectorAll('button'),function(b){b.classList.toggle('sel',b.getAttribute('data-size')===_textSize())})}}
function setTextSize(s){if(!(s in _TEXT_SIZES))return;_lsSet('codec-text-size',s);applyTextSize()}
window.addEventListener('storage',function(e){if(e.key==='codec-text-size')applyTextSize()});
applyTextSize();
</script>
<script>
// Theme: system / light / dark (ported from chat). "system" follows the OS and
// switches live at sunset; an explicit choice pins it until you cycle back.
function _themePref(){var v=null;try{v=_lsGet('codec-theme')}catch(e){}return (v==='light'||v==='dark'||v==='system')?v:'system'}
Expand Down
18 changes: 18 additions & 0 deletions codec_chat.html
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,11 @@
.modal-close { position:fixed; top:16px; right:16px; background:rgba(30,30,30,0.9); color:#fff; border:2px solid rgba(255,255,255,0.3); width:44px; height:44px; border-radius:50%; font-size:26px; cursor:pointer; z-index:101; display:flex; align-items:center; justify-content:center; transition:background 0.2s, transform 0.2s; }
.modal-close:hover { background:rgba(220,50,50,0.9); transform:scale(1.1); }
@media(max-width:600px){ .modal-close { width:52px; height:52px; font-size:30px; top:10px; right:10px; } }

.text-size-row{justify-content:space-between;cursor:default}
.text-size-group{display:inline-flex;gap:4px}
.text-size-group button{background:var(--surface-2);border:1px solid var(--border);color:var(--text-muted);border-radius:var(--radius-sm);width:28px;height:24px;font-size:12px;font-weight:600;cursor:pointer;font-family:var(--font)}
.text-size-group button.sel{background:var(--accent);border-color:var(--accent);color:#fff}
</style>
</head>
<body>
Expand Down Expand Up @@ -348,6 +353,7 @@ <h1><a href="/" style="color:inherit;text-decoration:none">CODEC</a></h1>
<div class="sp-divider"></div>
<a href="/tasks#reports" class="sp-item notif-bell" id="notifBellBtn"><svg class="ico" viewBox="0 0 24 24"><path d="M18 8A6 6 0 006 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 01-3.46 0"/></svg><span class="sp-item-label">Notifications</span><span class="notif-badge hidden" id="notifBadge">0</span></a>
<button class="sp-item" id="themeBtn" onclick="toggleTheme()"><svg class="ico" viewBox="0 0 24 24" id="themeIco"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg><span class="sp-item-label">Toggle Theme</span></button>
<div class="sp-item text-size-row"><span class="sp-item-label">Text size</span><span class="text-size-group" id="textSizeGroup"><button data-size="small" onclick="setTextSize('small')" title="Small">S</button><button data-size="medium" onclick="setTextSize('medium')" title="Medium">M</button><button data-size="large" onclick="setTextSize('large')" title="Large">L</button></span></div>
<button class="sp-item" onclick="window.location.href='/#settings'"><svg class="ico" viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z"/></svg><span class="sp-item-label">Settings</span></button>
<div class="sp-divider"></div>
<button class="sp-item" onclick="lockSession()" style="color:var(--danger)"><svg class="ico" viewBox="0 0 24 24"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0110 0v4"/></svg><span class="sp-item-label">Lock Session</span></button>
Expand Down Expand Up @@ -484,6 +490,18 @@ <h1><a href="/" style="color:inherit;text-decoration:none">CODEC</a></h1>
function _ssDel(k){try{sessionStorage.removeItem(k)}catch(e){}}
</script>
<script>
/* Text size: small / medium / large. Default MEDIUM (1.15x) — the 14px base was
reported too small in the native app window. `zoom` scales every px-sized
rule on the page in one move, which a font-size variable alone would not.
Shared across surfaces via localStorage + the storage event. */
var _TEXT_SIZES={small:1,medium:1.15,large:1.3};
function _textSize(){var v=_lsGet('codec-text-size');return (v in _TEXT_SIZES)?v:'medium'}
function applyTextSize(){document.documentElement.style.zoom=String(_TEXT_SIZES[_textSize()]);var g=document.getElementById('textSizeGroup');if(g){Array.prototype.forEach.call(g.querySelectorAll('button'),function(b){b.classList.toggle('sel',b.getAttribute('data-size')===_textSize())})}}
function setTextSize(s){if(!(s in _TEXT_SIZES))return;_lsSet('codec-text-size',s);applyTextSize()}
window.addEventListener('storage',function(e){if(e.key==='codec-text-size')applyTextSize()});
applyTextSize();
</script>
<script>
function openSidePanel(){document.getElementById('sidePanel').classList.add('open');document.getElementById('sidePanelOverlay').classList.add('open')}
function closeSidePanel(){document.getElementById('sidePanel').classList.remove('open');document.getElementById('sidePanelOverlay').classList.remove('open')}
// Auth + CSRF: inject session token and CSRF header on all requests
Expand Down
12 changes: 12 additions & 0 deletions codec_cortex.html
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,18 @@ <h3>Live Activity</h3>
function _ssDel(k){try{sessionStorage.removeItem(k)}catch(e){}}
</script>
<script>
/* Text size: small / medium / large. Default MEDIUM (1.15x) — the 14px base was
reported too small in the native app window. `zoom` scales every px-sized
rule on the page in one move, which a font-size variable alone would not.
Shared across surfaces via localStorage + the storage event. */
var _TEXT_SIZES={small:1,medium:1.15,large:1.3};
function _textSize(){var v=_lsGet('codec-text-size');return (v in _TEXT_SIZES)?v:'medium'}
function applyTextSize(){document.documentElement.style.zoom=String(_TEXT_SIZES[_textSize()]);var g=document.getElementById('textSizeGroup');if(g){Array.prototype.forEach.call(g.querySelectorAll('button'),function(b){b.classList.toggle('sel',b.getAttribute('data-size')===_textSize())})}}
function setTextSize(s){if(!(s in _TEXT_SIZES))return;_lsSet('codec-text-size',s);applyTextSize()}
window.addEventListener('storage',function(e){if(e.key==='codec-text-size')applyTextSize()});
applyTextSize();
</script>
<script>
// Hide header/nav when embedded in dashboard iframe
if(window.location.search.indexOf('embed=1')!==-1){
document.addEventListener('DOMContentLoaded',function(){
Expand Down
18 changes: 18 additions & 0 deletions codec_dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,11 @@
.setup-btn:disabled{background:var(--surface-3);color:var(--text-dim);cursor:not-allowed}
.setup-skip{background:none;border:none;color:var(--text-dim);font-size:12px;cursor:pointer;text-decoration:underline}


.text-size-row{justify-content:space-between;cursor:default}
.text-size-group{display:inline-flex;gap:4px}
.text-size-group button{background:var(--surface-2);border:1px solid var(--border);color:var(--text-muted);border-radius:var(--radius-sm);width:28px;height:24px;font-size:12px;font-weight:600;cursor:pointer;font-family:var(--font)}
.text-size-group button.sel{background:var(--accent);border-color:var(--accent);color:#fff}
</style>
</head>
<body>
Expand Down Expand Up @@ -703,6 +708,7 @@ <h2>MENU</h2>
<div class="sp-item sp-theme" id="themeBtn" role="group" aria-label="Theme"><svg class="ico" viewBox="0 0 24 24" id="themeIco"><circle cx="12" cy="12" r="9"/><path d="M12 3a9 9 0 000 18z" fill="currentColor" stroke="none"/></svg><span class="sp-item-label">Theme</span><span class="theme-seg"><button type="button" data-theme-opt="system" onclick="setThemePref('system')" title="Follow your system day-night setting">Auto</button><button type="button" data-theme-opt="light" onclick="setThemePref('light')">Light</button><button type="button" data-theme-opt="dark" onclick="setThemePref('dark')">Dark</button></span></div>
<button class="sp-item" onclick="showTab('settings');closeSidePanel()"><svg class="ico" viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z"/></svg><span class="sp-item-label">Settings</span></button>
<button class="sp-item" onclick="openConnectSetup();closeSidePanel()"><svg class="ico" viewBox="0 0 24 24"><path d="M12 2a10 10 0 100 20 10 10 0 000-20z"/><path d="M12 8v4l3 2"/></svg><span class="sp-item-label">Connect AI model</span></button>
<div class="sp-item text-size-row"><span class="sp-item-label">Text size</span><span class="text-size-group" id="textSizeGroup"><button data-size="small" onclick="setTextSize('small')" title="Small">S</button><button data-size="medium" onclick="setTextSize('medium')" title="Medium">M</button><button data-size="large" onclick="setTextSize('large')" title="Large">L</button></span></div>
<div class="sp-divider"></div>
<button class="sp-item" onclick="lockSession()" style="color:var(--danger)"><svg class="ico" viewBox="0 0 24 24"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0110 0v4"/></svg><span class="sp-item-label">Lock Session</span></button>
</div>
Expand Down Expand Up @@ -953,6 +959,18 @@ <h2>MENU</h2>
function _ssDel(k){try{sessionStorage.removeItem(k)}catch(e){}}
</script>
<script>
/* Text size: small / medium / large. Default MEDIUM (1.15x) — the 14px base was
reported too small in the native app window. `zoom` scales every px-sized
rule on the page in one move, which a font-size variable alone would not.
Shared across surfaces via localStorage + the storage event. */
var _TEXT_SIZES={small:1,medium:1.15,large:1.3};
function _textSize(){var v=_lsGet('codec-text-size');return (v in _TEXT_SIZES)?v:'medium'}
function applyTextSize(){document.documentElement.style.zoom=String(_TEXT_SIZES[_textSize()]);var g=document.getElementById('textSizeGroup');if(g){Array.prototype.forEach.call(g.querySelectorAll('button'),function(b){b.classList.toggle('sel',b.getAttribute('data-size')===_textSize())})}}
function setTextSize(s){if(!(s in _TEXT_SIZES))return;_lsSet('codec-text-size',s);applyTextSize()}
window.addEventListener('storage',function(e){if(e.key==='codec-text-size')applyTextSize()});
applyTextSize();
</script>
<script>
// Side panel open/close
function openSidePanel(){document.getElementById('sidePanel').classList.add('open');document.getElementById('sidePanelOverlay').classList.add('open');if(typeof refreshWakeState==='function')refreshWakeState()}
function closeSidePanel(){document.getElementById('sidePanel').classList.remove('open');document.getElementById('sidePanelOverlay').classList.remove('open')}
Expand Down
12 changes: 12 additions & 0 deletions codec_tasks.html
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,18 @@ <h2 style="font-size:16px; font-weight:600;">Task Reports</h2>
function _ssDel(k){try{sessionStorage.removeItem(k)}catch(e){}}
</script>
<script>
/* Text size: small / medium / large. Default MEDIUM (1.15x) — the 14px base was
reported too small in the native app window. `zoom` scales every px-sized
rule on the page in one move, which a font-size variable alone would not.
Shared across surfaces via localStorage + the storage event. */
var _TEXT_SIZES={small:1,medium:1.15,large:1.3};
function _textSize(){var v=_lsGet('codec-text-size');return (v in _TEXT_SIZES)?v:'medium'}
function applyTextSize(){document.documentElement.style.zoom=String(_TEXT_SIZES[_textSize()]);var g=document.getElementById('textSizeGroup');if(g){Array.prototype.forEach.call(g.querySelectorAll('button'),function(b){b.classList.toggle('sel',b.getAttribute('data-size')===_textSize())})}}
function setTextSize(s){if(!(s in _TEXT_SIZES))return;_lsSet('codec-text-size',s);applyTextSize()}
window.addEventListener('storage',function(e){if(e.key==='codec-text-size')applyTextSize()});
applyTextSize();
</script>
<script>
function openSidePanel(){document.getElementById('sidePanel').classList.add('open');document.getElementById('sidePanelOverlay').classList.add('open')}
function closeSidePanel(){document.getElementById('sidePanel').classList.remove('open');document.getElementById('sidePanelOverlay').classList.remove('open')}
// Auth + CSRF: inject session token and CSRF header on all requests
Expand Down
12 changes: 12 additions & 0 deletions codec_vibe.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@
function _ssSet(k,v){try{sessionStorage.setItem(k,v)}catch(e){}}
function _ssDel(k){try{sessionStorage.removeItem(k)}catch(e){}}
</script>
<script>
/* Text size: small / medium / large. Default MEDIUM (1.15x) — the 14px base was
reported too small in the native app window. `zoom` scales every px-sized
rule on the page in one move, which a font-size variable alone would not.
Shared across surfaces via localStorage + the storage event. */
var _TEXT_SIZES={small:1,medium:1.15,large:1.3};
function _textSize(){var v=_lsGet('codec-text-size');return (v in _TEXT_SIZES)?v:'medium'}
function applyTextSize(){document.documentElement.style.zoom=String(_TEXT_SIZES[_textSize()]);var g=document.getElementById('textSizeGroup');if(g){Array.prototype.forEach.call(g.querySelectorAll('button'),function(b){b.classList.toggle('sel',b.getAttribute('data-size')===_textSize())})}}
function setTextSize(s){if(!(s in _TEXT_SIZES))return;_lsSet('codec-text-size',s);applyTextSize()}
window.addEventListener('storage',function(e){if(e.key==='codec-text-size')applyTextSize()});
applyTextSize();
</script>
<script crossorigin="anonymous" src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.8/purify.min.js"></script>
<style>
:root {
Expand Down
12 changes: 12 additions & 0 deletions codec_voice.html
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,18 @@ <h1><a href="/" style="color:inherit;text-decoration:none">CODEC</a></h1>
function _ssSet(k,v){try{sessionStorage.setItem(k,v)}catch(e){}}
function _ssDel(k){try{sessionStorage.removeItem(k)}catch(e){}}
</script>
<script>
/* Text size: small / medium / large. Default MEDIUM (1.15x) — the 14px base was
reported too small in the native app window. `zoom` scales every px-sized
rule on the page in one move, which a font-size variable alone would not.
Shared across surfaces via localStorage + the storage event. */
var _TEXT_SIZES={small:1,medium:1.15,large:1.3};
function _textSize(){var v=_lsGet('codec-text-size');return (v in _TEXT_SIZES)?v:'medium'}
function applyTextSize(){document.documentElement.style.zoom=String(_TEXT_SIZES[_textSize()]);var g=document.getElementById('textSizeGroup');if(g){Array.prototype.forEach.call(g.querySelectorAll('button'),function(b){b.classList.toggle('sel',b.getAttribute('data-size')===_textSize())})}}
function setTextSize(s){if(!(s in _TEXT_SIZES))return;_lsSet('codec-text-size',s);applyTextSize()}
window.addEventListener('storage',function(e){if(e.key==='codec-text-size')applyTextSize()});
applyTextSize();
</script>
<script>
function openSidePanel(){document.getElementById('sidePanel').classList.add('open');document.getElementById('sidePanelOverlay').classList.add('open')}
function closeSidePanel(){document.getElementById('sidePanel').classList.remove('open');document.getElementById('sidePanelOverlay').classList.remove('open')}
Expand Down
40 changes: 40 additions & 0 deletions tests/test_text_size.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""Text size is adjustable on every surface and defaults to medium.

Reported 2026-09-04: "the size of the text on the CODEC app is too small". The
fix scales the whole page rather than one font variable, because the surfaces
are px-sized throughout and a font-size change alone leaves buttons, inputs and
icons at the old size.
"""
from __future__ import annotations

import re
from pathlib import Path

import pytest

REPO = Path(__file__).resolve().parent.parent
SURFACES = sorted(REPO.glob("codec_*.html"))


@pytest.mark.parametrize("path", SURFACES, ids=lambda p: p.name)
def test_every_surface_applies_text_size(path: Path):
s = path.read_text()
assert "codec-text-size" in s, f"{path.name} ignores the text-size setting"
assert "applyTextSize();" in s, f"{path.name} never applies it on load"
# Default must be medium, and medium must be larger than 1.0 — that is the fix.
m = re.search(r"_TEXT_SIZES=\{small:([\d.]+),medium:([\d.]+),large:([\d.]+)\}", s)
assert m, f"{path.name}: size map missing"
small, medium, large = map(float, m.groups())
assert small < medium < large
assert medium > 1.0, "medium must enlarge the page — that is the whole point"
assert "?v:'medium'" in s, f"{path.name}: default is not medium"
# Storage access must go through the shim — it throws when blocked.
assert "_lsGet('codec-text-size')" in s and "_lsSet('codec-text-size'" in s


def test_control_exists_where_users_look():
for name in ("codec_dashboard.html", "codec_chat.html"):
s = (REPO / name).read_text()
assert 'id="textSizeGroup"' in s, f"{name} has no text-size control"
for size in ("small", "medium", "large"):
assert f"setTextSize('{size}')" in s, f"{name}: no {size} button"