返回模板目录
landingglassmorphism

玻璃拟态落地页

现代玻璃拟态落地页,适合 SaaS 产品与科技类展示场景。

独立打开

完整模板源代码

查看 1148 行代码
"use client";

export const dynamic = "force-static";

import { useState } from "react";
import {
  ArrowRight,
  ArrowUpRight,
  Boxes,
  Check,
  Compass,
  Download,
  Gem,
  Layers,
  Menu,
  Minus,
  Moon,
  Pause,
  Play,
  Plus,
  Quote,
  Repeat,
  Shuffle,
  SkipBack,
  SkipForward,
  Sliders,
  Sparkles,
  Volume2,
  Waves,
  X,
} from "@/components/IconShim";
import {
  Albert_Sans,
  Cormorant_Garamond,
  JetBrains_Mono,
} from "@/components/templates/FontShim";
import { TemplateBackLink } from "@/components/templates/TemplateBackLink";

const display = Cormorant_Garamond({
  subsets: ["latin"],
  weight: ["500", "600"],
  style: ["normal", "italic"],
});
const sans = Albert_Sans({ subsets: ["latin"] });
const mono = JetBrains_Mono({ subsets: ["latin"], weight: ["400", "500"] });

/* ------------------------------------------------------------------ */
/* Content                                                             */
/* ------------------------------------------------------------------ */

const NAV_LINKS = [
  { label: "Engine", href: "#engine" },
  { label: "Spaces", href: "#spaces" },
  { label: "Pricing", href: "#pricing" },
  { label: "Questions", href: "#faq" },
];

const PRESS = [
  "Resonance",
  "The Mix Review",
  "Audio Frontier",
  "Pitch & Tone",
  "Studio Weekly",
  "Waveform",
  "The Listening Room",
];

// Deterministic waveform for the hero player (runs at build under force-static).
const WAVEFORM = Array.from({ length: 58 }, (_, i) => {
  const envelope = Math.sin((i / 57) * Math.PI);
  const texture = 0.5 + 0.5 * Math.abs(Math.sin(i * 1.27) * Math.cos(i * 0.63));
  return Math.round(16 + envelope * texture * 80);
});
const WAVE_PROGRESS = 0.36;

const FEATURES = [
  {
    icon: Compass,
    label: "HEAD-TRACKED",
    title: "The stage holds still",
    body: "Turn your head and the singer stays center, the cello stays stage-left. Motion sensors keep the room fixed in place, the way a real one would.",
  },
  {
    icon: Sliders,
    label: "REAL-TIME",
    title: "Mastered as it plays",
    body: "Loudness, width, and depth balance live against a reference curve. No bounce, no render queue, no waiting around to hear the change land.",
  },
  {
    icon: Layers,
    label: "STEMS",
    title: "Every part, placed",
    body: "Pull the vocal up front, push the pads to the back wall, lift the strings overhead. Each stem gets real coordinates in three dimensions.",
  },
  {
    icon: Gem,
    label: "LOSSLESS",
    title: "Nothing thrown away",
    body: "Twenty-four bit source, up to 192 kHz, rendered without a single re-encode. What you master is exactly what reaches the listener.",
  },
  {
    icon: Boxes,
    label: "ROOMS",
    title: "Borrow any acoustics",
    body: "Model a late-night jazz club, a stone cathedral, or the inside of a moving car. Swap the room and the whole mix breathes differently.",
  },
  {
    icon: Download,
    label: "OFFLINE",
    title: "Spatial on the flight",
    body: "Cache full head-tracked mixes straight to the device. Thirty-eight thousand feet, airplane mode, still surrounded on every side.",
  },
];

const STAGE_SOURCES = [
  { label: "Vocals", top: "20%", left: "50%", delay: "0s" },
  { label: "Piano", top: "40%", left: "23%", delay: "0.7s" },
  { label: "Strings", top: "34%", left: "77%", delay: "1.2s" },
  { label: "Bass", top: "72%", left: "37%", delay: "1.7s" },
  { label: "Percussion", top: "70%", left: "67%", delay: "2.3s" },
];

const ENGINE_POINTS = [
  "Object-based mixing, not fixed channels",
  "Sub-degree placement resolution",
  "Binaural render for any pair of headphones",
];

const METRICS = [
  {
    value: "12 ms",
    label: "motion-to-sound latency, measured head-tracked end to end",
  },
  {
    value: "128",
    label: "independent audio objects placed in a single session",
  },
  {
    value: "192 kHz",
    label: "lossless rendering ceiling, 24-bit, never re-encoded",
  },
  {
    value: "3,200+",
    label: "hours of spatial catalog, remastered and growing weekly",
  },
];

const TESTIMONIALS = [
  {
    quote:
      "I ran our last record through the cathedral profile and heard reverb tails I had been missing for a decade. It is the first spatial tool that stops feeling like a trick.",
    name: "Mara Oyelaran",
    role: "Mastering Engineer, Goldline",
  },
  {
    quote:
      "Head-tracking is the part nobody oversells enough. You turn, the mix stays put, and a plain pair of headphones becomes a room you are standing inside.",
    name: "Devin Ashcroft",
    role: "Producer, Lower Third",
  },
  {
    quote:
      "We release every single in stereo and Nocturne spatial now. Listeners feel the difference before they can name it, and they stay to the very last bar.",
    name: "Yuki Tanaka",
    role: "A&R, Nightglass Records",
  },
];

