// pastel-app.jsx — Sorra, pastel print edition. No italics. Everything dynamic on touch.
const { useEffect: pAUseE, useRef: pAUseR, useState: pAUseS, useMemo: pAUseM, useLayoutEffect: pAUseLE, useCallback: pAUseCb } = React;
const IS_TOUCH = !!window.IS_TOUCH;

const PA = {
  PAGE:   '#0A0504',           // derin siyah
  PAPER:  '#FBF3DC',
  INK:    '#EDE6D3',           // bone warm
  INK2:   'rgba(237,230,211,0.62)',
  INK3:   'rgba(237,230,211,0.42)',
  LINE:   'rgba(237,230,211,0.12)',
  ACCENT: '#D4382E',           // sinema kırmızısı (ripple)
  GOLD:   '#D4382E',           // kırmızı editöryel aksan (eski altın)
  GOLD2:  '#7E1410',           // derin oksun kırmızısı (vurgu)
};

// Build content for the three columns. Subtle pastel rotation so neighbouring
// cards always differ in tint, never two same-tint cards in a row.
function buildPastelStreams(colW) {
  const W = colW, MW = colW, RW = colW;
  const left = [], mid = [], right = [];

  const leftTints  = ['T_SKY', 'T_CREAM', 'T_PLUM', 'T_SAGE'];
  const rightTints = ['T_PLUM', 'T_SAGE', 'T_SUN', 'T_ROSE'];

  // SOL — KÜNYE ▲ (her 3 filmde bir stamp veya movement araya serpiştir)
  const stampTints  = [PC.T_CORAL, PC.T_SUN, PC.T_PLUM, PC.T_ROSE, PC.T_SAGE];
  const moveTints   = [PC.T_CREAM, PC.T_ROSE, PC.T_SAGE, PC.T_PLUM, PC.T_SUN];
  left.push(<PStampCard s={STAMPS[0]} w={W} tint={stampTints[0]} key="L-s0"/>);
  FILMS.forEach((f, i) => {
    left.push(<PSpecCard film={f} w={W} tint={PC[leftTints[i%leftTints.length]]} key={`L-sp-${f.id}`}/>);
    if (i % 3 === 2 && i < FILMS.length - 1) {
      const k = Math.floor(i/3);
      left.push(<PMovementCard name={MOVEMENTS[(k+1) % MOVEMENTS.length]} w={W} tint={moveTints[k%moveTints.length]} key={`L-m-${k}`}/>);
      if (STAMPS[k+1]) left.push(<PStampCard s={STAMPS[k+1]} w={W} tint={stampTints[(k+1)%stampTints.length]} key={`L-s-${k+1}`}/>);
    }
  });
  left.push(<PMovementCard name={MOVEMENTS[MOVEMENTS.length-1]} w={W} tint={PC.T_SAGE} key="L-m-end"/>);

  // ORTA — FİLMLER ▼
  FILMS.forEach((f, i) => {
    mid.push(<PFilmCard film={f} w={MW} tint={PC.T_PAPER} key={`M-${f.id}`}/>);
    if (i === 3)  mid.push(<PRibbon text="BAĞIMSIZ · SİNEMA · DÖNGÜ"      w={MW} dir="left"  key="M-r1"/>);
    if (i === 8)  mid.push(<PRibbon text="SORRA · NE BAŞLANGIÇ NE SON"    w={MW} dir="right" key="M-r2"/>);
    if (i === 12) mid.push(<PRibbon text="FESTİVAL · KAMERA ARKASI · MİT" w={MW} dir="left"  key="M-r3"/>);
  });

  // SAĞ — SESLER ▲
  QUOTES.forEach((q,i)=>{
    right.push(<PQuoteCard q={q} w={RW} tint={PC[rightTints[i%rightTints.length]]} key={`R-q-${i}`}/>);
    if (BTS[i])  right.push(<PBTSCard b={BTS[i]} w={RW} tint={PC.T_SAGE} key={`R-b-${i}`}/>);
    if (RECS[i]) right.push(<PRecCard r={RECS[i]} w={RW} tint={PC.T_SUN} key={`R-r-${i}`}/>);
    if (i === 2) right.push(<PStampCard s={STAMPS[4]} w={RW} tint={PC.T_CORAL} key="R-s0"/>);
    if (i === 5) right.push(<PMovementCard name={MOVEMENTS[5]} w={RW} tint={PC.T_CREAM} key="R-m0"/>);
  });

  return { left, mid, right };
}

