You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1125 lines
26 KiB
1125 lines
26 KiB
<script setup lang="ts">
|
|
const hero = {
|
|
img: 'https://picsum.photos/id/60/1200/900',
|
|
title: '这些是我的',
|
|
sub: '不是最好的,但都是有故事的',
|
|
}
|
|
|
|
const collections = [
|
|
{ id: 10, title: '午后', aspect: 'v', size: 'lg' },
|
|
{ id: 20, title: '城市', aspect: 'h', size: 'sm' },
|
|
{ id: 30, title: '海岸', aspect: 'v', size: 'md' },
|
|
{ id: 40, title: '远行', aspect: 'h', size: 'sm' },
|
|
{ id: 50, title: '静物', aspect: 'sq', size: 'md' },
|
|
{ id: 60, title: '人像', aspect: 'v', size: 'lg' },
|
|
{ id: 70, title: '夜色', aspect: 'h', size: 'md' },
|
|
{ id: 80, title: '山川', aspect: 'v', size: 'sm' },
|
|
{ id: 100, title: '森林', aspect: 'h', size: 'sm' },
|
|
{ id: 110, title: '街道', aspect: 'sq', size: 'lg' },
|
|
{ id: 120, title: '雨季', aspect: 'v', size: 'md' },
|
|
{ id: 130, title: '晴空', aspect: 'h', size: 'sm' },
|
|
{ id: 140, title: '咖啡', aspect: 'sq', size: 'md' },
|
|
{ id: 150, title: '旅途', aspect: 'v', size: 'lg' },
|
|
{ id: 160, title: '废墟', aspect: 'h', size: 'sm' },
|
|
{ id: 170, title: '浪潮', aspect: 'v', size: 'md' },
|
|
]
|
|
|
|
function imgSrc(id: number, aspect: string, h: number) {
|
|
const sizes: Record<string, number> = { h: 900, v: 600, sq: 700 }
|
|
const w = sizes[aspect] ?? 700
|
|
return `https://picsum.photos/id/${id}/${w}/${h}`
|
|
}
|
|
|
|
// ── Animation refs ──
|
|
const heroRef = ref<HTMLElement | null>(null)
|
|
const heroImgRef = ref<HTMLElement | null>(null)
|
|
const bentoItems = ref<HTMLElement[]>([])
|
|
const dwPhotos = ref<HTMLElement[]>([])
|
|
const scrollY = ref(0)
|
|
|
|
function onScroll() {
|
|
scrollY.value = window.scrollY
|
|
if (heroImgRef.value) {
|
|
const progress = scrollY.value * 0.35
|
|
heroImgRef.value.style.transform = `translateY(${progress}px) scale(1.0)`
|
|
}
|
|
}
|
|
|
|
// ── Typewriter for hero title ──
|
|
const displayTitle = ref('')
|
|
const titleText = hero.title
|
|
let charIndex = 0
|
|
|
|
function startTypewriter() {
|
|
if (charIndex < titleText.length) {
|
|
displayTitle.value += titleText[charIndex]
|
|
charIndex++
|
|
setTimeout(startTypewriter, 90 + Math.random() * 60)
|
|
}
|
|
}
|
|
|
|
// ── Bento scroll reveal ──
|
|
let bentoObserver: IntersectionObserver | null = null
|
|
|
|
function setupBentoObserver() {
|
|
bentoObserver = new IntersectionObserver(
|
|
(entries) => {
|
|
entries.forEach((entry) => {
|
|
if (entry.isIntersecting) {
|
|
const el = entry.target as HTMLElement
|
|
const delay = Number(el.dataset.delay ?? 0)
|
|
setTimeout(() => {
|
|
el.classList.add('is-visible')
|
|
}, delay)
|
|
bentoObserver?.unobserve(el)
|
|
}
|
|
})
|
|
},
|
|
{ threshold: 0.08 }
|
|
)
|
|
bentoItems.value.forEach((el, i) => {
|
|
if (el) {
|
|
el.dataset.delay = String(i * 75)
|
|
bentoObserver?.observe(el)
|
|
}
|
|
})
|
|
}
|
|
|
|
// ── Dark wall reveal ──
|
|
let dwObserver: IntersectionObserver | null = null
|
|
|
|
function setupDwObserver() {
|
|
dwObserver = new IntersectionObserver(
|
|
(entries) => {
|
|
entries.forEach((entry) => {
|
|
if (entry.isIntersecting) {
|
|
const el = entry.target as HTMLElement
|
|
const delay = Number(el.dataset.delay ?? 0)
|
|
setTimeout(() => {
|
|
el.classList.add('is-visible')
|
|
}, delay)
|
|
dwObserver?.unobserve(el)
|
|
}
|
|
})
|
|
},
|
|
{ threshold: 0.1 }
|
|
)
|
|
dwPhotos.value.forEach((el, i) => {
|
|
if (el) {
|
|
el.dataset.delay = String(i * 100)
|
|
dwObserver?.observe(el)
|
|
}
|
|
})
|
|
}
|
|
|
|
onMounted(() => {
|
|
window.addEventListener('scroll', onScroll, { passive: true })
|
|
setupBentoObserver()
|
|
setupDwObserver()
|
|
// Start typewriter after hero text animation begins
|
|
setTimeout(startTypewriter, 800)
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
window.removeEventListener('scroll', onScroll)
|
|
bentoObserver?.disconnect()
|
|
dwObserver?.disconnect()
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<main class="canvas">
|
|
|
|
<!-- ── Hero ── -->
|
|
<section class="hero" ref="heroRef">
|
|
<div class="hero-img-wrap" ref="heroImgRef">
|
|
<img :src="hero.img" :alt="hero.title" class="hero-img" />
|
|
<div class="hero-vignette" />
|
|
<div class="hero-sweep" />
|
|
</div>
|
|
<div class="hero-content">
|
|
<div class="hero-eyebrow reveal-item">私人收藏 · 随记</div>
|
|
<h1 class="hero-title"><span class="typewriter-text">{{ displayTitle }}</span><span class="typewriter-cursor">|</span></h1>
|
|
<p class="hero-sub reveal-item">{{ hero.sub }}</p>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- ── Bento grid — editorial rhythm ── -->
|
|
<section class="bento-section">
|
|
<div class="bento-header">
|
|
<span class="bento-index">01</span>
|
|
<h2 class="bento-heading">碎片收藏</h2>
|
|
<p class="bento-sub">每一格都是一段被打断的思绪</p>
|
|
</div>
|
|
<div class="bento">
|
|
<!-- ── Zone A: large left + 3-column strip right ── -->
|
|
<div class="b-zone-a">
|
|
<div class="b-a-main reveal-card" :ref="(el) => { if (el) bentoItems[0] = el as HTMLElement }">
|
|
<div class="b-img-wrap">
|
|
<img src="https://picsum.photos/id/10/700/1000" alt="午后" loading="lazy" />
|
|
</div>
|
|
</div>
|
|
<div class="b-a-side">
|
|
<div class="b-a-side-top reveal-card" :ref="(el) => { if (el) bentoItems[1] = el as HTMLElement }">
|
|
<div class="b-img-wrap">
|
|
<img src="https://picsum.photos/id/20/800/500" alt="城市" loading="lazy" />
|
|
</div>
|
|
</div>
|
|
<div class="b-a-side-bot reveal-card" :ref="(el) => { if (el) bentoItems[2] = el as HTMLElement }">
|
|
<div class="b-img-wrap">
|
|
<img src="https://picsum.photos/id/40/800/500" alt="远行" loading="lazy" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── Zone B: quote + 3-column photo strip ── -->
|
|
<div class="b-zone-b">
|
|
<div class="b-b-quote reveal-card" :ref="(el) => { if (el) bentoItems[3] = el as HTMLElement }">
|
|
<span class="note-mark">"</span>
|
|
<p class="note-text">每件东西都有自己的气味,闻到就穿越了</p>
|
|
<span class="note-source">— 手记 #1</span>
|
|
</div>
|
|
<div class="b-b-strip">
|
|
<div class="b-strip-item reveal-card" :ref="(el) => { if (el) bentoItems[4] = el as HTMLElement }">
|
|
<div class="b-img-wrap">
|
|
<img src="https://picsum.photos/id/50/700/700" alt="静物" loading="lazy" />
|
|
</div>
|
|
</div>
|
|
<div class="b-strip-item reveal-card" :ref="(el) => { if (el) bentoItems[5] = el as HTMLElement }">
|
|
<div class="b-img-wrap">
|
|
<img src="https://picsum.photos/id/30/600/1000" alt="海岸" loading="lazy" />
|
|
</div>
|
|
</div>
|
|
<div class="b-strip-item reveal-card" :ref="(el) => { if (el) bentoItems[6] = el as HTMLElement }">
|
|
<div class="b-img-wrap">
|
|
<img src="https://picsum.photos/id/60/600/1000" alt="人像" loading="lazy" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── Zone C: wide + accent number ── -->
|
|
<div class="b-zone-c">
|
|
<div class="b-c-wide reveal-card" :ref="(el) => { if (el) bentoItems[7] = el as HTMLElement }">
|
|
<div class="b-img-wrap">
|
|
<img src="https://picsum.photos/id/70/1200/600" alt="夜色" loading="lazy" />
|
|
</div>
|
|
</div>
|
|
<div class="b-c-accent reveal-card" :ref="(el) => { if (el) bentoItems[8] = el as HTMLElement }">
|
|
<div class="accent-block">
|
|
<span class="accent-num">02</span>
|
|
<span class="accent-label">城市<br>快照</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── Zone D: 4-grid + quote ── -->
|
|
<div class="b-zone-d">
|
|
<div class="b-d-4grid reveal-card" :ref="(el) => { if (el) bentoItems[9] = el as HTMLElement }">
|
|
<div class="b-img-wrap"><img src="https://picsum.photos/id/100/600/400" alt="森林" loading="lazy" /></div>
|
|
<div class="b-img-wrap"><img src="https://picsum.photos/id/110/600/600" alt="街道" loading="lazy" /></div>
|
|
<div class="b-img-wrap"><img src="https://picsum.photos/id/120/600/800" alt="雨季" loading="lazy" /></div>
|
|
<div class="b-img-wrap"><img src="https://picsum.photos/id/130/600/400" alt="晴空" loading="lazy" /></div>
|
|
</div>
|
|
<div class="b-d-quote reveal-card" :ref="(el) => { if (el) bentoItems[10] = el as HTMLElement }">
|
|
<span class="note-mark">"</span>
|
|
<p class="note-text">收集的过程比结果更重要</p>
|
|
<span class="note-source">— 手记 #2</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── Zone E: 3-column row ── -->
|
|
<div class="b-zone-e">
|
|
<div class="b-e-item reveal-card" :ref="(el) => { if (el) bentoItems[11] = el as HTMLElement }">
|
|
<div class="b-img-wrap">
|
|
<img src="https://picsum.photos/id/140/700/700" alt="咖啡" loading="lazy" />
|
|
</div>
|
|
</div>
|
|
<div class="b-e-item reveal-card" :ref="(el) => { if (el) bentoItems[12] = el as HTMLElement }">
|
|
<div class="b-img-wrap">
|
|
<img src="https://picsum.photos/id/150/600/1000" alt="旅途" loading="lazy" />
|
|
</div>
|
|
</div>
|
|
<div class="b-e-item reveal-card" :ref="(el) => { if (el) bentoItems[13] = el as HTMLElement }">
|
|
<div class="b-img-wrap">
|
|
<img src="https://picsum.photos/id/80/600/600" alt="山川" loading="lazy" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── Zone F: full-width quote ── -->
|
|
<div class="b-zone-f">
|
|
<div class="b-f-quote reveal-card" :ref="(el) => { if (el) bentoItems[14] = el as HTMLElement }">
|
|
<span class="note-mark">"</span>
|
|
<p class="note-text">有些东西扔不掉,不是因为值钱,是因为记得</p>
|
|
<span class="note-source">— 手记 #3</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- ── Mid-page interlude — dark editorial card ── -->
|
|
<section class="interlude">
|
|
<div class="interlude-inner">
|
|
<div class="interlude-label">03 · 精选</div>
|
|
<div class="interlude-grid">
|
|
<div class="interlude-text">
|
|
<h2 class="interlude-heading">不是作品集,<br>是私人日记</h2>
|
|
<p class="interlude-body">没有策划,没有主题,就是随手拍、随便留。三年下来,发现这些碎片其实比"正经作品"更像自己。</p>
|
|
<NuxtLink to="/photo" class="interlude-link">
|
|
进入全部收藏
|
|
<span class="link-arrow">→</span>
|
|
</NuxtLink>
|
|
</div>
|
|
<div class="interlude-feature">
|
|
<div class="feature-img-wrap">
|
|
<img src="https://picsum.photos/id/96/800/600" alt="海岸线" loading="lazy" />
|
|
</div>
|
|
<div class="feature-tag">2022 · 午后</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- ── Dark feature wall — 6 column editorial ── -->
|
|
<section class="dark-wall">
|
|
<div class="dark-wall-inner">
|
|
<div class="dw-header">
|
|
<span class="dw-index">04</span>
|
|
<span class="dw-label">最珍贵的几件</span>
|
|
</div>
|
|
<div class="dw-photos">
|
|
<div
|
|
class="dw-photo reveal-card"
|
|
v-for="(c, i) in collections.slice(0, 6)"
|
|
:key="c.id"
|
|
:ref="(el) => { if (el) dwPhotos[i] = el as HTMLElement }"
|
|
>
|
|
<div class="dw-photo-inner">
|
|
<img :src="imgSrc(c.id, c.aspect, 500)" :alt="c.title" loading="lazy" />
|
|
</div>
|
|
<div class="dw-photo-label">{{ c.title }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- ── Footer ── -->
|
|
<footer class="site-footer">
|
|
<div class="footer-grid">
|
|
<div class="footer-brand">收藏室</div>
|
|
<div class="footer-links">
|
|
<NuxtLink to="/photo">全部</NuxtLink>
|
|
<NuxtLink to="/portfolio">作品集</NuxtLink>
|
|
<NuxtLink to="/about">关于</NuxtLink>
|
|
</div>
|
|
</div>
|
|
<p class="footer-copy">© 2024 · 私人收藏 · 不必打扰</p>
|
|
</footer>
|
|
</main>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.canvas {
|
|
background: var(--color-canvas);
|
|
}
|
|
|
|
/* ── Hero ── */
|
|
.hero {
|
|
position: relative;
|
|
height: 100vh;
|
|
min-height: 600px;
|
|
margin-top: -64px; /* compensate for fixed nav */
|
|
display: flex;
|
|
align-items: flex-end;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.hero-img-wrap {
|
|
position: absolute;
|
|
inset: 0;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.hero-img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
transform-origin: center center;
|
|
transition: transform 0.6s cubic-bezier(0.25, 1, 0.5, 1);
|
|
}
|
|
|
|
.hero-img-wrap:hover .hero-img {
|
|
transform: scale(1.03) translateY(-4px);
|
|
}
|
|
|
|
.hero-vignette {
|
|
position: absolute;
|
|
inset: 0;
|
|
background: linear-gradient(
|
|
to top,
|
|
rgba(20, 20, 19, 0.85) 0%,
|
|
rgba(20, 20, 19, 0.3) 50%,
|
|
transparent 100%
|
|
);
|
|
}
|
|
|
|
/* ── Light sweep ── */
|
|
.hero-sweep {
|
|
position: absolute;
|
|
inset: 0;
|
|
overflow: hidden;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.hero-sweep::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: -60%;
|
|
left: -80%;
|
|
width: 60%;
|
|
height: 200%;
|
|
background: linear-gradient(
|
|
105deg,
|
|
transparent 30%,
|
|
rgba(250, 249, 245, 0.06) 45%,
|
|
rgba(250, 249, 245, 0.12) 50%,
|
|
rgba(250, 249, 245, 0.06) 55%,
|
|
transparent 70%
|
|
);
|
|
transform: translateX(-100%) translateY(-20%);
|
|
animation: light-sweep 1.6s cubic-bezier(0.16, 1, 0.3, 1) 0.3s forwards;
|
|
}
|
|
|
|
@keyframes light-sweep {
|
|
0% {
|
|
transform: translateX(-100%) translateY(-20%);
|
|
opacity: 0;
|
|
}
|
|
20% {
|
|
opacity: 1;
|
|
}
|
|
100% {
|
|
transform: translateX(300%) translateY(-20%);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
.hero-content {
|
|
position: relative;
|
|
z-index: 1;
|
|
padding: 0 64px 80px;
|
|
}
|
|
|
|
.hero-eyebrow {
|
|
font-family: var(--font-body);
|
|
font-size: 11px;
|
|
font-weight: 500;
|
|
letter-spacing: 3px;
|
|
text-transform: uppercase;
|
|
color: rgba(250, 249, 245, 0.6);
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.hero-title {
|
|
font-family: var(--font-display);
|
|
font-size: clamp(56px, 9vw, 112px);
|
|
font-weight: 400;
|
|
color: var(--color-on-dark);
|
|
letter-spacing: -3px;
|
|
line-height: 0.95;
|
|
margin: 0 0 20px;
|
|
}
|
|
|
|
.hero-sub {
|
|
font-family: var(--font-body);
|
|
font-size: 18px;
|
|
color: rgba(250, 249, 245, 0.7);
|
|
margin: 0;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
/* ── Bento heading ── */
|
|
.bento-section {
|
|
padding: 80px 40px 96px;
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.bento-header {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 20px;
|
|
margin-bottom: 48px;
|
|
border-bottom: 1px solid var(--color-hairline);
|
|
padding-bottom: 32px;
|
|
}
|
|
|
|
.bento-index {
|
|
font-family: var(--font-body);
|
|
font-size: 11px;
|
|
font-weight: 500;
|
|
letter-spacing: 2px;
|
|
color: var(--color-primary);
|
|
}
|
|
|
|
.bento-heading {
|
|
font-family: var(--font-display);
|
|
font-size: clamp(28px, 4vw, 48px);
|
|
font-weight: 400;
|
|
color: var(--color-ink);
|
|
letter-spacing: -1px;
|
|
margin: 0;
|
|
}
|
|
|
|
.bento-sub {
|
|
font-family: var(--font-body);
|
|
font-size: 14px;
|
|
color: var(--color-muted);
|
|
margin: 0;
|
|
margin-left: auto;
|
|
font-style: italic;
|
|
}
|
|
|
|
.bento {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 20px;
|
|
}
|
|
|
|
/* item helpers */
|
|
.b-img-wrap {
|
|
position: relative;
|
|
overflow: hidden;
|
|
border-radius: 8px;
|
|
background: var(--color-surface-card);
|
|
}
|
|
|
|
.b-img-wrap img {
|
|
display: block;
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
transition: transform 0.5s var(--ease-out-quint);
|
|
}
|
|
|
|
.b-img-wrap:hover img {
|
|
transform: scale(1.04);
|
|
}
|
|
|
|
/* ── Zone A: 5col main + 7col side stack ── */
|
|
.b-zone-a {
|
|
display: grid;
|
|
grid-template-columns: 5fr 7fr;
|
|
gap: 20px;
|
|
align-items: start;
|
|
}
|
|
|
|
.b-a-main .b-img-wrap {
|
|
height: 560px;
|
|
}
|
|
|
|
.b-a-side {
|
|
display: grid;
|
|
grid-template-rows: 1fr 1fr;
|
|
gap: 20px;
|
|
}
|
|
|
|
.b-a-side .b-img-wrap {
|
|
height: 270px;
|
|
}
|
|
|
|
/* ── Zone B: 4col quote + 8col 3-up strip ── */
|
|
.b-zone-b {
|
|
display: grid;
|
|
grid-template-columns: 4fr 8fr;
|
|
gap: 20px;
|
|
align-items: start;
|
|
}
|
|
|
|
.b-b-quote {
|
|
background: var(--color-surface-card);
|
|
border-radius: 8px;
|
|
padding: 40px 32px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
min-height: 320px;
|
|
}
|
|
|
|
.b-b-strip {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr 1fr;
|
|
gap: 20px;
|
|
}
|
|
|
|
.b-strip-item .b-img-wrap {
|
|
height: 320px;
|
|
}
|
|
|
|
/* ── Zone C: 7col wide + 5col accent ── */
|
|
.b-zone-c {
|
|
display: grid;
|
|
grid-template-columns: 7fr 5fr;
|
|
gap: 20px;
|
|
align-items: start;
|
|
}
|
|
|
|
.b-c-wide .b-img-wrap {
|
|
height: 380px;
|
|
}
|
|
|
|
.b-c-accent {
|
|
background: var(--color-surface-card);
|
|
border-radius: 8px;
|
|
height: 380px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
/* ── Zone D: 8col 4-grid + 4col quote ── */
|
|
.b-zone-d {
|
|
display: grid;
|
|
grid-template-columns: 8fr 4fr;
|
|
gap: 20px;
|
|
align-items: start;
|
|
}
|
|
|
|
.b-d-4grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 20px;
|
|
}
|
|
|
|
.b-d-4grid .b-img-wrap {
|
|
height: 240px;
|
|
}
|
|
|
|
.b-d-quote {
|
|
background: var(--color-surface-card);
|
|
border-radius: 8px;
|
|
padding: 40px 32px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
min-height: 260px;
|
|
}
|
|
|
|
/* ── Zone E: equal 3 columns ── */
|
|
.b-zone-e {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr 1fr;
|
|
gap: 20px;
|
|
}
|
|
|
|
.b-e-item .b-img-wrap {
|
|
height: 360px;
|
|
}
|
|
|
|
/* ── Zone F: full-width quote ── */
|
|
.b-zone-f {
|
|
width: 100%;
|
|
}
|
|
|
|
.b-f-quote {
|
|
background: var(--color-surface-card);
|
|
border-radius: 8px;
|
|
padding: 48px 56px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
text-align: center;
|
|
min-height: 180px;
|
|
}
|
|
|
|
/* ── Shared note styles ── */
|
|
.note-text {
|
|
font-family: var(--font-display);
|
|
font-size: clamp(18px, 2vw, 24px);
|
|
font-weight: 400;
|
|
color: var(--color-ink);
|
|
letter-spacing: -0.3px;
|
|
line-height: 1.4;
|
|
margin: 0 0 16px;
|
|
font-style: italic;
|
|
}
|
|
|
|
.note-mark {
|
|
display: block;
|
|
font-family: var(--font-display);
|
|
font-size: 56px;
|
|
line-height: 0.7;
|
|
color: var(--color-primary);
|
|
margin-bottom: 12px;
|
|
font-weight: 400;
|
|
}
|
|
|
|
.note-source {
|
|
font-family: var(--font-body);
|
|
font-size: 11px;
|
|
color: var(--color-muted);
|
|
letter-spacing: 2px;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
/* Accent number block */
|
|
.accent-block {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
.accent-num {
|
|
font-family: var(--font-display);
|
|
font-size: 56px;
|
|
font-weight: 400;
|
|
color: var(--color-primary);
|
|
letter-spacing: -2px;
|
|
line-height: 1;
|
|
}
|
|
|
|
.accent-label {
|
|
font-family: var(--font-body);
|
|
font-size: 10px;
|
|
font-weight: 500;
|
|
letter-spacing: 3px;
|
|
text-transform: uppercase;
|
|
color: var(--color-muted);
|
|
text-align: center;
|
|
line-height: 1.7;
|
|
}
|
|
|
|
/* ── Interlude editorial card ── */
|
|
.interlude {
|
|
background: var(--color-surface-dark);
|
|
padding: 80px 40px;
|
|
}
|
|
|
|
.interlude-inner {
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.interlude-label {
|
|
font-family: var(--font-body);
|
|
font-size: 11px;
|
|
font-weight: 500;
|
|
letter-spacing: 3px;
|
|
text-transform: uppercase;
|
|
color: var(--color-on-dark-soft);
|
|
margin-bottom: 40px;
|
|
}
|
|
|
|
.interlude-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 64px;
|
|
align-items: center;
|
|
}
|
|
|
|
.interlude-text {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 24px;
|
|
}
|
|
|
|
.interlude-heading {
|
|
font-family: var(--font-display);
|
|
font-size: clamp(32px, 4vw, 52px);
|
|
font-weight: 400;
|
|
color: var(--color-on-dark);
|
|
letter-spacing: -1px;
|
|
line-height: 1.1;
|
|
margin: 0;
|
|
}
|
|
|
|
.interlude-body {
|
|
font-family: var(--font-body);
|
|
font-size: 16px;
|
|
color: var(--color-on-dark-soft);
|
|
line-height: 1.7;
|
|
margin: 0;
|
|
max-width: 42ch;
|
|
}
|
|
|
|
.interlude-link {
|
|
font-family: var(--font-body);
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
color: var(--color-primary);
|
|
text-decoration: none;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
transition: gap 0.2s;
|
|
}
|
|
|
|
.interlude-link:hover {
|
|
gap: 14px;
|
|
}
|
|
|
|
.link-arrow {
|
|
font-size: 16px;
|
|
}
|
|
|
|
.feature-img-wrap {
|
|
border-radius: 12px;
|
|
overflow: hidden;
|
|
aspect-ratio: 4/3;
|
|
}
|
|
|
|
.feature-img-wrap img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
display: block;
|
|
transition: transform 0.5s var(--ease-out-quint);
|
|
}
|
|
|
|
.feature-img-wrap:hover img {
|
|
transform: scale(1.04);
|
|
}
|
|
|
|
.feature-tag {
|
|
font-family: var(--font-body);
|
|
font-size: 12px;
|
|
font-weight: 500;
|
|
letter-spacing: 2px;
|
|
text-transform: uppercase;
|
|
color: var(--color-on-dark-soft);
|
|
margin-top: 16px;
|
|
padding-left: 4px;
|
|
}
|
|
|
|
/* ── Dark wall ── */
|
|
.dark-wall {
|
|
background: var(--color-surface-dark);
|
|
padding: 80px 40px;
|
|
}
|
|
|
|
.dark-wall-inner {
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.dw-label {
|
|
font-family: var(--font-body);
|
|
font-size: 11px;
|
|
font-weight: 500;
|
|
letter-spacing: 3px;
|
|
text-transform: uppercase;
|
|
color: var(--color-on-dark-soft);
|
|
margin-bottom: 16px;
|
|
padding-left: 4px;
|
|
}
|
|
|
|
.dw-photos {
|
|
display: grid;
|
|
grid-template-columns: repeat(6, 1fr);
|
|
gap: 12px;
|
|
}
|
|
|
|
.dw-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16px;
|
|
margin-bottom: 32px;
|
|
}
|
|
|
|
.dw-index {
|
|
font-family: var(--font-body);
|
|
font-size: 11px;
|
|
font-weight: 500;
|
|
letter-spacing: 2px;
|
|
color: var(--color-primary);
|
|
}
|
|
|
|
.dw-photo {
|
|
position: relative;
|
|
overflow: hidden;
|
|
border-radius: 8px;
|
|
aspect-ratio: 3/4;
|
|
}
|
|
|
|
.dw-photo-inner {
|
|
width: 100%;
|
|
height: 100%;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.dw-photo-inner img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
transition: transform 0.5s var(--ease-out-quint);
|
|
}
|
|
|
|
.dw-photo:hover img {
|
|
transform: scale(1.05);
|
|
}
|
|
|
|
.dw-photo-label {
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
padding: 20px 16px 12px;
|
|
background: linear-gradient(to top, rgba(20, 20, 19, 0.7) 0%, transparent 100%);
|
|
font-family: var(--font-body);
|
|
font-size: 13px;
|
|
color: rgba(250, 249, 245, 0.85);
|
|
font-weight: 500;
|
|
}
|
|
|
|
/* ── Footer ── */
|
|
.site-footer {
|
|
background: var(--color-surface-dark);
|
|
padding: 48px 64px;
|
|
border-top: 1px solid rgba(250, 249, 245, 0.08);
|
|
}
|
|
|
|
.footer-grid {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 32px;
|
|
}
|
|
|
|
.footer-brand {
|
|
font-family: var(--font-display);
|
|
font-size: 28px;
|
|
font-weight: 400;
|
|
color: var(--color-on-dark);
|
|
letter-spacing: -1px;
|
|
}
|
|
|
|
.footer-links {
|
|
display: flex;
|
|
gap: 32px;
|
|
}
|
|
|
|
.footer-links a {
|
|
font-family: var(--font-body);
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
color: var(--color-on-dark-soft);
|
|
text-decoration: none;
|
|
transition: color 0.2s;
|
|
}
|
|
|
|
.footer-links a:hover {
|
|
color: var(--color-on-dark);
|
|
}
|
|
|
|
.footer-copy {
|
|
font-family: var(--font-body);
|
|
font-size: 13px;
|
|
color: var(--color-on-dark-soft);
|
|
margin: 0;
|
|
padding-top: 24px;
|
|
border-top: 1px solid rgba(250, 249, 245, 0.08);
|
|
}
|
|
|
|
/* ── Mobile ── */
|
|
@media (max-width: 768px) {
|
|
.hero-content {
|
|
padding: 0 24px 48px;
|
|
}
|
|
|
|
.bento-section {
|
|
padding: 48px 16px;
|
|
}
|
|
|
|
.bento-header {
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
margin-bottom: 32px;
|
|
}
|
|
|
|
.bento-sub {
|
|
margin-left: 0;
|
|
}
|
|
|
|
.bento {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
}
|
|
|
|
.b-img-wrap,
|
|
.b-a-main .b-img-wrap,
|
|
.b-a-side .b-img-wrap,
|
|
.b-strip-item .b-img-wrap,
|
|
.b-c-wide .b-img-wrap,
|
|
.b-d-4grid .b-img-wrap,
|
|
.b-e-item .b-img-wrap {
|
|
height: 240px !important;
|
|
}
|
|
|
|
.b-zone-a,
|
|
.b-zone-b,
|
|
.b-zone-c,
|
|
.b-zone-d {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
}
|
|
|
|
.b-b-strip {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
}
|
|
|
|
.b-d-4grid {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
}
|
|
|
|
.b-zone-e {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
}
|
|
|
|
.b-f-quote {
|
|
padding: 32px 24px;
|
|
}
|
|
|
|
.interlude { padding: 48px 16px; }
|
|
.interlude-grid { grid-template-columns: 1fr; gap: 32px; }
|
|
.interlude-heading { font-size: 32px; }
|
|
|
|
.dark-wall { padding: 48px 16px; }
|
|
.dw-photos { grid-template-columns: repeat(2, 1fr); gap: 12px; }
|
|
.dw-photo { aspect-ratio: 3/4; }
|
|
|
|
.site-footer { padding: 40px 24px; }
|
|
.footer-grid { flex-direction: column; gap: 20px; }
|
|
}
|
|
|
|
/* ── Animations ── */
|
|
@keyframes hero-img-reveal {
|
|
from {
|
|
transform: scale(1.08);
|
|
opacity: 0.6;
|
|
}
|
|
to {
|
|
transform: scale(1.0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
@keyframes hero-text-reveal {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(28px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
@keyframes card-reveal {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(36px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
/* Hero entrance */
|
|
.hero-img {
|
|
transform: scale(1.08);
|
|
animation: hero-img-reveal 1.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
|
}
|
|
|
|
.hero-eyebrow {
|
|
opacity: 0;
|
|
animation: hero-text-reveal 0.8s cubic-bezier(0.25, 1, 0.5, 1) 0.5s forwards;
|
|
}
|
|
|
|
.hero-title {
|
|
opacity: 0;
|
|
animation: hero-text-reveal 0.6s cubic-bezier(0.25, 1, 0.5, 1) 0.65s forwards;
|
|
}
|
|
|
|
.hero-sub {
|
|
opacity: 0;
|
|
animation: hero-text-reveal 0.8s cubic-bezier(0.25, 1, 0.5, 1) 0.85s forwards;
|
|
}
|
|
|
|
/* Bento scroll reveal */
|
|
.reveal-card {
|
|
opacity: 0;
|
|
transform: translateY(36px);
|
|
transition: opacity 0.65s cubic-bezier(0.25, 1, 0.5, 1), transform 0.65s cubic-bezier(0.25, 1, 0.5, 1);
|
|
}
|
|
|
|
.reveal-card.is-visible {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
|
|
/* Dark wall photos reveal */
|
|
.dw-photo {
|
|
opacity: 0;
|
|
transform: translateY(24px);
|
|
transition: opacity 0.6s cubic-bezier(0.25, 1, 0.5, 1), transform 0.6s cubic-bezier(0.25, 1, 0.5, 1);
|
|
}
|
|
|
|
.dw-photo.is-visible {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
|
|
/* ── Reduced motion ── */
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.hero-img,
|
|
.hero-eyebrow,
|
|
.hero-title,
|
|
.hero-sub {
|
|
animation: none !important;
|
|
opacity: 1;
|
|
transform: none;
|
|
}
|
|
|
|
.hero-sweep::after {
|
|
animation: none;
|
|
opacity: 0;
|
|
}
|
|
|
|
.reveal-card,
|
|
.dw-photo {
|
|
opacity: 1;
|
|
transform: none;
|
|
transition: none;
|
|
}
|
|
|
|
.typewriter-cursor {
|
|
animation: none;
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
/* ── Typewriter ── */
|
|
.typewriter-cursor {
|
|
display: inline-block;
|
|
color: var(--color-primary);
|
|
animation: cursor-blink 1s step-end infinite;
|
|
margin-left: 2px;
|
|
}
|
|
|
|
@keyframes cursor-blink {
|
|
0%, 100% { opacity: 1; }
|
|
50% { opacity: 0; }
|
|
}
|
|
</style>
|
|
|