/* =========================================================================
    public-profile-tabs.css — Profile tabs on the public profile (domain.com/{username})
    [profile-tabs T05, tech-design §4.1]

    Loaded by resources/views/frontend/new_ui_connect.blade.php immediately after
    public-profile-sections.css, and every rule is scoped under `body.rd-public` so it can never
    reach the editor, the dashboard or any legacy surface. Root `frontend/` is served directly by
    Apache/XAMPP and mirrored into public/ by `php artisan setup:local-assets`.

    Three things this file has to get right:

    1. INACTIVE PANELS STAY LAID OUT. In Tabs mode the panels that are not showing are
       position:absolute + visibility:hidden, and the panel is never taken out of the layout
       entirely. Everything inside a section measures itself at load — the HTML-embed srcdoc posts
       its own height, the gallery masonry reads getBoundingClientRect(), Owl reads its container
       width — and all of that returns 0 in an unrendered subtree. `visibility:hidden` keeps the box
       measurable while removing it from the accessibility tree and from hit testing.
    2. THE DOCKED CHROME IS ONE STACK. On mobile the CTA docks fixed at the top and the tab bar
       sticks directly under it, so the bar's `top` reads the CTA's RENDERED height through
       --pt-cta-h (written by the page's observer script, never hardcoded — the CTA is 76px tall
       normally and 56px in its slim variant, and the notch inset moves both on a notched phone).
    3. THE BAR HAS NO SURFACE AT REST. A profile can carry a background image, a gradient or a
       colour preset; a bar that painted its own background at rest would cut a band across it.
       The frost only appears once `.is-stuck` says the bar has actually docked, and then it uses
       the same surface value as the docked CTA so the two read as one piece of chrome.

    Theme axes (server-rendered <body> classes): .rd-public (always), .rd-dark, .profile-style-glass.
    Accent tinting for the active pill is NOT here — new_ui_connect.blade.php echoes those two rules
    inline from the profile's custom accent (or the WL brand), because only the server knows them.
========================================================================= */

/* ── Tokens ─────────────────────────────────────────────────────────────
   `--pt-active-bg` is the neutral active-pill fill. It is a TAB-OWNED token and deliberately not
   one of the `--swft-*` values `public-profile.css` declares: the mockup (assets/public.css L22)
   defines it as "between --swft-card and --swft-border" precisely BECAUSE no existing token works.
   `--swft-card` (#F1F1F1) is what tech-design §4.1 substituted, and at 1 point of luminance from
   the page's own #F2F4F7 the selected pill disappeared — its unselected white siblings, which carry
   a #D0D5DD border, read as the emphasised ones and the hierarchy inverted. #E6E8EC restores the
   step the mockup drew. Lives here rather than in public-profile.css because nothing outside the
   tab bar consumes it; the dark value is the mockup's L226. Glass overrides the fill with its own
   alpha values further down, so it does not redeclare this. The inline accent echo in
   new_ui_connect.blade.php overrides fill, text and border together with !important and is
   unaffected either way. */
body.rd-public {
    --pt-active-bg: #E6E8EC;
}

body.rd-public.rd-dark {
    --pt-active-bg: #474747;
}

/* ── Panels ─────────────────────────────────────────────────────────────
   The stacking context for the hidden panels. Jump-links and Single stack normally: the panels
   are static and the page scrolls through them. */
body.rd-public .pt-panels {
    position: relative;
}

/* An inactive panel is absolutely positioned but STILL PAINTED (visibility, never display), so its
   full height lands in the wrapper's scrollable-overflow region. A tab whose panel is 4,000px tall
   therefore gave the 200px tab 3,800px of blank scroll — the reader hits the end of the content and
   keeps scrolling through nothing but the docked chrome.

   `overflow: clip` is the fix and `overflow: hidden` is NOT: clip discards the overflow without
   turning the wrapper into a scroll container, so the anchor offset below and every scrollIntoView()
   on a section keep resolving against the document scroller. The bar is a SIBLING of this box (the
   partial is included before it), so its position:sticky is untouched; fixed-position descendants
   (Bootstrap modals inside a section) are laid out against the viewport and are not clipped either.
   The clip margin keeps focus rings and card shadows on the ACTIVE panel from being shaved. Jump
   and Single stack normally and are deliberately left visible. */
body.rd-public .pt-panels[data-mode="tabs"] {
    overflow: clip;
    overflow-clip-margin: 12px;
}

body.rd-public .pt-panels[data-mode="tabs"] .pt-panel[data-active="0"] {
    position: absolute;
    inset-inline-start: 0;
    top: 0;
    width: 100%;
    visibility: hidden;
    pointer-events: none;
}

