// ── Shared scrollable applet list (.applet-list) ───────────────────────────
// In-grid applet partials (My Posts, My Buds, My Notes, My Scrolls, My Games)
// + the dedicated applet-list pages (billbuds, billposts) all wrap items in a
// `<ul class="applet-list">`. The list rules live at top level so the same
// item-entry styling applies in both surfaces; per-context wrappers below
// handle flex sizing so the list scrolls inside its parent's aperture.

.applet-list {
    list-style: none;
    margin: 0;
    padding: 0 0.75rem 0 0;
    min-height: 0;
    overflow-y: auto;

    // Flex-column lets the empty-state entry fill the aperture so it can
    // centre vertically. Fires only when the list is entirely empty —
    // as soon as a real .applet-list-entry lands, layout reverts to the
    // default left-aligned vertical stack.
    &:has(> .applet-list-entry--empty) {
        display: flex;
        flex-direction: column;
    }
}

// Empty-state filler (`No <X> yet.` rows). Centres in any flex-column
// parent — the .applet-list above OR a `display: flex; flex-direction:
// column` applet section directly (e.g. #id_applet_most_recent_scroll
// when no Room has events yet).
.applet-list-entry--empty {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    opacity: 0.6;
    font-style: italic;
    margin: 0;
}

// 3-col applet row — `<title> | <body> | <ts>`. Mirrors post.html's
// `.post-line` grid (`minmax(4rem,auto) 1fr minmax(3rem,auto)`) so the
// rightward ts column lines up across post.html, scroll.html, and every
// applet list. Title gets the project-wide 35char/32+... truncation via
// the `truncate_title` template filter; body is dimmed to 0.6.
.applet-list-entry.row-3col {
    display: grid;
    grid-template-columns: minmax(4rem, auto) 1fr minmax(3rem, auto);
    align-items: baseline;
    gap: 0.5rem;
    padding-left: 0.5rem;
    padding-right: 0.5rem;
    border-radius: 0.25rem;
    transition: background-color 0.12s ease, color 0.12s ease;

    .row-title {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .row-body {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        opacity: 0.6;
    }

    .row-ts {
        font-size: 0.75rem;
        opacity: 0.5;
        text-align: right;
        white-space: nowrap;
    }

    // Hover (mouse) / click-lock (touch + click persistence) — both states
    // share the highlight. JS in `apps/applets/row-lock.js` toggles
    // `.row-locked` on click; `:hover` is pure CSS. Background to --secUser,
    // title to --quaUser, dimmed body + ts brought to full opacity in
    // --priUser (the back-of-card colour, readable against the --secUser
    // fill).
    &:hover,
    &.row-locked {
        background-color: rgba(var(--secUser), 1);

        .row-title,
        a.row-title { color: rgba(var(--quiUser), 1); text-shadow: none; }

        .row-body,
        .row-ts { color: rgba(var(--priUser), 1); opacity: 1; }
    }
}

.applet-list-entry {
    padding: 0.4rem 0;

    .bud-name { font-weight: bold; opacity: 0.85; }

    a {
        color: rgba(var(--terUser), 1);
        text-decoration: none;
        font-weight: bold;
        transition: text-shadow 0.15s ease;

        &:hover,
        &:active {
            color: rgba(var(--ninUser), 1);
            text-shadow: 0 0 0.55rem rgba(var(--terUser), 0.7);
        }
    }
}

.applet-list-buffer {
    flex-shrink: 0;
    height: 0.5rem;
}

// In-grid applet sections: flex-column so the .applet-list can flex:1
// and scroll within the applet box. Left-aligned items across the
// board (My Games used to centre — symmetrised w. the rest 2026-05-12).

#id_applet_my_posts,
#id_applet_my_buds,
#id_applet_my_scrolls,
#id_applet_notes {
    display: flex;
    flex-direction: column;

    .applet-list {
        flex: 1;
        padding-top: 0.25rem;
    }
}

