/* THE HUB'S SIDE-RAIL CHROME — every rule here is scoped to
 * body[data-global-nav="side"].
 *
 * Split out of global-nav-side.css on 2026-08-26. That file is linked from
 * partials/quaive_head.html on EVERY face, but `data-global-nav` is only ever
 * "side" (hub) or "compact" (One/Pro) — core.platform_modes.MODE_GLOBAL_NAV —
 * so on the personal cloud, which is always compact, these 53KB could never
 * match a single element. They were pure cold-start weight on the exact face
 * we care most about.
 *
 * What did NOT move: the bare `#global-nav-side` / `.gns-*` rules. Those ARE
 * live on compact — global-nav-side.css turns the same element into the phone's
 * bottom tab bar. Only the "side"-attributed rules are provably dead there.
 *
 * The blocks keep their original relative order. They now all sit AFTER the
 * shared file rather than interleaved with it, which can only matter for a
 * side-scoped rule that used to LOSE to an equal-specificity shared rule — and
 * the attribute selector these carry makes equal specificity the rare case.
 */

body[data-global-nav="side"] {
    transition: --gns-active-app-colour var(--gns-transition);
}

body[data-global-nav="side"] #global-nav-side {
    display: flex;
}

@media only screen and (min-width: calc(768px + 1px)) {
    body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side {
        width: var(--gns-width-collapsed);
        /* Fixed semi-transparent white, the same regardless of which app
         * is active (previously a 10% wash of the active app/space colour). */
        background: rgba(255, 255, 255, 0.5);
        box-shadow: var(--default-box-shadow);
        border-color: white;
    }
}
@media only screen and (min-width: calc(768px + 1px)) {
    body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-platform-name {
        zoom: 0.001;
        opacity: 0;
    }
    /* The user line shrinks away rather than popping out */
    body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-hub {
        margin-top: 0;
        opacity: 0;
    }
    /* Morph the full wordmark into the brandmark: scale down + slide left so
     * the orange swirl (on the right of the wordmark) arrives roughly where
     * the black mark sits, fading out as the mark fades in — reads as one
     * mark transforming rather than a hard crossfade. */
    body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-logo-full {
        opacity: 0;
        transform: scale(0.30) translate(-125px, -22px);
    }
    /* RTL: the rail (and mark) sit on the right, so slide the wordmark the
     * other way. */
    body[dir="rtl"][data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-logo-full {
        transform: scale(0.9) translateX(82px);
    }
    body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-logo-mark {
        opacity: 1;
        top: 5px;
        left: 6px;
        /* ink-coloured brandmark, slightly inset like the app glyphs */
        filter: grayscale(1) brightness(0.08);
        transform: scale(0.92);
    }
    body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-header {
        padding-left: 0;
        padding-right: 0;
        height: 35px;
    }
    /* Collapsed: the logo behaves like an icon tile — same size and
     * radius as the app icons, with the same light hover wash */
    body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-platform-logo {
        width: 38px;
        height: 38px;
        margin-left: 6px;
        border-radius: var(--kik-global-nav-icon-radius);
    }
    @media (hover: hover) {
      body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-platform-logo:hover {
          background-color: color-mix(in srgb, var(--gns-ink) 7%, transparent);
      }
    }
    
    /* Home is the active screen while the rail is collapsed (only the
     * tablet-portrait case — on desktop the rail collapses only once an
     * app is on screen). The logo tile then reads as the "current"
     * destination, exactly like a current app icon: solid accent fill,
     * brandmark inverted to white. */
    body[data-global-nav="side"].gns-collapsed:not(:has(#app-space.state-on)) #global-nav-side .gns-platform-logo {
        background-color: var(--colour-accent, var(--gns-accent));
    }

    @media (hover: hover) {
      body[data-global-nav="side"].gns-collapsed:not(:has(#app-space.state-on)) #global-nav-side .gns-platform-logo:hover {
          background-color: var(--colour-accent, var(--gns-accent));
      }
    }
    body[data-global-nav="side"].gns-collapsed:not(:has(#app-space.state-on)) #global-nav-side .gns-logo-mark {
        /* invert the brandmark to solid white (vs the dark-ink filter
         * the inactive collapsed state uses above) */
        filter: brightness(0) invert(1);
    }
}
@media only screen and (min-width: calc(768px + 1px)) {
    body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-section-title {
        zoom: 0.001;
        opacity: 0;
    }
    /* Updates is the dashboard's home surface on desktop — only the
     * mobile bottom bar gets its own Updates tab */
    body[data-global-nav="side"] #global-nav-side .gns-item.gns-app-updates {
        display: none;
    }
    /* The utility apps (preferences / administrator / password / help) ride
     * the avatar/personal menu, not the desktop rail — they stay available on
     * the mobile bottom bar's more-apps popover.
     *
     * …unless the user PINNED one. Pinning is an explicit "keep this one
     * click away", and an admin who stars Administrator has said exactly that;
     * silently dropping it made the star a lie. Same data-gns-pinned marker
     * and same reasoning as Team spaces (global-nav-mobile-order.css) —
     * default-hidden, pinned-visible. Unpinned still never shows here, not
     * even while the app is open, since these slugs stay in
     * quaive_tags._GNS_DESKTOP_HIDDEN_SLUGS and so get no open-reveal rule. */
    body[data-global-nav="side"] #global-nav-side .gns-apps > .gns-item:is(
        .gns-app-preferences,
        .gns-app-administrator,
        .gns-app-password,
        .gns-app-help
    ):not(:has([data-gns-pinned])) {
        display: none;
    }
    /* Open-or-pinned rail (the pro/One rail's behaviour): an app that is
     * neither a favourite nor open earns no desktop rail row. The template
     * flags those entries .gns-open-item and generates a per-app :has()
     * reveal that overrides this the moment the app body is on — see
     * global_nav_side.html. Both live behind this desktop breakpoint: the
     * mobile bottom bar keeps listing every app, capped by its own
     * nth-child rules. */
    body[data-global-nav="side"] #global-nav-side .gns-apps > .gns-item.gns-open-item {
        display: none;
    }

    /* Two halves: the apps you PINNED, then the ones that are merely open.
     *
     * Done with `order`, not DOM order: the mobile bar's icon cap is
     * nth-child-based, so it counts DOM position and the list must keep the
     * order quaive_tags.global_nav_apps hands over. Flex is what makes `order`
     * work on the rows, and a column flex box lays them out exactly as the
     * block list did. Desktop only — the mobile bar dissolves this same ul
     * with display: contents. */
    body[data-global-nav="side"] #global-nav-side .gns-apps {
        display: flex;
        flex-direction: column;
    }
    body[data-global-nav="side"] #global-nav-side .gns-apps > .gns-item {
        order: 1;
    }
    body[data-global-nav="side"] #global-nav-side .gns-apps > .gns-apps-separator {
        order: 2;
    }
    body[data-global-nav="side"] #global-nav-side .gns-apps > .gns-item.gns-open-item {
        order: 3;
    }
    /* The rule itself: a dim hairline with air either side, hidden until the
     * generated :has() rules say something is actually below it (an empty
     * rule floating under the pinned apps reads as a mistake). It is a bare
     * <li> with no row of its own, so it can't be tabbed to or hovered. */
    body[data-global-nav="side"] #global-nav-side .gns-apps > .gns-apps-separator {
        display: none;
        height: 0;
        /* 5px, not 3px: the rule is inset to the ICON TILE's edge, and the
         * tile now starts 5px in (the row's 2px padding + the icon's 3px
         * margin) in both rail states. */
        margin: 8px 5px;
        padding: 0;
        border-top: 2px solid color-mix(in srgb, var(--gns-ink) 10%, transparent);
        pointer-events: none;
    }

    /* Close an open, unpinned app from the EXPANDED rail.
     *
     * Those rows are on the rail only because their app is open, so closing is
     * the one thing you might want from them that the row itself doesn't do —
     * and it takes the row away, which is what makes the × honest here (a
     * pinned row stays put, so it gets no × at all).
     *
     * Different shape from the collapsed rail's close, which swaps the whole
     * tile: here the row keeps its icon and its label, and the × sits at the
     * right end as its own control. The HIT AREA is a square the height of the
     * row, flush to its right edge; the PLATE that appears under the × on
     * hover is inset well inside that — 32 square against the row's 44, more
     * tightly rounded — so it reads as nested inside rather than boxed against
     * it. It appears on row hover, taking the unread counter's place —
     * they share that end of the row. */
    body[data-global-nav="side"]:not(.gns-collapsed):not(:has(#app-space.state-on)) #global-nav-side .gns-apps > .gns-item.gns-open-item {
        position: relative;
    }
    body[data-global-nav="side"]:not(.gns-collapsed):not(:has(#app-space.state-on)) #global-nav-side .gns-apps > .gns-item.gns-open-item .gns-link.gns-close {
        display: flex;
        align-items: center;
        justify-content: center;
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        width: 44px;
        height: auto;
        padding: 0;
        background: none;
        opacity: 0;
        transition: opacity var(--gns-transition);
    }
    /* The × and nothing else. The control renders the shared app-icon partial,
     * which carries the app ICON and its LABEL as well — left up, the label
     * sat under the × clipped to its first letters ("Be✕" for Berichten). */
    body[data-global-nav="side"]:not(.gns-collapsed):not(:has(#app-space.state-on)) #global-nav-side .gns-apps > .gns-item.gns-open-item .gns-close .gns-icon:not(.gns-close-glyph),
    body[data-global-nav="side"]:not(.gns-collapsed):not(:has(#app-space.state-on)) #global-nav-side .gns-apps > .gns-item.gns-open-item .gns-close .gns-label {
        display: none;
    }
    body[data-global-nav="side"]:not(.gns-collapsed):not(:has(#app-space.state-on)) #global-nav-side .gns-apps > .gns-item.gns-open-item .gns-close .gns-close-glyph {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 32px;
        height: 32px;
        margin: 0;
        padding: 0;
        border-radius: var(--kik-global-nav-icon-radius);
        background-color: transparent;
        /* Dim through the COLOUR, not opacity — opacity would fade the plate
         * behind it along with the glyph. */
        color: color-mix(in srgb, var(--gns-ink) 45%, transparent);
        opacity: 1;
        transition: background-color var(--gns-transition), color var(--gns-transition);
    }
    @media (hover: hover) {
        body[data-global-nav="side"]:not(.gns-collapsed):not(:has(#app-space.state-on)) #global-nav-side .gns-apps > .gns-item.gns-open-item:hover .gns-link.gns-close {
            opacity: 1;
        }
        /* Keep the ROW washed while the pointer is on the ×. The wash lives on
         * .gns-link:hover, and the close control is a SIBLING anchor laid over
         * the launcher — so reaching for the × took the pointer off the
         * launcher and the row went cold underneath the very control it was
         * offering. Paint it from the row's own hover instead. (Not for the
         * active row: its state shows through the coloured icon tile, never a
         * wash — same exception the rule below this one makes.) */
        body[data-global-nav="side"]:not(.gns-collapsed):not(:has(#app-space.state-on)) #global-nav-side .gns-apps > .gns-item.gns-open-item:not(.current):hover .gns-link.gns-launcher {
            background: color-mix(in srgb, var(--gns-ink) 5%, transparent);
        }
        /* The × takes the COUNTER's place — they occupy the same end of the
         * row, so with the badge left up the two overlapped into an unreadable
         * knot (an orange 1 with a × through it). Hiding the badge for the
         * duration of the hover also says the right thing: while you are
         * reaching for close, how many unread there are is not the point. */
        body[data-global-nav="side"]:not(.gns-collapsed):not(:has(#app-space.state-on)) #global-nav-side .gns-apps > .gns-item.gns-open-item:hover .gns-link.gns-launcher .gns-badge {
            display: none;
        }
        /* A long label runs the full width of the row, so the × that fades in
         * over its right end lands ON the last letters ("Videovergadering✕").
         * The label fades out under the control instead of being clipped at a
         * hard edge — a gradient mask over the width the × occupies, so the
         * word trails off into it rather than colliding with it. Only where
         * there IS a × (.gns-open-item) and only on the expanded rail; the
         * collapsed rail has no label to fade. The mask is physical-right in
         * both directions because the control it hides behind is: .gns-close
         * is pinned with right: 0 and is not flipped for RTL. */
        body[data-global-nav="side"]:not(.gns-collapsed):not(:has(#app-space.state-on)) #global-nav-side .gns-apps > .gns-item.gns-open-item:hover .gns-link.gns-launcher .gns-label {
            mask-image: linear-gradient(to right, #000 calc(100% - 3rem), transparent 100%);
        }
        body[data-global-nav="side"]:not(.gns-collapsed):not(:has(#app-space.state-on)) #global-nav-side .gns-apps > .gns-item.gns-open-item .gns-link.gns-close:hover .gns-close-glyph {
            background-color: color-mix(in srgb, var(--gns-ink) 8%, transparent);
            color: color-mix(in srgb, var(--gns-ink) 85%, transparent);
        }
    }
}
@media only screen and (min-width: calc(768px + 1px)) {
    body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-label {
        flex-grow: 0;
        max-width: 0;
        opacity: 0;
    }
    /* The icon stays LEFT-aligned and the base row's 2px left padding does the
     * centring — it used to be justify-content: center, and that is not an
     * animatable property. It applied on the first frame of the collapse,
     * while the row was still 228px wide, so every icon was flung towards the
     * middle of a row that was about to disappear; the label's max-width then
     * snapped to 0 halfway through and threw them somewhere else again, and
     * the width animation walked them back. That three-step detour is the
     * wobble.
     *
     * Left-aligned there is no detour, and nothing here changes the icon's
     * position at all: every rail slot (38px icon + 3px margins, 26px space
     * letter + 9px margins) is 44px wide, so the row's own 2px + 44px + 2px
     * fills the collapsed rail's 48px content box and centres the slot to the
     * pixel — the same 2px the expanded rail already carries. Only the label's
     * trailing 10px goes, and there is no label here to push. */
    body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-link {
        padding: 0 0 0 2px;
        gap: 0;
    }
    
    /* Collapsed rail: hover feedback moves from the row to the icon
     * tile itself (active icons keep their app-colour fill) */
    @media (hover: hover) {
      body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-link:hover {
          background: transparent;
      }
    }
    @media (hover: hover) {
      body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-item:not(.current) .gns-link:hover .gns-icon.app-icon {
          background-color: color-mix(in srgb, var(--gns-ink) 7%, transparent);
      }
    }
    /* Collapsed rail: glyphs go full black (the active app keeps its
     * white-on-app-colour tile, untouched by the :not(.current) scope) */
    body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-item:not(.current) .gns-link:not([aria-current="page"]) .gns-icon.app-icon * {
        fill: #000 !important;
    }
    body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-item:not(.current) .gns-link:not([aria-current="page"]) .gns-icon.app-icon svg #dots {
        fill: transparent !important;
    }
    /* Rail line icons: colour the stroke black instead of the fill */
    body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-item:not(.current) .gns-link:not([aria-current="page"]) .gns-icon.rail-icon * {
        fill: none !important;
        stroke: #000 !important;
    }
}
/* HOVER: exactly what an app row does, in both rail states.
 *
 * EXPANDED — the whole row highlights, from the shared ``.gns-link:hover``
 * wash; nothing here overrides it.
 *
 * COLLAPSED (or any app open) — the row wash is off rail-wide and the feedback
 * moves to the icon: a rounded-corner square behind the mark at the app tile's
 * own geometry (38px, 10px radius, 7% ink). Painted as an ::after rather than
 * a background on the avatar, because the mark is a smaller circle sitting in
 * the middle of that slot; ``inset: -6px`` on the 26px circle lands exactly on
 * the app tile's footprint. */
@media (hover: hover) {
    body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-item.gns-space .gns-link:hover .gns-space-avatar::after {
        content: "";
        position: absolute;
        inset: -6px;
        border-radius: var(--kik-global-nav-icon-radius);
        background-color: color-mix(in srgb, var(--gns-ink) 7%, transparent);
        z-index: -1;
    }
    /* The open space is the ONE row that skips the square — its avatar is
     * already filled, and a wash behind a filled tile just muddies it. But
     * only while the space is actually in the foreground: an open space with
     * another app on top keeps its ``current`` class and renders like any
     * other row (same gate the accent-label rule uses), so with the row wash
     * off in this state it had no hover feedback left at all. */
    body:has(#app-space.state-on:is(.active-app-workspaces, .active-app-team-spaces)) #global-nav-side .gns-item.gns-space.current .gns-link:hover .gns-space-avatar::after {
        display: none;
    }
}
@media only screen and (min-width: calc(768px + 1px)) {
    body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-badge {
        position: absolute;
        top: 4px;
        right: 2px;
    }
}

/* Collapsed rail: labels become tooltips (CSS-only, from data-gns-label) */
@media only screen and (min-width: calc(768px + 1px)) {
    @media (hover: hover) {
      body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-link[data-gns-label]:hover::after,
      body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-hub[data-gns-label]:hover::after,
      body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-platform-logo[data-gns-label]:hover::after {
          content: attr(data-gns-label);
          position: fixed;
          left: calc(var(--gns-left) + var(--gns-width-collapsed) + 6px);
          background: var(--gns-background);
          color: var(--gns-ink);
          font-size: 0.8em;
          font-weight: 400;
          padding: 4px 10px;
          border-radius: 4px;
          box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
          white-space: nowrap;
          z-index: 1000;
          pointer-events: none;
      }
      /* A PINNED app says so in its tooltip — the row itself keeps showing the
       * app icon at every state, hover included. (An earlier take swapped the
       * icon for a pin glyph on hover; it cost you the icon for a fact that
       * isn't about what the click does.) The marker rides the tooltip's
       * ``content`` rather than data-gns-label so the attribute stays the plain
       * app name. A literal pushpin character, not the fontello glyph: the
       * pseudo-element renders the label in the UI font, and one content string
       * can only have one font-family. */
      body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-link[data-gns-label][data-gns-pinned]:hover::after {
          content: "\1F4CC\00a0" attr(data-gns-label);
      }
    }

    /* The platform logo is a tall 67px block, so the fixed pseudo's static
     * vertical position falls to the block's bottom — well below the small
     * 38px collapsed brandmark tile. Anchor it to the rail top instead so it
     * centres on the swirl tile (rail padding-top 22px + half the 38px tile). */
    @media (hover: hover) {
      body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-platform-logo[data-gns-label]:hover::after {
          top: calc(var(--gns-top) + 30px);
      }
    }
}

/* ------------------------------------------------------------------ */
/* Chrome swap: what Side mode does to the rest of the page            */
/* ------------------------------------------------------------------ */

/* The header is gone in Side mode, so every layout offset derived
 * from its height collapses to zero (0px, not 0 — unitless zero is
 * invalid inside calc() additions). The dashboard's top margin made
 * room under that header, so it goes too. */
body[data-global-nav="side"] {
    --global-header-height: 0px;
    --dashboard-margin-top: 0px;
}
/* The dashboard sits flush to the top in Side mode — no header to
 * clear. dashboard.css declares --dashboard-margin-top ON
 * .quaive-dashboard itself at large widths (80px, or 40px via
 * #portal:not(:has(#portal-tabs))), which out-ranks the inherited
 * body-level reset, so re-zero it on the element with matching/higher
 * specificity. The second selector beats the (2,1,0) 40px rule;
 * together they cover every width. */
body[data-global-nav="side"] #portal .quaive-dashboard,
body[data-global-nav="side"] #portal:not(:has(#portal-tabs)) .quaive-dashboard {
    --dashboard-margin-top: 0px;
}

/* Side-mode dashboard goes full-bleed: drop the 1280px container cap so
 * the portlet grid uses the whole canvas (the apps/favourites portal
 * sections keep their cap — this is scoped to .section-dashboard). The
 * content box also becomes a size container (gns-dash) so the rules below
 * react to the REAL available width, not the viewport — the rail inset
 * varies (expanded on Home, the 50px strip in tablet-portrait), so a
 * viewport breakpoint would mis-judge how many columns actually fit. */
body[data-global-nav="side"] #portal.section-dashboard #portal-content {
    max-width: none;
    --pat-container-width: none;
    container: gns-dash / inline-size;
}
/* Stop capping the column count: instead of a fixed 2fr/3-track template,
 * auto-fill spawns one more ~320px lane every time another fits, so the
 * portlet grid keeps gaining columns as the canvas widens. */
body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard {
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    grid-auto-flow: row dense;
    /* AN IMPLICIT LANE IS A FULL LANE. Zmanim and Apps are pinned to
     * ``grid-column: 3`` from container width 1000px on, but auto-fill only
     * spawns a third 320px lane once 3*320 + 2*30 = 1020px is available — so
     * in the 20px band between the two, column 3 does not exist in the
     * explicit grid and every portlet placed there landed in an IMPLICIT
     * track sized by ``grid-auto-columns: auto``, i.e. min-content: a 42px
     * ribbon of clipped text down the right edge (Daniel, screenshot,
     * 2026-08-23). Sizing implicit tracks like the explicit ones makes that
     * band a normal three-lane dashboard, and keeps any future drift between
     * a pin and the lane arithmetic from collapsing a column again. */
    grid-auto-columns: minmax(0, 1fr);
}
/* The Apps portlet used to be hidden here as redundant (the rail lists the
 * apps). It is back, directly after the Chokhmah/zmanim portlet — the rail's
 * own Apps entry is a candy-box launcher, not the grid — so it is now an
 * ordinary span-1 portlet: shown from size 3 on, hidden at sizes 1–2 by their
 * essentials filter like every other portlet. Its lane pin sits with zmanim's
 * at the bottom of this section. */
/* The activity stream always lives in the first column — pin its column
 * line to 1 so the masonry/auto-flow algorithm can't drift it into
 * another lane (it would otherwise seek the shortest one). The base
 * span-every-row pin is dropped (no fixed track count to span). */
body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard > .quaive-portlet#portlet-updates {
    grid-column: 1;
    grid-row: auto;
    align-self: start;
}
/* Native masonry where the browser has it: portlets pack up into the
 * shortest lane rather than aligning to row tracks, removing the ragged
 * vertical gaps a plain auto-flow grid leaves. Falls back to the grid
 * above wherever display: grid-lanes is unsupported. */
@supports (display: grid-lanes) {
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard {
        display: grid-lanes;
    }
}
/* The lane width (320px) + gutter (20px) sets the breakpoints:
 *   1 lane  : <660px    (size 1, "mobile")
 *   2 lanes : 660–999   (size 2)
 *   3 lanes : 1000–1339 (size 3) …and +340px per lane after that.
 *
 * Two lanes or more: the activity stream is the prominent wide column,
 * spanning the first two lanes. In size 2 that makes it full-width; from
 * size 3 on it's the wide left column with span-1 portlets to its right
 * — and it always starts at lane 1 ("stays in the first column"). */
@container gns-dash (width >= 660px) {
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard > .quaive-portlet#portlet-updates {
        grid-column: 1 / span 2;
    }
}

/* Size 1 (one lane, "mobile"): only the activity stream. Everything else,
 * Zmanim and News included, is hidden — and the lone activities portlet
 * sheds its card chrome to read as the bare feed (full-width column, no
 * title, no panel background/shadow/border/padding). Container-query
 * based, so it holds whenever the dashboard column is this narrow — the
 * mobile bottom-bar layout AND a desktop side-nav with the rail expanded. */
@container gns-dash (width < 660px) {
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard > .quaive-portlet:not(#portlet-updates) {
        display: none;
    }
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard {
        grid-template-columns: 1fr;
    }
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard > .quaive-portlet {
        grid-column: 1 / -1;
        background: transparent;
        box-shadow: none;
    }
    body[data-global-nav="side"] #portlet-updates .well-title-group,
    body[data-global-nav="side"] #portlet-activity-stream .well-title-group {
        display: none;
    }
    /* No card chrome and NO padding, on the portlet or its body: with nothing
     * above it the stream IS the page, so it starts at the top edge.
     *
     * Qualified through the dashboard (#portal.section-dashboard
     * .quaive-dashboard) only to outrank the ``padding-top: 20px`` in the
     * ≥769px MEDIA block further down. That one is a VIEWPORT query and this
     * is a CONTAINER query, so on a narrow tablet portrait — viewport ≥769,
     * dashboard column <660 because the expanded rail eats the width — both
     * matched at equal specificity and the later one won, dropping a 20px gap
     * above a feed that has nothing to be spaced from. */
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard #portlet-updates,
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard #portlet-activity-stream {
        padding: 0;
    }
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard #portlet-updates .panel-content,
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard #portlet-activity-stream .panel-content {
        background: transparent;
        box-shadow: none;
        border: none;
        padding: 0;
    }
    /* The standalone compose + comment boxes carry ``margin: 2rem auto`` from
     * base.css so they get breathing room on a roomy board. Here the card
     * padding around them is gone, so that fixed 2rem is measured from the
     * screen edge instead of from a card, and the `auto` centring has nothing
     * left to centre against. Percentages instead: the inset scales with the
     * column, which at this width IS the screen, so the box keeps the same
     * proportion of air around it from a narrow phone to a tablet portrait —
     * where a fixed rem is generous on one and cramped on the other. */
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard .update-social.post-box:not(.post *),
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard .update-social.comment-box:not(.post *) {
        margin: 5% 5% 3%;
        max-width: 100%;
    }
}

/* Mobile (the bottom-bar breakpoint): the stream and nothing above it.
 *
 * A VIEWPORT query, deliberately, where the tiers below are container queries.
 * With the rail dissolved into a bottom bar the dashboard column gets the whole
 * screen, so a phone in landscape measures wide enough to land in the two-lane
 * tier and grew a card above the feed. On a phone the feed is the page whatever
 * the column happens to measure. */
@media only screen and (max-width: 768px) {
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard > .quaive-portlet:not(#portlet-updates):not(#portlet-activity-stream) {
        display: none;
    }
    /* …and the same chrome the one-lane tier sheds. Deliberately repeated
     * rather than shared: the tier is a CONTAINER query and this is a VIEWPORT
     * one, and CSS has no way to say "either of these". Without it a phone whose
     * dashboard column happens to measure ≥660 — the bar gives the board the
     * whole screen — got the mobile bottom bar wearing the tablet's card: a
     * well title, a panel background and padding around a feed that is the
     * whole page. Keep the two blocks in step. */
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard {
        grid-template-columns: 1fr;
    }
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard > .quaive-portlet {
        grid-column: 1 / -1;
        background: transparent;
        box-shadow: none;
    }
    body[data-global-nav="side"] #portlet-updates .well-title-group,
    body[data-global-nav="side"] #portlet-activity-stream .well-title-group {
        display: none;
    }
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard #portlet-updates,
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard #portlet-activity-stream {
        padding: 0;
    }
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard #portlet-updates .panel-content,
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard #portlet-activity-stream .panel-content {
        background: transparent;
        box-shadow: none;
        border: none;
        padding: 0;
    }
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard .update-social.post-box:not(.post *),
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard .update-social.comment-box:not(.post *) {
        margin: 5% 5% 3%;
        max-width: 100%;
    }
}

