Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
9.6 KiB
id, title, status, date, parent
| id | title | status | date | parent |
|---|---|---|---|---|
| 24-1 | 24-1 Public Design Foundation (Stylesheet, Script, Fonts, Layout) | Ready for Dev | 2026-10-31 | 24 |
Description
Create the shared foundation every later redesign subtask builds on. It must be loaded only by
the public layout (and, for the stylesheet only, by the auth layouts in task 24-9), and every rule
must be scoped under body.site so the admin and client dashboards are unaffected.
The approved visual reference is the mockup file docs/ux-mockup.html (committed in caec396).
Where this task says "port lines X–Y", copy those CSS rules from that file and prefix every
selector with body.site (for example .btn-gold → body.site .btn-gold; :root{…} →
body.site{…}; body{…} → body.site{…}; html[dir=ltr] .x → html[dir=ltr] body.site .x;
html[lang=en] .x → html[lang=en] body.site .x). The mockup's lines contain no images, so line
numbers are exact.
Files to create
resources/css/public.css— contains, in this order:- Tokens on
body.site(from mockup lines 12–29):--forest:#2D3624; --forest-2:#232A1C; --gold:#A68966; --gold-ink:#8A7555; --gold-lt:#C4A882; --cream:#F4F1EA; --olive:#4A5D23; --ink:#1E2219; --muted:#5B6152; --line:rgba(45,54,36,.14); --display:"Markazi Text","Times New Roman",serif; --body:"IBM Plex Sans Arabic",system-ui,sans-serif; --r:10px; --ease:cubic-bezier(.2,.7,.2,1); --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); - Page ground and type on
body.site(port lines 32–39):font-family:var(--body); color:var(--ink); font-size:17px; line-height:1.75; background-color:var(--cream)plus the linen weavebackground-image: 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). This overrides the inlinestyle="font-family: var(--font-…)"on the body, so the layout's inline style is removed (see layout changes below). - Port lines 40–50 (img, links,
.wrap, skip link, focus-visible, h1–h3,.eyebrow,.art-no)..wrap=max-width:1200px; margin-inline:auto; padding-inline:28px. Focus =outline:2px solid var(--gold); outline-offset:3px; border-radius:4px. - Buttons: port lines 52–68 (
.btn,.btn-goldwith shimmer::after,.btn-ghost,.on-dark .btn-ghost,.btn .arrand LTR mirroring). Class names.btn,.btn-gold,.btn-ghostdo not exist inresources/css/app.css(which uses.btn-primary,.btn-secondary), and they are scoped underbody.site, so there is no collision. - Progress rule: port lines 70–73 (
#hem→ rename to.site-progress; fixed, top 0, z 60, height 2px, gradientlinear-gradient(90deg,#8A7555,#E2CDA4,#A68966),transform:scaleX(0), origin right;html[dir=ltr]origin left). - Sections: port lines 139–144 (
section{position:relative},.sec{padding:120px 0},.sec-head,.sec-head h2,.sec-head p). - Reveal: port lines 286–290, changed so content is hidden only when JavaScript runs:
body.site.js [data-reveal]{opacity:0;transform:translateY(28px);transition:opacity .9s var(--ease),transform .9s var(--ease)},body.site.js [data-reveal].in{opacity:1;transform:none}, and thedata-d1–5 delays (.08s, .16s, .24s, .32s, .4s). - Responsive base: at
max-width:760px:body.site{font-size:16px},body.site .wrap{padding-inline:18px},body.site .sec{padding:80px 0}. - Reduced motion (port lines 324–327): under
@media (prefers-reduced-motion:reduce),body.site *, body.site *::before, body.site *::after{animation:none!important; transition:none!important; scroll-behavior:auto!important}andbody.site [data-reveal]{opacity:1;transform:none}. html:has(body.site){scroll-behavior:smooth}.
- Tokens on
resources/js/public.js— imports./site/reveal.jsand./site/progress.js, and calls each module'sinit()on thelivewire:navigateddocument event (Livewire 3 dispatches it on the first page load and after everywire:navigate), and each module'sdestroy()onlivewire:navigating. On init it adds the classjstodocument.body.resources/js/site/reveal.js— exportsinit()/destroy(). IfmatchMedia('(prefers-reduced-motion: reduce)').matches, add classinto every[data-reveal]and return. Otherwise create oneIntersectionObserverwithrootMargin: '0px 0px -8% 0px'; when an observed element intersects, add classinand unobserve it.destroy()disconnects the observer.resources/js/site/progress.js— exportsinit()/destroy(). Adds a passivescrolllistener onwindowthat sets.site-progressstyle.transform = scaleX(p)wherep = max > 0 ? scrollY / max : 1andmax = document.documentElement.scrollHeight - innerHeight, and toggles classscrolledon#site-navwhenscrollY > 8(if that element exists; it is added in task 24-2). Runs once on init.destroy()removes the listener.resources/views/partials/site-fonts.blade.php— exactly:<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Markazi+Text:wght@400;500;600;700&family=IBM+Plex+Sans+Arabic:wght@300;400;500;600&display=swap" rel="stylesheet">lang/ar/site.phpandlang/en/site.php— each<?php return [ ... ];with the keysprogress_label(ar'تقدّم القراءة', en'Reading progress'). Later subtasks add keys to these files.
Files to modify
vite.config.js—inputbecomes['resources/css/app.css', 'resources/js/app.js', 'resources/css/public.css', 'resources/js/public.js'].resources/views/components/layouts/public.blade.php:- After
@include('partials.head')add@include('partials.site-fonts')and@vite(['resources/css/public.css', 'resources/js/public.js']). <body>becomes<body class="site min-h-screen flex flex-col">(removebg-backgroundand the inlinestyle="font-family: …").- Immediately after the skip link add
<div class="site-progress" aria-hidden="true"></div>. - Remove the spacer
<div class="h-16"></div>(the navigation becomes sticky in 24-2; until then the existing fixed navigation may overlap the first 64px — acceptable only between 24-1 and 24-2). <main>keepsid="main-content" role="main" class="flex-1" tabindex="-1"but its child<div class="max-w-[1200px] mx-auto px-4 sm:px-6 lg:px-8 py-6 sm:py-8">is removed, so{{ $slot }}is rendered directly inside<main>.
- After
- Because the wrapper is gone, wrap the root content of each existing public page that is not
yet redesigned in
<div class="wrap py-8">…</div>so these pages keep a contained width until their own subtask restyles them:resources/views/livewire/pages/home.blade.phpresources/views/livewire/pages/about.blade.php(also remove the negative margins-mx-4 sm:-mx-6 lg:-mx-8 -mt-6 sm:-mt-8from its first<section>)resources/views/livewire/pages/booking.blade.phpresources/views/livewire/pages/booking-success.blade.phpresources/views/livewire/pages/posts/index.blade.phpresources/views/livewire/pages/posts/show.blade.phpresources/views/pages/legal.blade.phpresources/views/pages/terms.blade.phpresources/views/pages/privacy.blade.php(resources/views/pages/booking.blade.phpis a dead placeholder —/bookingis served by the Volt page — and is left untouched.) For a Volt page whose root is a single element, put the wrapper inside the root element so the component keeps one root.
resources/views/partials/head.blade.php— change<meta name="theme-color" content="#4A4A42">to<meta name="theme-color" content="#2D3624">. Change nothing else in this file (the dashboards share it).
Do not modify resources/css/app.css or any file under resources/views/livewire/admin/,
resources/views/livewire/client/, resources/views/components/layouts/app*.
Acceptance Criteria
npm run buildsucceeds andpublic/build/manifest.jsoncontains entries forresources/css/public.cssandresources/js/public.js.- Every selector in
resources/css/public.cssis scoped underbody.site(orhtml[...] body.site, orhtml:has(body.site)), verify:grep -nE '^[^@/ }].*\{' resources/css/public.css | grep -v 'body.site'returns nothing. - The HTML of
/contains<body class="site, theMarkazi+Textfont link, apublic.cssand apublic.jsasset, and<div class="site-progress". - The HTML of
/admin/dashboard(logged in as admin) and/client/dashboard(logged in as a client) contains neitherpublic.css,public.js,Markazinorclass="site. resources/css/app.cssis unchanged:git diff --quiet BASE -- resources/css/app.css.- On
/with the browser at 390px wide, the document has no horizontal scroll, and every public page listed in item 9 still renders its content inside a 1200px-max container. - Scrolling
/changes the.site-progresselement's transform fromscaleX(0)towardscaleX(1); withprefers-reduced-motion: reduceemulated, every[data-reveal]element is visible without scrolling. partials/head.blade.phpcontainscontent="#2D3624"and no#4A4A42.
Sub-tasks
None.