{"tool":"get_design","slug":"drift","title":"Drift — Short vertical video, that keeps going","url":"/drift","kind":"Live website","code":"<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, viewport-fit=cover\" />\n<title>Drift — Short vertical video, that keeps going</title>\n<meta name=\"description\" content=\"Drift is a TikTok-style vertical video app. For You feed, Discover, upload your own clip, comments, likes, and a profile — built on the 6 real AI-generated clips from Still Standing, Part 2.\" />\n<style>\n*{box-sizing:border-box}\nhtml,body{margin:0;height:100%;background:#000;color:#fff;font-family:Inter,system-ui,sans-serif;overflow:hidden}\nbutton{font:inherit;color:inherit;background:none;border:0;cursor:pointer}\ninput,textarea{font:inherit;color:#fff}\na{color:inherit}\n:root{--pink:#FE2C55;--pink-dark:#E01E48}\n.topbar{position:fixed;top:0;left:0;right:0;z-index:20;display:flex;justify-content:space-between;align-items:center;padding:14px 16px;background:linear-gradient(180deg,rgba(0,0,0,.75),transparent);pointer-events:none}\n.topbar b{font-size:22px;letter-spacing:-.02em}\n.topbar .sub{font-size:12px;color:#ddd}\n.topbar>*{pointer-events:auto}\n.feedtabs{position:fixed;top:14px;left:50%;transform:translateX(-50%);z-index:21;display:flex;gap:18px;font-size:15px;font-weight:600}\n.feedtabs button{color:#bbb;padding:4px 2px}\n.feedtabs button.on{color:#fff;border-bottom:2px solid #fff}\n.soundbtn{position:fixed;top:56px;right:14px;z-index:21;background:rgba(0,0,0,.5);border:1px solid rgba(255,255,255,.35);border-radius:999px;padding:7px 12px;font-size:12px}\n.view{display:none;height:100dvh}\n.view.on{display:block}\n#feed{overflow-y:auto;scroll-snap-type:y mandatory;scrollbar-width:none}\n#feed::-webkit-scrollbar{display:none}\n.clip{position:relative;height:100dvh;scroll-snap-align:start;scroll-snap-stop:always;display:flex;align-items:flex-end;justify-content:center;background:#111}\n.clip video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}\n.clip::after{content:\"\";position:absolute;inset:0;z-index:1;pointer-events:none;background:linear-gradient(180deg,rgba(0,0,0,.35),transparent 22%,transparent 55%,rgba(0,0,0,.72));}\n.disc{position:absolute;right:14px;top:112px;z-index:3;width:44px;height:44px;border-radius:50%;background:conic-gradient(#FE2C55,#25F4EE,#FE2C55);display:grid;place-items:center;animation:spinRing 4s linear infinite;box-shadow:0 4px 18px rgba(0,0,0,.5)}\n.disc i{width:18px;height:18px;border-radius:50%;background:#111;border:2px solid #fff;display:block}\n.info{position:relative;z-index:2;width:100%;max-width:520px;padding:0 78px 96px 16px}\n.music{margin-top:10px;font-size:12px;color:#eee;overflow:hidden;white-space:nowrap;max-width:260px}\n.music span{display:inline-block;padding-left:100%;animation:marquee 9s linear infinite}\n@keyframes marquee{from{transform:translateX(0)}to{transform:translateX(-100%)}}\n.info h2{margin:6px 0 4px;font-size:19px;text-shadow:0 2px 12px rgba(0,0,0,.6)}\n.info p{margin:0;color:#e5e5e5;font-size:14px}\n.meta{display:flex;gap:10px;align-items:center;flex-wrap:wrap}\n.handle{font-weight:700;font-size:15px}\n.followbtn{border:1px solid #fff;border-radius:999px;padding:3px 12px;font-size:12px;font-weight:700}\n.followbtn.following{background:#fff;color:#000;border-color:#fff}\n.tag{font-size:12px;color:#ccc}\n.actions{position:absolute;right:12px;bottom:120px;z-index:3;display:flex;flex-direction:column;gap:16px;align-items:center}\n.act{display:flex;flex-direction:column;align-items:center;gap:3px}\n.act button{background:rgba(20,20,20,.5);backdrop-filter:blur(6px);border:1px solid rgba(255,255,255,.35);border-radius:999px;width:52px;height:52px;font-size:22px;transition:transform .18s ease,background .2s ease}\n.act button:active{transform:scale(.88)}\n.act span{font-size:11px;color:#eee;text-shadow:0 1px 6px rgba(0,0,0,.6)}\n.act button.liked{background:var(--pink);border-color:var(--pink)}\n.act span{font-size:11px;color:#eee}\n.progress{position:absolute;left:0;right:0;bottom:0;height:3px;background:rgba(255,255,255,.25);z-index:3}\n.progress i{display:block;height:100%;width:0;background:var(--pink)}\n.big-heart{position:absolute;left:50%;top:42%;transform:translate(-50%,-50%) scale(0);z-index:4;font-size:90px;color:var(--pink);pointer-events:none;text-shadow:0 4px 30px rgba(0,0,0,.5)}\n.big-heart.pop{animation:pop .6s ease forwards}\n@keyframes pop{0%{transform:translate(-50%,-50%) scale(0)}30%{transform:translate(-50%,-50%) scale(1.2)}60%{transform:translate(-50%,-50%) scale(1)}100%{transform:translate(-50%,-50%) scale(1);opacity:0}}\n.pause-badge{position:absolute;left:50%;top:42%;transform:translate(-50%,-50%);z-index:4;font-size:64px;opacity:.85;display:none;pointer-events:none}\n.hint{position:fixed;bottom:74px;left:50%;transform:translateX(-50%);z-index:10;font-size:12px;color:#ddd;background:rgba(0,0,0,.55);padding:6px 12px;border-radius:999px;white-space:nowrap}\n.toast{position:fixed;bottom:120px;left:50%;transform:translateX(-50%);z-index:40;background:#fff;color:#000;padding:9px 16px;border-radius:999px;font-size:13px;font-weight:600;display:none;box-shadow:0 8px 30px rgba(0,0,0,.5)}\n.endcard{position:relative;height:100dvh;scroll-snap-align:start;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;background:#0b0b0f;text-align:center;padding:0 24px 90px}\n.endcard h2{font-size:26px;margin:0}\n.endcard p{color:#aaa;margin:0;max-width:320px}\n.btn{display:inline-block;background:var(--pink);color:#fff;font-weight:700;text-decoration:none;padding:12px 22px;border-radius:999px;border:0}\n.btn.ghost{background:transparent;border:1px solid rgba(255,255,255,.4)}\n/* bottom nav */\n.bottomnav{position:fixed;left:0;right:0;bottom:0;z-index:30;display:flex;justify-content:space-around;align-items:center;height:62px;padding-bottom:env(safe-area-inset-bottom);background:linear-gradient(0deg,rgba(0,0,0,.92),rgba(0,0,0,.75))}\n.bottomnav button{display:flex;flex-direction:column;align-items:center;gap:2px;font-size:10px;color:#bbb;padding:6px 10px}\n.bottomnav button.on{color:#fff}\n.bottomnav button .ic{font-size:20px;line-height:1}\n.create-btn{width:46px;height:32px;border-radius:9px;background:linear-gradient(90deg,#25F4EE 0 33%,#fff 33% 66%,var(--pink) 66%);display:grid;place-items:center;color:#000;font-size:20px;font-weight:800}\n/* sub-pages */\n.page{overflow-y:auto;height:100dvh;padding:70px 16px 90px;scrollbar-width:none}\n.page::-webkit-scrollbar{display:none}\n.page h1{font-size:26px;margin:0 0 4px}\n.page .lede{color:#aaa;font-size:13px;margin:0 0 16px}\n.searchbar{width:100%;height:42px;border:1px solid rgba(255,255,255,.2);background:#111;border-radius:999px;padding:0 16px;font-size:14px;outline:none}\n.searchbar:focus{border-color:var(--pink)}\n.chips{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}\n.chip{border:1px solid rgba(255,255,255,.25);border-radius:999px;padding:7px 13px;font-size:12px;color:#ddd}\n.chip.on{background:#fff;color:#000;border-color:#fff}\n.grid{display:grid;grid-template-columns:repeat(3,1fr);gap:3px}\n.tile{position:relative;aspect-ratio:9/16;background:#1a1a1a;border-radius:10px;overflow:hidden;text-align:left;padding:0;transition:transform .25s ease,box-shadow .25s ease}\n.tile:hover{transform:scale(1.03);box-shadow:0 10px 30px rgba(0,0,0,.55)}\n.tile video{width:100%;height:100%;object-fit:cover;display:block}\n.tile .cap{position:absolute;left:0;right:0;bottom:0;padding:18px 7px 7px;background:linear-gradient(0deg,rgba(0,0,0,.8),transparent);font-size:11px;font-weight:600;text-align:left}\n.tile .dur{position:absolute;top:6px;right:6px;background:rgba(0,0,0,.6);border-radius:99px;padding:2px 7px;font-size:10px}\n.empty{border:1px dashed rgba(255,255,255,.25);border-radius:14px;padding:28px 18px;text-align:center;color:#aaa;font-size:13px;line-height:1.6;margin-top:10px}\n.empty b{color:#fff;display:block;font-size:15px;margin-bottom:4px}\n/* comments sheet */\n.sheet{position:fixed;left:0;right:0;bottom:0;z-index:50;height:70dvh;max-width:520px;margin:0 auto;background:#121212;border-radius:18px 18px 0 0;display:none;flex-direction:column;box-shadow:0 -10px 40px rgba(0,0,0,.6)}\n.sheet.on{display:flex}\n.sheet header{padding:14px 16px;border-bottom:1px solid rgba(255,255,255,.12);display:flex;justify-content:space-between;align-items:center;font-weight:700}\n.sheet .list{flex:1;overflow-y:auto;padding:12px 16px;display:flex;flex-direction:column;gap:14px}\n.comment{display:flex;gap:10px}\n.comment .av{width:34px;height:34px;border-radius:50%;background:linear-gradient(135deg,#666,#222);display:grid;place-items:center;font-size:13px;flex:none}\n.comment b{font-size:13px}\n.comment p{margin:2px 0 0;font-size:13px;color:#ddd}\n.sheet form{display:flex;gap:8px;padding:12px;border-top:1px solid rgba(255,255,255,.12)}\n.sheet form input{flex:1;height:42px;border:1px solid rgba(255,255,255,.2);background:#1c1c1c;border-radius:999px;padding:0 14px;font-size:14px;outline:none}\n.sheet form button{background:var(--pink);border-radius:999px;padding:0 18px;font-weight:700}\n/* profile */\n.profile-head{display:flex;gap:16px;align-items:center;margin:8px 0 14px}\n.avatar{width:72px;height:72px;border-radius:50%;background:linear-gradient(135deg,#FE2C55,#25F4EE);display:grid;place-items:center;font-size:30px;flex:none}\n.stats{display:flex;gap:18px;text-align:center}\n.stats b{display:block;font-size:17px}\n.stats span{font-size:11px;color:#aaa}\n.bio{font-size:13px;color:#ddd;margin:0 0 16px;line-height:1.6}\n.tabs{display:flex;border-bottom:1px solid rgba(255,255,255,.15);margin-bottom:3px}\n.tabs button{flex:1;padding:11px;font-size:13px;color:#aaa;font-weight:600}\n.tabs button.on{color:#fff;border-bottom:2px solid #fff}\n/* create */\n.field{margin-bottom:14px}\n.field label{display:block;font-size:12px;color:#aaa;margin-bottom:6px}\n.field input,.field textarea{width:100%;border:1px solid rgba(255,255,255,.2);background:#111;border-radius:10px;padding:11px 13px;font-size:14px;outline:none}\n.field input:focus,.field textarea:focus{border-color:var(--pink)}\n.drop{border:1px dashed rgba(255,255,255,.35);border-radius:14px;padding:22px;text-align:center;color:#aaa;font-size:13px}\n.drop video{width:100%;max-height:300px;border-radius:10px;background:#000}\n.note{font-size:12px;color:#888;line-height:1.6}\n/* inbox */\n.notif{display:flex;gap:12px;padding:14px 4px;border-bottom:1px solid rgba(255,255,255,.08);align-items:flex-start}\n.notif .ic{width:38px;height:38px;border-radius:50%;background:#1e1e1e;display:grid;place-items:center;font-size:17px;flex:none}\n.notif p{margin:0;font-size:13px;line-height:1.55;color:#ddd}\n.notif p b{color:#fff}\n.notif time{font-size:11px;color:#888}\n@keyframes fadeUp{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:translateY(0)}}\n@keyframes fadeIn{from{opacity:0}to{opacity:1}}\n@keyframes viewIn{from{opacity:0;transform:translateY(10px) scale(.995)}to{opacity:1;transform:translateY(0) scale(1)}}\n@keyframes popIn{0%{transform:scale(.6)}55%{transform:scale(1.25)}100%{transform:scale(1)}}\n@keyframes sheetUp{from{transform:translateY(40px);opacity:0}to{transform:translateY(0);opacity:1}}\n@keyframes toastUp{from{opacity:0;transform:translate(-50%,10px)}to{opacity:1;transform:translate(-50%,0)}}\n@keyframes glowPulse{0%,100%{box-shadow:0 0 0 0 rgba(254,44,85,.45)}50%{box-shadow:0 0 0 7px rgba(254,44,85,0)}}\n@keyframes floatY{0%,100%{transform:translateY(0) rotate(4deg)}50%{transform:translateY(-6px) rotate(4deg)}}\n@keyframes spinRing{to{transform:rotate(360deg)}}\n@keyframes shimmer{from{background-position:200% 0}to{background-position:-200% 0}}\n@keyframes navPop{0%{transform:scale(1)}40%{transform:scale(1.35)}100%{transform:scale(1)}}\n.view.on{animation:viewIn .28s ease both}\n.clip .info,.clip .actions{opacity:0;transform:translateY(16px);transition:opacity .45s ease,transform .45s ease}\n.clip.in-view .info,.clip.in-view .actions{opacity:1;transform:translateY(0)}\n.clip.in-view .actions{transition-delay:.08s}\n.tile{animation:fadeUp .3s ease both;animation-delay:var(--d,0s)}\n.tile .cap{animation:fadeIn .5s ease .15s both}\n.like-btn.liked{animation:popIn .35s ease}\n.followbtn{transition:transform .18s ease,background .2s ease,color .2s ease}\n.followbtn:active{transform:scale(.92)}\n.bottomnav button.on .ic{display:inline-block;animation:navPop .3s ease}\n.create-btn{animation:glowPulse 2.2s ease-in-out infinite}\n.avatar{position:relative}\n.avatar::after{content:\"\";position:absolute;inset:-5px;border-radius:50%;border:2px solid transparent;border-top-color:#FE2C55;border-right-color:#25F4EE;animation:spinRing 3s linear infinite}\n.sheet.on{animation:sheetUp .3s ease both}\n.toast{animation:toastUp .25s ease both}\n.searchbar{transition:border-color .2s ease,box-shadow .2s ease}\n.searchbar:focus{box-shadow:0 0 0 3px rgba(254,44,85,.25)}\n.chip{transition:transform .15s ease,background .2s ease,color .2s ease}\n.chip:active{transform:scale(.94)}\n.endcard h2{animation:fadeUp .5s ease both}\n.endcard p{animation:fadeUp .5s ease .1s both}\n.endcard .btn{animation:fadeUp .5s ease .2s both}\n.progress i{transition:width .2s linear}\n.topbar b{animation:fadeUp .4s ease both}\n@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation:none!important;transition:none!important}}\n@media(max-width:650px){.topbar .sub{display:none}.feedtabs{gap:14px;font-size:14px}}\n</style>\n</head>\n<body>\n<div class=\"topbar\" id=\"topbar\"><b>Drift</b><span class=\"sub\">Still Standing · Part 2</span></div>\n<div class=\"feedtabs\" id=\"feedtabs\"><button id=\"tabForYou\" class=\"on\">For You</button><button id=\"tabFollowing\">Following</button></div>\n<button class=\"soundbtn\" id=\"soundBtn\" type=\"button\">🔇 Sound off</button>\n\n<main class=\"view on\" id=\"feed\"></main>\n\n<section class=\"view page\" id=\"discover\">\n  <h1>Discover</h1>\n  <p class=\"lede\">Every clip in Drift, searchable. Tap one to watch it in the feed.</p>\n  <input class=\"searchbar\" id=\"discoverSearch\" type=\"search\" placeholder=\"Search clips, titles, tags...\" aria-label=\"Search clips\" />\n  <div class=\"chips\" id=\"tagChips\"></div>\n  <div class=\"grid\" id=\"discoverGrid\"></div>\n  <div class=\"empty\" id=\"discoverEmpty\" style=\"display:none\"><b>No clips match that</b>Try a different word or tag.</div>\n</section>\n\n<section class=\"view page\" id=\"create\">\n  <h1>Make a Drift</h1>\n  <p class=\"lede\">Upload a short vertical video from your device and add it to the feed.</p>\n  <div class=\"field\"><label>Your video</label><div class=\"drop\" id=\"drop\"><input type=\"file\" id=\"fileInput\" accept=\"video/*\" style=\"display:none\" /><button type=\"button\" id=\"pickBtn\" class=\"btn ghost\">Choose a video</button><p>MP4 or MOV, vertical works best.</p><video id=\"previewVideo\" style=\"display:none\" controls muted loop playsinline></video></div></div>\n  <div class=\"field\"><label for=\"upTitle\">Title</label><input id=\"upTitle\" maxlength=\"60\" placeholder=\"e.g. The comeback\" /></div>\n  <div class=\"field\"><label for=\"upCaption\">Caption</label><textarea id=\"upCaption\" rows=\"2\" maxlength=\"140\" placeholder=\"One line about this clip...\"></textarea></div>\n  <button class=\"btn\" id=\"publishBtn\" type=\"button\" style=\"width:100%\">Publish to the feed</button>\n  <p class=\"note\">Your clip is added to the feed, Discover, and your profile for this browser session. Drift doesn't upload it to a server yet — close the tab and it's gone.</p>\n</section>\n\n<section class=\"view page\" id=\"inbox\">\n  <h1>Inbox</h1>\n  <p class=\"lede\">Your activity in Drift. Nothing here comes from anyone else — these are your own likes, follows, and comments.</p>\n  <div id=\"activityList\"></div>\n  <div class=\"empty\" id=\"inboxEmpty\" style=\"display:none\"><b>Nothing yet</b>Like a clip, follow @stillstanding, or leave a comment — it'll show up here.</div>\n  <button class=\"btn ghost\" id=\"clearActivity\" type=\"button\" style=\"margin-top:16px\">Clear activity</button>\n</section>\n\n<section class=\"view page\" id=\"profile\">\n  <h1 style=\"display:none\">Profile</h1>\n  <div class=\"profile-head\">\n    <div class=\"avatar\">✦</div>\n    <div>\n      <div style=\"font-size:18px;font-weight:800\">@stillstanding</div>\n      <div class=\"stats\" style=\"margin-top:8px\">\n        <div><b id=\"statVideos\">6</b><span>Videos</span></div>\n        <div><b id=\"statLikes\">0</b><span>Likes given</span></div>\n        <div><b id=\"statFollowing\">0</b><span>Following</span></div>\n      </div>\n    </div>\n  </div>\n  <p class=\"bio\">Still Standing — a 60-second story about not quitting. Six AI-generated clips, one rooftop sunrise. Made for Drift.</p>\n  <div style=\"display:flex;gap:10px;margin-bottom:16px\"><button class=\"btn\" id=\"profileFollow\" type=\"button\" style=\"flex:1\">Follow</button><button class=\"btn ghost\" id=\"profileShare\" type=\"button\">Share profile</button></div>\n  <div class=\"tabs\"><button id=\"tabVideos\" class=\"on\">Videos</button><button id=\"tabLiked\">Liked</button></div>\n  <div class=\"grid\" id=\"profileGrid\" style=\"margin-top:3px\"></div>\n  <div class=\"empty\" id=\"profileEmpty\" style=\"display:none\"><b>No liked clips yet</b>Tap the heart on any clip and it'll live here.</div>\n</section>\n\n<nav class=\"bottomnav\" id=\"bottomnav\">\n  <button data-view=\"feed\" class=\"on\"><span class=\"ic\">⌂</span>Home</button>\n  <button data-view=\"discover\"><span class=\"ic\">⌕</span>Discover</button>\n  <button data-view=\"create\" aria-label=\"Create\"><span class=\"create-btn\">+</span></button>\n  <button data-view=\"inbox\"><span class=\"ic\">✉</span>Inbox</button>\n  <button data-view=\"profile\"><span class=\"ic\">◉</span>Me</button>\n</nav>\n\n<div class=\"hint\" id=\"hint\">Scroll to swipe · Tap video to play / pause · Double-tap to like</div>\n<div class=\"toast\" id=\"toast\"></div>\n\n<div class=\"sheet\" id=\"sheet\" role=\"dialog\" aria-label=\"Comments\">\n  <header><span id=\"sheetTitle\">Comments</span><button type=\"button\" id=\"sheetClose\" aria-label=\"Close comments\">✕</button></header>\n  <div class=\"list\" id=\"commentList\"></div>\n  <form id=\"commentForm\"><input id=\"commentInput\" maxlength=\"140\" placeholder=\"Add a comment...\" aria-label=\"Add a comment\" /><button type=\"submit\">Post</button></form>\n</div>\n\n<script>\nvar clips = [\n  {src:\"/sites/drift/assets/clip1.mp4\", handle:\"@stillstanding\", title:\"The call\", text:\"One phone call. Everything changes after this.\", tags:[\"Still Standing\",\"phone call\",\"motivation\"]},\n  {src:\"/sites/drift/assets/clip2.mp4\", handle:\"@stillstanding\", title:\"The pitch\", text:\"A cafe, a pitch, and a room full of doubt.\", tags:[\"Still Standing\",\"cafe\",\"pitch\"]},\n  {src:\"/sites/drift/assets/clip3.mp4\", handle:\"@stillstanding\", title:\"First yes\", text:\"The first yes is the loudest one.\", tags:[\"Still Standing\",\"first yes\",\"motivation\"]},\n  {src:\"/sites/drift/assets/clip4.mp4\", handle:\"@stillstanding\", title:\"Night grind\", text:\"Nobody sees the night grind.\", tags:[\"Still Standing\",\"night grind\",\"grind\"]},\n  {src:\"/sites/drift/assets/clip5.mp4\", handle:\"@stillstanding\", title:\"The crowd\", text:\"Then the crowd shows up.\", tags:[\"Still Standing\",\"crowd\",\"reveal\"]},\n  {src:\"/sites/drift/assets/clip6.mp4\", handle:\"@stillstanding\", title:\"Still standing\", text:\"Keep going. That's the whole story.\", tags:[\"Still Standing\",\"keep going\",\"motivation\"]}\n];\nfunction load(k, d){ try { var v = JSON.parse(localStorage.getItem(k)); return v === null || v === undefined ? d : v; } catch(e){ return d; } }\nfunction save(k, v){ try { localStorage.setItem(k, JSON.stringify(v)); } catch(e){} }\nvar liked = load(\"drift-likes\", {});\nvar following = load(\"drift-following\", false);\nvar comments = load(\"drift-comments\", {});\nvar activity = load(\"drift-activity\", []);\nvar uploads = []; // session-only: {src, title, text, tags}\nvar soundOn = false;\nvar feedMode = \"foryou\";\nvar activeTag = \"All\";\nvar profileTab = \"videos\";\nvar currentSheet = -1;\n\nfunction allClips(){ return uploads.concat(clips); }\nfunction clipKey(i){ return i < uploads.length ? \"u\" + i : \"c\" + (i - uploads.length); }\nfunction likeCount(i){ return liked[clipKey(i)] ? 1 : 0; }\nfunction toast(msg){ var t = document.getElementById(\"toast\"); t.textContent = msg; t.style.display = \"block\"; setTimeout(function(){ t.style.display = \"none\"; }, 2200); }\nfunction logActivity(icon, html){ activity.unshift({icon:icon, html:html, at:new Date().toLocaleString()}); save(\"drift-activity\", activity); renderInbox(); }\n\nvar feed = document.getElementById(\"feed\");\nfunction buildFeed(){\n  feed.innerHTML = \"\";\n  var list = allClips();\n  if (feedMode === \"following\" && !following){\n    var empty = document.createElement(\"section\");\n    empty.className = \"clip\";\n    empty.innerHTML = '<div class=\"endcard\" style=\"position:absolute;inset:0\"><h2>You\\'re not following anyone yet</h2><p>Follow @stillstanding and their clips will show up here.</p><button class=\"btn\" type=\"button\" id=\"emptyFollow\">Follow @stillstanding</button></div>';\n    feed.appendChild(empty);\n    empty.querySelector(\"#emptyFollow\").addEventListener(\"click\", function(){ setFollowing(true); });\n  }\n  list.forEach(function(c, i){\n    if (feedMode === \"following\" && !following) return;\n    var key = clipKey(i);\n    var el = document.createElement(\"section\");\n    el.className = \"clip\";\n    el.dataset.i = i;\n    el.innerHTML =\n      '<video src=\"' + c.src + '\" loop ' + (soundOn ? '' : 'muted') + ' playsinline preload=\"metadata\"></video>' +\n      '<div class=\"big-heart\">♥</div><div class=\"pause-badge\">▶</div><div class=\"disc\"><i></i></div>' +\n      '<div class=\"actions\">' +\n        '<div class=\"act\"><button type=\"button\" class=\"like-btn ' + (liked[key] ? 'liked' : '') + '\" aria-label=\"Like\">' + (liked[key] ? '♥' : '♡') + '</button><span class=\"like-count\">' + likeCount(i) + '</span></div>' +\n        '<div class=\"act\"><button type=\"button\" class=\"comment-btn\" aria-label=\"Comments\">💬</button><span>' + ((comments[key] || []).length || 'Comment') + '</span></div>' +\n        '<div class=\"act\"><button type=\"button\" class=\"share-btn\" aria-label=\"Share\">↗</button><span>Share</span></div>' +\n      '</div>' +\n      '<div class=\"info\"><div class=\"meta\"><span class=\"handle\">' + c.handle + '</span>' +\n        (c.handle === '@stillstanding' ? '<button type=\"button\" class=\"followbtn ' + (following ? 'following' : '') + '\">' + (following ? 'Following' : 'Follow') + '</button>' : '') +\n        '<span class=\"tag\">Clip ' + (i+1) + ' of ' + list.length + ' · 10s · AI-generated</span></div>' +\n        '<h2>' + c.title + '</h2><p>' + c.text + '</p><div class=\"music\"><span>♪ Still Standing · original sound · Keep going ♪&nbsp;</span></div></div>' +\n      '<div class=\"progress\"><i></i></div>';\n    feed.appendChild(el);\n  });\n  var end = document.createElement(\"section\");\n  end.className = \"endcard\";\n  end.innerHTML = '<h2>That\\'s the whole story.</h2><p>Six clips, one rooftop sunrise. Keep going — that\\'s the whole story.</p><div style=\"display:flex;gap:10px;flex-wrap:wrap;justify-content:center\"><button class=\"btn\" type=\"button\" id=\"replayBtn\">↻ Watch again</button><a class=\"btn ghost\" href=\"#/discover\">Browse clips</a></div>';\n  feed.appendChild(end);\n  end.querySelector(\"#replayBtn\").addEventListener(\"click\", function(){ feed.scrollTo({top:0, behavior:\"smooth\"}); });\n  wireFeed();\n  renderDiscover(); renderProfile();\n}\n\nfunction wireFeed(){\n  var videos = Array.prototype.slice.call(feed.querySelectorAll(\"video\"));\n  videos.forEach(function(v){\n    var lastTap = 0;\n    v.addEventListener(\"click\", function(){\n      var now = Date.now();\n      if (now - lastTap < 300){ doubleLike(v); lastTap = 0; return; }\n      lastTap = now;\n      setTimeout(function(){\n        if (Date.now() - lastTap < 300) return;\n        var badge = v.parentElement.querySelector(\".pause-badge\");\n        if (v.paused){ v.play(); badge.style.display = \"none\"; }\n        else { v.pause(); badge.style.display = \"block\"; }\n      }, 300);\n    });\n    v.addEventListener(\"timeupdate\", function(){\n      var bar = v.parentElement.querySelector(\".progress i\");\n      if (v.duration) bar.style.width = (v.currentTime / v.duration * 100) + \"%\";\n    });\n  });\n  feed.querySelectorAll(\".like-btn\").forEach(function(b){\n    b.addEventListener(\"click\", function(){ toggleLike(parseInt(b.closest(\".clip\").dataset.i, 10)); });\n  });\n  feed.querySelectorAll(\".comment-btn\").forEach(function(b){\n    b.addEventListener(\"click\", function(){ openSheet(parseInt(b.closest(\".clip\").dataset.i, 10)); });\n  });\n  feed.querySelectorAll(\".share-btn\").forEach(function(b){\n    b.addEventListener(\"click\", function(){ shareClip(parseInt(b.closest(\".clip\").dataset.i, 10)); });\n  });\n  feed.querySelectorAll(\".followbtn\").forEach(function(b){\n    b.addEventListener(\"click\", function(){ setFollowing(!following); });\n  });\n  var observer = new IntersectionObserver(function(entries){\n    entries.forEach(function(e){\n      var v = e.target.querySelector(\"video\");\n      e.target.classList.toggle(\"in-view\", e.intersectionRatio > 0.6);\n      if (!v) return;\n      if (e.intersectionRatio > 0.6){ v.muted = !soundOn; v.play().catch(function(){}); }\n      else v.pause();\n    });\n  }, {threshold:[0, 0.6, 1]});\n  feed.querySelectorAll(\".clip\").forEach(function(c){ observer.observe(c); });\n}\n\nfunction toggleLike(i, silent){\n  var key = clipKey(i);\n  liked[key] = !liked[key];\n  save(\"drift-likes\", liked);\n  var list = allClips();\n  if (liked[key] && !silent) logActivity(\"♥\", \"You liked <b>\" + list[i].title + \"</b>.\");\n  buildFeed();\n  renderProfile();\n  var el = feed.querySelector('.clip[data-i=\"' + i + '\"]');\n  if (el){ var v = el.querySelector(\"video\"); if (v && v.paused) v.play().catch(function(){}); }\n}\nfunction doubleLike(v){\n  var i = parseInt(v.parentElement.dataset.i, 10);\n  var key = clipKey(i);\n  var heart = v.parentElement.querySelector(\".big-heart\");\n  heart.classList.remove(\"pop\"); void heart.offsetWidth; heart.classList.add(\"pop\");\n  if (!liked[key]) toggleLike(i);\n}\nfunction setFollowing(val){\n  following = val;\n  save(\"drift-following\", following);\n  if (val) logActivity(\"＋\", \"You followed <b>@stillstanding</b>.\");\n  buildFeed();\n  renderProfile();\n  toast(val ? \"Following @stillstanding\" : \"Unfollowed @stillstanding\");\n}\nfunction shareClip(i){\n  var url = \"https://biton.is-a.dev/drift#clip-\" + (i+1);\n  if (navigator.clipboard){ navigator.clipboard.writeText(url).then(function(){ toast(\"Link copied\"); }, function(){ toast(url); }); }\n  else toast(url);\n}\nfunction openSheet(i){\n  currentSheet = i;\n  var list = allClips();\n  document.getElementById(\"sheetTitle\").textContent = \"Comments · \" + list[i].title;\n  renderComments();\n  document.getElementById(\"sheet\").classList.add(\"on\");\n}\nfunction renderComments(){\n  var key = clipKey(currentSheet);\n  var list = comments[key] || [];\n  var box = document.getElementById(\"commentList\");\n  box.innerHTML = list.length ? \"\" : '<div class=\"empty\"><b>No comments yet</b>Be the first to say something about this clip.</div>';\n  list.forEach(function(c){\n    var d = document.createElement(\"div\");\n    d.className = \"comment\";\n    d.innerHTML = '<div class=\"av\">Y</div><div><b>You</b><p></p></div>';\n    d.querySelector(\"p\").textContent = c.text;\n    box.appendChild(d);\n  });\n  box.scrollTop = box.scrollHeight;\n}\ndocument.getElementById(\"sheetClose\").addEventListener(\"click\", function(){ document.getElementById(\"sheet\").classList.remove(\"on\"); });\ndocument.getElementById(\"commentForm\").addEventListener(\"submit\", function(e){\n  e.preventDefault();\n  var input = document.getElementById(\"commentInput\");\n  var text = input.value.trim();\n  if (!text || currentSheet < 0) return;\n  var key = clipKey(currentSheet);\n  comments[key] = comments[key] || [];\n  comments[key].push({text:text, at:Date.now()});\n  save(\"drift-comments\", comments);\n  logActivity(\"💬\", \"You commented on <b>\" + allClips()[currentSheet].title + \"</b>: “\" + text.replace(/</g, \"&lt;\") + \"”\");\n  input.value = \"\";\n  renderComments();\n  buildFeed();\n});\n\n/* Discover */\nvar allTags = [\"All\"];\nclips.forEach(function(c){ c.tags.forEach(function(t){ if (allTags.indexOf(t) === -1) allTags.push(t); }); });\nfunction renderDiscover(){\n  var chips = document.getElementById(\"tagChips\");\n  chips.innerHTML = \"\";\n  allTags.forEach(function(t){\n    var b = document.createElement(\"button\");\n    b.type = \"button\"; b.className = \"chip\" + (activeTag === t ? \" on\" : \"\"); b.textContent = t;\n    b.addEventListener(\"click\", function(){ activeTag = t; renderDiscover(); });\n    chips.appendChild(b);\n  });\n  var q = (document.getElementById(\"discoverSearch\").value || \"\").trim().toLowerCase();\n  var grid = document.getElementById(\"discoverGrid\");\n  grid.innerHTML = \"\";\n  var shown = 0;\n  allClips().forEach(function(c, i){\n    var hay = (c.title + \" \" + c.text + \" \" + c.tags.join(\" \")).toLowerCase();\n    if (q && hay.indexOf(q) === -1) return;\n    if (activeTag !== \"All\" && c.tags.indexOf(activeTag) === -1) return;\n    shown++;\n    var t = document.createElement(\"button\");\n    t.type = \"button\"; t.className = \"tile\";\n    t.style.setProperty(\"--d\", (shown % 6) * 0.05 + \"s\");\n    t.innerHTML = '<video src=\"' + c.src + '\" muted playsinline preload=\"metadata\"></video><span class=\"dur\">0:10</span><span class=\"cap\">' + c.title + '</span>';\n    t.addEventListener(\"click\", function(){ showView(\"feed\"); setTimeout(function(){ var el = feed.querySelector('.clip[data-i=\"' + i + '\"]'); if (el) el.scrollIntoView({behavior:\"smooth\"}); }, 60); });\n    grid.appendChild(t);\n  });\n  document.getElementById(\"discoverEmpty\").style.display = shown ? \"none\" : \"block\";\n}\ndocument.getElementById(\"discoverSearch\").addEventListener(\"input\", renderDiscover);\n\n/* Create / upload */\nvar pickedFile = null;\ndocument.getElementById(\"pickBtn\").addEventListener(\"click\", function(){ document.getElementById(\"fileInput\").click(); });\ndocument.getElementById(\"fileInput\").addEventListener(\"change\", function(e){\n  pickedFile = e.target.files && e.target.files[0];\n  if (!pickedFile) return;\n  var url = URL.createObjectURL(pickedFile);\n  var pv = document.getElementById(\"previewVideo\");\n  pv.src = url; pv.style.display = \"block\"; pv.play().catch(function(){});\n  if (!document.getElementById(\"upTitle\").value) document.getElementById(\"upTitle\").value = pickedFile.name.replace(/\\.[^.]+$/, \"\").replace(/[-_]/g, \" \");\n});\ndocument.getElementById(\"publishBtn\").addEventListener(\"click\", function(){\n  if (!pickedFile){ toast(\"Choose a video first\"); return; }\n  var title = document.getElementById(\"upTitle\").value.trim() || \"Untitled Drift\";\n  var caption = document.getElementById(\"upCaption\").value.trim() || \"Made on Drift.\";\n  uploads.unshift({src:URL.createObjectURL(pickedFile), handle:\"@you\", title:title, text:caption, tags:[\"Your clip\"]});\n  logActivity(\"＋\", \"You published <b>\" + title + \"</b> to the feed.\");\n  document.getElementById(\"upTitle\").value = \"\"; document.getElementById(\"upCaption\").value = \"\";\n  document.getElementById(\"previewVideo\").style.display = \"none\"; pickedFile = null;\n  buildFeed();\n  showView(\"feed\");\n  toast(\"Published — it's at the top of your feed\");\n});\n\n/* Inbox */\nfunction renderInbox(){\n  var box = document.getElementById(\"activityList\");\n  box.innerHTML = \"\";\n  document.getElementById(\"inboxEmpty\").style.display = activity.length ? \"none\" : \"block\";\n  activity.forEach(function(a){\n    var d = document.createElement(\"div\");\n    d.className = \"notif\";\n    d.innerHTML = '<div class=\"ic\">' + a.icon + '</div><div><p>' + a.html + '</p><time>' + a.at + '</time></div>';\n    box.appendChild(d);\n  });\n}\ndocument.getElementById(\"clearActivity\").addEventListener(\"click\", function(){ activity = []; save(\"drift-activity\", activity); renderInbox(); });\n\n/* Profile */\nfunction renderProfile(){\n  var list = allClips();\n  document.getElementById(\"statVideos\").textContent = list.length;\n  document.getElementById(\"statLikes\").textContent = Object.keys(liked).filter(function(k){ return liked[k]; }).length;\n  document.getElementById(\"statFollowing\").textContent = following ? 1 : 0;\n  var btn = document.getElementById(\"profileFollow\");\n  btn.textContent = following ? \"Following\" : \"Follow\";\n  var grid = document.getElementById(\"profileGrid\");\n  grid.innerHTML = \"\";\n  var items = profileTab === \"liked\"\n    ? list.map(function(c, i){ return {c:c, i:i}; }).filter(function(x){ return liked[clipKey(x.i)]; })\n    : list.map(function(c, i){ return {c:c, i:i}; });\n  document.getElementById(\"profileEmpty\").style.display = items.length ? \"none\" : \"block\";\n  items.forEach(function(x){\n    var t = document.createElement(\"button\");\n    t.type = \"button\"; t.className = \"tile\";\n    t.style.setProperty(\"--d\", (items.indexOf(x) % 6) * 0.05 + \"s\");\n    t.innerHTML = '<video src=\"' + x.c.src + '\" muted playsinline preload=\"metadata\"></video><span class=\"dur\">0:10</span><span class=\"cap\">' + x.c.title + '</span>';\n    t.addEventListener(\"click\", function(){ showView(\"feed\"); setTimeout(function(){ var el = feed.querySelector('.clip[data-i=\"' + x.i + '\"]'); if (el) el.scrollIntoView({behavior:\"smooth\"}); }, 60); });\n    grid.appendChild(t);\n  });\n}\ndocument.getElementById(\"tabVideos\").addEventListener(\"click\", function(){ profileTab = \"videos\"; document.getElementById(\"tabVideos\").classList.add(\"on\"); document.getElementById(\"tabLiked\").classList.remove(\"on\"); renderProfile(); });\ndocument.getElementById(\"tabLiked\").addEventListener(\"click\", function(){ profileTab = \"liked\"; document.getElementById(\"tabLiked\").classList.add(\"on\"); document.getElementById(\"tabVideos\").classList.remove(\"on\"); renderProfile(); });\ndocument.getElementById(\"profileFollow\").addEventListener(\"click\", function(){ setFollowing(!following); });\ndocument.getElementById(\"profileShare\").addEventListener(\"click\", function(){\n  var url = \"https://biton.is-a.dev/drift\";\n  if (navigator.clipboard) navigator.clipboard.writeText(url).then(function(){ toast(\"Profile link copied\"); });\n});\n\n/* Views + routing */\nvar viewIds = [\"feed\", \"discover\", \"create\", \"inbox\", \"profile\"];\nfunction showView(v){\n  viewIds.forEach(function(id){ document.getElementById(id).classList.toggle(\"on\", id === v); });\n  document.querySelectorAll(\".bottomnav button\").forEach(function(b){ b.classList.toggle(\"on\", b.dataset.view === v); });\n  var isFeed = v === \"feed\";\n  document.getElementById(\"feedtabs\").style.display = isFeed ? \"flex\" : \"none\";\n  document.getElementById(\"soundBtn\").style.display = isFeed ? \"block\" : \"none\";\n  document.getElementById(\"hint\").style.display = isFeed ? \"block\" : \"none\";\n  document.getElementById(\"topbar\").style.display = isFeed ? \"flex\" : \"none\";\n  if (v === \"inbox\") renderInbox();\n  if (v === \"profile\") renderProfile();\n  if (v === \"discover\") renderDiscover();\n  if (!isFeed){ feed.querySelectorAll(\"video\").forEach(function(vid){ vid.pause(); }); }\n  if (location.hash !== \"#/\" + v) history.replaceState(null, \"\", \"#/\" + v);\n}\ndocument.querySelectorAll(\".bottomnav button\").forEach(function(b){\n  b.addEventListener(\"click\", function(){ showView(b.dataset.view); });\n});\ndocument.getElementById(\"tabForYou\").addEventListener(\"click\", function(){ feedMode = \"foryou\"; document.getElementById(\"tabForYou\").classList.add(\"on\"); document.getElementById(\"tabFollowing\").classList.remove(\"on\"); buildFeed(); });\ndocument.getElementById(\"tabFollowing\").addEventListener(\"click\", function(){ feedMode = \"following\"; document.getElementById(\"tabFollowing\").classList.add(\"on\"); document.getElementById(\"tabForYou\").classList.remove(\"on\"); buildFeed(); });\ndocument.getElementById(\"soundBtn\").addEventListener(\"click\", function(){\n  soundOn = !soundOn;\n  document.getElementById(\"soundBtn\").textContent = soundOn ? \"🔊 Sound on\" : \"🔇 Sound off\";\n  feed.querySelectorAll(\"video\").forEach(function(v){ v.muted = !soundOn; });\n  toast(soundOn ? \"Sound on — the clips talk\" : \"Sound off\");\n});\nwindow.addEventListener(\"hashchange\", function(){\n  var h = location.hash.replace(\"#/\", \"\");\n  if (viewIds.indexOf(h) !== -1) showView(h);\n  else if (h.indexOf(\"clip-\") === 0){ showView(\"feed\"); }\n});\nbuildFeed();\nrenderInbox();\n(function(){\n  var h = location.hash.replace(\"#/\", \"\");\n  if (viewIds.indexOf(h) !== -1) showView(h);\n  else if (h.indexOf(\"clip-\") === 0){\n    showView(\"feed\");\n    var n = parseInt(h.replace(\"clip-\", \"\"), 10) - 1;\n    setTimeout(function(){ var el = feed.querySelector('.clip[data-i=\"' + n + '\"]'); if (el) el.scrollIntoView(); }, 300);\n  }\n})();\nsetTimeout(function(){ document.getElementById(\"hint\").style.display = \"none\"; }, 6000);\n</script>\n</body>\n</html>\n","code_bytes":36235}