# The Freeside design system

**Status:** v0.1 · started 2026-07-23 · internal to NF + EA staff only

> One-liner: **EnterpriseAlumni's palette, wrapped in NativeFoundation's grammar.**
> Blue is the network you operate. Orange is the intelligence operating it.

This document is the spec. The runnable artefacts sit beside it:

```
design-system/
├── DESIGN_SYSTEM.md   ← you are here (philosophy, rationale, rules)
├── index.html         ← the living reference — every token & component, rendered, light + dark
└── freeside.css       ← drop-in stylesheet: tokens (--fs-*) + component classes (.fs-*)
```

---

## 1. Why this exists, and how it was made

Freeside wraps EA's platform as a backend and puts a genuinely new agentic + predictive cockpit on top. It has to feel like it *belongs* to the EA world (so EA staff and customer-admins trust it) **and** be unmistakably a NativeFoundation product (because that's the whole thesis — NF did what EA's v4 committee couldn't).

So the system is a deliberate fusion of two real, in-production design languages:

| Source | What we took | Evidence |
|---|---|---|
| **EnterpriseAlumni — "AlumniPortal"** | The **palette, iconography style, and texture** | Audited live at `alumni.your-corp.com/alumni/portal2`. Bootstrap-3 lineage: **Inter**, primary blue `#337AB7` / `#0F6DAE` / azure `#017CBF`, deep-navy **low-poly faceted** hero panels, teal-green `#008577`, violet offers, page `#EDEFF4`, pill inputs, outline filter chips, rounded white cards, **circular icon-badge** quick-links with chevrons, FontAwesome/Glyphicons **outline** icons in slate `#363C4A`. |
| **NativeFoundation — "RelayOS"** | The **grammar**: structure, type, motion, motifs, voice | `nf-design-system-local`. Paper-on-canvas cards lifted by **shadow + hairline (never a coloured border)**, layered inset depth, **Geist + JetBrains Mono** (no serif — emphasis is weight), editorial + CLI voice, the **human ◆ machine pair**, the orange breathing cursor, Lucide icons, calm 120ms motion, no emoji/glass/neon. |

The move that makes it cohere: **we don't paint NF orange over an EA layout, and we don't drop EA blue into NF's warm-stone world.** We keep NF's *structural discipline* and re-skin the *surface* in a cooler, EA-derived neutral, then give every EA colour a **job drawn from Freeside's own architecture** (Molly → Seldon → Case). Colour becomes semantic, not decorative.

---

## 2. Pillars

Four are inherited verbatim from RelayOS. The fifth is Freeside's own.

1. **Quiet confidence.** Restrained, dependable. No glow, no neon, no aggressive gradients.
2. **Layered depth, not loud complexity.** Inset surfaces, multi-stop shadows, hairline rings. Depth signals importance — cards *sink into* the page, they don't float.
3. **Editorial clarity with product precision.** Sentence-case headlines with a closing period. Humanist sans body. A monospace machine voice. Every label earns its place.
4. **Soft geometry, purposeful contrast.** 6–18px rounded corners, strong colour contrast inside calm shapes. Sharp 90° corners are forbidden.
5. **Two voices, one console.** *(Freeside)* Every surface holds a human moment in dialogue with a machine moment — the admin states intent in plain language; the agent plans, forecasts and reports back. This is the product rendered as a brand motif.

---

## 3. Colour — a semantic palette

Colour never carries decorative weight on its own. Every hue is a functional signal, and the mapping is the product architecture:

| Role | Token family | Source | Meaning |
|---|---|---|---|
| **Network blue** | `--fs-net*` | EA | The platform / the network / the data / shell chrome. **Structural + primary action.** The world Freeside operates on. |
| **Agent orange** | `--fs-agent*` | NF `#FF6B35` | NF's intelligence acting on that world. Live status, the dialogue cursor, the logo's orange node, and the *one* sanctioned CTA (dispatch). **A spot accent — never a fill, never dominant.** |
| **Forecast teal** | `--fs-forecast*` | EA `#008577` | Seldon: predictions, confidence bands, positive projection, predicted-vs-actual. |
| **Wargame violet** | `--fs-sim*` | EA offers pill | Simulation / what-if / wargaming / synthetic populations. |
| **Warn / Danger** | `--fs-warn*` `--fs-danger*` | derived | Needs-review (amber) · at-risk / destructive (red). |