// ─── COMPACT MASTHEAD ─────────────────────────────────────────────────────
// Tek satır: marka + akış durumu + oynat/durdur. Gereksiz yazılar kaldırıldı,
// çerçeve (içerik) alanı büyüsün diye olabildiğince ince.
function PMasthead({ paused, onTogglePause }) {
  return (
    <div style={{
      position:'absolute', top: IS_TOUCH ? 0 : 46, left:0, right:0, zIndex:30,
      background: PA.PAGE,
    }}>
      <div style={{
        display:'flex', alignItems:'center', justifyContent:'space-between',
        padding:'7px 14px 6px',
      }}>
        <div style={{ display:'flex', alignItems:'baseline', gap:7 }}>
          <span style={{
            fontFamily:'Instrument Serif, serif', fontSize:21, lineHeight:1,
            letterSpacing:-0.6, color: PA.INK, fontWeight:400,
          }}>Ben İzledim</span>
          <span style={{
            fontFamily:'JetBrains Mono, monospace', fontSize:6.5, letterSpacing:2,
            color: PA.GOLD, fontWeight:600,
          }}>BASKI 014</span>
        </div>
        <div style={{ display:'flex', alignItems:'center', gap:10 }}>
          <div style={{ display:'flex', alignItems:'center', gap:5 }}>
            <div style={{
              width:6, height:6, borderRadius:'50%',
              background: paused ? PA.INK3 : PA.GOLD,
              boxShadow: paused ? 'none' : `0 0 8px ${PA.GOLD}`,
              animation: paused ? 'none' : 'pulse 1.4s ease-in-out infinite',
            }}/>
            <span style={{
              fontFamily:'JetBrains Mono, monospace', fontSize:7.5, color: PA.INK,
              letterSpacing:2.4, fontWeight:500,
            }}>{paused ? 'DURDU' : 'AKIYOR'}</span>
          </div>
          <button
            onClick={(e)=>{ e.stopPropagation(); onTogglePause(); }}
            style={{
              background: paused ? PA.GOLD : 'transparent',
              border:`0.5px solid ${paused ? PA.GOLD : PA.GOLD2}`,
              color: paused ? '#fff' : PA.GOLD,
              fontFamily:'JetBrains Mono, monospace', fontSize:7, letterSpacing:1.6,
              padding:'3px 9px', cursor:'pointer', borderRadius:0, fontWeight:600,
            }}>
            {paused ? '▶ OYNAT' : '∥ DURDUR'}
          </button>
        </div>
      </div>
      <div style={{ height:0.5, background: `linear-gradient(90deg, transparent, ${PA.GOLD2} 30%, ${PA.GOLD} 50%, ${PA.GOLD2} 70%, transparent)` }}/>
    </div>
  );
}

