1/**
2 * Atelier Nord — Scandinavian fashion e-commerce.
3 *
4 * Monochrome high-fashion storefront: giant condensed type, an art-directed
5 * asymmetric grid and pre-rendered fabric photography (draped herringbone,
6 * cable knit, twill, poplin, check and leather, recoloured per swatch) with a
7 * CSS film-grain layer. No web fonts.
8 *
9 * Demo images: /img/lux/{dr-coat,dr-knit,dr-trouser,dr-shirt,dr-scarf,dr-bag,dunes-mono,still-grey}.webp
10 * (+ -800 variants), included in the repo's public/img/lux — copy them next to your page or swap in your own.
11 *
12 * Motion
13 * - Masthead: each letter of ATELIER / NORD scrubs on scroll at its own
14 * speed and tilt; the cover image drifts and scales underneath.
15 * - Zoom-parallax lookbook: a pinned stage starts zoomed into one image and
16 * pulls back until it settles into an asymmetric grid; tiles arrive at
17 * different depths.
18 * - Product cards: swatch changes cross-fade the fabric colour; "Quick add"
19 * morphs (clip-path) into a size picker, then into an "Added" state.
20 * - Cart drawer slides in on a real spring (stiffness 380, damping 30).
21 * - A cursor-following "View" label springs after the pointer over product
22 * imagery (mouse only).
23 * - Editorial press-quote marquee; reveal-on-scroll everywhere else.
24 *
25 * Reduced motion: no scrub, no pinning, no marquee, drawer/label snap.
26 * SSR-safe: no window/document access during render.
27 * Accessibility: real buttons with aria-pressed / aria-label, dialog with
28 * focus management + Escape, aria-live cart status, AA contrast.
29 */
30import { useEffect, useRef, useState, type CSSProperties, type ReactNode } from "react";
31
32/* ------------------------------------------------------------------ */
33/* Photography (pre-rendered, see /img/lux) */
34/* ------------------------------------------------------------------ */
35type GKind = "coat" | "knit" | "trouser" | "shirt" | "scarf" | "bag";
36type SceneK = "figure" | "fjord" | "birch" | "stack" | "detail" | "window" | "still";
37
38/* Fabric studies, rendered in neutral grey. The product image is multiplied
39 over the swatch colour (mix-blend-mode: overlay) so every colourway keeps
40 the same folds, weave and light. */
41const FABRIC: Record<GKind, string> = { coat: "dr-coat", knit: "dr-knit", trouser: "dr-trouser", shirt: "dr-shirt", scarf: "dr-scarf", bag: "dr-bag" };
42const SCENE_IMG: Record<SceneK, { f: string; w: number; h: number; pos: string; scale?: number }> = {
43 figure: { f: "dr-coat", w: 1200, h: 1500, pos: "50% 40%" },
44 fjord: { f: "dunes-mono", w: 1920, h: 1200, pos: "60% 50%" },
45 birch: { f: "dr-trouser", w: 1200, h: 1500, pos: "50% 50%" },
46 stack: { f: "dr-knit", w: 1200, h: 1500, pos: "50% 70%" },
47 detail: { f: "dr-coat", w: 1200, h: 1500, pos: "30% 30%", scale: 1.9 },
48 window: { f: "still-grey", w: 1200, h: 1500, pos: "50% 55%" },
49 still: { f: "dr-bag", w: 1200, h: 1500, pos: "50% 50%" },
50};
51
52function ProductShot({ kind, color, label }: { kind: GKind; color: string; label: string }) {
53 const f = FABRIC[kind];
54 return (
55 <div className="an-shot" role={label ? "img" : undefined} aria-label={label || undefined} style={{ background: color }}>
56 <img src={`/img/lux/${f}-800.webp`} srcSet={`/img/lux/${f}-800.webp 800w, /img/lux/${f}.webp 1200w`} sizes="(max-width: 700px) 90vw, 480px" width={1200} height={1500} alt={label ? "" : `Grey ${kind} fabric study showing folds and weave in studio light`} loading="lazy" decoding="async" />
57 </div>
58 );
59}
60
61function Scene({ k, label, eager = false }: { k: SceneK; label: string; eager?: boolean }) {
62 const s = SCENE_IMG[k];
63 return (
64 <img
65 className="an-scene"
66 src={`/img/lux/${s.f}-800.webp`}
67 srcSet={`/img/lux/${s.f}-800.webp 800w, /img/lux/${s.f}.webp ${s.w}w`}
68 sizes="(max-width: 700px) 100vw, 50vw"
69 width={s.w}
70 height={s.h}
71 alt={label}
72 loading={eager ? "eager" : "lazy"}
73 decoding="async"
74 style={{ objectPosition: s.pos, ...(s.scale ? { transform: `scale(${s.scale})`, transformOrigin: s.pos } : null) }}
75 />
76 );
77}
78
79/* ------------------------------------------------------------------ */
80/* Data */
81/* ------------------------------------------------------------------ */
82type Swatch = { name: string; hex: string };
83const SW = {
84 ecru: { name: "Ecru", hex: "#E6E0D3" },
85 stone: { name: "Stone", hex: "#A8A39A" },
86 charcoal: { name: "Charcoal", hex: "#3A3A3A" },
87 black: { name: "Black", hex: "#141414" },
88 fog: { name: "Fog", hex: "#C9C9C6" },
89 moss: { name: "Moss", hex: "#55574C" },
90};
91const PRODUCTS: { name: string; kind: GKind; price: number; tag?: string; swatches: Swatch[]; fabric: string; layout: string }[] = [
92 { name: "Sund Overcoat", kind: "coat", price: 690, tag: "New", swatches: [SW.charcoal, SW.stone, SW.black], fabric: "Wool herringbone, 680 g/m", layout: "an-p-a" },
93 { name: "Vind Cable Crew", kind: "knit", price: 230, swatches: [SW.ecru, SW.fog, SW.charcoal], fabric: "Extrafine merino", layout: "an-p-b" },
94 { name: "Ström Pleated Trouser", kind: "trouser", price: 260, swatches: [SW.black, SW.stone, SW.moss], fabric: "Wool twill", layout: "an-p-c" },
95 { name: "Ljus Poplin Shirt", kind: "shirt", price: 160, tag: "Restocked", swatches: [SW.ecru, SW.fog, SW.black], fabric: "Organic cotton poplin", layout: "an-p-d" },
96 { name: "Frost Check Scarf", kind: "scarf", price: 140, swatches: [SW.fog, SW.charcoal, SW.ecru], fabric: "Lambswool", layout: "an-p-e" },
97 { name: "Båt Leather Tote", kind: "bag", price: 320, swatches: [SW.black, SW.stone], fabric: "Vegetable-tanned leather", layout: "an-p-f" },
98];
99const SIZES = ["XS", "S", "M", "L", "XL"];
100const ONE_SIZE: GKind[] = ["scarf", "bag"];
101
102const LOOKS: { k: SceneK; label: string; cap: string }[] = [
103 { k: "birch", label: "Charcoal wool twill falling in raking light", cap: "Look 03 — Ström Trouser" },
104 { k: "stack", label: "Merino cable knit, draped over a plinth", cap: "Vind Cable Crew" },
105 { k: "detail", label: "Close-up of the herringbone weave on the overcoat", cap: "Herringbone, 680 g/m" },
106 { k: "fjord", label: "Wind-sculpted dunes at first light, in monochrome", cap: "Look 01 — Råbjerg Mile, 06:40" },
107 { k: "window", label: "Ceramics and a dried branch in window light", cap: "Frost Check Scarf" },
108 { k: "figure", label: "Charcoal herringbone wool, studio light", cap: "Look 07" },
109 { k: "still", label: "Vegetable-tanned black leather, close-up", cap: "Båt Tote" },
110];
111const LOOK_CENTER = 3;
112
113const QUOTES = [
114 { q: "The quietest coat of the season — and the one everyone asked about.", s: "Kvarter Magazine" },
115 { q: "Scandinavian restraint, cut with a tailor's arrogance.", s: "The Northern Review" },
116 { q: "Atelier Nord makes clothes you stop noticing, which is the point.", s: "Form & Fabric" },
117 { q: "A knit you will hand down, not throw out.", s: "Studio Weekly" },
118];
119
120const FABRICS = [
121 { name: "Herringbone wool", from: "Kvarnby Spinneri, Halland", spec: "680 g/m · 100% wool", cls: "an-tx-hb" },
122 { name: "Cable merino", from: "Filatura Orsi, Biella", spec: "19.5 µm · RWS certified", cls: "an-tx-knit" },
123 { name: "Bouclé alpaca", from: "Andean co-op, Arequipa", spec: "62% alpaca · 38% wool", cls: "an-tx-boucle" },
124 { name: "Cotton poplin", from: "Tessitura Vela, Como", spec: "120/2 · GOTS organic", cls: "an-tx-poplin" },
125];
126
127const JOURNAL = [
128 { k: "fjord" as SceneK, date: "14 Oct 2026", t: "Six days on Lysefjord: shooting AW26 in four hours of light a day" },
129 { k: "stack" as SceneK, date: "2 Oct 2026", t: "Why our cable crew takes eleven hours to knit — and why we refuse to speed it up" },
130 { k: "window" as SceneK, date: "19 Sep 2026", t: "Inside the Södermalm atelier: repairs, alterations and a very old Pfaff" },
131];
132
133const fmt = (n: number) => `€${n.toLocaleString("en-IE")}`;
134type CartItem = { key: string; name: string; kind: GKind; color: Swatch; size: string; price: number; qty: number };
135
136/* ------------------------------------------------------------------ */
137/* Page */
138/* ------------------------------------------------------------------ */
139export function Page() {
140 const rootRef = useRef<HTMLDivElement>(null);
141 const drawerRef = useRef<HTMLDivElement>(null);
142 const closeRef = useRef<HTMLButtonElement>(null);
143 const lastFocus = useRef<HTMLElement | null>(null);
144 const [small, setSmall] = useState(false);
145 const [menu, setMenu] = useState(false);
146 const [colors, setColors] = useState<number[]>(PRODUCTS.map(() => 0));
147 const [picking, setPicking] = useState<number | null>(null);
148 const [added, setAdded] = useState<number | null>(null);
149 const [cart, setCart] = useState<CartItem[]>([
150 { key: "ström-black-M", name: "Ström Pleated Trouser", kind: "trouser", color: SW.black, size: "M", price: 260, qty: 1 },
151 ]);
152 const [open, setOpen] = useState(false);
153 const [bump, setBump] = useState(0);
154 const [status, setStatus] = useState("");
155 const [email, setEmail] = useState("");
156 const [joined, setJoined] = useState(false);
157
158 const count = cart.reduce((a, c) => a + c.qty, 0);
159 const subtotal = cart.reduce((a, c) => a + c.qty * c.price, 0);
160 const FREE = 400;
161
162 /* Scroll engine, reveals, cursor label. */
163 useEffect(() => {
164 const root = rootRef.current;
165 if (!root) return;
166 const doc = root.ownerDocument;
167 const win = doc.defaultView;
168 if (!win) return;
169 const reduce = win.matchMedia("(prefers-reduced-motion: reduce)").matches;
170 root.classList.add("an-js");
171
172 // Hosts with overflow:hidden on html AND body make <body> a scroll container
173 // that never scrolls, which breaks position:sticky. `clip` looks the same.
174 let restoreBody: (() => void) | null = null;
175 const fixRaf = win.requestAnimationFrame(() => {
176 const b = doc.body;
177 const bs = win.getComputedStyle(b);
178 const hs = win.getComputedStyle(doc.documentElement);
179 if (hs.overflowX !== "visible" && (bs.overflowX === "hidden" || bs.overflowY === "auto")) {
180 const prev = [b.style.overflowX, b.style.overflowY];
181 b.style.overflowX = "clip";
182 b.style.overflowY = "visible";
183 restoreBody = () => {
184 b.style.overflowX = prev[0];
185 b.style.overflowY = prev[1];
186 };
187 }
188 });
189
190 const mast = root.querySelector<HTMLElement>(".an-mast");
191 const look = root.querySelector<HTMLElement>(".an-look");
192 const grid = root.querySelector<HTMLElement>(".an-look-grid");
193 const stage = root.querySelector<HTMLElement>(".an-look-stage");
194 const center = root.querySelector<HTMLElement>(`.an-tile-${LOOK_CENTER}`);
195 let s0 = 1;
196 let ox = 0;
197 let oy = 0;
198 let lookOn = false;
199
200 // Fit the masthead word to the content width whatever condensed face the OS supplies.
201 const word = root.querySelector<HTMLElement>(".an-word");
202 const fitWord = () => {
203 if (!word || !mast) return;
204 const lines = Array.from(word.querySelectorAll<HTMLElement>(".an-word-line"));
205 word.style.fontSize = "100px";
206 const widest = Math.max(...lines.map((l) => l.scrollWidth));
207 const avail = mast.clientWidth - parseFloat(win.getComputedStyle(mast).paddingLeft) * 2;
208 if (widest <= 0) return;
209 const byWidth = ((100 * avail) / widest) * 0.995;
210 // Keep the CTA row above the fold on short desktop viewports.
211 const byHeight = win.innerWidth > 760 ? (win.innerHeight - 330) / 1.56 : Infinity;
212 word.style.fontSize = `${Math.floor(Math.max(64, Math.min(byWidth, byHeight)))}px`;
213 };
214 doc.fonts?.ready.then(() => { fitWord(); }).catch(() => {});
215
216 const measure = () => {
217 fitWord();
218 lookOn = !reduce && win.innerWidth > 760;
219 if (!grid || !center || !stage) return;
220 grid.style.transform = "";
221 if (!lookOn) {
222 look?.classList.remove("is-zoom");
223 return;
224 }
225 look?.classList.add("is-zoom");
226 const cw = center.offsetWidth;
227 const ch = center.offsetHeight;
228 const cx = center.offsetLeft + cw / 2;
229 const cy = center.offsetTop + ch / 2;
230 grid.style.transformOrigin = `${cx}px ${cy}px`;
231 s0 = Math.max(win.innerWidth / cw, win.innerHeight / ch) * 1.02;
232 // Where the centre tile sits relative to the stage centre when settled.
233 ox = stage.clientWidth / 2 - (grid.offsetLeft + cx);
234 oy = stage.clientHeight / 2 - (grid.offsetTop + cy);
235 };
236
237 let raf = 0;
238 let lastSmall = false;
239 const update = () => {
240 raf = 0;
241 const vh = win.innerHeight;
242 const y = win.scrollY || doc.documentElement.scrollTop;
243 const sm = y > 40;
244 if (sm !== lastSmall) {
245 lastSmall = sm;
246 setSmall(sm);
247 }
248 if (mast && !reduce) {
249 const r = mast.getBoundingClientRect();
250 const p = Math.min(1, Math.max(0, -r.top / Math.max(1, r.height)));
251 mast.style.setProperty("--p", p.toFixed(4));
252 }
253 if (look && grid && lookOn) {
254 const r = look.getBoundingClientRect();
255 const p = Math.min(1, Math.max(0, -r.top / Math.max(1, r.height - vh)));
256 const k = Math.min(1, p / 0.78);
257 const e = 1 - Math.pow(1 - k, 3);
258 const s = s0 + (1 - s0) * e;
259 grid.style.transform = `translate3d(${(ox * (1 - e)).toFixed(1)}px, ${(oy * (1 - e)).toFixed(1)}px, 0) scale(${s.toFixed(4)})`;
260 look.style.setProperty("--e", e.toFixed(4));
261 }
262 };
263 const onScroll = () => {
264 if (!raf) raf = win.requestAnimationFrame(update);
265 };
266 const onResize = () => {
267 measure();
268 onScroll();
269 };
270 measure();
271 update();
272 win.addEventListener("scroll", onScroll, { passive: true });
273 win.addEventListener("resize", onResize);
274
275 const io = new win.IntersectionObserver(
276 (es) => es.forEach((e) => {
277 if (e.isIntersecting) {
278 e.target.classList.add("is-in");
279 io.unobserve(e.target);
280 }
281 }),
282 { rootMargin: "0px 0px -10% 0px", threshold: 0.12 },
283 );
284 root.querySelectorAll("[data-an-rv]").forEach((el) => io.observe(el));
285
286 // Cursor "View" label — spring-follow (stiffness 380, damping 30).
287 const label = root.querySelector<HTMLElement>(".an-cursor");
288 let tx = 0, ty = 0, x = 0, y2 = 0, vx = 0, vy = 0, active = false, cRaf = 0, last = 0;
289 const step = (now: number) => {
290 const dt = Math.min(0.032, (now - (last || now)) / 1000) || 0.016;
291 last = now;
292 const ax = 380 * (tx - x) - 30 * vx;
293 const ay = 380 * (ty - y2) - 30 * vy;
294 vx += ax * dt; vy += ay * dt;
295 x += vx * dt; y2 += vy * dt;
296 if (label) label.style.transform = `translate3d(${x.toFixed(1)}px, ${y2.toFixed(1)}px, 0)`;
297 if (Math.abs(tx - x) + Math.abs(ty - y2) + Math.abs(vx) + Math.abs(vy) > 0.3) cRaf = win.requestAnimationFrame(step);
298 else { cRaf = 0; last = 0; }
299 };
300 const onMove = (e: PointerEvent) => {
301 if (e.pointerType !== "mouse" || !label) return;
302 const t = e.target as Element | null;
303 // Show over imagery, but step aside for real controls (quick add, hotspots).
304 const hit = t?.closest?.("[data-an-view]") && !t.closest("button");
305 const rr = root.getBoundingClientRect();
306 tx = e.clientX - rr.left;
307 ty = e.clientY - rr.top;
308 if (hit && !active) {
309 active = true;
310 if (reduce || !label.classList.contains("is-on")) { x = tx; y2 = ty; vx = vy = 0; }
311 label.classList.add("is-on");
312 } else if (!hit && active) {
313 active = false;
314 label.classList.remove("is-on");
315 }
316 if (reduce) {
317 label.style.transform = `translate3d(${tx}px, ${ty}px, 0)`;
318 return;
319 }
320 if (!cRaf) cRaf = win.requestAnimationFrame(step);
321 };
322 root.addEventListener("pointermove", onMove, { passive: true });
323 const onLeave = () => { active = false; label?.classList.remove("is-on"); };
324 root.addEventListener("pointerleave", onLeave);
325
326 return () => {
327 win.cancelAnimationFrame(fixRaf);
328 if (raf) win.cancelAnimationFrame(raf);
329 if (cRaf) win.cancelAnimationFrame(cRaf);
330 win.removeEventListener("scroll", onScroll);
331 win.removeEventListener("resize", onResize);
332 root.removeEventListener("pointermove", onMove);
333 root.removeEventListener("pointerleave", onLeave);
334 io.disconnect();
335 restoreBody?.();
336 root.classList.remove("an-js");
337 };
338 }, []);
339
340 /* Cart drawer — spring slide + focus management. */
341 const springX = useRef({ x: 104, v: 0 });
342 useEffect(() => {
343 const el = drawerRef.current;
344 const win = el?.ownerDocument.defaultView;
345 if (!el || !win) return;
346 const reduce = win.matchMedia("(prefers-reduced-motion: reduce)").matches;
347 const target = open ? 0 : 104;
348 const st = springX.current;
349 let raf = 0;
350 let last = 0;
351 const paint = () => { el.style.transform = `translate3d(${st.x.toFixed(2)}%, 0, 0)`; };
352 if (reduce) {
353 st.x = target; st.v = 0; paint();
354 } else {
355 const tick = (now: number) => {
356 const dt = Math.min(0.032, (now - (last || now)) / 1000) || 0.016;
357 last = now;
358 const a = 380 * (target - st.x) - 30 * st.v;
359 st.v += a * dt;
360 st.x += st.v * dt;
361 paint();
362 if (Math.abs(target - st.x) > 0.05 || Math.abs(st.v) > 0.05) raf = win.requestAnimationFrame(tick);
363 else { st.x = target; st.v = 0; paint(); }
364 };
365 raf = win.requestAnimationFrame(tick);
366 }
367 if (open) {
368 lastFocus.current = el.ownerDocument.activeElement as HTMLElement | null;
369 win.setTimeout(() => closeRef.current?.focus({ preventScroll: true }), 60);
370 } else if (lastFocus.current) {
371 lastFocus.current.focus?.({ preventScroll: true });
372 lastFocus.current = null;
373 }
374 const onKey = (e: KeyboardEvent) => {
375 if (!open) return;
376 if (e.key === "Escape") setOpen(false);
377 if (e.key === "Tab") {
378 const f = Array.from(el.querySelectorAll<HTMLElement>("button, a[href], input")).filter((n) => !n.hasAttribute("disabled"));
379 if (!f.length) return;
380 const first = f[0];
381 const lastEl = f[f.length - 1];
382 const act = el.ownerDocument.activeElement;
383 if (e.shiftKey && act === first) { e.preventDefault(); lastEl.focus(); }
384 else if (!e.shiftKey && act === lastEl) { e.preventDefault(); first.focus(); }
385 }
386 };
387 el.ownerDocument.addEventListener("keydown", onKey);
388 return () => {
389 win.cancelAnimationFrame(raf);
390 el.ownerDocument.removeEventListener("keydown", onKey);
391 };
392 }, [open]);
393
394 const addToCart = (pi: number, size: string) => {
395 const p = PRODUCTS[pi];
396 const c = p.swatches[colors[pi]];
397 const key = `${p.name}-${c.name}-${size}`;
398 setCart((cs) => {
399 const ex = cs.find((x) => x.key === key);
400 if (ex) return cs.map((x) => (x.key === key ? { ...x, qty: x.qty + 1 } : x));
401 return [{ key, name: p.name, kind: p.kind, color: c, size, price: p.price, qty: 1 }, ...cs];
402 });
403 setPicking(null);
404 setAdded(pi);
405 setBump((b) => b + 1);
406 setStatus(`${p.name}, ${c.name}, size ${size} added to your bag.`);
407 const win = rootRef.current?.ownerDocument.defaultView;
408 win?.setTimeout(() => setOpen(true), 650);
409 win?.setTimeout(() => setAdded((a) => (a === pi ? null : a)), 2600);
410 };
411 const changeQty = (key: string, d: number) =>
412 setCart((cs) => cs.map((x) => (x.key === key ? { ...x, qty: x.qty + d } : x)).filter((x) => x.qty > 0));
413
414 const navL = ["Women", "Men", "Knitwear", "Lookbook", "Journal"];
415 const word1 = "ATELIER".split("");
416 const word2 = "NORD".split("");
417 const dyOf = (i: number, w: number) => (w === 0 ? -1 : 1) * (40 + ((i * 53 + w * 31) % 110));
418 const rotOf = (i: number, w: number) => (((i + w) % 3) - 1) * (2 + (i % 2) * 2);
419
420 return (
421 <div ref={rootRef} className="an">
422 <style>{css}</style>
423 <a className="an-skip" href="#an-main">Skip to content</a>
424 <span className="an-cursor" aria-hidden="true">View</span>
425
426 <p className="an-announce">Complimentary shipping & returns across the EU over €400 · Repairs free for life</p>
427
428 {/* NAV */}
429 <header className={`an-nav${small ? " is-small" : ""}${menu ? " is-open" : ""}`}>
430 <div className="an-nav-in">
431 <nav className="an-nav-l" aria-label="Primary">
432 <button type="button" className="an-burger" aria-expanded={menu} aria-label={menu ? "Close menu" : "Open menu"} onClick={() => setMenu((m) => !m)}><span /><span /></button>
433 {navL.map((l) => <a key={l} href={l === "Lookbook" ? "#an-look" : l === "Journal" ? "#an-journal" : "#an-shop"}>{l}</a>)}
434 </nav>
435 <a href="#an-top" className="an-logo" aria-label="Atelier Nord — home">Atelier Nord</a>
436 <div className="an-nav-r">
437 <a href="#an-top" className="an-nav-txt">Search</a>
438 <a href="#an-top" className="an-nav-txt">Account</a>
439 <button type="button" className="an-bag-btn" onClick={() => setOpen(true)} aria-label={`Bag, ${count} ${count === 1 ? "item" : "items"}`}>
440 Bag <span key={bump} className={`an-bag-n${bump ? " is-bump" : ""}`}>{count}</span>
441 </button>
442 </div>
443 </div>
444 <div className="an-sheet" hidden={!menu}>
445 {navL.map((l) => <a key={l} href={l === "Lookbook" ? "#an-look" : l === "Journal" ? "#an-journal" : "#an-shop"} onClick={() => setMenu(false)}>{l}</a>)}
446 </div>
447 </header>
448
449 <main id="an-main">
450 {/* MASTHEAD */}
451 <section id="an-top" className="an-mast" aria-labelledby="an-mast-title">
452 <div className="an-mast-meta">
453 <p>Autumn / Winter 2026<br />Collection 07 — <em>Stillhet</em></p>
454 <p className="an-mast-meta-r">Designed in Stockholm<br />Made in Portugal & Italy</p>
455 </div>
456 <figure className="an-mast-img" data-an-view>
457 <div className="an-mast-img-in an-grain"><Scene k="figure" eager label="Charcoal herringbone wool, draped in soft studio light" /></div>
458 <figcaption>Look 07 · Sund Overcoat, Charcoal</figcaption>
459 </figure>
460 <h1 id="an-mast-title" className="an-word" aria-label="Atelier Nord">
461 <span className="an-word-line" aria-hidden="true">
462 {word1.map((c, i) => (
463 <span key={i} className="an-ch" style={{ "--dy": dyOf(i, 0), "--rot": rotOf(i, 0), "--i": i } as CSSProperties}><span>{c}</span></span>
464 ))}
465 </span>
466 <span className="an-word-line an-word-line-2" aria-hidden="true">
467 {word2.map((c, i) => (
468 <span key={i} className="an-ch" style={{ "--dy": dyOf(i, 1), "--rot": rotOf(i, 1), "--i": i + 7 } as CSSProperties}><span>{c}</span></span>
469 ))}
470 </span>
471 </h1>
472 <div className="an-mast-foot">
473 <p>Clothes for long winters and short light. Seven-year coats, knits you repair, nothing you need to explain.</p>
474 <a href="#an-shop" className="an-btn an-btn-ink">Shop the collection <span aria-hidden="true">→</span></a>
475 </div>
476 </section>
477
478 {/* STATEMENT */}
479 <section className="an-statement" aria-label="About the collection">
480 <p className="an-statement-n" data-an-rv>(01)</p>
481 <p className="an-statement-t" data-an-rv>
482 Stillhet is Swedish for <em>stillness</em>. Thirty-one pieces in five colours, cut from cloth woven within
483 <span className="an-inline-img an-grain" aria-hidden="true"><Scene k="detail" label="" /></span>
484 a day of where it was spun — built to be worn hard and mended, not replaced.
485 </p>
486 </section>
487
488 {/* LOOKBOOK ZOOM */}
489 <section id="an-look" className="an-look" aria-labelledby="an-look-title">
490 <div className="an-look-stage">
491 <div className="an-look-head">
492 <h2 id="an-look-title" className="an-h2">Lookbook — AW26</h2>
493 <p>Shot on Lysefjord and in Tyresta, October 2026</p>
494 </div>
495 <ul className="an-look-grid">
496 {LOOKS.map((l, i) => (
497 <li key={l.k} className={`an-tile an-tile-${i}`} style={{ "--k": [140, -90, 200, 0, -160, 120, -60][i] } as CSSProperties} data-an-view>
498 <div className="an-tile-img an-grain"><Scene k={l.k} label={l.label} /></div>
499 <p className="an-tile-cap">{l.cap}</p>
500 </li>
501 ))}
502 </ul>
503 <p className="an-look-over" aria-hidden="true">Stillhet</p>
504 </div>
505 </section>
506
507 {/* SHOP */}
508 <section id="an-shop" className="an-shop" aria-labelledby="an-shop-title">
509 <div className="an-shop-head">
510 <h2 id="an-shop-title" className="an-h2 an-h2-xl" data-an-rv>New in</h2>
511 <p data-an-rv>Six pieces from Collection 07. Every garment ships with a repair card — send it back any time and we'll mend it free.</p>
512 <a href="#an-shop" className="an-link" data-an-rv>View all 31 pieces</a>
513 </div>
514 <p className="an-sr" aria-live="polite">{status}</p>
515 <ul className="an-grid">
516 {PRODUCTS.map((p, i) => {
517 const c = p.swatches[colors[i]];
518 const isPick = picking === i;
519 const isAdded = added === i;
520 const oneSize = ONE_SIZE.includes(p.kind);
521 return (
522 <li key={p.name} className={`an-card ${p.layout}`} data-an-rv>
523 <div className="an-card-media" data-an-view>
524 <a href="#an-shop" className="an-card-img an-grain" aria-label={`${p.name} in ${c.name}, ${fmt(p.price)}`}>
525 <ProductShot kind={p.kind} color={c.hex} label={`${p.name} in ${c.name}`} />
526 </a>
527 {p.tag && <span className="an-tag">{p.tag}</span>}
528 <div className={`an-qa${isPick ? " is-pick" : ""}${isAdded ? " is-added" : ""}`}>
529 <button type="button" className="an-qa-main" aria-expanded={isPick} onClick={() => (oneSize ? addToCart(i, "One size") : setPicking(isPick ? null : i))} disabled={isAdded}>
530 <span className="an-qa-plus" aria-hidden="true" />
531 <span className="an-qa-txt">{isAdded ? "Added" : oneSize ? "Add to bag" : "Quick add"}</span>
532 </button>
533 <div className="an-qa-sizes" role="group" aria-label={`Choose size for ${p.name}`} aria-hidden={!isPick}>
534 {SIZES.map((s, si) => (
535 <button key={s} type="button" tabIndex={isPick ? 0 : -1} disabled={p.kind === "coat" && si === 0} onClick={() => addToCart(i, s)} aria-label={`Size ${s}${p.kind === "coat" && si === 0 ? ", sold out" : ""}`}>{s}</button>
536 ))}
537 </div>
538 </div>
539 </div>
540 <div className="an-card-info">
541 <div>
542 <h3 className="an-card-name">{p.name}</h3>
543 <p className="an-card-fab">{p.fabric} · <span className="an-card-col">{c.name}</span></p>
544 </div>
545 <p className="an-card-price">{fmt(p.price)}</p>
546 </div>
547 <div className="an-sw" role="group" aria-label={`Colour for ${p.name}`}>
548 {p.swatches.map((s, si) => (
549 <button key={s.name} type="button" aria-label={s.name} aria-pressed={colors[i] === si} className={colors[i] === si ? "is-on" : ""} style={{ "--c": s.hex } as CSSProperties} onClick={() => setColors((cs) => cs.map((v, k) => (k === i ? si : v)))} />
550 ))}
551 </div>
552 </li>
553 );
554 })}
555 </ul>
556 </section>
557
558 {/* PRESS MARQUEE */}
559 <section className="an-press" aria-label="Press">
560 <div className="an-marquee">
561 <div className="an-marquee-track">
562 {[0, 1].map((k) => (
563 <ul key={k} className="an-marquee-set" aria-hidden={k === 1}>
564 {QUOTES.map((q) => (
565 <li key={q.s}><blockquote>“{q.q}”</blockquote><cite>— {q.s}</cite><span className="an-star" aria-hidden="true">✳</span></li>
566 ))}
567 </ul>
568 ))}
569 </div>
570 </div>
571 </section>
572
573 {/* FEATURE */}
574 <section className="an-feature" aria-labelledby="an-feature-title">
575 <div className="an-feature-media" data-an-view>
576 <div className="an-feature-img an-grain">
577 <ProductShot kind="coat" color={SW.charcoal.hex} label="Sund Overcoat, charcoal, front view" />
578 {[
579 { x: 47, y: 24, t: "Herringbone twill, 680 g/m wool" },
580 { x: 57, y: 55, t: "Brushed by hand for a soft, even nap" },
581 { x: 30, y: 70, t: "Lined in Bemberg cupro" },
582 ].map((h, i) => (
583 <button key={i} type="button" className="an-hot" style={{ left: `${h.x}%`, top: `${h.y}%` }} aria-label={h.t}>
584 <span aria-hidden="true">{i + 1}</span>
585 <em role="tooltip">{h.t}</em>
586 </button>
587 ))}
588 </div>
589 </div>
590 <div className="an-feature-text">
591 <p className="an-eyebrow" data-an-rv>The Sund Overcoat</p>
592 <h2 id="an-feature-title" className="an-h2 an-h2-xl" data-an-rv>Seven winters, minimum.</h2>
593 <p className="an-body" data-an-rv>A single-breasted coat in 680-gram herringbone, woven in Halland from wool shorn forty kilometres away. Canvassed through the chest, cut long enough to cover a blazer and roomy enough for a cable knit underneath.</p>
594 <dl className="an-specs" data-an-rv>
595 <div><dt>Cloth</dt><dd>100% wool herringbone, Kvarnby Spinneri</dd></div>
596 <div><dt>Lining</dt><dd>Bemberg cupro, body & sleeves</dd></div>
597 <div><dt>Fit</dt><dd>Relaxed. Model is 186 cm wearing M</dd></div>
598 <div><dt>Made</dt><dd>Guimarães, Portugal — 14 hours per coat</dd></div>
599 <div><dt>Care</dt><dd>Brush, air, steam. Free repairs for life</dd></div>
600 </dl>
601 <div className="an-feature-cta" data-an-rv>
602 <button type="button" className="an-btn an-btn-ink" onClick={() => addToCart(0, "M")}>Add to bag — {fmt(690)}</button>
603 <a href="#an-shop" className="an-link">Size guide</a>
604 </div>
605 </div>
606 </section>
607
608 {/* MATERIALS */}
609 <section className="an-mat" aria-labelledby="an-mat-title">
610 <div className="an-mat-head">
611 <p className="an-eyebrow" data-an-rv>(04) Materials</p>
612 <h2 id="an-mat-title" className="an-h2" data-an-rv>Four cloths. Four mills. We have visited every one.</h2>
613 </div>
614 <ul className="an-mat-grid">
615 {FABRICS.map((f, i) => (
616 <li key={f.name} className="an-mat-card" data-an-rv style={{ "--d": `${i * 80}ms` } as CSSProperties}>
617 <div className="an-mat-sw"><span className={`an-tx ${f.cls}`} /></div>
618 <h3 className="an-mat-name">{f.name}</h3>
619 <p className="an-mat-from">{f.from}</p>
620 <p className="an-mat-spec">{f.spec}</p>
621 </li>
622 ))}
623 </ul>
624 </section>
625
626 {/* JOURNAL */}
627 <section id="an-journal" className="an-journal" aria-labelledby="an-journal-title">
628 <div className="an-journal-head">
629 <h2 id="an-journal-title" className="an-h2 an-h2-xl" data-an-rv>Journal</h2>
630 <a href="#an-journal" className="an-link" data-an-rv>All stories</a>
631 </div>
632 <ul className="an-journal-grid">
633 {JOURNAL.map((j, i) => (
634 <li key={j.t} className="an-story" data-an-rv style={{ "--d": `${i * 90}ms` } as CSSProperties}>
635 <a href="#an-journal">
636 <div className="an-story-img an-grain"><Scene k={j.k} label={LOOKS.find((l) => l.k === j.k)?.label ?? "Atelier Nord journal story cover"} /></div>
637 <p className="an-story-date">{j.date}</p>
638 <h3 className="an-story-t">{j.t}</h3>
639 </a>
640 </li>
641 ))}
642 </ul>
643 </section>
644 </main>
645
646 {/* FOOTER */}
647 <footer className="an-foot">
648 <div className="an-foot-top">
649 <form className="an-news" onSubmit={(e) => { e.preventDefault(); if (/\S+@\S+\.\S+/.test(email)) setJoined(true); }}>
650 <h2 className="an-news-t">Letters from the atelier</h2>
651 <p className="an-news-s">New collections a week early, sample sales in Stockholm and Copenhagen. Twice a season, never more.</p>
652 <label htmlFor="an-email" className="an-news-l">Email</label>
653 <div className="an-news-row">
654 <input id="an-email" type="email" required autoComplete="email" placeholder="name@domain.com" value={email} onChange={(e) => setEmail(e.target.value)} disabled={joined} />
655 <button type="submit" disabled={joined}>{joined ? "Subscribed ✓" : "Subscribe"}</button>
656 </div>
657 <p className="an-news-note" aria-live="polite">{joined ? `Tack — the next letter goes to ${email}.` : "By subscribing you accept our privacy policy."}</p>
658 </form>
659 <div className="an-foot-cols">
660 <div><p className="an-foot-h">Stores</p><ul><li>Hornsgatan 54, Stockholm</li><li>Ravnsborggade 9, København</li><li>Markveien 35, Oslo</li></ul></div>
661 <div><p className="an-foot-h">Help</p><ul>{["Shipping & returns", "Repairs", "Size guide", "Care", "Contact"].map((x) => <li key={x}><a href="#an-top">{x}</a></li>)}</ul></div>
662 <div><p className="an-foot-h">Atelier</p><ul>{["About", "Mills & makers", "Impact report 2025", "Careers", "Stockists"].map((x) => <li key={x}><a href="#an-top">{x}</a></li>)}</ul></div>
663 <div><p className="an-foot-h">Follow</p><ul>{["Instagram", "Pinterest", "Spotify — Stillhet playlist"].map((x) => <li key={x}><a href="#an-top">{x}</a></li>)}</ul></div>
664 </div>
665 </div>
666 <p className="an-foot-word" aria-hidden="true">ATELIER NORD</p>
667 <div className="an-foot-legal">
668 <span>© 2026 Atelier Nord AB · Org. nr 559301-4471 · Stockholm</span>
669 <span><a href="#an-top">Privacy</a><a href="#an-top">Terms</a><a href="#an-top">Cookies</a><a href="#an-top">EUR € / English</a></span>
670 </div>
671 </footer>
672
673 {/* CART DRAWER */}
674 <div className={`an-scrim${open ? " is-on" : ""}`} onClick={() => setOpen(false)} aria-hidden="true" />
675 <div ref={drawerRef} className={`an-drawer${open ? " is-open" : ""}`} role="dialog" aria-modal="true" aria-labelledby="an-bag-title" aria-hidden={!open} style={{ transform: "translate3d(104%,0,0)" }}>
676 <div className="an-drawer-head">
677 <h2 id="an-bag-title" className="an-drawer-t">Bag <span>({count})</span></h2>
678 <button ref={closeRef} type="button" className="an-x" onClick={() => setOpen(false)} aria-label="Close bag" tabIndex={open ? 0 : -1}><span /><span /></button>
679 </div>
680 <div className="an-ship">
681 <p>{subtotal >= FREE ? "You've unlocked free shipping." : `You're ${fmt(FREE - subtotal)} away from free shipping.`}</p>
682 <span className="an-ship-bar"><i style={{ transform: `scaleX(${Math.min(1, subtotal / FREE)})` }} /></span>
683 </div>
684 <ul className="an-lines">
685 {cart.length === 0 && <li className="an-empty">Your bag is empty.</li>}
686 {cart.map((c) => (
687 <li key={c.key} className="an-line">
688 <div className="an-line-img"><ProductShot kind={c.kind} color={c.color.hex} label="" /></div>
689 <div className="an-line-info">
690 <p className="an-line-name">{c.name}</p>
691 <p className="an-line-meta">{c.color.name} · {c.size}</p>
692 <div className="an-qty">
693 <button type="button" onClick={() => changeQty(c.key, -1)} aria-label={`Remove one ${c.name}`} tabIndex={open ? 0 : -1}>−</button>
694 <span>{c.qty}</span>
695 <button type="button" onClick={() => changeQty(c.key, 1)} aria-label={`Add one ${c.name}`} tabIndex={open ? 0 : -1}>+</button>
696 </div>
697 </div>
698 <p className="an-line-price">{fmt(c.price * c.qty)}</p>
699 </li>
700 ))}
701 </ul>
702 <div className="an-drawer-foot">
703 <p className="an-sub"><span>Subtotal</span><span>{fmt(subtotal)}</span></p>
704 <p className="an-sub-note">Taxes included. Shipping calculated at checkout.</p>
705 <button type="button" className="an-btn an-btn-ink an-btn-block" disabled={!cart.length} tabIndex={open ? 0 : -1}>Checkout</button>
706 </div>
707 </div>
708 </div>
709 );
710}
711
712export default Page;
713
714/* ------------------------------------------------------------------ */
715/* Styles */
716/* ------------------------------------------------------------------ */
717const GRAIN = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .55 0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E")`;
718
719const css = String.raw`
720.an {
721 --an-paper: #F2F1EE;
722 --an-white: #FFFFFF;
723 --an-studio: #E4E2DD;
724 --an-ink: #0E0E0E;
725 --an-graphite: #2A2A2A;
726 --an-grey: #66645F;
727 --an-line: rgba(14, 14, 14, 0.14);
728 --an-cond: "HelveticaNeue-CondensedBold", "Helvetica Neue Condensed Bold", "Helvetica Neue Condensed", "Arial Narrow", "Roboto Condensed", "Nimbus Sans Narrow", "TeX Gyre Heros Cn", "Liberation Sans Narrow", ui-sans-serif, sans-serif;
729 --an-sans: "Helvetica Neue", Helvetica, ui-sans-serif, -apple-system, "Inter", "Segoe UI", Roboto, Arial, sans-serif;
730 --fd-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
731 --fd-ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
732 --fd-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
733 --fd-dur-1: 120ms;
734 --fd-dur-2: 240ms;
735 --fd-dur-3: 420ms;
736 --fd-dur-4: 700ms;
737 --an-gut: 24px;
738 position: relative;
739 display: block;
740 width: 100%;
741 margin: 0;
742 padding: 0;
743 overflow-x: clip;
744 background: var(--an-paper);
745 color: var(--an-ink);
746 font: 400 14px/1.5 var(--an-sans);
747 letter-spacing: 0;
748 text-align: left;
749 -webkit-font-smoothing: antialiased;
750 -moz-osx-font-smoothing: grayscale;
751}
752.an *, .an *::before, .an *::after {
753 box-sizing: border-box;
754 margin: 0;
755 padding: 0;
756 border: 0 solid transparent;
757 font: inherit;
758 color: inherit;
759 letter-spacing: inherit;
760 text-decoration: none;
761 list-style: none;
762 background: none;
763 -webkit-appearance: none;
764 appearance: none;
765 min-width: 0;
766 font-style: normal;
767}
768.an :where(svg) { display: block; }
769.an :where(button) { cursor: pointer; text-align: inherit; line-height: inherit; border-radius: 0; }
770.an :where(button:disabled) { cursor: not-allowed; }
771.an :focus-visible { outline: 2px solid rgba(14, 14, 14, 0.7); outline-offset: 2px; }
772.an [hidden] { display: none !important; }
773.an-skip { position: absolute; left: 12px; top: -60px; z-index: 200; padding: 12px 16px; background: var(--an-ink); color: #fff; font: 500 13px/1 var(--an-sans); }
774.an-skip:focus { top: 12px; }
775.an-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
776.an-grain { position: relative; }
777.an-grain::after { content: ""; position: absolute; inset: 0; pointer-events: none; background-image: ${GRAIN}; background-size: 160px 160px; opacity: 0.2; mix-blend-mode: multiply; }
778.an-shot, .an-scene { display: block; width: 100%; height: 100%; max-width: none; }
779.an-shot { position: relative; overflow: hidden; }
780.an-shot img { position: absolute; inset: 0; display: block; width: 100%; height: 100%; max-width: none; object-fit: cover; mix-blend-mode: overlay; }
781.an-scene { object-fit: cover; }
782.an-fab { transition: fill var(--fd-dur-4) var(--fd-ease-in-out); }
783.an-fab-stroke { transition: stroke var(--fd-dur-4) var(--fd-ease-in-out); }
784
785.an-eyebrow { font: 500 12px/1.4 var(--an-sans); letter-spacing: 0.1em; text-transform: uppercase; color: var(--an-grey); }
786.an-h2 { font: 700 clamp(40px, 5vw, 76px)/0.88 var(--an-cond); font-stretch: condensed; letter-spacing: -0.015em; text-transform: uppercase; color: var(--an-ink); }
787.an-h2-xl { font-size: clamp(64px, 9vw, 150px); line-height: 0.82; letter-spacing: -0.025em; }
788.an-body { font: 400 16px/1.6 var(--an-sans); color: var(--an-graphite); }
789.an-link { display: inline-flex; align-items: center; min-height: 44px; font: 500 13px/1 var(--an-sans); letter-spacing: 0.08em; text-transform: uppercase; color: var(--an-ink); background-image: linear-gradient(currentColor, currentColor); background-size: 100% 1px; background-repeat: no-repeat; background-position: 0 calc(50% + 10px); transition: background-size var(--fd-dur-3) var(--fd-ease-out); }
790.an-link:hover { background-size: 0% 1px; background-position: 100% calc(50% + 10px); }
791.an-btn { display: inline-flex; align-items: center; justify-content: center; gap: 12px; min-height: 52px; padding: 0 28px; font: 500 13px/1 var(--an-sans); letter-spacing: 0.1em; text-transform: uppercase; white-space: nowrap; transition: background-color var(--fd-dur-2) var(--fd-ease-out), color var(--fd-dur-2) var(--fd-ease-out), transform var(--fd-dur-2) var(--fd-spring); }
792.an-btn span { transition: transform var(--fd-dur-3) var(--fd-ease-out); }
793.an-btn:hover span { transform: translateX(4px); }
794.an-btn:active { transform: scale(0.97); transition-duration: var(--fd-dur-1); }
795.an-btn-ink { background: var(--an-ink); color: #FFFFFF; }
796.an-btn-ink:hover { background: #333; }
797.an-btn-ink:disabled { background: #9A9893; }
798.an-btn-block { width: 100%; }
799
800/* Cursor label */
801.an-cursor { position: absolute; left: 0; top: 0; z-index: 90; display: grid; place-items: center; width: 84px; height: 84px; margin: -42px 0 0 -42px; border-radius: 50%; background: var(--an-ink); color: #FFFFFF; font: 500 12px/1 var(--an-sans); letter-spacing: 0.12em; text-transform: uppercase; pointer-events: none; scale: 0; transition: scale var(--fd-dur-3) var(--fd-spring); will-change: transform; }
802.an-cursor.is-on { scale: 1; }
803
804/* Announcement + NAV */
805.an-announce { padding: 10px var(--an-gut); background: var(--an-ink); color: #EDEDEA; font: 400 12px/1.4 var(--an-sans); letter-spacing: 0.06em; text-align: center; }
806.an-nav { position: sticky; top: 0; z-index: 70; }
807.an-nav-in { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; height: 72px; padding: 0 var(--an-gut); background: var(--an-paper); border-bottom: 1px solid transparent; transition: height var(--fd-dur-3) var(--fd-ease-out), border-color var(--fd-dur-3) var(--fd-ease-out), background-color var(--fd-dur-3) var(--fd-ease-out); }
808.an-nav.is-small .an-nav-in { height: 52px; border-bottom-color: var(--an-line); background: rgba(242, 241, 238, 0.9); -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px); }
809.an-nav-l { display: flex; align-items: center; gap: 22px; }
810.an-nav-l a, .an-nav-txt { display: inline-flex; align-items: center; min-height: 44px; font: 500 12px/1 var(--an-sans); letter-spacing: 0.08em; text-transform: uppercase; color: var(--an-ink); }
811.an-nav-l a:hover, .an-nav-txt:hover { text-decoration: underline; text-underline-offset: 4px; }
812.an-logo { font: 700 30px/1 var(--an-cond); font-stretch: condensed; letter-spacing: 0.04em; text-transform: uppercase; color: var(--an-ink); white-space: nowrap; transition: font-size var(--fd-dur-3) var(--fd-ease-out), letter-spacing var(--fd-dur-3) var(--fd-ease-out); }
813.an-nav.is-small .an-logo { font-size: 22px; letter-spacing: 0.08em; }
814.an-nav-r { display: flex; align-items: center; justify-content: flex-end; gap: 22px; }
815.an-bag-btn { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; font: 500 12px/1 var(--an-sans); letter-spacing: 0.08em; text-transform: uppercase; color: var(--an-ink); }
816.an-bag-n { display: inline-grid; place-items: center; min-width: 22px; height: 22px; padding: 0 6px; border-radius: 9999px; background: var(--an-ink); color: #FFFFFF; font: 500 11px/1 var(--an-sans); letter-spacing: 0; }
817.an-bag-n.is-bump { animation: an-bump 600ms var(--fd-spring); }
818@keyframes an-bump { 0% { transform: scale(1); } 30% { transform: scale(1.5); } 100% { transform: scale(1); } }
819.an-burger { display: none; position: relative; width: 44px; height: 44px; margin-left: -10px; }
820.an-burger span { position: absolute; left: 11px; right: 11px; height: 1.5px; background: var(--an-ink); transition: transform var(--fd-dur-3) var(--fd-ease-out); }
821.an-burger span:first-child { top: 18px; }
822.an-burger span:last-child { top: 25px; }
823.an-nav.is-open .an-burger span:first-child { transform: translateY(3.5px) rotate(45deg); }
824.an-nav.is-open .an-burger span:last-child { transform: translateY(-3.5px) rotate(-45deg); }
825.an-sheet { display: flex; flex-direction: column; padding: 8px var(--an-gut) 24px; background: var(--an-paper); border-bottom: 1px solid var(--an-line); }
826.an-sheet a { padding: 10px 0; font: 700 44px/1 var(--an-cond); font-stretch: condensed; text-transform: uppercase; color: var(--an-ink); }
827
828/* MASTHEAD */
829.an-mast { position: relative; display: grid; grid-template-columns: 1fr; grid-template-rows: auto 1fr auto auto; min-height: calc(100vh - 110px); min-height: calc(100svh - 110px); padding: 20px var(--an-gut) 28px; --p: 0; overflow: hidden; }
830.an-mast-meta { display: flex; justify-content: space-between; gap: 24px; font: 500 12px/1.5 var(--an-sans); letter-spacing: 0.08em; text-transform: uppercase; color: var(--an-ink); position: relative; z-index: 3; }
831.an-mast > .an-word { isolation: auto; }
832.an-mast-meta em { font-style: italic; }
833.an-mast-meta-r { text-align: right; color: var(--an-grey); }
834.an-mast-img { position: absolute; right: 9vw; top: 84px; z-index: 2; width: 24vw; margin: 0; transform: translate3d(0, calc(var(--p) * 120px), 0); }
835.an-mast-img-in { aspect-ratio: 3 / 4; overflow: hidden; background: var(--an-studio); }
836.an-mast-img-in .an-scene { transform: scale(calc(1.12 + var(--p) * 0.12)); transform-origin: 50% 30%; }
837.an-mast-img figcaption { margin-top: 10px; font: 500 11px/1.4 var(--an-sans); letter-spacing: 0.08em; text-transform: uppercase; color: var(--an-grey); }
838.an-word { grid-row: 3; position: relative; z-index: 3; mix-blend-mode: difference; color: #FFFFFF; display: flex; flex-direction: column; font: 700 22.6vw/0.78 var(--an-cond); font-stretch: condensed; letter-spacing: -0.02em; text-transform: uppercase; margin: 0; }
839.an-word-line { display: flex; width: max-content; white-space: nowrap; }
840.an-word-line-2 { justify-content: flex-start; padding-left: 0; }
841.an-ch { display: inline-block; overflow: hidden; padding: 0.04em 0 0.02em; margin: -0.04em 0 -0.02em; transform: translate3d(0, calc(var(--p) * var(--dy) * 1px), 0) rotate(calc(var(--p) * var(--rot) * 1deg)); will-change: transform; }
842.an-ch > span { display: inline-block; animation: an-rise 1.1s var(--fd-ease-out) both; animation-delay: calc(var(--i) * 45ms + 120ms); }
843@keyframes an-rise { from { transform: translateY(102%); } to { transform: none; } }
844.an-mast-foot { grid-row: 4; position: relative; z-index: 3; display: flex; align-items: flex-end; justify-content: space-between; gap: 32px; margin-top: 24px; padding-top: 18px; border-top: 1px solid var(--an-ink); }
845.an-mast-foot p { max-width: 420px; font: 400 16px/1.5 var(--an-sans); color: var(--an-graphite); }
846
847/* STATEMENT */
848.an-statement { display: grid; grid-template-columns: 1fr 3fr; gap: var(--an-gut); padding: 160px var(--an-gut) 180px; }
849.an-statement-n { font: 500 12px/1.6 var(--an-sans); letter-spacing: 0.08em; color: var(--an-grey); }
850.an-statement-t { font: 400 clamp(28px, 3.4vw, 52px)/1.12 var(--an-sans); letter-spacing: -0.03em; color: var(--an-ink); text-indent: 12%; }
851.an-statement-t em { font-style: italic; }
852.an-inline-img { display: inline-block; width: 1.9em; height: 0.82em; margin: 0 0.12em; vertical-align: -0.06em; overflow: hidden; border-radius: 9999px; background: #2E2E2E; }
853.an-inline-img .an-scene { width: 100%; height: 100%; }
854
855/* REVEALS */
856.an-js [data-an-rv] { opacity: 0; transform: translate3d(0, 32px, 0); transition: opacity 900ms var(--fd-ease-out), transform 1s var(--fd-ease-out); transition-delay: var(--d, 0ms); }
857.an-js [data-an-rv].is-in { opacity: 1; transform: none; }
858
859/* LOOKBOOK */
860.an-look { position: relative; background: var(--an-paper); --e: 1; }
861.an-look.is-zoom { height: 320vh; height: 320svh; --e: 0; }
862.an-look-stage { position: relative; padding: 80px var(--an-gut); }
863.an-look.is-zoom .an-look-stage { position: sticky; top: 0; height: 100vh; height: 100svh; padding: 0 var(--an-gut); overflow: hidden; display: flex; align-items: center; justify-content: center; }
864.an-look-head { position: relative; z-index: 3; display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; margin-bottom: 32px; font: 500 12px/1.4 var(--an-sans); letter-spacing: 0.08em; text-transform: uppercase; color: var(--an-grey); }
865.an-look.is-zoom .an-look-head { position: absolute; left: var(--an-gut); right: var(--an-gut); top: 72px; margin: 0; opacity: calc((var(--e) - 0.75) * 4); transform: translate3d(0, calc((1 - var(--e)) * 30px), 0); }
866.an-look-grid { position: relative; display: grid; grid-template-columns: repeat(12, 1fr); grid-template-rows: repeat(6, minmax(0, 1fr)); gap: 14px; width: 100%; max-width: 1400px; height: min(66vh, 640px); will-change: transform; }
867.an-tile { position: relative; margin: 0; transform: translate3d(0, calc((1 - var(--e)) * var(--k) * 1px), 0); }
868.an-tile-img { width: 100%; height: 100%; overflow: hidden; background: var(--an-studio); }
869.an-tile-cap { position: absolute; left: 0; bottom: -22px; font: 500 11px/1.4 var(--an-sans); letter-spacing: 0.08em; text-transform: uppercase; color: var(--an-grey); white-space: nowrap; opacity: calc((var(--e) - 0.8) * 5); }
870.an-tile-0 { grid-column: 1 / 3; grid-row: 1 / 4; }
871.an-tile-1 { grid-column: 1 / 4; grid-row: 4 / 7; }
872.an-tile-2 { grid-column: 3 / 5; grid-row: 1 / 4; }
873.an-tile-3 { grid-column: 5 / 9; grid-row: 2 / 6; }
874.an-tile-4 { grid-column: 9 / 11; grid-row: 1 / 4; }
875.an-tile-5 { grid-column: 11 / 13; grid-row: 1 / 5; }
876.an-tile-6 { grid-column: 9 / 11; grid-row: 4 / 7; }
877.an-tile-1, .an-tile-6 { margin-top: 18px; }
878.an-look-over { position: absolute; z-index: 2; left: 50%; top: 50%; font: 700 15vw/0.8 var(--an-cond); font-stretch: condensed; text-transform: uppercase; letter-spacing: -0.02em; color: #FFFFFF; mix-blend-mode: difference; pointer-events: none; white-space: nowrap; transform: translate3d(-50%, -50%, 0) scale(calc(1 + (1 - var(--e)) * 0.25)); opacity: calc(1 - var(--e) * 2.4); }
879.an-look:not(.is-zoom) .an-look-over { display: none; }
880
881/* SHOP */
882.an-shop { padding: 140px var(--an-gut) 120px; background: var(--an-white); }
883.an-shop-head { display: grid; grid-template-columns: 1.4fr 1fr auto; align-items: end; gap: var(--an-gut); margin-bottom: 72px; }
884.an-shop-head p { max-width: 380px; font: 400 15px/1.55 var(--an-sans); color: var(--an-graphite); }
885.an-grid { display: grid; grid-template-columns: repeat(12, 1fr); column-gap: var(--an-gut); row-gap: 72px; align-items: start; }
886.an-p-a { grid-column: 1 / 6; }
887.an-p-b { grid-column: 7 / 10; margin-top: 160px; }
888.an-p-c { grid-column: 10 / 13; margin-top: 40px; }
889.an-p-d { grid-column: 2 / 5; }
890.an-p-e { grid-column: 6 / 9; margin-top: 120px; }
891.an-p-f { grid-column: 9 / 13; margin-top: -60px; }
892.an-card-media { position: relative; overflow: hidden; background: var(--an-studio); cursor: none; }
893.an-card-img { display: block; aspect-ratio: 4 / 5; overflow: hidden; }
894.an-card-img .an-shot { transition: transform 1.2s var(--fd-ease-out); }
895.an-card-media:hover .an-card-img .an-shot { transform: scale(1.04); }
896.an-tag { position: absolute; left: 14px; top: 14px; padding: 6px 10px; background: var(--an-white); font: 500 11px/1 var(--an-sans); letter-spacing: 0.08em; text-transform: uppercase; color: var(--an-ink); }
897.an-card-info { display: flex; justify-content: space-between; gap: 16px; margin-top: 14px; }
898.an-card-name { font: 500 14px/1.35 var(--an-sans); letter-spacing: 0.04em; text-transform: uppercase; color: var(--an-ink); }
899.an-card-fab { margin-top: 3px; font: 400 13px/1.4 var(--an-sans); color: var(--an-grey); }
900.an-card-col { display: inline-block; animation: an-fadein var(--fd-dur-3) var(--fd-ease-out); }
901.an-card-price { font: 500 14px/1.35 var(--an-sans); color: var(--an-ink); font-variant-numeric: tabular-nums; }
902.an-sw { display: flex; gap: 4px; margin-top: 8px; margin-left: -8px; }
903.an-sw button { position: relative; width: 36px; height: 36px; border-radius: 50%; }
904.an-sw button::before { content: ""; position: absolute; inset: 10px; border-radius: 50%; background: var(--c); box-shadow: inset 0 0 0 1px rgba(14, 14, 14, 0.18); transition: inset var(--fd-dur-2) var(--fd-spring); }
905.an-sw button::after { content: ""; position: absolute; inset: 6px; border-radius: 50%; box-shadow: 0 0 0 1px var(--an-ink); opacity: 0; transform: scale(0.7); transition: opacity var(--fd-dur-2) var(--fd-ease-out), transform var(--fd-dur-3) var(--fd-spring); }
906.an-sw button.is-on::after { opacity: 1; transform: none; }
907.an-sw button:hover::before { inset: 9px; }
908@keyframes an-fadein { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
909
910/* Quick add morph */
911.an-qa { position: absolute; left: 12px; right: 12px; bottom: 12px; height: 48px; display: flex; align-items: stretch; background: var(--an-white); clip-path: inset(0 calc(100% - 132px) 0 0); transform: translateY(8px); opacity: 0; transition: clip-path var(--fd-dur-3) var(--fd-ease-out), transform var(--fd-dur-3) var(--fd-ease-out), opacity var(--fd-dur-2) var(--fd-ease-out), background-color var(--fd-dur-3) var(--fd-ease-out); }
912.an-card-media:hover .an-qa, .an-qa:focus-within, .an-qa.is-pick, .an-qa.is-added { opacity: 1; transform: none; }
913.an-qa.is-pick { clip-path: inset(0 0 0 0); }
914.an-qa.is-added { clip-path: inset(0 calc(100% - 132px) 0 0); background: var(--an-ink); color: #FFFFFF; }
915.an-qa-main { flex: none; display: flex; align-items: center; gap: 10px; width: 132px; padding: 0 16px; font: 500 12px/1 var(--an-sans); letter-spacing: 0.08em; text-transform: uppercase; color: inherit; }
916.an-qa-main:disabled { cursor: default; }
917.an-qa-plus { position: relative; width: 12px; height: 12px; flex: none; transition: transform var(--fd-dur-3) var(--fd-ease-out); }
918.an-qa-plus::before, .an-qa-plus::after { content: ""; position: absolute; left: 0; top: 5.25px; width: 12px; height: 1.5px; background: currentColor; transition: transform var(--fd-dur-3) var(--fd-ease-out), width var(--fd-dur-3) var(--fd-ease-out); }
919.an-qa-plus::after { transform: rotate(90deg); }
920.an-qa.is-pick .an-qa-plus { transform: rotate(45deg); }
921.an-qa.is-added .an-qa-plus { transform: rotate(-45deg) translate(1px, -1px); }
922.an-qa.is-added .an-qa-plus::before { width: 6px; top: 8px; left: 0; transform: rotate(90deg) translateX(-3px); transform-origin: left; }
923.an-qa.is-added .an-qa-plus::after { width: 12px; top: 8px; transform: none; }
924.an-qa-sizes { flex: 1; display: grid; grid-template-columns: repeat(5, 1fr); border-left: 1px solid var(--an-line); }
925.an-qa-sizes button { font: 500 12px/1 var(--an-sans); letter-spacing: 0.06em; color: var(--an-ink); text-align: center; opacity: 0; transform: translateX(-8px); transition: opacity var(--fd-dur-2) var(--fd-ease-out), transform var(--fd-dur-3) var(--fd-ease-out), background-color var(--fd-dur-1) var(--fd-ease-out); }
926.an-qa.is-pick .an-qa-sizes button { opacity: 1; transform: none; }
927.an-qa.is-pick .an-qa-sizes button:nth-child(2) { transition-delay: 30ms; }
928.an-qa.is-pick .an-qa-sizes button:nth-child(3) { transition-delay: 60ms; }
929.an-qa.is-pick .an-qa-sizes button:nth-child(4) { transition-delay: 90ms; }
930.an-qa.is-pick .an-qa-sizes button:nth-child(5) { transition-delay: 120ms; }
931.an-qa-sizes button:hover:not(:disabled) { background: var(--an-paper); }
932.an-qa-sizes button:disabled { color: #8D8B86; text-decoration: line-through; }
933
934/* PRESS */
935.an-press { padding: 56px 0; background: var(--an-ink); color: #F2F1EE; overflow: hidden; }
936.an-marquee-track { display: flex; width: max-content; animation: an-marq 60s linear infinite; }
937.an-press:hover .an-marquee-track { animation-play-state: paused; }
938.an-marquee-set { display: flex; }
939.an-marquee-set li { display: flex; align-items: baseline; gap: 18px; padding-right: 18px; white-space: nowrap; }
940.an-marquee-set blockquote { font: 700 clamp(40px, 5vw, 72px)/1 var(--an-cond); font-stretch: condensed; letter-spacing: -0.01em; text-transform: uppercase; }
941.an-marquee-set cite { font: 500 12px/1 var(--an-sans); letter-spacing: 0.1em; text-transform: uppercase; color: #B9B7B2; }
942.an-star { font: 400 36px/1 var(--an-sans); color: #8C8A85; margin-left: 40px; }
943@keyframes an-marq { to { transform: translateX(-50%); } }
944
945/* FEATURE */
946.an-feature { display: grid; grid-template-columns: 7fr 5fr; gap: var(--an-gut); padding: 140px var(--an-gut); background: var(--an-paper); }
947.an-feature-media { position: sticky; top: 76px; align-self: start; cursor: none; }
948.an-feature-img { aspect-ratio: 4 / 5; overflow: hidden; background: var(--an-studio); max-height: calc(100vh - 100px); margin: 0 auto; }
949.an-hot { position: absolute; z-index: 2; display: grid; place-items: center; width: 44px; height: 44px; margin: -22px 0 0 -22px; cursor: pointer; }
950.an-hot span { display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; background: #FFFFFF; color: var(--an-ink); font: 500 12px/1 var(--an-sans); box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.6); animation: an-ping 2.4s var(--fd-ease-out) infinite; }
951@keyframes an-ping { 0% { box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.6); } 80%, 100% { box-shadow: 0 0 0 14px rgba(255, 255, 255, 0); } }
952.an-hot em { position: absolute; left: 50%; bottom: calc(100% + 4px); width: 220px; padding: 10px 12px; background: #FFFFFF; color: var(--an-ink); font: 400 13px/1.4 var(--an-sans); text-align: left; opacity: 0; transform: translate(-50%, 6px); pointer-events: none; transition: opacity var(--fd-dur-2) var(--fd-ease-out), transform var(--fd-dur-3) var(--fd-ease-out); }
953.an-hot:hover em, .an-hot:focus-visible em { opacity: 1; transform: translate(-50%, 0); }
954.an-feature-text { padding: 40px 0 0 4vw; }
955.an-feature-text .an-h2 { margin: 20px 0 32px; }
956.an-feature-text .an-body { max-width: 460px; }
957.an-specs { margin-top: 48px; border-top: 1px solid var(--an-ink); }
958.an-specs div { display: grid; grid-template-columns: 110px 1fr; gap: 16px; padding: 16px 0; border-bottom: 1px solid var(--an-line); }
959.an-specs dt { font: 500 12px/1.5 var(--an-sans); letter-spacing: 0.08em; text-transform: uppercase; color: var(--an-grey); }
960.an-specs dd { font: 400 15px/1.5 var(--an-sans); color: var(--an-ink); }
961.an-feature-cta { display: flex; align-items: center; gap: 28px; margin-top: 40px; }
962
963/* MATERIALS */
964.an-mat { padding: 140px var(--an-gut); background: var(--an-white); }
965.an-mat-head { display: grid; grid-template-columns: 1fr 2fr; gap: var(--an-gut); margin-bottom: 64px; }
966.an-mat-head .an-h2 { max-width: 14ch; }
967.an-mat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--an-gut); }
968.an-mat-sw { aspect-ratio: 1; overflow: hidden; background: var(--an-studio); }
969.an-tx { display: block; width: 100%; height: 100%; transition: transform 1.2s var(--fd-ease-out); }
970.an-mat-card:hover .an-tx { transform: scale(1.5); }
971.an-tx-hb { background-color: #3A3A3A; }
972.an-tx-hb { background-image: linear-gradient(90deg, transparent 50%, rgba(0,0,0,.06) 50%), repeating-linear-gradient(45deg, rgba(255,255,255,.1) 0 2px, transparent 2px 6px), repeating-linear-gradient(-45deg, rgba(255,255,255,.1) 0 2px, transparent 2px 6px); background-size: 28px 100%, 28px 28px, 28px 28px; }
973.an-tx-knit { background-color: #E6E0D3; background-image: radial-gradient(ellipse 5px 9px at 50% 50%, rgba(0,0,0,.14) 60%, transparent 62%), radial-gradient(ellipse 5px 9px at 50% 50%, rgba(255,255,255,.5) 40%, transparent 42%); background-size: 12px 14px, 12px 14px; background-position: 0 0, 6px 7px; }
974.an-tx-boucle { background-color: #C9C9C6; background-image: radial-gradient(circle at 30% 30%, rgba(255,255,255,.7) 0 2px, transparent 3px), radial-gradient(circle at 70% 60%, rgba(0,0,0,.18) 0 3px, transparent 4px), radial-gradient(circle at 50% 80%, rgba(255,255,255,.5) 0 2.5px, transparent 3.5px), radial-gradient(circle at 20% 70%, rgba(0,0,0,.12) 0 2px, transparent 3px); background-size: 11px 11px, 13px 13px, 9px 9px, 15px 15px; }
975.an-tx-poplin { background-color: #F1EEE7; background-image: repeating-linear-gradient(0deg, rgba(0,0,0,.05) 0 1px, transparent 1px 3px), repeating-linear-gradient(90deg, rgba(0,0,0,.04) 0 1px, transparent 1px 3px), linear-gradient(120deg, rgba(255,255,255,.6), rgba(0,0,0,.06)); }
976.an-mat-name { margin-top: 18px; font: 500 14px/1.35 var(--an-sans); letter-spacing: 0.04em; text-transform: uppercase; color: var(--an-ink); }
977.an-mat-from { margin-top: 4px; font: 400 14px/1.4 var(--an-sans); color: var(--an-graphite); }
978.an-mat-spec { margin-top: 2px; font: 400 13px/1.4 var(--an-sans); color: var(--an-grey); }
979
980/* JOURNAL */
981.an-journal { padding: 140px var(--an-gut); background: var(--an-paper); }
982.an-journal-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; margin-bottom: 56px; }
983.an-journal-grid { display: grid; grid-template-columns: 5fr 3fr 4fr; gap: var(--an-gut); align-items: start; }
984.an-story:nth-child(2) { margin-top: 120px; }
985.an-story:nth-child(3) { margin-top: 40px; }
986.an-story a { display: block; color: var(--an-ink); }
987.an-story-img { aspect-ratio: 4 / 5; overflow: hidden; background: var(--an-studio); }
988.an-story:first-child .an-story-img { aspect-ratio: 5 / 4; }
989.an-story-img .an-scene { transition: transform 1.2s var(--fd-ease-out); }
990.an-story a:hover .an-story-img .an-scene { transform: scale(1.05); }
991.an-story-date { margin-top: 16px; font: 500 12px/1.4 var(--an-sans); letter-spacing: 0.08em; text-transform: uppercase; color: var(--an-grey); }
992.an-story-t { margin-top: 8px; font: 400 22px/1.25 var(--an-sans); letter-spacing: -0.02em; color: var(--an-ink); max-width: 30ch; }
993.an-story a:hover .an-story-t { text-decoration: underline; text-underline-offset: 4px; text-decoration-thickness: 1px; }
994
995/* FOOTER */
996.an-foot { padding: 96px var(--an-gut) 28px; background: var(--an-ink); color: #EDEDEA; overflow: hidden; }
997.an-foot-top { display: grid; grid-template-columns: 5fr 7fr; gap: 64px; }
998.an-news-t { font: 700 44px/0.9 var(--an-cond); font-stretch: condensed; text-transform: uppercase; color: #FFFFFF; }
999.an-news-s { margin-top: 14px; max-width: 420px; font: 400 15px/1.55 var(--an-sans); color: #BDBBB6; }
1000.an-news-l { display: block; margin-top: 28px; font: 500 12px/1 var(--an-sans); letter-spacing: 0.08em; text-transform: uppercase; color: #BDBBB6; }
1001.an-news-row { display: flex; margin-top: 10px; border-bottom: 1px solid #EDEDEA; }
1002.an-news-row input { flex: 1; height: 52px; font: 400 18px/1 var(--an-sans); color: #FFFFFF; outline: none; }
1003.an-news-row input::placeholder { color: #8C8A85; }
1004.an-news-row button { padding: 0 4px 0 16px; font: 500 12px/1 var(--an-sans); letter-spacing: 0.1em; text-transform: uppercase; color: #FFFFFF; min-height: 52px; }
1005.an-news-row:focus-within { border-bottom-color: #FFFFFF; box-shadow: 0 1px 0 #FFFFFF; }
1006.an-news-note { margin-top: 10px; font: 400 12px/1.5 var(--an-sans); color: #A7A5A0; }
1007.an-foot-cols { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--an-gut); }
1008.an-foot-h { margin-bottom: 14px; font: 500 12px/1 var(--an-sans); letter-spacing: 0.08em; text-transform: uppercase; color: #A7A5A0; }
1009.an-foot-cols li { margin-bottom: 8px; font: 400 14px/1.45 var(--an-sans); color: #EDEDEA; }
1010.an-foot-cols a:hover { text-decoration: underline; text-underline-offset: 3px; }
1011.an-foot-word { margin: 96px -0.02em 0; font: 700 16.2vw/0.78 var(--an-cond); font-stretch: condensed; letter-spacing: -0.02em; color: #FFFFFF; white-space: nowrap; text-align: center; }
1012.an-foot-legal { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 12px; margin-top: 28px; padding-top: 18px; border-top: 1px solid rgba(237, 237, 234, 0.2); font: 400 12px/1.5 var(--an-sans); color: #A7A5A0; }
1013.an-foot-legal span:last-child { display: flex; flex-wrap: wrap; gap: 18px; }
1014.an-foot-legal a:hover { color: #FFFFFF; }
1015
1016/* DRAWER */
1017.an-scrim { position: fixed; inset: 0; z-index: 95; background: rgba(14, 14, 14, 0.4); opacity: 0; pointer-events: none; transition: opacity var(--fd-dur-3) var(--fd-ease-out); }
1018.an-scrim.is-on { opacity: 1; pointer-events: auto; }
1019.an-drawer { position: fixed; top: 0; right: 0; bottom: 0; z-index: 100; display: flex; flex-direction: column; width: min(440px, 100vw); background: var(--an-white); box-shadow: -30px 0 60px -30px rgba(0, 0, 0, 0.35); will-change: transform; visibility: hidden; transition: visibility 0s linear 600ms; }
1020.an-drawer.is-open { visibility: visible; transition: none; }
1021.an-drawer-head { display: flex; align-items: center; justify-content: space-between; height: 72px; padding: 0 var(--an-gut); border-bottom: 1px solid var(--an-line); }
1022.an-drawer-t { font: 700 32px/1 var(--an-cond); font-stretch: condensed; text-transform: uppercase; color: var(--an-ink); }
1023.an-drawer-t span { color: var(--an-grey); }
1024.an-x { position: relative; width: 44px; height: 44px; margin-right: -10px; }
1025.an-x span { position: absolute; left: 12px; right: 12px; top: 21px; height: 1.5px; background: var(--an-ink); transform: rotate(45deg); }
1026.an-x span:last-child { transform: rotate(-45deg); }
1027.an-ship { padding: 16px var(--an-gut); border-bottom: 1px solid var(--an-line); font: 400 13px/1.4 var(--an-sans); color: var(--an-graphite); }
1028.an-ship-bar { position: relative; display: block; height: 2px; margin-top: 10px; background: var(--an-line); }
1029.an-ship-bar i { position: absolute; inset: 0; background: var(--an-ink); transform-origin: left; transition: transform var(--fd-dur-4) var(--fd-ease-out); }
1030.an-lines { flex: 1; overflow-y: auto; padding: 8px var(--an-gut); }
1031.an-empty { padding: 40px 0; font: 400 15px/1.5 var(--an-sans); color: var(--an-grey); }
1032.an-line { display: grid; grid-template-columns: 84px 1fr auto; gap: 16px; padding: 16px 0; border-bottom: 1px solid var(--an-line); animation: an-fadein var(--fd-dur-3) var(--fd-ease-out); }
1033.an-line-img { aspect-ratio: 4 / 5; overflow: hidden; background: var(--an-studio); }
1034.an-line-name { font: 500 13px/1.35 var(--an-sans); letter-spacing: 0.04em; text-transform: uppercase; color: var(--an-ink); }
1035.an-line-meta { margin-top: 4px; font: 400 13px/1.4 var(--an-sans); color: var(--an-grey); }
1036.an-qty { display: inline-flex; align-items: center; margin-top: 12px; border: 1px solid var(--an-line); }
1037.an-qty button { width: 36px; height: 36px; font: 400 16px/1 var(--an-sans); color: var(--an-ink); text-align: center; }
1038.an-qty button:hover { background: var(--an-paper); }
1039.an-qty span { min-width: 24px; font: 500 13px/1 var(--an-sans); text-align: center; font-variant-numeric: tabular-nums; }
1040.an-line-price { font: 500 13px/1.35 var(--an-sans); color: var(--an-ink); font-variant-numeric: tabular-nums; }
1041.an-drawer-foot { padding: 20px var(--an-gut) 24px; border-top: 1px solid var(--an-line); }
1042.an-sub { display: flex; justify-content: space-between; font: 500 14px/1 var(--an-sans); letter-spacing: 0.06em; text-transform: uppercase; color: var(--an-ink); }
1043.an-sub-note { margin: 8px 0 16px; font: 400 12px/1.4 var(--an-sans); color: var(--an-grey); }
1044
1045/* RESPONSIVE */
1046@media (max-width: 1080px) {
1047 .an-nav-l a, .an-nav-txt { display: none; }
1048 .an-burger { display: block; }
1049 .an-mast-img { width: 32vw; right: 6vw; }
1050 .an-shop-head { grid-template-columns: 1fr 1fr; }
1051 .an-shop-head .an-link { grid-column: 2; }
1052 .an-mat-grid { grid-template-columns: repeat(2, 1fr); row-gap: 40px; }
1053 .an-foot-top { grid-template-columns: 1fr; }
1054}
1055@media (max-width: 760px) {
1056 .an { --an-gut: 16px; }
1057 .an-announce { font-size: 11px; }
1058 .an-nav-in { height: 60px; }
1059 .an-logo { font-size: 24px; }
1060 .an-nav.is-small .an-logo { font-size: 20px; }
1061 .an-mast { min-height: 0; padding-top: 16px; grid-template-rows: auto auto auto auto; }
1062 .an-mast-meta-r { display: none; }
1063 .an-mast-img { position: relative; right: auto; top: auto; grid-row: 2; width: 72%; margin: 20px 0 0 auto; transform: translate3d(0, calc(var(--p) * 60px), 0); }
1064 .an-word { font-size: 25.4vw; margin-top: -18vw; }
1065 .an-mast-foot { flex-direction: column; align-items: flex-start; gap: 18px; }
1066 .an-mast-foot .an-btn { width: 100%; }
1067 .an-statement { grid-template-columns: 1fr; padding: 96px var(--an-gut); }
1068 .an-statement-t { text-indent: 0; font-size: 28px; }
1069 .an-look-stage { padding: 72px var(--an-gut); }
1070 .an-look-head { flex-direction: column; align-items: flex-start; gap: 8px; }
1071 .an-look-grid { grid-template-columns: repeat(2, 1fr); grid-template-rows: none; grid-auto-rows: 200px; height: auto; gap: 10px; }
1072 .an-tile { grid-column: auto !important; grid-row: auto !important; margin: 0 !important; transform: none; }
1073 .an-tile-3 { grid-column: 1 / -1 !important; grid-row: span 2 !important; order: -1; }
1074 .an-tile-cap { position: static; margin-top: 6px; opacity: 1; }
1075 .an-look-grid { row-gap: 34px; }
1076 .an-shop { padding: 96px var(--an-gut); }
1077 .an-shop-head { grid-template-columns: 1fr; gap: 16px; margin-bottom: 48px; }
1078 .an-shop-head .an-link { grid-column: auto; }
1079 .an-grid { grid-template-columns: 1fr 1fr; column-gap: 10px; row-gap: 40px; }
1080 .an-card { grid-column: auto !important; margin-top: 0 !important; }
1081 .an-p-a, .an-p-f { grid-column: 1 / -1 !important; }
1082 .an-card-name { font-size: 12px; }
1083 .an-card-fab { font-size: 12px; }
1084 .an-card-info { flex-direction: column; gap: 4px; }
1085 .an-qa { opacity: 1; transform: none; left: 8px; right: 8px; bottom: 8px; height: 44px; clip-path: inset(0 calc(100% - 44px) 0 0); }
1086 .an-qa-main { width: 44px; padding: 0 16px; }
1087 .an-qa-txt { display: none; }
1088 .an-qa.is-pick { clip-path: inset(0 0 0 0); height: auto; flex-wrap: wrap; }
1089 .an-qa.is-pick .an-qa-sizes { flex-basis: 100%; grid-template-columns: repeat(3, 1fr); border-left: 0; border-top: 1px solid var(--an-line); }
1090 .an-qa.is-pick .an-qa-sizes button { min-height: 44px; }
1091 .an-qa.is-added { clip-path: inset(0 calc(100% - 44px) 0 0); }
1092 .an-mast-img figcaption { display: none; }
1093 .an-journal-head .an-link { white-space: nowrap; }
1094 .an-card-media { cursor: auto; }
1095 .an-feature { grid-template-columns: 1fr; padding: 96px var(--an-gut); }
1096 .an-feature-media { position: relative; top: auto; }
1097 .an-feature-text { padding: 32px 0 0; }
1098 .an-feature-cta { flex-direction: column; align-items: stretch; gap: 8px; }
1099 .an-hot em { width: 180px; }
1100 .an-mat { padding: 96px var(--an-gut); }
1101 .an-mat-head { grid-template-columns: 1fr; gap: 16px; margin-bottom: 40px; }
1102 .an-mat-grid { gap: 10px; row-gap: 32px; }
1103 .an-journal { padding: 96px var(--an-gut); }
1104 .an-journal-grid { grid-template-columns: 1fr; gap: 40px; }
1105 .an-story:nth-child(n) { margin-top: 0; }
1106 .an-story-t { font-size: 20px; }
1107 .an-foot { padding-top: 72px; }
1108 .an-foot-cols { grid-template-columns: 1fr 1fr; row-gap: 32px; }
1109 .an-foot-word { margin-top: 64px; }
1110 .an-specs div { grid-template-columns: 90px 1fr; }
1111}
1112@media (hover: none) {
1113 .an-cursor { display: none; }
1114 .an-card-media, .an-feature-media { cursor: auto; }
1115 .an-qa { opacity: 1; transform: none; }
1116}
1117@media (prefers-reduced-motion: reduce) {
1118 .an *, .an *::before, .an *::after { animation-duration: 1ms !important; animation-iteration-count: 1 !important; animation-delay: 0ms !important; transition-duration: 120ms !important; transition-delay: 0ms !important; }
1119 .an-ch, .an-mast-img, .an-mast-img-in .an-scene, .an-tile { transform: none !important; }
1120 .an-js [data-an-rv] { transform: none; }
1121 .an-marquee-track { animation: none !important; width: auto; }
1122 .an-marquee-set[aria-hidden="true"] { display: none; }
1123 .an-marquee-set { flex-direction: column; gap: 24px; padding: 0 var(--an-gut); }
1124 .an-marquee-set li { white-space: normal; flex-wrap: wrap; }
1125 .an-star { display: none; }
1126}
1127@media (prefers-contrast: more) {
1128 .an-nav.is-small .an-nav-in { background: var(--an-paper); -webkit-backdrop-filter: none; backdrop-filter: none; border-bottom-color: var(--an-ink); }
1129 .an-grain::after { display: none; }
1130}
1131@media (prefers-reduced-transparency: reduce) {
1132 .an-nav.is-small .an-nav-in { background: var(--an-paper); -webkit-backdrop-filter: none; backdrop-filter: none; }
1133}
1134`;