/* gd-rail.css — hybrid navigation: labeled left rail + top-right account cluster.
 *
 * Paired with gd-rail.js, which builds the markup and injects it. Nothing here
 * is page-specific, so every page gets identical navigation from one file.
 *
 * v11 REDESIGN (the "hybrid"): the rail now carries DESTINATIONS plus a few
 * glanceable page actions, as always-visible icon+label tiles (no hover-expand,
 * which touch devices could never see). Utilities that are set once and
 * forgotten (interface sounds, FX mode, Twitch sync) moved OFF the rail into a
 * gear menu in the top-right corner, next to the page's own Discord auth box.
 * The auth box keeps its own account menu untouched.
 *
 * Everything is namespaced `gd-rail-` / `gd-mast-` / `gd-top` / `gd-menu` to
 * stay clear of page classes. The site already has `.mast-eyes`/`.mast-eye`
 * element classes, hence the container-level `gd-mast-` prefix.
 *
 * Layout contract: the rail is FIXED, so it is outside page flow. body gains
 * `gd-railed`, and the gutter rule below indents page wrappers by
 * --gd-rail-gutter so content never sits beneath the rail.
 */

:root{
  --gd-rail-w:72px;            /* tile width; labels are always visible */
  --gd-rail-gap:8px;
  --gd-chrome-top:14px;        /* top offset; raised below a .devbar */
  --gd-rail-top:calc(var(--gd-chrome-top) + 62px);  /* clears the wordmark */
  --gd-rail-ink:#0a0d09;
  --gd-rail-line:rgba(143,255,46,.30);
  --gd-rail-line-hi:#8fff2e;
  --gd-rail-text:#cfe8b0;
  --gd-rail-brass:rgba(176,141,79,.35);
  /* the accent as an r,g,b triplet, so tints and glows can retint per theme */
  --gd-rail-glow:143,255,46;
}

/* ── purple theme ─────────────────────────────────────────────────────────────
   Pages whose accent is the Bot's purple (goodbot.html, buddy.html) add
   class="gd-rail-purple" to their <html> tag; every accent below follows. The
   wordmark's eyes and the live/status dots keep their own colours: the eyes
   are the brand, and a live dot means "live" on every page. */
