/* =========================================================
   STORIES.CSS (FEED / VIEWER) — FULL UPDATED FILE
   Includes: tray thumbs, skeleton, viewer overlay + OUTSIDE tap-zones
   ========================================================= */

/* =========================
   STORIES TRAY (REAL SWIPER)
   ========================= */

#stories-swiper {
    padding: 5px 0;
}

#stories-swiper .swiper-wrapper {
    align-items: flex-start;
}

/* Server-rendered tray: scroll natively (like the Exclusive For You / Reels strips) so the
   story cards are usable the instant the HTML paints — no dependency on Swiper/JS.
   NOTE: the element also has Swiper's .swiper-container class, whose base CSS sets
   overflow:hidden + touch-action:pan-y (which BLOCKS horizontal touch-swipe). We override
   both here with !important so the native horizontal scroll actually works. */
#stories-swiper.is-native-scroll {
    width: 100%;
    overflow-x: auto !important;
    overflow-y: hidden !important;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    touch-action: pan-x pan-y !important;   /* allow horizontal touch scrolling */
}
#stories-swiper.is-native-scroll .swiper-wrapper {
    transform: none !important;
    display: flex !important;
    flex-wrap: nowrap !important;
    width: max-content !important;    /* grow past the container so it can scroll */
    gap: 5px;                         /* Swiper isn't running, so the gap comes from CSS */
    /* 5px LEFT lead-in via padding. The RIGHT lead-in is a margin on the last card (below)
       because an overflow scroller clips trailing padding at the scroll end. */
    padding-left: 5px;
    padding-right: 0;
    box-sizing: content-box;
    touch-action: pan-x pan-y !important;
}
/* Slides must keep their width (never shrink) so the row overflows and scrolls. */
#stories-swiper.is-native-scroll .swiper-slide.story-thumb {
    flex: 0 0 auto;
}
/* Right lead-in that survives to the scroll end: 8px after the last card. */
#stories-swiper.is-native-scroll .swiper-wrapper > .story-thumb:last-child {
    margin-right: 8px;
}
#stories-swiper.is-native-scroll::-webkit-scrollbar { display: none; }

/* =========================================================
   FACEBOOK-STYLE STORY CARDS (tall thumbnails)
   ========================================================= */
#stories-swiper .swiper-slide.story-thumb {
    width: 105px;
}

/* MOBILE: show ~3 cards + a peek of the 4th (Facebook-style), and give the tray a bit
   of vertical breathing room above/below. Card width = a fraction of the viewport so
   about 3.25 cards fit; height scales with it via a 9:16 (real story) ratio.
   The tray itself has NO left/right padding — instead a 15px ::before/::after spacer on
   the swiper wrapper (same as the Exclusive/Reels panels) gives a normal left lead-in
   while letting the cards swipe right up to the screen edge. Gap between cards = 8px. */
@media (max-width: 767.98px) {
    /* Drop the wrapper's side padding on mobile so the tray reaches the screen edges;
       the 15px ::before/::after spacer below is the only left/right lead-in (edge-to-edge
       swipe, like the Exclusive/Reels panels). Targeted by the UNIQUE id #fx-stories-row
       (not the shared .neutral-bg/.py-2 classes) so this can NEVER affect any other
       element, and the id specificity still beats the "body .neutral-bg.py-2" rule. */
    #fx-stories-row {
        padding-left: 0 !important;
        padding-right: 0 !important;
    }
    #stories-swiper {
        padding: 8px 0 10px;
    }
    /* No ::before/::after spacer — the 8px wrapper padding above is the edge gap, so the
       edges never double. Card width: ~3.25 cards visible = (viewport - the two 5px edge
       paddings - 3 inter-card 5px gaps) / 3.25. The arithmetic has to follow the gap: leave
       16px here against a 5px gap and the cards come out narrow, with the row ending short
       of the edge. */
    #stories-swiper .swiper-slide.story-thumb {
        width: calc((100vw - 10px - 3 * 5px) / 3.25);
    }
    #stories-swiper .swiper-slide.story-thumb .story-card,
    #stories-swiper .swiper-slide.story-thumb .story-card--add {
        width: 100%;
        height: auto;
        aspect-ratio: 9 / 16;
    }
}

