/* ============================================================
   S&G PORTAL — standalone styles for the user portal pages.
   Matches the brand colours without depending on the main site's
   assets/ folder (the portal may be accessed before that's set up).
   ============================================================ */

:root {
    /* The portal is dark-only. Telling the UA makes NATIVE chrome dark too: <select> popup
       lists, the colour picker, number spinners, autofill backgrounds and default scrollbars —
       all of which render outside the DOM and so ignore our CSS. */
    color-scheme: dark;
    --bg:       #08080b;
    --surface:  #141418;
    --surface2: #1a1820;
    --surface3: #0f0e13;
    --border:   rgba(255,255,255,.09);
    --border-h: rgba(255,255,255,.17);
    --accent:   #f840c8;
    --accent-d: #c030a0;
    --accent-t: rgba(248,64,200,.12);
    --text:     #e8e0f0;
    --muted:    #9a92a6;
    --dim:      #888095;   /* was #6c6478 (3.27:1 on --surface — failed WCAG AA). Same hue/sat, +11%
                              lightness: 4.87:1 on --surface, 4.66:1 on --surface2, 5.30:1 on --bg.
                              Used ONLY as a text colour, so this is a pure contrast change. */
    --green:    #3ddc84;
    --blue:     #5aa6ff;
    --red:      #ff5b6e;
    --gold:     #ffb454;
    --radius:   14px;
    --radius-s: 8px;
    --pill:     999px;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

body {
    /* Soft magenta/maroon corner glows over a near-black page (the in-world HUD
       skin overrides this back to a flat var(--bg) — see body.is-hud below). */
    background:
        radial-gradient(58% 48% at 100% -6%, rgba(248,64,200,.10), transparent 56%),
        radial-gradient(54% 44% at -6% 106%, rgba(150,24,70,.13), transparent 56%),
        var(--bg);
    background-attachment: fixed;
    color: var(--text);
    font: 400 15px / 1.6 system-ui, -apple-system, 'Segoe UI', sans-serif;
    min-height: 100vh;
}

a                 { color: var(--accent); text-decoration: none; }
a:hover           { text-decoration: underline; }
strong            { font-weight: 600; }

/* ============================================================
   NAV
   ============================================================ */
.pnav {
    background: rgba(19,18,24,.94);
    border-bottom: 1px solid var(--border);
    backdrop-filter: blur(8px);
    padding: 0 28px;
    display: flex; align-items: center; justify-content: space-between;
    height: 56px; position: sticky; top: 0; z-index: 10;
}
.pnav-brand {
    font-weight: 700; font-size: 1rem; letter-spacing: .02em;
    color: var(--text); text-decoration: none !important;
}
.pnav-brand span { color: var(--accent); }
.pnav-user {
    font-size: .82rem; color: var(--muted);
    display: flex; align-items: center; gap: 14px;
}
.pnav-user strong { color: var(--text); }
.pnav-back { font-size: .82rem; color: var(--muted); display: flex; align-items: center; gap: 6px; }
.pnav-back:hover { color: var(--text); text-decoration: none !important; }

/* ============================================================
   LAYOUT
   ============================================================ */
.pwrap      { max-width: 860px; margin: 0 auto; padding: 36px 24px; }
.pwrap-sm   { max-width: 540px; margin: 0 auto; padding: 36px 24px; }
.phead      { margin-bottom: 28px; }
.phead h1   { font-size: 1.4rem; font-weight: 700; }
.phead p    { color: var(--muted); margin-top: 5px; font-size: .9rem; }
.phead-row  { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; }

/* ============================================================
   PANELS
   ============================================================ */
.panel {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 24px;
    margin-bottom: 20px;
}
.panel h2 { font-size: 1rem; font-weight: 600; margin-bottom: 18px; color: var(--text); }

/* ============================================================
   FLASH MESSAGES
   ============================================================ */
.flash {
    border-radius: var(--radius-s); padding: 10px 14px;
    margin-bottom: 18px; font-size: .88rem;
}
.flash.ok  { background: rgba(61,220,132,.10); border: 1px solid rgba(61,220,132,.28); color: var(--green); }
.flash.err { background: rgba(255,91,110,.10); border: 1px solid rgba(255,91,110,.28); color: var(--red); }
/* Pop the flash in so a post-save confirmation reads as an EVENT, not page furniture.
   settings.php adds .is-fading to its own success flash. fill-mode is `backwards`, NOT `both`:
   with `both` the finished animation pins opacity:1 and beats .is-fading's opacity:0 in the
   cascade, so the fade would never be visible. */
.flash { animation: flash-pop .28s ease-out backwards; }
.flash.is-fading { opacity: 0; transition: opacity .6s ease; }
@keyframes flash-pop { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .flash { animation: none; } }

/* ============================================================
   FORMS
   ============================================================ */
.field { margin-bottom: 16px; }
.field label { display: block; font-size: .8rem; color: var(--muted); margin-bottom: 5px; font-weight: 500; }
.field input[type="text"],
.field input[type="password"] {
    width: 100%; padding: 9px 12px;
    background: var(--surface2); border: 1px solid var(--border);
    border-radius: var(--radius-s); color: var(--text); font-size: .9rem;
    outline: none; transition: border-color .18s;
    font-family: inherit;
}
.field input:focus { border-color: var(--accent); }
.hint { font-size: .78rem; color: var(--dim); margin-top: 4px; }
.form-row { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; }
.form-row .field { flex: 1; min-width: 200px; margin-bottom: 0; }

/* ============================================================
   BUTTONS
   ============================================================ */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    padding: 9px 18px; border-radius: var(--pill);
    font-size: .85rem; font-weight: 600;
    border: none; cursor: pointer;
    transition: opacity .18s, background .18s, border-color .18s;
    text-decoration: none !important;
    white-space: nowrap;
}
.btn:hover   { opacity: .82; }
.btn-pink    { background: var(--accent); color: #fff; }
.btn-ghost   { background: transparent; border: 1px solid var(--border); color: var(--text); }
.btn-danger  { background: rgba(255,91,110,.12); border: 1px solid rgba(255,91,110,.28); color: var(--red); }
.btn-sm      { padding: 5px 13px; font-size: .78rem; }
.btn-full    { width: 100%; }

/* ============================================================
   DASHBOARD — stat strip + nav cards
   ============================================================ */
.stat-strip {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 14px;
    margin-bottom: 28px;
}
.stat {
    background: var(--surface2); border: 1px solid var(--border);
    border-radius: var(--radius); padding: 18px 20px; text-align: center;
}
.stat .n { font-size: 2rem; font-weight: 700; color: var(--accent); line-height: 1; }
.stat .l { font-size: .78rem; color: var(--muted); margin-top: 4px; letter-spacing: .02em; }

.nav-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px; }
.nav-card {
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
    padding: 22px; display: block; color: var(--text);
    text-decoration: none !important;
    transition: border-color .2s, transform .2s, box-shadow .2s;
}
.nav-card:hover {
    border-color: var(--accent);
    transform: translateY(-3px);
    box-shadow: 0 10px 28px rgba(248,64,200,.10);
}
.nav-card .nc-icon { font-size: 1.8rem; margin-bottom: 10px; }
.nav-card h3 { font-size: .95rem; font-weight: 600; margin-bottom: 4px; }
.nav-card p  { font-size: .8rem; color: var(--muted); line-height: 1.4; }

