/* --- shell.css --------------------------------------------------------------
 *
 * The navigation rail, and what it becomes on a phone. Loaded by every page
 * that has one: the lobby, /markets, and the admin panel.
 *
 * WHY THIS ONE IS ALLOWED TO HOLD RULES WHEN tokens.css IS NOT
 *
 * tokens.css holds no rules because the pages' inline <style> blocks disagree
 * with each other -- 111 selectors have different bodies on different pages,
 * and a shared rulesheet would introduce every one of those collisions at
 * once. None of that applies here. #side-nav, #nav-scrim, .nav-toggle and the
 * .side-* family are NEW selectors: they exist in no page's inline block, so
 * they can collide with nothing. What they would otherwise do is exist three
 * times over and drift apart the first time an item moved.
 *
 * This sheet is linked in <head>, so every rule in it is beaten by a page's
 * own inline block. That is deliberate: a page styles its own active item and
 * its own rail footer without fighting anything here.
 *
 * THE TWO WIDTHS
 *
 * --rail-w is the only number any page should know about. Everything that has
 * to sit beside the rail -- the lobby's wrapper, the headers, the game pages'
 * body padding -- reads it, so collapsing the rail moves them all without any
 * of them knowing there is a collapsed state at all.
 *
 * It changes with html[data-rail="mini"], which shell.js sets from
 * localStorage BEFORE the first paint. That is why shell.js is loaded from
 * <head> and not deferred on any page: deferred, the rail would paint wide and
 * then jump.
 *
 * Mini is a DESKTOP state. Below 1100px the rail is an off-canvas drawer that
 * is either there or not, and 60px of icons sliding over the page would be
 * neither -- so the override lives in the desktop half of the two
 * complementary media blocks at the foot of this file.
 */

:root {
    --rail-w:    208px;   /* the rail, and so the gutter every page leaves it */
    --rail-mini:  60px;   /* the same rail with the words taken out */
}

/* A persistent rail, so a page's siblings read as peer products rather than
   as one page with a link on it. Fixed, so it stays put while the page
   scrolls past it. Below 1100px it is the drawer at the foot of this file. */
#side-nav {
    position: fixed; left: 0; top: 0; bottom: 0; width: var(--rail-w);
    background: var(--surface); border-right: 1px solid var(--border);
    display: flex; flex-direction: column; padding: 0 12px;
    z-index: 20; box-sizing: border-box;
    transition: width 0.18s ease;
}
.side-brand {
    height: 64px; display: flex; align-items: center; gap: 9px;
    padding: 0 12px; margin: 0 -12px 14px -12px;
    border-bottom: 1px solid var(--border);
}
.side-brand-name { font-size: 15px; font-weight: 900; letter-spacing: 1.4px; color: #fff; }
.side-group {
    font-size: 9px; font-weight: 800; letter-spacing: 1.2px;
    color: var(--text-dim); padding: 16px 12px 7px 12px;
}
.side-group:first-of-type { padding-top: 6px; }
.side-item {
    display: flex; align-items: center; gap: 11px; padding: 9px 12px;
    border-radius: 8px; color: var(--text); font-size: 13px; font-weight: 600;
    text-decoration: none; cursor: pointer; border: none; background: none;
    font-family: inherit; width: 100%; text-align: left; transition: background 0.15s;
    /* width:100% is the rail's CONTENT box (--rail-w less 24px of
       padding); without this the 12px padding is added outside it and
       every item is a full rail wider than the space it sits in. Only
       the active one has a background, so what it looked like was a
       purple tab sticking out of the closed drawer -- and on desktop,
       out of the rail into the page. */
    box-sizing: border-box;
    position: relative;   /* the flyout label in mini is absolute to this */
    white-space: nowrap;
}
.side-item svg { stroke: var(--text-dim); flex-shrink: 0; }
.side-item:hover { background: var(--surface-raised); }
.side-item.active,
html[data-view="lobby"]  #nav-lobby { background: var(--surface-raised); color: #fff; font-weight: 800; }
.side-item.active svg,
html[data-view="lobby"]  #nav-lobby svg { stroke: var(--accent); }
.side-item.soon { opacity: 0.55; cursor: default; }
.side-item.soon:hover { background: none; }
.side-pill {
    margin-left: auto; font-size: 9px; font-weight: 900; letter-spacing: 0.5px;
    color: var(--text-on-accent); background: var(--gold);
    padding: 2px 7px; border-radius: 999px;
}
/* The rail is a drawer on a phone. Same element, same links: a second
   copy of the nav would have gone out of step the first time an item
   moved. Desktop never sees any of this -- the button is hidden and
   the rail has no transform. */
.nav-toggle {
    display: none; align-items: center; justify-content: center;
    width: 36px; height: 36px; flex-shrink: 0; padding: 0;
    background: var(--surface-raised); border: 1px solid var(--border-strong);
    border-radius: 8px; color: var(--text); cursor: pointer; font-family: inherit;
}
.nav-toggle:hover { border-color: var(--accent); color: var(--accent); }
#nav-scrim {
    display: none; position: fixed; inset: 0;
    background: rgba(0,0,0,0.6); z-index: 1400;
}

