Design System
Version: 1.1.0 | Last Updated: May 2026 Stack: React + TypeScript, Tailwind CSS v4, shadcn/ui (Radix UI primitives), GSAP + ScrollTrigger, Three.js / WebGL, Lucide icons Reference: Aether Architecture design system (Neuform community)
This document is the single source of truth for visual design and front-end implementation decisions across the Shanvi Travels platform. It covers both the public-facing marketing site and the internal agent dashboard.
1. Design Principles & Visual Identity
Section titled “1. Design Principles & Visual Identity”Brand Personality
Section titled “Brand Personality”Shanvi Travels is a premium, trust-first travel agency focused on serving primarily Nepali and South Asian travellers. The visual language communicates:
- Trustworthy — Clean whites, navy blues, and precise layouts convey reliability.
- Premium — Glassmorphism surfaces, strong shadows, and bold typography signal quality.
- Approachable — Rounded corners, warm photography, and readable fonts keep things human.
- Efficient — Dashboard components prioritise density and scanability for agent workflows.
Two Distinct Surfaces
Section titled “Two Distinct Surfaces”| Surface | Audience | Tone |
|---|---|---|
| Marketing Site | Travellers | Aspirational, warm, immersive imagery |
| Agent Dashboard | Internal agents / consultancies | Dense, functional, data-forward |
The same token system and component library supports both, but usage patterns differ.
Core Visual Rules
Section titled “Core Visual Rules”- White space is intentional — never fill space just to fill it.
- The brand gradient (blue → cyan) is used for hero backgrounds and CTAs, never in body text.
- Photography always has a dark overlay to ensure text readability.
- The primary dark navy
#001f3fis used for the highest-emphasis dashboard actions.
2. Color Palette & Usage Rules
Section titled “2. Color Palette & Usage Rules”Brand Colors
Section titled “Brand Colors”| Token | Hex | Usage |
|---|---|---|
--color-brand-blue | #2563eb | Primary interactive elements, links, focus rings |
--color-brand-cyan | #06b6d4 | Gradient endpoint, accent highlights |
brand-navy | #1e3a8a | Active tabs, primary CTAs, selected states |
deep-navy | #001f3f | Dashboard headings, modal panels, bulk-action bars |
Brand Gradient:
--brand-gradient: linear-gradient(135deg, #2563eb 0%, #06b6d4 100%);Used on hero section overlays and promotional banners. Never on text.
Semantic Color Tokens (Light Mode)
Section titled “Semantic Color Tokens (Light Mode)”| Token | Value | Usage |
|---|---|---|
--background | #ffffff | Page background |
--foreground | oklch(0.145 0 0) ≈ #0a0a0f | Primary text |
--card | #ffffff | Card surface |
--primary | #030213 | Default button fill, primary actions |
--primary-foreground | #ffffff | Text on primary buttons |
--secondary | oklch(0.95 0.0058 264.53) ≈ #f0f0f7 | Secondary button fills |
--muted | #ececf0 | Muted backgrounds, disabled surfaces |
--muted-foreground | #717182 | Placeholder, helper, caption text |
--accent | #e9ebef | Hover backgrounds, subtle highlights |
--destructive | #d4183d | Error states, delete actions |
--border | rgba(0,0,0,0.1) | All borders |
--input-background | #f3f3f5 | Input field fills |
--ring | oklch(0.708 0 0) | Focus ring color |
Status Colors (Dashboard)
Section titled “Status Colors (Dashboard)”| Status | Background | Text | Border |
|---|---|---|---|
| Active / Success | bg-emerald-50 | text-emerald-600 | border-emerald-100 |
| Error / Rejected | bg-red-50 | text-red-600 | border-red-100 |
| In Progress | bg-blue-50 | text-blue-600 | border-blue-100 |
| Paid | bg-green-50 | text-green-600 | border-green-100 |
| Pending / Neutral | bg-gray-50 | text-gray-400 | border-gray-100 |
Chart Colors
Section titled “Chart Colors”| Token | Value |
|---|---|
--chart-1 | oklch(0.646 0.222 41.116) — orange |
--chart-2 | oklch(0.6 0.118 184.704) — teal |
--chart-3 | oklch(0.398 0.07 227.392) — slate blue |
--chart-4 | oklch(0.828 0.189 84.429) — yellow |
--chart-5 | oklch(0.769 0.188 70.08) — amber |
3. Typography System
Section titled “3. Typography System”Font Stack
Section titled “Font Stack”Primary: Inter, system-ui, -apple-system, sans-serifBase font size: 16px | Font smoothing: antialiased (webkit + moz)
Type Scale
Section titled “Type Scale”| Element | Size | Weight | Line Height |
|---|---|---|---|
h1 | text-2xl (1.5rem) | 500 | 1.5 |
h2 | text-xl (1.25rem) | 500 | 1.5 |
h3 | text-lg (1.125rem) | 500 | 1.5 |
h4 | text-base (1rem) | 500 | 1.5 |
p | text-base (1rem) | 400 | 1.5 |
label | text-base (1rem) | 500 | 1.5 |
button | text-base (1rem) | 500 | 1.5 |
input | text-base (1rem) | 400 | 1.5 |
Specialised Type Patterns
Section titled “Specialised Type Patterns”Hero headline:
text-[4.5rem] font-bold tracking-wide leading-[1.1] text-[#edeeef]Responsive: text-4xl → text-5xl (sm) → text-[4.5rem] (lg+)
Dashboard section heading:
text-2xl font-black text-[#001f3f] italic tracking-tight uppercaseTable column header:
text-[10px] font-black text-gray-400 uppercase tracking-tightTable primary data (name):
text-[11px] font-bold text-blue-900Table secondary data:
text-[11px] font-medium text-gray-500Micro-label (above input fields):
text-[10px] font-bold text-slate-400 uppercase tracking-wider block mb-0.5Status badge text:
text-[10px] font-black uppercase4. Spacing & Layout Guidelines
Section titled “4. Spacing & Layout Guidelines”Base unit: 4px (Tailwind 1 = 4px).
| Class | Value | Usage |
|---|---|---|
gap-1 / p-1 | 4px | Tight icon spacing |
gap-2 / p-2 | 8px | Inline element gaps |
gap-3 / p-3 | 12px | Small component padding |
gap-4 / p-4 | 16px | Standard cell padding |
gap-5 / p-5 | 20px | Card internal padding (compact) |
gap-6 / p-6 | 24px | Card standard padding |
gap-8 / p-8 | 32px | Section gutters |
max-w-7xl mx-auto | 1280px max | Primary content container |
Section padding:
px-4 sm:px-6 lg:px-8 ← horizontalpy-12 sm:py-16 ← vertical (marketing sections)5. Grid System
Section titled “5. Grid System”Page container:
max-w-7xl mx-auto px-4 sm:px-6 lg:px-8| Component | Grid |
|---|---|
| Footer | grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 |
| Featured Destinations | grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 |
| Thai Visa Search Bar | grid-cols-1 md:grid-cols-4 gap-2 |
| Payment form fields | grid-cols-1 sm:grid-cols-2 gap-8 |
Flight search widget: flex flex-col lg:flex-row — stacked on mobile, single row on desktop.
Tab content stacking (avoids layout shift):
<div class="grid"> <div class="col-start-1 row-start-1 ...">Tab A</div> <div class="col-start-1 row-start-1 opacity-0 invisible pointer-events-none"> Tab B </div></div>6. Design Tokens & CSS Variables
Section titled “6. Design Tokens & CSS Variables”Tokens live in two files:
| File | Purpose |
|---|---|
src/index.css | Brand colors, glassmorphism vars, custom animations |
src/styles/globals.css | shadcn/ui semantic tokens, dark mode, typography base |
Border Radius Tokens
Section titled “Border Radius Tokens”| Token | Value | Usage |
|---|---|---|
--radius | 0.625rem (10px) | Base |
--radius-sm | 6px | Small elements |
--radius-md | 8px | Standard rounded-md |
--radius-lg | 10px | Cards, dialogs |
--radius-xl | 14px | Large cards |
Custom radii (not via token):
rounded-xl(12px) — dropdowns, search fieldsrounded-2xl(16px) — filter bars, visa searchrounded-3xl(24px) — main search box, date pickerrounded-[2rem](32px) — VFS table containerrounded-[2.5rem](40px) — payment modalrounded-full— pill buttons, social icons, status pills
Glassmorphism Variables
Section titled “Glassmorphism Variables”--glass-bg: rgba(255, 255, 255, 0.7) --glass-border: rgba(255, 255, 255, 0.2);Utility classes:
.glass { bg-white/70 backdrop-blur-md border border-white/20 }.glass-dark { bg-black/40 backdrop-blur-md border border-white/10 }7. Component Library
Section titled “7. Component Library”The project uses shadcn/ui (Radix UI primitives + Tailwind). Components live in src/components/ui/.
Buttons
Section titled “Buttons”| Variant | Visual | Usage |
|---|---|---|
default | bg-primary text-white | Default action |
destructive | bg-destructive text-white | Delete, danger |
outline | border bg-background | Secondary option |
secondary | bg-secondary | Lower-emphasis |
ghost | Hover bg only | Toolbar/icon buttons |
link | Underline on hover | Inline navigation |
| Size | Height | Padding |
|---|---|---|
default | h-9 | px-4 py-2 |
sm | h-8 | px-3 |
lg | h-10 | px-6 |
icon | size-9 | Square |
Pill CTA button (used on search/submit):
px-6 py-2.5 bg-[#1e3a8a] hover:bg-[#152a66] text-white rounded-fullfont-bold text-xs uppercase tracking-wider transition-all active:scale-95 shadow-mdPremium shimmer button (.btn-premium):
.btn-premium { @apply relative overflow-hidden transition-all duration-300 active:scale-95;}.btn-premium::after { content: ""; @apply absolute inset-0 bg-white/20 translate-y-full transition-transform duration-300;}.btn-premium:hover::after { @apply translate-y-0;}Rules: One primary button per section. Always active:scale-95. rounded-full reserved for CTAs and social icons.
Forms, Inputs & Controls
Section titled “Forms, Inputs & Controls”Standard input:
h-9 w-full rounded-md border px-3 py-1 bg-input-backgroundfocus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]aria-invalid:border-destructiveCustom radio button:
<div className={`w-4 h-4 rounded-full border flex items-center justify-center transition-all ${selected ? "border-blue-600 bg-blue-600" : "border-slate-300 bg-white"}`}> {selected && <div className="w-1.5 h-1.5 rounded-full bg-white" />}</div>Custom checkbox:
<button className={`w-5 h-5 rounded border-2 flex items-center justify-center transition-all ${checked ? "bg-blue-600 border-blue-600 text-white" : "border-gray-200 bg-white hover:border-blue-400"}`}> {checked && <Check size={12} strokeWidth={4} />}</button>File upload zone:
flex flex-col items-center justify-center w-full h-32border-2 border-dashed border-gray-200 bg-white rounded-2xlcursor-pointer hover:border-blue-400 transition-allActive state: border-green-300 bg-green-50
<Card> {/* bg-card rounded-xl border flex flex-col gap-6 */} <CardHeader> {/* px-6 pt-6 grid auto-rows-min gap-1.5 */} <CardContent> {/* px-6 */} <CardFooter> {/* px-6 pb-6 flex items-center */}</Card>Dashboard table container:
bg-white rounded-[2rem] shadow-sm border border-gray-100 overflow-hiddenPayment modal dark panel:
md:w-80 bg-[#001f3f] p-8 text-whiteBadges & Status Indicators
Section titled “Badges & Status Indicators”Status pill:
inline-flex items-center px-3 py-1 rounded-full text-[10px] font-black uppercase borderColors follow the Status Colors table.
IATA code tag:
px-2 py-0.5 bg-slate-100 text-[#1e3a8a] font-black text-[10px] roundedTables & Data Display
Section titled “Tables & Data Display”<div className="bg-white rounded-[2rem] shadow-sm border border-gray-100 overflow-hidden"> <div className="overflow-x-auto"> <table className="w-full text-left border-collapse"> <thead className="bg-gray-50/50 border-b border-gray-100"> <tr> <th className="px-5 py-5 text-[10px] font-black text-gray-400 uppercase tracking-tight whitespace-nowrap"> Header </th> </tr> </thead> <tbody className="divide-y divide-gray-100"> <tr className="hover:bg-blue-50/5 transition-colors text-[11px]"> <td className="px-5 py-4 whitespace-nowrap font-medium text-gray-500"> Data </td> </tr> </tbody> </table> </div></div>Row hover: hover:bg-blue-50/5 | Selected row: bg-blue-50/30 | Always overflow-x-auto.
Navigation Patterns
Section titled “Navigation Patterns”Tab bar (search widget):
<button className={`flex items-center gap-2 py-3 px-1 font-bold text-sm tracking-wide relative ${active ? "text-[#1e3a8a]" : "text-slate-500 hover:text-slate-800"}`}> {active && ( <div className="absolute bottom-0 left-0 right-0 h-[2px] bg-[#1e3a8a]" /> )}</button>Container: flex items-center gap-6 border-b border-slate-100 pb-2 mb-4 overflow-x-auto
Active tab uses a 2px bottom border, not an underline. Tabs never wrap.
Modals & Overlays
Section titled “Modals & Overlays”Backdrop: fixed inset-0 bg-[#001f3f]/80 backdrop-blur-sm
Modal container:
bg-white w-full max-w-4xl rounded-[2.5rem] shadow-2xl overflow-hiddenanimate-modal-enter flex flex-col md:flex-rowRules: z-[100] for modals, z-[99] for dropdowns. Dark panel always left at md:w-80. Click backdrop to close.
Dropdowns & Popovers
Section titled “Dropdowns & Popovers”absolute top-[105%] left-0 bg-white rounded-xl shadow-2xl border border-slate-100 p-3 z-[99]animate-in fade-in slide-in-from-top-1 duration-200Items: p-2.5 hover:bg-slate-50 cursor-pointer rounded-lg flex justify-between items-center
Max scroll height: max-h-52 overflow-y-auto
Click-outside via mousedown + contains(). Inner clicks use e.stopPropagation().
Toasts & Notifications
Section titled “Toasts & Notifications”Uses Sonner. Severity rules:
toast.error()— validation failurestoast.success()— completionstoast.info()— in-progress actions (sparingly add emoji, e.g. ✈️)
8. Glassmorphism & Surface Styles
Section titled “8. Glassmorphism & Surface Styles”| Level | Style | Usage |
|---|---|---|
| Hero overlay | bg-gradient-to-r from-black/75 via-black/40 to-transparent backdrop-blur-[0.5px] | Full-bleed hero readability |
| Glass card | .glass = bg-white/70 backdrop-blur-md border border-white/20 | Floating over imagery |
| Glass dark | .glass-dark = bg-black/40 backdrop-blur-md border border-white/10 | Dark overlays |
Search box (pure white for form legibility):
bg-white rounded-3xl shadow-[0_15px_45px_rgba(0,0,0,0.25)] p-5 md:p-6Dark panel card surface (Aether-adapted):
background: rgba(12, 74, 110, 0.8);backdrop-filter: blur(12px);padding: 24px;/* Use rounded-3xl for Shanvi — Aether uses 0px */Gradient border shell technique:
<!-- Outer shell: 1px padding + gradient = premium depth edge --><div style="padding: 1px; background: linear-gradient(to right, rgba(8,47,73,0.9), rgba(7,89,133,0.5), rgba(0,0,0,0)); border-radius: 1rem;"> <!-- Inner surface --> <div style="background: rgba(12,74,110,0.8); backdrop-filter: blur(12px); border-radius: calc(1rem - 1px); padding: 24px;" > <!-- content --> </div></div>Use on hero panels, featured destination cards, and premium modal surfaces.
9. Elevation, Depth & Shadow System
Section titled “9. Elevation, Depth & Shadow System”| Level | Value | Usage |
|---|---|---|
| Flat | none | Table separators, inline elements |
| Subtle | 0px 1px 2px rgba(0,0,0,0.05) | Input fields, secondary cards |
| Standard | shadow-md | Regular cards, buttons |
| Elevated | 0px 15px 45px rgba(0,0,0,0.25) | Search box over hero |
| Deep | 0px 20px 50px rgba(0,0,0,0.2) | Date picker, large popovers |
| Glow | 0px 0px 12px rgba(12,74,110,0.5) | Premium glass cards |
| Bulk bar | shadow-2xl shadow-blue-900/40 | Floating action bar |
Blur levels:
| Usage | Blur |
|---|---|
| Glass cards / overlays | backdrop-blur-md (12px) |
| Modal backdrop | backdrop-blur-sm (4px) |
| Hero micro-blur | backdrop-blur-[0.5px] |
Rules:
- Never mix more than two shadow recipes in one component.
- Gradient border shell replaces a visible stroke — don’t add both.
- Never blur plain coloured backgrounds — only surfaces over imagery or other content.
10. Icons & Illustrations
Section titled “10. Icons & Illustrations”Primary library: Lucide React (import individually for tree-shaking).
| Context | Size |
|---|---|
| Tab icons | size={16} |
| Field prefix icons | size={18} |
| Dropdown search | size={15} |
| Table action | size={14} |
| Button icons | size={14}–size={16} |
| Social / contact icons | w-5 h-5 |
| Modal close | size={20} |
Icon colours:
- Decorative:
text-slate-400 - Active/branded:
text-[#1e3a8a]ortext-blue-600 - Error:
text-red-500| Success:text-emerald-600| Info:text-blue-400
Special: Plane icon in flight tab uses transform -rotate-45. Loading spinner is a CSS border trick (border-t-transparent animate-spin), not an icon.
Photography rules:
- Hero: full-bleed Unsplash,
object-cover, always with dark overlay. - Logo on dark bg:
filter: brightness(0) invert(1). - Maps: Google Maps embed in
rounded-2xl overflow-hidden h-40.
11. Animation & Motion Guidelines
Section titled “11. Animation & Motion Guidelines”Timing Reference (Aether Architecture)
Section titled “Timing Reference (Aether Architecture)”| Duration | Easing | Usage |
|---|---|---|
150ms | ease | Colour changes, icon swaps |
200ms | cubic-bezier(0.4, 0, 0.2, 1) | Dropdown open, tab switch |
250ms | ease-out | Fade in, modal enter |
300ms | ease | Standard hover transitions |
350ms | cubic-bezier(0.16, 1, 0.3, 1) | Slide-in panels |
1000ms+ | power3.out (GSAP) | Hero entrance sequences |
GSAP Hero Entrance
Section titled “GSAP Hero Entrance”const tl = gsap.timeline({ defaults: { ease: "power3.out" } });tl.fromTo( textRef.current, { y: 60, opacity: 0 }, { y: 0, opacity: 1, duration: 1.2 },);tl.fromTo( searchRef.current, { y: 40, opacity: 0 }, { y: 0, opacity: 1, duration: 1 }, "-=0.9",);CSS Keyframes
Section titled “CSS Keyframes”Slide in from right (drawer):
@keyframes slideInFromRight { from { transform: translateX(100%); } to { transform: translateX(0); }}.animate-slide-in { animation: slideInFromRight 0.35s cubic-bezier(0.16, 1, 0.3, 1) forwards;}Fade in:
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; }}.animate-fade-in { animation: fadeIn 0.25s ease-out forwards;}Modal enter:
@keyframes modalEnter { from { opacity: 0; transform: scale(0.95) translateY(8px); } to { opacity: 1; transform: scale(1) translateY(0); }}.animate-modal-enter { animation: modalEnter 0.25s cubic-bezier(0.16, 1, 0.3, 1) forwards;}Transition rules:
active:scale-95on every clickable element.transition-colorsfor colour-only changes (nottransition-all).transition-[color,box-shadow]on form inputs.hover:scale-110on social icons only.
12. WebGL & Three.js Background Layer
Section titled “12. WebGL & Three.js Background Layer”The hero section background is a full-bleed Three.js canvas — a perspective grid field with cool monochrome tones, depth fade, slow breathing pulse, and subtle pointer parallax.
<canvas id="webgl" class="fixed inset-0 w-full h-full z-0"></canvas><div class="hero-fallback-bg" style="display:none;"><!-- fallback bg --></div>Three.js Setup
Section titled “Three.js Setup”const renderer = new THREE.WebGLRenderer({ canvas, alpha: true, antialias: true,});renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); // DPR clamp
const scene = new THREE.Scene();scene.background = new THREE.Color(0xf0f9ff); // sky-50scene.fog = new THREE.FogExp2(0xf0f9ff, 0.025);
const camera = new THREE.PerspectiveCamera(50, w / h, 0.1, 1000);
// Lightingscene.add(new THREE.AmbientLight(0xffffff, 0.6));scene.add(new THREE.DirectionalLight(0x38bdf8, 1.0));
// Materialconst mat = new THREE.MeshStandardMaterial({ color: 0x38bdf8 });Grid Field
Section titled “Grid Field”- Lines in
rgba(56,189,248,0.3)on#F0F9FFbackground. FogExp2fades distant lines naturally.- Breathing pulse: Y-axis oscillation ±5 units over 4–6s using
Math.sin(time).
Pointer Parallax
Section titled “Pointer Parallax”document.addEventListener("mousemove", (e) => { const x = (e.clientX / window.innerWidth - 0.5) * 2; const y = (e.clientY / window.innerHeight - 0.5) * 2; camera.position.x += (x * 3 - camera.position.x) * 0.02; // lerp camera.position.y += (-y * 2 - camera.position.y) * 0.02; camera.lookAt(scene.position);});DOM Fallback
Section titled “DOM Fallback”if (!window.WebGLRenderingContext) { document.getElementById("webgl").style.display = "none"; document.querySelector(".hero-fallback-bg").style.display = "block";}Integration notes:
- Canvas at
z-0, hero content atz-20+. - Dark overlay still applies on top of canvas.
- On mobile: cap DPR at
1.5. - Use GSAP ScrollTrigger to fade canvas out as user scrolls past the hero.
13. Responsive Behavior & Breakpoints
Section titled “13. Responsive Behavior & Breakpoints”| Breakpoint | Min Width | Prefix |
|---|---|---|
| Default (mobile) | 0px | — |
sm | 640px | sm: |
md | 768px | md: |
lg | 1024px | lg: |
xl | 1280px | xl: |
2xl | 1536px | 2xl: |
| Component | Mobile | Desktop |
|---|---|---|
| Hero | min-h-0 py-16 | lg:h-[80vh] lg:min-h-[620px] lg:py-0 |
| Search fields | flex-col, border-b | lg:flex-row, lg:border-r |
| Date picker | Single month, w-[92vw] | Two months, md:w-[640px] |
| Footer | grid-cols-1 | lg:grid-cols-4 |
| Modals | flex-col | md:flex-row |
Minimum touch target: 40×40px. Prefer h-10 buttons on mobile.
14. Accessibility Standards
Section titled “14. Accessibility Standards”- Focus rings:
focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]on all interactive elements. - ARIA: Label all inputs. Modals get
role="dialog" aria-modal="true" aria-labelledby. Loading containers getaria-busy="true". - Disabled:
disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 - Error inputs:
aria-invalid="true"triggersaria-invalid:ring-destructive/20 aria-invalid:border-destructive
Contrast minimums (WCAG AA):
text-slate-500(#64748b) on white = 4.6:1 ✅text-slate-400(#94a3b8) on white = 2.5:1 — placeholders/labels only#1e3a8aon white = high contrast ✅
Reduced motion:
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }}15. Dark Mode
Section titled “15. Dark Mode”Implemented via .dark class on <html> (not prefers-color-scheme). Toggle not yet wired to a UI control — pending feature.
| Token | Light | Dark |
|---|---|---|
--background | #ffffff | #0d0d12 |
--foreground | #0a0a0f | #fafaff |
--primary | #030213 | oklch(0.985 0 0) |
--muted | #ececf0 | oklch(0.269 0 0) |
--border | rgba(0,0,0,0.1) | oklch(0.269 0 0) |
--sidebar | oklch(0.985 0 0) | oklch(0.205 0 0) |
To implement: ThemeToggle button in dashboard header toggles .dark on <html> and persists to localStorage.
16. Page Templates & Screen Patterns
Section titled “16. Page Templates & Screen Patterns”Marketing Site — Home Page
Section titled “Marketing Site — Home Page”<Navbar /> ← Sticky top nav<Hero /> ← 80vh full-bleed, WebGL bg, search widget<Services /> ← Icon + description cards<FeaturedDestinations /> ← Image cards with hover overlay<StopoverPackages /> ← Package cards<Testimonials /> ← Star ratings + quotes<Team /> ← Team member cards<Footer /> ← 4-column grid with mapDashboard — Main Layout
Section titled “Dashboard — Main Layout”<Sidebar /> ← shadcn/ui sidebar, collapsible<main> <DashboardHeader /> ← User info, notifications <TabView> ← Tickets | VFS | SettingsDashboard — VFS Tab
Section titled “Dashboard — VFS Tab”<VfsTrackingFlow /> ← 8-stage pipeline with counts<VfsFilterBar /> ← Search + multi-select filters<PageHeader /> ← Title + Export CSV button<VfsList /> ← Data table ← Bulk action bar (fixed bottom) ← Payment modal (full-screen overlay)Bulk action bar (fixed bottom, appears on row selection):
fixed bottom-8 left-1/2 -translate-x-1/2 bg-[#001f3f] text-whitepx-8 py-4 rounded-3xl shadow-2xl shadow-blue-900/40flex items-center gap-10 z-50 border border-blue-400/20 backdrop-blur-xl17. Developer Quick Reference
Section titled “17. Developer Quick Reference”Hardcoded Brand Values (Approved Exceptions)
Section titled “Hardcoded Brand Values (Approved Exceptions)”| Hex | Intended Token | Usage |
|---|---|---|
#1e3a8a | brand-navy | Active states, primary CTAs |
#152a66 | brand-navy-dark | Hover on brand-navy |
#001f3f | deep-navy | Dashboard headings, modal panels |
#edeeef | hero-text | Hero headline text |
These should be moved to @theme tokens in index.css during the rebuild.
Do’s and Don’ts
Section titled “Do’s and Don’ts”| ✅ Do | ❌ Don’t |
|---|---|
Use active:scale-95 on all clickable elements | Use transform: scale() without transition |
Use transition-colors for colour-only changes | Use transition-all when only colour changes |
Wrap tables in overflow-x-auto | Let tables overflow the viewport |
| Use semantic status colours from the token system | Hardcode raw hex for status colours |
Apply whitespace-nowrap to table cells | Let table cells wrap unexpectedly |
Use z-[99] dropdowns / z-[100] modals | Mix z-index values inconsistently |
| Keep spacing on the 4px rhythm | Introduce arbitrary spacing values |
| Glass surface first; shadow/blur reinforce | Use shadows to fake depth without glass material |
| Provide DOM fallback for WebGL canvas | Render Three.js without a fallback |
| Keep motion at 150–200ms for micro-interactions | Exceed moderate motion without deliberate reason |
Key Libraries
Section titled “Key Libraries”| Library | Usage |
|---|---|
gsap + ScrollTrigger | Hero entrance + scroll-triggered reveals |
three (r128+) | WebGL background canvas |
lucide-react | All icons |
sonner | Toast notifications |
react-router-dom | Client-side routing |
@radix-ui/react-* | Accessible UI primitives (via shadcn) |
class-variance-authority | Button/Badge variant system |
clsx + tailwind-merge | Class merging via cn() |