**Core values (light):**
`net #137CC4` · `net-strong #0F5A99` · `net-deep #0B2542` · `net-soft #E4EFF8`
`agent #FF6B35` · `forecast #008577` · `sim #6C5CE0` · `warn #E8912A` · `danger #D64545`

**Neutrals & ink** — a **white page, like EA**. Cards are white too, separated by shadow + hairline rather than by tone (NF's paper-on-canvas discipline, executed on white); the one soft grey is reserved for inset surfaces. Ink is cool slate navy, never warm grey:
`canvas #FFFFFF` · `surface #EEF1F6` · `paper #FFFFFF` · `line #E2E6ED`
`ink #16202E` · `ink2 #3A4657` · `ink3 #7A8698`

**Dark "night watch" theme** ships in the tokens (`[data-theme="dark"]`): a deep navy-slate habitat (`canvas #0C1420`) where blue, orange and teal pop. It's not an afterthought — a lights-down orbital cockpit is arguably the *native* Freeside look.

**The rule that keeps it honest:** blue = the network, orange = the agent. Never swap them. If a screen reads as mostly orange, pull it back.

---

## 4. Typography

Two families. No serif — the earlier Fraunces italic flourish was dropped (it didn't fit here), and emphasis is now carried by **weight**, which keeps the whole thing closer to EA.

| Family | Job | Notes |
|---|---|---|
| **Geist** (sans) | Everything visible — headings, body, UI, nav | The upright voice of the system is sans throughout. |
| **JetBrains Mono** | Eyebrows, captions, timestamps, metrics, status, CLI voice | The machine voice. Never body copy. |
| *(emphasis)* | **Weight**, not a display face — semibold Geist, `.fs-em` | No serif, no italic, no colour change. |

**Inter** (EA's face) is the declared **systems-continuity fallback** in the sans stack — so a Freeside surface embedded next to the live EA portal degrades gracefully. Geist is canonical.

Scale: display 56 / h2 32 / h3 20 / body 15 / eyebrow 10 (mono). Big metric numbers use Geist with `font-feature-settings:"tnum"` and a mono eyebrow above.

**Voice:** editorial, calm, precise, second-person. Sentence case with closing periods. ALL-CAPS only for mono eyebrows/captions. No hype, no exclamation marks, **no emoji, ever.**

---

## 5. Iconography

**Lucide** (NF's set) at 1.5–2px stroke — outline, rounded, visually continuous with EA's FontAwesome/Glyphicons line icons and their slate colouring. Ink (`--fs-ink2`) by default; tinted only to carry a signal — `net` for active, `agent` for the intelligence, `forecast` for prediction. Sizes: 18 inline · 20 nav · 24 section.

The **circular icon-badge** (a Lucide glyph inside a 1.5px ring, tinted by semantic) is lifted directly from EA's quick-links and is Freeside's channel/quick-action affordance. No emoji, no icon-as-text.

---

## 6. Shape, spacing, elevation, motion

- **Radii:** `sm 6 · md 10 · lg 14 · xl 18 · pill 999`. Cards `lg`/`xl`; inputs `md` or `pill`; controls `pill`.
- **Spacing:** 8px grid (`--fs-1…10` = 4→64). Section spacing 40–64px, card padding 24–32.
- **Elevation:** cool slate-tinted multi-stop shadows (`xs · sm · card · pop · hero · inset`) + a hairline ring. **Inset depth is the signature** — nested rectangles sink. Borders are hairlines or absent; **never a 1px coloured card frame, never a coloured left-edge bar.**
- **Motion:** calm. 120ms for state changes, 140ms card pop, `cubic-bezier(0.4,0,0.2,1)`, no bounce. Cards lift `−2px` on hover (card→pop shadow); buttons `−1px`. The orange breathing cursor is the "agent is live/thinking" indicator. Skeleton loaders, never neon spinners. All motion respects `prefers-reduced-motion`.

---

## 7. Components (see `index.html` for every one, rendered)

- **Buttons** — Primary = network blue (commit to the platform). **Agent orange is reserved for the single verb that dispatches an agent** — the one sanctioned exception to "orange is never a CTA," because dispatching *is* the NF-intelligence act. Ghost = hairline. Danger = red outline.
- **Intent field** — the marquee input: a large rounded field with a mono `OBJECTIVE` label and an orange prompt caret. Plus EA-style pill search inputs and inset labelled fields.
- **Filter chips** — EA's pill chips in NF hairline; selected = filled blue.
- **Status** — CLI pills `[ AWAITING APPROVAL ]`, solid semantic badges, pulsing status dots (live/pred/done).
- **Cards** — content card, **person card** (EA directory pattern: avatar / bold name / muted role / mono location / bottom action row), **stat & forecast tile** (big number + confidence bar), **agent proposal card** (human-gated: agent eyebrow, `[ AWAITING APPROVAL ]`, the intent pair, and Approve / Edit / Dismiss).
- **Channels** — EA quick-link pills, NF-styled: circular icon-badge + mono label + chevron, tinted by semantic.
- **List rows, pagination, confidence bar, shell nav** — nav carries the NF 4-node "share" mark (orange hub + arm) and an agent-status cluster (`● 2 AGENTS LIVE`).

---

## 8. Signature motifs — where EA meets NF

1. **The constellation hero.** EA's low-poly faceted deep-navy panel, reinterpreted through NF's 4-node network mark: orange nodes and thin edges sit over the blue faceted field — *the agent (orange) watching the network (blue).* One per view; restraint is the rule.
2. **The human ◆ machine pair (the intent line).** A bold-sans human phrase ◆ a JetBrains-mono machine phrase, with the breathing cursor alternating orange (human) and blue (machine). In Freeside it *is* the core interaction: stated objective ◆ agent plan/status.
3. **Console voice.** Boot-info strips, numbered agent menus, `[ … ]` CLI status pills, mono metadata — the "supervise agents / command the network" register.
4. **Human-gated proposal.** Keith's non-negotiable propose → review → approve → run, rendered as its own card family (never an auto-run button).

---

## 9. Do / Don't

**Do** — keep blue for the network and orange for the intelligence, always · keep orange to spot accents (the logo node, a live signal, one dispatch) · lift white cards with shadow + hairline · put a mono machine caption beside a human phrase · gate every agent action behind approve → run · keep motion calm (120ms, −2px).

**Don't** — let orange dominate a screen, or use it as a fill / for body emphasis · frame a card with a coloured border or left-edge bar · reach for serif, emoji, glassmorphism, neon, or bluish-purple SaaS gradients · show Freeside / Molly / Seldon / Case naming to an end customer · put more than one constellation panel (or two textures) on a view.

---

## 10. Accessibility — mandatory, and scan-clean

**Target: WCAG 2.1 / 2.2 level AA, on every surface.** Accessibility is not a polish pass — the tokens and components are built to pass, so an axe / Lighthouse / pa11y scan should find nothing. If you use the system as documented, you inherit that. Don't undo it.

### Colour & contrast (the thing scanners flag most)
Every text/UI pairing in the tokens meets AA (verified with the WCAG formula, both themes):

| Pair | Ratio | Rule |
|---|---|---|
| `ink` / `ink2` / `ink3` on white | 16.4 · 9.6 · 5.2 | Body & captions all clear AA. `ink3` is the floor — don't go lighter for text. |
| `net` link text / `net` button | 5.1 | `--fs-net` is tuned so it passes **both** as link text and as a white-on-blue fill. |
| Accent **lettering** | ≥4.5 | Use the `*-text` tokens: `--fs-agent-text`, `--fs-warn-text`, `--fs-danger-text`, `net-strong`. `forecast`/`sim` pass as-is. |
| Badges (`*-ink` on `*-soft`) | 6.4–10.8 | The dark-on-tint badge pairs are all safe. |
| Dispatch (orange) button | 5.8 | **Dark ink on the orange fill** — white-on-orange fails AA, so we never do it. |

**The rules:**
- **The vivid accent hues (`--fs-agent`, `--fs-warn`, `--fs-danger`) are for fills, dots, icons and borders — never small text.** For coloured lettering use the matching `*-text` token. This is baked into `.fs-eyebrow--*` and `.fs-pill--*`; follow it in bespoke CSS too.
- **White text only goes on `net`, `net-strong`, `net-deep`, `sim`, `forecast` fills.** Orange takes dark ink; amber/red as a solid fill needs checking (prefer the `-soft`/`-ink` badge pair).
- **Never rely on colour alone.** A status is a colour *and* a text label (the CLI pills) or a shape. The green/red delta arrows carry a glyph (▲/▼), not just hue.
- Re-run the contrast check if you introduce a colour: the formula + the token table live in the repo; keep new pairs ≥4.5 (text) / ≥3.0 (UI & large text).

### Keyboard & focus
- **Every interactive element has a visible focus ring** (`:focus-visible` → 3px `net` outline, ≥3:1 both themes). Never set `outline:none` without an equally-visible replacement.
- Everything operable by mouse is operable by keyboard, in a logical tab order. Use real `<button>` / `<a>` — not clickable `<div>`s.
- Provide a **skip link** to main content (`.fs-skip` / `.fs-sr-only` becomes visible on focus).

### Semantics & ARIA
- Real landmarks: `<header>`, `<nav>`, `<main>`, `<footer>`. One `<h1>` per page; headings in order, no skips.
- **Icon-only controls need an accessible name** — `aria-label` or a `.fs-sr-only` span. Icons that sit next to a text label are decorative → `aria-hidden="true"`.
- **Decorative SVG is `aria-hidden="true"`** — the logo mark, the constellation hero, the breathing cursor, the facet field. They carry no information.
- Live agent status that updates should sit in an `aria-live="polite"` region.

### Forms
- Every field has a programmatic label — a `<label for>` or `aria-label`. **Placeholder text is not a label.**
- Errors are announced in text (and associated via `aria-describedby`), never signalled by red border alone. Mark required fields in text, not colour.

### Motion, media, language
- **`prefers-reduced-motion` is honoured** globally — the breathing cursor, pulse and hovers stop. Don't add motion that ignores it. Nothing flashes more than 3×/sec.
- Real images need meaningful `alt`; decorative images get `alt=""`. Avatars fall back to initials, not an empty box announced to AT.
- Set `<html lang>`. Copy is plain and second-person (see §4) — readability is an a11y feature.

### Target size & robustness
- Interactive targets are ≥24×24px (WCAG 2.5.8); buttons ship at 40px. Give small controls `.fs-target`.
- **Forced-colors / Windows High Contrast** is supported — cards, chips, buttons keep a border and focus stays visible.

### How we verify (do this before you ship)
1. **Automated:** an axe-core / Lighthouse / pa11y run with **zero violations** is the bar. Wire it into CI where you can.
2. **Keyboard:** tab through the whole surface — everything reachable, visible focus, no traps, Esc closes overlays.
3. **Screen reader:** one pass (VoiceOver / NVDA) — names, roles, and live updates make sense.
4. **Zoom & reflow:** 200% zoom and a 320px-wide viewport with no loss of content or horizontal scroll.

### PR checklist
- [ ] axe/Lighthouse: 0 violations · [ ] contrast ≥ AA (used tokens, not raw hues, for text) · [ ] keyboard-operable with visible focus · [ ] every control & field has an accessible name · [ ] decorative visuals `aria-hidden` · [ ] status isn't colour-only · [ ] reduced-motion respected · [ ] `<html lang>` + heading order · [ ] 200% zoom / 320px reflow OK.

---

## 11. Component library

`freeside-components.css` (load after `freeside.css`) is the full kit. It is plain CSS + markup
patterns — deliberately framework-agnostic, so the shell, Seldon and Case can all consume it
whatever they're built in. Live gallery: **`components.html`**.

| Group | Components |
|---|---|
| **Fields** | text · textarea · select · multi-select · search (pill) · password · number stepper · date · range slider · checkbox (+ indeterminate, boxed) · radio · switch · segmented control · token/tag input · file dropzone · file row · fieldset · form grid |
| **Field anatomy** | label · required/optional marker · hint · error / success / warning message · character count · prefix & suffix addons · leading/trailing icons |
| **Field states** | default · hover · focus · filled · error · success · warning · disabled · read-only · loading |
| **Buttons** | primary · agent (dispatch) · ghost · subtle · danger · link · sizes sm/md/lg · icon-only · block · loading · disabled · button group · toolbar |
| **Navigation** | tabs (underline + pill) · breadcrumbs · sidebar nav (+ collapsed rail) · dropdown/context menu · pagination · stepper/wizard · skip link |
| **Status** | CLI pills · badges · status dots · alerts (info/success/warn/danger/agent) · status boxes · toasts · tooltips · progress (determinate & indeterminate) · spinner · skeleton · empty state |
| **Overlays** | modal · drawer · scrim · toast region · tooltip |
| **Data** | table (sortable, selectable, zebra, dense, sticky) · key-value list · avatars & stacks · accordion · timeline · list rows |

**Rules of use**
- Compose from these classes; don't fork them per app. If something is missing, add it *here* and
  push, so every service gets it.
- Every interactive element inherits the focus ring — don't remove it.
- Icon-only controls take an `aria-label`; decorative icons take `aria-hidden="true"`.
- Status is icon + text, never colour alone. Required is text, never colour alone.
- Sizes: one size per surface. Don't mix `sm` and `lg` controls in the same row.

### Iconography
118 icons ship as a sprite at `assets/freeside-icons.svg`, generated from
`tools/build-icons.py` (the single source of truth — edit that, re-run, never hand-edit the sprite).
Gallery with search + copy-name: **`icons.html`**.

```html
<svg class="fs-icon" aria-hidden="true"><use href="assets/freeside-icons.svg#fs-i-forecast"/></svg>
```

Categories: **Navigation** (25) · **Actions** (36) · **Status** (18) · **Domain** (32, Freeside-specific —
network, agent, intent, forecast, campaign, approval, scenario…) · **Files** (7). Outline, 24×24,
1.7 stroke, `currentColor` — continuous with EA's line iconography. Sizes: 15 inline · 18 default ·
22 section · 28 feature. Ink by default; tint only to carry a signal. **No emoji, ever.**

---

## 12. Charts & data visualisation

Freeside is a predictive product, so charts are the product. `freeside-charts.css` +
**`charts.html`** (worked examples and the full rule list).

**The palette was computed, not chosen.** It passes the lightness band, chroma floor, colourblind
separation (deutan/protan/tritan), normal-vision separation and contrast-vs-surface — in light
**and** dark, which use separately-selected steps rather than a flip.

| Job | Tokens | Rule |
|---|---|---|
| **Categorical** (identity) | `--fs-c1…c6` | Fixed order, never cycled. Six is the ceiling — a 7th series folds into "Other" or gets faceted. |
| **Sequential** (magnitude) | `--fs-seq1…6` | One hue, light → dark. Heatmaps, density. |
| **Diverging** (polarity) | `--fs-div-neg2…pos2` | Two poles + a **neutral grey** midpoint. Never a hue in the middle. |
| **Status** (state) | `forecast` / `warn` / `danger` / `agent` | Reserved. Never reused as "series 4". |

**Picking the form:** one number → stat tile (not a chart) · over time → line/area · magnitude → bar ·
composition → stacked bar · comparison → grouped bar or dot plot · polarity → diverging bar ·
density → heatmap · trend-in-a-row → sparkline.

**Non-negotiables**
- **No dual axes, ever.** Two measures of different scale → two charts, small multiples, or index both.
- No rainbow, no invented hues, no 3D, no shadows on marks. Bars start at zero.
- Colour follows the entity, never its rank — filtering must not repaint the survivors.
- Predicted data is **dashed**; uncertainty is a **band**, not a second line; the "now" boundary is
  marked (the one place orange appears in a chart).
- State the **unit and period** in the subtitle.
- Legend for ≥2 series (one series needs none); direct-label up to 4. Legend/value **text stays ink** —
  the swatch carries identity.
- **Every chart ships an accessible table twin** behind a toggle, plus an `aria-label` that states the
  takeaway, not just the chart type.
- Changing a chart colour? **Re-run the validator** — CVD separation is computed, never eyeballed.

---

## 13. Mobile web

Freeside is a cockpit, but it gets read on a phone between meetings — an admin approving a
proposal in a taxi is a first-class use case. **Build mobile-first**: design the 375px layout, then
enhance upward. The rules below are enforced in `freeside-components.css` §6; don't undo them.

### Breakpoints
`sm 480` · `md 768` · `lg 1024` · `xl 1280`. Use `max-width:768px` as the "is this a phone" line.
Layouts collapse to one column at `md`. **Never** ship a horizontal scrollbar on the page itself —
WCAG 1.4.10 requires reflow at 320px CSS width with no two-dimensional scrolling. Test at 375px and 320px.

### Touch
- **Targets are 44×44px on coarse pointers** (WCAG 2.5.8's floor is 24px; 44 is the usable size).
  Buttons, icon buttons, pagination and stepper controls all grow automatically under
  `@media (pointer:coarse)`. Give small custom controls `.fs-target` plus padding — grow the *hit
  area*, not the visual box.
- **≥8px between adjacent targets.** Two 44px buttons touching is one 88px mistake.
- **Nothing may be hover-only.** Hover doesn't exist on touch: any action revealed on hover must
  also be reachable by tap or a visible affordance. CSS tooltips are hidden on touch — use a
  popover or inline text instead.
- Every control needs a **pressed state** (`:active`), because there's no hover to confirm the tap.
- Put the primary action **within thumb reach** — bottom of the screen, not the top-right corner.

### Inputs
- **16px minimum font-size on inputs**, or iOS silently zooms the whole page on focus. Enforced
  below `md` — never override it back down.
- Use the right keyboard: `type="email|tel|url|number"`, `inputmode="numeric|decimal|search"`,
  and `autocomplete` (`name`, `email`, `organization`, `one-time-code`). This is a usability *and*
  accessibility win, and it's free.
- Labels stay **above** the field on mobile (never inline/left) so the label survives zoom.
- Full-width controls and full-width buttons below `md`; stack form actions with the **primary
  last** (closest to the thumb) — `.fs-form-actions` does this via `column-reverse`.
- Avoid multi-column forms, tight date pickers, and anything needing precise dragging.

### Layout patterns
| Desktop | Mobile |
|---|---|
| Sidebar nav | **Bottom bar** (`.fs-bottombar`, ≤5 items) or off-canvas drawer + hamburger |
| Centred modal | **Bottom sheet** — `.fs-modal` becomes one below 600px, with a safe-area inset |
| Side drawer | Full-width drawer |
| Wide table | **Card table** (`.fs-table--cards` + `data-label` per cell) *or* horizontal scroll inside `.fs-table-wrap` with `.fs-scroll-hint` — pick one, don't shrink the type |
| Toolbar row | `.fs-actionbar` sticky at the bottom |
| Multi-column grid | Single column (`.fs-form-grid`, `.fs-steps` collapse automatically) |

Utilities: `.fs-hide-mobile` · `.fs-only-mobile` · `.fs-stack-mobile` · `.fs-full-mobile` · `.fs-scroll-x`.

### Viewport & chrome
- `<meta name="viewport" content="width=device-width, initial-scale=1">` — and **never**
  `user-scalable=no` or `maximum-scale=1` (blocks pinch-zoom; WCAG 1.4.4 failure).
- Use **`dvh`, not `vh`** (`.fs-app{min-height:100dvh}`) — mobile browser chrome resizes the viewport.
- Respect the notch: pad fixed bottom elements with `env(safe-area-inset-bottom)`.
- **Support both orientations** (WCAG 1.3.4) — never lock to portrait.
- Beware fixed elements when the on-screen keyboard opens; prefer `position:sticky` inside the
  scroll container over `position:fixed` for form action bars.

### Charts on mobile
- One chart per row; give the plot a `min-height` (~180px) so it doesn't collapse.
- Reduce tick density and drop to **direct labels** instead of a legend where you can.
- Long time series: horizontal scroll inside `.fs-scroll-x`, keeping the y-axis fixed — never
  squash 90 points into 320px.
- **The table twin matters more on mobile**, not less — often it's the better default there.
- Tooltips need tap-to-show and tap-elsewhere-to-dismiss, since hover doesn't exist.

### Content & performance
- Body text stays **16px**; never below 12px for any text on mobile.
- Headings step down (display 56 → ~30) — keep the hierarchy, lose the scale.
- Truncate with real ellipsis + a title/`aria-label`, never by clipping overflow.
- Images and avatars are `max-width:100%`; the sprite keeps icons at one request.
- Keep the payload lean — the design system is plain CSS with no runtime; don't add a framework
  to a surface that only needs a list.

### Mobile PR checklist
- [ ] No horizontal page scroll at 375px **and** 320px · [ ] targets ≥44px with ≥8px gaps ·
- [ ] no hover-only actions · [ ] inputs ≥16px with correct `inputmode`/`autocomplete` ·
- [ ] primary action thumb-reachable · [ ] tables scroll or stack (type not shrunk) ·
- [ ] pinch-zoom not blocked · [ ] `dvh` + safe-area on fixed bottom UI · [ ] both orientations ·
- [ ] tested in light and dark.

---

## 14. Provenance & confidentiality

Colours and texture are **sourced from** EnterpriseAlumni's live portal; grammar, type and motifs from NativeFoundation's RelayOS. This is a *new NF system informed by* EA — not EA's assets. Freeside / Molly / Seldon / Case are internal NF + EA-staff names, **never** shown to end customers. Per the hard constraint: **EA-confidential work must not leak into NF public branding**, and this system must not leak into EA's customer-facing surfaces beyond the agreed cockpit.
