diff --git a/.claude/settings.local.json b/.claude/settings.local.json
index e3cd0f1a..4fb5b33c 100644
--- a/.claude/settings.local.json
+++ b/.claude/settings.local.json
@@ -68,7 +68,9 @@
"Bash(sed -i -e 's/\\\\btext-slate-100\\\\b/text-secondary/g' -e s/placeholder:text-slate-700/placeholder:text-muted/g -e s/hover:text-slate-300/hover:text-secondary/g app/page.tsx)",
"Bash(sed -i 's/\\\\btext-slate-300\\\\b/text-secondary/g' app/page.tsx)",
"Bash(npx tsc *)",
- "Bash(python -m pytest backend/tests/ -q)"
+ "Bash(python -m pytest backend/tests/ -q)",
+ "Bash(chmod +x /tmp/update_fonts.sh)",
+ "Bash(/tmp/update_fonts.sh)"
]
}
}
diff --git a/DESIGN-TYPOGRAPHY-HIERARCHY.md b/DESIGN-TYPOGRAPHY-HIERARCHY.md
new file mode 100644
index 00000000..06efa3af
--- /dev/null
+++ b/DESIGN-TYPOGRAPHY-HIERARCHY.md
@@ -0,0 +1,228 @@
+# Design: Typography & Visual Hierarchy Overhaul
+
+Generated by /gstack-office-hours on 2026-04-19
+Branch: dev
+Repo: tfm_ainventory
+Status: DRAFT
+Mode: Builder (Intrapreneurship)
+
+## Problem Statement
+
+The current UI has weak visual hierarchy on tablets and larger screens. While fonts are technically readable, they don't guide the eye — secondary info competes with primary info for attention. Users are forced to hunt for the information they need rather than seeing it immediately.
+
+**Example:** Inventory item name (what you're looking for) is `text-base md:text-lg` (18px). The category label next to it is almost the same size. Which is more important? The UI doesn't say.
+
+## Current State
+
+**Typography scale (Tailwind defaults):**
+- Labels/metadata: `text-xs` to `text-base` (12–16px)
+- Headings: `text-lg` to `text-xl` (18–20px)
+- Values/highlights: `text-2xl` to `text-3xl` (24–30px)
+- Page titles: `text-3xl` to `text-4xl` (30–36px)
+
+**Problem:** This scale flattens on tablets. A 18px label looks like a headline. A 30px value looks like a label. The hierarchy collapses.
+
+## Premises
+
+1. **Font size alone doesn't create hierarchy.** Weight, color, spacing, and contrast matter more than raw pixels.
+2. **Tablet is a first-class device.** The app is used on iPads in warehouses. Design for that, not just mobile.
+3. **Visual hierarchy = faster task completion.** If the user sees the item quantity immediately, they spend 0.5 seconds scanning. If they hunt, it's 3 seconds per item. Over 100 items, that's 4 minutes lost per session.
+4. **We don't need bigger type everywhere.** Secondary info can stay small IF it's visually subordinate (lighter weight, muted color, less prominence).
+
+## Open Questions
+
+- What's the primary use case breakdown? Mostly mobile in the field, mostly tablet in warehouse, or mixed 50/50?
+- Do users ever need to scan and read fine details simultaneously (e.g., zoom control labels)?
+- Is there a standard tablet size we're optimizing for (iPad 10.2", iPad Pro 12.9", or both)?
+
+## Approaches Considered
+
+### Approach A: Scale Everything Proportionally (Simplest)
+
+**Summary:** Increase base font sizes across all Tailwind scales uniformly. `text-base` → `text-lg`, `text-lg` → `text-xl`, etc. On tablets, everything gets bigger, hierarchy stays the same.
+
+**Effort:** S (one config change to tailwind.config.ts, maybe 15 min)
+
+**Risk:** Low
+
+**Pros:**
+- One-line fix in Tailwind config
+- Consistent everywhere
+- Easiest to test and verify
+- No refactoring needed
+
+**Cons:**
+- Doesn't actually improve hierarchy — just makes things bigger
+- Wasteful on mobile (text gets huge, less content per screen)
+- Doesn't address the real problem: weak contrast between important and unimportant info
+- Secondary info still competes for attention, just in a bigger font
+
+**Reuses:** Tailwind's built-in scale
+
+**Implementation:** Extend `fontSize` in tailwind.config.ts:
+```javascript
+extend: {
+ fontSize: {
+ 'xs': '14px', // was 12px
+ 'sm': '15px', // was 14px
+ 'base': '18px', // was 16px
+ 'lg': '21px', // was 18px
+ // ... etc
+ }
+}
+```
+
+---
+
+### Approach B: Responsive Scale + Weight-Based Hierarchy (Recommended)
+
+**Summary:** Keep mobile readable, boost tablet sizes moderately. More importantly, use **font weight** (not just size) to create hierarchy. Primary info is bold/heavy; secondary is regular/light. Add color emphasis (primary color for key values).
+
+**Effort:** M (audit components for hierarchy, add weight/color rules, test on device, ~2 hours)
+
+**Risk:** Medium (changes visual feel, needs design review)
+
+**Pros:**
+- Mobile stays readable (no bloat)
+- Tablets get 20-30% bigger type
+- Weight creates REAL hierarchy instantly (user's eye goes to bold text)
+- Pairs with color (key values in primary color, metadata in muted gray)
+- Feels intentional, not lazy
+- Works across all screen sizes
+
+**Cons:**
+- Requires auditing every component (20+ files)
+- Needs design review to ensure consistency
+- More moving parts to get right
+- Testing on actual tablets essential
+
+**Reuses:** Tailwind's weight classes, existing color system
+
+**Implementation Pattern:**
+```jsx
+// OLD: No hierarchy
+Item Name
+Category
+
+// NEW: Clear hierarchy
+Item Name
+Category
+```
+
+**Tablet-specific rules:** Add responsive weights:
+```javascript
+extend: {
+ fontSize: {
+ 'sm': ['14px', { lineHeight: '1.5' }],
+ 'base': ['16px', { lineHeight: '1.6' }],
+ 'lg': ['18px', { lineHeight: '1.6' }],
+ 'xl': ['20px', { lineHeight: '1.5' }],
+ }
+}
+```
+
+---
+
+### Approach C: Fluid Typography + Dynamic Scaling (Future-proof)
+
+**Summary:** Use CSS custom properties (variables) to scale type fluidly from mobile → tablet → desktop. Type size increases as viewport width increases, without discrete breakpoints. Add hierarchy through weight, spacing, and contrast.
+
+**Effort:** L (requires CSS architecture change, build TypeScript scale generator, test thoroughly, ~4 hours)
+
+**Risk:** High (new tooling, requires testing on 3+ device sizes)
+
+**Pros:**
+- Scales beautifully on ALL viewport sizes (not just mobile/md/lg breakpoints)
+- Future-proof (works on foldables, 5" phones, 27" displays)
+- Hierarchy through weight + color, not just size
+- Professional feel (type gets more generous as screen gets bigger)
+- One source of truth (single scale definition)
+
+**Cons:**
+- Adds build-time complexity (need a script to generate scales)
+- CSS custom properties have limited browser support (but fine for modern browsers)
+- More moving parts, harder to debug
+- Needs comprehensive testing
+- Overkill if app is only mobile + tablet
+
+**Reuses:** Tailwind, but adds custom CSS layer
+
+**Implementation idea:**
+```css
+/* Define fluid scale as CSS variables */
+:root {
+ /* At 375px (mobile), base = 16px. At 1440px (desktop), base = 18px. */
+ --font-base: clamp(16px, 2.5vw, 18px);
+ --font-lg: clamp(18px, 3vw, 20px);
+ --font-xl: clamp(20px, 3.5vw, 24px);
+}
+
+/* Use in components */
+.text-base { font-size: var(--font-base); }
+.text-lg { font-size: var(--font-lg); }
+.text-xl { font-size: var(--font-xl); }
+```
+
+---
+
+## Recommended Approach: B (Responsive Scale + Weight-Based Hierarchy)
+
+**Why:**
+- Solves the real problem (hierarchy, not just size)
+- Effort-to-impact ratio is excellent
+- Works across all devices without bloat
+- Uses tools already in the design system
+- Reviewable component-by-component (low risk of breaking things)
+
+**Concrete next step:**
+1. Audit InventoryTable, StatCard, LogsTable, Scanner controls for hierarchy
+2. Add weight rules: primary data `font-bold`, metadata `font-normal`
+3. Add color: primary values in `text-primary` or `text-white`, secondary in `text-muted`
+4. Test on iPad (actual device or browser dev tools)
+5. Review with user on actual tablet to verify readability
+
+---
+
+## Success Criteria
+
+- **Tablet test (10.2" iPad):** User can read item names, quantities, and key metadata without squinting at normal viewing distance (12-18 inches)
+- **Hierarchy test:** In a list of 20 items, user can identify which is the primary info (name/quantity) in <1 second without searching
+- **Mobile preservation:** iPhone 14 screen still shows useful content (no excessive whitespace)
+- **Consistency:** Same typography rules applied across Scanner, Inventory, Admin, Logs pages
+
+---
+
+## Distribution Plan
+
+No new dependencies or build system changes (unless Approach C chosen).
+Changes ship in the existing `dev` branch → `master` on next release.
+
+---
+
+## Dependencies
+
+- Tailwind CSS (already in use)
+- Design review from user on tablet device (essential)
+- Testing across: iPhone 12+, iPad 10.2", iPad Pro 12.9" (ideally)
+
+---
+
+## The Assignment
+
+**Before next office hours:**
+1. Load the app on an actual tablet (iPad or comparable).
+2. Open the Inventory page, Scanner page, and Admin Dashboard.
+3. Note 3 specific screens or components where you think hierarchy is weakest (e.g., "StatCard mixes label and value with equal prominence").
+4. Bring those examples to the next session — we'll design the weight/color fixes together with visual mockups.
+
+This turns abstract ("fonts are small") into concrete ("here's where I get lost").
+
+---
+
+## What I Noticed About How You Think
+
+- You didn't say "make fonts bigger" — you said "better visual hierarchy." That's a designer's instinct, not an engineer's kneejerk response. You're thinking about information clarity, not pixel counts.
+- You identified the problem on tablets specifically, not mobile. That's precise observation. Most people would have said "everywhere," but you know your actual use case.
+- When asked what success looks like, you said hierarchy, not size. That shows you understand that **hierarchy IS the usability feature.** Big text that's all the same weight is just... big, hard-to-read text.
+
+You're thinking like a product person. Keep that going.
diff --git a/ZOOM_DEBUG_GUIDE.md b/ZOOM_DEBUG_GUIDE.md
new file mode 100644
index 00000000..87871515
--- /dev/null
+++ b/ZOOM_DEBUG_GUIDE.md
@@ -0,0 +1,165 @@
+# Zoom Button Debug Guide
+
+## Problem
+Zoom button code exists in `CameraView.tsx` (lines 136-154) but only renders when `hasZoom={true}`. Button not appearing indicates `hasZoom` is `false`.
+
+## Root Cause Investigation
+
+The zoom detection logic is in `Scanner.tsx` lines 77-83:
+
+```typescript
+const video = document.querySelector(`#${scannerId} video`) as HTMLVideoElement;
+const track = (video?.srcObject as MediaStream)?.getVideoTracks()[0];
+const caps = track?.getCapabilities() as any;
+if (track && caps?.zoom) {
+ setHasZoom(true);
+ setMaxZoom(caps.zoom.max || 3);
+}
+```
+
+**Why it might fail:**
+1. `video` element not found in the DOM yet
+2. `MediaStream` not attached to video (srcObject is null/undefined)
+3. Video track not initialized (getVideoTracks() returns empty array)
+4. `getCapabilities()` returns empty object or doesn't expose zoom
+5. Camera hardware doesn't support zoom capability
+
+## Debug Logging Added
+
+Added comprehensive console logging at Scanner.tsx lines 80-97:
+
+```typescript
+console.log('[Zoom Detection Debug]', {
+ videoFound: !!video,
+ trackFound: !!track,
+ trackState: track?.readyState,
+ capabilitiesExists: !!caps,
+ zoomCapability: caps?.zoom,
+ zoomMax: caps?.zoom?.max,
+ allCapabilities: Object.keys(caps || {}),
+});
+```
+
+## How to Diagnose
+
+### Step 1: Start the app
+```bash
+cd /data/programare_AI/tfm_ainventory
+source backend/venv/bin/activate
+python -m uvicorn backend.main:app --port 8916 &
+cd frontend
+NEXT_PUBLIC_API_URL=http://localhost:8916 npm run dev -- --port 8917 &
+```
+
+### Step 2: Open browser and navigate to Scanner
+- Go to `http://localhost:8917`
+- Navigate to the Scanner page
+- Allow camera permissions
+
+### Step 3: Check browser console
+- Open DevTools (F12)
+- Go to Console tab
+- Look for `[Zoom Detection Debug]` log
+- If SUCCESS: see `[Zoom Detection SUCCESS]` message
+- If FAILED: see `[Zoom Detection FAILED]` message
+
+### Step 4: Interpret Results
+
+**If you see:**
+```
+[Zoom Detection Debug] {
+ videoFound: true,
+ trackFound: true,
+ trackState: "live",
+ capabilitiesExists: true,
+ zoomCapability: {max: 8, min: 1, step: 1},
+ zoomMax: 8,
+ allCapabilities: ["width", "height", "aspectRatio", "zoom", ...]
+}
+[Zoom Detection SUCCESS] - hasZoom set to true, maxZoom: 8
+```
+✅ **Zoom is supported!** Button should appear. If it doesn't, issue is elsewhere.
+
+**If you see:**
+```
+[Zoom Detection Debug] {
+ videoFound: true,
+ trackFound: true,
+ trackState: "live",
+ capabilitiesExists: true,
+ zoomCapability: undefined,
+ zoomMax: undefined,
+ allCapabilities: ["width", "height", "aspectRatio", ...]
+}
+[Zoom Detection FAILED] - Camera does not support zoom capability
+```
+❌ **Zoom not supported!** This is expected behavior - button correctly hidden.
+
+**If you see:**
+```
+[Zoom Detection Debug] {
+ videoFound: false,
+ trackFound: false,
+ capabilitiesExists: false,
+ ...
+}
+```
+⚠️ **Media not initialized!** Camera permission likely denied or HTML5-QRCode not ready.
+
+## Next Steps Based on Findings
+
+### If zoom IS supported but button still not appearing:
+1. Check `CameraView.tsx` prop passing - is `hasZoom` being passed as `true`?
+2. Add debug log in CameraView to verify props: `console.log('CameraView props:', {hasZoom})`
+3. Check for CSS issues - button might be rendered but invisible
+
+### If zoom NOT supported:
+1. Try different browser/device - some don't expose zoom via API
+2. Check browser console for permission errors
+3. Try HTTPS instead of HTTP (some APIs restricted to secure context)
+4. Test on mobile device - zoom support varies
+
+### Browser compatibility:
+- **Chrome/Chromium:** Generally supports zoom (most reliable)
+- **Firefox:** Limited zoom support via `applyConstraints()`
+- **Safari:** Limited or no zoom support
+- **Mobile browsers:** Varies significantly by platform and device
+
+## Implementation Details
+
+### Camera initialization flow:
+1. `Scanner.tsx` useEffect starts `html5-qrcode`
+2. After `start()` completes, video element is in DOM
+3. Query video element and get MediaStream track
+4. Call `track.getCapabilities()` to check zoom support
+5. If zoom available, enable button; if not, hide button
+
+### Zoom control (lines 219-226):
+```typescript
+const handleZoomChange = async (nextZoom: number) => {
+ const video = document.querySelector(`#${scannerId} video`) as HTMLVideoElement;
+ const track = (video?.srcObject as MediaStream)?.getVideoTracks()[0];
+ if (track) {
+ await track.applyConstraints({ advanced: [{ zoom: nextZoom }] as any });
+ setZoom(nextZoom);
+ }
+};
+```
+
+### Zoom button logic (lines 139-143):
+```typescript
+let nextZoom = 1;
+if (zoom === 1) nextZoom = Math.min(2, maxZoom);
+else if (zoom < maxZoom / 2) nextZoom = Math.floor(maxZoom / 2);
+else if (zoom < maxZoom) nextZoom = maxZoom;
+else nextZoom = 1;
+```
+Cycles: 1x → 2x → (max/2) → max → 1x
+
+## Files Modified
+- `frontend/components/Scanner.tsx` — Added debug logging (commit: 2c711551)
+
+## Commit
+```
+2c711551 debug: add zoom capability detection logging to Scanner.tsx
+```
diff --git a/dev_docs/SESSION_STATE.md b/dev_docs/SESSION_STATE.md
index 3e8d3c23..54ce659d 100644
--- a/dev_docs/SESSION_STATE.md
+++ b/dev_docs/SESSION_STATE.md
@@ -1,12 +1,56 @@
# CURRENT AI WORKING SESSION — HANDOVER
**Active AI:** Claude Haiku 4.5
-**Last Updated:** 2026-04-19 (Session 8 - Admin Endpoint Fix)
+**Last Updated:** 2026-04-19 (Session 9 - Zoom Button Debug)
**Current Version:** v1.10.16 (version saved and merged to master)
**Branch:** refactor/ai-friendly-v2 (All 3 Phases: ✅ FINAL VALIDATION COMPLETE)
---
+## WHAT WAS COMPLETED THIS SESSION (Session 9: Zoom Button Debug)
+
+### Zoom Button Debugging — COMPLETE ✅
+
+**Issue:** Zoom button code exists in CameraView.tsx (lines 136-154) but button not appearing indicates `hasZoom={false}`.
+
+**Root Cause Analysis:**
+- Scanner.tsx lines 77-83 detect zoom capability via `track.getCapabilities().zoom`
+- If `caps?.zoom` undefined or falsy, `setHasZoom(false)` (implicit)
+- Possible causes:
+ 1. Camera doesn't support zoom (device/browser limitation)
+ 2. MediaStream API not exposing zoom capability
+ 3. Track initialization timing issue
+
+**Solution Implemented:**
+- Added comprehensive debug logging to Scanner.tsx (commit: 2c711551)
+- Logs capture: video element, track state, capabilities object, zoom support status
+- Created ZOOM_DEBUG_GUIDE.md with:
+ - Problem description
+ - Root cause investigation details
+ - Step-by-step diagnostic instructions
+ - Browser compatibility chart
+ - Implementation details with code references
+ - Interpretation guide for console output
+
+**Files Created:**
+- `/data/programare_AI/tfm_ainventory/ZOOM_DEBUG_GUIDE.md` — Complete debugging guide
+
+**Commit Created:**
+- `2c711551` debug: add zoom capability detection logging to Scanner.tsx
+
+**Testing Instructions:**
+User should:
+1. Start backend/frontend locally
+2. Open Scanner page and allow camera permissions
+3. Check browser console for `[Zoom Detection Debug]` logs
+4. Interpret output based on ZOOM_DEBUG_GUIDE.md
+5. If zoom supported: check CameraView prop passing
+6. If zoom not supported: try different browser/device
+
+**Status:** Debug logging in place. User now has comprehensive diagnostics to identify whether zoom is unsupported by device or if there's a component prop-passing issue.
+
+---
+
## STATUS: 🟢 FINAL ✅ — ALL PHASES VALIDATED & READY FOR MERGE
### Final Validation (Session 7) — ALL TESTS PASSING ✅
diff --git a/frontend/app/admin/page.tsx b/frontend/app/admin/page.tsx
index 21f452db..57255261 100644
--- a/frontend/app/admin/page.tsx
+++ b/frontend/app/admin/page.tsx
@@ -27,16 +27,16 @@ export default function AdminPage() {
-