Files
fourge-portal/layout.md
T
Krao Hasanee 986d831186 feat: finance page overhaul — pie charts, month nav, tab improvements
- Overview tab: 3 donut pie charts (expenses by category, sub payments, invoiced) each with independent month navigation arrows
- Expenses tab: big red total in category sidebar, left-aligned category column, white text
- Subcontractors tab: big gold total in sidebar, pending/paid breakdown with gold highlight
- Invoices tab: big green total in companies sidebar, dashboard-inline-link for invoice# and company, StatusBadge with Invoiced/Paid labels, column widths tuned
- StatusBadge: add optional label prop for custom display text
- Layout/style polish across tabs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 20:14:14 -04:00

20 KiB

Fourge Portal Layout System

This is the single source of truth for dashboard/profile visual structure and UI geometry.

1) Global Frame

  • Viewport app shell: height: 100vh, overflow: hidden
  • Main content gutter: 24px all sides
  • Sidebar: width: 76px, top: 24px, left: 24px, height: calc(100vh - 48px), border-radius: 8px
  • Main wrapper offset from sidebar: margin-left: 100px
  • Page rhythm unit: 24px (header spacing, card gaps, section gaps)

2) Theme + Background

  • Background ownership is body via background: var(--bg).
  • Dark base token --bg is full gradient:
    • radial glow + vertical dark gradient.
  • Light base token --bg is full gradient:
    • gray radial glow + white vertical gradient.
  • Do not use html theme-gradient scripting for Safari chrome behavior.

3) Tokens

  • Accent: #F5A523
  • Card bg dark: rgba(255,255,255,0.02)
  • Card bg light: rgba(0,0,0,0.02)
  • Sidebar/menu shell uses the same transparent card background token as cards
  • Secondary card tone dark: rgba(255,255,255,0.08)
  • Secondary card tone light: rgba(0,0,0,0.08)
  • Border dark: rgba(245,165,35,0.15)
  • Border light: rgba(0,0,0,0.1)
  • Text primary dark/light: #ffffff / #0d0d0d
  • Text secondary dark/light: #a8a8a8 / rgba(0,0,0,0.6)
  • Text muted dark/light: #666666 / rgba(0,0,0,0.38)

4) Typography

  • Font family: Fourge, then -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif
  • Base font size: 14px
  • Header title: 28px, 500, line-height: 1.2
  • Header subtitle: 13px
  • Widget title: 11px, 500, uppercase, letter-spacing: 0.8px
  • Section header (new standard): 18px, 500, Title Case, letter-spacing: 0.2px, line-height: 1.1
  • Body table text: 12px/13px by column importance

5) Card System

  • Default widget shell:
    • background: var(--card-bg)
    • border: 1px solid var(--border)
    • border-radius: 8px
    • padding: 18px 21px
    • backdrop-filter: blur(12px) + -webkit-backdrop-filter
  • Card width is not an intrinsic card token.
    • Width is owned by the page/grid/container the card lives in.
    • Cards should fill the slot provided by that page layout unless a page-level rule explicitly fixes a track.
  • Compact card radius (legacy generic .card): 4px (do not use for new dashboard widgets)

6) Header + Top Right Controls

  • Site header: padding-top: 24px, padding-bottom: 24px
  • Right control row:
    • Search icon button: 32x32
    • Search button to theme toggle space: 7px (search-wrap margin-right)
    • Theme toggle: 32x32
    • Theme toggle to avatar: 14px (avatar-wrap margin-left)
    • Avatar button: 49x49, circle, 2px inner ring + 2px accent outline

6.5) Section Control Bars (Tabs + Actions)

  • For page-level card controls (ex: Tasks/Projects, Finances tabs):
    • container uses: display: flex, align-items: center, gap: 4, margin-bottom: 10, flex-shrink: 0
    • margin-bottom: 10 is the site-wide standard gap between any tab/control bar and the card(s) below — use this everywhere, no exceptions
    • tab bar row must always be min-height: var(--btn-height) so the gap to the card never shifts when action buttons appear/disappear
    • tabs stay on the left in source order
    • action buttons group sits on the right using: margin-left: auto, display: flex, align-items: center, gap: 8
    • do not use hardcoded spacer blocks (width filler divs) to force alignment
    • icon-only filter/action buttons share the same row and align vertically with add buttons
    • when the control bar uses a multi-column grid (to align with split-card layouts below), add align-items: center to the grid and min-height: var(--btn-height) to every column so row height is stable across all tab states

