# Tawaaf — Site Review & Recommendations

**Date:** 2026-05-18 (initial) · updated 2026-05-19 (privacy work shipped, UI/UX review added, phasing revised)
**Scope:** Full code, UI, UX, content review + Hajj 2024-2026 research
**Purpose:** Comprehensive list of ideas to review together before any code changes
**Timing context:** Hajj 1447 begins ~25 May 2026 (8 Dhul-Hijjah). Six days away. Anything pilgrim-facing that ships must be ready by ~22 May to allow pilgrims to install before they lose connectivity in Mina.

---

## Where we left off — pick up here next session

**Last touched: 2026-05-20.** Heavy implementation day. As of end-of-session:

**Phase A — DONE.** All 8 items shipped between 2026-05-19 and 2026-05-20 (privacy reconciliation, accessibility fixes, file corruption, .htaccess, Arabic lang/dir, prayer.js refetch, typo, service worker).

**Phase B — 8 of 16 done.** Shipped today: 2.2 Today hub, 2.4 Emergency card, 2.6 Heat & hydration, 2.7 Doubt resolver, 2.8 Talbiyah window timer, 2.9 Wajib/Sunnah chips (pulled forward from Phase C), 2.10 Wheelchair guidance. Plus NEW §2.11 trip-mode picker added per your feedback.

**Deferred — awaiting your mockup review** (you asked to pause on these and review the mockups first):
- **§2.3 Pebble counter (Jamarat)** — mockup at `/mockups/jamarat.html`
- **§2.5 Drop my tent pin** — mockup at `/mockups/tent-pin.html`

