/* global React */
const { useState: useStateDS, useEffect: useEffectDS, useRef: useRefDS, useLayoutEffect: useLayoutEffectDS } = React;

// Photo placeholders mapped per scene — replaces SVG scene plates with the
// uploaded studio mockups so the detail view feels like a real space, not
// an illustration. Will be swapped for the real shoot later.
const SCENE_PHOTO = {
  northLight: '/site/uploads/mockup1.png',
  motionLab:  '/site/uploads/mockup2.png',
  atelier:    '/site/uploads/mockup3.png',
  podcast:    '/site/uploads/mockup2.png',
  workshop:   '/site/uploads/mockup3.png',
  lounge:     '/site/uploads/mockup1.png',
};
function scenePhotoFor(scene) { return SCENE_PHOTO[scene] || '/site/uploads/mockup2.png'; }
function ScenePhoto({ scene }) {
  return (
    <img src={scenePhotoFor(scene)} alt="" loading="lazy" style={{
      position: 'absolute', inset: 0,
      width: '100%', height: '100%',
      objectFit: 'cover', display: 'block',
    }}/>
  );
}

/* ----------------------------------------------------------------- */
/*  STUDIO DETAIL OVERLAY                                            */
/*  - Receives an "originRect" (the card image rect) + studio data    */
/*  - Plays a FLIP-style zoom: starts at originRect, expands to       */
/*    fullscreen, then resolves the detail layout underneath.         */
/* ----------------------------------------------------------------- */

