# Handoff: Days Inn Guest Hub — Guest Homepage & Staff Phone App

## Overview

Two guest- and staff-facing surfaces of the Days Inn Guest Hub:

1. **Guest homepage** (`/`) — the property's public page. Hero with an availability snapshot, room types, amenities, policies, an in-room request section for guests already staying, nearby highlights, gallery, FAQ, a Wyndham Rewards block, and location/access.
2. **Staff phone app** — the housekeeping flow on a personal phone, installed as a PWA: install → name picker → PIN → shift start → route → push alert → offline → clock out. Eight screens, 390px wide.

These are companions to `design_handoff_ops_portal/`, which covers the three desktop staff screens. Palette, typography and status colours are shared across both bundles — **read the ops portal token tables as the canonical set**; this document repeats only what differs or is new here.

## About the Design Files

The files in this bundle are **design references created in HTML** — prototypes showing intended look and behaviour. They are **not production code to copy directly**.

The source app is a **TanStack Router + React + Tailwind CSS v4** project (`rulloa1/daysinn`). Recreate these designs in that environment:

- Use the existing route files as integration points (`src/routes/index.tsx` for the homepage, `src/routes/housekeeping.tsx` plus `src/components/pwa-install-prompt.tsx` and `src/lib/device-push.ts` for the phone flow).
- Use the existing `src/components/ui/*` primitives rather than introducing new ones.
- Express colours as Tailwind theme tokens in `src/styles.css` (the project already has an `@theme` block with oklch values), not hard-coded hex in components.
- **Do not port the inline styles.** The prototyping environment requires them; translate to Tailwind classes.

## Fidelity

**High-fidelity on the guest homepage** — colours, type, spacing, radii and copy are final. Every value below is exact.

**High-fidelity on the phone screens' layout and copy**, with two caveats:

- The eight phone screens are a *flow*, not eight routes. Screens 1–3 are the auth path, 4 is shift start, 5 is the route home, 6–7 are states (push, offline), 8 is clock-out. Screen 6's lock-screen mock is illustration only — the real thing is an OS notification.
- Icons are inline Lucide SVG paths. The codebase depends on `lucide-react` — use the named components (listed per screen).

Data is hard-coded sample data throughout. Wire to the real queries.

---

## Tokens specific to this bundle

The brand palette, neutrals, status colours and type scale are in `design_handoff_ops_portal/README.md`. Additions used here:

### Colour

| Token | Hex | Use |
| --- | --- | --- |
| `ink-deep` | `#00243F` | Hero base behind the exterior photo, Wyndham Rewards section, phone-app page background, PIN and lock screens. Darker than brand blue — used only where a photo sits behind or where the screen should read as night. |
| `canvas-guest` | `#DCE4ED` | Guest homepage page background. |
| `surface-guest` | `#F5F8FB` | Guest homepage cards, hero booking bar. |
| `border-guest` | `#D2DBE6` | Guest homepage card borders. |
| `border-input` | `#BCC9D8` | Form field borders (date, select). |
| `rule-guest` | `#C6D1DE` | Amenity and FAQ list dividers. |
| `canvas-device` | `#A8B7CA` | Phone-frame body background (the phone screens sit on a mid-slate, not white). |
| `device-surface` | `#D8E1EC` | Phone cards, tab bar, header strips. |
| `device-surface-2` | `#C9D4E1` | Phone chips, avatars, selected rows. |
| `device-border` | `#9FAEC2` | Phone card borders. |
| `device-border-strong` | `#8B9CB3` | Phone frame border, secondary button borders on device. |
| `device-text` | `#33445C` | Phone body copy. |
| `device-text-muted` | `#4C5C74` | Phone secondary copy. |
| `positive-dot` | `#34D399` | "Online", "All synced", "10-min average response". |
| `offline-bar` | `#8A5A12` bg / `#FBE3A8` text | The offline banner. Only place this pair is used. |

Gold on `#00243F` is legible; gold on `#D4AF37`-tinted panels uses `rgba(212,175,55,0.14)` background with `rgba(212,175,55,0.5)` border.

### Type additions