7) Dashboard Grids (Team)

  • Stat row: grid-template-columns: 1fr 1fr 1fr 1.5fr, gap: 24, margin-bottom: 0
  • Row 2: grid-template-columns: 1fr 1fr 280px, gap: 24, margin-top: 24
    • Order: Recent Activity (left), Tasks In Progress (center), Calendar (right, fixed width)
  • Row 3: grid-template-columns: 1fr 1fr, gap: 24, margin-top: 24
  • Row 4 full-width: margin-top: 24

8) Stat Cards

  • Card min height: 120px
  • Internal row gap: 21px
  • Label/value/sub spacing:
    • Label: margin-bottom: 5px
    • Value: 30px, 400, letter-spacing: -0.5, line-height: 1.1
    • Sub: 12px, margin-top: 5px
  • Icon badge: 27x27, circle
  • Icon glyph: 13x13

9) Calendar

  • Card uses widget shell
  • Header-to-grid gap: 14px
  • Weekday label: 10px, 600, letter-spacing: 0.5
  • Day cell button: 28x28, circular
  • Day number: 12px
  • Today style: bg #F5A523, text #0d0d0d, 700
  • Dots: up to 3, each 3x3, gap 2
  • Popover:
    • Anchored left of cell: right: calc(100% + 8px), vertical centered
    • width: 210px, padding: 10px 12px, border-radius: 8px
    • shadow 0 12px 32px rgba(0,0,0,0.45)
    • row dot 6x6, row text 12px

10) Activity + Performance Rows

  • Visible rows target: 5
  • Row layout: display:flex, align-items:center, gap:10px
  • Row spacing: margin-top: 10px from second row onward
  • Name text: 13px
  • Meta/date text: 11px
  • Progress track: height: 4px, radius: 2px
  • Percentage width slot: min-width: 28px
  • Empty states in all cards (dashboard, profile, tasks, projects, file sharing, etc.):
    • any No ... message is centered in the card body (display:flex, align-items:center, justify-content:center)
    • use shared class treatment (.card-empty-center) for consistency
    • avoid top-offset-only placement for empty text

11) Tables

  • General table layout in dashboard cards: table-layout: fixed, border-collapse: collapse
  • Column widths are table-specific, not universal tokens.
    • Widths belong to the individual table/view that defines them.
    • Reuse widths only when the same table pattern is intentionally repeated.
  • Header cells:
    • font-size: 10px, font-weight: 500, uppercase, letter-spacing: 0.6px
    • bottom spacing: padding-bottom: 12px
    • sticky behavior for scrollable tables:
      • table headers stay fixed while body scrolls
      • use shared sticky-head treatment for all app tables (position: sticky; top: 0)
    • table scrollbars are visually hidden for table scroll containers; wheel/trackpad scrolling remains active
  • Body cells:
    • primary text: 13px
    • secondary/metrics text: 12px
    • row vertical spacing via cell padding: typically 5px
  • Hot Tasks column widths:
    • check 10%, task 40%, requested by 35%, due by 15%
  • Client Highlight column widths:
    • icon 5%, company 22%, contact 23%, projects 13%, open 13%, outstanding 12%, paid 12%
  • Sorting rule:
    • Every visible data column header must be sortable.
    • Use clickable header controls (SortTh) with ascending/descending indicator.
    • Exclude only non-data utility/action columns (checkbox-only, icon-only status marker, action buttons).