/* Jump links stacks every group, and `.col-lg-7 .section-panel:first-child { margin-top: 0 }`
   (public-profile-sections.css) now matches once per PANEL instead of once per page — so without
   this the first card of every group after the first butts straight against the previous group's
   last card (0px instead of the 16px every other card gets). Restoring it on the PANEL rather than
   the card keeps the sections stylesheet untouched and stays correct however the builders nest
   their markup: the 16px collapses through the panel's zero-margin first child, and collapses WITH
   a card that already has its own 16px, so the gap is 16px either way. Tabs overlays its panels and
   Single has only one, so both are deliberately excluded. */
body.rd-public .pt-panels[data-mode="jump"] .pt-panel + .pt-panel {
    margin-top: 16px;
}

/* Anchors land below the docked chrome instead of underneath it. --pt-bar-h is written by the
   page script alongside --pt-cta-h. */
body.rd-public .pt-panel,
body.rd-public .section-panel {
    scroll-margin-top: calc(var(--pt-cta-h, 0px) + var(--pt-bar-h, 0px) + 8px);
}

/* ── Bar ────────────────────────────────────────────────────────────────
   z-index sits deliberately UNDER a.public-share-trigger (9000 when fixed ≤767px) — the share
   kebab must stay tappable over the docked bar. */
body.rd-public .pt-sentinel {
    height: 1px;
    margin-top: -1px;
}

/* The CTA's own dock sentinel. 1px, not 0 — a zero-height box gives IntersectionObserver nothing
   to intersect and the dock never fires. It sits directly above .connect-btn on every profile,
   tabbed or not, because the observer replaced the old scroll threshold for all of them. */
body.rd-public .pt-cta-sentinel {
    height: 1px;
    margin-bottom: -1px;
    pointer-events: none;
}

/* The radius lives on the BASE rule, not on `.is-stuck`, so it never animates: `.is-stuck` fades the
   surface in and a radius cannot be interpolated against a box that has none. At rest the bar has no
   surface at all, so the value is inert until the frost arrives.

   ≥992px the bar is the width of the sections column and floats between the profile card above and
   the section cards below — every one of which is `--swft-radius-card`. A square-cornered strip in
   that stack reads as a seam. ≤991.98px it is NOT this shape: it bleeds to the viewport edge and
   pins under the docked CTA as one full-width app header, so the radius is taken back off down
   there (the override lives with the bleed it belongs to, further down). */
body.rd-public .pt-bar {
    position: sticky;
    top: calc(var(--pt-cta-h, 0px) + env(safe-area-inset-top, 0px));
    z-index: 900;
    background: transparent;
    border-radius: var(--swft-radius-card);
    padding: 10px 0;
    margin-bottom: 6px;
    transition: background 160ms ease, box-shadow 160ms ease;
}

body.rd-public .pt-bar.is-stuck {
    background: rgba(255, 255, 255, 0.75);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
}

/* The pills own a stacking context of their own so the frosted bar can never paint over them
   (mockup 01 dev note). No backdrop-filter on the pills themselves — nesting one inside a
   backdrop-filtered parent produces the muddy double blur the mockup review rejected. */
body.rd-public .pt-tabs {
    position: relative;
    z-index: 1;
    display: flex;
    gap: 8px;
    padding: 1px;
    margin: 0;
    list-style: none;
}

body.rd-public .pt-tab {
    flex: none;
    height: 34px;
    padding: 0 14px;
    border-radius: 999px;
    border: 1px solid var(--swft-border);
    background: var(--swft-bg);
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    color: var(--swft-fg1);
    cursor: pointer;
    white-space: nowrap;
    max-width: 220px;
    overflow: hidden;
    text-overflow: ellipsis;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    /* box-shadow is in the list for glass, where the active chip's brighter top rim is half of
       what says "selected" — without it the fill cross-fades while the rim snaps. */
    transition: background 150ms ease, color 150ms ease, border-color 150ms ease, box-shadow 150ms ease;
}

body.rd-public .pt-tab:hover {
    background: var(--swft-bg-page);
}

body.rd-public .pt-tab:focus-visible {
    outline: 2px solid var(--swft-fg1);
    outline-offset: 2px;
}

/* Neutral active state. "Low-key, never solid" — the accent version echoed inline by the blade
   replaces these two values only, so the shape stays identical whatever the accent is. */
body.rd-public .pt-tab.is-active,
body.rd-public .pt-tab[aria-current="true"] {
    background: var(--pt-active-bg);
    color: var(--swft-fg1);
    border-color: var(--pt-active-bg);
    font-weight: 600;
}

/* ── Overflow: scroll on phones, wrap on desktop ────────────────────────
   mask-image has no logical direction keyword, so the RTL case gets an explicit override rather
   than a logical property. Everything else in this file uses logical properties. */