/* Size 2a (two lanes, but only just): the LAUNCHER and the activity stream,
 * nothing else. Two cards do fit side by side from 660px, but not these two —
 * Zmanim wants the width for its Hebrew date and Shabbat times, and the lane
 * left for Apps collapsed to a sliver of a card. So at the narrow end of the
 * two-lane range only one card sits above the stream, and it is the launcher:
 * a squeezed grid of app tiles is useless, while the same grid across the full
 * width is the most useful thing on a small board. Zmanim rejoins at 860px,
 * where both lanes are ~420px and neither has to give anything up. */
@container gns-dash (660px <= width < 860px) {
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard {
        display: grid;
    }
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard > .quaive-portlet:not(#portlet-apps, #portlet-updates) {
        display: none;
    }
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard > #portlet-apps {
        grid-column: 1 / span 2;
        order: 1;
    }
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard > #portlet-updates {
        order: 2;
    }
}

/* Size 2b (two roomy lanes): Zmanim, Apps and the activity stream. Zmanim and
 * Apps sit on the top row side by side (one lane each); the activity stream
 * spans both lanes underneath (its span comes from the ≥660 rule above, so it
 * drops to the next row). `order` fixes the stack: Zmanim, Apps, then
 * Activities.
 *
 * Apps rather than News here: at this width you get three cards, and the one
 * that earns a slot is the one that takes you somewhere — the launcher for
 * everything the rail doesn't already pin. News is a read, and the activity
 * stream below it is already the reading surface. */
