Files
videogen/prototyp-app.html
root 65a19d7678 Design-Sync: Kapsel-Shape (8) fuer Dither-Chips, Liquid-Metal u_shape 0
Aus prototyp-app.html im Design-Projekt uebernommen: neue GLSL-Shape 8
(aspect-korrigierte Kapsel statt zentrierter Kugel - passt sich der
Pill-Breite an), Chips auf shape:8, Liquid-Metal-Uniform u_shape 1->0.
Bildpfade bleiben .jpg (Design-Kopie basierte auf aelterem .png-Stand).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 19:14:15 +00:00

1693 lines
100 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<meta name="theme-color" content="#0a0a0a">
<title>BrandLoop Prototyp</title>
<link rel="stylesheet" href="border-beam.css">
<script type="module">import('https://esm.sh/@paper-design/shaders').then(function(m){window.__paperShaders=m;var u={u_repetition:4,u_softness:.5,u_shiftRed:.3,u_shiftBlue:.3,u_distortion:0,u_contour:0,u_angle:45,u_scale:8,u_shape:0,u_offsetX:.1,u_offsetY:-.1};setInterval(function(){document.querySelectorAll('.lm-shader:not([data-lm])').forEach(function(el){el.dataset.lm='1';try{new m.ShaderMount(el,m.liquidMetalFragmentShader,u,undefined,0.6)}catch(e){}})},500)}).catch(function(){})</script>
<style>
/* Liquid-Metal-Buttons (aus BrandLoop.dc.html): Shader-Canvas ueber
Metall-Gradient (Fallback ohne WebGL/offline), schwarzer Kern, graues Icon */
.lm-shader canvas{width:100%!important;height:100%!important;display:block!important;position:absolute!important;top:0!important;left:0!important;border-radius:100px!important;}
.lm-bg{position:absolute; inset:0; border-radius:100px; overflow:hidden;
background:linear-gradient(135deg,#e8e8e8,#6f6f6f 35%,#f2f2f2 50%,#5c5c5c 68%,#cfcfcf);}
.lm-bg.deg120{background:linear-gradient(120deg,#e8e8e8,#6f6f6f 35%,#f2f2f2 50%,#5c5c5c 68%,#cfcfcf);}
.lm-core{position:absolute; inset:2px; border-radius:100px; background:linear-gradient(180deg,#202020,#000);}
.lm-ic{position:absolute; inset:0; display:grid; place-items:center;}
.lm-btn{position:relative; height:52px; border-radius:100px; cursor:pointer;
box-shadow:0 2px 5px rgba(0,0,0,.35), 0 9px 9px rgba(0,0,0,.12);}
.lm-label{position:absolute; inset:0; display:flex; align-items:center; justify-content:center; gap:8px;
font-size:14.5px; font-weight:700; color:#9a9a9a; text-shadow:0 1px 2px rgba(0,0,0,.5);}
</style>
<style>
:root{
--bg:#0a0a0a;
--surface:rgba(255,255,255,.05);
--surface2:rgba(255,255,255,.1);
--sheet:#131316;
--card:#161616;
--border:rgba(255,255,255,.09);
--border-strong:rgba(255,255,255,.18);
--txt:#fff;
--mut:rgba(255,255,255,.6);
--faint:rgba(255,255,255,.4);
--accent:#ff5c39;
--ok:#34d399;
--gold:#fbbf24;
}
*{box-sizing:border-box; margin:0; padding:0;}
html{-webkit-text-size-adjust:100%;}
html, body{overscroll-behavior-y:none;}
/* Explore ist ein fixer Vollbild-Screen: Seite darf nicht scrollen/wippen */
body.noscroll{overflow:hidden; height:100dvh;}
body.noscroll .app{padding-bottom:0;}
body{
background:var(--bg); color:var(--txt);
font-family:-apple-system,BlinkMacSystemFont,"Helvetica Neue","Inter",Roboto,system-ui,sans-serif;
font-size:15px; line-height:1.5;
-webkit-font-smoothing:antialiased;
-webkit-tap-highlight-color:transparent;
}
svg.ic{fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round; stroke-linejoin:round;}
.mono{font-family:ui-monospace,Menlo,SFMono-Regular,Consolas,monospace;}
.app{position:relative; max-width:430px; margin:0 auto; min-height:100dvh; overflow-x:hidden;}
@media(min-width:480px){.app{border-inline:1px solid var(--border);}}
.screen{display:none; animation:fade .28s ease; position:relative; z-index:1;
padding:0 18px calc(112px + env(safe-area-inset-bottom));}
.screen.active{display:block;}
@keyframes fade{from{opacity:0; transform:translateY(8px);} to{opacity:1; transform:none;}}
/* ---- Topbar ---- */
.topbar{position:sticky; top:0; z-index:20; display:flex; align-items:center; gap:12px;
margin:0 -18px 14px; padding:calc(12px + env(safe-area-inset-top)) 18px 12px;
background:rgba(10,10,10,.85); backdrop-filter:blur(16px); -webkit-backdrop-filter:blur(16px);}
.topbar h1{font-size:16px; font-weight:700; letter-spacing:-.01em;}
.backpill{display:flex; align-items:center; gap:7px; padding:9px 16px 9px 12px; border-radius:100px;
background:var(--surface2); border:none; color:var(--txt); font-size:13px; font-weight:600; font-family:inherit;
cursor:pointer; flex-shrink:0; transition:transform .12s;}
.backpill:active{transform:scale(.94);}
.backpill .ar{font-size:14px; opacity:.8;}
.iconbtn{display:grid; place-items:center; width:36px; height:36px; border-radius:100px;
background:var(--surface); border:1px solid var(--border); color:var(--mut); cursor:pointer; flex-shrink:0; transition:transform .12s, color .15s;}
.iconbtn:active{transform:scale(.92);}
.iconbtn svg{width:18px; height:18px;}
/* ---- Typo ---- */
h3{font-size:12px; font-weight:700; color:var(--faint); text-transform:uppercase; letter-spacing:.1em; margin:22px 0 10px;}
.sub{color:var(--mut); font-size:13.5px; line-height:1.55; margin-top:4px;}
.note{font-size:12px; color:var(--faint); line-height:1.55; margin-top:10px;}
.hl{color:var(--txt); font-weight:600;}
/* ---- Cards ---- */
.card{background:var(--card); border:1px solid rgba(255,255,255,.07); border-radius:16px; padding:15px 16px; margin-bottom:12px; position:relative;}
.card h4{font-size:15px; font-weight:700; margin-bottom:3px;}
.card h4.t-sm{font-size:13.5px;}
.card p{font-size:13px; color:var(--mut); line-height:1.55;}
.card.click{cursor:pointer; transition:border-color .15s, transform .1s, background .15s;}
.card.click:hover{border-color:var(--border-strong);}
.card.click:active{transform:scale(.98);}
.cardrow{display:flex; align-items:center; gap:13px;}
.cardrow .body{flex:1; min-width:0;}
.ico{width:42px; height:42px; border-radius:14px; display:grid; place-items:center; flex-shrink:0;}
.ico svg{width:20px; height:20px;}
.ico.rose{background:rgba(255,92,57,.14); color:var(--accent);}
.ico.orange{background:rgba(249,115,22,.12); color:#fb923c;}
.ico.amber{background:rgba(251,191,36,.12); color:var(--gold);}
.ico.emerald{background:rgba(52,211,153,.12); color:var(--ok);}
.ico.zinc{background:var(--surface2); color:var(--mut);}
.chev{width:16px; height:16px; color:var(--faint); flex-shrink:0;}
/* ---- Media-Platzhalter ---- */
.ph{display:flex; gap:10px; align-items:flex-start; border:1.5px dashed rgba(255,255,255,.18); border-radius:14px;
padding:13px 14px; font-size:12.5px; color:var(--mut); font-style:italic; line-height:1.55;
background:rgba(255,255,255,.02); margin:10px 0;}
.ph svg{width:16px; height:16px; flex-shrink:0; margin-top:2px; color:var(--faint);}
/* ---- Buttons ---- */
.btn{display:flex; align-items:center; justify-content:center; gap:8px; width:100%;
border:none; border-radius:100px; padding:15px; font-size:14.5px; font-weight:800; font-family:inherit; cursor:pointer; margin-top:14px;
background:var(--accent); color:#0a0a0a;
box-shadow:0 0 22px rgba(255,92,57,.27);
transition:transform .12s, filter .15s;}
.btn:hover{filter:brightness(1.06);}
.btn:active{transform:scale(.98);}
.btn.sec{background:var(--surface2); color:var(--txt); border:1px solid var(--border); box-shadow:none; font-weight:600;}
.btn svg{width:17px; height:17px;}
/* ---- Formulare ---- */
input[type=text], textarea{width:100%; background:var(--card); border:1px solid rgba(255,255,255,.1); border-radius:16px;
color:var(--txt); padding:13px 15px; font-size:13.5px; font-family:inherit; margin:6px 0 14px; line-height:1.55;
transition:border-color .15s, box-shadow .15s; -webkit-appearance:none;}
::placeholder{color:var(--faint);}
input:focus, textarea:focus{outline:none; border-color:rgba(255,92,57,.6); box-shadow:0 0 0 3px rgba(255,92,57,.14);}
textarea{min-height:96px; resize:vertical;}
label{font-size:12px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:var(--faint); display:block;}
.req{color:var(--accent); text-transform:none;}
/* ---- Tags, Scores, Badges ---- */
.tag{display:inline-flex; align-items:center; gap:5px; background:var(--surface2); border:none;
color:var(--txt); border-radius:100px; padding:7px 13px; font-size:12px; font-weight:600; margin:3px 5px 0 0;}
.score{color:var(--gold); font-weight:700; font-size:.95em;}
.badge{display:inline-block; font-size:10px; border-radius:999px; padding:3px 9px; font-weight:700; letter-spacing:.03em; vertical-align:2px;}
.b-ok{background:rgba(52,211,153,.14); color:var(--ok);}
.b-arch{background:rgba(161,161,170,.14); color:var(--mut);}
.b-new{background:rgba(255,92,57,.16); color:var(--accent);}
/* ---- Favorit ---- */
.fav{border-color:rgba(251,191,36,.45); box-shadow:0 0 0 1px rgba(251,191,36,.25), 0 8px 28px rgba(251,191,36,.07);}
.favlabel{position:absolute; top:-10px; right:14px; background:linear-gradient(135deg,#fbbf24,#f59e0b);
color:#1c1400; font-size:10px; font-weight:700; letter-spacing:.04em; border-radius:999px; padding:3px 10px;}
/* ---- Chips / Pills ---- */
.pill-row{display:flex; gap:7px; margin:10px 0 4px;}
.pill{flex:1; text-align:center; background:var(--surface); border:1px solid var(--border); border-radius:100px;
padding:11px 6px; font-size:12.5px; color:rgba(255,255,255,.8); font-weight:600; cursor:pointer;
transition:color .15s, background .15s, transform .1s, border-color .15s;}
.pill:active{transform:scale(.96);}
.pill.on{border-color:transparent; color:#000; background:#fff;}
.chiprow{display:flex; gap:8px; overflow-x:auto; margin:0 -18px; padding:2px 18px 4px; scrollbar-width:none;}
.chiprow::-webkit-scrollbar{display:none;}
.chip{flex:none; display:flex; align-items:center; gap:8px; padding:10px 15px; border-radius:100px;
font-size:12.5px; font-weight:600; cursor:pointer; background:var(--surface); color:rgba(255,255,255,.8);
transition:background .15s, color .15s;}
.chip.on{background:#fff; color:#000;}
.chip .dot{width:9px; height:9px; border-radius:100px; flex:none; background:rgba(255,255,255,.3);}
.chip.on .dot{background:var(--accent);}
/* ---- Steps ---- */
.steps{display:flex; gap:6px; margin-bottom:18px;}
.steps div{flex:1; height:4px; border-radius:4px; background:var(--surface2);}
.steps div.on{background:var(--accent);}
/* ---- Metriken ---- */
.row{display:flex; gap:10px;}
.row .card{flex:1;}
.metric{text-align:center; padding:14px 8px;}
.metric p{font-size:10.5px; color:var(--faint); margin-bottom:4px; text-transform:uppercase; letter-spacing:.06em; font-weight:700;}
.metric h4{font-size:19px; font-weight:800; margin:0;}
.metric h4.g{color:var(--ok);}
/* ---- Listen in Cards ---- */
.rule{display:flex; gap:10px; align-items:center; padding:9px 0; border-bottom:1px solid var(--border); font-size:13.5px; color:var(--txt);}
.rule:last-child{border-bottom:none; padding-bottom:2px;}
.rule:first-child{padding-top:2px;}
.rule svg{width:16px; height:16px; color:var(--ok); flex-shrink:0;}
.asset{display:flex; align-items:center; gap:10px; padding:8px 0; border-bottom:1px solid var(--border); font-size:13.5px;}
.asset:last-child{border-bottom:none; padding-bottom:2px;}
.asset:first-child{padding-top:2px;}
.asset svg{width:16px; height:16px; color:var(--mut); flex-shrink:0;}
.asset .score{margin-left:auto;}
/* ---- Log & Code ---- */
.log{font-size:12.5px; color:var(--mut); border-left:2px solid var(--border-strong); padding:5px 0 5px 12px; margin:8px 0; line-height:1.5;}
.code{font-family:ui-monospace,SFMono-Regular,Consolas,monospace; font-size:11px; line-height:1.7; color:var(--mut);
background:#0c0c0f; border:1px solid var(--border); border-radius:14px; padding:14px; overflow-x:auto; margin:10px 0;}
.code b{color:var(--accent); font-weight:600;}
/* ---- Tutorial ---- */
.tut{display:flex; flex-direction:column; justify-content:center; min-height:calc(100dvh - 160px); text-align:center; padding:20px 6px;}
.tut .emoji{font-size:52px; margin-bottom:18px;}
.tut h1{font-size:26px; font-weight:800; letter-spacing:-.02em; margin-bottom:12px;}
.tut .sub{font-size:14.5px;}
/* ================= EXPLORE (Feed) ================= */
#explore{padding:0; --xs:max(env(safe-area-inset-top, 0px), 64px);}
#explore.active{display:flex; flex-direction:column; height:100dvh; overflow:hidden;}
.x-blur{position:absolute; inset:-50px; pointer-events:none; z-index:0;
filter:blur(36px) brightness(.78) saturate(1.15); transform:scale(1.08);
transition:background .7s ease, opacity .25s ease;}
.x-hood{position:absolute; inset:0; pointer-events:none; z-index:2;}
.x-hood svg{position:absolute; top:calc(var(--xs) - 14px); left:0; display:block; width:100%; height:120px;}
.x-hood .solid{position:absolute; top:calc(var(--xs) + 105px); left:0; right:0; bottom:0; background:var(--bg);}
.x-hood .glowred, .glowred-screen{background:radial-gradient(125% 125% at 50% 150%, rgba(241,99,99,.21) 40%, transparent 100%);}
.x-hood .glowred{position:absolute; inset:0;}
.x-tabs{position:absolute; top:calc(var(--xs) + 12px); left:0; right:0; height:24px; z-index:6;
display:flex; justify-content:center; align-items:center; gap:96px;}
.x-tab{position:relative; white-space:nowrap; padding:4px 6px;
font-size:14.5px; font-weight:600; cursor:pointer; color:rgba(255,255,255,.42); transition:color .25s;}
.x-tab::before{content:''; position:absolute; inset:-18px -30px;}
.x-tab.on{color:#fff; text-shadow:0 1px 10px rgba(0,0,0,.45);}
.x-deck{flex:1; position:relative; margin:calc(var(--xs) + 144px) 22px 10px; min-height:0; z-index:3;}
.x-card{position:absolute; inset:0; border-radius:26px; overflow:hidden; background:#141414;
touch-action:none; box-shadow:0 18px 44px rgba(0,0,0,.45);}
.x-card .img{position:absolute; inset:0; pointer-events:none;}
.x-card .imglabel{position:absolute; inset:0; display:grid; place-items:center; pointer-events:none;}
.x-card .imglabel span{font-family:ui-monospace,Menlo,monospace; font-size:12px; color:rgba(255,255,255,.85);
background:rgba(0,0,0,.35); padding:6px 12px; border-radius:8px;}
.x-card .playwrap{position:absolute; inset:0; display:grid; place-items:center; pointer-events:none;}
.x-card .play{width:64px; height:64px; border-radius:100px; background:rgba(10,10,10,.55);
backdrop-filter:blur(10px); display:grid; place-items:center; margin-top:90px;}
.x-segs{position:absolute; top:12px; left:14px; right:14px; display:flex; gap:5px; pointer-events:none;}
.x-segs div{flex:1; height:3px; border-radius:100px;}
.x-chips{position:absolute; top:24px; left:14px; display:flex; gap:6px; pointer-events:none;}
.x-chips div{padding:7px 13px; border-radius:100px; background:rgba(10,10,10,.55); backdrop-filter:blur(12px); font-size:12px; font-weight:600;}
.x-meta{position:absolute; left:0; right:0; bottom:0; padding:56px 18px 18px;
background:linear-gradient(transparent,rgba(0,0,0,.78)); pointer-events:none; display:flex; align-items:center; gap:10px;}
.x-meta .av{width:38px; height:38px; border-radius:100px; flex:none; display:grid; place-items:center; font-size:14px; font-weight:700;}
.x-meta .nm{font-size:15px; font-weight:700;}
.x-meta .md{font-size:12px; color:rgba(255,255,255,.6); white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}
.x-badge{position:absolute; top:48px; padding:8px 16px; border-radius:12px; font-size:22px; font-weight:800;
letter-spacing:.08em; pointer-events:none; opacity:0;}
.x-badge.like{left:20px; border:3px solid var(--accent); color:var(--accent); transform:rotate(-14deg);}
.x-badge.skip{right:20px; border:3px solid #ff5c5c; color:#ff5c5c; transform:rotate(14deg);}
.x-empty{position:absolute; inset:0; border-radius:26px; background:#141414; border:1px dashed rgba(255,255,255,.15);
display:flex; flex-direction:column; align-items:center; justify-content:center; gap:14px;}
.x-actions{position:relative; z-index:3; display:flex; justify-content:center; align-items:center; gap:22px;
padding:6px 0 84px;}
.x-act{width:56px; height:56px; border-radius:100px; background:rgba(255,255,255,.08); border:1px solid rgba(255,255,255,.12);
display:grid; place-items:center; cursor:pointer; font-size:20px; color:rgba(255,255,255,.8); transition:transform .12s;}
.x-act:active{transform:scale(.92);}
.x-act.sm{width:44px; height:44px;}
.x-act.like{position:relative; background:none; border:none;
box-shadow:0 2px 5px rgba(0,0,0,.4), 0 9px 9px rgba(0,0,0,.15);}
/* ================= DETAIL & CREATE ================= */
#detail.active, #create.active{min-height:100dvh;
background:radial-gradient(125% 125% at 50% 150%, rgba(241,99,99,.21) 40%, transparent 100%);}
/* Create = fixer Vollbild-Screen mit internem Scroll + Fake-Tastatur */
#create.active{display:flex; flex-direction:column; height:100dvh; overflow:hidden; position:relative;}
.c-scroll{flex:1; overflow-y:auto; min-height:0; margin:0 -20px; padding:8px 18px 110px; scrollbar-width:none;
transition:padding-bottom .3s ease;}
.c-scroll::-webkit-scrollbar{display:none;}
.c-scroll.kb-open{padding-bottom:380px;}
.c-optlabel{font-size:11px; font-weight:700; letter-spacing:.12em; color:rgba(255,255,255,.4); margin-bottom:9px;}
/* Dithering-Shader-Chips (Testeffekt auf den Modell-Chips) */
.chip.dither{position:relative; overflow:hidden; background:#000; color:#fff;
border:1px solid rgba(255,255,255,.14);}
.chip.dither.on{background:#000; color:#fff; border-color:rgba(255,255,255,.55);}
.chip.dither canvas{position:absolute; inset:0; width:100%; height:100%;}
.chip.dither > *:not(canvas){position:relative; z-index:1;}
.chip.dither span{text-shadow:0 1px 2px rgba(0,0,0,.7);}
.c-behind{position:absolute; top:0; left:50%; border-radius:22px; background:#1b1b1b;
border:1px solid rgba(255,255,255,.09); transform-origin:top center; z-index:0;}
.c-preview{position:relative; border-radius:22px; overflow:hidden; z-index:1;
box-shadow:0 18px 44px rgba(0,0,0,.5); transition:width .25s ease, height .25s ease;}
.kb{position:fixed; left:0; right:0; bottom:0; z-index:45; max-width:430px; margin:0 auto;
transform:translateY(112%); transition:transform .34s cubic-bezier(.22,1,.36,1);}
.kb.open{transform:none;}
.kb-row{display:flex; gap:5px; margin-bottom:8px;}
.kb-key{flex:1; height:38px; border-radius:6px; background:rgba(255,255,255,.16); display:grid; place-items:center;
font-size:16px; font-weight:500; color:#fff; cursor:pointer; user-select:none; -webkit-user-select:none; min-width:0;}
.kb-key.mod{background:rgba(255,255,255,.28); font-size:15px;}
.kb-chip{flex:none; display:flex; align-items:center; gap:7px; padding:8px 13px; border-radius:100px;
background:rgba(255,255,255,.12); font-size:12.5px; font-weight:600; cursor:pointer; white-space:nowrap; color:#fff;}
.kb-chip .dot{width:8px; height:8px; border-radius:100px; flex:none;}
.d-strip{display:flex; gap:10px; overflow-x:auto; margin:0 -18px; padding:0 18px; scrollbar-width:none; scroll-snap-type:x mandatory;}
.d-strip::-webkit-scrollbar{display:none;}
.d-img{flex:none; width:272px; height:330px; border-radius:20px; position:relative; display:grid; place-items:center; scroll-snap-align:center;}
.d-img .lbl{font-family:ui-monospace,Menlo,monospace; font-size:11.5px; color:rgba(255,255,255,.85);
background:rgba(0,0,0,.35); padding:5px 10px; border-radius:8px;}
.d-img .num{position:absolute; top:10px; right:12px; font-size:11px; font-weight:700; background:rgba(10,10,10,.55); padding:5px 9px; border-radius:100px;}
.d-title{font-size:26px; font-weight:800; letter-spacing:-.5px; margin:18px 0 4px;}
.d-sub{font-size:13px; color:rgba(255,255,255,.5); margin-bottom:16px;}
.promptbox{border-radius:16px; background:var(--card); border:1px solid rgba(255,255,255,.07); padding:14px 16px; margin-bottom:14px;}
.promptbox .k{font-size:11px; font-weight:700; letter-spacing:.12em; color:var(--faint); margin-bottom:8px;}
.promptbox .v{font-family:ui-monospace,Menlo,monospace; font-size:12.5px; line-height:1.6; color:rgba(255,255,255,.85);}
.frames{display:flex; gap:8px; overflow-x:auto; margin:0 -18px; padding:0 18px; scrollbar-width:none;}
.frames::-webkit-scrollbar{display:none;}
.frame{flex:none; border-radius:14px; border:1px dashed rgba(255,255,255,.2);
background:repeating-linear-gradient(135deg,transparent 0 12px,rgba(255,255,255,.04) 12px 24px); display:grid; place-items:center;}
.frame span{font-family:ui-monospace,Menlo,monospace; font-size:11px; color:rgba(255,255,255,.5);}
/* ================= PROFIL (Menschlein) ================= */
.p-hero{text-align:center; padding:calc(30px + env(safe-area-inset-top)) 0 6px;}
.p-hero .av{width:76px; height:76px; border-radius:100px; margin:0 auto 12px; display:grid; place-items:center;
font-size:28px; font-weight:800; background:linear-gradient(140deg,oklch(.72 .13 40),oklch(.5 .13 40));}
.p-hero h2{font-size:22px; font-weight:800; letter-spacing:-.02em;}
.p-hero p{color:var(--mut); font-size:13px; margin-top:3px;}
/* ================= Bottom-Navigation ================= */
/* Liquid-Glass-Nav (aus BrandLoop.dc.html): echte Refraktion via dynamischer
Displacement-Map (bl-glass-refract, RGB-Split) + Blur/Saturate-Backdrop +
Weiss-Layer + Kanten-Ring. bottom:14px = exakt die Hoehe aus dem Design. */
.nav{position:fixed; bottom:14px; left:50%; transform:translateX(-50%); z-index:30;
display:flex; align-items:center; gap:6px; padding:8px 10px; border-radius:100px;
box-shadow:0 6px 6px rgba(0,0,0,.2), 0 0 20px rgba(0,0,0,.1);
transition:all .7s cubic-bezier(.175,.885,.32,2.2);}
.nav-glass{position:absolute; inset:0; border-radius:100px;}
.nav-glass.blur{overflow:hidden; -webkit-backdrop-filter:blur(3px) saturate(1.15); backdrop-filter:blur(3px) saturate(1.15);}
.nav-glass.refract{overflow:hidden; -webkit-backdrop-filter:url(#bl-glass-refract); backdrop-filter:url(#bl-glass-refract);}
.nav-glass.white{background:rgba(255,255,255,.12); z-index:1;}
.nav-glass.ring{z-index:2; pointer-events:none;
box-shadow:inset 2px 2px 1px 0 rgba(255,255,255,.4), inset -1px -1px 1px 1px rgba(255,255,255,.3);}
.nav button{position:relative; z-index:3; display:flex; align-items:center; gap:8px; background:none; border:none; font-family:inherit;
width:40px; height:40px; justify-content:center; border-radius:100px; color:rgba(255,255,255,.6);
font-size:13.5px; font-weight:600; cursor:pointer; transition:background .2s, color .2s, width .2s;}
.nav button svg{width:20px; height:20px; flex:none;}
.nav button span{display:none;}
.nav button.on{width:auto; padding:9px 16px 9px 12px; background:rgba(255,255,255,.14); color:#fff;}
.nav button.on span{display:inline;}
/* Plus-Button = Liquid-Metal (Shader + schwarzer Kern) */
.nav button.plus{background:none; box-shadow:0 2px 5px rgba(0,0,0,.35);}
.nav button.plus.on{width:40px; padding:0;}
.nav button.plus.on span{display:none;}
/* ---- Info-Sheet ---- */
.backdrop{position:fixed; inset:0; background:rgba(0,0,0,.6); opacity:0; pointer-events:none; transition:opacity .25s; z-index:40;}
.backdrop.open{opacity:1; pointer-events:auto;}
.sheet{position:fixed; bottom:0; left:0; right:0; margin:0 auto; max-width:430px; background:var(--sheet);
border:1px solid var(--border); border-bottom:none; border-radius:24px 24px 0 0;
padding:14px 20px calc(28px + env(safe-area-inset-bottom));
transform:translateY(105%); transition:transform .32s cubic-bezier(.32,.72,0,1); z-index:50; max-height:80dvh; overflow-y:auto;}
.sheet.open{transform:none;}
.sheet .grab{width:36px; height:4px; border-radius:4px; background:var(--surface2); margin:0 auto 18px;}
.sheet h2{font-size:17px; font-weight:700; margin-bottom:10px;}
.sheet p{color:var(--mut); font-size:13.5px; line-height:1.6; margin-bottom:12px;}
.sheet ul{list-style:none; margin-bottom:12px;}
.sheet li{color:var(--mut); font-size:13.5px; line-height:1.6; padding-left:14px; position:relative; margin-bottom:4px;}
.sheet li::before{content:"·"; position:absolute; left:2px; color:var(--accent); font-weight:700;}
</style>
</head>
<body class="noscroll">
<!-- Lucide-Icon-Sprite + Liquid-Glass-Filter -->
<svg width="0" height="0" style="position:absolute" aria-hidden="true">
<defs>
<filter id="bl-glass-refract" color-interpolation-filters="sRGB" x="0%" y="0%" width="100%" height="100%">
<feImage id="glassMapImage" x="0" y="0" width="100%" height="100%" preserveAspectRatio="none" href="" result="map"/>
<feDisplacementMap in="SourceGraphic" in2="map" scale="-180" xChannelSelector="R" yChannelSelector="G" result="dispRed"/>
<feColorMatrix in="dispRed" type="matrix" values="1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0" result="red"/>
<feDisplacementMap in="SourceGraphic" in2="map" scale="-170" xChannelSelector="R" yChannelSelector="G" result="dispGreen"/>
<feColorMatrix in="dispGreen" type="matrix" values="0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0" result="green"/>
<feDisplacementMap in="SourceGraphic" in2="map" scale="-160" xChannelSelector="R" yChannelSelector="G" result="dispBlue"/>
<feColorMatrix in="dispBlue" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0" result="blue"/>
<feBlend in="red" in2="green" mode="screen" result="rg"/>
<feBlend in="rg" in2="blue" mode="screen" result="out"/>
<feGaussianBlur in="out" stdDeviation="0.7"/>
</filter>
<symbol id="i-back" viewBox="0 0 24 24"><path d="m15 18-6-6 6-6"/></symbol>
<symbol id="i-chev" viewBox="0 0 24 24"><path d="m9 18 6-6-6-6"/></symbol>
<symbol id="i-home" viewBox="0 0 24 24"><path d="M4 11 L12 4 L20 11 V20 H14 V15 H10 V20 H4 Z"/></symbol>
<symbol id="i-plus" viewBox="0 0 24 24"><path d="M12 5 V19 M5 12 H19"/></symbol>
<symbol id="i-spark" viewBox="0 0 24 24"><path d="m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z"/><path d="M5 3v4"/><path d="M19 17v4"/><path d="M3 5h4"/><path d="M17 19h4"/></symbol>
<symbol id="i-db" viewBox="0 0 24 24"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5V19A9 3 0 0 0 21 19V5"/><path d="M3 12A9 3 0 0 0 21 12"/></symbol>
<symbol id="i-gear" viewBox="0 0 24 24"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/></symbol>
<symbol id="i-film" viewBox="0 0 24 24"><path d="M20.2 6 3 11l-.9-2.4c-.3-1.1.3-2.2 1.3-2.5l13.5-4c1.1-.3 2.2.3 2.5 1.3Z"/><path d="m6.2 5.3 3.1 3.9"/><path d="m12.4 3.4 3.1 4"/><path d="M3 11h18v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z"/></symbol>
<symbol id="i-user" viewBox="0 0 24 24"><circle cx="12" cy="8.5" r="3.5"/><path d="M5 20 c1.2-3.6 4-5 7-5 s5.8 1.4 7 5"/></symbol>
<symbol id="i-box" viewBox="0 0 24 24"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.29 7 12 12 20.71 7"/><line x1="12" x2="12" y1="22" y2="12"/></symbol>
<symbol id="i-pin" viewBox="0 0 24 24"><path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z"/><circle cx="12" cy="10" r="3"/></symbol>
<symbol id="i-bulb" viewBox="0 0 24 24"><path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"/><path d="M9 18h6"/><path d="M10 22h4"/></symbol>
<symbol id="i-mic" viewBox="0 0 24 24"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" x2="12" y1="19" y2="22"/></symbol>
<symbol id="i-up" viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" x2="12" y1="3" y2="15"/></symbol>
<symbol id="i-play" viewBox="0 0 24 24"><polygon points="6 3 20 12 6 21 6 3"/></symbol>
<symbol id="i-img" viewBox="0 0 24 24"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/></symbol>
<symbol id="i-info" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></symbol>
<symbol id="i-check" viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></symbol>
<symbol id="i-refresh" viewBox="0 0 24 24"><path d="M4 12 a8 8 0 1 1 2.3 5.7"/><path d="M4 18 v-5 h5"/></symbol>
<symbol id="i-lock" viewBox="0 0 24 24"><rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></symbol>
</defs>
</svg>
<div class="app">
<!-- ============ EXPLORE / FEED (neu, aus BrandLoop.dc.html) ============ -->
<div class="screen active" id="explore">
<div class="x-blur" id="xBlur"></div>
<div class="x-hood">
<svg viewBox="0 0 430 120" preserveAspectRatio="none"><path id="xHoodPath" d="" fill="#0a0a0a"></path></svg>
<div class="solid"></div>
<div class="glowred"></div>
</div>
<button class="iconbtn" style="position:absolute; top:calc(var(--xs) - 54px); right:14px; z-index:8;" onclick="toggleInfo(true)" aria-label="Info zum Prototyp"><svg class="ic"><use href="#i-info"/></svg></button>
<div class="x-tabs">
<div class="x-tab" data-tab="videos">Videos</div>
<div class="x-tab" data-tab="folge">Folge ich</div>
<div class="x-tab on" data-tab="posts">Posts</div>
</div>
<div class="x-deck" id="xDeck"></div>
<div class="x-actions">
<div class="x-act" id="btnSkip" role="button" aria-label="Skip"></div>
<div class="x-act sm" id="btnDetail" role="button" aria-label="Details / Nachmachen"><svg class="ic" style="width:18px;height:18px;color:rgba(255,255,255,.8)"><use href="#i-refresh"/></svg></div>
<div class="x-act like" id="btnLike" role="button" aria-label="Like">
<div class="lm-shader lm-bg"></div>
<div class="lm-core"></div>
<div class="lm-ic"><svg width="24" height="24" viewBox="0 0 24 24" fill="#9a9a9a" style="filter:drop-shadow(0 1px 2px rgba(0,0,0,.5))"><path d="M12 21 C5 15.5 2.5 12 2.5 8.5 A4.7 4.7 0 0 1 12 6.2 A4.7 4.7 0 0 1 21.5 8.5 C21.5 12 19 15.5 12 21 Z"/></svg></div>
</div>
</div>
</div>
<!-- ============ POST-DETAIL (neu) ============ -->
<div class="screen" id="detail">
<div class="topbar">
<button class="backpill" onclick="go('explore')"><span class="ar"></span> Zurück</button>
<div style="margin-left:auto; display:flex; align-items:center; gap:10px;">
<div id="dAvatar" style="width:34px; height:34px; border-radius:100px; background:linear-gradient(140deg,oklch(.72 .13 40),oklch(.55 .13 40)); display:grid; place-items:center; font-size:13px; font-weight:700;">M</div>
<div><div style="font-size:13.5px; font-weight:700;">Mara S.</div><div style="font-size:11px; color:rgba(255,255,255,.5);">1.2k Remakes</div></div>
</div>
</div>
<div class="d-strip" id="dStrip"></div>
<div class="d-title">Skincare Routine 3er Kette</div>
<div class="d-sub">Bild-Kette · Produkt-Modell · Format 4:5</div>
<div class="promptbox">
<div class="k">PROMPT</div>
<div class="v" id="detailPrompt">Roter Toner im rosa Bogenfenster, weiches Gegenlicht, Editorial-Look — Kette: Fenster-Szene → Dropper auf Glaskante → Poster-Ad in Orange</div>
</div>
<div style="margin-bottom:22px;">
<span class="tag">Modell · Glow Serum v3</span><span class="tag">4:5</span><span class="tag">Editorial</span><span class="tag">3 Bilder</span>
</div>
<div style="font-size:15px; font-weight:800; margin-bottom:10px;">Mit deinem Modell nachmachen</div>
<div class="chiprow" id="detailModels"></div>
<div class="lm-btn" id="remakeBtn" role="button" style="margin-top:16px;">
<div class="lm-shader lm-bg deg120"></div>
<div class="lm-core"></div>
<div class="lm-label"><svg width="15" height="15" viewBox="0 0 24 24" fill="#9a9a9a" style="filter:drop-shadow(0 1px 2px rgba(0,0,0,.5))"><path d="M12 2 L14.4 9.6 L22 12 L14.4 14.4 L12 22 L9.6 14.4 L2 12 L9.6 9.6 Z"/></svg><span id="remakeLabel"></span></div>
</div>
<div style="text-align:center; font-size:11.5px; color:rgba(255,255,255,.4); margin-top:10px;">Prompt + Einstellungen werden übernommen, dein Modell wird eingesetzt</div>
</div>
<!-- ============ POST ERSTELLEN (neu, aus BrandLoop.dc.html v4) ============ -->
<div class="screen" id="create">
<div class="topbar">
<button class="backpill" onclick="go('explore')"><span class="ar"></span> Zurück</button>
<h1 style="flex:1; text-align:center; margin-right:80px;">Neuer KI-Post</h1>
</div>
<div class="c-scroll" id="cScroll">
<div style="display:flex; flex-direction:column; align-items:center; padding:10px 0 4px;">
<div id="cStack" onclick="toggleOpts()" style="position:relative; cursor:pointer;"></div>
<div onclick="toggleOpts()" style="display:flex; align-items:center; gap:8px; margin-top:14px; padding:9px 10px 9px 16px; border-radius:100px; background:rgba(255,255,255,.08); cursor:pointer;">
<span style="font-size:13px; font-weight:600;" id="cSelLabel"></span>
<svg id="cChevron" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="rgba(255,255,255,.6)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="transition:transform .2s;"><path d="M6 9 l6 6 l6 -6"/></svg>
</div>
<div id="cOpts" style="display:none; width:100%; margin-top:14px; border-radius:20px; background:#161616; border:1px solid rgba(255,255,255,.09); padding:16px; box-sizing:border-box;">
<div class="c-optlabel">TYP</div>
<div class="pill-row" style="margin:0 0 16px;" id="typeRow"></div>
<div class="c-optlabel">FORMAT</div>
<div class="pill-row" style="margin:0 0 16px;" id="formatRow"></div>
<div class="c-optlabel">KETTE</div>
<div class="pill-row" style="margin:0;" id="countRow"></div>
</div>
</div>
<label style="margin:22px 0 8px;">Dein Modell</label>
<div class="chiprow" id="createModels"></div>
<label style="margin:20px 0 8px;">Prompt</label>
<div data-beam="bb" data-active="true" style="border-radius:24px;">
<div style="border-radius:24px; background:#171717; border:1px solid rgba(255,255,255,.05); box-shadow:0 12px 34px rgba(0,0,0,.4);">
<textarea id="createPrompt" inputmode="none" placeholder="Beschreibe deinen Post … z.B. Sneaker auf Betonboden, goldenes Abendlicht" style="display:block; width:100%; box-sizing:border-box; height:104px; resize:none; border:none; border-radius:23px; background:transparent; color:#fff; font-size:13.5px; line-height:1.55; padding:16px 18px; outline:none;"></textarea>
</div>
<div data-beam-bloom="true"></div>
</div>
<div class="lm-btn" id="generateBtn" role="button" style="margin-top:22px;">
<div class="lm-shader lm-bg deg120"></div>
<div class="lm-core"></div>
<div class="lm-label"><svg width="15" height="15" viewBox="0 0 24 24" fill="#9a9a9a" style="filter:drop-shadow(0 1px 2px rgba(0,0,0,.5))"><path d="M12 2 L14.4 9.6 L22 12 L14.4 14.4 L12 22 L9.6 14.4 L2 12 L9.6 9.6 Z"/></svg><span id="generateLabel">Post generieren</span></div>
</div>
<h3 style="margin-top:28px;">Mehr erstellen</h3>
<div class="card click" onclick="go('tut1')">
<div class="cardrow">
<div class="ico rose"><svg class="ic"><use href="#i-film"/></svg></div>
<div class="body"><h4 class="t-sm">Szene (Video)</h4><p>Video aus Prompt mit Script-Bestätigung mehrere KI-Modelle parallel.</p></div>
<svg class="ic chev"><use href="#i-chev"/></svg>
</div>
</div>
<div class="card click" onclick="go('model-create')">
<div class="cardrow">
<div class="ico orange"><svg class="ic"><use href="#i-user"/></svg></div>
<div class="body"><h4 class="t-sm">Modell</h4><p>Person oder Produkt als festes Brand-Asset bleibt in jedem Video 1:1 gleich.</p></div>
<svg class="ic chev"><use href="#i-chev"/></svg>
</div>
</div>
</div><!-- /c-scroll -->
<!-- Fake-Tastatur (Prototyp): erscheint beim Fokus aufs Prompt-Feld -->
<div class="kb" id="kbOverlay">
<div style="display:flex; align-items:center; gap:8px; padding:10px 12px; background:rgba(24,24,24,.96); border-top:1px solid rgba(255,255,255,.08);">
<div style="display:flex; gap:8px; overflow-x:auto; flex:1; scrollbar-width:none;" id="kbModels"></div>
<div id="kbDone" style="flex:none; padding:8px 14px; border-radius:100px; background:rgba(255,255,255,.14); font-size:12px; font-weight:700; cursor:pointer;">Fertig</div>
</div>
<div style="padding:8px 4px 24px; background:rgba(30,30,32,.98); backdrop-filter:blur(20px); -webkit-backdrop-filter:blur(20px);" id="kbKeys"></div>
</div>
</div>
<!-- ============ PROFIL / MENSCHLEIN (neu, enthält Knowledge Base) ============ -->
<div class="screen" id="profile">
<div class="p-hero">
<div class="av">V</div>
<h2>Velvet Rouge</h2>
<p>Brand-Profil · seit 2021 · mutig, clean, luxuriös</p>
</div>
<div class="row" style="margin-top:14px;">
<div class="card metric"><p>Videos</p><h4>31</h4></div>
<div class="card metric"><p>Vote-Match</p><h4 class="g">78 %</h4></div>
<div class="card metric"><p>Follower</p><h4 class="g">+218</h4></div>
</div>
<div class="card click" onclick="go('improve-select')">
<div class="cardrow">
<div class="ico amber"><svg class="ic"><use href="#i-spark"/></svg></div>
<div class="body"><h4 class="t-sm">Asset verbessern</h4><p>Gesicht, Produkt oder Szene weiterentwickeln jederzeit.</p></div>
<svg class="ic chev"><use href="#i-chev"/></svg>
</div>
</div>
<div class="card click" onclick="go('scene-results')">
<div class="cardrow">
<div class="ico zinc"><svg class="ic"><use href="#i-film"/></svg></div>
<div class="body"><h4 class="t-sm">Zuletzt: „Roter Lippenstift Close-up"</h4><p>3 Videos generiert · Vote offen</p></div>
<svg class="ic chev"><use href="#i-chev"/></svg>
</div>
</div>
<h3>Knowledge Base · Feste Regeln <span style="text-transform:none; letter-spacing:0; color:var(--faint); font-weight:500;">(kein Score, gelten immer)</span></h3>
<div class="card">
<div class="rule"><svg class="ic"><use href="#i-check"/></svg><p style="color:var(--txt);">Cleaner Hintergrund</p></div>
<div class="rule"><svg class="ic"><use href="#i-check"/></svg><p style="color:var(--txt);">Nur zeigen, was verlangt ist</p></div>
<div class="rule"><svg class="ic"><use href="#i-check"/></svg><p style="color:var(--txt);">Logo nie verzerren</p></div>
</div>
<h3>Assets (freigegebene Versionen)</h3>
<div class="card">
<div class="asset"><svg class="ic"><use href="#i-user"/></svg><span>Mara <span class="badge b-ok">v4</span></span><span class="score">6120</span></div>
<div class="asset"><svg class="ic"><use href="#i-box"/></svg><span>Rouge No. 5 <span class="badge b-ok">v2</span></span><span class="score">6480</span></div>
</div>
<h3>Attribute (Elo 010.000)</h3>
<div class="card click" onclick="go('kb-detail')">
<div class="cardrow">
<div class="ico rose"><svg class="ic"><use href="#i-pin"/></svg></div>
<div class="body"><h4 class="t-sm">Location: Kaiserslautern <span class="score">5240 ▲</span></h4><p>12 Videos · 8 Siege · Unter-Attribut: Stadion <span class="score">5560</span></p></div>
<svg class="ic chev"><use href="#i-chev"/></svg>
</div>
</div>
<div class="card">
<div class="cardrow">
<div class="ico zinc"><svg class="ic"><use href="#i-pin"/></svg></div>
<div class="body"><h4 class="t-sm">Location: Köln <span class="score" style="color:var(--faint);">4980 ▼</span> <span class="badge b-arch">ARCHIVIERT</span></h4><p>Historie bleibt erhalten ein schlechter Score ist auch Wissen.</p></div>
</div>
</div>
<div class="card">
<div class="asset"><svg class="ic"><use href="#i-bulb"/></svg><span>Licht: warmes Abendlicht</span><span class="score">6350 ▲</span></div>
<div class="asset"><svg class="ic"><use href="#i-mic"/></svg><span>Voice: warm-weiblich</span><span class="score">5890</span></div>
</div>
<h3>Log (letzte Einträge)</h3>
<div class="log">19.07. · Vote „Verbessern Mara v4": warmes Abendlicht +14 (K hoch), Studio-Look 14</div>
<div class="log">18.07. · Ad-Performance Video #31: Kaiserslautern +22, Close-up +22 <b style="color:#fb923c;">(Performance zählt 2×)</b></div>
<div class="log">17.07. · Gezielte Frage: „Kaiserslautern besser als Köln" → K'lautern +10, Köln 10</div>
<div class="log">17.07. · LLM-Vergleich K'lautern vs. Köln: „Stadion war der Unterschied" → neues Unter-Attribut Stadion (Start: Ø 5480)</div>
</div>
<!-- ============ KB DETAIL ============ -->
<div class="screen" id="kb-detail">
<div class="topbar"><button class="backpill" onclick="go('profile')"><span class="ar"></span> Zurück</button><h1>Kaiserslautern</h1></div>
<div class="card">
<h4>Score: <span class="score">5240</span> · 12 Videos · 8 Siege</h4>
<p style="margin-top:10px;"><span class="hl">Was diese Location ausmacht:</span><br>Urban, aber nahbar; Stadion als Wiedererkennungspunkt. Warmes Abendlicht funktioniert besser als Tageslicht.</p>
<p style="margin-top:10px;"><span class="hl">Gelernt aus Vergleichen:</span><br>vs. Köln (12.07.): Stadion-Hintergrund war der Unterschied → Stadion als eigenes Unter-Attribut angelegt.</p>
</div>
<h3>Score-Verlauf</h3>
<div class="log">Start 5000 → 5090 (Votes) → 5180 (Ad-Performance) → 5240 (heute)</div>
<div class="note">Vollständige Historie pro Attribut: jeder Vote mit Datum, Vergleichspartner, Punktänderung und Grund. Ablesbar, was besser und was schlechter geworden ist.</div>
</div>
<!-- ============ TUTORIAL 1 (Fullscreen) ============ -->
<div class="screen" id="tut1">
<div class="tut">
<div class="emoji">👋</div>
<h1>Bevor's losgeht</h1>
<p class="sub">Damit deine Videos nach <span class="hl">deiner Brand</span> aussehen, stellen wir dir einmalig 5 kurze Fragen.<br><br>Danach nie wieder ab dann lernt die App von selbst, mit jedem Video.</p>
<button class="btn" onclick="go('onboarding1')">Los geht's</button>
<button class="btn sec" onclick="go('create')">Zurück</button>
</div>
</div>
<!-- ============ ONBOARDING 1 ============ -->
<div class="screen" id="onboarding1">
<div class="topbar"><button class="backpill" onclick="go('tut1')"><span class="ar"></span> Zurück</button><h1>Dein Unternehmen</h1></div>
<div class="steps"><div class="on"></div><div></div></div>
<label>Labelname <span class="req">*</span></label>
<input type="text" placeholder="z. B. VELVET ROUGE Cosmetics">
<label>Was verkaufst du? <span class="req">*</span></label>
<input type="text" placeholder="z. B. vegane Lippenstifte & Lipgloss">
<label>Wen willst du erreichen? <span class="req">*</span></label>
<input type="text" placeholder="z. B. Frauen 1835, TikTok & Instagram">
<label>3 Worte, die deine Brand beschreiben <span class="req">*</span></label>
<input type="text" placeholder="z. B. mutig, clean, luxuriös">
<label>Wie lange seid ihr schon auf dem Markt? <span class="req">*</span></label>
<input type="text" placeholder="z. B. seit 2021">
<button class="btn" onclick="go('tut2')">Weiter</button>
</div>
<!-- ============ TUTORIAL 2 (Fullscreen) ============ -->
<div class="screen" id="tut2">
<div class="tut">
<div class="emoji">📸</div>
<h1>Zeig uns deine Brand</h1>
<p class="sub">Logo, Produktbilder, deine besten bisherigen Ads alles optional.<br><br>Aber: Je mehr du hochlädst, desto besser sieht schon dein <span class="hl">allererstes Video</span> aus.</p>
<button class="btn" onclick="go('onboarding2')">Weiter</button>
</div>
</div>
<!-- ============ ONBOARDING 2 ============ -->
<div class="screen" id="onboarding2">
<div class="topbar"><button class="backpill" onclick="go('tut2')"><span class="ar"></span> Zurück</button><h1>Uploads</h1></div>
<div class="steps"><div class="on"></div><div class="on"></div></div>
<p class="sub" style="margin-bottom:12px;">Optional, aber empfohlen füttert deine Knowledge Base von Tag 1.</p>
<div class="ph"><svg class="ic"><use href="#i-up"/></svg><span>[Upload: Logo]</span></div>
<div class="ph"><svg class="ic"><use href="#i-up"/></svg><span>[Upload: Produktbilder z. B. Lippenstift „Rouge No. 5" aus 3 Winkeln]</span></div>
<div class="ph"><svg class="ic"><use href="#i-up"/></svg><span>[Upload: Deine bisher besten Ads (Video/Bild) das System lernt daraus deine Startattribute]</span></div>
<button class="btn" onclick="go('scene-create')">Profil speichern → Erste Szene</button>
<button class="btn sec" onclick="go('scene-create')">Überspringen</button>
</div>
<!-- ============ SZENE ERSTELLEN ============ -->
<div class="screen" id="scene-create">
<div class="topbar"><button class="backpill" onclick="go('create')"><span class="ar"></span> Zurück</button><h1>Szene erstellen</h1></div>
<label>Dein Prompt</label>
<textarea>Eine Frau hält einen roten Lippenstift in die Kamera.</textarea>
<h3>Anzahl Videos</h3>
<div class="pill-row">
<div class="pill" onclick="pick(this)">3</div>
<div class="pill on" onclick="pick(this)">4</div>
<div class="pill" onclick="pick(this)">5</div>
<div class="pill" onclick="pick(this)">6</div>
</div>
<div class="note">Jedes Video von einem anderen Top-KI-Modell. Mehr Videos = mehr Vergleichssignal, Preis pro Video.</div>
<h3>Automatisch eingebaut (Brand Knowledge)</h3>
<div class="card">
<span class="tag">Regel: cleaner Hintergrund</span>
<span class="tag">Gesicht: „Mara" v3 <span class="score">6120</span></span>
<span class="tag">Produkt: Rouge No. 5 v2 <span class="score">6480</span></span>
<span class="tag">Location: Kaiserslautern <span class="score">5240</span></span>
<span class="tag">Voice: warm-weiblich <span class="score">5890</span></span>
<p style="margin-top:10px;">Dein Prompt wird automatisch überarbeitet und mit den Top-Attributen &amp; freigegebenen Assets angereichert.</p>
</div>
<button class="btn" onclick="go('script-confirm')">Weiter → Script</button>
</div>
<!-- ============ SCRIPT BESTÄTIGEN ============ -->
<div class="screen" id="script-confirm">
<div class="topbar"><button class="backpill" onclick="go('scene-create')"><span class="ar"></span> Zurück</button><h1>Dein Script</h1></div>
<p class="sub" style="margin-bottom:10px;">Aus deinem Prompt + Brand Knowledge erstellt. Lies es, ändere was du willst generiert wird erst nach deiner Bestätigung.</p>
<textarea style="min-height:250px; font-size:13px; line-height:1.6;">SZENE: „Roter Lippenstift Close-up"
SETTING: Kaiserslautern, Abendlicht (golden hour), cleaner unscharfer Hintergrund
PERSON: Mara (v3, freigegeben) dunkle schulterlange Haare, nahbar-edel
ABLAUF:
1. Close-up: Maras Hand hebt Rouge No. 5 (v2) frontal in die Kamera
2. Schnitt auf Gesicht: natürliches Lächeln, Blick in die Linse
3. Produkt dreht sich langsam, Logo sichtbar (nie verzerrt)
VOICE (warm-weiblich): „Dein Rot. Dein Statement."
TEXT-OVERLAY: keins (Brand-Stil: clean)</textarea>
<div class="note">Erst nach Bestätigung werden die Videos generiert Kosten entstehen erst dann. Änderungen am Script fließen als Signal in die Knowledge Base.</div>
<button class="btn" onclick="go('scene-results')"><svg class="ic"><use href="#i-check"/></svg>Bestätigen &amp; 4 Videos generieren</button>
<button class="btn sec" onclick="go('script-confirm')"><svg class="ic"><use href="#i-refresh"/></svg>Script neu schreiben lassen</button>
</div>
<!-- ============ SZENE ERGEBNISSE ============ -->
<div class="screen" id="scene-results">
<div class="topbar"><button class="backpill" onclick="go('scene-create')"><span class="ar"></span> Zurück</button><h1>Wähle das Beste</h1></div>
<p class="sub" style="margin-bottom:16px;">Tippe auf dein Favoriten-Video. Die goldene Umrandung ist die System-Vorhersage.</p>
<div class="card click fav" onclick="go('scene-vote')">
<span class="favlabel">SYSTEM-FAVORIT</span>
<h4 class="t-sm">Video 1 · Modell A</h4>
<div class="ph"><svg class="ic"><use href="#i-play"/></svg><span>[VIDEO: Mara (Gesicht v3) hält Rouge No. 5 frontal in die Kamera, Close-up, warmes Abendlicht, Kaiserslautern-Kulisse unscharf im Hintergrund, warme weibliche Stimme: „Dein Rot. Dein Statement."]</span></div>
<span class="tag">warm-rot</span><span class="tag">Close-up</span><span class="tag">Kaiserslautern</span>
</div>
<div class="card click" onclick="go('scene-vote')">
<h4 class="t-sm">Video 2 · Modell B</h4>
<div class="ph"><svg class="ic"><use href="#i-play"/></svg><span>[VIDEO: Gleiche Szene, aber kühles Studiolicht, langsamer Schwenk von der Hand zum Gesicht, Text-Overlay statt Stimme]</span></div>
<span class="tag">Studio</span><span class="tag">Schwenk</span><span class="tag">Text-Overlay</span>
</div>
<div class="card click" onclick="go('scene-vote')">
<h4 class="t-sm">Video 3 · Modell C</h4>
<div class="ph"><svg class="ic"><use href="#i-play"/></svg><span>[VIDEO: Outdoor Köln, Mara läuft auf Kamera zu, hält Lippenstift hoch, Upbeat-Musik, schnelle Schnitte]</span></div>
<span class="tag">Köln</span><span class="tag">Bewegung</span><span class="tag">Upbeat</span>
</div>
<div class="card click" onclick="go('scene-vote')">
<h4 class="t-sm">Video 4 · Modell D</h4>
<div class="ph"><svg class="ic"><use href="#i-play"/></svg><span>[VIDEO: Extreme Makro-Aufnahme nur vom Lippenstift, der sich dreht, ASMR-Sound beim Öffnen]</span></div>
<span class="tag">Makro</span><span class="tag">ASMR</span><span class="tag">ohne Gesicht</span>
</div>
<div class="note">Bestätigst du den markierten Favoriten → wenig Elo-Punkte. Weichst du ab → volle Punkte (stärkeres Signal).</div>
</div>
<!-- ============ VOTE + GEZIELTE FRAGE ============ -->
<div class="screen" id="scene-vote">
<div class="topbar"><button class="backpill" onclick="go('scene-results')"><span class="ar"></span> Zurück</button><h1>Danke!</h1></div>
<div class="card" style="border-color:rgba(52,211,153,.4);">
<h4><span class="badge b-ok">GESPEICHERT</span></h4>
<p style="margin-top:8px;">Dein Vote fließt in die Knowledge Base. Übereinstimmung mit System-Vorhersage: <span class="hl">78 %</span> (letzte 30 Votes).</p>
</div>
<h3>Kurze Frage (optional)</h3>
<div class="card">
<p style="color:var(--txt); font-size:14px; margin-bottom:8px;">Welche Location war besser?</p>
<div class="pill-row">
<div class="pill" onclick="pick(this)">Kaiserslautern</div>
<div class="pill" onclick="pick(this)">Köln</div>
<div class="pill" onclick="pick(this)">Egal</div>
</div>
<div class="note">Gezielte Fragen wirken nur auf dieses eine Attribut das schnellste Signal gegen das Zuordnungsproblem.</div>
</div>
<h3>Video verwenden</h3>
<button class="btn" onclick="go('publish')"><svg class="ic"><use href="#i-up"/></svg>Hochladen / Ad schalten</button>
<button class="btn sec" onclick="go('improve-select')"><svg class="ic"><use href="#i-spark"/></svg>Erst noch verbessern</button>
</div>
<!-- ============ PUBLISH / PERFORMANCE ============ -->
<div class="screen" id="publish">
<div class="topbar"><button class="backpill" onclick="go('scene-vote')"><span class="ar"></span> Zurück</button><h1>Ad läuft</h1></div>
<div class="card">
<h4 class="t-sm">„Roter Lippenstift Close-up" · Video 1</h4>
<div class="ph"><svg class="ic"><use href="#i-play"/></svg><span>[Gewähltes Video veröffentlicht auf TikTok &amp; Instagram via Ads-API]</span></div>
</div>
<h3>Live-Performance (Meta / TikTok API)</h3>
<div class="row">
<div class="card metric"><p>CTR</p><h4 class="g">2,4 %</h4></div>
<div class="card metric"><p>Thumbstop</p><h4 class="g">41 %</h4></div>
<div class="card metric"><p>ROAS</p><h4 class="g">3,1×</h4></div>
</div>
<div class="card">
<p><span class="hl">+218</span> neue Follower seit Schaltung</p>
</div>
<div class="note">Performance-Daten fließen automatisch und höher gewichtet als Votes in die Scores der Markt entscheidet, keine Bestätigung nötig. Jedes Video loggt, welche Asset-Versionen es nutzte.</div>
<button class="btn sec" onclick="go('profile')">→ Was hat das System gelernt?</button>
</div>
<!-- ============ MODELL ERSTELLEN ============ -->
<div class="screen" id="model-create">
<div class="topbar"><button class="backpill" onclick="go('create')"><span class="ar"></span> Zurück</button><h1>Modell erstellen</h1></div>
<div class="pill-row">
<div class="pill on" onclick="pick(this)">Person</div>
<div class="pill" onclick="pick(this)">Produkt</div>
</div>
<label style="margin-top:14px;">Beschreibe deine Person</label>
<textarea>Frau, Ende 20, dunkle schulterlange Haare, natürliches Lächeln, nahbar aber edel passt zu „mutig, clean, luxuriös".</textarea>
<label>Referenzbilder</label>
<div class="ph"><svg class="ic"><use href="#i-up"/></svg><span>[Upload: 310 Referenzbilder der gewünschten Person / des Looks]</span></div>
<div class="note">Rechte-Regel: Gesichter echter Personen nur mit dokumentierter Einwilligung. Rein KI-generierte Gesichter sind der sichere Standard.</div>
<button class="btn" onclick="go('model-result')">Modell generieren</button>
</div>
<!-- ============ MODELL ERGEBNIS ============ -->
<div class="screen" id="model-result">
<div class="topbar"><button class="backpill" onclick="go('model-create')"><span class="ar"></span> Zurück</button><h1>Dein Modell</h1></div>
<div class="card">
<h4>„Mara" <span class="badge b-new">v1 · ENTWURF</span></h4>
<div class="ph"><svg class="ic"><use href="#i-img"/></svg><span>[BILD: Generierte Frau, Ende 20, dunkle schulterlange Haare, natürliches Lächeln, cleaner Studiohintergrund aus 4 Blickwinkeln]</span></div>
<span class="tag">Ende 20</span><span class="tag">dunkle Haare</span><span class="tag">nahbar-edel</span>
</div>
<button class="btn" onclick="go('profile')"><svg class="ic"><use href="#i-check"/></svg>Freigeben (Release v1)</button>
<button class="btn sec" onclick="go('improve-input')"><svg class="ic"><use href="#i-spark"/></svg>Verbessern sieht noch nicht gut aus</button>
<div class="note">Nur <span class="hl">freigegebene</span> Versionen werden in Videos verwendet. Verbessern erzeugt neue Versionen (v2, v3 …) ein neues Gesicht ist ein bewusster Release, kein schleichender Drift.</div>
</div>
<!-- ============ VERBESSERN: ASSET WÄHLEN ============ -->
<div class="screen" id="improve-select">
<div class="topbar"><button class="backpill" onclick="go('profile')"><span class="ar"></span> Zurück</button><h1>Verbessern</h1></div>
<p class="sub" style="margin-bottom:16px;">Wähle das Asset, das du weiterentwickeln willst.</p>
<div class="card click" onclick="go('improve-input')">
<div class="cardrow">
<div class="ico rose"><svg class="ic"><use href="#i-user"/></svg></div>
<div class="body"><h4 class="t-sm">Gesicht „Mara" <span class="badge b-ok">v3 · FREIGEGEBEN</span></h4><p>Verwendet in 12 Videos · Score <span class="score">6120</span></p></div>
<svg class="ic chev"><use href="#i-chev"/></svg>
</div>
</div>
<div class="card click" onclick="go('improve-input')">
<div class="cardrow">
<div class="ico orange"><svg class="ic"><use href="#i-box"/></svg></div>
<div class="body"><h4 class="t-sm">Produkt „Rouge No. 5" <span class="badge b-ok">v2 · FREIGEGEBEN</span></h4><p>Verwendet in 18 Videos · Score <span class="score">6480</span></p></div>
<svg class="ic chev"><use href="#i-chev"/></svg>
</div>
</div>
<div class="card click" onclick="go('improve-input')">
<div class="cardrow">
<div class="ico zinc"><svg class="ic"><use href="#i-film"/></svg></div>
<div class="body"><h4 class="t-sm">Szene „Lippenstift Close-up"</h4><p>Video-Iteration: Licht, Schnitt, Tempo anpassen</p></div>
<svg class="ic chev"><use href="#i-chev"/></svg>
</div>
</div>
</div>
<!-- ============ VERBESSERN: EINGABE ============ -->
<div class="screen" id="improve-input">
<div class="topbar"><button class="backpill" onclick="go('improve-select')"><span class="ar"></span> Zurück</button><h1>„Mara" verbessern</h1></div>
<div class="pill-row">
<div class="pill on" onclick="pick(this)">Text-Feedback</div>
<div class="pill" onclick="pick(this)">Referenz hochladen</div>
</div>
<label style="margin-top:14px;">Was soll besser werden?</label>
<textarea>Haare etwas dunkler, Ausstrahlung natürlicher, weniger Studio-Look.</textarea>
<div class="card" style="border-style:dashed;">
<p style="margin-bottom:8px;"><span class="hl">Bei Referenz-Upload:</span></p>
<div class="ph"><svg class="ic"><use href="#i-up"/></svg><span>[Upload: Referenzbild]</span></div>
<label>Was übernehmen? <span class="req">* Pflichtfeld</span></label>
<input type="text" placeholder="z. B. nur die Frisur und der Hautton nicht das Gesicht" style="margin-bottom:0;">
<div class="note">Ohne Beschreibung rät das System, was gemeint ist, und kopiert das Falsche. Aus fremden Referenzen wird gelernt, nie 1:1 kopiert.</div>
</div>
<button class="btn" onclick="go('improve-results')">Neue Versionen generieren</button>
</div>
<!-- ============ VERBESSERN: VORHER/NACHHER ============ -->
<div class="screen" id="improve-results">
<div class="topbar"><button class="backpill" onclick="go('improve-input')"><span class="ar"></span> Zurück</button><h1>Vorher / Nachher</h1></div>
<h3>Vorher (v3 aktuell freigegeben)</h3>
<div class="ph"><svg class="ic"><use href="#i-img"/></svg><span>[BILD: Mara v3 schulterlange dunkle Haare, Studio-Look]</span></div>
<h3>Wähle die neue Version</h3>
<p class="sub" style="margin-bottom:12px;">Jede Version zieht andere Vorlieben aus deiner Knowledge Base.</p>
<div class="card click" onclick="go('improve-vote')">
<h4 class="t-sm">Version A</h4>
<div class="ph"><svg class="ic"><use href="#i-img"/></svg><span>[BILD: Haare fast schwarz, Tageslicht statt Studio, dezentes Lächeln]</span></div>
<span class="tag">Tageslicht <span class="score">5210</span></span><span class="tag">dezent</span>
</div>
<div class="card click" onclick="go('improve-vote')">
<h4 class="t-sm">Version B</h4>
<div class="ph"><svg class="ic"><use href="#i-img"/></svg><span>[BILD: Dunkelbraune Haare, warmes Abendlicht (Top-Attribut!), offenes Lachen]</span></div>
<span class="tag">warmes Abendlicht <span class="score">6350</span></span><span class="tag">offen</span>
</div>
<div class="card click" onclick="go('improve-vote')">
<h4 class="t-sm">Version C</h4>
<div class="ph"><svg class="ic"><use href="#i-img"/></svg><span>[BILD: Wie v3, aber Outdoor-Hintergrund unscharf, natürlichere Haut-Textur]</span></div>
<span class="tag">Outdoor <span class="score">5580</span></span><span class="tag">natürliche Haut <span class="badge b-new">NEU · Start 5720 (Ø Kategorie)</span></span>
</div>
<div class="note">Gewinner-Merkmale steigen in der Elo gegenüber der ersetzten Version aber nur Merkmale, in denen sich die Versionen <span class="hl">unterscheiden</span>. Neue Merkmale starten beim Kategorie-Durchschnitt (nicht bei 5000) mit hohem K-Faktor.</div>
</div>
<!-- ============ VERBESSERN: VOTE ============ -->
<div class="screen" id="improve-vote">
<div class="topbar"><button class="backpill" onclick="go('improve-results')"><span class="ar"></span> Zurück</button><h1>Version gewählt</h1></div>
<div class="card" style="border-color:rgba(52,211,153,.4);">
<h4><span class="badge b-ok">MARA v4 ERSTELLT</span></h4>
<p style="margin-top:8px;">Versionskette geloggt: v3 → v4 · Grund: „Haare dunkler, natürlicher" · Gewinner: Version B</p>
<p style="margin-top:6px;">Elo-Update: <b style="color:var(--gold);">warmes Abendlicht +14</b> · Studio-Look 14</p>
</div>
<button class="btn" onclick="go('profile')"><svg class="ic"><use href="#i-check"/></svg>v4 freigeben (ab jetzt in Videos)</button>
<button class="btn sec" onclick="go('improve-input')"><svg class="ic"><use href="#i-spark"/></svg>Weiter verbessern (v5)</button>
<div class="note">Bis zur Freigabe nutzen alle Videos weiterhin v3 Wiedererkennung bleibt erhalten, und es bleibt messbar, welche Version performt.</div>
</div>
<!-- ============ DEVELOPER-MODUS ============ -->
<div class="screen" id="devmode">
<div class="topbar"><button class="backpill" onclick="go('explore')"><span class="ar"></span> Zurück</button><h1>Developer-Modus</h1></div>
<div class="card" style="border-color:rgba(255,92,57,.4);">
<div class="cardrow">
<div class="ico orange"><svg class="ic"><use href="#i-lock"/></svg></div>
<div class="body"><p><b style="color:var(--accent);">Nur intern.</b> Dieser Bereich ist für Nutzer unsichtbar hier liegt das Feintuning, das die App ausmacht. Im Prototyp zur Präsentation sichtbar geschaltet.</p></div>
</div>
</div>
<h3>Feste Regeln (Prompt-Injection, jede Generierung)</h3>
<div class="card">
<div class="rule"><svg class="ic"><use href="#i-check"/></svg><p style="color:var(--txt);">Cleaner, neutraler Hintergrund</p></div>
<div class="rule"><svg class="ic"><use href="#i-check"/></svg><p style="color:var(--txt);">Nur zeigen, was verlangt ist nicht mehr, nicht weniger</p></div>
<div class="rule"><svg class="ic"><use href="#i-check"/></svg><p style="color:var(--txt);">Logo nie verzerren oder umfärben</p></div>
<div class="rule"><svg class="ic"><use href="#i-check"/></svg><p style="color:var(--txt);">Aus fremden Referenzen lernen, nie 1:1 kopieren</p></div>
</div>
<input type="text" placeholder="+ Regel hinzufügen …">
<div class="note" style="margin-top:0;">Regeln nehmen nicht am Scoring teil und können nicht absteigen. Der Nutzer sieht und verwaltet sie nicht sie sind Teil des Produkts.</div>
<h3>Prompt-Einblick (letzte Generierung)</h3>
<div class="code">[SYSTEM] Regeln: cleaner Hintergrund; nur Verlangtes zeigen; Logo unverändert …<br>[ASSETS] Gesicht: Mara v3 (ref_0231) · Produkt: Rouge No. 5 v2 (ref_0198)<br>[ATTRIBUTE] Location: Kaiserslautern (5240) · Licht: warmes Abendlicht (6350) · Voice: warm-weiblich (5890)<br>[SCRIPT] Close-up: Hand hebt Lippenstift frontal … Voice: „Dein Rot. Dein Statement."<br><b>[USER-PROMPT]</b> Eine Frau hält einen roten Lippenstift in die Kamera.</div>
<h3>Elo-Parameter</h3>
<div class="row">
<div class="card metric"><p>K-Faktor neu</p><h4>32</h4></div>
<div class="card metric"><p>K-Faktor etabliert</p><h4>8</h4></div>
</div>
<div class="row">
<div class="card metric"><p>Performance : Vote</p><h4>2 : 1</h4></div>
<div class="card metric"><p>Favorit bestätigt</p><h4>× 0,3</h4></div>
</div>
<div class="card"><p>Startwert neuer Einträge: <span class="hl">Kategorie-Durchschnitt</span> (Fallback 5000, wenn Kategorie leer)</p></div>
</div>
</div>
<!-- ============ NAVIGATION (neu: Feed · Profil · Plus · Dev) ============ -->
<nav class="nav" id="navBar">
<div class="nav-glass blur"></div>
<div class="nav-glass refract"></div>
<div class="nav-glass white"></div>
<div class="nav-glass ring"></div>
<button id="n-feed" class="on" onclick="go('explore')"><svg class="ic"><use href="#i-home"/></svg><span>Feed</span></button>
<button id="n-profile" onclick="go('profile')"><svg class="ic"><use href="#i-user"/></svg><span>Profil</span></button>
<button id="n-create" class="plus" onclick="go('create')" aria-label="Neuer KI-Post">
<div class="lm-shader lm-bg"></div>
<div class="lm-core"></div>
<div class="lm-ic"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#9a9a9a" stroke-width="2.4" stroke-linecap="round" style="filter:drop-shadow(0 1px 2px rgba(0,0,0,.5))"><path d="M12 5 V19 M5 12 H19"/></svg></div>
</button>
<button id="n-dev" onclick="go('devmode')" style="opacity:.55;" title="Nur intern sichtbar"><svg class="ic"><use href="#i-gear"/></svg><span>Dev</span></button>
</nav>
<!-- ============ INFO-SHEET (Präsentationsnotizen) ============ -->
<div class="backdrop" id="backdrop" onclick="toggleInfo(false)"></div>
<div class="sheet" id="infoSheet">
<div class="grab"></div>
<h2>BrandLoop Prototyp</h2>
<p><b>Textversion:</b> Alle Bilder &amp; Videos sind durch Beschreibungen / Dummy-Verläufe ersetzt. Alles ist klickbar, Karten sind swipebar.</p>
<p style="margin-bottom:6px;"><b>Neu (Explore-Konzept):</b></p>
<ul>
<li>Feed: swipen wie Tinder rechts = Like, links = Skip, Tippen blättert die Bild-Kette</li>
<li>Detail (↺-Button): Prompt übernehmen, eigenes Modell einsetzen → landet vorausgefüllt im Editor</li>
<li>Plus: neuer KI-Post mit Bild-Kette &amp; Format Szene- und Modell-Flow von dort erreichbar</li>
<li>Menschlein (Profil): Brand-Profil inkl. kompletter Knowledge Base &amp; Verbessern</li>
<li>Navbar verschlankt: Home → Profil, „Erstellen"/„Verbessern" raus, Knowledge im Profil</li>
</ul>
<p style="margin-bottom:0;"><b>Klickpfad zum Präsentieren:</b><br>Feed (swipen) → ↺ Detail → Nachmachen → Editor → Profil (Knowledge) → Verbessern → Dev-Modus</p>
</div>
<script>
/* ---------- Navigation ---------- */
function go(id){
document.querySelectorAll('.screen').forEach(s=>s.classList.remove('active'));
document.getElementById(id).classList.add('active');
var navMap={
explore:'n-feed',
profile:'n-profile','kb-detail':'n-profile','improve-select':'n-profile','improve-input':'n-profile','improve-results':'n-profile','improve-vote':'n-profile',
create:'n-create',detail:'n-create',tut1:'n-create',tut2:'n-create',onboarding1:'n-create',onboarding2:'n-create',
'scene-create':'n-create','script-confirm':'n-create','scene-results':'n-create','scene-vote':'n-create',publish:'n-create',
'model-create':'n-create','model-result':'n-create',
devmode:'n-dev'
};
document.querySelectorAll('.nav button').forEach(b=>b.classList.remove('on'));
if(navMap[id]) document.getElementById(navMap[id]).classList.add('on');
document.body.classList.toggle('noscroll', id==='explore'||id==='create');
if(id==='create') requestAnimationFrame(initCreateDither);
window.scrollTo(0,0);
}
function pick(el){
el.parentElement.querySelectorAll('.pill').forEach(p=>p.classList.remove('on'));
el.classList.add('on');
}
function toggleInfo(open){
document.getElementById('backdrop').classList.toggle('open',open);
document.getElementById('infoSheet').classList.toggle('open',open);
}
/* ---------- Explore-Feed (Swipe-Deck, portiert aus BrandLoop.dc.html) ---------- */
var ACCENT='#ff5c39';
var HUES={Produkt:40, Mensch:260, Szene:170};
var POSTS=[
{id:1, creator:'Lena M.', cat:'Produkt', model:'Sneaker Studio v2', video:true, h:250, imgs:['[ki-video: sneaker spot]'],
pics:['uploads/pasted-1784663207742-0.jpg']},
{id:2, creator:'Mara S.', cat:'Produkt', model:'Glow Serum v3', video:false, h:150, imgs:['Toner im Bogenfenster','Age Decoder Essence','Poster-Ad'],
pics:['uploads/pasted-1784643149542-0.jpg','uploads/pasted-1784643165286-0.jpg','uploads/pasted-1784643111353-0.jpg'],
avatar:'uploads/pasted-1784663200459-0.jpg'},
{id:3, creator:'Jonas K.', cat:'Mensch', model:'Coach Avatar', video:true, h:40, imgs:['[ki-video: gym coaching ad]'],
pics:['uploads/pasted-1784663200459-0.jpg']},
{id:4, creator:'Tom B.', cat:'Mensch', model:'Barber Ich v1', video:false, h:90, imgs:['[ki-bild 1/4: portrait]','[ki-bild 2/4: fade cut]','[ki-bild 3/4: shop szene]','[ki-bild 4/4: logo karte]'],
pics:['uploads/pasted-1784663261701-0.jpg','uploads/pasted-1784663207742-0.jpg','uploads/pasted-1784663200459-0.jpg','uploads/pasted-1784663233931-0.jpg']},
{id:5, creator:'Feld & Co',cat:'Szene', model:'Café Interieur', video:false, h:190, imgs:['[ki-bild 1/3: tresen]','[ki-bild 2/3: latte art]','[ki-bild 3/3: fassade]'],
pics:['uploads/pasted-1784663233931-0.jpg','uploads/pasted-1784663383522-0.jpg','uploads/pasted-1784663261701-0.jpg']},
{id:6, creator:'Nina R.', cat:'Produkt', model:'Schmuck Makro', video:false, h:310, imgs:['[ki-bild: ring makro]'],
pics:['uploads/pasted-1784663383522-0.jpg']},
{id:7, creator:'Kai W.', cat:'Szene', model:'Immo Walkthrough', video:true, h:210, imgs:['[ki-video: wohnungs-tour]'],
pics:['uploads/pasted-1784663233931-0.jpg']}
];
var X={tab:'posts', idx:0, dx:0, imgIdx:0, liked:[], anim:false, hoodCx:null, hoodHalf:null, hoodRaf:null, centers:null, halves:null};
var TAB_CENTERS={videos:40, folge:205, posts:366};
var TAB_HALVES={videos:40, folge:46, posts:35};
/* Bilder vorladen: nur geladene Dateien werden benutzt, sonst Dummy-Verlauf */
var PICS_OK={};
function pic(p,i){ var u=p.pics&&p.pics[i]; return (u&&PICS_OK[u])?u:null; }
function preloadPics(){
var all={};
POSTS.forEach(function(p){ (p.pics||[]).forEach(function(u){ all[u]=1; }); if(p.avatar) all[p.avatar]=1; });
Object.keys(all).forEach(function(u){
var im=new Image();
im.onload=function(){ PICS_OK[u]=true; renderDeck(); renderDetailStrip(); renderCreateStack(); };
im.src=u;
});
}
function dummy(h){
return 'linear-gradient(rgba(0,0,0,.12),rgba(0,0,0,.12)),'+
'repeating-linear-gradient(135deg,transparent 0 14px,rgba(255,255,255,.05) 14px 28px),'+
'linear-gradient(160deg,oklch(.62 .09 '+h+'),oklch(.34 .09 '+(h+40)+'))';
}
function deck(){
if(X.tab==='videos') return POSTS.filter(function(p){return p.video;});
if(X.tab==='folge') return POSTS.filter(function(p){return ['Mara S.','Kai W.','Lena M.'].indexOf(p.creator)>=0;});
return POSTS.filter(function(p){return !p.video;});
}
/* Hood-Kurve unter dem aktiven Tab (Geometrie 1:1 aus BrandLoop.dc.html):
pro Tab eigene Breite (nh = halbe Plateau-Breite), am Bildschirmrand
verschmilzt die Hood mit der Kante statt eine Schulter zu zeichnen */
function hoodPath(cx, nh){
var W=430, top=8, floor=76, r=40, sw=80, bt=.6, tt=.6, H=120;
var xl=cx-nh, xr=cx+nh, lStart=xl-sw, rEnd=xr+sw;
var rl=Math.max(8,Math.min(r,lStart-2)), rr=Math.max(8,Math.min(r,W-rEnd-2));
var d;
if(lStart<=24){
d='M0 '+H+' L0 '+Math.min(floor+r,H-4)+' Q0 '+floor+' '+Math.min(Math.max(xl,r),xr-10)+' '+floor+' ';
}else{
d='M0 '+H+' L0 '+(top+rl)+' Q0 '+top+' '+rl+' '+top+' ';
d+='L'+lStart+' '+top+' C'+(lStart+sw*tt)+' '+top+' '+(xl-sw*bt)+' '+floor+' '+xl+' '+floor+' ';
}
d+='L'+xr+' '+floor+' ';
if(rEnd>=W-24){
d+='L'+Math.max(Math.min(xr,W-r),xl+10)+' '+floor+' Q'+W+' '+floor+' '+W+' '+Math.min(floor+r,H-4)+' L'+W+' '+H+' Z';
}else{
d+='C'+(xr+sw*bt)+' '+floor+' '+(rEnd-sw*tt)+' '+top+' '+rEnd+' '+top+' ';
d+='L'+(W-rr)+' '+top+' Q'+W+' '+top+' '+W+' '+(top+rr)+' L'+W+' '+H+' Z';
}
return d;
}
function centerOf(k){ return (X.centers&&X.centers[k]!=null)?X.centers[k]:TAB_CENTERS[k]; }
function halfOf(k){ return (X.halves&&X.halves[k]!=null)?X.halves[k]:TAB_HALVES[k]; }
/* Tab-Positionen aus dem DOM messen (in 430er-viewBox-Koordinaten) */
function measureTabs(){
var cont=document.querySelector('.x-tabs');
if(!cont||!cont.offsetWidth) return;
var scale=430/cont.offsetWidth;
var els={};
['videos','folge','posts'].forEach(function(k){ els[k]=cont.querySelector('.x-tab[data-tab="'+k+'"]'); });
if(!els.videos||!els.folge||!els.posts) return;
function m(el){ return {L:el.offsetLeft*scale, R:(el.offsetLeft+el.offsetWidth)*scale}; }
var v=m(els.videos), f=m(els.folge), p=m(els.posts);
var sw=80, m1=(v.R+f.L)/2, m2=(f.R+p.L)/2;
var x={videos:[v.L-12, m1-sw/2], folge:[m1+sw/2, m2-sw/2], posts:[m2+sw/2, p.R+12]};
var c={}, h={};
for(var k in x){ c[k]=(x[k][0]+x[k][1])/2; h[k]=(x[k][1]-x[k][0])/2; }
X.centers=c; X.halves=h;
}
function setHood(cx,nh){
X.hoodCx=cx; X.hoodHalf=nh;
document.getElementById('xHoodPath').setAttribute('d',hoodPath(cx,nh));
}
function animateHood(target,targetHalf){
if(X.hoodRaf) cancelAnimationFrame(X.hoodRaf);
var from=(X.hoodCx==null)?centerOf(X.tab):X.hoodCx;
var fromH=(X.hoodHalf==null)?halfOf(X.tab):X.hoodHalf;
var t0=performance.now(), dur=460, c1=1.3;
function step(now){
var t=Math.min((now-t0)/dur,1);
var e=1+(c1+1)*Math.pow(t-1,3)+c1*Math.pow(t-1,2);
setHood(from+(target-from)*e, fromH+(targetHalf-fromH)*e);
if(t<1) X.hoodRaf=requestAnimationFrame(step);
}
X.hoodRaf=requestAnimationFrame(step);
}
function renderTabs(){
document.querySelectorAll('.x-tab').forEach(function(el){
el.classList.toggle('on', el.dataset.tab===X.tab);
});
}
function renderBlur(){
var d=deck(), top=d[X.idx];
var el=document.getElementById('xBlur');
if(!top){ el.style.background='var(--bg)'; return; }
var imgI=Math.min(X.imgIdx, top.imgs.length-1), u=pic(top,imgI);
el.style.background = u ? '#0a0a0a url("'+u+'") center / cover no-repeat' : dummy(top.h+imgI*25);
}
function esc(s){ return s.replace(/&/g,'&amp;').replace(/</g,'&lt;'); }
function cardTransform(depth){
return depth===0 ? 'translateX(0px) rotate(0deg)' : 'scale('+(1-depth*.06)+') translateY('+(-depth*34)+'px)';
}
/* settle=true: Karten starten eine Position tiefer und gleiten nach vorn
(Nachrueck-Animation aus dem Design nach Fling/Tab-Wechsel) */
function renderDeck(settle){
var host=document.getElementById('xDeck');
var d=deck();
renderBlur();
if(X.idx>=d.length){
host.innerHTML=
'<div class="x-empty">'+
'<div style="font-size:17px; font-weight:700;">Alles gesehen ✦</div>'+
'<div style="font-size:13px; color:rgba(255,255,255,.5);">Du hast '+X.liked.length+' Posts gemerkt</div>'+
'<div id="xReset" style="padding:11px 22px; border-radius:100px; background:#fff; color:#000; font-size:13px; font-weight:700; cursor:pointer;">Nochmal ansehen</div>'+
'</div>';
document.getElementById('xReset').onclick=function(){ X.idx=0; X.dx=0; X.imgIdx=0; renderDeck(); };
return;
}
var html='';
var slice=d.slice(X.idx, X.idx+4);
for(var i=slice.length-1; i>=0; i--){
var p=slice[i], top=(i===0);
var imgI=top?Math.min(X.imgIdx,p.imgs.length-1):0;
var u=pic(p,imgI);
var hue=p.h+imgI*25;
var depth=settle?i+1:i;
var tf=(top&&!settle)
? 'translateX('+X.dx+'px) rotate('+(X.dx/22)+'deg)'
: cardTransform(depth);
html+='<div class="x-card'+(top?' top':'')+'" data-i="'+i+'" style="z-index:'+(5-i)+'; transform:'+tf+'; transition:'+(settle?'none':'transform .45s cubic-bezier(.22,1,.36,1)')+'; cursor:'+(top?'grab':'default')+';">';
var bg=u ? '#141414 url(&quot;'+u+'&quot;) center / cover no-repeat' : dummy(hue);
html+='<div class="img" style="background:'+bg+';'+(top?'':' filter:brightness(.85);')+'"></div>';
if(top){
if(!u) html+='<div class="imglabel"><span>'+esc(p.imgs[imgI])+'</span></div>';
if(p.video){
html+='<div class="playwrap"><div class="play"><svg width="22" height="22" viewBox="0 0 24 24" fill="#fff"><path d="M8 5 L19 12 L8 19 Z"/></svg></div></div>';
}
html+='<div class="x-segs">';
for(var j=0;j<p.imgs.length;j++){
html+='<div style="background:'+(j<=imgI?'rgba(255,255,255,.9)':'rgba(255,255,255,.28)')+';"></div>';
}
html+='</div>';
html+='<div class="x-chips"><div>'+esc(p.cat)+'</div>'+(p.imgs.length>1?'<div>⧉ '+p.imgs.length+' Bilder</div>':'')+'</div>';
var avOk=p.avatar&&PICS_OK[p.avatar];
var avBg=avOk ? '#141414 url(&quot;'+p.avatar+'&quot;) 50% 16% / 300% no-repeat'
: 'linear-gradient(140deg,oklch(.72 .13 '+HUES[p.cat]+'),oklch(.5 .13 '+HUES[p.cat]+'))';
html+='<div class="x-meta">'+
'<div class="av" style="background:'+avBg+';">'+(avOk?'':esc(p.creator[0]))+'</div>'+
'<div style="min-width:0;"><div class="nm">'+esc(p.creator)+'</div><div class="md">Modell · '+esc(p.model)+'</div></div>'+
'</div>';
html+='<div class="x-badge like" id="xLikeBadge">LIKE</div><div class="x-badge skip" id="xSkipBadge">SKIP</div>';
}
html+='</div>';
}
host.innerHTML=html;
var topEl=host.querySelector('.x-card.top');
if(topEl) topEl.addEventListener('pointerdown', onDown);
if(settle){
requestAnimationFrame(function(){ requestAnimationFrame(function(){
host.querySelectorAll('.x-card').forEach(function(el){
el.style.transition='transform .45s cubic-bezier(.22,1,.36,1)';
el.style.transform=cardTransform(+el.dataset.i);
});
});});
}
}
function fling(dir){
if(X.anim) return;
var d=deck(), post=d[X.idx];
X.anim=true;
var topEl=document.querySelector('#xDeck .x-card.top');
if(topEl){
topEl.style.transition='transform .3s cubic-bezier(.4,0,.7,1), opacity .3s ease';
topEl.style.transform='translateX('+(dir*640)+'px) rotate('+(dir*640/22)+'deg)';
topEl.style.opacity='0';
}
setTimeout(function(){
if(dir>0 && post) X.liked.push(post.id);
X.idx++; X.dx=0; X.imgIdx=0; X.anim=false;
renderDeck(true);
},300);
}
function onDown(e){
if(X.anim) return;
e.preventDefault();
var sx=e.clientX, moved=false;
var topEl=e.currentTarget;
var likeB=document.getElementById('xLikeBadge'), skipB=document.getElementById('xSkipBadge');
function mv(ev){
var d=ev.clientX-sx;
if(Math.abs(d)>5) moved=true;
X.dx=d;
topEl.style.transition='none';
topEl.style.transform='translateX('+d+'px) rotate('+(d/22)+'deg)';
if(likeB) likeB.style.opacity=Math.min(Math.max(d,0)/90,1);
if(skipB) skipB.style.opacity=Math.min(Math.max(-d,0)/90,1);
}
function up(ev){
window.removeEventListener('pointermove',mv);
window.removeEventListener('pointerup',up);
var d=ev.clientX-sx;
if(Math.abs(d)>110){ fling(d>0?1:-1); return; }
X.dx=0;
topEl.style.transition='transform .45s cubic-bezier(.22,1,.36,1)';
topEl.style.transform='translateX(0) rotate(0)';
if(likeB) likeB.style.opacity=0;
if(skipB) skipB.style.opacity=0;
if(!moved){
var post=deck()[X.idx];
if(post && post.imgs.length>1){ X.imgIdx=(X.imgIdx+1)%post.imgs.length; renderDeck(); }
}
}
window.addEventListener('pointermove',mv);
window.addEventListener('pointerup',up);
}
document.querySelectorAll('.x-tab').forEach(function(el){
el.addEventListener('click',function(){
if(X.tab===el.dataset.tab) return;
var k=el.dataset.tab;
var deckEl=document.getElementById('xDeck'), blurEl=document.getElementById('xBlur');
animateHood(centerOf(k), halfOf(k));
deckEl.style.transition='opacity .18s ease';
deckEl.style.opacity='0'; blurEl.style.opacity='0';
setTimeout(function(){
X.tab=k; X.idx=0; X.dx=0; X.imgIdx=0;
renderTabs(); renderDeck(true);
deckEl.style.opacity='1'; blurEl.style.opacity='1';
},180);
});
});
window.addEventListener('resize',function(){
measureTabs(); setHood(centerOf(X.tab), halfOf(X.tab)); updateGlassMap();
});
document.getElementById('btnSkip').onclick=function(){ fling(-1); };
document.getElementById('btnLike').onclick=function(){ fling(1); };
document.getElementById('btnDetail').onclick=function(){ go('detail'); };
/* ---------- Detail: Bild-Strip (Maras Kette, echte Bilder mit Fallback) ---------- */
function renderDetailStrip(){
var host=document.getElementById('dStrip');
if(!host) return;
var p=POSTS[1];
var av=document.getElementById('dAvatar');
if(av && p.avatar && PICS_OK[p.avatar]){
av.style.background='#141414 url("'+p.avatar+'") 50% 16% / 300% no-repeat';
av.textContent='';
}
host.innerHTML=p.imgs.map(function(label,i){
var u=pic(p,i);
var bg=u ? '#141414 url(&quot;'+u+'&quot;) center / cover no-repeat' : dummy(150+i*25);
return '<div class="d-img" style="background:'+bg+';">'+
(u?'':'<span class="lbl">'+esc(label)+'</span>')+
'<span class="num">'+(i+1)+'/'+p.imgs.length+'</span></div>';
}).join('');
}
/* ---------- Detail: Modell wählen + Nachmachen ---------- */
var MODELS=['Mensch Ich (Avatar)','Produkt Kerze Studio','Szene Showroom'];
var D={model:1, remade:false};
function renderDetailModels(){
var host=document.getElementById('detailModels');
host.innerHTML=MODELS.map(function(m,i){
return '<div class="chip'+(i===D.model?' on':'')+'" data-i="'+i+'"><div class="dot"></div>'+m+'</div>';
}).join('');
host.querySelectorAll('.chip').forEach(function(c){
c.onclick=function(){ D.model=+c.dataset.i; D.remade=false; renderDetailModels(); };
});
document.getElementById('remakeLabel').textContent=
D.remade ? '✓ Übernommen — im Editor geöffnet' : 'Nachmachen mit „'+MODELS[D.model].split(' ')[1]+'“';
}
document.getElementById('remakeBtn').onclick=function(){
if(D.remade) return;
D.remade=true; renderDetailModels();
setTimeout(function(){
document.getElementById('createPrompt').value=document.getElementById('detailPrompt').textContent.trim();
C.model=D.model; renderCreateModels();
go('create');
D.remade=false; renderDetailModels();
},900);
};
/* ---------- Dithering-Shader (WebGL2-Port von designali-in/dithering-shader) ----------
Testweise auf den Modell-Chips im Create-Screen: Sphere/Random,
ausgewaehlt = weiss/silber, nicht ausgewaehlt = dunkelgrau. */
var DITHER_VERT='#version 300 es\nprecision mediump float;\nlayout(location = 0) in vec4 a_position;\nvoid main(){ gl_Position = a_position; }';
var DITHER_FRAG=[
'#version 300 es',
'precision mediump float;',
'uniform float u_time;',
'uniform vec2 u_resolution;',
'uniform vec4 u_colorBack;',
'uniform vec4 u_colorFront;',
'uniform float u_shape;',
'uniform float u_type;',
'uniform float u_pxSize;',
'out vec4 fragColor;',
'vec3 permute(vec3 x) { return mod(((x * 34.0) + 1.0) * x, 289.0); }',
'float snoise(vec2 v) {',
' const vec4 C = vec4(0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439);',
' vec2 i = floor(v + dot(v, C.yy));',
' vec2 x0 = v - i + dot(i, C.xx);',
' vec2 i1;',
' i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);',
' vec4 x12 = x0.xyxy + C.xxzz;',
' x12.xy -= i1;',
' i = mod(i, 289.0);',
' vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0));',
' vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), 0.0);',
' m = m * m;',
' m = m * m;',
' vec3 x = 2.0 * fract(p * C.www) - 1.0;',
' vec3 h = abs(x) - 0.5;',
' vec3 ox = floor(x + 0.5);',
' vec3 a0 = x - ox;',
' m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h);',
' vec3 g;',
' g.x = a0.x * x0.x + h.x * x0.y;',
' g.yz = a0.yz * x12.xz + h.yz * x12.yw;',
' return 130.0 * dot(m, g);',
'}',
'#define TWO_PI 6.28318530718',
'#define PI 3.14159265358979323846',
'float hash11(float p) {',
' p = fract(p * 0.3183099) + 0.1;',
' p *= p + 19.19;',
' return fract(p * p);',
'}',
'float hash21(vec2 p) {',
' p = fract(p * vec2(0.3183099, 0.3678794)) + 0.1;',
' p += dot(p, p + 19.19);',
' return fract(p.x * p.y);',
'}',
'float getSimplexNoise(vec2 uv, float t) {',
' float noise = .5 * snoise(uv - vec2(0., .3 * t));',
' noise += .5 * snoise(2. * uv + vec2(0., .32 * t));',
' return noise;',
'}',
'const int bayer2x2[4] = int[4](0, 2, 3, 1);',
'const int bayer4x4[16] = int[16](0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5);',
'const int bayer8x8[64] = int[64](0, 32, 8, 40, 2, 34, 10, 42, 48, 16, 56, 24, 50, 18, 58, 26, 12, 44, 4, 36, 14, 46, 6, 38, 60, 28, 52, 20, 62, 30, 54, 22, 3, 35, 11, 43, 1, 33, 9, 41, 51, 19, 59, 27, 49, 17, 57, 25, 15, 47, 7, 39, 13, 45, 5, 37, 63, 31, 55, 23, 61, 29, 53, 21);',
'float getBayerValue(vec2 uv, int size) {',
' ivec2 pos = ivec2(mod(uv, float(size)));',
' int index = pos.y * size + pos.x;',
' if (size == 2) { return float(bayer2x2[index]) / 4.0; }',
' else if (size == 4) { return float(bayer4x4[index]) / 16.0; }',
' else if (size == 8) { return float(bayer8x8[index]) / 64.0; }',
' return 0.0;',
'}',
'void main() {',
' float t = .5 * u_time;',
' vec2 uv = gl_FragCoord.xy / u_resolution.xy;',
' uv -= .5;',
' float pxSize = u_pxSize;',
' vec2 pxSizeUv = gl_FragCoord.xy;',
' pxSizeUv -= .5 * u_resolution;',
' pxSizeUv /= pxSize;',
' vec2 pixelizedUv = floor(pxSizeUv) * pxSize / u_resolution.xy;',
' pixelizedUv += .5;',
' pixelizedUv -= .5;',
' vec2 shape_uv = pixelizedUv;',
' vec2 dithering_uv = pxSizeUv;',
' vec2 ditheringNoise_uv = uv * u_resolution;',
' float shape = 0.;',
' if (u_shape < 1.5) {',
' shape_uv *= .001;',
' shape = 0.5 + 0.5 * getSimplexNoise(shape_uv, t);',
' shape = smoothstep(0.3, 0.9, shape);',
' } else if (u_shape < 2.5) {',
' shape_uv *= .003;',
' for (float i = 1.0; i < 6.0; i++) {',
' shape_uv.x += 0.6 / i * cos(i * 2.5 * shape_uv.y + t);',
' shape_uv.y += 0.6 / i * cos(i * 1.5 * shape_uv.x + t);',
' }',
' shape = .15 / abs(sin(t - shape_uv.y - shape_uv.x));',
' shape = smoothstep(0.02, 1., shape);',
' } else if (u_shape < 3.5) {',
' shape_uv *= .05;',
' float stripeIdx = floor(2. * shape_uv.x / TWO_PI);',
' float rand = hash11(stripeIdx * 10.);',
' rand = sign(rand - .5) * pow(.1 + abs(rand), .4);',
' shape = sin(shape_uv.x) * cos(shape_uv.y - 5. * rand * t);',
' shape = pow(abs(shape), 6.);',
' } else if (u_shape < 4.5) {',
' shape_uv *= 4.;',
' float wave = cos(.5 * shape_uv.x - 2. * t) * sin(1.5 * shape_uv.x + t) * (.75 + .25 * cos(3. * t));',
' shape = 1. - smoothstep(-1., 1., shape_uv.y + wave);',
' } else if (u_shape < 5.5) {',
' float dist = length(shape_uv);',
' float waves = sin(pow(dist, 1.7) * 7. - 3. * t) * .5 + .5;',
' shape = waves;',
' } else if (u_shape < 6.5) {',
' float l = length(shape_uv);',
' float angle = 6. * atan(shape_uv.y, shape_uv.x) + 4. * t;',
' float twist = 1.2;',
' float offset = pow(l, -twist) + angle / TWO_PI;',
' float mid = smoothstep(0., 1., pow(l, twist));',
' shape = mix(0., fract(offset), mid);',
' } else if (u_shape < 7.5) {',
' shape_uv *= 2.;',
' float d = 1. - pow(length(shape_uv), 2.);',
' vec3 pos = vec3(shape_uv, sqrt(d));',
' vec3 lightPos = normalize(vec3(cos(1.5 * t), .8, sin(1.25 * t)));',
' shape = .5 + .5 * dot(lightPos, pos);',
' shape *= step(0., d);',
' } else {',
' float ar = u_resolution.x / u_resolution.y;',
' vec2 p = shape_uv * vec2(ar, 1.) * 2.1;',
' vec2 q = vec2(sign(p.x) * max(abs(p.x) - (1.05 * ar - 1.), 0.), p.y);',
' float d = 1. - dot(q, q);',
' vec3 pos = vec3(q, sqrt(max(d, 0.)));',
' vec3 lightPos = normalize(vec3(cos(1.5 * t), .8, sin(1.25 * t)));',
' shape = .5 + .5 * dot(lightPos, pos);',
' shape *= step(0., d);',
' }',
' int type = int(floor(u_type));',
' float dithering = 0.0;',
' switch (type) {',
' case 1: {',
' dithering = step(hash21(ditheringNoise_uv), shape);',
' } break;',
' case 2:',
' dithering = getBayerValue(dithering_uv, 2);',
' break;',
' case 3:',
' dithering = getBayerValue(dithering_uv, 4);',
' break;',
' default:',
' dithering = getBayerValue(dithering_uv, 8);',
' break;',
' }',
' dithering -= .5;',
' float res = step(.5, shape + dithering);',
' vec3 fgColor = u_colorFront.rgb * u_colorFront.a;',
' float fgOpacity = u_colorFront.a;',
' vec3 bgColor = u_colorBack.rgb * u_colorBack.a;',
' float bgOpacity = u_colorBack.a;',
' vec3 color = fgColor * res;',
' float opacity = fgOpacity * res;',
' color += bgColor * (1. - opacity);',
' opacity += bgOpacity * (1. - opacity);',
' fragColor = vec4(color, opacity);',
'}'
].join('\n');
function ditherHexToRgba(hex){
var m=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
if(!m) return [0,0,0,1];
return [parseInt(m[1],16)/255, parseInt(m[2],16)/255, parseInt(m[3],16)/255, 1];
}
function mountDither(canvas, opts){
var gl=canvas.getContext('webgl2');
if(!gl) return null;
function sh(type,src){
var s=gl.createShader(type);
gl.shaderSource(s,src); gl.compileShader(s);
if(!gl.getShaderParameter(s,gl.COMPILE_STATUS)){ console.error(gl.getShaderInfoLog(s)); return null; }
return s;
}
var vs=sh(gl.VERTEX_SHADER,DITHER_VERT), fs=sh(gl.FRAGMENT_SHADER,DITHER_FRAG);
if(!vs||!fs) return null;
var prog=gl.createProgram();
gl.attachShader(prog,vs); gl.attachShader(prog,fs); gl.linkProgram(prog);
if(!gl.getProgramParameter(prog,gl.LINK_STATUS)){ console.error(gl.getProgramInfoLog(prog)); return null; }
var L={};
['u_time','u_resolution','u_colorBack','u_colorFront','u_shape','u_type','u_pxSize'].forEach(function(n){ L[n]=gl.getUniformLocation(prog,n); });
var buf=gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,buf);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]),gl.STATIC_DRAW);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0,2,gl.FLOAT,false,0,0);
var dpr=window.devicePixelRatio||1;
var r=canvas.parentElement.getBoundingClientRect();
canvas.width=Math.max(2,Math.round((r.width||120)*dpr));
canvas.height=Math.max(2,Math.round((r.height||36)*dpr));
gl.viewport(0,0,canvas.width,canvas.height);
var front=ditherHexToRgba(opts.front||'#ffffff');
var back=ditherHexToRgba(opts.back||'#000000');
var t0=Date.now();
(function frame(){
var t=(Date.now()-t0)*.001*(opts.speed||1.5);
gl.useProgram(prog);
gl.uniform1f(L.u_time,t);
gl.uniform2f(L.u_resolution,canvas.width,canvas.height);
gl.uniform4fv(L.u_colorBack,back);
gl.uniform4fv(L.u_colorFront,front);
gl.uniform1f(L.u_shape,opts.shape||7);
gl.uniform1f(L.u_type,opts.type||1);
gl.uniform1f(L.u_pxSize,opts.pxSize||2);
gl.drawArrays(gl.TRIANGLES,0,6);
requestAnimationFrame(frame);
})();
return { setFront:function(hex){ front=ditherHexToRgba(hex); } };
}
/* ---------- Create: Vorschau-Stack / Optionen / Prompt-Beam / Fake-Tastatur ---------- */
var C={model:0, count:1, format:'4:5', mediaType:'image', optOpen:false, kbOpen:false, generating:0};
var C_MODELS=[
{name:'Ich (Avatar)', token:'@Ich', hue:260},
{name:'Kerze Studio', token:'@Kerze', hue:40},
{name:'Showroom', token:'@Showroom', hue:170}
];
function renderCreateStack(){
var host=document.getElementById('cStack');
if(!host) return;
var isVideo=C.mediaType==='video';
var isChain=!isVideo&&C.count>1;
var pr={'1:1':1,'4:5':.8,'9:16':.5625}[C.format];
var ph=258, pw=Math.round(ph*pr);
var cp=POSTS[1], u=pic(cp,0);
var bg=u?'#141414 url(&quot;'+u+'&quot;) center / cover no-repeat':dummy(150);
var html='';
var nBehind=isChain?Math.min(C.count-1,2):0;
for(var k=nBehind;k>=1;k--){
html+='<div class="c-behind" style="width:'+pw+'px; height:'+ph+'px; transform:translateX(-50%) rotate('+(k===1?-6:6)+'deg) translateY('+(4*k)+'px) scale('+(1-.04*k)+');"></div>';
}
html+='<div class="c-preview" style="width:'+pw+'px; height:'+ph+'px; background:'+bg+';">';
if(isVideo){
html+='<div style="position:absolute; inset:0; display:grid; place-items:center; pointer-events:none;"><div style="width:62px; height:62px; border-radius:100px; background:rgba(10,10,10,.5); backdrop-filter:blur(8px); display:grid; place-items:center;"><svg width="20" height="20" viewBox="0 0 24 24" fill="#fff"><path d="M8 5 L19 12 L8 19 Z"/></svg></div></div>';
html+='<div style="position:absolute; top:12px; left:12px; padding:5px 10px; border-radius:100px; background:rgba(10,10,10,.55); font-size:11px; font-weight:700; letter-spacing:.06em;">VIDEO · 0:08</div>';
}
if(isChain){
html+='<div style="position:absolute; top:12px; right:12px; padding:5px 10px; border-radius:100px; background:rgba(10,10,10,.55); font-size:11px; font-weight:700;">1/'+C.count+'</div>';
html+='<div style="position:absolute; left:0; right:0; bottom:14px; display:flex; justify-content:center; align-items:center; gap:5px;">';
for(var i=0;i<C.count;i++){
html+='<div style="width:'+(i===0?16:6)+'px; height:6px; border-radius:100px; background:'+(i===0?'#fff':'rgba(255,255,255,.45)')+'; transition:width .2s;"></div>';
}
html+='</div>';
}
html+='</div>';
host.innerHTML=html;
document.getElementById('cSelLabel').textContent = isVideo ? ('Video · '+C.format) : ((C.count===1?'Bild':C.count+'er-Kette')+' · '+C.format);
document.getElementById('cChevron').style.transform=C.optOpen?'rotate(180deg)':'none';
document.getElementById('cOpts').style.display=C.optOpen?'block':'none';
}
function pills(hostId, items, activeVal, onPick){
var host=document.getElementById(hostId);
host.innerHTML=items.map(function(it){
return '<div class="pill'+(it.v===activeVal?' on':'')+'" data-v="'+it.v+'">'+it.label+'</div>';
}).join('');
host.querySelectorAll('.pill').forEach(function(p){
p.onclick=function(){ onPick(p.dataset.v); };
});
}
function renderCreateOpts(){
pills('typeRow',[{v:'image',label:'Bild'},{v:'video',label:'Video'}],C.mediaType,function(v){C.mediaType=v; renderCreateOpts(); renderCreateStack();});
pills('formatRow',[{v:'1:1',label:'1:1'},{v:'4:5',label:'4:5'},{v:'9:16',label:'9:16'}],C.format,function(v){C.format=v; renderCreateOpts(); renderCreateStack();});
pills('countRow',[{v:'1',label:'1 Bild'},{v:'3',label:'3er'},{v:'5',label:'5er'}],String(C.count),function(v){C.count=+v; renderCreateOpts(); renderCreateStack();});
}
function toggleOpts(){ C.optOpen=!C.optOpen; renderCreateStack(); }
var DCHIPS={built:false, mounted:false, insts:[]};
var DITHER_ON='#f2f2f2', DITHER_OFF='#555555';
function renderCreateModels(){
var host=document.getElementById('createModels');
if(!DCHIPS.built){
host.innerHTML=C_MODELS.map(function(m,i){
return '<div class="chip dither" data-i="'+i+'"><canvas></canvas><div class="dot"></div><span>'+m.name+'</span></div>';
}).join('');
host.querySelectorAll('.chip').forEach(function(c){
c.onclick=function(){ C.model=+c.dataset.i; renderCreateModels(); };
});
DCHIPS.built=true;
}
host.querySelectorAll('.chip').forEach(function(c,i){
var on=(i===C.model);
c.classList.toggle('on',on);
c.querySelector('.dot').style.background=on?'var(--accent)':'rgba(255,255,255,.3)';
if(DCHIPS.insts[i]) DCHIPS.insts[i].setFront(on?DITHER_ON:DITHER_OFF);
});
}
/* Shader erst mounten, wenn der Create-Screen sichtbar ist (sonst Groesse 0) */
function initCreateDither(){
if(DCHIPS.mounted) return;
var chips=document.querySelectorAll('#createModels .chip.dither');
if(!chips.length) return;
DCHIPS.mounted=true;
chips.forEach(function(c,i){
DCHIPS.insts[i]=mountDither(c.querySelector('canvas'), {front:(i===C.model)?DITHER_ON:DITHER_OFF, shape:8, type:1, pxSize:2, speed:1.5});
});
}
/* Prompt-Editing über die Fake-Tastatur (Caret-genau wie im Design) */
function editPrompt(mutate){
var ta=document.getElementById('createPrompt');
var p=ta.value, s=ta.selectionStart, e=ta.selectionEnd;
var r=mutate(p,s,e);
ta.value=r.val;
ta.focus(); ta.setSelectionRange(r.caret,r.caret);
}
function applyKey(code){
editPrompt(function(p,s,e){
if(code==='del'){
if(s!==e) return {val:p.slice(0,s)+p.slice(e), caret:s};
return {val:p.slice(0,Math.max(0,s-1))+p.slice(e), caret:Math.max(0,s-1)};
}
var ins=code==='space'?' ':code==='ret'?'\n':code;
return {val:p.slice(0,s)+ins+p.slice(e), caret:s+ins.length};
});
}
function insertToken(tok){
editPrompt(function(p,s,e){
var before=p.slice(0,s);
var lead=before&&!/\s$/.test(before)?' ':'';
var ins=lead+tok+' ';
return {val:before+ins+p.slice(e), caret:s+ins.length};
});
}
function setKb(open){
C.kbOpen=open;
document.getElementById('kbOverlay').classList.toggle('open',open);
document.getElementById('cScroll').classList.toggle('kb-open',open);
if(open){
C.optOpen=false; renderCreateStack();
requestAnimationFrame(function(){requestAnimationFrame(function(){
var el=document.getElementById('cScroll'); el.scrollTop=el.scrollHeight;
});});
}
}
function renderKb(){
var mh=document.getElementById('kbModels');
mh.innerHTML=C_MODELS.map(function(m,i){
return '<div class="kb-chip" data-i="'+i+'"><div class="dot" style="background:oklch(.7 .13 '+m.hue+');"></div>'+m.name+'</div>';
}).join('');
mh.querySelectorAll('.kb-chip').forEach(function(c){
function ins(e){ e.preventDefault(); insertToken(C_MODELS[+c.dataset.i].token); }
c.addEventListener('mousedown',ins);
c.addEventListener('touchstart',ins,{passive:false});
});
var rows=[
{pad:0, keys:'qwertyuiop'.split('').map(function(l){return {label:l, code:l};})},
{pad:16, keys:'asdfghjkl'.split('').map(function(l){return {label:l, code:l};})},
{pad:0, keys:[{label:'⇧', code:null, cls:'mod', flex:1.5}].concat('zxcvbnm'.split('').map(function(l){return {label:l, code:l};})).concat([{label:'⌫', code:'del', cls:'mod', flex:1.5}])},
{pad:0, keys:[{label:'123', code:null, cls:'mod', flex:1.6, fs:13},{label:'', code:'space', flex:5},{label:'return', code:'ret', flex:1.9, fs:13, bg:'rgba(122,162,255,.9)'}]}
];
var kh=document.getElementById('kbKeys'); var html='';
rows.forEach(function(row,ri){
html+='<div class="kb-row" style="padding:0 '+row.pad+'px;">';
row.keys.forEach(function(k,ki){
var st='';
if(k.flex) st+='flex:'+k.flex+';';
if(k.fs) st+='font-size:'+k.fs+'px;';
if(k.bg) st+='background:'+k.bg+';';
html+='<div class="kb-key'+(k.cls?' '+k.cls:'')+'" data-r="'+ri+'" data-k="'+ki+'" style="'+st+'">'+k.label+'</div>';
});
html+='</div>';
});
kh.innerHTML=html;
kh.querySelectorAll('.kb-key').forEach(function(el){
var k=rows[+el.dataset.r].keys[+el.dataset.k];
function press(e){ e.preventDefault(); if(k.code) applyKey(k.code); }
el.addEventListener('mousedown',press);
el.addEventListener('touchstart',press,{passive:false});
});
function done(e){ e.preventDefault(); document.getElementById('createPrompt').blur(); setKb(false); }
document.getElementById('kbDone').addEventListener('mousedown',done);
document.getElementById('kbDone').addEventListener('touchstart',done,{passive:false});
}
(function(){
var ta=document.getElementById('createPrompt');
ta.addEventListener('focus',function(){ setKb(true); });
ta.addEventListener('blur',function(){ setKb(false); });
})();
document.getElementById('generateBtn').onclick=function(){
if(C.generating) return;
var lbl=document.getElementById('generateLabel');
C.generating=1; lbl.textContent='Generiere '+C.count+' Bilder …';
setTimeout(function(){ C.generating=2; lbl.textContent='✓ In der Warteschlange'; },1400);
setTimeout(function(){ C.generating=0; lbl.textContent='Post generieren'; },3200);
};
/* ---------- Nav-Glas: dynamische Displacement-Map (aus dem Design) ---------- */
function updateGlassMap(){
var nav=document.getElementById('navBar'), img=document.getElementById('glassMapImage');
if(!nav||!img) return;
var w=nav.offsetWidth||286, h=nav.offsetHeight||56;
var r=Math.min(100,h/2), e=Math.min(w,h)*0.035;
var svg='<svg viewBox="0 0 '+w+' '+h+'" xmlns="http://www.w3.org/2000/svg">'+
'<defs><linearGradient id="rg" x1="100%" y1="0%" x2="0%" y2="0%"><stop offset="0%" stop-color="#0000"/><stop offset="100%" stop-color="red"/></linearGradient>'+
'<linearGradient id="bg" x1="0%" y1="0%" x2="0%" y2="100%"><stop offset="0%" stop-color="#0000"/><stop offset="100%" stop-color="blue"/></linearGradient></defs>'+
'<rect width="'+w+'" height="'+h+'" fill="black"/>'+
'<rect width="'+w+'" height="'+h+'" rx="'+r+'" fill="url(#rg)"/>'+
'<rect width="'+w+'" height="'+h+'" rx="'+r+'" fill="url(#bg)" style="mix-blend-mode:difference"/>'+
'<rect x="'+e+'" y="'+e+'" width="'+(w-e*2)+'" height="'+(h-e*2)+'" rx="'+r+'" fill="hsl(0 0% 50% / 0.93)" style="filter:blur(11px)"/></svg>';
img.setAttribute('href','data:image/svg+xml,'+encodeURIComponent(svg));
}
/* ---------- Init ---------- */
setHood(centerOf(X.tab), halfOf(X.tab));
requestAnimationFrame(function(){ measureTabs(); setHood(centerOf(X.tab), halfOf(X.tab)); updateGlassMap(); });
renderTabs();
renderDeck();
renderDetailStrip();
preloadPics();
renderDetailModels();
renderCreateModels();
renderCreateOpts();
renderCreateStack();
renderKb();
</script>
</body>
</html>