const DETAIL_DATA = {
  northLight: {
    overline: 'PRIVATE STUDIO · NATURAL LIGHT',
    paragraph:
      'A double-height room in the south wing of ASPACE, oriented to the morning sun. The studio takes its character from a wall of original factory windows — soft, raking light from 7am, full daylight by 10. Designed for photographers, painters and anyone whose work begins with the sun.',
    spec: [
      ['Size', '16 m²'],
      ['Light', 'East-facing, full window wall'],
      ['Floor', 'Concrete, sealed'],
      ['Ceiling', '4.2 m'],
      ['Power', '4 × 16A circuits'],
      ['Access', '24 / 7 keycard'],
    ],
    features: [
      { label: 'Natural light',  desc: 'Full-height factory windows, east-facing.' },
      { label: 'Private access', desc: 'Lockable, with 24/7 keycard.' },
      { label: 'Flexible rental', desc: 'Month to month — no long contracts.' },
      { label: 'Shoot-ready',    desc: 'Floor markings, neutral walls, power loops.' },
      { label: 'Community',      desc: 'Lounge, kitchen and shower included.' },
    ],
    angles: ['Window wall', 'Working corner', 'Door view', 'Light study'],
  },
  motionLab: {
    overline: 'CREATIVE SUITE · LED PRODUCTION',
    paragraph:
      'A blacked-out room built around a calibrated LED wall and dedicated camera bay. Pre-rigged for hybrid productions: virtual production, look-development, music and immersive shoots. Dimmable, light-tight, ready in minutes.',
    spec: [
      ['Size', '22 m²'],
      ['LED wall', '3.6 × 2.2 m, 2.6mm pitch'],
      ['Floor', 'Studio black, matte'],
      ['Ceiling', '3.4 m, truss grid'],
      ['Power', '32A three-phase'],
      ['Access', '24 / 7 keycard'],
    ],
    features: [
      { label: 'LED wall',      desc: 'Calibrated 2.6mm pitch, sync-ready.' },
      { label: 'Camera bay',    desc: 'Dedicated rig position with cable raceway.' },
      { label: 'Light control', desc: 'Fully blacked-out, DMX house grid.' },
      { label: 'Shoot-ready',   desc: 'Pre-rigged truss, mounting points throughout.' },
      { label: 'Community',     desc: 'Lounge, kitchen and shower included.' },
    ],
    angles: ['LED wall', 'Camera bay', 'Control desk', 'Floor markings'],
  },
  atelier: {
    overline: 'PRIVATE STUDIO · FASHION-READY',
    paragraph:
      'A garment-ready studio with steel rails, a fitting wall and a long oak bench. Built for designers, stylists and small brands who need somewhere real to make collections. Daylight, hanging space, and room to lay it all out.',
    spec: [
      ['Size', '18 m²'],
      ['Light', 'North-facing, soft daylight'],
      ['Storage', '6 m of steel rail'],
      ['Bench', '2.8 m oak, 90 cm deep'],
      ['Power', '3 × 16A circuits'],
      ['Access', '24 / 7 keycard'],
    ],
    features: [
      { label: 'Garment rails',  desc: '6 metres of steel rail at full height.' },
      { label: 'Fitting wall',   desc: 'Mirrored, with adjustable lighting.' },
      { label: 'Workbench',      desc: 'Long oak surface, drawer storage below.' },
      { label: 'Flexible rental', desc: 'Month to month — no long contracts.' },
      { label: 'Community',      desc: 'Lounge, kitchen and shower included.' },
    ],
    angles: ['Rail wall', 'Fitting mirror', 'Workbench', 'Storage corner'],
  },
  podcast: {
    overline: 'PRODUCTION ROOM · TREATED',
    paragraph:
      'A small acoustically-treated room for podcasts, voice work and long-form interviews. Two-mic ready out of the box, low noise floor, and a soft ambience that disappears the moment you press record.',
    spec: [
      ['Size', '14 m²'],
      ['Treatment', 'Foam + bass traps'],
      ['Noise floor', '< 28 dB'],
      ['Mics', '2 × Shure SM7B'],
      ['Power', '2 × 16A, isolated ground'],
      ['Access', '24 / 7 keycard'],
    ],
    features: [
      { label: 'Acoustic treatment', desc: 'Full-room foam plus four bass traps.' },
      { label: 'Two-mic ready',  desc: 'Pre-routed Shure SM7Bs and interface.' },
      { label: 'On-air sign',    desc: 'External light to keep neighbours quiet.' },
      { label: 'Flexible rental', desc: 'Month to month — no long contracts.' },
      { label: 'Community',      desc: 'Lounge, kitchen and shower included.' },
    ],
    angles: ['Mic position', 'Treatment wall', 'Console', 'On-air light'],
  },
  workshop: {
    overline: 'WORKSHOP STUDIO · MAKERS',
    paragraph:
      'Bench, tools and surface space for product designers, makers and prototyping-driven creative work. Pendant lights, a heavy worktop and pegboard wall. Built for the messy middle of making something real.',
    spec: [
      ['Size', '24 m²'],
      ['Worktop', '4 m × 1 m beech'],
      ['Tooling', 'Pegboard wall'],
      ['Lighting', '3 pendant + task'],
      ['Power', '4 × 16A + air line'],
      ['Access', '24 / 7 keycard'],
    ],
    features: [
      { label: 'Heavy worktop', desc: '4-metre beech bench, vises ready.' },
      { label: 'Tool wall',     desc: 'Full-height pegboard, magnetic strip.' },
      { label: 'Air & power',   desc: 'Compressed-air line, plenty of circuits.' },
      { label: 'Flexible rental', desc: 'Month to month — no long contracts.' },
      { label: 'Community',     desc: 'Lounge, kitchen and shower included.' },
    ],
    angles: ['Worktop', 'Tool wall', 'Pendant light', 'Storage'],
  },
  lounge: {
    overline: 'SHARED LOUNGE · MEMBERS',
    paragraph:
      'The shared room at the centre of ASPACE — soft seating, a working kitchen, and a long bench for long conversations. Always open to studio members. The room where everything else happens between the work.',
    spec: [
      ['Type', 'Communal'],
      ['Hours', '24 / 7'],
      ['Capacity', '~20 people'],
      ['Kitchen', 'Full + espresso bar'],
      ['Wifi', 'Studio fibre network'],
      ['Access', 'Member keycard'],
    ],
    features: [
      { label: 'Always open',    desc: '24/7 access for all studio members.' },
      { label: 'Working kitchen', desc: 'Full kitchen plus espresso bar.' },
      { label: 'Quiet corners',  desc: 'Tucked seats for calls and reading.' },
      { label: 'Long bench',     desc: 'A 5-metre table for shared meals.' },
      { label: 'Soft chairs',    desc: 'For when you need to think slower.' },
    ],
    angles: ['Sofa wall', 'Long bench', 'Kitchen view', 'Reading nook'],
  },
};

