/* Hero and work tunnel. wheel.js lays out and moves the stills (transforms, opacity
   and --shade); everything else is here. */

.hero-type { margin: 0; display: flex; flex-direction: column; font-weight: var(--display-weight); letter-spacing: var(--display-track); font-size: min(8.6vh, 5.4vw); line-height: 1; }
/* "obvious choice.": the outer span draws the underline line by line (so it can wrap);
   the inner span is filled with a slow warm glow that drifts across the words */
.mark { color: var(--ember); background: linear-gradient(var(--ember-line), var(--ember-line)) 0 100% / 100% .08em no-repeat; -webkit-box-decoration-break: clone; box-decoration-break: clone; animation: underline 1s .6s cubic-bezier(.6,0,.2,1) backwards; }
.mark__glow { background: linear-gradient(90deg, var(--ember), var(--ember-glow), var(--ember), var(--ember-glow)) 0 50% / 300% 100%; -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; animation: glow 9s ease-in-out infinite alternate; }
@keyframes glow { to { background-position: 100% 50%; } }
@media (forced-colors: active) { .mark__glow { background: none; -webkit-text-fill-color: CanvasText; } }
/* Headline entrance: the words rise in turn, then the underline draws */
.hero-type > span { animation: rise .8s var(--spring) backwards; }
.hero-type > span:nth-child(2) { animation-delay: .12s; }
@keyframes rise { from { opacity: 0; transform: translateY(.3em); } }

.wheel { position: relative; --card-w: min(46vw, 720px); --stack-x: 64%; --stack-y: 52%; --tunnel-persp: 500px; --tunnel-gap: 650; --tunnel-offset: .62; --vp-x: 50%; --vp-y: 50%; --shot-w: 42vw; --cta-w: 40vw; }
/* The large viewport height (what the screen is with the address bar slid away), which stays the same while the bar
   comes and goes, so nothing in the tunnel jumps. The readout and the prompt are lifted by however much of the stage
   the bar is covering (100lvh - 100dvh), so they're never under it. */
.wheel__stage { position: sticky; top: 0; height: 100vh; overflow: hidden; --bar: 0px; }
@supports (height: 100lvh) { .wheel__stage { height: 100lvh; --bar: calc(100lvh - 100dvh); } }
.wheel__stack { position: absolute; inset: 0; }

/* Work tunnel: real 3D. The view holds the perspective; wheel.js moves the tunnel towards the viewer */
.tunnel-view { position: absolute; inset: 0; overflow: hidden; perspective: var(--tunnel-persp); perspective-origin: var(--vp-x) var(--vp-y); }
.tunnel { position: absolute; inset: 0; transform-style: preserve-3d; will-change: transform; }
.shot { position: absolute; left: var(--vp-x); top: var(--vp-y); width: var(--shot-w); aspect-ratio: 16 / 10; display: block; color: var(--fg); text-decoration: none; transform: translate(-50%, -50%) translate3d(var(--x, 0), var(--y, 0), var(--z, 0)); }
/* Each project's live front page: the real site at 1440x900, scaled to the frame (wheel.js sets --s). It can't be
   scrolled or clicked inside; the whole frame is a link to the site. */
