// ── My Posts applet ──────────────────────────────────────────────────────── #id_applet_my_posts { display: flex; flex-direction: column; .my-posts-container { flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; &::-webkit-scrollbar { display: none; } mask-origin: padding-box; mask-clip: padding-box; mask-image: linear-gradient( to bottom, transparent 0%, black 5%, black 85%, transparent 100% ); } } // ── Shared aperture fill for both billboard pages ────────────────────────── %billboard-page-base { flex: 1; min-width: 0; min-height: 0; overflow-y: auto; position: relative; } html:has(body.page-billboard), html:has(body.page-billscroll), html:has(body.page-billpost) { overflow: hidden; } body.page-billboard, body.page-billscroll, body.page-billpost { overflow: hidden; .container { overflow: hidden; display: flex; flex-direction: column; flex: 1; min-height: 0; } .row { flex-shrink: 0; 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; .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; opacity: 0.75; 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 `` 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); } } } } // ── 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_contacts { 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_contacts, #id_applet_notes, #id_applet_most_recent_scroll { grid-column: 1 / span 12; grid-row: span var(--applet-rows, 3); } } } // ── Notes applet — vertical title ───────────────────────────────────────── #id_applet_notes { h2 { writing-mode: vertical-rl; transform: rotate(180deg); margin: 0; height: 100%; display: flex; align-items: center; justify-content: center; } } // ── 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 list ──────────────────────────────────────────────────────── #id_applet_my_scrolls { .scroll-list { list-style: none; padding: 0; margin: 0; overflow-y: auto; li { padding: 0.25rem 0; border-bottom: 1px solid rgba(var(--priUser), 0.15); &:last-child { border-bottom: none; } a { text-decoration: none; } } } }