.story-card {
    position: relative;
    width: 105px;
    height: 155px;
    border-radius: 10px;
    overflow: hidden;
    cursor: pointer;
    background: #1e1e1e;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .2);
}
body.fx-theme-dark .story-card { background: #242526; }

.story-card-media {
    position: absolute;
    inset: 0;
}
.story-card-cover {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: transform .25s ease;
}
.story-card:hover .story-card-cover { transform: scale(1.04); }
.story-card-cover--ph { background: linear-gradient(160deg, #d1d5db, #9ca3af); }

/* dark gradient at bottom so the name is readable */
.story-card::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 50%;
    background: linear-gradient(transparent, rgba(0, 0, 0, .85));
    pointer-events: none;
}

/* number badge = stories posted in the last 24h (top-right pill, like the
   Exclusive For You media-count badge) */
.story-card-count {
    position: absolute;
    top: 6px; right: 6px;
    z-index: 4;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px; height: 20px;
    padding: 0 7px;
    border-radius: 999px;
    background: rgba(0, 0, 0, .55) !important;
    color: #fff !important;
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
    text-align: center;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .35);
}

/* avatar ring hidden inside story card per user request */
.story-card-avatar-ring {
    display: none !important;
}

/* name at the bottom */
.story-card-name {
    position: absolute;
    left: 6px; right: 6px; bottom: 6px;
    z-index: 3;
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    line-height: 1.2;
    text-shadow: 0 1px 3px rgba(0, 0, 0, .8);
    max-width: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* seen -> grey ring */
.story-thumb.story-thumb-seen .story-card-avatar-ring { background: #b0b3b8; }
.story-thumb.story-thumb-seen .story-card-name { opacity: .85; }

/* =========================
   CREATE STORY CARD (Facebook)
   ========================= */
.story-card--add {
    background: #fff;
    display: flex;
    flex-direction: column;
}
body.fx-theme-dark .story-card--add { background: #242526; }
.story-card--add .story-card-media { position: relative; height: 68%; inset: auto; }
.story-card--add::after { display: none; }
.story-card--add .story-card-cover { border-radius: 0; }

.story-card-add-foot {
    position: relative;
    height: 32%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    padding-bottom: 12px;
}
.story-card-add-btn {
    position: absolute;
    top: 0;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 34px; height: 34px;
    border-radius: 50%;
    background: #d10054;               /* our pink + button */
    border: 2px solid #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    /* box-shadow removed at the user's request -- the white ring already separates the
       button from the cover behind it. */
}
body.fx-theme-dark .story-card-add-btn { border-color: transparent; }
.story-card-add-label {
    font-size: 12px;
    font-weight: 700;
    color: #1c1e21;
    text-align: center;
}
body.fx-theme-dark .story-card-add-label { color: #e4e6eb; }

/* =========================
   STORIES SKELETON (LOADING)
   Works everywhere (feed + profile highlights)
   ========================= */

/* Base skeleton row */
/* Skeleton mirrors the REAL story cards (tall 9:16 rounded rectangles at the same
   width) so there's no size jump / layout shift when the stories load. */
.stories-swiper-skeleton {
    display: flex;
    gap: 8px;
    align-items: flex-start;
    padding: 0;
    margin: 0;
    overflow: hidden;
}

/* Skeleton item = a story card placeholder (same 105px width as the real card). */
.stories-swiper-skeleton__item {
    width: 105px;
    min-width: 105px;
    display: block;
}

/* The card block: tall rounded rectangle matching .story-card (shimmering). */
.stories-swiper-skeleton__ring {
    width: 100%;
    height: 155px;
    border-radius: 10px;
    padding: 0;
    background: linear-gradient(90deg, #e6eaee 25%, #f2f4f7 37%, #e6eaee 63%);
    background-size: 400% 100%;
    animation: storiesSkeletonShimmer 1.1s ease-in-out infinite;
    display: block;
}

/* Inner avatar dot removed — the card block itself is the placeholder now. */
.stories-swiper-skeleton__avatar,
.stories-swiper-skeleton__name {
    display: none;
}

.stories-swiper-skeleton__line {
    height: 10px;
    border-radius: 6px;
    background: linear-gradient(90deg, #e6eaee 25%, #f2f4f7 37%, #e6eaee 63%);
    background-size: 400% 100%;
    animation: storiesSkeletonShimmer 1.1s ease-in-out infinite;
}

/* MOBILE: match the real cards' viewport-fraction width + 9:16 ratio + 15px lead-in. */
@media (max-width: 767.98px) {
    .stories-swiper-skeleton { padding-left: 15px; }
    .stories-swiper-skeleton__item {
        width: calc((100vw - 15px - 3 * 8px) / 3.25);
        min-width: calc((100vw - 15px - 3 * 8px) / 3.25);
    }
    .stories-swiper-skeleton__ring {
        height: auto;
        aspect-ratio: 9 / 16;
    }
}

@keyframes storiesSkeletonShimmer {
    0% { background-position: 100% 0; }
    100% { background-position: 0 0; }
}

/* --- Optional: smaller skeleton variant (highlights) --- */
/* Just add class="stories-swiper-skeleton stories-swiper-skeleton--sm" on the wrapper */
.stories-swiper-skeleton--sm .stories-swiper-skeleton__item {
    width: 72px;
    min-width: 72px;
}

.stories-swiper-skeleton--sm .stories-swiper-skeleton__ring {
    width: 56px;
    height: 56px;
    padding: 3px;
}


/* =========================
   VIEWER OVERLAY (REFINED)
   ========================= */

.stories-viewer-overlay {
    position: fixed;
    inset: 0;                 /* full screen — covers the bottom nav (unlike reels) */
    z-index: 2300;            /* above the bottom nav (2200) so the story is truly full-screen */
    display: none;
}

.stories-viewer-overlay.visible { display: block; }

/* When a story is ACTUALLY open (overlay visible), a modal opened from it must
   clear the full-screen story viewer. Gate on the visible overlay so this can
   NEVER leak to normal site modals (which was burying them under the backdrop
   -> the "dim screen, can't click" bug). Also raise ANY .modal (not just three)
   above the boosted backdrop so nothing gets buried. */
body:has(.stories-viewer-overlay.visible).modal-open .modal-backdrop {
    z-index: 1000000;
}
body:has(.stories-viewer-overlay.visible).modal-open .modal {
    z-index: 1000010;
}

#story-delete-dialog {
    z-index: 1000010;
}

.stories-viewer-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0,0,0,0.82);
    opacity: 0;
    transition: opacity 250ms ease-out;
}

/* IMPORTANT:
   .stories-viewer is the full-screen stage
   tap-zones live inside it and the card sits above them */
.stories-viewer {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    opacity: 0;
    transform: translateY(10px);
    transition: opacity 250ms ease-out, transform 250ms ease-out;
    z-index: 1;
}

/* Card wrapper */
.stories-viewer-inner {
    width: min(420px, 100vw - 32px);
    height: calc(100vh - 80px);
    max-height: 900px;
    border-radius: 20px;
    overflow: hidden; /* IMPORTANT: keep hidden for clean chrome */
    display: flex;
    position: relative;
    z-index: 3; /* ABOVE tap-zones */
}

/* Fade in/out */
.stories-viewer-overlay.visible .stories-viewer-backdrop { opacity: 1; }
.stories-viewer-overlay.visible .stories-viewer { opacity: 1; transform: translateY(0); }

.stories-viewer-overlay.closing .stories-viewer-backdrop { opacity: 0; }
.stories-viewer-overlay.closing .stories-viewer { opacity: 0; transform: translateY(10px); }

/* Screen container (the story stage) */
.stories-viewer-swiper {
    position: relative;
    width: 100%;
    height: 100%;
    background: #000;
    border-radius: 20px;
    overflow: hidden;
}

/* Media
   ------
   contain is the default because the fit is only known once the media has loaded and
   reported its dimensions -- JS then switches portrait media to cover (see
   StoriesSwiper.applyStoryFit). Starting at cover would crop a landscape photo for the
   moment before that runs, which reads as a glitch.

   A flat cover was what shipped, so anything not portrait was permanently cropped: a
   landscape photo lost its sides, a square lost its top and bottom. */
.story-image,
.story-video {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
}

.stories-media-loading,
.stories-media-error {
    align-items: center;
    background: rgba(0, 0, 0, .42);
    border-radius: 999px;
    color: #fff;
    display: flex;
    left: 50%;
    position: absolute;
    top: 50%;
    transform: translate(-50%, -50%);
    z-index: 7;
}

.stories-media-loading {
    height: 3.25rem;
    justify-content: center;
    pointer-events: none;
    width: 3.25rem;
}

.stories-media-error {
    border-radius: 14px;
    flex-direction: column;
    gap: .45rem;
    max-width: 70%;
    padding: 1rem;
    pointer-events: none;
    text-align: center;
}

.stories-media-error ion-icon {
    font-size: 1.6rem;
}

.stories-viewer-swiper.has-media-error .story-image,
.stories-viewer-swiper.has-media-error .story-video {
    opacity: .45;
}

/* Legibility gradients */
.stories-legibility {
    position: absolute;
    left: 0;
    right: 0;
    z-index: 3;
    pointer-events: none;
}

.stories-legibility--top {
    top: 0;
    height: 120px;
    background: linear-gradient(to bottom, rgba(0,0,0,0.55), rgba(0,0,0,0));
}

.stories-legibility--bottom {
    bottom: 0;
    height: 140px;
    background: linear-gradient(to top, rgba(0,0,0,0.55), rgba(0,0,0,0));
}

/* Chrome wrappers (top/bottom) */
.stories-chrome {
    position: absolute;
    left: 0;
    right: 0;
    z-index: 8;
    pointer-events: none;
}

.stories-chrome--top { top: 0; padding: 10px 10px 0; }
.stories-chrome--bottom { bottom: 0; padding: 0 10px 10px; }

/* Progress bars */
.stories-viewer-progress-wrap {
    display: flex;
    gap: 6px;
    padding: 2px 0 10px;
    pointer-events: none;
}

.story-progress-bar {
    flex: 1;
    height: 3px;
    border-radius: 999px;
    background: rgba(255,255,255,0.22);
    overflow: hidden;
}

.story-progress-fill {
    width: 0;
    height: 100%;
    background: rgba(255,255,255,0.88);
}

/* =========================
   HEADER (SINGLE SOURCE)
   ========================= */

.stories-viewer-header{
    display:flex;
    align-items:flex-start;
    justify-content:space-between;
    gap:10px;
    color:#fff;
    pointer-events:none;
}

/* Left user block */
.stories-viewer-user{
    display:flex;
    align-items:flex-start;
    gap:10px;
    min-width:0;       /* enables ellipsis */
    flex:1 1 auto;
}

.stories-viewer-avatar{
    width:36px;
    height:36px;
    border-radius:50%;
    object-fit:cover;
    border:1px solid rgba(255,255,255,0.25);
    flex:0 0 auto;
    pointer-events:auto; /* clickable */
}

/* Stack: username / meta */
.stories-viewer-user-info{
    display:flex;
    flex-direction:column;
    align-items:flex-start;
    gap:4px;
    min-width:0;
    flex:1 1 auto;
    line-height:1.1;
}

/* Username truncates */
.stories-viewer-username{
    display:block;
    max-width:100%;
    min-width:0;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
    font-weight:600;
    line-height:1.1;
    margin:0;
    padding:0;
    color:#fff;
    text-decoration:none;
    pointer-events:auto; /* clickable */
}
.stories-viewer-username:hover{ text-decoration: underline; }

/* Meta row (time + views + pill inline) */
.stories-viewer-meta{
    display:flex;
    align-items:center;
    gap:8px;
    min-width:0;
    line-height:1;
    font-size:12px;
    opacity:0.85;
}

.stories-viewer-time{
    font-size:12px;
    opacity:0.75;
    margin-top:0;
    white-space:nowrap;
}

.stories-viewer-views{
    display:inline-flex;
    align-items:center;
    gap:4px;
    font-size:12px;
    opacity:.9;
    white-space:nowrap;
}
.stories-viewer-views ion-icon{ font-size:14px; }

/* Sound pill (badge-like + truncates) */
#stories-sound-pill.stories-sound-pill{
    display:inline-flex;
    align-items:center;
    gap:6px;
    max-width:min(220px, 60vw);
    min-width:0;
    padding:4px 8px;
    border-radius:999px;
    font-size:11px;
    line-height:1;
    letter-spacing:0.2px;
    color:rgba(255,255,255,0.88);
    background:rgba(0,0,0,0.28);
    border:1px solid rgba(255,255,255,0.12);
    backdrop-filter: none;
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
    opacity:.92;
}

/* Right controls block */
.stories-viewer-controls{
    flex:0 0 auto;
    display:flex;
    align-items:center;
    gap:8px;
    pointer-events:auto;
}

.stories-viewer-controls button,
.stories-viewer-controls .stories-owner-menu-btn {
    background: rgba(0,0,0,0.40);
    border: 1px solid rgba(255,255,255,0.14);
    border-radius: 999px;
    width: 34px;
    height: 34px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    outline: none;
    color: #fff;
    pointer-events: auto;
    text-decoration: none;
}

.stories-viewer-controls button:focus,
.stories-viewer-controls .stories-owner-menu-btn:focus {
    outline: none;
    box-shadow: none;
}

.stories-viewer-controls ion-icon {
    font-size: 18px;
    color: #fff;
    pointer-events: none;
}

/* Custom mute/unmute SVG (same set as feed & reels players). */
.stories-viewer-toggle-sound span {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
}
.stories-viewer-toggle-sound svg {
    width: 18px;
    height: 18px;
    display: block;
}

.stories-owner-menu-btn.dropdown-toggle::after {
    display: none !important;
}

/* Close button */
.stories-viewer-close{
    width:34px;
    height:34px;
    border-radius:999px;
}

/* =========================
   REPLY (visual only)
   ========================= */

/* ---- Fansly-style: emoji quick-react row ---- */
.stories-emoji-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
    margin-bottom: 10px;
    pointer-events: auto;
}
.stories-emoji {
    background: transparent;
    border: 0;
    padding: 0;
    font-size: 26px;
    line-height: 1;
    cursor: pointer;
    transition: transform .12s ease;
    filter: drop-shadow(0 1px 3px rgba(0,0,0,.5));
}
.stories-emoji:hover { transform: scale(1.25); }
.stories-emoji:active { transform: scale(.9); }

/* ---- Inline reply input (no modal) ---- */
.stories-reply{
    display:flex;
    align-items:center;
    gap:8px;
    pointer-events: auto;
}
/* reply box: input with the send button INSIDE on the right */
.stories-reply-field{
    position: relative;
    flex: 1 1 auto;
    min-width: 0;
}
.stories-reply-input{
    width: 100%;
    height: 44px;
    border-radius: 999px;
    padding: 0 46px 0 16px;   /* room for the send button inside */
    color: #fff;
    font-size: 0.9rem;
    background: rgba(255,255,255,0.10);
    border: 1px solid rgba(255,255,255,0.30);
    outline: none;
}
.stories-reply-input::placeholder { color: rgba(255,255,255,0.7); }
.stories-reply-input:focus { border-color: rgba(255,255,255,0.6); background: rgba(255,255,255,0.14); }
.stories-reply-send{
    position: absolute;
    top: 50%;
    right: 5px;
    transform: translateY(-50%);
    width: 36px;
    height: 36px;
    border-radius: 50%;
    display:flex;
    align-items:center;
    justify-content:center;
    background: transparent;
    border: 0;
    color: #fff;
    cursor: pointer;
}
.stories-reply-send ion-icon { font-size: 20px; pointer-events: none; }
.stories-reply-send:hover { color: #d10054; }

/* ---- Send Tip pill (sits inline in the reply row, right side) ---- */
.stories-action-love,
.stories-tip-pill { flex: 0 0 auto; }
.stories-tip-pill{
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: transparent;
    border: 0;
    color: #fff;
    font-weight: 800;
    font-size: 0.8rem;
    letter-spacing: .04em;
    cursor: pointer;
    padding: 6px 4px;
    transition: color .15s ease, transform .12s ease;
}
.stories-tip-pill ion-icon { font-size: 20px; pointer-events: none; }
.stories-tip-pill:hover { color: #ffd54a; transform: translateY(-1px); }
.stories-tip-label { pointer-events: none; }
/* mobile: tighter row so the reply box is a bit narrower and the tip stays visible */
@media (max-width: 480px) {
    .stories-reply { gap: 6px; }
    .stories-action-love { padding: 4px; }
    .stories-action-love ion-icon { font-size: 24px; }
    .stories-reply-input { height: 40px; padding: 0 42px 0 14px; font-size: 0.85rem; }
    .stories-reply-send { width: 32px; height: 32px; right: 4px; }
    .stories-tip-pill { font-size: 0.72rem; padding: 4px 2px; }
    .stories-tip-pill ion-icon { font-size: 18px; }
}

/* Story action buttons: Love (bottom-left) — borderless icon, Fansly style */
.stories-action-btn {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 0;
    color: #fff;
    cursor: pointer;
    pointer-events: auto;
    padding: 6px;
    transition: transform .12s ease, color .15s ease;
}
.stories-action-btn ion-icon { font-size: 26px; pointer-events: none; filter: drop-shadow(0 1px 3px rgba(0,0,0,.5)); }
.stories-action-btn:active { transform: scale(.9); }
.stories-action-love:hover { color: #ff3b6b; }
.stories-action-love.is-loved { color: #ff2d55; }
.stories-action-love.is-loved ion-icon { color: #ff2d55; }
.stories-action-love.fx-pop ion-icon { animation: fxStoryHeart .4s ease; }
@keyframes fxStoryHeart {
    0% { transform: scale(1); }
    40% { transform: scale(1.4); }
    70% { transform: scale(.9); }
    100% { transform: scale(1); }
}

/* Center prev/next arrows (multi-story users) */
.stories-nav-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 9;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, .4);
    border: 1px solid rgba(255, 255, 255, .25);
    color: #fff;
    cursor: pointer;
    pointer-events: auto;
    transition: background-color .15s ease, opacity .15s ease;
}
.stories-nav-arrow ion-icon { font-size: 22px; pointer-events: none; }
.stories-nav-arrow:hover { background: rgba(0, 0, 0, .6); }
.stories-nav-prev { left: 10px; }
.stories-nav-next { right: 10px; }
.stories-nav-arrow.stories-nav-disabled { opacity: .3; pointer-events: none; }

/* =========================
   TAP ZONES (OUTSIDE THE CARD)
   ========================= */

.stories-viewer-tap-zones-outside {
    position: absolute;
    inset: 0;
    z-index: 2;            /* above backdrop, below the card */
    display: flex;
    pointer-events: none;  /* enable only on left/right */
}

.stories-viewer-tap-left,
.stories-viewer-tap-right {
    width: 35%;
    pointer-events: auto;
}

.stories-viewer-tap-middle {
    flex: 1;
    pointer-events: none;  /* hole over the card */
}

/* =========================
   RESPONSIVE
   ========================= */

@media (max-width: 768px) {
    .stories-viewer-inner {
        width: 100vw;
        height: 100vh;
        max-height: none;
        border-radius: 0;
    }

    .stories-viewer-swiper { border-radius: 0; }

    .stories-viewer-tap-left,
    .stories-viewer-tap-right {
        width: 50%;
    }

    .stories-viewer-tap-middle {
        display: none;
    }
}

@media (min-width: 992px) {
    .stories-viewer { padding: 0; }

    .stories-viewer-inner {
        height: calc(100vh - 32px);
        width: min(540px, 100vw - 64px);
        max-height: none;
        border-radius: 20px;
    }
}

/* =========================
   TEXT OVERLAY LAYER
   ========================= */

.stories-text-layer{
    position: absolute;
    z-index: 6;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: calc(100% - 36px);
    max-width: calc(100% - 36px);
    text-align: center;
    color: #fff;
    font-weight: 700;
    text-shadow: 0 10px 28px rgba(0,0,0,0.45);
    word-break: break-word;
    pointer-events: none;
    font-size: clamp(1.15rem, 1.0rem + 0.7vw, 1.65rem);
    line-height: 1.25;
}

/* =========================
   LINK CTA (BOTTOM)
   ========================= */

.stories-chrome--bottom{
    z-index: 8;
    pointer-events: none;
}

#stories-link-btn{
    pointer-events: auto;
}

.stories-link-btn{
    position: relative;
    left: 50%;
    transform: translateX(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    margin: 0 0 10px;
    padding: 10px 14px;
    border-radius: 999px;
    background: rgba(0,0,0,0.45);
    border: 1px solid rgba(255,255,255,0.18);
    color: #fff;
    text-decoration: none;
    max-width: calc(100% - 24px);
}

.stories-link-btn:hover,
.stories-link-btn:focus,
.stories-link-btn:active{
    color: #fff;
    text-decoration: none;
    background: rgba(0,0,0,0.45);
    border-color: rgba(255,255,255,0.18);
    outline: none;
}

.stories-link-btn .stories-link-text{
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 260px;
}

.stories-link-btn ion-icon{
    font-size: 16px;
    pointer-events: none;
}

/* =========================
   TEXT STORY BACKGROUNDS

   NOT tied to .stories-viewer-swiper any more.

   Every one of these used to begin with that class, so the colours applied in the full-screen
   viewer and nowhere else. The bubble in the stories row carries the same story-bg-- class on
   a .story-card-cover div, and matched none of the rules -- so an empty div sat on a dark
   background and every text story, whatever colour it was posted in, showed up black in the
   row. The cube preview had the same problem for the same reason.

   Written against the class alone, so anything carrying it gets its colour: the viewer, the
   bubble, the preview, and whatever comes next.
   ========================= */

.story-bg--solid_black { background: #000 !important; }

.story-bg--grad_orange { background: linear-gradient(135deg, #ff8a00, #ff5722) !important; }
.story-bg--grad_pink   { background: linear-gradient(135deg, #ff2d8d, #d10054) !important; }
.story-bg--grad_red    { background: linear-gradient(135deg, #ff5252, #e53935) !important; }
.story-bg--grad_purple { background: linear-gradient(135deg, #d10054, #3f51b5) !important; }
.story-bg--grad_indigo { background: linear-gradient(135deg, #3f51b5, #d10054) !important; }
.story-bg--grad_blue   { background: linear-gradient(135deg, #2196f3, #d10054) !important; }
.story-bg--grad_teal   { background: linear-gradient(135deg, #d10054, #4caf50) !important; }
.story-bg--grad_green  { background: linear-gradient(135deg, #4caf50, #ffca28) !important; }
.story-bg--grad_yellow { background: linear-gradient(135deg, #ffca28, #ff8a00) !important; }
.story-bg--grad_brown  { background: linear-gradient(135deg, #6d4c41, #e53935) !important; }

.story-bg--grad_default{
    background:
            radial-gradient(circle at 25% 10%, rgba(209,0,84, 0.35), rgba(0,0,0,0) 55%),
            radial-gradient(circle at 75% 90%, rgba(155, 61, 255, 0.35), rgba(0,0,0,0) 55%),
            #0b0b10 !important;
}

/* =========================================================
   DROPDOWN FIX (BS4) — KEEP THIS LAST
   Fixes: "clickable but invisible" + "expanded by default"
   ========================================================= */

.stories-owner-menu {
    position: relative;     /* anchor dropdown menu */
    pointer-events: auto;
    z-index: 9999;          /* above chrome/gradients */
}

.stories-owner-menu .dropdown-menu {
    right: 0;
    left: auto;
    top: 100%;
    margin-top: 8px;
    z-index: 99999;
    pointer-events: auto;
}

/* only visible when BS adds .show */
.stories-owner-menu.show .dropdown-menu {
    display: block;
}

/* =========================================================
   DROPDOWN "GHOST CLICK" HARD FIX (BS4)
   Put this at the VERY END of stories.css
   ========================================================= */

/* Always keep the menu fully disabled unless .show is present */
.stories-owner-menu .dropdown-menu {
    display: none !important;
    opacity: 0 !important;
    visibility: hidden !important;
    pointer-events: none !important;
}

/* Only Bootstrap-opened menus become visible + clickable */
.stories-owner-menu.show .dropdown-menu,
.stories-owner-menu .dropdown-menu.show {
    display: block !important;
    opacity: 1 !important;
    visibility: visible !important;
    pointer-events: auto !important;
}

/* Ensure menu stacks above chrome/gradients */
.stories-owner-menu { position: relative; z-index: 99999; }
.stories-owner-menu .dropdown-menu { z-index: 999999; }

/* Story reply */
/*todo: unused*/
#backToStoryBtn.btn-link {
    padding: 0 .25rem;
    text-decoration: none;
}
#backToStoryBtn.btn-link:hover {
    text-decoration: underline;
}
#backToStoryBtn.btn-link:focus {
    box-shadow: none;
}

/*own story comment disabled*/

.stories-reply.stories-reply--disabled {
    opacity: .45;
    cursor: default;
    /* DO NOT use pointer-events:none; */
}

/* =========================================================
   MOBILE 100vh FIX (URL bar / notch)
   Put at VERY END of stories.css
   ========================================================= */

/* Use dynamic viewport units when available */
@supports (height: 100dvh) {
    .stories-viewer-inner {
        height: 100dvh !important;
        max-height: 100dvh !important;
    }
}

/* JS fallback (uses --vh set in JS) */
.stories-viewer-inner {
    height: calc(var(--vh, 1vh) * 100) !important;
    max-height: calc(var(--vh, 1vh) * 100) !important;
}

/* MOBILE only: cap the usable height so the story clears the fixed bottom menu, which is
   56px tall. It was written here as 60, so the story stopped four pixels short of the nav
   and left a strip of page showing between them.
   Placed AFTER the JS fallback so it wins on phones; desktop rules below still apply. */
@media (max-width: 767.98px) {
    .stories-viewer-inner {
        position: absolute;
        top: 0 !important;
        left: 0;
        right: 0;
        bottom: 56px;
        height: 100dvh !important;
        max-height: calc(100dvh - 56px) !important;
    }
}

/* Keep your desktop sizing rules working */
@media (min-width: 992px) {
    .stories-viewer-inner {
        height: calc((var(--vh, 1vh) * 100) - 32px) !important;
        max-height: none !important;
    }
}

/* If you want to respect safe areas on iOS */
.stories-viewer-inner {
    padding-bottom: env(safe-area-inset-bottom);
}

/* Prevent background scroll when viewer is open */
.stories-no-scroll {
    overflow: hidden !important;
    height: 100% !important;
}

/* Tap zones INSIDE card (mobile) */
.stories-viewer-tap-zones-inside{
    position:absolute;
    inset:0;
    z-index:5;            /* above media, below chrome (chrome is 8) */
    display:none;
    pointer-events:none;
}

.stories-viewer-tap-left-inside,
.stories-viewer-tap-right-inside{
    position:absolute;
    top:0; bottom:0;
    width:50%;
    pointer-events:auto;
}

.stories-viewer-tap-left-inside{ left:0; }
.stories-viewer-tap-right-inside{ right:0; }

@media (max-width: 768px){
    .stories-viewer-tap-zones-inside{ display:block; }
}

.stories-viewer-username .story-verified svg {
    width: 1em !important;
    height: 1em !important;
    display: block;
}


/* ---------------------------------------------------------------------------
   "Your story": the Create-story card once the viewer actually has a story.

   The card used to render the avatar and nothing else, with the avatar ring
   disabled -- so a user who had just posted or SHARED a story saw exactly the
   same card as a user with none, and had no reason to tap it. It now shows the
   real story cover and takes the same unseen ring the other cards use.
   --------------------------------------------------------------------------- */
/* THE RING IS THE ONLY SIGNAL that you have a story -- the card keeps your avatar
   rather than swapping in the story cover -- so it has to be unmissable and it must
   not get clipped.

   Drawn as an ::after overlay rather than a box-shadow: the card is overflow:hidden
   for its rounded corners, which clips an outer shadow on some browsers. An inset
   overlay is painted inside the card and always shows. */
.story-card--add.story-card--has-story {
    position: relative;
}

.story-card--add.story-card--has-story::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    border: 3px solid #d10054;
    pointer-events: none;   /* the whole card stays tappable */
    z-index: 4;
}

/* Already seen: a quieter grey ring, matching .story-thumb-seen elsewhere. */
.story-card--add.story-card--has-story:not(.is-unseen)::after {
    border-color: #b0b3b8;
}

.story-card--add.story-card--has-story .story-card-cover {
    object-fit: cover;
}


/* ============================================================
   THE CUBE TURN BETWEEN ONE PERSON'S STORIES AND THE NEXT

   ONLY between people. The left and right arrows move through one person's own stories and
   are deliberately left alone: same person, next thing they posted, no turn. Swiping is what
   changes person, and giving that its own three-dimensional move is what makes the two read
   as different kinds of navigation without anything having to say so.

   TWO FACES, not one rotating panel. The script clones the outgoing story and stands it at
   right angles to the live viewer inside a stage that turns as one -- so there is a real
   corner between them, and for most of the movement you can see both. A single pane spinning
   has no corner and reads as a picture being flipped.
   ============================================================ */
.stories-viewer {
    /* The perspective belongs to the PARENT. An element cannot give itself depth: without
       this the rotation flattens into a horizontal squash that looks like a fault. */
    perspective: 1600px;
    perspective-origin: 50% 50%;
}

.stories-cube-stage {
    position: relative;
    transform-style: preserve-3d;
    /*
        300ms, on a curve that leaves quickly and settles slowly.

        Quick to leave keeps the movement feeling attached to the finger; slow to settle is
        what gives the cube weight rather than making it look like an animation playing. A
        faster turn was tried and read as a cut with a flourish attached.
    */
    transition: transform 340ms cubic-bezier(.32, .72, .28, 1);
    will-change: transform;
}

/*
   While the finger is down the transition comes off.

   With it on, every frame would chase the last one and the cube would trail the finger by
   its own animation length -- which feels like lag, not weight.
*/
.stories-cube-instant {
    transition: none !important;
}

.stories-cube-face {
    position: absolute !important;
    top: 0;
    left: 0;
    /* Each face is the full size of the viewer; the stage sizes itself to match. */
    width: 100% !important;
    height: 100% !important;
    /* A face turned away from the viewer is not drawn, so the two never show through each
       other at the corner. */
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
    /*
        No rounded corners while turning.

        The viewer is a rounded card, and two rounded rectangles meeting at a right angle
        leave a notch of background showing exactly at the corner -- which is the seam the
        eye goes to. Square edges make the two faces meet as a solid.
    */
    border-radius: 0 !important;
    /* Something behind each face, so a story that does not fill its frame shows black at
       the edges rather than the page behind the viewer. */
    background: #000;
    overflow: hidden;
}

/* The clone is a still: nothing in it should respond to a touch meant for the live face. */
.stories-cube-face-out {
    pointer-events: none;
}

/*
    The incoming person, previewed on the face that is turning in.

    Covers the live viewer for the length of the turn only. Without it both faces of the cube
    showed the same story -- the clone and the viewer it was cloned from -- and turning
    between two identical pictures revealed nothing at all.

    Removed the moment the turn ends, at which point openViewer has loaded that person for
    real underneath.
*/
.stories-cube-peek {
    position: absolute;
    inset: 0;
    z-index: 20;
    background-color: #000;
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    pointer-events: none;
    overflow: hidden;
}

/*
    A video story's first frame.

    Feeding a video URL to background-image paints nothing at all, which is why the incoming
    face came up black for every story that was not a photograph -- and most are not. A real
    element shows the frame; #t=0.001 on the source is what makes the browser decode and
    display it without being played.

    Contain, not cover: a preview that crops differently from the story it is previewing
    would jump the moment the real one loads underneath.
*/
.stories-cube-peek-media {
    width: 100%;
    height: 100%;
    object-fit: contain;
    background: #000;
}

/* A text story: centred, and large enough to be recognised in passing rather than read. */
.stories-cube-peek-text {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 12%;
    color: #fff;
    font-size: 1.4rem;
    font-weight: 700;
    line-height: 1.35;
    text-align: center;
    /* A long story would otherwise push its own preview out of shape. */
    overflow: hidden;
}

/* Anyone who has asked for less movement gets the navigation and none of the turn. The
   script checks this too; the rule is here so a stale script cannot animate anyway. */
@media (prefers-reduced-motion: reduce) {
    .stories-cube-stage {
        transition: none !important;
        transform: none !important;
    }
}

/*
    SOLID BLACK BEHIND THE CUBE while it turns.

    Two faces meeting at a right angle cannot cover the whole screen as they rotate -- there
    is a wedge either side of the corner that neither reaches -- so whatever is behind them
    shows through it. The viewer's backdrop normally sits at 82%, which lets a little of the
    page through: right for a story at rest, wrong the moment a cube opens that gap.

    THE VIEWER'S OWN BACKDROP, not something inside the stage. A backdrop placed in the stage
    shares its 3-D space and rotates with it, swinging away from the corner exactly where it
    is needed; this one is outside the rotation and simply stays put.

    Nothing about the cube itself is touched -- the faces, the perspective and the timing are
    as they were.
*/
.stories-viewer-overlay.stories-cube-active .stories-viewer-backdrop {
    background: #000;
    opacity: 1 !important;
}

/*
    A text story's bubble in the row: its colour, and the first words of it.

    The colour comes from the story-bg-- class it already carries (see TEXT STORY
    BACKGROUNDS above). This puts the words on top, small and clipped, so a row of text
    stories is distinguishable rather than being a row of coloured squares.
*/
.story-card-cover--text {
    /* !important because .story-card-cover sets display: block, and a block box would put
       the words at the top-left corner instead of centring them. */
    display: flex !important;
    align-items: center;
    justify-content: center;
    padding: 5px;
    color: #fff;
    /* Small, but not so small it becomes texture. At 9px the words were there and
       effectively invisible, which is worse than not showing them. */
    font-size: 11px;
    font-weight: 700;
    line-height: 1.2;
    text-align: center;
    overflow: hidden;
}

.story-card-cover--text span {
    /*
        Clipped by height rather than by line-clamp.

        -webkit-line-clamp needs display: -webkit-box on the same element, and that box
        model does not take part in the flex centring above -- so the span collapsed and the
        words disappeared. A max-height of three lines does the same job with none of that.
    */
    max-height: 3.6em;
    overflow: hidden;
    /* The colours run from light yellow to dark brown; a shadow keeps white legible on
       every one of them. */
    text-shadow: 0 1px 3px rgba(0, 0, 0, .55);
    /* A long unbroken word would otherwise force the tile wider than its frame. */
    overflow-wrap: anywhere;
}
