website_designs

Spatial UI Design Reference

Overview

Spatial UI is a design aesthetic born from Apple’s Vision Pro and visionOS platform, translating the principles of spatial computing into two-dimensional interfaces that feel three-dimensional. Rather than simulating full 3D environments in the browser, Spatial UI borrows the language of depth, glass materials, and ambient layering to create interfaces where panels appear to float in physical space, content occupies distinct depth planes, and interactions feel tactile yet weightless. It is the web’s interpretation of what Apple calls “designing for spatial computing” – an approach where digital elements coexist with the user’s environment rather than demanding full attention on a flat screen.

The defining visual element is the glass panel: translucent, frosted surfaces that blur whatever sits behind them, letting ambient color and light bleed through while maintaining sharp text legibility. Apple’s visionOS uses a physically based “glass material” as its primary container, and Spatial UI adopts this with CSS backdrop-filter: blur() over semi-transparent backgrounds. These panels do not sit flush against a canvas; they hover above layered backgrounds with soft, diffused shadows that imply physical separation. The result is an interface that breathes – one where negative space is not empty but atmospheric.

Color palettes are restrained and luminous. Backgrounds lean toward deep, muted tones (dark indigos, charcoal, soft blacks) that recede visually, while foreground elements use clean whites, soft blues, and carefully placed accent colors. Apple’s visionOS defaults to white text on glass because it provides the highest legibility against unpredictable blurred backgrounds, and Spatial UI follows this convention. Accent colors are cool and ethereal – lavender, sky blue, soft cyan – applied sparingly to interactive elements and focus states rather than as decorative fills.

Typography is generous and airy. VisionOS uses a slightly heavier variant of SF Pro with increased tracking for readability in spatial environments, and web implementations mirror this with medium-weight sans-serifs, open letter-spacing, and generous line heights. The overall impression is one of calm precision: every element has room to exist, every surface suggests physical materiality, and the interface invites interaction through subtle depth cues rather than aggressive visual contrast.


Visual Characteristics

Core Design Traits

Design Principles


Color Palette

Spatial UI palettes are built around deep, receding backgrounds and luminous, clean foreground surfaces. The glass material tints everything slightly cool, so the overall temperature leans blue-grey. Accent colors are ethereal and calming – lavender, sky blue, soft teal – never harsh neons. The philosophy follows visionOS: white is the default text color because it provides the highest contrast on glass, and backgrounds are dark enough to let translucent surfaces glow without washing out.

Swatch Hex Role/Usage
Void #0D0D12 Deepest background; app canvas behind all layers
Deep Space #141420 Secondary background; section containers
Charcoal Glass #1C1C2A Card and panel base tint beneath glass blur
Slate Layer #252536 Elevated mid-ground surfaces; sidebar backgrounds
Glass White #FFFFFF Primary text on glass; highest legibility default
Soft White #F0F0F5 Secondary text; descriptions and body content
Mist Grey #A0A0B8 Tertiary text; captions, timestamps, metadata
Lavender Accent #9B8FFF Primary accent; interactive focus rings, active states
Sky Blue #64B5F6 Secondary accent; links, informational highlights
Soft Cyan #80DEEA Tertiary accent; badges, subtle indicators
Warm Blush #F8A4C8 Warm accent; notifications, gentle alerts
Faint Teal #4DB6AC Success states; confirmation indicators
Glass Border #FFFFFF1A Panel edge borders; light-catching separators (10% white)
Shadow Black #00000033 Elevation shadows; floating panel depth (20% black)
Ambient Indigo #2A2A4A Background gradient midpoint; ambient glow source

CSS Custom Properties

:root {
  --sp-void: #0D0D12;
  --sp-deep-space: #141420;
  --sp-charcoal: #1C1C2A;
  --sp-slate: #252536;
  --sp-white: #FFFFFF;
  --sp-soft-white: #F0F0F5;
  --sp-mist: #A0A0B8;
  --sp-lavender: #9B8FFF;
  --sp-sky: #64B5F6;
  --sp-cyan: #80DEEA;
  --sp-blush: #F8A4C8;
  --sp-teal: #4DB6AC;
  --sp-glass-border: rgba(255, 255, 255, 0.1);
  --sp-shadow: rgba(0, 0, 0, 0.2);
  --sp-ambient: #2A2A4A;

  /* Glass material tokens */
  --sp-glass-bg: rgba(255, 255, 255, 0.06);
  --sp-glass-bg-hover: rgba(255, 255, 255, 0.1);
  --sp-glass-blur: 40px;
  --sp-glass-border-width: 1px;
  --sp-glass-radius: 20px;
  --sp-glass-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);
}

Typography

Spatial UI typography follows Apple’s visionOS conventions: slightly heavier font weights than typical web defaults, increased letter-spacing for readability against blurred glass surfaces, and generous line heights that prevent text from feeling cramped. VisionOS uses SF Pro at medium weight for body text and bold for titles – heavier than the regular/semibold defaults on iOS – because spatial environments demand higher contrast. On the web, geometric sans-serifs with clean strokes and open counters replicate this clarity. Display text stays sentence-case or title-case (never all-caps) to maintain the calm, approachable tone.