/* ----------------------------------------------------------------- */
/*  IMMERSIVE HERO — Spatial scene reused                             */
/* ----------------------------------------------------------------- */

function ImmersiveHero({ scene, blue, breathe }) {
  const ref = useRefDS(null);
  const [tilt, setTilt] = useStateDS({ rx: 0, ry: 0, mx: 50, my: 50, active: false });

  const onMove = (e) => {
    const el = ref.current; if (!el) return;
    const r = el.getBoundingClientRect();
    const px = (e.clientX - r.left) / r.width;
    const py = (e.clientY - r.top) / r.height;
    setTilt({ rx: (0.5 - py) * 4, ry: (px - 0.5) * 6, mx: px * 100, my: py * 100, active: true });
  };
  const onLeave = () => setTilt({ rx: 0, ry: 0, mx: 50, my: 50, active: false });

  return (
    <div ref={ref} onMouseMove={onMove} onMouseLeave={onLeave}
      style={{
        width: '100%',
        aspectRatio: '16 / 9',
        borderRadius: 'clamp(20px, 2.4vw, 32px)',
        overflow: 'hidden',
        position: 'relative',
        perspective: 1600,
        background: '#0A0A0B',
        boxShadow: '0 40px 100px -40px rgba(0,0,0,0.4)',
        transformStyle: 'preserve-3d',
      }}>
      <div style={{
        position: 'absolute', inset: 0,
        transform: `rotateX(${tilt.rx}deg) rotateY(${tilt.ry}deg) scale(${1 + breathe * 0.012})`,
        transition: tilt.active ? 'transform 240ms cubic-bezier(0.22,1,0.36,1)' : 'transform 900ms cubic-bezier(0.22,1,0.36,1)',
        transformStyle: 'preserve-3d',
      }}>
        <ScenePhoto scene={scene}/>
        <div aria-hidden="true" style={{
          position: 'absolute', inset: 0,
          backgroundImage: "url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.8 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>\")",
          mixBlendMode: 'multiply', opacity: 0.16,
        }}/>
        <div aria-hidden="true" style={{
          position: 'absolute', inset: 0,
          background: `radial-gradient(circle at ${tilt.mx}% ${tilt.my}%, rgba(255,255,255,${tilt.active ? 0.18 : 0.06}) 0%, rgba(255,255,255,0) 45%)`,
          mixBlendMode: 'screen',
          transform: 'translateZ(40px)',
        }}/>
        <div aria-hidden="true" style={{
          position: 'absolute', inset: 0,
          boxShadow: 'inset 0 0 240px rgba(0,0,0,0.4)',
        }}/>
      </div>
    </div>
  );
}

/* ----------------------------------------------------------------- */
/*  BOOKING MODULE — Premium reservation card                         */
/* ----------------------------------------------------------------- */