| Role | Family | Size | Weight | Notes |
| --- | --- | --- | --- | --- |
| Guest hero `h1` | Playfair Display SC | 3.1rem | 700 | line-height 1.08, tracking -0.015em, `max-width: 44rem`, `text-wrap: pretty` |
| Guest section `h2` | Playfair Display SC | 2.1rem | 700 | tracking -0.01em, `#004986` (or `#fff` on dark sections) |
| Guest card `h3` | Playfair Display SC | 1.2–1.3rem | 700 | `#004986` |
| Phone screen `h2` | Playfair Display SC | 1.4–1.6rem | 700 | `#004986` on light, `#fff` on blue |
| Lock screen clock | Karla | 3.6rem | 600 | tabular-nums, line-height 1 |
| Hero room number (route) | Karla | 3.4rem | 600 | tabular-nums, line-height 0.9 |
| Legal / disclaimer | Karla | 0.76–0.78rem | 400 | line-height 1.65, `rgba(255,255,255,0.45)` |

### Radii additions

`6px` logo plate on device · `12px` gallery figure, offline row · `14px` policy/nearby/device card · `16px` room card, hero booking bar, section card · `18px` "Do this next" on device, notification card, install logo plate · `32px` phone frame · `999px` pills and dots.

### Shadows

| Value | Use |
| --- | --- |
| `0 20px 25px rgba(0,26,46,0.25)` | Hero booking bar |
| `0 25px 50px rgba(0,0,0,0.35)` | Phone frames (prototype presentation only — not part of the app) |
| `0 10px 15px rgba(0,36,63,0.18)` | Install-screen logo plate |
| `0 10px 15px rgba(0,0,0,0.2)` | Foreground lock-screen notification |

---

## Screen 1 — Guest homepage

**Route**: `/` · **Purpose**: convert a traveller looking for a room off I-75, and give a guest already in-house a way to ask for something without calling the desk.

Page background `#DCE4ED`. Content sections are `max-width: 1180px; margin: 0 auto; padding: 72px 40px 0`. Full-bleed dark sections break that container and use `padding: 72px 40px` with an inner 1180px wrapper.

### 1.1 Header (sticky)

`position: sticky; top: 0; z-index: 60`, `background: #004986`, `padding: 14px 40px`, space-between.

- Left lockup: logo on a white plate (radius 8, `padding: 7px 10px`, logo `height: 26px`), then a `1px solid rgba(255,255,255,0.28)` left border with `padding-left: 14px` holding two stacked eyebrow lines — `Guest Hub` (`#fff`) and `Days Inn® by Wyndham` (`rgba(255,255,255,0.6)`), both `0.6875rem`, 700/600, uppercase, tracking 0.18em.
- Right: four anchor links (`Rooms`, `Amenities`, `Gallery`, `Location` → `#rooms`, `#amenities`, `#gallery`, `#location`), same eyebrow treatment at `rgba(255,255,255,0.7)`, `gap: 22px`; then **Book direct ↗** — gold, `#004986` text, 700, `11px 18px`, radius 10, href to the Wyndham property overview page.

### 1.2 Hero

`position: relative; isolation: isolate; overflow: hidden; background: #00243F`.

- Photo layer: `assets/p-exterior-dusk.avif`, absolutely positioned, `z-index: -2`, `object-fit: cover`, `opacity: 0.55`.
- Gradient layer: `z-index: -1`, `linear-gradient(100deg, rgba(0,36,63,0.92) 0%, rgba(0,36,63,0.72) 48%, rgba(0,36,63,0.25) 100%)`.
- Content: `padding: 88px 40px 40px`.
  - Gold eyebrow, preceded by a `12×3px` gold bar: `Days Inn® by Wyndham Wildwood I-75 · I-75 Exit 329 · Wildwood, FL`
  - `h1`: `Rooms off I-75 with free breakfast, pool & parking.`
  - Sub (`1.05rem`, `rgba(255,255,255,0.8)`, `max-width: 38rem`): `Check-in 3:00 PM · Check-out 11:00 AM. Pet-friendly rooms, free Wi-Fi, and RV/truck parking — 10 minutes from The Villages.`
  - **Booking bar**: `display: grid; grid-template-columns: 1fr 1fr 1fr auto; align-items: end`, `max-width: 56rem`, `background: #F5F8FB`, radius 16, `padding: 18px 20px`. Three labelled fields (Check in / Check out as `input[type=date]`, Guests as a `select`), divided by `1px solid #D2DBE6` right borders with `20px` padding, each field `min-height: 44px`, `1px solid #BCC9D8`, radius 10, white. Then **Check availability** — `#004986`, `#fff`, 700, radius 10, `min-height: 44px`.
  - Disclaimer below (`0.78rem`, `rgba(255,255,255,0.55)`, `max-width: 52rem`): the snapshot/confirmed-on-Wyndham.com wording. **Keep this copy verbatim** — it is the compliance line for showing availability outside the official flow.