@media (max-width: 991.98px) {
    body.rd-public .pt-tabs {
        overflow-x: auto;
        scrollbar-width: none;
        -webkit-overflow-scrolling: touch;
        scroll-snap-type: x proximity;
        -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent);
        mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent);
    }

    body.rd-public .pt-tabs::-webkit-scrollbar {
        width: 0;
        height: 0;
    }

    body.rd-public .pt-tab {
        scroll-snap-align: start;
    }

    body.rd-public [dir="rtl"].pt-tabs, body.rd-public [dir="rtl"] .pt-tabs {
        -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 32px), transparent);
        mask-image: linear-gradient(to left, #000 calc(100% - 32px), transparent);
    }

    /* The bar bleeds to the card gutter so a scrolled pill row reaches the screen edge. Which is
       exactly why the radius comes back off here: rounded corners sitting ON the viewport edge cut
       four notches out of the top chrome, and the top pair would break the seam with the docked CTA
       that stacks directly above. */
    body.rd-public .pt-bar {
        margin-left: -16px;
        margin-right: -16px;
        padding-left: 16px;
        padding-right: 16px;
        border-radius: 0;
    }
}

@media (min-width: 992px) {
    body.rd-public .pt-tabs {
        flex-wrap: wrap;
        overflow: visible;
        row-gap: 8px;
        -webkit-mask-image: none;
        mask-image: none;
    }
}

/* ── Docked CTA, slim variant ───────────────────────────────────────────
   new_frontend.css declares `.connect-btn.scrolled { padding: 20px 16px }` inside its own ≤767px
   block (→ 76px tall), so the slim override has to live in the same breakpoint and out-specify it.
   45px of top padding is reserved on the following .profile-details for the 76px chrome; with the
   slim CTA that compensation is 20px too tall and the header visibly jumps on docking. */
@media (max-width: 767px) {
    body.rd-public .connect-btn.scrolled.is-slim {
        padding: 10px 16px;
    }

    body.rd-public .connect-btn.scrolled.is-slim + .profile-details {
        padding-top: 25px;
    }
}

/* ── Dark ───────────────────────────────────────────────────────────────
   Solid, not frosted: a blurred translucent panel over the near-black page reads as grey haze
   (mockup README decision 10), so the blur is switched off here — which is exactly why the fill has
   to be OPAQUE. `--pt-bar-bg: #1B1B1B` in the mockup (assets/public.css L228) is the page colour at
   full alpha: turning the blur off while keeping an 0.85 alpha left the bio text plainly legible
   through the docked pill row. The two halves of that decision only work together. */
body.rd-public.rd-dark .pt-bar.is-stuck {
    background: #1B1B1B;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06);
}

/* …and the CTA it docks under has to match, or the stack reads as one opaque strip with one
   see-through strip glued to it. `dark_new_frontend.css` L695-699 paints the docked CTA
   rgba(34,34,34,.75) in this breakpoint; scoped to `.is-slim` (a class only a profile WITH a bar
   ever carries) this leaves every existing dark profile's dock exactly as it was. */
@media (max-width: 767px) {
    body.rd-public.rd-dark .connect-btn.scrolled.is-slim {
        background: #1B1B1B;
    }
}

body.rd-public.rd-dark .pt-tab {
    background: #292929;
    border-color: #3D3D3D;
    color: #F5F5F5;
}

body.rd-public.rd-dark .pt-tab:hover {
    background: #333333;
}

body.rd-public.rd-dark .pt-tab.is-active,
body.rd-public.rd-dark .pt-tab[aria-current="true"] {
    background: var(--pt-active-bg);
    border-color: var(--pt-active-bg);
    color: #FFFFFF;
}

body.rd-public.rd-dark .pt-tab:focus-visible {
    outline-color: #F5F5F5;
}

/* ── Glass ──────────────────────────────────────────────────────────────
   The pills are made of THE SAME MATERIAL as the section cards, not a lookalike. Every other
   surface a glass profile paints — `.col-lg-7 .accordion-item` and the profile card's
   `.content-box::before` in public-profile.css — is a tinted pane with
   `blur(28px) saturate(180%) brightness(1.12)` behind it, a `rgba(255,255,255,0.35)` hairline and a
   soft drop shadow with a bright inset rim along the top edge. The pills previously had NO
   backdrop-filter and no shadow, and in light mode a HIGHER white alpha than the cards
   (0.42 idle / 0.82 active vs the cards' 0.36) with a near-solid 0.55/0.90 border — so a row of flat
   white stickers floated over a frosted page. Matching the card values on all four axes (tint, blur,
   hairline, rim) is what makes the bar read as part of the profile instead of pasted onto it.

   Selection is carried by the MATERIAL, not by an outline: the active chip is a denser pane with a
   brighter top rim, the way the cards catch more light where they face up. The border barely moves.
   That also keeps the inline accent echo in new_ui_connect.blade.php working unchanged — it
   replaces fill/text/border with !important, and the blur + rim underneath still apply, so an
   accent-tinted pill is frosted glass in an accent colour rather than a flat swatch.

   Blur radius is the cards' 28px verbatim. A smaller radius on a 34px chip samples a narrower slice
   of the backdrop and reads as a DIFFERENT material next to a card — which is the whole bug. */