Font Weight(s) Usage Link
Inter 300, 400, 500, 600, 700 Body text; labels; exceptional screen legibility at all sizes Inter
Plus Jakarta Sans 300, 400, 500, 600, 700, 800 Headings; display text; soft geometric character Plus Jakarta Sans
DM Sans 400, 500, 700 Alternative body; clean low-contrast geometric DM Sans
Outfit 300, 400, 500, 600, 700 Versatile geometric sans; friendly spatial feel Outfit
IBM Plex Mono 400, 500 Code snippets; technical labels; monospaced accent IBM Plex Mono

Font Pairing Suggestions

Heading Body Vibe
Plus Jakarta Sans 700 Inter 400 Clean spatial operating system; visionOS-inspired
Outfit 600 DM Sans 400 Soft, approachable ambient interface
Plus Jakarta Sans 600 Outfit 400 Modern spatial product UI; warm and precise

CSS Example

@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&family=Inter:wght@300;400;500;600;700&family=DM+Sans:wght@400;500;700&family=IBM+Plex+Mono:wght@400;500&display=swap');

body {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.75;
  color: var(--sp-white);
  letter-spacing: 0.01em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3 {
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.2;
  color: var(--sp-white);
}

h1 { font-size: clamp(2rem, 4.5vw, 3.5rem); }
h2 { font-size: clamp(1.4rem, 3vw, 2.2rem); }
h3 { font-size: clamp(1.1rem, 2vw, 1.5rem); }

.caption {
  font-family: 'Inter', sans-serif;
  font-size: 0.85rem;
  font-weight: 500;
  letter-spacing: 0.03em;
  color: var(--sp-mist);
}

.mono {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.88rem;
  letter-spacing: 0.02em;
}

Layout Principles


CSS / Design Techniques

Glass Panel (Card)

.sp-card {
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 20px;
  padding: 36px;
  backdrop-filter: blur(40px) saturate(1.4);
  -webkit-backdrop-filter: blur(40px) saturate(1.4);
  box-shadow:
    0 8px 32px rgba(0, 0, 0, 0.18),
    inset 0 1px 0 rgba(255, 255, 255, 0.06);
  transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1),
              box-shadow 0.4s ease,
              background 0.3s ease;
}

.sp-card:hover {
  transform: translateY(-4px) scale(1.005);
  background: rgba(255, 255, 255, 0.09);
  box-shadow:
    0 16px 48px rgba(0, 0, 0, 0.25),
    inset 0 1px 0 rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.16);
}

.sp-card h3 {
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 1.15rem;
  font-weight: 600;
  color: #FFFFFF;
  margin-bottom: 10px;
}

.sp-card p {
  color: #A0A0B8;
  font-size: 0.95rem;
  line-height: 1.7;
}

Spatial Button

.sp-button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 14px 30px;
  font-family: 'Inter', sans-serif;
  font-size: 0.88rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: #FFFFFF;
  background: rgba(155, 143, 255, 0.2);
  border: 1px solid rgba(155, 143, 255, 0.3);
  border-radius: 14px;
  cursor: pointer;
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
  transition: all 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
  position: relative;
  overflow: hidden;
}

.sp-button::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(
    135deg,
    rgba(255, 255, 255, 0.1) 0%,
    rgba(255, 255, 255, 0) 50%
  );
  pointer-events: none;
}

.sp-button:hover {
  background: rgba(155, 143, 255, 0.3);
  border-color: rgba(155, 143, 255, 0.5);
  box-shadow:
    0 8px 24px rgba(155, 143, 255, 0.15),
    0 4px 16px rgba(0, 0, 0, 0.15);
  transform: translateY(-2px);
}

.sp-button:active {
  transform: translateY(0) scale(0.98);
  transition-duration: 0.1s;
}

.sp-button-ghost {
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.12);
  color: var(--sp-soft-white);
}

.sp-button-ghost:hover {
  background: rgba(255, 255, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.2);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}

Glass Navigation

.sp-nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 40px;
  background: rgba(13, 13, 18, 0.5);
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  backdrop-filter: blur(40px) saturate(1.3);
  -webkit-backdrop-filter: blur(40px) saturate(1.3);
  transition: background 0.4s ease, border-color 0.4s ease;
}

.sp-nav.scrolled {
  background: rgba(13, 13, 18, 0.82);
  border-bottom-color: rgba(255, 255, 255, 0.1);
}

.sp-nav .logo {
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 1.15rem;
  font-weight: 700;
  color: #FFFFFF;
  text-decoration: none;
  letter-spacing: -0.01em;
}

.sp-nav .logo span {
  color: var(--sp-lavender);
}

.sp-nav-links {
  display: flex;
  gap: 4px;
  list-style: none;
}

.sp-nav-links a {
  font-family: 'Inter', sans-serif;
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--sp-mist);
  text-decoration: none;
  padding: 8px 18px;
  border-radius: 10px;
  transition: color 0.25s ease, background 0.25s ease;
}

.sp-nav-links a:hover {
  color: #FFFFFF;
  background: rgba(255, 255, 255, 0.06);
}