### 1.3 Rooms (`#rooms`)

Header row: gold eyebrow `Choose Your Room`, `h2` `Rooms & Sleeping Options`, right-aligned link **See live rates ↗**.

Three cards, `grid-template-columns: repeat(3, minmax(0,1fr)); gap: 20px`. Each: `1px solid #D2DBE6`, radius 16, `background: #F5F8FB`, `overflow: hidden`, flex column. Image `height: 220px`, `object-fit: cover`. Body `padding: 22px 24px 24px`: baseline row of `h3` + a sleeps pill (`#E7EDF5` bg, `#0065AB` text, `0.68rem`, 700, uppercase, radius 999), then beds line (`0.82rem`, 600, `#64748B`), body copy (`0.92rem`, `#475569`), and a `margin-top: auto` **Check rates ↗** eyebrow link.

| Name | Pill | Beds | Copy |
| --- | --- | --- | --- |
| One King Bed | Sleeps 2 | 1 king bed · 300 sq ft | Work desk, mini fridge, microwave, flat-screen TV and free Wi-Fi. |
| Two Queen Beds | Sleeps 4 | 2 queen beds · 330 sq ft | Our most popular room for families and road-trip crews heading down I-75. |
| Hospitality Suite | Sleeps 4 | 1 king bed + sofa · sitting area | Extra living space with sofa, desk and second TV for longer stays. |

Images: `p-king.avif`, `p-two-queen.avif`, `p-suite.avif`. Every room links to the Wyndham overview URL with `?adults=2&roomType=…`.

### 1.4 Amenities (`#amenities`)

Two columns, `minmax(0,0.85fr) minmax(0,1fr)`, `gap: 40px`, `align-items: start`.

- Left: eyebrow `Included With Every Stay`, `h2` `Amenities`, then `p-pool.avif` at `height: 280px`, radius 16.
- Right: a two-column `ul`, `gap: 2px 24px`. Each item: 8px gold dot + `0.98rem` `#334155` text, `border-bottom: 1px solid #C6D1DE`, `padding: 18px 0`.

Items: Free Daybreak® hot breakfast · Outdoor heated pool · Free high-speed Wi-Fi · Free parking — RV & truck friendly · Pet-friendly rooms (fees apply) · Micro-fridge in every room · Guest laundry access · Right off I-75 Exit 329.

### 1.5 Policies

Eyebrow `Good To Know`, `h2` `Policies`, then six cards `repeat(3, minmax(0,1fr))`, `gap: 16px`: `1px solid #D2DBE6`, radius 14, `#F5F8FB`, `padding: 20px 22px`. Faint uppercase label, then `1.02rem` weight-600 `#004986` value.

Check-in 3:00 PM · Check-out 11:00 AM · Cancellation: free until 4:00 PM day of arrival on most rates · Pets: welcome in select rooms — additional fee at check-in · Smoking: non-smoking property · Age to check in: 21+ with valid photo ID and credit card.

### 1.6 In-room requests (full-bleed `#004986`)

The bridge between the marketing page and the ops system. `margin-top: 72px`, `padding: 72px 40px`.