.side-foot {
    margin-top: auto; margin-bottom: 16px; background: var(--bg);
    border: 1px solid var(--border); border-radius: 10px; padding: 14px;
}

/* The collapse control, and the whole of the brand strip's left side: it is
   where the logo mark used to be, and the mark is gone. Not a .side-item --
   it is not a place to go, and as an item it would have picked up the flyout
   label the mini rules give the others. In mini it is the only thing left in
   that strip, which is the point: the control you need is the one that is
   still there. */
.side-collapse {
    flex-shrink: 0; padding: 0;
    width: 30px; height: 30px; border-radius: 8px;
    display: flex; align-items: center; justify-content: center;
    background: none; border: none; color: var(--text-dim);
    cursor: pointer; font-family: inherit;
}
.side-collapse:hover { background: var(--surface-raised); color: #fff; }
.side-collapse svg { transition: transform 0.18s ease; }

/* --- THE HEADER ------------------------------------------------------------
 *
 * One 64px bar, on every page that has a rail. It was built for the game pages
 * and it is the standard now: the lobby's was a retrofit -- the profile block
 * and the balance were still `position: fixed` overlays from before there was
 * a header, held in place by overrides -- and markets had a third copy of the
 * same idea.
 *
 * Only the LOOK is here. Where the bar sits is per page, because the pages sit
 * differently: a game page and markets pad the body out of its way, the lobby
 * gives its wrapper a margin. The base below is fixed and starts at the rail,
 * which is what the lobby and the game pages already did; a page that wants
 * otherwise says so in its own block, which is parsed after this file.
 */
#top-bar {
    position: fixed; top: 0; left: var(--rail-w); right: 0; height: 64px; z-index: 19;
    transition: left 0.18s ease;
    display: flex; align-items: center; gap: 14px; padding: 0 22px;
    background: var(--bg); border-bottom: 1px solid var(--border);
    box-sizing: border-box;
}
/* What page you are on, in the header, on a phone only -- where the strip that
   would otherwise say it is not displayed. Pages without one are unaffected:
   there is no element for this rule to find. */
#gt-title { display: none; font-size: 14px; font-weight: 800; letter-spacing: 0.6px; color: #fff; }
#gt-search { position: relative; flex: 0 0 260px; }
#gt-search svg { position: absolute; left: 12px; top: 11px; }
/* type="search", and that is a security choice as much as a semantic one.
   The login form on these pages takes a Torn API KEY in a field marked
   autocomplete="username", so browsers save the key as this site's username and
   then offer it on any bare type="text" input -- the market search box included.
   Reported 2026-09-27: the autofill panel dropped the owner's Torn ID and live
   API key over the lobby. autocomplete="off" does not stop it; Firefox ignores
   that for saved logins. It does not offer saved usernames on a search input.

   The UA decorations that come with the type are removed so nothing about the
   box looks different from the text input it replaced. */
