/*
 * Virgo CMS - Panorama Hotspot module styles (FRONTEND only).
 *
 * A local Pannellum-powered 360° equirectangular viewer with N native Pannellum
 * hotspots. The stage is the Pannellum render target; its height comes from
 * --pv-height and its aspect from --pv-aspect (the image's intrinsic ratio). The
 * loading overlay + custom controls (zoom, fullscreen, compass) mirror the
 * panorama_viewer module.
 *
 * The hotspot pin / tooltip / popup visual layer mirrors the hotspot_image
 * module's pin / tooltip / popup exactly (same tokens, sizes, hover/animation
 * behavior) so both modules render an identical pin + label + popup. It uses
 * its own class vocabulary (.ph-pin / .ph-tooltip / .panorama-hotspot-info-*)
 * so it does NOT depend on hotspot-image.css (module CSS/JS independence rule).
 * Per-item colors are applied at runtime as --ph-pin-color / --ph-pin-glyph /
 * --ph-pin-glow custom properties on the hotspot wrapper; the tooltip text is
 * injected via Pannellum's createTooltipFunc so the tooltip_position setting
 * (top/bottom/left/right) can be honored (Pannellum's built-in text tooltip is
 * always above+centered).
 *
 * The admin editor uses a FLAT equirectangular image with the shared
 * .hotspot-editor / .hotspot-pin styles from admin/assets/css/admin.css (the
 * same as the hotspot_image module) — nothing panorama-specific lives here.
 */

/* ============================================
 * ROOT + STAGE (mirror panorama_viewer)
 * ============================================ */

.panorama-hotspot {
    --pv-height: 500px;
    --pv-radius: 12px;
    --ph-pin-size: 32px;
    --ph-pin-opacity: 1;

    box-sizing: border-box;
    position: relative;
    width: 100%;
    border-radius: var(--pv-radius);
    overflow: hidden;
    background: #141a18;
}