- Header row: gold eyebrow `Already Staying With Us?`, `h2` `In-Room Requests & Guest Tools` in `#fff`; right side a pill (`rgba(255,255,255,0.12)`, radius 999, `9px 16px`) with a `#34D399` dot: `10-min average response`.
- Four cards, `repeat(4, minmax(0,1fr))`, `gap: 16px`: `1px solid rgba(255,255,255,0.18)`, `background: rgba(255,255,255,0.07)`, radius 16, `padding: 22px 22px 20px`. `h3` `1.05rem` 700 `#fff`, body `rgba(255,255,255,0.7)`, then a `margin-top: auto` gold `Request →` eyebrow.

| Card | Copy |
| --- | --- |
| Fresh Towels & Linens | Bath towels, washcloths, extra pillows |
| Housekeeping Refresh | Room tidy, trash removal & amenities |
| Maintenance & Repairs | Fast repair dispatch to your room |
| Front Desk Assistance | Direct messaging with our front team |

These four map 1:1 to the request types in the ops portal queue. Adding a type here means adding it there.

- Action row: **Sign in to your room** (gold), **Track a request** and **Local guide** (outline `rgba(255,255,255,0.35)`), then `margin-left: auto` `DaysInn_Guest Wi-Fi`.
- Late checkout strip: above a `rgba(255,255,255,0.18)` top border, `padding-top: 36px`. Gold eyebrow `Extended Departure`, `h3` `Need a slower morning?`, body, and **Ask about late checkout ↗** (gold).

### 1.7 Nearby highlights

Eyebrow `Local Convenience`, `h2` `Nearby Highlights`, link **Open property map ↗** (Google Maps at `28.872883,-82.093933`). Three cards: `1px solid #D2DBE6` with `border-left: 4px solid #D4AF37`, radius 14, `#F5F8FB`, `padding: 22px 24px`. Faint kicker, Playfair `h3`, body.

Dining → Breakfast & Coffee · Convenience → Fuel & Travel Essentials · Explore → Local Attractions & Dining.

### 1.8 Gallery (`#gallery`)

Ten figures, `repeat(5, minmax(0,1fr))`, `gap: 12px`. Each: radius 12, `background: #C9D4E1`, `overflow: hidden`; image `height: 150px`, `object-fit: cover`; caption `padding: 11px 12px`, `0.72rem`, 600, uppercase, tracking 0.1em, `#475569`.

Order: Front Entrance & Canopy · Two Queen Guest Room · One King Guest Room · Outdoor Heated Pool · Picnic Lawn & Grills · Daybreak® Breakfast Room · Business Center · Hospitality Suite · Fridge & Microwave · Guest Bath. Every image needs the descriptive `alt` text from the prototype — they are in the file, use them.

### 1.9 FAQ

Two columns `minmax(0,0.7fr) minmax(0,1fr)`, `gap: 40px`. Left: eyebrow `Before You Book` + `h2`. Right: a `dl`; each entry `border-bottom: 1px solid #C6D1DE`, `padding: 20px 0`, `dt` `1.02rem` 700 `#004986`, `dd` `0.94rem` `#475569`.

Five questions: distance from I-75 · breakfast · pets · truck and RV parking · how Wyndham Rewards member rates and points work. Copy is final — the rewards answer in particular is deliberately non-committal about rates.

### 1.10 Wyndham Rewards (full-bleed `#00243F`)

`padding: 64px 40px`. Gold eyebrow, `h2` `Book through Wyndham. Earn points on qualifying stays.` (`2rem`, `max-width: 40rem`), body, then **Book on Wyndham.com ↗** (gold, `#00243F` text) and **Join Wyndham Rewards ↗** (outline).

Three columns above a `rgba(255,255,255,0.15)` top border: faint kicker, gold `0.98rem` title, `rgba(255,255,255,0.7)` body. Closing legal paragraph (`0.78rem`, `max-width: 60rem`) with an underlined link to the Wyndham Rewards terms.

**All rewards copy and the legal paragraph are compliance-reviewed. Do not rewrite, shorten, or make the earning claim more specific.**

### 1.11 Location & access (`#location`)

Two equal columns, `gap: 20px`, `align-items: start`.