.sp-nav-links a.active {
  color: var(--sp-lavender);
  background: rgba(155, 143, 255, 0.08);
}

Hero Section

.sp-hero {
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  overflow: hidden;
  padding: 120px 24px 80px;
}

.sp-hero .ambient-bg {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at 30% 20%, rgba(155, 143, 255, 0.08) 0%, transparent 50%),
    radial-gradient(ellipse at 70% 80%, rgba(100, 181, 246, 0.06) 0%, transparent 50%),
    radial-gradient(ellipse at 50% 50%, rgba(128, 222, 234, 0.04) 0%, transparent 40%);
  pointer-events: none;
}

.sp-hero .content {
  position: relative;
  z-index: 5;
  max-width: 680px;
}

.sp-hero .eyebrow {
  font-family: 'Inter', sans-serif;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--sp-lavender);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 20px;
  display: inline-block;
  padding: 6px 18px;
  border-radius: 20px;
  background: rgba(155, 143, 255, 0.1);
  border: 1px solid rgba(155, 143, 255, 0.15);
}

.sp-hero h1 {
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: clamp(2.4rem, 5.5vw, 4rem);
  font-weight: 800;
  line-height: 1.1;
  color: #FFFFFF;
  margin-bottom: 24px;
  letter-spacing: -0.02em;
}

.sp-hero .subtitle {
  font-size: 1.15rem;
  color: var(--sp-mist);
  line-height: 1.8;
  max-width: 520px;
  margin: 0 auto 36px;
}

Depth Shadow System

/* Elevation levels for spatial depth */
.sp-elevation-1 {
  box-shadow:
    0 2px 8px rgba(0, 0, 0, 0.1),
    0 1px 2px rgba(0, 0, 0, 0.06);
}

.sp-elevation-2 {
  box-shadow:
    0 8px 32px rgba(0, 0, 0, 0.18),
    0 2px 8px rgba(0, 0, 0, 0.08);
}

.sp-elevation-3 {
  box-shadow:
    0 20px 60px rgba(0, 0, 0, 0.25),
    0 8px 24px rgba(0, 0, 0, 0.12);
}

.sp-elevation-4 {
  box-shadow:
    0 32px 80px rgba(0, 0, 0, 0.3),
    0 16px 40px rgba(0, 0, 0, 0.15);
}

/* Inset light edge for glass panels */
.sp-glass-inset {
  box-shadow:
    0 8px 32px rgba(0, 0, 0, 0.18),
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    inset 0 0 0 1px rgba(255, 255, 255, 0.03);
}

Ambient Background

.sp-ambient {
  position: fixed;
  inset: 0;
  z-index: 0;
  background: var(--sp-void);
  overflow: hidden;
}

.sp-ambient::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at 25% 25%, rgba(155, 143, 255, 0.06) 0%, transparent 50%),
    radial-gradient(ellipse at 75% 75%, rgba(100, 181, 246, 0.05) 0%, transparent 50%),
    radial-gradient(ellipse at 50% 10%, rgba(128, 222, 234, 0.03) 0%, transparent 40%);
  animation: ambientShift 20s ease-in-out infinite alternate;
}

.sp-ambient::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at 60% 60%, rgba(248, 164, 200, 0.04) 0%, transparent 45%),
    radial-gradient(ellipse at 20% 80%, rgba(155, 143, 255, 0.03) 0%, transparent 40%);
  animation: ambientShift 25s ease-in-out infinite alternate-reverse;
}

@keyframes ambientShift {
  0% { transform: translate(0, 0) scale(1); }
  50% { transform: translate(-2%, 1%) scale(1.02); }
  100% { transform: translate(1%, -1%) scale(1); }
}

Floating Depth Layers

.sp-depth-container {
  perspective: 1200px;
  perspective-origin: 50% 50%;
}

.sp-layer-back {
  transform: translateZ(-80px) scale(1.06);
  opacity: 0.5;
  filter: blur(2px);
  pointer-events: none;
}

.sp-layer-mid {
  transform: translateZ(-30px) scale(1.02);
  opacity: 0.8;
}

.sp-layer-front {
  transform: translateZ(0);
  position: relative;
  z-index: 1;
}

/* Parallax scroll response */
.sp-parallax-section {
  transform-style: preserve-3d;
  overflow: hidden;
}

.sp-parallax-bg {
  position: absolute;
  inset: -20%;
  transform: translateZ(-1px) scale(1.2);
  z-index: -1;
}

Glass Modal Overlay

.sp-modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 30;
  background: rgba(0, 0, 0, 0.4);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  display: flex;
  align-items: center;
  justify-content: center;
  animation: fadeIn 0.3s ease;
}