12) Profile Page

  • Container: full available content width, column, gap: 24
  • Top row: grid-template-columns: 60fr 40fr, gap: 24
  • At <=1200px: top row stacks to one column
  • Main profile card uses widget shell
  • Profile card width is determined by the profile page grid, not by the card itself.
  • Internal card layout:
    • row gap: 20px
    • portrait max 140x140, circle
    • portrait aligns flush in the row without extra wrapper padding/side space
    • detail grid 140px 1fr, row-gap: 8, column-gap: 12, margin-top: 14
    • profile name/title: 18px, 500, line-height: 1.2
    • company subtitle: 13px, secondary text
    • contact/detail rows: 13px, primary text
    • social row margin-top: 14, gap: 8
    • company line under title is always visible; fallback display is when no company is assigned
    • right-side meta labels (Member Since, Role) use widget-title sizing: 11px, 500, uppercase, letter-spacing: 0.8px
    • right-side meta values use body sizing: 13px
    • self-only edit button: position: absolute, top: 18px, right: 21px (aligns to card padding), border-radius: 8px (matches card), height: 22px, font-size: 12px, padding: 0 12px
    • default outline button hover/focus fills with accent gold and uses dark text
  • Right calendar card shows only tasks/events assigned to the viewed profile user
  • Profile page left column includes a Tasks In Progress card above Recent Activity
  • Profile Tasks In Progress follows the dashboard table/card pattern:
    • same widget shell and header treatment
    • same show-all behavior (5 visible by default)
    • profile-specific filter is tasks assigned to the viewed user with statuses in_progress, on_hold, or client_review
    • columns are Task and Status
  • Profile activity feed action text pattern: Task started, Task submitted, Task approved, Task rejected (sentence title case)
  • Activity feed includes:
    • actions performed by the viewed user
    • Task approved and Task rejected entries for tasks assigned to that viewed user (even if actioned by someone else)

12.5) File Sharing

  • Main split: grid-template-columns: minmax(0, 1fr) minmax(0, 3fr) for an effective 25 / 75 layout, gap: 24
  • Left stacked cards (Pinned, Navigation): gap: 24
  • Canonical folder structure:
    • team and subcontractor profile folders live at Team/<User Name>
    • company folders live at Clients/<Company Name>
    • project folders live at Clients/<Company Name>/Projects/<Project Name>
    • every project auto-creates 00 Project Files
    • task folders live at Clients/<Company Name>/Projects/<Project Name>/<Task Name>
    • every task auto-creates Request Info, Working Files, and Old Books
    • request submission files are copied into Request Info/R00, R01, and higher revision folders
    • renaming a team user, subcontractor user, company, project, or task must rename the matching filesystem folder
    • folder repair/backfill is additive only: create missing folders, leave existing folders untouched
    • request-info backfill must skip files that already exist and must not overwrite added working files or user-managed files
    • deleting a task in the portal moves its task folder into Archive/Clients/<Company Name>/Projects/<Project Name>/<Task Name> instead of deleting it
    • deleting a project in the portal moves its project folder into Archive/Clients/<Company Name>/Projects/<Project Name> instead of deleting it
    • orphan reconciliation may move folders into archive when they no longer map to portal records
    • orphan team folders move to Archive/Team/<Folder Name> when no team or subcontractor profile matches that folder name
    • orphan project folders move to Archive/Clients/<Company Name>/Projects/<Project Name> when no portal project matches that folder name under that company
    • orphan reconciliation does not remove company roots or overwrite archived content; it merge-moves into archive
  • Access/home rules:
    • team members have full file access
    • client users with exactly one tied company use that company folder as home: /Clients/<Company Name>
    • client users tied to multiple companies use /Clients as home and only see company folders they are tied to
    • /Clients acts as a virtual parent for multi-company client users and must not expose unrelated company folders
    • subcontractor users use virtual home /
    • subcontractor virtual home shows Team plus only the project folders they are assigned to
    • subcontractor users skip all other root folders and must not see unrelated client or internal roots
    • subcontractor Team maps to the real shared Team folder
    • each subcontractor project folder is a virtual root that maps to the real client project path /Clients/<Company>/Projects/<Project>
  • Right card header:
    • title label is File Browser
    • drag/drop note sits directly under the title and uses subtext sizing: 12px
    • current file path uses the same 11px uppercase label treatment as the title row family
    • toolbar does not show + Folder or Upload buttons
    • upload happens by dragging and dropping files or folders into the right card
    • delete action uses the same geometry as the profile edit button (top: 18px, right: 21px, 8px radius, 22px height, 12px text, 0 12px padding) but uses danger styling with red hover/fill
  • Right card table:
    • uses dashboard table styling (table-layout: fixed, transparent header row, 10px uppercase headers, 13px/12px body text)
    • card padding matches dashboard widget shell (18px 21px)
    • clickable text inside the table highlights in accent; rows do not use block hover fill
    • body cells are borderless like dashboard card tables
    • body cell padding matches dashboard tables exactly: 5px
    • visible headers (Name, Size, Modified) use shared sortable header controls
    • file/folder icon footprint is compact so row height stays on the same cadence as dashboard tables
    • alternating rows use a very subtle theme-aware tint for scanability
  • Navigation tree:
    • Home aligns to the first arrow column
    • connector line runs through the arrow center column
    • pinned folders are user-specific and must not be shared across users on the same device/browser session
    • hover is text-only accent color, no row fill