- Left card (`#F5F8FB`, radius 16, `padding: 26px 28px`): property name, address `551 East SR 44, Wildwood, FL 34785`, the I-75 Exit 329 paragraph, then a `Turn-by-Turn GPS Navigation` label and three outline buttons — **Google Maps ↗**, **Apple Maps ↗**, **Waze ↗**, each a deep link to `28.872883,-82.093933`. Closing line about free parking for cars, SUVs, buses, RVs and commercial trucks.
- Right: faint label `On-Site Highlights · Property Amenities`, then a 2×2 grid of four small cards (gold `0.6rem` tag, `0.98rem` 700 `#004986` name, body) — Courtyard / Lobby / Free Parking / On-Site. Below, a 2-column pair: a `#004986` link card carrying the address and `(Right off I-75 Exit 329)`, and a `#F5F8FB` card for the Wi-Fi network `DaysInn_Guest` plus a `tel:+13527487766` front desk link.

### 1.12 Footer

`#004986`, `padding: 44px 40px`. Repeat the header lockup on the left; on the right the gold eyebrow `Warm hospitality · Effortless service`. Below, the franchise-disclosure paragraph at `0.76rem`, `rgba(255,255,255,0.45)` — **verbatim, on every page**.

---

## Screen 2 — Staff phone app (8 screens)

Frame in the prototype: `width: 390px`, `1px solid #8B9CB3`, radius 32, `overflow: hidden`. **The frame, its shadow, and the numbered captions are prototype presentation — do not build them.** Build the screens as the responsive mobile layout of the housekeeping route.

Every touch target is ≥48px; primary actions are 54–56px; the name-picker and claim rows are 64px.

Status bars in the mock (`7:58`, `2:33`, `4:12`) are illustrative of the OS bar. The in-app right-hand status indicator (`Online` / `All synced` / `Wildwood I-75`) **is** part of the app.

### 2.1 Install

Shown once, from the manager's invite link. Card is the PWA install prompt (`src/components/pwa-install-prompt.tsx`).

- Logo on a white plate, radius 18, `padding: 14px 16px`, logo `height: 40px`.
- `h2` `Add Guest Hub to your phone`; body: `Installing keeps you signed in, works when Wi-Fi drops, and lets the front desk send you room alerts.`
- Three benefit rows (`#D8E1EC`, `1px solid #9FAEC2`, radius 12, `padding: 14px 16px`), each with a 26px `#004986` tile holding a gold Lucide `Check`: *Stay signed in between shifts* · *Keeps working when Wi-Fi drops* · *Get room alerts from the front desk*.
- **Add to Home Screen** — full width, `min-height: 54px`, `#004986`, `#fff`, radius 14. Below it the Share-menu fallback line, then a text-only **Continue in browser**.

Fires the `beforeinstallprompt` flow where available; on iOS Safari show the Share-sheet instructions since the event does not fire.

### 2.2 Name picker

No email, no password — a housekeeper signs on with wet hands in a corridor.

- Blue header: time + `Wildwood I-75`, logo plate, `h2` `Good morning`, `Tap your name to start your shift.`
- Label `On the schedule today`, then one 64px button per person: 40px circular avatar with initials, name (`1rem`, 700), role line (`0.8rem`), right-aligned tag. Selected row: `background: #004986`, name `#fff`, role `rgba(255,255,255,0.7)`, tag gold, avatar gold with `#004986` initials. Unselected: `#D8E1EC` on `1px solid #9FAEC2`, name `#004986`, avatar `#C9D4E1`.
- Footer button **I'm not on this list** (outline, 48px) → tells the guest they may be scheduled under a different date and to call the desk.

Sample crew: Marisol Reyes (Housekeeping · Main floor 1 · 8 rooms), Ana Guzmán (Main floor 2 · 12 rooms), Teresa López (Building 2 · 10 rooms), Dana Price (Front desk · 7–3 · On desk), Luis Ortega (Maintenance · on call · 2 tickets).

**The list is today's schedule only.** Do not show the full staff roster.

### 2.3 PIN

Background `#00243F`.

