类型: · 收录:2026-10-26 23:39:21 · 源码:会员可见
付费可阅读内容 · 可复制
# Prompt: recreate the Fossil Atlas page exactly
Copy everything below the line into a new chat.
---
Build a single-file `index.html` called **Fossil Atlas**, an interactive 3D field guide to two dinosaurs. Vanilla HTML, CSS and JavaScript only, Three.js r170 loaded from a CDN import map. Follow this spec exactly: same tokens, fonts, layout, copy, icons, data, animations and interactions. Do not substitute fonts, colours, model URLs or wording.
## 1. Head
- `<!DOCTYPE html>`, `lang="en"`, `charset="utf-8"`, viewport `width=device-width, initial-scale=1, viewport-fit=cover`.
- Title: `Fossil Atlas — Featured dinosaurs`.
- Meta description: `Turn a velociraptor and a triceratops in your hands. An interactive 3D field guide to the Cretaceous.`
- Preconnect to `https://fonts.googleapis.com` and `https://fonts.gstatic.com` (crossorigin).
- Google Fonts stylesheet, exactly:
`https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,300;0,9..144,400;0,9..144,500;1,9..144,300;1,9..144,400&family=Instrument+Sans:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap`
- Import map:
```json
{ "imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/"
} }
```
## 2. Design tokens (CSS custom properties on `:root`)
```
--bg: #ebe1cd sandstone page background
--panel: #f8f2e6 cards, tabs, buttons
--line: #d6c9ae hairlines
--ink: #241c14 text
--muted: #7a6b58 secondary text
--accent: #b4532a ochre
--accent-ink: #ffffff
--accent-tint: #f3dfcd
--chip: #e4d8c2
--shadow: 70, 48, 24 (rgb triplet used in the ground shadow gradient)
--serif: "Fraunces", "Iowan Old Style", Georgia, serif
--sans: "Instrument Sans", "Segoe UI", system-ui, sans-serif
--mono: "JetBrains Mono", ui-monospace, Menlo, monospace
--ease: cubic-bezier(.22, .8, .24, 1)
```
Dusk theme, applied when the hero has `data-light="dusk"`:
```
--bg: #17120d; --panel: #211a13; --line: #3d3225; --ink: #f1e7d6; --muted: #a89880;
--accent: #e08a4f; --accent-ink: #17120d; --accent-tint: #3b2415; --chip: #2d251b; --shadow: 0, 0, 0
```
Global: `* { box-sizing: border-box; margin: 0 }`, `html, body { height: 100% }`, body uses `--bg`, `--sans`, `--ink`, `overflow: hidden`, antialiased. Buttons reset to inherit font and colour with no background or border. `:focus-visible` is a 2px `--accent` outline, offset 2px, radius 3px. `.ico` is a 20px inline SVG, `fill: none; stroke: currentColor; stroke-width: 1.5; round caps and joins`.
## 3. Layout
`<main class="hero" id="hero" data-light="day">` fills `100dvh` and is a CSS grid with three columns: `196px | minmax(0,1fr) | clamp(300px, 27vw, 356px)`. Background and colour transition 0.6s.
A `<canvas id="gl">` is absolutely positioned over the entire hero (`inset: 0; z-index: 5; pointer-events: none`). The 3D model is drawn on this full-size canvas, and the camera's principal point is shifted onto the stage centre using `camera.setViewOffset`, so the model is never cropped by the side panels.
### 3a. Left sidebar `<aside class="side">`
- Padding `22px 12px 18px 24px`, right hairline border, flex column.
- Brand: `Fossil Atlas` in Fraunces 27px, weight 400, letter-spacing −0.02em, `font-variation-settings: "opsz" 48`. Beneath it a `<small>` in mono 9.5px, letter-spacing 0.18em, uppercase, muted: `Mesozoic · Vol. I`.
- Nav list (`.nav`, 2px gap). Each item is a full-width button, flex, 16px gap, padding `7px 10px`, radius 3px, 14px text. Hover background `--chip`. The current item (`aria-current="page"`) has `--accent-tint` background and a 2px inset left bar in `--accent` (via `box-shadow: inset 2px 0 0`). Counts are a `<small>` in mono 10.5px muted.
1. Home (icon `i-home`)
2. Featured (icon `i-star`) ← current
3. Theropods, 42 species (icon `i-claw`)
4. Ceratopsians, 18 species (icon `i-skull`)
5. Sauropods, 27 species (icon `i-bone`)
6. Ankylosaurs, 11 species (icon `i-shield`)
7. Pterosaurs, 15 species (icon `i-wing`)
8. Eggs & nests, 9 sites (icon `i-egg`)
- Feature card (`.feature`) pushed to the bottom with `margin-top: auto`: `--panel` background, 1px `--line` border, 3px `--accent` left border, radius 3px, padding `14px 14px 16px`. Contains eyebrow `Featured species`, an image (92×76, contain, centred), an `<h3 id="featTitle">` in Fraunces 18px, a `<p id="featText">` 12px muted, and a link `Learn more` with the `i-arrow` icon at 14px.
- Eyebrow style everywhere: mono 9.5px, letter-spacing 0.2em, uppercase, muted, weight 500.
### 3b. Centre column `<section class="main">`
Grid rows `auto minmax(0,1fr)`, padding `48px 18px 14px 26px`.
**Tabs** (`.tabs`, role tablist, flex, 10px gap). Each tab is 130px wide, `--panel` background, 1px `--line` border, radius 3px, padding `8px 8px 11px`, grid with centred items. A `::before` shows `attr(data-no)` (`01`, `02`) top-left in mono 9.5px muted. A `::after` is a 2px `--accent` bar along the bottom edge, `scaleX(0)` by default. Hover lifts the tab 2px and sets border to `--muted`. Selected tab has `--ink` border and the bar scaled to 1 (0.35s ease). Contents: image 58×52 contain, `<b>` name in Fraunces 15.5px, `<i>` latin name in Fraunces 12px muted.
**Stage** (`.stage`, `id="stage"`, `tabindex="0"`, aria-label `3D dinosaur model. Drag to rotate, scroll or pinch to zoom, double-click to reset.`). `position: relative; touch-action: none; cursor: grab; user-select: none; border-radius: 3px`. Class `dragging` switches to `grabbing`. Inside, in order:
1. `.plate` — four 14×14 corner marks drawn with 1px `--line` borders, inset `10px 0 24px`, pointer-events none.
2. `.ground` — a soft elliptical shadow: absolutely centred at `bottom: 15%`, width `min(62%, 460px)`, height 44px, `radial-gradient(closest-side, rgba(var(--shadow), .22), transparent)`. When the stage has class `switching` it fades out and squashes to `scaleX(.4)`.
3. `.fallback` — hidden image div shown only if a model fails to load.
4. `.loader` — centred, mono 11px uppercase letter-spaced muted text `Preparing the fossil…` with a 30px spinner ring above (1px `--line` border, top colour `--accent`, `spin` 1s linear). Opacity toggled by class `show`.
5. `.hint` — top right, mono 10.5px muted: hand icon + `Drag to turn · scroll to zoom`. Fades out once the hero has class `touched`.
6. `.rail` — vertical toolbar on the left, vertically centred, 9px gap. Four 38×38 buttons, radius 3px, `--panel` with `--line` border; hover border `--accent`; active scales to 0.92; class `on` fills with `--accent`. Buttons: zoom in (`i-plus`, starts `on`), zoom out (`i-search`), expand (`i-expand`), light (`i-sun`, aria-label `Switch to dusk lighting`).
7. `.turn` — pill group centred at `bottom: 46px`: `--panel`, `--line` border, radius 3px, padding `3px 4px`, mono 12px. Three buttons: turn left (`i-ccw`), `360°`, turn right (`i-cw`). Each 28px tall, radius 2px, hover `--chip`.
8. `.scale` — bottom left at `bottom: 30px`, mono 10px muted; a 72×6 bracket drawn with a 1px `--muted` border (no top) above the text.
9. `.caption` — centred at the bottom, Fraunces italic weight 300, `clamp(17px, 1.65vw, 22px)`.
### 3c. Right column `<section class="info">`
Grid rows `auto minmax(0,1fr)`, 16px gap, padding `13px 26px 14px 0`.
**Top bar** (`.top`): a search field (flex 1, 32px tall, `--panel`, `--line` border, radius 3px, search icon 15px, placeholder `Search species, periods, or regions…`, focus border `--accent`), a round 32px bell button (`i-bell`), and a round account button containing a 24px dark circle avatar with `i-user`.
**Card** (`.card`): `--panel`, 1px `--line` border, radius 3px, padding `26px 24px 20px`, scrollable, and a double rule drawn with `box-shadow: inset 0 0 0 4px var(--panel), inset 0 0 0 5px var(--line)`. Inside, `<article class="detail" id="detail" aria-live="polite">` is a flex column with `min-height: 100%`, filled by JavaScript in this order (each child gets `style="--i:n"` for staggered entry):
1. Eyebrow: `{FAMILY} · Specimen {NO}`.
2. `<h1>` in Fraunces weight 300, `clamp(42px, 4.4vw, 58px)`, line-height 0.96, letter-spacing −0.035em, `"opsz" 144`; contains an `<em>` block with the Latin name at 0.36em, italic, muted, 8px top margin.
3. Tags: mono 10.5px, 1px `--line` border, radius 2px, padding `5px 9px`, 8px gap.
4. Lede paragraph 13.5px, line-height 1.55.
5. Era strip (`.era`): a 6px bar split into three segments with widths in the ratio 51 : 56 : 79 (Triassic 252–201, Jurassic 201–145, Cretaceous 145–66 Mya), `--chip` fill with 1px `--panel` dividers and 2px end radii. An absolutely positioned `<u>` marker in `--accent`, 12px tall, overhanging 3px above, placed by percentage along the 252→66 scale, with a mono 9.5px accent label (`data-l`, e.g. `68–66 Mya`) right-aligned beneath it. Labels row 20px below: `Triassic`, `Jurassic`, `Cretaceous` in mono 9px uppercase letter-spaced muted, same grid ratio.
6. `<h2>` `Key Traits`: mono 10px, letter-spacing 0.2em, uppercase, muted, top hairline border, margin-top 18px, padding-top 14px.
7. `<dl class="traits">` with 9px gap. Each row is flex, baseline-aligned, 13px: an 18px muted icon, a `<dt>` in muted that flexes and ends in a dotted leader (`::after` flex 1, 1px dotted `--line`, 8px side margins, raised 3px), and a right-aligned `<dd>` weight 500.
8. `<h2>` `Habitat`, then `.habitat`: `t-reed` icon + text, flex, 16px gap.
9. Close-up button (`.closeup`, inside `.closeup-wrap` pushed to the bottom with `margin-top: auto; padding-top: 16px`): grid `76px 1fr 18px`, 14px gap, padding 10px, `--line` border, radius 3px. Left cell is a 76×76 square `.lens` showing the species image at `background-size: 520%` and a per-species `background-position`. Middle: `<b>Close-up Detail</b>` Fraunces 18px and a `<small>` 11.5px muted. Right: `i-chev`, rotates 180° when `aria-pressed="true"`. Hover or pressed: border and background switch to `--accent` / `--accent-tint`.
Detail entry animation: each child runs `rise` 0.6s (`from { opacity: 0; transform: translateY(12px) }`) with delay `calc(var(--i) * 45ms)`. When the article has class `leaving`, children run `sink` 0.2s to `opacity 0; translateY(-6px)`.
## 4. SVG icon sprite
Place a hidden `<svg width="0" height="0">` with `<symbol>` elements, all `viewBox="0 0 24 24"`, stroke-only paths (no fill), used via `<svg class="ico"><use href="#id"/></svg>`:
```
i-home M4 11.5 12 5l8 6.5V20h-5.5v-5h-5v5H4z
i-star m12 3.8 2.5 5.3 5.7.7-4.2 4 1.1 5.7-5.1-2.8-5.1 2.8L8 13.8l-4.2-4 5.7-.7z
i-claw M12 20c-1.5-3-1-7 1.5-10.5M12 20c-3.5-1.5-6-5-6.5-9.5M12 20c3.5-1.5 6-5 6.5-9.5M13.5 9.5 15 4M5.5 10.5 3.5 6M18.5 10.5 20.5 6
i-skull M12 3.5c4.5 0 7.5 3 7.5 7 0 2.5-1.2 4.2-3 5.3V20h-9v-4.2c-1.8-1.1-3-2.8-3-5.3 0-4 3-7 7.5-7z + circles (9.3,11,r1.6) (14.7,11,r1.6) + M11 20v-2.5M13 20v-2.5
i-bone M7.5 9.5 14.5 16.5M5 5.5a2.2 2.2 0 0 1 3.5 2.6 2.2 2.2 0 0 1-2.6 3.5A2.2 2.2 0 1 1 5 5.5zM19 18.5a2.2 2.2 0 0 1-3.5-2.6 2.2 2.2 0 0 1 2.6-3.5 2.2 2.2 0 1 1 .9 6.1z
i-shield M12 3.5 19 6.5v5c0 4.5-3 7.8-7 9-4-1.2-7-4.5-7-9v-5z + M12 8v9M8.5 10.5h7
i-wing M3 15c3-6 8-9 15-9.5 1.5 0 3 .3 3 .3-1.5 1.5-2.5 4-4.5 5.5C13 14 8.5 15 3 15z + M3 15c3.5.5 7 1.5 9.5 4.5M9 12.5l1.5 2.5
i-egg M12 3.5c3.5 0 6.5 4.5 6.5 9.5a6.5 6.5 0 0 1-13 0c0-5 3-9.5 6.5-9.5z + m8 11 2 1.5 1.5-2 2 2 1.5-1.5
i-arrow M4 12h15M14 7l5 5-5 5
i-plus circle(10.5,10.5,r6.5) + m15.5 15.5 4.5 4.5M10.5 8v5M8 10.5h5
i-search circle(10.5,10.5,r6.5) + m15.5 15.5 4.5 4.5
i-expand M4 9V4h5M15 4h5v5M20 15v5h-5M9 20H4v-5
i-sun circle(12,12,r3.8) + M12 3v2.2M12 18.8V21M3 12h2.2M18.8 12H21M5.6 5.6l1.6 1.6M16.8 16.8l1.6 1.6M5.6 18.4l1.6-1.6M16.8 7.2l1.6-1.6
i-ccw M5 12a7 7 0 1 0 2.3-5.2L5 9M5 4.5V9h4.5
i-cw M19 12a7 7 0 1 1-2.3-5.2L19 9M19 4.5V9h-4.5
i-bell M6.5 16.5V11a5.5 5.5 0 0 1 11 0v5.5l1.5 2H5zM10 20.5h4
i-user circle(12,9,r3.5) + M5.5 19.5c1.2-3 3.6-4.5 6.5-4.5s5.3 1.5 6.5 4.5
i-chev m9 5 7 7-7 7
i-hand M8.5 12V5.5a1.5 1.5 0 0 1 3 0V11m0-1.5a1.5 1.5 0 0 1 3 0V11m0-.5a1.5 1.5 0 0 1 3 0v4.5c0 3.3-2.2 5.5-5.5 5.5-2.5 0-4-1-5.3-3.2L4.5 13.5c-.6-1.2 1-2.3 2-1.2l2 2.2
t-ruler m3.5 15.5 12-12 5 5-12 12zM7.5 11.5l2 2M10.5 8.5l2 2M13.5 5.5l2 2
t-speed M4 16a8.5 8.5 0 1 1 16 0M12 14l3.5-4.5 + M8 19h8
t-weight M12 4v3M4 7h16M6 7l-2.5 6a3 3 0 0 0 6 0zM18 7l-2.5 6a3 3 0 0 0 6 0zM9 20h6M12 7v13
t-diet M3 12c3-4 7-5 11-3.5 2 .7 3.5 2 5 3.5-1.5 1.5-3 2.8-5 3.5C10 17 6 16 3 12zM19 12l2.5-2.5v5zM8 11.5h.01
t-range circle(12,12,r8.5) + M3.5 12h17M12 3.5c2.5 2.5 3.5 5.3 3.5 8.5s-1 6-3.5 8.5c-2.5-2.5-3.5-5.3-3.5-8.5s1-6 3.5-8.5z
t-reed M12 21V6M12 6c-1.2-1.2-1.2-2.5 0-3.5 1.2 1 1.2 2.3 0 3.5zM8 21v-8c0-2-1-3.5-2.5-4.5M16 21v-8c0-2 1-3.5 2.5-4.5M4 21h16
```
## 5. Data (JavaScript `DINOS` array, exact values)
```js
const DINOS = [
{
id: 'velociraptor', no: 'FA-001', mya: [75, 71], scale: '1 m',
name: 'Velociraptor', latin: 'Velociraptor mongoliensis', family: 'Dromaeosauridae',
image: 'https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20261012_035232_c0461fb5-11e9-4e2e-9db1-69f0e756048e.png',
model: 'https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20261012_035345_302b35db-48e3-43da-9673-765087b33c8f.glb',
yaw: 0.75, pitch: 0.12,
tags: ['Theropod', 'Pack hunter', 'Feathered'],
lede: 'Turkey-sized and quick, the velociraptor hunted the dunes of Late Cretaceous Mongolia. Its arms carried true feathers and each foot a raised sickle claw, used to pin prey rather than slash it. A famous fossil preserves one locked in combat with a Protoceratops.',
traits: [
['t-ruler', 'Length', '1.5–2 m'],
['t-speed', 'Top speed', 'Up to 40 km/h'],
['t-diet', 'Diet', 'Small reptiles and mammals'],
['t-range', 'Found', 'Gobi Desert, Mongolia, 1923'],
],
habitat: 'Arid dune fields and seasonal streams.',
caption: 'A claw raised, and the dune goes quiet.',
closeup: 'Quill knobs along the forearm show where flight-style feathers anchored to the bone.',
lens: '62% 22%',
feature: ['A sickle on every foot.', 'Feathers, speed and nerve. The desert hunter of the Gobi.'],
},
{
id: 'triceratops', no: 'FA-002', mya: [68, 66], scale: '3 m',
name: 'Triceratops', latin: 'Triceratops horridus', family: 'Ceratopsidae',
image: 'https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20261012_035232_61fbc176-0698-4768-824f-18a31d8b2ec4.png',
model: 'https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20261012_035347_b7f83241-7062-4586-8070-b327e8766dd0.glb',
yaw: 0.75, pitch: 0.12,
tags: ['Ceratopsian', 'Browser', 'Three horns'],
lede: 'One of the last dinosaurs, the triceratops grazed the floodplains of western North America right up to the end of the Cretaceous. Two brow horns over a metre long and a solid bony frill made it a match for Tyrannosaurus, whose bite marks heal on some skulls.',
traits: [
['t-ruler', 'Length', '8–9 m'],
['t-weight', 'Weight', 'Up to 9 tonnes'],
['t-diet', 'Diet', 'Cycads, ferns and palms'],
['t-range', 'Found', 'Denver, Colorado, 1887'],
],
habitat: 'Subtropical floodplains and open woodland.',
caption: 'Lower the horns, and the forest steps aside.',
closeup: 'The frill is scored with blood-vessel grooves, so it may have flushed with colour in display.',
lens: '24% 30%',
feature: ['A wall of horn and bone.', 'Three horns, one frill. The last great browser of the Cretaceous.'],
},
];
```
The Triceratops (index 1) is active on load. Tabs are generated from this array with `data-i` and `data-no` (`01`, `02`), `role="tab"`, `aria-selected`, roving `tabindex`.
## 6. Three.js scene
- `WebGLRenderer({ canvas, alpha: true, antialias: true, powerPreference: 'high-performance' })`, pixel ratio capped at 2, `SRGBColorSpace`, `NeutralToneMapping`, exposure 1.05.
- Environment: `PMREMGenerator.fromScene(new RoomEnvironment(), 0.04)`, `scene.environmentIntensity = 0.95`.
- Camera: `PerspectiveCamera(26, 1, 0.1, 100)`.
- Lights: key `DirectionalLight(0xfff4e2, 1.6)` at (2.5, 4, 5); rim `DirectionalLight(0xbfd8ff, 0.5)` at (−4, 2, −3).
- Light presets, lerped every frame with rate 4:
`day: { env .95, key 1.6, rim .5, keyColor 0xfff4e2, exposure 1.05 }`
`dusk: { env .28, key 2.6, rim 1.9, keyColor 0xffc98a, exposure 1.0 }`
- Loader: `GLTFLoader` with `DRACOLoader` (decoder path `https://www.gstatic.com/draco/versioned/decoders/1.5.7/`) and `MeshoptDecoder`.
- Each species has a rig: `pivot` group (handles slide, scale and sway) containing a `spin` group (free rotation) containing the model. `home` orientation is a quaternion from `Euler(pitch, yaw, 0, 'YXZ')`.
- On load: compute the bounding sphere, recentre the model on it, wrap in a holder scaled to `1 / radius` so every model has radius 1. Set `frustumCulled = false`, max anisotropy on maps, `envMapIntensity = 1`. On error, mark the rig failed and show the fallback image.
- Layout: `measure()` reads the hero and stage rects, sets `goal.cx/cy` to the stage centre (y at 44% of stage height, 50% in focus mode), `goal.px = min(stageW * .5, stageH * .6) * 1.16` (pixels per world unit), resizes the renderer to the hero, updates aspect. ResizeObservers on hero and stage, plus `orientationchange`.
- Every frame: ease `view.cx/cy/px` to goals with rate 7, zoom with rate 6, then `camera.position.z = H / (2 · tan(FOV/2) · px · zoom)` and `camera.setViewOffset(W, H, W/2 − cx, H/2 − cy, W, H)`.
## 7. Interactions
- **Drag to rotate**: pointer events on the stage (ignored when the target is a button). Pointer capture. Delta × `k = π / max(260, px · 1.6)` applied as yaw (world Y) then pitch (world X) premultiplied quaternions. Velocity stored for **inertia**, decayed by `exp(−dt · 4.5)` after release.
- **Pinch zoom** with two pointers; **wheel zoom** `zoomGoal · exp(−deltaY · 0.0016)` (0.01 with ctrl). Zoom clamped to [0.55, 3.4].
- **Double-click** resets (homing slerp to `home` at rate 6, zoom 1).
- **Keyboard** on the stage: arrows rotate by 0.18 rad, `+`/`=` and `-` zoom by 1.2×, `0` resets. Escape leaves focus mode.
- **Rail**: zoom in ×1.35, zoom out ÷1.35 (the `on` state follows whether zoom ≥ 1), expand toggles `.focus` on the hero, light toggles `data-light` between day and dusk, sets `body` background to `#14170f` in dusk, swaps the aria-label, and lerps the light preset.
- **Turn buttons**: left/right queue ±π/2, `360°` queues +2π; the queue drains with rate 4.2 each frame.
- **Close-up button**: toggles zoom between 2.6 and 1; `aria-pressed` reflects zoom > 2.2.
- Any interaction adds class `touched` to the hero (hides the hint) and records `lastTouch`.
- **Idle life**: after 1.8s untouched, over 1.5s ease in a slow sway (`rotation.x = sin(t·0.9)·0.03`, `rotation.y += sin(t·0.55)·0.16`) and a hover (`position.y = sin(t·1.3 + i)·0.028`). Disabled with reduced motion.
## 8. Tab switch animation (`DUR = 780ms`)
On selecting a tab: update aria, repaint the info card (add `leaving` for 200ms then refill), add `switching` to the stage, reset zoom and velocity. The outgoing model leaves at once over `DUR · 0.6` with ease-in-cubic: scale 1→0, slides `−dir · slide` (where `slide = stageW · 0.95 / px` world units) and twists `−dir · 1.4` rad. The incoming model (after loading if needed, showing the loader) resets to `home`, then over `DUR` with ease-out-cubic: scale follows `outBack(t) · (0.25 + 0.75·e)` where `outBack(t) = 1 + 2.2(t−1)³ + 1.2(t−1)²`, slides from `dir · slide` to 0, twist from `dir · 1.6` to 0. Remove `switching` when done. Boot runs the same entrance for the active model, then preloads the other.
## 9. Focus (expanded) mode
`.hero.focus` fades and slides the sidebar (−24px), info column (+24px) and tabs (−16px) out with pointer-events none; the camera centre moves to the hero centre.
## 10. Responsive
- `≤1100px`: hide the sidebar; grid becomes `minmax(0,1fr) clamp(280px, 36vw, 340px)`.
- `≤760px` (phone): hero becomes a flex column; `.info` uses `display: contents`. Top bar first with a `::before` reading `Fossil Atlas` in Fraunces 21px, search collapses to a 32px round icon. Stage second (flex 1). Tabs become two equal horizontal cards with the image at 44×40 on the left. Card third as a bottom sheet: `max-height: 40dvh`, radius `10px 10px 0 0`, top border only, no double rule, safe-area bottom padding; in focus mode it slides down 105%. h1 34px. Hint hidden.
- `max-height: 620px` on desktop: tighter paddings, hide the feature image and text.
- `prefers-reduced-motion: reduce`: all animation and transition durations 0.01s; JS disables sway, hover, inertia and uses instant tab switches.
## 11. Accessibility
Tabs use `role="tablist"`/`tab`, `aria-controls="detail"`, roving tabindex and arrow-key navigation. The stage is focusable with a descriptive aria-label. Rail and turn buttons have aria-labels; toggles use `aria-pressed`. The detail article is `aria-live="polite"`. Body text contrast meets 4.5:1 in both themes.
Deliver the complete file in one response.