Canthus — Design System & Copy Reference
Version 2.4 | March 2026North Star: Protect the user’s mental state first. Enable task completion second.Every colour, typeface, spacing decision, animation, and word choice in this system must pass one question: does this make the person feel capable, or does it subtly imply failure? This is not a productivity app. It is a capacity tool for people whose capacity fluctuates unpredictably. Every design choice flows from this distinction.
Table of Contents
- Typography
- Colour System
- Spacing & Layout
- Elevation & Depth
- Iconography
- App Structure & Navigation
- Core Components
- Temporal Tasks & Appointments
- Add Task Flow
- Motion & Animation
- Copy System
- Accessibility
- Data & Privacy
- What This System Does Not Do
1. Typography
1.1 Font Pairing
Primary (body text): Atkinson Hyperlegible Developed by the Braille Institute specifically for low vision and reading difficulty. Used for all body text, labels, and captions. Chosen for its proven legibility during cognitive fatigue and its unique letterforms that prevent common misreadings (b/d, i/l, 0/O). Free on Google Fonts, available in Flutter viagoogle_fonts.
Display (headings): DM Sans
A warm humanist sans-serif used in Bold and SemiBold weights for headings and the mana display number. Brings warmth and approachability to high-visibility elements without sacrificing readability. Also free on Google Fonts.
Why this pairing: Atkinson Hyperlegible provides the strongest accessibility foundation where it matters most — body text the user reads repeatedly during cognitive fatigue. DM Sans display weights bring warmth and character to high-visibility elements.
1.2 Type Scale
| Token | Font | Size | Weight | Line Height | Letter Spacing | Use |
|---|---|---|---|---|---|---|
display | DM Sans | 28sp | 700 | 1.2 | -0.3px | Mana number, screen hero text |
heading-1 | DM Sans | 22sp | 600 | 1.3 | -0.2px | Screen titles |
heading-2 | DM Sans | 18sp | 600 | 1.35 | -0.1px | Section headers, card titles |
body-lg | Atkinson | 16sp | 400 | 1.65 | 0 | Primary task text |
body | Atkinson | 14sp | 400 | 1.65 | 0 | Supporting content |
label | Atkinson | 13sp | 700 | 1.0 | 0.2px | Buttons, nav labels, chips |
caption | Atkinson | 12sp | 400 | 1.5 | 0.1px | Timestamps, hints |
1.3 Hard Rules
- Minimum readable size: 14sp. Nothing the user needs to read is smaller.
- Body line height: never below 1.5. Non-negotiable for brain fog readability.
- No italics for body text. Increases cognitive load for visual processing difficulties.
- No label-as-placeholder pattern. Form fields always show a persistent visible label.
2. Colour System
Dark mode is the designed and primary experience. Light mode is deferred. All contrast ratios are validated against dark mode pairings.2.1 Compliance
This system targets compliance with three standards, all of which converge on the same contrast requirements:- WCAG 2.1 AA — 4.5:1 normal text, 3:1 large text, 3:1 UI components
- ADA (2024 DOJ rule) — requires WCAG 2.1 AA for digital services
- European Accessibility Act 2025 — mandates EN 301 549 v3.2.1, which references WCAG 2.1 AA
2.2 Dark Mode Foundation
| Token | Hex | Use |
|---|---|---|
bg-base | #13141C | App background |
surface-1 | #1C1D29 | Cards, elevated surfaces |
surface-2 | #272839 | Input fields, secondary surfaces |
surface-3 | #353647 | Tertiary surfaces, hover states |
border | #606388 | Dividers, card outlines |
border-strong | #7578A0 | Focused inputs, emphasis borders |
2.3 Text Colours
All ratios measured againstbg-base (#13141C).
| Token | Hex | Ratio vs bg-base | Notes |
|---|---|---|---|
text-primary | #F1F1FA | 16.2:1 ✅ AAA | Main content text |
text-secondary | #A3A5C8 | 9.3:1 ✅ AAA | Supporting text |
text-tertiary | #8385A8 | 4.7:1 ✅ AA | Hints, timestamps |
text-disabled | #484963 | 2.1:1 ❌ intentional | Disabled state — WCAG exempts disabled components |
⚠️ Tertiary text constraint:text-tertiaryonly passes contrast onbg-base. It must not be used on card surfaces (surface-1orsurface-2). On cards, usetext-secondaryas the minimum for any readable text. This is a hard rule.
Disabled text: Always accompanied by a non-colour indicator (strikethrough or lock icon). The low contrast communicates non-interactivity.
2.4 Mana Accent
| Token | Hex | Ratio vs bg-base | Usage rules |
|---|---|---|---|
mana-50 | #0E0F1A | — | Subtle fill only, never for text |
mana-100 | #161829 | — | Background chips |
mana-200 | #252A4A | — | Mana cost icon washed state |
mana-300 | #3A4280 | — | Hover/pressed states |
mana-400 | #5560CC | 3.1:1 | UI components, borders, icons — not for body text |
mana-500 | #6B73D8 | 4.4:1 | Large text (18sp+) or icons only |
mana-600 | #8E96E6 | 6.2:1 | Primary interactive text, active labels |
mana-700 | #B8BCF0 | 9.1:1 | High-emphasis mana text (mana number) |
Key rule: Any mana-coloured text at body size must usemana-600minimum.mana-400is only for UI components (icons, borders), never body text.
2.5 Semantic Colours
| Token | Hex | Ratio | Use |
|---|---|---|---|
success | #5DBF8A | 7.2:1 ✅ | Task completed |
caution | #D4A843 | 6.8:1 ✅ | Gentle heads-up, deadline approaching |
rest | #9B8FD4 | 5.3:1 ✅ | Recovery day, rest state |
critical | #E07060 | 4.8:1 ✅ | Genuine errors only |
2.6 Contrast Validation Summary
All text/background pairings used in the system have been validated. The key constraints to remember:- ✅
text-primary,text-secondarypass on all surfaces - ✅
text-tertiarypasses onbg-baseonly - ❌
text-tertiaryfails onsurface-1(3.7:1) andsurface-2(2.9:1) — never use it on cards - ✅
mana-600passes onbg-base(6.2:1) andsurface-1(4.9:1) - ✅ All semantic colours pass on
bg-base
3. Spacing & Layout
3.1 Grid
Base grid: 8pt. Micro-adjustments: 4pt.| Token | Value | Use |
|---|---|---|
space-1 | 4px | Micro — icon internal padding, tight badges |
space-2 | 8px | XS — tight internal spacing |
space-3 | 12px | SM — compact card padding |
space-4 | 16px | MD — standard gap, content padding |
space-5 | 20px | LG — section gaps |
space-6 | 24px | XL — between cards |
space-8 | 32px | 2XL — major section breaks |
space-12 | 48px | 3XL — hero areas |
3.2 Screen Layout
- Horizontal margins: 20px (wider than standard 16px — reduces density and overwhelm)
- Safe areas: Always respected. Nothing behind notch, dynamic island, or home indicator.
- Content never truncates at any system text scale setting.
3.3 Touch Targets
- Minimum: 48×48dp for all interactive elements (WCAG 2.5.8 AA)
- Primary actions: 56×56dp
- Minimum gap between targets: 8dp
- All swipe gestures have a tap alternative (WCAG 2.5.1)
3.4 Corner Radius
| Token | Value | Use |
|---|---|---|
radius-sm | 8px | Chips, tags, small badges |
radius-md | 12px | Cards, inputs, task cards |
radius-lg | 16px | Bottom sheets, large cards |
radius-xl | 24px | Modals, nav bar pill |
radius-full | 9999px | Buttons, completion circles, pills |
4. Elevation & Depth
Hierarchy uses colour temperature shift, not drop shadows. Surfaces get progressively warmer as they elevate. This produces lower visual noise than shadows and works better in dark mode.| Level | Surface Token | Additional Treatment | Use |
|---|---|---|---|
| 0 | bg-base | None | App base |
| 1 | surface-1 | None | Cards at rest |
| 2 | surface-2 | 1px border top edge only | Focused states, active cards |
| 3 | surface-3 | Subtle mana-tinted glow rgba(85,96,204,0.06) | Bottom sheets, floating nav |
| 4 | surface-3 | Stronger mana glow rgba(85,96,204,0.12) | Critical overlays |
5. Iconography
5.1 Philosophy
Icons carry the mana/wizardry metaphor. They should feel like objects from an arcane world — not gamified (no cartoonish effects), not clinical (no medical crosses or charts), not corporate (no briefcases or bar graphs). The aesthetic is quiet enchantment — things that feel like they belong in an apothecary or a scholar’s study.5.2 Style Specifications
- Grid: 24×24dp base, 2dp padding (20dp content area)
- Stroke weight: 1.5px at 24dp — slightly lighter than standard, more delicate and arcane
- Corners: Fully rounded joins and terminals — no sharp points
- Style: Outline at rest, filled/glowing for active states
- Colour at rest:
text-tertiary - Colour active:
mana-600fill with subtlemana-400glow
5.3 Mana Cost Icons — Crystal Orbs
The mana cost metaphor uses crystal orbs — spherical gems that show fill level, connecting directly to the mana pool concept. Four tiers:| Tier | Visual | Cost Range |
|---|---|---|
| 1 | Single small orb | 1–3 mana |
| 2 | Single larger orb with inner glow | 4–8 mana |
| 3 | Orb with orbiting spark | 9–15 mana |
| 4 | Double orb cluster with radiant burst | 16+ mana |
mana-200 outlines) and a filled state (using mana-500 through mana-700). The number itself is shown in caption size beside the orb cluster.
5.4 Full Icon Set
| Icon | Metaphor | Use |
|---|---|---|
| Crystal orb (4 tiers × 2 states) | Glowing sphere | Mana cost on tasks |
| Mana pool / cauldron | Bubbling vessel | Mana screen, pool display |
| Rune / sigil | Abstract geometric mark | Check-in state, loading |
| Wand / spark | Thin wand with star tip | Add task, create action |
| Scroll | Rolled parchment | Task list item |
| Seedling / sprout | Small growing plant | Orchard tab icon |
| Constellation | 3 connected stars | Insights / pattern view |
| Moon phase | Crescent | Rest day, low mana state |
| Hourglass (arcane) | Sand timer with rune markings | Temporal task indicator |
| Shield | Simple rounded shield | Protection mode, essential task flag |
| Eye | Arcane eye | Transparency panel |
| Spiral | Inward spiral | Loading, calibrating |
| Flame (small) | Gentle candle flame | ”Warmth” indicator (not a streak) |
| Body axis | Simplified person | Check-in body axis |
| Brain / star burst | Abstract neural burst | Check-in mind axis |
| Heart | Soft heart | Check-in mood axis |
| Settings / compass | Arcane compass rose | Settings |
6. App Structure & Navigation
6.1 Three Tabs
| Tab | Purpose | What it contains |
|---|---|---|
| Mana | Where the user learns what they have today | Check-in, pool display, upcoming appointments, patterns |
| Tasks | Survival and maintenance tasks | Only tasks achievable within current pool, plus essential tasks always |
| Orchard | Leisure, hobbies, passion projects | Same mana pool — creative nourishment is equal to chores |
6.2 Navigation Bar
- Floating pill shape,
surface-3background, level-3 mana glow,radius-xl - 16px above bottom safe area edge, width = screen width minus 32px
- Active:
mana-600filled icon + label,mana-100circle background behind icon - Inactive:
text-tertiaryoutline icon, no label - Before check-in: All three tabs are navigable. Tasks and Orchard use estimated pools (see §7.1 tiers). A subtle
text-secondarybanner at the top of Tasks/Orchard reads: “Your mana is estimated today — check in when you’re ready for a better reading.” The banner is dismissable. - Touch targets: 56dp each
7. Core Components
7.1 Mana Screen
The first screen the user sees each day. Single scrollable column — all content in one continuous flow.State A — Check-in required
The screen opens showing the full 3-axis check-in as the recommended path. Three rows, one per axis (Body, Mind, Mood). Each axis is a 1–5 scale implemented as five large tappable circles (56dp each). No sliders — sliders require fine motor precision that isn’t appropriate for this audience. Anchor labels for each axis:| Axis | Low End | High End |
|---|---|---|
| Body | ”Moving gently" | "Feeling strong” |
| Mind | ”Foggy today" | "Sharp and clear” |
| Mood | ”A hard one" | "Really good” |
State B — Check-in complete
Shows the daily mana pool (see Pool Display below), then scrollable content: check-in summary pills, Upcoming section, Your Patterns section.7.2 Pool Display
- Large mana number in
displaystyle,mana-700, centred - Below: the word “mana” in
body,mana-400 - Below: crystal orb icons indicating pool tier (decorative)
- Below: a single transparency sentence in
body,text-secondary— explains why today’s pool is what it is
7.3 Task Card
The repeating unit for both Tasks and Orchard screens. Anatomy:- Container:
surface-1,radius-md, 1pxborderstroke - Left accent bar: 3px wide, full card height, colour maps to mana tier
- Completion target: 44dp circle,
borderstroke at rest - Task name:
body-lg,text-primary - Subtitle:
caption,text-secondary(not tertiary — must pass contrast on surface-1) - Mana cost: right-aligned orb cluster + number in
caption,mana-600
7.3.1 Essential Tasks
A task can be flagged as essential by the user via a toggle at creation or edit time: “This is essential” (with a small shield icon). Essential tasks are things the user cannot safely skip — medication, feeding a dependent, critical medical appointments. The toggle is off by default. The app does not suggest which tasks should be essential — the user decides. Surfacing rules: Essential tasks are always visible on the Tasks screen, regardless of pool. Their display adapts based on whether they fit within the remaining pool:- Within pool: Standard task card. No special treatment. The essential flag is invisible in normal operation — it only activates below the pool threshold.
-
Over pool: The task card appears with a distinct treatment:
- Card background shifts to
surface-2(slightly elevated — this card is different) - Mana cost orbs use
cautionamber instead of standard mana colour - A single line below the task name: “This will use more than you have today” in
caption,text-tertiary - The completion circle remains active — completing an over-pool essential task pushes the user into overflow, which the existing system handles gracefully
- Card background shifts to
-
On rest days (pool ≤ 5): Essential tasks appear in a dedicated “Essentials” section at the top of the Tasks screen, above any regular tasks. Section header: “What matters most today” in
heading-2,text-primary. Below it: “These are your essentials. Everything else can wait.” incaption,text-secondary.
7.4 Multi-Task Completion
Long press on any task card enters multi-complete mode. User taps additional cards to select, then taps “Complete all” — all selected cards animate simultaneously in a single 800ms hold. Completing 10 tasks takes: 1 long press + 9 taps + 1 confirm + 800ms (not 10 × 800ms = 8 seconds of forced waiting).7.5 Stability Indicator
A small ambient constellation icon in the top-left corner of the Mana screen. Three dots connected by two thin lines forming a triangle. Only the colour changes across states. Availability: Not shown until 14 check-in days recorded.| State | Colour | Meaning |
|---|---|---|
| Stable | mana-400 | Consistent rhythm for 14+ days |
| Transitional | text-tertiary | Pattern is settling or recovering |
| Unstable | text-secondary | Regime shift detected — app is adjusting |
7.6 Your Patterns Section
Lives at the bottom of the Mana screen scroll. Three tabbed panels: Rhythm (available from 5 check-in days) — 14-day bar chart showing daily mana spend (what was done, not what was available). Y-axis uses named bands (Rest / Gentle / Moderate / Full) relative to personal baseline. No numerical axis by default. Long-press any bar for a percentage tooltip. Days (available from 21 check-in days) — Weekly pattern view showing average spend per day of the week over 28 days. Purely a cross-day comparison — cannot show a directional trend. Balance (available from 7 check-in days) — Proportion bar showing physical vs cognitive mana split over 14 days. Descriptive context sentence below (e.g. “A fairly even mix lately”). Purely descriptive, never implies the balance should change. Missing days are filled with greyed estimated bars (using day-of-week average or personal baseline), with honest tooltips explaining the estimation. PEM recovery banner: Shown above active panel content when the system is in post-PEM recovery. Text: “Your pattern is in recovery — this data reflects a difficult stretch. It will settle as you feel better.” Below the banner text, a quiet text link: “Do you know what triggered this?” — tapping opens a bottom sheet listing completed tasks from the past 7 days. The user can select tasks they believe triggered the crash, or tap “Not sure” to dismiss. This is never prompted via notification or modal — it appears only within Patterns, only when scrolled to, only during recovery.7.7 Buttons
| Variant | Background | Text | Height |
|---|---|---|---|
| Primary | mana-400 | bg-base | 52dp |
| Secondary | Transparent | mana-600 (1.5px mana-400 border) | 52dp |
| Destructive | critical @ 20% | critical (1px critical border) | 52dp |
| Ghost | Transparent | mana-600 | 44dp |
label type, radius-full, 48dp minimum touch target. Destructive actions always require two confirmations.
7.8 Bottom Sheets
- Background:
surface-3,radius-lgtop corners, flat bottom - Drag handle: 36×4px,
border-strong, centred, 12px below top edge - Overlay:
rgba(20,18,16,0.72)— warm-tinted dark scrim - Always dismissible by drag or overlay tap
- Max height: 85% screen height with internal scroll
8. Temporal Tasks & Appointments
8.1 Philosophy
Temporal tasks are treated as a capacity problem, not a time problem. The design never says “you are running out of time.” It says “here is what this needs, and here is what you have.” This is grounded in stress appraisal theory: the same deadline can be appraised as a threat (“I might fail”) or a challenge (“here is what I need to solve this”). The system systematically produces challenge appraisal. PEM risk from emotional distress is equivalent to physical exertion — a poorly designed urgency signal is a medical risk.8.2 Two Task Types
Deadline tasks — Can be completed on any day within a window. “Pay electricity bill by Thursday.” Governed by the horizon system. Appointment tasks — Fixed to a specific day and time. A GP visit, a hospital scan. Cannot be completed early or deferred without real-world consequence.8.3 Deadline Tasks — Horizon System
| Window | Behaviour |
|---|---|
| > 7 days out | Invisible — not in any list |
| 3–7 days out | Surfaces in task list with hourglass icon and calm date label |
| < 3 days out | Hourglass becomes filled, caution amber pill label added |
| Day of | Amber pill reads “Today” — single word, no countdown |
caution amber is the maximum urgency signal.
Date labels use day names only — “Thursday”, not “3 days” or “Due Thu 14 Mar”. Day names are calendar-natural. Countdowns are pressure.
8.4 Appointment Tasks
Created via a “This happens on a specific day” toggle. Fields: name, date, optional time, mana estimate (1–5 scale), optional recurrence, optional notes. Mana reservation: On creation, users can set aside mana for the appointment day. On the day, the pool reflects the reservation and task surfacing uses the reduced available mana. Day-of Anchor card: Appears at the top of the Tasks screen,surface-2 background, caution amber accent bar, filled hourglass icon. Cannot be swiped away — can only be marked as attended.
Needs Updating flow: If an appointment passes without being marked attended, it moves to a “Needs updating” section (never “Missed” or “Failed”). The correction window is 3 check-in days (not calendar days) — a user in a flare who hasn’t opened the app is not locked out.
8.5 Day-Before Notification
Sent at 11am (configurable 8am–6pm). Suppressed if the user has already viewed the Upcoming section that day. Appointment name is never included in the notification body — lock screen privacy. Single appointment: “You have something tomorrow that will take some energy.” Multiple: “You have a couple of things tomorrow that will take some energy.”9. Add Task Flow
9.1 Philosophy
Task creation must never cost more energy than the task itself. Two principles: fast capture first, detail optional second, and the task exists the moment the user names it.9.2 Two-Step Flow
Step 1 — Quick Capture (half-height bottom sheet):- Text input for task name (keyboard raised immediately)
- Duration field (natural language: “20 minutes”, “half an hour”)
- Destination chips: Task · Orchard · Appointment
- Essential toggle (shield icon, off by default) — only shown for Task destination
- Two buttons: Done (creates immediately) and More (expands to detail)
- Name (pre-filled)
- Duration (chip selector: Quick 5min / Short 15min / Medium 30min / Long 60min / Custom)
- Difficulty rating 1–5 (“How much energy does this usually take you?”) — shown with the same “big circles” UI pattern as the check-in, positioned as the first detail field after name and duration to emphasise its importance
- Physical or Mental? (Physical / Mix / Mental)
- Essential toggle (if not already set in Step 1)
- Live mana preview
- Notes, Repeat options
9.3 Cost Estimation Pipeline
Runs automatically as the user types. Five steps in priority order:- Personal library lookup — Matches against tasks the user has previously created/completed. Token-level Levenshtein distance matching with recency weighting. After 10 completions of a personal library task, template-derived costs are permanently overridden by the user’s actual patterns.
- System template lookup — Matches against bundled task templates. Same Levenshtein matching.
- Semantic embedding match — On-device MiniLM-L6-v2 model (~22MB) computes cosine similarity against pre-encoded template embeddings.
- LLM estimation (opt-in) — On-device model preferred, cloud fallback sends task name only.
- Difficulty rating fallback — User rates 1–5 manually.
9.4 Mana Cost Display States
| State | Trigger | Appearance |
|---|---|---|
| Known | High-confidence match or all fields user-confirmed | Normal colour, full opacity |
| Uncertain | Any field defaulted | 50% opacity, text-tertiary colour |
| Range | Future-day task with calculable range | Shows ~X or X–Y |
| Unknown | No match, no user input | Shows ? |
10. Motion & Animation
10.1 Principles
No spring physics. No bounce. No overshoot. No parallax. No looping animations except the mana calibration loading state (slow spiral rotation, stops when complete). Vestibular disorders are common in ME/CFS, fibromyalgia, and POTS. Any motion suggesting rotation, oscillation, or rapid movement can trigger symptoms. Transitions should feel like the UI is already in the right state before you noticed it moved.10.2 Duration & Easing
| Token | Duration | Curve | Use |
|---|---|---|---|
motion-instant | 0ms | — | Reduce Motion mode only |
motion-fast | 120ms | ease-standard | Toggle states, icon changes |
motion-med | 220ms | ease-enter | Card selections, panel opens |
motion-slow | 380ms | ease-enter | Screen transitions, bottom sheet entry |
motion-complete | 800ms | ease-standard | Task completion hold |
| Curve | Value |
|---|---|
ease-standard | cubic-bezier(0.4, 0.0, 0.2, 1.0) |
ease-enter | cubic-bezier(0.0, 0.0, 0.2, 1.0) |
ease-exit | cubic-bezier(0.4, 0.0, 1.0, 1.0) |
10.3 Reduce Motion
Detected viaMediaQuery.of(context).disableAnimations in Flutter. When enabled:
- All transitions become instant opacity fades at
motion-fast(120ms, opacity only) - Task completion hold retained at 400ms with opacity fade only (success feedback preserved, motion removed)
- No exceptions. Every animation has a declared Reduce Motion variant.
11. Copy System
11.1 Voice
The app speaks as a calm, knowledgeable friend who happens to understand energy management. Not a medical professional (clinical distance), not a productivity coach (pressure), not a cheerleader (false positivity). Warm, matter-of-fact, never surprised by difficulty. Copy principles:- Honest. The system does not hide bad states. Users with chronic illness know when they’re in a bad period.
- Non-patronising. Never tell the user how to feel or what they should do.
- Non-prescriptive. Avoid “you should”, “you need to”, “make sure to”.
- No urgency manufacture. The user already has enough. Do not add to it.
- No false positivity. Don’t celebrate low activity or frame hard days as opportunities.
11.2 Banned Phrases
| ❌ Banned | Why | ✅ Replacement |
|---|---|---|
| ”You only completed…” | Frames completion as a score | Don’t surface completion counts this way |
| ”Don’t forget…” | Creates urgency | Remove or rephrase as neutral info |
| ”You’re falling behind” | Implies failure | Never use |
| ”Great job!” / “You did it!” | Patronising for adults managing illness | Remove or use neutral acknowledgement |
| ”Push yourself” / “Keep going!” | Encourages overexertion | Never use |
| ”No tasks completed today” | Frames rest as failure | ”Nothing tracked today” or nothing at all |
| ”Streak” | Implies continuity is a goal | Never use |
| ”Overdue” | Guilt-inducing | ”Carried over”, or remove |
| ”You missed…” | Blame | Never use |
| Any red urgency indicator on tasks | Visual guilt | Do not implement |
| ”Low energy” | Clinical framing | ”Gentle day" |
| "Depleted” | Deficit language | ”Resting" |
| "Task too expensive” | Transactional | ”Save this for a stronger day" |
| "Failed to complete” | Failure language | ”Carried forward" |
| "Insufficient mana” | System language | ”Not quite yet" |
| "Try harder” | — | Never, under any circumstances |
| ”Welcome back” | Implies leaving was notable | Don’t comment on absence |
| ”We missed you” | Implies obligation to use the app | Don’t comment on absence |
11.3 Copy by Context
Low capacity day: Show the shorter task list without comment. If a label is needed: “Today’s list” or nothing. Never say “You don’t have much energy today. Take it easy!” Rest day with essentials (pool ≤ 5): The Essentials section header reads “What matters most today”. Below it: “These are your essentials. Everything else can wait.” No commentary on the low pool. Skipped or deferred tasks: “Carried over” or move silently. No badge, no indicator. If the user asks: “Carried from [day].” Empty states:| Context | Copy |
|---|---|
| Tasks — all done | ”You’ve done enough for today.” |
| Tasks — no tasks yet | ”Nothing here yet. Add something small if you’d like.” |
| Orchard — empty | ”Your orchard is waiting. Add something you love.” |
| Mana pool at minimum | ”Today is a rest day. That is enough.” |
| No check-in data | ”Let’s see how you’re feeling before we figure out your day.” |
11.4 Transparency Sentences
The sentences that explain the mana pool. Translate system state into accessible language:- Low confidence (< 0.3): “We’re still learning your patterns. Today’s mana is set carefully — it’s designed to feel comfortable, not like a stretch.”
- Medium confidence (0.3–0.7): “On days you’ve felt like this recently, you’ve usually managed around [X] mana. Today is set a little below that to give you room.”
- High confidence (> 0.7): “Based on your history, [X] mana is a good fit for how you’re feeling today.”
- Post-PEM: “You had a tough stretch recently. Your mana is lower while you recover — it’ll grow back as you feel better.”
- Post-overflow: “You’ve been doing more than your pool lately — we’ve nudged it up a bit.”
- Returning after absence (7+ days, first 3 check-in days): “It’s been a little while — today’s mana is set gently while the app catches up.”
- Quick check-in or skip used: “Your mana is estimated today — check in when you’re ready for a better reading.”
11.5 Copy Review Checklist
Before shipping any new UI copy, check:- No banned phrases or variants
- No urgency or alarm
- No implied failure state for rest or low activity
- No patronising affirmations
- No commentary on absence or return
- One clear next step if action is needed, or no action implied if none is needed
- Consistent with the product contract anti-goals
12. Accessibility
12.1 Standards
- WCAG 2.1 AA (all success criteria)
- WCAG 2.2 AA (adds 2.5.8 Target Size minimum)
- ADA 2024 (DOJ rule requires WCAG 2.1 AA)
- European Accessibility Act 2025 / EN 301 549 v3.2.1
12.2 Key Requirements
Colour & Contrast: All pairings validated (see §2.6).text-tertiary on bg-base only. mana-400 and below for UI components only, never body text. mana-600 minimum for interactive text. Semantic colours always paired with a non-colour indicator.
Motor & Touch: 48dp minimum touch targets throughout. 8dp minimum gap between adjacent targets. All gestures have tap alternatives. No time-limited interactions. No precision gestures (discrete taps replace sliders in check-in).
Cognitive: No content auto-dismisses. All form fields have persistent visible labels. Error states explain the corrective action. Single action per screen where possible. The check-in is always bypassable — the tiered system (§7.1) ensures the user is never hard-locked from their task list.
Screen Readers (Flutter Semantics): All interactive widgets wrapped in Semantics with meaningful labels. Mana orb clusters labelled (e.g. “3 mana cost”). Completion circles labelled (e.g. “Complete [task name]”). Live regions on mana number update and task completion. Bottom sheets announce heading on open. Multi-select announces count. Essential task flag announced: “Essential task: [task name]”.
Text Scaling: All layouts tested at 200% text scale. No fixed-height containers that clip. Task cards expand vertically — names never truncate. Icon+label pairs in nav bar reflow to stacked if needed.
12.3 Acceptance Criteria for New Screens
Before a new screen ships:- Renders correctly at maximum system text size (no clipping, no overflow)
- All interactive elements have semantic labels
- Focus order is logical under screen reader navigation
- State changes are announced
- Reduced motion preference disables or replaces all animations
- All text and UI elements meet WCAG AA contrast
- All touch targets are ≥ 48×48dp
13. Data & Privacy
13.1 Architecture
The app uses four layers: UI (widgets, screens, navigation), Domain (mana logic, services), Data (local SQLite via Drift), and Platform (notifications). Domain has no outward dependencies — it defines interfaces that other layers implement. Local-first: The app is fully functional with no internet connection. SQLite (Drift) is the source of truth. Every feature works against the local store alone. No cross-device sync — user data stays on their device.13.2 Storage
| Store | Contents | Encrypted | Wiped on Reset |
|---|---|---|---|
| SQLite (Drift) | Tasks, check-ins, events, mana state | Yes (SQLCipher) | Yes |
shared_preferences | Settings, feature flags | No | No |
13.3 Encryption
All SQLite data is encrypted at rest using SQLCipher. A 256-bit key is generated on first launch and stored in the platform keystore (iOS Keychain / Android Keystore). The key is never written to iCloud, Google Drive, or any cloud backup.13.4 Delete All Data
Accessible from Settings. Wipes the SQLite database and encryption key atomically. Settings and feature flags survive. Calm, factual confirmation copy: “This will permanently delete all your data on this device. Your app settings will be kept. This cannot be undone.” Button: “Delete everything” — no exclamation marks, no “Are you sure?”, no blame framing.14. What This System Does Not Do
- No streaks. No consecutive day tracking of any kind.
- No leaderboards or comparison. This is a private capacity tool.
- No red mana states. Low mana =
restpurple. Red = system errors only. - No task counts in headers. The list shows what is achievable, not the full backlog count.
- No animations celebrating high-capacity days. High days are not achievements. They are just high days.
- No internal numbers shown. Coefficient, confidence score, EWMA values, pool percentage — none of these are ever visible. The user sees the mana number and a human sentence.
- No automatic recalibration prompts. The system adapts silently. Recalibration is a user-initiated option, never suggested.
- No “you exceeded your pool” warning framing. Overflow is noted warmly, once per day, never as an alarm.
- No “you should” language. Ever.
- No hard lock-out. The user always has access to their task list, regardless of check-in status.
- No absence penalty. Time away from the app does not decay the user’s data, patterns, or system trust. The app waits.
- No commentary on absence. No “welcome back,” no “we missed you.” The app picks up where the user is.
Changelog — v2.3 → v2.4
Issue 1 — Tiered check-in (no hard lock): §6.1 rewritten from “gated entry point” to “primary entry point.” §6.2 navigation bar updated to remove locked state. §7.1 Mana screen now documents three alternative check-in paths (quick, momentum carry-forward, skip). §12 cognitive accessibility updated. Issue 2 — Absence handling: §11.2 added “Welcome back” and “We missed you” to banned phrases. §11.4 added returning-after-absence transparency sentence and quick-check-in/skip sentence. §14 added no absence penalty and no commentary on absence. Issue 3 — Terminology: All references tonetMET and impliedNetMET throughout this document have been replaced with relativeCost and impliedRelativeCost. These values represent relative effort for this specific person, not absolute metabolic equivalents. The mana formula, pipeline, and personal library logic are unchanged — only the naming. §9.3 strengthened personal library override: after 10 completions, user patterns permanently override template-derived costs. §9.2 elevated difficulty rating to first detail field after name and duration.
Issue 4 — PEM attribution: §7.6 PEM recovery banner now includes optional “Do you know what triggered this?” link for user-reported crash attribution.
Issue 5 — Essential tasks: New §7.3.1 specifying the essential task flag, surfacing rules, over-pool display treatment, rest-day Essentials section, and essential count limit prompt. §7.3 visibility rule updated with the essential exception. §9.2 Quick Capture gains essential toggle. §11.3 added rest-day-with-essentials copy. §5.4 shield icon usage updated.
This document is the single design and copy source of truth for Canthus. When a new design or copy decision arises, return to the North Star and work forward.