/* =============================================================================
   THE PORTAL SIDEBAR
   =============================================================================

   ONE OWNER. The portal shell exists in two stylesheet families — the media
   screens load series-listening/quizflix.css, the quiz/trivia/game screens load
   series.listening.portal.v2.css — and the sidebar rules were copied into both.
   They had already drifted: the v2 sheet never got .nav-profile or the sign-out
   block, so the profile entry rendered as a plain row on half the application.

   Every rule that is NEW or that was only in one sheet lives here instead, and
   this file is linked LAST on all fifteen portal pages so it wins either way.
   The rules still duplicated across both families (.sidebar, .logo, .nav-item)
   are deliberately left where they are — moving them is a separate job and
   touching one copy is what caused the drift in the first place. .nav-caret,
   .nav-group and .nav-thumb were in that list until the sidebar lost its last
   expanding pane; they were deleted from both sheets together, for the same
   reason — one copy is a drift waiting to happen.

   Three things this file owns:
     1. the collapse — the sidebar contracts to an icon rail and back
     2. the head     — the brand mark and the collapse control
     3. the profile  — the entry and the menu that pops out of it
   ============================================================================ */


/* --- The sidebar frame ------------------------------------------------------

   One rendered menu row, MEASURED rather than derived — 1rem of padding top and
   bottom around a 24px icon comes out at 64px on screen, not the 56 the box
   model reads like. It is a variable because the profile block is two menu items
   tall: change .nav-item's padding and this number has to move with it.

   --nav-rail is the collapsed width, and it is not a round number by accident:
   .nav-item's 1.5rem of side padding (24 + 24) plus its 4px active edge plus a
   24px icon is exactly 76. Anything less clips the icon; anything more leaves
   the rail looking like a failed sidebar rather than a rail. */
.sidebar {
    --nav-item-height: 64px;
    --nav-rail: 76px;
    overflow: visible;
}

/* THE EXPANDED WIDTH. Both base sheets declare this on :root at 250px, and this
   file is linked last on all fifteen portal pages, so one declaration here moves
   the sidebar, .main-content's margin and the film page's --film-rail together
   — which is the whole reason those three read the token rather than a number.
   Redeclaring it in the two base sheets instead would mean two edits and a third
   copy waiting to drift.

   176px is what the MENU needs, measured rather than chosen: the widest label is
   Featured at 68px, and a row spends 4px on its active edge, 24px of padding, a
   24px icon and a 10px gap before it — 154px, with the 24px of right padding
   still to come. The profile name is the longer of the two cases at 105px, and
   it starts at the icon column rather than after an icon, so it lands at 157px.
   176 clears both without either running to its ellipsis.

   The head used to be what did not fit — the wordmark's 126px plus the collapse
   control beside it wanted 204, which was the only reason the column had ever
   been as wide as it was. The control now hangs off the sidebar's edge instead
   of sharing the line, so the head is 162 and the menu sets the width. */
:root {
    --sidebar-width: 176px;
}

/* The list takes the space between the head and the bottom of the sidebar, and
   scrolls inside it. Without this the list has no height limit and a long menu
   runs off the bottom of the screen instead of scrolling. `min-height: 0` is the
   part that is easy to miss — a flex item will not shrink below its content
   without it, so the scrollbar never appears.

   This lived in the media-screen sheet only, which is why the game screens'
   sidebars ran off the bottom instead of scrolling. */
.nav-list {
    list-style: none;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    /* Not `hidden`: the profile menu is a sibling of this list precisely so it
       is not clipped, but a stray horizontal scrollbar here would still show. */
    overflow-x: hidden;
}


/* --- 2. The head: brand mark + collapse control ------------------------------

   .nav-head is built by quizflix.navigation.js, which moves the page's existing
   .logo div into it. The logo markup stays in the fifteen HTML files untouched;
   only its container is new. */
.nav-head {
    display: flex;
    align-items: center;
    gap: 6px;
    /* 28px, not .nav-item's 1.5rem: a menu row spends 4px of its own on the
       active edge before its icon starts, so 24 puts the wordmark four pixels
       inside the column it heads. Written as the sum the two share one axis. */
    padding: 0 0.5rem 2rem 28px;
    /* Anchor for the collapse control, which comes out of the flow on the rail
       so that it cannot push the brand mark off centre. */
    position: relative;
}