// ── Shared aperture fill for both billboard pages ──────────────────────────
//
// Aperture foundation (html/body/.container overflow + flex-column +
// .row flex-shrink: 0) now lives universally in _base.scss. Only the
// page-specific `.row { margin-bottom: -1rem }` pull (tightening the
// h2 row against subsequent applet content) stays here, since wallet
// + sky pages deliberately don't carry that pull.

%billboard-page-base {
    flex: 1;
    min-width: 0;
    min-height: 0;
    overflow-y: auto;
    position: relative;
}

body.page-billboard,
body.page-billscroll,
body.page-billpost,
body.page-billbuds,
body.page-billposts {
    .row {
        margin-bottom: -1rem;
    }
}

// ── Billboard page (three-applet grid) ─────────────────────────────────────

.billboard-page {
    @extend %billboard-page-base;
}

// ── Billscroll page (single full-aperture applet) ──────────────────────────

.billscroll-page {
    @extend %billboard-page-base;
    display: flex;
    flex-direction: column;
    padding: 0.75rem;

    // The single scroll applet stretches to fill the remaining aperture
    .applet-scroll {
        @extend %applet-box;
        flex: 1;
        min-height: 0;
        display: flex;
        flex-direction: column;

        #id_drama_scroll {
            flex: 1;
            min-height: 0;
            overflow-y: auto;
            padding-right: 0.75rem;

            .scroll-buffer {
                display: flex;
                justify-content: center;
                align-items: baseline;
                padding: 2rem 0 1rem;
                opacity: 0.4;
                font-size: 0.8rem;
                text-transform: uppercase;

                .scroll-buffer-text {
                    letter-spacing: 0.33em;
                }

                .scroll-buffer-dots {
                    display: inline-flex;
                    letter-spacing: 0;

                    span {
                        display: inline-block;
                        width: 0.7em;
                        text-align: center;
                    }
                }
            }
        }
    }
}

// ── Dashpost page (bottom-anchored thread + composer) ─────────────────────
// Mirrors billscroll's flex-column / overflow-y / scroll-buffer pattern,
// with the composer pinned at the bottom (flex-shrink: 0) so the thread
// breathes against the viewport bottom and the input stays in reach.

.post-page {
    @extend %billboard-page-base;
    display: flex;
    flex-direction: column;
    padding: 0.75rem;
    gap: 0.5rem;

    // Username + title attribution spans — line author column, self/shared
    // header lines, server-rendered grant prose. --quaUser palette key
    // unifies them across the page; placed at .post-page scope so it
    // applies in BOTH .post-header and #id_post_table descendants.
    .post-attribution {
        color: rgba(var(--quaUser), 1);
    }

    .post-header {
        flex-shrink: 0;

        .post-title {
            margin: 0 0 0.25rem;
            font-weight: bold;
        }

        .post-shared-recipients,
        .post-shared-self {
            margin: 0;
            font-size: 0.85rem;
            opacity: 0.75;
        }
    }

    #id_post_table {
        list-style: none;
        margin: 0;
        padding: 0 0.75rem 0 0;
        flex: 1;
        min-height: 0;
        overflow-y: auto;
        display: flex;
        flex-direction: column;
        // Bottom-anchor: scroll buffer above the lines pushes them down
        // until they fill from the bottom; once content exceeds the
        // aperture, normal scrolling kicks in.
        justify-content: flex-end;

        .post-line {
            display: grid;
            grid-template-columns: minmax(4rem, auto) 1fr minmax(3rem, auto);
            align-items: baseline;
            gap: 0.5rem;
            padding: 0.25rem 0;

            .post-line-author {
                font-weight: bold;
                color: rgba(var(--quaUser), 1);
                white-space: nowrap;
                font-size: 0.85rem;
            }

            .post-line-text {
                min-width: 0;
                overflow-wrap: anywhere;
            }

            .post-line-time {
                font-size: 0.75rem;
                opacity: 0.5;
                text-align: right;
                white-space: nowrap;
            }

            // System-authored Lines (adman) get a subtler typographic key
            // — the inline `<a class="note-ref">` carries the emphasis.
            &.post-line--system .post-line-text {
                font-style: italic;
                opacity: 0.85;
            }
        }

        .post-line-buffer {
            flex-shrink: 0;
            height: 0.25rem;
        }
    }

    .post-line-form {
        flex-shrink: 0;
        margin: 0;
        padding-top: 0.25rem;

        input.form-control {
            width: 100%;

            // Admin-Post readonly input — no response is invited, so the
            // focus halo softens to --secUser (cooler than the regular
            // --terUser glow used on user-Post composers).
            &[readonly]:focus {
                border-color: rgba(var(--secUser), 0.6);
                box-shadow: 0 0 0.75rem rgba(var(--secUser), 0.4);
            }
        }
    }
}