- **Not you?** back affordance (Lucide `ChevronLeft`) clears the pick.
- 64px gold circular avatar with initials, `h2` with the person's name, hint `Enter your 4-digit PIN` → `Signing you in…` when four digits are entered.
- Four 16px dots, `gap: 14px`: empty is `2px solid rgba(255,255,255,0.35)` on transparent; filled is gold border and gold fill.
- 3×4 keypad, `gap: 12px`, each key `min-height: 62px`, radius 14. Digits: `rgba(255,255,255,0.1)` on `1px solid rgba(255,255,255,0.2)`, `1.5rem`, 600, `#fff`, tabular-nums. `Clear` (`0.8rem`) and `⌫` (`1.1rem`): transparent on `1px solid rgba(255,255,255,0.12)`, `rgba(255,255,255,0.6)`.
- **Forgot PIN — text the front desk** (text only, 44px) → sends a reset request to the desk; a manager resets in seconds, no new invite link.

Auto-submit on the fourth digit. Never reuse a PIN across people — room work is recorded under whoever signed in.

### 2.4 Shift start

- Blue header: time, `Online` indicator with a `#34D399` dot, gold eyebrow `Thursday · 8:01 AM`, `h2` `Start your shift`, and the pre-assignment line.
- **Assigned to you** card: label + `8 rooms · ~5h 20m` (estimate at a 40-minute average turn — label it as a guide, not a target). Below, a wrapping row of room chips: `#C9D4E1`, `1px solid #9FAEC2`, radius 10, `padding: 9px 12px`, 8px status dot + room number, `0.9rem`, 700, tabular-nums.
- **Unclaimed nearby · tap to add**: 64px rows with a 28px checkbox (unchecked `2px solid #8B9CB3` transparent; checked `#004986` fill with a white Lucide `Check`), room number at `1.15rem`, note, and a short status label in the status colour. Selected row: `#C9D4E1` on `1px solid #004986`.
- Primary **Start shift · {8 + claimed} rooms** — gold, `#004986`, 56px, radius 14. The count is live.

Claiming writes the claimer's name onto the room so two people cannot double up.

### 2.5 Route (the app's home)

- Light header strip (`#D8E1EC`, bottom `1px solid #9FAEC2`): logo plate + name + 28px avatar.
- **Do this next** panel (`#004986`, radius 18, `padding: 22px`): gold eyebrow, right-aligned pill `Front desk priority` (`rgba(212,175,55,0.2)` bg, gold text); room number at `3.4rem` beside `Guest arriving 4 PM` in gold; a one-line condition summary; then **Start room 114** — gold, 54px, radius 12, `1.02rem`, 700.
- **Your shift** card: label + `4 of 11 done · since 8:02 AM`, then a 7px `#B4C2D2` track with a `#D4AF37` fill.
- **Rest of your route · 6**: 64px rows — a `40×5px` rounded status bar, room number at `1.5rem`, a flexible note, and a status chip (`#C9D4E1` bg, status-colour text, `0.62rem`, 700, uppercase).
- **Bottom tab bar** (`#D8E1EC`, top `1px solid #9FAEC2`): four equal items, `min-height: 60px`, `padding: 12px 0 18px`, 21px icon + `0.6rem` uppercase label. Active `#004986`, inactive `#5C6B82`. Tabs: **Route** (`Footprints`), **Map** (`Map`), **Issues** (`Wrench`), **Shift** (`Clock`).

Route order is computed by the front desk's priority, not by room number. When the desk reprioritises, the list reorders live — animate it, and surface the change as 2.6.

### 2.6 Push alert

Two halves, both real behaviour:

- **Lock screen** (illustration): the standard OS notification. Title `Room 114 moved to the top of your route`, body `Guest arriving 4 PM. Dana P. marked it priority.` A second, dimmer card shows an older alert (`Room 118 reported no AC`, 12m ago). Write the notification payload so the title alone is actionable — most staff read it without unlocking.
- **In the app**: a gold-tinted banner (`rgba(212,175,55,0.14)` on `1px solid rgba(212,175,55,0.5)`, radius 14) with `Route changed` / `just now`, headline `114 is now your next room`, body `113 stays on your list, just after it.`, and two buttons — **Go to 114** (gold, 48px) and **Later** (outline).

**Later** must not silently drop the change: the route is already reordered; Later only dismisses the banner.

