# Layout2 — Redesign Tracker > Visual redesign only. **Functions stay identical.** No data flow, query, route, or > behavior changes. If a change touches logic, it does not belong in Layout2. - **Branch:** `redesign` - **Dev:** http://localhost:5173/ (Vite HMR, no rebuild) - **Live:** untouched — nothing deploys until explicitly approved. No `vercel --prod` during Layout2. - **Started:** 2026-06-23 --- ## Rules 1. Redesign = layout, spacing, hierarchy, components' visual form. No prop/state/handler edits. 2. Keep every element that exists today (buttons, fields, badges) — reposition/restyle, don't remove function. 3. Preserve all routes, role gates (`team`/`external`/`client`), and conditional rendering as-is. 4. Reuse design tokens (below). Add new tokens rather than hard-coding values. 5. Commit per page/section with `redesign:` prefix so it's revertible. --- ## Direction - **Background:** solid 95% black `#0d0d0d`, no gradient, no animation. - **Cards:** solid gray `#1a1a1a` (5% lighter than bg); elevated/hover `#242424`. - **Font:** **Inter** (Google Fonts, weights 300–700) — modern, readable, app-wide. Brand `Fourge` font retired from UI text; logo is an image, unaffected. --- ## Control panel (single source of truth — `src/index.css :root`) Change one line, every card/page across **all roles** updates. | Knob | Token / line | Scope | |---|---|---| | Background | `--bg` | whole app | | Card fill | `--card-bg` (+ `--card-bg-2` elevated/hover) | every card | | Card border | `--card-border` (`1px solid transparent` = off) | every card | | Card radius | `--card-radius` | every card | | Font | body `font-family` (Inter) | whole app | | Accent / gold | `--accent` (+ `--accent-hover`) | all gold UI | | Status: error | `--danger` (+ `--danger-strong`) | all red | | Status: success | `--success` (+ `--success-strong`) | success greens | | Money/positive | `--positive` | dashboard/positive green | | Info | `--info` | blue | | Violet | `--violet` | purple | | Warning | `--warning` | amber | **Tints** pull from the same token: `color-mix(in srgb, var(--accent) 15%, transparent)`. All semantic colors are theme-independent (badge light palette stays in `index.css`). ~168 hardcoded hex/rgba across 15 JSX files were swept to these tokens (zero visual change). Cards = elements with `var(--card-bg)`; their frame uses `var(--card-border)`. The **menu/sidebar** also uses `--card-border` + `--card-radius`. Inputs/tables/toolbar dividers keep their own `--border` and are intentionally NOT card-controlled. **Theming:** tokens live in `:root` (dark defaults); `[data-theme="light"]` overrides values. Same token name site-wide, one value per theme. `--card-border` is set in both themes (dark `#262626`, light `rgba(0,0,0,0.08)`); `--card-radius` is shared (color-free). ## Full token chart (canonical — `src/index.css`) All in `:root` (dark); `[data-theme="light"]` overrides where noted. Same token name site-wide, one value per theme. Solids = `var(--x)`; tints = `color-mix(in srgb, var(--x) N%, transparent)`. ### Surfaces | Token | Dark | Light | |---|---|---| | `--bg` | `#1a1a1a` | `#ffffff` | | `--card-bg` | `#1f1f1f` | `rgba(0,0,0,.02)` | | `--card-bg-2` | `#262626` | `rgba(0,0,0,.08)` | | `--surface-sunken` | `#141414` | `#f5f5f5` | | `--popup-bg` | `var(--card-bg)` (= `#1f1f1f`) | `rgba(255,255,255,.92)` (opaque; light card-bg is translucent) | ### Borders | Token | Dark | Light | |---|---|---| | `--border` | `rgba(245,165,35,.15)` | `rgba(0,0,0,.1)` | | `--card-border` | `1px solid #262626` | `1px solid rgba(0,0,0,.08)` | | `--card-radius` | `8px` | shared | | `--interactive-hover-border` | `rgba(245,165,35,.3)` | `rgba(0,0,0,.2)` | ### Text | Token | Dark | Light | |---|---|---| | `--text-primary` | `#ffffff` | `#0d0d0d` | | `--text-secondary` | `#a8a8a8` | `rgba(0,0,0,.6)` | | `--text-muted` | `#666666` | `rgba(0,0,0,.38)` | | `--text-on-accent` | `#000000` | shared | ### Brand & status (theme-independent) | Token | Value | |---|---| | `--accent` / `--accent-hover` | `#F5A523` / `#e09510` | | `--danger` / `--danger-strong` | `#ef4444` / `#dc2626` | | `--success` / `--success-strong` | `#22c55e` / `#16a34a` | | `--positive` | `#4ade80` | | `--info` | `#60a5fa` | | `--violet` | `#a78bfa` | | `--warning` | `#f59e0b` | ### Data / categorical (charts, file-type chips — by hue) | Token | Value | Token | Value | |---|---|---|---| | `--data-blue` | `#3b82f6` | `--data-indigo` | `#2563eb` | | `--data-purple` | `#8b5cf6` | `--data-purple-soft` | `#c084fc` | | `--data-pink` | `#ec4899` | `--data-pink-soft` | `#f472b6` | | `--data-orange` | `#f97316` | `--data-orange-soft` | `#fb923c` | | `--data-emerald` | `#10b981` | `--data-emerald-soft` | `#34d399` | | `--data-gray` | `#6b7280` | | | ### Utility / misc | Token | Dark | Light | |---|---|---| | `--overlay-scrim` | `rgba(0,0,0,.58)` | `rgba(255,255,255,.72)` | | `--popup-shadow` | `0 24px 64px rgba(0,0,0,.5)` | lighter | | `--avatar-inner-ring` | `#111111` | `#ffffff` | | `--sidebar-*` | bg `#0d0d0d`, text `#888`, active `#fff`/`#1a1a1a` | inverted | | motion | `--motion-fast 160ms`, `--motion-base 220ms`, ease `cubic-bezier(0.22,1,0.36,1)` | | | buttons | h `22px`, radius `8px`, font `11px/500`, tracking `0.8px` | | **Intentionally NOT tokenized (must stay literal):** - Canvas/PDF export colors (`BrandBook.jsx`, `Converters.jsx` — `ctx.fillStyle`), white logo backgrounds. - `PayInvoice.jsx` — public printable invoice, standalone light styling, must not follow app theme. **Established patterns (from memory):** - Card label color `rgba(255,255,255,0.8)`. - Filter/tab layout: dropdowns *outside* card, tab buttons *inside* card above table. Canonical: `Tasks.jsx` (Requests). --- ## Shared shell / components | Item | File | Status | |---|---|---| | App shell / sidebar / nav | `src/components/Layout.jsx` | ⬜ | | Global tokens & base CSS | `src/index.css` | ⬜ | | StatusBadge | `src/components/StatusBadge.jsx` | ⬜ | | FilterDropdown | `src/components/FilterDropdown.jsx` | ⬜ | | SortTh (table headers) | `src/components/SortTh.jsx` | ⬜ | | ProfileAvatar | `src/components/ProfileAvatar.jsx` | ⬜ | | LoadingButton / PageLoader | `src/components/{LoadingButton,PageLoader}.jsx` | ⬜ | | RequestForm | `src/components/RequestForm.jsx` | ⬜ | | Invoice popups / tables | `InvoiceDetailPopup`, `InvoicePopupTable` | ⬜ | | Subcontractor invoice form/view | `SubcontractorInvoice{Form,DetailView}.jsx` | ⬜ | | FileAttachment | `src/components/FileAttachment.jsx` | ⬜ | ## Pages | Route | Page | Roles | Status | |---|---|---|---| | `/` | Login | all | ⬜ | | `/dashboard` | `team/TeamDashboard.jsx` | team/external/client | ⬜ | | `/tasks` | `Tasks.jsx` (Requests) | team/external/client | ⬜ | | `/tasks/:id` | `TaskDetail.jsx` | team/external/client | ⬜ | | `/projects/:id` | `ProjectDetail.jsx` | team/external/client | ⬜ | | `/company` | `Companies.jsx` | team/client | ⬜ | | `/company/:id` | `CompanyDetail.jsx` | team/client | ⬜ | | `/finances` | `team/TeamInvoices.jsx` | team | ⬜ | | `/finances/:id` | `team/TeamInvoiceDetail.jsx` | team | ⬜ | | `/subcontractor-pos/new` | `team/TeamCreateSubcontractorPO.jsx` | team | ⬜ | | `/subcontractor-pos/:id` | `team/TeamSubcontractorPODetail.jsx` | team | ⬜ | | `/sub-invoices/:id` | `team/TeamSubInvoiceDetail.jsx` | team | ⬜ | | `/reports` | `team/TeamReports.jsx` | team | ⬜ | | `/fourge-passwords` | `team/TeamFourgePasswords.jsx` | team | ⬜ | | `/survey-maker` | `SurveyMaker.jsx` | team/external | ⬜ | | `/brand-book` | `BrandBook.jsx` | team/external | ⬜ | | `/converters` | `Converters.jsx` | team/external | ⬜ | | `/my-purchase-orders` | `external/ExternalMyPurchaseOrders.jsx` | external | ⬜ | | `/subs-invoices` | `external/ExternalMyInvoices.jsx` | external | ⬜ | | `/subs-invoices/new` | `external/ExternalMyInvoiceCreate.jsx` | external | ⬜ | | `/subs-invoices/:id` | `external/ExternalMyInvoiceDetail.jsx` | external | ⬜ | | `/client-invoices` | `client/ClientMyInvoices.jsx` | client | ⬜ | | `/profile`, `/profile/:id` | `Profile.jsx` | all | ⬜ | | `/pay/:id` | `PayInvoice.jsx` | public | ⬜ | Legend: ⬜ todo · 🔄 in progress · ✅ done --- ## Log - 2026-06-23 — Doc created, `redesign` branch cut, dev on 5173. - 2026-06-23 — Base tokens: solid `#0d0d0d` bg, killed animated grid; cards `#1a1a1a`/`#242424`. Font → Inter. - 2026-06-23 — bg → `#1a1a1a` (90% K), cards `#1f1f1f`/`#262626` (88% K), solid/no transparency. - 2026-06-23 — Tokenized cards: added `--card-border` (off) + `--card-radius`; swept 28 inline card frames + `.card` class to the tokens. All cards now controllable from one line. - 2026-06-23 — Card border on at `#262626` (85% K); light-mode `--card-border` = `rgba(0,0,0,0.08)`; menu/sidebar routed to `--card-border`/`--card-radius`. - 2026-06-23 — Color system: added `--positive/--info/--violet/--warning/--danger-strong/--success-strong`; swept 168 hardcoded colors across 15 JSX files to tokens + `color-mix` tints. Site/role/page colors now single-source. - 2026-06-23 — Completed palette: added `--data-*` (hue-named) categorical set, `--surface-sunken`, `--text-on-accent`. Swept file-type chips + chart colors + surface neutrals to tokens. Remaining literals are canvas/PDF exports + PayInvoice (intentional). Full chart documented above. - 2026-06-23 — Popups single-source: `--popup-bg` now = `var(--card-bg)` (dark); stripped 8 inline `background: var(--card-bg)` overrides on `popupSurfaceStyle` so loader/modals/menus all use the token. Light stays opaque white. - 2026-06-23 — Dashboard reflow: row2 = To Do (fluid) + Calendar (280px); row3 = Activity / In-Progress / Team Perf. New `.dash-row-todo` / `.dash-row-trio` classes; responsive (trio 2-up ≤1200, all stack ≤768). Retired bottomCardsHeight viewport-fill hack. Mobile-friendly is now a standing requirement for Layout2. - 2026-06-23 — Perf sweep: root cause = ~400–770ms/query server cold-start (compute tier, infra). Code fixes: added FK/filter index migration (pushed to DB); removed redundant client/external scope waterfall in Tasks + Dashboard (rely on RLS, verified `has_company_access`/`project_members` parity); embedded submitter-profiles + deliveries into the Tasks submissions query (−2 round trips all roles). Test client/external dashboards on 5173. - 2026-07-15 — Naming cleanup: the 91045a1 Project→Client rename was only partially walked back by later commits, leaving the project entity mislabeled "Client" in ~20 spots (Add Project modal, filters, PO/report/dashboard columns, etc.) while table headers already said "Project". Confirmed with user: **Company** = the customer org (e.g. "Public Storage"), **Project** = a job within that company — "Client" was a leftover label, not a third entity. Reverted all mislabeled text to "Project"; reverted the `/clients/:id` route back to canonical `/projects/:id` (nothing deployed to prod yet, so no live URLs broke). Also: removed stale pre-redesign `layout.md` (superseded by this doc), stopped tracking `.env.backfill` (had a live admin password/token committed — rotate those credentials separately).