/**
 * Party — the stage skin.
 *
 * Ported from stitch_minimalist_web_page_design (2), "STAGE//CORE".
 *
 * Third time with this constraint, so briefly: the mock is a Tailwind CDN
 * build with its own config, this app's tuka.css is a compiled artifact with
 * no build step, and a class that is not already in it renders as nothing at
 * all -- silently. So the design is real CSS.
 *
 * Sibling to battle.css (.bt) and comms.css (.cx). Three files now share a
 * chamfer, a grid and a neon glow, which is one more than is comfortable:
 * the next screen in this language should start by pulling those primitives
 * into one place. They are still apart here because merging means touching
 * two screens that already work, and this one is the biggest of the three.
 *
 * Scoped under `.pt`.
 */

/* ------------------------------------------------------------- tokens */

.pt {
    --pt-bg: #08090d;
    --pt-surface: #0f1016;
    --pt-low: #13141b;
    --pt-card: #181922;
    --pt-high: #22232f;

    --pt-magenta: #ff007f;
    --pt-cyan: #00f0ff;
    --pt-violet: #dcb8ff;
    --pt-gold: #ffcc00;

    /* Per-card accent: border, glow and hype figure all follow it. */
    --pt-accent: var(--pt-magenta);
}

/* ------------------------------------------------------------ surface */

.pt-stage {
    position: relative;
    background-color: var(--pt-bg);
}

.pt-stage::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background-size: 28px 28px;
    background-image:
        linear-gradient(to right, rgba(255, 0, 127, .035) 1px, transparent 1px),
        linear-gradient(to bottom, rgba(0, 240, 255, .025) 1px, transparent 1px);
}

/*
 * Scanlines, at a third of the mock's weight.
 *
 * Same call as on Messages: a 25%-black stripe every 4px is a texture on a
 * poster and a readability problem on a screen full of host names and seat
 * counts. Off entirely for anyone asking for more contrast.
 */
.pt-scan::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 30;
    opacity: .3;
    background: linear-gradient(rgba(18, 16, 26, 0) 50%, rgba(0, 0, 0, .08) 50%);
    background-size: 100% 4px;
}

@media (prefers-contrast: more) {
    .pt-scan::after { display: none; }
}

/* -------------------------------------------------------------- shape */

.pt-chamfer {
    clip-path: polygon(0 0, calc(100% - 7px) 0, 100% 7px,
                       100% 100%, 7px 100%, 0 calc(100% - 7px));
}

.pt-chamfer-md {
    clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 12px,
                       100% 100%, 12px 100%, 0 calc(100% - 12px));
}

/* A tag cut on the trailing edge only. */
.pt-hud-tag { clip-path: polygon(0 0, 100% 0, calc(100% - 8px) 100%, 0 100%); }

/* A full parallelogram. */
.pt-slant   { clip-path: polygon(8px 0, 100% 0, calc(100% - 8px) 100%, 0 100%); }

/* ------------------------------------------------------------ borders */

.pt-edge {
    border: 1px solid color-mix(in srgb, var(--pt-accent) 35%, transparent);
    box-shadow: 0 0 18px color-mix(in srgb, var(--pt-accent) 12%, transparent),
                inset 0 0 14px color-mix(in srgb, var(--pt-accent) 5%, transparent);
}

.pt-edge-gold    { --pt-accent: var(--pt-gold); }
.pt-edge-magenta { --pt-accent: var(--pt-magenta); }
.pt-edge-cyan    { --pt-accent: var(--pt-cyan); }

/* --------------------------------------------------------- typography */

.pt-mono {
    font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
    letter-spacing: .04em;
}

.pt-display {
    font-family: 'Space Grotesk', sans-serif;
    font-weight: 800;
    font-style: italic;
    letter-spacing: -.02em;
}

.pt-hype {
    color: var(--pt-accent);
    text-shadow: 0 0 12px color-mix(in srgb, var(--pt-accent) 55%, transparent);
}

/* ---------------------------------------------------------- mic seats */

/*
 * A seat on stage: portrait, coloured ring, role badge.
 *
 * The ring pulses only for somebody who is actually unmuted. The mock
 * pulses every seat, which makes a silent room look like a busy one --
 * on a screen whose whole job is showing you where the party is, that is
 * the one thing it must not get wrong.
 */
.pt-mic {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .25rem;
    min-width: 0;
}

.pt-mic__ring {
    position: relative;
    display: block;
    padding: 2px;
    border-radius: 9999px;
    background-image: linear-gradient(135deg, var(--pt-accent), transparent 75%);
}

.pt-mic__ring::before {
    content: '';
    position: absolute;
    inset: -3px;
    border-radius: 9999px;
    border: 1px solid var(--pt-accent);
    opacity: 0;
}

.pt-mic--live .pt-mic__ring::before {
    animation: pt-ring 2.2s cubic-bezier(.4, 0, .6, 1) infinite;
}