function BookingModule({ studio, blue }) {
  const [mode, setMode] = useStateDS('viewing'); // viewing | monthly
  const [date, setDate] = useStateDS(2);
  const days = ['Mon 11', 'Tue 12', 'Wed 13', 'Thu 14', 'Fri 15', 'Sat 16'];
  return (
    <div style={{
      background: '#FFFFFF',
      borderRadius: 'clamp(20px, 2.2vw, 28px)',
      padding: 'clamp(24px, 2.6vw, 36px)',
      border: '1px solid rgba(10,10,11,0.08)',
      boxShadow: '0 24px 60px -32px rgba(0,0,0,0.18), 0 1px 3px rgba(0,0,0,0.04)',
    }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div className="aspace-eyebrow">Reserve a viewing</div>
        <span style={{
          display: 'inline-flex', alignItems: 'center', gap: 8,
          fontSize: 12, color: 'rgba(10,10,11,0.6)',
          padding: '6px 12px', borderRadius: 99,
          background: 'rgba(0,194,255,0.08)',
          whiteSpace: 'nowrap',
        }}>
          <span style={{ width: 6, height: 6, borderRadius: '50%', background: blue, boxShadow: `0 0 8px ${blue}` }}/>
          {studio.status}
        </span>
      </div>

      {/* Mode toggle */}
      <div style={{
        marginTop: 22,
        display: 'grid', gridTemplateColumns: '1fr 1fr',
        background: '#F4F2EC', borderRadius: 14, padding: 4,
        position: 'relative',
      }}>
        <span aria-hidden="true" style={{
          position: 'absolute', top: 4, bottom: 4, left: 4, width: 'calc(50% - 4px)',
          background: '#0A0A0B', borderRadius: 11,
          transform: mode === 'viewing' ? 'translateX(0)' : 'translateX(100%)',
          transition: 'transform 460ms cubic-bezier(0.22,1.2,0.36,1)',
        }}/>
        {[['viewing','Viewing'],['monthly','Monthly']].map(([k, l]) => (
          <button key={k} onClick={() => setMode(k)} style={{
            all: 'unset', cursor: 'pointer',
            padding: '12px 0', textAlign: 'center',
            position: 'relative', zIndex: 1,
            color: mode === k ? '#fff' : '#0A0A0B',
            transition: 'color 360ms ease',
            fontSize: 14, fontWeight: 500,
          }}>{l}</button>
        ))}
      </div>

      {/* Date strip */}
      <div style={{ marginTop: 22 }}>
        <div className="aspace-eyebrow" style={{ marginBottom: 12, fontSize: 11 }}>Choose a date</div>
        <div style={{ display: 'flex', gap: 8, overflowX: 'auto', paddingBottom: 4 }}>
          {days.map((d, i) => {
            const active = date === i;
            const disabled = i === 1 || i === 4;
            return (
              <button key={i} onClick={() => !disabled && setDate(i)} disabled={disabled}
                style={{
                  all: 'unset', cursor: disabled ? 'not-allowed' : 'pointer',
                  flex: '0 0 auto',
                  minWidth: 64,
                  padding: '14px 12px',
                  borderRadius: 14,
                  textAlign: 'center',
                  background: active ? '#0A0A0B' : 'transparent',
                  color: active ? '#fff' : (disabled ? 'rgba(10,10,11,0.25)' : '#0A0A0B'),
                  border: '1px solid ' + (active ? '#0A0A0B' : 'rgba(10,10,11,0.10)'),
                  position: 'relative',
                  transition: 'background 280ms ease, color 280ms ease, border-color 280ms ease, transform 280ms cubic-bezier(0.22,1.2,0.36,1)',
                  transform: active ? 'translateY(-1px)' : 'translateY(0)',
                  textDecoration: disabled ? 'line-through' : 'none',
                }}>
                <div style={{ fontSize: 11, letterSpacing: '0.08em', textTransform: 'uppercase', opacity: 0.7 }}>{d.split(' ')[0]}</div>
                <div style={{ fontSize: 20, fontWeight: 500, marginTop: 4, fontFamily: "'Inter Tight', sans-serif" }}>{d.split(' ')[1]}</div>
                {active && <span style={{ position: 'absolute', bottom: 8, left: '50%', transform: 'translateX(-50%)', width: 6, height: 6, borderRadius: '50%', background: blue, boxShadow: `0 0 6px ${blue}` }}/>}
              </button>
            );
          })}
        </div>
      </div>

      {/* Time slots */}
      <div style={{ marginTop: 18 }}>
        <div className="aspace-eyebrow" style={{ marginBottom: 12, fontSize: 11 }}>Suggested times</div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 8 }}>
          {['10:00', '13:30', '16:00'].map((t, i) => (
            <button key={t} style={{
              all: 'unset', cursor: 'pointer', textAlign: 'center',
              padding: '12px 0', fontSize: 14,
              borderRadius: 12,
              border: '1px solid rgba(10,10,11,0.10)',
              transition: 'all 280ms ease',
            }}
            onMouseEnter={e => { e.currentTarget.style.background = '#0A0A0B'; e.currentTarget.style.color = '#fff'; e.currentTarget.style.borderColor = '#0A0A0B'; }}
            onMouseLeave={e => { e.currentTarget.style.background = 'transparent'; e.currentTarget.style.color = '#0A0A0B'; e.currentTarget.style.borderColor = 'rgba(10,10,11,0.10)'; }}
            >{t}</button>
          ))}
        </div>
      </div>

      {/* Summary */}
      <div style={{
        marginTop: 22, padding: '16px 0',
        borderTop: '1px solid rgba(10,10,11,0.10)',
        display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
      }}>
        <div>
          <div style={{ fontSize: 11, letterSpacing: '0.12em', textTransform: 'uppercase', color: 'rgba(10,10,11,0.5)' }}>{mode === 'viewing' ? 'In-person tour' : 'Monthly rental'}</div>
          <div style={{ fontFamily: "'Inter Tight', sans-serif", fontWeight: 500, fontSize: 22, marginTop: 4 }}>
            {mode === 'viewing' ? 'Free · 30 min' : 'From €620 / month'}
          </div>
        </div>
        <div style={{ fontSize: 12, color: 'rgba(10,10,11,0.5)' }}>{days[date]}</div>
      </div>

      <a href="#contact" data-open-contact className="aspace-pill solid" style={{
        marginTop: 16, justifyContent: 'space-between',
        display: 'inline-flex', width: '100%',
        background: blue, color: '#000', borderColor: blue,
        padding: '18px 22px',
      }}>
        <span style={{ fontSize: 15 }}>{mode === 'viewing' ? 'Confirm viewing request' : 'Request availability'}</span>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
        </span>
      </a>

      <p style={{ marginTop: 14, fontSize: 12, color: 'rgba(10,10,11,0.5)', lineHeight: 1.5 }}>
        Booking placeholder — you'll receive a confirmation by email within one working day. Real booking system arrives next.
      </p>
    </div>
  );
}