.panorama-hotspot--framed {
    border: 1px solid var(--bs-border-color, #dee2e6);
}

.panorama-hotspot *,
.panorama-hotspot *::before,
.panorama-hotspot *::after {
    box-sizing: border-box;
}

.panorama-hotspot__stage {
    position: relative;
    width: 100%;
    height: var(--pv-height);
    aspect-ratio: var(--pv-aspect, auto);
    background: #141a18 center / cover no-repeat;
}

/* Suppress Pannellum's native loading box — the module's own spinner replaces it. */
.panorama-hotspot .pnlm-load-box,
.panorama-hotspot .pnlm-lbox,
.panorama-hotspot .pnlm-loading,
.panorama-hotspot .pnlm-lbar,
.panorama-hotspot .pnlm-lbar-fill,
.panorama-hotspot .pnlm-lmsg {
    display: none !important;
}

/* Pannellum's native device-orientation button (.pnlm-orientation-button) is
 * auto-injected on orientation-capable devices (mobiles) when gyroscope support
 * is on. It has no config toggle to suppress it, and it duplicates the module's
 * own controls at the top-left, so it is hidden here. The module's gyroscope
 * handling (lazy activation on first tap) keeps working independently of this
 * button. */
.panorama-hotspot .pnlm-orientation-button {
    display: none !important;
}

.panorama-hotspot__loading {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    background: radial-gradient(circle at center, rgba(0, 0, 0, 0.35), rgba(0, 0, 0, 0.6));
    pointer-events: none;
}

.panorama-hotspot__loading-spinner {
    color: var(--primary-color);
}

.panorama-hotspot.is-ready .panorama-hotspot__loading,
.panorama-hotspot.has-error .panorama-hotspot__loading {
    display: none;
}

.panorama-hotspot__fallback {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.panorama-hotspot.is-ready .panorama-hotspot__fallback {
    display: none;
}

/* Caption (mirrors panorama_viewer). The overlay variant sits as a bottom band
 * over the stage; the below variant flows beneath it. Logical properties keep
 * RTL correct. The wrapper is a flex column so the title and description stack
 * with a small gap. */
.panorama-hotspot__caption {
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    gap: 4px;
    width: 100%;
    color: #fff;
}

.panorama-hotspot__caption--overlay {
    position: absolute;
    inset-block-end: 0;
    inset-inline: 0;
    /* Below the interactive controls (z-index:3) so the zoom/fullscreen buttons
     * and compass stay clickable; coexists with the loading overlay (also 2)
     * because loading hides via .is-ready before the user sees the caption. */
    z-index: 2;
    padding: 12px 16px;
    background: linear-gradient(to top, rgba(0, 0, 0, 1), transparent);
    pointer-events: none;
}

.panorama-hotspot__caption--below {
    padding: 10px 14px;
    background: #1d2522;
}

.panorama-hotspot__caption-title {
    font-size: 0.9rem;
    line-height: 1.35;
    font-weight: 600;
}

/* Description body. Clamped to 3 lines on both positions. The below variant
 * sits on the dark #1d2522 band so its text is dimmed white (rgba .7); the
 * overlay variant rides the black gradient so it is a brighter white (.9). */
.panorama-hotspot__caption--below .panorama-hotspot__caption-desc {
    font-size: 0.75rem;
    line-height: 1.4;
    color: rgba(255, 255, 255, 0.7);
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.panorama-hotspot__caption--overlay .panorama-hotspot__caption-desc {
    font-size: 0.75rem;
    line-height: 1.4;
    color: rgba(255, 255, 255, 0.9);
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    margin-top: 2px;
}

/* ============================================
 * CUSTOM CONTROLS (mirror panorama_viewer)
 * ============================================ */

.panorama-hotspot__controls {
    position: absolute;
    bottom: 12px;
    right: 12px;
    z-index: 3;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

[dir="rtl"] .panorama-hotspot__controls {
    right: auto;
    left: 12px;
}

.panorama-hotspot__btn {
    width: 38px;
    height: 38px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    border-radius: 8px;
    background: rgba(0, 0, 0, 0.55);
    color: #fff;
    cursor: pointer;
    transition: background 0.15s ease;
}
.panorama-hotspot__btn:hover {
    background: rgba(0, 0, 0, 0.75);
}
.panorama-hotspot__btn:disabled {
    opacity: 0.4;
    cursor: default;
}
.panorama-hotspot__btn i {
    font-size: 18px;
    line-height: 1;
}

.panorama-hotspot__compass {
    position: absolute;
    top: 12px;
    right: 12px;
    z-index: 3;
    width: 42px;
    height: 42px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.5);
    color: #fff;
    cursor: pointer;
}

[dir="rtl"] .panorama-hotspot__compass {
    right: auto;
    left: 12px;
}
.panorama-hotspot__compass i {
    font-size: 22px;
    line-height: 1;
}
.panorama-hotspot__compass-needle {
    display: inline-block;
    transform-origin: center center;
}

/* ============================================
 * PANNELLUM NATIVE HOTSPOT PINS
 * Pannellum wraps each hotspot in .pnlm-hotspot; the cssClass we pass (.ph-pin
 * + .ph-pin--<style>) is applied to that wrapper. The pin visual mirrors the
 * hotspot_image .hotspot-image__pin exactly: --ph-pin-size sizing, primary-color
 * fill, --ph-pin-glyph foreground, --shadow / --shadow-lg token shadows, hover
 * feedback via a stronger shadow + full opacity (no transform-scale flicker),
 * and a pulse halo via box-shadow spread (NOT transform). Per-item colors are
 * applied at runtime as --ph-pin-color / --ph-pin-glyph / --ph-pin-glow.
 * ============================================ */

/* Pin the hotspot wrapper to the container's top-left corner. Pannellum's own
 * CSS sets only top:0 on .pnlm-hotspot-base (no left), then positions each pin
 * with a translate() computed from the top-left origin. With left:auto the
 * browser anchors an absolutely-positioned element differently under dir=ltr vs
 * dir=rtl, so the translate lands on the wrong anchor: in LTR the pin ends up
 * offset from the right edge (off-stage), while in RTL it sits correctly. Forcing
 * left:0 (and right:auto to undo any inherited RTL value) makes the top-left
 * origin explicit and identical in both directions. */
.panorama-hotspot .pnlm-hotspot-base {
    left: 0;
    right: auto;
}

.panorama-hotspot .ph-pin {
    --ph-pin-color: var(--primary-color, var(--bs-primary, #0d6efd));
    --ph-pin-glyph: var(--bg-color, #ffffff);
    --ph-pin-glow: var(--primary-color, var(--bs-primary, #0d6efd));
    width: var(--ph-pin-size);
    height: var(--ph-pin-size);
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: var(--ph-pin-color);
    color: var(--ph-pin-glyph);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: calc(var(--ph-pin-size) * 0.5);
    font-weight: 700;
    line-height: 1;
    box-shadow: var(--shadow, 0 4px 8px rgba(26, 36, 33, 0.35));
    transition: box-shadow 0.18s ease, opacity 0.18s ease;
    opacity: var(--ph-pin-opacity, 1);
}

/* Hover and focus do NOT scale the pin (mirrors hotspot_image). A hover-scale
 * transform is a flicker source: the pin enlarges, the cursor (still at the same
 * screen point) slips off the now-shifted hit-box edge, hover drops, the pin
 * snaps back, the cursor is over the pin again, hover re-enters — repeat. The
 * only hover feedback is a stronger shadow + full opacity so a dimmed pin still
 * reads clearly when the user is about to click it. */
.panorama-hotspot .ph-pin:hover,
.panorama-hotspot .ph-pin:focus-visible {
    box-shadow: var(--shadow-lg, 0 12px 32px rgba(26, 36, 33, 0.45));
    opacity: 1;
    outline: none;
}
.panorama-hotspot .ph-pin:focus-visible {
    outline: 2px solid var(--primary-color);
    outline-offset: 2px;
}

/* Icon variant: a slightly larger glyph so common icons read clearly. Scales
 * with the pin box (--ph-pin-size) so the icon grows/shrinks with the pin. */
.panorama-hotspot .ph-pin--icon {
    font-size: calc(var(--ph-pin-size) * 0.55) !important;
}

/* The numeral span (number variant). pointer-events:none so the digit never
 * steals the click from the button. font-size is pinned to --ph-pin-size directly
 * (mirroring the icon variant) instead of relying on inheritance, so the digit
 * scales with the pin box when the pin size setting changes. */
.panorama-hotspot .ph-pin-num {
    pointer-events: none;
    font-size: calc(var(--ph-pin-size) * 0.5) !important;
}

/* Pulse halo (enabled via .ph-pin--pulse on each pin wrapper). The halo expands
 * via box-shadow spread, NOT transform: scale. A transform on ::before combined
 * with the pin's hover-scale transition forces continuous compositing/repaint
 * (visible flicker), and a scaled ::before also makes the perceived pin much
 * larger than its hit box (off-center clicks miss the button). box-shadow keeps
 * the halo purely visual — the clickable area stays the pin's own box — and adds
 * no transform layer, so there is no flicker. The halo color tracks the pin
 * color via --ph-pin-glow (set by the engine when a per-pin color is present),
 * falling back to the primary token. */
/* z-index is 0 (NOT -1). The pin carries a transform (the centering translate),
 * which establishes a new stacking context on the button itself. With z-index:-1
 * the ::before would be painted BEHIND the pin's own opaque background — and
 * since the pin's box exactly covers the ::before, the halo box-shadow spread
 * (the only part that extends past the pin) renders behind the stage too, so the
 * pulse visually vanishes. z-index:0 keeps the halo below the pin content (the
 * number/icon) but above the pin's own background layer, so the expanding spread
 * stays visible while pulsing. */
.panorama-hotspot .ph-pin--pulse::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    box-shadow: 0 0 0 0 var(--ph-pin-glow);
    animation: ph-pulse 2s ease-out infinite;
    pointer-events: none;
    z-index: 0;
}
@keyframes ph-pulse {
    0% {
        box-shadow: 0 0 0 0 var(--ph-pin-glow);
        opacity: 1;
    }
    70% {
        box-shadow: 0 0 0 calc(var(--ph-pin-size) * 0.6) var(--ph-pin-glow);
        opacity: 0;
    }
    100% {
        box-shadow: 0 0 0 calc(var(--ph-pin-size) * 0.6) var(--ph-pin-glow);
        opacity: 0;
    }
}

/* ============================================
 * POPUP MODAL (SweetAlert2 — hotspot_image InfoWindow clone)
 * ============================================ */

/* The popup uses this module's OWN .panorama-hotspot-info-* vocabulary and does
 * NOT depend on hotspot-image.css (module CSS/JS independence rule). The popup
 * markup mirrors the hotspot_image InfoWindow so both modules render the same
 * popup, but the styles live here under self-named classes.
 * SweetAlert2 injects its own padding on .swal2-popup; reset it so the padding
 * lives on the inner .panorama-hotspot-info-window box (matching the hotspot_image
 * layout where the close button anchors to the padded box's corner). The card
 * chrome (border-radius + box-shadow) mirrors the hotspot_image popup card so
 * both popups look identical.
 * Margin is zeroed here as a static default so the engine's runtime top/left
 * (inline-CSS exception 1) anchor the popup to the clicked pin without fighting
 * SweetAlert2's flex-centering margins; top/left/transform are applied by JS at
 * open time because they depend on the live pin coordinates. */
.panorama-hotspot-modal__popup {
    padding: 0 !important;
    margin: 0;
    text-align: initial;
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-lg);
}

/* SweetAlert2 centers its content (.swal2-popup text-align:center + grid) and
 * wraps the inner HTML in .swal2-html-container which carries its own padding.
 * The hotspot_image InfoWindow has no such wrapper — content padding comes only
 * from .panorama-hotspot-info-window (12px 14px). Zero out the SweetAlert2
 * wrapper's padding+margin so the single padded box matches the hotspot_image
 * layout exactly, and force start alignment so title, image+desc row and the
 * standalone link sit flush to the inline-start edge like the hotspot_image
 * popup. */
.panorama-hotspot-modal .swal2-html-container {
    text-align: start;
    margin: 0;
    padding: 0;
}

/* ============================================
 * POPUP INFO WINDOW CONTENT (self-contained, no hotspot-image.css dependency)
 * ============================================ */

/* Popup content mirrors the hotspot_image InfoWindow exactly (min/max width +
 * padding), so the rendered box is the same size as the hotspot_image popup.
 * position: relative anchors the custom close button (.panorama-hotspot-info-close-btn). */
.panorama-hotspot-info-window {
    position: relative;
    font-family: inherit !important;
    min-width: 180px;
    max-width: 300px;
    padding: 12px 14px;
    font-size: 0.875rem !important;
    text-align: start;
}

/* Popup content row: image + description side by side */
.panorama-hotspot-info-content-row {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    gap: 8px;
    margin-top: 6px;
}

/* RTL: image left, text right */
[dir="rtl"] .panorama-hotspot-info-content-row {
    flex-direction: row-reverse;
}

.panorama-hotspot-info-image {
    width: 100px;
    border-radius: var(--radius-xs);
    flex-shrink: 0;
}

.panorama-hotspot-info-text {
    min-width: 0;
    flex: 1;
}

.panorama-hotspot-info-title {
    font-weight: 700;
    font-size: 1rem !important;
    margin-bottom: 4px;
    color: var(--text-ink);
    line-height: 1.3;
}

.panorama-hotspot-info-desc {
    font-size: 0.8125rem !important;
    color: var(--text-color);
    margin-bottom: 6px;
    line-height: 1.4;
}

.panorama-hotspot-info-link {
    font-size: 1rem !important;
    font-weight: 600;
    color: var(--primary-color);
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    outline: none;
    justify-content: flex-start;
}

.panorama-hotspot-info-link:hover {
    text-decoration: underline;
    color: var(--primary-deep);
}

.panorama-hotspot-info-link:focus-visible {
    outline: 2px solid var(--primary-color);
    outline-offset: 2px;
    border-radius: var(--radius-xs);
}

.panorama-hotspot-info-link:hover sup {
    opacity: 1;
}

/* ============================================
 * POPUP CLOSE BUTTON (module-consistent, no hotspot-image.css dependency)
 * ============================================ */

/* A single close button rendered inside the popup content. Sized and positioned
 * identically to the hotspot_image InfoWindow close control so both modules show
 * the exact same control in the exact same place. Anchored to the inline-end
 * (right in LTR) top corner of the padded .panorama-hotspot-info-window box. */
.panorama-hotspot-info-close-btn {
    position: absolute;
    top: 5px;
    inset-inline-end: 5px;
    width: 11px;
    height: 11px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: none;
    border-radius: var(--radius-xs);
    background-color: transparent;
    color: var(--text-muted);
    cursor: pointer;
    line-height: 1;
    z-index: 5;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.panorama-hotspot-info-close-btn:hover,
.panorama-hotspot-info-close-btn:focus-visible {
    color: var(--text-ink);
    outline: none;
}

.panorama-hotspot-info-close-btn i {
    font-size: 0.5rem;
}

/* ============================================
 * POPUP RESPONSIVE (small viewports)
 * ============================================ */

/* Stack image + description vertically on narrow screens (matches the hotspot_image
 * popup responsive behavior). */
@media (max-width: 767.98px) {
    /* The engine opens the popup at a fixed SweetAlert2 width (200px on mobile).
       That value is applied as a fixed .swal2-popup width, which would overflow
       a sub-320px viewport and fight the engine's horizontal clamp. Cap the
       popup at the live viewport width (minus the MARGIN kept by the clamp) so
       it shrinks to fit narrow screens instead of bleeding past the edge. */
    .panorama-hotspot-modal__popup {
        max-width: calc(100vw - 16px) !important;
    }

    .panorama-hotspot-info-content-row {
        flex-direction: column !important;
    }

    .panorama-hotspot-info-image {
        width: auto;
        max-width: 150px !important;
        max-height: 50px !important;
    }

    .panorama-hotspot-info-desc {
        font-size: 0.8rem !important;
    }

    .panorama-hotspot-info-title.panorama-hotspot-info-link {
        display: inline;
        background: none;
    }
}

/* ============================================
 * POPUP DARK MODE
 * ============================================ */

/* Dark mode — match the hotspot_image InfoWindow dark card: same #242830
 * background and deeper shadow. Overrides template.css's generic dark .swal2-popup
 * for this popup. */
html[data-bs-theme="dark"] .panorama-hotspot-modal__popup {
    background-color: #242830 !important;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
}

html[data-bs-theme="dark"] .panorama-hotspot-info-title {
    color: #e2e2f0;
}

html[data-bs-theme="dark"] .panorama-hotspot-info-desc {
    color: #a0a0b8;
}

html[data-bs-theme="dark"] .panorama-hotspot-info-link {
    color: #2d8676;
}

html[data-bs-theme="dark"] .panorama-hotspot-info-link:hover {
    color: var(--primary-color);
}

html[data-bs-theme="dark"] .panorama-hotspot-info-close-btn {
    color: #a0a0b8;
}

html[data-bs-theme="dark"] .panorama-hotspot-info-close-btn:hover {
    background-color: rgba(255, 255, 255, 0.08);
    color: #e2e2f0;
}

/* ============================================
 * TOOLTIP (pin hover label) — hotspot_image clone, self-named .ph-tooltip
 * ============================================ */

/* Tooltip surface = the page surface token (--bg-color) and label = the ink
 * token (--text-ink). These two tokens are theme-aware opposites in template.css
 * :root (light: white bg / dark ink; dark: dark bg / light ink), so the tooltip
 * reads correctly in BOTH themes. The tooltip is injected into the Pannellum
 * hotspot wrapper via createTooltipFunc (the wrapper carries .ph-pin, so
 * position:absolute is relative to the pin). */
.panorama-hotspot--tooltip .ph-tooltip {
    position: absolute;
    left: 50%;
    background: var(--bg-color, rgba(0, 0, 0, 0.85));
    color: var(--text-ink, #ffffff);
    padding: var(--radius-xs) var(--radius-xs);
    border-radius: var(--radius-xs);
    font-size: 12px;
    font-weight: 500;
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.15s ease;
    z-index: 3;
}

.panorama-hotspot--tooltip-top .ph-tooltip    { bottom: calc(100% + 8px);  transform: translateX(-50%); }
.panorama-hotspot--tooltip-bottom .ph-tooltip { top: calc(100% + 8px);     transform: translateX(-50%); }
.panorama-hotspot--tooltip-left .ph-tooltip   { right: calc(100% + 8px);   top: 50%; transform: translateY(-50%); }
.panorama-hotspot--tooltip-right .ph-tooltip  { left: calc(100% + 8px);    top: 50%; transform: translateY(-50%); }

/* Kill-switch: when the module has no .panorama-hotspot--tooltip modifier
 * (show_tooltip off) the tooltip is hidden regardless of direction. */
.panorama-hotspot:not(.panorama-hotspot--tooltip) .ph-tooltip {
    display: none;
}

.panorama-hotspot .ph-pin:hover .ph-tooltip,
.panorama-hotspot .ph-pin:focus-visible .ph-tooltip {
    opacity: 1;
}

/* ============================================
 * ACCESSIBILITY — reduced motion
 * ============================================ */

@media (prefers-reduced-motion: reduce) {
    .panorama-hotspot .ph-pin,
    .panorama-hotspot .ph-pin::before,
    .panorama-hotspot .ph-tooltip {
        transition: none;
        animation: none;
    }

    .panorama-hotspot .ph-pin--pulse::before {
        animation: none;
        opacity: 0;
    }
}
