/* Served through functions/site.css.js, which keeps this file in browsers for
   a year only when the ?v= it was asked for is the version being served (see
   functions/_versioned.js). */
/* The frame every page shares: the site name and the add box in the header,
   the menu in the bar beneath it, your channels down the left. Written by
   functions/_chrome.js; driven by /site.js.

   Everything here is addressed by id, or by an sl- class, because the pages it
   sits in have their own .btn, .plat-badge and .chan-name meaning something
   else, and a shared class name would restyle one from the other. Pages that
   do not zero margins and padding globally still get a tidy frame, so each
   rule sets its own.

   Served under ?v=ASSET_VERSION, a hash of this file (tools/sync-chrome.mjs):
   browsers keep it for a year, Cloudflare's edge for five minutes (_headers). */

:root{
    /* --sidebar-open-w is how wide the list is; --sidebar-w how much room it
       takes from the page, which is none while it is folded away. */
    --sidebar-open-w:175px;--sidebar-w:var(--sidebar-open-w);--sidebar-gap:5px;
    /* Measured at runtime by syncChromeHeight() in site.js, because the header
       and menu wrap onto more rows on a narrow screen. These are the desktop
       values, used for the moment before the script has run. */
    --header-h:47px;--chrome-h:84px;
}
body.sidebar-collapsed{--sidebar-w:0px;--sidebar-gap:0px;}
html{scroll-padding-top:calc(var(--chrome-h) + 8px);}

/* ---------- header: site name, add box, view tools ---------- */
#header{
    position:fixed;top:0;left:0;right:0;min-height:47px;box-sizing:border-box;
    display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);align-items:center;gap:12px;padding:7px 14px;margin:0;
    background:#141414;border-bottom:1px solid #2c2c2c;z-index:1100;font-family:sans-serif;
}
/* Three columns, the outer two always equal, so the add box sits dead centre
   however long the site name or however many tools are on the right. */
#header .brand{
    justify-self:start;max-width:100%;margin:0;font-size:14px;font-weight:600;color:#c4c4c4;letter-spacing:.3px;line-height:1.2;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;flex:0 1 auto;
}
/* What the site is, on a line of its own under the name. */
#header .brand-dim{display:block;color:#7a7a7a;font-weight:400;font-size:11px;line-height:1.3;margin-top:1px;
    overflow:hidden;text-overflow:ellipsis;}
/* Below this the tagline would be cut off mid-word beside the centred box
   (it needs about 1035px since "& schedules" joined it, 2026-10-07). */
@media(max-width:1060px){#header .brand-dim{display:none;}}

/* One control, not three: the platform, the name and the button share one
   border, so the add box reads as a single thing to type into. */
#add-bar{
    display:flex;align-items:stretch;min-width:0;height:32px;box-sizing:border-box;
    background:#1c1c1c;border:1px solid #2f2f2f;border-radius:7px;transition:border-color .15s,box-shadow .15s;
}
#add-bar:focus-within{border-color:#3f6f3f;box-shadow:0 0 0 2px rgba(76,175,80,.13);}
#platform-select{
    margin:0;padding:0 4px 0 10px;background:transparent;color:#bbb;border:none;border-right:1px solid #2c2c2c;
    border-radius:6px 0 0 6px;font-size:12px;cursor:pointer;outline:none;
}
#platform-select option{background:#1c1c1c;color:#ddd;}
#channel-wrap{position:relative;display:flex;min-width:0;}
#channel-input{
    margin:0;padding:0 10px;width:230px;min-width:0;background:transparent;color:#ddd;border:none;outline:none;
    font-size:12.5px;font-family:inherit;
}
#channel-input::placeholder{color:#666;}
#add-btn{
    margin:0;padding:0 16px;background:#16281a;color:#aee0ae;border:none;border-left:1px solid #2f4f2f;
    border-radius:0 6px 6px 0;font-size:12px;font-weight:600;cursor:pointer;transition:background .15s,color .15s;
}
#add-btn:hover{background:#1e3a24;color:#d4f5d4;}

/* Grid and Share act on what is already open rather than adding to it, so
   they sit apart from the add box at the far side, as rounded outline buttons
   with an icon each instead of another filled block. */
#view-tools{justify-self:end;display:flex;align-items:center;gap:6px;flex-shrink:0;}
.sl-tool{
    display:inline-flex;align-items:center;gap:6px;height:30px;margin:0;padding:0 13px 0 11px;box-sizing:border-box;
    background:transparent;color:#9a9a9a;border:1px solid #353535;border-radius:15px;
    font-size:11.5px;font-family:inherit;cursor:pointer;white-space:nowrap;
    transition:color .15s,border-color .15s,background .15s;
}
.sl-tool:hover{color:#e0e0e0;border-color:#5a5a5a;background:#1d1d1d;}
.sl-tool svg{width:13px;height:13px;flex-shrink:0;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round;}
.sl-tool.on{color:#cfe6cf;border-color:#3f6f3f;}
/* Kick vs Twitch and the recaps, as links in the same shape. */
a.sl-tool,a.sl-tool:hover{text-decoration:none;}
.sl-link svg .vs-k{fill:#53b153;stroke:none;}
.sl-link svg .vs-t{fill:#8f6fd0;stroke:none;}
/* Their names go first when the header runs short: the icon and its tooltip
   stay. On the viewer, Grid and Share keep theirs a little longer. */
@media(max-width:1240px){.sl-link{padding:0 8px;}.sl-link span{display:none;}}
/* Then, beside the centred add box, every tool goes to its icon. */
@media(min-width:701px) and (max-width:900px){#view-tools .sl-tool{padding:0 8px;}#view-tools .sl-tool span{display:none;}}

/* Suggestions under the add box. Results are other people's names and bios,
   and site.js only ever sets them through textContent. */
#suggest{
    position:absolute;top:calc(100% + 6px);left:-1px;width:300px;max-height:320px;overflow-y:auto;box-sizing:border-box;
    background:#141414;border:1px solid #2c2c2c;border-radius:6px;
    box-shadow:0 8px 28px rgba(0,0,0,.6);z-index:1200;display:none;padding:4px;font-family:sans-serif;
}
#suggest.open{display:block;}
#suggest .sg-item{display:flex;align-items:center;gap:8px;padding:6px 7px;border-radius:4px;cursor:pointer;}
#suggest .sg-item:hover,#suggest .sg-item.active{background:#222;}
#suggest .sg-avatar{width:26px;height:26px;border-radius:50%;flex-shrink:0;background:#222;object-fit:cover;border:1px solid #2c2c2c;}
#suggest .sg-avatar.blank{display:flex;align-items:center;justify-content:center;font-size:12px;color:#666;font-weight:700;}
#suggest .sg-body{min-width:0;flex:1;}
#suggest .sg-name{font-size:13px;color:#ddd;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
#suggest .sg-meta{font-size:11px;color:#7a7a7a;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
#suggest .sg-live{color:#4caf50;font-weight:600;}
#suggest .sg-note{padding:8px 9px;font-size:12px;color:#7a7a7a;}
#suggest .sg-warn{padding:6px 9px;font-size:11px;color:#8a7a4a;border-top:1px solid #2c2c2c;}

/* ---------- menu bar ---------- */
/* Three columns, the two sides always the same width: the go-live notice on
   the left, the menu in the middle, the grid's layouts on the right. As a
   flex row the notice took its width from the menu's, and every notice that
   came or went slid the links sideways under the pointer; now the middle
   column is centred whatever either side holds, and the menu never moves. */
#controls{
    position:fixed;top:var(--header-h);left:0;right:0;min-height:37px;box-sizing:border-box;
    display:grid;grid-template-columns:minmax(0,1fr) minmax(0,max-content) minmax(0,1fr);
    align-items:center;column-gap:10px;padding:0 10px;margin:0;
    background:#161616;border-bottom:1px solid #2c2c2c;z-index:1000;font-family:sans-serif;
}
/* One line at every width: it scrolls sideways once the links outgrow it, and
   stays centred while they fit — the auto margins give way when space runs
   out, where centring would clip the first link off the left edge. */
#site-nav{
    grid-column:2;grid-row:1;min-width:0;height:36px;display:flex;align-items:center;gap:14px;padding:0 4px;margin:0;
    font-size:12px;flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;
}
#site-nav::-webkit-scrollbar{display:none;}
#site-nav>:first-child{margin-left:auto;}
#site-nav>:last-child{margin-right:auto;}
#site-nav a,#site-nav span{white-space:nowrap;flex-shrink:0;}
#site-nav a{color:#8a8a8a;text-decoration:none;transition:color .15s;}
#site-nav a:hover{color:#ccc;text-decoration:none;}
#site-nav .current{color:#7a7a7a;cursor:default;}
#site-nav .sep{color:#333;}
/* The pages that only show what is live this minute. Pulses gently, and holds
   still for anyone who has asked for less motion. */
#site-nav .live-dot{
    display:inline-block;width:6px;height:6px;border-radius:50%;background:#4caf50;margin-right:5px;vertical-align:1px;
    box-shadow:0 0 5px rgba(76,175,80,.7);animation:nav-live 2.4s ease-in-out infinite;
}
@keyframes nav-live{50%{opacity:.35;}}
@media(prefers-reduced-motion:reduce){#site-nav .live-dot{animation:none;}}
@media(max-width:780px){#site-nav{gap:12px;}#site-nav .sep{display:none;}}
/* Its edges where it scrolls (navEdges, site.js): a chevron on a fade, held
   at the edge as the links pass under it, and only while there is more that
   way. Overlapping the link beside it (the negative margin takes back its
   own width and the gap), so they add nothing to the menu's length. */
#site-nav.has-edges>:first-child{margin-left:0;}
#site-nav.has-edges>:last-child{margin-right:0;}
#site-nav.has-edges>:nth-child(2){margin-left:auto;}
#site-nav.has-edges>:nth-last-child(2){margin-right:auto;}
#site-nav .nav-edge{
    position:sticky;z-index:1;flex:0 0 46px;align-self:stretch;margin:0;padding:0;border:0;
    color:#d6d6d6;font-size:20px;line-height:1;cursor:pointer;font-family:inherit;
    visibility:hidden;opacity:0;transition:opacity .15s;
}
#site-nav .nav-edge.r{right:-4px;margin-left:-58px;padding:0 2px 0 0;text-align:right;background:linear-gradient(to right,rgba(22,22,22,0),#161616 45%);}
#site-nav .nav-edge.l{left:-4px;margin-right:-58px;padding:0 0 0 2px;text-align:left;background:linear-gradient(to left,rgba(22,22,22,0),#161616 45%);}
#site-nav.more-r .nav-edge.r,#site-nav.more-l .nav-edge.l{visibility:visible;opacity:1;}
#site-nav .nav-edge:hover{color:#fff;}

/* The grid's layouts, at the right end of the bar while the grid is on. */
#grid-layouts{grid-column:3;grid-row:1;justify-self:end;display:flex;margin:4px 0;border:1px solid #353535;border-radius:13px;overflow:hidden;font-family:sans-serif;}
#grid-layouts[hidden]{display:none;}
#grid-layouts button{display:flex;align-items:center;margin:0;padding:4px 8px;background:transparent;border:none;color:#9a9a9a;cursor:pointer;}
#grid-layouts svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linejoin:round;}
#grid-layouts .mirror-x svg{transform:scaleX(-1);}
#grid-layouts .mirror-y svg{transform:scaleY(-1);}
#grid-layouts .mirror-x.mirror-y svg{transform:scale(-1,-1);}
#grid-layouts button:hover{color:#ddd;}
#grid-layouts button[aria-pressed="true"]{background:#1e3a24;color:#cfe6cf;}
/* Full screen for the whole grid, set apart from the three layouts. */
#grid-layouts .gl-full{border-left:1px solid #353535;}
#grid-layouts .gl-full[aria-pressed="true"]{background:transparent;color:#ddd;}
#grid-layouts .gl-full svg{stroke-linecap:round;}

/* The go-live notice, shown while the list is folded away. It sits in the
   chrome, and everything below starts at the chrome's measured height, so it
   can never land over a playing stream — the platforms pause a player that is
   covered. It leads the bar, at the left, over the list it opens. */
#live-bar{
    grid-column:1;grid-row:1;justify-self:start;display:flex;align-items:center;gap:6px;margin:4px 0;
    max-width:min(300px,100%);min-width:0;padding:4px 5px 4px 8px;box-sizing:border-box;
    background:#16281a;border:1px solid #2f4f2f;border-radius:5px;font-size:12px;color:#bbb;
}
#live-bar[hidden]{display:none;}
#live-bar .wave{font-size:13px;line-height:1;flex-shrink:0;display:inline-block;animation:sl-wave 1.5s infinite;}
#live-bar-text{
    background:none;border:none;padding:0;margin:0;font:inherit;color:#cfe6cf;cursor:pointer;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;
}
#live-bar-text:hover{color:#eee;text-decoration:underline;}
#live-bar-x{flex-shrink:0;background:none;border:none;margin:0;color:#6a8a6a;font-size:14px;line-height:1;cursor:pointer;padding:0 2px;transition:color .15s;}
#live-bar-x:hover{color:#ddd;}
/* Special events (site.js): the ribbon on every page while one is featured,
   and the bar over an event page's streams - each a full-width row of its own
   under the site's links, in the achievements' amber. */