@container gns-dash (860px <= width < 1000px) {
    /* Plain grid here, never grid-lanes: this tier relies on `order` +
     * row placement to stack Zmanim/Apps over the spanning activity
     * stream, which the masonry algorithm wouldn't honour. Overrides the
     * @supports (display: grid-lanes) rule above (same selector, later in
     * source). */
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard {
        display: grid;
    }
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard > .quaive-portlet:not(#portlet-zmanim, #portlet-apps, #portlet-updates) {
        display: none;
    }
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard > #portlet-zmanim {
        order: 1;
    }
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard > #portlet-apps {
        order: 2;
    }
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard > #portlet-updates {
        order: 3;
    }
    /* No Zmanim (Jewish add-on off): Apps takes the full top row, the
     * activity stream below it. */
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard:not(:has(#portlet-zmanim)) > #portlet-apps {
        grid-column: 1 / span 2;
        order: 1;
    }
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard:not(:has(#portlet-zmanim)) > #portlet-updates {
        order: 2;
    }
}

/* Size 3 and up (three+ lanes): every portlet is back. The activity
 * stream holds the first two lanes and the span-1 portlets fill the lanes
 * to its right, gaining one more column per +340px. Native masonry packs
 * those narrow portlets into the shortest lane on its own. The plain-grid
 * fallback can't — without help a row-grid aligns every lane to shared
 * row tracks, so the tall activity stream would blow open huge gaps in
 * the narrow lanes. The classic fix: make it span every row (1 / span
 * 100) so the span-1 portlets pack row-by-row down lanes 3+ instead. Only
 * needed where grid-lanes is absent. */
@supports not (display: grid-lanes) {
    @container gns-dash (width >= 1000px) {
        body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard > .quaive-portlet#portlet-updates {
            grid-row: 1 / span 100;
        }
    }
}
/* From size 3 on, Zmanim is a normal span-1 portlet — but it and Apps are
 * the only ones that precede the activity stream in source order, so under
 * masonry (which places in document order) they would otherwise settle into
 * lane 1 ABOVE the stream. Pin both into the second column (lane 3 — the
 * first narrow lane, since the stream spans lanes 1–2) so they sit beside
 * the stream, not above it; source order then stacks Apps directly under
 * Zmanim, which is where it belongs. Harmless in the plain-grid fallback,
 * where they already land there. */