**Phase B still pending direction** (your call which to do next):
- **11.** Add 7 missing duas to `/data/duas.json` library (Arafat dua, Multazam, Mash'ar al-Haram, Talbiyah, Istikhārah, Madinah entry, Rukn al-Yamani). Mockup: `/mockups/duas-additions.html`
- **12.** Add "I need water" phrase to Prepare → Phrases. Mockup: `/mockups/prepare-additions.html#water`
- **13.** Add 4 Hajj packing items to Prepare → Packing (cooling towel, mylar blanket, USB-C fan, pebble pouch). Mockup: `/mockups/prepare-additions.html#packing`
- **14.** Ship the prepare-resources mockup (15 sourced links). Mockup: `/mockups/prepare-additions.html#resources`
- **18.** Day-jump pill bar + collapsible accordion on rituals page. Mockup: `/mockups/rituals-improvements.html`
- **22.** Tasreeh / Nusuk permit explainer. Mockup: `/mockups/tasreeh.html`
- **23.** Tahajjud / night mode toggle. Mockup: `/mockups/night-mode.html`

**Open product decisions waiting for you** (no work blocked, but worth deciding):
- Should the Prepare/Rituals tab toggles **sync with the global tripMode**, or stay independent? (Currently independent — see §2.11.)
- Settings screen: when do we want to build one? The gear icon currently opens the trip-mode picker directly; long-term it should open Settings with trip-mode as one row inside.

**Recently-shipped infrastructure** (so you don't re-touch these accidentally):
- `/js/hijri.js` — Hijri date helper, browser-native `Intl.DateTimeFormat`
- `/js/trip-mode.js` — trip-mode helper with localStorage + change event
- `sw.js` at CACHE_VERSION `v3-202605200300` with 29 APP_SHELL entries
- Bottom-nav says "Today" not "Home" across all 10 app pages

---

## Update log

### 2026-05-20 (later) — Phase B items 2.2, 2.4, 2.6, 2.7, 2.8, 2.9, 2.10 shipped + NEW trip-mode picker ✅

Major implementation pass. Seven recommendation-doc items moved from mockup to production, plus one new feature added in response to a UX question that came up during review.

**Shipped:**

- **§2.2 Today hub** (Phase B item 17) — `/app/index.html` rebuilt as Hijri-aware daily-briefing hub. Hijri date in header, talbiyah chip, heat banner, today's-action card that adapts to Hajj day (Tarwiyah/Arafah/Naḥr/Tashreeq), 6 hub tiles, today's recommended dua.
- **§2.4 Emergency card** (Phase B item 9) — `/app/emergency.html`. Green ID-card with localStorage-stored details, inline edit form (auto-opens for first-time users), tel: links for 997/999/998/1966, 5-step lost-passport recovery.
- **§2.6 Heat &amp; hydration** (Phase B item 10) — `/app/heat.html`. Danger window, three-city forecast, ORS reminders, heat-stroke symptoms, walking-distance reality check.
- **§2.7 Doubt resolver** (Phase B item 19) — `/app/doubt.html`. 8 doubt chips (tawaf count, sa'i count, niyyah, wudu, wuquf, talbiyah, stoning, other) each opening a four-madhāhib sourced answer.
- **§2.8 Talbiyah window timer** (Phase B item 20) — header chip on Today, auto-shown during 8–9 Dhul-Ḥijjah for Hajj mode, with manual ihram toggle for Umrah mode.
- **§2.9 Wajib/Sunnah/Custom chips** (was Phase C item 24, moved to B) — 4 distinct status pill colors added to `/app/rituals.html`. All 19 cards reclassified: 6 Rukn (pillars), 9 Wajib (required), 4 Sunnah (recommended). Per-substep labelling is the follow-on editorial pass.
- **§2.10 Wheelchair guidance** (Phase B item 21) — `/app/wheelchair.html`. Validity statement, free wheelchair gates (KAA, 74, Ajyad, Bab al-Salam), upper-Mataf path, Tanaqol pricing, sa'i lane, Arafat/Muzdalifah confirmation.

**NEW: Trip-mode picker (§2.11)** — Added in response to user feedback that the Hijri-aware Today framing only makes sense for Hajj users. Today now opens with a welcome modal asking "What are you here for?" — Umrah / Hajj / Just exploring. The choice persists in `tawaaf:tripMode` localStorage. The Today action card and recommended dua adapt to mode:
- **Hajj** → Hijri-date-driven (existing behaviour)
- **Umrah** → ihram-toggle-driven (chip "Tap when you enter ihram" → "Talbiyah active", action card flips from "make ihram at the miqāt" to "begin tawaaf")
- **Browse** → generic welcome with three CTAs

The gear icon in the header (and a small mode tag next to the wordmark) re-open the picker any time. New file `/js/trip-mode.js` exposes `window.tawaafTripMode` with `get/set/clear/isFirstRun` and a `tawaaf:tripModeChange` event for re-rendering. See §2.11 for the full design rationale.

**Infrastructure:**
- New file `/js/hijri.js` — browser-native `Intl.DateTimeFormat('en-u-ca-islamic-umalqura')` helper. Exposes `today()`, `isInHajjWindow()`, `isTalbiyahWindow()`, `dayOfArafah()`. Zero external dependency.
- Bottom-nav renamed "Home" → "Today" across all 10 app pages.
- `sw.js` bumped to `v3-202605200300` with the new files in APP_SHELL (29 entries total).
- Gear-icon placeholder in the Today header is now wired to the trip-mode picker. The future Settings page (night mode, family share, after-Hajj companion, reading size) is still pending — gear icon's primary action will likely become "open Settings" with trip-mode as one item inside it.

**One linter-truncation incident caught and patched:** `prepare.html` got silently truncated during the bottom-nav rename (~halfway through the IIFE). Caught in the verification pass, restored the missing countdown/tab-toggle/Download-for-Mina logic plus closing tags. Confirms the new "verify after every write" discipline is paying for itself.

### 2026-05-20 — Truncation fix on three app pages (regression)

**Issue:** A pilgrim review surfaced six broken interactions across the app:
1. *Start tawaaf* button on `/app/tawaaf.html` didn't respond
2. *Switch to manual* link on the same page didn't respond
3. Reading-size *Aa* button on `/app/tawaaf.html` was inert
4. Umrah ↔ Hajj toggle on `/app/rituals.html` didn't switch
5. Reading-size *Aa* on `/app/rituals.html` was inert
6. Reading-size *Aa* on `/app/prayer.html` was inert

**Root cause:** the same null-byte / mid-token truncation that hit `contact.html` and `sources.html` earlier had also corrupted three app pages. The breakage was silent because the failures were "JS just doesn't load" rather than visible markup errors:

- `/app/tawaaf.html` ended at line 245 with a dangling `<script` — the closing script tags for `tawaaf-counter.js`, `tawaaf.js`, and `reading-size.js` were missing entirely, along with `</body></html>`.
- `/app/rituals.html` ended at line 1622 mid-statement (`tabUmrah.setA`) — the rest of the IIFE that handles the tab toggle was gone, plus the `reading-size.js` script tag and closing markup.
- `/app/prayer.html` ended at line 229 mid-tag (`</scri`) — the `reading-size.js` tag never closed, so the script never loaded.

**Resolution:** restored the missing tails on all three files. Verified each now closes with `</html>\n`, has no null bytes, carries the right script tags, and that `tawaaf.js` parses cleanly. All six interactions are now wired.

**Why this kept happening — recommend a deploy-time check.** Five files are now known to have suffered the same corruption (`contact`, `sources`, `tawaaf`, `rituals`, `prayer`). The 2026-05-02 review caught the first two but missed the next three because they fail silently. **Add a CI check** in `.github/workflows/` that, before any FTPS push, fails if any `*.html` file:
- contains a null byte (`\x00`), or
- does not end with `</html>` followed by an optional newline.

That single check would have caught every instance and would prevent recurrence.

### 2026-05-20 — Service worker (offline app shell) shipped

Phase A item 8 — biggest functional gap for actual Hajj — is now resolved.

- **Added** `/sw.js` — a service worker that precaches the marketing pages, the app surface, all CSS/JS, `data/duas.json`, brand assets and `manifest.json` on install (25 URLs total). HTML uses network-first with cache fallback; static assets use stale-while-revalidate with query-string-insensitive matching, so `?v=…` cache-busts still resolve to the right precached entry.
- **Added** `/js/sw-register.js` — small registration shim that boots the SW after the `load` event (the canonical pattern, so it doesn't compete with critical page resources) and exposes `window.__tawaafSW.warmCache(onProgress)` for the Download button.
- **Wired** the registration into every production HTML page (11 files) alongside the existing `analytics.js` script tag.
- **Added** a "Download for Mina" card on `/app/prepare.html`, visible on both Umrah and Hajj tabs. Sends a `WARM_CACHE` message to the SW, shows live progress ("Saving 12 of 25…"), persists the saved state in localStorage. The card auto-hides on browsers without SW support so legacy users don't see a broken button.
- **Excluded** `/api/`, `/admin/`, and all cross-origin requests (Aladhan, Nominatim, Google Fonts) from the cache — these must always be fresh or are not ours to cache.
- Cache version is `v1-202605190100`. Bump that constant in `/sw.js` whenever a precached file changes meaningfully — the activate handler deletes any prior cache and re-warms on next navigation.

### 2026-05-19 — Phase A items 1.2–1.7 shipped ✅

Six foundational code/config fixes landed in one session, completing the non-service-worker portion of Phase A:

- **§1.2** — `user-scalable=no` removed from `/app/index.html` and `/app/tawaaf.html` viewport metas (WCAG 1.4.4 — pinch-zoom now works).
- **§1.3** — `contact.html` and `sources.html` re-saved end-to-end: `<\!DOCTYPE` → `<!DOCTYPE`, `</htm` → `</html>`, the escaped `!` in `contact.html`'s inline JS fixed, trailing null bytes stripped.
- **§1.4** — `.htaccess` cleanup: generalized markdown deny (`*.md`), added `RedirectMatch 403` for `scratch/`, `icon-(concepts|preview|review).html`, `GeoLite2-*`, and `mockups/`.
- **§1.5** — 40 Arabic spans site-wide now carry `lang="ar" dir="rtl"`: `.arabic-mark`, `.phrase-ar`, `.rc-ar`, `.dua-ar`, `.d-arabic`, `.cv-kaaba-lbl`, `.kaaba-lbl`, `.compass-kaaba`, `.cs-n` (Arabic-Indic numerals), the inline Harwala parenthetical, the Bismillah specimen, and the dua library template in `js/duas.js`.
- **§1.6** — `prayer.js` refactored: `fullLoad()` + `refreshCountdown()`. Nominatim now called once per session instead of every 60s; Aladhan refetched only on day rollover or method change.
- **§1.7** — `menigngitis` → `meningitis` in `prepare.html` `data-k` attribute.

### 2026-05-19 — Privacy reconciliation shipped

Per the decision to treat current users as test users (no public change to announce):

- **Removed** the policy update banner from `index.html` (the dated banner + its inline-JS trigger). The marketing home now flows straight from `<body>` into `<nav>`.
- **Rewrote** the privacy wording on `privacy.html` to accurately describe what's stored: *"The country and city your IP resolves to (e.g. SA / Makkah, GB / London). No street address, no precise location, no GPS coordinates."* The short-version paragraph and the IP-lookup bullet were updated to match.
- **Removed** the dated April-2026 "Change notice" callout and the historical sentence in the changes-to-policy section that referenced the (now-deleted) homepage announcement.
- **Updated** `api/track.php` to set `$region = null` rather than reading it from the GeoLite2 lookup, with a comment explaining why. The `region` column in the schema is retained for backward compatibility but is always written as NULL going forward.
- **Updated** the privacy page "Last updated" date to 19 May 2026.

This resolves the §1.1 mismatch. The code now matches the promise: country + city, nothing finer.

A follow-up SQL scrub of existing rows (`UPDATE pageviews SET region = NULL`) is optional — to be run through phpMyAdmin when convenient, since none of the existing test-user rows are user-identifying anyway.

---

## How to read this document

Recommendations are grouped by what they're for, not by where they live in the code, so we can discuss them as themes. Each item is tagged with:

- **Severity / Impact:** P0 (urgent / safety / promise-breaking) · P1 (high-impact) · P2 (quality of life) · P3 (nice-to-have)
- **Effort:** S (small, <2h) · M (medium, half-day) · L (large, multi-day)
- **Audience:** *Pilgrim* (used during Hajj/Umrah) · *Marketing* (pre-trip) · *Internal* (code/admin)

Skip ahead to **§10 Suggested phasing** for a prioritized plan if you want the short version.

---

## 1. Critical issues to fix first (still open from 2026-05-02 or newly found)

These are non-negotiable: they affect the site's promise, accessibility, or are simply broken.

### 1.1 PRIVACY PROMISE vs. CODE MISMATCH — RESOLVED 2026-05-19 ✅
~~`api/track.php` stores city/region; `privacy.html` says it doesn't.~~

**Resolution:** The wording on `privacy.html` was updated to accurately reflect that we collect country + city. `api/track.php` was updated to stop populating the `region` column (always writes NULL). The policy update banner on the homepage was removed since the only users so far are test users, and the dated "Change notice" callout on the privacy page was removed for the same reason. See Update log at the top for full details.

### 1.2 `user-scalable=no` on three app pages — RESOLVED 2026-05-19 ✅
~~`/app/index.html`, `/app/tawaaf.html` (and likely others) ship `user-scalable=no` in the viewport meta. Elderly pilgrims with presbyopia literally cannot pinch-zoom.~~

**Resolution:** `user-scalable=no` removed from both viewport meta tags. Pinch-zoom now works app-wide; meets WCAG 1.4.4 (Resize text).

### 1.3 File corruption + `<\!DOCTYPE` typo on `contact.html` and `sources.html` — RESOLVED 2026-05-19 ✅
~~Flagged 2026-05-02. Still ends `</htm` and starts `<\!DOCTYPE html>` (literal backslash).~~

**Resolution:** Both files re-saved end-to-end. `<\!DOCTYPE` → `<!DOCTYPE`, `</htm` → `</html>`, escaped `!` in `contact.html`'s inline JS fixed (`if (\!form)` → `if (!form)`, `json.success \!== false` → `json.success !== false`), trailing null bytes stripped. No more quirks-mode.

### 1.4 Public dev files reachable — RESOLVED 2026-05-19 ✅
~~`icon-concepts.html`, `icon-preview.html`, `icon-review.html` at docroot · `scratch/` folder · `PROJECT-OVERVIEW.md` and similar · `GeoLite2-*` zip · `db/*.sql`.~~

**Resolution:** `.htaccess` updated with a generalized markdown deny (`*.md`) plus `RedirectMatch 403` rules for `scratch/`, `icon-(concepts|preview|review).html`, `GeoLite2-*`, and `mockups/`. All previously-public dev artifacts now return 403.

### 1.5 Arabic text has no `lang="ar"` / `dir="rtl"` — RESOLVED 2026-05-19 ✅
~~Every `.rc-ar`, `.d-arabic`, `.dua-ar`, `.phrase-ar` lacks language attribution. Screen readers either skip them or mispronounce them.~~

**Resolution:** 40 Arabic spans across production files now carry `lang="ar" dir="rtl"`. Covers `.arabic-mark`, `.phrase-ar`, `.rc-ar`, `.dua-ar`, `.d-arabic`, `.cv-kaaba-lbl`, `.kaaba-lbl`, `.compass-kaaba`, `.cs-n` (Arabic-Indic numerals), the inline Harwala parenthetical, the Bismillah specimen on the styleguide, and the dynamically-rendered Arabic in `js/duas.js`. Verified with a Unicode-range audit: 40 OK, 0 missing.

### 1.6 `prayer.js` Nominatim refresh-every-60s — RESOLVED 2026-05-19 ✅
~~`loadData()` re-fetches full prayer times AND reverse-geocodes every 60s. Nominatim's usage policy explicitly forbids "frequent absolute queries".~~

**Resolution:** `prayer.js` refactored into `fullLoad()` (initial location grant, method change, day rollover) and `refreshCountdown()` (lightweight 30s tick that re-renders from cached data, no network). Nominatim is called once per session instead of every 60s. Aladhan refetched only on day rollover or method change. Cache-bust bumped to `v=202605190100`.

### 1.7 The `menigngitis` typo in `prepare.html:215` — RESOLVED 2026-05-19 ✅
~~Was: `data-k="menigngitis"`.~~

**Resolution:** Fixed to `data-k="meningitis"`. One-time reset of that single checkbox for any early user; low impact.

---

## 2. Highest-impact NEW features for Hajj 2026

These directly address the most cited pilgrim pain points from Hajj 2024 and 2025. Ranked by **risk reduction × frequency of pain**.

### 2.1 Service worker / offline app shell — RESOLVED 2026-05-20 ✅
~~Pilgrim opening Tawaaf in a Mina tent at 22:00 currently gets the browser offline screen.~~

**Resolution:** Shipped `/sw.js` and `/js/sw-register.js`. Precaches every production page, every CSS/JS, `data/duas.json`, brand assets, and the marketing info pages (25 entries total). HTML uses network-first with cache fallback; static assets use stale-while-revalidate with `ignoreSearch: true` so versioned URLs (`?v=…`) still match precached unversioned entries. `/api/` and `/admin/` and all cross-origin requests are passed straight through, so personal/auth flows and third-party APIs (Aladhan, Nominatim, Google Fonts) are unaffected.

A "Download for Mina" card was added to `/app/prepare.html`, visible on both the Umrah and Hajj tabs. States: idle → "Saving N of 25…" → "Saved for offline use" (persisted in localStorage so returning users see confirmation) or "Couldn't save — try again". On browsers without service-worker support the card is hidden entirely, so legacy users don't see a broken button.

### 2.2 Hijri-aware "Today" view with one-screen action — RESOLVED 2026-05-20 ✅
**Why:** A pilgrim in Mina at 4am needs ONE screen that says *"Today is 9 Dhul-Hijjah — Get to Arafat by zawal — Combine Dhuhr+Asr at Arafat — Stay until sunset — Pebbles at Muzdalifah after Maghrib."* Currently they have to navigate to rituals → Hajj tab → scroll to find the right day.

**What to ship:** A `/app/today.html` (or just promote the right card on `/app/`) that reads the current Hijri date and surfaces the relevant ritual card with hard-coded sensitive timings ("do NOT leave Arafat before sunset", "stop talbiyah at first pebble"). Display Hijri date in the app header on every page.

### 2.3 Pebble counter (mirror of tawaaf counter) [P1, M, *Pilgrim*]
**Why:** Stoning Jamarat is 21 pebbles across three pillars in 45°C heat with crowd pressure — counting is genuinely hard, and skipping one invalidates the day. This is the most universally-requested missing tool across pilgrim accounts.

**What to ship:** Same compass-style 1-7 counter at `/app/jamarat.html`, with three sub-counts for days 11/12/13 (Sughra → Wusta → Kubra in order) and one-count for day 10 (Aqabah only). Reuse `tawaaf-counter.js`'s engine pattern. Add a visual cue when the order is wrong on days 11-13.

### 2.4 Emergency card screen — RESOLVED 2026-05-20 ✅
**Why:** Getting separated from group in Mina is the single most-cited fear in pilgrim accounts. The pilgrim needs to hand a stranger their phone with everything visible. Currently nothing in the app supports this.

**What to ship:** `/app/emergency.html` with localStorage-stored: hotel name (Arabic + English), group leader phone, country embassy emergency number, languages spoken, blood type, allergies, "I am lost — please call this number" in Arabic. All locally stored, no account. Pre-filled from a one-time form in Prepare. Print-friendly CSS so they can also print a wallet card.

### 2.5 "Drop my tent pin" with offline map preview [P1, M, *Pilgrim*]
**Why:** Mina tents are visually identical and Indonesian House investigators described them as "refugee-camp-like" in 2024. Standard pilgrim advice is "drop a pin in Google Maps the moment you arrive" — but most don't.

**What to ship:** One-tap `navigator.geolocation` save, with a photo upload (stored as local blob URL in IndexedDB) so they can also keep a picture of the tent number / street sign. Optional pre-cached static-tile of Mina (~2 MB) so the pin shows on a recognizable map offline. No backend, no account.

### 2.6 Heat & hydration card — RESOLVED 2026-05-20 ✅
**Why:** 1,300+ pilgrims died in 2024, 83% unauthorized but the same heat physics applied to authorized pilgrims. Lancet documented 2,764 heat-related cases on 16 June 2024 alone.

**What to ship:** A simple `/app/heat.html` or top card showing:
- Today's Makkah/Mina/Arafat forecast (cached, fetched once daily)
- Peak danger window (11am-4pm by default; site reads forecast for the day)
- "Drink now" reminder with ORS guidance
- White umbrella + cooling-towel reminders (the cited single most impactful interventions)
- Heat exhaustion vs heat stroke symptom cards
- Saudi Red Crescent number (997) prominent

### 2.7 Doubt-resolver microflow — RESOLVED 2026-05-20 ✅
**Why:** *"I lost count during tawaf"* is one of the most stressful and most googled Hajj questions, and fatwa sites are inconsistent. Tawaaf is uniquely positioned to surface the calm, sourced answer.

**What to ship:** A single page `/app/doubt.html` with chips: "I lost count during tawaf/sa'i" · "I'm not sure about my niyyah" · "I think I broke my wudu" · "Did I miss talbiyah window?" — each leading to a short card with the four-madhāhib position, citation, and "what to do now". Sourced exactly like the rituals page.

### 2.8 Talbiyah window timer — RESOLVED 2026-05-20 ✅
**Why:** Most pilgrims aren't sure when talbiyah ends. The rule is "stops at first Jamrah al-Aqabah pebble on 10 DH" — but many keep reciting or stop too early.

**What to ship:** A small persistent header chip that shows "Talbiyah active" once they tick "Entered ihram" on Prepare, then fades to "Talbiyah optional" after they tick "First stoning at Aqabah" on the rituals checklist (which doesn't exist yet — needs a small ritual-checklist add).

### 2.9 Wajib / Sunnah / Custom view per ritual — RESOLVED 2026-05-20 ✅ (card-header)
**Why:** First-timers can't distinguish what's required, recommended, or merely cultural. This is the #1 driver of Bid'ah-by-accident.

**What to ship:** On each ritual card add three small chips: green "Rukn/Wajib" · gold "Sunnah/Mustahabb" · gray "Custom" — applied per sub-step within the card. With one-line scholar quotes from across the four schools where they differ.

### 2.10 Wheelchair / accessibility guidance — RESOLVED 2026-05-20 ✅
**Why:** Hajj is increasingly performed by older pilgrims; wheelchair tawaf has a dedicated upper-Mataf path, Tanaqol e-cart booking exists (SAR 57.50-230), and all rituals are valid wheelchair. Most pilgrim accounts say their families didn't know this until arrival.

**What to ship:** A "Pilgrim with limited mobility" card on Prepare and on Rituals → expanding to a short page explaining: free wheelchair locations (KAA Gate, Gate 74, Ajyad), Tanaqol app, upper-level tawaf path, wheelchair sa'i lane, validity of wheelchair Wuquf.

---

### 2.11 Trip-mode picker (Umrah / Hajj / Browse) — RESOLVED 2026-05-20 ✅ (NEW item)

**Why it was added.** Mid-implementation, a UX review surfaced that the Hijri-aware Today hub leaned hard into Hajj and felt generic-to-polite for Umrah users (who outnumber Hajj pilgrims significantly and can perform Umrah any time of year). Inferring trip context from clicks or page visits was rejected as unreliable for browsers; an explicit toggle was the cleaner pattern.

**Design.**

- `tawaaf:tripMode` localStorage key with three valid values: `umrah` / `hajj` / `browse`. Unset = first-time visitor.
- First-run modal: "Welcome to Tawaaf. What are you here for?" with three big tappable buttons. No cancel on first run — they must pick.
- Re-opening the picker: gear icon (⚙) in the Today header and a small mode tag next to the wordmark both open the same modal with a Cancel button, tap-outside-to-close, and the current mode highlighted with a ✓.
- Mode changes fire a `tawaaf:tripModeChange` event so the page re-renders without reload.

**Today rendering per mode:**

| Mode | Action card | Talbiyah chip | Recommended dua |
|---|---|---|---|
| **Hajj** | Hijri-date-driven (Tarwiyah/Arafah/Naḥr/Tashreeq) — same as the §2.2 build. Off-season: "Your Hajj · Plan ahead" with countdown link. | Auto-shows during 8–9 Dhul-Ḥijjah. | Day-of-Arafah dua on 9 DH; talbiyah on 8 / 10–13 DH; fallback otherwise. |
| **Umrah** | Two states based on `tawaaf:ihram` localStorage: (1) Not in ihram — "Your Umrah · When you reach the miqāt, make ihram" + chip "I've entered ihram". (2) In ihram — green-tinted "You are in ihram · Enter the Haram and begin tawaaf" + chip "I've started tawaaf". | Manual: dim chip "Tap when you enter ihram" → tap toggles to "Talbiyah active". | At first sight of the Kaʿbah (pre-ihram); Qur'an 2:201 (in ihram). |
| **Browse** | "Welcome to Tawaaf · A quiet companion for your Hajj and Umrah" with three CTAs: `Set up an Umrah`, `Set up a Hajj`, `Open Rituals`. | Hidden. | Generic Qur'an 2:201. |

**Mode-independent elements** (shown in all three modes): Hijri date in header (general Islamic-calendar context), heat banner during 11 AM – 4 PM Saudi time, the six hub tiles, the privacy note.

**Files added/changed:**
- NEW `/js/trip-mode.js` — helper with `get/set/clear/isFirstRun/LABEL` and the `tawaaf:tripModeChange` event.
- `/app/index.html` rebuilt with mode-aware logic, welcome modal, and ihram toggle.
- `sw.js` bumped to v3 and added trip-mode.js to APP_SHELL.

**Open question — synchronization with Prepare/Rituals tabs.** The Prepare and Rituals pages have their own local Umrah/Hajj tab toggles. Currently independent from the global tripMode (local tabs let users browse content for the other mode without changing their identity). Alternative: sync them, so flipping the Prepare tab updates the global mode too. Test with users first.

**Open question — Settings home.** The gear icon currently opens the trip-mode picker directly. Long-term, the gear should open a proper Settings screen where trip mode is one of several preferences (Tahajjud / night mode, family share, after-Hajj companion, reading size). The trip-mode picker would become a row in that settings screen rather than the only modal it opens. Deferred until we build Settings.

---

## 3. Critical Hajj-specific content gaps

Tawaaf started Umrah-leaning. These are content holes for Hajj proper.

### 3.1 Day-of-Hajj quick-reference content [P1, M, *Pilgrim*]
The rituals page has the cards but they're buried. A pilgrim should be able to type "Arafat" in search and land on the right card with the right timing reminder. Add anchor links per day (`#tarwiyah`, `#arafat`, `#nahr`, `#tashreeq`, `#wada`), plus a top sticky pill row: `8 · 9 · 10 · 11-13 · Farewell`.

### 3.2 Missing duas for the Hajj sequence [P1, S, *Pilgrim*]
The 27-entry library is missing:
- **Wuquf at Arafat** dua (the prophetic *"Lā ilāha illallāhu waḥdah …"* — Tirmidhī 3585) — *highest priority gap*
- **Multazam** dua (mentioned in rituals card but no library entry)
- **Mash'ar al-Haram / Muzdalifah Fajr** supplication
- **Talbiyah** as a library entry (currently only on a ritual card)
- **Rukn al-Yamani** specific supplication
- **Istikhārah** (pre-trip)
- **Madinah / Masjid an-Nabawi entry** dua

### 3.3 No Madinah content at all [P1, M, *Pilgrim*]
Most Hajj packages include 3-5 days in Madinah. Add a section to the rituals page or a new tab: visit etiquette at Masjid an-Nabawi, salaam at the Prophet's grave ﷺ, Rawdah booking via Nusuk, Quba mosque (the recommended Saturday visit, narrated in Bukhari), Uhud, baqī al-gharqad.

### 3.4 Hajj walking-distance reality check [P2, S, *Marketing/Pilgrim*]
Pilgrim accounts consistently say they underestimated walking. Cumulative Hajj walking is **20-50 km**. The prepare page should call this out with a "physical preparation" card recommending 3-4 months of pre-Hajj walking training and broken-in shoes (NEVER new). This is one of the most common preventable pain points.

### 3.5 Tasreeh / Nusuk permit explainer [P2, S, *Marketing*]
The Tasreeh system is new (April 2025) and confuses Western pilgrims. Plain-English card: why you need it, what auto-issues it from Nusuk registration, where it's checked (every Makkah entry from 13 April 2026), penalties for non-compliance (SAR 20,000 fine, deportation, 10-year ban). Reduces anxiety.

### 3.6 Tahallul state tracker [P3, S, *Pilgrim*]
First exit (after Aqabah stoning + halq) vs second exit (after Tawaf al-Ifadah). Tiny toggle on the rituals page so the pilgrim can check "Am I out of ihram yet?" without re-reading the cards.

### 3.7 Sacrifice (hady) voucher storage [P3, S, *Pilgrim*]
Adahi voucher is critical paperwork pilgrims often lose. Optional localStorage on emergency card / papers page.

### 3.8 "What NOT to do" / common-mistakes content [P2, S, *Pilgrim*]
Top mistakes from research:
- Leaving Arafat before sunset
- Standing outside Arafat boundary (boundary is marked but missable)
- Treating customs as obligations
- Pelting kubra/wusta/sughra out of order on tashreeq days
- Stoning before Dhuhr on days 11-13 (invalid)

Render as a quiet "before you go" reading rather than an alarmist warning.

---

## 4. Per-page improvement list

### 4.1 `/` (index.html) — marketing home
- **Inline-CSS bloat (109 lines):** extract to `marketing.css`; mobile downloads desktop-only CSS only to override it with `mobile.css`.
- **Hero font:** `74px → 32px !important` is a 56% step. Use `clamp(32px, 6vw, 74px)` and drop the `!important`.
- **`backdrop-filter` on nav:** GPU stutter on older Android and iPhone SE 2 (common pilgrim phones). Use `@supports not` fallback.
- **Hex pattern SVG:** base64-inlined and duplicated across 6 places. Extract to `/img/hex-pattern.svg`.
- **Policy banner expires 2026-05-24 (silently).** Either move expiry or replace with a permanent quieter footnote.
- **No `<meta name="description">` or OG tags.** WhatsApp/Slack share previews are bare.
- **No hamburger nav on mobile.** All marketing-side nav links are hidden — only "Get started →" survives.

### 4.2 `/app/` (companion hub)
- **`user-scalable=no` — remove (§1.2).**
- **Greeting script uses device-local time.** Pilgrim in CA with un-updated phone sees "Sabah al-khayr" at 9pm Makkah. Either drop or compute from forecast/Makkah-tz.
- **Card order differs desktop vs mobile bottom nav.** Pick one canonical order.
- **Reading-aa `<a href="#">` should be `<button>`** for screen readers.
- **Currently fetches no offline shell** (see §2.1).

### 4.3 `/app/prepare.html`
- **Departure date stored as date string; countdown uses `new Date(...)`** — TZ bug when pilgrim opens from a different time zone.
- **Single shared date across Umrah and Hajj tabs.** A pilgrim doing both has to overwrite. Store one per leg.
- **No "Clear all" / "Reset for next trip" button** per section.
- **Phrases section is missing the survival phrase "I need water"** (أَحْتَاجُ مَاءً / *aḥtāju mā'an*) — the single phrase a 2024 collapse victim or bystander needed most.
- **Hajj packing list missing items recurring in 2024 advice:** cooling-towel / neck gaiter (worn pre-soaked at Arafat), thermal-mylar emergency blanket (Muzdalifah cold mornings), USB-C-to-Saudi-plug fan, pre-counted pebble pouch.
- **Authentic-resources mockup at `scratch/prepare-resources-mockup.html` was never merged** — the resources section in prepare is still 3 hardcoded items + stub. Ship the mockup with the 15 sources prepared (Sunnah.com, Nusuk, Adahi, Saudi MoH, IslamQA, Dar al-Iftaa, SeekersGuidance, AMJA, Yasir Qadhi, Mufti Menk, Assim al-Hakeem, CBHUK, ICNA, Ibn ʿUthaymīn manasik, Hisn al-Muslim).
- **Heading order h1→h2→mixed h3** in info cards — minor screen-reader hierarchy issue.

### 4.4 `/app/rituals.html`
- **1,633 lines on one page is too much scrolling — make the list collapsible.** *Added 2026-05-20 per user request.* Today every ritual card is rendered fully expanded, so a pilgrim looking for "what do I do at Muzdalifah?" has to scroll through ten dense cards. Restructure the page as an accordion: each ritual becomes a one-line header row (number badge · title · day · Wajib/Sunnah/Custom status pill · chevron). Tap a row to expand the four-part body (The act · The Sunnah · Where scholars differ · Pilgrim tips); tap again to collapse. Default state: collapsed. Multiple rows can be open at once (not strict accordion) so a pilgrim can compare two rituals side-by-side. Combined with the day-jump pill bar (§3.1), the rituals page becomes scannable on a phone instead of an endurance test. See the mockup at `/mockups/rituals-improvements.html`.
- **1,633 lines is also heavy for in-flight wifi.** Either split into `rituals-umrah.html`/`rituals-hajj.html` or lazy-hide the Hajj cards until tab clicked.
- **"Reviewed by: Pending — this card will be reviewed by a credentialed scholar before being treated as final guidance" appears on every single card.** The site claims authority while disclaiming it 19 times. Either consolidate to a single page-level note, remove from confidently-sourced cards (most cite Bukhari/Muslim), or pin a single named reviewer + date.
- **No table of contents / sticky day jump.** Add a `8 · 9 · 10 · 11-13 · Farewell` chip row at top.
- **No card for Jeddah airport arrival** — the most disorienting 4-6 hours, and the rituals page is the only thing a confused pilgrim opens in transit.
- **No card for ʿUmrat al-Tanʿīm** (re-entering ihram from Tan'im for a second Umrah while waiting for Hajj — very common).
- **HAJJ 7 status tag says "After Fajr"** but the Saudi Civil Defense post-2015-crisis guidance is post-sunrise / off-peak — contradicted by a separate tip below. Reconcile.
- **HAJJ 11 (Tashreeq stoning) doesn't address missed Nusuk timeslots** — a real and common 2024 stress. Add a one-liner that the slot is a Saudi safety mandate, not a scholarly requirement.
- **Hajar al-Aswad wording:** card UMRAH 3 has *"Bismillāhi wa-Allāhu akbar"*, but the more strongly attested form from Bukhari 1613 is just *"Allāhu akbar"*. Update to surface both as the duas treatment does elsewhere.
- **UMRAH 1 niyyah** says *"Labbayk Allāhumma ʿUmrah"* — a colloquial blend. Muslim 1218's wording is *"Labbayka ʿumratan"*.

### 4.5 `/app/tawaaf.html`
- **`user-scalable=no` — remove.**
- **`.wrap { width: min(64vw, 260px); }`** crushes the rings on 320px-wide landscape with keyboard. Add `min-width: 220px`.
- **Pulse animation respects no `prefers-reduced-motion`.** Wrap in media query.
- **Vibrate API is silently a no-op on iOS.** iPhone in pocket = zero feedback on circuit completion. Add a soft toggleable audio cue.
- **`MIN_CIRCUIT_MS = 30000` will under-count fit pilgrims** doing inner-ring tawaaf at 5am (Saudi-published lap times go as low as ~25s). Either lower to 22-25s or make tunable.
- **No "calibrate compass" hint.** Drift doesn't affect the counter (you integrate deltas) but doesn't matter — mention this on-page to reduce anxiety.
- **iOS Motion-vs-Orientation permission split** isn't handled. If Orientation granted but Motion denied, MIN_STEPS gate fails silently forever.
- **"Switch to manual" link is easy to miss in bright sunlight.** Promote to a chip-style toggle adjacent to start.
- **No circuit history / session timestamp.** Accidental Reset = lost session, no undo.

### 4.6 `/app/duas.html`
- **Search only matches Arabic and transliteration fields.** Typing "anxiety" works (`when` field), "grief" doesn't (it's in `category`). Add `category` and `source_label` to search corpus.
- **Detail sheet close button is at top** — bad for thumb reach. Add edge-swipe to close.
- **Sticky search wrap top-positioning** doesn't account for iOS Safari notch when `viewport-fit=cover` — it rides up under the notch.
- **Library size (27) is small.** See §3.2 for the highest-priority additions.
- **No bookmark/favorite persistence** even though `privacy.html` mentions "your dua bookmarks." Either remove the mention or ship the feature.
- **Zamzam dua still grades it ḥasan** without surfacing al-Albānī's ḍaʿīf grading.

### 4.7 `/app/prayer.html`
- **Refresh-every-60s — see §1.6.**
- **No error handling for Aladhan 429.** Silent failure.
- **Qibla shows "0 km to Kaaba" when pilgrim is inside Makkah** — comical. Add bounding-box detection → "You are at the Haram. Face the Kaaba."
- **Method order** has ISNA first, but Umm al-Qura should be first for pilgrims at the Haram. Re-order.
- **Method chips have no description** — pilgrim has no idea what "ISNA" or "Karachi" means. Add a 1-line "Hanafi · later Asr" type hint per chip.
- **Compass rotates the entire face including cardinals** — drift looks like the world is tilting. Add an EMA filter on heading for stability.
- **No reading-size control** on this page, where elderly pilgrims will struggle most with 11px legend text.
- **No third-party disclosure on-page.** Privacy doc mentions Aladhan/Nominatim, but the consent ask for location should call out where the request is going.
- **Imsak/Midnight/Sunset not surfaced** even though Aladhan returns them — Hanafi-tradition users expect Imsak.

### 4.8 `/contact.html`
- See §1.3 for the corruption.
- **No CSRF token / Turnstile.** Session rate-limit easily defeated.
- **Honeypot `name="website"` is too obvious** for modern spam bots. Use something innocuous like `name="phone-confirm"` with `tabindex="-1"`.
- **IP recorded in email body** but not disclosed on privacy page.

### 4.9 `/privacy.html`
- **See §1.1 (city/region mismatch).**
- Otherwise the page is excellent — keep the DNT/GPC honoring, visitor-hash explanation, and "what we deliberately don't collect" list as-is.

### 4.10 `/sources.html`
- See §1.3 for the truncation.
- **Missing Muwaṭṭaʾ Mālik in editions table** — flagged 2026-05-02.
- **Hisn al-Muslim edition not specified.**
- **Consider adding dorar.net** for Arabic-reader hadith verification.

### 4.11 `/styleguide.html`
- Add `<meta name="robots" content="noindex">` so Google doesn't surface it as a brand page.

### 4.12 `manifest.json` & PWA
- **Only one SVG icon.** iOS ignores SVG for home-screen icon → falls back to favicon. Add 192/512 PNGs.
- **No `categories` field.** Add `["lifestyle", "travel", "religion"]`.
- **No `shortcuts`.** Declaring shortcuts for "Open tawaaf counter" / "Open duas" gives long-press menus on Android.

### 4.13 `.htaccess`
- **CSP missing.** Add `Content-Security-Policy: default-src 'self'; img-src 'self' data:; font-src 'self' fonts.gstatic.com; style-src 'self' 'unsafe-inline' fonts.googleapis.com; script-src 'self'; connect-src 'self' api.aladhan.com nominatim.openstreetmap.org;`
- **ErrorDocument 404 routes to `index.html`.** No real router → typos render the marketing homepage with no 404 indication. Either ship a real `/404.html` or strip this rule.
- **Generalize markdown deny** beyond `README.md` specifically (§1.4).

---

## 4A. UI/UX review — visual system, type, color, layout, night mode

Added 2026-05-19 per request. The earlier review covered specific page-level issues; this section steps back and asks whether the visual decisions themselves are right.

### 4A.1 Color palette

**Current palette (from `styleguide.html`):**

| Token | Hex | Role |
|---|---|---|
| Deep Green | `#0a2e22` | Hero backgrounds, theme-color |
| Forest Green | `#0f3d2e` | Primary type, CTAs, wordmark |
| Hover Green | `#1a5440` | Link/CTA hover |
| Gold | `#c9a961` | Tiraz, accent, primary button |
| Deep Gold | `#8b6f2e` | Tiraz shadow, writing hint |
| Cream | `#faf8f3` | Paper |
| Cream-2 | `#faf4e5` | Secondary surfaces |

**What's working:**
- The deep-green / cream / gold trio is culturally and religiously resonant. Green has deep prophetic association (the Kiswah of the Prophet's chamber ﷺ); the cream + gold echoes the Kaaba's tiraz band and the conventional paper-cream of Saudi documents. This is premium without being gaudy and unmistakable for a Hajj product.
- The styleguide rule "*No bright accents. No rainbow states. Error and success states borrow from the gold and green families*" is genuinely differentiated. Most pilgrim apps look like fitness apps.
- AA contrast: green-on-cream and white-on-deep-green both pass comfortably for body and large text.

**What's not working / decisions needed:**
- **Outdoor sunlight readability is mediocre.** Many tertiary labels use `rgba(255,255,255,0.55)` or muted greys. At Saudi midday (~50,000 lux) these are functionally invisible. Recommend raising all tertiary text to `0.7+` opacity at minimum, and adding an opt-in "high-contrast" toggle.
- **No defined semantic state colors.** The styleguide says "borrow from gold and green" but in practice the UI has no obvious way to communicate: heat warning, lost connection, missed Nusuk timeslot, validation error. Inventing colors per page risks fragmentation. **Recommend** defining four semantic states derived from but distinct from the brand palette: warn (deeper amber from the gold family), info (deeper green), success (uses the green-2), error (a warm clay tone like `#a04830` that doesn't break the palette). Document in styleguide.
- **Gold on cream is borderline 3.1:1** — fails AA for body text. Currently used for some footnote links and accent type. Safe only at large display sizes or as decorative trim. Recommend: gold for accents/icons only; switch inline links to forest green.

### 4A.2 Typography

**Current stack:**
- **Italiana** — wordmark only ("tawaaf")
- **Fraunces** (4 cuts: 400i, 600, 700) — serif display, headings, accents
- **Inter** (6 weights: 300/400/500/600/700/800) — UI body
- **Amiri** (400, 700) — Arabic

**What's working:**
- Fraunces is a confident editorial serif and pairs beautifully with Inter. Its variable-axis support is a real asset if we use it.
- Amiri is the right choice for Arabic — Naskh-based, scholarly, broadly readable, ships with Uthmani diacritics.
- The reading-size "Aa" control is unusually considerate — elderly pilgrims and presbyopic users will appreciate it. This is a defensible product moment.

**What's not working / decisions needed:**
- **Six Inter weights when only 4 are used.** Grep confirms only 400/500/600/700 appear in source. Drop 300 and 800 — saves ~60-80 KB on cold load. Same audit for Fraunces (404i, 600, 700 only).
- **Fraunces optical sizing isn't exploited.** Fraunces has `opsz` axis support. At hero sizes (74px on the marketing home) `opsz="144"` produces noticeably tighter, more elegant rendering than the default. One-line CSS change.
- **No display-weight Arabic.** Amiri 700 is used for body emphasis but display Arabic (e.g. the *طواف* hero mark) uses Amiri Regular scaled large, which lacks weight at 96px+. **Recommend** adding **Reem Kufi** or **Cairo** as an Arabic display face (or pulling Amiri Quran Wght 700+).
- **Arabic line-height too tight.** Inherits the body `line-height: 1.55`. Arabic diacritics need 1.85-2.0 to breathe. Add a `.arabic { line-height: 1.9; }` override.
- **Web-font fallback chain is undefined.** If Google Fonts is blocked (China, locked-down corporate wifi at airports, intermittent connectivity), the fallback drops to generic sans-serif and the brand collapses. Recommend explicit fallbacks site-wide:
  - Wordmark: `'Italiana', 'Cormorant Garamond', 'Cormorant', 'Times New Roman', serif`
  - UI body: `'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif`
  - Editorial: `'Fraunces', Georgia, 'Iowan Old Style', serif`
  - Arabic: `'Amiri', 'Traditional Arabic', 'Geeza Pro', 'Times New Roman', serif`
- **No type scale documented.** Sizes appear ad-hoc (74, 32, 28, 24, 20, 18, 16, 15, 14, 13, 11). **Recommend** a modular scale: 12, 14, 16, 18, 22, 28, 36, 48, 64. Drop everything else.

### 4A.3 Layout, spacing, and rhythm

**What's working:**
- Mobile-first foundation in `app.css` is solid: bottom-nav, sticky header, safe-area inset handling done correctly.
- 48px tap targets meet HIG (Apple) and Material (Android) guidelines.
- `min-height: 100dvh` is the correct iOS Safari pattern.
- Generous whitespace; reads as premium rather than cluttered.

**What's not working / decisions needed:**
- **No documented spacing scale.** Padding values are ad-hoc (16, 20, 24, 28, 32, 36, 48). **Recommend** an 8-point scale: 4, 8, 12, 16, 24, 32, 48, 64. Replace existing values to nearest scale token.
- **Bottom-nav `backdrop-filter: blur(14px)`** is GPU-heavy on older Androids common in pilgrim demographics. Add a `@supports not (backdrop-filter: blur(2px))` fallback to a solid color.
- **Mobile content `padding: 20px 16px`** is fine but inconsistent — desktop hero is 48px, app surface is 16/20px. Worth aligning to the spacing scale.
- **No text-column max-width** on the rituals page at tablet+ widths. Lines exceed the ~70-character readability ceiling on landscape iPad. Cap text columns at `max-width: 65ch`.
- **Sticky header + bottom-nav consume ~120px** of viewport on mobile — ~70% remains for content. Fine in portrait; in landscape with keyboard open, the rituals page becomes unreadable. Consider hiding the sticky header on scroll (Twitter-style auto-hide).

### 4A.4 Iconography

**Current state:** mixed. Custom isometric Kaaba SVG is the brand mark. Inside pages: emoji (`📿 📑 🕌 ⟲`), Unicode glyphs (`◈ ›`), and ad-hoc inline SVGs all coexist. Emoji rendering varies wildly between Apple, Google, and Samsung — slightly weakens the premium feel.

**Recommend** picking one icon system and standardizing:
- **Phosphor Icons** (free, ~9000 icons, multiple weights — "regular" pairs well with Fraunces) — *my pick*, primarily because it has a "duotone" option that maps cleanly to our deep-green + gold accent
- **Lucide** (free, ~1500 line icons, more austere)
- Either one shipped as a small SVG sprite (~15 icons we'd actually use), inline `<svg>` references, no external dependency

### 4A.5 Microcopy and tone

**Working well:** the "quiet companion" voice is consistent. Hero line — *"A resource for Hajj and Umrah pilgrims — to prepare with before you go, and to lean on while you're there"* — is exceptional and shouldn't change. The honest "Reviewed by: Pending" disclosure (though over-applied; see §4.4) is unusually transparent.

**Cleanups:**
- **Mixed capitalization conventions.** "Get started →" / "Companion" / "tawaaf" / "Tawaaf" / "Authentic resources". Pick canonical forms: product name "Tawaaf" capitalized in body text, "tawaaf" lowercase only in the wordmark; nav labels sentence case; CTA buttons sentence case with arrow ("Get started →" stays).
- **Define an error/empty-state voice.** When Aladhan fails, the user currently sees nothing. What should they see? In voice with the brand: "*Prayer times are taking longer than usual. Trying again…*"
- **No 404 page voice.** Currently `.htaccess` redirects 404 to the homepage. Add a `/404.html` with a quiet line: *"That page hasn't been written yet — or it has been put away. Try the [companion](/app/) or [contact us](/contact.html)."*

### 4A.6 Motion

Mostly static — appropriate for the premium voice. Two issues:
- **Pulse animation on tawaaf status dot** doesn't respect `prefers-reduced-motion`. Wrap in the media query.
- **Inconsistent transitions.** Dua detail sheet slides up at 200ms ease-out; prayer-times refresh is instant; tawaaf circuit completion has no transition feedback. **Recommend** a documented motion system: 150ms ease-out for instant UI feedback (button presses), 240ms ease-out for content reveal (sheets, expansions), 0ms (no animation) for data updates. Audit pages against it.

### 4A.7 Night mode — explicit question

The current state is mixed and probably wrong:
- **Marketing site (root)** is cream/light, with deep-green hero panels.
- **App (`/app/`)** is cream/light overall, BUT `/app/tawaaf.html` and `/app/prayer.html` are dark green-on-dark for their live components.

This creates real friction:
- The app feels visually inconsistent. Going from `/app/` (cream) to `/app/tawaaf.html` (dark green) is an abrupt context shift.
- Pilgrims doing Tahajjud in a Mina tent, or pre-dawn Mash'ar al-Haram supplications at Muzdalifah at Fajr, are reading by phone in pitch dark. A cream background blasts their dark-adapted vision and ruins night vision for ten minutes.
- Outdoor Saudi midday on a cream background is highly readable — the dark theme isn't ideal there.

**Three options to discuss:**

**Option A — System-aware full night mode.** Respect `prefers-color-scheme: dark` with a manual toggle in the app header. Cream becomes deep green; deep green becomes a more saturated forest. Gold stays. The brand still reads as Tawaaf because the gold and the typography remain. This is the standard modern pattern.

**Option B — "Tahajjud mode" specifically (low-luminance amber).** Different from a generic dark mode. Surfaces become a deep low-luminance amber/gold (think the gold-on-velum aesthetic of an old Hajj passport, but very dim) that doesn't kill dark-adapted vision. Closer to a "red night mode" but using the gold instead of red — fits the brand. Surfaced as a one-tap "moon" button in the app header. Designed specifically for pre-dawn supplication and Tahajjud.

**Option C — Keep mixed approach but make it intentional.** Define which pages/components are light vs. dark, stop the inconsistency, document in styleguide.

**My recommendation:** ship **Option B (Tahajjud mode) for Hajj 2026** — it directly addresses pre-dawn Mash'ar al-Haram and Tahajjud in Mina, which is one of the highest-friction night moments of the trip. Then add **Option A (full dark mode)** as a post-Hajj refinement, properly thought through. The mockup at `/mockups/night-mode.html` shows what each option looks like.

### 4A.8 Visual hierarchy

**Working:** Typographic scale (h1 → h2 → h3 → body) is generally legible at a glance. The styleguide pins it.

**Not working:**
- **No weight-of-information signaling for ritual content.** Wajib vs Sunnah vs Custom (covered in §2.9 — moving to Phase B per request) is the obvious place to use color + iconography to convey gravity. Currently all guidance is rendered identically.
- **"From recent pilgrims" tips and "Where scholars differ" panels look almost identical.** Both are subtle gray panels with a small label. The latter is doctrinally weightier and should be visually distinct — recommend a different background tint (warm cream vs cool gray) and a small ⚖ icon.

### 4A.9 Touch density and one-handed reachability

**Working:** Bottom nav puts primary actions in thumb zone; reading-size control accommodates motor difficulties.

**Not working:** Action buttons on long-scroll pages live in the top half. "Reset" on `tawaaf.html` is mid-screen — a one-handed pilgrim in a crowd cannot reach it without re-gripping. Move critical actions to the bottom third of the viewport.

### 4A.10 Loading and empty states

**Loading:**
- Skeleton/shimmer states would feel like Instagram and break tone. **Recommend** instead a quiet "calculating prayer times…" or "loading duas…" line, italic Fraunces, gold underline. Used sparingly.
- For the offline case (post-service-worker), surface "*Showing the version you last loaded — connect to refresh*" as a small banner with a gold underline.

**Empty:**
- Avoid stock illustrations (cardboard boxes, magnifying glasses). They break voice.
- For the dua search "no results", show a short Quranic fragment as the empty state. *"And speak good words to people." (Qur'an 2:83)* — turns a dead end into a moment of reflection. Same for empty prayer-times state.

### 4A.11 Accessibility (additions beyond §1)

- **Focus rings:** `:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }` — keyboard users currently get no indicator because `-webkit-tap-highlight-color: transparent` swallows the default.
- **`prefers-reduced-transparency`:** iOS users with this on don't get the backdrop-filter — verify the fallback isn't broken (probably fine since it gracefully degrades to no blur, but worth testing).
- **`prefers-contrast: more`:** define a high-contrast variant — bumps all greys to full black and tertiary text to 100% opacity.

### 4A.12 Verdict

Tawaaf's visual system is unusually thoughtful for the category. The color, type, and tonal decisions are mostly right and shouldn't be overhauled. The biggest open question is night mode — and the answer for Hajj 2026 should be the Tahajjud mode (Option B), since Mash'ar al-Haram and pre-dawn Mina tent reading is real and the cream background actively hurts pilgrims at those moments. Everything else in this section is polish, codification, and consistency — not redesign.

---

## 5. Cross-cutting concerns

### 5.1 Outdoor sunlight readability
The dark-app theme uses `rgba(255,255,255,0.55)` for chip rail text and several tertiary labels. At Saudi midday (~50,000 lux), this is functionally invisible. Raise all tertiary text to `0.7+`. Test the screen under direct sunlight on a phone with auto-brightness on.

### 5.2 Font payload
Inter (6 weights) + Fraunces (4) + Amiri (2) + Italiana = ~180-220 KB cold. Source shows only Inter 700/600/500/400, Italiana 400, Amiri 400/700, Fraunces 600/700/italic-400 in use. Trim the request.

### 5.3 `tawaaf-counter.js` loads on every app page
Even when no session exists. Split into a tiny "is there a session?" probe + lazy-loaded full engine.

### 5.4 Cache-bust versioning
Three different `?v=` patterns are live. A single release constant + grep would make this one-line.

### 5.5 Mixed icon system
Emoji + SVG + Unicode glyphs. Emoji rendering varies between Apple and Google, slightly weakening the premium feel. Pick one (Phosphor recommended — see §4A.4).

---

## 6. Authenticity / content nuance items

- **Dua C1** (between Rukn al-Yamani and Black Stone): add Abu Dawud 1892 as the more direct citation for the practice.
- **Dua C2** (Zamzam, Hisn 78): currently graded hasan; al-Albani graded it daif. Surface the disagreement.
- **Dua C3** (Farewell tawaaf): change `source_label` to "Practice: Bukhari 1755 · Wording: classical recommendation (chains weak)."
- **UMRAH 1 niyyah wording**: replace blend with "Labbayka umratan" (Muslim 1218).
- **At the Black Stone**: surface that "Allahu akbar" alone is more strongly attested (Bukhari 1613).
- **Ayat al-Kursi after salah**: primary source is al-Nasai Sunan al-Kubra 9928 (also in Tabarani).
- **Add Muwatta Malik** to editions; **specify Hisn al-Muslim edition**.

---

## 7. Security & code hygiene

1. ~~**Privacy promise vs code (§1.1).**~~ ✅ resolved 2026-05-19.
2. **CSP missing** site-wide (§4.13).
3. **CSRF + better honeypot** on contact form (§4.8).
4. **`error_log` of PDO exception messages in `track.php`** — verify HostGator `php.ini` has `display_errors = Off`.
5. **Origin check in `track.php`** uses string-prefix matching — easily forged. Use parsed URL host equality.
6. **`setup-admin.php`, `setup-geoip.php`** — if these are first-run only, delete them post-deploy.
7. **GeoLite2 CSV zip publicly served** despite `.htaccess` block — verify with `curl -I`.

---

## 8. Tone-respecting feature ideas to discuss

### 8.1 Family-back-home companion view
A second mode for families/friends NOT on Hajj: a read-only schedule view of "where the pilgrim is now in the sequence" without any location tracking — just the shared Hajj timeline rendered in the family's time zone.

### 8.2 Post-Hajj "one year later" companion
A quiet, optional monthly check-in for 12 months post-Hajj — one ayah, one dhikr, one short reflection. Mocked at `/mockups/one-year-later.html`.

### 8.3 Curated reading list per ritual
Each ritual card could expose a small "Read more" panel pointing to specific Sunnah.com pages, Quran.com verses, and scholar talks.

### 8.4 Quiet "what NOT to do" cards
Bid'ah without scolding.

### 8.5 Lost-passport 5-step page
~~Already covered~~ — implemented on the Emergency card page (§2.4) on 2026-05-20.

### 8.6 Hijri date in the header
~~Already implemented~~ on the Today hub (§2.2) on 2026-05-20.

---

## 9. Things to be honest about

- ~~**Service worker** adds first-load weight and requires versioning discipline~~ — ✅ resolved 2026-05-20.
- ~~**"Today" Hijri-aware views** require a Hijri date library~~ — ✅ resolved using browser-native `Intl.DateTimeFormat`, zero dependency.
- **Family-back-home view** introduces a different audience to Tawaaf — still open.
- **Push notifications** would extend Today but require a service worker + push subscription, which conflicts with no-account / no-tracking. Defer.
- **The "Reviewed by: Pending"** line on rituals: still open.

---

## 10. Suggested phasing

### Phase A — Ship by 22 May 2026 (pre-Hajj install window)
*Code/config foundational fixes only.*

1. ~~Fix `track.php` city/region vs privacy.html mismatch (§1.1)~~ **✅ shipped 2026-05-19**
2. ~~Remove `user-scalable=no` (§1.2)~~ **✅ shipped 2026-05-19**
3. ~~Fix `contact.html`/`sources.html` corruption + escaped doctype (§1.3)~~ **✅ shipped 2026-05-19**
4. ~~`.htaccess` cleanup for `*.md`, `scratch/`, `icon-*.html`, `GeoLite2-*` (§1.4)~~ **✅ shipped 2026-05-19**
5. ~~Add `lang="ar" dir="rtl"` to Arabic spans (§1.5)~~ **✅ shipped 2026-05-19**
6. ~~Fix `prayer.js` 60s refetch (§1.6)~~ **✅ shipped 2026-05-19**
7. ~~Fix `menigngitis` typo (§1.7)~~ **✅ shipped 2026-05-19**
8. ~~Service worker for offline (§2.1)~~ **✅ shipped 2026-05-20**

> **Phase A is complete.** All 8 items shipped between 2026-05-19 and 2026-05-20.

### Phase B — Ship 23 May – mid-June 2026 (during Hajj 1447)

**Status legend:** ✅ shipped · 🟡 deferred (awaiting your mockup review) · ⚪ pending direction

9. ~~Emergency card with localStorage (§2.4)~~ **✅ shipped 2026-05-20**
10. ~~Heat & hydration card (§2.6)~~ **✅ shipped 2026-05-20**
11. ⚪ Add critical missing duas — Wuquf at Arafat is the standout (§3.2). *Partial: Arafat dua + Talbiyah surface on Today; the full 7 new entries still need to be added to `/data/duas.json` and rendered in `/app/duas.html`.*
12. ⚪ Add survival phrase "I need water" (§4.3)
13. ⚪ Hajj-specific packing items: cooling towel, mylar blanket (§4.3)
14. ⚪ Ship the prepare-resources mockup that's been sitting in scratch (§4.3)
15. 🟡 **Pebble counter (§2.3)** — *deferred 2026-05-20, mockup needs review*
16. 🟡 **"Drop my tent pin" + offline map (§2.5)** — *deferred 2026-05-20, mockup needs review*
17. ~~Hijri-aware Today view (§2.2)~~ **✅ shipped 2026-05-20**
18. ⚪ Day-jump anchors **+ collapsible accordion** on rituals page (§3.1, §4.4)
19. ~~Doubt-resolver microflow (§2.7)~~ **✅ shipped 2026-05-20**
20. ~~Talbiyah window timer (§2.8)~~ **✅ shipped 2026-05-20**
21. ~~Wheelchair guidance card (§2.10)~~ **✅ shipped 2026-05-20**
22. ⚪ Tasreeh / Nusuk explainer (§3.5)
23. ⚪ **Tahajjud / night mode toggle (§4A.7)**
23a. ~~**Trip-mode picker (§2.11)**~~ **✅ shipped 2026-05-20** — *NEW item added per user request*

> **Phase B progress: 8 shipped + 1 new = 9 of 16 done.** 2 deferred awaiting your mockup review (15, 16). 6 still pending your direction (11, 12, 13, 14, 18, 22, 23).

### Phase C — Ship post-Hajj 2026 (preparing for 1448)

24. ~~Wajib/Sunnah/Custom view (§2.9)~~ **✅ shipped 2026-05-20 (card-header level — pulled forward from Phase C)** · per-substep labelling still pending
25. Madinah content (§3.3)
26. Common-mistakes cards (§3.8)
27. Post-Hajj "one year later" companion (§8.2)
28. Authenticity content updates (§6)
29. All per-page polish from §4 not above
30. CSP, CSRF, all security hygiene (§7)
31. Family-back-home view (§8.1)
32. **Full system-aware dark mode (§4A.7 Option A)** — *added 2026-05-19*
33. **Define semantic state colors, type scale, spacing scale** — *added 2026-05-19*
34. **Standardize icon system on Phosphor or Lucide** (§4A.4) — *added 2026-05-19*
35. **Define font-fallback chains and motion system** — *added 2026-05-19*
36. **Build proper Settings screen** — *added 2026-05-20*. Gear icon currently opens the trip-mode picker directly; long-term it should open Settings with trip-mode as one row among: night mode, reading size, family share, after-Hajj companion.

---

## 11. Open questions for you

1. ~~Privacy resolution direction~~ — ✅ answered.
2. Rituals "Reviewed by: Pending" caveat — consolidate to page-level, find a named reviewer, or keep as-is?
3. **Splitting rituals.html (§4.4):** worth the engineering for the in-flight load saving, or wait?
4. **"Drop my tent pin" (§2.5):** comfortable with localStorage geolocation? *Awaiting your mockup review.*
5. ~~Service worker (§2.1)~~ — ✅ shipped.
6. **Pebble counter (§2.3):** is this in scope, or feature creep? *Awaiting your mockup review.*
7. ~~Hijri calendar source~~ — ✅ answered (browser-native Intl, no dependency).
8. **Family-back-home view (§8.1):** new audience or scope-bloat?
9. **Madinah content (§3.3):** in-scope? It expands the app beyond Hajj/Umrah proper.
10. **0-Archive/ folder:** keep in repo or move out-of-tree now?
11. **NEW — Trip-mode + Prepare/Rituals tab sync:** keep them independent (current) or sync, so flipping the Prepare tab updates the global mode? See §2.11.
12. **NEW — Settings screen scope:** when do we want to build a proper Settings home? See §2.11 + Phase C item 36.

---

## 12. Things Tawaaf already does well (for morale and to avoid changing what works)

- Content authenticity — best-in-class for the category. "Where scholars differ" is unique.
- Tawaaf-counter engine — four-gate false-trigger prevention is genuinely careful engineering.
- Privacy page transparency (post-2026-05-19 reconciliation) — DNT/GPC honoring, visitor-hash explanation are exemplary.
- Reading-size control with per-page persistence — most pilgrim apps don't consider this.
- Hajj packing list including whistle, ID wristband, "more cash than Umrah" shows real domain knowledge.
- The site stays out of monetization, gamification, and tracker territory — keep that.
- **NEW 2026-05-20:** the trip-mode picker (§2.11) — explicit context-setting rather than inference is a strong UX choice. The first-run prompt is uncommonly polite.

---

*Reviewed files: `/index.html`, `/app/index.html`, `/app/prepare.html`, `/app/rituals.html`, `/app/tawaaf.html`, `/app/duas.html`, `/app/prayer.html`, `/app/emergency.html`, `/app/heat.html`, `/app/doubt.html`, `/app/wheelchair.html`, `/css/app.css`, `/css/mobile.css`, `/css/info.css`, `/js/tawaaf-counter.js`, `/js/prayer.js`, `/js/duas.js`, `/js/analytics.js`, `/js/reading-size.js`, `/js/hijri.js`, `/js/trip-mode.js`, `/js/sw-register.js`, `/data/duas.json`, `/sources.html`, `/styleguide.html`, `/contact.html`, `/privacy.html`, `/manifest.json`, `/.htaccess`, `/api/contact.php`, `/api/track.php`, `/sw.js`.*