.shot__live { position: relative; display: block; width: 100%; height: 100%; overflow: hidden; border-radius: 6px; background: #0b0a09; box-shadow: 0 30px 60px -30px rgba(0,0,0,.8); }
.shot__still, .card__still { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: top; }
.shot__live iframe { opacity: 0; transition: opacity .6s ease; } /* the picture shows until the live page is ready */
.shot__live.is-ready iframe { opacity: 1; }
.shot__live iframe { position: absolute; left: 0; top: 0; width: 1440px; height: 900px; border: 0; transform-origin: 0 0; transform: scale(var(--s, .4)); pointer-events: none; }
.shot__cap { position: absolute; left: 0; top: calc(100% + 10px); font-size: 13px; font-weight: 600; color: var(--soft); white-space: nowrap; }
.shot__shade { position: absolute; inset: 0; border-radius: 6px; background: #000; opacity: var(--shade, 0); pointer-events: none; }
.shot--cta { width: var(--cta-w); }
.shot__panel { display: flex; flex-direction: column; justify-content: flex-end; height: 100%; padding: clamp(16px, 3vw, 32px); border-radius: 6px; background: var(--accent); color: var(--on-accent); }
.shot__panel-title, .shot__panel-note { margin-top: 8px; opacity: .9; }
.shot__panel-cta { margin-top: 14px; font-weight: 600; }
.shot__panel--clip .shot__panel-cta { color: var(--accent); }
/* With its clip (clips.js): a smoky obsidian slab, ivory words over a shadow in the lower left */
.shot__panel--clip { position: relative; overflow: hidden; isolation: isolate; background: #0b0a09; color: var(--fg); }
.shot__panel--clip .clip { z-index: -1; border-radius: inherit; }
.shot__panel--clip::after { content: ''; position: absolute; inset: 0; z-index: -1; background: linear-gradient(20deg, rgba(8, 6, 4, .75), transparent 55%); }
.shot__panel--clip .shot__panel-note { opacity: 1; color: var(--soft); }
/* In motion mode the cards are only the readout's data; the reduced-motion list shows them instead of the tunnel */
.wheel:not(.is-static) .wheel__stack { display: none; }
.wheel.is-static .tunnel-view { display: none; }

/* Wheel pages sit in glass frames (the only glass on the site) */
.card {
  position: absolute; left: var(--stack-x); top: var(--stack-y); width: var(--card-w); aspect-ratio: 16 / 10.4;
  display: flex; flex-direction: column; padding: 8px; overflow: hidden; text-decoration: none; color: var(--fg);
  border-radius: var(--radius); transform: translate3d(-50%, -50%, 0); will-change: transform, opacity;
  background: var(--glass-bg); border: 1px solid var(--glass-line);
  -webkit-backdrop-filter: blur(16px) saturate(140%); backdrop-filter: blur(16px) saturate(140%);
  box-shadow: var(--glass-shadow), 0 40px 80px -36px rgba(0,0,0,.55);
}
.card img { flex: 1; min-height: 0; width: 100%; object-fit: cover; object-position: top; border-radius: 6px; }
.card__pic { position: relative; flex: 1; overflow: hidden; border-radius: 6px; background: #000; }
.card__panel { position: relative; flex: 1; display: flex; flex-direction: column; justify-content: flex-end; padding: clamp(16px, 3vw, 32px); border-radius: 6px; background: var(--panel-bg); }
.card__panel-note { color: var(--muted); margin-top: 8px; }
.card--cta .card__panel { background: var(--accent); color: var(--on-accent); }
.card--cta .card__panel-note { color: var(--on-accent); opacity: .9; }
.card__caption { display: none; }
.card__shade { position: absolute; inset: 0; border-radius: inherit; background: #000; opacity: var(--shade, 0); pointer-events: none; }

.readout { position: absolute; left: var(--gutter); bottom: calc(28px + var(--bar)); z-index: 2000; width: min(400px, 32vw); padding: 20px 22px; }
.readout p { margin: 0; }
.readout__meta { color: var(--muted); }
.readout__meta:empty { display: none; }
.readout__name { font-weight: var(--display-weight); letter-spacing: -.03em; font-size: 30px; line-height: 1.05; margin-top: 8px; }
.readout__meta:empty + .readout__name { margin-top: 0; }
.readout__blurb { color: var(--soft); font-size: 14px; margin-top: 6px; }
.readout__link { position: relative; display: inline-flex; margin-top: 14px; color: var(--fg); font-weight: 600; font-size: 14px; text-decoration: none; border-bottom: 2px solid var(--accent); padding-bottom: 2px; }

.readout__link:not([href]) { border-bottom-color: transparent; color: var(--muted); font-weight: 500; }

/* Phones and tablets: as the work comes up the screen, the tunnel rides up with the page and its first project is
   still small and low, so the top of the section says what it is and to keep going. It fades as the section pins.
   (With a mouse the first project floats into this space instead.) */
.wheel__intro { display: none; }
@media (hover: none), (pointer: coarse) {
  .wheel__intro { display: block; position: absolute; left: 0; right: 0; top: clamp(84px, 12vh, 132px); z-index: 2000; padding: 0 var(--gutter); text-align: center; pointer-events: none; transition: opacity .5s ease, translate .5s ease; }
  .wheel.is-pinned .wheel__intro { opacity: 0; translate: 0 -12px; }
}
.wheel.is-static .wheel__intro { display: none; }
.wheel__title { margin: 0; font-weight: var(--display-weight); letter-spacing: var(--display-track); font-size: clamp(44px, 12vw, 96px); line-height: .95; }
.wheel__prompt { margin: 14px 0 0; color: var(--soft); font-size: 16px; }

/* Phones: a ruler, one short tick per project (wheel.js adds them), the one you're on lit and longer, like the
   marks on a dial. It stands in for the index the computers have, and shows the count without words. */
.ruler { display: none; }
@media (max-width: 760px) {
  .ruler { display: flex; position: absolute; left: 50%; bottom: calc(150px + var(--bar)); z-index: 2000; align-items: flex-end; gap: 10px; height: 28px; translate: -50% 0; pointer-events: none; transition: opacity .4s ease; }
  .ruler i { width: 1px; height: 14px; background: var(--muted); opacity: .6; transition: height .4s ease, background-color .3s ease, opacity .3s ease; }
  .ruler i.is-on { height: 28px; background: var(--accent); opacity: 1; }
  .wheel.is-final .ruler { opacity: 0; } /* on "Your site here" */
}
@media (max-width: 760px) and (prefers-reduced-motion: no-preference) { .ruler i.is-on { animation: ruler-tick 2.4s ease-in-out infinite; } }
@keyframes ruler-tick { 50% { height: 20px; } }
.wheel.is-static .ruler { display: none; }
.rail { position: absolute; right: var(--gutter); top: 50%; transform: translateY(-50%); z-index: 2000; display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 6px; }
.rail__btn { width: 36px; height: 32px; border: 0; border-radius: 6px; background: none; color: var(--muted); cursor: pointer; font: 600 12px var(--font); transition: background .25s, color .25s; }
.rail__btn:hover { color: var(--fg); }
.rail__btn[aria-current="true"] { background: var(--fg); color: var(--bg); }
/* The scroll prompt: centred under the pages until you've flown past the first project (wheel.js sets is-exploring),
   back again if you scroll back to the start. A dot keeps sliding down its track. */
.cue { position: absolute; left: 50%; bottom: calc(28px + var(--bar)); z-index: 2000; display: flex; flex-direction: column; align-items: center; gap: 10px; margin: 0; color: var(--soft); font-size: 15px; white-space: nowrap; transform: translateX(-50%); transition: opacity .5s ease, translate .5s ease; }
/* a thin line with a short light running down it */
.cue__track { position: relative; width: 1px; height: 40px; overflow: hidden; background: var(--line); }
.cue__dot { position: absolute; left: 0; top: 0; width: 1px; height: 40%; background: linear-gradient(transparent, var(--accent)); }
@media (prefers-reduced-motion: no-preference) { .cue__dot { animation: cue-run 1.8s cubic-bezier(.6, 0, .4, 1) infinite; } }
@keyframes cue-run { from { translate: 0 -100%; } to { translate: 0 250%; } }
.wheel.is-exploring .cue { opacity: 0; translate: 0 10px; pointer-events: none; }
@media (min-width: 761px) and (max-width: 1179px) { .cue { left: auto; right: var(--gutter); transform: none; } } /* clear of the readout on the left */
/* The tunnel opens empty: the readout waits until the first page has arrived. The index stays throughout. */
.readout { transition: opacity .5s ease, translate .5s ease; }
.wheel.is-arriving .readout { opacity: 0; translate: 0 12px; pointer-events: none; }

/* Short laptop screens: a slimmer readout keeps clear of the headline */
@media (min-width: 761px) and (max-height: 760px) {
  .readout { padding: 16px 20px; }
  .readout__blurb { display: none; }
}

@media (max-width: 760px) {
  /* --vp-y: the pages pass through the middle of the space between the header and the readout */
  .wheel { --card-w: 90vw; --stack-x: 50%; --stack-y: 49%; --vp-x: 50%; --vp-y: 47%; --shot-w: 72vw; --cta-w: 84vw; --tunnel-offset: .26; --tunnel-gap: 600; }
  .rail { display: none; }
  .cue { display: none; } /* phones have the ruler instead */
  .readout { left: 12px; right: 12px; bottom: calc(12px + var(--bar)); width: auto; padding: 14px 16px; }
  .readout__name { font-size: 24px; }
  .readout__blurb { display: none; }
}

/* Reduced motion: the work becomes a plain list */
.wheel.is-static .wheel__stage { position: relative; height: auto; overflow: visible; padding: 108px 0 64px; }
.wheel.is-static .wheel__stack { position: static; display: grid; gap: 24px; justify-items: center; }
.wheel.is-static .card { position: relative; left: auto; top: auto; transform: none; aspect-ratio: auto; }
.wheel.is-static .card img, .wheel.is-static .card__pic, .wheel.is-static .card__panel { aspect-ratio: 16 / 10; flex: none; }
.wheel.is-static .card__caption { display: grid; gap: 2px; padding: 12px 8px 4px; }
.card__caption-kind { font-size: 12px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.card__caption-name { font-weight: var(--display-weight); font-size: 22px; letter-spacing: -.02em; }
.card__caption-cta { color: var(--soft); font-size: 14px; }
.card__caption-blurb { color: var(--soft); font-size: 15px; line-height: 1.5; max-width: 52ch; }
.readout__link::before { content: ''; position: absolute; inset: -10px -6px; } /* a 44px tap area */
.wheel.is-static .readout, .wheel.is-static .rail, .wheel.is-static .cue { display: none; }
@media (prefers-reduced-motion: reduce) { .mark, .mark__glow { animation: none; } .hero-type > span { animation: none; } }