// ─── TAM EKRAN DETAY ──────────────────────────────────────────────────────
// Karta basılı tutulunca: kartın ön + arka içeriği büyütülüp tam okunur açılır.
function PDetailOverlay({ detail, onClose }) {
  if (!detail) return null;
  const z = IS_TOUCH ? 2.05 : 1.5;
  const card = (bg, ink, node) => (
    <div style={{
      position:'relative', background:bg, color:ink, borderRadius:4,
      padding:'22px 20px 26px',
      boxShadow:'0 24px 60px -20px rgba(0,0,0,0.7)',
    }}>
      <div style={{ zoom:z }}>{node}</div>
    </div>
  );
  return (
    <div onClick={onClose} style={{
      position:'absolute', inset:0, zIndex:200,
      background:'rgba(7,4,3,0.90)',
      display:'flex', alignItems:'flex-start', justifyContent:'center',
      padding:'30px 14px 40px', overflowY:'auto', WebkitOverflowScrolling:'touch',
      animation:'fadein 200ms ease',
    }}>
      <div onClick={(e)=>e.stopPropagation()} style={{
        width:'100%', maxWidth:560, display:'flex', flexDirection:'column', gap:14,
      }}>
        <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center' }}>
          <span style={{
            fontFamily:'JetBrains Mono, monospace', fontSize:8.5, letterSpacing:3,
            color: PA.GOLD, fontWeight:600,
          }}>{(detail.edition || 'BEN İZLEDİM')} · TAM KAYIT</span>
          <button onClick={onClose} style={{
            background: PA.GOLD2, color:'#fff', border:'none',
            fontFamily:'JetBrains Mono, monospace', fontSize:9, letterSpacing:2,
            padding:'7px 13px', cursor:'pointer', fontWeight:600, borderRadius:2,
          }}>✕ KAPAT</button>
        </div>
        {card(detail.tint || PA.PAPER, '#1F1812', detail.front)}
        {detail.back && card('linear-gradient(155deg,#15100C,#0E0A07)', PA.PAPER, detail.back)}
        <div style={{
          textAlign:'center', fontFamily:'JetBrains Mono, monospace',
          fontSize:8, letterSpacing:2.4, color: PA.INK3, paddingBottom:8,
        }}>boş alana dokun · kapat</div>
      </div>
    </div>
  );
}