/* ----------------------------------------------------------------- */
/*  ANGLE THUMB — small variant of a scene with a subtle hover zoom   */
/* ----------------------------------------------------------------- */

function AngleTile({ scene, blue, label, idx }) {
  return (
    <div className="angle-tile" style={{
      position: 'relative',
      borderRadius: 'clamp(14px, 1.6vw, 20px)',
      overflow: 'hidden',
      aspectRatio: idx % 3 === 0 ? '4 / 5' : '4 / 3',
      cursor: 'pointer',
      background: '#0A0A0B',
    }}>
      <div className="angle-scene" style={{
        position: 'absolute', inset: 0,
        transition: 'transform 880ms cubic-bezier(0.22,1,0.36,1)',
        transform: `scale(1) translateX(${idx * -2}%)`,
      }}>
        <ScenePhoto scene={scene}/>
      </div>
      <div aria-hidden="true" style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(0,0,0,0) 50%, rgba(0,0,0,0.55) 100%)' }}/>
      <div style={{
        position: 'absolute', left: 14, bottom: 14,
        color: '#fff', fontSize: 12, letterSpacing: '0.12em', textTransform: 'uppercase',
        fontFamily: "'Inter Tight', sans-serif",
      }}>{String(idx+1).padStart(2,'0')} · {label}</div>
    </div>
  );
}

/* ----------------------------------------------------------------- */
/*  STUDIO DETAIL — Full layout                                       */
/* ----------------------------------------------------------------- */