13) Radius + Geometry Rules

  • Dashboard/profile widgets: 8px radius
  • Sidebar: 8px radius
  • Standard app buttons use the Edit Profile geometry:
    • geometry is tokenized globally in CSS vars and must be reused (no per-page hardcoded button geometry):
      • --btn-height
      • --btn-padding-x
      • --btn-radius
      • --btn-font-size
      • --btn-font-weight
      • --btn-letter-spacing
      • --btn-line-height
    • height: 22px
    • horizontal padding: 0 12px
    • border-radius: 8px
    • font-size: 11px
    • font-weight: 500
    • letter-spacing: 0.8px
    • text-transform: uppercase
    • line-height: 1
    • label color follows theme text roles:
      • dark mode: primary button labels use dark text on accent fill; outline labels use primary text on transparent surface
      • light mode: outline labels use light-theme primary text; danger labels use danger text
    • outline button border uses the same var(--border) token as card outlines unless a button role explicitly overrides it
    • keep existing button role styling intact (outline, primary, danger); geometry changes, not role colors
  • Inputs/dropdowns may use their own control radius unless a page-specific rule says otherwise
  • Circular elements (avatar/day/icon badges): 50%

14) Z-Index Stack

  • Sidebar: 200
  • Header dropdowns/tooltips: 300
  • Calendar hover popover: 1002 within card context (card can be 1001 active)
  • Modal overlay: 1200

14.5) Loading Popup

  • Use shared PageLoader component for loading overlays instead of page-specific popup implementations.
  • Loading popups/overlays, including shared site-wide page loaders and file-sharing loading states, use the same widget shell as dashboard cards:
    • background: var(--popup-bg)
    • border: 1px solid var(--border)
    • border-radius: 8px
    • padding: 18px 21px
    • backdrop-filter: blur(12px) + -webkit-backdrop-filter
  • Popup surface is theme-aware:
    • dark mode: deep translucent dark surface
    • light mode: bright translucent white surface
  • Loading overlay scrim is theme-aware:
    • dark mode: rgba(0,0,0,0.58)
    • light mode: soft light scrim via --overlay-scrim
  • Loading title uses widget header treatment: 11px, 500, uppercase, letter-spacing: 0.8px, secondary text
  • Progress track:
    • height: 4px
    • radius: 2px
    • track color: secondary card tone (var(--card-bg-2))
    • progress fill: accent
  • Progress/meta text under the bar uses subtext sizing (12px) and secondary text

14.6) Modal Form Fields

  • Modal forms that follow Edit Profile styling (including Add Task/New Task) share the same field typography and theme tokens:
    • modal surface transparency matches Edit Profile card shell (background: var(--card-bg)), not a denser popup-specific override
    • field labels: 11px, 500, uppercase, letter-spacing: 0.8px, color var(--text-secondary)
    • input/select text: 13px, color var(--text-primary), left aligned
    • textarea text: 13px, color var(--text-primary)
    • field surfaces and borders use global theme tokens (var(--card-bg-2) + var(--border)) for dark/light parity
    • modal form action buttons use the standard outline geometry/style (btn btn-outline) unless a page explicitly defines a different role