// ─── PWA YÜKLEME BANNER'I ─────────────────────────────────────────────────
// Siteyi açana "ana ekrana ekle" bildirimi. Android/Chrome: gerçek yükleme
// prompt'u. iOS Safari: Paylaş → Ana Ekrana Ekle ipucu (iOS başka yol vermez).
function PInstallPrompt() {
  // null | 'android' (tek-dokunuş yükle) | 'android-hint' (menüden ekle) | 'ios'
  const [mode, setMode] = pAUseS(null);

  pAUseE(() => {
    const standalone =
      (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches) ||
      window.navigator.standalone === true ||
      document.referrer.startsWith('android-app://');
    if (standalone) return;   // zaten uygulama olarak açık

    let dismissedUntil = 0;
    try { dismissedUntil = +localStorage.getItem('bi_pwa_dismiss') || 0; } catch (_) {}
    if (Date.now() < dismissedUntil) return;

    const ua = navigator.userAgent || '';
    const isIOS = /iphone|ipad|ipod/i.test(ua) && !window.MSStream;
    const isAndroid = /android/i.test(ua);
    // Instagram/Facebook/TikTok vb. uygulama-içi tarayıcı: orada PWA kurulamaz,
    // önce gerçek tarayıcıya çıkmak gerekir.
    const inApp = /Instagram|FBAN|FBAV|FB_IAB|Line\/|Twitter|TikTok|musical_ly|Snapchat/i.test(ua);

    // EN BAŞTA göster — beforeinstallprompt'u bekleme.
    const pick = () => {
      if (inApp) return isIOS ? 'inapp-ios' : 'inapp-android';
      if (window.__bipEvent) return 'android';
      if (isAndroid) return 'android-hint';
      if (isIOS) return 'ios';
      return null;
    };
    const t = setTimeout(() => setMode((m) => m || pick()), 250);

    const onReady = () => setMode('android');
    const onInstalled = () => setMode(null);
    window.addEventListener('bip-ready', onReady);
    window.addEventListener('bip-installed', onInstalled);
    return () => {
      clearTimeout(t);
      window.removeEventListener('bip-ready', onReady);
      window.removeEventListener('bip-installed', onInstalled);
    };
  }, []);

  if (!mode) return null;
  const inApp = mode === 'inapp-android' || mode === 'inapp-ios';
  const title = inApp ? 'Tam sürüm için tarayıcıda aç' : 'Ben İzledim’i ana ekrana ekle';
  const hintText =
    mode === 'inapp-android'
      ? 'Instagram içi tarayıcıdasın. Sağ üst ⋮ → “Chrome’da aç”.'
      : mode === 'inapp-ios'
      ? 'Instagram içi tarayıcıdasın. Sağ üst ⋯ → “Safari’de aç”.'
      : mode === 'ios'
      ? 'Aşağıdaki Paylaş ⎙ → “Ana Ekrana Ekle” ile uygulama gibi kullan.'
      : mode === 'android-hint'
      ? 'Chrome menüsü ⋮ → “Uygulamayı yükle / Ana ekrana ekle”.'
      : 'Uygulama gibi tam ekran, tek dokunuşla aç.';

  const close = () => {
    try { localStorage.setItem('bi_pwa_dismiss', String(Date.now() + 14 * 864e5)); } catch (_) {}
    setMode(null);
  };
  const install = async () => {
    const e = window.__bipEvent;
    if (!e) { setMode(null); return; }
    e.prompt();
    try { await e.userChoice; } catch (_) {}
    window.__bipEvent = null;
    setMode(null);
  };
  // Android'de uygulama-içi tarayıcıdan gerçek Chrome'a çık (kullanıcı dokunuşuyla)
  const openInChrome = () => {
    const intent =
      'intent://benizledim.store/#Intent;scheme=https;package=com.android.chrome;' +
      'S.browser_fallback_url=https%3A%2F%2Fbenizledim.store%2F;end';
    try { window.location.href = intent; } catch (_) { window.location.href = 'https://benizledim.store/'; }
  };

  return (
    <div style={{
      position:'absolute', left:12, right:12,
      bottom: (IS_TOUCH ? 40 : 74),
      zIndex:160,
      background:'linear-gradient(155deg,#15100C,#0E0A07)',
      border:`0.5px solid ${PA.GOLD2}`, borderRadius:10,
      boxShadow:'0 18px 40px -16px rgba(0,0,0,0.8)',
      padding:'12px 12px 12px 14px',
      display:'flex', alignItems:'center', gap:12,
      animation:'fadein 240ms ease',
    }}>
      <div style={{
        width:38, height:38, borderRadius:9, flexShrink:0,
        background:PA.PAGE, border:`1px solid ${PA.GOLD2}`,
        display:'flex', alignItems:'center', justifyContent:'center',
        fontFamily:'Instrument Serif, serif', fontSize:20, color:PA.INK,
      }}>Bİ</div>
      <div style={{ flex:1, minWidth:0 }}>
        <div style={{
          fontFamily:'Instrument Serif, serif', fontSize:14, color:PA.INK,
          lineHeight:1.15,
        }}>{title}</div>
        <div style={{
          fontFamily:'JetBrains Mono, monospace', fontSize:8.5, letterSpacing:0.6,
          color:PA.INK2, marginTop:3, lineHeight:1.35,
        }}>{hintText}</div>
      </div>
      {(mode === 'android' || mode === 'inapp-android') && (
        <button onClick={mode === 'android' ? install : openInChrome} style={{
          background:PA.GOLD, color:'#fff', border:'none',
          fontFamily:'JetBrains Mono, monospace', fontSize:9, letterSpacing:1.2,
          fontWeight:700, padding:'9px 12px', borderRadius:6, cursor:'pointer',
          flexShrink:0, whiteSpace:'nowrap',
        }}>{mode === 'android' ? 'YÜKLE' : 'CHROME’DA AÇ'}</button>
      )}
      <button onClick={close} aria-label="Kapat" style={{
        background:'transparent', border:'none', color:PA.INK3,
        fontFamily:'JetBrains Mono, monospace', fontSize:14, cursor:'pointer',
        padding:'4px 4px', flexShrink:0, lineHeight:1,
      }}>✕</button>
    </div>
  );
}