const PLANS = [
  {
    name: "Listener",
    monthly: 0,
    yearly: 0,
    blurb: "Immersive playback on the headphones you already own.",
    features: [
      "Head-tracked spatial playback",
      "Lossless streaming to 48 kHz",
      "Six signature room profiles",
      "Offline cache, twenty tracks",
    ],
    cta: "Start listening",
    featured: false,
  },
  {
    name: "Studio",
    monthly: 18,
    yearly: 15,
    blurb: "Compose, place, and master a full mix in real space.",
    features: [
      "Everything in Listener",
      "24-bit rendering up to 192 kHz",
      "128 audio objects per session",
      "Every room profile, plus custom rooms",
      "Real-time mastering suite",
      "Spatial and stereo stem export",
    ],
    cta: "Start 14-day trial",
    featured: true,
  },
  {
    name: "Label",
    monthly: null,
    yearly: null,
    blurb: "Ship spatial across an entire back catalog.",
    features: [
      "Everything in Studio",
      "Batch spatial rendering",
      "Catalog retention analytics",
      "SSO and shared team seats",
      "A dedicated mastering engineer",
    ],
    cta: "Talk to us",
    featured: false,
  },
];

const FAQS = [
  {
    q: "Do I need special headphones?",
    a: "Any stereo headphones work. Head-tracking uses the motion sensors already in modern earbuds and headsets, or your phone held steady in front of you. There is no proprietary hardware to buy, ever.",
  },
  {
    q: "Will spatial change how my stereo master sounds?",
    a: "Never. Your stereo master stays untouched. Nocturne renders a separate spatial layer beside it, and you can A/B the two instantly at any point in the session.",
  },
  {
    q: "What can I export?",
    a: "Dolby Atmos ADM BWF, binaural stereo, and a standard stereo fold-down in a single pass. Stems carry their spatial coordinates with them, so a mix reopens anywhere with its geometry intact.",
  },
  {
    q: "Is the Listener plan really free?",
    a: "Yes, free for as long as you want it, including head-tracked playback and lossless streaming. Creators begin on a 14-day Studio trial that needs no card up front.",
  },
];

const FOOTER_COLS = [
  {
    title: "Product",
    links: [
      "Engine",
      "Room profiles",
      "Mastering",
      "Spatial export",
      "Desktop app",
    ],
  },
  {
    title: "Listen",
    links: ["Catalog", "New releases", "Sessions", "Gift a year"],
  },
  { title: "Company", links: ["Studio", "Careers", "Press kit", "Contact"] },
  { title: "Legal", links: ["Privacy", "Terms", "Licensing", "Credits"] },
];

// Signature glass surfaces reused across the page.
const GLASS =
  "border border-white/10 bg-gradient-to-b from-white/[0.09] to-white/[0.02] backdrop-blur-xl shadow-[0_30px_80px_-32px_rgba(0,0,0,0.9),inset_0_1px_0_0_rgba(255,255,255,0.16)]";
const GLASS_SOFT =
  "border border-white/10 bg-white/[0.035] backdrop-blur-xl shadow-[0_20px_50px_-30px_rgba(0,0,0,0.85),inset_0_1px_0_0_rgba(255,255,255,0.10)]";

/* ------------------------------------------------------------------ */
/* Page                                                                */
/* ------------------------------------------------------------------ */

