diff --git a/docs/design/edition-color-vocabulary.md b/docs/design/edition-color-vocabulary.md
index a0f818fcc..0377741d5 100644
--- a/docs/design/edition-color-vocabulary.md
+++ b/docs/design/edition-color-vocabulary.md
@@ -9,7 +9,7 @@ This names the **roles** colors play in the voter-facing edition views, independ
- **Reuse and retheme the existing shadcn token names** where a role already exists (`background`, `foreground`, `muted-foreground`, `border`, `ring`, `popover`, `accent`, `destructive`). New names are added only for roles shadcn doesn't cover. No `ed-*` namespace.
- **No numeric ramps.** Each role is one value per theme; "lighter/darker" variants are expressed as alpha on the base token (Tailwind `/NN` over an HSL var) or as an explicit `-soft` companion, not as `-100…-900` scales.
- **`/NN` opacity modifiers work only on opaque roles** (`foreground`, `accent`, `live`, `vote-must`, …). The inherently translucent roles (`surface`/`surface-raised`/`surface-active`, `accent-soft`, `border`/`border-strong`, `*-soft`) carry their alpha inside the CSS variable, so `bg-surface/50` expands to a double-alpha `hsl(… / 0.05 / .5)` — silently invalid CSS. Use the next step in the role family (`surface` → `surface-raised` → `surface-active`) instead of a modifier.
-- **Portals escape the scope.** The variables live on the edition root (`EditionViewRoot`), but Radix `Select`/`Popover`/`Sheet` content portals under `document.body` and resolves the global values there. Before tokenizing portaled content, give it the scope (portal `container` inside the edition root, or the scope class on the content element).
+- **The tokens live on `:root`, not a scope class (#367).** The whole app renders on the same dark identity today, so there's one set of values for the whole app — including admin and Radix portal content — and no scope class to remember. The flip (#359) will attach `data-edition-theme="light"` to the document root.
- Values below reference today's hardcoded classes only to define the mapping; the actual palette is chosen in #320/#321.
## Token set
@@ -32,6 +32,8 @@ This names the **roles** colors play in the voter-facing edition views, independ
| `surface-active` **(new)** | Hover/pressed/selected layer | `bg-white/20`, `bg-white/30` |
| `popover` (existing) | Solid floating sheets, dropdowns, drawers | `bg-gray-800`, `bg-gray-900`, `bg-gray-900/95` |
+`paper-background` / `paper-foreground` / `paper-muted-foreground` / `paper-border` **(new, admin/auth only)** are a stopgap for shared shadcn primitives (`Dialog`, `Input`, `InputOTP`, `Table`, toasts, `AuthDialog`) that render on a plain white chrome surface outside the edition views and were left invisible when `background`/`foreground`/`muted-foreground`/`border` were repointed to the dark identity. Named `paper-*` (not `surface-*`) specifically to avoid colliding with the `surface`/`surface-raised`/`surface-active` overlay-fill family above — those are translucent layers on the dark ground, `paper-*` is an opaque light page/dialog background, and the two are unrelated roles that happen to share a domain vocabulary. They're hardcoded grays/white today, not theme-aware. Once the light/dark flip (#359) lands, fold them into `background`/`foreground`/`muted-foreground`/`border` (scoped to the light theme value) and delete this family.
+
### Borders & focus
| Token | Role | Absorbs today |
@@ -40,11 +42,14 @@ This names the **roles** colors play in the voter-facing edition views, independ
| `border-strong` **(new)** | Emphasis / selected outlines | `border-purple-400/40`–`/50`, `border-purple-400`, `border-white/50`–`/80` |
| `ring` | Focus/selection ring | `ring-purple-400`, `ring-white` |
+A hairline drawn in `border-white/NN` (not purple) doesn't fit either border role — reach for `border-foreground/NN` instead: `foreground` is opaque and already carries today's white value, so the opacity modifier reproduces the exact color without borrowing a fill role (`surface`) for a border.
+
### Brand accent (interactive)
| Token | Role | Absorbs today |
| ------------------------------ | ------------------------------------------------ | -------------------------------------------------- |
-| `accent` / `accent-foreground` | Primary interactive fill: selected toggles, CTAs | `bg-purple-600`, `bg-purple-700`, `bg-purple-400` |
+| `accent` / `accent-foreground` | Primary interactive fill: selected toggles, CTAs | `bg-purple-600`, `bg-purple-400` |
+| `accent-hover` | Hover state for the accent fill | `hover:bg-purple-700` |
| `accent-soft` **(new)** | Translucent accent wash for selected/hover chips | `bg-purple-600/30`–`/60`, `bg-purple-400/10`–`/30` |
| `text-accent` | Accent-colored text/icons | `text-purple-400` |
diff --git a/docs/design/edition-identity-spec.md b/docs/design/edition-identity-spec.md
index a5b9d822a..0483153b9 100644
--- a/docs/design/edition-identity-spec.md
+++ b/docs/design/edition-identity-spec.md
@@ -2,7 +2,7 @@
Resolution of [#321](https://github.com/chiptus/UpLine/issues/321), part of the visual-identity wayfinder map [#317](https://github.com/chiptus/UpLine/issues/317). Written in the semantic token vocabulary from [`edition-color-vocabulary.md`](./edition-color-vocabulary.md); implementation tickets are cut from this document.
-**Scope:** the voter-facing edition views only (EditionView hero/tabs, schedule Now/Timeline/List, artists, explore, set details). Admin, groups/settings, and landing/auth keep the old skin.
+**Scope:** the voter-facing edition views (EditionView hero/tabs, schedule Now/Timeline/List, artists, explore, set details). The tokens themselves live on `:root` globally (#367), so admin and Radix portal content pick them up too — but the palette and component work described here targets the edition views.
**Provenance:** direction decided in [#320](https://github.com/chiptus/UpLine/issues/320) (Festival v2 winner, soft-border light graft), confirmed against real screens by the in-app prototype pass on PR #354 (`src/pages/EditionView/prototype/`, deleted after rollout). Values below are the prototype's confirmed values, extended to the full #319 role set.
@@ -12,7 +12,7 @@ One skeleton, two color themes. **Dark is the default**: a violet poster ground
## Theme mechanics (CSS contract)
-- Token values are CSS variables scoped to the edition-view root. Dark values are the default; light values apply under an explicit `data-edition-theme="light"` scope on that root.
+- Token values are CSS variables on `:root` (#367). Dark values are the default; light values apply under an explicit `data-edition-theme="light"` attribute on the document root.
- Both themes ship. How the theme is chosen (system preference vs in-app toggle) and persisted is a rollout decision — [#322](https://github.com/chiptus/UpLine/issues/322)'s territory. The CSS contract above is what it plugs into.
- Values are stored as HSL channels to match the existing shadcn `hsl(var(--…))` plumbing; hex given here for legibility. Opaque roles are plain triples (`H S% L%`); the inherently translucent roles (`surface*`, `accent-soft`, `border*`, `*-soft`) carry their alpha inside the variable (`H S% L% / A`) — see the vocabulary's ground rules for why those roles must not take Tailwind `/NN` modifiers.
@@ -107,7 +107,7 @@ Same in both themes.
## What implementation consumes
-1. Token values above land in `src/index.css` under the edition scope, replacing the roles named in `edition-color-vocabulary.md`'s "absorbs today" mapping (~350 occurrences / 60 files per the #319 audit).
+1. Token values above land in `src/index.css` under `:root`, replacing the roles named in `edition-color-vocabulary.md`'s "absorbs today" mapping (~350 occurrences / 60 files per the #319 audit).
2. `tailwind.config.ts` gains the new role names (`surface*`, `subtle-foreground`, `border-strong`, `accent-soft`, `live*`, `notice*`, `vote-*`).
3. Font families wired once at the edition-view root; display styling via the heading rules above.
4. The prototype directory `src/pages/EditionView/prototype/` and its wiring are deleted once the real implementation lands.
diff --git a/src/components/ui/alert-dialog.tsx b/src/components/ui/alert-dialog.tsx
index 5cb5a1a36..4b40f13a7 100644
--- a/src/components/ui/alert-dialog.tsx
+++ b/src/components/ui/alert-dialog.tsx
@@ -34,7 +34,7 @@ const AlertDialogContent = React.forwardRef<
));
@@ -99,7 +102,7 @@ const TableCaption = React.forwardRef<
>(({ className, ...props }, ref) => (