/* ============================================================================
   IG Post — the ONE post design.
   ----------------------------------------------------------------------------
   Every surface that shows a generated image as a "post" (character profile
   Feed tab, the full-screen image preview opened from the gallery grid, the
   search all-images feed) renders the same `.igp-card` markup produced by
   `public/js/ig-post.js`. Restyle here and every surface follows.

   Anatomy (mirrors Instagram):
     .igp-card
       .igp-head      avatar · name/handle · time · ⋮ (owner only)
       .igp-media     the image (or the server-blurred locked preview)
       .igp-actions   like · comment · share · ✨ send to generation (· save)
       .igp-likes     "N likes"
       .igp-caption   title
   Plus `.igp-feed-overlay`, the full-screen "Posts" page with a top nav.
   ============================================================================ */

.igp-scope {
    /* Prefer the product's OWN design-system tokens (public/css/design-system.css)
       so a post looks like this product, not like a copy of another app. The
       --ig-* / --bg-* fallbacks keep older pages that predate the DS working. */
    --igp-bg: var(--ds-bg, var(--ig-bg, var(--bg-primary, #f3f3f3)));
    --igp-surface: var(--ds-bg-elev, var(--ig-surface, var(--bg-secondary, #e7e7e7)));
    --igp-surface-2: var(--ds-bg-elev-2, #dfdfdf);
    --igp-border: var(--ds-line, var(--ig-border, var(--border-color, rgba(0, 0, 0, 0.08))));
    --igp-text: var(--ds-text, var(--ig-text, var(--text-primary, #0a0a0a)));
    --igp-text-2: var(--ds-text-soft, var(--ig-text-secondary, var(--text-secondary, #424242)));
    --igp-text-3: var(--ds-text-muted, #7f7f7f);
    --igp-accent: var(--ds-brand, var(--ig-purple, #000000));
    --igp-accent-light: var(--ds-brand-light, #000000);
    --igp-accent-grad: var(--ds-brand-grad, linear-gradient(105deg, #000000 0%, #101010 55%, #252525 120%));
    --igp-accent-glow: var(--ds-brand-glow, 0 8px 24px rgba(0, 0, 0, 0.16));
    --igp-radius: var(--ds-r-lg, 20px);
    --igp-radius-sm: var(--ds-r-md, 14px);
    --igp-shadow: var(--ds-shadow-md, 0 8px 30px rgba(0, 0, 0, 0.16));
    --igp-like: #ce0025;
    /* Minimum comfortable touch target. Mobile is the primary surface here. */
    --igp-tap: 44px;
}

/* The search/explore page uses its own palette tokens; map them so the shared
   post looks native there instead of importing the character page's greys.
   The full-screen overlay is appended to <body>, so it inherits this too. */
.explore-body .igp-scope {
    --igp-bg: var(--explore-bg, #ffffff);
    --igp-surface: var(--explore-card-bg, #eeeeee);
    --igp-border: var(--explore-border, rgba(0, 0, 0, 0.1));
    --igp-text: var(--explore-text, #000000);
    --igp-text-2: var(--explore-text-secondary, rgba(0, 0, 0, 0.7));
}

/* ── Feed list ───────────────────────────────────────────────────────────── */
.igp-feed {
    display: flex;
    flex-direction: column;
    gap: 14px;
    max-width: 520px;
    margin: 0 auto;
    width: 100%;
}

/* ── Card ────────────────────────────────────────────────────────────────── */
.igp-card {
    background: var(--igp-surface);
    border: 1px solid var(--igp-border);
    border-radius: var(--igp-radius);
    color: var(--igp-text);
    box-shadow: var(--igp-shadow);
    /* NOT `overflow:hidden` — that would clip the ⋮ dropdown, which hangs below
       the header. The media clips itself instead (.igp-media). */
    isolation: isolate;
    transition: border-color 0.2s ease, transform 0.2s ease;
}
@media (hover: hover) {
    .igp-card:hover { border-color: var(--line); }
}
/* Subscribers-only posts wear the brand gradient as a hairline: the paywall is
   a feature to advertise, not a warning to bury. */
.igp-card.is-premium {
    border-color: transparent;
    background:
        linear-gradient(var(--igp-surface), var(--igp-surface)) padding-box,
        var(--igp-accent-grad) border-box;
}
.igp-card.is-private {
    border-style: dashed;
    border-color: rgba(233, 131, 0, 0.34);
}

/* ── Header ──────────────────────────────────────────────────────────────── */
.igp-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
}
/* The whole identity block is the link to the creator. The media deliberately
   is NOT — tapping it is reserved for double-tap-to-like. */
.igp-identity {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 1 1 auto;
    min-width: 0;
    text-decoration: none;
    color: inherit;
    /* Comfortable touch target on mobile without inflating the header. */
    padding: 2px 0;
}
a.igp-identity:hover .igp-name { text-decoration: underline; }
.igp-avatar {
    width: 34px;
    height: 34px;
    border-radius: 999px;
    object-fit: cover;
    flex: 0 0 auto;
    border: 1px solid var(--igp-border);
    background: var(--igp-bg);
}
.igp-head-meta {
    display: flex;
    flex-direction: column;
    line-height: 1.25;
    min-width: 0;
    flex: 1 1 auto;
}
.igp-name-row {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}
.igp-name {
    font-weight: 600;
    font-size: 0.875rem;
    color: var(--igp-text);
    text-decoration: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
a.igp-name:hover { text-decoration: underline; }
.igp-sub-row {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    font-size: 0.72rem;
    color: var(--igp-text-2);
}
.igp-sub-row .igp-handle {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.igp-handle + .igp-time::before {
    content: '·';
    margin-right: 6px;
    opacity: 0.6;
}

/* Badges shown next to the name (private / subscribers-only) */
.igp-tag {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    flex: 0 0 auto;
    padding: 2px 7px;
    border-radius: 7px;
    font-size: 0.64rem;
    font-weight: 650;
    letter-spacing: 0.01em;
    white-space: nowrap;
    border: 1px solid rgba(0, 0, 0, 0.16);
    background: var(--veil-strong);
    color: var(--ink);
}
.igp-tag i { font-size: 0.9em; }
.igp-tag-premium { border-color: var(--line-strong); }
.igp-tag-premium i { color: var(--ink-soft); }
/* Paid CHARACTER price tag — price-first, so a subscription character never
   reads as free in browse. Distinct from .igp-tag-premium (one locked post). */
.igp-tag-price {
    border-color: var(--line-strong);
    font-variant-numeric: tabular-nums;
}
.igp-tag-price i { color: var(--ink-soft); }
.igp-tag-price em { font-style: normal; font-weight: 500; opacity: 0.72; }
.igp-tag-private {
    border-color: rgba(233, 131, 0, 0.36);
    background: rgba(60, 40, 10, 0.55);
    color: #ff9a02;
}

/* Follow pill (member or character, decided by the caller) */
.igp-follow {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    flex: 0 0 auto;
    padding: 5px 12px;
    border-radius: 999px;
    border: 1px solid transparent;
    background: var(--igp-accent);
    /* --igp-accent already falls back to black; the ink has to follow it down,
       or an unresolved --brand-ink leaves black-on-black. */
    color: var(--brand-ink, #f6f6f6);
    font-size: 0.74rem;
    font-weight: 600;
    line-height: 1.2;
    cursor: pointer;
    white-space: nowrap;
    transition: filter 0.18s ease, background 0.18s ease, color 0.18s ease, border-color 0.18s ease;
}
.igp-follow i { font-size: 0.85em; }
/* Gated on a real pointer: on touch, :hover latches after the tap and the pill
   stays in its hover paint until something else is tapped. */
@media (hover: hover) {
    .igp-follow:hover { filter: brightness(1.08); }
}
/* Followed: a quieter fill, but still a FILL — the label stays white ink. A
   ghost pill with grey text was the one place the button dropped out of the
   white-on-fill pattern, and it read as disabled next to the black one. */
.igp-follow.following {
    background: var(--fill-mid-strong, #5c5c62);
    border-color: transparent;
    color: var(--brand-ink, #f6f6f6);
}
/* Unfollowing is destructive, so hover turns it red — again as a fill, so the
   label is white here too instead of red ink on the card. */
@media (hover: hover) {
    .igp-follow.following:hover {
        background: var(--status-danger, #c62828);
        border-color: var(--status-danger, #c62828);
        color: var(--status-ink, #ffffff);
        filter: none;
    }
}
.igp-follow:disabled { opacity: 0.6; cursor: default; }

/* ── Owner-only ⋮ menu ───────────────────────────────────────────────────── */
.igp-menu { position: relative; flex: 0 0 auto; }
.igp-menu-btn {
    width: 30px;
    height: 30px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 999px;
    background: transparent;
    color: var(--igp-text);
    font-size: 1.05rem;
    cursor: pointer;
    transition: background 0.15s ease;
}
.igp-menu-btn:hover { background: var(--glass-strong); }
.igp-menu-list {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 30;
    min-width: 216px;
    padding: 6px;
    border-radius: 14px;
    border: 1px solid var(--igp-border);
    background: var(--surface-overlay);
    -webkit-backdrop-filter: blur(18px);
    backdrop-filter: blur(18px);
    box-shadow: 0 18px 44px rgba(0, 0, 0, 0.16);
}
.igp-menu-list[hidden] { display: none; }
.igp-menu-title {
    padding: 6px 10px 8px;
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--igp-text-2);
}
.igp-menu-sep {
    height: 1px;
    margin: 5px 8px;
    background: var(--igp-border);
}
.igp-menu-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 9px 10px;
    border: none;
    border-radius: 10px;
    background: transparent;
    color: var(--igp-text);
    font-size: 0.82rem;
    font-weight: 500;
    text-align: left;
    cursor: pointer;
    transition: background 0.15s ease;
}
.igp-menu-item:hover { background: var(--glass-strong); }
.igp-menu-item:disabled { opacity: 0.5; cursor: default; }
.igp-menu-item i {
    width: 18px;
    font-size: 0.95rem;
    color: var(--igp-text-2);
    flex: 0 0 auto;
}
.igp-menu-item.is-active i,
.igp-menu-item.is-active { color: var(--ink-soft); }
.igp-menu-item.is-danger,
.igp-menu-item.is-danger i { color: #e00000; }

/* ── Media ───────────────────────────────────────────────────────────────── */
.igp-media {
    display: block;
    position: relative;
    width: 100%;
    line-height: 0;
    background: var(--igp-bg);
    cursor: pointer;
    /* The card can't clip (it would eat the ⋮ dropdown), so the media clips
       itself and rounds its own corners when it sits at the card's edges. */
    overflow: hidden;
}
.igp-card > .igp-media:last-child {
    border-bottom-left-radius: 13px;
    border-bottom-right-radius: 13px;
}
.igp-media img {
    width: 100%;
    height: auto;
    display: block;
}
.igp-media .igp-video { display: block; }
/* A VIDEO POST HAS A FIXED BOX.
   ---------------------------------------------------------------------------
   A <video> reports 300x150 (2:1) until its metadata arrives, so a feed of
   portrait clips laid itself out short and then jolted taller one card at a
   time as each one loaded — the reported "video resizes while scrolling".
   Nothing tells us the real ratio up front (video rows carry no aspectRatio,
   and the poster is often missing too), so the box is DECLARED here instead of
   measured: 3:4, the same portrait shape the grid tiles use. The layout is
   final before a byte of video is fetched, and it never moves again.

   `contain` + a black bed, not `cover`: a clip that isn't 3:4 gets letterboxed
   rather than cropped through the character's face. */
.igp-media[data-igp-type="video"] {
    position: relative;
    aspect-ratio: 3 / 4;
    max-height: 78vh;
    background: var(--surface-page);
}
.igp-media .igp-video {
    width: 100%;
    height: 100%;
    background: var(--surface-page);
    object-fit: contain;
}
.igp-media.is-blurred img { filter: blur(18px); transform: scale(1.06); }

/* Sound toggle — the ONLY control an inline video offers. The native control
   bar is deliberately off (see videoHtml in ig-post.js): it owns its own hit
   areas, which swallowed double-tap-to-like. */
.igp-video-sound {
    position: absolute;
    right: 12px;
    bottom: 12px;
    z-index: 3;
    width: 34px;
    height: 34px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: var(--veil-strong);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    color: var(--ink);
    font-size: 0.9rem;
    line-height: 1;
    cursor: pointer;
    transition: background 0.18s ease, transform 0.18s ease;
}
.igp-video-sound:hover { background: var(--veil-strong); }
.igp-video-sound:active { transform: scale(0.94); }
.igp-video-sound.is-on { background: var(--veil-strong); }
.igp-media-lock {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 20px;
    text-align: center;
    background: var(--veil);
    line-height: 1.35;
}
.igp-media-lock > i { font-size: 1.8rem; color: var(--ink-soft); }
.igp-lock-copy {
    margin: 0;
    font-size: 0.85rem;
    color: var(--ink);
}
.igp-unlock-btn {
    padding: 9px 18px;
    border: none;
    border-radius: 999px;
    background: var(--igp-accent);
    color: var(--brand-ink);
    font-size: 0.82rem;
    font-weight: 700;
    cursor: pointer;
}
.igp-unlock-btn:hover { filter: brightness(1.08); }

/* ── Shoppable product tags ──────────────────────────────────────────────────
   The cards laid over the bottom of a try-on photo: what is being worn, and
   where to buy it. Rendered by productTagsHtml() in ig-post.js and only when
   the surface supplies `post.products` (the try-on shop does; nothing else).

   THE SCRIM IS PART OF THE COMPONENT. These sit on an arbitrary photograph, so
   nothing about the pixels underneath can be assumed — a white card on a pale
   studio background would vanish. The gradient behind them is what makes the
   tags legible on any image, and it fades to fully transparent well before the
   middle of the frame so it never reads as a filter over the model.

   Two different colour rules, deliberately:
     - The TAG is an opaque floating surface, like a popover, so it takes the
       surface/ink tokens and flips correctly with the theme.
     - The LABEL is bare text on the scrim, so it takes `--ink-inverse` — the
       token for ink on a dark surface — and stays light in either theme,
       because the scrim it sits on is dark in both. */
.igp-shop {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    padding: 44px 10px 10px;
    background: linear-gradient(to top, rgba(0, 0, 0, 0.72) 0%, rgba(0, 0, 0, 0.45) 45%, rgba(0, 0, 0, 0) 100%);
    pointer-events: none;   /* the scrim is decoration; the tags re-enable it */
    z-index: 2;
}
.igp-shop-label {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin: 0 0 7px 2px;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--ink-inverse);
    text-shadow: 0 1px 6px rgba(0, 0, 0, 0.5);
}

/* Several products scroll sideways rather than stacking: a look with four
   pieces would otherwise cover half the picture. The scrollbar is hidden but
   the row stays swipeable, and snap points mean a flick lands on a card. */
.igp-shop-row {
    display: flex;
    gap: 8px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    -ms-overflow-style: none;
    pointer-events: auto;
    padding-bottom: 2px;
}
.igp-shop-row::-webkit-scrollbar { display: none; }

.igp-shop-tag {
    display: flex;
    align-items: center;
    gap: 9px;
    flex: 0 0 auto;
    max-width: 78%;
    scroll-snap-align: start;
    padding: 6px 10px 6px 6px;
    border-radius: 12px;
    background: var(--surface-overlay);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    box-shadow: var(--shadow-md);
    color: var(--ink);
    text-decoration: none;
    line-height: 1.2;
    transition: transform 0.14s ease, background 0.14s ease;
}
.igp-shop-tag:hover {
    background: var(--surface-raised);
    color: var(--ink);
    transform: translateY(-1px);
}
.igp-shop-tag:focus-visible {
    outline: 2px solid var(--ink-inverse);
    outline-offset: 2px;
}
.igp-shop-thumb {
    width: 38px;
    height: 38px;
    flex: 0 0 auto;
    border-radius: 8px;
    overflow: hidden;
    background: var(--surface-sunken);
    display: grid;
    place-items: center;
}
.igp-shop-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.igp-shop-thumb .bi { font-size: 1rem; color: var(--ink-muted); }
.igp-shop-text { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.igp-shop-name {
    font-size: 0.82rem;
    font-weight: 700;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.igp-shop-meta {
    font-size: 0.7rem;
    color: var(--ink-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.igp-shop-tag .bi-arrow-right-short { font-size: 1.15rem; color: var(--ink-muted); flex: 0 0 auto; }

/* A blurred (NSFW-veiled) photo blurs its tags too — they'd otherwise be the
   one sharp thing on a deliberately obscured card. */
.igp-media.is-blurred .igp-shop { display: none; }

@media (prefers-reduced-motion: reduce) {
    .igp-shop-tag { transition: none; }
    .igp-shop-tag:hover { transform: none; }
}

/* Double-tap heart */
.igp-heart-burst {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) scale(0.4);
    font-size: 5rem;
    color: var(--ink);
    opacity: 0;
    pointer-events: none;
    text-shadow: 0 4px 22px rgba(0, 0, 0, 0.16);
}
.igp-heart-burst.animate { animation: igpHeartPop 0.9s ease forwards; }
@keyframes igpHeartPop {
    0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.4); }
    18%  { opacity: 1; transform: translate(-50%, -50%) scale(1.15); }
    36%  { transform: translate(-50%, -50%) scale(0.95); }
    70%  { opacity: 1; transform: translate(-50%, -50%) scale(1); }
    100% { opacity: 0; transform: translate(-50%, -50%) scale(1.05); }
}

/* ── Action row ──────────────────────────────────────────────────────────── */
/* Action row: pill-shaped chips on a subtle rail, rather than a row of naked
   glyphs. Reads as this product's control surface and gives every control a
   full-size touch target on mobile. */
.igp-actions {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 10px 10px 4px;
}
.igp-action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    min-height: var(--igp-tap);
    padding: 0 14px;
    border: 1px solid transparent;
    border-radius: var(--ds-r-pill, 999px);
    background: var(--ds-glass, rgba(0, 0, 0, 0.045));
    color: var(--igp-text-2);
    font-size: 0.82rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease, transform 0.12s ease;
}
.igp-action i { font-size: 1.15rem; line-height: 1; }
@media (hover: hover) {
    .igp-action:hover {
        background: var(--ds-glass-strong, rgba(0, 0, 0, 0.08));
        color: var(--igp-text);
    }
}
.igp-action:active { transform: scale(0.95); }
.igp-action:focus-visible {
    outline: none;
    border-color: var(--igp-accent-light);
}

/* Liked is the one state worth colouring — it's the user's own mark. */
.igp-action-like.liked {
    color: var(--igp-like);
    background: rgba(206, 0, 37, 0.12);
    border-color: rgba(206, 0, 37, 0.28);
}
.igp-action-save { margin-left: auto; }
.igp-action-save.saved { color: var(--igp-accent-light); }
.igp-action-count:empty { display: none; }

/* Like and comment carry counts, so they stay pill-shaped. */
.igp-action-like,
.igp-action-comment { min-width: var(--igp-tap); }

/* "Send to the generation dashboard" — sits at the far end of the row, away
   from like/comment/share, because it LEAVES the feed. */
.igp-action-generate { margin-left: auto; }

/* Icon-only controls stay square so they don't read as lopsided pills. */
.igp-action-generate,
.igp-action-share,
.igp-action-save { padding: 0; width: var(--igp-tap); }

/* ── Likes + caption ─────────────────────────────────────────────────────── */
.igp-caption {
    padding: 8px 16px 14px;
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--igp-text-2);
}
.igp-caption .igp-caption-name { color: var(--igp-text); }
.igp-caption:empty { display: none; }
.igp-caption .igp-caption-name {
    font-weight: 600;
    margin-right: 6px;
}
.igp-comments-link {
    display: block;
    padding: 0 14px 12px;
    background: none;
    border: none;
    color: var(--igp-text-2);
    font-size: 0.8rem;
    text-align: left;
    cursor: pointer;
}
.igp-comments-link:hover { color: var(--igp-text); }

/* ── Status / empty / gate cards ─────────────────────────────────────────── */
.igp-status {
    padding: 14px 12px 6px;
    text-align: center;
    font-size: 0.8rem;
    color: var(--igp-text-2);
}
.igp-empty {
    padding: 48px 20px;
    text-align: center;
    color: var(--igp-text-2);
}
.igp-empty i { font-size: 2rem; display: block; margin-bottom: 12px; color: var(--igp-accent); }
.igp-empty p { margin: 0; font-size: 0.9rem; }
.igp-gate {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 28px 20px;
    text-align: center;
    border: 1px solid var(--igp-border);
    border-radius: 14px;
    background: var(--igp-surface);
    color: var(--igp-text);
}
.igp-gate > i { font-size: 1.8rem; color: var(--ink-soft); }
.igp-gate-btn {
    padding: 9px 20px;
    border: none;
    border-radius: 999px;
    background: var(--igp-accent);
    color: var(--brand-ink);
    font-size: 0.84rem;
    font-weight: 700;
    cursor: pointer;
}
.igp-gate-btn:hover { filter: brightness(1.08); }

/* ============================================================================
   Full-screen "Posts" page (opened by tapping a grid image).
   Same cards, wrapped in an Instagram-style top nav + scroll container.
   ============================================================================ */
.igp-feed-overlay {
    position: fixed;
    inset: 0;
    /* Above the sticky nav/action bar (z-index 1051) but BELOW the live comment
       overlay (2000) so tapping a comment opens the sheet on top of the post. */
    z-index: 1900;
    display: none;
    flex-direction: column;
    background: var(--igp-bg, #f0f0f0);
}
.igp-feed-overlay.open { display: flex; }

.igp-topnav {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 0 0 auto;
    padding: max(8px, env(safe-area-inset-top)) 10px 8px;
    border-bottom: 1px solid var(--igp-border);
    background: var(--igp-bg, #f0f0f0);
}
.igp-topnav-btn {
    width: 38px;
    height: 38px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    border: none;
    border-radius: 999px;
    background: transparent;
    color: var(--igp-text);
    font-size: 1.2rem;
    cursor: pointer;
}
.igp-topnav-btn:hover { background: var(--glass-strong); }
.igp-topnav-titles {
    display: flex;
    flex-direction: column;
    align-items: center;
    flex: 1 1 auto;
    min-width: 0;
    line-height: 1.2;
    /* Keep the title optically centred against the single left button */
    margin-right: 38px;
}
.igp-topnav-title {
    font-size: 1rem;
    font-weight: 700;
    color: var(--igp-text);
}
.igp-topnav-sub {
    font-size: 0.74rem;
    color: var(--igp-text-2);
    max-width: 100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.igp-feed-scroll {
    flex: 1 1 auto;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    padding: 12px 10px calc(28px + env(safe-area-inset-bottom));
}

/* Inside the full-screen page the cards read as one continuous feed */
.igp-feed-overlay .igp-card {
    border-radius: 12px;
}

/* The overlay owns the screen — hide the app's sticky bottom nav under it. */
body.igp-feed-open { overflow: hidden; }
body.igp-feed-open .sticky-bottom-nav,
body.igp-feed-open #stickyBottomNav { display: none !important; }

@media (min-width: 768px) {
    .igp-feed-scroll { padding: 20px 16px 40px; }
    .igp-topnav { padding: 10px 14px; }
}

/* ── Mobile refinement ───────────────────────────────────────────────────────
   On a phone a boxed card inside a padded scroller wastes ~10% of the width and
   makes the media feel small. Go edge-to-edge: square off the side borders and
   let the image span the viewport, keeping the rounded corners only where the
   card actually ends. */
@media (max-width: 599.98px) {
    .igp-feed { gap: 10px; }
    .igp-feed-scroll { padding-left: 0; padding-right: 0; }
    .igp-card {
        border-radius: 0;
        border-left: none;
        border-right: none;
        box-shadow: none;
    }
    .igp-card > .igp-media:last-child {
        border-bottom-left-radius: 0;
        border-bottom-right-radius: 0;
    }
    .igp-card.is-premium {
        /* The gradient border trick needs a box; on mobile mark it with a top
           hairline instead so the card can still go edge-to-edge. */
        background: var(--igp-surface);
        border-top: 1px solid var(--igp-accent);
    }
    .igp-head { padding: 10px 14px; }
    .igp-actions { padding: 8px 8px 2px; gap: 4px; }
    /* Labels off, targets intact: the count still shows next to the heart. */
    .igp-action { padding: 0 12px; }
    .igp-caption { padding: 6px 14px 14px; }
    .igp-menu-list { min-width: 232px; }
}
