adding in design files
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
# Admin spec — parent phone card
|
||||
|
||||
Screens `1d`–`1i`. One card, `nestquest-admin-card`, four tabs. Reference viewport
|
||||
390×844. Plain CubeCraft styling and plain domain words — no parchment, no Cinzel, no
|
||||
quest vocabulary in this surface.
|
||||
|
||||
## 1. Shell
|
||||
|
||||
- Page `--nq-a-page`; cards `--nq-a-surface` with 1px `--nq-a-border`.
|
||||
- **Header** white, 1px bottom border: screen title 24px/800, tracking −.02em, plus a
|
||||
12px/600 `--nq-a-ink-secondary` sub-line. Optional trailing action (icon square 36px,
|
||||
or a gradient `New` button).
|
||||
- **Tab bar** absolute bottom, `--nq-a-tabbar-height` 70px + 12px bottom padding, white,
|
||||
1px top border, 4 items: `house` Today · `list-checks` Tasks · `calendar-days` Schedule ·
|
||||
`history` History. Active icon and label `--nq-brand-blue` at 700; inactive icon
|
||||
`--nq-a-ink-tertiary`, label `--nq-a-ink-secondary` 600.
|
||||
- **Every scroll column ends with 92px bottom padding** so content clears the tab bar.
|
||||
This was a real defect in review — do not omit it.
|
||||
- Two densities exist. Ship **compact**; `--nq-a-density-*` carries the roomy values.
|
||||
- Everything this card mutates goes through a NestQuest service, which enforces the admin
|
||||
allowlist server-side. The card must assume it can be rendered by a non-admin and still
|
||||
be safe — hiding controls is not the boundary (D-003).
|
||||
|
||||
## 2. Today (1d compact, 1h roomy)
|
||||
|
||||
### 2.1 Header
|
||||
Title `Today`; sub `<weekday>, <Month D> · cycle day N of 14`; trailing `settings` square.
|
||||
|
||||
### 2.2 Stat row
|
||||
Three equal cards, 8px gap, padding 12px: numeral 22px/800 (done in `--nq-brand-blue`,
|
||||
remaining in `--nq-a-ink`, overdue in `--nq-a-danger`), label 10px/600 uppercase tracking
|
||||
.08em `--nq-a-ink-secondary` — `Done`, `Remaining`, `Overdue`.
|
||||
|
||||
### 2.3 Child rows
|
||||
One card, rows divided by `--nq-a-divider`, row padding 11px 13px:
|
||||
30px gradient avatar square (radius 7px, initial 13px/800 white) · name 14px/700 ·
|
||||
meta 11px/600 (`3 of 7 · 1 overdue`; all-done in `--nq-a-success`; away reads
|
||||
`Away · returns <Mon D>`) · 82×6px progress track with gradient fill. An away child's
|
||||
avatar is flat `#9898A8` and the row carries a lowercase `override` pill when the absence
|
||||
comes from a presence override rather than the pattern.
|
||||
|
||||
### 2.4 Roomy variant (1h)
|
||||
Header becomes a hero: kicker 11px/700 uppercase, `8 of 12 done` 32px/800, 10px gradient
|
||||
progress bar, 13px/600 sub-line. Each child gets its own 12px-radius card with
|
||||
`0 4px 12px rgba(0,0,0,.06)`, 48px avatar, 19px/800 name, right-aligned `3/7` +
|
||||
status line, and its overdue item inlined as a `--nq-a-danger-bg` row with a
|
||||
`Mark done` action.
|
||||
|
||||
### 2.5 Needs attention
|
||||
Section label 11px/700 uppercase, then one card of event rows: Lucide glyph 18px ·
|
||||
title `<Quest> · <Child>` 13px/700 · meta 11px/600 (`Overdue since 9:00 AM` in
|
||||
`--nq-a-danger`; `Completed 7:04 AM from panel` in `--nq-a-ink-secondary`) · trailing
|
||||
text action `Mark done` (`--nq-brand-blue`) or `Undo` (`--nq-brand-purple`).
|
||||
|
||||
### 2.6 Permission note
|
||||
An info strip (`--nq-a-info-bg`, `info` glyph, 11.5px/600 `--nq-a-info-ink`):
|
||||
"Undo is admin-only. A panel tap can never reverse a completion." Keep this copy — it is
|
||||
the one place the security model is explained to the user.
|
||||
|
||||
## 3. Definitions (1e)
|
||||
|
||||
### 3.1 List
|
||||
Header `Tasks` / `7 definitions · 3 children` + gradient `New` button. Filter chips row
|
||||
(All / one per child): active `#18181D` fill white text, inactive white with border.
|
||||
Rows: glyph 17px · title 13.5px/700 · meta 11px/600 `<assignees> · <recurrence> · <windows>`
|
||||
· `chevron-right`. An inactive definition renders the whole row at
|
||||
`--nq-a-ink-tertiary` with `· inactive` in the meta — never hard-deleted (glossary).
|
||||
The row being edited takes `--nq-a-selected` with brand-blue glyph, `Editing` meta and
|
||||
`chevron-down`.
|
||||
|
||||
### 3.2 Edit sheet
|
||||
Bottom sheet, `--nq-a-radius-sheet`, `--nq-a-sheet-shadow`, 38×4px grabber, padding
|
||||
14px 18px 24px. Title 19px/800. Fields, 11px gap, each with a 10px/700 uppercase label:
|
||||
|
||||
| Field | Control |
|
||||
|---|---|
|
||||
| Assigned children | multi-select row → sheet; shows `Declan` or `All three` |
|
||||
| Repeats | select (Daily / Weekly / Monthly / Yearly / Custom + interval) |
|
||||
| Due time | time field per window |
|
||||
| Window | 3-up segmented, **multi-select** — a definition may own several |
|
||||
| Skip on away days | toggle, gradient when on, sub "No instance when the child is absent" |
|
||||
|
||||
Footer: `Cancel` (flex 1, bordered) + `Save changes` (flex 2, gradient), both 13px vertical
|
||||
padding. Sheet enters over the dimmed list in `--nq-dur-modal`.
|
||||
|
||||
### 3.3 Icon picker
|
||||
Each definition carries a Lucide glyph, shown on both surfaces. **The allowed subset is not
|
||||
yet defined** — pick 24–40 household-relevant glyphs and ship them as a grid picker.
|
||||
|
||||
## 4. Schedule (1f)
|
||||
|
||||
- Header `Schedule` / `2-week cycle · anchor <weekday>, <Mon D>`.
|
||||
- **Month grid** card: month label 11px/700 uppercase + chevron pair; weekday initials
|
||||
10px/700 `--nq-a-ink-tertiary`; day cells `aspect-ratio: 1`, radius 6px —
|
||||
rotation-home days `--nq-a-selected` with `#201F7A` numerals, away days
|
||||
`--nq-a-page` with `--nq-a-ink-secondary`, override days `--nq-a-warning-bg` with
|
||||
`--nq-a-warning-ink` and a 1px warning border, today filled with the brand gradient in
|
||||
white 800. Legend row beneath, 10.5px/600, one swatch per state.
|
||||
- **Presence pattern** card: one row per child, name 13px/700 + rule 12px/600
|
||||
(`Weeks 1 & 3 of cycle`, `Every day`).
|
||||
- **Overrides** card: `Add` text action; rows with `calendar-x` / `calendar-check`,
|
||||
title `<Child> away · <Mon D – D>`, meta reason, trailing `trash-2`.
|
||||
- Cycle position is always computed from the anchor date. **Never** from ISO week numbers
|
||||
or week parity (D-004).
|
||||
|
||||
## 5. History (1g)
|
||||
|
||||
- Header `History` / `Append-only event log · last 14 days` + bordered `CSV` button
|
||||
(`download` glyph) that exports the filtered range.
|
||||
- Stat row: `91%` On time · `128` Completed · `7` Missed, numerals 20px/800.
|
||||
- Filter chips: `All events` / `Reversals` / `Missed`.
|
||||
- Day-grouped sections (label 11px/700 uppercase) of event rows: 7px status dot
|
||||
(green completed, `--nq-a-reversal` un-completed, `--nq-a-danger` missed) ·
|
||||
title `<Quest> · <Child>` 12.5px/700 · meta 10.5px/600 giving event type, actor and
|
||||
on-time flag (`completed · panel (Declan) · on time`, `uncompleted · joshua (admin)`,
|
||||
`missed · nightly sweep`, `completed · panel (Declan) · late 22 min`) · time 11px/600.
|
||||
- Footer strip (`--nq-a-page`, `lock` glyph): "Events are never edited or deleted. A
|
||||
reversal is its own row." Rows are never editable in the UI (D-005).
|
||||
|
||||
## 6. Presence override editor (1i)
|
||||
|
||||
Pushed screen with a back chevron; title `Presence override` / sub "Beats the custody
|
||||
pattern for these dates".
|
||||
|
||||
- Form card (roomy density, 18px padding, 16px gaps):
|
||||
**Child** 3-up segmented, selected = gradient;
|
||||
**Status for these dates** 2-up segmented (`Away` / `Home`), selected = `#18181D`;
|
||||
**From** / **Through** date fields side by side, 13px padding, 14px/700 values;
|
||||
**Reason (optional)** text field.
|
||||
- **Consequence warning** — `--nq-a-warning-bg` card with `alert-circle`:
|
||||
headline `This removes N upcoming tasks` 13.5px/700 `--nq-a-warning-ink`, body 12px/600
|
||||
`--nq-a-warning-ink-2` naming the child, the date range, and stating "Completed days are
|
||||
untouched." The count must be computed live from the materialiser before saving.
|
||||
- Footer: `Cancel` (flex 1, white, bordered) + `Save override` (flex 2, gradient), 15px
|
||||
vertical padding.
|
||||
- Saving must never delete an instance that already has a completion event.
|
||||
@@ -0,0 +1,82 @@
|
||||
# NestQuest — design handoff
|
||||
|
||||
Approved UI design for the NestQuest Home Assistant integration, ready to implement.
|
||||
Source of truth for visuals: the mockup file `NestQuest Mockups.dc.html` (9 screens,
|
||||
option ids `1a`–`1j`). This folder is the written form of those screens.
|
||||
|
||||
## What is in here
|
||||
|
||||
| File | Contents |
|
||||
|---|---|
|
||||
| `PANEL-SPEC.md` | Kids' DAKOS wall panel: party board, quest log, confirm, quest complete |
|
||||
| `ADMIN-SPEC.md` | Parent phone admin: today, definitions, schedule, history, overrides |
|
||||
| `ENTITIES-AND-SERVICES.md` | Every screen mapped to the HA entities, services and events it needs |
|
||||
| `IMPLEMENTATION-ORDER.md` | Build order, with the decisions that change existing code first |
|
||||
| `tokens/nestquest-panel-tokens.css` | Panel card custom properties |
|
||||
| `tokens/nestquest-admin-tokens.css` | Admin card custom properties |
|
||||
|
||||
## Screen index
|
||||
|
||||
| id | Screen | Surface | Spec |
|
||||
|---|---|---|---|
|
||||
| 1a | The Party (attract) | panel 1920×1080 | PANEL §2 |
|
||||
| 1b | Quest Log | panel 1920×1080 | PANEL §3 |
|
||||
| 1j | Complete confirm | panel 1920×1080 | PANEL §4 |
|
||||
| 1c | Quest complete | panel 1920×1080 | PANEL §5 |
|
||||
| 1d | Today (compact) | phone 390×844 | ADMIN §2 |
|
||||
| 1e | Definitions + edit sheet | phone 390×844 | ADMIN §3 |
|
||||
| 1f | Schedule + custody | phone 390×844 | ADMIN §4 |
|
||||
| 1g | History + CSV | phone 390×844 | ADMIN §5 |
|
||||
| 1h | Today (roomy) | phone 390×844 | ADMIN §2.4 |
|
||||
| 1i | Presence override | phone 390×844 | ADMIN §6 |
|
||||
|
||||
## Design decisions taken during this handoff
|
||||
|
||||
These were open in CTXD and are now settled. Several contradict the current repo and
|
||||
docs — read `IMPLEMENTATION-ORDER.md` §1 before writing code.
|
||||
|
||||
1. **`quest_*` naming throughout.** The domain model is renamed from `task_*` to
|
||||
`quest_*` in DB, services, entities and UI. Migration note in IMPLEMENTATION-ORDER §1.1.
|
||||
2. **Instance key becomes `(definition_id, child_id, due_date, window)`.** Required by
|
||||
multi-assignee definitions and by twice-daily quests. Supersedes the documented
|
||||
`(definition_id, due_date)`.
|
||||
3. **A definition may have multiple assignees**, and materialises one instance per
|
||||
assigned child per date per window. Each child completes their own.
|
||||
4. **A definition may declare more than one window** (morning / afternoon / evening),
|
||||
producing one instance per window per day.
|
||||
5. **Missed quests vanish from the panel at rollover.** Kids never see a wall of failure;
|
||||
the missed event is in the parent's history only.
|
||||
6. **Three Lovelace cards**: `nestquest-party-board-card`, `nestquest-quest-log-card`,
|
||||
`nestquest-admin-card`. Board and log live in separate Lovelace views; a crest tap
|
||||
navigates.
|
||||
7. **Completion needs a confirm step** (screen 1j) because children cannot undo.
|
||||
8. **The quest log owns idle return**: 40 s of no touch navigates back to the board.
|
||||
TouchHub Auto-Return must be configured longer than 40 s so the two do not fight.
|
||||
9. **Actor on a panel completion** is `panel` plus the tapped child profile, per glossary.
|
||||
10. **Weather is a configured entity** on the party board card (`weather_entity`), not
|
||||
NestQuest data.
|
||||
11. **Fonts are bundled** as local woff2 in the card's `www/` folder — the panel may be
|
||||
offline. Nunito (400/600/700/800) and Cinzel + Cinzel Decorative.
|
||||
|
||||
## Vocabulary
|
||||
|
||||
The panel speaks tabletop; the admin speaks plainly. Both sit on the same `quest_*` model.
|
||||
|
||||
| Model / admin | Panel display string |
|
||||
|---|---|
|
||||
| quest instance | quest |
|
||||
| child | adventurer |
|
||||
| child's task list | Quest Log |
|
||||
| household | The Party |
|
||||
| all complete | Quest complete |
|
||||
| absent | On travels |
|
||||
|
||||
## Open questions
|
||||
|
||||
- Empty and error states are unspecified by request (child with no quests, everyone away,
|
||||
integration unconfigured, DB unreachable). Panel must not render a blank parchment —
|
||||
decide before shipping the card.
|
||||
- No gamification is in scope. XP, levels, streaks and rarity were explicitly deferred,
|
||||
but the append-only event log already supports computing them later.
|
||||
- Icon per quest definition is chosen by the parent from a Lucide subset; the subset is
|
||||
not yet defined (`ADMIN-SPEC.md` §3.3).
|
||||
@@ -0,0 +1,117 @@
|
||||
# Screens → HA entities, services and events
|
||||
|
||||
Planned surface from CTXD CONTEXT.MD, adjusted for the design decisions in
|
||||
`DESIGN-HANDOFF.md`. Names use the `quest_*` model.
|
||||
|
||||
## 1. Entities the cards read
|
||||
|
||||
| Entity | Type | Used by |
|
||||
|---|---|---|
|
||||
| `sensor.nestquest_<child>_quests_due_today` | int | 1a plate progress, 1b counts, 1d stats |
|
||||
| `sensor.nestquest_<child>_quests_completed_today` | int | 1a, 1b, 1c, 1d, 1h |
|
||||
| `sensor.nestquest_<child>_quests_remaining_today` | int | 1b remaining block, 1d |
|
||||
| `sensor.nestquest_<child>_completion_pct_today` | float | progress bars |
|
||||
| `sensor.nestquest_<child>_next_quest` | str + attrs | optional panel hint |
|
||||
| `binary_sensor.nestquest_<child>_all_done` | bool | 1c trigger, 1d "all done" |
|
||||
| `binary_sensor.nestquest_<child>_present_today` | bool | 1a away plate, 1d away row |
|
||||
| `sensor.nestquest_household_quests_due_today` | int | 1b party line, 1c party stat |
|
||||
| `sensor.nestquest_household_quests_completed_today` | int | same |
|
||||
| `sensor.nestquest_cycle_day` | int | 1d sub-line, 1f header |
|
||||
| *configured* `weather.<entity>` | HA core | panel dock |
|
||||
|
||||
Per-instance data is too granular for entity state. The cards read the day's instance list
|
||||
from an attribute payload on the per-child sensor (or a websocket command —
|
||||
implementer's call), shaped:
|
||||
|
||||
```json
|
||||
{
|
||||
"instances": [
|
||||
{ "id": 4821, "definition_id": 12, "child_id": 3, "title": "Fill bird feeder",
|
||||
"icon": "bird", "window": "afternoon", "due_time": "17:00",
|
||||
"state": "open", "overdue": true, "completed_at": null, "on_time": null }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`state` ∈ `open` | `completed`. Missed instances are **omitted** from panel payloads
|
||||
(decision 5) and included in admin payloads.
|
||||
|
||||
## 2. Services the cards call
|
||||
|
||||
| Service | Admin only | Called from |
|
||||
|---|---|---|
|
||||
| `nestquest.complete_quest` | no (panel allowed) | 1j confirm |
|
||||
| `nestquest.uncomplete_quest` | **yes** | 1d `Undo` |
|
||||
| `nestquest.create_quest_definition` | **yes** | 1e `New` |
|
||||
| `nestquest.update_quest_definition` | **yes** | 1e sheet `Save changes` |
|
||||
| `nestquest.set_quest_definition_active` | **yes** | 1e row action |
|
||||
| `nestquest.set_presence_pattern` | **yes** | 1f presence card |
|
||||
| `nestquest.create_presence_override` | **yes** | 1i `Save override` |
|
||||
| `nestquest.delete_presence_override` | **yes** | 1f override row `trash-2` |
|
||||
| `nestquest.export_history_csv` | **yes** | 1g `CSV` |
|
||||
| `nestquest.manage_child` | **yes** | settings |
|
||||
|
||||
`complete_quest` payload from the panel:
|
||||
|
||||
```yaml
|
||||
service: nestquest.complete_quest
|
||||
data:
|
||||
instance_id: 4821
|
||||
actor: panel # kiosk user context
|
||||
actor_child_id: 3 # the tapped profile (decision 9)
|
||||
```
|
||||
|
||||
Every service resolves `call.context.user_id` against the admin allowlist and **fails
|
||||
closed** with no user context (D-003). The panel's kiosk user is never allowlisted, so
|
||||
`uncomplete_quest` is unreachable from the wall even though the card never renders the
|
||||
control.
|
||||
|
||||
## 3. Events the cards listen for
|
||||
|
||||
| Event | Effect |
|
||||
|---|---|
|
||||
| `nestquest_quest_completed` | stamp the seal, re-sort the column, refresh counts |
|
||||
| `nestquest_quest_uncompleted` | un-seal, restore the card (admin action, panel must reflect it) |
|
||||
| `nestquest_quest_missed` | remove the instance from the panel; add a history row |
|
||||
| `nestquest_child_day_complete` | show screen 1c |
|
||||
|
||||
All four come off the `DataUpdateCoordinator`; cards should also refresh on
|
||||
`state_changed` for their sensors so they recover if an event is dropped.
|
||||
|
||||
## 4. Card configuration
|
||||
|
||||
```yaml
|
||||
# kids' panel, view 1
|
||||
type: custom:nestquest-party-board-card
|
||||
weather_entity: weather.home # optional; dock falls back to date/time
|
||||
quest_log_path: /nestquest/log # view the crest tap navigates to
|
||||
child_order: [declan, jordyn, chloe]
|
||||
|
||||
# kids' panel, view 2
|
||||
type: custom:nestquest-quest-log-card
|
||||
board_path: /nestquest/board
|
||||
idle_return_seconds: 40 # must be shorter than TouchHub Auto-Return
|
||||
confirm_timeout_seconds: 15
|
||||
complete_screen_seconds: 12
|
||||
|
||||
# parent phone
|
||||
type: custom:nestquest-admin-card
|
||||
density: compact # compact | roomy
|
||||
default_tab: today
|
||||
```
|
||||
|
||||
The quest log reads the selected child from the view's URL/`hass` path parameter so the
|
||||
board → log hop is a plain Lovelace navigation (decision 6).
|
||||
|
||||
## 5. Data-shape consequences of the design
|
||||
|
||||
1. Instance key is `(definition_id, child_id, due_date, window)` — the schema's
|
||||
`task_instances` unique index must widen.
|
||||
2. `quest_definitions` needs an **assignees** join table, replacing the single
|
||||
`child_id` column.
|
||||
3. `quest_definitions` needs a **windows** set (morning/afternoon/evening) plus an
|
||||
optional due time per window.
|
||||
4. The materialiser emits one instance per (assignee × window × firing date), still
|
||||
idempotent on the widened key, still only when the child is present.
|
||||
5. `completion_events` gains `actor_child_id` so a panel completion records which
|
||||
profile was tapped, while `actor` stays `panel`.
|
||||
@@ -0,0 +1,80 @@
|
||||
# Implementation order
|
||||
|
||||
Written for an agent working in `code.cubecraftlabs.com/Maniacs_Mansion/NestQuest`.
|
||||
Steps 1.x change existing code and must land first; the frontend is step 4 onward.
|
||||
|
||||
## 1. Model changes (breaking, pre-release)
|
||||
|
||||
### 1.1 Rename `task_*` → `quest_*`
|
||||
Nothing is released (main/dev are at "first commit", version 0.1.0), so rename in place
|
||||
rather than aliasing.
|
||||
|
||||
- `schema.py`: `task_definitions` → `quest_definitions`, `task_instances` →
|
||||
`quest_instances`. Keep `completion_events`, `children`, `admin_users`,
|
||||
`schedule_rules`, `presence_schedules`, `presence_overrides`.
|
||||
- `db.py` / `store.py`: rename DAO methods and any SQL literals.
|
||||
- `const.py`: no table names live there today; keep it that way.
|
||||
- `tests/test_schema.py`, `tests/test_store.py`, `tests/test_db.py`: update expectations.
|
||||
- **Migration note:** the versioned migration runner has no released version to upgrade
|
||||
from. Bump the schema version, and make migration 1 create the `quest_*` tables
|
||||
directly. If any dev machine already holds a `nestquest.db` with `task_*` tables, the
|
||||
runner should detect the legacy names and `ALTER TABLE ... RENAME TO` before applying
|
||||
the widened index — a dev-only path, worth ~20 lines and a test.
|
||||
|
||||
### 1.2 Widen the instance key
|
||||
Unique index becomes `(definition_id, child_id, due_date, window)`. Materialisation stays
|
||||
idempotent on that tuple. Add a test for the twice-daily case (one definition, two windows,
|
||||
one child, one date → two rows) and the shared case (one definition, three assignees, one
|
||||
window → three rows).
|
||||
|
||||
### 1.3 Multi-assignee definitions
|
||||
Add `quest_definition_assignees(definition_id, child_id)`. Drop the single `child_id`
|
||||
column on the definition. The "exactly one assigned child" rule in GLOSSARY.MD no longer
|
||||
holds — CTXD has been updated.
|
||||
|
||||
### 1.4 Windows
|
||||
Add `quest_definition_windows(definition_id, window, due_time)` with
|
||||
`window ∈ ('morning','afternoon','evening')`. Window clock ranges are fixed for now:
|
||||
morning ≤ 11:59, afternoon 12:00–17:00, evening 17:00–21:00. Store the ranges in
|
||||
`const.py` so they are configurable later.
|
||||
|
||||
### 1.5 `actor_child_id` on completion events
|
||||
Nullable int. Set for panel completions, null for admin ones. Still append-only.
|
||||
|
||||
## 2. Engines and materialisation
|
||||
Unchanged in intent: pure recurrence engine, pure presence engine with anchor-date
|
||||
arithmetic, daily materialiser over `horizon_days` at `day_rollover_time`. Only the
|
||||
instance fan-out changes (assignees × windows).
|
||||
|
||||
## 3. Services, permissions, entities
|
||||
Implement the service table in `ENTITIES-AND-SERVICES.md` §2 behind the permission
|
||||
decorator, then the sensors and binary sensors in §1, then the four events in §3.
|
||||
`complete_quest` is the only service a non-admin context may call.
|
||||
|
||||
## 4. Frontend groundwork
|
||||
1. Create `custom_components/nestquest/www/`.
|
||||
2. Bundle fonts as woff2: Nunito 400/600/700/800; Cinzel 600/700/900; Cinzel Decorative
|
||||
700/900. Declare `@font-face` with `font-display: swap` in a shared
|
||||
`nestquest-fonts.css`. No CDN — the panel may be offline.
|
||||
3. Copy `design/tokens/nestquest-panel-tokens.css` and
|
||||
`design/tokens/nestquest-admin-tokens.css` in as the cards' `:host` blocks.
|
||||
4. Register the three cards with `customCards` and ship editors later; hand-written YAML
|
||||
is fine for v1.
|
||||
|
||||
## 5. Cards, in this order
|
||||
1. `nestquest-party-board-card` (screen 1a) — read-only, proves the entity payload.
|
||||
2. `nestquest-quest-log-card` (1b) — read-only first, no completion.
|
||||
3. Confirm dialog + `complete_quest` (1j) with optimistic seal and revert-on-failure.
|
||||
4. Quest complete screen (1c) driven by `nestquest_child_day_complete`.
|
||||
5. Idle return (40 s) and the documented TouchHub Auto-Return constraint.
|
||||
6. `nestquest-admin-card`: Today (1d) → Definitions + sheet (1e) → Schedule (1f) →
|
||||
History + CSV (1g) → Presence override (1i).
|
||||
|
||||
## 6. Before shipping
|
||||
- `use_x_frame_options: false` is required for TouchHub embedding — document the
|
||||
clickjacking trade-off next to the setting, per D-006.
|
||||
- Verify no NestQuest control in the dock strip is tappable.
|
||||
- Verify the kiosk HA user is absent from the admin allowlist, and that
|
||||
`uncomplete_quest` denies it with a logged denial.
|
||||
- Empty and error states are still unspecified (see DESIGN-HANDOFF "Open questions").
|
||||
Do not ship a card that renders a blank parchment.
|
||||
@@ -0,0 +1,170 @@
|
||||
# Panel spec — kids' DAKOS wall panel
|
||||
|
||||
Screens `1a`, `1b`, `1j`, `1c` of the mockups. Two cards:
|
||||
`nestquest-party-board-card` (§2) and `nestquest-quest-log-card` (§3–5).
|
||||
|
||||
## 1. Frame and constraints
|
||||
|
||||
- **Canvas** 1920×1080, landscape, fixed. No scrolling — content must fit. Every screen in
|
||||
the mockups measures exactly 1920×1080 with no overflow; keep it that way.
|
||||
- **Viewing distance** ~3 ft. **No text below 22px.** Meta lines are 22px/600 Nunito;
|
||||
quest titles 30px/700 Cinzel; section heads 32px.
|
||||
- **Contrast** every ink token is ≥4.5:1 on parchment. Do not introduce alpha-muted text.
|
||||
- **Ground** `--nq-p-parchment` + `--nq-p-vignette`, CSS only, no image assets.
|
||||
- **Double frame** inset 26px (`--nq-p-frame-outer`, radius 14px) and inset 36px
|
||||
(`--nq-p-frame-inner`, radius 8px), both `pointer-events: none`.
|
||||
- **Dock** bottom strip, 84px, inset 46px, radius 14px, `--nq-p-dock-bg`. Weather only.
|
||||
**Nothing in the dock is tappable** (D-006).
|
||||
- **No login.** Every action comes from the kiosk HA user; the kiosk user is never in the
|
||||
admin allowlist.
|
||||
|
||||
## 2. The Party — attract state (1a)
|
||||
|
||||
Default view on the wall. Layout top to bottom:
|
||||
|
||||
1. **Wordmark row** at y=64. Rule · d20 hexagon · `NestQuest` (66px/900 display, brand
|
||||
gradient via `background-clip: text`) · d20 · rule. d20 marks are 34px hexagons
|
||||
(`clip-path: polygon(50% 0, 93% 25%, 93% 75%, 50% 100%, 7% 75%, 7% 25%)`) filled with
|
||||
the brand gradient, numeral 15px/700 Cinzel.
|
||||
2. **Kicker** `The Party · <weekday>, <Month D>` — 21px/600 Cinzel, tracking .30em, uppercase.
|
||||
3. **Adventurer plates**, 3-up grid, 56px gap, page inset 110px, top y=262. One plate per
|
||||
child returned by the party sensor, in configured order.
|
||||
4. **Hint line** `Tap your crest to open your Quest Log`, 27px/600 Nunito, y≈930.
|
||||
5. **Dock.**
|
||||
|
||||
### 2.1 Adventurer plate (present)
|
||||
|
||||
Radius 20px, `--nq-p-card-panel`, 2px `--nq-p-panel-border`, `--nq-p-panel-shadow`,
|
||||
padding 44px 28px 40px, contents centred, 26px gap. **The whole plate is the tap target**
|
||||
(≥188px wide, ≥600px tall — far above minimum).
|
||||
|
||||
- **Crest** 188×214, shield via `clip-path: polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%)`,
|
||||
`--nq-p-crest`, inset ring `inset 0 0 0 4px rgba(255,255,255,.22)`, child's initial
|
||||
82px/700 display in white.
|
||||
- **Name** 48px/700 Cinzel, `--nq-p-ink`, tracking .02em.
|
||||
- **Presence pill** radius 9999px, `#e8f4ea` on `rgba(22,120,60,.35)`, `check-circle` 22px
|
||||
`#157a3c`, label `Home today` 19px/600 Cinzel uppercase `#146b36`.
|
||||
- **Progress line** `N of M quests claimed` 26px/700 Cinzel `--nq-p-ink-secondary`.
|
||||
- **Progress bar** full width, 16px, radius 9999px, track `rgba(92,62,26,.18)` with 1px
|
||||
border, fill `--nq-brand-gradient-h`.
|
||||
|
||||
### 2.2 Adventurer plate (away)
|
||||
|
||||
Same geometry, muted: `linear-gradient(#f2ecdd, #e6dcc6)`, **2px dashed** border, no lift
|
||||
shadow. Crest uses `--nq-p-crest-away`; initial stays **full-opacity white** (never alpha).
|
||||
Name in `--nq-p-ink-away`. Pill: `tent` icon, label `On travels`, neutral fill. Progress
|
||||
line reads `Returns <weekday>, <Mon D>`; empty progress track, no fill. **Not tappable** —
|
||||
the plate must not navigate, since the child has no instances.
|
||||
|
||||
### 2.3 Dock
|
||||
|
||||
`cloud-sun` 40px · temperature 38px/800 Nunito `--nq-p-dock-ink` · 1px divider ·
|
||||
condition + high/low 26px/600 `--nq-p-dock-ink-secondary` · divider · one short forecast
|
||||
phrase. All read from the configured `weather_entity`; if unset, render the dock with date
|
||||
and time only rather than removing it (the strip is part of the frame).
|
||||
|
||||
## 3. Quest Log (1b)
|
||||
|
||||
Reached by tapping a present crest. Header at y=56, page inset 62px:
|
||||
|
||||
- Small crest 96×110 (initial 44px/700 display).
|
||||
- Title `<Name>'s Quest Log` 56px/700 display.
|
||||
- Sub `<weekday>, <Month D> · N of M claimed` 20px/600 Cinzel, tracking .24em, uppercase.
|
||||
- **Remaining block** right-aligned: radius 14px panel, d20 mark 44px with the remaining
|
||||
count, `N quests left` 28px/700 Cinzel, and a party line
|
||||
`Party progress · X of Y today` 22px/600 Nunito.
|
||||
|
||||
### 3.1 Window columns
|
||||
|
||||
Three equal columns, 34px gap, top y=236, one per window — **Morning** (until 11:59 AM),
|
||||
**Afternoon** (12:00–5:00 PM), **Evening** (5:00–9:00 PM). Column head: icon
|
||||
(`sunrise` / `sun` / `moon`) 34px, name 32px/700 Cinzel, sub-label 21px/600 Cinzel
|
||||
uppercase with the window's clock range, right-aligned `done/total` 26px/700 Cinzel,
|
||||
14px bottom padding, `--nq-p-rule` underline.
|
||||
|
||||
Cards stack at `--nq-p-quest-gap` (24px). Order within a column: **incomplete first,
|
||||
sealed below**. A window with no quests renders its head and nothing else — do not
|
||||
collapse the column, the three-column rhythm is the layout.
|
||||
|
||||
### 3.2 Quest card — open
|
||||
|
||||
`--nq-p-quest-min-height` 116px, radius 12px, `--nq-p-card-open`, 1px
|
||||
`--nq-p-card-border`, `--nq-p-card-shadow`, padding 22px, 22px gap, row layout:
|
||||
|
||||
1. **Icon tile** 64×64, radius 10px, `--nq-p-icon-tile`, Lucide glyph 34px white.
|
||||
2. **Text** title 30px/700 Cinzel `--nq-p-ink`; meta 22px/600 Nunito
|
||||
`--nq-p-ink-secondary` reading `Due by <h:mm A>`. If past due:
|
||||
`Overdue · due <h:mm A>` in 22px/700 Cinzel uppercase, tracking .10em,
|
||||
`--nq-p-ink-late`.
|
||||
3. **Complete button** `--nq-p-button-height` 72px × min 150px, radius 10px,
|
||||
`--nq-brand-gradient`, `check` 30px + `Complete` 24px/700 Cinzel white,
|
||||
`box-shadow: 0 3px 0 rgba(40,20,60,.35)`.
|
||||
|
||||
Both the card body and the button open the confirm dialog (§4). Press feedback:
|
||||
`scale(.98)`, `--nq-dur-micro`.
|
||||
|
||||
### 3.3 Quest card — sealed
|
||||
|
||||
`--nq-p-card-done`, `opacity: .82`, no shadow, **not tappable**. Icon tile
|
||||
`--nq-p-icon-tile-done` with the glyph in `--nq-p-ink-secondary`. Title 30px/700 Cinzel
|
||||
`--nq-p-ink-muted` with `text-decoration: line-through`. Meta reads
|
||||
`Claimed <h:mm A>` 22px/600 Nunito `--nq-p-ink-secondary`.
|
||||
|
||||
**Wax seal** `--nq-p-seal-size` 78px circle, `--nq-p-seal`, `--nq-p-seal-shadow`,
|
||||
`check` 38px in `rgba(255,235,235,.95)`, absolutely positioned `right: 16px; top: -12px`,
|
||||
rotated a few degrees — **vary the rotation per card** (−9°, +6°, −4° in the mockup) so the
|
||||
board looks stamped by hand, not templated. Entrance: fade + `scale(1.15 → 1)`,
|
||||
`--nq-dur-base`, `--nq-ease-out`.
|
||||
|
||||
### 3.4 Party roll-up
|
||||
|
||||
An optional dashed panel in the afternoon column: label `Party roll-up` 18px/600 Cinzel
|
||||
uppercase, body 23px/600 Nunito `--nq-p-ink-secondary` — one or two sentences on the other
|
||||
children ("Jordyn has finished her log. Chloe is on travels until Sunday."). Read-only.
|
||||
|
||||
### 3.5 Idle return
|
||||
|
||||
40 s with no touch → navigate back to the party board view. Reset on any pointer or touch
|
||||
event. The card owns this; TouchHub Auto-Return must be set longer than 40 s.
|
||||
|
||||
## 4. Complete confirm (1j)
|
||||
|
||||
Modal over the dimmed log — scrim `rgba(30,20,10,.62)` over the live board.
|
||||
|
||||
Dialog 1000px wide at `top: 196px; left: 460px`, radius 20px, parchment panel with 3px
|
||||
`rgba(92,62,26,.5)`, `box-shadow: 0 26px 60px rgba(20,10,0,.5)`, padding 64px 68px 56px.
|
||||
|
||||
- Header row: 104px icon tile (radius 12px, brand gradient, glyph 56px) · window kicker
|
||||
21px/600 Cinzel uppercase tracking .24em · quest title 58px/700 display.
|
||||
- Body 32px/600 Nunito `#3f2f1c`: `Mark this quest complete? Once the seal is set, only a
|
||||
parent can undo it.`
|
||||
- Buttons, 24px gap, both `--nq-p-confirm-button` 108px tall:
|
||||
**Not yet** flex 1, `rgba(92,62,26,.1)` with 2px border, `x` 34px + 30px/700 Cinzel;
|
||||
**Complete** flex 2, brand gradient, `check` 38px + 32px/700 Cinzel white.
|
||||
- Dialog enters with fade + `scale(.96 → 1)`, `--nq-dur-modal`, `--nq-ease-out`.
|
||||
- Dismiss: **Not yet**, scrim tap, or 15 s of no input.
|
||||
|
||||
On confirm, call the completion service optimistically, stamp the seal, and re-sort the
|
||||
column. On service failure, revert the card and surface a single-line parchment toast.
|
||||
|
||||
## 5. Quest complete (1c)
|
||||
|
||||
Shown when the last instance for a child's day is completed; auto-returns to the board
|
||||
after 12 s (countdown line `Returning to The Party in N seconds`, 25px/600 Nunito).
|
||||
|
||||
- Large seal 168px at y=96 (`check` 86px), rotated −6°, `0 10px 24px rgba(60,10,20,.42)`.
|
||||
- `Quest complete` 86px/900 display, brand-gradient text fill.
|
||||
- Sub 34px/600 Nunito `--nq-p-ink-secondary`, max-width 1000px, centred, `text-wrap: pretty`:
|
||||
names the child, the date, and how the day went.
|
||||
- **Stat blocks** 4-up at y=540, inset 200px, 26px gap: radius 16px parchment panels,
|
||||
numeral 58px/900 Cinzel, label 17px/600 Cinzel uppercase tracking .14em —
|
||||
`Quests claimed`, `On time`, `Late`, `The Party` (household X/Y).
|
||||
- Dock switches to the evening variant (`cloud-moon`).
|
||||
|
||||
## 6. Accessibility and input
|
||||
|
||||
- Minimum tap target on this surface is the quest card itself (116px) and the 72px button;
|
||||
nothing interactive is smaller than 72px.
|
||||
- 24px between adjacent tap targets so a stray finger cannot claim the wrong quest.
|
||||
- No hover states — this is a touch-only surface. Provide `:active` feedback only.
|
||||
- No animation loops. Entrances only, per the CubeCraft motion rules.
|
||||
Reference in New Issue
Block a user