function StudioDetail({ studio, blue, onClose, originRect }) {
  const [phase, setPhase] = useStateDS('zoom'); // 'zoom' (start at originRect) → 'open' (full)
  const [breathe, setBreathe] = useStateDS(0);
  const data = DETAIL_DATA[studio.scene] || {};

  // Phase orchestration: start at origin rect → expand → resolve content
  useLayoutEffectDS(() => {
    document.body.style.overflow = 'hidden';
    return () => { document.body.style.overflow = ''; };
  }, []);

  useEffectDS(() => {
    const t = setTimeout(() => setPhase('open'), 30);
    const onKey = (e) => { if (e.key === 'Escape') handleClose(); };
    window.addEventListener('keydown', onKey);
    return () => { clearTimeout(t); window.removeEventListener('keydown', onKey); };
  }, []);

  // Subtle breathing on hero — sin wave
  useEffectDS(() => {
    let raf, t0 = performance.now();
    const tick = (t) => {
      const elapsed = (t - t0) / 1000;
      setBreathe(Math.sin(elapsed * 0.6));
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);

  const handleClose = () => {
    setPhase('zoom');
    setTimeout(onClose, 760);
  };

  // Compute the hero card transform.
  // We render the hero in a fixed container that occupies its natural slot,
  // but during 'zoom' phase we transform from origin rect to the natural slot.
  const heroOuterRef = useRefDS(null);
  const [transformStr, setTransformStr] = useStateDS('');
  useLayoutEffectDS(() => {
    const compute = () => {
      const el = heroOuterRef.current;
      if (!el || !originRect) return;
      const r = el.getBoundingClientRect();
      // Translate FROM target TO origin
      const tx = originRect.left - r.left;
      const ty = originRect.top - r.top;
      const sx = originRect.width / r.width;
      const sy = originRect.height / r.height;
      setTransformStr(`translate(${tx}px, ${ty}px) scale(${sx}, ${sy})`);
    };
    compute();
    window.addEventListener('resize', compute);
    return () => window.removeEventListener('resize', compute);
  }, [originRect]);

  return (
    <React.Fragment>
      {/* Backdrop */}
      <div onClick={handleClose} style={{
        position: 'fixed', inset: 0, zIndex: 9700,
        background: '#F4F2EC',
        opacity: phase === 'open' ? 1 : 0,
        transition: 'opacity 720ms cubic-bezier(0.22,1,0.36,1)',
      }}/>
      {/* The page */}
      <div style={{
        position: 'fixed', inset: 0, zIndex: 9800,
        overflow: 'auto',
        opacity: phase === 'open' ? 1 : 0,
        pointerEvents: phase === 'open' ? 'auto' : 'auto',
        transition: 'opacity 600ms ease 200ms',
      }}>
        {/* Top action bar */}
        <div style={{
          position: 'sticky', top: 0, zIndex: 5,
          padding: 'clamp(16px, 2vw, 28px) var(--gutter)',
          display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          background: 'linear-gradient(to bottom, rgba(244,242,236,0.92), rgba(244,242,236,0))',
          backdropFilter: 'blur(8px)',
          WebkitBackdropFilter: 'blur(8px)',
          opacity: phase === 'open' ? 1 : 0,
          transform: `translateY(${phase === 'open' ? 0 : -10}px)`,
          transition: 'opacity 500ms ease 350ms, transform 600ms ease 350ms',
        }}>
          <div className="aspace-eyebrow" style={{ display: 'inline-flex', gap: 12, alignItems: 'center' }}>
            <span className="aspace-plus"/> Studio · {studio.n}
          </div>
          <button onClick={handleClose}
            className="aspace-pill"
            style={{ borderColor: 'rgba(10,10,11,0.2)' }}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8"><path d="M19 12H5M11 6l-6 6 6 6"/></svg>
            <span>Back to studios</span>
          </button>
        </div>

        {/* Title block */}
        <div style={{ padding: '0 var(--gutter)', maxWidth: 1600, margin: '0 auto' }}>
          <RevealRow phase={phase} delay={350}>
            <div className="aspace-eyebrow" style={{ marginBottom: 18 }}>{data.overline}</div>
          </RevealRow>
          <RevealRow phase={phase} delay={420} amount={28}>
            <h1 style={{
              margin: 0,
              fontFamily: "'Inter Tight', sans-serif",
              fontWeight: 500,
              fontSize: 'clamp(56px, 11vw, 200px)',
              lineHeight: 0.86,
              letterSpacing: '-0.04em',
              textWrap: 'balance',
            }}>{studio.title}.</h1>
          </RevealRow>
        </div>

        {/* HERO IMAGE — flies from originRect to its natural slot */}
        <div style={{
          padding: 'clamp(40px, 5vw, 80px) var(--gutter) 0',
          maxWidth: 1600, margin: '0 auto',
        }}>
          <div ref={heroOuterRef} style={{ position: 'relative' }}>
            <div style={{
              transformOrigin: 'top left',
              transform: phase === 'open' ? 'translate(0,0) scale(1,1)' : transformStr,
              transition: 'transform 880ms cubic-bezier(0.7, 0, 0.3, 1)',
              willChange: 'transform',
              filter: phase === 'open' ? 'blur(0)' : 'blur(0.5px)',
            }}>
              <ImmersiveHero scene={studio.scene} blue={blue} breathe={breathe}/>
            </div>
            {/* Floating availability badge */}
            <div style={{
              position: 'absolute', top: 18, left: 18,
              display: 'inline-flex', alignItems: 'center', gap: 10,
              padding: '10px 16px', borderRadius: 99,
              background: 'rgba(255,255,255,0.92)',
              backdropFilter: 'blur(12px)',
              fontSize: 12, letterSpacing: '0.1em', textTransform: 'uppercase',
              opacity: phase === 'open' ? 1 : 0,
              transition: 'opacity 600ms ease 600ms',
            }}>
              <span style={{ width: 8, height: 8, borderRadius: '50%', background: blue, boxShadow: `0 0 8px ${blue}` }}/>
              {studio.status}
            </div>
          </div>
        </div>

        {/* INFO LAYOUT — left description / right booking */}
        <div className="detail-grid" style={{
          padding: 'clamp(56px, 8vw, 120px) var(--gutter)',
          maxWidth: 1600, margin: '0 auto',
          display: 'grid',
          gridTemplateColumns: 'minmax(0, 1.4fr) minmax(360px, 1fr)',
          gap: 'clamp(40px, 5vw, 96px)',
          alignItems: 'start',
        }}>
          {/* Left */}
          <div>
            <RevealRow phase={phase} delay={650}>
              <p style={{
                margin: 0,
                fontFamily: "'Inter Tight', sans-serif", fontWeight: 400,
                fontSize: 'clamp(20px, 1.8vw, 28px)',
                lineHeight: 1.4, letterSpacing: '-0.01em',
                color: '#0A0A0B', maxWidth: 720,
              }}>{data.paragraph}</p>
            </RevealRow>

            {/* Spec */}
            <RevealRow phase={phase} delay={750}>
              <div style={{
                marginTop: 'clamp(40px, 5vw, 64px)',
                display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))',
                borderTop: '2px solid rgba(10,10,11,0.18)',
              }}>
                {(data.spec || []).map(([k, v]) => (
                  <div key={k} style={{
                    padding: '18px 0',
                    borderBottom: '1px solid rgba(10,10,11,0.10)',
                    paddingRight: 16,
                  }}>
                    <div style={{ fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'rgba(10,10,11,0.5)', marginBottom: 6 }}>{k}</div>
                    <div style={{ fontFamily: "'Inter Tight',sans-serif", fontWeight: 500, fontSize: 17 }}>{v}</div>
                  </div>
                ))}
              </div>
            </RevealRow>

            {/* Features */}
            <div style={{ marginTop: 'clamp(56px, 7vw, 96px)' }}>
              <div className="aspace-eyebrow" style={{ marginBottom: 32 }}>What this studio includes</div>
              <ul style={{ listStyle: 'none', padding: 0, margin: 0 }}>
                {(data.features || []).map((f, i) => (
                  <RevealRow key={f.label} phase={phase} delay={850 + i * 80}>
                    <li style={{
                      display: 'grid',
                      gridTemplateColumns: '40px minmax(0, 1.2fr) minmax(0, 2fr)',
                      gap: 24,
                      padding: '22px 0',
                      borderTop: i === 0 ? '1px solid rgba(10,10,11,0.12)' : 'none',
                      borderBottom: '1px solid rgba(10,10,11,0.12)',
                      alignItems: 'baseline',
                    }}>
                      <span style={{ fontFamily: 'monospace', fontSize: 13, color: 'rgba(10,10,11,0.4)' }}>0{i+1}</span>
                      <span style={{
                        fontFamily: "'Inter Tight', sans-serif", fontWeight: 500,
                        fontSize: 'clamp(22px, 2vw, 30px)',
                        letterSpacing: '-0.01em',
                      }}>{f.label}</span>
                      <span style={{ color: 'rgba(10,10,11,0.65)', fontSize: 15, lineHeight: 1.5 }}>{f.desc}</span>
                    </li>
                  </RevealRow>
                ))}
              </ul>
            </div>
          </div>

          {/* Right — Booking */}
          <div className="detail-booking" style={{
            position: 'sticky', top: 96,
          }}>
            <RevealRow phase={phase} delay={700} amount={20}>
              <BookingModule studio={studio} blue={blue}/>
            </RevealRow>
          </div>
        </div>

        {/* Gallery */}
        <div style={{
          padding: 'clamp(40px, 5vw, 80px) var(--gutter) clamp(80px, 10vw, 160px)',
          maxWidth: 1600, margin: '0 auto',
        }}>
          <RevealRow phase={phase} delay={1100}>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 28, gap: 24, flexWrap: 'wrap' }}>
              <div className="aspace-eyebrow" style={{ display: 'inline-flex', alignItems: 'center', gap: 12 }}>
                <span className="aspace-plus"/> Angles
              </div>
              <span style={{ fontSize: 13, color: 'rgba(10,10,11,0.5)' }}>4 views · scroll →</span>
            </div>
          </RevealRow>
          <RevealRow phase={phase} delay={1200} amount={32}>
            <div style={{
              display: 'grid',
              gridTemplateColumns: 'repeat(4, minmax(0, 1fr))',
              gap: 'clamp(12px, 1.4vw, 20px)',
            }} className="angle-grid">
              {(data.angles || []).map((a, i) => (
                <AngleTile key={i} idx={i} label={a} scene={studio.scene} blue={blue}/>
              ))}
            </div>
          </RevealRow>
        </div>

        {/* Footer CTA */}
        <div style={{
          background: '#0A0A0B', color: '#fff',
          padding: 'clamp(96px, 14vw, 200px) var(--gutter)',
          textAlign: 'center',
        }}>
          <RevealRow phase={phase} delay={1300}>
            <div className="aspace-eyebrow" style={{ color: 'rgba(255,255,255,0.55)', marginBottom: 20, justifyContent: 'center', display: 'inline-flex', gap: 12 }}>
              <span className="aspace-plus" style={{ background: 'rgba(255,255,255,0.6)' }}/> Want to see it?
            </div>
          </RevealRow>
          <RevealRow phase={phase} delay={1380} amount={28}>
            <h2 style={{
              margin: 0, fontFamily: "'Inter Tight', sans-serif", fontWeight: 500,
              fontSize: 'clamp(56px, 10vw, 168px)',
              lineHeight: 0.88, letterSpacing: '-0.04em',
              maxWidth: '14ch', marginInline: 'auto',
              textWrap: 'balance',
            }}>Book a viewing<br/><span style={{ color: blue }}>this week.</span></h2>
          </RevealRow>
          <RevealRow phase={phase} delay={1480}>
            <div style={{ marginTop: 40, display: 'inline-flex', gap: 12, flexWrap: 'wrap', justifyContent: 'center' }}>
              {studio.bookingId && (
                <a href={`/site/booking.html?studio=${studio.bookingId}`} className="aspace-pill" style={{ background: blue, color: '#000', border: 'none' }}>
                  <span>Book this studio</span>
                  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
                </a>
              )}
              <button data-open-contact className="aspace-pill" style={
                studio.bookingId
                  ? { borderColor: 'rgba(255,255,255,0.3)', color: '#fff' }
                  : { background: blue, color: '#000', border: 'none' }
              }>
                <span>Book a viewing</span>
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
              </button>
              <button onClick={handleClose} className="aspace-pill" style={{ borderColor: 'rgba(255,255,255,0.3)', color: '#fff' }}>
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8"><path d="M19 12H5M11 6l-6 6 6 6"/></svg>
                <span>Other studios</span>
              </button>
            </div>
          </RevealRow>
        </div>

        <style>{`
          @media (max-width: 980px) {
            .detail-grid { grid-template-columns: 1fr !important; }
            .detail-booking { position: static !important; }
            .angle-grid { grid-template-columns: repeat(2, 1fr) !important; }
          }
          .angle-tile:hover .angle-scene { transform: scale(1.06) !important; }
        `}</style>
      </div>
    </React.Fragment>
  );
}

function RevealRow({ children, phase, delay = 0, amount = 16 }) {
  const open = phase === 'open';
  return (
    <div style={{
      transform: open ? 'translateY(0)' : `translateY(${amount}px)`,
      opacity: open ? 1 : 0,
      filter: open ? 'blur(0)' : 'blur(6px)',
      transition: `transform 900ms cubic-bezier(0.22,1,0.36,1) ${delay}ms, opacity 700ms ease ${delay}ms, filter 700ms ease ${delay}ms`,
    }}>{children}</div>
  );
}

window.StudioDetail = StudioDetail;