/* The logo carries `padding: 0 1.5rem 2rem` of its own in both sheets. Inside a
   flex row that padding is now the head's job, or the brand mark and the button
   sit on two different baselines.

   The size is the base sheets' own 1.5rem/2px and stays that way. It was cut to
   1.25rem while the collapse control sat on this line and 28 + 126 + the control
   would not fit in the column; the control is out of the flow now, so the line
   is the wordmark's alone — 28 + 126 + 8 = 162 inside 176 — and there is nothing
   left for a smaller type to buy. */
.nav-head .logo {
    flex: 1 1 auto;
    min-width: 0;
    padding: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* A disc straddling the sidebar's right edge: `right: 0` puts its right edge on
   the boundary and translateX(50%) pushes half of it back out, so what shows over
   the content is a half moon and what shows over the menu is the other half of
   the same circle. The sidebar is `overflow: visible` (top of this file) — the
   profile menu already hangs off this edge, which is what proved it.

   The disc is drawn ALL the time, not on hover. It has to be: half of it is over
   the page and needs an edge to be seen against, and a control that only appears
   under the cursor cannot be found by someone looking for it. Its fill is the
   sidebar's own black, so the outer half reads as a tab of the sidebar rather
   than a button parked next to it, and the hairline is what separates that black
   from the page's #050505.

   Out of the flow, so it no longer shares the head's line with the wordmark —
   `top: 0; bottom: 2rem` spans exactly the head's content box (the wordmark's own
   line, the 2rem being the head's bottom padding) and `margin: auto 0` centres a
   fixed height inside that band, so the disc sits on the wordmark's middle
   however the type happens to measure. */
.nav-collapse-btn {
    position: absolute;
    top: 0;
    bottom: 2rem;
    right: 0;
    transform: translateX(50%);
    margin: auto 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    background-color: var(--sidebar-bg);
    border:none;
    border-radius: 50%;
    color: var(--text-secondary);
    cursor: pointer;
    transition: color 0.2s, border-color 0.2s;
}

.nav-collapse-btn svg {
    width: 16px;
    height: 16px;
    transition: transform 0.22s ease;
}

/* Hover brightens the glyph and the hairline only. The fill does not change:
   a disc that lights up under the cursor is a second shape appearing where the
   first one was, and this one is already visible without it.

   The three `none`s and the repeated transform are not belt-and-braces: the base
   sheet has a global `button:hover` that adds a box-shadow and a text-shadow and
   sets `transform: translateY(2px)`. That last one is the whole reason the disc
   used to hop — transform is one property, so translateY REPLACES the translateX
   that holds the disc on the edge and it snaps 14px back inside. Restating it
   here is what pins it. Same for :focus-visible and :active. */
.nav-collapse-btn:hover,
.nav-collapse-btn:focus-visible,
.nav-collapse-btn:active {
    transform: translateX(50%);
    box-shadow: none;
    text-shadow: none;
    border:none;
    
}

.nav-collapse-btn:hover {
    color: var(--text-primary);
    border-color: var(--text-secondary);
}

/* Keyboard focus still needs to be obvious, and outline draws outside the box
   without moving it — the ring follows the border-radius, so it is a ring. */
.nav-collapse-btn:focus-visible {
    color: var(--text-primary);
    outline: 2px solid var(--accent-color);
    outline-offset: 2px;
}


/* --- 3. The profile entry ----------------------------------------------------

   The icon over the user's name, at two menu items tall. It keeps .nav-item's
   hover, active edge and padding so it is the same control as the rest of the
   column — only its axis and its height differ.

   It is a menu trigger now, not a link. The name is still the user's own, so
   this is also the only row whose label length is not under our control.

   The NAME is what is aligned left, on the same axis as every icon below it, and
   the icon is centred over the name rather than over the sidebar. .nav-item sets
   `align-items: center`, which on this one row is the horizontal axis because the
   row is a column — that is what had both of them centred in the middle of a menu
   whose every other item starts at 28px. flex-start hands the pair to the column.

   Centring the icon over the name is then the wrapper's job, not this rule's:
   two siblings in a column cannot be aligned to each other, only to the box they
   are in. See .nav-profile-id. */
.nav-item.nav-profile {
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    min-height: calc(var(--nav-item-height) * 2);
}

/* The icon and the name, boxed together so they have something to be centred on.

   The box is a flex ITEM of the row above, which is `align-items: flex-start` —
   so it shrinks to its widest child instead of filling the row. That child is the
   name (105px against the icon's 48), which puts the box's left edge on the icon
   column and leaves the icon centred inside it. A name shorter than 48px inverts
   that and the name centres under the icon, which is the same rule read the other
   way, not an exception to it.

   `min-width: 0` is what lets the name be clipped rather than widen the box: a
   flex item does not shrink below its content without it. */
.nav-profile-id {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    min-width: 0;
    max-width: 100%;
}

/* The profile icon at 48px, and the block does NOT grow with it — it stays the
   two menu items it is specified at. 48 + 6px gap + one line of name + 1rem top
   and bottom fits inside 128px with room to spare.

   Done here rather than in NavIcons: the width/height are attributes on the SVG
   markup and that map is shared by every icon. A CSS rule beats a presentation
   attribute, so this reaches the profile icon alone. */
.nav-item.nav-profile svg {
    width: 48px;
    height: 48px;
}

/* A real name is longer than "Profile" and the sidebar is a fixed width, so the
   overflow rule is not decoration — without it a long name widens the row and
   pushes the whole column out. One line, clipped; the full name is on the item's
   title attribute. */
.nav-profile-name {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The caret that says this row opens something rather than going somewhere.
   Absolutely placed so it does not join the column flex and push the name. */
.nav-item.nav-profile {
    position: relative;
}

.nav-profile-chev {
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 0.75rem;
    line-height: 1;
    opacity: 0.6;
    transition: transform 0.2s ease;
}


/* --- The profile menu -------------------------------------------------------

   A SIBLING of .nav-list, not a list item. .nav-list scrolls, and anything
   inside a scroll container is clipped by it — a menu built into the profile
   <li> would be cut off at the list's edge the moment it extended past it.
   Placed against the sidebar instead, it can hang outside the rail entirely,
   which is the whole point of a pop-out.

   Its `top` is written by JS from the profile row's live position, because the
   list scrolls underneath it. */
.nav-profile-menu {
    position: absolute;
    left: calc(100% - 10px);
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 186px;
    padding: 6px;
    background-color: #1b1b1b;
    border: 1px solid #333;
    border-radius: 6px;
    box-shadow: 0 14px 34px rgba(0, 0, 0, 0.65);
    z-index: 2;
}

/* `display: flex` above beats the [hidden] attribute's own display:none, so the
   hidden state has to be spelled out or the menu is never closed. */
.nav-profile-menu[hidden] {
    display: none;
}

.nav-profile-menu-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 9px 12px;
    background: none;
    border: none;
    border-radius: 4px;
    font: inherit;
    font-size: 0.95rem;
    color: var(--text-secondary);
    text-align: left;
    white-space: nowrap;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}

.nav-profile-menu-item svg {
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
}

.nav-profile-menu-item:hover,
.nav-profile-menu-item:focus-visible {
    background-color: #2a2a2a;
    color: var(--text-primary);
    outline: none;
}

/* Sign Out is the one item here that cannot be undone by clicking again. It
   reads in the brand red on hover for the same reason a delete does. */
.nav-profile-menu-item.is-signout:hover,
.nav-profile-menu-item.is-signout:focus-visible {
    color: var(--accent-color);
}

/* The hairline between "go somewhere" and "leave". */
.nav-profile-menu-sep {
    height: 1px;
    margin: 4px 6px;
    background-color: #333;
}


/* --- 1. Collapsed: the icon rail --------------------------------------------

   Desktop only. Below the breakpoint the sidebar is already a slide-in drawer
   that covers the page, and a 76px rail sliding over the content would be a
   third state nobody asked for — so every collapsed rule is scoped to the width
   where a docked sidebar exists at all, and nothing has to be undone on mobile.

   --sidebar-width is redefined on <body> rather than the rail being hardcoded
   on .sidebar. Everything that has to move with the sidebar already reads that
   variable: .main-content's margin and width, and the film page's --film-rail,
   which is what pins its full-screen header to the content column. One value
   changes and all four follow. */
@media (min-width: 769px) {

    body.nav-collapsed {
        --sidebar-width: 76px;
    }

    /* Every label in the column. They are wrapped in this span by the nav module
       for exactly this rule — before it they were bare text nodes, and CSS
       cannot hide a text node. */
    body.nav-collapsed .nav-label,
    body.nav-collapsed .nav-profile-name,
    body.nav-collapsed .nav-profile-chev {
        display: none;
    }

    /* Centred on the RAIL, not on the row. .nav-item's 4px active edge is inside
       its box, so a row that simply centres its content puts the icon at 40px
       across a 76px rail — 2px right of the middle, which reads as a wobble down
       a column of six. The 4px is given back on the other side. */
    body.nav-collapsed .nav-item {
        justify-content: center;
        padding-left: 0;
        padding-right: 4px;
    }

    /* The rules that hid the sub-list panes and their carets on the rail are
       gone with the panes themselves — there is no expanding section left in
       this sidebar to hide. */

    /* The profile block gives up its second row with the name that filled it.

       And it takes back the centring it gives up when expanded: on the rail
       there is no column of labels to start against, only the icons' axis, and
       `justify-content: center` from the rule above is this row's VERTICAL axis
       — for a column, centring across the rail is align-items. The box inside it
       needs nothing: with the name hidden it is exactly its icon wide. */
    body.nav-collapsed .nav-item.nav-profile {
        min-height: 0;
        align-items: center;
    }

    body.nav-collapsed .nav-item.nav-profile svg {
        width: 30px;
        height: 30px;
    }

    /* The head stays ONE ROW on the rail. Stacking the control under the brand
       mark made the head taller than the expanded one, so the whole icon column
       dropped as the sidebar contracted — the menu appeared to jump. Same row,
       same 2rem below it, and the first icon does not move between the two
       states.

       The horizontal padding goes, so the head's content box is the full 76px
       and a centred brand mark lands on the same axis as the icons: .nav-item
       centres inside 4px of active edge and 4px of padding, which is also the
       middle of the rail. */
    body.nav-collapsed .nav-head {
        gap: 0;
        padding: 0 0 2rem;
    }

    /* The wordmark is HTML on fifteen pages and cannot be rewritten from CSS, so
       it is zeroed and the initial is drawn in its place. Full width, centred —
       NOT `flex: 0 0 auto`, which would shrink the box to the glyph and hand the
       remaining width to the button, taking the Q off the icons' axis. */
    body.nav-collapsed .nav-head .logo {
        flex: 1 1 auto;
        width: 100%;
        font-size: 0;
        text-align: center;
        /* `font-size: 0` does NOT make the wordmark weightless. .logo carries
           `letter-spacing: 2px`, and letter-spacing is a length — it is added
           after every character whatever the type size, so the eight invisible
           letters of QUIZFLIX still occupied 16px on the line. Centring that
           line put the Q eight pixels left of the icon column: a box measured
           dead centre, drawn off centre. */
        letter-spacing: 0;
    }

    body.nav-collapsed .nav-head .logo::before {
        content: "Q";
        font-size: 1.5rem;
    }

    /* The disc needs nothing here any more. It is positioned against the head,
       which is the rail's full 76px, so `right: 0` follows the edge in as the
       sidebar contracts — and being out of the flow already, it cannot push the
       Q off the icons' axis. Only the arrow turns around. */
    body.nav-collapsed .nav-collapse-btn svg {
        transform: rotate(180deg);
    }

    /* Off the rail entirely, with the arrow of the trigger under it. */
    body.nav-collapsed .nav-profile-menu {
        left: calc(100% + 6px);
    }

    /* The animation is opt-in, added by JS one frame after the first paint. The
       stored collapsed state is applied before that frame, so a user who left
       the sidebar collapsed sees it collapsed — not a 176px sidebar sliding
       shut every time they open a page. */
    body.nav-animate .sidebar {
        transition: transform 0.3s ease, width 0.22s ease;
    }

    body.nav-animate .main-content {
        transition: margin-left 0.22s ease, width 0.22s ease;
    }

    /* The film page's header is three fixed layers pinned to the content column
       by --film-rail. They are not children of .main-content, so its transition
       does not reach them, and without this they jump the full 174px while the
       sidebar beside them slides. */
    body.nav-animate.film-page .film-bg,
    body.nav-animate.film-page .film-scrim,
    body.nav-animate.film-page .film-logo-layer {
        transition: left 0.22s ease;
    }
}


/* --- Mobile -----------------------------------------------------------------

   The hamburger already opens and closes the sidebar here, so a second control
   that does a similar-but-different thing is noise. */
@media (max-width: 768px) {
    .nav-collapse-btn {
        display: none;
    }

    /* The drawer is 176px wide and starts at the left edge, so a menu hung off
       its right edge is still on screen — but only just. Pulled back inside. */
    .nav-profile-menu {
        left: auto;
        right: 8px;
    }
}
