/* PT MEDIA HUB — the shell and the review-aware panel, shared (6 Oct 2026).
   A verbatim copy of single-product-page-styles.css lines 1054–1571 (section 7.0) and 1658–1821 (variant + desktop arrows), 6 Oct. The hub is printed on every
   page (11-frontend-mods.php) and used by forum galleries + the build-log "See all photos", but its styles only loaded on
   product pages, so off the shop it rendered half-styled. Loaded only where the hub script runs WITHOUT the product
   stylesheet (01-enqueue-styles-scripts.php). Keep both copies in step until the product file drops its section. */
/* ==========================================================================
   7.0 - PT MEDIA HUB STYLES (FINAL V6 - FIXED MOBILE)
   ========================================================================== */

/* 1. Container */
/* ══════════════════════════════════════════════════════════════════════════════════════════
   MEDIA HUB SHELL — restyled 23 Sep 2026 (brief "Review media hub", §3).
   Tokens: graphite #23211E, bone #EFEBE3, paper #FAF9F6, ink #1A1A1A.
   ⚠️ Shared with the marketplace listing gallery (`.pt-media-hub--marketplace`). Everything here is
   shell only — no review feature reaches that one.
   ══════════════════════════════════════════════════════════════════════════════════════════ */
.pt-media-hub {
    position: fixed;
    inset: 0;
    z-index: 9999999;
    /* Rows: a 56px bar, then everything else. The old flex-centring is what left no room for a bar. */
    display: grid;
    grid-template-rows: 56px minmax(0, 1fr);
    padding-top: env(safe-area-inset-top, 0px);
    padding-bottom: env(safe-area-inset-bottom, 0px);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.25s ease;
}
.pt-media-hub.open { opacity: 1; pointer-events: auto; }

/* 🔴 GRAPHITE, NOT BLACK. Pure black makes a photo of a dark engine bay look like a hole in the
   screen; the warm graphite is the same surface the rest of the site's dark bands use. */
.pt-hub-backdrop {
    position: absolute;
    inset: 0;
    background: #23211E;
    z-index: 0;
}

/* ── TOP BAR ─────────────────────────────────────────────────────────────────────────────── */
.pt-hub-bar {
    position: relative;
    z-index: 2;
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 0 12px 0 20px;
    border-bottom: 1px solid rgba(239,235,227,0.14);
    min-width: 0;
    color: #EFEBE3;
}
.pt-hub-bar__title span { color: rgba(239,235,227,0.62); }
.pt-hub-bar__title {
    font-size: 14px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}
/* The count is the bar's one number, so it is mono and it never wraps. */
.pt-media-hub .pt-hub-counter {
    margin-left: auto;
    font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 13px;
    white-space: nowrap;
    color: rgba(239,235,227,0.62);
    position: static;
    background: none;
    padding: 0;
}
.pt-hub-keys {
    /* The gaps between the three hints are CSS, not entities — see the note in pt-media-hub.js. */
    word-spacing: 0.5em;
    font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12px;
    color: rgba(239,235,227,0.62);
    white-space: nowrap;
}

/* 🔴 CLOSE IS IN THE BAR. No longer fixed-positioned over the panel, no longer a grey circle.
   Square, bordered, with the word beside the icon — it is the one control people hunt for. */
.pt-hub-close {
    position: static;
    display: flex;
    align-items: center;
    gap: 8px;
    background: none;
    border: 1px solid rgba(239,235,227,0.14);
    border-radius: 0;
    color: #EFEBE3;
    width: auto;
    height: auto;
    min-height: 36px;
    padding: 8px 12px;
    cursor: pointer;
    box-shadow: none;
    transition: border-color 0.15s ease, background 0.15s ease;
}
/* 🔴 ALL FOUR STATES, EXPLICITLY (24 Sep). GeneratePress ships an inline
   `button:hover, button:focus { background-color: #333 }`. My rule covered `:hover` and
   `:focus-visible` but NOT plain `:focus` — and a mouse click sets `:focus` without setting
   `:focus-visible`, so after one click the button went dark grey and stayed there.
   A control has four states; naming three of them leaves the theme to decide the fourth.
   Scoped to `.pt-media-hub` rather than reaching for `!important`. */