@container gns-dash (width >= 1000px) {
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard > #portlet-zmanim,
    body[data-global-nav="side"] #portal.section-dashboard .quaive-dashboard > #portlet-apps {
        grid-column: 3;
    }
}

/* App sidebars span the full app-body height — the header is gone, so
 * the height calc that subtracted it no longer applies. */
body[data-global-nav="side"] #app-space .sidebar.left {
    height: 100%;
}

/* Rail mode: paint the app sidebars with the light app colour — a pale wash of
 * the active app's hue — so they read as part of the app, not the chrome.
 * Overriding the shared --sidebar-background-colour recolours both the sidebar
 * and its content (both consume that variable). */
body[data-global-nav="side"] .application-body {
    --sidebar-background-colour: color-mix(in srgb, var(--app-colour, white) 15%, white);
}

/* Legacy top chrome disappears while Side is active */
body[data-global-nav="side"] #global-header,
body[data-global-nav="side"] #portal-tabs,
body[data-global-nav="side"] #tabs-bar {
    display: none !important;
}

/* base.html's default #portal-content lazy-loads the APPS PORTAL (grid + its
 * launcher toolbar) as the fallback landing, so on any full-page app load —
 * e.g. the redirect after saving language prefs — that portal would otherwise
 * flash in #portal behind the open app. Home in Side mode is the dashboard,
 * reached from the rail, so suppress it.
 *
 * Scoped to the apps portal's OWN grid (#apps-listing), not to
 * `.kik-apps-grid` at large: the dashboard's Apps portlet is a grid in #portal
 * too, and the blanket rule silently blanked it — a card with a header and no
 * tiles, with nothing in the markup to explain why. */