#gt-search input {
    appearance: none; -webkit-appearance: none;
    /* border-box explicitly, not inherited from a page's global `*` rule:
       markets has one and the lobby does not, which is why the same 260px box
       held a 260px input on one page and a 326px one on the other. */
    width: 100%; box-sizing: border-box; background: var(--surface-sunken);
    border: 1px solid var(--border-strong); border-radius: 8px;
    color: #fff; font-family: inherit; font-size: 13px; font-weight: 600;
    padding: 9px 12px 9px 34px; outline: none;
}
#gt-search input:focus { border-color: var(--accent); }
#gt-search input::placeholder { color: var(--text-dim); }
/* Chrome and Safari draw their own clear button on a search field. It is an
   unstyleable light-on-dark glyph and the page already offers a Clear of its
   own, so it is taken off rather than left looking like a rendering fault. */
#gt-search input::-webkit-search-cancel-button,
#gt-search input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }

.gt-right { margin-left: auto; display: flex; align-items: center; gap: 12px; }
.balance-pill {
    display: flex; align-items: stretch; background: var(--surface-sunken);
    border: 1px solid var(--border-strong); border-radius: 8px; overflow: hidden;
}
.balance-pill .amount { padding: 7px 14px; display: flex; flex-direction: column; justify-content: center; }
.balance-pill .label { font-size: 8px; font-weight: 800; letter-spacing: 0.9px; color: var(--text-dim); }
/* .balance-val is the id the pages already write the number into; it stops
   being a chip of its own and becomes the figure inside the pill. */
.balance-val {
    font-family: var(--font-ui); font-variant-numeric: tabular-nums;
    font-size: 14px; font-weight: 800; color: #fff; letter-spacing: 0.3px;
}
/* A <button> on every page now that it opens the wallet in place rather than
   linking to the lobby, so it has to be told it is not a browser button:
   font-family and border do not inherit into one. */
.balance-pill .wallet {
    background: var(--accent); color: var(--text-on-accent);
    font-family: inherit; font-size: 12px; font-weight: 900; letter-spacing: 0.6px;
    border: none; cursor: pointer;
    padding: 0 16px; display: flex; align-items: center; text-decoration: none;
}
.balance-pill .wallet:hover { background: var(--accent-bright); }

/* --- the reader who has not signed in ------------------------------------
   The lobby, the markets list and every market page render for a stranger, so
   the chrome has to have a shape for one. Two rules, both shared, because both
   pages need the same thing and a second copy of a call to action is a second
   copy that drifts.

   WHY [hidden] IS SPELLED OUT HERE

   The browser's own `[hidden] { display: none }` is the weakest rule there is,
   and .side-item, .balance-pill and #user-info all set a display of their own,
   which beats it -- so `el.hidden = true` on any of them does nothing at all.
   The attribute is re-asserted below at a specificity that wins: the CLASS plus
   the attribute, not a new .is-hidden class, for the same reason the stake field
   is scoped by id -- a bare class loses to the component's own rule. */
.side-item[hidden],
.side-group[hidden],
.balance-pill[hidden],
.head-icon[hidden],
#user-info[hidden],
.sign-in-btn[hidden] { display: none; }

/* The way in, in the header, where the balance pill sits for somebody who has
   an account. Violet because it is the one thing on the page we are asking a
   stranger to do -- and var(--accent), never a literal. */
.sign-in-btn {
    display: flex; align-items: center; background: var(--accent);
    color: var(--text-on-accent); border: none; border-radius: 8px;
    font-family: inherit; font-size: 12px; font-weight: 900; letter-spacing: 0.6px;
    padding: 9px 16px; text-decoration: none; cursor: pointer; white-space: nowrap;
}
.sign-in-btn:hover { background: var(--accent-bright); }

/* --- who you are ---------------------------------------------------------
   Two lines, right-aligned: rank and name over level and the XP bar. On the
   game pages this was a fixed overlay pinned to the width of a panel that no
   longer existed; on the lobby it was four stacked rows tall enough to make
   the header look like a different bar from every other page's. Same markup
   and the same ids in both places, in the header, one shape. */