html.gd-rail-purple{--gd-rail-line:rgba(169,107,255,.38);--gd-rail-line-hi:#a96bff;
  --gd-rail-text:#d9c2ff;--gd-rail-glow:169,107,255}

/* ── wordmark, top-left, directly above the rail ─────────────────────────── */
.gd-mast{position:fixed;top:var(--gd-chrome-top);left:14px;z-index:97;
  display:flex;align-items:center;gap:12px;padding:6px 14px 6px 8px;
  border-radius:999px;text-decoration:none;cursor:pointer;
  background:rgba(8,10,9,.82);border:1px solid transparent;transition:.2s}
.gd-mast:hover{border-color:var(--gd-rail-line);background:rgba(10,14,10,.94)}
.gd-mast-eyes{display:flex;gap:11px;flex:none}
.gd-mast-eye{width:13px;height:13px;border-radius:50%;
  background:radial-gradient(circle at 38% 32%, #e8ffc0, #aaff3c 38%, #3a7a0e 72%, #0a2104);
  box-shadow:0 0 10px #8fff2e, 0 0 22px rgba(143,255,46,.4);
  animation:gdMastFlick 5.5s infinite}
@keyframes gdMastFlick{0%,93%,100%{opacity:1}95%{opacity:.25}97%{opacity:1}}
.gd-mast-name{font-family:'Cinzel Decorative',serif;font-size:.82rem;letter-spacing:.02em;
  color:#e6dcc4;white-space:nowrap;text-shadow:0 0 12px rgba(143,255,46,.25)}
body.lite .gd-mast-eye{animation:none}
@media(prefers-reduced-motion:reduce){.gd-mast-eye{animation:none}}

/* ── the rail ────────────────────────────────────────────────────────────── */
.gd-rail{position:fixed;left:14px;top:var(--gd-rail-top);z-index:97;
  display:flex;flex-direction:column;gap:var(--gd-rail-gap);
  width:var(--gd-rail-w);align-items:stretch;
  max-height:calc(100vh - var(--gd-rail-top) - 12px);overflow-y:auto;
  scrollbar-width:none}
.gd-rail::-webkit-scrollbar{display:none}

/* A TILE: icon above an always-visible label. No hover-expand — labels that
   only exist on :hover do not exist at all on a touch screen. */
.gd-rail-btn{position:relative;display:flex;flex-direction:column;align-items:center;
  gap:4px;flex:none;width:var(--gd-rail-w);padding:9px 4px 7px;
  border-radius:14px;cursor:pointer;text-decoration:none;text-align:center;
  background:rgba(10,14,10,.92);border:1px solid var(--gd-rail-line);
  color:var(--gd-rail-text);box-shadow:0 6px 20px rgba(0,0,0,.5);
  transition:background .18s, border-color .18s, color .18s, box-shadow .18s;
  font-family:'IM Fell English',serif}
.gd-rail-btn:hover,.gd-rail-btn:focus-visible{
  border-color:var(--gd-rail-line-hi);color:#fff;background:rgba(var(--gd-rail-glow),.14);
  box-shadow:0 0 16px rgba(var(--gd-rail-glow),.28)}
.gd-rail-ico{flex:none;height:24px;display:grid;place-items:center;font-size:1.15rem;line-height:1}
.gd-rail-ico img{width:22px;height:22px;object-fit:contain;display:block}
.gd-rail-lbl{display:block;font-size:.62rem;line-height:1.2;letter-spacing:.01em;
  max-width:100%;overflow-wrap:break-word;opacity:.92}
.gd-rail-btn:hover .gd-rail-lbl,.gd-rail-btn:focus-visible .gd-rail-lbl{opacity:1}

/* current page */
.gd-rail-btn.on{border-color:var(--gd-rail-line-hi);color:#fff;
  background:linear-gradient(180deg,rgba(var(--gd-rail-glow),.20),rgba(var(--gd-rail-glow),.05))}
.gd-rail-btn.on::before{content:'';position:absolute;left:0;top:12px;bottom:12px;width:3px;
  border-radius:0 3px 3px 0;background:var(--gd-rail-line-hi)}

/* ── host tools accent ───────────────────────────────────────────────────────
   The host tools tile wears the host's own colour, mirrored from the
   --tools-accent that applyToolsAccent() puts on #adminDock. Falls back to the
   rail's green when the host has set no colour. */
.gd-rail-btn.tinted{border-color:var(--gd-rail-accent);color:var(--gd-rail-accent)}
.gd-rail-btn.tinted:hover,.gd-rail-btn.tinted:focus-visible,
.gd-rail-btn.tinted.open{border-color:var(--gd-rail-accent);color:#fff;
  background:color-mix(in srgb, var(--gd-rail-accent) 18%, transparent);
  box-shadow:0 0 16px color-mix(in srgb, var(--gd-rail-accent) 45%, transparent)}
/* Older browsers without color-mix simply keep the flat tint above. */
.gd-rail-btn.open{border-color:var(--gd-rail-line-hi);background:rgba(var(--gd-rail-glow),.16)}

/* ── flyout panel ────────────────────────────────────────────────────────────
   A POSITIONING SHELL, not a frame: no background, no border, no shadow. The
   host tools card has its own chrome and carries the host's colour, so wrapping
   it in a second box just drew a rectangle around a rectangle.

   v11: the tiles no longer expand on hover, so the old .pushed slide (which
   moved the panel clear of a grown button) is gone along with its JS.

   overflow is VISIBLE, never auto: the drawer draws an 18px outer glow, and any
   clipping context shaved it off the left edge, which read as a half-drawn box.
   The scroll lives on .admin-drawer below instead, inside the border, where it
   cannot clip the frame. */
.gd-rail-flyout{position:fixed;
  left:calc(14px + var(--gd-rail-w) + 12px);
  top:var(--gd-rail-top);
  z-index:96;width:max-content;max-width:min(380px, calc(100vw - 150px));
  display:none;background:none;border:0;box-shadow:none;padding:0;
  overflow:visible}
.gd-rail-flyout.on{display:block}

/* Strip the PAGE's card chrome from the adopted dock. #adminDock carries
   .lp2-rail-card, which paints its own bordered panel — that was the stray
   green box around the tools. The inner .admin-drawer keeps its own frame and
   the host's tint, which is the box that should be visible. */
.gd-rail-flyout .lp2-rail-card,
.gd-rail-flyout .host-tools-card{background:none !important;border:0 !important;
  border-radius:0 !important;box-shadow:none !important;overflow:visible !important;
  position:static;margin:0;padding:0;width:auto;max-width:none;display:block !important}
/* The tall list scrolls INSIDE its own border, so the frame and its glow are
   always fully drawn.
   !important on the border properties is doing real work here. The page's
   .admin-dock.open .admin-drawer rule is specificity 0,3,0 and sets
   border-left:0, border-radius:0 12px 12px 0 and margin-left:-1px — it was
   written for a drawer that slid out of the screen edge, where a flat left side
   is correct. In the flyout that produced a box with a sharp, borderless left
   edge. This restores a complete, evenly rounded frame. */
.gd-rail-flyout .admin-drawer{max-width:none;opacity:1;width:auto;
  max-height:calc(100vh - var(--gd-rail-top) - 26px);overflow:hidden auto;
  border:1px solid var(--tools-accent) !important;
  border-radius:12px !important;
  margin:0 !important}
.gd-rail-flyout .admin-handle{display:none !important}

/* a thin divider between groups of tiles */
.gd-rail-sep{flex:none;width:46px;height:1px;margin:2px auto;
  background:linear-gradient(90deg,transparent,var(--gd-rail-line),transparent)}

/* status pip, used by the doctor-live dot (top-right corner of the tile) */
.gd-rail-pip{position:absolute;top:7px;right:12px;min-width:9px;height:9px;border-radius:999px;
  background:#c0392b;box-shadow:0 0 0 2px rgba(8,10,9,.95);display:none}
.gd-rail-pip.on{display:block}
.gd-rail-pip.live{background:#8fff2e;box-shadow:0 0 0 2px rgba(8,10,9,.95),0 0 8px #8fff2e}

/* ── the notification bell, adopted into its tile ────────────────────────────
   The bell (#gdnBell) injects itself as a FIXED circle with its own chrome.
   gd-rail.js moves it into the icon area of a rail tile; these rules strip its
   circle so only the glyph and badge remain — the tile is the chrome now.
   The tile hides itself whenever the bell is hidden (the page only shows it
   for signed-in visitors, via .gdn-show). gd-rail.js mirrors this in JS as
   well, for browsers without :has(). */
.gd-rail-btn .gdn-bell{position:static !important;top:auto !important;right:auto !important;
  left:auto !important;bottom:auto !important;margin:0 !important;padding:0 !important;
  width:auto !important;height:auto !important;display:inline-flex !important;
  background:none !important;border:0 !important;box-shadow:none !important;
  font-size:1.15rem;color:inherit;cursor:pointer}
.gd-rail-btn .gdn-bell .gd-bell-img{width:22px;height:22px;object-fit:contain;display:block}
.gd-rail-btn .gdn-badge{top:2px !important;right:10px !important;left:auto !important}
.gd-rail-btn:has(.gdn-bell:not(.gdn-show)){display:none}

/* ── top-right cluster: gear menu + the page's own auth box ────────────────── */
.gd-top{position:fixed;top:var(--gd-chrome-top);right:14px;z-index:97;
  display:flex;align-items:center;gap:10px}
.gd-gear{flex:none;width:40px;height:40px;border-radius:999px;cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;font-size:1.05rem;
  background:rgba(10,14,10,.92);border:1px solid var(--gd-rail-brass);
  color:var(--gd-rail-text);box-shadow:0 6px 20px rgba(0,0,0,.5);
  transition:background .18s, border-color .18s, color .18s}
.gd-gear:hover,.gd-gear:focus-visible,.gd-gear.open{
  border-color:var(--gd-rail-line-hi);color:#fff;background:rgba(var(--gd-rail-glow),.14);
  box-shadow:0 0 14px rgba(var(--gd-rail-glow),.28)}
.gd-gear img{width:24px;height:24px;object-fit:contain;display:block}
/* The adopted #lp2Auth keeps the page's own pill styling and its own account
   menu (.lp2-auth-menu anchors to it and already opens down-right). */
.gd-top-auth{flex:none;display:inline-flex}

/* ── the gear menu ─────────────────────────────────────────────────────────── */
.gd-menu{position:fixed;top:calc(var(--gd-chrome-top) + 48px);right:14px;z-index:98;min-width:238px;
  display:none;background:rgba(12,15,12,.97);border:1px solid var(--gd-rail-brass);
  border-radius:12px;padding:8px;box-shadow:0 18px 50px rgba(0,0,0,.6)}
.gd-menu.on{display:block}
.gd-menu-head{font-family:'Orbitron',sans-serif;font-size:.56rem;letter-spacing:.2em;
  text-transform:uppercase;color:#8a8a78;padding:4px 10px 8px}
.gd-menu-row{display:flex;align-items:center;gap:10px;width:100%;text-align:left;
  background:none;border:0;border-radius:9px;padding:9px 10px;cursor:pointer;
  color:#e2dcc6;font-family:'EB Garamond',serif;font-size:.98rem;transition:background .15s}
.gd-menu-row:hover,.gd-menu-row:focus-visible{background:rgba(var(--gd-rail-glow),.10);color:#fff}
.gd-menu-ico{flex:none;width:22px;text-align:center;font-size:1rem}
.gd-menu-dot{margin-left:auto;flex:none;width:9px;height:9px;border-radius:999px;
  background:#8fff2e;box-shadow:0 0 8px #8fff2e;display:none}
.gd-menu-row.live .gd-menu-dot{display:block}
/* The FX dot is a status light, always visible on that row: lit green while
   full effects are on, dim while in Lite mode. */
.gd-menu-row[data-key="fx"] .gd-menu-dot{display:block;background:#5c5c4d;box-shadow:none}
.gd-menu-row[data-key="fx"].live .gd-menu-dot{background:#8fff2e;box-shadow:0 0 8px #8fff2e}
/* The Twitch dot matches the old topbar badge's platform purple. */
.gd-menu-row[data-key="twitch"] .gd-menu-dot{background:#b98bff;box-shadow:0 0 8px #9146ff}
/* The adopted sound toggle keeps its own circle chrome, shrunk to a control at
   the right edge of its row. Its fixed positioning (from sfx.js's injected
   stylesheet) is undone here. */
.gd-menu-row .sfx-toggle{position:static !important;top:auto !important;right:auto !important;
  margin:0 0 0 auto !important;width:30px !important;height:30px !important;
  font-size:.9rem !important;border-radius:999px !important;box-shadow:none !important;flex:none}

/* ── the Good Bot chooser ─────────────────────────────────────────────────────
   Opened from the rail's Good Bot tile: pick the Discord bot or the Desktop
   Buddy. The panel IS the banner: the art fills it edge to edge (the bot's
   portrait sits in the banner's right half), framed and corner-clipped so it
   reads as a clean modal rather than a floating image. Everything readable
   lives in a left column over a dark scrim, so the bot is never covered.
   Accents come from the theme vars. Sits above the rail (98), below page
   overlays (105+). */
.gd-choice{position:fixed;inset:0;z-index:104;display:none;
  align-items:center;justify-content:center;padding:20px;
  background:rgba(4,6,4,.82)}
.gd-choice.on{display:flex}
.gd-choice-panel{position:relative;width:min(760px,100%);aspect-ratio:1983/793;
  min-height:280px;border:1px solid var(--gd-rail-brass);border-radius:14px;
  overflow:hidden;box-shadow:0 24px 70px rgba(0,0,0,.7);
  display:flex;align-items:stretch;
  /* scrim first, art second: the gradient keeps the left column readable and
     fades out before the bot's half of the banner */
  background:
    linear-gradient(90deg,rgba(5,7,5,.92) 0%,rgba(5,7,5,.78) 38%,rgba(5,7,5,.25) 58%,rgba(5,7,5,0) 72%),
    url("assets/ui/goodbot-banner.webp") right center / cover no-repeat #070907}
.gd-choice-x{position:absolute;top:10px;right:10px;z-index:2;
  width:30px;height:30px;border-radius:7px;cursor:pointer;
  background:rgba(8,10,8,.65);border:1px solid var(--gd-rail-brass);color:#a8a894;
  font-size:.85rem;line-height:1;transition:.15s}
.gd-choice-x:hover{border-color:var(--gd-rail-line-hi);color:#fff}
.gd-choice-left{position:relative;z-index:1;align-self:center;
  width:min(54%,340px);padding:22px 10px 22px 24px;
  display:flex;flex-direction:column;gap:6px}
.gd-choice-title{font-family:'Cinzel Decorative',serif;font-size:1.04rem;letter-spacing:.05em;
  color:var(--gd-rail-line-hi);text-shadow:0 2px 8px rgba(0,0,0,.8)}
.gd-choice-sub{font-family:'IM Fell English',serif;font-style:italic;font-size:.92rem;
  color:#b9b9a4;margin-bottom:8px}
.gd-choice-opts{display:flex;flex-direction:column;gap:10px}
.gd-choice-opt{display:block;text-align:left;padding:11px 14px;border-radius:11px;
  text-decoration:none;cursor:pointer;background:rgba(8,11,8,.72);
  border:1px solid var(--gd-rail-line);transition:.18s}
.gd-choice-opt:hover,.gd-choice-opt:focus-visible{border-color:var(--gd-rail-line-hi);
  background:rgba(var(--gd-rail-glow),.12);box-shadow:0 0 18px rgba(var(--gd-rail-glow),.3)}
.gd-choice-name{display:block;font-family:'Cinzel Decorative',serif;font-size:.76rem;
  letter-spacing:.08em;text-transform:uppercase;color:var(--gd-rail-text)}
.gd-choice-opt:hover .gd-choice-name{color:#fff}
.gd-choice-note{display:block;margin-top:3px;font-family:'EB Garamond',serif;
  font-size:.86rem;line-height:1.4;color:#a8a894}
@media(max-width:620px){
  /* portrait phones: the banner becomes a backdrop behind a full-width column,
     scrimmed all the way across so the text stays readable */
  .gd-choice-panel{aspect-ratio:auto;min-height:0;
    background:
      linear-gradient(180deg,rgba(5,7,5,.86),rgba(5,7,5,.86)),
      url("assets/ui/goodbot-banner.webp") right center / cover no-repeat #070907}
  .gd-choice-left{width:100%;padding:20px 18px}
}

/* Page-side cards the rail has taken over. Hidden, not removed: page JS still
   reads and writes these nodes, and the flyout adopts #adminDock. The flyout's
   own rule re-shows the dock once it has been moved in. */
.gd-rail-replaced{display:none !important}
.gd-rail-flyout .gd-rail-replaced{display:flex !important}

/* ── page gutter ─────────────────────────────────────────────────────────────
   The rail is fixed, so pages must indent their own content or it sits beneath.
   gd-rail.js adds `gd-railed` to <body>; each page's wrapper opts in here. */
body.gd-railed{--gd-rail-gutter:104px}
body.gd-railed .wrap,
body.gd-railed .page,
body.gd-railed .buddy-wrap,
body.gd-railed .gd-gutter{padding-left:var(--gd-rail-gutter)}

/* ── narrow screens ──────────────────────────────────────────────────────────
   A vertical rail does not survive a phone. Below 820px it becomes a bottom
   tab bar — icon+label tiles, horizontally scrollable if the page adds host
   tiles. The gear + auth cluster stays top-right; the wordmark shrinks to just
   the eyes. */
@media(max-width:820px){
  .gd-rail{left:0;right:0;top:auto;bottom:0;width:auto;max-height:none;
    flex-direction:row;align-items:stretch;gap:6px;
    padding:7px 10px calc(7px + env(safe-area-inset-bottom, 0px));
    overflow-x:auto;overflow-y:hidden;
    background:rgba(8,10,9,.95);border-top:1px solid var(--gd-rail-line);
    box-shadow:0 -6px 20px rgba(0,0,0,.5)}
  .gd-rail-btn{width:62px;padding:6px 2px 5px;gap:3px;border-radius:12px;box-shadow:none}
  .gd-rail-ico{height:20px;font-size:1.05rem}
  .gd-rail-ico img{width:20px;height:20px}
  .gd-rail-lbl{font-size:.55rem}
  .gd-rail-sep{width:1px;height:auto;margin:6px 2px;align-self:stretch;
    background:linear-gradient(180deg,transparent,var(--gd-rail-line),transparent)}
  .gd-rail-btn.on::before{left:12px;right:12px;top:auto;bottom:0;width:auto;height:3px;
    border-radius:3px 3px 0 0}
  .gd-rail-pip{top:4px;right:8px}
  .gd-rail-btn .gdn-badge{top:0 !important;right:6px !important}
  body.gd-railed{--gd-rail-gutter:0px}
  body.gd-railed .wrap,body.gd-railed .page,body.gd-railed .buddy-wrap,
  body.gd-railed .gd-gutter{padding-left:0;padding-bottom:88px}
  /* The hype meter is fixed to the bottom centre of the listening page; lift it
     clear of the bottom bar. */
  body.gd-railed .hype-meter{bottom:88px}
  /* On a phone the rail is along the bottom, so the flyout becomes a sheet
     above it rather than a column beside it. */
  .gd-rail-flyout{left:8px;right:8px;width:auto;max-width:none;top:auto;
    bottom:88px;max-height:60vh}
  .gd-rail-flyout .admin-drawer{max-height:60vh}
  .gd-mast{top:var(--gd-chrome-top);left:8px;padding:5px 10px 5px 6px}
  .gd-mast-name{display:none}
  .gd-top{top:var(--gd-chrome-top);right:8px}
  .gd-menu{top:calc(var(--gd-chrome-top) + 46px);right:8px;left:auto;max-width:calc(100vw - 16px)}
}