body[data-global-nav="side"] #portal #apps-listing,
body[data-global-nav="side"] #portal #app-launcher-toolbar {
    display: none !important;
}
/* The header drop-shadow #app-space paints along its top edge belongs
 * to the hidden header — without this it floats as a stray gradient. */
body[data-global-nav="side"] #app-space:not(.injecting)::before {
    opacity: 0 !important;
}

/* Content stays at left: 0 — the rail is superimposed on top of it,
 * exactly like the workspace-tabs column floats over workspace pages.
 * top: 0 because the hidden header no longer needs headroom. */
body[data-global-nav="side"] #app-space,
body[data-global-nav="side"] #portal {
    top: 0;
    margin-left: 0;
}

@media only screen and (min-width: calc(768px + 1px)) {
    /* The portal content clears the full rail */
    body[data-global-nav="side"] #portal {
        padding-left: calc(var(--gns-left) + var(--gns-width));
        box-sizing: border-box;
    }
    /* …but a collapsed rail (tablet-portrait Home, or any open app)
     * shrinks to the 50px icon strip — the portal reclaims that width
     * and only clears the strip, so it never sits narrow beside a gap
     * where the expanded rail used to be. Tracks the same trigger as the
     * rail-width rule above. */
    body[data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #portal {
        padding-left: calc(var(--gns-left) + var(--gns-width-collapsed));
    }
    /* Apps (collapsed rail): every app body adopts the workspaces-app
     * layout recipe — the sidebar's content padding and the document
     * body's left distance both reserve the 50px rail, exactly as
     * #application-body-workspaces does for its own tabs column. The
     * stock aside.sidebar/.document-body rules in all.css consume
     * these vars; nothing else is touched. */
    body[data-global-nav="side"] #app-space .application-body {
        /* same width the workspaces app gives its sidebar (475px vs the
         * 400px platform default) */
        --sidebar-width: 475px;
        /* re-declared HERE (like #application-body-workspaces does) so
         * the calc picks up the 475px width — the :root default already
         * resolved against 400px and inherits as that fixed value */
        --document-body-left-distance-sidebar-open: calc(var(--sidebar-width) + var(--sidebar-margin-left, 15px));
        --sidebar-padding:
            var(--sidebar-padding-top)
            var(--sidebar-padding-right)
            var(--sidebar-padding-bottom)
            calc(var(--gns-width-collapsed) + 1.5 * var(--sidebar-padding-left));
        --document-body-left-distance: calc(var(--gns-width-collapsed) + var(--sidebar-padding-left));
        /* Closed sidebars keep a visible strip under the rail, exactly
         * like the workspaces app: its -397px against a 475px sidebar
         * leaves ~78px = tabs column + inset. Here that strip is the
         * rail width + the rail's left inset, whatever the app's
         * sidebar width. */
        --sidebar-margin-left-closed: calc(var(--gns-width-collapsed) + var(--gns-left) - var(--sidebar-width, 400px));
    }
    /* Large sidebars get the bigger left padding the workspaces app
     * uses (#application-body-workspaces.sidebar-large:
     * --sidebar-padding-left-large = 85px + padding) so the content
     * clears the rail. */
    body[data-global-nav="side"] #app-space .application-body.sidebar-large {
        --sidebar-padding-left-large: calc(85px + var(--sidebar-padding-left, 25px));
    }
    /* Switching to an app with an open sidebar: the sidebar slides and
     * fades in from outside the left edge. CSS animations restart when
     * the app body flips from display:none to rendered (pane switch)
     * and when a fresh body is pat-injected, so every arrival animates. */
    body[data-global-nav="side"] #app-space .application-body.sidebar-left-open aside.sidebar.left {
        animation: gns-sidebar-slide-in var(--base-animation-duration, 0.3s) ease-out;
    }
    /* The visible strip of a closed sidebar is chrome, not content —
     * fade its contents out and let clicks fall through (the stock
     * .sidebar-content transition animates the fade). */

    body[data-global-nav="side"] aside.sidebar.left .sidebar-content {
        transition: all var(--gns-transition);
        
        > * {
            transition: all var(--gns-transition);
        }
    }

    body[data-global-nav="side"] #app-space .application-body.sidebar-left-closed aside.sidebar.left #sidebar-content,
    body[data-global-nav="side"] #app-space .application-body.sidebar-left-closed aside.sidebar.left .sidebar-content {
        /* opacity: 0; */
        pointer-events: none;

        > * {
            opacity: 0;
            /* opacity alone is NOT enough: a direct child with
             * display: contents (the workspace-host sidebars wrap their
             * toolbar + listing in a pat-form rendered that way) generates
             * no box, so opacity on it composites nothing and its children
             * stay fully visible — the sidebar toolbar's white pills kept
             * peeking out around the rail on every closed team-space page.
             * visibility is INHERITED, so it reaches through a boxless
             * wrapper; being discretely animatable it also rides the same
             * transition instead of snapping. */
            visibility: hidden;
        }
    }
    /* Dashboard updates portlet: no well header (the rail/logo is the
     * navigation), just the feed with a little breathing room on top.
     * Covers the lean id (portlet-updates) and classic
     * (portlet-activity-stream). */
    body[data-global-nav="side"] #portlet-updates .well-title-group,
    body[data-global-nav="side"] #portlet-activity-stream .well-title-group {
        display: none;
    }
    body[data-global-nav="side"] #portlet-updates .panel-content,
    body[data-global-nav="side"] #portlet-activity-stream .panel-content {
        padding-top: 20px;
    }
    /* Messages Element iframe — same insets as the calendar canvas
     * below (its stock rule uses the 15px sidebar margins). */
    body[data-global-nav="side"] #app-space .application-body.application-messages .pat-element {
        top: calc(var(--sidebar-margin-top, 15px) + 0.5 * var(--sidebar-padding-top, 25px));
        right: calc(var(--sidebar-margin-top, 15px) + 0.5 * var(--sidebar-padding-top, 25px));
        bottom: calc(var(--sidebar-margin-top, 15px) + 0.5 * var(--sidebar-padding-top, 25px));
        left: var(--sidebar-padding-left, 25px);
    }
    /* Mail webmail iframe — same inset "card" box as the Messages Element
     * iframe above so the two full-bleed iframe apps line up in hub mode.
     * (Mail has no base absolute rule, so set position here too; the default
     * is the full-bleed width/height:100% from apps.css.) */
    body[data-global-nav="side"] #app-space .application-body.application-mail .mail-webmail-frame {
        position: absolute;
        top: calc(var(--sidebar-margin-top, 15px) + 0.5 * var(--sidebar-padding-top, 25px));
        right: calc(var(--sidebar-margin-top, 15px) + 0.5 * var(--sidebar-padding-top, 25px));
        bottom: calc(var(--sidebar-margin-top, 15px) + 0.5 * var(--sidebar-padding-top, 25px));
        left: var(--sidebar-padding-left, 25px);
        width: -webkit-fill-available;
        height: -webkit-fill-available;
        /* Same card chrome as the generic `.pat-element iframe` (workspace
         * chat / office editors): rounded corners + the standard drop shadow. */
        border-radius: var(--border-radii);
        box-shadow: var(--default-box-shadow);
    }
    /* Calendar canvas — same inset recipe as the workspace-chat
     * Element iframe (#application-body-workspaces .pat-element
     * iframe): 27.5px top/right/bottom, 25px left, card chrome. */
    body[data-global-nav="side"] #app-space .application-calendar .pat-calendar#calendar-app {
        position: absolute;
        top: calc(var(--sidebar-margin-top, 15px) + 0.5 * var(--sidebar-padding-top, 25px));
        right: calc(var(--sidebar-margin-top, 15px) + 0.5 * var(--sidebar-padding-top, 25px));
        bottom: calc(var(--sidebar-margin-top, 15px) + 0.5 * var(--sidebar-padding-top, 25px));
        left: var(--sidebar-padding-left, 25px);
        border-radius: var(--border-radii, 8px);
        box-shadow: var(--default-box-shadow);
    }
    /* The workspaces host reserves the SAME 50px for its own tabs
     * column — push its tabs right of the global rail and widen the
     * insets so both columns fit side by side. */
    body[data-global-nav="side"] #app-space #application-body-workspaces {
        --workspace-tabs-left: calc(var(--gns-left) + var(--gns-width-collapsed));
        --workspace-tabs-left-closed: calc(var(--gns-left) + var(--gns-width-collapsed));
        --sidebar-padding:
            var(--sidebar-padding-top)
            var(--sidebar-padding-right)
            var(--sidebar-padding-bottom)
            calc(2 * var(--gns-width-collapsed) + 1.5 * var(--sidebar-padding-left));
        --document-body-left-distance: calc(2 * var(--gns-width-collapsed) + var(--sidebar-padding-left));
    }
}
@media only screen and (min-width: calc(768px + 1px)) {
    
    /* Collapsed-rail label tooltips flip to the rail's left side (match
     * the LTR selector breadth incl. the :has() collapse variant). */
    @media (hover: hover) {
      body[dir="rtl"][data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-link[data-gns-label]:hover::after,
      body[dir="rtl"][data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-hub[data-gns-label]:hover::after,
      body[dir="rtl"][data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-platform-logo[data-gns-label]:hover::after {
          left: auto;
          right: calc(var(--gns-left) + var(--gns-width-collapsed) + 6px);
      }
    }
    /* Collapsed logo tile insets from the right edge; the brandmark
     * keeps its 5px inset measured from the right. */
    body[dir="rtl"][data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-platform-logo {
        margin-left: 0;
        margin-right: 6px;
    }
    body[dir="rtl"][data-global-nav="side"]:is(.gns-collapsed, :has(#app-space.state-on)) #global-nav-side .gns-logo-mark {
        left: auto;
        right: 5px;
    }
    /* The portal clears the rail on the right instead */
    body[dir="rtl"][data-global-nav="side"] #portal {
        padding-left: 0;
        padding-right: calc(var(--gns-left) + var(--gns-width));
    }
    /* The --sidebar-padding shorthand is physical (top right bottom
     * left): the rail inset moves from the left to the right component,
     * mirroring the workspaces-app RTL recipe in _sidebar.scss. */
    body[dir="rtl"][data-global-nav="side"] #app-space .application-body {
        --sidebar-padding:
            var(--sidebar-padding-top)
            calc(var(--gns-width-collapsed) + 1.5 * var(--sidebar-padding-left))
            var(--sidebar-padding-bottom)
            var(--sidebar-padding-right);
    }
    body[dir="rtl"][data-global-nav="side"] #app-space #application-body-workspaces {
        --sidebar-padding:
            var(--sidebar-padding-top)
            calc(2 * var(--gns-width-collapsed) + 1.5 * var(--sidebar-padding-left))
            var(--sidebar-padding-bottom)
            var(--sidebar-padding-right);
    }
    /* Open sidebars slide in from the right edge */
    body[dir="rtl"][data-global-nav="side"] #app-space .application-body.sidebar-left-open aside.sidebar.left {
        animation-name: gns-sidebar-slide-in-rtl;
    }
    /* Messages Element iframe + calendar canvas: mirror the wide rail
     * inset onto the right side. */
    body[dir="rtl"][data-global-nav="side"] #app-space .application-body.application-messages .pat-element,
    body[dir="rtl"][data-global-nav="side"] #app-space .application-calendar .pat-calendar#calendar-app {
        left: calc(var(--sidebar-margin-top, 15px) + 0.5 * var(--sidebar-padding-top, 25px));
        right: var(--sidebar-padding-left, 25px);
    }
}
/* In the popover, show only what the rail dropped. The mobile bar drives the
 * same popover through its nth-child mirrors, so this desktop-only marker
 * applies above the mobile breakpoint. */