.sp-modal {
  background: rgba(28, 28, 42, 0.75);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 24px;
  padding: 40px;
  max-width: 520px;
  width: 90%;
  backdrop-filter: blur(60px) saturate(1.5);
  -webkit-backdrop-filter: blur(60px) saturate(1.5);
  box-shadow:
    0 32px 80px rgba(0, 0, 0, 0.35),
    inset 0 1px 0 rgba(255, 255, 255, 0.08);
  animation: modalSlideUp 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes modalSlideUp {
  from {
    opacity: 0;
    transform: translateY(24px) scale(0.96);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

Design Do’s and Don’ts

Do’s

Don’ts


Aesthetic Relationship
Glassmorphism The direct visual ancestor; Spatial UI extends glassmorphism with depth hierarchy, ambient environments, and Apple’s spatial computing principles rather than treating it as a surface decoration
3D Immersive Shares the philosophy of depth and spatial content organization; 3D Immersive uses WebGL-rendered environments while Spatial UI achieves dimensional feeling through CSS layers and glass
Minimalism Both prioritize clean space, restrained color, and typographic clarity; Spatial UI adds the glass material layer and depth hierarchy that pure Minimalism avoids
Neomorphism Both explore soft, touchable interfaces with subtle shadows; Neomorphism uses embossed/debossed surfaces on light backgrounds while Spatial UI uses translucent floating panels on dark environments
Dark Mode UI Shares the dark background and light text convention; Spatial UI enhances dark mode with glass materials, depth layers, and ambient gradients rather than flat dark surfaces
Soft UI Both favor rounded corners, gentle shadows, and approachable surfaces; Soft UI tends toward opaque pastels while Spatial UI is translucent and layered
Holographic Both use light-refracting, luminous visual language; Holographic leans toward iridescent rainbow surfaces while Spatial UI is more restrained with cool-toned glass
Futuristic / Sci-Fi Interface Both suggest advanced technology; Sci-Fi interfaces use harsh neons, grid lines, and HUD overlays while Spatial UI is deliberately calm, ambient, and human-centered

Quick-Start HTML Template

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Spatial UI Layout</title>
  <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&family=Inter:wght@300;400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet">
  <style>
    *, *::before, *::after {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    :root {
      --sp-void: #0D0D12;
      --sp-deep-space: #141420;
      --sp-charcoal: #1C1C2A;
      --sp-slate: #252536;
      --sp-white: #FFFFFF;
      --sp-soft-white: #F0F0F5;
      --sp-mist: #A0A0B8;
      --sp-lavender: #9B8FFF;
      --sp-sky: #64B5F6;
      --sp-cyan: #80DEEA;
      --sp-blush: #F8A4C8;
      --sp-teal: #4DB6AC;
      --sp-glass-border: rgba(255, 255, 255, 0.1);
      --sp-shadow: rgba(0, 0, 0, 0.2);
      --sp-ambient: #2A2A4A;
      --sp-glass-bg: rgba(255, 255, 255, 0.06);
      --sp-glass-bg-hover: rgba(255, 255, 255, 0.1);
      --sp-glass-blur: 40px;
      --sp-glass-radius: 20px;
    }

    html {
      scroll-behavior: smooth;
    }

    body {
      font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
      font-size: 1rem;
      font-weight: 400;
      line-height: 1.75;
      color: var(--sp-white);
      background: var(--sp-void);
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      overflow-x: hidden;
    }

    /* ===== AMBIENT BACKGROUND ===== */
    .ambient {
      position: fixed;
      inset: 0;
      z-index: 0;
      pointer-events: none;
      background: var(--sp-void);
    }

    .ambient::before {
      content: '';
      position: absolute;
      inset: 0;
      background:
        radial-gradient(ellipse at 25% 20%, rgba(155, 143, 255, 0.07) 0%, transparent 50%),
        radial-gradient(ellipse at 75% 75%, rgba(100, 181, 246, 0.05) 0%, transparent 50%),
        radial-gradient(ellipse at 50% 50%, rgba(128, 222, 234, 0.03) 0%, transparent 40%);
      animation: ambientDrift 25s ease-in-out infinite alternate;
    }

    .ambient::after {
      content: '';
      position: absolute;
      inset: 0;
      background:
        radial-gradient(ellipse at 60% 30%, rgba(248, 164, 200, 0.04) 0%, transparent 45%),
        radial-gradient(ellipse at 15% 70%, rgba(155, 143, 255, 0.03) 0%, transparent 40%);
      animation: ambientDrift 30s ease-in-out infinite alternate-reverse;
    }

    @keyframes ambientDrift {
      0% { transform: translate(0, 0) scale(1); opacity: 1; }
      50% { transform: translate(-1.5%, 1%) scale(1.01); opacity: 0.85; }
      100% { transform: translate(1%, -0.5%) scale(1); opacity: 1; }
    }

    /* ===== NAVIGATION ===== */
    .nav {
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      z-index: 20;
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 16px 40px;
      background: rgba(13, 13, 18, 0.45);
      border-bottom: 1px solid rgba(255, 255, 255, 0.05);
      backdrop-filter: blur(40px) saturate(1.3);
      -webkit-backdrop-filter: blur(40px) saturate(1.3);
      transition: background 0.4s ease, border-color 0.4s ease;
    }

    .nav.scrolled {
      background: rgba(13, 13, 18, 0.8);
      border-bottom-color: rgba(255, 255, 255, 0.1);
    }

    .nav .logo {
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-size: 1.15rem;
      font-weight: 700;
      color: var(--sp-white);
      text-decoration: none;
      letter-spacing: -0.01em;
    }

    .nav .logo span {
      color: var(--sp-lavender);
    }

    .nav-links {
      display: flex;
      gap: 4px;
      list-style: none;
    }

    .nav-links a {
      font-family: 'Inter', sans-serif;
      font-size: 0.85rem;
      font-weight: 500;
      color: var(--sp-mist);
      text-decoration: none;
      padding: 8px 18px;
      border-radius: 10px;
      transition: color 0.25s ease, background 0.25s ease;
    }

    .nav-links a:hover {
      color: var(--sp-white);
      background: rgba(255, 255, 255, 0.06);
    }

    .nav-links a.active {
      color: var(--sp-lavender);
      background: rgba(155, 143, 255, 0.08);
    }

    /* ===== CONTENT WRAPPER ===== */
    .content-wrapper {
      position: relative;
      z-index: 10;
    }

    /* ===== HERO ===== */
    .hero {
      position: relative;
      min-height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      text-align: center;
      padding: 120px 24px 80px;
    }

    .hero .inner {
      position: relative;
      z-index: 5;
      max-width: 680px;
    }

    .hero .eyebrow {
      font-family: 'Inter', sans-serif;
      font-size: 0.78rem;
      font-weight: 600;
      color: var(--sp-lavender);
      letter-spacing: 0.08em;
      text-transform: uppercase;
      margin-bottom: 24px;
      display: inline-block;
      padding: 6px 20px;
      border-radius: 20px;
      background: rgba(155, 143, 255, 0.1);
      border: 1px solid rgba(155, 143, 255, 0.15);
    }

    .hero h1 {
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-size: clamp(2.4rem, 5.5vw, 4rem);
      font-weight: 800;
      line-height: 1.08;
      color: var(--sp-white);
      margin-bottom: 24px;
      letter-spacing: -0.02em;
    }

    .hero h1 .highlight {
      background: linear-gradient(135deg, var(--sp-lavender), var(--sp-sky));
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;
      background-clip: text;
    }

    .hero .subtitle {
      font-size: 1.1rem;
      color: var(--sp-mist);
      line-height: 1.8;
      max-width: 520px;
      margin: 0 auto 40px;
    }

    .hero .cta-group {
      display: flex;
      gap: 16px;
      justify-content: center;
      flex-wrap: wrap;
    }

    .scroll-hint {
      position: absolute;
      bottom: 40px;
      left: 50%;
      transform: translateX(-50%);
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 8px;
      color: var(--sp-mist);
      font-size: 0.72rem;
      font-weight: 500;
      letter-spacing: 0.1em;
      text-transform: uppercase;
      animation: hintFloat 3s ease-in-out infinite;
    }

    .scroll-hint .dot {
      width: 6px;
      height: 6px;
      border-radius: 50%;
      background: var(--sp-lavender);
      opacity: 0.6;
    }

    @keyframes hintFloat {
      0%, 100% { transform: translateX(-50%) translateY(0); opacity: 1; }
      50% { transform: translateX(-50%) translateY(8px); opacity: 0.5; }
    }

    /* ===== BUTTONS ===== */
    .btn {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      padding: 14px 30px;
      font-family: 'Inter', sans-serif;
      font-size: 0.88rem;
      font-weight: 600;
      letter-spacing: 0.02em;
      text-decoration: none;
      border-radius: 14px;
      cursor: pointer;
      transition: all 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
      position: relative;
      overflow: hidden;
    }

    .btn::before {
      content: '';
      position: absolute;
      inset: 0;
      border-radius: inherit;
      background: linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0) 50%);
      pointer-events: none;
    }

    .btn-primary {
      color: var(--sp-white);
      background: rgba(155, 143, 255, 0.2);
      border: 1px solid rgba(155, 143, 255, 0.3);
      backdrop-filter: blur(20px);
      -webkit-backdrop-filter: blur(20px);
    }

    .btn-primary:hover {
      background: rgba(155, 143, 255, 0.3);
      border-color: rgba(155, 143, 255, 0.5);
      box-shadow: 0 8px 28px rgba(155, 143, 255, 0.15);
      transform: translateY(-2px);
    }

    .btn-primary:active {
      transform: translateY(0) scale(0.98);
      transition-duration: 0.1s;
    }

    .btn-ghost {
      color: var(--sp-soft-white);
      background: rgba(255, 255, 255, 0.04);
      border: 1px solid rgba(255, 255, 255, 0.1);
    }

    .btn-ghost:hover {
      color: var(--sp-white);
      background: rgba(255, 255, 255, 0.08);
      border-color: rgba(255, 255, 255, 0.18);
      box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
      transform: translateY(-2px);
    }

    /* ===== SECTION LAYOUT ===== */
    .section {
      padding: 120px 24px;
      max-width: 1080px;
      margin: 0 auto;
    }

    .section-eyebrow {
      font-family: 'Inter', sans-serif;
      font-size: 0.75rem;
      font-weight: 600;
      color: var(--sp-lavender);
      letter-spacing: 0.08em;
      text-transform: uppercase;
      margin-bottom: 12px;
    }

    .section-title {
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-size: clamp(1.5rem, 3.5vw, 2.4rem);
      font-weight: 700;
      color: var(--sp-white);
      margin-bottom: 16px;
      letter-spacing: -0.01em;
    }

    .section-desc {
      font-size: 1.05rem;
      color: var(--sp-mist);
      max-width: 560px;
      line-height: 1.8;
      margin-bottom: 48px;
    }

    .divider {
      height: 1px;
      max-width: 1080px;
      margin: 0 auto;
      background: linear-gradient(
        90deg,
        transparent,
        rgba(155, 143, 255, 0.12),
        rgba(100, 181, 246, 0.08),
        transparent
      );
    }

    /* ===== CARD GRID ===== */
    .card-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
      gap: 24px;
    }

    .card {
      background: var(--sp-glass-bg);
      border: 1px solid var(--sp-glass-border);
      border-radius: var(--sp-glass-radius);
      padding: 36px;
      backdrop-filter: blur(var(--sp-glass-blur)) saturate(1.4);
      -webkit-backdrop-filter: blur(var(--sp-glass-blur)) saturate(1.4);
      box-shadow:
        0 8px 32px rgba(0, 0, 0, 0.18),
        inset 0 1px 0 rgba(255, 255, 255, 0.06);
      transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1),
                  box-shadow 0.4s ease,
                  background 0.3s ease,
                  border-color 0.3s ease;
    }

    .card:hover {
      transform: translateY(-4px);
      background: var(--sp-glass-bg-hover);
      box-shadow:
        0 16px 48px rgba(0, 0, 0, 0.25),
        inset 0 1px 0 rgba(255, 255, 255, 0.08);
      border-color: rgba(255, 255, 255, 0.16);
    }

    .card .icon-wrap {
      width: 48px;
      height: 48px;
      border-radius: 14px;
      background: rgba(155, 143, 255, 0.12);
      border: 1px solid rgba(155, 143, 255, 0.15);
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 1.3rem;
      margin-bottom: 20px;
    }

    .card h3 {
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-size: 1.1rem;
      font-weight: 600;
      color: var(--sp-white);
      margin-bottom: 10px;
    }

    .card p {
      color: var(--sp-mist);
      font-size: 0.92rem;
      line-height: 1.7;
    }

    /* ===== FEATURE SPLIT ===== */
    .feature-split {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 60px;
      align-items: center;
      margin-top: 60px;
    }

    .feature-visual {
      aspect-ratio: 4 / 3;
      border-radius: 24px;
      background: rgba(255, 255, 255, 0.03);
      border: 1px solid rgba(255, 255, 255, 0.06);
      backdrop-filter: blur(20px);
      -webkit-backdrop-filter: blur(20px);
      display: flex;
      align-items: center;
      justify-content: center;
      position: relative;
      overflow: hidden;
    }

    .feature-visual::before {
      content: '';
      position: absolute;
      width: 180px;
      height: 180px;
      border-radius: 50%;
      background: radial-gradient(circle, rgba(155, 143, 255, 0.12) 0%, transparent 70%);
      animation: softPulse 5s ease-in-out infinite;
    }

    .feature-visual::after {
      content: '';
      position: absolute;
      width: 120px;
      height: 120px;
      border-radius: 50%;
      background: radial-gradient(circle, rgba(100, 181, 246, 0.1) 0%, transparent 70%);
      top: 25%;
      right: 20%;
      animation: softPulse 6s ease-in-out 1s infinite;
    }

    @keyframes softPulse {
      0%, 100% { transform: scale(1); opacity: 0.6; }
      50% { transform: scale(1.15); opacity: 1; }
    }

    .feature-visual .placeholder {
      font-family: 'Inter', sans-serif;
      font-size: 0.8rem;
      font-weight: 500;
      color: var(--sp-mist);
      letter-spacing: 0.06em;
      z-index: 1;
    }

    .feature-content h3 {
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-size: 1.4rem;
      font-weight: 700;
      color: var(--sp-white);
      margin-bottom: 16px;
      letter-spacing: -0.01em;
    }

    .feature-content p {
      color: var(--sp-mist);
      line-height: 1.8;
      margin-bottom: 24px;
    }

    .feature-list {
      list-style: none;
      display: flex;
      flex-direction: column;
      gap: 12px;
    }

    .feature-list li {
      font-size: 0.92rem;
      color: var(--sp-soft-white);
      padding-left: 22px;
      position: relative;
    }

    .feature-list li::before {
      content: '';
      position: absolute;
      left: 0;
      top: 9px;
      width: 6px;
      height: 6px;
      border-radius: 50%;
      background: var(--sp-lavender);
      box-shadow: 0 0 8px rgba(155, 143, 255, 0.4);
    }

    /* ===== STATS ===== */
    .stats-row {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
      gap: 24px;
      margin-top: 48px;
    }

    .stat {
      text-align: center;
      padding: 32px 16px;
      background: var(--sp-glass-bg);
      border: 1px solid var(--sp-glass-border);
      border-radius: 16px;
      backdrop-filter: blur(30px);
      -webkit-backdrop-filter: blur(30px);
      box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
    }

    .stat .number {
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-size: 2.4rem;
      font-weight: 700;
      color: var(--sp-lavender);
      display: block;
      margin-bottom: 6px;
    }

    .stat .label {
      font-family: 'Inter', sans-serif;
      font-size: 0.78rem;
      font-weight: 500;
      color: var(--sp-mist);
      letter-spacing: 0.04em;
    }

    /* ===== TESTIMONIAL / QUOTE PANEL ===== */
    .quote-panel {
      background: rgba(155, 143, 255, 0.06);
      border: 1px solid rgba(155, 143, 255, 0.1);
      border-radius: 24px;
      padding: 48px;
      text-align: center;
      backdrop-filter: blur(40px);
      -webkit-backdrop-filter: blur(40px);
      margin-top: 60px;
    }

    .quote-panel blockquote {
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-size: 1.3rem;
      font-weight: 500;
      color: var(--sp-soft-white);
      line-height: 1.7;
      font-style: italic;
      max-width: 600px;
      margin: 0 auto 20px;
    }

    .quote-panel cite {
      font-family: 'Inter', sans-serif;
      font-size: 0.85rem;
      color: var(--sp-mist);
      font-style: normal;
    }

    /* ===== FOOTER ===== */
    .footer {
      padding: 60px 40px;
      text-align: center;
      border-top: 1px solid rgba(255, 255, 255, 0.05);
      margin-top: 80px;
    }

    .footer p {
      font-size: 0.85rem;
      color: var(--sp-mist);
    }

    .footer a {
      color: var(--sp-lavender);
      text-decoration: none;
      transition: opacity 0.25s;
    }

    .footer a:hover {
      opacity: 0.7;
    }

    /* ===== SCROLL REVEAL ===== */
    .reveal {
      opacity: 0;
      transform: translateY(24px);
      transition: opacity 0.7s cubic-bezier(0.25, 0.46, 0.45, 0.94),
                  transform 0.7s cubic-bezier(0.25, 0.46, 0.45, 0.94);
    }

    .reveal.visible {
      opacity: 1;
      transform: translateY(0);
    }

    /* ===== REDUCED MOTION ===== */
    @media (prefers-reduced-motion: reduce) {
      *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
      }
      .reveal {
        opacity: 1;
        transform: none;
      }
    }

    /* ===== RESPONSIVE ===== */
    @media (max-width: 768px) {
      .nav {
        padding: 14px 20px;
      }

      .nav-links {
        display: none;
      }

      .hero h1 {
        font-size: clamp(1.8rem, 8vw, 2.8rem);
      }

      .hero .subtitle {
        font-size: 1rem;
      }

      .section {
        padding: 80px 20px;
      }

      .feature-split {
        grid-template-columns: 1fr;
        gap: 32px;
      }

      .card-grid {
        grid-template-columns: 1fr;
      }

      .stats-row {
        grid-template-columns: repeat(2, 1fr);
      }

      .cta-group {
        flex-direction: column;
        align-items: center;
      }

      .quote-panel {
        padding: 32px 24px;
      }

      .quote-panel blockquote {
        font-size: 1.1rem;
      }
    }

    @media (max-width: 480px) {
      .stats-row {
        grid-template-columns: 1fr;
      }

      .hero {
        padding: 100px 16px 60px;
      }

      .card {
        padding: 28px;
      }
    }
  </style>
