/* global React */
const { useState: useStateSt, useEffect: useEffectSt, useRef: useRefSt } = React;

/* ----------------------------------------------------------------- */
/*  STUDIO PLACEHOLDER VISUALS                                       */
/*  We have no real photography yet — render credible architectural   */
/*  scenes via SVG so the page reads premium without stock noise.     */
/* ----------------------------------------------------------------- */

// Temporary photo placeholders — three studio mockups distributed across
// the six scenes. Each mockup keeps a different visual mood so the grid
// still has variation. Will be replaced with real shoots later.
const SCENE_MOCKUP = {
  northLight: '/site/uploads/mockup1.png',  // bright loft
  motionLab:  '/site/uploads/mockup2.png',  // industrial cyc
  atelier:    '/site/uploads/mockup3.png',  // moody atelier
  podcast:    '/site/uploads/mockup2.png',  // dark studio
  workshop:   '/site/uploads/mockup3.png',  // dark workspace
  lounge:     '/site/uploads/mockup1.png',  // bright lounge
};
function mockupFor(scene) { return SCENE_MOCKUP[scene] || '/site/uploads/mockup2.png'; }

const STUDIO_SCENES = {
  northLight: ({ blue }) => (
    <svg viewBox="0 0 1600 1100" preserveAspectRatio="xMidYMid slice" style={{ width: '100%', height: '100%', display: 'block' }}>
      <defs>
        <linearGradient id="nl-floor" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0" stopColor="#E9E4DA"/><stop offset="1" stopColor="#C7BFB1"/>
        </linearGradient>
        <linearGradient id="nl-wall" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0" stopColor="#FBF8F2"/><stop offset="1" stopColor="#E8E2D5"/>
        </linearGradient>
        <linearGradient id="nl-light" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0" stopColor="#FFFFFF" stopOpacity="0.85"/>
          <stop offset="1" stopColor="#FFFFFF" stopOpacity="0"/>
        </linearGradient>
      </defs>
      <rect width="1600" height="1100" fill="url(#nl-wall)"/>
      <rect y="780" width="1600" height="320" fill="url(#nl-floor)"/>
      {/* tall window grid */}
      <g transform="translate(140 80)">
        <rect width="780" height="780" fill="#F5F1E8" stroke="#0A0A0B" strokeWidth="3"/>
        {[0,1,2,3].map(c => [0,1,2,3,4].map(r => (
          <rect key={c+'-'+r} x={c*195} y={r*156} width="195" height="156" fill="none" stroke="#0A0A0B" strokeWidth="2.5"/>
        )))}
        <rect width="780" height="780" fill="url(#nl-light)" opacity="0.9"/>
      </g>
      {/* light shaft on floor */}
      <polygon points="160,860 920,860 1180,1100 0,1100" fill="#FFFFFF" opacity="0.18"/>
      {/* easel and stool silhouettes */}
      <g fill="#0A0A0B">
        <rect x="1080" y="540" width="6" height="380"/>
        <polygon points="1010,920 1170,920 1090,540 1100,540"/>
        <rect x="1010" y="540" width="160" height="160" fill="#1A1A1B"/>
        <rect x="1014" y="544" width="152" height="152" fill="none" stroke="#3B3B3D" strokeWidth="2"/>
      </g>
      <g fill="#1A1A1B">
        <ellipse cx="1320" cy="900" rx="48" ry="10"/>
        <rect x="1316" y="780" width="8" height="120"/>
        <ellipse cx="1320" cy="780" rx="38" ry="8"/>
      </g>
      {/* electric blue accent line */}
      <line x1="40" y1="1040" x2="1560" y2="1040" stroke={blue} strokeWidth="2" opacity="0.7"/>
    </svg>
  ),
  motionLab: ({ blue }) => (
    <svg viewBox="0 0 1600 1100" preserveAspectRatio="xMidYMid slice" style={{ width: '100%', height: '100%', display: 'block' }}>
      <defs>
        <radialGradient id="ml-bg" cx="0.5" cy="0.4" r="0.9">
          <stop offset="0" stopColor="#1A1B22"/><stop offset="1" stopColor="#08080A"/>
        </radialGradient>
        <linearGradient id="ml-led" x1="0" x2="1" y1="0" y2="0">
          <stop offset="0" stopColor={blue} stopOpacity="0.0"/>
          <stop offset="0.4" stopColor={blue} stopOpacity="0.55"/>
          <stop offset="0.6" stopColor={blue} stopOpacity="0.55"/>
          <stop offset="1" stopColor={blue} stopOpacity="0.0"/>
        </linearGradient>
      </defs>
      <rect width="1600" height="1100" fill="url(#ml-bg)"/>
      {/* LED wall — subdivided panels */}
      <g transform="translate(80 90)">
        <rect width="1440" height="720" fill="#0F1118" stroke="#22242C" strokeWidth="2"/>
        {[...Array(12)].map((_,i) => (
          <line key={i} x1={i*120} y1="0" x2={i*120} y2="720" stroke="#1B1D26" strokeWidth="1"/>
        ))}
        {[...Array(6)].map((_,i) => (
          <line key={i} x1="0" y1={i*120} x2="1440" y2={i*120} stroke="#1B1D26" strokeWidth="1"/>
        ))}
        {/* projected scene — a soft horizon */}
        <rect x="0" y="0" width="1440" height="430" fill={blue} opacity="0.08"/>
        <rect x="0" y="430" width="1440" height="290" fill="#000" opacity="0.6"/>
        <ellipse cx="720" cy="430" rx="380" ry="60" fill={blue} opacity="0.18"/>
        <rect x="0" y="425" width="1440" height="3" fill="url(#ml-led)"/>
      </g>
      {/* camera rig */}
      <g fill="#1F2128" stroke="#3A3D48" strokeWidth="2">
        <rect x="640" y="900" width="320" height="40" rx="6"/>
        <rect x="780" y="820" width="40" height="80"/>
        <rect x="700" y="860" width="200" height="50" rx="6"/>
        <rect x="900" y="870" width="100" height="34" rx="4"/>
      </g>
      <circle cx="800" cy="900" r="36" fill="#0B0B10" stroke="#3A3D48" strokeWidth="3"/>
      {/* floor seam */}
      <line x1="0" y1="980" x2="1600" y2="980" stroke="#1B1D26" strokeWidth="2"/>
      {/* blue line accent */}
      <line x1="80" y1="1050" x2="1520" y2="1050" stroke={blue} strokeWidth="2" opacity="0.7"/>
    </svg>
  ),
  atelier: ({ blue }) => (
    <svg viewBox="0 0 1600 1100" preserveAspectRatio="xMidYMid slice" style={{ width: '100%', height: '100%', display: 'block' }}>
      <defs>
        <linearGradient id="at-wall" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0" stopColor="#F8F4EB"/><stop offset="1" stopColor="#D9D2C2"/>
        </linearGradient>
      </defs>
      <rect width="1600" height="1100" fill="url(#at-wall)"/>
      {/* wood floor */}
      <rect y="820" width="1600" height="280" fill="#A98D6A"/>
      {[...Array(20)].map((_,i) => (
        <line key={i} x1={i*80} y1="820" x2={i*80} y2="1100" stroke="#8C6E4D" strokeWidth="1" opacity="0.5"/>
      ))}
      {/* hanging garments rail */}
      <line x1="200" y1="280" x2="1100" y2="280" stroke="#0A0A0B" strokeWidth="6"/>
      <line x1="220" y1="280" x2="220" y2="120" stroke="#0A0A0B" strokeWidth="3"/>
      <line x1="1080" y1="280" x2="1080" y2="120" stroke="#0A0A0B" strokeWidth="3"/>
      {/* garments */}
      {[
        {x:260, color:'#1B1D24', w:80},
        {x:360, color:'#3A3D48', w:90},
        {x:470, color:'#0A0A0B', w:70},
        {x:560, color:'#7B7268', w:90},
        {x:670, color:'#2C2F38', w:80},
        {x:770, color:'#1B1D24', w:90},
        {x:880, color:'#0A0A0B', w:70},
        {x:970, color:'#7B7268', w:80},
      ].map((g, i) => (
        <g key={i}>
          <rect x={g.x} y="290" width={g.w} height="380" fill={g.color}/>
          <ellipse cx={g.x + g.w/2} cy="290" rx={g.w/2} ry="6" fill={g.color}/>
        </g>
      ))}
      {/* mannequin */}
      <g fill="#E0DACA" stroke="#9C9684" strokeWidth="2">
        <ellipse cx="1300" cy="380" rx="36" ry="44"/>
        <rect x="1264" y="424" width="72" height="180" rx="20"/>
        <rect x="1278" y="600" width="44" height="220" rx="10"/>
        <rect x="1294" y="816" width="40" height="14"/>
      </g>
      {/* table with fabric swatches */}
      <rect x="1180" y="780" width="380" height="40" fill="#3A2D1F"/>
      <rect x="1200" y="740" width="80" height="40" fill={blue} opacity="0.85"/>
      <rect x="1290" y="746" width="100" height="34" fill="#0A0A0B"/>
      <rect x="1400" y="752" width="80" height="28" fill="#C9BFA8"/>
      {/* blue accent line */}
      <line x1="40" y1="1050" x2="1560" y2="1050" stroke={blue} strokeWidth="2" opacity="0.65"/>
    </svg>
  ),
  podcast: ({ blue }) => (
    <svg viewBox="0 0 1600 1100" preserveAspectRatio="xMidYMid slice" style={{ width: '100%', height: '100%', display: 'block' }}>
      <defs>
        <radialGradient id="pc-bg" cx="0.5" cy="0.5" r="0.9">
          <stop offset="0" stopColor="#1B1D26"/><stop offset="1" stopColor="#08080B"/>
        </radialGradient>
      </defs>
      <rect width="1600" height="1100" fill="url(#pc-bg)"/>
      {/* acoustic foam wall */}
      <g transform="translate(80 80)">
        {[...Array(14)].map((_,c) => [...Array(8)].map((_,r) => (
          <polygon key={c+'-'+r}
            points={`${c*100},${r*100} ${c*100+50},${r*100+50} ${c*100},${r*100+100} `}
            fill="#1F2128" opacity={(c+r)%2 ? 0.6 : 0.85}/>
        )))}
      </g>
      {/* table */}
      <rect x="240" y="700" width="1120" height="200" fill="#101117" stroke="#22242C" strokeWidth="2"/>
      {/* mic 1 */}
      <g transform="translate(540 460)">
        <rect x="44" y="240" width="12" height="60" fill="#3A3D48"/>
        <rect x="20" y="180" width="60" height="80" rx="8" fill="#0A0A0B" stroke="#3A3D48" strokeWidth="2"/>
        <ellipse cx="50" cy="220" rx="20" ry="30" fill={blue} opacity="0.22"/>
      </g>
      {/* mic 2 */}
      <g transform="translate(940 480)">
        <rect x="44" y="240" width="12" height="60" fill="#3A3D48"/>
        <rect x="20" y="180" width="60" height="80" rx="8" fill="#0A0A0B" stroke="#3A3D48" strokeWidth="2"/>
        <ellipse cx="50" cy="220" rx="20" ry="30" fill={blue} opacity="0.22"/>
      </g>
      {/* on-air sign */}
      <rect x="660" y="160" width="280" height="80" rx="8" fill="#0A0A0B" stroke={blue} strokeWidth="2"/>
      <text x="800" y="216" fill={blue} fontSize="44" textAnchor="middle" fontFamily="Inter Tight" fontWeight="600" letterSpacing="6">ON AIR</text>
      <line x1="80" y1="1040" x2="1520" y2="1040" stroke={blue} strokeWidth="2" opacity="0.6"/>
    </svg>
  ),
  workshop: ({ blue }) => (
    <svg viewBox="0 0 1600 1100" preserveAspectRatio="xMidYMid slice" style={{ width: '100%', height: '100%', display: 'block' }}>
      <defs>
        <linearGradient id="ws-wall" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0" stopColor="#F4F0E5"/><stop offset="1" stopColor="#D2CBBC"/>
        </linearGradient>
      </defs>
      <rect width="1600" height="1100" fill="url(#ws-wall)"/>
      {/* concrete floor */}
      <rect y="780" width="1600" height="320" fill="#9D998E"/>
      {/* workbench */}
      <rect x="120" y="640" width="1360" height="160" fill="#3A2D1F"/>
      <rect x="160" y="800" width="40" height="120" fill="#3A2D1F"/>
      <rect x="1400" y="800" width="40" height="120" fill="#3A2D1F"/>
      {/* tools / objects */}
      <rect x="200" y="540" width="120" height="100" fill="#0A0A0B"/>
      <rect x="360" y="580" width="80" height="60" fill={blue}/>
      <circle cx="540" cy="600" r="40" fill="#1A1A1B"/>
      <rect x="640" y="500" width="160" height="140" fill="#E0DACA"/>
      <rect x="660" y="520" width="120" height="100" fill="none" stroke="#0A0A0B" strokeWidth="2"/>
      <rect x="860" y="560" width="200" height="80" fill="#7B7268"/>
      <rect x="1100" y="540" width="60" height="100" fill="#0A0A0B"/>
      <circle cx="1240" cy="610" r="30" fill={blue} opacity="0.85"/>
      <rect x="1320" y="560" width="120" height="80" fill="#1A1A1B"/>
      {/* hanging pendant lamps */}
      {[400, 800, 1200].map(x => (
        <g key={x}>
          <line x1={x} y1="0" x2={x} y2="200" stroke="#0A0A0B" strokeWidth="2"/>
          <ellipse cx={x} cy="220" rx="40" ry="20" fill="#0A0A0B"/>
          <ellipse cx={x} cy="240" rx="30" ry="6" fill="#FFE8B0" opacity="0.6"/>
        </g>
      ))}
      <line x1="40" y1="1050" x2="1560" y2="1050" stroke={blue} strokeWidth="2" opacity="0.65"/>
    </svg>
  ),
  lounge: ({ blue }) => (
    <svg viewBox="0 0 1600 1100" preserveAspectRatio="xMidYMid slice" style={{ width: '100%', height: '100%', display: 'block' }}>
      <defs>
        <linearGradient id="lg-wall" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0" stopColor="#EFEAE0"/><stop offset="1" stopColor="#CFC8B8"/>
        </linearGradient>
      </defs>
      <rect width="1600" height="1100" fill="url(#lg-wall)"/>
      <rect y="780" width="1600" height="320" fill="#A88B68"/>
      {/* sofa */}
      <rect x="200" y="600" width="780" height="220" rx="20" fill="#3A3027"/>
      <rect x="220" y="540" width="220" height="80" rx="14" fill="#4F4337"/>
      <rect x="460" y="540" width="220" height="80" rx="14" fill="#4F4337"/>
      <rect x="700" y="540" width="220" height="80" rx="14" fill="#4F4337"/>
      {/* coffee table */}
      <rect x="320" y="840" width="540" height="40" rx="6" fill="#0A0A0B"/>
      <rect x="340" y="800" width="80" height="40" fill={blue} opacity="0.7"/>
      <rect x="460" y="810" width="120" height="30" fill="#E0DACA"/>
      <circle cx="700" cy="822" r="22" fill="#1A1A1B"/>
      {/* tall plant */}
      <rect x="1240" y="660" width="80" height="160" fill="#3A2D1F"/>
      {[...Array(8)].map((_,i) => (
        <ellipse key={i} cx={1280 + Math.cos(i)*80} cy={660 - i*40} rx="60" ry="20" fill="#2A4733" opacity="0.85"/>
      ))}
      {/* large artwork */}
      <rect x="1080" y="200" width="380" height="280" fill="#F5F1E8" stroke="#0A0A0B" strokeWidth="3"/>
      <rect x="1110" y="230" width="320" height="220" fill="#0A0A0B"/>
      <rect x="1140" y="260" width="80" height="160" fill={blue}/>
      <rect x="1240" y="280" width="160" height="80" fill="#E0DACA"/>
      <line x1="40" y1="1050" x2="1560" y2="1050" stroke={blue} strokeWidth="2" opacity="0.65"/>
    </svg>
  ),
};