@keyframes pt-ring {
    0%   { transform: scale(.92); opacity: .95; }
    50%  { transform: scale(1.18); opacity: .2; }
    100% { transform: scale(.92); opacity: .95; }
}

.pt-mic__img {
    display: block;
    width: 100%;
    height: 100%;
    border-radius: 9999px;
    object-fit: cover;
    background: var(--pt-low);
}

/* HOST / CO-HOST / VIP, under the face. */
.pt-role {
    display: block;
    max-width: 100%;
    padding: 1px 6px;
    font-size: 8px;
    line-height: 1.5;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: #000;
    background: var(--pt-accent);
    clip-path: polygon(3px 0, 100% 0, calc(100% - 3px) 100%, 0 100%);
}

/*
 * A muted seat's accent is a dark slate, and the role badge puts black text
 * on the accent -- which on that colour is about 3.5:1 at 8px. The badge
 * gets its own pair.
 */
.pt-role--off {
    background: #334155;
    color: #cbd5e1;
}

/* ------------------------------------------------------- equaliser */

@keyframes pt-eq {
    0%, 100% { height: 4px; }
    50%      { height: 14px; }
}

.pt-eq { display: inline-flex; align-items: flex-end; gap: 2px; height: 14px; }
.pt-eq > i {
    display: block;
    width: 2px;
    height: 4px;
    border-radius: 1px;
    background: currentColor;
    animation: pt-eq .9s ease-in-out infinite;
}
.pt-eq > i:nth-child(1) { animation-duration: .8s; }
.pt-eq > i:nth-child(2) { animation-duration: 1.1s; animation-delay: .2s; }
.pt-eq > i:nth-child(3) { animation-duration: .6s;  animation-delay: .4s; }
.pt-eq > i:nth-child(4) { animation-duration: 1.3s; animation-delay: .1s; }
.pt-eq > i:nth-child(5) { animation-duration: .9s;  animation-delay: .3s; }

/* --------------------------------------------------------- the grid */

/* Two rooms across, which is what the mock does and what 375px allows. */
.pt-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: .625rem;
}

/* Stacked avatars, for the listeners strip. */
.pt-stack { display: flex; }
.pt-stack > * { margin-left: -.4rem; }
.pt-stack > *:first-child { margin-left: 0; }

/* ------------------------------------------------------- progress */

.pt-tier {
    position: relative;
    height: .5rem;
    width: 100%;
    border-radius: 9999px;
    background: #0a0b12;
    border: 1px solid rgba(255, 255, 255, .07);
    overflow: hidden;
}

.pt-tier__fill {
    height: 100%;
    border-radius: 9999px;
    background-image: linear-gradient(to right, #7c3aed, var(--pt-magenta), var(--pt-gold));
    box-shadow: 0 0 12px -2px var(--pt-magenta);
    transition: width .6s cubic-bezier(.2, .9, .3, 1);
}

/* ------------------------------------------------------------ slate */

/* The mock's text ladder, which tuka.css has none of. Scoped, so these
   names still mean nothing anywhere else in the app. */
.pt .text-slate-100 { color: #f1f5f9; }
.pt .text-slate-200 { color: #e2e8f0; }
.pt .text-slate-300 { color: #cbd5e1; }
.pt .text-slate-400 { color: #94a3b8; }
.pt .text-slate-500 { color: #64748b; }
.pt .text-slate-600 { color: #475569; }

.pt .pt-plate     { background-color: var(--pt-card); }
.pt .pt-plate-low { background-color: var(--pt-low); }

/* ------------------------------------------------------- borrowed utils */

/*
 * `no-scrollbar` is used on every horizontal strip in this app and is not
 * in the compiled sheet, so those strips all show a scrollbar. Carried here
 * scoped to `.pt`, which fixes this screen only -- the app-wide version
 * belongs in tuka.css and is worth a separate pass.
 */
.pt .no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
.pt .no-scrollbar::-webkit-scrollbar { display: none; }

/* Same story: `-mx-1` on the country strip resolves to nothing. */
.pt .-mx-1 { margin-left: -.25rem; margin-right: -.25rem; }

/* ------------------------------------------------- the load-more row */

/*
 * `col-span-full` is not in the compiled sheet, and partials/_load_more
 * relies on it: the button is a direct child of #partiesGrid, which is a
 * two-column grid, so without this it takes one cell and sits beside a
 * party card instead of spanning the row.
 */
.pt .col-span-full { grid-column: 1 / -1; }

/* Same partial, same problem: its button asks for a 40px floor. */
.pt .min-h-\[40px\] { min-height: 40px; }

@media (prefers-reduced-motion: reduce) {
    .pt-mic--live .pt-mic__ring::before,
    .pt-eq > i { animation: none; }
    .pt-eq > i { height: 9px; }
    .pt-tier__fill { transition: none; }
}