</head>
<body>

  <!-- Ambient background environment -->
  <div class="ambient"></div>

  <!-- Glass navigation -->
  <nav class="nav" id="mainNav">
    <a href="#" class="logo">Spatial<span>Flow</span></a>
    <ul class="nav-links">
      <li><a href="#features" class="active">Features</a></li>
      <li><a href="#showcase">Showcase</a></li>
      <li><a href="#metrics">Metrics</a></li>
      <li><a href="#philosophy">Philosophy</a></li>
    </ul>
  </nav>

  <!-- Content sits above ambient layer -->
  <div class="content-wrapper">

    <!-- Hero -->
    <section class="hero">
      <div class="inner">
        <span class="eyebrow">Spatial Computing for the Web</span>
        <h1>Interfaces That <span class="highlight">Float in Space</span></h1>
        <p class="subtitle">
          Glass panels, depth layers, and ambient environments.
          Design interfaces that feel like they exist in the room with you,
          not trapped behind a screen.
        </p>
        <div class="cta-group">
          <a href="#features" class="btn btn-primary">Explore Panels</a>
          <a href="#philosophy" class="btn btn-ghost">Learn More</a>
        </div>
      </div>
      <div class="scroll-hint">
        <span>Scroll</span>
        <div class="dot"></div>
      </div>
    </section>

    <div class="divider"></div>

    <!-- Features -->
    <section class="section" id="features">
      <div class="reveal">
        <p class="section-eyebrow">Core Capabilities</p>
        <h2 class="section-title">Spatial Design Principles</h2>
        <p class="section-desc">
          Every panel floats with purpose. Depth communicates hierarchy,
          glass reveals environment, and generous space lets the interface breathe.
        </p>
      </div>

      <div class="card-grid">
        <div class="card reveal">
          <div class="icon-wrap">&#9673;</div>
          <h3>Glass Material</h3>
          <p>Translucent panels with backdrop blur let ambient color and
             light pass through, connecting UI to its environment.</p>
        </div>
        <div class="card reveal">
          <div class="icon-wrap">&#9672;</div>
          <h3>Depth Hierarchy</h3>
          <p>Z-position communicates importance. Closer elements demand attention
             while receding layers provide context.</p>
        </div>
        <div class="card reveal">
          <div class="icon-wrap">&#9711;</div>
          <h3>Ambient Light</h3>
          <p>Subtle gradient backgrounds simulate environmental lighting,
             creating atmosphere behind floating panels.</p>
        </div>
        <div class="card reveal">
          <div class="icon-wrap">&#10070;</div>
          <h3>Soft Elevation</h3>
          <p>Large, diffused shadows with low opacity imply floating separation
             rather than hard surface contact.</p>
        </div>
        <div class="card reveal">
          <div class="icon-wrap">&#9676;</div>
          <h3>Generous Space</h3>
          <p>Wide margins and padding treat negative space as atmosphere,
             giving every element room to exist in its depth plane.</p>
        </div>
        <div class="card reveal">
          <div class="icon-wrap">&#10023;</div>
          <h3>Spring Motion</h3>
          <p>Animations use spring-like easing with natural deceleration,
             making transitions feel physical and responsive.</p>
        </div>
      </div>
    </section>

    <div class="divider"></div>

    <!-- Showcase -->
    <section class="section" id="showcase">
      <div class="feature-split reveal">
        <div class="feature-visual">
          <span class="placeholder">Spatial Viewport</span>
        </div>
        <div class="feature-content">
          <h3>Panels That Float</h3>
          <p>
            Inspired by Apple Vision Pro, each UI surface exists as a
            translucent panel suspended in space. Glass materials blur
            the environment behind them while maintaining crisp, legible
            content in the foreground.
          </p>
          <ul class="feature-list">
            <li>Backdrop blur with saturation boost for rich glass</li>
            <li>Inset light edges simulate material rim lighting</li>
            <li>Multi-layer depth shadows for spatial elevation</li>
            <li>Hover interactions lift panels in the z-axis</li>
          </ul>
        </div>
      </div>

      <div class="quote-panel reveal">
        <blockquote>
          "When you look at an app in visionOS, it looks like it's right
          there in the room with you, and you can interact with it just
          by looking at it."
        </blockquote>
        <cite>Apple Design Team &mdash; Designing for visionOS</cite>
      </div>
    </section>

    <div class="divider"></div>

    <!-- Metrics -->
    <section class="section" id="metrics">
      <div class="reveal">
        <p class="section-eyebrow">Performance</p>
        <h2 class="section-title">Built for Comfort</h2>
        <p class="section-desc">
          Spatial interfaces prioritize user comfort and smooth rendering.
          Every glass panel is GPU-composited. Every transition is natural.
        </p>
      </div>
      <div class="stats-row reveal">
        <div class="stat">
          <span class="number">40px</span>
          <span class="label">Glass Blur</span>
        </div>
        <div class="stat">
          <span class="number">44px</span>
          <span class="label">Min Touch Target</span>
        </div>
        <div class="stat">
          <span class="number">20px</span>
          <span class="label">Panel Radius</span>
        </div>
        <div class="stat">
          <span class="number">60fps</span>
          <span class="label">Target Rate</span>
        </div>
      </div>
    </section>

    <div class="divider"></div>

    <!-- Philosophy -->
    <section class="section" id="philosophy">
      <div class="reveal">
        <p class="section-eyebrow">Philosophy</p>
        <h2 class="section-title">Space Invites Interaction</h2>
        <p class="section-desc">
          Spatial UI does not demand attention with bright colors and aggressive
          contrast. It invites interaction through depth, translucency, and
          atmosphere. Interfaces float calmly, revealing information through
          layered glass rather than flat screens.
        </p>
      </div>
      <div style="text-align: center; margin-top: 36px;" class="reveal">
        <a href="#" class="btn btn-primary">Start Building</a>
      </div>
    </section>

    <!-- Footer -->
    <footer class="footer">
      <p>Spatial UI Design Reference &middot;
         Inspired by <a href="https://developer.apple.com/design/human-interface-guidelines/designing-for-visionos" target="_blank">Apple visionOS</a></p>
    </footer>

  </div>

  <script>
    // --- Nav scroll effect ---
    const nav = document.getElementById('mainNav');
    window.addEventListener('scroll', () => {
      nav.classList.toggle('scrolled', window.scrollY > 60);
    }, { passive: true });

    // --- Scroll reveal (IntersectionObserver) ---
    const revealEls = document.querySelectorAll('.reveal');
    const observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          entry.target.classList.add('visible');
          observer.unobserve(entry.target);
        }
      });
    }, { threshold: 0.12, rootMargin: '0px 0px -40px 0px' });
    revealEls.forEach(el => observer.observe(el));

    // --- Respect reduced motion ---
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
      revealEls.forEach(el => el.classList.add('visible'));
    }
  </script>

</body>
</html>

Implementation Tips