/* ----------------------------------------------------------------- */
/*  STUDIOS DATA                                                     */
/* ----------------------------------------------------------------- */

// `bookingId` matches BOOKING_STUDIOS in booking-core.jsx and powers the
// `/site/booking.html?studio=<id>` deep-links. Studios without a bookingId
// (Atelier 05 waitlist, Living Room communal) keep the contact-panel CTA.
const STUDIOS = [
  { n:'01', label:'PRIVATE STUDIO • 16M²',      title:'North Light',   subtitle:'A high-ceiling room oriented to morning light. Built for photographers and painters who work to the sun.', scene:'northLight', tags:['Photography','Painting','Daylight'], status:'Available now',    bookingId:'north-light' },
  { n:'02', label:'CREATIVE SUITE • 22M²',      title:'Motion Lab',    subtitle:'LED wall, calibrated grid and a dedicated camera bay for hybrid productions and immersive shoots.',    scene:'motionLab',  tags:['LED wall','Video','XR'],            status:'1 spot left',      bookingId:'motion-lab' },
  { n:'03', label:'PRIVATE STUDIO • 18M²',      title:'Atelier 03',    subtitle:'A garment-ready studio with rails, fitting wall and a long bench for fashion designers and small brands.', scene:'atelier',  tags:['Fashion','Design','Production'],     status:'Available June',   bookingId:'atelier-03' },
  { n:'04', label:'PRODUCTION ROOM • 14M²',    title:'Signal Booth',  subtitle:'A treated room for podcasts, voice and long-form interviews. Two-mic ready, low-noise floor.',         scene:'podcast',     tags:['Podcast','Voice','Sound'],          status:'Available now',    bookingId:'signal-booth' },
  { n:'05', label:'WORKSHOP STUDIO • 24M²',    title:'Atelier 05',    subtitle:'Bench, tools and surface space for product designers, makers and prototyping-driven creative work.',   scene:'workshop',    tags:['Product','Prototype','Maker'],      status:'Waitlist' },
  { n:'06', label:'SHARED LOUNGE • COMMUNAL',  title:'The Living Room', subtitle:'Soft seating, a kitchen and a long bench for conversations between studios. Free with every membership.', scene:'lounge',  tags:['Lounge','Kitchen','Members'],       status:'Always open' },
];