.pt-media-hub .pt-hub-close:hover,
.pt-media-hub .pt-hub-close:focus,
.pt-media-hub .pt-hub-close:focus-visible,
.pt-media-hub .pt-hub-close:active {
    background-color: transparent;
    background-image: none;
    color: #EFEBE3;
    border-color: rgba(239,235,227,0.62);
    transform: none;
    box-shadow: none;
}
/* Keyboard focus still has to be VISIBLE — the ring is the difference between a quiet hover and
   "this is where you are". */
.pt-media-hub .pt-hub-close:focus-visible {
    outline: 2px solid #EFEBE3;
    outline-offset: 2px;
}

/* The arrows have the same theme problem, and the same answer. */
.pt-media-hub .pt-hub-nav:hover,
.pt-media-hub .pt-hub-nav:focus,
.pt-media-hub .pt-hub-nav:focus-visible {
    background-color: rgba(35,33,30,0.9);
    color: #EFEBE3;
    border-color: rgba(239,235,227,0.62);
}
.pt-media-hub .pt-hub-nav:focus-visible { outline: 2px solid #EFEBE3; outline-offset: 2px; }
.pt-hub-close svg { width: 14px; height: 14px; }
.pt-hub-close__t { font-size: 13px; }

/* ── BODY: stage, then the review panel ──────────────────────────────────────────────────── */
.pt-hub-content-wrapper {
    position: relative;
    z-index: 1;
    width: 100%;
    height: 100%;
    max-width: none;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 400px;
    background: transparent;
    box-shadow: none;
    border-radius: 0;
    overflow: hidden;
    min-height: 0;
}

.pt-hub-media-stage {
    position: relative;
    display: grid;
    /* 🔴 `minmax(0, 1fr)` ON THE COLUMN, AND THIS IS THE WHOLE OF GAP 1 (24 Sep).
       A grid track's default minimum is `auto`, which means MIN-CONTENT. The filmstrip inside this
       stage is a flex row of 44 thumbnails, so its min-content width is about 3110px — and the single
       implicit column grew to fit it. Measured in headless Chrome: stage 1040px wide, its grid column
       3110px, `#pt-hub-current-media` filling that 3110 and centring the photo at x=1053 — outside
       the stage, which is `overflow:hidden`, so it was clipped away entirely.
       The photo was never failing to load. `img.complete` was true and naturalWidth was 1024. It was
       rendered, correctly, off the side of the screen.
       `minmax(0, …)` lets the track be narrower than its content, which is what makes the filmstrip
       scroll instead of pushing everything else out of the box. */
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr) auto;
    background: transparent;
    height: 100%;
    min-height: 0;
    overflow: hidden;
    cursor: default;
    user-select: none;
    /* Vertical scroll still works; horizontal is the hub's, for swipe. */
    touch-action: pan-y;
}

/* 🔴 ARROWS SIT INSIDE THE STAGE, 16px from ITS edges. Square, 48px, and they cannot reach the
   review panel at any width because they are no longer positioned against the viewport. */
.pt-hub-nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 3;
    width: 48px;
    height: 48px;
    border-radius: 0;
    background: rgba(35,33,30,0.7);
    border: 1px solid rgba(239,235,227,0.14);
    color: #EFEBE3;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: border-color 0.15s ease;
}
.pt-hub-nav:hover { background: rgba(35,33,30,0.9); color: #EFEBE3; border-color: rgba(239,235,227,0.62); }
.pt-hub-nav svg { width: 16px; height: 16px; }
.pt-hub-nav.prev { left: 16px; right: auto; }
.pt-hub-nav.next { right: 16px; left: auto; }

/* The old flex definitions of `.pt-hub-content-wrapper` and `.pt-hub-media-stage` were HERE, after
   the grid ones above, and were winning purely on source order — the hub kept its 95%-wide black card
   no matter what the new rules said. Deleted rather than overridden: two definitions of one layout is
   how this started. */

/* Counter */
.pt-hub-counter {
    position: absolute;
    top: 20px; left: 20px;
    color: rgba(255,255,255,0.7);
    font-size: 14px;
    font-weight: 600;
    z-index: 20;
    background: rgba(0,0,0,0.5);
    padding: 4px 10px;
    border-radius: 4px;
}

/* Current Image Area */
/* 🔴 THE STAGE IS A GRID NOW, so `flex:1` did nothing and this had no definite height — which made
   the image's own `max-height:100%` resolve against nothing and collapse to zero. The hub rendered
   as a black void. It is a grid ITEM, so it is placed and sized explicitly. */
#pt-hub-current-media {
    grid-row: 1;
    min-height: 0;
    min-width: 0;
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px 80px;
}
#pt-hub-current-media img,
#pt-hub-current-media video {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   REVIEW-AWARE PARTS (gaps 3, 6, 7, 8, 9, 10 — 24 Sep)
   ══════════════════════════════════════════════════════════════════════════════════════════ */

