/**
 * player-content-zoom.css — content-only zoom for spillerprofilens
 * destinationer (.hd-player-content-mount), delt af BÅDE player-portal OG den
 * anonyme flade (A1: anonymous = logget-ind minus de låste faner, samme mounts).
 *
 * Topbar stays persistent/fixed as global player chrome. The tabbar stays as
 * the fixed edge menu, while destination content mounts are normal flow
 * surfaces with top/bottom/right clearance for that chrome.
 */

@layer components {
  :root {
    /* Landscape side-bar WIDTH (the vertical right-edge bar) + non-portal
     * fallback. Kept at 56px — landscape geometry is unchanged. */
    --player-tab-bar-base-size: 56px;
    /* Portrait bottom-reel HEIGHT (the wooden skriftrulle). Restored to the
     * original compact 56px (matching the landscape side-bar width): the reel was
     * briefly raised to 84px then 64px for a "fuller rod" look, but that left the
     * bottom bar visibly longer than before and pushed the whole portal skeleton
     * up. Back at 56px the bar reads the same height as the pre-regression layout
     * and lines up with the landscape side-bar width. Only drives the portrait
     * --player-tab-bar-size below; the landscape override keeps using
     * --player-tab-bar-base-size. */
    --player-tab-bar-portrait-base: 56px;
    /* Bottom safe-area reservation for the portrait tab-bar, kept as a single
     * source of truth shared by both --player-tab-bar-size (the reservation the
     * content-mount/PiP/modals/dasham lay out against) and the bar's own
     * padding-bottom — so the bar's border-box height always equals the
     * reservation and the parchment gap from a25876bc6 can never reopen.
     *
     * Default = the FULL env(safe-area-inset-bottom): in a browser tab Safari's
     * own bottom toolbar overlaps the home-indicator band, so reserving the full
     * inset reads correctly there. In a standalone PWA the full inset (~34px)
     * left a large empty bar-coloured band BELOW the icon row, making the icons
     * float well above the screen edge — the @media (display-mode: standalone)
     * block below caps it to a small home-indicator clearance so the icons sit
     * near the bottom, matching the in-browser look. */
    --hd-tab-bar-bottom-inset: env(safe-area-inset-bottom, 0px);
    --player-tab-bar-size: calc(var(--player-tab-bar-portrait-base) + var(--hd-tab-bar-bottom-inset));
    --hd-visual-viewport-width: 100vw;
    --hd-visual-viewport-height: 100vh;
    --hd-visual-viewport-offset-left: 0px;
    --hd-visual-viewport-offset-top: 0px;
    --hd-visual-viewport-scale: 1;
    --hd-player-usable-width: var(--hd-visual-viewport-width, 100vw);
    --hd-player-usable-height: calc(var(--hd-visual-viewport-height, 100vh) - var(--player-top-bar-height, 0px) - var(--player-tab-bar-size, 0px));
    --hd-player-split-width: calc(var(--hd-player-usable-width) / 2);
    --hd-player-split-height: calc(var(--hd-player-usable-height) / 2);
    --hd-player-pip-frame-height: 96px;
    --hd-player-pip-clearance-bottom: 0px;
    --hd-player-chrome-z: 12000;
  }

@media (min-aspect-ratio: 1/1) {
    :root {
      --player-tab-bar-size: calc(var(--player-tab-bar-base-size) + env(safe-area-inset-right, 0px));
    }
  }

  /* Standalone PWA only — cap the portrait bottom reservation so the tab icons
   * are not pushed up by the full home-indicator inset (see --hd-tab-bar-bottom-inset
   * note above). The browser-tab path keeps the full env() inset untouched. The
   * landscape rule above sets --player-tab-bar-size from the RIGHT inset and does
   * not read this variable, so right-edge-bar layout is unaffected.
   *
   * --hd-tab-bar-pwa-clearance is the empty band kept below the icon row: enough
   * to clear the home-indicator pill while keeping the icons anchored near the
   * bottom. Tune this single value if the icons need to sit higher/lower on
   * device (min() means a device with a smaller real inset keeps its own). */
  @media (display-mode: standalone) {
    :root {
      --hd-tab-bar-pwa-clearance: 10px;
      --hd-tab-bar-bottom-inset: min(env(safe-area-inset-bottom, 0px), var(--hd-tab-bar-pwa-clearance));
    }
  }

  /* Hide the shared content mounts only OUTSIDE the surface-hosting player modes
   * (faelles / admin). player-portal, anonymous (A1) AND the DM portal (dm) all
   * drive the SAME .hd-player-content-mount surface — each flips per-mount
   * [hidden] via its tab-bar onChange (dm through DmPortalShell.bindDestinations). */
  body:not(.hd-player-mode-player-portal):not(.hd-player-mode-anonymous):not(.hd-player-mode-dm) .hd-player-content-mount {
    display: none !important;
  }

  /* Player-portal min font floor (chrome): raise --hd-text-micro 9px → 10px at
   * the body level so the chrome that lives OUTSIDE .hd-player-content-mount
   * — PiP mode-tag, tab-bar badge/tooltip, player top-bar — also clears 10px.
   * Flat (non-zoom), matching the global token it overrides; the content-mount
   * block re-declares --hd-text-micro zoom-scaled so in-content micro-text still
   * tracks pinch-zoom (more specific selector wins inside the mount). Scoped to
   * the player-portal + anonymous-landing body classes, so admin is unaffected. */
  body:is(.hd-player-mode-player-portal, .hd-player-mode-anonymous, .hd-player-mode-dm) {
    --hd-text-micro: 0.625rem; /* 10px */
  }

  body.hd-player-mode-player-portal {
    --hd-player-usable-width: var(--hd-visual-viewport-width, 100vw);
    --hd-player-usable-height: calc(var(--hd-visual-viewport-height, 100vh) - var(--player-top-bar-height, 0px) - var(--player-tab-bar-size, 0px));
    --hd-player-split-width: calc(var(--hd-player-usable-width) / 2);
    --hd-player-split-height: calc(var(--hd-player-usable-height) / 2);
  }

  /* Shared content-zoom token overrides + iOS pinch suppression for both the
   * player-portal destinations and the anonymous landing. Token overrides
   * cascade to descendants, so `var(--hd-text-body)` etc. inside either mount
   * picks up the zoomed value from `--hd-player-content-zoom` (default 1,
   * overridden by inline style from PlayerContentZoom.setZoom). */
  body:is(.hd-player-mode-player-portal, .hd-player-mode-anonymous, .hd-player-mode-dm) .hd-player-content-mount {
    --hd-player-content-zoom: 1;
    font-size: calc(1rem * var(--hd-player-content-zoom));

    /* display was the lone typography token missing here: globally it is
     * clamp(2rem, …, 3.5rem) — viewport-fluid but NOT zoom-scaled — so every
     * player-mount call-site (overview hero, butik title, statblock title)
     * ignored content-zoom. Scaled to its clamp-min (2rem) * zoom, matching
     * the fixed-rem * zoom pattern the headings below already use. */
    --hd-text-display: calc(2rem * var(--hd-player-content-zoom));
    --hd-text-h1: calc(1.75rem * var(--hd-player-content-zoom));
    --hd-text-h2: calc(1.5rem * var(--hd-player-content-zoom));
    --hd-text-h3: calc(1.25rem * var(--hd-player-content-zoom));
    --hd-text-h4: calc(1.125rem * var(--hd-player-content-zoom));
    --hd-text-h5: calc(1rem * var(--hd-player-content-zoom));
    --hd-text-h6: calc(0.875rem * var(--hd-player-content-zoom));
    --hd-text-body-large: calc(1.0625rem * var(--hd-player-content-zoom));
    --hd-text-body: calc(1rem * var(--hd-player-content-zoom));
    --hd-text-body-small: calc(0.875rem * var(--hd-player-content-zoom));
    /* Player-surface alias (test-backed: player-content-layout-contract) — scaled
     * like --hd-text-ui (14px). Kept available for player-flader; canonical UI
     * call-sites prefer --hd-text-ui directly. */
    --hd-text-small: calc(0.875rem * var(--hd-player-content-zoom));
    --hd-text-md: var(--hd-text-body);
    --hd-text-ui: calc(0.875rem * var(--hd-player-content-zoom));
    --hd-text-ui-small: calc(0.75rem * var(--hd-player-content-zoom));
    --hd-text-caption: calc(0.75rem * var(--hd-player-content-zoom));
    /* Player-portal min font floor: 10px (was 9px / 0.5625rem). Raised across the
     * whole portal so the smallest in-content micro-text (badges, pills, meta) is
     * never below 10px. Admin keeps the global 9px --hd-text-micro untouched. */
    --hd-text-micro: calc(0.625rem * var(--hd-player-content-zoom));

    --hd-space-1: calc(4px * var(--hd-player-content-zoom));
    --hd-space-2: calc(8px * var(--hd-player-content-zoom));
    --hd-space-3: calc(12px * var(--hd-player-content-zoom));
    --hd-space-4: calc(16px * var(--hd-player-content-zoom));
    --hd-space-5: calc(24px * var(--hd-player-content-zoom));
    --hd-space-6: calc(32px * var(--hd-player-content-zoom));

    --hd-dasham-portal-chip-gap: calc(4px * var(--hd-player-content-zoom));

    /* Block browser-handled pinch on this surface so iOS' visual-viewport
     * gesture engine does not pre-empt PlayerContentZoom. Panning stays
     * enabled for vertical scroll and inner horizontal scroll containers. */
    touch-action: pan-x pan-y;
  }

  body:is(.hd-player-mode-player-portal, .hd-player-mode-anonymous, .hd-player-mode-dm) .hd-player-content-mount :where(input, textarea, select) {
    font-size: max(16px, var(--hd-text-body));
  }

  body:is(.hd-player-mode-player-portal, .hd-player-mode-anonymous, .hd-player-mode-dm) :is(.hd-player-top-bar, .hd-player-tab-bar) {
    touch-action: pan-x pan-y;
  }

  body:is(.hd-player-mode-player-portal, .hd-player-mode-anonymous, .hd-player-mode-dm) :is(.hd-player-top-bar-mount, .hd-player-tab-bar-mount) {
    touch-action: pan-x pan-y;
  }

  body:is(.hd-player-mode-player-portal, .hd-player-mode-anonymous, .hd-player-mode-dm) .hd-player-top-bar {
    position: fixed;
    top: var(--hd-visual-viewport-offset-top, 0px);
    left: var(--hd-visual-viewport-offset-left, 0px);
    right: calc(100vw - var(--hd-visual-viewport-offset-left, 0px) - var(--hd-visual-viewport-width, 100vw));
    width: auto;
    z-index: var(--hd-player-chrome-z);
  }

  body:is(.hd-player-mode-player-portal, .hd-player-mode-anonymous, .hd-player-mode-dm) .hd-player-tab-bar {
    left: var(--hd-visual-viewport-offset-left, 0px);
    right: calc(100vw - var(--hd-visual-viewport-offset-left, 0px) - var(--hd-visual-viewport-width, 100vw));
    bottom: 0;
    z-index: var(--hd-player-chrome-z);
  }

  /* Flow shell shared by player-portal AND anonymous (A1): both render
   * destinations into .hd-player-content-mount. The topbar is persistent chrome,
   * so mounts reserve its height with margin instead of becoming fixed viewport
   * panels. The mount itself remains viewport-bounded and owns vertical scroll,
   * because the player shell document is chrome-locked and does not grow with
   * destination content. */
  body:is(.hd-player-mode-player-portal, .hd-player-mode-anonymous, .hd-player-mode-dm) .hd-player-content-mount {
    --hd-player-surface-pad-top: 0px;
    --hd-player-surface-pad-right: 0px;
    --hd-player-surface-pad-bottom: 0px;
    position: relative;
    z-index: 40;
    width: 100%;
    height: calc(var(--hd-visual-viewport-height, 100vh) - var(--player-top-bar-height, 0px) - var(--player-tab-bar-size, 0px));
    min-height: calc(var(--hd-visual-viewport-height, 100vh) - var(--player-top-bar-height, 0px) - var(--player-tab-bar-size, 0px));
    margin-top: var(--player-top-bar-height, 0px);
    padding-top: 0;
    padding-right: 0;
    padding-bottom: 0;
    box-sizing: border-box;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: auto;
    -webkit-overflow-scrolling: touch;
    /* The mount is the scroll owner; parchment is painted by the scroll-stack
     * paper layer so the fibres move with content without background-attachment:
     * local repaint coupling. --hd-surface-base stays below the paper layer. */
    background-color: var(--hd-surface-base);
    color: var(--hd-text-primary);
  }

  .hd-player-surface-stack {
    display: grid;
    min-height: 100%;
    isolation: isolate;
    box-sizing: border-box;
  }

  .hd-player-surface-paper,
  .hd-player-surface-slot {
    grid-area: 1 / 1;
    min-width: 0;
    box-sizing: border-box;
  }

  .hd-player-surface-paper {
    pointer-events: none;
    z-index: 0;
    background-color: var(--hd-surface-base);
    background-image: var(--hd-parchment-surface);
    background-repeat: var(--hd-parchment-repeat, repeat);
    background-size: var(--hd-parchment-size, auto);
  }

  .hd-player-surface-slot {
    position: relative;
    z-index: 1;
    padding-top: var(--hd-player-surface-pad-top, 0px);
    padding-right: var(--hd-player-surface-pad-right, 0px);
    padding-bottom: var(--hd-player-surface-pad-bottom, 0px);
  }

  /* Item 1 — while a fixed CTA pill is visible (questionnaire or characterless
   * banner), reserve a band at the top of the scrolling mount so the pill no
   * longer overlaps the surface's first interactive row. The body class is
   * toggled by portal-questionnaire-launcher.js / characterless-cta.js.
   * Specificity (0,3,1) must out-rank the roller crease rule in player-roller.css
   * (body.hd-player-mode-* .hd-player-content-mount = (0,2,1)), which otherwise
   * sets padding-top: var(--hd-roller-crease-h) and wins on source order. The band
   * (≥ crease-h) replaces that clearance; the decorative crease shadow is unaffected.
   * Both modes covered (characterless CTA shows in anonymous). :is() is Safari 16.6-safe. */
  body.hd-player-mode-player-portal:is(.hd-has-portal-cta, .hd-has-characterless-cta) .hd-player-content-mount,
  body.hd-player-mode-anonymous:is(.hd-has-portal-cta, .hd-has-characterless-cta) .hd-player-content-mount {
    --hd-player-surface-pad-top: var(--hd-portal-cta-band);
  }
  /* Frayed nav panels keep the same scroll-mount geometry as every other
   * destination. They need (0,4,1) to out-rank the decorative paper-edge rule
   * in player-content-transition.css, but CTA clearance remains the same shared
   * band token — no extra deckle/tuck padding belongs in layout. */
  body.hd-player-mode-player-portal:is(.hd-has-portal-cta, .hd-has-characterless-cta) .hd-player-content-mount.hd-content-frayed,
  body.hd-player-mode-anonymous:is(.hd-has-portal-cta, .hd-has-characterless-cta) .hd-player-content-mount.hd-content-frayed {
    --hd-player-surface-pad-top: var(--hd-portal-cta-band);
  }

  /* Anonymous inline-login mount (A1) sits ONE layer above the other content
   * mounts (which share z-index:40 in the shell above) so opening login covers
   * whatever tab content is showing; closing it simply uncovers — no sibling
   * show/hide bookkeeping. Still below the chrome (top-bar/tab-bar).
   *
   * The sibling content mounts are position:relative in-flow scroll owners, so a
   * bare z-index cannot make this mount OVERLAP them: an un-hidden in-flow mount
   * appends BELOW the still-visible tab content (off-screen, under the fold) and
   * the login form became unreachable — the top-bar "Log ind" CTA looked dead
   * (regression 2026-07-06). Pin it as a FIXED overlay over the same content
   * region the chrome brackets (below the top-bar, above the z-index:40 mounts, but
   * below the z-index:12000 chrome) so "covers whatever tab content is showing" is
   * literally true again. The inner .hd-player-surface-slot still reserves the
   * tab-bar via --hd-player-surface-pad-bottom (portrait) / -pad-right (landscape),
   * so the form clears the chrome in both orientations. The two-class selector
   * (0,3,1) keeps this geometry winning over the landscape .hd-player-content-mount
   * height override without !important. */
  body.hd-player-mode-anonymous .hd-anonymous-login-mount.hd-player-content-mount {
    position: fixed;
    top: calc(var(--hd-visual-viewport-offset-top, 0px) + var(--player-top-bar-height, 0px));
    left: var(--hd-visual-viewport-offset-left, 0px);
    right: calc(100vw - var(--hd-visual-viewport-offset-left, 0px) - var(--hd-visual-viewport-width, 100vw));
    bottom: 0;
    width: auto;
    height: auto;
    min-height: 0;
    margin-top: 0;
    z-index: 41;
  }

  body.hd-player-mode-player-portal.hd-pip-state-pip .hd-player-content-mount {
    --hd-player-pip-clearance-bottom: calc(var(--hd-player-pip-frame-height, 96px) + var(--hd-space-5, 24px));
    scroll-padding-bottom: var(--hd-player-pip-clearance-bottom);
  }

  /* PiP scroll-clearance goes on the LAST direct child only (the bottom of the
   * scroll content), NOT on the mount's layout padding-bottom (a height:100% root
   * resolves against the mount's content box, leaving a visible band) and NOT on
   * EVERY direct child (`> *`): destinations like karakterark append ~10 sections
   * straight into the mount, so `> *` padded every section and the whole tab's
   * content was pushed apart whenever PiP was up (#1). `:last-child` clears the
   * PiP frame at the scroll end and is correct for BOTH structures — a
   * single-root destination's root IS its last child, a multi-section tab's last
   * section carries the bottom clearance. */
  body.hd-player-mode-player-portal.hd-pip-state-pip .hd-player-surface-slot > *:last-child {
    padding-bottom: var(--hd-player-pip-clearance-bottom);
  }

  /* Split-view reflow for destination mounts (study-zone) in dual-plane.
   * Keeps content in a dedicated 50% zone so it reflows instead of overlapping
   * the admin projection. */
  body.hd-player-mode-player-portal.hd-pip-state-dualplane .hd-player-content-mount {
    position: fixed;
    margin-top: 0;
    top: calc(
      var(--hd-visual-viewport-offset-top, 0px)
      + var(--player-top-bar-height, 0px)
    );
    left: var(--hd-visual-viewport-offset-left, 0px);
    right: calc(
      100vw - var(--hd-visual-viewport-offset-left, 0px)
      - var(--hd-visual-viewport-width, 100vw)
    );
    height: var(--hd-player-split-height);
    bottom: auto;
    width: auto;
    min-height: 0;
    overflow-y: auto;
  }

  body.hd-player-mode-player-portal.hd-pip-state-dualplane.hd-dualplane-flipped .hd-player-content-mount {
    top: calc(
      var(--hd-visual-viewport-offset-top, 0px)
      + var(--player-top-bar-height, 0px)
      + var(--hd-player-split-height)
    );
  }

  body:is(.hd-player-mode-player-portal, .hd-player-mode-dm) .hd-player-content-mount .hd-quest-feed__compose-fab {
    bottom: calc(var(--player-tab-bar-size) + var(--hd-space-3));
  }

  @media (min-aspect-ratio: 1/1) {
    body.hd-player-mode-player-portal {
      --hd-player-usable-width: calc(var(--hd-visual-viewport-width, 100vw) - var(--player-tab-bar-size, 0px));
      --hd-player-split-width: calc(var(--hd-player-usable-width) / 2);
    }

    /* BOTH modes: logged-in (player-portal) AND logged-out (anonymous) share the
     * same chrome, so the right-edge landscape anchor must cover both. Scoping it
     * to player-portal only left the anonymous portal on the base left:0 rule, so
     * the vertical side-menu rendered on the WRONG (left) edge when logged out
     * (regression 2026-07-06) while the logged-in view sat correctly on the right. */
    body:is(.hd-player-mode-player-portal, .hd-player-mode-anonymous, .hd-player-mode-dm) .hd-player-tab-bar {
      /* Start UNDER top-baren (matcher player-tab-bar.css' hensigt) — ellers ligger
       * den lodrette side-menus øverste fane bag top-baren + dens højre hjul. */
      top: calc(var(--hd-visual-viewport-offset-top, 0px) + var(--player-top-bar-height));
      left: auto;
      right: calc(100vw - var(--hd-visual-viewport-offset-left, 0px) - var(--hd-visual-viewport-width, 100vw));
      bottom: 0;
    }

    body:is(.hd-player-mode-player-portal, .hd-player-mode-anonymous, .hd-player-mode-dm) .hd-player-content-mount {
      height: calc(var(--hd-visual-viewport-height, 100vh) - var(--player-top-bar-height, 0px));
      min-height: calc(var(--hd-visual-viewport-height, 100vh) - var(--player-top-bar-height, 0px));
      --hd-player-surface-pad-right: var(--player-tab-bar-size, 0px);
      --hd-player-surface-pad-bottom: 0px;
      padding-bottom: 0;
    }

  body.hd-player-mode-player-portal.hd-pip-state-dualplane .hd-player-content-mount {
    position: fixed;
    top: calc(
      var(--hd-visual-viewport-offset-top, 0px)
      + var(--player-top-bar-height, 0px)
    );
    left: auto;
    right: calc(100vw - var(--hd-visual-viewport-offset-left, 0px) - var(--hd-visual-viewport-width, 100vw) + var(--player-tab-bar-size, 0px));
    width: var(--hd-player-split-width);
    height: auto;
    min-height: 0;
    bottom: 0;
  }

  body.hd-player-mode-player-portal.hd-pip-state-dualplane.hd-dualplane-flipped .hd-player-content-mount {
    left: var(--hd-visual-viewport-offset-left, 0px);
    right: auto;
    width: var(--hd-player-split-width);
    /* Portrait flipped rule has higher specificity and sets top to lower-half position —
     * override so content fills from top-bar in landscape. */
    top: calc(var(--hd-visual-viewport-offset-top, 0px) + var(--player-top-bar-height, 0px));
  }

  body:is(.hd-player-mode-player-portal, .hd-player-mode-dm) .hd-player-content-mount .hd-quest-feed__compose-fab {
      right: calc(var(--player-tab-bar-size) + var(--hd-space-3));
      bottom: var(--hd-space-3);
    }
  }

  .hd-player-content-mount[hidden] {
    display: none !important;
  }
}