/* ============================================================
   BLOCKLIST TABLE
   ============================================================ */
.bl-table { width: 100%; border-collapse: collapse; }
.bl-table th {
    text-align: left; font-size: .72rem; color: var(--dim);
    text-transform: uppercase; letter-spacing: .06em;
    padding-bottom: 10px; border-bottom: 1px solid var(--border);
}
.bl-table td {
    padding: 11px 0; border-bottom: 1px solid var(--border);
    vertical-align: middle; font-size: .88rem;
}
.bl-table tr:last-child td { border-bottom: none; }
.bl-name { font-weight: 500; }
.bl-uuid {
    font-family: 'SFMono-Regular', Consolas, monospace; font-size: .74rem;
    color: var(--dim); word-break: break-all;
}
.bl-date { font-size: .76rem; color: var(--dim); white-space: nowrap; }
.bl-act  { text-align: right; }

.bl-empty { text-align: center; padding: 48px 20px; color: var(--muted); font-size: .9rem; }

/* ============================================================
   PATTERN SLOTS
   ============================================================ */
.slot-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(186px, 1fr));
    gap: 16px;
}
.slot {
    background: var(--surface2); border: 1px solid var(--border);
    border-radius: var(--radius); padding: 18px; text-align: center;
    display: flex; flex-direction: column; gap: 10px;
}
.slot.is-empty { border-style: dashed; }
.slot-num {
    font-size: .7rem; color: var(--dim);
    text-transform: uppercase; letter-spacing: .08em; font-weight: 600;
}
.slot-wave {
    height: 40px; display: flex; align-items: flex-end; justify-content: center;
    gap: 2px; flex-wrap: nowrap; overflow: hidden;
}
.wave-bar { width: 3px; border-radius: 2px; background: var(--accent); min-height: 2px; flex-shrink: 0; }
.slot-empty-msg { height: 40px; display: flex; align-items: center; justify-content: center; color: var(--dim); font-size: .8rem; }
.slot-meta { font-size: .76rem; color: var(--muted); }
.slot-actions { margin-top: auto; }

/* ============================================================
   LOGIN PAGE
   ============================================================ */
.login-shell { max-width: 420px; margin: 72px auto; padding: 0 20px; }
.login-brand { text-align: center; margin-bottom: 32px; }
.login-brand .mark {
    font-size: 1.5rem; font-weight: 700; letter-spacing: .02em;
}
.login-brand .mark .pink { color: var(--accent); }
.login-brand p { font-size: .85rem; color: var(--muted); margin-top: 4px; }

.step-tag {
    font-size: .68rem; color: var(--dim);
    text-transform: uppercase; letter-spacing: .1em; font-weight: 600;
    margin-bottom: 14px;
}

.code-input {
    width: 100%; text-align: center;
    letter-spacing: .3em; font-size: 1.8rem; font-weight: 700;
    padding: 12px 8px; background: var(--surface2);
    border: 1px solid var(--border); border-radius: var(--radius-s);
    color: var(--text); outline: none; font-family: inherit;
    transition: border-color .18s;
}
.code-input:focus { border-color: var(--accent); }

.login-or { text-align: center; font-size: .78rem; color: var(--dim); margin: 10px 0; }

/* ============================================================
   HUB-STYLE LAYOUT — top nav + left sidebar + main column
   (used by dashboard / patterns / blocklist via _header.php)
   ============================================================ */
.ptopnav {
    background: rgba(11,10,14,.92);
    border-bottom: 1px solid var(--border);
    backdrop-filter: blur(8px);
    position: sticky; top: 0; z-index: 30;
}
.ptopnav-inner {
    max-width: none; position: relative;
    height: 54px; padding: 0 22px;
    display: flex; align-items: center; justify-content: center; gap: 6px;
}
.ptopnav-links { display: flex; align-items: center; gap: 4px; }
.ptopnav-links a {
    color: var(--muted); font-size: .78rem; font-weight: 600;
    letter-spacing: .04em; text-transform: uppercase;
    padding: 8px 13px; border-radius: var(--pill);
    display: inline-flex; align-items: center; gap: 7px;
    text-decoration: none !important; transition: color .18s, background .18s;
}
.ptopnav-links a:hover { color: var(--text); background: var(--surface2); }
.ptopnav-actions { position: absolute; right: 22px; display: flex; align-items: center; gap: 10px; }
.pt-contact {
    color: var(--text); font-size: .78rem; font-weight: 600;
    padding: 7px 14px; border-radius: var(--pill); border: 1px solid var(--border);
    display: inline-flex; align-items: center; gap: 7px; text-decoration: none !important;
    transition: border-color .18s;
}
.pt-contact:hover { border-color: var(--accent); }
.pt-hub {
    color: #fff; font-size: .78rem; font-weight: 700;
    padding: 7px 16px; border-radius: var(--pill);
    background: linear-gradient(135deg, var(--accent), var(--accent-d));
    display: inline-flex; align-items: center; gap: 7px; text-decoration: none !important;
    box-shadow: 0 4px 14px rgba(248,64,200,.3); transition: opacity .18s;
}
.pt-hub:hover { opacity: .9; }