@media (min-width: calc(768px + 1px)) {
    #global-nav-side .gns-more-popover .gns-more-app.gns-more-app-railed {
        display: none;
    }
    /* …and dock the popover beside the RAIL. The base rules park it over the
     * mobile bar (fixed to the bottom, spanning the viewport width), which is
     * nowhere near the desktop trigger. Cap the height and let the popover
     * itself scroll: it is the overflow surface, so it may legitimately be
     * longer than the rail that couldn't hold its contents. */
    body[data-global-nav="side"] .gns-more-popover {
        /* rail's right edge + a 15px gap */
        left: calc(var(--gns-width-collapsed, 64px) + var(--gns-left, 15px) + 15px);
        right: auto;
        bottom: calc(var(--gns-left, 15px) + 48px);
        width: min(280px, calc(100vw - 120px));
        max-height: 70vh;
        overflow-y: auto;
    }
    /* Apps only on tablet + desktop. The popover carries a mirror of the
     * personal menu (org switcher, personal cloud, Preferences, Log out)
     * because on PHONES it doubles as the user menu — the avatar trigger is
     * hidden at that width. Above it the avatar is back in the header, so
     * those entries would be a second copy; here the popover is purely the
     * rail's app overflow. */
    body[data-global-nav="side"] .gns-more-popover > .pat-menu-list {
        display: none;
    }
    /* One column, not two. The two-track grid is a phone affordance — the
     * popover spans the viewport there, so pairing the apps keeps it short.
     * Beside the rail it is a narrow panel, so a single column reads as a
     * plain list and the labels stop competing for half-width tracks. */
    body[data-global-nav="side"] .gns-more-popover .gns-more-list {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* The Home dashboard's back-to-landing button is a mobile-only affordance
 * in Side mode: on desktop the rail's Home button already returns there,
 * so hide it there. (On mobile the rule below re-shows it, restyled as a
 * toolbar icon.)
 *
 * The in-app .document-body back button is NOT hidden on desktop: the rail
 * only switches apps, it can't pop a detail view back to the list it lives
 * in (e.g. a Library document back to the Library), so that toolbar
 * pat-back-button has to stay visible at every width. */
@media only screen and (min-width: calc(768px + 1px)) {
    body[data-global-nav="side"] #portal .pat-toolbar .pat-back-button {
        display: none !important;
    }
}

