// iPhone drawn as faked isometric 3D using PURE 2D CSS (no preserve-3d).
// Technique: layer a tilted front face over a back/shadow shape offset down-right.
// This renders correctly in html-to-image AND real Chrome.
const { useRef, useEffect: useE, useState: useS } = React;
function IPhoneMobile({ lang }) {
const t = (de, pl) => lang === 'de' ? de : pl;
const [stage, setStage] = useS(0); // 0=off, 1=slam-in, 2=power-on, 3=ui-in, 4=idle
const videoRef = useRef(null);
useE(() => {
const ts = [
setTimeout(() => setStage(1), 250),
setTimeout(() => setStage(2), 1100),
setTimeout(() => setStage(3), 1700),
setTimeout(() => setStage(4), 2400),
setTimeout(() => { if (videoRef.current) videoRef.current.play().catch(()=>{}); }, 1800),
];
return () => ts.forEach(clearTimeout);
}, []);
const revealed = stage >= 1;
const powered = stage >= 2;
const uiIn = stage >= 3;
const W = 220, H = 448;
const RADIUS = 48;
const BEZEL = 10;
const INNER_RADIUS = RADIUS - BEZEL;
// The trick: make a "fake depth" by placing multiple copies of the phone
// offset behind each other with a slight translate, creating a thick-edge look.
// Then tilt the whole thing slightly with skew for perspective.
const DEPTH_STACK = 9; // half of the previous 18 — slimmer phone
const DEPTH_STEP_X = 0.6; // half of 1.2
const DEPTH_STEP_Y = -0.2;// half of -0.4
return (
{/* Gold halo that pulses behind the phone */}
{/* Shockwave ring — expands once at entry */}
{revealed && (
<>
>
)}
{/* Gold sparks flying outward during slam */}
{revealed && [...Array(14)].map((_, i) => {
const angle = (i / 14) * Math.PI * 2;
const dist = 180 + (i % 3) * 40;
return (
);
})}
{/* GROUND SHADOW */}
{/* The phone wrapper — dramatic slam-in entrance */}
= 4 ? 'phoneFloat 6s ease-in-out infinite' : 'none',
zIndex: 2
}}>
{/* Stacked back layers — each slightly offset — creates visible thickness at edges */}
{[...Array(DEPTH_STACK)].map((_, i) => {
const t = i / (DEPTH_STACK - 1); // 0 (deepest) -> 1 (closest to front)
return (
);
})}
{/* FRONT FACE — titanium bezel */}
{/* Inner black rim */}
{/* LEFT-side physical buttons drawn on the stack thickness */}
{/* Right power button on the offset thickness */}
{/* SCREEN */}
{/* Power-on white flash */}
{powered && (
)}
{/* Scanline sweep */}
{powered && (
)}
{/* UI content — fades/slides in after power-on */}
{/* Looping hero video — plays on repeat, muted, autoplay.
Poster image renders below as fallback for screenshot tools. */}
{/* STATUS BAR */}
{/* Dynamic Island */}
{/* TikTok top tabs */}
{t('Folge ich','Obserwuję')}
{t('Für dich','Dla ciebie')}
{/* Search */}
{/* RIGHT ACTION RAIL */}
} label="12.4K"/>
} label="847"/>
} label="1.2K"/>
} label="203"/>
{/* BOTTOM caption */}
@jk_media · {t('folgen','obserwuj')}
{t('Wie Handwerker in Guben durchstarten 🚀 ','Jak rzemieślnicy w Guben ruszają 🚀 ')}
#socialmedia{' '}
#gubin
{t('Original Sound · JK Media','Oryginalny dźwięk · JK Media')}
{/* TikTok bottom nav */}
{[{n:t('Start','Start'), active:true},{n:t('Freunde','Znajomi')},{plus:true},{n:t('Inbox','Skrzynka')},{n:t('Profil','Profil')}].map((item,i) => (
{item.plus ? (
+
) : item.n}
))}
{/* Front glare */}
);
}
// Helper: hex shade
function shade(v) {
const h = Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2,'0');
return `#${h}${h}${h}`;
}
function TikTokAction({ icon, label }) {
return (
);
}
window.IPhoneMobile = IPhoneMobile;