14.7) Status Tags

  • Shared status tags use StatusBadge (.badge.badge-status).
  • Rule: any workflow/state value (not_started, in_progress, on_hold, client_review, client_approved, invoiced, paid, active, completed, etc.) must render through StatusBadge only.
  • Do not use raw span.badge badge-* for statuses.
  • Base badge geometry:
    • display: inline-flex
    • align-items: center
    • gap: 4px
    • padding: 3px 10px
    • border-radius: 4px
    • font-size: 11px
    • font-weight: 400
    • letter-spacing: 0.3px
    • white-space: nowrap
  • Status badge geometry override (.badge-status):
    • display: inline-flex
    • align-items: center
    • justify-content: center
    • min-width: 78px
    • height: 20px
    • padding: 0 8px
    • font-size: 10px
    • line-height: 1.05
    • box-sizing: border-box
    • padding-top: 1px (optical vertical-centering correction for current font metrics)
  • Status colors are variant classes (.badge-not_started, .badge-in_progress, etc.) and are theme-aware.
  • Non-status chips (example: invoice line-item type Initial/Revision, or service-type labels) may use .badge variants directly.
  • When a non-status chip should visually align with status pills, add .badge-status to match geometry.
  • Exception: compact urgent tag (.badge-needs_revision) uses tighter geometry:
    • min-width: 28px
    • padding: 3px 4px
    • border-radius: 4px
    • fixed red treatment in both dark/light themes.

15) Motion

  • Motion vars:
    • fast 160ms
    • base 220ms
    • easing cubic-bezier(0.22, 1, 0.36, 1)
  • Dropdown animation: ui-fade-up from translateY(4px) + opacity 0 -> 1

17) Hover Interaction Contract

  • Sidebar, header icon buttons, dropdown items, and avatar menu items must show a visible hover surface before click.
  • Single hover source-of-truth block controls these elements.
  • Dark hover surface baseline: #1f1f1f.
  • Light hover surface baseline: rgba(0,0,0,0.08).
  • Nav icon opacity must lift from muted to full on hover (opacity: 1).
  • Clickable text links use text-only highlight on hover/focus (color: var(--accent)), not whole-row/background fill.
  • Hover and active must be visually distinct:
    • hover uses stronger temporary contrast (bg + thin border),
    • active remains persistent selected-state background.
  • File Sharing left navigation exception:
    • Pinned + Navigation tree rows use text-only hover highlight (color: var(--accent)).
    • Do not apply row background fill for hover in this section.
  • Use shared link classes only; do not hand-roll page-specific link hover styles:
    • table/text links inside cards and tables: table-link
    • inline action links/buttons in cards/feeds: dashboard-inline-link
  • Hover behavior for both classes:
    • color changes to accent gold (var(--accent))
    • no underline on hover/focus
    • cursor remains pointer
  • For table-heavy rows where hit targets are tight, row hover may also promote link color to accent; still keep text-only link treatment (no full-row fill just for links).
  • Do not rely on inline style color overrides for hover behavior; if a variant is needed, add/extend a shared class in index.css.

16) Non-Negotiable Implementation Rules

  • Keep gradient backgrounds on html, not body
  • Keep widget shell values (18px 21px, 8px, blur 12, border token) consistent
  • Maintain global 24px spacing rhythm for page/frame/grid gaps
  • Keep team dashboard card order:
    1. Open Tasks
    2. Active Projects
    3. Net Profit
    4. Revenue (wide)
  • Keep row 2 order: Recent Activity (left), Tasks In Progress (center), Calendar (right fixed at 280px)

18) Invoice Rules

  • New work (R00) is billed at the new-service rate.
  • Revision R01 is free.
  • Revisions R02+ are billed incrementally: each uninvoiced revision entry contributes exactly 1x revision charge.
  • Previously invoiced revisions are excluded; later invoices only charge newly uninvoiced revisions (e.g. if R02 was already invoiced, at R04 only R03 + R04 are billed).