.portal-layout {
    display: flex; align-items: flex-start;
    min-height: calc(100vh - 54px);   /* full-width: sidebar sticks to the LEFT edge, main centered below */
}
.portal-sidebar {
    width: 244px; flex: none; align-self: stretch;
    background: var(--surface); border-right: 1px solid var(--border);
    padding: 26px 16px 20px;
    display: flex; flex-direction: column;
    position: sticky; top: 54px; min-height: calc(100vh - 54px);
}
.ps-brand { padding: 0 8px 18px; border-bottom: 1px solid var(--border); margin-bottom: 16px; }
.ps-kicker { font-size: .62rem; font-weight: 700; letter-spacing: .18em; text-transform: uppercase; color: var(--accent); }
.ps-brand h2 { font-size: 1.15rem; font-weight: 700; margin: 6px 0 4px; }
.ps-brand p  { font-size: .75rem; color: var(--muted); }
.ps-nav { display: flex; flex-direction: column; gap: 4px; }
.ps-link {
    display: flex; align-items: center; gap: 11px;
    padding: 10px 13px; border-radius: 10px;
    color: var(--muted); font-size: .9rem; font-weight: 500;
    text-decoration: none !important; transition: background .16s, color .16s;
}
.ps-link i { width: 18px; text-align: center; font-size: .95rem; }
.ps-link:hover { background: var(--surface2); color: var(--text); }
.ps-link.is-active {
    background: linear-gradient(135deg, var(--accent), var(--accent-d));
    color: #fff; box-shadow: 0 4px 14px rgba(248,64,200,.25);
}
.ps-foot { margin-top: auto; padding-top: 18px; }
.ps-user {
    display: flex; align-items: center; gap: 11px;
    background: var(--surface2); border: 1px solid var(--border);
    border-radius: 12px; padding: 10px 12px;
}
.ps-avatar {
    position: relative; width: 36px; height: 36px; flex: none;
    border-radius: 50%; background: var(--surface); overflow: hidden;
    display: flex; align-items: center; justify-content: center; color: var(--dim);
}
.ps-avatar img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.ps-user-meta { display: flex; flex-direction: column; min-width: 0; }
.ps-user-name { font-size: .82rem; font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ps-user-status { font-size: .66rem; color: var(--green); display: flex; align-items: center; gap: 5px; }
.ps-user-status i { font-size: .5rem; }
.ps-logout {
    display: flex; align-items: center; justify-content: center; gap: 8px;
    margin-top: 10px; padding: 9px; border-radius: 10px;
    border: 1px solid var(--border); color: var(--muted);
    font-size: .82rem; font-weight: 600; text-decoration: none !important;
    transition: border-color .16s, color .16s;
}
.ps-logout:hover { border-color: var(--accent); color: var(--text); }

.portal-main { flex: 1 1 auto; min-width: 0; padding: 26px 30px 24px; }
/* Centre the page content within the main column so there's breathing room on the sides
   (the sidebar is pinned hard-left; content sits in the middle of the remaining space). */
.portal-main > * { max-width: 760px; margin-left: auto; margin-right: auto; }

/* Gradient page banner (hub style) */
.dash-banner {
    background: linear-gradient(115deg, var(--accent), #b8308f 52%, #181320);
    border: 1px solid var(--border); border-radius: var(--radius);
    padding: 22px 28px; margin-bottom: 24px;
    display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap;
    box-shadow: 0 12px 34px rgba(248,64,200,.12);
}
.dash-banner h1 { font-size: 1.6rem; font-weight: 800; color: #fff; display: flex; align-items: center; gap: 12px; }
.dash-banner p  { color: #fff; font-size: .88rem; }   /* .85 alpha composited to 2.66:1 on the pink gradient */

/* Hub-style metric cards */
.hub-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px; }
.hub-card {
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
    padding: 22px; display: flex; flex-direction: column;
    text-decoration: none !important; color: var(--text);
    transition: border-color .2s, transform .2s, box-shadow .2s;
}
.hub-card:hover { border-color: var(--border-h); transform: translateY(-3px); box-shadow: 0 14px 30px rgba(0,0,0,.32); }
.hub-card .hc-top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.hub-card .hc-icon { width: 46px; height: 46px; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 1.2rem; }
.hub-card .hc-num { font-size: 2rem; font-weight: 800; line-height: 1; color: var(--text); }
.hub-card h3 { font-size: 1rem; font-weight: 700; margin-bottom: 3px; }
.hub-card .hc-sub { font-size: .82rem; color: var(--muted); line-height: 1.4; }
.hub-card .hc-link { margin-top: 16px; font-size: .82rem; font-weight: 600; color: var(--accent); display: flex; align-items: center; gap: 7px; transition: gap .18s; }
.hub-card:hover .hc-link { gap: 11px; }
.hc-pink  { color: #fff; background: linear-gradient(135deg, #f840c8, #c030a0); }
.hc-green { color: #fff; background: linear-gradient(135deg, #3ddc84, #1f9e60); }
.hc-blue  { color: #fff; background: linear-gradient(135deg, var(--blue), #2f6fd0); }
.hc-gold  { color: #fff; background: linear-gradient(135deg, #ffb454, #d98a2a); }

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width: 860px) {
    .ptopnav-links { display: none; }
    .ptopnav-inner { justify-content: space-between; }

    .portal-layout { flex-direction: column; min-height: 0; }

    /* The sidebar becomes a fixed, app-style bottom tab bar. */
    .portal-sidebar {
        position: fixed; left: 0; right: 0; bottom: 0; top: auto;
        width: auto; min-height: 0; z-index: 40;
        flex-direction: row; align-items: stretch; gap: 0;
        padding: 6px 6px calc(6px + env(safe-area-inset-bottom, 0px));
        border-right: none; border-top: 1px solid var(--border);
        overflow-x: auto;
    }
    .ps-brand, .ps-foot, .ps-group-label { display: none; }   /* no room in a tab bar */
    .ps-link.is-soon { display: none; }                        /* hide coming-soon on mobile */
    /* Flatten the nav/group wrappers so all links are direct, evenly-sized tabs. */
    .ps-nav, .ps-group { display: contents; }
    .ps-link {
        flex: 1 0 auto; min-width: 62px;
        flex-direction: column; gap: 3px; text-align: center;
        padding: 6px 8px; border-radius: 10px; font-size: .62rem; font-weight: 600;
        white-space: nowrap;
    }
    .ps-link i { width: auto; font-size: 1.05rem; }
    .ps-link.is-active { box-shadow: none; }

    /* Main content goes full width and clears the bottom bar. */
    .portal-main { padding: 18px 14px calc(86px + env(safe-area-inset-bottom, 0px)); }

    .dash-banner    { padding: 18px 18px; border-radius: 14px; }
    .dash-banner h1 { font-size: 1.3rem; }
    .hub-cards      { grid-template-columns: 1fr; }            /* stack the cards */
    .panel          { overflow-x: auto; }                      /* wide tables scroll inside */
    .seg-tabs       { overflow-x: auto; flex-wrap: nowrap; }
    .set-actions    { flex-wrap: wrap; }
    /* Tips on a phone / the 380px-wide SL browser: chips must wrap or a long command scrolls. */
    .tip-card       { padding: 12px 14px; gap: 10px; }
    .tip-cmd        { white-space: normal; word-break: break-word; }
    /* Clear the fixed bottom tab bar the sidebar becomes at this breakpoint. */
    .set-actions.is-sticky { bottom: calc(86px + env(safe-area-inset-bottom, 0px)); padding: 10px 12px; }
    .save-state     { flex: 1 1 100%; order: -1; margin-right: 0; }
    .slot-grid      { grid-template-columns: 1fr 1fr; }
}

/* ============================================================
   WEB HUD (body.is-hud) — a FOCUSED phone app, not the full dashboard.
   Sized in vw (a fraction of the screen) so it reads at whatever
   resolution SL renders the media at — px/rem come out tiny because SL
   ignores the viewport width. Home = big product tiles; tap one for that
   product's leaderboard. Everything else stays in the browser dashboard.
   ============================================================ */
body.is-hud { background: var(--bg); }
body.is-hud .ptopnav,
body.is-hud .sgf-root,
body.is-hud .portal-sidebar { display: none; }              /* no site nav, footer, or tab bar */
body.is-hud .portal-layout  { display: block; min-height: 100vh; }
body.is-hud .portal-main    { padding: 0; max-width: none; }
body.is-hud .login-shell    { margin: 16vw auto 0; }

/* iPhone-style status bar — tall enough to clear the rounded top + camera/Island. */
.hud-statusbar { display: none; }
body.is-hud .hud-statusbar {
    display: flex; align-items: flex-end; justify-content: space-between;
    position: fixed; top: 0; left: 0; right: 0; z-index: 60;
    height: 13vw; padding: 0 6vw 2.4vw;
    background: var(--bg); color: var(--text);
    font-size: 4.4vw; font-weight: 700;
}
body.is-hud .hud-clock { font-variant-numeric: tabular-nums; letter-spacing: .02em; }
body.is-hud .hud-icons { display: flex; align-items: center; gap: 2.4vw; font-size: 3.7vw; }

/* The scrolling screen below the status bar. */
.hud-screen { display: none; }
body.is-hud .hud-screen { display: block; padding: 15vw 5vw 9vw; }
body.is-hud .hud-head {
    font-size: 6vw; font-weight: 800; margin: 0 0 1.5vw;
    display: flex; align-items: center; gap: 2.6vw;
}
body.is-hud .hud-head i { color: var(--accent); }
body.is-hud .hud-sub { font-size: 3.7vw; color: var(--muted); margin: 0 0 5vw; }

/* Home: big product tiles. */
body.is-hud .hud-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 4.5vw; }
body.is-hud .hud-tile {
    background: var(--surface); border: 1px solid var(--border); border-radius: 5vw;
    padding: 7vw 3vw; text-decoration: none; color: var(--text);
    display: flex; flex-direction: column; align-items: center; gap: 3vw;
}
body.is-hud .hud-tile:active { border-color: var(--accent); }
body.is-hud .hud-tile .ico { font-size: 13vw; color: var(--accent); line-height: 1; }
body.is-hud .hud-tile .nm  { font-size: 4.6vw; font-weight: 700; text-align: center; }

/* Per-product leaderboard. */
body.is-hud .hud-back { display: inline-flex; align-items: center; gap: 2vw; font-size: 4.2vw; color: var(--accent); text-decoration: none; margin-bottom: 4vw; }
body.is-hud .hud-stats { display: flex; gap: 3.5vw; margin: 1vw 0 6vw; }
body.is-hud .hud-stat { flex: 1; background: var(--surface); border: 1px solid var(--border); border-radius: 4vw; padding: 4.5vw 2vw; text-align: center; }
body.is-hud .hud-stat .n { font-size: 8.5vw; font-weight: 800; color: var(--accent); line-height: 1; }
body.is-hud .hud-stat .l { font-size: 3.2vw; color: var(--muted); margin-top: 1.6vw; letter-spacing: .03em; }
body.is-hud .hud-sec { font-size: 4.6vw; font-weight: 700; margin: 6vw 0 2.5vw; }
body.is-hud .hud-row { display: flex; align-items: center; gap: 3vw; padding: 3.2vw 1vw; border-bottom: 1px solid var(--border); font-size: 4.2vw; }
body.is-hud .hud-row .rk { color: var(--dim); min-width: 6vw; }
body.is-hud .hud-row .nm { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
body.is-hud .hud-row .ct { font-weight: 700; color: var(--accent); white-space: nowrap; }
body.is-hud .hud-empty { color: var(--muted); font-size: 3.8vw; text-align: center; padding: 5vw 0; }

@media (max-width: 600px) {
    .pwrap, .pwrap-sm { padding: 20px 14px; }
    .pnav   { padding: 0 14px; }
    .pnav-user .btn { display: none; } /* only show logout link on mobile */
    .slot-grid { grid-template-columns: 1fr; }
}

/* ============================================================
   DASHBOARD — "coming soon" sidebar items + small badges
   ============================================================ */
.ps-link.is-soon {
    opacity: .55; cursor: default;
}
.ps-link.is-soon:hover { background: none; color: var(--muted); }
.ps-soon {
    margin-left: auto; font-size: .58rem; font-weight: 700;
    letter-spacing: .08em; text-transform: uppercase;
    color: var(--gold); background: rgba(255,180,84,.12);
    border: 1px solid rgba(255,180,84,.28);
    border-radius: var(--pill); padding: 2px 7px;
}
.hub-card.is-soon { opacity: .72; }
.hub-card.is-soon:hover { transform: none; border-color: var(--border); box-shadow: none; }
.hc-badge {
    margin-left: auto; font-size: .6rem; font-weight: 700;
    letter-spacing: .08em; text-transform: uppercase;
    color: var(--gold); background: rgba(255,180,84,.12);
    border: 1px solid rgba(255,180,84,.28);
    border-radius: var(--pill); padding: 3px 9px;
}

/* ============================================================
   SIDEBAR GROUP (folded-in product sub-nav, e.g. Lovense)
   ============================================================ */
.ps-group { margin-top: 16px; }
.ps-group-label {
    font-size: .62rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
    color: var(--dim); padding: 0 13px; margin-bottom: 6px;
}

/* ============================================================
   PER-PRODUCT SETTINGS FORM
   ============================================================ */
.seg-tabs {
    /* Stay on ONE line and scroll sideways if there are more tabs than fit (e.g. the slapper's ~10
       section tabs in the narrower 760px body) instead of wrapping to a second row. */
    display: flex; flex-wrap: nowrap; justify-content: center; justify-content: safe center;
    overflow-x: auto; scrollbar-width: none; gap: 3px; margin-bottom: 18px;   /* see the SCROLLBAR note below */
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--pill); padding: 5px;
}
.seg-tab { flex: 0 0 auto; white-space: nowrap; }
.seg-tab {
    border: none; cursor: pointer; background: transparent; color: var(--muted);
    font-size: .74rem; font-weight: 600; font-family: inherit;
    padding: 7px 11px; border-radius: var(--pill); transition: background .16s, color .16s;
}
.seg-tab:hover { color: var(--text); }
.seg-tab.is-active {
    background: linear-gradient(135deg, var(--accent), var(--accent-d));
    color: #fff;
}
.set-panel { display: none; }
.set-panel.is-active { display: block; }

.set-field {
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius); padding: 18px 20px; margin-bottom: 14px;
}
.set-field-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.set-field-head label { font-size: .92rem; font-weight: 600; color: var(--text); }
.set-val { font-size: .9rem; font-weight: 700; color: var(--accent); font-family: var(--font-mono, monospace); }
.set-help { font-size: .78rem; color: var(--dim); margin-top: 8px; line-height: 1.5; }

.set-range {
    -webkit-appearance: none; appearance: none; width: 100%; height: 5px; margin-top: 14px;
    background: var(--surface2); border-radius: 3px; outline: none;
}
.set-range::-webkit-slider-thumb {
    -webkit-appearance: none; appearance: none; width: 18px; height: 18px; border-radius: 50%;
    background: var(--accent); cursor: pointer; border: 3px solid var(--surface); box-shadow: 0 0 0 1px var(--accent);
}
.set-range::-moz-range-thumb {
    width: 16px; height: 16px; border-radius: 50%; background: var(--accent); cursor: pointer; border: 3px solid var(--surface);
}

.set-select, .set-input {
    width: 100%; margin-top: 12px; padding: 9px 12px;
    background: var(--surface2); border: 1px solid var(--border); border-radius: var(--radius-s);
    color: var(--text); font-size: .9rem; font-family: inherit; outline: none; transition: border-color .18s;
}
.set-select:focus, .set-input:focus { border-color: var(--accent); }
.set-color {
    margin-top: 12px; width: 56px; height: 34px; padding: 2px;
    background: var(--surface2); border: 1px solid var(--border); border-radius: var(--radius-s); cursor: pointer;
}

/* toggle switch */
.set-switch { position: relative; display: inline-block; width: 46px; height: 26px; flex: none; }
.set-switch input { opacity: 0; width: 0; height: 0; }
.set-knob {
    position: absolute; inset: 0; cursor: pointer; border-radius: var(--pill);
    /* OFF state: the track FILL carries no information (--surface2 on a --surface card is 1.05:1),
       so the pill BOUNDARY is the whole component. --border composites to 1.35:1, under WCAG
       1.4.11 3:1 for a UI component boundary. --dim clears 3:1 on both surfaces it appears on. */
    background: var(--surface2); border: 1px solid var(--dim); transition: background .18s, border-color .18s;
}
.set-knob::before {
    content: ""; position: absolute; height: 18px; width: 18px; left: 3px; top: 3px;
    background: var(--muted); border-radius: 50%; transition: transform .18s, background .18s;
}
.set-switch input:checked + .set-knob { background: var(--accent-t); border-color: var(--accent); }
.set-switch input:checked + .set-knob::before { transform: translateX(20px); background: var(--accent); }

.set-actions {
    display: flex; align-items: center; justify-content: flex-end; gap: 12px;
    margin-top: 8px; padding-top: 8px;
}
/* ============================================================
   IN-WORLD TIPS (.tips)
   The "how this works in Second Life" cards settings.php builds from each product's
   'tips' array in products.php. Same surface as .set-field with a pink left spine, so
   they read as guidance rather than as another setting.
   ============================================================ */
.tips { display: flex; flex-direction: column; gap: 10px; margin-bottom: 14px; }
.tip-card {
    display: flex; gap: 13px; align-items: flex-start;
    background: var(--surface); border: 1px solid var(--border);
    border-left: 3px solid var(--accent); border-radius: var(--radius);
    padding: 14px 18px;
}
.tip-ic {
    flex: 0 0 auto; width: 30px; height: 30px; border-radius: 9px;
    display: grid; place-items: center;
    background: var(--accent-t); color: var(--accent); font-size: .82rem;
}
.tip-txt { min-width: 0; }
.tip-t   { font-size: .86rem; font-weight: 700; color: var(--text); }
.tip-b   { font-size: .8rem; color: var(--muted); line-height: 1.55; margin-top: 4px; }
.tip-cmds { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 9px; }
.tip-cmd {
    font-family: 'SFMono-Regular', Consolas, monospace; font-size: .78rem;
    background: var(--surface3); border: 1px solid var(--border); border-radius: 6px;
    padding: 3px 9px; color: var(--accent); white-space: nowrap;
}
.tip-link {
    display: inline-flex; align-items: center; gap: 7px; margin-top: 10px;
    font-size: .78rem; font-weight: 600; color: var(--accent);
    background: var(--accent-t); border: 1px solid rgba(248,64,200,.3);
    border-radius: var(--pill); padding: 6px 13px;
    text-decoration: none !important; transition: background .16s;
}
.tip-link:hover { background: rgba(248,64,200,.2); }

/* Sticky save bar. Keeps Save reachable down a long tab and carries the saved/unsaved readout.
   Sticky, not fixed, so it stays inside the content column. */
.set-actions.is-sticky {
    position: sticky; bottom: 12px; z-index: 5;
    margin-top: 18px; padding: 11px 14px;
    background: rgba(20,20,24,.94);
    -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
    border: 1px solid var(--border); border-radius: var(--radius);
    box-shadow: 0 12px 30px rgba(0,0,0,.42);
}
.set-actions.is-dirty { border-color: rgba(255,180,84,.42); }   /* --gold @ 42% */
.save-state {
    margin-right: auto; display: flex; align-items: center; gap: 7px;
    font-size: .8rem; color: var(--dim); white-space: nowrap;
}
.save-state.is-dirty { color: var(--gold); }
.save-state .dot {
    width: 7px; height: 7px; border-radius: 50%;
    background: var(--gold); box-shadow: 0 0 0 3px rgba(255,180,84,.15);
}
/* Dot the tab holding the unsaved edit — with up to 10 tabs, "something is unsaved" is useless
   without saying where. Scoped to the tablist so a .set-seg pill never gets one. */
.seg-tabs[role=tablist] .seg-tab.has-dirty::after {
    content: ''; display: inline-block; vertical-align: middle;
    width: 6px; height: 6px; margin-left: 6px; border-radius: 50%; background: var(--gold);
}
.seg-tabs[role=tablist] .seg-tab.is-active.has-dirty::after { background: #fff; }

/* ============================================================
   CONFIG-PAGE POLISH (badge / swatch / lsl-vec / cfg / owned-list)
   Banner sync badge + Back button, colour-field preset swatches and
   LSL-vector readout, the read-only "Current configuration" panel,
   and the sidebar "My Products" owned list.
   ============================================================ */

/* Banner: "Connected to SL" / "Linked" / "Not linked yet" badge + Back */
.dash-badge {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: .7rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
    color: var(--green); background: rgba(61,220,132,.14);
    border: 1px solid rgba(61,220,132,.32); border-radius: var(--pill);
    padding: 5px 11px; white-space: nowrap;
}
.dash-badge i { font-size: .5rem; }
.dash-badge.is-stale { color: var(--muted); background: rgba(255,255,255,.06); border-color: var(--border); }
.dash-badge.is-off   { color: var(--dim); background: transparent; border-color: var(--border); }

.dash-back {
    display: inline-flex; align-items: center; gap: 7px;
    font-size: .78rem; font-weight: 600; color: #fff;
    background: rgba(255,255,255,.14); border: 1px solid rgba(255,255,255,.22);
    border-radius: var(--pill); padding: 7px 15px;
    text-decoration: none !important; transition: background .16s;
}
.dash-back:hover { background: rgba(255,255,255,.24); }

.dash-banner-actions {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-left: auto;
}

/* ---- "Waiting for first sync" (settings.php + my-products.php) --------------
   GOLD, never green: product_status can be fresh while product_settings has no row yet —
   sync.php stamps a status row even on a pull that found no settings — so this state is
   "linked but not synced", not "connected". */
.dash-badge.is-wait { color: var(--gold); background: rgba(255,180,84,.12); border-color: rgba(255,180,84,.30); }
.cfg-pill.is-wait   { color: var(--gold); background: rgba(255,180,84,.12); border-color: rgba(255,180,84,.28); }
.hub-card .hc-link.is-wait { color: var(--gold); }   /* match .hub-card .hc-link's specificity */

/* First-run "never synced yet" notice on settings.php. The device is the source of truth
   until it pushes its real config, so the form renders READ-ONLY behind this. */
.sync-wait {
    background: rgba(255,180,84,.07);
    border: 1px solid rgba(255,180,84,.30);
    border-left: 3px solid var(--gold);
    border-radius: var(--radius);
    padding: 18px 20px; margin-bottom: 18px;
}
.sync-wait h2 {
    font-size: .98rem; font-weight: 700; color: var(--gold); margin-bottom: 8px;
    display: flex; align-items: center; gap: 9px;
}
.sync-wait p    { font-size: .85rem; color: var(--muted); line-height: 1.55; }
.sync-wait p b  { color: var(--text); font-weight: 600; }
.sync-wait ol   { margin: 12px 0 0 20px; font-size: .85rem; color: var(--muted); line-height: 1.75; }
.sync-wait ol b { color: var(--text); font-weight: 600; }
.sync-wait .sw-foot {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    margin-top: 14px; padding-top: 12px; border-top: 1px solid rgba(255,180,84,.18);
    font-size: .8rem; color: var(--dim);
}
.sync-wait .sw-txt { margin-right: auto; }          /* push "Check again" to the right edge */
.sync-wait .sw-dot {
    width: 8px; height: 8px; border-radius: 50%; background: var(--gold); flex: none;
    animation: swpulse 1.4s ease-in-out infinite;
}
@keyframes swpulse { 0%, 100% { opacity: .3 } 50% { opacity: 1 } }

/* Read-only field wrapper while we wait for the first sync. The `disabled` attribute does the
   real work (nothing serialises, nothing is focusable); this only makes it LOOK inert. The
   border/min-width/padding clear the fieldset's UA defaults, which the global reset doesn't. */
.set-lock           { border: 0; min-width: 0; padding: 0; }
.set-lock[disabled] { opacity: .5; }

/* Colour field: preset swatches + live LSL-vector readout */
.swatch-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.swatch {
    width: 26px; height: 26px; border-radius: 8px;
    border: 1px solid var(--border); cursor: pointer; padding: 0;
    transition: transform .12s, border-color .12s;
    box-shadow: inset 0 0 0 1px rgba(0,0,0,.25);
}
.swatch:hover { transform: scale(1.08); border-color: var(--border-h); }
.swatch.is-active {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--accent-t), inset 0 0 0 1px rgba(0,0,0,.25);
}

.lsl-vec {
    display: inline-block; margin-top: 12px; padding: 7px 12px;
    background: var(--surface3); border: 1px solid var(--border); border-radius: var(--radius-s);
    font-family: 'SFMono-Regular', Consolas, monospace; font-size: .8rem;
    color: var(--blue); letter-spacing: .02em;
}
.lsl-vec b { color: var(--dim); font-weight: 400; user-select: all; }

/* "Current configuration" read-only panel rows */
.cfg-row {
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    padding: 11px 0; border-bottom: 1px solid var(--border); font-size: .88rem;
}
.cfg-row:last-child { border-bottom: none; }
.cfg-row .cfg-k { color: var(--muted); font-weight: 500; }
.cfg-row .cfg-v { color: var(--text); font-weight: 600; text-align: right; word-break: break-word; }
.cfg-pill {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: .64rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
    color: var(--green); background: rgba(61,220,132,.12);
    border: 1px solid rgba(61,220,132,.28); border-radius: var(--pill); padding: 3px 10px;
}
.cfg-pill.off { color: var(--dim); background: transparent; border-color: var(--border); }
.cfg-swatch {
    display: inline-block; width: 14px; height: 14px; border-radius: 4px;
    border: 1px solid var(--border); vertical-align: -2px; margin-right: 6px;
}

/* Sidebar "My Products" owned-product list */
.ps-count {
    margin-left: 8px; font-size: .58rem; font-weight: 700;
    color: var(--accent); background: var(--accent-t);
    border: 1px solid rgba(248,64,200,.3); border-radius: var(--pill);
    padding: 1px 7px; vertical-align: 1px;
}
.ps-prod {
    display: flex; align-items: center; gap: 11px;
    padding: 9px 13px; border-radius: 10px;
    color: var(--muted); font-size: .86rem; font-weight: 500;
    text-decoration: none !important; transition: background .16s, color .16s;
}
.ps-prod i { width: 18px; text-align: center; font-size: .9rem; }
.ps-prod:hover { background: var(--surface2); color: var(--text); }
.ps-prod.is-active {
    background: linear-gradient(135deg, var(--accent), var(--accent-d));
    color: #fff; box-shadow: 0 4px 14px rgba(248,64,200,.25);
}

/* On the bottom-tab-bar layout the "My Products" primary tab already covers
   mobile, so hide the duplicate per-product list (mirrors .ps-group-label). */
@media (max-width: 860px) {
    .ps-group-myprod, .ps-prod, .ps-count { display: none; }
}

/* ============================================================
   LANDING LEADERBOARD WIDGET
   Compact "Leaderboards" panel on the browser-mode dashboard: a
   product switcher (reuses .seg-tabs visuals), a ranked top-5 list
   with the owner's own row highlighted, and a "Your rank" footer.
   ============================================================ */
.lb-panel-head {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    margin-bottom: 14px;
}
.lb-panel-head h2 { margin-bottom: 0; }

/* reuses .seg-tabs visuals; this only trims the default 18px bottom margin
   so it sits tighter inside the .panel */
.lb-tabs { margin-bottom: 14px; }

.lb-list { display: flex; flex-direction: column; }

.lb-row {
    display: flex; align-items: center; gap: 12px;
    padding: 10px 12px; border-radius: 10px; font-size: .88rem;
    border: 1px solid transparent;
}
.lb-row + .lb-row { margin-top: 2px; }

.lb-rank {
    width: 26px; flex: 0 0 26px; text-align: center;
    font-weight: 700; color: var(--dim); font-variant-numeric: tabular-nums;
}

.lb-name {
    flex: 1 1 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lb-name a { color: var(--accent); text-decoration: none; }
.lb-name a:hover { text-decoration: underline; }

.lb-count {
    flex: 0 0 auto; font-weight: 700; color: var(--accent); font-variant-numeric: tabular-nums;
}

.lb-row.is-you { background: var(--surface2); border-color: var(--border-h); }
.lb-row.is-you .lb-rank { color: var(--accent); }
.lb-row.is-you .lb-you-tag {
    font-size: .66rem; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
    color: #fff; background: linear-gradient(135deg, var(--accent), var(--accent-d));
    padding: 2px 7px; border-radius: var(--pill); margin-left: 8px;
}

.lb-foot {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border);
    font-size: .82rem; color: var(--muted); flex-wrap: wrap;
}
.lb-foot .lb-yourrank strong { color: var(--text); }
.lb-foot a {
    color: var(--accent); text-decoration: none; font-weight: 600;
    display: inline-flex; align-items: center; gap: 6px;
}
.lb-foot a:hover { gap: 9px; }

.lb-empty { text-align: center; padding: 32px 20px; color: var(--muted); font-size: .88rem; }

/* ============================================================
   ACCESS LISTS (global white/blacklist)
   Pills tagging the global whitelist / blacklist panels on
   access-lists.php, plus the read-only "global entries also
   apply here" note shown under the per-product list fields.
   ============================================================ */
.al-pill {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 3px 10px; border-radius: var(--pill);
    font-size: 12px; font-weight: 600;
    border: 1px solid var(--border); color: var(--muted); background: var(--surface3);
}
.al-pill.is-white { color: var(--green); border-color: rgba(61,220,132,.35); background: rgba(61,220,132,.08); }
.al-pill.is-black { color: var(--accent); border-color: rgba(248,64,200,.35); background: rgba(248,64,200,.08); }

.al-scope-note {
    font-size: 12px; color: var(--dim); margin-top: 6px;
    display: flex; align-items: center; gap: 6px;
}

/* --- per-product whitelist / blacklist editor (settings.php 'list' fields) ---
   The <textarea name="whitelist|blacklist"> stays the posted control; JS adds .js-on to hide
   it and drive the rows below. With no JS, .al-raw stays visible and the field behaves exactly
   as it did before. */
.al-editor.js-on .al-raw { display: none; }

.al-add { display: flex; gap: 8px; align-items: center; margin-top: 12px; }
.al-add[hidden] { display: none; }
.al-add .al-add-in {
    margin-top: 0; flex: 1 1 auto; min-width: 0;   /* .set-input carries a margin-top */
    font-family: 'SFMono-Regular', Consolas, monospace; font-size: .8rem;
}
.al-add .al-add-btn { flex: 0 0 auto; }

.al-msg { font-size: .78rem; color: var(--muted); margin-top: 8px; line-height: 1.5; }
.al-msg.is-err { color: var(--red); }
.al-msg[hidden] { display: none; }

.al-none { font-size: .82rem; color: var(--dim); padding: 14px 2px 4px; }
.al-none[hidden] { display: none; }

.al-rows { display: flex; flex-direction: column; gap: 6px; margin-top: 12px; }
.alr {
    display: flex; align-items: center; gap: 10px; padding: 9px 12px;
    background: var(--surface2); border: 1px solid var(--border);
    border-radius: var(--radius-s); transition: border-color .16s;
}
.alr:hover { border-color: var(--border-h); }
.alr.is-global { background: var(--surface3); opacity: .9; }

.alr-main {
    flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px;
    color: inherit; text-decoration: none;
}
.alr-name {
    font-size: .88rem; font-weight: 600; color: var(--text);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.alr-name.is-unknown { color: var(--dim); font-weight: 500; }
.alr-name.is-pending { color: var(--dim); font-weight: 500; font-style: italic; }
.alr-main:hover .alr-name { color: var(--accent); }
.alr-uuid {
    font-family: 'SFMono-Regular', Consolas, monospace; font-size: .68rem;
    color: var(--dim); word-break: break-all;
}

.alr-tag {
    flex: 0 0 auto; font-size: .62rem; font-weight: 700; letter-spacing: .05em;
    text-transform: uppercase; padding: 3px 9px; border-radius: var(--pill);
    color: var(--muted); background: var(--surface); border: 1px solid var(--border);
    text-decoration: none; white-space: nowrap;
}
.alr-tag:hover { color: var(--text); border-color: var(--border-h); }

.alr-x {
    flex: 0 0 auto; display: grid; place-items: center; width: 30px; height: 30px;
    padding: 0; cursor: pointer; background: transparent; color: var(--dim);
    border: 1px solid transparent; border-radius: var(--radius-s); font-size: .95rem;
    transition: color .16s, background .16s, border-color .16s;
}
.alr-x:hover { color: var(--red); background: rgba(255,91,110,.12); border-color: rgba(255,91,110,.28); }

.al-globalhead {
    display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
    margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border);
    font-size: .74rem; font-weight: 600; letter-spacing: .04em;
    text-transform: uppercase; color: var(--dim);
}
.al-globalhead a { margin-left: auto; text-transform: none; letter-spacing: 0; font-size: .76rem; }

.al-down { color: var(--gold); }

@media (max-width: 520px) {
    .al-add { flex-wrap: wrap; }
    .al-add .al-add-btn { width: 100%; }
}

/* ============================================================
   DANGER PANEL (.panel.is-danger)
   Red-tinted border + red heading for destructive zones, e.g. the
   "Delete my data" panel on account.php (lifts its inline overrides).
   ============================================================ */
.panel.is-danger { border-color: rgba(255,91,110,.4); }
.panel.is-danger h2 { color: var(--red); }

/* ============================================================
   PATTERN EDITOR (lifted from lovense-patterns.php)
   The custom-pattern help box, per-slot "Enter values manually"
   expander, and full-width editor/clear buttons.
   ============================================================ */
.help-box { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 18px 20px; margin-bottom: 22px; font-size: .86rem; line-height: 1.65; }
.help-box h2 { font-size: 1rem; margin: 0 0 10px; }
.help-box dl { margin: 0; }
.help-box dt { font-weight: 700; color: var(--accent); margin-top: 12px; }
.help-box dd { margin: 2px 0 0; color: var(--muted); }
.help-box code { font-family: 'SFMono-Regular', Consolas, monospace; font-size: .82rem; background: var(--bg); border: 1px solid var(--border); border-radius: 5px; padding: 1px 6px; color: var(--text); }
.help-ex { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border); }
.help-ex .ex { margin-top: 8px; }
.help-ex .ex b { color: var(--text); }
.slot-edit { margin-top: 10px; }
.slot-edit > summary { cursor: pointer; font-size: .76rem; font-weight: 600; letter-spacing: .03em; color: var(--muted); list-style: none; padding: 6px 0; user-select: none; }
.slot-edit > summary::-webkit-details-marker { display: none; }
.slot-edit > summary::before { content: '✏️ '; }
.slot-edit[open] > summary { color: var(--accent); }
.slot-edit .fe-label { display: block; font-size: .68rem; font-weight: 600; letter-spacing: .05em; text-transform: uppercase; color: var(--dim); margin: 10px 0 4px; }
.slot-edit input[type="text"], .slot-edit input[type="number"] { width: 100%; padding: 8px 10px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; color: var(--text); font-size: .84rem; font-family: 'SFMono-Regular', Consolas, monospace; outline: none; transition: border-color .18s; box-sizing: border-box; }
.slot-edit input:focus { border-color: var(--accent); }
.btn-editor { width: 100%; }
.btn-clear { width: 100%; margin-top: 8px; }

/* ============================================================
   SEGMENTED CONTROL WRAPPER (select fields rendered as pills)
   The buttons themselves reuse the existing .seg-tabs/.seg-tab look;
   this just spaces the pill row away from the field label like the
   other controls (.set-range/.set-select get a 12-14px top margin).
   ============================================================ */
.set-seg { margin-top: 12px; }
/* Segmented buttons fill the row equally (full-width), like the reference Access modes. */
.set-seg .seg-tab { flex: 1 1 0; padding-top: 11px; padding-bottom: 11px; text-align: center; justify-content: center; }

/* ============================================================
   SCROLLBAR — hot pink (brand)
   ============================================================ */
html { scrollbar-width: thin; scrollbar-color: var(--accent) var(--surface); }   /* Firefox */
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: var(--surface); }
::-webkit-scrollbar-thumb {
    background: linear-gradient(var(--accent), var(--accent-d));
    border-radius: var(--pill); border: 3px solid var(--surface);
}
::-webkit-scrollbar-thumb:hover { background: var(--accent); }
::-webkit-scrollbar-corner { background: var(--surface); }

/* The two ROUNDED strips scroll horizontally by design, so the bare global ::-webkit-scrollbar
   above renders a 12px pink bar INSIDE them, sliced by their own border-radius — worst on mobile,
   where a 10-tab slapper strip always overflows a narrow viewport. Suppress it on those two only;
   the page's own pink bar is untouched. (.seg-tabs::-webkit-scrollbar is more specific than the
   bare selector, so it wins regardless of order — but it lives here, next to what it corrects.) */
.portal-sidebar { scrollbar-width: none; }
.seg-tabs::-webkit-scrollbar,
.portal-sidebar::-webkit-scrollbar { display: none; }

/* ============================================================
   EMOJI TEXTURE PICKER (texture fields) — keys only, never the
   owner's preset UUIDs. A grid of preset KEYS plus a "custom UUID"
   box; mirrors the in-world hud.css picker but uses this file's
   tokens. The custom box reuses .set-input (already styled above).
   ============================================================ */
.texemoji { margin-top: 12px; }
.texemoji .tiles { display: flex; flex-wrap: wrap; gap: 8px; }
.texemoji .tile {
    flex: 0 0 calc(20% - 7px); display: flex; align-items: center; justify-content: center;
    aspect-ratio: 1 / 1; padding: 0; cursor: pointer;
    background: var(--surface2); border: 1px solid var(--border); border-radius: var(--radius-s);
    transition: border-color .12s, background .12s, box-shadow .12s;
}
.texemoji .tile:hover { border-color: var(--border-h); background: rgba(255,255,255,.06); }
.texemoji .tile.on { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-t); }
.texemoji .tile .tnm { font-size: 1.4rem; line-height: 1; }
.texemoji .txtrow { margin-top: 10px; }

/* Image-preview multi-select tiles (e.g. slapper comic-word particles) */
.texmulti { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 12px; }
.texmulti .textile {
    flex: 0 0 calc(33.333% - 7px);
    display: flex; flex-direction: column; align-items: center; gap: 7px;
    background: var(--surface2); border: 1px solid var(--border); border-radius: var(--radius-s);
    padding: 12px 10px; cursor: pointer;
    transition: border-color .12s, background .12s, box-shadow .12s;
}
.texmulti .textile input { position: absolute; opacity: 0; pointer-events: none; }
.texmulti .textile img { width: 100%; max-width: 110px; height: 74px; object-fit: contain; display: block; }
.texmulti .textile .tnm2 { font-size: .74rem; font-weight: 700; letter-spacing: .03em; color: var(--muted); }
.texmulti .textile:hover { border-color: var(--border-h); }
.texmulti .textile:has(input:checked) { border-color: var(--accent); background: rgba(248,64,200,.10); box-shadow: 0 0 0 1px var(--accent) inset; }
.texmulti .textile:has(input:checked) .tnm2 { color: var(--text); }
@media (max-width: 560px) { .texmulti .textile { flex-basis: calc(50% - 5px); } }

/* ============================================================
   CHEEK TEXTURE MASK TILES (slapper rednessTexture picker)
   Mirrors the in-world HUD h_tiles preview: each tile reuses the
   .texemoji .tile container (selected state = .texemoji .tile.on,
   tile carries data-texe with the preset KEY — flush/hurt/scratch —
   never a UUID). The inner .cheekmask is a square filled with the
   saved redness colour (--tint) and clipped by the LOCAL white mask
   PNG (--mask, images/<key>.png) so the white shape shows tinted by
   the redness colour, exactly like in-world. No preset UUID ever
   reaches the browser — the mask is a local preview asset.
   ============================================================ */
.texemoji .tile .cheekmask {
    width: 56px; height: 56px; flex: 0 0 auto;
    background: var(--tint, var(--accent));
    -webkit-mask: var(--mask) center / contain no-repeat;
            mask: var(--mask) center / contain no-repeat;
}
.texemoji .tile .cheeknm { margin-top: 6px; font-size: .72rem; font-weight: 700; letter-spacing: .03em; color: var(--muted); }
.texemoji .tile.on .cheeknm { color: var(--text); }
/* The cheek tile stacks the masked square above its label */
.texemoji .tile:has(.cheekmask) { flex-direction: column; gap: 0; }

/* Cheek picker (slapper): the 3 tiles fill the FULL row, each with a large tinted preview inside.
   Scoped to [data-texcheek] so the 9-preset emoji particle picker keeps its 5-per-row grid. */
.texemoji[data-texcheek] .tiles { gap: 12px; }
.texemoji[data-texcheek] .tile { flex: 1 1 0; aspect-ratio: auto; padding: 18px 12px 14px; }
.texemoji[data-texcheek] .tile .cheekmask { width: 100%; height: 120px; }
.texemoji[data-texcheek] .tile .cheeknm { text-transform: capitalize; font-size: .82rem; margin-top: 10px; }

/* ============================================================
   FOCUS VISIBILITY  (WCAG 2.4.7)
   Nothing in this file drew a keyboard focus ring, and five rules actively deleted the
   browser default with `outline: none`.
   THIS BLOCK MUST STAY AT THE END OF THE FILE. `.field input[type="text"]` ties on
   specificity with `.field input:focus-visible`, and the same tie exists for
   `.slot-edit input[type="text"]`, so source order is the only thing making the ring win.
   Move this block up and the login + pattern-editor rings vanish.
   `outline` (not box-shadow) is deliberate: outlines survive Windows High Contrast /
   forced-colors mode, box-shadows are dropped there.
   ============================================================ */
a:focus-visible,
button:focus-visible,
select:focus-visible,
textarea:focus-visible,
input:focus-visible,
summary:focus-visible,
/* These two need the source-order tiebreak described above. */
.field input:focus-visible,
.slot-edit input:focus-visible,
/* The real input is visually hidden here, so ring its visible proxy instead. */
.texmulti .textile:has(input:focus-visible),
.set-switch input:focus-visible + .set-knob {
    /* --accent is 5.74:1 on --surface, 6.25:1 on --bg. The +2px offset puts the ring on the
       CARD, never on the control, so a .swatch's arbitrary user colour is irrelevant. */
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* The 0x0 / opacity:0 inputs behind the switch and the image tiles can never paint a visible
   ring themselves — their proxy is ringed above, so silence them. */
.set-switch input:focus-visible,
.texmulti .textile input:focus-visible { outline: none; }

/* WHITE, INSET ring for every control that can sit on the accent gradient — an accent ring on
   an accent background measures 1.00:1. #fff is 3.20:1 on the gradient's light end, 5.03:1 on
   its dark end and 18.38:1 on an inactive --surface pill, so one colour covers both states.
   INSET because .seg-tabs and the mobile .portal-sidebar are overflow-x:auto, which per spec
   makes overflow-y compute to auto — an outset ring would be clipped by the strip. */
.seg-tab:focus-visible,
.ps-link:focus-visible,
.ps-prod:focus-visible,
.dash-back:focus-visible,
.pt-hub:focus-visible {
    outline: 2px solid #fff;
    outline-offset: -2px;
}

/* The Volume slider: a 5px-tall track needs the ring pushed clear of it. 6px sits inside the
   track's top margin and the gap to .set-help below, and roughly matches the 18px thumb. */
.set-range:focus-visible { outline-offset: 6px; }
