Files
libra/docs/ux-design.md
T
2026-10-31 19:26:47 +02:00

457 lines
30 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# UX Design Spec: Libra for Rights — Public-Site Redesign
**Version:** 2.0
**Date:** 2026-10-31
**Status:** Approved (client approved mockup v3 on 2026-10-31)
**Visual mockup:** `docs/ux-mockup.html` (open in a browser to view; v3, commit `caec396`)
This file has two parts:
- **Part A — Public site (redesign, approved 2026-10-31).** Governs every page rendered through
`resources/views/components/layouts/public.blade.php` and the auth layouts' type and controls.
- **Part B — Dashboards, emails and the Nablus form (unchanged).** The retrospective record of the
design system as built before the redesign. It still governs the admin and client dashboards,
the emails and `/forms/nablus-workshop`, none of which the redesign touches.
Where Part A and Part B disagree about a public page, Part A wins.
---
# Part A — Public site
## Design Direction
Arabic-first, editorial and quiet: the firm reads like a well-bound legal document, not a tech
product. The brand palette (forest, gold, cream, olive) is kept and used with more confidence —
large forest bands, gold as thread and rule, cream as linen. Headlines are set in an editorial
naskh serif (Markazi Text); body in IBM Plex Sans Arabic. Sections are numbered like articles of
a statute ("المادة ٠١ — المؤسِّسة"). The signature is an engraved-gold balance over olive-tree
photography that settles into level on load and is weighed by the visitor's pointer. Tatreez
appears only inside real photography — Naser ruled out drawn cross-stitch ("drawing using xxx and
other symbols is more of a tech stuff not lawyers", 2026-10-31). Every claim on the page is backed
by the code (code-fit check, 2026-10-31): no availability promises, no response-time promises, no
article images.
**Layout default:** desktop-first; every layout works at 768px and 390px with no horizontal scroll.
**Scope:** public pages only — home `/`, about `/about`, posts `/posts` and `/posts/{post}`,
booking `/booking` and `/booking/success`, legal `/page/{slug}` (terms, privacy), and the auth
pages (type and controls only, see *Auth pages*). Out of scope: admin and client dashboards,
emails, PDFs, `/forms/nablus-workshop`.
## Layout & Navigation
- **Containment.** The public layout no longer wraps pages in one padded 1200px container; each
page section is full-bleed and places its own content in a `.wrap` container:
`max-width: 1200px; margin-inline: auto; padding-inline: 28px` (18px at ≤760px).
- **Section rhythm.** Standard section padding 120px top and bottom (80px at ≤760px). Section
header (`.sec-head`): flex row, items aligned to the end, space-between, gap 32px, wrap,
margin-bottom 54px; left side holds the article label and h2, right side a muted lede
(max-width 30em).
- **Article label** (`.art-no`): display font, 1.15rem, weight 600, `--gold-ink`. Format
`المادة ٠N — <name>` / `Article 0N — <Name>` (Arabic-Indic digits in Arabic).
- **Eyebrow** (`.eyebrow`): 0.82rem, weight 600, `--gold-ink`, preceded by a 22×2px rule in
currentColor with 10px gap; in English 0.74rem, uppercase, letter-spacing .16em. Arabic text
never gets letter-spacing (it breaks joining).
- **Navigation** (sticky, top 0, z 50, height 72px): background `rgba(244,241,234,.82)` with
`backdrop-filter: blur(14px) saturate(1.2)`; bottom border transparent until the page has
scrolled more than 8px, then `1px solid var(--line)` plus shadow `0 8px 24px -18px
rgba(30,34,25,.5)`. Order (start → end): brand (seal + wordmark), links, then tools (language
toggle, client login, gold "Book a consultation" button). Links: Home, About, Services (→
`/#services`), Articles (→ `/posts`), Booking (→ `/booking`). Link style: 10px 14px padding,
weight 500, .95rem; hover colour `--olive`; a 2px dashed gold underline (4px dash, 3px gap)
scales in from the inline-start edge on hover and stays on the current page's link
(`aria-current="page"`). Logged-in visitors see "Dashboard" (to their role's dashboard) and
"Log out" in place of "Client login", as today.
- **Brand mark:** a 46×46px "seal" — `public/images/logo.png` as a cover background on white,
2px solid `#1A1A1A` border, shadow `3px 3px 5px rgba(26,26,26,.35)` — followed by the wordmark:
«ليبرا» (display font, 1.35rem) over «للحقوق» (.72rem, muted). English: "Libra" over
"FOR RIGHTS" (letter-spacing .12em).
- **Mobile (≤1100px):** links hide; a 44×44px menu button (1.5px `--line` border, radius 10px,
white) opens the existing Alpine mobile menu, restyled as a cream sheet below the nav with
full-width 48px rows. At ≤760px the nav's gold button and the client-login link also hide (both
remain inside the sheet).
- **Reading progress rule:** a fixed 2px bar at the very top of the viewport (z 60), gradient
`#8A7555 → #E2CDA4 → #A68966`, `transform: scaleX(p)` where p = scrollY / (scrollHeight −
innerHeight); origin is the inline-start edge (right in RTL, left in LTR). Decorative
(`aria-hidden`).
- **Footer:** background `--forest-2` (#232A1C), text `--gold-lt`, margin-top 120px, padding 72px 0
28px, .92rem. A 1px top hairline: horizontal gradient transparent → `rgba(196,168,130,.7)` →
transparent. Four columns (1.4fr 1fr 1fr 1fr, gap 40px; 2 columns ≤1100px; 1 column ≤760px):
(1) brand mark with cream wordmark and the tagline «ملتزمون بالعدالة – متجذرون بالكرامة – مدفوعون
للدفاع»; (2) "Explore": About, Services, Articles, Booking; (3) "Clients": Client login, Terms of
use, Privacy policy; (4) "Contact": phone (LTR), email, address. Column headings: display font,
1.15rem, cream. Links: 10px vertical padding, hover → cream and a 3px nudge toward the
inline-start. Bottom row: copyright, top border `rgba(244,241,234,.1)`, .8rem. No photography
credit line.
## Visual Style
### Color Palette
| Token | Hex | Use |
|---|---|---|
| `--forest` | `#2D3624` | hero frame ground, pillar band, booking card, hover fill of service rows |
| `--forest-2` | `#232A1C` | footer only (depth) |
| `--gold` | `#A68966` | gold buttons, rules, row numbers, focus ring |
| `--gold-ink` | `#7A6648` | gold text on cream (labels, dates) — darkened from the brand gold-hover `#8A7555` on 2026-10-31 so small text meets WCAG AA (4.9:1 on cream, 5.5:1 on white) |
| `--gold-lt` | `#C4A882` | small gold text on forest |
| `--cream` | `#F4F1EA` | page ground |
| `--olive` | `#4A5D23` | link hover, emphasis word in the hero, active accents |
| `--ink` | `#1E2219` | body and heading text |
| `--muted` | `#5B6152` | secondary text |
| `--line` | `rgba(45,54,36,.14)` | hairlines and borders |
| fabric ground | `#ECE7DC` | background of the Vision section |
The palette is the brand's own (`docs/brand.md`); `--ink`, `--muted`, `--forest-2` and the fabric
ground are darker/lighter steps of it, added for contrast and depth. Status colours (success,
danger, warning) are unchanged from Part B.
**Page ground:** `--cream` with a linen weave —
`repeating-linear-gradient(0deg, rgba(45,54,36,.025) 0 1px, transparent 1px 3px),
repeating-linear-gradient(90deg, rgba(45,54,36,.022) 0 1px, transparent 1px 4px)`.
**Shadows:** `--shadow-1: 0 1px 2px rgba(30,34,25,.06), 0 4px 14px rgba(30,34,25,.06)`;
`--shadow-2: 0 2px 4px rgba(30,34,25,.08), 0 18px 40px -12px rgba(30,34,25,.28)`.
**Easing:** `--ease: cubic-bezier(.2,.7,.2,1)`. **Radius:** cards 16px, buttons and chips 999px,
inputs 12px.
### Typography
- **Display** (h1–h3, article labels, blockquotes, numbers): **Markazi Text**, weights 400–700,
fallback `"Times New Roman", serif`. Headings weight 700, line-height 1.25.
- **Body and UI:** **IBM Plex Sans Arabic**, weights 300–600, fallback `system-ui, sans-serif`.
17px, line-height 1.75 (16px at ≤760px). Both families carry Latin glyphs, so English uses the
same two families.
- Loaded from Google Fonts with `display=swap`, on the public and auth layouts only. The dashboards
keep Cairo/Montserrat.
- Sizes: hero h1 `clamp(2.6rem, 4.6vw, 4.1rem)`, line-height 1.12, word-spacing .08em (English:
letter-spacing −.02em); section h2 `clamp(2rem, 3.4vw, 3rem)`; row h3 1.65rem; card h3 1.4rem;
post h3 1.35rem; lede 1.15rem.
### Tone & Style
Editorial, warm, unhurried. Real photography only (olive tree, embroidery on a hoop, olives,
hills, the founder's portrait). No drawn cross-stitch, no gradient blobs, no carousels. Depth comes
from layered shadows, gold hairlines and the engraved balance.
### Buttons
- **Gold** (`.btn-gold`): pill (radius 999px), min-height 48px, padding 12px 26px, weight 600,
background `--gold`, text `--ink`, shadow `0 1px 0 rgba(255,255,255,.35) inset, 0 8px 22px -8px
rgba(166,137,102,.8)`. Hover: lift 2px, deeper glow plus a 6px `rgba(166,137,102,.14)` halo, and
a white shimmer (105° gradient, 30–70%) sweeps across in .7s.
- **Ghost** (`.btn-ghost`): transparent, 1.5px inset `--forest` ring, text `--ink`. Hover: fills
`--forest`, text cream, lift 2px. On dark grounds: cream text and a `rgba(244,241,234,.6)` ring;
hover fills cream with forest text.
- An arrow icon inside a button nudges 4px toward the reading direction on hover; it is mirrored
in LTR.
- Focus (all controls): `outline: 2px solid var(--gold); outline-offset: 3px`.
## Key Screens / Flows
### Home `/`
Top to bottom (content is real; copy keys are listed in the tasks):
1. **Hero** — two columns (1fr : 1.08fr, gap 56px; one column ≤1100px). Start column: eyebrow
«ليبرا للحقوق · فلسطين»; h1 «العدالة *ممارسةٌ يومية*، لا مبدأٌ نظري.» with the emphasised phrase
in `--olive` and a dashed gold underline; lede (the existing `home.intro`); gold "Book a
consultation" (→ `#book`) and ghost "Our services" (→ `#services`); a trust strip of three
items separated from the CTAs by a hairline: «أفراد وشركات / استشارات وتمثيل», «المرأة والأسرة /
دعم قانوني متخصص», «عربي · English / خدمة بلغتين». End column: the **balance frame** (see
Signature Moment): an arched frame (aspect 4:4.6, radius 999px 999px 18px 18px) holding the
olive-tree photo under a forest gradient veil, a soft gold glow, the gold balance, and the
italic caption «لكلّ حقٍّ وزنُه». A cream tag with a pulsing olive dot overlaps the frame edge:
«استشارات حضورية أو عن بُعد».
2. **Pillars band** — full-bleed forest band, three columns divided by cream hairlines: Justice,
Dignity, Advocacy, each with a gold gem (12px rotated square) and a one-line gloss in
`--gold-lt`. Hover lightens the column background.
3. **Founder** (Article 01) — portrait (aspect 4:5, radius 18px, greyscale, an inset dashed gold
frame, a cream name card «هدى عرموش / المؤسِّسة · محامية»), h2 «تعرّف على المؤسِّسة», a pull
quote «العدالة ممارسة يومية، وليست مجرد مبدأ نظري.» (display font, gold inline-start rule), the
two bio paragraphs, and a ghost "Read our story" → `/about`. Hover on the portrait restores some
colour and scales it 3%.
4. **Services docket** (Article 02) — four rows, each a link to `#book`: big gold number, title,
chips of the service's items, a round arrow button. Hover: the row fills forest, text turns
cream, chips go gold-light, the arrow fills gold, a dashed gold inner border appears, lift 2px.
5. **Vision** (Article 03, fabric ground `#ECE7DC`) — text column (h2 «منسوجةٌ من نسيج المجتمع»
and a display-font paragraph) beside the embroidery-hoop photo (circular, two gold ring
shadows). Below it, three cards: "For our institution" (forest panel with a static balance),
"For society" (olives photo), "For Palestinians in the diaspora" (hills photo); each with an
italic label on the image, a title and one line.
6. **Values** (Article 04) — six cards in a row (3 ≤1100px, 2 ≤760px): a gold-ringed medallion
with a fine-line icon, and the value name. Hover: card lifts and tilts −0.6°, the medallion
rotates −8°, gains a gold glow, the icon turns olive.
7. **Latest articles** (Article 05) — the three most recent published posts as text-only cards
(date, title, excerpt, "Read more"), gold top border turning olive on hover, a large faint
quotation mark in the corner; "View all articles" ghost button → `/posts`. No post → the
existing "Articles coming soon" line in place of the grid.
8. **Booking card** (Article 06, `id="book"`) — one rounded (28px) forest card in two columns:
start panel with h2 "Book a consultation", the lede «اختر يوماً ووقتاً متاحَين، وأخبرنا باختصار
عن قضيتك. نراجع كل طلب ونؤكّد الموعد بالبريد الإلكتروني — دون الحاجة إلى حساب.», phone, email,
address, and the finale balance (190px); end panel is a cream inset form (see *Booking flow*).
### Booking flow (home card and `/booking`)
Both surfaces run the existing guest-booking component and its rules unchanged: name, email,
phone (all required), a case summary (required, minimum 20 characters), the math captcha, one
booking per email per day, slots from `AvailabilityService`, the existing confirm step, and the
redirect to `/booking/success`. Logged-in visitors see the existing "you are logged in" message,
restyled, in place of the form.
- **Home card (compact):** fields in this order — name and phone side by side, email, a **day
strip**, a **slot row**, the case summary, the captcha, the gold submit "Request this
appointment" (full width), and the note «ملاحظة: يمكنك حجز استشارة واحدة كحدّ أقصى في اليوم.».
The day strip shows the next 14 calendar days that have at least one available slot, as
66×72px buttons (weekday name over the day number), horizontally scrollable; the first is
pre-selected. Selected day: forest fill, cream number. The slot row shows that day's available
slots as pill buttons (min-height 44px); selected slot: gold fill. Both use `aria-pressed`.
Submit opens the existing confirm step inside the same card (summary of date, time and contact,
with Confirm and Back).
- **`/booking` page:** the same two-panel forest card, full page; the end panel keeps the month
calendar (the existing component, restyled: cream ground, 44px day cells, selected day forest,
available days with a gold dot, unavailable days muted), then the fields and confirm step.
- **Inputs:** min-height 48px, padding 12px 16px, radius 12px, 1.5px border `rgba(45,54,36,.18)`,
white; focus: border `--gold` plus a 4px `rgba(166,137,102,.2)` ring. Labels .85rem, weight 600.
Errors: the existing message under the field, in the danger colour.
- **`/booking/success`:** a centred cream card on the linen ground with a small level balance, the
existing success copy and a ghost button home.
### About `/about`
The same system, existing content only (no new copy beyond section labels): hero (eyebrow, h1
from `about.title`, the tagline, the identity statement), Vision and Mission (the fabric section
pattern; the three mission cards with the olives, hills and static-balance panels), Values (the
medallion row), Goals (a numbered docket list: gold display numbers, no chips, no links), Legal
services (the docket rows, linking to `/booking`), closing gold CTA to `/booking`.
### Articles `/posts` and `/posts/{post}`
- **Index:** page head (article label, h2 "Articles"), the existing search field restyled as a
pill input, the text-only post cards in a three-column grid (2 ≤1100px, 1 ≤760px), the existing
pagination restyled (pill buttons, current page forest).
- **Show:** a reading column max-width 720px; date in `--gold-ink`; title in the display font
`clamp(2rem, 3.4vw, 3rem)`; body in the existing prose styles with headings in the display font
and links in `--olive`; a "Back to articles" ghost button.
### Legal pages `/page/{slug}`
Reading column max-width 720px, display-font title, existing prose body.
### Auth pages (login, forgot/reset password, confirm password, verify email)
Type and controls only: the auth layouts load the two new families and apply the input, focus and
gold-button styles above. The split composition (forest panel with the logo, cream form panel) and
the existing auth pattern stay as they are.
## Signature Moment
**Element:** an engraved-gold balance (scales of justice) drawn as layered SVG — gradient-filled
beam, pillar, olive-leaf finial, base and two pans with a drop shadow — standing over the
olive-tree photograph in the hero frame. A second instance (the "finale", 190px) sits in the
booking card; a static instance fills the "For our institution" card.
**Built from:** the firm's own name — Libra, the balance — and the olive tree of the region; the
photograph is real.
**Trigger:** page load; pointer movement over the hero frame (fine pointers only); scroll position
for the finale.
**Mapping:**
- Load: the hero beam starts tilted 14° and, after 450ms, a damped spring settles it to 0°
(per frame: `v += (target − a) × 0.028; v ×= 0.935; a += v`; stop when |v| < 0.002 and
|target − a| < 0.01).
- Pointer: x = (clientX − frame.left) / frame.width; target = clamp((x − 0.5) × 2.4, −1, 1) × 9°.
The gold glow follows the pointer; the photo pans opposite the pointer by
`(pointer − centre) / −40` px at scale 1.08. Pointer leave → target 0°, photo resets.
- Pans hang from the beam ends: for beam angle θ, pan centres are at (200 ∓ 142·cos θ,
110 ∓ 142·sin θ) in the 400×400 viewBox, so they stay vertical while the beam tips.
- Finale: with p the page progress, q = clamp((p − 0.7) / 0.25, 0, 1); target = −12° × (1 − q), so
the balance comes level as the reader reaches the booking card.
**Tech suggestion:** an inline SVG Blade component and a small vanilla JS module
(`requestAnimationFrame`); no library.
**Reduced-motion fallback:** all balances render level (0°), no spring, no pointer response, no
glow movement; the photo stays still.
## Interaction Patterns (secondary)
- **Entrance choreography:** elements marked `data-reveal` start at opacity 0 and translateY 28px
and transition (.9s, `--ease`) to rest when 8% inside the viewport (IntersectionObserver,
`rootMargin: 0px 0px -8% 0px`, observe once). Delays by `data-d` 1–5: .08s steps. Content stays
visible if JavaScript fails (the hidden state applies only once the script adds a `js` class).
- **Hover depth:** cards lift 6px with `--shadow-2` and a gold border `rgba(166,137,102,.55)`;
card images scale 1.05–1.06 over .8s.
- **Language toggle:** the existing `/language/{locale}` route; a 48×44px pill showing "EN" in
Arabic and "ع" in English.
- **Reduced motion:** `@media (prefers-reduced-motion: reduce)` disables every animation and
transition on the public pages and shows all `data-reveal` content at rest.
- **Touch targets:** every interactive element at least 44×44px.
- **RTL/LTR:** logical properties throughout; arrows and the progress rule's origin mirror.
## Design Decisions & Rationale
- **Markazi Text + IBM Plex Sans Arabic** — Amiri's calligraphic ligatures broke in large
headlines; Markazi is an editorial naskh with a matching Latin serif (brand.md asks for a serif
headline); Plex Arabic is highly legible at body size. Two families total.
- **Balance over olive photography, no drawn tatreez** — Naser rejected the cross-stitch drawings
as "tech stuff"; the balance is the firm's name and reads as law at a glance.
- **Article numbering** — frames the firm's content in the language of a statute; costs nothing.
- **Text-only article cards** — posts have no image field (code-fit check); no images are promised.
- **Copy limited to what the code backs** — no availability or response-time claims; booking copy
is drawn from the existing lang strings.
- **Public-only scope** — the dashboards share global tokens and `.btn` classes; the redesign is
scoped to the public layout so no dashboard screen changes.
- **Compact booking on the home page** — the client approved a one-screen form; it reuses the same
component and rules, so the backend does not change.
## Open Questions
None blocking. Rulings taken for the build (ledger, 2026-10-31):
1. **Photography** — the mockup's four Unsplash photos (olive tree, embroidery hoop, olives, hills)
ship as the production images; the Unsplash licence allows commercial use without attribution.
The client may replace them later with their own.
2. **Home day strip** — the next 14 calendar days with an available slot; `/booking` keeps the
month calendar.
3. **Pages the mockup does not show** (about, articles, booking page, success, legal) — composed
from the homepage's components with their existing content; no new sections.
4. **Auth pages** — type and controls only; composition unchanged.
---
# Part B — Dashboards, emails and the Nablus form (pre-redesign record)
Retrospective documentation of the design system as it is currently **built and live**. This
is not a proposal — it describes what shipped, so a dev/QA agent picking up a new task can match
existing patterns rather than invent new ones. Synthesized from `docs/brand.md`, epics 9/10/12/13/14/16,
and the root `CLAUDE.md`.
## Brand colors (current — source of truth: `docs/brand.md`)
The palette has changed twice since the original PRD. **Use the values below**, from `docs/brand.md`,
for any new work — they are the most recent and match what Epic 12 shipped.
| Token | Hex | Usage |
|---|---|---|
| Primary — Dark Forest Green | `#2D3624` | Header/footer backgrounds |
| CTA — Warm Gold | `#A68966` | Buttons, links, accents |
| Background — Warm Cream | `#F4F1EA` | Main page background |
| Text — Forest Green | `#2D322A` | Headings, body text |
| Card — Pure White | `#FFFFFF` | Card backgrounds |
| Active — Olive Green | `#4A5D23` | Active states, language toggle |
| Primary Light | `#3D4634` | Primary hover state |
| CTA Hover | `#8A7555` | Button hover state |
| CTA Light | `#C4A882` | Light accents |
| Active Hover | `#5A7030` | Active-state hover |
| Deep Black | `#1A1A1A` | Logo artwork, headline emphasis |
**History (do not use these for new work, they are superseded):**
- Epic 1 / PRD / Epic 9 originally specified **Navy Blue `#0A1F44` + Gold `#D4AF37`**.
- Epic 10 ("Brand Color Refresh") replaced that with **Charcoal `#4A4A42` + Warm Gray `#C9C4BA`**.
- Epic 12 ("Branding Refresh") replaced *that* with the **Dark Forest Green + Warm Gold** palette
above, which is what `docs/brand.md` documents and what is currently live. Epic 9's own stories
(button/form/card specs) still reference the original Navy+Gold hex values — treat those as
structural/pattern guidance only (border-radius, padding, states) and substitute the current
hex values from the table above.
## Typography
- **Arabic:** Cairo or Tajawal (Google Fonts), weights Light 300 / Regular 400 / SemiBold 600 / Bold 700.
- **English:** Montserrat or Lato, same weight set.
- `docs/brand.md` additionally suggests a serif (Playfair Display / Libre Baskerville) for the
organization name/headline treatment and an italic serif for taglines, with a sans body
(Source Sans Pro / Open Sans / Inter) — this is brand-identity guidance; the app itself
implements the Cairo/Tajawal + Montserrat/Lato pairing from Epic 9.2.
- **Hierarchy:** H1 Bold 2.5rem/40px · H2 SemiBold 2rem/32px · H3 SemiBold 1.5rem/24px ·
Body Regular 1rem/16px · Small Regular 0.875rem/14px.
- Line height: 1.6 body, 1.3 headings.
- `font-display: swap`, critical fonts preloaded, loaded via Google Fonts + Tailwind `font-family`
config with `@font-face` fallbacks.
## Layout system
- Container max-width: **1200px**.
- Card padding: 24px; card border-radius: 8px; card shadow `0 2px 8px rgba(0,0,0,0.1)`, with a
subtle lift + shadow increase on hover.
- Button padding 12px 24px, border-radius 6px; input/textarea padding 12px 16px, border-radius 6px,
textarea min-height 120px.
- **Breakpoints:** Mobile `<576px` · Tablet `576–991px` · Desktop `992–1199px` · Large Desktop `>=1200px`.
Mobile-first: single-column + collapsible sections on mobile, two-column/collapsible sidebar on
tablet, full multi-column grid + sidebars on desktop. Touch targets >= 44px. Tables scroll
horizontally on small screens; calendar and forms must remain usable on mobile.
- Transitions are short and subtle: button hover 150ms ease, card hover 200ms ease, modal
open/close 200ms, all under 300ms — and must respect `prefers-reduced-motion` (no auto-playing
animations).
## Component patterns (Epic 9 stories 9.4–9.7)
- **Buttons:** primary = CTA-gold background / dark text, hover to CTA-hover; secondary =
transparent with gold border + gold text, hover fills gold with dark text; disabled = flat gray
background/text, no hover, `cursor: not-allowed`; danger = solid red (`#E74C3C`) with white text.
Loading state shows a spinner; all buttons have a visible focus state. Built by extending Flux UI's
button component with Tailwind component classes.
- **Forms:** inputs/textareas/selects share consistent border + radius, gold border on focus;
selects and checkboxes/radios are custom-styled (not native) with gold accents on
checked/selected state; labels are SemiBold with a `*` required indicator; errors show a red
border plus a message rendered directly below the field. Built on Flux UI form components with
explicit RTL alignment handling.
- **Cards/containers:** off-white/cream background, optional gold top/left accent border for
featured or important cards; dashboard stat cards add a gold-accented icon, a large number, and
a trend indicator; list cards use consistent item spacing and clear click targets. Implemented as
a reusable Blade card component with variant props.
- **Navigation/footer:** fixed-top nav, brand-primary background, logo left on desktop / centered
on mobile, gold link text with an active-link indicator, styled language toggle, and a full-width
slide/dropdown mobile menu (Alpine.js) with 44px+ touch targets. Footer shares the brand-primary
background and carries logo + firm info, contact details, Terms/Privacy links, and copyright; it
stays pinned to the bottom of short pages (sticky footer).
## Bilingual / RTL–LTR rules
- Arabic is primary and renders RTL; English is secondary, LTR. `dir="rtl"` is set on `<html>` for
Arabic; layout uses Tailwind's RTL support and logical properties (`start`/`end` rather than
`left`/`right`) so components flip automatically rather than needing per-direction overrides.
- In RTL: text aligns right, navigation mirrors (logo moves to the right), form labels sit on the
right, directional icons/arrows flip, and margins/paddings swap sides.
- Switching language must not break layout — calendars and tables must render correctly in both
directions, and every component is expected to be tested in both.
- All user-facing strings live in language files (`ar`/`en`); there is no hardcoded UI copy.
## Key page layouts
- **Home** (Epic 14): Navigation → Hero (tagline + intro + CTA buttons, Warm Cream background) →
About (Huda Armouche's photo + bio) → Services (4 cards: Consultations, Representation,
Litigation, Contracts) → Values (6 icon cards) → Latest Posts (3 most recent published posts,
pulled live via `Post::where('status','published')->latest()->take(3)->get()`, with a "View All"
link) → Footer (phone + address + links). Sections alternate between Warm Cream and White
backgrounds; CTAs use Warm Gold.
- **About Us** (Epic 16, new page at `/about`): Navigation → Hero (title + identity statement) →
Vision & Mission (three-fold: For Itself / For Society / For Diaspora, card layout) → Values
(6 core values: Integrity, Justice, Knowledge, Women's Empowerment, Professionalism, Social
Innovation) → Goals (7 goals, numbered/scannable) → Legal Services (grouped by category:
consultations, litigation, family law, business services) → Footer. (A Scholarship Aspiration
section was built under this epic but removed from `/about` entirely on 2026-01-11 at Naser's
request — do not re-add without confirming; see `docs/tasks/16-6.md`.)
- **Auth pages** (Epic 13 — login, forgot/reset password, confirm-password, email verify): the
2FA challenge page exists in code but is currently dormant — 2FA has been disabled in production
since 2026-01-17 (see root `CLAUDE.md` Authentication section). Split-screen layout. Left panel: Dark Forest Green (`#2D3624`) background with the
LIBRA logo centered. Right panel: Warm Cream background with a subtle SVG botanical/geometric
background pattern (low-opacity brand colors) behind the form. On mobile, only the form side
shows, with the logo displayed above it. The language toggle's `light` variant was darkened
(`text-primary` instead of `text-body/70`) specifically for visibility on this light panel,
without changing its appearance on the dark public-nav background.
- **Dashboards** (Epics 6 admin / 7 client): standard authenticated-app shell — nav/sidebar +
content area using the same card, button, and table components as the rest of the app. Admin
dashboard emphasizes stat cards, Chart.js analytics, and data tables with export actions; client
dashboard is read-mostly (consultations, timelines, profile) with a single primary action
(submit new booking) and a booking-limit indicator.
## Accessibility (WCAG AA — Epic 9.10)
- Color contrast: body text >= 4.5:1, large text (18px+ bold or 24px+ regular) >= 3:1, UI elements
(buttons, borders, icons) >= 3:1. The gold-on-dark-forest-green and text-on-cream combinations
must be verified against these ratios whenever a color changes.
- Focus indicators must be visible (a gold outline), never conveyed by color change alone.
- Full keyboard navigation: every interactive element reachable, logical tab order, a skip-to-main-content
link.
- Screen readers: correct heading hierarchy (h1 > h2 > h3), alt text on all images, ARIA labels
where needed, form labels programmatically associated with their fields.
- Motion: respect `prefers-reduced-motion`; no auto-playing animations.