  :root{
    --ink:#08080c; --panel:#111118; --line:#23232e;
    --text:#f2f0ea; --muted:#8b8b96;
    --signal:#5df0c2; --like:#ff3b5c;
    --display:'Unbounded', system-ui, sans-serif;
    --ui:system-ui, -apple-system, 'Segoe UI', sans-serif;
  }
  *{box-sizing:border-box; -webkit-tap-highlight-color:transparent}
  html,body{margin:0; height:100%; overflow:hidden; background:var(--ink); color:var(--text);
    font-family:var(--ui); overscroll-behavior:none; touch-action:none}
  button{font-family:var(--ui); border:0; background:none; color:inherit; cursor:pointer; padding:0}

  #app{position:fixed; inset:0}
  #track{position:absolute; inset:0; will-change:transform}
  .card{position:absolute; left:0; width:100%; height:100%; overflow:hidden; background:var(--ink)}
  .card canvas{position:absolute; inset:0; width:100%; height:100%}
  .card .svgwrap{position:absolute; inset:0}
  .card .svgwrap svg{width:100%; height:100%; display:block}

  #top{position:fixed; top:0; left:0; right:0; z-index:20; display:flex; align-items:center;
    justify-content:space-between; padding:calc(env(safe-area-inset-top) + 12px) 16px 10px;
    background:linear-gradient(#08080cd0, transparent); pointer-events:none}
  #logo{font-family:var(--display); font-weight:700; font-size:17px; letter-spacing:.5px}
  #logo em{font-style:normal; color:var(--signal)}
  #devicechip{font-size:10px; color:var(--muted); letter-spacing:.8px; text-transform:uppercase;
    display:flex; gap:6px; align-items:center}
  #devicechip .dot{width:7px; height:7px; border-radius:50%; background:var(--signal)}

  .chrome{position:absolute; inset:0; z-index:5; pointer-events:none}
  .caption{position:absolute; left:14px; right:86px; bottom:calc(env(safe-area-inset-bottom) + 22px);
    text-shadow:0 1px 8px #000c}
  .caption .cap{font-size:16px; line-height:1.35; margin:0 0 6px; font-weight:600}
  .caption .tags{font-size:13px; color:#d8d6cf; font-weight:600}
  .caption .genbadge{display:inline-flex; align-items:center; gap:5px; margin-top:10px;
    font-size:11px; font-weight:700; color:var(--ink); background:var(--signal);
    border-radius:99px; padding:4px 10px; letter-spacing:.2px; font-variant-numeric:tabular-nums}
  .caption .credit{font-size:10px; color:#c6c4bd; margin-top:7px; line-height:1.35; opacity:.85}

  .rail{position:absolute; right:10px; bottom:calc(env(safe-area-inset-bottom) + 30px);
    display:flex; flex-direction:column; gap:20px; align-items:center; pointer-events:auto}
  .rail button{display:flex; flex-direction:column; align-items:center; gap:3px;
    font-size:11px; color:var(--text); text-shadow:0 1px 6px #000c}
  .rail svg{width:31px; height:31px; fill:#fff; filter:drop-shadow(0 1px 4px #000a)}
  .rail .likebtn.on svg{fill:var(--like)}

  .heartburst{position:absolute; z-index:8; width:96px; height:96px; margin:-48px 0 0 -48px;
    pointer-events:none; animation:burst .7s ease-out forwards}
  .heartburst svg{width:100%; height:100%; fill:var(--like); filter:drop-shadow(0 2px 12px #0009)}
  @keyframes burst{0%{transform:scale(.4); opacity:0} 25%{transform:scale(1.15); opacity:1}
    70%{transform:scale(1); opacity:1} 100%{transform:scale(1.5); opacity:0}}
  @media (prefers-reduced-motion:reduce){.heartburst{animation:none; opacity:0}}

  #sheet{position:fixed; left:0; right:0; bottom:0; z-index:30; max-height:74%;
    background:var(--panel); border-radius:18px 18px 0 0; border-top:1px solid var(--line);
    transform:translateY(105%); transition:transform .28s cubic-bezier(.2,.8,.2,1);
    display:flex; flex-direction:column; padding-bottom:env(safe-area-inset-bottom)}
  #sheet.open{transform:translateY(0)}
  #sheet header{display:flex; align-items:flex-start; justify-content:space-between; padding:16px 18px 10px}
  #sheet h2{font-family:var(--display); font-size:14px; font-weight:700; margin:0;
    letter-spacing:.4px; color:var(--signal)}
  #sheet .sub{font-size:12px; color:var(--muted); margin:4px 0 0; line-height:1.4}
  #sheetclose{font-size:22px; color:var(--muted); line-height:1; padding:6px}
  #sheetbody{overflow-y:auto; padding:0 18px 22px}
  .statrow{display:grid; grid-template-columns:repeat(4,1fr); gap:8px; margin:8px 0 6px}
  .stat{background:var(--ink); border:1px solid var(--line); border-radius:10px; padding:10px 6px; text-align:center}
  .stat b{display:block; font-size:16px; font-variant-numeric:tabular-nums}
  .stat span{font-size:9px; color:var(--muted); text-transform:uppercase; letter-spacing:.6px}
  .privacyline{font-size:11px; color:var(--signal); margin:8px 0 12px; text-align:center}
  .dim h3{font-size:11px; text-transform:uppercase; letter-spacing:1px; color:var(--muted); margin:16px 0 8px}
  .bar{display:grid; grid-template-columns:96px 1fr 34px; gap:8px; align-items:center; font-size:12px; margin:5px 0}
  .bar .lbl{white-space:nowrap; overflow:hidden; text-overflow:ellipsis; text-transform:capitalize}
  .bar .tube{height:7px; border-radius:99px; background:var(--ink); border:1px solid var(--line); overflow:hidden}
  .bar .fill{height:100%; border-radius:99px; background:var(--signal)}
  .bar .val{color:var(--muted); text-align:right; font-variant-numeric:tabular-nums}
  #resetbtn{display:block; margin:18px auto 4px; font-size:12px; color:var(--muted);
    border:1px solid var(--line); border-radius:99px; padding:8px 18px}

  #toast{position:fixed; left:50%; bottom:110px; transform:translateX(-50%) translateY(20px);
    z-index:40; background:#1c1c26ee; border:1px solid var(--line); color:var(--text);
    border-radius:99px; padding:8px 16px; font-size:13px; opacity:0; transition:.25s; pointer-events:none}
  #toast.show{opacity:1; transform:translateX(-50%) translateY(0)}


  /* Shown until the first gesture unlocks audio; browsers block autoplay
     sound without one, so the feed starts silent rather than not at all. */
  /* Under the logo, not over the caption. At the bottom it sat across the
     title, the credit and the generated-on-device badge of the very first card
     - the three pieces of text most worth reading on the clip a stranger sees
     first. Raising it by a fixed amount only moved the collision: the caption
     block grows and shrinks with how many hashtags wrap, so there is no bottom
     offset that clears it on every clip. The top of the screen has one row in
     it and that row is a fixed height. */
  #soundpill{position:fixed; left:50%; transform:translateX(-50%); z-index:35;
    top:calc(env(safe-area-inset-top) + 56px); display:flex; align-items:center; gap:8px;
    background:#12121aee; border:1px solid var(--line); color:var(--text);
    border-radius:99px; padding:11px 20px; font-size:13px; font-weight:600;
    backdrop-filter:blur(8px); animation:pillpulse 2.6s ease-in-out infinite}
  #soundpill .ico{font-size:15px}
  @keyframes pillpulse{0%,100%{opacity:.82} 50%{opacity:1}}
  @media (prefers-reduced-motion:reduce){#soundpill{animation:none}}

  /* Visible only when app.js never executed - it removes this on boot. */
  /* Held back until a load has genuinely failed. The data file is over two
     megabytes, so from the first paint until app.js runs is seconds on a
     real connection - and this used to be on screen for all of it, telling
     people their host was broken while it was simply still downloading.
     A CSS delay rather than a timer: an inline script is the one thing
     script-src 'self' blocks, which is the host this banner is here for. */
  .bootnote{visibility:hidden; animation:bootreveal 0s linear 8s forwards;
    position:fixed; inset:auto 16px 16px; z-index:60; display:flex;
    flex-direction:column; gap:6px; background:#2a1420; border:1px solid #6b2740;
    color:#ffd9e2; border-radius:12px; padding:14px 16px; font-size:13px; line-height:1.5}
  @keyframes bootreveal{ to{ visibility:visible } }
  .bootnote code{background:#00000055; border-radius:4px; padding:1px 5px; font-size:12px}

  /* Only present with ?debug=1 */
  #audiodebug{position:fixed; left:8px; top:56px; z-index:70; max-width:82vw;
    background:#0d1a16ee; border:1px solid var(--signal); color:var(--signal);
    border-radius:8px; padding:7px 11px; font-size:11px; line-height:1.4;
    font-family:ui-monospace, SFMono-Regular, Menlo, monospace; word-break:break-all}

  /* ?debug=1 only: export the clip on screen for hand-editing */
  #savesvg{position:fixed; left:8px; top:104px; z-index:70; font-size:11px; font-weight:600;
    background:#12121a; border:1px solid var(--signal); color:var(--signal);
    border-radius:8px; padding:7px 12px; cursor:pointer}

  /* ?audit=1 only */
  #audit{position:fixed; left:8px; right:8px; top:56px; z-index:80; max-height:72vh; overflow:auto;
    background:#0d1016f2; border:1px solid var(--signal); color:var(--text);
    border-radius:10px; padding:12px 14px; font-size:12px; line-height:1.6;
    font-family:ui-monospace, SFMono-Regular, Menlo, monospace}
  #audit b{color:var(--signal)}
  #audit .bad{margin-top:8px; color:#ff9aa8}
  #audit button{margin-top:10px; background:var(--signal); color:var(--ink);
    border-radius:99px; padding:7px 14px; font-weight:700; font-size:12px}

/* The overlay sits above the base layer - canvas or SVG - and must never
   intercept a swipe. */
.svgwrap.overlay{ position:absolute; inset:0; pointer-events:none; z-index:2; }

/* ---- channels ---- */
.chanrow{ display:flex; align-items:center; gap:8px; margin-bottom:6px; }
.chan{ font-size:12px; font-weight:700; letter-spacing:.02em; opacity:.92; }
/* .chrome is pointer-events:none so a swipe anywhere on the card passes
   through to the feed. Anything inside it that is meant to be pressed has to
   opt back in - .rail does, and this did not, so the button rendered, styled
   and labelled itself correctly and a click went straight through it into
   the artwork. */
.followbtn{ font:inherit; font-size:11px; font-weight:700; letter-spacing:.03em;
  padding:3px 10px; border-radius:999px; cursor:pointer; pointer-events:auto;
  background:rgba(255,255,255,.14); color:#fff; border:1px solid rgba(255,255,255,.34); }
.followbtn.on{ background:#5df0c2; color:#08080c; border-color:#5df0c2; }
#lockpill{ display:none; align-items:center; gap:8px; font:inherit; font-size:11px;
  font-weight:700; padding:4px 10px; border-radius:999px; cursor:pointer;
  background:#5df0c2; color:#08080c; border:0; }
#lockpill.on{ display:inline-flex; }
#lockpill b{ opacity:.6; }
.onlyrow{ display:flex; align-items:center; gap:10px; padding:10px 2px 14px; font-size:13px; }
.chanrow2{ display:flex; align-items:center; gap:12px; padding:12px 2px;
  border-top:1px solid rgba(255,255,255,.10); }
.chanico{ font-size:26px; width:34px; text-align:center; flex:0 0 auto; }
.chanmeta{ display:flex; flex-direction:column; gap:2px; min-width:0; flex:1 1 auto; }
.chanmeta b{ font-size:14px; }
.chanmeta span{ font-size:11.5px; opacity:.62; }
.chanmeta .chanseen{ opacity:.4; font-size:10.5px; letter-spacing:.04em; }
.chanbtns{ display:flex; flex-direction:column; gap:6px; flex:0 0 auto; }
.watchbtn{ font:inherit; font-size:11px; font-weight:700; padding:3px 10px; border-radius:999px;
  cursor:pointer; background:transparent; color:#fff; border:1px solid rgba(255,255,255,.34); }
.watchbtn.on{ background:#fff; color:#08080c; }
#unlockbtn{ margin-top:16px; }

.onlyrow small{ opacity:.55; font-size:10.5px; font-weight:400; }

/* The credits link has to be tappable. .chrome is pointer-events:none so a
   swipe passes through the caption, and anything in there that is meant to be
   touched has to opt back in - the same reason the follow button does. */
.caption .creditlink{color:#c6c4bd; text-decoration:underline; pointer-events:auto;
  padding:2px 0; display:inline-block}