/* ----------------------------------------------------------------- */
/*  SPATIAL HOVER WRAPPER                                            */
/* ----------------------------------------------------------------- */

function SpatialMedia({ scene, blue, scrollProgress = 0 }) {
  const ref = useRefSt(null);
  const [tilt, setTilt] = useStateSt({ 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;
    // Subtle: max ±4 degrees
    setTilt({ rx: (0.5 - py) * 6, ry: (px - 0.5) * 8, mx: px * 100, my: py * 100, active: true });
  };
  const onLeave = () => setTilt({ rx: 0, ry: 0, mx: 50, my: 50, active: false });

  // Scroll-driven settle: image enters slightly zoomed/rotated then normalizes
  // scrollProgress 0 = below fold, 0.5 = centered, 1 = scrolled past
  const settle = Math.max(0, Math.min(1, (scrollProgress - 0.0) / 0.6));
  const enterZoom = 1.06 - settle * 0.06;
  const enterRot  = (1 - settle) * 0.6;

  const Scene = STUDIO_SCENES[scene];

  return (
    <div ref={ref}
      onMouseMove={onMove} onMouseLeave={onLeave}
      style={{
        position: 'relative',
        width: '100%',
        aspectRatio: '16 / 11',
        borderRadius: 'clamp(18px, 2vw, 28px)',
        overflow: 'hidden',
        boxShadow: '0 30px 80px -30px rgba(0,0,0,0.35), 0 8px 24px -12px rgba(0,0,0,0.18)',
        perspective: 1400,
        background: '#0A0A0B',
        transition: 'box-shadow 480ms var(--ease-cinema)',
        transformStyle: 'preserve-3d',
      }}>
      {/* Inner plane — perspective rotation */}
      <div style={{
        position: 'absolute', inset: 0,
        transform: `rotateX(${tilt.rx + enterRot}deg) rotateY(${tilt.ry}deg) scale(${enterZoom})`,
        transition: tilt.active ? 'transform 220ms cubic-bezier(0.22,1,0.36,1)' : 'transform 720ms cubic-bezier(0.22,1,0.36,1)',
        transformStyle: 'preserve-3d',
        willChange: 'transform',
      }}>
        {/* Background scene plane — photo mockup, SVG fallback for safety */}
        <div style={{ position: 'absolute', inset: 0, transform: 'translateZ(0)' }}>
          <img
            src={mockupFor(scene)}
            alt=""
            loading="lazy"
            style={{
              position: 'absolute', inset: 0,
              width: '100%', height: '100%',
              objectFit: 'cover', display: 'block',
            }}
          />
        </div>
        {/* Grain plane */}
        <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.18,
          pointerEvents: 'none',
        }}/>
        {/* Lighting plane — ambient highlight that follows cursor */}
        <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%)`,
          transform: 'translateZ(40px)',
          mixBlendMode: 'screen',
          transition: tilt.active ? 'background 220ms ease' : 'background 720ms ease',
        }}/>
        {/* Edge vignette plane */}
        <div aria-hidden="true" style={{
          position: 'absolute', inset: 0,
          boxShadow: 'inset 0 0 200px rgba(0,0,0,0.35)',
          pointerEvents: 'none',
          transform: 'translateZ(20px)',
        }}/>
      </div>
      {/* Overlay label — moves on a separate plane for parallax */}
      <div style={{
        position: 'absolute',
        bottom: 'clamp(20px, 2.4vw, 36px)',
        left: 'clamp(20px, 2.4vw, 36px)',
        right: 'clamp(20px, 2.4vw, 36px)',
        display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between',
        gap: 16, color: '#fff',
        transform: `translate3d(${tilt.ry * -2}px, ${tilt.rx * 2}px, 0)`,
        transition: tilt.active ? 'transform 220ms cubic-bezier(0.22,1,0.36,1)' : 'transform 720ms cubic-bezier(0.22,1,0.36,1)',
        pointerEvents: 'none',
      }}>
        <div style={{
          display: 'inline-flex', alignItems: 'center', gap: 10,
          padding: '8px 14px', borderRadius: 99,
          background: 'rgba(255,255,255,0.12)',
          backdropFilter: 'blur(12px)', WebkitBackdropFilter: 'blur(12px)',
          fontSize: 12, letterSpacing: '0.08em', textTransform: 'uppercase',
          border: '1px solid rgba(255,255,255,0.2)',
        }}>
          <span style={{ width: 6, height: 6, borderRadius: '50%', background: blue, boxShadow: `0 0 8px ${blue}` }}/>
          Spatial preview
        </div>
        <div style={{
          width: 56, height: 56, borderRadius: '50%',
          background: blue, color: '#000',
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
          opacity: tilt.active ? 1 : 0,
          transform: tilt.active ? 'scale(1)' : 'scale(0.7)',
          transition: 'opacity 320ms ease, transform 480ms cubic-bezier(0.22,1.2,0.36,1)',
        }}>
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M7 17L17 7M9 7h8v8"/></svg>
        </div>
      </div>
    </div>
  );
}

/* ----------------------------------------------------------------- */
/*  USE SCROLL PROGRESS — returns 0..1 of element passing viewport   */
/* ----------------------------------------------------------------- */

function useScrollProgress(ref) {
  const [p, setP] = useStateSt(0);
  useEffectSt(() => {
    if (!ref.current) return;
    const onScroll = () => {
      const el = ref.current; if (!el) return;
      const r = el.getBoundingClientRect();
      const vh = window.innerHeight;
      // 0 when bottom of element enters from below; 1 when top exits
      const total = r.height + vh;
      const passed = vh - r.top;
      setP(Math.max(0, Math.min(1, passed / total)));
    };
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onScroll);
    return () => { window.removeEventListener('scroll', onScroll); window.removeEventListener('resize', onScroll); };
  }, [ref]);
  return p;
}

/* ----------------------------------------------------------------- */
/*  TYPOGRAPHY: title that lands into place                           */
/* ----------------------------------------------------------------- */

function StudioTitle({ children, progress }) {
  // 0 → 0.6 lands. blur 8 → 0, rotate 1.4deg → 0
  const land = Math.max(0, Math.min(1, (progress - 0.05) / 0.45));
  return (
    <h3 style={{
      margin: 0,
      fontFamily: "'Inter Tight', sans-serif",
      fontWeight: 500,
      fontSize: 'clamp(56px, 9vw, 168px)',
      lineHeight: 0.92,
      letterSpacing: '-0.035em',
      filter: `blur(${(1 - land) * 8}px)`,
      transform: `translateY(${(1 - land) * 24}px) rotate(${(1 - land) * 1.4}deg)`,
      opacity: 0.2 + land * 0.8,
      transition: 'filter 80ms linear',
      textWrap: 'balance',
    }}>{children}</h3>
  );
}

function StaggerLabel({ children, progress, delay = 0 }) {
  const land = Math.max(0, Math.min(1, (progress - delay) / 0.5));
  const text = String(children);
  return (
    <div className="aspace-eyebrow" style={{ display: 'inline-flex', alignItems: 'center', gap: 12 }}>
      <span className="aspace-plus" style={{ opacity: land }}/>
      <span style={{ display: 'inline-flex', overflow: 'hidden' }}>
        {text.split('').map((ch, i) => (
          <span key={i} style={{
            display: 'inline-block',
            transform: `translateY(${(1 - Math.max(0, Math.min(1, land - i*0.012))) * 18}px)`,
            opacity: Math.max(0, Math.min(1, land - i*0.012)),
            transition: 'none',
            whiteSpace: 'pre',
          }}>{ch}</span>
        ))}
      </span>
    </div>
  );
}

/* ----------------------------------------------------------------- */
/*  STUDIO CARD                                                       */
/* ----------------------------------------------------------------- */

function StudioCard({ s, blue, idx, onOpen }) {
  const ref = useRefSt(null);
  const progress = useScrollProgress(ref);
  const mediaRef = useRefSt(null);
  const handleOpen = (e) => {
    if (!onOpen || !mediaRef.current) return;
    e.preventDefault();
    const r = mediaRef.current.getBoundingClientRect();
    onOpen(s, { left: r.left, top: r.top, width: r.width, height: r.height });
  };
  return (
    <article ref={ref} style={{
      padding: 'clamp(56px, 8vw, 140px) var(--gutter) clamp(40px, 6vw, 100px)',
      borderTop: idx === 0 ? 'none' : '1px solid rgba(10,10,11,0.10)',
      position: 'relative',
    }}>
      <div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 5fr) minmax(0, 4fr)', gap: 'clamp(40px, 6vw, 96px)', alignItems: 'start' }} className="studio-grid">
        {/* Left: copy */}
        <div style={{ position: 'sticky', top: '15vh' }} className="studio-copy">
          <div style={{
            fontFamily: 'monospace', fontSize: 13, color: 'rgba(10,10,11,0.4)',
            marginBottom: 18,
          }}>{s.n} / 06</div>
          <StaggerLabel progress={progress}>{s.label}</StaggerLabel>
          <div style={{ marginTop: 18 }}>
            <StudioTitle progress={progress}>{s.title}</StudioTitle>
          </div>
          <p style={{
            marginTop: 28, maxWidth: 460,
            color: 'rgba(10,10,11,0.65)',
            fontSize: 'clamp(15px, 1.2vw, 17px)',
            lineHeight: 1.55,
          }}>{s.subtitle}</p>
          <div style={{ marginTop: 28, display: 'flex', flexWrap: 'wrap', gap: 8 }}>
            {s.tags.map(t => (
              <span key={t} style={{
                padding: '8px 14px', borderRadius: 99,
                border: '1px solid rgba(10,10,11,0.18)',
                fontSize: 12, letterSpacing: '0.04em',
                whiteSpace: 'nowrap',
              }}>{t}</span>
            ))}
          </div>
          <div style={{ marginTop: 36, display: 'flex', alignItems: 'center', gap: 16, flexWrap: 'wrap' }}>
            {s.bookingId ? (
              <a href={`/site/booking.html?studio=${s.bookingId}`} className="aspace-pill solid" style={{ background: blue, borderColor: blue, color: '#000' }}>
                <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>
            ) : (
              <a href="#contact" className="aspace-pill solid" style={{ background: blue, borderColor: blue, color: '#000' }}>
                <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>
              </a>
            )}
            <span style={{
              display: 'inline-flex', alignItems: 'center', gap: 8,
              fontSize: 13, color: 'rgba(10,10,11,0.55)',
              whiteSpace: 'nowrap', flexShrink: 0,
            }}>
              <span style={{ width: 8, height: 8, borderRadius: '50%', background: blue, boxShadow: `0 0 8px ${blue}`, flexShrink: 0 }}/>
              {s.status}
            </span>
          </div>
        </div>
        {/* Right: spatial media */}
        <div className="studio-media" ref={mediaRef} onClick={handleOpen} style={{ cursor: 'pointer' }}>
          <SpatialMedia scene={s.scene} blue={blue} scrollProgress={progress}/>
        </div>
      </div>
    </article>
  );
}

/* ----------------------------------------------------------------- */
/*  PAGE SECTIONS                                                     */
/* ----------------------------------------------------------------- */

function StudiosHero({ blue }) {
  return (
    <section data-aurora="hero" style={{
      padding: 'clamp(140px, 20vh, 240px) var(--gutter) clamp(72px, 10vw, 140px)',
      borderBottom: '1px solid rgba(10,10,11,0.10)',
      position: 'relative',
    }}>
      <div className="aspace-eyebrow" style={{ marginBottom: 32, display: 'inline-flex', alignItems: 'center', gap: 12 }}>
        <span className="aspace-plus"/> Index 01 · Studios
      </div>
      <h1 style={{
        margin: 0,
        fontFamily: "'Inter Tight', sans-serif",
        fontWeight: 500,
        fontSize: 'clamp(72px, 14vw, 240px)',
        lineHeight: 0.86,
        letterSpacing: '-0.04em',
        textWrap: 'balance',
      }}>
        Private<br/>creative<br/><span className="blue-swipe">studios.</span>
      </h1>
      <div style={{
        display: 'grid',
        gridTemplateColumns: 'minmax(0,1fr) minmax(0,1fr)',
        gap: 'clamp(28px, 4vw, 80px)',
        marginTop: 'clamp(48px, 6vw, 96px)',
      }} className="hero-meta">
        <p style={{
          margin: 0, maxWidth: 520,
          fontSize: 'clamp(17px, 1.3vw, 21px)',
          lineHeight: 1.45, color: 'rgba(10,10,11,0.7)',
        }}>
          Flexible creative workspaces for photographers, designers, filmmakers, artists and independent brands. Lockable, monthly, real space — Amsterdam-Duivendrecht.
        </p>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          <Meta k="Location"  v="Joop Geesinkweg 306, Amsterdam"/>
          <Meta k="Sizes"     v="14m² – 24m² · room to grow"/>
          <Meta k="Terms"     v="Monthly · no long contracts"/>
          <Meta k="Inventory" v="6 studios · 2 available now"/>
        </div>
      </div>
    </section>
  );
}

function Meta({ k, v }) {
  return (
    <div style={{ display: 'flex', justifyContent: 'space-between', borderTop: '1px solid rgba(10,10,11,0.12)', padding: '14px 0' }}>
      <span style={{ fontSize: 12, letterSpacing: '0.12em', textTransform: 'uppercase', color: 'rgba(10,10,11,0.5)' }}>{k}</span>
      <span style={{ fontSize: 14 }}>{v}</span>
    </div>
  );
}

function FeaturesStrip({ blue }) {
  const features = [
    'Flexible monthly rental','Shared kitchen & lounge','Natural light','Shoot-ready spaces','Creative community','Amsterdam-Duivendrecht','Production-ready','Private lockable rooms',
  ];
  // double the list for marquee continuity
  const loop = [...features, ...features];
  return (
    <section style={{
      padding: 'clamp(72px, 10vw, 160px) 0',
      borderTop: '1px solid rgba(10,10,11,0.10)',
      borderBottom: '1px solid rgba(10,10,11,0.10)',
      overflow: 'hidden',
      position: 'relative',
    }}>
      <div className="aspace-eyebrow" style={{ paddingLeft: 'var(--gutter)', marginBottom: 32, display: 'inline-flex', gap: 12, alignItems: 'center' }}>
        <span className="aspace-plus"/> What every studio includes
      </div>
      <div className="features-marquee">
        <div className="features-track">
          {loop.map((f, i) => (
            <span key={i} style={{
              fontFamily: "'Inter Tight', sans-serif", fontWeight: 500,
              fontSize: 'clamp(36px, 6vw, 96px)',
              letterSpacing: '-0.025em',
              padding: '0 36px',
              display: 'inline-flex', alignItems: 'center', gap: 36,
            }}>
              {f}
              <span style={{
                width: 12, height: 12, borderRadius: '50%',
                background: blue, boxShadow: `0 0 16px ${blue}`,
              }}/>
            </span>
          ))}
        </div>
      </div>
    </section>
  );
}

function AvailableNow({ blue }) {
  const open = STUDIOS.filter(s => s.status.includes('now') || s.status.includes('left') || s.status.includes('June'));
  return (
    <section style={{ padding: 'clamp(96px, 14vw, 200px) var(--gutter)' }}>
      <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 24, flexWrap: 'wrap', marginBottom: 'clamp(40px, 6vw, 80px)' }}>
        <div>
          <div className="aspace-eyebrow" style={{ marginBottom: 18, display: 'inline-flex', alignItems: 'center', gap: 12 }}>
            <span className="aspace-plus"/> Available
          </div>
          <h2 style={{
            margin: 0,
            fontFamily: "'Inter Tight', sans-serif",
            fontWeight: 500,
            fontSize: 'clamp(48px, 7.4vw, 132px)',
            lineHeight: 0.94,
            letterSpacing: '-0.03em',
            maxWidth: '14ch',
          }}>Spaces opening this season.</h2>
        </div>
        <a href="#contact" className="aspace-pill" style={{ borderColor: 'rgba(10,10,11,0.22)' }}>
          <span>Request the full list</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>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))', gap: 16 }}>
        {open.map(s => (
          <a key={s.n}
            href={s.bookingId ? `/site/booking.html?studio=${s.bookingId}` : '#contact'}
            className="avail-card">
            <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 12, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'rgba(10,10,11,0.5)' }}>
              <span>{s.n}</span>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8, whiteSpace: 'nowrap' }}>
                <span style={{ width: 6, height: 6, borderRadius: '50%', background: blue, boxShadow: `0 0 6px ${blue}`, flexShrink: 0 }}/>
                {s.status}
              </span>
            </div>
            <div style={{ marginTop: 24, fontFamily: "'Inter Tight',sans-serif", fontWeight: 500, fontSize: 'clamp(28px, 3.4vw, 44px)', lineHeight: 0.95, letterSpacing: '-0.02em' }}>
              {s.title}
            </div>
            <div style={{ marginTop: 12, fontSize: 13, color: 'rgba(10,10,11,0.55)' }}>{s.label}</div>
            <div style={{ marginTop: 36, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
              <span style={{ fontSize: 13 }}>{s.bookingId ? 'Book this studio' : 'Book a viewing'}</span>
              <span className="avail-arrow" style={{
                width: 40, height: 40, borderRadius: '50%',
                border: '1px solid rgba(10,10,11,0.2)',
                display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
              }}>
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8"><path d="M7 17L17 7M9 7h8v8"/></svg>
              </span>
            </div>
          </a>
        ))}
      </div>
    </section>
  );
}

function StudiosFinalCTA({ blue }) {
  return (
    <section style={{
      background: '#0A0A0B', color: '#fff',
      padding: 'clamp(120px, 18vw, 240px) var(--gutter)',
      borderTop: '1px solid rgba(255,255,255,0.06)',
      position: 'relative', overflow: 'hidden',
    }}>
      <div className="aspace-eyebrow" style={{ color: 'rgba(255,255,255,0.55)', marginBottom: 24, display: 'inline-flex', gap: 12 }}>
        <span className="aspace-plus" style={{ background: 'rgba(255,255,255,0.6)' }}/> Final invitation
      </div>
      <h2 style={{
        margin: 0,
        fontFamily: "'Inter Tight', sans-serif",
        fontWeight: 500,
        fontSize: 'clamp(72px, 14vw, 240px)',
        lineHeight: 0.86,
        letterSpacing: '-0.04em',
        textWrap: 'balance',
        maxWidth: '13ch',
      }}>
        Find your<br/>creative<br/><span style={{ color: blue }}>base.</span>
      </h2>
      <div style={{ marginTop: 'clamp(48px, 7vw, 96px)', display: 'flex', gap: 14, flexWrap: 'wrap' }}>
        <a href="#contact" className="aspace-pill" style={{ background: blue, borderColor: blue, color: '#000' }}>
          <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>
        </a>
        <a href="#" className="aspace-pill" style={{ borderColor: 'rgba(255,255,255,0.3)', color: '#fff' }}>
          <span>Talk to us</span>
        </a>
      </div>
      {/* large faint wordmark */}
      <div aria-hidden="true" style={{
        position: 'absolute', left: 'var(--gutter)', right: 'var(--gutter)',
        bottom: 24,
        fontFamily: "'Inter Tight',sans-serif", fontWeight: 600,
        fontSize: 'clamp(40px, 12vw, 200px)',
        letterSpacing: '-0.04em', lineHeight: 1,
        color: 'rgba(255,255,255,0.05)',
        pointerEvents: 'none', userSelect: 'none',
      }}>ASPACE</div>
    </section>
  );
}

function StudiosPage({ onOpenStudio }) {
  const [blue, setBlue] = useStateSt(getComputedStyle(document.documentElement).getPropertyValue('--aspace-blue').trim() || '#00C2FF');
  // Re-read on tweaks update
  useEffectSt(() => {
    const obs = new MutationObserver(() => {
      const v = getComputedStyle(document.documentElement).getPropertyValue('--aspace-blue').trim();
      if (v && v !== blue) setBlue(v);
    });
    obs.observe(document.documentElement, { attributes: true, attributeFilter: ['style'] });
    return () => obs.disconnect();
  }, [blue]);

  return (
    <main>
      <StudiosHero blue={blue}/>
      <section style={{ padding: 0 }}>
        {STUDIOS.map((s, i) => <StudioCard key={s.n} s={s} blue={blue} idx={i} onOpen={onOpenStudio}/>)}
      </section>
      <FeaturesStrip blue={blue}/>
      <AvailableNow blue={blue}/>
      <StudiosFinalCTA blue={blue}/>
    </main>
  );
}

window.StudiosPage = StudiosPage;
window.STUDIO_SCENES = STUDIO_SCENES;
window.STUDIOS_DATA = STUDIOS;