/* ------------------------------------------------------------------ */
/* Reduced motion                                                      */
/* ------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
    #global-nav-side,
    #global-nav-side .gns-platform-logo img,
    #global-nav-side .gns-hub,
    #global-nav-side .gns-hub-name,
    #global-nav-side .gns-platform-name,
    #global-nav-side .gns-section-title,
    #global-nav-side .gns-label,
    #global-nav-side .gns-link,
    #global-nav-side .gns-icon.app-icon,
    body[data-global-nav="side"] #app-space,
    body[data-global-nav="side"] #portal {
        transition: none;
    }
    body[data-global-nav="side"] #app-space .application-body.sidebar-left-open aside.sidebar.left {
        animation: none;
    }
}

/* ------------------------------------------------------------------ */
/* Phones: HUB uses its own sidebar insets; One/Pro fill the screen        */
/* ------------------------------------------------------------------ */
/*
 * The mobile bar, the panes and the portal are shared by both faces (the
 * ≤768px section above matches "compact" alongside "side"), so the app shell
 * measures the same in either mode — with ONE exception, here.
 *
 * Compact zeroes the sidebar insets: a DESKTOP decision that reclaims the
 * space the tabs bar used to occupy. Hub's bar FLOATS 10px off the screen
 * edge, so a sidebar running the full height would pass behind it — hub keeps
 * its 15px inset.
 *
 * One and Pro do not: their dock is flush to the bottom edge now, and the
 * sidebar's own content already reserves the bar's footprint as padding (the
 * .sidebar-content rule above). An inset there only left a strip of backdrop
 * under the list — Daniel, 2026-08-12: the sidebar's height IS the viewport.
 *
 * Last in the file on purpose: the rules it overrides carry the same
 * specificity, so source order is what decides.
 */
@media only screen and (max-width: 768px) {
    body[data-global-nav="side"] .sidebar,
    body[data-global-nav="side"] .application-body {
        --sidebar-margin-top: var(--sidebar-margin);
        --sidebar-margin-bottom: var(--sidebar-margin);
        --sidebar-margin-left: var(--sidebar-margin);
    }
}