// ─── BOTTOM HUD ───────────────────────────────────────────────────────────
function PBottomHUD() {
  return (
    <div style={{
      position:'absolute', bottom: IS_TOUCH ? 0 : 34, left:0, right:0,
      height:28, zIndex:30,
      background:'linear-gradient(rgba(10,5,4,0.0), rgba(10,5,4,0.96) 45%)',
      display:'flex', alignItems:'center', padding:'0 14px',
      color: PA.INK, fontFamily:'JetBrains Mono, monospace', fontSize:7.5,
      letterSpacing:2, justifyContent:'space-between',
    }}>
      <div style={{
        position:'absolute', top:0, left:0, right:0, height:0.5,
        background:`linear-gradient(90deg, transparent, ${PA.GOLD2} 50%, transparent)`,
      }}/>
      <div style={{ display:'flex', alignItems:'center', gap:6 }}>
        <svg width="12" height="12" viewBox="0 0 14 14">
          <rect x="1" y="1" width="12" height="12" fill="none" stroke={PA.GOLD2} strokeWidth="0.7"/>
          <circle cx="7" cy="7" r="2.6" fill="none" stroke={PA.GOLD} strokeWidth="0.7"/>
          <circle cx="7" cy="7" r="1" fill={PA.GOLD}/>
        </svg>
        <span style={{ color: PA.GOLD, fontWeight:600 }}>BEN İZLEDİM</span>
      </div>
      <div style={{
        fontFamily:'Instrument Serif, serif', fontSize:10, letterSpacing:0.3,
        color: PA.INK, opacity:0.65,
      }}>
        dokun · çevir · basılı tut
      </div>
    </div>
  );
}

// ─── GRAIN OVERLAY ────────────────────────────────────────────────────────
function PGrain({ intensity=0.06 }) {
  // Android'de animasyonlu tam ekran SVG turbulence + mix-blend = ana takılma
  // kaynağı. Dokunmatik cihazlarda tamamen kapat.
  if (IS_TOUCH) return null;
  return (
    <div style={{
      position:'absolute', inset:0, zIndex:80, pointerEvents:'none',
      mixBlendMode:'overlay', opacity: intensity,
      backgroundImage:'url("data:image/svg+xml;utf8,'+encodeURIComponent(
        `<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%' height='100%' filter='url(%23n)' opacity='1'/></svg>`
      )+'")',
      animation:'grain 0.9s steps(4) infinite',
    }}/>
  );
}

// ─── PELİKÜL ŞERİDİ ───────────────────────────────────────────────────────
// Gerçek 35mm makara hissi: sabit aralık (her iki şeritte birebir aynı boyut),
// "kapıdan akan film" gibi sürekli dikey kayma. GPU transform — Android dostu.
// PITCH/HOLE iki şeritte de aynı sabit → eşit boyut garantili.
const PERF_PITCH = 10;          // delik aralığı (px) — daha sık, daha pro
const PERF_HOLE_W = 4.5;
const PERF_HOLE_H = 6;
function PPerf({ leftPct, top, bottom, dir = 'up' }) {
  // bir adımdan büyük şerit; iki PITCH kadar kayıp başa sarar (kesintisiz döngü)
  const holes = Array.from({ length: 64 });
  return (
    <div style={{
      position:'absolute', top, bottom, left:leftPct, width:6,
      transform:'translateX(-50%)', zIndex:24, pointerEvents:'none',
      overflow:'hidden',
    }}>
      <div style={{
        position:'absolute', left:'50%', top:-PERF_PITCH*2, transform:'translateX(-50%)',
        display:'flex', flexDirection:'column', alignItems:'center',
        willChange:'transform',
        animation:`perf-${dir === 'down' ? 'down' : 'up'} 3.2s linear infinite`,
      }}>
        {holes.map((_,i)=>(
          <div key={i} style={{
            width:PERF_HOLE_W, height:PERF_HOLE_H,
            marginBottom:PERF_PITCH-PERF_HOLE_H,
            background:'rgba(214,58,46,0.62)',
            boxShadow:'0 0 4px rgba(214,58,46,0.45), inset 0 0 0 0.6px rgba(255,150,138,0.7)',
            borderRadius:1.5,
          }}/>
        ))}
      </div>
    </div>
  );
}