body.rd-public.profile-style-glass .pt-tab {
    background: rgba(255, 255, 255, 0.34);
    border-color: rgba(255, 255, 255, 0.35);
    color: rgba(20, 20, 20, 0.88);
    -webkit-backdrop-filter: blur(28px) saturate(180%) brightness(1.12);
    backdrop-filter: blur(28px) saturate(180%) brightness(1.12);
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.10), inset 0 1px 0 rgba(255, 255, 255, 0.45);
}

body.rd-public.profile-style-glass .pt-tab:hover {
    background: rgba(255, 255, 255, 0.46);
}

body.rd-public.profile-style-glass .pt-tab.is-active,
body.rd-public.profile-style-glass .pt-tab[aria-current="true"] {
    background: rgba(255, 255, 255, 0.62);
    border-color: rgba(255, 255, 255, 0.50);
    color: rgba(20, 20, 20, 0.95);
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.14), inset 0 1px 0 rgba(255, 255, 255, 0.70);
}

/* The docked bar uses the cards' filter too, at its own alpha — chrome, so it sits a step back from
   a content card. The base rule's `0 1px 0 rgba(0,0,0,0.06)` hairline is invisible against a photo;
   a light rim reads on both. */
body.rd-public.profile-style-glass .pt-bar.is-stuck {
    background: rgba(255, 255, 255, 0.30);
    -webkit-backdrop-filter: blur(28px) saturate(180%) brightness(1.12);
    backdrop-filter: blur(28px) saturate(180%) brightness(1.12);
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.30);
}

/* NESTED BACKDROP-FILTERS COMPOUND. A filtered parent's OUTPUT is what the child then samples, so
   once the bar docks and frosts, a pill that also frosts blurs an already-blurred backdrop and both
   go muddy (the double-blur the mockup review rejected — mockup 01 dev note). At rest the bar has no
   surface at all, so the pills own the frost; once `.is-stuck` says the bar has taken it over, they
   hand it back and keep only their tint. The tints stack to roughly the same density either way
   (0.30 bar + 0.34 pill ≈ 0.54), so the chip does not visibly change weight on docking. */
body.rd-public.profile-style-glass .pt-bar.is-stuck .pt-tab {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

/* ── Glass dark ─────────────────────────────────────────────────────────
   POLARITY was the dark-mode bug: every glass surface here is a DARK pane (`rgba(22,22,22,0.45)`),
   and the pills were white-tinted (`rgba(255,255,255,0.08)`) — the one element on the page tinting
   the opposite way, which is why they looked stuck on. They are dark panes now, at a slightly
   lighter alpha than a card so the chrome sits behind the content, and selection reads as MORE
   material (a denser pane + a brighter rim), not as a white ring. */
body.rd-public.profile-style-glass.rd-dark .pt-tab {
    background: rgba(22, 22, 22, 0.38);
    border-color: rgba(255, 255, 255, 0.12);
    color: rgba(255, 255, 255, 0.82);
    -webkit-backdrop-filter: blur(28px) saturate(160%) brightness(0.85);
    backdrop-filter: blur(28px) saturate(160%) brightness(0.85);
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.28), inset 0 1px 0 rgba(255, 255, 255, 0.16);
}

body.rd-public.profile-style-glass.rd-dark .pt-tab:hover {
    background: rgba(22, 22, 22, 0.50);
}

body.rd-public.profile-style-glass.rd-dark .pt-tab.is-active,
body.rd-public.profile-style-glass.rd-dark .pt-tab[aria-current="true"] {
    background: rgba(22, 22, 22, 0.66);
    border-color: rgba(255, 255, 255, 0.22);
    color: rgba(255, 255, 255, 0.98);
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.36), inset 0 1px 0 rgba(255, 255, 255, 0.28);
}

body.rd-public.profile-style-glass.rd-dark .pt-bar.is-stuck {
    background: rgba(22, 22, 22, 0.45);
    -webkit-backdrop-filter: blur(28px) saturate(160%) brightness(0.85);
    backdrop-filter: blur(28px) saturate(160%) brightness(0.85);
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.10);
}

/* ── Reduced motion ─────────────────────────────────────────────────────
   These are the first transitions in frontend/new_css/, and the tab/jump interaction is the first
   scripted smooth scroll on the public page — both opt out here. */
@media (prefers-reduced-motion: reduce) {
    body.rd-public .pt-bar,
    body.rd-public .pt-tab,
    body.rd-public .pt-panel {
        transition: none;
    }

    html {
        scroll-behavior: auto;
    }
}
