Problem: on the iPad the Safari URL bar stayed visible even after
"Add to Home Screen" because index.html had no PWA manifest and no
Apple PWA meta tags — the home-screen icon opened a normal Safari tab.
Changes:
- New `artifacts/tx-os/public/manifest.webmanifest`:
name/short_name "Tx OS", start_url "/", scope "/",
display "standalone", background_color and theme_color "#0B1E3F"
(matches the Meetings brand), and 3 icons (192/512 "any" + 512
"maskable" with safe-area padding).
- Generated icon PNGs from the existing `public/favicon.svg` brand
mark via ImageMagick:
public/icons/icon-192.png (192x192)
public/icons/icon-512.png (512x512)
public/icons/icon-maskable-512.png (512x512, 360x360 logo
centered on #0B1E3F so iOS/
Android masks don't crop)
public/apple-touch-icon.png (180x180, iPad/iPhone home)
- `artifacts/tx-os/index.html` head: added <link rel="manifest">,
<link rel="apple-touch-icon">, plus apple-mobile-web-app-capable,
mobile-web-app-capable, apple-mobile-web-app-status-bar-style
(default), apple-mobile-web-app-title, and theme-color meta tags.
- `replit.md`: new "iPad / iPhone — open Tx OS full-screen" section
with the one-time Add-to-Home-Screen steps and the gotcha that
pre-existing shortcuts must be removed and re-added to pick up the
manifest.
Verified: dev server returns 200 for /manifest.webmanifest,
/apple-touch-icon.png, and /icons/icon-192.png. The new files all
live under public/ so they're copied verbatim into the nginx image
on the next docker build.
Task #476. On iPad Safari, opening the keyboard while writing a new
note or replying inside the note thread dialog covered the bottom of
the dialog (textarea + send button). The dialog used
`top:50%; translate(-50%,-50%)` against the layout viewport and never
reacted to the visual viewport shrinking when the keyboard appeared.
Changes:
- artifacts/tx-os/index.html: added `interactive-widget=resizes-content`
to the viewport meta so iOS 17+ resizes the layout viewport when the
software keyboard opens.
- artifacts/tx-os/src/hooks/use-visual-viewport.ts: new hook that
subscribes to `window.visualViewport` `resize` / `scroll` /
`orientationchange` events (rAF-throttled) and exposes the current
visible height plus the bottom keyboard inset.
- artifacts/tx-os/src/components/ui/dialog.tsx: `DialogContent` now
reads the hook and, when the keyboard inset is non-trivial (> 80px),
pins its center to the visible viewport mid-line and caps
`max-height` to the visible height. Desktop renders unchanged
(inset is 0 → no inline style applied beyond what the caller passes).
- artifacts/tx-os/src/pages/notes.tsx: the thread dialog reply
textarea and the top composer textarea now `scrollIntoView({ block:
"center" })` on focus (after a 250ms delay so the keyboard animation
settles), so the cursor lands inside the visible region on touch
devices. Desktop focus is unaffected — `scrollIntoView` is a no-op
when the element is already in the viewport.
Verification:
- `tsc --noEmit` clean.
- Existing `notes-thread-dialog` e2e still passes (dialog stays
capped at 85% viewport height, scroller still overflows, recipient
chips and composer remain in viewport).
Update font configurations to exclusively use DIN Next LT Arabic, preload necessary font files, and implement eager font loading to prevent display issues during printing.
Preload DIN Next LT Arabic and Tajawal fonts in index.html and adjust the print CSS font stack to ensure correct Arabic character shaping in print mode.
User report: "the dropdown for changing the site font does not work."
Root cause: FontSettingsSection listed Cairo / Tajawal / Noto Naskh
Arabic / Amiri, but only Tajawal had been registered with @font-face.
Picking the others was a no-op. Site default body font was also not
DIN Next LT Arabic as designed.
Changes:
- artifacts/tx-os/src/index.css: --app-font-sans now starts with
"DIN Next LT Arabic"; dropped IBM Plex Mono.
- artifacts/tx-os/index.html: removed Google Fonts <link> + preconnect.
- artifacts/tx-os/src/pages/executive-meetings.tsx: FontSettingsSection
dropdown replaced with the 5 actually-bundled families + system.
- artifacts/api-server/src/routes/executive-meetings.ts: FONT_FAMILIES
Zod allowlist updated to match.
- artifacts/api-server/src/lib/sanitize.ts: FONT_NAME_PART regex now
allows the new families (kept IBM Plex Sans Arabic for backward
compat). Fixes a latent bug from #301 where the rich-text sanitizer
silently stripped attendee font picks on save.
- artifacts/api-server/src/lib/pdf-renderer.ts: FAMILY_MAP and
ARABIC_FONT_NAMES updated. Sans-style families map to the bundled
NotoSansArabic; Naskh-style families to NotoNaskhArabic.
- artifacts/api-server/tests/executive-meetings.test.mjs: PDF
sans-vs-naskh assertion updated from Cairo/Noto Naskh Arabic to
DIN Next LT Arabic/Majalla, preserving its semantics. Other
Cairo/Noto Naskh Arabic occurrences swapped to the new names.
- replit.md: documented site default font + lockstep allowlist rule.
Deviations from plan: kept DEFAULT_FONT.fontFamily = "system" on the
frontend (and the backend Zod default) instead of changing it to
"DIN Next LT Arabic". "system" semantically means "no override → use
the CSS default", which is now DIN Next LT Arabic — same end result
without forcing a migration on existing rows. The sanitizer change
was not in the original plan but was required to make the picker
actually persist.
Verification:
- Frontend tsc clean.
- Backend tsc shows the same pre-existing unrelated errors as before
(isHighlighted boolean/number; Drizzle scope typing).
- E2E browser test verified all 7 assertions: site default font,
no Google Fonts requests, exactly 6 dropdown options, font picker
applies + reverts correctly, attendee font picks persist after save.
- Code review verdict: PASS.
Reverts the phone-only stacked-card layout introduced in Task #119
back to a single tidy table for every viewport, and re-enables
pinch-zoom on the whole app.
Changes:
- artifacts/tx-os/index.html: viewport meta no longer pins
maximum-scale=1, so iOS/Android pinch gestures work everywhere
(now: width=device-width, initial-scale=1).
- artifacts/tx-os/src/pages/executive-meetings.tsx:
* Removed the md:hidden cards branch (the entire em-schedule-cards
block) so the table is the only schedule view at every width.
* Dropped the `hidden md:block print:block` gating on the table
container; it now renders at all viewports inside the existing
overflow-x-auto wrapper, so a too-wide table scrolls horizontally
inside its own container instead of breaking the page layout.
* Deleted the now-orphaned MeetingCard component and its only
consumer of the inline-only RowColorPickerInline variant.
* Deleted RowColorPickerInline (no remaining consumer); the hover
RowColorPicker is still used by table rows.
Preserved:
- Desktop (≥xl) fixed-width + resizable column behavior is unchanged
(table-fixed at xl, resize handles still mouse-only).
- Print fixed-layout behavior (`print:table-fixed`) and RTL support
are unchanged.
- Localized labels for the customizer/highlight popover are unchanged.
Verification:
- pnpm --filter @workspace/tx-os exec tsc --noEmit shows no new
errors in executive-meetings.tsx (pre-existing admin.tsx errors
from the just-merged Task #96 codegen drift are unrelated).
- The table renders at 390 / 768 / 1280 px widths; horizontal scroll
appears only when the table is wider than the container.
Out of scope (per task spec):
- Print/PDF page (executive-meetings-print.tsx) — Task #120.
- API, schema, columns, or RBAC — none changed.