diff --git a/src/content/home.ts b/src/content/home.ts
index 32735d6..b665820 100644
--- a/src/content/home.ts
+++ b/src/content/home.ts
@@ -73,7 +73,7 @@ export type HomePageContent = {
eyebrow: string;
title: string;
body: string;
- items: readonly { caption: string; image: ImageContent }[];
+ items: readonly { caption: string; description: string; image: ImageContent }[];
};
privacy: {
icon: IconName;
@@ -113,18 +113,18 @@ export const homeContent = {
hero: {
announcement: `${siteContent.brand.name} ${siteContent.release.badge} · Free on ${siteContent.release.platform}`,
title: {
- text: "Read at the speed of",
- emphasis: "thought.",
+ text: "A little more space to",
+ emphasis: "read.",
},
lede:
- "Bring your own books and documents. Read with full context, then shift into adaptive RSVP or Bionic Reading whenever you want more momentum.",
+ "Your books. Your pace. A thoughtful Android reader that lets you settle into a page, find your focus, and keep the world on pause.",
actions: {
learnMore: { label: "See how it works", href: "#experience", icon: "arrow" },
support: { ...siteContent.actions.support, label: "Buy me a coffee" },
},
proofAriaLabel: "Kairo highlights",
proofItems: [
- { icon: "check", label: "10 format families" },
+ { icon: "check", label: "Free to use" },
{ icon: "shield", label: "Local-first" },
{ icon: "github", label: "Open source" },
],
@@ -133,28 +133,28 @@ export const homeContent = {
{
position: "back",
image: {
- src: "/assets/screens/library.webp",
+ src: "/assets/screens/library-2026.webp",
alt: "Kairo library with imported books, progress and bookmarks",
- width: 1080,
- height: 1920,
+ width: 810,
+ height: 1440,
},
},
{
position: "middle",
image: {
- src: "/assets/screens/reader-controls.webp",
- alt: "Kairo reader with chapter text and reading controls",
- width: 1080,
- height: 1920,
+ src: "/assets/screens/linen-2026.webp",
+ alt: "Kairo reader in the warm linen theme",
+ width: 810,
+ height: 1440,
},
},
{
position: "front",
image: {
- src: "/assets/screens/rsvp.webp",
+ src: "/assets/screens/rsvp-2026.webp",
alt: "Kairo RSVP screen with a focused word and playback controls",
- width: 1080,
- height: 1920,
+ width: 810,
+ height: 1440,
},
},
],
@@ -174,7 +174,7 @@ export const homeContent = {
experience: {
heading: {
eyebrow: "One continuous reading flow",
- title: "Change how you read. Not where you are.",
+ title: "Find your reading rhythm.",
body:
"Kairo keeps the library, the page and your accelerated reading modes connected. Pick the experience that fits the next passage.",
},
@@ -188,10 +188,10 @@ export const homeContent = {
visual: {
kind: "phone",
image: {
- src: "/assets/screens/reader-rsvp-dock.webp",
- alt: "Kairo standard reader with the RSVP launch control",
- width: 1080,
- height: 1920,
+ src: "/assets/screens/linen-2026.webp",
+ alt: "Alice’s Adventures in Wonderland in Kairo’s warm linen reading theme",
+ width: 810,
+ height: 1440,
},
},
},
@@ -204,10 +204,10 @@ export const homeContent = {
visual: {
kind: "phone",
image: {
- src: "/assets/screens/rsvp.webp",
- alt: "Kairo RSVP mode showing the word seldom at a stable focal point",
- width: 1080,
- height: 1920,
+ src: "/assets/screens/rsvp-2026.webp",
+ alt: "Kairo RSVP mode with a focused word and surrounding sentence context",
+ width: 810,
+ height: 1440,
},
},
},
@@ -229,7 +229,7 @@ export const homeContent = {
formats: {
heading: {
eyebrow: `${siteContent.brand.name} ${siteContent.release.badge} format support`,
- title: "Your reading list is bigger than one file type.",
+ title: "A home for your whole reading list.",
body:
"Choose a supported file from Android storage. Kairo detects it automatically, builds a local library entry and opens the same focused reading toolkit.",
},
@@ -250,16 +250,16 @@ export const homeContent = {
},
tuning: {
eyebrow: "Power when you want it",
- title: "Simple on the surface. Remarkably tuneable underneath.",
+ title: "Make yourself comfortable.",
body:
"Start with a profile, press play and read. When you want finer control, Kairo exposes the pacing, typography, brightness and focus settings that actually change how a session feels.",
profilesAriaLabel: "Built-in RSVP profiles",
profiles: ["Balanced", "Chill", "Narrative", "Focus", "Flow", "Sprint", "Study"],
image: {
- src: `/assets/screens/rsvp-settings.webp?v=${siteContent.release.version}`,
+ src: "/assets/screens/speed-2026.webp",
alt: "Kairo RSVP settings with profile and timing controls",
- width: 1080,
- height: 1920,
+ width: 810,
+ height: 1440,
},
callouts: [
{ label: "Estimated pace", value: "811 WPM" },
@@ -314,45 +314,69 @@ export const homeContent = {
gallery: {
eyebrow: "Inside Kairo",
title: "A reading interface that gets out of the way.",
- body: "Near-black surfaces, restrained colour and controls that appear when they are useful.",
+ body: "From your first import to the last page. Explore the little details that make Kairo feel like your own reading space.",
items: [
{
- caption: "Library",
- image: {
- src: "/assets/screens/library.webp",
- alt: "Kairo library showing book covers, progress and navigation tabs",
- width: 1080,
- height: 1920,
- },
+ "caption": "Your library",
+ "description": "All your books, with a place for every next chapter.",
+ "image": {
+ "src": "/assets/screens/library-2026.webp",
+ "alt": "Kairo: Your library",
+ "width": 810,
+ "height": 1440
+ }
},
{
- caption: "Settings",
- image: {
- src: "/assets/screens/settings.webp",
- alt: "Kairo settings home with RSVP, reader, focus and startup settings",
- width: 333,
- height: 592,
- },
+ "caption": "The reading room",
+ "description": "Warm linen, comfortable type, and room to lose yourself in a book.",
+ "image": {
+ "src": "/assets/screens/linen-2026.webp",
+ "alt": "Kairo: The reading room",
+ "width": 810,
+ "height": 1440
+ }
},
{
- caption: "Reader themes",
- image: {
- src: "/assets/screens/reader-settings.webp",
- alt: "Kairo reader settings with font, theme, brightness and scrolling options",
- width: 1080,
- height: 1920,
- },
+ "caption": "Find your focus",
+ "description": "One focal point. Your own pace. The surrounding words, still in reach.",
+ "image": {
+ "src": "/assets/screens/rsvp-2026.webp",
+ "alt": "Kairo: Find your focus",
+ "width": 810,
+ "height": 1440
+ }
},
{
- caption: "Reader controls",
- image: {
- src: "/assets/screens/reader-controls.webp",
- alt: "Kairo book reader with bookmarks, focus mode and table of contents controls",
- width: 1080,
- height: 1920,
- },
+ "caption": "Make it yours",
+ "description": "Tune the type, colours, and brightness to the way you like to read.",
+ "image": {
+ "src": "/assets/screens/themes-2026.webp",
+ "alt": "Kairo: Make it yours",
+ "width": 810,
+ "height": 1440
+ }
},
- ],
+ {
+ "caption": "Keep your place",
+ "description": "Bookmarks and reading tools, always close at hand.",
+ "image": {
+ "src": "/assets/screens/tools-2026.webp",
+ "alt": "Kairo: Keep your place",
+ "width": 810,
+ "height": 1440
+ }
+ },
+ {
+ "caption": "Bring your books",
+ "description": "Start with the ebooks and documents you already own.",
+ "image": {
+ "src": "/assets/screens/import-2026.webp",
+ "alt": "Kairo: Bring your books",
+ "width": 810,
+ "height": 1440
+ }
+ }
+],
},
privacy: {
icon: "shield",
diff --git a/src/lib/parallax.ts b/src/lib/parallax.ts
new file mode 100644
index 0000000..73bd1e0
--- /dev/null
+++ b/src/lib/parallax.ts
@@ -0,0 +1,88 @@
+/** Scroll-driven depth without a CSS timeline dependency or a continuous RAF loop. */
+export function mountParallax(root: HTMLElement): () => void {
+ const motion = window.matchMedia("(prefers-reduced-motion: reduce)");
+ // Explicit local preview only; production always honors the OS preference.
+ const previewMotion = import.meta.env.DEV && new URLSearchParams(window.location.search).get("motion") === "on";
+ const reducedMotion = () => motion.matches && !previewMotion;
+ const specs = [
+ { selector: ".hero-phone-mid", anchor: ".hero-visual", speed: 0.2, limit: 80, hero: true },
+ { selector: ".hero-phone-front", anchor: ".hero-visual", speed: -0.32, limit: 128, hero: true },
+ { selector: ".tuning-visual .phone-frame", anchor: ".tuning-visual", speed: -0.16, limit: 64, hero: false },
+ { selector: ".gallery-preview", anchor: ".gallery-layout", speed: -0.12, limit: 48, hero: false },
+ ];
+ const layers = specs.flatMap((spec) => {
+ const element = root.querySelector
(spec.selector);
+ const anchor = root.querySelector(spec.anchor);
+ return element && anchor ? [{ ...spec, element, anchor, top: 0, height: 0, previous: element.style.translate }] : [];
+ });
+ let frame = 0;
+ let dirty = true;
+ let disposed = false;
+ let viewport = 0;
+ let mobile = false;
+
+ const update = () => {
+ frame = 0;
+ if (disposed || reducedMotion()) return;
+ const scroll = window.scrollY;
+ // Read stationary anchors only on layout changes, never on ordinary scroll frames.
+ if (dirty) {
+ viewport = window.innerHeight;
+ mobile = window.innerWidth <= 820;
+ for (const layer of layers) {
+ const rect = layer.anchor.getBoundingClientRect();
+ layer.top = rect.top + scroll;
+ layer.height = rect.height;
+ }
+ dirty = false;
+ }
+ for (const layer of layers) {
+ const origin = layer.hero
+ ? Math.max(0, layer.top - viewport * 0.55)
+ : layer.top + layer.height / 2 - viewport / 2;
+ const distance = layer.hero ? Math.max(0, scroll - origin) : scroll - origin;
+ const strength = mobile ? 0.55 : 1;
+ const offset = Math.max(-layer.limit, Math.min(layer.limit, distance * layer.speed)) * strength;
+ // Independent translation preserves the existing rotation/centering transforms.
+ const value = `0 ${offset.toFixed(2)}px`;
+ if (layer.element.style.translate !== value) layer.element.style.translate = value;
+ }
+ };
+ const schedule = () => {
+ if (!disposed && !reducedMotion() && !frame) frame = window.requestAnimationFrame(update);
+ };
+ const measure = () => {
+ dirty = true;
+ schedule();
+ };
+ const reset = () => {
+ window.cancelAnimationFrame(frame);
+ frame = 0;
+ for (const layer of layers) layer.element.style.translate = layer.previous;
+ };
+ const syncMotion = () => {
+ window.removeEventListener("scroll", schedule);
+ if (reducedMotion()) reset();
+ else {
+ window.addEventListener("scroll", schedule, { passive: true });
+ measure();
+ }
+ };
+ const observer = new ResizeObserver(measure);
+ observer.observe(root);
+ for (const layer of layers) observer.observe(layer.anchor);
+ window.addEventListener("resize", measure, { passive: true });
+ root.addEventListener("load", measure, true);
+ motion.addEventListener("change", syncMotion);
+ syncMotion();
+
+ return () => {
+ disposed = true;
+ reset();
+ observer.disconnect();
+ window.removeEventListener("scroll", schedule);
+ window.removeEventListener("resize", measure);
+ root.removeEventListener("load", measure, true);
+ motion.removeEventListener("change", syncMotion);
+ };
+}
diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx
index f5fe32e..8d9d2bc 100644
--- a/src/pages/HomePage.tsx
+++ b/src/pages/HomePage.tsx
@@ -1,3 +1,5 @@
+import { onCleanup, onMount } from "solid-js";
+import { mountParallax } from "../lib/parallax";
import { CoverageSection } from "../components/home/CoverageSection";
import { FaqSection } from "../components/home/FaqSection";
import { FeaturesSection } from "../components/home/FeaturesSection";
@@ -11,14 +13,17 @@ import { ReadingExperienceSection } from "../components/home/ReadingExperienceSe
import { TuningSection } from "../components/home/TuningSection";
export function HomePage() {
+ let main!: HTMLElement;
+ onMount(() => onCleanup(mountParallax(main)));
+
return (
-
+
-
-
+
+
diff --git a/src/styles.css b/src/styles.css
index 3064774..206f3b6 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -4,19 +4,19 @@
:root {
color-scheme: light;
- --bg: #f4f6f3;
- --bg-soft: #e9eeeb;
+ --bg: #f6f3ec;
+ --bg-soft: #ece8df;
--surface: rgba(255, 255, 255, 0.72);
--surface-solid: #ffffff;
- --surface-strong: #dfe7e3;
- --text: #0a1718;
- --text-soft: #526365;
- --text-faint: #758486;
+ --surface-strong: #e2e4e8;
+ --text: #252a30;
+ --text-soft: #61656a;
+ --text-faint: #72767a;
--line: rgba(10, 23, 24, 0.12);
--line-strong: rgba(10, 23, 24, 0.21);
- --accent: #089fbb;
- --accent-two: #30c98d;
- --accent-soft: #d9f4f2;
+ --accent: #4c648d;
+ --accent-two: #58735e;
+ --accent-soft: #e2e8f1;
--glow: rgba(15, 178, 190, 0.18);
--shadow: 0 32px 90px rgba(8, 31, 32, 0.15);
--phone-shadow: 0 35px 75px rgba(5, 18, 19, 0.25);
@@ -27,19 +27,19 @@
:root[data-theme="dark"] {
color-scheme: dark;
- --bg: #071011;
- --bg-soft: #0b1719;
+ --bg: #15191f;
+ --bg-soft: #1c2129;
--surface: rgba(16, 29, 31, 0.72);
- --surface-solid: #0f1b1d;
- --surface-strong: #142326;
- --text: #edf8f6;
- --text-soft: #9eb3b5;
- --text-faint: #718789;
+ --surface-solid: #20262e;
+ --surface-strong: #2a323e;
+ --text: #f0eee7;
+ --text-soft: #b1b5be;
+ --text-faint: #9299a5;
--line: rgba(207, 240, 238, 0.1);
--line-strong: rgba(207, 240, 238, 0.2);
- --accent: #35c9e6;
- --accent-two: #52e0a4;
- --accent-soft: #112d31;
+ --accent: #b5c6e7;
+ --accent-two: #b4c5af;
+ --accent-soft: #283345;
--glow: rgba(32, 198, 211, 0.2);
--shadow: 0 32px 90px rgba(0, 0, 0, 0.36);
--phone-shadow: 0 42px 100px rgba(0, 0, 0, 0.58);
@@ -305,7 +305,7 @@ img {
.final-cta h2,
.editorial-page h1 {
margin: 0;
- font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, ui-serif, serif;
+ font-family: "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
font-weight: 500;
letter-spacing: -0.052em;
}
@@ -624,7 +624,7 @@ img {
padding: 1.35rem 1rem;
border-right: 1px solid var(--line);
color: var(--text-soft);
- font-family: "Iowan Old Style", Georgia, serif;
+ font-family: "Palatino Linotype", Palatino, Georgia, serif;
font-size: clamp(1rem, 1.7vw, 1.25rem);
font-style: italic;
text-align: center;
@@ -704,7 +704,7 @@ img {
.mode-copy h3,
.bento-card h3 {
margin: 0.75rem 0 0;
- font-family: "Iowan Old Style", Georgia, serif;
+ font-family: "Palatino Linotype", Palatino, Georgia, serif;
font-size: clamp(2rem, 3vw, 2.75rem);
font-weight: 500;
letter-spacing: -0.04em;
@@ -759,12 +759,12 @@ img {
display: block;
width: 42%;
height: 100%;
- background: linear-gradient(90deg, #39c7e5, #52e0a4);
+ background: linear-gradient(90deg, #39c7e5, #b4c5af);
}
.bionic-sample p {
margin: 0;
- font-family: "Iowan Old Style", Georgia, serif;
+ font-family: "Palatino Linotype", Palatino, Georgia, serif;
font-size: clamp(1.45rem, 2.3vw, 2rem);
line-height: 1.5;
}
@@ -796,7 +796,7 @@ img {
width: 48px;
height: 48px;
background: #a9dce5;
- color: #071011;
+ color: #15191f;
}
.bionic-controls svg {
@@ -870,7 +870,7 @@ img {
.format-card strong {
margin: auto 0 0.15rem;
- font-family: "Iowan Old Style", Georgia, serif;
+ font-family: "Palatino Linotype", Palatino, Georgia, serif;
font-size: clamp(1.4rem, 2.5vw, 2.2rem);
font-weight: 500;
letter-spacing: -0.04em;
@@ -1086,13 +1086,13 @@ img {
.orp-demo > span {
color: rgba(222, 241, 239, 0.22);
- font-family: "Iowan Old Style", Georgia, serif;
+ font-family: "Palatino Linotype", Palatino, Georgia, serif;
font-size: 1.25rem;
}
.orp-demo strong {
color: #d8e7e6;
- font-family: "Iowan Old Style", Georgia, serif;
+ font-family: "Palatino Linotype", Palatino, Georgia, serif;
font-size: clamp(2.4rem, 5vw, 4.25rem);
font-weight: 500;
}
@@ -1164,7 +1164,7 @@ img {
background:
radial-gradient(circle at 15% 20%, rgba(52, 204, 231, 0.15), transparent 28rem),
radial-gradient(circle at 90% 100%, rgba(80, 226, 164, 0.1), transparent 28rem),
- #071011;
+ #15191f;
}
.privacy-grid {
@@ -1276,7 +1276,7 @@ img {
justify-content: space-between;
gap: 1.5rem;
cursor: pointer;
- font-family: "Iowan Old Style", Georgia, serif;
+ font-family: "Palatino Linotype", Palatino, Georgia, serif;
font-size: clamp(1.25rem, 2.2vw, 1.75rem);
font-weight: 500;
letter-spacing: -0.025em;
@@ -1360,7 +1360,7 @@ img {
.coverage-grid h3 {
margin: 0.35rem 0 0;
- font-family: "Iowan Old Style", Georgia, serif;
+ font-family: "Palatino Linotype", Palatino, Georgia, serif;
font-size: 1.65rem;
font-weight: 500;
letter-spacing: -0.035em;
@@ -1415,7 +1415,7 @@ img {
.site-footer {
padding: 4.5rem 0 1.5rem;
border-top: 1px solid var(--line);
- background: #071011;
+ background: #15191f;
color: #eaf7f5;
}
@@ -1428,7 +1428,7 @@ img {
.footer-grid > div:first-child > p {
margin: 1rem 0 0;
color: #7e9394;
- font-family: "Iowan Old Style", Georgia, serif;
+ font-family: "Palatino Linotype", Palatino, Georgia, serif;
font-style: italic;
}
@@ -1566,7 +1566,7 @@ img {
.contact-card h2,
.privacy-summary h2 {
margin: 0;
- font-family: "Iowan Old Style", Georgia, serif;
+ font-family: "Palatino Linotype", Palatino, Georgia, serif;
font-size: clamp(2rem, 4vw, 3.2rem);
font-weight: 500;
letter-spacing: -0.04em;
@@ -2146,3 +2146,123 @@ img {
transition-duration: 0.01ms !important;
}
}
+
+/* Reading room: quiet surfaces, editorial type, and real app previews. */
+:root { --glow: transparent; --shadow: 0 18px 50px #17202d0c; }
+:root[data-theme="dark"] { --glow: transparent; --surface: #20262e; }
+.site-shell { background: var(--bg); }
+.content-wrap { width: min(100% - 5rem, 1200px); }
+.section-pad { padding-block: clamp(5rem, 8vw, 8rem); }
+section[id] { scroll-margin-top: 100px; }
+:focus-visible { outline: 2px solid var(--accent); outline-offset: 5px; }
+.site-header { padding: 0 2.5rem; background: color-mix(in srgb, var(--bg) 94%, transparent); backdrop-filter: blur(18px); }
+.nav-wrap { width: min(100%, 1200px); min-height: 84px; padding: 0; border-width: 0 0 1px; border-radius: 0; background: transparent; box-shadow: none; backdrop-filter: none; }
+.brand { font-size: 1.5rem; letter-spacing: -.06em; }
+.brand img { width: 32px; height: 32px; }
+.version-pill { font-size: .6rem; letter-spacing: .02em; }
+.nav-links .nav-play, .icon-button { border-radius: 999px; }
+.hero { min-height: auto; padding-top: 10rem; padding-bottom: 2rem; }
+.hero-grid { min-height: 610px; grid-template-columns: 1fr 1fr; gap: 4rem; }
+.hero-copy > .eyebrow { border: 0; padding: 0; background: none; font-size: .64rem; letter-spacing: .12em; }
+.hero h1 { margin-top: 2rem; font-size: clamp(4.5rem, 7.8vw, 7rem); line-height: .98; letter-spacing: -.065em; }
+.hero h1 span { color: var(--accent); background: none; }
+.hero-lede { max-width: 440px; font-size: 1.05rem; line-height: 1.8; }
+.hero-actions { gap: .75rem; }
+.play-button { min-height: 58px; border: 0; border-radius: 999px; padding: .6rem 1.5rem .6rem .75rem; background: var(--text); color: var(--bg); box-shadow: none; }
+.play-button:hover { box-shadow: 0 8px 22px #17202d20; }
+.play-icon { background: transparent; }
+.button-secondary, .button-primary { border-radius: 999px; font-size: .8rem; }
+.hero-actions .button-secondary { background: transparent; border-color: transparent; padding-inline: .5rem; }
+.hero-proof { margin-top: 1.75rem; gap: 1.2rem; font-size: .68rem; color: var(--text-soft); }
+.hero-visual { min-height: 610px; border-radius: 48% 48% 8px 8px; background: var(--bg-soft); perspective: none; }
+.visual-kicker { position: absolute; top: 2.5rem; width: 100%; text-align: center; font-family: Georgia, serif; font-style: italic; font-size: .95rem; color: var(--text-soft); }
+.hero-phone { width: 48%; border-radius: 21px; }
+.hero-phone-mid { top: 105px; left: 7%; transform: rotate(-7deg); }
+.hero-phone-front { top: 156px; right: 5%; bottom: auto; width: 48%; transform: rotate(7deg); }
+.phone-frame { border: 5px solid #282d35; box-shadow: 0 20px 35px #121b2926; }
+.phone-frame::after, .phone-speaker { display: none; }
+.scroll-cue { margin-top: 3rem; }
+.intro-strip { background: transparent; }
+.intro-strip p { padding-block: 1.8rem; font-size: 1rem; }
+.section-heading h2, .tuning-copy h2, .gallery-heading h2, .privacy-grid h2, .open-card h2, .faq-intro h2, .coverage-head h2, .gallery-copy h2 { font-size: clamp(2.5rem, 4.5vw, 4rem); line-height: 1.08; letter-spacing: -.045em; }
+.section-heading { max-width: 700px; }
+.eyebrow { font-size: .65rem; letter-spacing: .16em; }
+.mode-grid { gap: 1.5rem; margin-top: 3rem; }
+.mode-card { border: 0; border-top: 1px solid var(--line-strong); border-radius: 0; min-height: 690px; padding: 1.7rem 1rem 0; background: var(--bg-soft); }
+.mode-card::before { display: none; }
+.mode-number { margin-bottom: 1.5rem; }
+.mode-copy h3, .bento-card h3 { font-size: 2.1rem; line-height: 1.12; }
+.mode-card .phone-frame { top: 320px; right: 12%; left: auto; width: 76%; transform: none; border-radius: 20px; }
+.bionic-sample { top: 320px; border-radius: 12px; background: #20262e; box-shadow: none; }
+.bionic-progress span { background: #b5c6e7; }
+.tuning-section { border-block: 1px solid var(--line); background: var(--bg-soft); }
+.tuning-visual { background: none; min-height: 620px; }
+.tuning-visual .phone-frame { width: 290px; transform: translateX(-50%) rotate(4deg); }
+.tuning-callout { border-radius: 8px; box-shadow: none; }
+.profile-list span { border-radius: 4px; }
+.gallery-layout { display: grid; grid-template-columns: 1fr 1fr; gap: 7rem; align-items: center; }
+.gallery-copy h2 { margin: 1rem 0; font-family: Palatino, Georgia, serif; font-weight: 500; }
+.gallery-description { color: var(--text-soft); line-height: 1.8; font-size: .95rem; }
+.gallery-choices { margin-top: 2rem; border-top: 1px solid var(--line); }
+.gallery-choices button { display: flex; align-items: center; gap: 1rem; width: 100%; padding: 1.25rem .7rem; text-align: left; background: none; border: 0; border-bottom: 1px solid var(--line); cursor: pointer; color: var(--text-soft); }
+.gallery-choices button[aria-pressed="true"] { background: var(--bg-soft); color: var(--accent); }
+.gallery-index { font-size: .65rem; font-family: monospace; }
+.gallery-choices button span:last-child { margin-left: auto; }
+.gallery-preview { margin: 0; padding: 2.5rem 2.5rem 1.5rem; background: var(--bg-soft); border-radius: 8px; text-align: center; }
+.gallery-preview img { display: block; width: 280px; height: auto; margin: auto; border-radius: 16px; box-shadow: 0 12px 25px #121b2920; }
+.gallery-preview figcaption { margin: 1.5rem auto 0; max-width: 290px; min-height: 3em; color: var(--text-soft); font-size: .8rem; line-height: 1.6; }
+.bento-card { border-radius: 8px; background: var(--bg-soft); min-height: 300px; }
+.bento-context { background: #20262e; }
+.bento-card > svg { margin-bottom: 2.5rem; }
+.orp-demo em { color: #b5c6e7; }
+.formats-section { background: var(--bg-soft); }
+.format-card { min-height: 120px; }
+.privacy-section { background: #252e3c; }
+.privacy-mark { border-radius: 50%; color: #b4c5af; }
+.privacy-section .eyebrow { color: #b5c6e7; }
+.open-card { padding: 0; border: 0; border-radius: 0; background: none; }
+.coverage-grid h3 { font-size: 1.4rem; }
+.final-cta { background: var(--bg-soft); }
+.final-cta-inner { min-height: 360px; }
+.final-cta h2 { font-size: clamp(3.5rem, 8vw, 7rem); line-height: 1.05; }
+.site-footer { background: #20262e; }
+.editorial-page { padding-top: 8rem; }
+@media (max-width: 1050px) {
+ .hero-grid { gap: 2rem; }
+ .hero-visual { min-height: 540px; }
+ .hero h1 { font-size: 5.5rem; }
+ .gallery-layout { gap: 3rem; }
+}
+@media (max-width: 820px) {
+ .site-header { padding-inline: 1.5rem; }
+ .nav-wrap { min-height: 72px; }
+ .content-wrap { width: calc(100% - 3rem); }
+ .hero-grid { grid-template-columns: 1fr; gap: 3rem; }
+ .hero { padding-top: 8rem; }
+ .hero-copy { max-width: 580px; }
+ .hero h1 { font-size: clamp(4rem, 12vw, 6rem); }
+ .hero-visual { width: min(100%, 500px); min-height: 600px; }
+ .gallery-layout { grid-template-columns: 1fr; }
+ .gallery-preview img { width: min(100%, 300px); }
+ .mode-bionic { min-height: 480px; }
+}
+@media (max-width: 620px) {
+ .hero-visual { min-height: 500px; margin-top: 0; }
+ .hero-phone-mid { top: 100px; left: 6%; }
+ .hero-phone-front { top: 140px; right: 6%; }
+ .hero-actions { flex-direction: row; align-items: center; }
+ .hero-actions > * { width: auto; }
+ .hero-actions .button-secondary { min-height: 44px; }
+ .hero-proof { gap: .8rem; font-size: .64rem; }
+ .mode-card { min-height: 680px; }
+ .mode-bionic { min-height: 660px; }
+ .mode-bionic .bionic-sample { top: 300px; bottom: 1rem; }
+ .gallery-preview { padding: 2rem 1.5rem 1.5rem; }
+ .tuning-visual { min-height: 550px; }
+ .tuning-visual .phone-frame { width: 260px; }
+ .final-cta h2 { font-size: 3.8rem; }
+}
+@media (max-width: 380px) {
+ .hero-visual { min-height: 445px; }
+ .hero h1 { font-size: 3.8rem; }
+}
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts
new file mode 100644
index 0000000..11f02fe
--- /dev/null
+++ b/src/vite-env.d.ts
@@ -0,0 +1 @@
+///