Notification permission is requested on the install screen, not mid-shift.

### 2.7 Offline

The property has dead spots in Building 2 and some stairwells. Offline is a first-class state, not an error.

- **Banner**: `background: #8A5A12`, `padding: 14px 20px`, a `#FBE3A8` Lucide `WifiOff`, title `No signal in Building 2` and body `Keep working. Your 3 changes send as soon as you're back in range.` The count is live.
- **Waiting to send · 3** card: label + `Last sync 2:11 PM`; rows divided by `1px solid #BFCAD8` with a `#8A5A12` Lucide `Clock`, an action title, a `Saved on this phone` note, and a timestamp. Closing reassurance: `Nothing is lost — these are saved on your phone.`
- **Still available offline**: three rows each with a 26px `#0F7B4F` tile and a white `Check` — the full route and room notes, marking rooms clean or flagging issues, taking photos for a maintenance ticket.
- **Try syncing now** (outline, 52px) — a manual retry; the queue also drains automatically.

Queued mutations must survive a force-quit and a reboot. Photos queue too — show their size (the prototype shows `1 image · 240 KB`) so a housekeeper on cellular understands the wait.

### 2.8 Clock out

- Blue header: time, `All synced` with a `#34D399` dot, gold eyebrow `Shift complete`, `h2` `Nice work, Marisol`, and the hours line `8:02 AM – 4:12 PM · 8h 10m on the clock`.
- 2×2 summary cards (`#D8E1EC`, radius 14): Rooms turned 11 (*of 11 assigned*) · Avg per room 34m (*4m under target*) · Issues flagged 2 (*118 AC, 116 lamp*) · Priority turns 3 (*all before arrival*).
- **Left for the next shift** card: rows with a `26×4px` status bar, room number, and a note — blocked rooms, DND rooms never opened, rooms turned but not inspected. This is the handover; it is generated, not typed.
- **Clock out** (`#004986`, 56px), then `You'll stay signed in — tomorrow just tap your PIN.` and a text-only **Sign out of this phone** for a device handback.

Block clock-out — or warn hard — if the offline queue is not empty. The desk needs to know the board is behind.

---

## Interactions & Behavior

### Guest homepage

- Nav links are in-page anchors; add `scroll-margin-top` for the sticky header. **Do not use `scrollIntoView`.**
- The booking bar is a **snapshot**, not a booking engine. Submitting hands off to the Wyndham flow with the chosen dates and occupancy as query params. Never show a price the property cannot honour, and keep the disclaimer visible in the same block as the button.
- Request cards require an in-house guest: signed-out taps route to **Sign in to your room** (room number + last name), then straight back to the chosen request type. A submitted request lands in the ops portal queue as `New`.
- **Track a request** shows the guest's own open requests and their status changes — the same state the desk sees.
- Gallery: click opens a lightbox if the codebase has one; otherwise no interaction. Do not add a carousel.
- All external links (`↗`) open in a new tab with `rel="noopener"`.

### Phone app

- Auth: name picker → PIN → shift start. Session persists across shifts on the device; only **Sign out of this phone** clears it.
- Wrong PIN: shake the dots, clear, and count attempts; five failures notify the desk rather than locking the person out mid-shift.
- **Start room** starts a timer and swaps the panel's action to **Mark clean**. **Flag issue** opens a ticket prefilled with the room and the camera ready. **Skip** demands a reason for arrival-linked rooms.
- Marking a room clean puts it on sale within a minute — treat the tap as consequential: no undo affordance beyond an immediate 5-second window.
- All mutations are optimistic and queued; the offline banner and `Waiting to send` count are driven by the queue length.
- Realtime: route reorders, new priorities and unassigned-room claims push over the existing channel. Reorder with animation, never a hard swap, and never while the user's finger is down.

### Responsive

| Width | Guest homepage | Phone flow |
| --- | --- | --- |
| ≥1180px | As specified | n/a |
| 900–1180px | Sections keep 40px gutters; rooms and gallery drop a column (3→2, 5→4) | n/a |
| 640–900px | Single-column sections; booking bar stacks to 2×2 with a full-width button; gallery 3 columns | n/a |
| <640px | Header collapses to logo + **Book direct**; nav becomes a sheet; all grids single-column; gallery 2 columns | This is the phone flow — full-bleed, no frame, `env(safe-area-inset-bottom)` on the tab bar |