// ─── TOUCH RIPPLES ────────────────────────────────────────────────────────
// Anywhere the user taps inside the phone, a soft pastel ring radiates.
function TouchRippleLayer() {
  const [ripples, setRipples] = pAUseS([]);
  const idRef = pAUseR(0);

  const onDown = (e) => {
    const rect = e.currentTarget.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;
    const id = ++idRef.current;
    const colors = [PA.ACCENT, '#A8BFD2', '#A8BC9F', '#EBC76F', '#C8A9C5'];
    const c = colors[id % colors.length];
    setRipples(rs => [...rs, { id, x, y, c }]);
    setTimeout(() => {
      setRipples(rs => rs.filter(r => r.id !== id));
    }, 900);
  };

  return (
    <div
      onPointerDown={onDown}
      style={{
        position:'absolute', inset:0, zIndex:90, pointerEvents:'none',
      }}>
      {/* This wrapper is pointer-events:none so it never blocks. We attach the
          handler on a sibling overlay instead — see below. */}
      <div style={{ position:'absolute', inset:0 }}>
        {ripples.map(r => (
          <div key={r.id} style={{
            position:'absolute', left:r.x, top:r.y,
            width:0, height:0, borderRadius:'50%',
            border:`1.2px solid ${r.c}`,
            transform:'translate(-50%,-50%)',
            animation:'ripple 850ms cubic-bezier(.2,.7,.2,1) forwards',
          }}/>
        ))}
      </div>
    </div>
  );
}

// listener overlay (sits below ripple display, captures all pointerdown)
function TouchListener({ onDown }) {
  return (
    <div
      onPointerDown={onDown}
      style={{
        position:'absolute', inset:0, zIndex:5, pointerEvents:'none',
      }}
    />
  );
}