export default function GlassLandingPage() {
  const [menuOpen, setMenuOpen] = useState(false);
  const [playing, setPlaying] = useState(true);
  const [yearly, setYearly] = useState(true);
  const [openFaq, setOpenFaq] = useState<number | null>(0);

  const played = Math.floor(WAVEFORM.length * WAVE_PROGRESS);

  return (
    <div
      className={`${sans.className} relative min-h-screen bg-[#050D0F] text-[#E7F2F0] antialiased selection:bg-[#7DE3E0] selection:text-[#04191A]`}
    >
      <TemplateBackLink />

      <style>{`
        @keyframes noc-rise { from { opacity: 0; transform: translateY(22px); } to { opacity: 1; transform: none; } }
        @keyframes noc-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-12px); } }
        @keyframes noc-drift { 0%, 100% { transform: translate(0, 0) scale(1); opacity: 0.75; } 50% { transform: translate(4%, -3%) scale(1.1); opacity: 1; } }
        @keyframes noc-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
        @keyframes noc-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
        @keyframes noc-sonar { to { transform: rotate(360deg); } }
        @keyframes noc-ping { 0% { transform: scale(1); opacity: 0.7; } 100% { transform: scale(2.8); opacity: 0; } }
        @keyframes noc-eq { 0%, 100% { transform: scaleY(0.3); } 50% { transform: scaleY(1); } }
        .noc-rise { opacity: 0; animation: noc-rise 0.85s cubic-bezier(0.22, 1, 0.36, 1) forwards; }
        .noc-float { animation: noc-float 7s ease-in-out infinite; }
        .noc-drift { animation: noc-drift 17s ease-in-out infinite; }
        .noc-drift-slow { animation: noc-drift 24s ease-in-out infinite; }
        .noc-marquee { animation: noc-marquee 36s linear infinite; }
        .noc-pulse { animation: noc-pulse 2.4s ease-in-out infinite; }
        .noc-sonar { animation: noc-sonar 9s linear infinite; }
        .noc-ping { animation: noc-ping 3.2s ease-out infinite; }
        .noc-eq { animation: noc-eq 900ms ease-in-out infinite; transform-origin: bottom; }
        @media (prefers-reduced-motion: reduce) {
          .noc-rise { animation: none; opacity: 1; }
          .noc-float, .noc-drift, .noc-drift-slow, .noc-marquee, .noc-pulse, .noc-sonar, .noc-ping, .noc-eq { animation: none; }
        }
      `}</style>

      {/* ── Aurora backdrop ─────────────────────────────────────── */}
      <div
        aria-hidden
        className="pointer-events-none fixed inset-0 z-0 overflow-hidden"
      >
        <div
          className="absolute inset-0"
          style={{
            backgroundImage:
              "radial-gradient(60% 50% at 14% 8%, rgba(16,185,129,0.18), transparent 60%)," +
              "radial-gradient(55% 45% at 86% 14%, rgba(34,211,238,0.15), transparent 60%)," +
              "radial-gradient(75% 60% at 50% 104%, rgba(125,227,224,0.13), transparent 66%)",
          }}
        />
        <div className="noc-drift absolute -left-32 top-[-12%] h-[46vw] w-[46vw] rounded-full bg-emerald-500/20 blur-[130px]" />
        <div className="noc-drift-slow absolute right-[-14%] top-[6%] h-[42vw] w-[42vw] rounded-full bg-cyan-500/[0.16] blur-[140px]" />
        <div className="noc-drift absolute bottom-[-18%] left-1/3 h-[44vw] w-[44vw] rounded-full bg-teal-400/[0.14] blur-[150px]" />
        <div
          className="absolute inset-0"
          style={{
            background:
              "radial-gradient(120% 80% at 50% 0%, transparent 52%, rgba(2,7,8,0.82) 100%)",
          }}
        />
        <div
          className="absolute inset-0 opacity-[0.06] mix-blend-soft-light"
          style={{
            backgroundImage:
              "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E\")",
          }}
        />
      </div>

      <div className="relative z-10">
        {/* ── Nav ─────────────────────────────────────────────── */}
        <header className="sticky top-0 z-40 px-4 pt-4">
          <div
            className={`mx-auto flex max-w-6xl items-center justify-between rounded-2xl ${GLASS} px-4 py-3 md:px-6`}
          >
            <a href="#top" className="flex items-center gap-2.5">
              <span className="relative grid h-8 w-8 place-items-center rounded-xl border border-white/15 bg-gradient-to-br from-[#7DE3E0]/30 to-emerald-400/10">
                <Moon className="h-4 w-4 text-[#7DE3E0]" strokeWidth={2} />
              </span>
              <span className="text-lg font-semibold tracking-tight">
                Nocturne
              </span>
            </a>

            <nav className="hidden items-center gap-8 md:flex">
              {NAV_LINKS.map((link) => (
                <a
                  key={link.label}
                  href={link.href}
                  className="text-sm text-[#E7F2F0]/60 transition-colors hover:text-[#E7F2F0]"
                >
                  {link.label}
                </a>
              ))}
            </nav>

            <div className="hidden items-center gap-3 md:flex">
              <a
                href="#top"
                className="text-sm text-[#E7F2F0]/60 transition-colors hover:text-[#E7F2F0]"
              >
                Sign in
              </a>
              <a
                href="#pricing"
                className="group inline-flex items-center gap-1.5 rounded-full bg-gradient-to-r from-[#7DE3E0] to-emerald-300 px-4 py-2 text-sm font-semibold text-[#04191A] shadow-[0_8px_30px_-8px_rgba(125,227,224,0.6)] transition-transform hover:-translate-y-0.5"
              >
                Get started
                <ArrowRight className="h-3.5 w-3.5 transition-transform group-hover:translate-x-0.5" />
              </a>
            </div>

            <button
              type="button"
              onClick={() => setMenuOpen(!menuOpen)}
              aria-label="Toggle menu"
              className="text-[#E7F2F0] md:hidden"
            >
              {menuOpen ? (
                <X className="h-5 w-5" />
              ) : (
                <Menu className="h-5 w-5" />
              )}
            </button>
          </div>

          {menuOpen && (
            <div
              className={`mx-auto mt-2 max-w-6xl rounded-2xl ${GLASS} p-4 md:hidden`}
            >
              {NAV_LINKS.map((link) => (
                <a
                  key={link.label}
                  href={link.href}
                  onClick={() => setMenuOpen(false)}
                  className="block py-2.5 text-sm text-[#E7F2F0]/75"
                >
                  {link.label}
                </a>
              ))}
              <a
                href="#pricing"
                onClick={() => setMenuOpen(false)}
                className="mt-3 block rounded-full bg-gradient-to-r from-[#7DE3E0] to-emerald-300 px-4 py-2.5 text-center text-sm font-semibold text-[#04191A]"
              >
                Get started
              </a>
            </div>
          )}
        </header>

        {/* ── Hero ────────────────────────────────────────────── */}
        <section
          id="top"
          className="mx-auto grid max-w-6xl gap-14 px-5 pb-20 pt-14 md:grid-cols-[1.02fr_0.98fr] md:items-center md:px-8 md:pb-28 md:pt-20"
        >
          <div>
            <p
              className={`${mono.className} noc-rise mb-6 inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-3 py-1.5 text-[11px] tracking-[0.18em] text-[#7DE3E0]`}
            >
              <Sparkles className="h-3.5 w-3.5" strokeWidth={2} />
              SPATIAL AUDIO, MASTERED LIVE
            </p>
            <h1
              className={`${display.className} noc-rise text-[3.1rem] font-medium leading-[0.98] tracking-tight md:text-[4.6rem]`}
              style={{ animationDelay: "80ms" }}
            >
              Your music,
              <br />
              <em className="text-[#7DE3E0]">unfurled</em>
              <br />
              into space.
            </h1>
            <p
              className="noc-rise mt-7 max-w-md text-base leading-relaxed text-[#E7F2F0]/60 md:text-lg"
              style={{ animationDelay: "160ms" }}
            >
              Nocturne renders every stem into a room you can walk through —
              head-tracked, lossless, and mastered as it plays. Put on any
              headphones and step inside the mix.
            </p>
            <div
              className="noc-rise mt-9 flex flex-wrap items-center gap-4"
              style={{ animationDelay: "240ms" }}
            >
              <a
                href="#pricing"
                className="group inline-flex items-center gap-2 rounded-full bg-gradient-to-r from-[#7DE3E0] to-emerald-300 px-6 py-3.5 text-sm font-semibold text-[#04191A] shadow-[0_14px_44px_-12px_rgba(125,227,224,0.65)] transition-transform hover:-translate-y-0.5"
              >
                Start listening
                <ArrowRight className="h-4 w-4 transition-transform group-hover:translate-x-0.5" />
              </a>
              <a
                href="#engine"
                className="inline-flex items-center gap-2 rounded-full border border-white/15 bg-white/5 px-6 py-3.5 text-sm font-medium text-[#E7F2F0] backdrop-blur-md transition-colors hover:bg-white/10"
              >
                Hear a demo
                <ArrowUpRight className="h-4 w-4" />
              </a>
            </div>
            <p
              className={`${mono.className} noc-rise mt-8 text-[11px] tracking-wide text-[#E7F2F0]/35`}
              style={{ animationDelay: "320ms" }}
            >
              FREE FOREVER FOR LISTENERS · NO CARD · ANY HEADPHONES
            </p>
          </div>

          {/* Hero player — pure CSS product art */}
          <div
            className="noc-rise relative"
            style={{ animationDelay: "200ms" }}
          >
            <div
              aria-hidden
              className="absolute -inset-8 bg-[#7DE3E0]/10 blur-3xl"
            />
            <div className="noc-float relative">
              <div className={`relative rounded-[1.75rem] ${GLASS} p-4`}>
                {/* Artwork */}
                <div className="relative aspect-[5/4] overflow-hidden rounded-2xl">
                  <div
                    className="absolute inset-0"
                    style={{
                      backgroundImage:
                        "radial-gradient(circle at 30% 24%, rgba(125,227,224,0.55), transparent 55%)," +
                        "radial-gradient(circle at 74% 82%, rgba(52,211,153,0.5), transparent 55%)," +
                        "linear-gradient(135deg, #06171A 0%, #0A2A2C 100%)",
                    }}
                  />
                  {/* Concentric soundstage rings */}
                  <div
                    aria-hidden
                    className="absolute inset-0 grid place-items-center"
                  >
                    {[88, 62, 38].map((size) => (
                      <div
                        key={size}
                        className="absolute rounded-full border border-white/15"
                        style={{ width: `${size}%`, height: `${size}%` }}
                      />
                    ))}
                    <div className="absolute h-3 w-3 rounded-full bg-[#7DE3E0] shadow-[0_0_30px_8px_rgba(125,227,224,0.7)]" />
                  </div>
                  {/* Now-playing chip + equalizer */}
                  <div
                    className={`${mono.className} absolute left-3 top-3 flex items-center gap-2 rounded-full border border-white/15 bg-black/25 px-2.5 py-1 text-[10px] tracking-[0.14em] text-[#E7F2F0]/80 backdrop-blur-md`}
                  >
                    <span className="flex h-3 items-end gap-[2px]">
                      {[0, 1, 2, 3].map((bar) => (
                        <span
                          key={bar}
                          className={`w-[2px] rounded-sm bg-[#7DE3E0] ${playing ? "noc-eq" : ""}`}
                          style={{
                            height: "70%",
                            animationDelay: `${bar * 130}ms`,
                          }}
                        />
                      ))}
                    </span>
                    NOW PLAYING
                  </div>
                  <span
                    className={`${mono.className} absolute right-3 top-3 rounded-full border border-white/15 bg-black/25 px-2.5 py-1 text-[10px] tracking-[0.12em] text-[#7DE3E0] backdrop-blur-md`}
                  >
                    ATMOS
                  </span>
                  {/* Title scrim */}
                  <div className="absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/70 to-transparent p-4">
                    <p
                      className={`${display.className} text-2xl italic leading-none`}
                    >
                      Meridian
                    </p>
                    <p className="mt-1 text-xs text-[#E7F2F0]/60">
                      Vesper Lang · Nocturnes, Vol. II
                    </p>
                  </div>
                </div>

                {/* Waveform */}
                <div className="px-1 pt-4">
                  <div className="flex h-12 items-center gap-[3px]">
                    {WAVEFORM.map((h, i) => (
                      <div
                        key={i}
                        className="flex-1 rounded-full"
                        style={{
                          height: `${h}%`,
                          backgroundColor:
                            i <= played ? "#7DE3E0" : "rgba(231,242,240,0.16)",
                        }}
                      />
                    ))}
                  </div>
                  <div
                    className={`${mono.className} mt-2 flex justify-between text-[10px] text-[#E7F2F0]/45`}
                  >
                    <span>1:24</span>
                    <span>3:58</span>
                  </div>
                </div>

                {/* Transport */}
                <div className="mt-2 flex items-center justify-between px-1 pb-1">
                  <button
                    type="button"
                    aria-label="Shuffle"
                    className="text-[#E7F2F0]/50 transition-colors hover:text-[#E7F2F0]"
                  >
                    <Shuffle className="h-4 w-4" />
                  </button>
                  <div className="flex items-center gap-4">
                    <button
                      type="button"
                      aria-label="Previous track"
                      className="text-[#E7F2F0]/80 transition-colors hover:text-[#E7F2F0]"
                    >
                      <SkipBack className="h-5 w-5" fill="currentColor" />
                    </button>
                    <button
                      type="button"
                      onClick={() => setPlaying(!playing)}
                      aria-label={playing ? "Pause" : "Play"}
                      className="grid h-12 w-12 place-items-center rounded-full bg-gradient-to-br from-[#7DE3E0] to-emerald-300 text-[#04191A] shadow-[0_10px_30px_-8px_rgba(125,227,224,0.7)] transition-transform hover:scale-105"
                    >
                      {playing ? (
                        <Pause className="h-5 w-5" fill="currentColor" />
                      ) : (
                        <Play
                          className="h-5 w-5 translate-x-0.5"
                          fill="currentColor"
                        />
                      )}
                    </button>
                    <button
                      type="button"
                      aria-label="Next track"
                      className="text-[#E7F2F0]/80 transition-colors hover:text-[#E7F2F0]"
                    >
                      <SkipForward className="h-5 w-5" fill="currentColor" />
                    </button>
                  </div>
                  <button
                    type="button"
                    aria-label="Repeat"
                    className="text-[#E7F2F0]/50 transition-colors hover:text-[#E7F2F0]"
                  >
                    <Repeat className="h-4 w-4" />
                  </button>
                </div>

                {/* Spatial footer */}
                <div className="mt-3 flex items-center justify-between border border-white/10 px-1 pt-3">
                  <span
                    className={`${mono.className} flex items-center gap-1.5 text-[10px] tracking-[0.12em] text-[#E7F2F0]/45`}
                  >
                    <Waves className="h-3.5 w-3.5 text-[#7DE3E0]" />
                    HEAD-TRACKED · LDAC
                  </span>
                  <span className="flex items-center gap-1.5 text-[#E7F2F0]/45">
                    <Volume2 className="h-3.5 w-3.5" />
                    <span className="h-1 w-16 rounded-full bg-white/10">
                      <span className="block h-1 w-2/3 rounded-full bg-[#7DE3E0]" />
                    </span>
                  </span>
                </div>
              </div>
            </div>
          </div>
        </section>

        {/* ── Press marquee ───────────────────────────────────── */}
        <section className="overflow-hidden border-y border-white/[0.06] py-7">
          <p
            className={`${mono.className} mb-5 text-center text-[10px] tracking-[0.24em] text-[#E7F2F0]/30`}
          >
            HEARD ABOUT IN
          </p>
          <div className="noc-marquee flex w-max items-center gap-14 pr-14">
            {[...PRESS, ...PRESS].map((name, i) => (
              <span
                key={i}
                className={`${display.className} whitespace-nowrap text-xl italic text-[#E7F2F0]/30`}
              >
                {name}
              </span>
            ))}
          </div>
        </section>

        {/* ── Features ────────────────────────────────────────── */}
        <section
          id="engine"
          className="mx-auto max-w-6xl px-5 py-20 md:px-8 md:py-28"
        >
          <div className="mb-14 flex flex-wrap items-end justify-between gap-6">
            <div>
              <p
                className={`${mono.className} mb-4 flex items-center gap-2 text-xs tracking-[0.22em] text-[#7DE3E0]`}
              >
                <Waves className="h-4 w-4" />
                THE ENGINE
              </p>
              <h2
                className={`${display.className} max-w-xl text-4xl font-medium leading-[1.02] md:text-5xl`}
              >
                Six pieces, tuned for{" "}
                <em className="text-[#7DE3E0]">careful ears.</em>
              </h2>
            </div>
            <p className="max-w-sm text-sm leading-relaxed text-[#E7F2F0]/50">
              One engine, split into the parts that matter — so spatial audio
              finally sounds like a place you are in, not an effect switched on
              over the top.
            </p>
          </div>

          <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
            {FEATURES.map((feature) => (
              <article
                key={feature.title}
                className={`group rounded-2xl ${GLASS_SOFT} p-6 transition-all duration-300 hover:-translate-y-1 hover:border-white/20`}
              >
                <div className="mb-5 flex items-center justify-between">
                  <span className="grid h-11 w-11 place-items-center rounded-xl border border-white/10 bg-gradient-to-br from-white/15 to-white/[0.02] transition-transform duration-300 group-hover:scale-110">
                    <feature.icon
                      className="h-5 w-5 text-[#7DE3E0]"
                      strokeWidth={1.75}
                    />
                  </span>
                  <span
                    className={`${mono.className} text-[10px] tracking-[0.18em] text-[#E7F2F0]/30`}
                  >
                    {feature.label}
                  </span>
                </div>
                <h3 className="mb-2 text-lg font-semibold">{feature.title}</h3>
                <p className="text-sm leading-relaxed text-[#E7F2F0]/55">
                  {feature.body}
                </p>
              </article>
            ))}
          </div>
        </section>

        {/* ── Spatial showcase ────────────────────────────────── */}
        <section id="spaces" className="border-y border-white/[0.06]">
          <div className="mx-auto grid max-w-6xl gap-14 px-5 py-20 md:grid-cols-2 md:items-center md:px-8 md:py-28">
            <div>
              <p
                className={`${mono.className} mb-4 text-xs tracking-[0.22em] text-[#7DE3E0]`}
              >
                THE SOUNDSTAGE
              </p>
              <h2
                className={`${display.className} text-4xl font-medium leading-[1.02] md:text-5xl`}
              >
                A room you can <em className="text-[#7DE3E0]">stand inside.</em>
              </h2>
              <p className="mt-6 max-w-md text-base leading-relaxed text-[#E7F2F0]/60">
                Nocturne places every source on a real stage around the
                listener. The rings show a live mix — five instruments
                positioned in space, sweeping past your ears as the track plays.
                Move, and the geometry moves with you.
              </p>
              <ul className="mt-8 space-y-3">
                {ENGINE_POINTS.map((point) => (
                  <li
                    key={point}
                    className="flex items-start gap-3 text-sm text-[#E7F2F0]/75"
                  >
                    <span className="mt-0.5 grid h-5 w-5 shrink-0 place-items-center rounded-full border border-[#7DE3E0]/30 bg-[#7DE3E0]/10">
                      <Check
                        className="h-3 w-3 text-[#7DE3E0]"
                        strokeWidth={2.5}
                      />
                    </span>
                    {point}
                  </li>
                ))}
              </ul>
            </div>

            {/* CSS-drawn soundstage */}
            <div className="relative">
              <div
                aria-hidden
                className="absolute inset-6 rounded-full bg-[#7DE3E0]/10 blur-3xl"
              />
              <div
                className={`relative mx-auto aspect-square w-full max-w-md rounded-full ${GLASS_SOFT}`}
              >
                <div className="absolute inset-0 overflow-hidden rounded-full">
                  {/* sonar sweep */}
                  <div
                    className="noc-sonar absolute inset-0"
                    style={{
                      background:
                        "conic-gradient(from 0deg, transparent 0deg, rgba(125,227,224,0.22) 42deg, transparent 80deg)",
                    }}
                  />
                </div>
                {/* rings */}
                <div
                  aria-hidden
                  className="absolute inset-0 grid place-items-center"
                >
                  {[92, 68, 44, 20].map((size) => (
                    <div
                      key={size}
                      className="absolute rounded-full border border-white/10"
                      style={{ width: `${size}%`, height: `${size}%` }}
                    />
                  ))}
                  {/* axis hairlines */}
                  <div className="absolute h-[92%] w-px bg-white/[0.06]" />
                  <div className="absolute h-px w-[92%] bg-white/[0.06]" />
                </div>
                {/* listener */}
                <div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 text-center">
                  <span className="grid h-9 w-9 place-items-center rounded-full border border-[#7DE3E0]/40 bg-[#7DE3E0]/15 shadow-[0_0_30px_6px_rgba(125,227,224,0.4)]">
                    <Compass className="h-4 w-4 text-[#7DE3E0]" />
                  </span>
                  <span
                    className={`${mono.className} mt-1.5 block text-[9px] tracking-[0.14em] text-[#E7F2F0]/45`}
                  >
                    YOU
                  </span>
                </div>
                {/* sources */}
                {STAGE_SOURCES.map((source) => (
                  <div
                    key={source.label}
                    className="absolute -translate-x-1/2 -translate-y-1/2"
                    style={{ top: source.top, left: source.left }}
                  >
                    <span className="relative flex items-center justify-center">
                      <span
                        className="noc-ping absolute h-3 w-3 rounded-full bg-[#7DE3E0]/50"
                        style={{ animationDelay: source.delay }}
                      />
                      <span className="relative h-2.5 w-2.5 rounded-full bg-[#7DE3E0] shadow-[0_0_14px_3px_rgba(125,227,224,0.6)]" />
                    </span>
                    <span
                      className={`${mono.className} mt-1.5 block whitespace-nowrap text-center text-[9px] tracking-[0.1em] text-[#E7F2F0]/60`}
                    >
                      {source.label}
                    </span>
                  </div>
                ))}
              </div>
            </div>
          </div>
        </section>

        {/* ── Metrics ─────────────────────────────────────────── */}
        <section className="mx-auto max-w-6xl px-5 py-16 md:px-8 md:py-20">
          <div
            className={`grid gap-px overflow-hidden rounded-2xl ${GLASS_SOFT} sm:grid-cols-2 lg:grid-cols-4`}
          >
            {METRICS.map((metric) => (
              <div key={metric.value} className="bg-white/[0.01] p-7">
                <p
                  className={`${display.className} text-4xl font-medium tracking-tight text-[#7DE3E0] md:text-5xl`}
                >
                  {metric.value}
                </p>
                <p className="mt-3 text-[13px] leading-snug text-[#E7F2F0]/55">
                  {metric.label}
                </p>
              </div>
            ))}
          </div>
        </section>

        {/* ── Testimonials ────────────────────────────────────── */}
        <section className="mx-auto max-w-6xl px-5 py-20 md:px-8 md:py-28">
          <p
            className={`${mono.className} mb-12 text-xs tracking-[0.22em] text-[#7DE3E0]`}
          >
            FROM THE STUDIOS
          </p>
          <div className="grid gap-6 md:grid-cols-3">
            {TESTIMONIALS.map((testimonial) => (
              <figure
                key={testimonial.name}
                className={`flex flex-col rounded-2xl ${GLASS_SOFT} p-7`}
              >
                <Quote
                  className="h-6 w-6 text-[#7DE3E0]/50"
                  fill="currentColor"
                  strokeWidth={0}
                />
                <blockquote
                  className={`${display.className} mt-4 flex-1 text-xl italic leading-[1.35] text-[#E7F2F0]/90`}
                >
                  {testimonial.quote}
                </blockquote>
                <figcaption className="mt-6 border border-white/10 pt-4">
                  <p className="text-sm font-semibold">{testimonial.name}</p>
                  <p
                    className={`${mono.className} mt-1 text-[11px] tracking-wide text-[#E7F2F0]/40`}
                  >
                    {testimonial.role}
                  </p>
                </figcaption>
              </figure>
            ))}
          </div>
        </section>

        {/* ── Pricing ─────────────────────────────────────────── */}
        <section
          id="pricing"
          className="mx-auto max-w-6xl px-5 py-20 md:px-8 md:py-28"
        >
          <div className="mb-12 flex flex-wrap items-end justify-between gap-6">
            <div>
              <p
                className={`${mono.className} mb-4 text-xs tracking-[0.22em] text-[#7DE3E0]`}
              >
                PRICING
              </p>
              <h2
                className={`${display.className} text-4xl font-medium leading-[1.02] md:text-5xl`}
              >
                Free to listen.{" "}
                <em className="text-[#7DE3E0]">Fair to create.</em>
              </h2>
            </div>
            <div
              className={`${mono.className} flex items-center gap-3 text-xs`}
            >
              <span className={yearly ? "text-[#E7F2F0]/40" : "text-[#E7F2F0]"}>
                MONTHLY
              </span>
              <button
                type="button"
                role="switch"
                aria-checked={yearly}
                onClick={() => setYearly(!yearly)}
                className="relative h-6 w-11 rounded-full border border-white/20 bg-white/5 transition-colors"
              >
                <span
                  className={`absolute top-1/2 h-4 w-4 -translate-y-1/2 rounded-full bg-[#7DE3E0] transition-all ${
                    yearly ? "left-[calc(100%-1.25rem)]" : "left-1"
                  }`}
                />
              </button>
              <span className={yearly ? "text-[#E7F2F0]" : "text-[#E7F2F0]/40"}>
                YEARLY <span className="text-[#7DE3E0]">-17%</span>
              </span>
            </div>
          </div>

          <div className="grid gap-6 lg:grid-cols-3">
            {PLANS.map((plan) => (
              <article
                key={plan.name}
                className={`relative flex flex-col rounded-2xl p-8 ${
                  plan.featured ? `${GLASS} border-[#7DE3E0]/30` : GLASS_SOFT
                }`}
              >
                {plan.featured && (
                  <span
                    className={`${mono.className} absolute -top-3 left-8 inline-flex items-center gap-1.5 rounded-full bg-gradient-to-r from-[#7DE3E0] to-emerald-300 px-3 py-1 text-[10px] font-medium tracking-[0.12em] text-[#04191A]`}
                  >
                    <Sparkles className="h-3 w-3" />
                    MOST LOVED
                  </span>
                )}
                <h3
                  className={`${mono.className} mb-2 text-sm tracking-[0.16em]`}
                >
                  {plan.name.toUpperCase()}
                </h3>
                <p className="mb-6 min-h-10 text-sm leading-relaxed text-[#E7F2F0]/50">
                  {plan.blurb}
                </p>
                <div className="mb-8">
                  {plan.monthly === null ? (
                    <span
                      className={`${display.className} text-4xl italic text-[#E7F2F0]`}
                    >
                      Custom
                    </span>
                  ) : (
                    <span className="flex items-end gap-1">
                      <span className="mt-2 self-start text-lg text-[#E7F2F0]/50">
                        $
                      </span>
                      <span
                        className={`${mono.className} text-5xl font-medium leading-none tracking-tight`}
                      >
                        {yearly ? plan.yearly : plan.monthly}
                      </span>
                      <span
                        className={`${mono.className} mb-1 text-sm text-[#E7F2F0]/45`}
                      >
                        /mo
                      </span>
                    </span>
                  )}
                </div>
                <ul className="mb-10 flex-1 space-y-3">
                  {plan.features.map((feature) => (
                    <li
                      key={feature}
                      className="flex items-start gap-2.5 text-sm text-[#E7F2F0]/75"
                    >
                      <Check
                        className="mt-0.5 h-4 w-4 shrink-0 text-[#7DE3E0]"
                        strokeWidth={2.5}
                      />
                      {feature}
                    </li>
                  ))}
                </ul>
                <a
                  href="#top"
                  className={`inline-flex items-center justify-center gap-2 rounded-full px-5 py-3 text-sm font-semibold transition-all ${
                    plan.featured
                      ? "bg-gradient-to-r from-[#7DE3E0] to-emerald-300 text-[#04191A] shadow-[0_12px_36px_-12px_rgba(125,227,224,0.6)] hover:-translate-y-0.5"
                      : "border border-white/15 bg-white/5 text-[#E7F2F0] hover:bg-white/10"
                  }`}
                >
                  {plan.cta}
                </a>
              </article>
            ))}
          </div>
        </section>

        {/* ── FAQ ─────────────────────────────────────────────── */}
        <section
          id="faq"
          className="mx-auto grid max-w-6xl gap-12 px-5 py-20 md:grid-cols-[0.8fr_1.2fr] md:px-8 md:py-28"
        >
          <div>
            <p
              className={`${mono.className} mb-4 text-xs tracking-[0.22em] text-[#7DE3E0]`}
            >
              QUESTIONS
            </p>
            <h2
              className={`${display.className} text-4xl font-medium leading-[1.02] md:text-5xl`}
            >
              Asked, <em className="text-[#7DE3E0]">answered.</em>
            </h2>
            <p className="mt-5 max-w-xs text-sm leading-relaxed text-[#E7F2F0]/50">
              Anything else and a real engineer answers the shared inbox within
              a business day.
            </p>
          </div>
          <div className="space-y-3">
            {FAQS.map((faq, index) => {
              const open = openFaq === index;
              return (
                <div key={faq.q} className={`rounded-2xl ${GLASS_SOFT} px-5`}>
                  <button
                    type="button"
                    onClick={() => setOpenFaq(open ? null : index)}
                    aria-expanded={open}
                    className="flex w-full items-center justify-between gap-4 py-5 text-left"
                  >
                    <span className="text-base font-medium">{faq.q}</span>
                    <span className="grid h-7 w-7 shrink-0 place-items-center rounded-full border border-white/10 bg-white/5 text-[#7DE3E0]">
                      {open ? (
                        <Minus className="h-4 w-4" />
                      ) : (
                        <Plus className="h-4 w-4" />
                      )}
                    </span>
                  </button>
                  {open && (
                    <p className="pb-6 pr-6 text-sm leading-relaxed text-[#E7F2F0]/55">
                      {faq.a}
                    </p>
                  )}
                </div>
              );
            })}
          </div>
        </section>

        {/* ── Final CTA ───────────────────────────────────────── */}
        <section className="relative overflow-hidden">
          <div
            aria-hidden
            className="pointer-events-none absolute inset-0"
            style={{
              backgroundImage:
                "radial-gradient(ellipse 60% 80% at 50% 120%, rgba(125,227,224,0.3), transparent 62%)," +
                "radial-gradient(ellipse 50% 60% at 20% 0%, rgba(16,185,129,0.18), transparent 60%)",
            }}
          />
          <div className="relative mx-auto max-w-4xl px-5 py-24 text-center md:px-8 md:py-32">
            <p
              className={`${mono.className} mb-6 text-xs tracking-[0.22em] text-[#7DE3E0]`}
            >
              PRESS PLAY
            </p>
            <h2
              className={`${display.className} mx-auto max-w-2xl text-4xl font-medium leading-[1.02] md:text-6xl`}
            >
              Put on your headphones.
              <br />
              <em className="text-[#7DE3E0]">Step inside the mix.</em>
            </h2>
            <div className="mt-10 flex flex-wrap items-center justify-center gap-4">
              <a
                href="#pricing"
                className="group inline-flex items-center gap-2 rounded-full bg-gradient-to-r from-[#7DE3E0] to-emerald-300 px-7 py-4 text-sm font-semibold text-[#04191A] shadow-[0_16px_50px_-14px_rgba(125,227,224,0.7)] transition-transform hover:-translate-y-0.5"
              >
                Open Nocturne free
                <ArrowRight className="h-4 w-4 transition-transform group-hover:translate-x-0.5" />
              </a>
              <span
                className={`${mono.className} text-[11px] tracking-wide text-[#E7F2F0]/35`}
              >
                LISTENER PLAN, FREE FOREVER
              </span>
            </div>
          </div>
        </section>

        {/* ── Footer ──────────────────────────────────────────── */}
        <footer className="border border-white/[0.06]">
          <div className="mx-auto max-w-6xl px-5 py-16 md:px-8">
            <div className="grid gap-10 md:grid-cols-[1.3fr_repeat(4,0.7fr)]">
              <div>
                <a href="#top" className="flex items-center gap-2.5">
                  <span className="grid h-8 w-8 place-items-center rounded-xl border border-white/15 bg-gradient-to-br from-[#7DE3E0]/30 to-emerald-400/10">
                    <Moon className="h-4 w-4 text-[#7DE3E0]" strokeWidth={2} />
                  </span>
                  <span className="text-lg font-semibold tracking-tight">
                    Nocturne
                  </span>
                </a>
                <p className="mt-5 max-w-[16rem] text-sm leading-relaxed text-[#E7F2F0]/40">
                  Spatial audio for people who do their best listening after
                  dark.
                </p>
              </div>
              {FOOTER_COLS.map((col) => (
                <nav key={col.title}>
                  <p
                    className={`${mono.className} mb-4 text-[11px] tracking-[0.18em] text-[#E7F2F0]/35`}
                  >
                    {col.title.toUpperCase()}
                  </p>
                  {col.links.map((link) => (
                    <a
                      key={link}
                      href="#top"
                      className="block py-1.5 text-sm text-[#E7F2F0]/55 transition-colors hover:text-[#E7F2F0]"
                    >
                      {link}
                    </a>
                  ))}
                </nav>
              ))}
            </div>
            <div className="mt-14 flex flex-wrap items-center justify-between gap-4 border border-white/[0.06] pt-6">
              <p className={`${mono.className} text-[11px] text-[#E7F2F0]/30`}>
                &copy; 2026 NOCTURNE AUDIO
              </p>
              <p
                className={`${mono.className} flex items-center gap-2 text-[11px] tracking-[0.14em] text-[#E7F2F0]/30`}
              >
                <span className="noc-pulse h-1.5 w-1.5 rounded-full bg-[#7DE3E0]" />
                MASTERED IN THE DARK
              </p>
            </div>
          </div>
        </footer>
      </div>
    </div>
  );
}

查看关联风格