---

## State Management

Guest homepage (new presentation state):

| State | Type | Notes |
| --- | --- | --- |
| `snapshotQuery` | `{ checkIn, checkOut, guests }` | Hero bar. Defaults: today, +2 nights, 2 adults. |
| `guestSession` | `{ roomNumber, lastName } \| null` | Gates the request cards. |
| `activeRequestType` | request type key `\| null` | Which request sheet is open. |

Phone app:

| State | Type | Notes |
| --- | --- | --- |
| `pickedStaffId` | `id \| null` | Name picker. |
| `pinEntry` | `string` | Max 4, cleared on submit. Never persisted. |
| `claimedRoomIds` | `id[]` | Shift-start claims, before Start shift commits them. |
| `shiftId` | `id \| null` | Set by Start shift, cleared by Clock out. |
| `hkTab` | `'route' \| 'map' \| 'issues' \| 'shift'` | Bottom tabs. |
| `mutationQueue` | queued action[] | Persisted (IndexedDB). Survives reload and force-quit. |
| `online` | `boolean` | Drives the banner. |

Derived: `nextRoom` (front-desk priority), `shiftProgress`, `queueCount`, `estimatedRemaining` (40 min × rooms left), `handoverRooms` (blocked / DND / uninspected at clock-out).

Data requirements — all present in the source app:

- Rooms with status, wing, floor, bed type, assigned staff, timestamps.
- Requests with type, status, room, guest, opened/started/resolved times and actor.
- Staff with role, zone, today's schedule and PIN hash.
- Reservations with arrival/departure times and assigned rooms.
- Realtime subscription on rooms and requests; web push for staff devices.

---

## Assets

| Asset | Notes |
| --- | --- |
| `assets/days-inn-logo.png` | 1045×543 PNG, transparent, **dark artwork**. Always on a white or `#004986` plate — never `filter: invert()`. |
| `assets/p-exterior-dusk.avif` | Hero background. Used at `opacity: 0.55` under the gradient. |
| `assets/p-exterior-day.avif`, `p-king.avif`, `p-king-wide.avif`, `p-two-queen.avif`, `p-suite.avif`, `p-suite-alt.avif`, `p-pool.avif`, `p-pool-lawn.avif`, `p-breakfast.avif`, `p-business.avif`, `p-amenity.avif`, `p-bath.avif` | Room cards, amenities and gallery. Real property photography. |
| `assets/exterior.webp` | Lock-screen wallpaper on the push screen, `opacity: 0.35`. Illustrative only. |

Icons: `lucide-react`. Used here — `Check`, `ChevronLeft`, `WifiOff`, `Clock`, `Footprints`, `Map`, `Wrench`. The status-bar glyphs in the phone mocks are OS chrome, not app icons.

---

## Files

| File | What it is |
| --- | --- |
| `Guest Homepage.dc.html` | The guest-facing homepage. |
| `Staff Phone App.dc.html` | The eight-screen phone flow. The PIN keypad and shift-start claim rows are interactive — try them. |
| `assets/` | Logo and property photography. |
| `support.js` | Prototyping runtime. **Not part of the design** — ignore it. |

Open the HTML files directly in a browser.

### Where this lands in the source repo

| Design | Repo file |
| --- | --- |
| Guest homepage | `src/routes/index.tsx` |
| Phone route / shift views | `src/routes/housekeeping.tsx` |
| Install prompt | `src/components/pwa-install-prompt.tsx` |
| Push alerts | `src/lib/device-push.ts` |
| Room status model | `src/lib/room-model.ts` |
| Colour + font tokens | `src/styles.css` (`@theme` block) |
| Shared primitives | `src/components/ui/button.tsx`, `badge.tsx`, `card.tsx` |
| Brand lockup | `src/components/brand-lockup.tsx` |

The four guest request types on the homepage and the request types in the ops portal queue are one list. Define them once (`src/lib/`) and read from both, or they will drift.