// ─── MAIN APP ──────────────────────────────────────────────────────────────
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "speed": 22,
  "grain": 0.06,
  "directions": "up-down-up",
  "ripples": true
}/*EDITMODE-END*/;

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [paused, setPaused] = pAUseS(false);
  const [detail, setDetail] = pAUseS(null);

  // uzun-bas → tam ekran detay (kartlardan global çağrılır)
  pAUseE(() => {
    window.__sorraDetail = (p) => setDetail(p);
    return () => { if (window.__sorraDetail) delete window.__sorraDetail; };
  }, []);
  // detay açıkken akış durur (Esc/kapat ile geri döner)
  pAUseE(() => {
    if (!detail) return;
    const onKey = (e) => { if (e.key === 'Escape') setDetail(null); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [detail]);
  const streamsPaused = paused || !!detail;
  const onTogglePause = pAUseCb(() => setPaused(p => !p), []);

  // sütun genişliğini ölç → kartlar sütunu doldursun, içerik okunur olsun
  const colsRef = pAUseR(null);
  const [colW, setColW] = pAUseS(0);
  pAUseLE(() => {
    const measure = () => {
      if (colsRef.current) {
        const w = Math.floor(colsRef.current.clientWidth / 3);
        if (w > 0) setColW(w);
      }
    };
    measure();
    const ro = new ResizeObserver(measure);
    if (colsRef.current) ro.observe(colsRef.current);
    window.addEventListener('resize', measure);
    return () => { ro.disconnect(); window.removeEventListener('resize', measure); };
  }, []);
  const streams = pAUseM(() => buildPastelStreams(colW || 124), [colW]);

  // ripple state lifted to App so the listener can be a sibling at top z-index
  const [ripples, setRipples] = pAUseS([]);
  const idRef = pAUseR(0);
  const onAnyDown = (e) => {
    if (!t.ripples) return;
    const rect = e.currentTarget.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;
    const id = ++idRef.current;
    const colors = [PA.ACCENT, '#7E1410', '#E0564C', PA.GOLD2, '#A8160F'];
    const c = colors[id % colors.length];
    setRipples(rs => [...rs, { id, x, y, c }]);
    setTimeout(() => setRipples(rs => rs.filter(r => r.id !== id)), 900);
  };

  const dirMap = {
    'up-down-up':   ['up',   'down', 'up'],
    'down-up-down': ['down', 'up',   'down'],
    'up-up-up':     ['up',   'up',   'up'],
    'split':        ['down', 'up',   'down'],
  };
  const [dL, dM, dR] = dirMap[t.directions] || dirMap['up-down-up'];
  const colsTop = IS_TOUCH ? 40 : 92;
  const colsBottom = IS_TOUCH ? 30 : 60;

  return (
    <IOSDevice width={402} height={874} dark={true}>
      <div
        onPointerDown={onAnyDown}
        style={{
          position:'absolute', inset:0, background: PA.PAGE, overflow:'hidden',
          fontFamily:'system-ui',
        }}>

        {/* COMPACT MASTHEAD */}
        <PMasthead paused={paused} onTogglePause={onTogglePause} />

        {/* THREE COLUMNS */}
        <div ref={colsRef} style={{
          position:'absolute', top:colsTop, bottom:colsBottom, left:0, right:0,
          display:'flex', flexDirection:'row', background: PA.PAGE,
        }}>
          <PColumn direction={dL} speed={t.speed * 0.9} paused={streamsPaused} w={colW} bg={PA.PAGE}>
            {streams.left}
          </PColumn>
          <PColumn direction={dM} speed={t.speed * 1.3} paused={streamsPaused} w={colW} bg={PA.PAGE}>
            {streams.mid}
          </PColumn>
          <PColumn direction={dR} speed={t.speed * 1.05} paused={streamsPaused} w={colW} bg={PA.PAGE}>
            {streams.right}
          </PColumn>
        </div>

        {/* Sütun sınırlarına hizalı pelikül şeritleri — her ikisi birebir aynı */}
        <PPerf leftPct="33.333%" top={colsTop} bottom={colsBottom} dir={dL}/>
        <PPerf leftPct="66.666%" top={colsTop} bottom={colsBottom} dir={dR}/>

        <PBottomHUD/>
        <PGrain intensity={t.grain}/>

        {/* RIPPLES on top */}
        <div style={{ position:'absolute', inset:0, zIndex:95, pointerEvents:'none' }}>
          {ripples.map(r => (
            <div key={r.id} style={{
              position:'absolute', left:r.x, top:r.y,
              width:240, height:240, marginLeft:-120, marginTop:-120,
              willChange:'transform, opacity',
              animation:'ripple 850ms cubic-bezier(.2,.7,.2,1) forwards',
              borderRadius:'50%',
              border:`1.5px solid ${r.c}`,
              boxShadow:`0 0 12px ${r.c}55`,
            }}/>
          ))}
        </div>

        <PDetailOverlay detail={detail} onClose={() => setDetail(null)}/>

        <PInstallPrompt/>

        <TweaksPanel title="Ayarlar">
          <TweakSection label="Hareket"/>
          <TweakSlider label="Akış hızı" value={t.speed} min={6} max={60} step={1} unit="px/s"
            onChange={(v)=>setTweak('speed', v)}/>
          <TweakSelect label="Scroll deseni" value={t.directions}
            options={[
              { value:'up-down-up',   label:'▲ ▼ ▲   (varsayılan)' },
              { value:'down-up-down', label:'▼ ▲ ▼   (aynalı)'    },
              { value:'up-up-up',     label:'▲ ▲ ▲   (nehir)'     },
              { value:'split',        label:'▼ ▲ ▼   (bölünmüş)'  },
            ]}
            onChange={(v)=>setTweak('directions', v)}/>
          <TweakSection label="Doku"/>
          <TweakSlider label="Kağıt grain" value={t.grain} min={0} max={0.18} step={0.01}
            onChange={(v)=>setTweak('grain', v)}/>
          <TweakToggle label="Dokunma halkaları" value={t.ripples}
            onChange={(v)=>setTweak('ripples', v)}/>
        </TweaksPanel>
      </div>
    </IOSDevice>
  );
}

// Sabit-proplu kabuk bileşenleri memoize: App her dokunuşta (ripple/detay state)
// yeniden render olduğunda bunlar yeniden çalışmasın → ana iş parçacığı boşalır,
// kaydırma yüksek Hz'de akıcı kalır.
PMasthead     = React.memo(PMasthead);
PBottomHUD    = React.memo(PBottomHUD);
PPerf         = React.memo(PPerf);
PInstallPrompt = React.memo(PInstallPrompt);

window.App = App;