/* Gap 6 — position within the current review, top left of the stage. */
.pt-hub-pos {
    position: absolute;
    z-index: 3;
    top: 16px;
    left: 20px;
    font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 13px;
    color: rgba(239,235,227,0.62);
    pointer-events: none;
}

/* Gap 3 — the arrow widens only when it carries a label, so it is a square the rest of the time. */
.pt-hub-nav { min-width: 48px; width: auto; padding: 0 12px; gap: 8px; }
.pt-hub-nav__l { font-size: 13px; white-space: nowrap; }
.pt-hub-nav__l:empty { display: none; }
.pt-hub-nav[hidden] { display: none !important; }

/* Gap 7 — grouped by reviewer, 24px between groups, 20px of padding so nothing clips. */
.pt-hub-thumbnails-track { gap: 24px; padding-left: 20px; padding-right: 20px; }
.pt-hub-group { flex: none; display: flex; flex-direction: column; gap: 6px; }
.pt-hub-group__n {
    font-size: 12px;
    color: rgba(239,235,227,0.62);
    white-space: nowrap;
}
.pt-hub-group.on .pt-hub-group__n { color: #EFEBE3; }
.pt-hub-group__t { display: flex; gap: 4px; }
/* The current review's group lifts to 0.85; everything else sits at 0.5, so the eye finds the
   group it is in before it finds the thumb it is on. */
.pt-hub-thumbnails-track .pt-hub-thumb { opacity: .5; border: 2px solid transparent; border-radius: 0; padding: 0; background: none; cursor: pointer; position: relative; }
.pt-hub-group.on .pt-hub-thumb { opacity: .85; }
.pt-hub-thumbnails-track .pt-hub-thumb.active { border-color: #EFEBE3; opacity: 1; }
.pt-hub-thumb__v {
    position: absolute; right: 3px; bottom: 3px; width: 14px; height: 14px; font-size: 8px;
    background: rgba(35,33,30,.85); color: #EFEBE3; display: flex; align-items: center; justify-content: center;
}

/* Gaps 9 and 10 — the panel scrolls, the footer does not. */
.pt-hub-scroll { flex: 1; overflow-y: auto; min-height: 0; }
.pt-hub-variation { display: block; font-size: 13px; color: #6B6862; margin-top: 2px; }
.pt-hub-variation:empty, .pt-hub-variation[hidden] { display: none; }
.pt-hub-verified {
    display: inline-flex; align-items: center; gap: 5px;
    color: #2F6B3A;   /* ASSUMED verified green — flagged in the brief, confirm against design-tokens.md */
    font-size: 13px; margin-top: 6px;
}
.pt-hub-verified[hidden] { display: none; }

.pt-hub-minis { display: block; margin-top: 22px; }
.pt-hub-minis[hidden] { display: none; }
.pt-hub-minis__l { display: block; font-size: 13px; color: #6B6862; margin-bottom: 8px; }
.pt-hub-minis__row { display: flex; gap: 6px; flex-wrap: wrap; }
.pt-hub-mini { width: 52px; height: 52px; padding: 0; border: 1px solid #C9C7BF; background: none; cursor: pointer; border-radius: 0; }
.pt-hub-mini.on { outline: 2px solid #1A1A1A; outline-offset: 1px; }
.pt-hub-mini img { width: 100%; height: 100%; object-fit: cover; display: block; }

.pt-hub-helpful { margin-top: 20px; background: #fff; border: 1px solid #C9C7BF; padding: 7px 12px; font-size: 13px; cursor: pointer; border-radius: 0; color: #1A1A1A; }
.pt-hub-helpful[hidden] { display: none; }

.pt-hub-reply { margin-top: 22px; background: #EFEBE3; border-left: 2px solid #1A1A1A; padding: 14px 16px; }
.pt-hub-reply[hidden] { display: none; }
.pt-hub-reply__h { font-size: 13px; font-weight: 600; display: flex; justify-content: space-between; gap: 12px; }
.pt-hub-reply__h .pt-mono { font-weight: 400; color: #6B6862; font-size: 12px; font-family: ui-monospace, Menlo, monospace; }
.pt-hub-reply p { margin: 6px 0 0; font-size: 14px; line-height: 1.55; }

.pt-hub-foot {
    flex: 0 0 auto;
    border-top: 1px solid #E4E2DB;
    padding: 12px 20px;
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 8px;
    /* Pulled out to the panel's edges. The inset is a variable so it tracks the panel's padding
       rather than being written twice and drifting — which is exactly what happened on mobile. */
    margin: 0 calc(var(--pt-hub-pad, 40px) * -1) calc(var(--pt-hub-pad, 40px) * -1);
}
.pt-hub-foot__b { background: #fff; border: 1px solid #C9C7BF; padding: 9px 12px; font-size: 13px; white-space: nowrap; cursor: pointer; border-radius: 0; color: #1A1A1A; }
.pt-hub-foot__b:hover { border-color: #1A1A1A; }
.pt-hub-foot__b.prev { justify-self: start; }
.pt-hub-foot__b.next { justify-self: end; }
.pt-hub-foot__n { font-family: ui-monospace, Menlo, monospace; font-size: 12px; color: #6B6862; text-align: center; white-space: nowrap; }

/* Thumbnails Strip */
.pt-hub-thumbnails {
    grid-row: 2;
    position: relative;
    width: 100%;
    height: 90px;
    flex: 0 0 90px;
    background: #0a0a0a;
    z-index: 20;
    display: flex;
    align-items: center;
    justify-content: center;
    border-top: 1px solid #333;
}
.pt-hub-thumbnails-track {
    display: flex;
    gap: 10px;
    padding: 0 20px;
    overflow-x: auto;
    scrollbar-width: none; 
    max-width: 100%;
    height: 100%;
    align-items: center;
}
.pt-hub-thumbnails-track::-webkit-scrollbar { display: none; } 

.pt-hub-thumb {
    width: 60px; height: 60px;
    border-radius: 4px;
    overflow: hidden;
    opacity: 0.5;
    cursor: pointer;
    border: 2px solid transparent;
    transition: all 0.2s;
    flex-shrink: 0;
}
.pt-hub-thumb img { width: 100%; height: 100%; object-fit: contain; }
.pt-hub-thumb.active { opacity: 1; border-color: #fff; transform: scale(1.1); }

/* 5. Sidebar (Right) */
.pt-hub-details {
    --pt-hub-pad: 40px;
    /* 🔴 GAP 11. It had `width:380px` inside a 400px grid column, so it sat 20px short of the right
       edge with graphite showing through the gap. The COLUMN owns the width now; the panel fills it. */
    width: 100%;
    min-width: 0;
    background: #fff;
    display: flex;
    flex-direction: column;
    padding: 40px;
    overflow-y: auto;
}
.pt-hub-user-meta { display: flex; align-items: center; gap: 15px; margin-bottom: 25px; }
.pt-hub-avatar { width: 48px; height: 48px; background: #000; color: #fff; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 700; flex-shrink: 0; }
.pt-hub-user-info h4 { margin: 0; font-size: 16px; font-weight: 800; color: #000; }
/* 🔴 INK, NOT ORANGE (23 Sep). #ffa200 is the last orange star left on the site — the product
   page, the reviews hub and the review hub all went to ink weeks ago, and the mockup shows ink.
   A star is a rating: the COUNT carries the meaning, not the temperature. */
.pt-hub-rating { color: #1A1A1A; font-size: 15px; letter-spacing: 1px; margin-top: 4px; }
/* Gap 8 — mono, sentence case. It was 11px bold uppercase, which turned "31 Dec 2024" into
   "31 DECEMBER 2024" shouting at the top of the panel. A date is a fact, not a heading. */
#pt-hub-date { display: block; font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, monospace;
    font-size: 12px; color: #6B6862; font-weight: 400; text-transform: none; letter-spacing: 0; margin-bottom: 0; }
.pt-hub-review-text h5 { margin: 0 0 10px 0; font-size: 18px; font-weight: 700; line-height: 1.3; }
.pt-hub-review-text p { font-size: 15px; line-height: 1.6; color: #444; }

/* Loader */
.pt-hub-loader { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 40px; height: 40px; border: 4px solid rgba(255,255,255,0.2); border-top-color: #fff; border-radius: 50%; animation: ptSpin 1s linear infinite; z-index: 5; display: none; }
@keyframes ptSpin { to { transform: translate(-50%, -50%) rotate(360deg); } }

/* Sidebar Gallery (Desktop) */
.pt-hub-sidebar-gallery {
    margin-top: auto;
    padding-top: 20px;
    border-top: 1px solid #eee;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(60px, 1fr));
    gap: 8px;
    width: 100%;
}
.pt-sidebar-thumb {
    aspect-ratio: 1 / 1;
    border-radius: 4px;
    overflow: hidden;
    cursor: pointer;
    border: 2px solid transparent;
    opacity: 0.7;
    background: #f0f0f0;
}
.pt-sidebar-thumb img { width: 100%; height: 100%; object-fit: contain; }
.pt-sidebar-thumb.active { opacity: 1; border-color: #000; }

/* ==========================================================================
   MOBILE RESPONSIVE (UPDATED V8 - FIXED HEIGHT APP LAYOUT)
   ========================================================================== */
@media (max-width: 900px) {
    
    /* One column: stage, then the panel. Grid rather than flex, to match the desktop definition —
       the same structure described twice in two different layout systems is the bug above, repeated. */
    .pt-hub-content-wrapper {
        grid-template-columns: 1fr;
        grid-template-rows: minmax(0, 1fr) auto;
        width: 100%;
        height: 100%;
        border-radius: 0;
        background: transparent;
        overflow: hidden;
    }

    .pt-hub-media-stage {
        width: 100%;
        min-height: 0;
        background: transparent;
        padding-bottom: 0;
    }

    /* 44px and 8px from the edges on a phone (§5) — still inside the stage, still never on the panel. */
    .pt-hub-nav { width: 44px; height: 44px; }
    .pt-hub-nav.prev { left: 8px; }
    .pt-hub-nav.next { right: 8px; }

    /* The bar loses the title and the key hint; Close keeps its 44px target and drops the word. */
    .pt-media-hub { grid-template-rows: 52px minmax(0, 1fr); }
    .pt-hub-bar { padding: 0 8px 0 16px; }
    .pt-hub-bar__title, .pt-hub-keys { display: none; }
    .pt-media-hub .pt-hub-counter { margin-left: 0; margin-right: auto; }
    .pt-hub-close__t { display: none; }
    .pt-hub-close { min-width: 44px; min-height: 44px; justify-content: center; }
    
    /* Image Container */
    #pt-hub-current-media {
        grid-row: 1;
        min-height: 0;
        width: 100%;
        height: 100%;
        /* 🔴 8px, not the desktop 80px. Measured at 500px wide: 160px of side padding left the photo
           340px, so a portrait shot rendered smaller than its own thumbnail. §5 asks for
           `32px 8px 8px` — the 32 at the top is what keeps "Photo n of m" clear of the picture. */
        padding: 32px 8px 8px;
        display: flex;
        align-items: center;
        justify-content: center;
    }
    
    /* The Actual Image: Fit nicely */
    #pt-hub-current-media img {
        width: 100%;
        height: 100%;
        max-height: none; /* Remove pixel limits, let Flex handle it */
        object-fit: contain;
    }

    /* 3. Filmstrip Thumbnails: Fixed height at bottom of Media Area */
    .pt-hub-thumbnails {
        display: flex !important; 
        height: 100px; 
        flex: 0 0 100px; /* Don't shrink */
        background: #111;
        padding-top: 5px;
        padding-bottom: 5px;
        z-index: 20;
    }
    .pt-hub-thumb { 
        width: 80px; 
        height: 80px; 
        border-radius: 4px;
    }

    /* 4. Text/Details Area: Restrict height, Scroll internally */
    .pt-hub-details {
        width: 100%;
        flex: 0 0 auto; /* Sizing based on content... */
        max-height: 45vh; /* 🏆 ...but NEVER taller than 45% of screen */
        padding: 20px;
        /* The footer below pulls itself out to the panel edges with a negative margin, and that margin
           has to match THIS padding. It was still -40px here, so the footer hung 40px over the side. */
        --pt-hub-pad: 20px;
        overflow-y: auto; /* 🏆 Internal scroll for text/gallery */
        background: #fff;
        border-top: 1px solid #eee;
    }

    /* 5. Mobile Sidebar Gallery (User images): Always visible */
    .pt-hub-sidebar-gallery {
        display: grid !important; 
        margin-top: 15px;
        /* Larger grid items for easy tapping */
        grid-template-columns: repeat(auto-fill, minmax(70px, 1fr));
        gap: 10px;
    }

    /* 🔴 THE FLOATING CIRCLE WAS REBUILT HERE, with `!important` on top, position and colour — so the
       new in-bar Close reverted to a white disc over the panel the moment the viewport hit 900px.
       Deleted. Close lives in the bar at every width; the mobile sizing is set in the block above. */
    .pt-hub-close svg { width: 16px; height: 16px; }
}

/* Off the shop the theme title-cases headings ("Cage Tacked In"); the headline is the member's own words. */
#pt-media-hub #pt-hub-headline { text-transform: none; }

/* ── copied from single-product-page-styles.css lines 1658–1821 (6 Oct): the marketplace variant + the desktop nav arrows ── */
/* ══════════════════════════════════════════════════════════════════════════
   MEDIA HUB · MARKETPLACE VARIANT (Leon 2026-08-16)
   ══════════════════════════════════════════════════════════════════════════
   The hub is shared with the shop and the reviews archive, where the right-hand
   details panel carries the reviewer, their rating and their words. A
   marketplace listing is a ONE-TIME SALE with no review to show, so that panel
   is dead space — and it sat exactly where the "next" arrow lives, which is why
   that arrow could not be seen.
   ══════════════════════════════════════════════════════════════════════════ */

/* 1. No details panel — the stage takes the whole hub. */
.pt-media-hub--marketplace .pt-hub-details { display: none; }
.pt-media-hub--marketplace .pt-hub-content-wrapper {
    display: block;
    width: 100%;
    max-width: 100%;
}
.pt-media-hub--marketplace .pt-hub-media-stage {
    width: 100%;
    max-width: 100%;
}

/* 2. Arrows: the icon was 24px inside a 50px button, which read as a dot. The
      button grows and the glyph grows more, so it looks like a control. */
.pt-media-hub--marketplace .pt-hub-nav {
    width: 56px;
    height: 56px;
    background: rgba(255, 255, 255, 0.14);
}
.pt-media-hub--marketplace .pt-hub-nav svg {
    width: 32px;
    height: 32px;
    stroke-width: 2.5;
}
/* Pulled in from 80px: with no details panel there is nothing to clear, and at
   80px they float oddly far from the image on a wide screen. */
.pt-media-hub--marketplace .pt-hub-nav.prev { left: 32px; }
.pt-media-hub--marketplace .pt-hub-nav.next { right: 32px; }

/* Hover: the arrow stays WHITE on hover — the shared rule inverts to a black
   glyph on a white disc, which over a photo reads as the control switching OFF
   rather than lighting up (Leon 2026-08-16). Only the disc brightens. */
.pt-media-hub--marketplace .pt-hub-nav:hover,
.pt-media-hub--marketplace .pt-hub-nav:focus {
    background: rgba(255, 255, 255, 0.3);
    color: #fff;
}
.pt-media-hub--marketplace .pt-hub-nav:hover svg,
.pt-media-hub--marketplace .pt-hub-nav:focus svg {
    stroke: #fff;
}
.pt-media-hub--marketplace .pt-hub-nav:active {
    background: rgba(255, 255, 255, 0.42);
}

/* 3. Drag affordance — the stage is swipeable, so say so. */
.pt-media-hub--marketplace .pt-hub-media-stage {
    cursor: grab;
    touch-action: pan-y;   /* let vertical scroll through, claim horizontal */
}
.pt-media-hub--marketplace .pt-hub-media-stage.is-dragging { cursor: grabbing; }

@media (max-width: 768px) {
    .pt-media-hub--marketplace .pt-hub-nav { width: 46px; height: 46px; }
    .pt-media-hub--marketplace .pt-hub-nav svg { width: 26px; height: 26px; }
    .pt-media-hub--marketplace .pt-hub-nav.prev { left: 12px; }
    .pt-media-hub--marketplace .pt-hub-nav.next { right: 12px; }
}
/* ── SHOP / REVIEWS HUB · NEXT ARROW CLEARS THE DETAILS PANEL ───────────────
   The details panel is 380px wide and sits on the right, so `right: 80px` put
   the next arrow ON TOP of it — half hidden and awkward to hit (Leon 2026-08-16,
   spotted while checking the marketplace variant had not broken this).

   450px clears the panel with room to spare. Only above 900px, where the panel
   is side-by-side; below that it stacks underneath and the arrow belongs back at
   the edge.

   The marketplace variant is excluded — it has no panel and sets its own 32px. */
/* 🔴 `right: 450px` WAS HERE, and it is what put the next arrow in the middle of the picture.
   It was a workaround from when the arrows were positioned against the whole overlay and had to dodge
   the 450px review panel by hand. They live inside the stage now, so the panel is not theirs to avoid
   — and 450px measured from the stage's own right edge is 450px of nothing. Deleted, not adjusted:
   the geometry that made it necessary is gone. */
/* ── SHOP / REVIEWS HUB · ARROWS MUST READ ON ANY IMAGE ─────────────────────
   They were `rgba(255,255,255,0.1)` — 10% white. Over a dark photo that is
   almost invisible, and over a light one (a screenshot, a white studio shot)
   it disappears entirely (Leon 2026-08-16).

   A DARK translucent disc with a white glyph is the one combination that reads
   on both, which is why every photo viewer uses it. The hairline border and the
   blur keep it separated from whatever is behind it. */
@media (min-width: 1px) {   /* wrapper keeps this after the base rule regardless of order */
    .pt-media-hub:not(.pt-media-hub--marketplace) .pt-hub-nav {
        /* Still a dark translucent panel, because the arrow genuinely does sit over the photo and has
           to read on a white studio shot as well as a dark engine bay. Square now, to match the bar. */
        background: rgba(35, 33, 30, 0.72);
        border: 1px solid rgba(239, 235, 227, 0.35);
        border-radius: 0;
        color: #EFEBE3;
        backdrop-filter: blur(4px);
        -webkit-backdrop-filter: blur(4px);
        box-shadow: none;
    }
    .pt-media-hub:not(.pt-media-hub--marketplace) .pt-hub-nav svg {
        stroke: #EFEBE3;
        stroke-width: 2;
        width: 18px;
        height: 18px;
    }
    /* Hover brightens; the glyph stays white rather than inverting to black,
       which over a photo reads as the control switching off. */
    .pt-media-hub:not(.pt-media-hub--marketplace) .pt-hub-nav:hover,
    .pt-media-hub:not(.pt-media-hub--marketplace) .pt-hub-nav:focus {
        background: rgba(0, 0, 0, 0.78);
        border-color: rgba(255, 255, 255, 0.6);
        color: #fff;
    }
    .pt-media-hub:not(.pt-media-hub--marketplace) .pt-hub-nav:hover svg,
    .pt-media-hub:not(.pt-media-hub--marketplace) .pt-hub-nav:focus svg {
        stroke: #fff;
    }
    /* Close needs none of this now: it sits on the graphite bar, never over a photo, so there is no
       light image for it to disappear against. */
}
/* ── VIDEO IN THE HUB (brief §6, 24 Sep) ───────────────────────────────────────────────────── */
#pt-hub-current-media video,
#pt-hub-current-media .pt-hub-stream {
    max-width: 100%;
    max-height: 100%;
    width: auto;
    height: auto;
    display: block;
    border: 0;
    background: #000;
}
/* The Stream iframe has no intrinsic size, so it needs one — 16:9, capped by the stage. */
#pt-hub-current-media .pt-hub-stream {
    width: 100%;
    aspect-ratio: 16 / 9;
    max-height: 100%;
}
/* The length, bottom right, until playback starts. Mono, because it is a number. */
.pt-hub-len {
    position: absolute;
    right: 92px;
    bottom: 28px;
    z-index: 3;
    font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12px;
    color: #EFEBE3;
    background: rgba(35, 33, 30, 0.8);
    padding: 2px 6px;
    pointer-events: none;
}
.pt-hub-len[hidden] { display: none; }
@media (max-width: 900px) { .pt-hub-len { right: 16px; bottom: 16px; } }

/* A video's own thumbnail in the filmstrip and the minis carries a play mark, so you can see there
   is a clip in there before you open it. */
.pt-hub-mini .pt-hub-thumb__v { position: absolute; right: 3px; bottom: 3px; }

/* A gallery has no review panel, so the stage takes the whole width rather than leaving a 400px gap. */
.pt-hub-content-wrapper.is-solo { grid-template-columns: minmax(0, 1fr); }
.pt-hub-details[hidden] { display: none !important; }