// ── Applet-list page (Billbuds, Billposts) ───────────────────────────────
// Shared shell for pages built around _applet-list-shell.html — vertical
// title rotated on the left of an .applet-scroll card + scrollable <ul>
// aperture. `--single` hosts one section (My Buds); `--two-up` stacks
// two sections in portrait, places them side-by-side in landscape (My
// Posts: own + shared).

.applet-list-page {
    @extend %billboard-page-base;
    display: flex;
    flex-direction: column;
    padding: 0.75rem;
    gap: 0.75rem;

    .applet-scroll {
        @extend %applet-box;
        flex: 1;
        min-height: 0;
        display: flex;
        flex-direction: column;

        // .applet-list / .applet-list-entry / .applet-list-buffer rules
        // live at top level (above) so they apply to in-grid applets too.
        .applet-list { flex: 1; }
    }

    // Side-by-side in landscape; stacked in portrait (default).
    &--two-up {
        @media (orientation: landscape) {
            flex-direction: row;
            .applet-scroll { flex: 1; }
        }
    }
}

// ── Billboard applet placement ─────────────────────────────────────────────
// Left column (4-wide): My Scrolls → Contacts → Notes stacked.
// Right column (8-wide): Most Recent Scroll spans full height.
// Portrait override (container query) restores stacked full-width layout.

#id_billboard_applets_container {
    #id_applet_my_scrolls         { grid-column: 1 / span 4; grid-row:  1 / span 3; }
    #id_applet_my_buds        { grid-column: 1 / span 4; grid-row:  4 / span 3; }
    #id_applet_notes              { grid-column: 1 / span 4; grid-row:  7 / span 4; }
    #id_applet_most_recent_scroll { grid-column: 5 / span 8; grid-row:  1 / span 10; }

    @container (max-width: 550px) {
        #id_applet_my_scrolls,
        #id_applet_my_buds,
        #id_applet_notes,
        #id_applet_most_recent_scroll {
            grid-column: 1 / span 12;
            grid-row: span var(--applet-rows, 3);
        }
    }
}

// ── Most Recent Scroll applet — scrollable drama feed ─────────────────────

#id_applet_most_recent_scroll {
    display: flex;
    flex-direction: column;

    .most-recent-room-link {
        flex-shrink: 0;
        margin-bottom: 0.25rem;
        font-weight: bold;
    }

    #id_drama_scroll {
        flex: 1;
        min-height: 0;
        overflow-y: auto;
    }

    .most-recent-load-more {
        display: block;
        padding-bottom: 0.5rem;
        font-size: 0.8rem;
        text-align: center;
    }
}

// ── Drama event entries: 90 / 10 column split ─────────────────────────────

.drama-event {
    display: flex;
    align-items: baseline;

    .drama-event-body {
        flex: 0 0 80%;

        &.struck {
            text-decoration: line-through;
            opacity: 0.5;
        }
    }

    .drama-event-time {
        flex: 0 0 20%;
        font-size: 0.75rem;
        opacity: 0.5;
        text-align: right;
    }
}

// My Scrolls now rides the shared `.applet-list` rule above (lifted out of
// `.applet-list-page .applet-scroll`). Old `.scroll-list` styling removed.