#event-ribbon,#event-bar{grid-column:1 / -1;grid-row:2;margin:0 -10px;border-top:1px solid #2c2c2c;}
#event-ribbon{display:flex;align-items:center;gap:8px;padding:0 10px;min-height:30px;background:linear-gradient(90deg,#2a1d0e,#1a140d 60%,#161616);font-size:12.5px;}
#event-ribbon a{flex:1;min-width:0;display:flex;align-items:center;justify-content:center;gap:8px;color:#e9cf9a;text-decoration:none;overflow:hidden;white-space:nowrap;}
#event-ribbon a:hover .er-go{text-decoration:underline;}
.er-dot{width:7px;height:7px;border-radius:50%;background:#4caf50;flex-shrink:0;box-shadow:0 0 0 3px rgba(76,175,80,.18);}
.er-k,.eb-k{color:#c9a35a;font-weight:700;text-transform:uppercase;letter-spacing:.6px;font-size:10.5px;}
.er-name{color:#f2d394;font-weight:700;overflow:hidden;text-overflow:ellipsis;min-width:0;}
.er-n,.eb-n,.eb-when{color:#a89a7c;font-size:12px;}
.er-go{color:#f2d394;font-weight:600;}
.er-x{flex-shrink:0;background:none;border:0;color:#8a7a5a;font-size:16px;line-height:1;cursor:pointer;padding:0 2px;}
.er-x:hover{color:#eee;}
#event-bar{padding:7px 12px 8px;background:linear-gradient(90deg,#2a1d0e,#17130e 70%,#161616);font-size:13px;}
.eb-row{display:flex;align-items:center;flex-wrap:wrap;gap:6px 10px;}
.eb-name{color:#f2d394;font-weight:700;font-size:15px;}
.eb-tools{margin-left:auto;display:flex;gap:6px;}
.eb-btn{padding:4px 10px;font:600 12px sans-serif;color:#e9cf9a;background:#2f2513;border:1px solid #5a4520;border-radius:5px;cursor:pointer;white-space:nowrap;}
.eb-btn:hover{background:#3a2d14;color:#fff0cc;}
.eb-btn.eb-go{color:#cfe6cf;background:#16281a;border-color:#2f4f2f;}
.eb-btn.eb-go:hover{background:#1d3a24;}
.eb-about{margin-top:3px;color:#8f8a80;font-size:12px;}
.eb-about a{color:#d6d6d6;font-weight:600;text-decoration:underline;text-decoration-color:#555;text-underline-offset:2px;}
.eb-about a:hover{color:#fff;}
@media (max-width:640px){.eb-tools{margin-left:0;width:100%;} .eb-btn{flex:1;}}
.sl-emoji{font-family:"Apple Color Emoji","Segoe UI Emoji","Noto Color Emoji",sans-serif;}
@keyframes sl-wave{0%,100%{transform:rotate(0deg);}25%{transform:rotate(-20deg);}75%{transform:rotate(20deg);}}
/* Where the menu leaves no room beside it for the notice, the notice takes a
   line of its own under the menu rather than squeezing in beside it, so the
   links still stay where they are. The chrome's height is measured (site.js),
   so the page below moves down with it and nothing is covered. */
@media(max-width:1080px){
    #controls{grid-template-columns:minmax(0,1fr) auto;}
    #site-nav{grid-column:1;}
    #grid-layouts{grid-column:2;}
    #live-bar{grid-column:1 / -1;grid-row:2;max-width:100%;margin:0 0 6px;}
}

/* ---------- your channels ---------- */
/* It slides rather than narrowing: a transform is moved by the compositor,
   where animating the width laid the list out again on every frame. */
#sidebar{
    position:fixed;left:0;top:var(--chrome-h);bottom:0;width:var(--sidebar-open-w);box-sizing:border-box;margin:0;
    display:flex;flex-direction:column;padding:10px 8px;overflow-y:auto;
    background:#151515;border-right:1px solid #2c2c2c;z-index:999;color:#ddd;font-family:sans-serif;
    transition:transform .18s ease;
}
body.sidebar-collapsed #sidebar{transform:translateX(-100%);visibility:hidden;transition:transform .18s ease,visibility 0s linear .18s;}
#sidebar .history-separator{height:1px;background:#2c2c2c;margin:8px 0;}
#history-list{list-style:none;flex-grow:1;overflow-y:auto;margin:0 0 8px;padding:0;}
#history-list li{
    display:flex;align-items:center;gap:6px;padding:5px 6px;margin:0;border-bottom:1px solid #2c2c2c;color:#ddd;
    cursor:pointer;font-size:13px;line-height:1.3;transition:background .2s;
}
#history-list li:hover{background:#222;}
.sl-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.sl-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0;}
.sl-dot.live{background:#4caf50;}
.sl-dot.offline{background:#f44336;}
.sl-dot.error,.sl-dot.unknown{background:#ff9800;}
/* An event page's channels not on yet (site.js), in its list rather than folded away. */
#history-list li.sl-off .sl-name{color:#7c7c7c;}
#history-list li.sl-off .sl-dot{background:#444;}
.sl-dot.notfound{background:#ffca28;}
.sl-dot.just-went-live{width:auto;height:auto;font-size:14px;color:#4caf50;margin-right:4px;animation:sl-wave 1.5s infinite;}
.sl-badge{display:inline-block;background:#444;color:#bbb;font-size:10px;line-height:1.4;padding:1px 5px;border-radius:3px;font-weight:bold;margin-right:5px;}
.history-remove{
    margin-left:auto;flex-shrink:0;font-size:10px;color:#666;background:none;border:none;cursor:pointer;
    width:16px;height:16px;padding:0;display:flex;align-items:center;justify-content:center;border-radius:3px;
}
.history-remove:hover{color:#aaa;background:#333;}
/* On an event page, an event channel's row offers it to your own list. */
.history-mine{
    margin-left:auto;flex-shrink:0;font-size:13px;font-weight:700;color:#8fbf8f;background:none;border:none;cursor:pointer;
    width:16px;height:16px;padding:0;display:flex;align-items:center;justify-content:center;border-radius:3px;
}
.history-mine:hover{color:#cfe6cf;background:#1d3a24;}
.history-mine.done{color:#4caf50;cursor:default;background:none;font-size:11px;}
#offline-header{
    cursor:pointer;padding:8px 6px;background:#1e1e1e;border-radius:4px;margin:0 0 6px;
    font-weight:600;font-size:12px;color:#7a7a7a;white-space:nowrap;
}
#offline-header:hover{background:#282828;}
#list-tools{display:flex;flex-wrap:wrap;gap:6px;}
.sl-btn{
    flex:1 1 auto;margin:0;padding:6px 6px;background:#242424;color:#9a9a9a;border:1px solid #2c2c2c;border-radius:5px;
    font-size:11px;font-family:inherit;cursor:pointer;white-space:nowrap;transition:background .15s,color .15s;
}
.sl-btn:hover{background:#333;color:#ddd;}
#alerts-btn{flex-basis:100%;}
#alerts-btn[aria-pressed="true"]{color:#9fd89f;border-color:#2f4f2f;background:#16221a;}

#sidebar-toggle{
    position:fixed;left:0;top:calc(var(--chrome-h) + (100vh - var(--chrome-h)) / 2);
    transform:translate(var(--sidebar-w),-50%);width:18px;height:64px;padding:0;margin:0;box-sizing:border-box;
    background:#242424;color:#9a9a9a;border:1px solid #2c2c2c;border-left:none;border-radius:0 5px 5px 0;
    display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;
    font-size:12px;line-height:1;cursor:pointer;z-index:1001;
    transition:background .15s,color .15s,transform .18s ease;
}
#sidebar-toggle:hover{background:#333;color:#ddd;}
/* Its broadcast mark, drawn like the chat handle's bubble; the dot goes green
   while anyone in the list is live. */
#sidebar-toggle .sl-live-icon{width:11px;height:11px;flex-shrink:0;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round;}
#sidebar-toggle .sl-live-core{fill:currentColor;stroke:none;transition:fill .2s;}
#sidebar-toggle.has-live .sl-live-core{fill:#4caf50;filter:drop-shadow(0 0 2px rgba(76,175,80,.8));}
#sidebar-toggle.has-live .sl-live-icon path{stroke:#7fd67f;}
/* The go-live count on the handle, so the notice is still findable after it
   has been dismissed. */
#sidebar-toggle[data-live]::after{
    content:attr(data-live);position:absolute;top:-7px;left:2px;width:14px;height:14px;border-radius:50%;
    background:#4caf50;color:#0d0d0d;font-size:9px;font-weight:700;line-height:1;
    display:flex;align-items:center;justify-content:center;
}
body.no-sidebar-anim #sidebar,body.no-sidebar-anim #sidebar-toggle,body.no-sidebar-anim.site-page{transition:none;}
/* The list's and the chat's tabs, big enough for a finger on a touch screen
   and on a small one (18px was hard to hit), and centred on the screen that
   is actually showing: 100vh on a phone includes the address bar's height. */
@supports (height:100dvh){
    body #sidebar-toggle,body #chat-toggle{top:calc(var(--chrome-h) + (100dvh - var(--chrome-h)) / 2);}
}
@media (pointer:coarse),(max-width:1024px){
    body #sidebar-toggle,body #chat-toggle{width:30px;height:80px;gap:7px;font-size:15px;}
    body #sidebar-toggle .sl-live-icon,body #chat-toggle svg{width:15px;height:15px;}
    #sidebar-toggle[data-live]::after{left:7px;top:-8px;width:16px;height:16px;font-size:10px;}
}

#offline-modal{position:fixed;inset:0;background:rgba(0,0,0,.85);z-index:2000;display:none;align-items:center;justify-content:center;font-family:sans-serif;}
#offline-content{background:#1a1a1a;width:90%;max-width:500px;max-height:80vh;overflow-y:auto;border:1px solid #2c2c2c;border-radius:8px;padding:15px;box-sizing:border-box;color:#ddd;}
#offline-content .ol-title{margin:0 0 15px;padding:0;border:none;color:#eee;font-size:14px;font-weight:600;}
#offline-list{list-style:none;padding:0;margin:0;}
#offline-list li{display:flex;align-items:center;gap:6px;padding:8px;margin:0;border-bottom:1px solid #444;font-size:13px;color:#ddd;}
#close-offline{width:100%;margin-top:15px;}

/* ---------- the chat column (viewer only; chat.js) ---------- */
/* The channel list's twin on the right: open, it takes --chat-w from the
   streams, which move over to make room; folded, a tab on the edge brings it
   back. --chat-dock-w is how wide it is, --chat-w how much room it takes -
   the same, except on a phone, where it lies over the page instead. */
:root{--chat-dock-w:340px;}
body.chat-open{--chat-w:var(--chat-dock-w);}
#chat-dock{
    position:fixed;right:0;top:var(--chrome-h);bottom:0;width:var(--chat-dock-w);box-sizing:border-box;margin:0;
    display:flex;flex-direction:column;background:#0e0e10;border-left:1px solid #2c2c2c;z-index:999;
    color:#dedee3;font-family:sans-serif;font-size:13px;
    transform:translateX(100%);visibility:hidden;transition:transform .18s ease,visibility 0s linear .18s;
}
body.chat-open #chat-dock{transform:none;visibility:visible;transition:transform .18s ease;}
/* The grab strip on its left edge, a few pixels either side of the border. */
#cd-resize{position:absolute;left:-4px;top:0;bottom:0;width:8px;cursor:col-resize;z-index:2;touch-action:none;}
#cd-resize::after{content:"";position:absolute;left:3px;top:0;bottom:0;width:2px;background:transparent;transition:background .15s;}
#cd-resize:hover::after,#cd-resize:focus-visible::after,body.chat-resizing #cd-resize::after{background:#3f6f3f;}
#cd-resize:focus-visible{outline:none;}
body.chat-resizing{cursor:col-resize;user-select:none;}
@media(max-width:700px){#cd-resize{display:none;}}
#chat-dock .cd-top{display:flex;align-items:center;gap:8px;padding:7px 10px;background:#151515;border-bottom:1px solid #2c2c2c;}
#chat-dock .cd-title{margin-right:auto;font-weight:600;font-size:12.5px;color:#ccc;}
#cd-count{color:#7a7a7a;font-weight:400;}
#chat-dock .cd-mode{display:flex;border:1px solid #353535;border-radius:13px;overflow:hidden;}
#chat-dock .cd-mode button{margin:0;padding:3px 10px;background:transparent;border:none;color:#9a9a9a;font:inherit;font-size:11.5px;cursor:pointer;}
#chat-dock .cd-mode button[aria-pressed="true"]{background:#1e3a24;color:#cfe6cf;}
#cd-strip{display:flex;gap:4px;padding:6px 8px;overflow-x:auto;background:#151515;border-bottom:1px solid #2c2c2c;scrollbar-width:thin;}
#chat-dock.stack:not(.pick) #cd-strip,#chat-dock.empty #cd-strip{display:none;}
#chat-dock .cd-chip{
    display:inline-flex;align-items:center;gap:5px;flex-shrink:0;max-width:150px;margin:0;padding:4px 9px;
    background:#1c1c1c;border:1px solid #2a2a2a;border-radius:13px;color:#bbb;font:inherit;font-size:12px;cursor:pointer;white-space:nowrap;
}
#chat-dock .cd-chip:hover{border-color:#3a3a3a;color:#eee;}
#chat-dock .cd-chip[aria-selected="true"]{border-color:#3f6f3f;color:#e6f5e6;background:#16241a;}
.cd-scope .cd-chan{overflow:hidden;text-overflow:ellipsis;min-width:0;}
.cd-scope .cd-plat.kick{background:#1b3320;color:#7fd67f;}
.cd-scope .cd-plat.twitch{background:#271d3b;color:#b79cf2;}
#cd-frames{flex:1;min-height:0;display:flex;flex-direction:column;}
#chat-dock .cd-chat{display:flex;flex-direction:column;flex:1;min-height:0;}
#chat-dock:not(.stack) .cd-chat:not(.active){display:none;}
#chat-dock.stack .cd-chat:not(.stacked){display:none;}
#chat-dock.stack .cd-chat.stacked{min-height:0;}
#chat-dock.stack .cd-chat.stacked + .cd-chat.stacked,#chat-dock.stack .cd-chat.stacked ~ .cd-chat.stacked{border-top:2px solid #2c2c2c;}
#chat-dock .cd-head{display:none;align-items:center;gap:6px;padding:4px 8px;background:#18181b;border-bottom:1px solid #2c2c2c;}
#chat-dock.stack .cd-head{display:flex;}
#chat-dock:not(.stack) .cd-chat.active .cd-head{display:flex;}
#chat-dock .cd-head .cd-chan{flex:1;color:#ccc;font-size:12px;}
.cd-scope .cd-tool{margin:0;padding:2px 6px;background:none;border:none;border-radius:4px;color:#8a8a8a;font:inherit;cursor:pointer;}
.cd-scope .cd-tool:hover{color:#eee;background:#262626;}
.cd-scope .cd-view{position:relative;flex:1;min-height:0;display:flex;}
.cd-scope .cd-lines{flex:1;min-height:0;overflow-y:auto;padding:6px 0;line-height:1.5;scrollbar-width:thin;}
.cd-scope .cd-line{padding:3px 10px;margin:0;overflow-wrap:anywhere;}
.cd-scope .cd-line:hover{background:#18181b;}
.cd-scope .cd-line.system{color:#adadb8;font-size:12px;}
.cd-scope .cd-line.faint{color:#6f6f78;font-style:italic;}
.cd-scope .cd-line.notice{border-left:3px solid #6f3fb0;background:#18181b;margin:2px 0;}
.cd-scope .cd-line.deleted .cd-body{color:#6f6f78;font-style:italic;}
.cd-scope .cd-notice{color:#bf94ff;font-size:12px;}
.cd-scope .cd-reply{color:#8a8a93;font-size:11.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.cd-scope .cd-badge{display:inline-block;margin-right:4px;padding:0 4px;border-radius:3px;color:#fff;font-size:9.5px;font-weight:700;line-height:15px;vertical-align:1px;}
.cd-scope .cd-name{font-weight:700;}
.cd-scope .cd-emote{height:28px;width:auto;vertical-align:middle;margin:-5px 1px;}
.cd-scope .cd-url{color:#bf94ff;text-decoration:underline;text-underline-offset:2px;overflow-wrap:anywhere;}
.cd-scope .cd-url:hover{color:#d9c2ff;}
.cd-scope .cd-more{position:absolute;left:50%;bottom:10px;transform:translateX(-50%);margin:0;padding:5px 12px;border:none;border-radius:14px;background:#2f2f35;color:#efeff1;font:inherit;font-size:12px;cursor:pointer;box-shadow:0 4px 14px rgba(0,0,0,.5);}
.cd-scope .cd-more[hidden]{display:none;}
.cd-scope .cd-type{
    margin:6px 8px;padding:7px 10px;background:#1c1c1c;color:#bbb;border:1px solid #2f2f2f;border-radius:6px;
    font:inherit;font-size:12px;text-align:left;cursor:pointer;transition:background .15s,color .15s,border-color .15s;
}
.cd-scope .cd-type:hover{background:#232323;color:#e6e6e6;border-color:#3f6f3f;}
/* A stream's chat inside its card while the card is full screen (placeFull in
   chat.js), as it looks in the column. Typing opens a window over the column,
   which is not on screen then, so that waits until full screen is left. */
.fs-chat{display:flex;flex-direction:column;min-width:0;min-height:0;background:#0e0e10;border-left:1px solid #2c2c2c;color:#dedee3;font-family:sans-serif;font-size:13px;cursor:auto;}
.fs-chat .cd-head{display:flex;align-items:center;gap:6px;padding:4px 8px;background:#18181b;border-bottom:1px solid #2c2c2c;}
.fs-chat .cd-head .cd-chan{flex:1;color:#ccc;font-size:12px;}
.fs-chat .cd-type{display:none;}
#chat-dock .cd-empty{display:none;margin:0;padding:24px 18px;color:#8a8a8a;text-align:center;line-height:1.5;}
#chat-dock.empty .cd-empty{display:block;}
#chat-toggle{
    position:fixed;right:0;top:calc(var(--chrome-h) + (100vh - var(--chrome-h)) / 2);
    transform:translate(calc(-1 * var(--chat-w, 0px)),-50%);width:18px;height:64px;padding:0;margin:0;box-sizing:border-box;
    display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;
    background:#242424;color:#9a9a9a;border:1px solid #2c2c2c;border-right:none;border-radius:5px 0 0 5px;
    font-size:12px;line-height:1;cursor:pointer;z-index:1001;transition:background .15s,color .15s,transform .18s ease;
}
#chat-toggle:hover{background:#333;color:#ddd;}
#chat-toggle svg{width:11px;height:11px;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linejoin:round;}
body.chat-open #chat-toggle svg{stroke:#7fd67f;}
body.no-sidebar-anim #chat-dock,body.no-sidebar-anim #chat-toggle,body.chat-no-anim #chat-dock,
body.chat-no-anim #chat-toggle{transition:none;}
/* On a phone it lies over the page, like the list does there. */
@media(max-width:700px){
    :root{--chat-dock-w:min(340px, 88vw);}
    body.chat-open{--chat-w:0px;}
    body.chat-open #chat-toggle{transform:translate(calc(-1 * var(--chat-dock-w)),-50%);}
    #chat-dock{box-shadow:-8px 0 28px rgba(0,0,0,.6);z-index:1002;}
}
/* Held upright, under the streams instead: across the bottom of the screen,
   the streams in the room above it (the grid lays itself out again), where
   from the side it covered most of them. Its tab rides above it. */
@media(max-width:700px) and (orientation:portrait){
    :root{--chat-dock-h:36dvh;}   /* its tab drags it taller or shorter (chat.js) */
    #chat-dock{top:auto;left:0;right:0;width:auto;height:var(--chat-dock-h);border-left:none;border-top:1px solid #2c2c2c;
        box-shadow:0 -8px 24px rgba(0,0,0,.5);transform:translateY(100%);}
    body.chat-open #chat-dock{transform:none;}
    body.viewer.chat-open #container{bottom:calc(var(--chat-dock-h) + var(--chat-tab-h));}
    #cd-resize{display:none;}
    /* Its tab is the chat's own: a handle on the bottom edge, riding on top
       of the chat when it is open - not on the side, a thumb's stretch from
       the chat it opens. The streams stop above it (Twitch stops a player
       anything is drawn over). */
    :root{--chat-tab-h:26px;}
    body.viewer #container{bottom:var(--chat-tab-h);}
    body #chat-toggle,body.chat-open #chat-toggle{top:auto;right:auto;left:50%;bottom:0;transform:translateX(-50%);
        width:96px;height:var(--chat-tab-h);flex-direction:row;gap:8px;
        border:1px solid #2c2c2c;border-bottom:none;border-radius:9px 9px 0 0;}
    body.chat-open #chat-toggle{bottom:var(--chat-dock-h);}
    /* The list's tab, in the middle of what is left above the chat. */
    body.viewer.chat-open #sidebar-toggle{top:calc(var(--chrome-h) + (100dvh - var(--chrome-h) - var(--chat-dock-h) - var(--chat-tab-h)) / 2);}
    /* ‹ closed and › open (chat.js), turned to point up and down. */
    body #chat-toggle .cd-arrow{transform:rotate(90deg);}
    body.chat-open #chat-toggle{touch-action:none;cursor:ns-resize;}
}

/* ---------- every page but the viewer ---------- */
/* The page scrolls under the fixed frame and beside the list. Folding the list
   away gives its width back to the page. */
body.site-page{
    padding-top:var(--chrome-h);
    padding-left:calc(var(--sidebar-w) + var(--sidebar-gap));
    transition:padding-left .18s ease;
}
/* Each page's title, which used to be a second heading under a short label in
   the header. At the size the h2 had, unless the page says otherwise. */
:where(h1.page-title){font-size:1.5em;}

@media(max-width:700px){
    :root{--sidebar-open-w:170px;--sidebar-gap:0px;}
    /* Brand and the view tools on the first row, the add box across the whole
       second one, where there is room to type. */
    #header{display:flex;flex-wrap:wrap;row-gap:6px;padding:6px 10px;}
    #header .brand-dim{display:none;}
    #view-tools{margin-left:auto;}
    #add-bar{order:3;flex:1 0 100%;margin-left:0;height:36px;}
    #channel-wrap{flex:1;}
    #channel-input{width:100%;font-size:16px;}   /* 16px stops iOS zooming the page on focus */
    #suggest{width:min(300px,calc(100vw - 24px));}
    #site-nav{gap:12px;}
    #site-nav a,#site-nav .current{display:inline-block;padding:7px 2px;}
    #live-bar{max-width:100%;}
    /* On a phone the list lays over the page instead of squeezing it: a page
       beside a 170px column on a 375px screen is a page nobody can read. It
       starts folded away. The viewer's streams move over for it instead
       (index.html), so nothing lies over a player. */
    body.site-page{padding-left:0;}
    body.site-page #sidebar{box-shadow:8px 0 28px rgba(0,0,0,.6);}
}
@media(max-width:500px){
    :root{--sidebar-open-w:150px;}
    #history-list li{font-size:12px;padding:6px 4px;}
    #site-nav{font-size:11.5px;}
}

/* ---------------------------------- type ----------------------------------
   The reading pages' typography: Inter for text, Space Grotesk for titles,
   section labels and the big figures. Served from /fonts rather than a font
   service, so a page load asks nobody new for anything (see privacy.html).
   Latin only, which is every word the site writes; a channel name in another
   script falls back to the system font, as it did before.

   Scoped to body.site-page, and it outranks each page's own rules by that
   alone, so the pages' styles stay as they were and this sits on top. Two
   more places take it on every page, the viewer's included: the channel list
   on the left, and the homepage's text under the viewer (#home-about). The
   header and menu keep their own font, and so does the viewer itself. */
@font-face{
    font-family:"Inter";font-style:normal;font-weight:100 900;font-display:swap;
    src:url("/fonts/inter-latin-wght-normal.woff2") format("woff2");
    unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
    font-family:"Space Grotesk";font-style:normal;font-weight:300 700;font-display:swap;
    src:url("/fonts/space-grotesk-latin-wght-normal.woff2") format("woff2");
    unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
:root{
    --font-text:Inter,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
    --font-display:"Space Grotesk",Inter,system-ui,sans-serif;
}
body.site-page,#sidebar,#offline-modal,body #home-about{
    font-family:var(--font-text);
    font-feature-settings:"cv11";   /* Inter's single-storey a: less corporate */
    -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
    text-rendering:optimizeLegibility;
}
/* The channel list: names set tight, the Offline heading and its window in
   the display face. */
#history-list .sl-name,#offline-list li{letter-spacing:-.01em;}
/* Each channel in its platform's colour: a short line of it under the name's
   first letter, so the list reads by platform at a glance. It replaced a K or
   T badge before each name. data-platform is set where site.js builds the list
   and the Offline window. */
:is(#history-list,#offline-list) li[data-platform="kick"]{--plat:#53fc18;}
:is(#history-list,#offline-list) li[data-platform="twitch"]{--plat:#9146ff;}
:is(#history-list,#offline-list) li[data-platform] .sl-name::first-letter{
    text-decoration:underline 2px var(--plat);text-underline-offset:3px;text-decoration-skip-ink:none;
}
/* The name clips a long name at its edge, and the line would sit just past the
   bottom of it: room below, taken back so the row stays the same height. */
:is(#history-list,#offline-list) li[data-platform] .sl-name{padding-bottom:4px;margin-bottom:-4px;}
#offline-header{font-family:var(--font-display);letter-spacing:.02em;}
#offline-content .ol-title{font-family:var(--font-display);letter-spacing:-.01em;}

/* The homepage's text, as the reading pages: headings in the display face,
   the small section labels in spaced green capitals. The page's own rules are
   ids, so these carry one more selector to sit on top. */
body #home-about h2{font-family:var(--font-display);font-weight:700;letter-spacing:-.02em;line-height:1.2;}
body #home-about .ha-welcome h2{font-size:23px;}
body #home-about h3{
    font-family:var(--font-display);font-size:13px;font-weight:600;letter-spacing:.1em;
    text-transform:uppercase;color:#9fc79f;
}
body #home-about p{line-height:1.65;}
/* Form controls do not inherit a font unless told to. */
body.site-page .container :is(button,input,select,textarea){font-family:inherit;}

/* Page titles: the display face, tight, a touch larger on a wide screen. */
body.site-page .container :is(h1,.page-title){
    font-family:var(--font-display);font-weight:700;letter-spacing:-.022em;line-height:1.15;
    font-size:clamp(24px,calc(1.1vw + 17px),30px);
}
/* Section headings are what break a page into parts. Every block sits in the
   same dark box, so it is the heading's job to say a new one starts: the
   display face, a size clearly above the text, and a hairline under it with a
   short green lead-in. Drawn with a border and a positioned mark rather than
   by making the heading a flex row, so a heading with a link in the middle of
   its words keeps its spacing. Section headings are h2 on every page, under
   the page's one h1 - they were h3, a level skipped, which is how a crawler
   reads a page's outline. The homepage's take the same; its small link-column
   labels stay as they are. */
:is(body.site-page .container h2,body #home-about .ha-block > h2){
    position:relative;
    font-family:var(--font-display);font-size:19px;font-weight:600;line-height:1.25;
    letter-spacing:-.012em;text-transform:none;color:#ececec;
    padding-bottom:9px;margin-bottom:14px;border-bottom:1px solid #262626;
}
:is(body.site-page .container h2,body #home-about .ha-block > h2)::after{
    content:"";position:absolute;left:0;bottom:-1px;width:28px;height:2px;border-radius:1px;background:#4caf50;
}
body.site-page .container .chan-group h2 .count{font-family:var(--font-text);letter-spacing:0;}
/* Sub-headings, inside a section. :where() keeps this to a default: a page's
   own smaller label style for them (Kick and Twitch columns, say) stands. */
:where(body.site-page .container) h3{font-family:var(--font-display);font-size:16px;font-weight:600;letter-spacing:-.005em;}

/* One scale for everything else, where there were up to seventeen sizes on a
   page, half a pixel apart:
     11px    badges and the smallest labels
     12.5px  the details: counts, "live · watching", notes, timestamps
     14px    list text: names in a grid, stream titles
     15px    paragraphs, and the channel name heading a row
     16px    the lead: a page's intro, the first line of its facts
   Page titles and section headings are above. The details were 11 and 11.5px
   grey on near-black, the hardest text on the site to read; they gain the most. */
:is(body.site-page .container,body #home-about) p{font-size:15px;line-height:1.65;}
:is(body.site-page .container,body #home-about) :is(.intro,.facts p:first-child,.facts-lead p:first-child){font-size:16px;}
:is(body.site-page .container,body #home-about) :is(.channel-name){font-size:15px;}
:is(body.site-page .container,body #home-about) :is(.title,.reg-name,.oc-name,.chan-name,.cta){font-size:14px;}
:is(body.site-page .container,body #home-about) :is(.measured,.oc-meta,.oc-lead,.reg-meta,.reg-note,.reg-more,.chan-meta,.chan-also,
    .viewers,.views,.clip-views,.clips-note,.offair,.count,.stat-sub,.stat-foot,figcaption,.add-btn,.list-more,.chan-more){font-size:12.5px;}
:is(body.site-page .container,body #home-about) :is(.plat-badge,.stat-label,.tag,.here-chip,.oc-here){font-size:11px;}

/* Figures line up: counts, ranks and viewer numbers in tabular digits, and the
   big stat values in the display face. */
:is(body.site-page,#home-about) :is(.viewers,.views,.rank,.chan-rank,.count,.reg-meta,.chan-meta,.oc-meta,.clip-views,.measured,.stat-sub,.stat-foot){font-variant-numeric:tabular-nums;}
:is(body.site-page,#home-about) .stat-value{font-family:var(--font-display);font-size:22px;letter-spacing:-.015em;font-variant-numeric:tabular-nums;}
@media(max-width:500px){:is(body.site-page,#home-about) .stat-value{font-size:20px;}}
:is(body.site-page,#home-about) .stat-label{letter-spacing:.06em;}

/* Channel names, set tight like names should be. */
:is(body.site-page,#home-about) :is(.channel-name,.chan-name,.reg-name,.oc-name){letter-spacing:-.01em;}
/* "Updated 3 min ago" on its own, outside a facts block (updatedNote in
   functions/_lib.js): the same small grey line and green dot as the notes. */
:is(body.site-page .container,body #home-about) .upd-line{display:flex;align-items:center;gap:7px;color:#6e6e6e;font-size:11.5px;line-height:1.45;margin:-4px 0 12px;}
:is(body.site-page .container,body #home-about) .upd-line .dot{width:6px;height:6px;border-radius:50%;background:#4caf50;box-shadow:0 0 6px rgba(76,175,80,.75);flex:0 0 auto;}
:is(body.site-page .container,body #home-about) .upd-line:empty{display:none;}
/* "Watch" and "Add" side by side, wherever a row has a Watch button
   (rowActions, functions/_lib.js; and the static pages' own rows). Add puts
   the channel in the list and stays on the page (site.js). */
.row-actions{display:flex;align-items:center;gap:6px;flex-shrink:0;}
.row-actions > :is(a,button){margin:0;}
:is(body.site-page,#home-about) a.add-mini,.add-mini{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;min-width:48px;padding:6px 11px;font-size:12px;font-weight:600;line-height:1.2;color:#a9a9a9;background:transparent;border:1px solid #333;border-radius:5px;white-space:nowrap;text-decoration:none;cursor:pointer;}
:is(body.site-page,#home-about) a.add-mini:hover,.add-mini:hover{color:#ddd;border-color:#4a4a4a;background:#1c1c1c;text-decoration:none;}
:is(body.site-page,#home-about) a.add-mini.added,.add-mini.added{color:#9fc79f;border-color:#2f4f2f;background:#13201a;cursor:default;}
/* In a list row (.lr), under the lines, where a lone Watch button sat. */
.lr > li > .row-actions{grid-column:2 / -1;justify-self:start;margin-top:8px;}
@media(max-width:640px){
  /* Full width under the row, as the lone button was, Watch taking the room. */
  :is(.row,.card,.lr > li) > .row-actions{flex:1 0 100%;}
  body .row-actions .add-btn{flex:1 1 auto;width:auto;max-width:none;}
}
/* "Update", beside "Updated 34 min ago" when it is half an hour old (site.js).
   Above the measured lines' own "a { color: inherit }" (id-level), which it
   sits in. */
:is(body.site-page,#home-about) :is(.measured,.upd-line) a.upd-now,.upd-now{color:#9fc79f;font-weight:600;text-decoration:underline;text-decoration-color:#3c5a3c;text-underline-offset:2px;}
:is(body.site-page,#home-about) :is(.measured,.upd-line) a.upd-now:hover,.upd-now:hover{color:#c4e8c4;text-decoration-color:currentColor;}
/* The "measured" footnotes, a hair open so the small size stays legible. */
:is(body.site-page,#home-about) .measured{letter-spacing:.015em;}
/* A link in a footnote - the CC BY 4.0 licence - stays the footnote's grey, underlined. */
:is(body.site-page,#home-about) :is(.measured,.method,.rc-source) a{color:inherit;text-decoration:underline;text-decoration-color:#4a4a4a;text-underline-offset:2px;}
:is(body.site-page,#home-about) :is(.measured,.method,.rc-source) a:hover{color:#ccc;text-decoration-color:currentColor;}

/* -------------------------------- backdrop --------------------------------
   The background on a wide screen: the two platforms' colours as light,
   Kick's green rising from the bottom left beside the channel list and
   Twitch's purple from the top right, each with broadcast rings spreading out
   of its corner (the live icon's arcs, drawn large), and a faint grain over
   both. A fixed layer behind the page, so it never scrolls or repaints with
   it, drawn from inline SVG and gradients: nothing to download. Kept faint
   on purpose; it is the room, not the content.

   It only ever fills the spare space, and stands back from the content: each
   reading page's column carries a panel of the page's own background behind
   it (the .container::before below), solid for --focus-gap past the column's
   edge and feathering out over --focus-fade, so the art frames the content at
   the same distance on every page whatever its width, and moves with it when
   the channel list opens or closes. No text is ever set over the art, and
   every box stays as it was.

   The homepage takes it too while no stream is open, behind its text: there
   the viewer's area is its own scrolling box with its own background, so the
   layer sits inside it and a band around the text is masked out of it
   instead. With a stream open it is gone, and the viewer is as it was.

   Below 1100px there is no spare space, and no backdrop. */
@media (min-width:1100px){
    /* On body, not :root: the green corner sits at the channel list's edge,
       and a folded list is set on body (body.sidebar-collapsed). Defined on
       :root it read the open list's width whatever the list was doing, and
       with the list folded the rings started 175px in, cut off square. */
    body{
        --backdrop:
            url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1000 1000'><g fill='none' stroke='%239146ff' stroke-width='1.4'><circle cx='1000' cy='0' r='95' stroke-opacity='0.325'/><circle cx='1000' cy='0' r='160' stroke-opacity='0.288'/><circle cx='1000' cy='0' r='230' stroke-opacity='0.252'/><circle cx='1000' cy='0' r='305' stroke-opacity='0.217'/><circle cx='1000' cy='0' r='385' stroke-opacity='0.184'/><circle cx='1000' cy='0' r='470' stroke-opacity='0.153'/><circle cx='1000' cy='0' r='560' stroke-opacity='0.124'/><circle cx='1000' cy='0' r='655' stroke-opacity='0.098'/><circle cx='1000' cy='0' r='755' stroke-opacity='0.074'/><circle cx='1000' cy='0' r='860' stroke-opacity='0.053'/><circle cx='1000' cy='0' r='970' stroke-opacity='0.035'/></g></svg>") right top / min(70vmax,1300px) no-repeat,
            url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1000 1000'><g fill='none' stroke='%2353fc18' stroke-width='1.4'><circle cx='0' cy='1000' r='95' stroke-opacity='0.325'/><circle cx='0' cy='1000' r='160' stroke-opacity='0.288'/><circle cx='0' cy='1000' r='230' stroke-opacity='0.252'/><circle cx='0' cy='1000' r='305' stroke-opacity='0.217'/><circle cx='0' cy='1000' r='385' stroke-opacity='0.184'/><circle cx='0' cy='1000' r='470' stroke-opacity='0.153'/><circle cx='0' cy='1000' r='560' stroke-opacity='0.124'/><circle cx='0' cy='1000' r='655' stroke-opacity='0.098'/><circle cx='0' cy='1000' r='755' stroke-opacity='0.074'/><circle cx='0' cy='1000' r='860' stroke-opacity='0.053'/><circle cx='0' cy='1000' r='970' stroke-opacity='0.035'/></g></svg>") calc(var(--sidebar-w) + var(--sidebar-gap)) 100% / min(70vmax,1300px) no-repeat,
            radial-gradient(46vmax 46vmax at 100% 0%,rgba(145,70,255,.11),transparent 72%),
            radial-gradient(46vmax 46vmax at calc(var(--sidebar-w) + var(--sidebar-gap)) 100%,rgba(83,252,24,.075),transparent 72%),
            url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 .5 0'/></filter><rect width='100%' height='100%' filter='url(%23n)' opacity='.07'/></svg>") repeat;
    }

    /* The reading pages. The page's background moves to the root, so nothing
       on the body covers the layer: How to use set it on both, and the body's
       then painted over everything behind the page. */
    html:has(> body.site-page){background:var(--bg,#0d0d0d);}
    body.site-page{background:transparent;}
    body.site-page::before{
        content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;
        background:var(--backdrop);
    }
    /* The focus panel: the column's box, widened by gap and fade on each side
       and reaching up behind the header. Later in the page than the backdrop
       and on the same layer, so it paints over it; under the content, which
       sits on the page itself. The body clips it at the window's edges, which
       only holds once the root has an overflow of its own - otherwise the
       body's is handed to the window and ignored. */
    html:has(> body.site-page){overflow-x:hidden;}
    body.site-page{overflow-x:clip;}
    body.site-page .container{position:relative;--focus-gap:60px;--focus-fade:240px;}
    body.site-page .container::before{
        content:"";position:absolute;z-index:-1;pointer-events:none;
        top:calc(-1 * var(--chrome-h));bottom:0;
        left:calc(-1 * (var(--focus-gap) + var(--focus-fade)));right:calc(-1 * (var(--focus-gap) + var(--focus-fade)));
        background:var(--bg,#0d0d0d);
        -webkit-mask-image:linear-gradient(90deg,transparent,#000 var(--focus-fade),#000 calc(100% - var(--focus-fade)),transparent);
                mask-image:linear-gradient(90deg,transparent,#000 var(--focus-fade),#000 calc(100% - var(--focus-fade)),transparent);
    }

    /* The homepage, while nothing is playing. Fixed, so it holds still while
       the text scrolls; inside the viewer's area, so above its background and
       under its text. The clear band is the text's 780px plus the same gap
       and fade, centred where the text is: between the channel list and the
       chat column. */
    body.viewer #container:not(:has(.stream-card))::before{
        --cc:calc(50% + (var(--sidebar-w) + var(--sidebar-gap) - var(--chat-w,0px)) / 2);
        content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;
        background:var(--backdrop);
        -webkit-mask-image:linear-gradient(90deg,#000 calc(var(--cc) - 710px),transparent calc(var(--cc) - 470px),transparent calc(var(--cc) + 470px),#000 calc(var(--cc) + 710px));
                mask-image:linear-gradient(90deg,#000 calc(var(--cc) - 710px),transparent calc(var(--cc) - 470px),transparent calc(var(--cc) + 470px),#000 calc(var(--cc) + 710px));
    }
}

/* --------------------------------- finish ---------------------------------
   The last of the look, on every page. */

/* The frame in the site's type: the header, the add box's suggestions and the
   menu bar, on the viewer too. The name in the display face. The menu scrolls
   rather than wrapping when it runs out of room, so the wider face costs
   nothing at a narrow width. The chat column keeps its own. */
#header,#suggest,#controls{
    font-family:var(--font-text);font-feature-settings:"cv11";
    -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
}
#grid-layouts{font-family:var(--font-text);}
/* The grid's layout buttons only while there is a grid: with no stream open
   they arranged nothing. The Grid/Free switch likewise. */
body:not(:has(.stream-card)) #grid-layouts,
body:not(:has(.stream-card)) #layout-btn{display:none;}

/* The homepage's top channels: the line under the heading smaller, so it sits
   on one line on a desktop. */
body #home-about #home-top > p{font-size:13px;line-height:1.5;color:#8d8d8d;margin-bottom:10px;}
#header .brand{font-family:var(--font-display);letter-spacing:-.01em;}
#header .brand-dim{font-family:var(--font-text);letter-spacing:0;}

/* One width for every page's column. They ran from 700px (the 404) to 1100px
   (Top clips), so the page, and the backdrop's frame around it, changed size
   from one link to the next. 900px is what most already were. */
body.site-page .container{max-width:900px;}

/* Every page title on the left, as most already were: How to use and Top clips
   centred theirs. How to use's line under the title reads as the lead. */
body.site-page .container :is(h1,.page-title,.intro){text-align:left;}
body.site-page .container .subtitle{text-align:left;font-size:16px;color:#b4b4b4;margin-bottom:28px;}

/* A list's "Watch": quiet until it is itself pointed at, so a long list reads
   by its names rather than as a column of identical green buttons. Still a
   button at rest - a plain grey outline, as its "Add" is, where bare grey text
   read as a stray label - and lit only under the pointer (or keyboard focus),
   in the colour of the platform the stream is on: Kick's green, Twitch's
   purple. A row says its platform with a badge (category pages) or on the
   button itself (data-platform); one that says neither lights in the site's
   green. Not when only its row is pointed at: a list then lit a button on
   every row the pointer crossed. */
body.site-page .container :is(.row,.row-actions) .add-btn:not(.add-stream){
    --pf:#8fbf8f;--pf-line:#2f4f2f;--pf-bg:#16281a;--pf-hi:#aee0ae;--pf-edge:#4a8f4a;
    color:#9a9a9a;border-color:#303030;background:transparent;
    transition:color .15s,border-color .15s,background .15s;
}
body.site-page .container :is(.row:has(.plat-badge.kick) .add-btn,.add-btn[data-platform="kick"]):not(.add-stream){
    --pf:#86e064;--pf-line:#2c5a1e;--pf-bg:#132410;--pf-hi:#bff7a8;--pf-edge:#53fc18;
}
body.site-page .container :is(.row:has(.plat-badge.twitch) .add-btn,.add-btn[data-platform="twitch"]):not(.add-stream){
    --pf:#b69aff;--pf-line:#46307a;--pf-bg:#1d1530;--pf-hi:#ddd0ff;--pf-edge:#9146ff;
}
body.site-page .container :is(.row,.row-actions) .add-btn:not(.add-stream):is(:hover,:focus-visible){
    background:var(--pf-bg);color:var(--pf-hi);border-color:var(--pf-edge);text-decoration:none;
}
/* And one width, so the buttons line up as a column down the list instead of
   ending wherever their channel's name does. A name too long for it is cut
   with an ellipsis; the button's title still carries it whole. */
@media (min-width:700px){
    body.site-page .container .row .add-btn{
        box-sizing:border-box;flex:0 0 196px;width:196px;max-width:none;
        text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
    }
    /* Beside its "Add", it says "Watch" on every row - the name is the
       row's own - so one width that fits that is the column, and the room
       goes back to the row's title. */
    body.site-page .container .row .row-actions .add-btn{flex:0 0 84px;width:84px;}
}

/* Depth. Every box was the same flat fill and grey line; a lighter top edge
   lights them from above. A border rather than a shadow or a gradient, so the
   boxes that have one of those keep it. Cards you can click lift a pixel with
   a soft shadow under the pointer - moved as the whole list item, so a line
   laid over a card (Led by, also) moves with it. */
body.site-page .container :is(.facts,.pattern,.list,.stat,.step,.other-list a,.reg-list a,.chan-card){border-top-color:#383838;}
@media (hover:hover){
    body.site-page .container :is(.other-list,.reg-list,.chan-list) > li{transition:transform .15s ease;}
    body.site-page .container :is(.other-list,.reg-list,.chan-list) > li:hover{transform:translateY(-1px);}
    body.site-page .container :is(.other-list a,.reg-list a,.chan-card){transition:box-shadow .15s ease,background .15s,border-color .15s;}
    body.site-page .container :is(.other-list a,.reg-list a,.chan-card):hover{box-shadow:0 6px 16px rgba(0,0,0,.4);}
}
@media (prefers-reduced-motion:reduce){
    body.site-page .container :is(.other-list,.reg-list,.chan-list) > li:hover{transform:none;}
}

/* A row with no picture: the site's live mark on a dark green ground, rather
   than a grey box with LIVE or CLIP written in it, which read as a picture that
   failed. Not the ones carrying a game's art (.art). */
body.site-page .container .thumb-placeholder:not(.art){
    font-size:0;color:transparent;
    background:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><circle cx='8' cy='8' r='1.9' fill='%234caf50'/><path d='M5.3 5.3a3.8 3.8 0 0 0 0 5.4M10.7 5.3a3.8 3.8 0 0 1 0 5.4M3.2 3.2a6.8 6.8 0 0 0 0 9.6M12.8 3.2a6.8 6.8 0 0 1 0 9.6' fill='none' stroke='%234caf50' stroke-width='1.2' stroke-linecap='round'/></svg>") center / 22px no-repeat,linear-gradient(135deg,#17221a,#111411);
    border:1px solid #243024;
}

/* Keyboard focus, one way everywhere: a green ring just outside. Only for the
   keyboard (focus-visible), so a click shows nothing. Fields keep their own. */
:is(a,button,summary,[tabindex]):focus-visible{outline:2px solid rgba(111,191,111,.85);outline-offset:2px;}

/* The footer every page ends with (siteFooter, functions/_chrome.js): the map of
   the site in three columns, as wide as the page it closes. Headings in the
   site's green, links in the grey the rest of the site uses for links that are
   not the point of the page. On the homepage it sits inside #home-about, which
   already has its own width and side padding - and its own rules for links and
   paragraphs, scoped by id. The rules inside the footer are written
   :is(#home-about,body) so they carry an id's weight on every page and look the
   same on the homepage as everywhere else. */
.site-footer{max-width:900px;margin:16px auto 0;padding:24px 20px 44px;border-top:1px solid #262626;font-family:var(--font-text);}
:is(#home-about,body) .site-footer nav{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(180px,100%),1fr));gap:22px 40px;}
:is(#home-about,body) .site-footer .sf-head{margin:0 0 10px;font-family:var(--font-display);font-size:12px;line-height:1.4;font-weight:700;letter-spacing:.7px;text-transform:uppercase;color:#8fcf8f;}
:is(#home-about,body) .site-footer ul{list-style:none;margin:0;padding:0;}
:is(#home-about,body) .site-footer li{margin:0 0 8px;font-size:14px;line-height:1.4;}
:is(#home-about,body) .site-footer a{color:#9a9a9a;text-decoration:none;}
:is(#home-about,body) .site-footer a:hover{color:#e0e0e0;text-decoration:underline;text-underline-offset:2px;}
:is(#home-about,body) .site-footer [aria-current]{color:#dcdcdc;}
#home-about .site-footer{margin-top:8px;padding:22px 0 0;}
@media(max-width:640px){
    .site-footer{padding:22px 14px 36px;}
}

/* ---------- leaving for another page ----------
   The bar and "Loading..." shown on the page being left while the next one is
   built (navStarting in site.js). Kick green to Twitch purple, filling most of
   the way and waiting there for the page to arrive. */
#nav-loading{position:fixed;inset:0 0 auto 0;z-index:3000;pointer-events:none;opacity:0;transition:opacity .15s;}
#nav-loading.on{opacity:1;}
#nav-loading .nl-bar{display:block;height:3px;background:linear-gradient(90deg,#53fc18,#9146ff);transform:scaleX(0);transform-origin:left;}
#nav-loading.on .nl-bar{animation:nl-fill 6s cubic-bezier(.08,.7,.25,1) forwards;}
@keyframes nl-fill{from{transform:scaleX(0);}to{transform:scaleX(.9);}}
#nav-loading .nl-label{position:fixed;top:calc(var(--chrome-h) + 10px);left:50%;transform:translateX(-50%);
    padding:5px 13px;border-radius:999px;background:#1b1b1b;border:1px solid #333;color:#bdbdbd;
    font:12.5px/1.4 sans-serif;box-shadow:0 4px 14px rgba(0,0,0,.45);white-space:nowrap;}
@media(prefers-reduced-motion:reduce){
    #nav-loading.on .nl-bar{animation:none;transform:scaleX(1);opacity:.7;}
}

/* The site's lists of channels and categories (lrRow in functions/_lib.js):
   the name on a line of its own, wrapping if it is long, and under it the
   figure in bold, then the details, muted and cut short rather than wrapped. */
.lr{list-style:none;margin:0 0 6px;padding:0;counter-reset:lr;}
.lr > li{counter-increment:lr;display:grid;grid-template-columns:20px minmax(0,1fr);column-gap:10px;row-gap:2px;
    align-items:baseline;padding:8px 0;border-bottom:1px solid #222;}
.lr > li:last-child{border-bottom:none;}
.lr > li::before{content:counter(lr);color:var(--muted);font-size:12.5px;font-variant-numeric:tabular-nums;}
.lr.keyed > li{grid-template-columns:48px minmax(0,1fr);}
.lr:is(.keyed,.plain) > li::before{content:none;display:none;}
.lr.plain > li{grid-template-columns:minmax(0,1fr);}
.lr.plain .lr-sub{grid-column:1 / -1;}
.lr .lr-k{grid-row:span 2;color:#9a9a9a;font-size:13px;white-space:nowrap;font-variant-numeric:tabular-nums;}
.lr .lr-k em{display:block;font-style:normal;color:#6e6e6e;font-size:11px;}
.lr .lr-name{min-width:0;overflow-wrap:anywhere;color:#e2e2e2;font-size:15px;font-weight:600;line-height:1.35;}
.lr .lr-name a{color:inherit;text-decoration:none;}
.lr .lr-name a:hover{text-decoration:underline;text-underline-offset:2px;}
.lr .lr-sub{grid-column:2 / -1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#8f8f8f;font-size:13.5px;font-variant-numeric:tabular-nums;}
.lr .lr-sub a{color:#a9a9a9;text-decoration:none;}
.lr .lr-sub a:hover{color:#ddd;text-decoration:underline;}
.lr .lr-tag{margin-left:8px;color:#8f8f8f;font-size:13.5px;font-weight:400;}
/* A category beside the name stands out from the grey around it, in the
   shade Best on's rows give theirs; a plain note there ("· also on Twitch")
   stays grey. */
.lr .lr-tag a{color:#b4b4b4;}
/* And in the same shade: a category with no page to link (.cat-name), and a
   platform's name (.plat-name), wherever a row names one. */
:is(.lr, .depth, .row) :is(.cat-name, .plat-name){color:#b4b4b4;}
.lr .lr-tag a:hover{color:#ddd;}
.lr .lr-plat{display:inline-block;margin-left:6px;padding:1px 5px;border-radius:3px;font-size:10px;font-weight:700;line-height:1.4;vertical-align:1px;}
.lr .lr-plat.kick{background:#1b3320;color:#7fd67f;}
.lr .lr-plat.twitch{background:#271d3b;color:#b79cf2;}
.lr .lr-sub b{color:#e3bd6d;font-weight:600;}
.lr .lr-sub .up{color:#7cc97c;font-weight:600;}
.lr .lr-sub .down{color:#d68a8a;font-weight:600;}
/* A Kick/Twitch split in a list row (lrShare): the week's move, the dot on
   its track, the share in words. The tick in the middle is an even split. */
.lr .lr-share{grid-column:2 / -1;display:grid;grid-template-columns:40px minmax(0,1fr) 88px;align-items:center;gap:12px;margin:5px 0 3px;}
.lr.plain .lr-share{grid-column:1 / -1;}
.lr .lr-move{font-size:13px;font-weight:600;white-space:nowrap;color:#6e6e6e;font-variant-numeric:tabular-nums;}
.lr .lr-move.kick{color:#7fd67f;}
.lr .lr-move.twitch{color:#b79cf2;}
.lr .lr-track{position:relative;height:4px;border-radius:2px;background:linear-gradient(90deg,rgba(79,159,79,.5),rgba(138,108,192,.5));}
.lr .lr-track::after{content:"";position:absolute;left:50%;top:-3px;width:1px;height:10px;background:#555;}
.lr .lr-track i{position:absolute;top:50%;z-index:1;width:12px;height:12px;margin:-6px 0 0 -6px;border-radius:50%;border:2px solid #121212;}
.lr .lr-track i.kick{background:#5fbf5f;}
.lr .lr-track i.twitch{background:#9b7ae0;}
.lr .lr-pct{text-align:right;font-size:13.5px;font-weight:600;white-space:nowrap;font-variant-numeric:tabular-nums;}
.lr .lr-pct.kick{color:#7fd67f;}
.lr .lr-pct.twitch{color:#b79cf2;}
.lr .lr-sub .k{color:#8fd08f;}
.lr .lr-sub .t{color:#b79cf2;}

/* Two lists side by side (.kvt-cols: Kick and Twitch, biggest and most):
   each held to a readable width and centred in its half, so the space left
   over is even on both sides rather than all on the right. Where only one
   fits (two need 538px), the one fills the width from the left: held to
   360px and centred, it floated mid-page with a gap on either side - a phone
   on its side, most of all. */
.kvt-cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(260px,100%),1fr));gap:18px;margin-top:12px;container-type:inline-size;}
.kvt-cols > div{display:flex;flex-direction:column;align-items:center;}
.kvt-cols > div > *{width:100%;max-width:360px;}
@container (max-width:537px){
    .kvt-cols > div{align-items:stretch;}
    .kvt-cols > div > *{max-width:none;}
}
/* Figures in running text (proseFigures in functions/_lib.js): amber like the
   figure in a list row, a rise green and a fall red; Kick and Twitch named in
   their own colours. */
.fig{color:#e3bd6d;font-weight:600;font-variant-numeric:tabular-nums;}
.fig.up{color:#7fd67f;}
.fig.down{color:#e48a8a;}
.pf.k{color:#8fd08f;}
.pf.t{color:#b79cf2;}
/* A figure far above a channel's usual audience (_abnormal.js), noted. */
.spike-mark{color:#e0a85a;font-weight:700;cursor:help;margin-left:1px;}
/* A category's last seven days (catSpark, functions/_lib.js): a bar a day,
   Kick's part in green under Twitch's in purple. */
.cat-spark{display:inline-flex;align-items:flex-end;gap:2px;height:12px;margin-right:7px;vertical-align:-1px;flex:0 0 auto;}
.cat-spark i{display:flex;flex-direction:column;justify-content:flex-end;width:4px;border-radius:1px;background:#8a6cc0;overflow:hidden;}
.cat-spark i b.k{display:block;width:100%;background:#4f9f4f;}
.cat-spark i.off{height:2px;background:#333;}
.cat-spark.big{height:30px;gap:3px;margin-right:12px;vertical-align:middle;}
.cat-spark.big i{width:10px;border-radius:2px;}
/* Its labels (catLabels): rising, falling, its best day, new. */
.cat-label{display:inline-block;flex:0 0 auto;margin-left:6px;padding:0 6px;border:1px solid;border-radius:9px;font-size:10px;font-weight:700;letter-spacing:.4px;line-height:15px;text-transform:uppercase;vertical-align:1px;cursor:help;white-space:nowrap;}
.cat-label.rising{color:#8fd08f;border-color:#2f5a2f;background:#132013;}
.cat-label.falling{color:#e09a9a;border-color:#5a2f2f;background:#201313;}
.cat-label.best{color:#e9cf9a;border-color:#5a4520;background:#211a10;}
.cat-label.new{color:#8fc3e6;border-color:#2a4a60;background:#111c24;}
/* An event page's "Watch the N live now" (functions/event/[slug].js), in the
   viewer's own green rather than a grey button. */
body #home-about #ev-open-live{padding:8px 16px;background:#16281a;color:#aee0ae;border:1px solid #2f4f2f;border-radius:6px;font-size:13px;font-weight:600;cursor:pointer;}
body #home-about #ev-open-live:hover{background:#1e3a24;color:#d4f5d4;border-color:#4a8f4a;}
/* A channel's last seven days (chanSpark, functions/_lib.js): a bar a day in
   its platform's colour, as the recap draws a channel's week. */
.ch-spark{display:inline-flex;align-items:flex-end;gap:2px;height:11px;margin-right:8px;vertical-align:-1px;flex:0 0 auto;}
.ch-spark i{display:block;width:4px;border-radius:1px;background:#7a7a7a;}
.ch-spark.kick i{background:#4f9f4f;}
.ch-spark.twitch i{background:#8a6cc0;}
.ch-spark i.off{height:2px;background:#333 !important;}
/* Scrollbars, thin and dark on every page, as the viewer has them (its own
   copy is in index.html): the browser's light default was the one bright edge
   on the rest of the site - the pages, the list, the stats. scrollbar-color
   inherits from html; scrollbar-width does not, hence the *. The -webkit-
   rules are for older WebKit, which ignores the standard ones. */
html{scrollbar-color:#333 transparent;}
*{scrollbar-width:thin;}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-track{background:transparent;}
::-webkit-scrollbar-thumb{background:#333;border-radius:6px;border:2px solid transparent;background-clip:content-box;}
::-webkit-scrollbar-thumb:hover{background:#4a4a4a;background-clip:content-box;}
::-webkit-scrollbar-corner{background:transparent;}
