/* ══════════════════════════════════════════════════════════════════
   site-header — the one page header.

   Markup and options: views/partials/site-header.ejs. This file is the
   static half; the partial emits only its per-render height variables
   inline, because those depend on whether a tab strip is rendering.

   Loaded via views/partials/mydreampark-ui-assets.ejs, so it is one
   cached request rather than ~13KB inlined into every page.

   Surface-specific colour goes through the custom properties this file
   reads, NOT through new rules:
     --site-header-bg          bar fill (set to `transparent` for a bar
                               whose colour the PAGE owns — see below)
     --site-header-blur        backdrop-filter value
     --site-header-border-w    border-bottom width
     --site-header-border-color  hairline colour, shown only when scrolled
     --site-header-max-w       inner max width. Default `none`: the bar
                               runs edge to edge, which is what the public
                               header, /download and the homepage always
                               did. Only surfaces that deliberately align
                               the bar to a centred content column set it
                               (the portals, and /assets).
     --site-header-tab-active  active tab ink + underline

   Not every surface wants this file to paint the bar at all. The public
   header (views/partials/header.ejs) is backgroundless by design: its
   pages decide what the bar looks like, because only they know what is
   behind it. views/share/share-head.ejs computes page luminance on the
   server and drives three different bar states plus an ink flip from it;
   views/dreamjam.ejs paints its own gradient. Those pages set the three
   properties above rather than fighting a fill from here.
   ══════════════════════════════════════════════════════════════════ */

    /* THIS FILE IS SERVED STATICALLY FROM public/ — no EJS may live in it.

       It shipped with an un-rendered EJS tag as its `position` value, and
       the CSS parser dropped that declaration along with the z-index
       below it. Every page got a position:static header, which then took
       72px of NORMAL FLOW while the page under it was ALSO padding itself
       down by --site-header-h — a header's height of dead space at the
       top of every layout on the site. On /download, a deliberately
       one-screen page, that dead space was the whole reason it scrolled.

       The partial already emits `dph-fixed` / `dph-sticky` (shRootClasses
       in views/partials/site-header.ejs), so position is a class here,
       and the zIndex prop arrives as a custom property from the partial's
       inline :root block. */
    .dph {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        z-index: var(--site-header-z, 1000);
        transition: background 0.3s ease, backdrop-filter 0.3s ease, border-color 0.3s ease;
    }
    /* position: 'sticky' surfaces scroll with the document, so they stay
       in flow and must not be pinned across the viewport. */
    .dph-sticky {
        position: sticky;
        left: auto;
        right: auto;
    }

    .dph-bar {
        max-width: var(--site-header-max-w, none);
        margin: 0 auto;
        min-height: var(--site-header-bar-h);
        padding: 12px 24px;
        /* The notch. Padding rather than margin so the bar's background
           still paints behind the status bar on iOS. */
        padding-top: calc(env(safe-area-inset-top, 0px) + 12px);
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 12px;
        box-sizing: border-box;
    }

    /* ── The hairline ─────────────────────────────────────────────
       Only once the page has actually moved. At the top of a document
       there is nothing above the fold for the bar to be separated FROM,
       so the rule is just a line across the design.

       The border is always PRESENT and only ever changes colour, so
       turning it on cannot shift the bar by a pixel. Width and colour
       are separate properties for exactly that reason — a single
       shorthand var can't have its colour toggled independently. */
    .dph {
        border-bottom: var(--site-header-border-w, 1px) solid transparent;
    }
    .dph.is-scrolled {
        border-bottom-color: var(--site-header-border-color, transparent);
    }

    /* ── Chrome: dark ─────────────────────────────────────────────── */
    .dph-dark {
        --site-header-border-color: rgba(255, 255, 255, 0.10);
        background: var(--site-header-bg, rgba(11, 11, 16, 0.88));
        backdrop-filter: var(--site-header-blur, blur(14px));
        -webkit-backdrop-filter: var(--site-header-blur, blur(14px));
    }
    /* ── Chrome: light ────────────────────────────────────────────── */
    .dph-light {
        --site-header-border-color: rgba(11, 11, 15, 0.08);
        background: var(--site-header-bg, rgba(255, 255, 255, 0.82));
        backdrop-filter: var(--site-header-blur, blur(14px) saturate(150%));
        -webkit-backdrop-filter: var(--site-header-blur, blur(14px) saturate(150%));
    }

    /* ── Auto-hide on scroll ──────────────────────────────────────
       Down hides the bar, up brings it back — the phone-app pattern, so
       a long page gets its full viewport once you're reading. Hiding is
       a transform, NOT a height or display change: the bar keeps
       occupying --site-header-h as far as every clearance offset on the
       site is concerned, so nothing reflows when it goes and comes back.

       The reveal is quicker than the hide. Wanting the bar back is a
       deliberate act and should feel immediate; losing it is passive. */
    .dph[data-auto-hide] {
        transition: transform 0.26s cubic-bezier(0.16, 1, 0.3, 1),
                    background 0.3s ease, backdrop-filter 0.3s ease, border-color 0.3s ease;
    }
    /* No `will-change: transform` here, deliberately.
   
       It forces the header onto its own compositing layer PERMANENTLY,
       and mydreampark-badge carries its own backdrop-filter: blur(10px).
       A backdrop-filter element inside a permanently composited ancestor
       is the combination WebKit mis-rasterises during rubber-band
       overscroll — the badge draws offset and clipped while the page
       springs back. The old .header was never promoted, so this was a
       regression introduced with the auto-hide, not a pre-existing quirk.

       A 0.26s translate on one element composites fine without the hint.
       will-change is documented as a last resort for measured jank, not
       a default; if this ever needs it, add it for the duration of the
       transition and take it off again rather than leaving it on. */
    .dph[data-auto-hide].is-hidden {
        transform: translateY(-100%);
        transition-duration: 0.34s, 0.3s, 0.3s, 0.3s;
    }
    @media (prefers-reduced-motion: reduce) {
        .dph[data-auto-hide],
        .dph[data-auto-hide].is-hidden { transition: none; }
    }

    /* ── Chrome: transparent-over-hero ────────────────────────────
       Starts as a scrim and solidifies past 8px of scroll. */
    .dph-transparent {
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
    }
    .dph-transparent.dph-dark {
        background: linear-gradient(180deg, rgba(12, 2, 32, 0.55) 0%, rgba(12, 2, 32, 0) 100%);
    }
    .dph-transparent.dph-light {
        background: linear-gradient(180deg, rgba(255, 255, 255, 0.82) 0%, rgba(255, 255, 255, 0) 100%);
    }
    .dph-transparent.dph-dark.is-scrolled {
        background: rgba(12, 2, 32, 0.78);
        backdrop-filter: blur(18px) saturate(160%);
        -webkit-backdrop-filter: blur(18px) saturate(160%);
        --site-header-border-color: rgba(255, 255, 255, 0.08);
    }
    .dph-transparent.dph-light.is-scrolled {
        background: rgba(255, 255, 255, 0.86);
        backdrop-filter: blur(18px) saturate(160%);
        -webkit-backdrop-filter: blur(18px) saturate(160%);
        --site-header-border-color: rgba(11, 11, 15, 0.08);
    }

    /* ── Brand ────────────────────────────────────────────────────── */
    .dph-brand-cluster {
        display: flex;
        align-items: center;
        gap: 12px;
        min-width: 0;
        flex: 0 1 auto;
    }
    .dph-brand {
        display: inline-flex;
        align-items: center;
        text-decoration: none;
        line-height: 0;
        flex: 0 0 auto;
    }
    .dph-brand img {
        display: block;
        width: auto;
        object-fit: contain;
        transform-origin: center center;
        transition: transform 0.2s ease;
    }
    .dph-mark-icon { height: 28px; }
    .dph-mark-text { height: 28px; }
    .dph-brand:hover img { transform: scale(1.08); }

    /* 'responsive': wordmark on desktop, icon mark on small screens so a
       surface label still fits beside it. */
    .dph-brand-responsive .dph-mark-icon { display: none; }
    @media (max-width: 640px) {
        .dph-brand-responsive .dph-mark-text { display: none; }
        .dph-brand-responsive .dph-mark-icon { display: block; height: 30px; }
    }

    /* Dim uppercase text, not a bordered pill: the pill used to get
       clipped by the action button on narrow screens, and text
       truncates gracefully where a pill gets cut off mid-border. */
    .dph-surface {
        display: inline-block;
        min-width: 0;
        font-family: var(--mdp-font-body, 'Inter', system-ui, sans-serif);
        font-size: 11px;
        font-weight: 700;
        letter-spacing: 0.14em;
        text-transform: uppercase;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        padding-left: 12px;
    }
    .dph-dark  .dph-surface { color: rgba(255, 255, 255, 0.62); border-left: 1px solid rgba(255, 255, 255, 0.16); }
    .dph-light .dph-surface { color: rgba(21, 10, 36, 0.55);   border-left: 1px solid rgba(21, 10, 36, 0.14); }

    /* ── Centred title ────────────────────────────────────────────── */
    .dph-center {
        flex: 1 1 auto;
        display: flex;
        justify-content: center;
        min-width: 0;
        padding: 0 12px;
    }
    .dph-title {
        max-width: min(52vw, 560px);
        font-family: var(--mdp-ui-heading, var(--mdp-font-display, 'Inter', system-ui, sans-serif));
        font-size: 1.15rem;
        font-weight: 800;
        letter-spacing: -0.02em;
        line-height: 1.1;
        text-align: center;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    .dph-dark  .dph-title { color: #fff; }
    .dph-light .dph-title { color: #150a24; }

    /* ── Inline nav ───────────────────────────────────────────────── */
    .dph-nav { display: flex; align-items: center; gap: 6px; }
    .dph-nav a {
        position: relative;
        padding: 10px 14px;
        border-radius: 999px;
        font-family: var(--mdp-font-body, 'Inter', system-ui, sans-serif);
        font-size: 0.82rem;
        font-weight: 500;
        letter-spacing: 0.02em;
        text-decoration: none;
        white-space: nowrap;
        transition: color 0.2s ease, background 0.2s ease;
    }
    .dph-dark  .dph-nav a { color: rgba(246, 239, 225, 0.78); }
    .dph-dark  .dph-nav a:hover,
    .dph-dark  .dph-nav a.is-active { color: #f6efe1; background: rgba(255, 255, 255, 0.08); }
    .dph-light .dph-nav a { color: rgba(11, 11, 15, 0.62); }
    .dph-light .dph-nav a:hover,
    .dph-light .dph-nav a.is-active { color: #0b0b0f; background: rgba(11, 11, 15, 0.06); }

    /* Hamburger. Same chrome as the badge beside it — 48px, the badge's
       outer pill height, so the two never sit at different heights. */
    .dph-nav-toggle {
        display: none;
        width: 48px; height: 48px; padding: 0;
        border-radius: 999px;
        border: 1px solid var(--mdp-border, rgba(255, 255, 255, 0.284));
        background: var(--mdp-bg, linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.1)));
        color: var(--mdp-text, #fff);
        cursor: pointer;
        align-items: center;
        justify-content: center;
        transition: border-color 0.25s ease;
    }
    .dph-nav-toggle:hover { border-color: var(--mdp-border-hover, rgba(255, 255, 255, 0.45)); }
    .dph-nav-toggle svg { width: 18px; height: 18px; }

    @media (max-width: 760px) {
        .dph-nav {
            position: fixed;
            top: calc(var(--site-header-bar-h) + env(safe-area-inset-top, 0px));
            left: 12px; right: 12px;
            flex-direction: column;
            align-items: stretch;
            padding: 10px;
            border-radius: 18px;
            display: none;
        }
        .dph-nav.is-open { display: flex; }
        .dph-nav-toggle { display: inline-flex; }
        .dph-dark  .dph-nav { background: rgba(12, 2, 32, 0.95); border: 1px solid rgba(255, 255, 255, 0.1); }
        .dph-light .dph-nav { background: rgba(255, 255, 255, 0.96); border: 1px solid rgba(11, 11, 15, 0.1); box-shadow: 0 18px 48px rgba(11, 11, 15, 0.12); }
    }

    /* ── Right cluster ────────────────────────────────────────────── */
    .dph-actions {
        display: inline-flex;
        align-items: center;
        gap: 12px;
        flex: 0 0 auto;
        position: relative;
    }

    /* ── CTA ──────────────────────────────────────────────────────
       Height pinned to 48px, the badge's outer pill (34px avatar + 6px
       padding x2 + 1px border x2). Pinned rather than left to padding so
       the two stay on one line whatever the badge's avatar or point
       count does. */
    .dph-cta {
        position: relative;
        display: inline-flex;
        align-items: center;
        gap: 8px;
        height: 48px;
        padding: 0 20px;
        border-radius: 999px;
        font-family: var(--mdp-font-body, 'Inter', system-ui, sans-serif);
        font-weight: 800;
        font-size: 0.84rem;
        letter-spacing: 0.04em;
        text-decoration: none;
        white-space: nowrap;
        box-sizing: border-box;
        transition: transform 0.16s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.16s ease, border-color 0.2s ease, background 0.2s ease;
    }
    .dph-cta:hover { transform: translateY(-1px); }
    .dph-cta svg { flex: none; }

    .dph-cta-primary {
        border: 1px solid rgba(119, 0, 255, 0.5);
        background: linear-gradient(180deg, rgba(255,255,255,0.18) 0%, transparent 48%),
                    linear-gradient(135deg, #7700ff 0%, #9d4edd 55%, #c77dff 100%);
        color: #fff;
        box-shadow: 0 8px 24px rgba(119, 0, 255, 0.30), inset 0 1px 0 rgba(255,255,255,0.28);
    }
    .dph-cta-primary:hover { box-shadow: 0 12px 30px rgba(119, 0, 255, 0.42), inset 0 1px 0 rgba(255,255,255,0.34); }

    .dph-cta-gold {
        border: 1px solid rgba(255, 209, 102, 0.65);
        background: rgba(255, 209, 102, 0.12);
        color: #fff;
        text-transform: uppercase;
    }
    .dph-cta-gold:hover { background: rgba(255, 209, 102, 0.2); }

    .dph-cta-discord {
        border: 1px solid rgba(88, 101, 242, 0.75);
        background: linear-gradient(180deg, rgba(255,255,255,0.16) 0%, transparent 48%),
                    linear-gradient(135deg, #5865F2 0%, #7289DA 100%);
        color: #fff;
        box-shadow: 0 8px 24px rgba(88, 101, 242, 0.32), inset 0 1px 0 rgba(255,255,255,0.28);
    }
    .dph-cta-discord:hover { box-shadow: 0 12px 30px rgba(88, 101, 242, 0.45), inset 0 1px 0 rgba(255,255,255,0.34); }

    /* Inherits the badge's own tokens, so it flips with the theme for
       free instead of needing a light and a dark rule. */
    .dph-cta-ghost {
        border: 1px solid var(--mdp-border, rgba(255, 255, 255, 0.284));
        background: var(--mdp-bg, linear-gradient(to bottom, rgba(255,255,255,0), rgba(255,255,255,0.1)));
        color: var(--mdp-text, #fff);
        backdrop-filter: blur(10px);
        -webkit-backdrop-filter: blur(10px);
    }
    .dph-cta-ghost:hover { border-color: var(--mdp-border-hover, rgba(255, 255, 255, 0.45)); }

    /* ── Tab strip ────────────────────────────────────────────────
       Fixed 46px so --site-header-tabs-h is exact. Links are centred in
       the strip rather than padded into it, which is what makes the
       published height trustworthy. */
    .dph-tabs { border-top: 1px solid rgba(255, 255, 255, 0.08); }
    .dph-light .dph-tabs { border-top-color: rgba(11, 11, 15, 0.08); }
    .dph-tabs-inner {
        max-width: var(--site-header-max-w, none);
        margin: 0 auto;
        padding: 0 24px;
        height: var(--site-header-tabs-h);
        display: flex;
        align-items: stretch;
        gap: 4px;
        /* More tabs than a phone is wide: scroll the STRIP, never the
           page. */
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
        box-sizing: border-box;
    }
    .dph-tabs-inner::-webkit-scrollbar { display: none; }
    .dph-tab {
        position: relative;
        flex: 0 0 auto;
        display: inline-flex;
        align-items: center;
        padding: 0 14px;
        font-family: var(--mdp-font-body, 'Inter', system-ui, sans-serif);
        font-size: 0.9rem;
        font-weight: 500;
        line-height: 1;
        text-decoration: none;
        white-space: nowrap;
        transition: color 0.15s ease;
    }
    .dph-dark  .dph-tab { color: rgba(255, 255, 255, 0.68); }
    .dph-dark  .dph-tab:hover { color: #fff; }
    .dph-light .dph-tab { color: rgba(21, 10, 36, 0.6); }
    .dph-light .dph-tab:hover { color: #150a24; }
    .dph-tab.is-active { color: var(--site-header-tab-active, #fff); }
    .dph-light .dph-tab.is-active { color: var(--site-header-tab-active, #150a24); }
    .dph-tab.is-active::after {
        content: '';
        position: absolute;
        left: 10px; right: 10px; bottom: 0;
        height: 2px;
        border-radius: 2px 2px 0 0;
        background: var(--site-header-tab-active, currentColor);
    }

    @media (max-width: 720px) {
        .dph-bar { padding-left: 16px; padding-right: 16px; }
        .dph-tabs-inner { padding: 0 16px; }
        .dph-cta { padding: 0 14px; }
        /* Keep the mark, drop the word — the badge must never be
           squeezed to make room for a CTA label. A CTA with no icon has
           nothing left to show, so it keeps its label. */
        .dph-cta-has-icon .dph-cta-label { display: none; }
    }
    /* The badge goes to its avatar circle on small screens, which is
       what .header-profile-trigger did on the old public header. Doing
       it here means every surface gets it, and the CTA beside it keeps
       its 48px partner rather than being crowded. */
    @media (max-width: 768px) {
        .dph-actions .mdp-badge { padding: 6px; gap: 0; }
        .dph-actions .mdp-meta { display: none; }
    }

    @media (max-width: 480px) {
        .dph-bar { gap: 10px; }
        .dph-actions { gap: 10px; }
        .dph-center { padding: 0 6px; }
        .dph-title { max-width: min(42vw, 220px); font-size: 0.86rem; }
        .dph-surface { font-size: 10px; letter-spacing: 0.1em; }
    }