// ── My Sign applet (billboard) ────────────────────────────────────────────
// Saved-sig preview — mirrors the `.sig-stage-card` layout (corner top-
// left + face w. name + arcana + mirror corner bottom-right) but sized
// to fill the applet's vertical aperture rather than a fixed 5rem.
// Container queries on `.my-sign-applet-body` lift `--applet-card-w` to
// `min(100cqi, 62.5cqh)` — the card grows to fill whichever axis is
// constraining (62.5cqh = `100cqh * 5/8` keeps the 5:8 aspect inside
// the container height). All child font sizes calc off --applet-card-w
// so the typography scales w. the card without per-applet tuning.
#id_applet_my_sign {
    display: flex;
    flex-direction: column;
    // Anchor for #id_applet_sky_delete_btn's absolute centering.
    position: relative;
    background-color: rgba(var(--duoUser), 1) !important;
    
    .my-sign-applet-empty {
        opacity: 1 !important;
    }

    h2 {
        flex-shrink: 0;
        background-color: rgba(var(--priUser), 1);
        box-shadow: rgba(0, 0, 0, 1) !important;
    }

    .my-sign-applet-body {
        flex: 1;
        min-height: 0;
        display: flex;
        flex-direction: row;
        align-items: center;
        justify-content: center;
        gap: 0.5rem;
        padding: 0.3rem;
        container-type: size;
    }

    .my-sign-applet-card {
        // Width-cap shrinks by half the row (card + gap + stat-block) so the
        // pair centres without horizontal overflow. `1.0cqi` keeps the
        // gap/padding allowance — anything left after the stat-block grows
        // to fill, capped by the card's natural 5:8 aspect.
        --applet-card-w: min(48cqi, 62.5cqh);
        width: var(--applet-card-w);
        aspect-ratio: 5 / 8;
        border-radius: 0.4rem;
        // Gravity default — `--priUser` bg + `--terUser` ink. `--levity`
        // modifier below inverts to `--secUser` bg + `--quiUser` ink,
        // matching the page stage card's polarity convention (cf
        // `_card-deck.scss:1002-1019` for levity, :1039-1057 for gravity).
        background: rgba(var(--priUser), 1);
        border: 0.12rem solid rgba(var(--secUser), 0.6);

        // Sprint A.6 — image-mode override. `_card-deck.scss` imports before
        // `_billboard.scss`, so the shared `.my-sign-applet-card--image` rule
        // there gets out-cascaded by the base bg/border above (same specificity,
        // later declaration wins). Re-state the transparency here AFTER the
        // base. The contour stroke + depth shadow on the <img> still come
        // from the shared `_card-deck.scss` rule, which only loses on `bg` +
        // `border` properties — not on the filter chain.
        &.my-sign-applet-card--image {
            background: transparent;
            border: 0;
            position: relative;  // anchor for the absolute FLIP btn
        }
        color: rgba(var(--terUser), 1);
        padding: 0.35rem;
        position: relative;
        display: flex;
        flex-direction: column;
        overflow: hidden;
        transition: transform 0.4s ease;

        // Top-left + bottom-right corners — rank + suit icon stacked.
        // br is rotated 180° (mirror) so the card reads as "completed"
        // from both edges, matching the stage card pattern.
        .fan-card-corner--tl,
        .fan-card-corner--br {
            display: flex;
            flex-direction: column;
            align-items: center;
            line-height: 1.05;
            gap: 0.05rem;
            position: absolute;

            .fan-corner-rank {
                font-size: calc(var(--applet-card-w) * 0.16);
                font-weight: 700;
            }
            i { font-size: calc(var(--applet-card-w) * 0.13); }
        }
        .fan-card-corner--tl { top: 0.25rem; left: 0.3rem; }
        .fan-card-corner--br {
            bottom: 0.25rem; right: 0.3rem;
            transform: rotate(180deg);
        }

        // Card face — qualifier + title + arcana stacked, centred in the
        // remaining vertical space between the two corners. `gap: 0` so
        // qualifier sits directly above the title at the title's own
        // line-height; `.fan-card-arcana` carries its own margin-top to
        // restore breathing room between title block and arcana label.
        .fan-card-face {
            flex: 1;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            gap: 0;
            text-align: center;
            padding: 0 0.2rem;
        }

        // Qualifier + title share the same typography (per `_card-deck.scss`
        // convention at lines 568-572 / 1821-1823) — both bold, same size,
        // same wrap, same line-height. Polarity color (gravity → --terUser,
        // levity → --quiUser) lives on the parent — both elements inherit.
        .fan-card-qualifier,
        .fan-card-name {
            margin: 0;
            font-size: calc(var(--applet-card-w) * 0.11);
            font-weight: 700;
            line-height: 1.15;
            text-wrap: balance;
            color: inherit;
        }
        .fan-card-qualifier:empty { display: none; }

        .fan-card-arcana {
            margin: calc(var(--applet-card-w) * 0.05) 0 0;
            font-size: calc(var(--applet-card-w) * 0.075);
            text-transform: uppercase;
            letter-spacing: 0.06em;
            opacity: 0.6;
        }

        // Levity inversion — `--secUser` bg + `--quiUser` ink + `--priUser`
        // border, mirroring `.sig-overlay[data-polarity="levity"]
        // .sig-stage-card` at `_card-deck.scss:1002-1010`.
        &.my-sign-applet-card--levity {
            background: rgba(var(--secUser), 1);
            border-color: rgba(var(--priUser), 0.6);
            color: rgba(var(--quiUser), 1);
            .fan-card-corner { color: rgba(var(--priUser), 0.75); }
            .fan-card-arcana { color: rgba(var(--priUser), 1); }
        }
    }

    // Sprint A.6 — FLIP btn for non-polarized image-equipped decks in the
    // applet. Nested INSIDE the .my-sign-applet-card.--image (which has
    // position: relative) so absolute positioning anchors to the card bounds.
    // Hidden during the rotateY animation via the [data-flipping] hook on
    // the parent card — same pattern as the my_sign page (`_card-deck.scss:889`)
    // and the tarot-fan view (`_card-deck.scss:459`).
    .my-sign-applet-card .my-sign-applet-flip-btn {
        position: absolute;
        z-index: 10;
        bottom: 0.6rem;
        left: 0.6rem;
        margin: 0;
    }
    .my-sign-applet-card[data-flipping] .my-sign-applet-flip-btn {
        opacity: 0;
        pointer-events: none;
    }

    // Stat block — mirrors the stage card's footprint (same 5:8 aspect +
    // height) so the pair reads as a balanced 2-tile composition centred
    // in the applet aperture. Styling cribbed from `.sig-stat-block` in
    // `_card-deck.scss:595-607` (priUser-translucent bg + terUser border)
    // minus the SPIN/FYI button apparatus — applet is read-only, no
    // interaction needed. `--applet-card-w` is reused as the sizing knob
    // so stat-face-label + stat-keywords typography scales w. the card.
    .my-sign-applet-stat-block {
        --applet-card-w: min(48cqi, 62.5cqh);
        width: var(--applet-card-w);
        aspect-ratio: 5 / 8;
        align-self: center;
        // Sprint A.7.5-polish-3 — unified 1.0 alpha across all stat-block surfaces.
        background: rgba(var(--priUser), 1);
        border-radius: 0.4rem;
        border: 0.1rem solid rgba(var(--terUser), 0.15);
        padding: calc(var(--applet-card-w) * 0.08);
        display: flex;
        flex-direction: column;
        overflow: hidden;

        .stat-face-label {
            font-size: calc(var(--applet-card-w) * 0.08);
            text-transform: uppercase;
            letter-spacing: 0.09em;
            opacity: 0.7;
            // Sprint A.7.5 user-spec 2026-05-25 PM — applet sets the convention:
            // EMANATION/REVERSAL label is --secUser so it recedes against the
            // title (--quaUser/--terUser per arcana). Shared mixin + the other
            // 3 stat-block surfaces (sig-stat-block, sea-stat-block, fan-stage-
            // block) updated to match.
            color: rgba(var(--secUser), 1);
            margin: 0;
            // text-decoration dropped in polish-4 — the `.stat-face-header`
            // border-bottom (below) now underscores the whole header unit.
        }

        // Sprint A.7.5-polish-4 — header is a 2-row vertical stack: rank on
        // row 1 (room for long Roman numerals), icon + EMANATION/REVERSAL on
        // row 2 inline. Border-bottom underscores both rows as one header
        // unit, separating it from the title block below. Sized off the
        // applet's `--applet-card-w` container-query var rather than `--sig-
        // card-w`. Mirrors the shared mixin shape; deliberate parallel since
        // applet sizing is independent.
        .stat-face-header {
            display: flex;
            flex-direction: column;
            align-items: flex-start;
            gap: calc(var(--applet-card-w) * 0.015);
            margin: 0 0 calc(var(--applet-card-w) * 0.06);
            padding-bottom: calc(var(--applet-card-w) * 0.035);
            border-bottom: 0.05rem solid rgba(var(--secUser), 0.4);
        }
        .stat-chip-rank {
            font-size: calc(var(--applet-card-w) * 0.12);
            font-weight: bold;
            line-height: 1;
            color: rgba(var(--secUser), 1);
            &:empty { display: none; }
        }
        .stat-chip-tag {
            display: inline-flex;
            align-items: baseline;
            gap: calc(var(--applet-card-w) * 0.04);
            line-height: 1;

            i {
                font-size: calc(var(--applet-card-w) * 0.085);
                color: rgba(var(--secUser), 1);
            }
        }

        // Sprint A.7-polish-3 — title + arcana in applet stat-block per
        // user spec 2026-05-25 PM. Title color keys off the parent's
        // `data-arcana-key` (rendered server-side from `card.arcana`).
        .stat-face-title {
            font-size: calc(var(--applet-card-w) * 0.11);
            font-weight: 700;
            line-height: 1.15;
            margin: 0 0 calc(var(--applet-card-w) * 0.03);
            text-wrap: balance;
            color: rgba(var(--quaUser), 1);
        }
        &[data-arcana-key="MAJOR"] .stat-face-title {
            color: rgba(var(--terUser), 1);
        }
        .stat-face-arcana {
            font-size: calc(var(--applet-card-w) * 0.075);
            text-transform: uppercase;
            letter-spacing: 0.06em;
            opacity: 0.6;
            margin: 0 0 calc(var(--applet-card-w) * 0.06);
        }
        .stat-face-title:empty,
        .stat-face-arcana:empty { display: none; }

        .stat-keywords {
            list-style: none;
            padding: 0;
            margin: 0;

            li {
                font-size: calc(var(--applet-card-w) * 0.1);
                padding: calc(var(--applet-card-w) * 0.04) 0;
                color: rgba(var(--quiUser), 1);
                border-bottom: 0.05rem solid rgba(var(--terUser), 0.18);
                &:last-child { border-bottom: none; }
            }
        }
    }

    // Polarity inversion of the stat block — mirrors the page convention
    // where the stat block always carries the OPPOSITE-polarity colors of
    // its sibling card (`_card-deck.scss:1042-1046` for the gravity case,
    // levity inherits the default --priUser bg). Gravity polarity card →
    // --secUser stat block (light), w. --quiUser label + --priUser
    // keywords for contrast against the light bg.
    .my-sign-applet-body[data-polarity="gravity"] .my-sign-applet-stat-block {
        // Sprint A.7.5-polish-2 — bg override dropped; default 0.5 alpha
        // applies in both polarities now that we've unified opacity across
        // the 4 stat-block surfaces. Border + keyword color overrides kept
        // because they specifically target the gravity card-pair convention.
        border-color: rgba(var(--secUser), 0.15);
        .stat-keywords li {
            color: rgba(var(--secUser), 1);
            border-bottom-color: rgba(var(--secUser), 0.18);
        }
    }

    .my-sign-applet-empty {
        flex: 1;
        display: flex;
        align-items: center;
        justify-content: center;
        text-align: center;
        opacity: 0.6;
        font-style: italic;
        margin: 0;
    }
}