#user-info { display: none; flex-direction: column; align-items: flex-end; gap: 5px; }
.profile-row { display: flex; align-items: center; gap: 8px; }
.rank-badge {
    font-size: 10px; font-weight: 900; padding: 2px 6px; border-radius: 4px;
    border: 1px solid currentColor; letter-spacing: 1px; text-transform: uppercase;
}
.rank-BRONZE   { color: #cd7f32; background: rgba(205, 127, 50, 0.12); }
.rank-SILVER   { color: #e0e0e0; background: rgba(224, 224, 224, 0.12); }
.rank-GOLD     { color: var(--gold); background: rgba(245, 196, 81, 0.12); }
.rank-PLATINUM { color: var(--accent); background: rgba(157, 92, 255, 0.14); }
.rank-DIAMOND  { color: #b9f2ff; background: rgba(185, 242, 255, 0.12); }
.rank-OBSIDIAN { color: var(--danger); background: rgba(255, 77, 109, 0.12); }
.xp-container {
    width: 90px; height: 4px; background: var(--surface-sunken);
    border: 1px solid var(--border); border-radius: 2px; position: relative;
}
.xp-fill {
    height: 100%; background: linear-gradient(90deg, var(--accent), var(--accent-bright));
    width: 0%; transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}
.xp-container:hover::after {
    content: attr(data-xp); position: absolute; top: 12px; right: 0;
    background: var(--surface); color: #fff; font-size: 10px; padding: 5px 7px;
    border-radius: 5px; border: 1px solid var(--border-strong);
    white-space: nowrap; z-index: 100;
}


/* Actions that only some pages can offer -- settings and signing out are the
   lobby's, because it is the only page that has the code for either. A page
   without them simply has no such button; nothing here needs to know. */
.head-icon {
    width: 32px; height: 32px; flex-shrink: 0; padding: 0;
    display: flex; align-items: center; justify-content: center;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: 8px; color: var(--text-dim);
    cursor: pointer; font-family: inherit; transition: color 0.15s, border-color 0.15s;
}
.head-icon:hover { color: #fff; border-color: var(--border-strong); }
.head-icon.danger:hover { color: var(--danger); border-color: var(--danger); }

/* --- COLLAPSED, ON A DESKTOP -----------------------------------------------
   Same rail, same links, no words: 60px of icons that stays put rather than a
   rail that goes away. Everything beside it follows because it reads --rail-w
   and nothing else.

   This is the desktop half of the two complementary blocks at the foot of this
   sheet -- `not all and (max-width: 1100px)` and `max-width: 1100px` are exact
   complements, so no viewport width falls between them and no width gets both.
   Mini has no meaning on a phone, where the rail is off-canvas: 60px of icons
   sliding over the page would be neither open nor closed. */
@media not all and (max-width: 1100px) {
    html[data-rail="mini"] { --rail-w: var(--rail-mini); }

    html[data-rail="mini"] #side-nav { padding: 0 8px; }
    html[data-rail="mini"] .side-brand {
        justify-content: center; padding: 0; margin: 0 -8px 12px -8px;
    }
    /* 60px is one control wide, and the wordmark is not the control. */
    html[data-rail="mini"] .side-brand-name { display: none; }
    html[data-rail="mini"] .side-collapse { width: 34px; height: 34px; }
    html[data-rail="mini"] .side-item { justify-content: center; gap: 0; padding: 10px 0; }

    /* The foot card is prose. There is no reading it at 60px, and unlike the
       items it has no icon to fall back to, so it goes. */
    html[data-rail="mini"] .side-foot { display: none; }

    /* A heading with no room to be read becomes the rule it was drawing. */
    html[data-rail="mini"] .side-group {
        font-size: 0; padding: 0; height: 1px; margin: 11px 6px;
        background: var(--border); overflow: hidden;
    }
    html[data-rail="mini"] .side-group:first-of-type { margin-top: 4px; }

    /* The label is not deleted, it is parked. On hover it flies out beside its
       icon, so a rail of eight unlabelled glyphs can still be read -- which is
       the difference between this and a rail that is simply gone.

       :not(.side-pill) because the NEW pill is a <span> in the same item and
       would otherwise be turned into a second flyout -- and it would WIN, this
       selector being one class more specific than the pill's own rule below. */
    html[data-rail="mini"] .side-item > span:not(.side-pill) {
        position: absolute; left: calc(100% + 10px); top: 50%;
        transform: translateY(-50%);
        background: var(--surface-raised); color: #fff;
        border: 1px solid var(--border-strong); border-radius: 7px;
        padding: 7px 11px; font-size: 12px; font-weight: 700;
        box-shadow: 0 10px 24px rgba(0,0,0,0.55);
        opacity: 0; pointer-events: none; transition: opacity 0.12s;
        z-index: 30;
    }
    html[data-rail="mini"] .side-item:hover > span:not(.side-pill) { opacity: 1; }

    /* The pill cannot say NEW at 60px, so it says the only other thing it was
       there for: that there is something new behind this icon. */
    html[data-rail="mini"] .side-pill {
        position: absolute; top: 6px; right: 8px; margin: 0;
        width: 7px; height: 7px; padding: 0; font-size: 0; border-radius: 50%;
    }

    html[data-rail="mini"] .side-collapse svg { transform: rotate(180deg); }
}

/* --- ON A PHONE ------------------------------------------------------------
   The rail slides in from the left instead of being there all the time. Same
   element and the same links: a second copy of the nav would have gone out of
   step the first time an item moved. */
@media (max-width: 1100px) {
    /* Off-canvas rather than gone: everything in it -- the daily gift,
       rakeback, referrals, provably fair, Casino, Markets -- has no
       other way in on a phone. */
    #side-nav {
        display: flex;
        transform: translateX(-100%);
        transition: transform 0.25s ease;
        z-index: 1500;
    }
    body.nav-open #side-nav {
        transform: none;
        box-shadow: 0 0 40px rgba(0,0,0,0.6);
    }
    body.nav-open #nav-scrim,
    body.nav-dragging #nav-scrim { display: block; }
    .nav-toggle { display: flex; order: 0; }
    /* Nothing to collapse to: below this width the rail is off-canvas, so the
       drawer is either open or it is not. */
    .side-collapse { display: none; }

    /* Inside the media block, which is AFTER the base rule -- a query adds no
       specificity, so this above it would silently do nothing. */
    .sign-in-btn { padding: 8px 11px; font-size: 11px; letter-spacing: 0.4px; }
}

/* --- THE RESULTS PANEL UNDER #gt-search -------------------------------------
 *
 * Shared, because the box is. The lobby and the markets page both carry
 * #gt-search, and the panel was written for the lobby first: leaving it there
 * would have meant a second copy of forty lines the next time somebody touched
 * one of them, which is how this codebase ended up with two figures that
 * disagreed.
 *
 * Anchored to #gt-search, which is position:relative above. z-index clears the
 * sticky header's own 19 so the panel is not clipped by the page under it.
 */
#gt-results {
    position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 40;
    background: var(--surface); border: 1px solid var(--border-strong);
    border-radius: 10px; overflow: hidden auto; max-height: min(60vh, 420px);
    box-shadow: 0 18px 44px rgba(0, 0, 0, 0.55);
}
#gt-results[hidden] { display: none; }
.gt-r-item {
    display: block; padding: 9px 12px; text-decoration: none;
    border-bottom: 1px solid var(--border); cursor: pointer;
}
.gt-r-item:last-child { border-bottom: 0; }
/* One rule for hover and for the keyboard cursor, so arrowing down the list
   looks the same as moving a mouse down it. */
.gt-r-item:hover, .gt-r-item.on { background: var(--surface-sunken); }
.gt-r-q {
    color: #fff; font-size: 13px; font-weight: 700; line-height: 1.35;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden;
}
.gt-r-meta {
    margin-top: 3px; color: var(--text-dim); font-size: 11px; font-weight: 600;
    display: flex; gap: 8px; flex-wrap: wrap;
}
.gt-r-meta .soon { color: var(--warn, #f5a524); }
/* Sticky, because the list scrolls: with a full panel the way out of it sat
   below the fold of a dropdown, which is a worse place to hide a link than the
   page it leads to. */
.gt-r-foot {
    display: block; padding: 9px 12px; text-align: center;
    background: var(--surface-sunken); color: var(--accent);
    font-size: 12px; font-weight: 800; text-decoration: none;
    position: sticky; bottom: 0; border-top: 1px solid var(--border);
}
.gt-r-foot:hover { text-decoration: underline; }
.gt-r-empty { padding: 14px 12px; color: var(--text-muted); font-size: 12px; }
