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

        /*
         * Theme palette — literal values copied 1:1 from the c-chat.to
         * forum theme's .ipsButton system (framework.css): the site's real
         * button colors are neutral greys, with green/red reserved for
         * positive/negative outcomes. No invented shades.
         */
        :root {
            /* Tells the browser this UI is intentionally dark, so native
               form controls stay legible under forced/high-contrast modes
               instead of being auto-inverted to a light UA theme. */
            color-scheme: dark;
            --btn-normal: #424242;
            --btn-primary: #484848;
            --btn-important: #646464;
            --btn-positive: #598f5b;
            --btn-intermediate: #f09348;
            --btn-negative: #c75050;
            --btn-light: #353535;
            --btn-text: #dddddd;
            --btn-border: rgba(0, 0, 0, 0.1);
            --btn-hover-overlay: linear-gradient(to bottom, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.08) 100%);
            --btn-active-overlay: linear-gradient(to bottom, rgba(0, 0, 0, 0.2) 0%, rgba(0, 0, 0, 0.2) 100%);
            --btn-active-border: rgba(0, 0, 0, 0.4);
            --btn-radius: 3px;
            --btn-text-shadow: 0 1px 1px rgba(0, 0, 0, 0.4);
            /* .ips-masthead (142px) + .chat-header (52px) — how far down the
               members overlay/backdrop starts, so it opens parallel to the
               header instead of covering it. Redefined for the shorter
               mobile masthead below.
               Texture band raised from 90px to 142px to match the reference
               screenshot's taller masthead (measured proportionally from
               the reference image — texture-only band is 142px tall there
               before the nav bar begins, vs. our old 90px). */
            --header-total-height: 192px;
            /* Actual rendered height of .ads-section, kept in sync by a
               ResizeObserver in the script below (0 there until it's run
               once, and naturally 0 whenever the ads section is hidden, e.g.
               on Reports/Treuhand/DM). Added on top of --header-total-height
               so the members column/backdrop start right where the ad
               banners end instead of overlapping them. */
            --ads-section-height: 0px;
        }

        button,
        input[type="text"], input[type="password"], input[type="number"],
        input[type="email"], input[type="search"], input:not([type]),
        textarea {
            appearance: none;
            -webkit-appearance: none;
            forced-color-adjust: none;
        }

        button:focus-visible {
            outline: 2px solid #6ea8ff;
            outline-offset: 1px;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
            background: #1a1a1a;
            color: #b0b0b0;
            overflow: hidden;
            font-weight: 400;
        }

        .auth-overlay {
            display: flex;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.5);
            /* Was 100 -- lower than .chat-header's 255 (and .members-column's
               250, .news-modal-overlay's 260...). The chrome behind this
               overlay is real, present-in-the-DOM markup even while logged
               out (confirmed: #chatroomTitle/.chat-header render immediately
               on page load, only the overlay's own .hidden class gates the
               app itself), not just inert background -- so wherever the
               centered .auth-modal happened to reach up into the header's
               ~142-192px band (any viewport under roughly 800px tall, e.g.
               1366x768 -- reproduced directly, confirmed nothing
               Tor/Firefox-specific about it), the translucent header
               rendered on top of "Login"/the username field instead of
               behind them, since 100 lost that stacking fight. This overlay
               is the one layer that, by definition, only ever shows before
               login -- every other overlay in this file (toast 500, account
               modal 400, dropdowns/context-menu 300, news modal 260) only
               opens after login, i.e. never actually competes with this one
               for the same screen -- so it can safely sit above all of them
               with room to spare, rather than threading a value between
               .chat-header (255) and .members-column (250) that the next
               unrelated z-index bump could just as easily reopen. */
            z-index: 1000;
            align-items: center;
            justify-content: center;
            padding: 20px;
        }

        .auth-overlay.hidden {
            display: none;
        }

        .auth-modal {
            background: #1a1a1a;
            border: 1px solid #444;
            border-radius: 8px;
            width: 100%;
            max-width: 600px;
            display: flex;
            flex-direction: column;
            max-height: 90vh;
            overflow-y: auto;
        }

        .auth-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px;
            border-bottom: 1px solid #333;
            background: #2d2d2d;
        }

        .auth-header h1 {
            color: #e0e0e0;
            font-size: 20px;
            font-weight: 400;
            margin: 0;
        }

        .auth-body {
            padding: 30px;
            flex: 1;
        }

        .form-group {
            margin-bottom: 25px;
        }

        .hidden {
            display: none !important;
        }

        .form-group.hidden {
            display: none;
        }

        .form-label {
            display: flex;
            align-items: baseline;
            gap: 8px;
            margin-bottom: 8px;
        }

        .form-label label {
            color: #e0e0e0;
            font-weight: 400;
            font-size: 15px;
        }

        .form-required {
            color: #999;
            font-size: 12px;
        }

        .form-description {
            color: #a8a8a8;
            font-size: 12px;
            margin-bottom: 8px;
            line-height: 1.4;
        }

        .form-group input {
            width: 100%;
            padding: 10px 12px;
            background: #2d2d2d;
            border: 1px solid #444;
            border-radius: 4px;
            color: #e0e0e0;
            font-size: 14px;
            font-family: inherit;
            transition: all 0.3s;
        }

        .form-group input:focus {
            outline: none;
            border-color: #666;
            box-shadow: 0 0 8px rgba(102, 102, 102, 0.2);
        }

        /* Cloudflare Turnstile renders its own fixed-width iframe (~300px)
           into this div, while the surrounding inputs above stretch to the
           full, much wider .auth-modal width (max-width: 600px) via
           `width: 100%` -- left to its own devices the widget therefore
           sits flush left with empty space next to it instead of lining up
           under the centered form. Centering the wrapper, not the iframe
           itself (Cloudflare's script owns that element and can re-render
           it), keeps this safe regardless of widget size/state. */
        #turnstileContainer {
            display: flex;
            justify-content: center;
        }

        .auth-button-group {
            padding: 20px 30px;
            border-top: 1px solid #333;
            display: flex;
            gap: 0;
        }

        .btn-submit {
            flex: 1;
            padding: 12px;
            background: transparent;
            color: var(--btn-text);
            border: none;
            border-bottom: 2px solid var(--btn-primary);
            border-radius: 0;
            cursor: pointer;
            font-weight: 700;
            font-size: 14px;
            transition: all 0.2s;
        }

        .btn-submit:hover {
            color: #ffffff;
            background-image: var(--btn-hover-overlay);
            border-bottom-color: var(--btn-important);
        }

        .btn-toggle {
            flex: 1;
            padding: 12px;
            background: transparent;
            color: #666;
            border: none;
            border-bottom: 1px solid #444;
            border-radius: 0;
            cursor: pointer;
            font-weight: 400;
            font-size: 14px;
            transition: all 0.2s;
        }

        .btn-toggle:hover {
            color: #888;
            border-bottom-color: #666;
        }

        .main-container {
            display: flex;
            flex-direction: column;
            height: 100vh;
            height: 100dvh;
            background: #1a1a1a;
        }

        .main-container.hidden {
            display: none;
        }

        .welcome-toast {
            position: fixed;
            top: 16px;
            left: 50%;
            transform: translateX(-50%) translateY(-16px);
            background: #2d2d2d;
            border: 1px solid #555;
            border-radius: 4px;
            padding: 12px 20px;
            color: #e0e0e0;
            font-size: 13px;
            z-index: 500;
            opacity: 0;
            pointer-events: none;
            transition: opacity 0.3s ease, transform 0.3s ease;
            white-space: nowrap;
        }

        .welcome-toast.show {
            opacity: 1;
            transform: translateX(-50%) translateY(0);
        }

        .welcome-toast b {
            color: #fff;
        }

        /* Exact .header-wrap recipe from the c-chat.to custom.css: same
           background-color, same masthead texture, same sizing — but served
           as a local file (public/header-bg.png) instead of the archive.org
           URL, so it loads instantly with no extra external request.
           Stretched to the full masthead+header height, with .chat-header
           living inside it (flexed to the bottom) instead of overlapping it
           from outside — .chat-header's own background is semi-transparent,
           so this texture shows through it directly, no negative-margin/
           z-index tricks needed and nothing fights .chat-main's overflow.

           header-bg.png (?v=2) is the original reference PNG with its last
           ~6px trimmed off: pixel-checked (R==G==B on every one of those
           rows, at every x sampled — real scan grain never lines up that
           perfectly) and confirmed as a synthetic fade-to-black baked into
           the source file's bottom edge, not real texture. Because
           .chat-header sits inside the bottom of this element with only
           ~30% opacity, that fade showed straight through as an unwanted
           dark band across the nav bar instead of blending into whatever
           the real site places below the masthead. Trimming it is a crop,
           not an invented pixel — everything left is untouched original
           texture. */
        .ips-masthead {
            flex: 0 0 auto;
            height: var(--header-total-height);
            background-color: #333333;
            background-image: url('/header-bg.png?v=2');
            background-size: cover;
            background-position: 50% 50%;
            /* box-shadow instead of border-bottom: a real border is part of
               the border-box height, so it was eating 1px off the flex
               content area — .chat-header (flexed to the bottom) ended 1px
               short of where the texture background actually ends, so the
               two edges weren't level with each other. A shadow paints the
               same hairline without consuming any layout height, so both
               now end on the exact same line. */
            box-shadow: 0 1px 0 0 #1a1a1a;
            display: flex;
            flex-direction: column;
            justify-content: flex-end;
            /* Deliberate deviation from "flush with the very bottom edge"
               above, at Björn's request: without this, .chat-header (still
               flex-end aligned) sits exactly on .ips-masthead's own bottom
               edge, so the textured background ends the instant the header
               does -- reads as an abrupt cutoff. This leaves a thin strip
               of that same texture visible below the header instead, for a
               softer transition. --header-total-height below is bumped by
               the same 4px so this comes out of new space, not the
               existing ~142px texture band above the header. */
            padding-bottom: 4px;
        }

        .ips-masthead-logo {
            display: block;
            height: 100%;
            max-height: 90px;
            padding: 10px 16px 10px 0;
            /* .ips-masthead is a column flex container with .chat-header
               below it stretched full-width for its own left/right content
               -- align-self here (only on the logo, not align-items on the
               parent) positions just this element horizontally without
               affecting .chat-header's width.
               At Björn's request (with a marked-up screenshot pointing at
               .chat-header's own left edge) the logo's visible artwork now
               starts exactly where the header BAR itself begins, not where
               the "ChatRoom" text inside it sits -- margin-left mirrors
               .chat-header's own literal margin-left:6% below, and
               padding-left is 0 (dropped the 16px it had before, which
               matched .chat-header's inner text padding -- the wrong
               reference point once the target became the bar's own edge
               instead) so nothing pushes the image in past that edge.
               Vertically, at Björn's request the logo is centered in the
               gap between the masthead's own top edge and .chat-header
               (rather than sitting flush against .chat-header, which is
               what .ips-masthead's justify-content:flex-end would do on
               its own) -- auto top/bottom margins claim 100% of the free
               main-axis space split evenly on both sides of this item
               specifically, which also overrides justify-content for this
               item without needing to touch it (it still governs
               .chat-header, which has no auto margins of its own and
               stays flush at the bottom exactly as before). */
            align-self: flex-start;
            margin-left: 6%;
            margin-top: auto;
            margin-bottom: auto;
        }

        /* FontAwesome 4.7.0 — same version c-chat.to loads (see framework.css's
           @font-face), self-hosted here instead of pulled from their domain, so the
           .ipsMessage_success checkmark below renders with zero extra network request. */
        @font-face {
            font-family: 'FontAwesome';
            src: url('/fonts/fontawesome-webfont.eot?v=4.7.0');
            src: url('/fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'), url('/fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'), url('/fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'), url('/fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'), url('/fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');
            font-weight: normal;
            font-style: normal;
        }

        /* .ipsMessage / .ipsMessage_success / .ipsfocus-globalMessage — literal recipe
           from framework.css cascaded with custom.css's overrides (custom.css loads
           last on the real site, so its values win where both define a property):
             framework.css: border-radius:2px; position:relative; margin-bottom:10px;
                             color:#fff; text-shadow:1px 1px 0 rgba(0,0,0,.1);
                             padding:15px 15px 15px 45px (html[dir="ltr"] .ipsMessage);
                             :before{font-family:FontAwesome;top:15px;left:15px;font-size:20px}
                             .ipsMessage_success{background:#479c87}
                             .ipsMessage_success:before{content:'\f00c'}  (fa-check)
             custom.css:    .ipsMessage{color:#fff;box-shadow:inset rgba(0,0,0,.2) ...;
                             text-shadow:none;border-radius:0} then later overridden again
                             to box-shadow:inset rgba(255,255,255,.1) 0 2px 0 0, inset
                             rgba(255,255,255,.1) 0 -2px 0 0 (last declaration wins)
                             .ipsMessage_success{background:#63aa4e}  (wins over framework's #479c87)
                             .ipsfocus-globalMessage{padding-right:50px} (html[dir='ltr']) */
        .ipsMessage {
            border-radius: 0;
            position: relative;
            margin-bottom: 10px;
            color: #fff;
            text-shadow: none;
            box-shadow: inset rgba(255, 255, 255, 0.1) 0px 2px 0px 0px, inset rgba(255, 255, 255, 0.1) 0px -2px 0px 0px;
            padding: 15px 15px 15px 45px;
        }

        .ipsMessage:before {
            font-family: 'FontAwesome';
            position: absolute;
            top: 15px;
            left: 15px;
            font-size: 20px;
        }

        .ipsMessage a {
            color: #fff;
            border-bottom: 1px dotted #fff;
        }

        .ipsMessage_success {
            background: #63aa4e;
        }

        .ipsMessage_success:before {
            content: '\f00c';
        }

        /* Grey variant for the news modal below — same #545454 custom.css
           assigns to both .ipsMessage_general and .ipsMessage_info/
           _information (framework.css's own #7f858d/#5e95bc get overridden
           the same way .ipsMessage_success's green does), and the same
           fa-info-circle icon framework.css gives both of those classes. */
        .ipsMessage_information {
            background: #545454;
        }

        .ipsMessage_information:before {
            content: '\f05a';
        }

        /* News modal — shown once per login (see login() in the script below)
           instead of sitting inline in the page. Same fixed/centered/dimmed-
           backdrop pattern as .auth-overlay/.auth-modal, just for this. */
        .news-modal-overlay {
            display: flex;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.5);
            z-index: 260;
            align-items: center;
            justify-content: center;
            padding: 20px;
        }

        .news-modal-overlay.hidden {
            display: none;
        }

        .news-modal {
            width: 100%;
            max-width: 600px;
            max-height: 90vh;
            overflow-y: auto;
        }

        .news-modal .ipsMessage {
            margin-bottom: 0;
            padding-right: 50px;
        }

        /* Every line in here is a bare <div> with no default browser
           margin and "normal" (~1.15x) line-height -- fine for the
           original 3 short one-liners, but once items got long enough to
           wrap onto 2 lines, the wrapped line touched the next item's
           first line with zero gap between them, so the whole block read
           as one dense run-on paragraph instead of a list. Line-height
           gives each wrapped item room to breathe internally; the
           per-item margin is what actually separates one point from the
           next regardless of how many lines it wraps to. */
        .news-modal .ipsMessage > div {
            line-height: 1.5;
            margin-bottom: 10px;
        }

        .news-modal .ipsMessage > div:last-child {
            margin-bottom: 0;
        }

        /* first-of-type, not first-child -- .news-modal-close is a
           <button>, not a <div>, so it's the actual first child of
           .ipsMessage and :first-child would never match any div here. */
        .news-modal .ipsMessage > div:first-of-type {
            margin-bottom: 14px;
        }

        /* Same rhythm as the div rule above (line-height for readability,
           margin-bottom to separate this block from the next), just for the
           one bulleted list in here -- ul isn't a div so it needs its own
           copy of that rule rather than being picked up by the selector
           above, and it needs its own reset since <ul> carries browser
           default margin/padding that the divs never had to begin with. */
        .news-modal .ipsMessage > ul {
            margin: 0 0 10px 0;
            padding-left: 20px;
            line-height: 1.5;
        }

        .news-modal .ipsMessage > ul:last-child {
            margin-bottom: 0;
        }

        .news-modal .ipsMessage > ul > li {
            margin-bottom: 4px;
        }

        .news-modal .ipsMessage > ul > li:last-child {
            margin-bottom: 0;
        }

        .news-modal-close {
            position: absolute;
            top: 8px;
            right: 12px;
            background: transparent;
            border: none;
            color: #fff;
            opacity: 0.7;
            font-size: 24px;
            line-height: 1;
            cursor: pointer;
            padding: 4px 8px;
            border-radius: 3px;
        }

        .news-modal-close:hover {
            opacity: 1;
            background-color: rgba(255, 255, 255, 0.15);
        }

        .ipsfocus-globalMessage {
            padding-right: 50px;
            /* Our own spacing choice (not part of the literal reference recipe):
               a bit of breathing room under the header, roughly one text line. */
            margin-top: 18px;
            /* Side inset measured directly off the reference screenshots
               (~6% on each edge, consistent across both the nav bar and this
               box) — so it doesn't run edge-to-edge like the page background
               behind it does. */
            margin-left: 6%;
            margin-right: 6%;
        }

        .ipsfocus-globalMessage p {
            margin: 0 0 0.7em 0;
        }

        .ipsfocus-globalMessage .ipsMessage,
        .ipsfocus-globalMessage p:last-of-type {
            margin: 0;
        }

        .ads-section {
            /* Hidden by default now — only the homepage/main chat view
               (#normalChatContent) should show ads, so Reports, Treuhand
               and DMs get the freed-up vertical space. Re-enabled below
               via :has() when that panel is the visible one. */
            display: none;
            /* Side by side instead of stacked — same combined 970px cap as
               before (see .ad-banner below), just split into two columns
               so the section's total height roughly halves, leaving more
               room for the chat underneath. flex-wrap is a safety net for
               very narrow windows: rather than squeezing both into
               illegibly thin strips, the second one drops to its own row. */
            flex-direction: row;
            flex-wrap: wrap;
            align-items: center;
            justify-content: center;
            gap: 6px;
            padding: 6px 12px;
            /* Same background as the rest of the chat column (.chat-messages,
               .main-container) instead of its own slightly-lighter panel tone. */
            background: #1a1a1a;
            border-bottom: 1px solid #444;
            flex: 0 0 auto;
        }

        .chat-column:has(#normalChatContent:not(.hidden)) .ads-section {
            display: flex;
        }

        .ad-banner {
            flex: 1 1 0;
            /* Half of the original 970px cap (minus half the gap) — the
               same combined width as the single full-width banner before,
               now split two-up. aspect-ratio (unchanged) scales each
               banner's height down to match, so nothing gets stretched or
               cropped differently than before, just rendered smaller. */
            min-width: 160px;
            max-width: 482px;
            aspect-ratio: 970 / 90;
            border-radius: 4px;
            overflow: hidden;
            display: flex;
        }

        .ad-banner a {
            display: block;
            width: 100%;
            height: 100%;
        }

        .ad-banner img {
            width: 100%;
            height: 100%;
            object-fit: cover;
            display: block;
        }

        .ad-banner-placeholder {
            flex: 1 1 0;
            min-width: 160px;
            max-width: 482px;
            aspect-ratio: 970 / 90;
            background: #f5f5f5;
            border: 1px solid #ccc;
            border-radius: 4px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: #333;
            font-size: 14px;
            font-weight: 400;
        }

        .chat-main {
            display: flex;
            flex: 1;
            gap: 0;
            overflow: hidden;
        }

        .chat-column {
            flex: 1;
            display: flex;
            flex-direction: column;
            overflow: hidden;
            /* Only ever actually animates on desktop, where opening/closing
               the members column below toggles margin-right on this — see
               the ".chat-main:has(#membersColumn.mobile-open)" rule. */
            transition: margin-right 0.25s ease;
        }

        .chat-header {
            /* Exact .nav-bar recipe from c-chat.to's custom.css (confirmed via
               DevTools computed styles on the live #ipsLayout_header nav bar):
               a translucent frosted-glass strip — light grey wash + a subtle
               white-to-transparent gradient + backdrop-blur — NOT a solid
               grey gradient. This is what lets the masthead texture show
               through softened/blurred behind the bar, same as the reference. */
            /* Darkened a bit from the literal c-chat.to value (200,200,200)
               at Björn's request -- a deliberate deviation from the 1:1
               extraction above, not a re-measurement of the live site. */
            background: rgba(170, 170, 170, 0.3);
            background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0) 100%);
            box-shadow: inset rgba(255, 255, 255, 0.2) 0px 1px 0px, rgba(0, 0, 0, 0.4) 0px 1px 3px;
            border-radius: 3px;
            text-shadow: rgba(0, 0, 0, 0.6) 0px 1px 2px;
            -webkit-backdrop-filter: blur(10px);
            backdrop-filter: blur(10px);
            /* .ipsNavBar_primary{color:rgba(255,255,255,1);} — pure white. */
            color: #ffffff;
            /* Also thinned a bit (52px -> 46px) at Björn's request -- kept in
               lockstep with --header-total-height above/below (both -6px),
               since that variable is a static estimate of this element's
               real height, not something a ResizeObserver keeps in sync
               (unlike --ads-section-height). */
            min-height: 46px;
            padding: 4px 16px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            flex: 0 0 auto;
            position: relative;
            /* backdrop-filter above implicitly creates a new stacking context
               on this element (per spec, independent of z-index/position) —
               without a z-index of its own, that context has no explicit
               stacking level, so it loses to .chat-main (a later DOM sibling)
               wherever they visually overlap. That's normally invisible, but
               .user-menu/.notif-dropdown hang down from here via
               position:absolute; their z-index:300 only ranks them among
               OTHER children of .chat-header — it can't reach out and beat
               real content in .chat-main. Net effect: a scrolled chat with
               real messages renders on top of the dropdown's top rows and
               silently eats clicks meant for them (e.g. "Account details"),
               even though the dropdown is drawn as if it were on top. Giving
               the header its own z-index lifts its whole stacking context
               (dropdown included) above whatever it needs to beat, closing
               that gap. Must clear .members-column/.members-backdrop
               (240-250, open by default on desktop now) as well as
               .chat-main's plain auto level, but stay below .context-menu/
               .notif-dropdown/.user-menu's own tier (300) and above
               (.news-modal-overlay's 260 included, so an open news modal
               still wins a same-tier DOM-order tie against the header). */
            z-index: 255;
            /* Same ~6% side inset as .ipsfocus-globalMessage, measured off the
               reference screenshots — the bar floats over the full-bleed
               masthead texture instead of touching the page edges. */
            margin-left: 6%;
            margin-right: 6%;
        }

        .chat-header h1 {
            margin: 0;
            /* Same font-size/weight/letter-spacing as .header-reports-btn
               (Reports / Treuhand-Panel) — on the real site the first nav
               item ("Shoutbox") isn't a bigger bold logo either, it's styled
               exactly like every other tab in the row. font-family already
               matched via inheritance from body; font-size/letter-spacing
               were the actual mismatch. */
            font-size: 14px;
            font-weight: 700;
            letter-spacing: normal;
            white-space: nowrap;
            color: #ffffff;
            /* Inherits .chat-header's literal text-shadow (rgba(0,0,0,0.6) 0px 1px 2px)
               instead of its own invented one. */
        }

        #chatroomTitle:before {
            /* True 1:1 reproduction — not a substitute icon. Same real
               FontAwesome 4.7.0 glyph (\f0ac = fa-globe, the exact codepoint
               c-chat.to itself assigns via #elNavSecondary_19), same
               self-hosted @font-face already used above for .ipsMessage_success,
               and the complete literal .ipsNavBar_primary a:before recipe from
               custom.css (font-size/weight, smoothing, transform, spacing,
               opacity, line-height, vertical-align) — nothing approximated. */
            content: '\f0ac';
            font-family: 'FontAwesome';
            font-size: 14px;
            font-weight: normal;
            display: inline-block;
            -webkit-font-smoothing: antialiased;
            -moz-osx-font-smoothing: grayscale;
            transform: translate(0, 0);
            margin-right: 4px;
            opacity: 0.6;
            line-height: 1;
            vertical-align: middle;
        }

        .header-right {
            display: flex;
            align-items: center;
            gap: 12px;
            position: relative;
            flex-shrink: 0;
        }

        .bell-wrap {
            position: relative;
        }

        .bell-btn {
            background: transparent;
            border: none;
            color: #ffffff;
            cursor: pointer;
            padding: 4px 6px;
            position: relative;
            border-radius: 3px;
            transition: background-color 0.2s, box-shadow 0.2s, transform 0.2s;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .bell-btn:hover {
            /* Exact .ipsApp .ipsNavBar_primary > ul > li:hover > a recipe —
               a flat translucent white wash, NOT a restatement of the
               .nav-bar frosted-glass recipe (that combo belongs to the bar
               itself, not to hovering an item inside it). */
            background: rgba(255, 255, 255, 0.08);
            color: #ffffff;
        }

        .bell-btn.active {
            /* Exact .ipsApp .ipsNavBar_primary > ul > li[data-active] > a
               recipe — persistent highlight while this button's page
               (currently only DM) is the one open. */
            background: rgba(255, 255, 255, 0.15);
            color: #ffffff;
        }

        .bell-btn.ringing {
            animation: bellRing 0.6s ease;
        }

        @keyframes bellRing {
            0%, 100% { transform: rotate(0deg); }
            20% { transform: rotate(15deg); }
            40% { transform: rotate(-15deg); }
            60% { transform: rotate(8deg); }
            80% { transform: rotate(-8deg); }
        }

        .bell-badge {
            position: absolute;
            top: -2px;
            right: -2px;
            background: #d63333;
            color: #fff;
            font-size: 9px;
            font-weight: 400;
            min-width: 15px;
            height: 15px;
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 0 3px;
            line-height: 1;
        }

        .notif-dropdown {
            display: none;
            position: absolute;
            top: 100%;
            right: 0;
            margin-top: 8px;
            background: #2d2d2d;
            border: 1px solid #444;
            border-radius: 4px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.8);
            z-index: 300;
            width: 280px;
            max-height: 200px;
            overflow-y: auto;
        }

        .notif-dropdown.active {
            display: block;
        }

        .notif-dropdown-title {
            padding: 10px 14px;
            color: #999;
            font-size: 11px;
            font-weight: 400;
            text-transform: uppercase;
            letter-spacing: 0.5px;
            border-bottom: 1px solid #444;
        }

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

        .notif-item {
            padding: 10px 14px;
            border-bottom: 1px solid #3a3a3a;
            font-size: 12px;
        }

        .notif-item-clickable {
            cursor: pointer;
        }

        .notif-item-clickable:hover {
            background: #2a2a2a;
        }

        .notif-item:last-child {
            border-bottom: none;
        }

        .notif-item-from {
            color: #d0d0d0;
            font-weight: 400;
        }

        .notif-item-type {
            color: #777;
            font-weight: 400;
        }

        .notif-item-preview {
            color: #999;
            margin-top: 2px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .notif-item-time {
            color: #555;
            font-size: 10px;
            margin-top: 4px;
        }

        .notif-empty {
            padding: 20px 14px;
            text-align: center;
            color: #666;
            font-size: 12px;
        }

        .user-menu {
            display: none;
            position: absolute;
            top: 100%;
            right: 0;
            background: #2d2d2d;
            border: 1px solid #444;
            border-radius: 4px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.8);
            z-index: 300;
            min-width: 300px;
            overflow: hidden;
            margin-top: 8px;
        }

        .user-menu.active {
            display: block;
        }

        .user-menu-header {
            padding: 12px;
            border-bottom: 1px solid #444;
            display: flex;
            align-items: center;
            justify-content: flex-start;
            gap: 12px;
            width: 100%;
        }

        .user-menu-avatar {
            width: 32px;
            height: 32px;
            min-width: 32px;
            border-radius: 50%;
            background-size: cover;
            background-position: center;
            border: 1px solid #666;
        }

        .user-menu-name {
            color: #e0e0e0;
            font-size: 13px;
            font-weight: 400;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        .user-menu-section {
            padding: 12px;
            border-bottom: 1px solid #3a3a3a;
        }

        .user-menu-section:last-child {
            border-bottom: none;
        }

        .user-menu-section-title {
            color: #999;
            font-size: 11px;
            font-weight: 400;
            text-transform: uppercase;
            margin-bottom: 8px;
            letter-spacing: 0.5px;
        }

        .user-menu-item {
            padding: 8px 0;
            color: #b0b0b0;
            cursor: pointer;
            font-size: 12px;
            transition: color 0.2s;
        }

        .user-menu-item:hover {
            color: #e0e0e0;
        }

        .user-info {
            display: flex;
            align-items: center;
            gap: 8px;
            cursor: pointer;
        }

        .user-info-avatar {
            width: 24px;
            height: 24px;
            min-width: 24px;
            border-radius: 50%;
            background-size: cover;
            background-position: center;
            border: 1px solid #666;
        }

        .user-info-text {
            display: flex;
            flex-direction: column;
            justify-content: center;
        }

        .user-info-name {
            color: #e0e0e0;
            font-size: 11px;
            font-weight: 400;
            white-space: nowrap;
        }

        .user-info-status {
            display: none;
        }

        .btn-logout {
            padding: 6px 8px;
            background: transparent;
            color: #999;
            border: none;
            border-radius: 0;
            cursor: pointer;
            font-size: 11px;
            transition: all 0.2s;
            font-weight: 400;
        }

        .btn-logout:hover {
            color: #ccc;
        }

        .news-banner {
            flex: 0 0 auto;
            background: rgba(92, 184, 92, 0.06);
            border-bottom: 1px solid #444;
            padding: 10px 16px;
        }

        .news-banner-title {
            display: flex;
            align-items: center;
            gap: 6px;
            color: #7bc47f;
            font-size: 11px;
            font-weight: 400;
            margin-bottom: 3px;
        }

        .news-banner-text {
            color: #999;
            font-size: 12px;
            line-height: 1.5;
        }

        .chat-messages {
            flex: 1;
            overflow-y: auto;
            padding: 16px;
            display: flex;
            flex-direction: column;
            background: #1a1a1a;
        }

        .empty-state {
            text-align: center;
            color: #555;
            margin-top: 60px;
            font-size: 13px;
        }

        .message {
            margin-bottom: 8px;
            display: flex;
            gap: 10px;
            position: relative;
            align-items: center;
        }

        .avatar {
            width: 32px;
            height: 32px;
            min-width: 32px;
            border-radius: 4px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: 400;
            color: white;
            font-size: 14px;
            border: none;
            background-size: cover;
            background-position: center;
            background-repeat: no-repeat;
            cursor: pointer;
        }

        .message-bubble {
            flex: 0 1 auto;
            width: fit-content;
            max-width: 70%;
            padding: 6px 10px;
            border: 1px solid #3a3a3a;
            background: #2d2d2d;
            word-break: break-word;
            border-radius: 2px;
            transition: all 0.3s;
            min-height: 16px;
        }

        .message-right {
            display: flex;
            flex-direction: row;
            align-items: center;
            gap: 6px;
            opacity: 0;
            transition: opacity 0.2s;
            flex-shrink: 0;
        }

        .message:hover .message-right {
            opacity: 1;
        }

        @media (hover: none) {
            .message-right {
                opacity: 1;
            }
        }

        .message-bubble.highlighted {
            background: #3a3a3a;
            border-left-color: #888;
            box-shadow: inset 0 0 8px rgba(136, 136, 136, 0.2);
        }

        .message-info {
            font-size: 9px;
            color: #999;
            margin-bottom: 2px;
        }

        .username {
            color: #888;
            font-weight: 400;
            margin-right: 6px;
            cursor: pointer;
        }

        .message-content {
            margin: 0;
            font-size: 12px;
            color: #b0b0b0;
            line-height: 1.3;
            flex: 1;
        }

        .message-image {
            max-width: 110px;
            max-height: 80px;
            border: 1px solid #444;
            margin-top: 4px;
            border-radius: 2px;
            cursor: pointer;
            display: block;
        }

        .message-video {
            max-width: 260px;
            max-height: 200px;
            border: 1px solid #444;
            margin-top: 4px;
            border-radius: 2px;
            display: block;
            background: #000;
        }

        .audio-card {
            display: flex;
            align-items: center;
            gap: 10px;
            background: #242424;
            border: 1px solid #3a3a3a;
            border-radius: 4px;
            padding: 8px 10px;
            margin-top: 4px;
            max-width: 260px;
        }

        .audio-card-broken {
            opacity: 0.6;
            font-size: 12px;
            color: #777;
        }

        #normalChatContent, #reportsContent, #treuhandContent, #dmContent {
            flex: 1;
            display: flex;
            flex-direction: column;
            min-height: 0;
            overflow: hidden;
        }

        #normalChatContent.hidden, #reportsContent.hidden, #treuhandContent.hidden, #dmContent.hidden {
            display: none;
        }

        .reports-toolbar {
            padding: 10px 16px;
            display: flex;
            align-items: center;
            gap: 12px;
            background: #242424;
            border-bottom: 1px solid #444;
        }

        .reports-toolbar span {
            flex: 1;
            font-size: 13px;
            color: #999;
            letter-spacing: 0.5px;
        }

        .reports-inline-back-btn {
            background: transparent;
            border: none;
            color: #999;
            cursor: pointer;
            font-size: 12px;
            padding: 0 0 10px 0;
            display: block;
            /* <button> defaults to centered text in the browser's UA
               stylesheet — without this override the label centers
               itself even once the button's own box is left-aligned. */
            text-align: left;
            /* .reports-view centers its content children (see below) so
               the report/thread itself stays in the middle of a wide
               window, but the back button opts out of that centering
               and hugs the true left edge — flush under the toolbar's
               "Report(s)" title — instead of following the content. */
            align-self: flex-start;
            width: auto;
            forced-color-adjust: none;
        }

        .reports-inline-back-btn:hover {
            color: #ccc;
        }

        /* Exact .ipsButton_primary / .ipsButton_alternate recipe from
           framework.css: flat #484848, generic hover/active overlays. */
        .reports-new-btn,
        .reports-page-btn,
        .report-primary-btn,
        .profile-dm-btn {
            background-color: var(--btn-primary);
            border: 1px solid var(--btn-border);
            color: var(--btn-text);
            font-weight: 700;
            text-shadow: var(--btn-text-shadow);
            cursor: pointer;
            transition: all 0.1s linear;
        }

        .reports-new-btn:hover,
        .reports-page-btn:hover:not(:disabled),
        .report-primary-btn:hover:not(:disabled),
        .profile-dm-btn:hover {
            background-image: var(--btn-hover-overlay);
        }

        .reports-new-btn:active,
        .reports-page-btn:active:not(:disabled),
        .report-primary-btn:active:not(:disabled),
        .profile-dm-btn:active {
            background-image: var(--btn-active-overlay);
            box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.3) inset;
            border: 1px solid var(--btn-active-border);
        }

        /* Exact .ipsApp .ipsButton_primary recipe (background:#484848;
           color:#dddddd) — same grey used everywhere else in this app
           (New Report, composer submits, profile DM button etc.), swapped
           in from .ipsButton_positive's green. */
        .treuhand-wallet-btn {
            background-color: var(--btn-primary);
            border: 1px solid var(--btn-border);
            color: var(--btn-text);
            font-weight: 700;
            text-shadow: var(--btn-text-shadow);
            cursor: pointer;
            transition: all 0.1s linear;
        }

        .treuhand-wallet-btn:hover {
            background-image: var(--btn-hover-overlay);
        }

        .treuhand-wallet-btn:active {
            background-image: var(--btn-active-overlay);
            box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.3) inset;
            border: 1px solid var(--btn-active-border);
        }

        .reports-new-btn {
            border-radius: 4px;
            padding: 6px 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 18px;
            line-height: 1;
            width: 32px;
            height: 32px;
            forced-color-adjust: none;
        }

        .reports-view {
            flex: 1;
            overflow-y: auto;
            padding: 16px;
            /* Full width now (no max-width/margin:auto here) — the
               720px cap moves to the content children below, via
               align-items:center, so the "← Back to list" button (which
               opts out with align-self:flex-start) can sit flush at the
               true left edge, under the toolbar title, while the actual
               report/thread/form content still appears centered in the
               middle of the page like before. */
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        /* The centered 720px content column — every direct child of a
           reports-view EXCEPT the back button gets it, so list rows,
           thread posts, the composer, create-forms etc. all line up
           in the middle regardless of how wide the window is. */
        .reports-view > *:not(.reports-inline-back-btn) {
            width: 100%;
            max-width: 720px;
        }

        /* Desktop-only: compose-new-DM gets more room than the shared 720px
           Reports/Treuhand column above. On a wide desktop viewport, a form
           stuck at a fixed 720px in the middle of a lot of empty space is
           exactly what read as "off" here -- this widens it further and
           gives the message box a bit more height, using the same >768px
           breakpoint the header/member-list layout already switches on
           (see toggleMobileMembers() in index.html). Scoped to the compose
           screen specifically, since that's the one that was reported as
           broken; the reply composer in #dmDetailView still uses the
           shared 720px width. */
        @media (min-width: 769px) {
            #dmCreateView > *:not(.reports-inline-back-btn) {
                max-width: 900px;
            }
            #dmCreateView .dm-composer-input {
                min-height: 130px;
            }
        }

        .reports-detail-view {
            display: flex;
            flex-direction: column;
            min-height: 0;
            overflow: hidden;
        }

        .reports-detail-view > .reports-inline-back-btn {
            flex-shrink: 0;
        }

        .reports-create-view {
            display: flex;
            flex-direction: column;
            min-height: 0;
        }

        .reports-create-view > .reports-inline-back-btn {
            flex-shrink: 0;
        }

        .reports-create-view > .report-create-form,
        .reports-create-view > .treuhand-claim-result {
            flex: 1;
            display: flex;
            flex-direction: column;
            justify-content: center;
            min-height: 0;
        }

        .reports-create-view > .treuhand-my-withdrawals {
            flex-shrink: 0;
        }

        .reports-list {
            display: flex;
            flex-direction: column;
            gap: 8px;
        }

        .report-card {
            background: #242424;
            border: 1px solid #3a3a3a;
            border-radius: 4px;
            padding: 12px 14px;
            cursor: pointer;
            transition: border-color 0.2s;
        }

        .report-card:hover {
            border-color: #666;
        }

        .report-card-top {
            display: flex;
            justify-content: space-between;
            align-items: baseline;
            margin-bottom: 4px;
        }

        .report-card-target {
            font-size: 13px;
            color: #e0e0e0;
        }

        .report-card-date {
            font-size: 11px;
            color: #777;
        }

        .report-card-desc {
            font-size: 12px;
            color: #999;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .report-card-meta {
            margin-top: 6px;
            font-size: 11px;
            color: #777;
        }

        .reports-empty {
            text-align: center;
            color: #666;
            font-size: 13px;
            padding: 40px 0;
        }

        .reports-pagination {
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 12px;
            margin-top: 20px;
        }

        .reports-page-btn {
            border-radius: 4px;
            padding: 6px 14px;
            font-size: 12px;
        }

        .reports-page-btn:disabled {
            opacity: 0.35;
            cursor: not-allowed;
        }

        .reports-page-indicator {
            font-size: 12px;
            color: #777;
        }

        .report-detail-card {
            background: #242424;
            border: 1px solid #3a3a3a;
            border-radius: 4px;
            padding: 16px;
            margin-bottom: 16px;
            flex-shrink: 0;
        }

        .report-detail-title {
            font-size: 16px;
            font-weight: 400;
            color: #e0e0e0;
            margin-bottom: 10px;
        }

        .report-detail-meta {
            display: flex;
            flex-wrap: wrap;
            gap: 14px;
            font-size: 12px;
            color: #999;
            margin-bottom: 12px;
        }

        .report-detail-meta strong {
            color: #e0e0e0;
            font-weight: 400;
        }

        .report-detail-screenshot {
            margin-bottom: 12px;
            display: flex;
            flex-wrap: wrap;
            gap: 12px;
        }

        .report-screenshot-item {
            max-width: 240px;
        }

        .report-detail-screenshot img {
            max-width: 100%;
            max-height: 220px;
            border-radius: 4px;
            border: 1px solid #3a3a3a;
            display: block;
        }

        .report-detail-screenshot a {
            color: #6ea8ff;
            font-size: 12px;
            text-decoration: none;
        }

        .report-detail-screenshot a:hover {
            text-decoration: underline;
        }

        .report-detail-description {
            font-size: 13px;
            color: #d0d0d0;
            line-height: 1.5;
            white-space: pre-wrap;
            word-break: break-word;
        }

        /* Exact .ipsButton_negative recipe: flat #c75050, white text. */
        .report-close-btn {
            margin-top: 14px;
            background-color: var(--btn-negative);
            border: 1px solid var(--btn-border);
            color: #ffffff;
            border-radius: var(--btn-radius);
            padding: 6px 12px;
            font-size: 12px;
            font-weight: 700;
            cursor: pointer;
            transition: all 0.1s linear;
        }

        .report-close-btn:hover {
            background-image: var(--btn-hover-overlay);
        }

        .report-close-btn:active {
            background-image: var(--btn-active-overlay);
            box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.3) inset;
            border: 1px solid var(--btn-active-border);
        }

        .report-replies {
            display: flex;
            flex-direction: column;
            gap: 8px;
            flex: 1;
            min-height: 0;
            overflow-y: auto;
            margin-bottom: 12px;
        }

        .report-reply {
            background: #242424;
            border: 1px solid #3a3a3a;
            border-radius: 4px;
            padding: 10px 12px;
        }

        .report-reply-top {
            display: flex;
            justify-content: space-between;
            font-size: 11px;
            color: #999;
            margin-bottom: 4px;
        }

        .report-reply-content {
            font-size: 13px;
            color: #d0d0d0;
            white-space: pre-wrap;
            word-break: break-word;
        }

        .report-reply-form {
            display: flex;
            gap: 8px;
            flex-shrink: 0;
        }

        .report-reply-form textarea {
            flex: 1;
            min-height: 60px;
            background: #2d2d2d;
            border: 1px solid #444;
            border-radius: 4px;
            color: #e0e0e0;
            font-size: 13px;
            padding: 8px 10px;
            font-family: inherit;
            resize: vertical;
        }

        .report-reply-form button {
            background: transparent;
            border: 1px solid #666;
            border-radius: 4px;
            color: #ccc;
            padding: 0 16px;
            cursor: pointer;
            font-size: 12px;
        }

        .report-reply-form button:hover {
            border-color: #999;
        }

        .report-reply-denied {
            font-size: 12px;
            color: #777;
            text-align: center;
            padding: 10px 0;
            flex-shrink: 0;
        }

        /* ============================================================
           Reports-as-forum-thread — modeled on open-source forum layout
           conventions (phpBB "prosilver" topic list / post structure),
           adapted to this app's own dark IPS-flavored theme. Scoped to its
           own class name prefixes (report-thread-, report-post-,
           report-composer-) rather than the shared .report-card /
           .report-reply- classes above, so Treuhand and DMs — which
           reuse those — are untouched. */

        .report-thread-row {
            display: flex;
            align-items: center;
            gap: 12px;
            background: #242424;
            border: 1px solid #3a3a3a;
            border-radius: 4px;
            padding: 12px 14px;
            cursor: pointer;
            transition: border-color 0.2s;
        }

        .report-thread-row:hover {
            border-color: #666;
        }

        .report-thread-row:hover .report-thread-title {
            text-decoration: underline;
        }

        .report-thread-icon {
            flex-shrink: 0;
            width: 20px;
            text-align: center;
            font-size: 10px;
            color: #598f5b;
            line-height: 1;
        }

        .report-thread-main {
            flex: 1;
            min-width: 0;
        }

        .report-thread-title {
            font-size: 14px;
            color: #6ea8ff;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .report-thread-sub {
            margin-top: 4px;
            font-size: 11px;
            color: #999;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .report-thread-sub strong {
            font-weight: 400;
        }

        .report-thread-stats {
            flex-shrink: 0;
            width: 64px;
            text-align: center;
            color: #999;
        }

        .report-thread-stat-num {
            font-size: 15px;
            color: #d0d0d0;
        }

        .report-thread-stat-label {
            font-size: 10px;
            letter-spacing: 0.3px;
            text-transform: uppercase;
        }

        .report-thread-lastpost {
            flex-shrink: 0;
            display: flex;
            align-items: center;
            gap: 8px;
            width: 160px;
        }

        .report-thread-lastpost-avatar {
            width: 30px;
            height: 30px;
            min-width: 30px;
            border-radius: 50%;
            background-size: cover;
            background-position: center;
            background-repeat: no-repeat;
            background-color: #2d2d2d;
            border: 1px solid #666;
        }

        .report-thread-lastpost-text {
            min-width: 0;
        }

        .report-thread-lastpost-user {
            font-size: 12px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .report-thread-lastpost-date {
            font-size: 10px;
            color: #777;
        }

        @media (max-width: 640px) {
            .report-thread-stats {
                display: none;
            }
            .report-thread-lastpost {
                width: auto;
            }
            .report-thread-lastpost-text {
                display: none;
            }
        }

        /* Thread header (title + close button) above the post list. */
        .report-thread-header {
            flex-shrink: 0;
            display: flex;
            align-items: flex-start;
            flex-wrap: wrap;
            gap: 4px 14px;
            padding-bottom: 12px;
            margin-bottom: 12px;
            border-bottom: 1px solid #3a3a3a;
        }

        .report-thread-header-title {
            flex: 1 1 auto;
            min-width: 0;
            font-size: 16px;
            font-weight: 400;
            color: #e0e0e0;
            word-break: break-word;
        }

        .report-thread-header-sub {
            flex-basis: 100%;
            font-size: 12px;
            color: #999;
        }

        .report-thread-header-sub strong {
            color: #e0e0e0;
            font-weight: 400;
        }

        .report-thread-header .report-close-btn {
            margin-top: 0;
        }

        /* One post = one .report-post, whether it's the original report
           (report-post-op) or a reply. Two columns: a narrow author sidebar
           (phpBB's .postprofile) and the content body (.postbody). */
        .report-posts {
            display: flex;
            flex-direction: column;
            gap: 8px;
            flex: 1;
            min-height: 0;
            overflow-y: auto;
            margin-bottom: 12px;
        }

        .report-post {
            display: flex;
            gap: 14px;
            background: #242424;
            border: 1px solid #3a3a3a;
            border-radius: 4px;
            padding: 14px;
        }

        .report-post-op {
            border-color: #4a5f4a;
            background: #22271f;
        }

        .report-post-side {
            flex-shrink: 0;
            width: 96px;
            display: flex;
            flex-direction: column;
            align-items: center;
            text-align: center;
            gap: 4px;
        }

        .report-post-avatar {
            width: 56px;
            height: 56px;
            border-radius: 50%;
            background-size: cover;
            background-position: center;
            background-repeat: no-repeat;
            background-color: #2d2d2d;
            border: 1px solid #666;
            cursor: pointer;
        }

        .report-post-username {
            font-size: 12px;
            font-weight: 700;
            word-break: break-word;
            cursor: pointer;
        }

        .report-post-main {
            flex: 1;
            min-width: 0;
        }

        .report-post-header {
            display: flex;
            align-items: center;
            gap: 8px;
            font-size: 11px;
            color: #777;
            padding-bottom: 8px;
            margin-bottom: 8px;
            border-bottom: 1px dashed #3a3a3a;
        }

        .report-post-op-badge {
            background: var(--btn-positive);
            color: #fff;
            font-size: 10px;
            font-weight: 700;
            text-transform: uppercase;
            letter-spacing: 0.3px;
            padding: 2px 6px;
            border-radius: 3px;
        }

        .report-post-content {
            font-size: 13px;
            color: #d0d0d0;
            line-height: 1.5;
            word-break: break-word;
        }

        .report-post-content code {
            background: #1a1a1a;
            border: 1px solid #3a3a3a;
            border-radius: 3px;
            padding: 1px 5px;
            font-size: 12px;
        }

        .report-post-content a {
            color: #6ea8ff;
        }

        .report-quote-line {
            display: block;
            border-left: 3px solid #4a4a4a;
            padding: 2px 0 2px 10px;
            margin: 4px 0;
            color: #999;
            font-style: italic;
        }

        .report-post-attachments {
            margin-top: 10px;
            display: flex;
            flex-wrap: wrap;
            gap: 12px;
        }

        .report-post-attachment {
            max-width: 240px;
        }

        .report-post-attachment img {
            max-width: 100%;
            max-height: 220px;
            border-radius: 4px;
            border: 1px solid #3a3a3a;
            display: block;
        }

        .report-post-attachment a {
            font-size: 12px;
            display: inline-block;
            margin-top: 4px;
        }

        @media (max-width: 640px) {
            .report-post {
                flex-direction: column;
                align-items: center;
            }
            .report-post-side {
                flex-direction: row;
                width: auto;
            }
            .report-post-main {
                width: 100%;
            }
        }

        /* Composer — a toolbar-topped reply box (phpBB's classic BBCode
           editor: buttons wrap the textarea selection instead of a full
           rich-text engine), styled to match this app's own chrome. */
        .report-composer {
            flex-shrink: 0;
            display: flex;
            gap: 12px;
            align-items: flex-start;
        }

        .report-composer-avatar {
            flex-shrink: 0;
            width: 40px;
            height: 40px;
            border-radius: 50%;
            background-size: cover;
            background-position: center;
            background-repeat: no-repeat;
            background-color: #2d2d2d;
            border: 1px solid #666;
        }

        .report-composer-box {
            flex: 1;
            min-width: 0;
            background: #242424;
            border: 1px solid #3a3a3a;
            border-radius: 4px;
            /* No overflow:hidden here (removed) — same fix as .dm-composer-box:
               it silently clipped the emoji popover's buttons unclickable.
               Corner-matching now comes from the toolbar/footer's own
               border-radius instead. */
        }

        .report-composer-toolbar {
            display: flex;
            align-items: center;
            gap: 2px;
            padding: 6px;
            border-radius: 4px 4px 0 0;
            background: #2a2a2a;
            border-bottom: 1px solid #3a3a3a;
        }

        /* Same frosted-glass hover recipe as the chrome header buttons
           (.chat-header's literal .nav-bar recipe) for a consistent feel. */
        .report-composer-btn {
            background: transparent;
            border: none;
            color: #ccc;
            width: 26px;
            height: 26px;
            border-radius: 3px;
            cursor: pointer;
            font-size: 12px;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: background-color 0.15s, box-shadow 0.15s;
        }

        .report-composer-btn-code {
            font-size: 10px;
        }

        .report-composer-btn:hover {
            background-color: rgba(200, 200, 200, 0.3);
            background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0) 100%);
            box-shadow: inset rgba(255, 255, 255, 0.2) 0px 1px 0px, rgba(0, 0, 0, 0.4) 0px 1px 2px;
            color: #fff;
        }

        .report-composer-sep {
            width: 1px;
            align-self: stretch;
            margin: 4px 4px;
            background: #3a3a3a;
        }

        .report-composer-emoji-wrap {
            position: relative;
        }

        .report-composer-input {
            display: block;
            width: 100%;
            min-height: 70px;
            background: transparent;
            border: none;
            color: #e0e0e0;
            font-size: 13px;
            padding: 10px 12px;
            font-family: inherit;
            resize: vertical;
        }

        .report-composer-input:focus {
            outline: none;
        }

        .report-composer-footer {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 10px;
            padding: 8px 10px;
            background: #2a2a2a;
            border-top: 1px solid #3a3a3a;
            border-radius: 0 0 4px 4px;
        }

        .report-composer-hint {
            font-size: 10px;
            color: #666;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .report-composer-submit {
            flex-shrink: 0;
            background-color: var(--btn-primary);
            border: 1px solid var(--btn-border);
            color: var(--btn-text);
            font-weight: 700;
            text-shadow: var(--btn-text-shadow);
            cursor: pointer;
            transition: all 0.1s linear;
            border-radius: 4px;
            padding: 6px 14px;
            font-size: 12px;
        }

        .report-composer-submit:hover {
            background-image: var(--btn-hover-overlay);
        }

        .report-composer-submit:active {
            background-image: var(--btn-active-overlay);
            box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.3) inset;
            border: 1px solid var(--btn-active-border);
        }

        @media (max-width: 640px) {
            .report-composer-hint {
                display: none;
            }
        }

        .report-create-form {
            display: flex;
            flex-direction: column;
            gap: 18px;
        }

        .report-create-row {
            display: flex;
            flex-direction: column;
            gap: 6px;
        }

        .report-create-row label {
            font-size: 12px;
            color: #999;
        }

        .report-create-row select,
        .report-create-row input[type="text"] {
            background: #2d2d2d;
            border: 1px solid #444;
            border-radius: 4px;
            color: #e0e0e0;
            font-size: 13px;
            padding: 8px 10px;
            font-family: inherit;
            /* Was missing entirely -- without it a text input falls back to
               its intrinsic browser default width (~size=20, roughly 170px)
               instead of filling its row, which is exactly the tiny
               left-stuck "To:" box on the DM compose screen. This one rule
               fixes it there and on every other form sharing
               .report-create-row (Reports, Treuhand), since the row's own
               .reports-view > *:not(.reports-inline-back-btn) ancestor rule
               already centers a 720px column -- the field just needs to
               actually fill it. */
            width: 100%;
        }

        .report-create-row textarea {
            background: #2d2d2d;
            border: 1px solid #444;
            border-radius: 4px;
            color: #e0e0e0;
            font-size: 13px;
            padding: 8px 10px;
            font-family: inherit;
            min-height: 100px;
            resize: vertical;
        }

        .report-primary-btn {
            border-radius: 4px;
            padding: 10px 16px;
            font-size: 13px;
        }

        .report-primary-btn:disabled {
            opacity: 0.5;
            cursor: not-allowed;
        }

        #reportCreateSubmitBtn {
            align-self: flex-start;
            background: transparent;
            border: 1px solid #666;
            border-radius: 4px;
            color: #ccc;
            padding: 8px 18px;
            cursor: pointer;
            font-size: 13px;
        }

        #reportCreateSubmitBtn:hover {
            border-color: #999;
        }

        .user-search-wrap {
            position: relative;
        }

        .user-search-results {
            position: absolute;
            top: calc(100% + 4px);
            left: 0;
            right: 0;
            max-height: 220px;
            overflow-y: auto;
            background: #242424;
            border: 1px solid #444;
            border-radius: 4px;
            z-index: 10;
        }

        .user-search-result-item {
            padding: 8px 10px;
            font-size: 13px;
            color: #d0d0d0;
            cursor: pointer;
        }

        .user-search-result-item:hover, .user-search-result-item.active {
            background: #333;
        }

        .user-search-empty {
            padding: 8px 10px;
            font-size: 12px;
            color: #777;
        }

        .user-search-selected-hint {
            margin-top: 4px;
            font-size: 11px;
            color: #7ba05b;
        }

        #reportScreenshotInputs {
            display: flex;
            flex-direction: column;
            gap: 6px;
        }

        .screenshot-input-row {
            display: flex;
            align-items: center;
            gap: 6px;
        }

        .screenshot-input-row .report-screenshot-input {
            flex: 1;
        }

        .screenshot-remove-btn {
            background: transparent;
            border: 1px solid #444;
            border-radius: 4px;
            color: #999;
            cursor: pointer;
            width: 28px;
            height: 28px;
            font-size: 14px;
            flex: 0 0 auto;
        }

        .screenshot-remove-btn:hover {
            color: #ff6b6b;
            border-color: #ff6b6b;
        }

        .reports-add-screenshot-btn {
            align-self: flex-start;
            margin-top: 6px;
            background: transparent;
            border: none;
            color: #999;
            cursor: pointer;
            font-size: 12px;
            padding: 0;
        }

        .reports-add-screenshot-btn:hover {
            color: #ccc;
        }

        .reports-add-screenshot-btn:disabled {
            opacity: 0.4;
            cursor: not-allowed;
        }

        .treuhand-wallet-bar {
            padding: 10px 16px;
            display: flex;
            align-items: center;
            justify-content: space-between;
            flex-wrap: wrap;
            gap: 10px;
            background: #202020;
            border-bottom: 1px solid #3a3a3a;
        }

        .treuhand-balance {
            font-size: 13px;
            color: #999;
        }

        .treuhand-balance strong {
            color: #ccc;
            font-weight: 600;
        }

        .treuhand-wallet-actions {
            display: flex;
            gap: 8px;
            flex-wrap: wrap;
        }

        .treuhand-wallet-btn {
            border-radius: 4px;
            padding: 6px 12px;
            font-size: 12px;
            white-space: nowrap;
        }


        .treuhand-card-locked {
            cursor: not-allowed;
            opacity: 0.6;
        }

        .treuhand-card-locked:hover {
            border-color: #3a3a3a;
        }

        .treuhand-status-pill {
            display: inline-block;
            font-size: 10px;
            font-weight: 400;
            letter-spacing: 0.3px;
            padding: 2px 8px;
            border-radius: 10px;
            border: 1px solid currentColor;
            white-space: nowrap;
            flex-shrink: 0;
        }

        .treuhand-status-open {
            color: #ffd700;
        }

        .treuhand-status-completed {
            color: #3ddc5c;
        }

        .treuhand-status-cancelled {
            color: #ff6b6b;
        }

        .treuhand-detail-top {
            display: flex;
            align-items: baseline;
            justify-content: space-between;
            gap: 10px;
            margin-bottom: 10px;
        }

        .treuhand-detail-top .report-detail-title {
            margin-bottom: 0;
        }

        .treuhand-detail-actions {
            display: flex;
            gap: 10px;
            flex-wrap: wrap;
            margin-top: 14px;
        }

        .treuhand-confirm-btn {
            background: transparent;
            border: 1px solid #3ddc5c;
            color: #3ddc5c;
            border-radius: 4px;
            padding: 6px 12px;
            font-size: 12px;
            cursor: pointer;
            transition: background 0.2s;
        }

        .treuhand-confirm-btn:hover {
            background: rgba(61, 220, 92, 0.1);
        }

        .treuhand-amount-row {
            display: flex;
            align-items: center;
            gap: 6px;
        }

        .treuhand-amount-row .account-input {
            flex: 0 0 140px;
        }

        .treuhand-my-withdrawals {
            margin-top: 20px;
        }

        .treuhand-my-withdrawals-title {
            font-size: 12px;
            color: #999;
            margin-bottom: 8px;
        }

        .treuhand-admin-withdrawals-list {
            display: flex;
            flex-direction: column;
            gap: 8px;
        }

        .treuhand-withdrawal-row {
            background: #242424;
            border: 1px solid #3a3a3a;
            border-radius: 4px;
            padding: 10px 12px;
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 12px;
            margin-bottom: 8px;
        }

        .treuhand-withdrawal-row:last-child {
            margin-bottom: 0;
        }

        .treuhand-withdrawal-info {
            display: flex;
            flex-direction: column;
            gap: 4px;
            min-width: 0;
            font-size: 13px;
            color: #d0d0d0;
        }

        .treuhand-withdrawal-destination {
            font-size: 11px;
            color: #999;
            word-break: break-all;
            font-family: monospace;
        }

        .treuhand-withdrawal-actions {
            display: flex;
            gap: 8px;
            flex-shrink: 0;
            flex-wrap: wrap;
        }

        .treuhand-claim-result {
            background: #242424;
            border: 1px solid #3ddc5c;
            border-radius: 4px;
            padding: 16px;
            margin-bottom: 20px;
        }

        .treuhand-claim-result-title {
            color: #3ddc5c;
            font-size: 14px;
            font-weight: 600;
            margin-bottom: 8px;
        }

        .treuhand-claim-link-btn {
            display: inline-block;
            margin: 10px 0;
            text-decoration: none;
            text-align: center;
        }

        .treuhand-claim-link-inline {
            display: inline-block;
            color: #6ea8ff;
            font-size: 12px;
            text-decoration: none;
        }

        .treuhand-claim-link-inline:hover {
            text-decoration: underline;
        }

        .treuhand-withdrawal-review-notice {
            font-size: 11px;
            color: #ffd700;
            margin-top: 4px;
        }

        .dm-avatar {
            width: 40px;
            height: 40px;
            min-width: 40px;
            border-radius: 50%;
            background-size: cover;
            background-position: center;
            background-repeat: no-repeat;
            background-color: #2d2d2d;
            border: 1px solid #666;
            flex-shrink: 0;
        }

        .dm-avatar-lg {
            width: 44px;
            height: 44px;
            min-width: 44px;
        }

        .dm-avatar-sm {
            width: 26px;
            height: 26px;
            min-width: 26px;
            border-width: 1px;
        }

        .dm-retention-notice {
            margin-bottom: 12px;
            border: 1px solid #3a3a3a;
            border-radius: 4px;
        }

        .dm-thread-header {
            display: flex;
            align-items: center;
            gap: 10px;
            margin-bottom: 14px;
            padding-bottom: 14px;
            border-bottom: 1px solid #444;
            flex-shrink: 0;
        }

        .dm-thread-header-meta {
            display: flex;
            flex-direction: column;
            gap: 3px;
            min-width: 0;
        }

        .dm-thread-header-name {
            font-size: 15px;
            font-weight: 400;
        }

        .dm-thread-header-subject {
            font-size: 13px;
            color: #ccc;
        }

        .dm-thread-header-seen {
            font-size: 11px;
            color: #777;
            /* Sibling of .dm-thread-header-meta within .dm-thread-header
               (not stacked inside that column) so it can sit in the
               bottom-right corner of the header bar, level with the
               border-bottom divider, instead of under the subject line.
               margin-left:auto pushes it to the far right on the row's
               main axis; align-self:flex-end opts it out of the row's own
               align-items:center so it pins to the bottom edge instead of
               vertically centering next to the 3-line name/rank/subject
               column beside it. */
            margin-left: auto;
            align-self: flex-end;
            white-space: nowrap;
            padding-left: 12px;
        }

        /* ============================================================
           DMs-as-forum-thread — same architecture as the Reports redesign
           above (inspired by phpBB prosilver's topic-list / postprofile /
           postbody structure, and its private-messaging screens which
           reuse that same layout — see ucp_pm_viewmessage.html), adapted
           for a two-party conversation. Independently scoped under its own
           dm-thread-/dm-post-/dm-composer- prefixes rather than reusing
           Reports' report-thread-/report-post-/report-composer- classes,
           so the two features stay editable without risk of one breaking
           the other — same reasoning that kept Reports off the older
           shared .report-card/.report-reply- classes. */

        .dm-thread-row {
            display: flex;
            align-items: center;
            gap: 12px;
            background: #242424;
            border: 1px solid #3a3a3a;
            border-radius: 4px;
            padding: 10px 14px;
            cursor: pointer;
            transition: border-color 0.2s;
        }

        .dm-thread-row:hover {
            border-color: #666;
        }

        .dm-thread-row:hover .dm-thread-title {
            text-decoration: underline;
        }

        .dm-thread-avatar {
            flex-shrink: 0;
            width: 40px;
            height: 40px;
            min-width: 40px;
            border-radius: 50%;
            background-size: cover;
            background-position: center;
            background-repeat: no-repeat;
            background-color: #2d2d2d;
            border: 1px solid #666;
        }

        .dm-thread-main {
            flex: 1;
            min-width: 0;
        }

        .dm-thread-title {
            font-size: 14px;
            color: #e0e0e0;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .dm-thread-row-unread .dm-thread-title {
            font-weight: 700;
            color: #fff;
        }

        .dm-thread-sub {
            margin-top: 3px;
            font-size: 12px;
            color: #999;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .dm-thread-row-unread .dm-thread-sub {
            color: #ccc;
        }

        /* The sender's username inside .dm-thread-sub (see renderDmThreadRow)
           gets its color from rankStyle() inline, same as everywhere else
           rank colors apply -- this just stops the <strong> tag itself from
           also bolding it, matching .report-thread-sub strong's identical
           rule right above for the same reason: a heavy-bold name reads as
           too loud next to the muted 12px preview text beside it. */
        .dm-thread-sub strong {
            font-weight: 400;
        }

        .dm-thread-meta {
            flex-shrink: 0;
            display: flex;
            flex-direction: column;
            align-items: flex-end;
            gap: 5px;
        }

        .dm-thread-badge {
            position: static;
        }

        .dm-thread-date {
            font-size: 10px;
            color: #777;
        }

        /* Message list — one .dm-post per message, direct sibling of the
           .dm-thread-header above (see .reports-view's centering rule). */
        .dm-posts {
            display: flex;
            flex-direction: column;
            gap: 8px;
            flex: 1;
            min-height: 0;
            overflow-y: auto;
            margin-bottom: 12px;
        }

        .dm-post {
            display: flex;
            gap: 14px;
            background: #242424;
            border: 1px solid #3a3a3a;
            border-radius: 4px;
            padding: 14px;
        }

        /* Marks the other participant's latest message while it's still
           unread — never "mine vs theirs" (the sidebar avatar + name
           already say who sent each post). Reuses the same red as
           .bell-badge/.dm-thread-badge elsewhere, since that's already
           this app's established "something's new" color, just toned down
           to a border + label instead of a filled badge. Cleared the next
           time this conversation loads (open or poll), once it's read. */
        .dm-post-new {
            border-left: 3px solid #d63333;
            background: #2a2222;
        }

        .dm-post-new-label {
            color: #d63333;
            font-weight: 700;
            font-size: 10px;
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }

        .dm-post-side {
            flex-shrink: 0;
            width: 96px;
            display: flex;
            flex-direction: column;
            align-items: center;
            text-align: center;
            gap: 4px;
        }

        .dm-post-avatar {
            width: 56px;
            height: 56px;
            border-radius: 50%;
            background-size: cover;
            background-position: center;
            background-repeat: no-repeat;
            background-color: #2d2d2d;
            border: 1px solid #666;
        }

        .dm-post-username {
            font-size: 12px;
            font-weight: 700;
            word-break: break-word;
        }

        .dm-post-main {
            flex: 1;
            min-width: 0;
        }

        .dm-post-header {
            display: flex;
            align-items: center;
            gap: 8px;
            font-size: 11px;
            color: #777;
            padding-bottom: 8px;
            margin-bottom: 8px;
            border-bottom: 1px dashed #3a3a3a;
        }

        .dm-post-content {
            font-size: 13px;
            color: #d0d0d0;
            line-height: 1.5;
            word-break: break-word;
        }

        .dm-post-content code {
            background: #1a1a1a;
            border: 1px solid #3a3a3a;
            border-radius: 3px;
            padding: 1px 5px;
            font-size: 12px;
        }

        .dm-post-content a {
            color: #6ea8ff;
        }

        .dm-quote-line {
            display: block;
            border-left: 3px solid #4a4a4a;
            padding: 2px 0 2px 10px;
            margin: 4px 0;
            color: #999;
            font-style: italic;
        }

        .dm-post-quote-btn {
            margin-top: 10px;
            background: #2a2a2a;
            border: 1px solid #3a3a3a;
            color: #aaa;
            font-size: 11px;
            padding: 4px 10px;
            border-radius: 3px;
            cursor: pointer;
            transition: all 0.15s;
        }

        .dm-post-quote-btn:hover {
            background: #333;
            color: #fff;
            border-color: #555;
        }

        @media (max-width: 640px) {
            .dm-post {
                flex-direction: column;
                align-items: center;
            }
            .dm-post-side {
                flex-direction: row;
                width: auto;
            }
            .dm-post-main {
                width: 100%;
            }
        }

        /* Composer — identical toolbar recipe to Reports' .report-composer
           (own copy, same reasoning as the rest of this block). */
        .dm-composer {
            flex-shrink: 0;
            display: flex;
            gap: 12px;
            align-items: flex-start;
        }

        .dm-composer-avatar {
            flex-shrink: 0;
            width: 40px;
            height: 40px;
            border-radius: 50%;
            background-size: cover;
            background-position: center;
            background-repeat: no-repeat;
            background-color: #2d2d2d;
            border: 1px solid #666;
        }

        .dm-composer-box {
            flex: 1;
            min-width: 0;
            background: #242424;
            border: 1px solid #3a3a3a;
            border-radius: 4px;
            /* No overflow:hidden here (removed) — it used to clip the toolbar/
               footer's square corners to match this box's rounded corners,
               but it also silently clipped the emoji popover (which opens
               upward past the toolbar's own top edge) so its buttons were
               unclickable. Corner-matching now comes from giving the toolbar
               and footer their own matching border-radius instead. */
        }

        .dm-composer-toolbar {
            display: flex;
            align-items: center;
            gap: 2px;
            padding: 6px;
            background: #2a2a2a;
            border-bottom: 1px solid #3a3a3a;
            border-radius: 4px 4px 0 0;
        }

        .dm-composer-btn {
            background: transparent;
            border: none;
            color: #ccc;
            width: 26px;
            height: 26px;
            border-radius: 3px;
            cursor: pointer;
            font-size: 12px;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: background-color 0.15s, box-shadow 0.15s;
        }

        .dm-composer-btn-code {
            font-size: 10px;
        }

        .dm-composer-btn:hover {
            background-color: rgba(200, 200, 200, 0.3);
            background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0) 100%);
            box-shadow: inset rgba(255, 255, 255, 0.2) 0px 1px 0px, rgba(0, 0, 0, 0.4) 0px 1px 2px;
            color: #fff;
        }

        .dm-composer-sep {
            width: 1px;
            align-self: stretch;
            margin: 4px 4px;
            background: #3a3a3a;
        }

        .dm-composer-emoji-wrap {
            position: relative;
        }

        .dm-composer-input {
            display: block;
            width: 100%;
            min-height: 70px;
            background: transparent;
            border: none;
            color: #e0e0e0;
            font-size: 13px;
            padding: 10px 12px;
            font-family: inherit;
            resize: vertical;
        }

        .dm-composer-input:focus {
            outline: none;
        }

        .dm-composer-footer {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 10px;
            padding: 8px 10px;
            background: #2a2a2a;
            border-top: 1px solid #3a3a3a;
            border-radius: 0 0 4px 4px;
        }

        .dm-composer-hint {
            font-size: 10px;
            color: #666;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .dm-composer-submit {
            flex-shrink: 0;
            background-color: var(--btn-primary);
            border: 1px solid var(--btn-border);
            color: var(--btn-text);
            font-weight: 700;
            text-shadow: var(--btn-text-shadow);
            cursor: pointer;
            transition: all 0.1s linear;
            border-radius: 4px;
            padding: 6px 14px;
            font-size: 12px;
        }

        .dm-composer-submit:hover {
            background-image: var(--btn-hover-overlay);
        }

        .dm-composer-submit:active {
            background-image: var(--btn-active-overlay);
            box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.3) inset;
            border: 1px solid var(--btn-active-border);
        }

        .member-rank-report {
            color: #999;
            font-weight: 400;
            margin-left: 6px;
            font-size: 10px;
        }

        .audio-play-btn {
            width: 32px;
            height: 32px;
            min-width: 32px;
            border-radius: 50%;
            background: #444;
            border: 1px solid #666;
            color: #e0e0e0;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
            transition: background 0.2s;
            padding: 0;
        }

        .audio-play-btn:hover {
            background: #505050;
        }

        .audio-info {
            flex: 1;
            min-width: 0;
        }

        .audio-title {
            font-size: 12px;
            color: #d0d0d0;
            font-weight: 400;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            margin-bottom: 5px;
        }

        .audio-progress-bar {
            height: 4px;
            background: #444;
            border-radius: 2px;
            cursor: pointer;
            position: relative;
            margin-bottom: 4px;
        }

        .audio-progress-fill {
            height: 100%;
            background: #999;
            border-radius: 2px;
            width: 0%;
            pointer-events: none;
        }

        .audio-meta {
            font-size: 10px;
            color: #777;
            display: flex;
            justify-content: space-between;
        }


        .message-timestamp {
            color: #555;
            font-size: 11px;
            white-space: nowrap;
            order: 1;
        }

        .message-action-btn {
            background: transparent;
            border: none;
            color: #666;
            cursor: pointer;
            font-size: 12px;
            padding: 0 2px;
            transition: color 0.2s;
            order: 2;
        }

        .message-action-btn:hover {
            color: #888;
        }

        .chat-input-area {
            background: #2d2d2d;
            padding: 12px;
            border-top: 1px solid #444;
            flex: 0 0 auto;
        }

        .chat-input-form {
            display: flex;
            gap: 8px;
        }

        .voice-record-bar {
            display: none;
            align-items: center;
            gap: 10px;
            padding: 8px 4px;
        }

        .voice-record-bar.active {
            display: flex;
        }

        .voice-record-dot {
            width: 10px;
            height: 10px;
            min-width: 10px;
            border-radius: 50%;
            background: #ff3b3b;
            animation: recordPulse 1s infinite;
        }

        @keyframes recordPulse {
            0%, 100% { opacity: 1; }
            50% { opacity: 0.25; }
        }

        .voice-record-timer {
            color: #ccc;
            font-size: 13px;
            min-width: 34px;
            font-variant-numeric: tabular-nums;
        }

        .voice-record-hint {
            color: #888;
            font-size: 12px;
            flex: 1;
        }

        .voice-cancel-btn, .voice-send-btn {
            background: transparent;
            border: none;
            color: #999;
            border-radius: 0;
            cursor: pointer;
            padding: 8px 12px;
            font-size: 12px;
            transition: all 0.2s;
            font-weight: 400;
        }

        .voice-cancel-btn:hover {
            color: var(--btn-negative);
        }

        .voice-send-btn {
            color: var(--btn-text);
            font-weight: 700;
        }

        .voice-send-btn:hover {
            color: #ffffff;
        }

        #micBtn.recording {
            background: #4a2a2a;
            border-color: #ff5c5c;
            color: #ff7b7b;
        }

        .input-icon-btn {
            cursor: pointer;
            padding: 8px 6px;
            background: transparent;
            border: none;
            border-radius: 0;
            color: #999;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 14px;
            transition: all 0.2s;
        }

        .input-icon-btn:hover {
            color: #ccc;
        }

        .emoji-picker-wrap {
            position: relative;
            display: flex;
            align-items: center;
        }

        .emoji-picker {
            display: none;
            position: absolute;
            bottom: 100%;
            left: 0;
            margin-bottom: 8px;
            background: #2d2d2d;
            border: 1px solid #444;
            border-radius: 6px;
            padding: 8px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.8);
            grid-template-columns: repeat(6, 1fr);
            gap: 4px;
            width: 216px;
            z-index: 300;
        }

        .emoji-picker.active {
            display: grid;
        }

        .emoji-picker-item {
            width: 32px;
            height: 32px;
            display: flex;
            align-items: center;
            justify-content: center;
            background: transparent;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            padding: 4px;
            transition: background 0.15s;
        }

        .emoji-picker-item:hover {
            background: #3a3a3a;
        }

        .emoji-picker-item img {
            max-width: 100%;
            max-height: 100%;
        }

        .chat-emoji {
            width: 20px;
            height: 20px;
            vertical-align: middle;
            margin: 0 1px;
        }

        .message-input-editable {
            flex: 1;
            padding: 8px;
            border: 1px solid #3a3a3a;
            background: #1a1a1a;
            font-size: 13px;
            color: #b0b0b0;
            min-height: 34px;
            max-height: 120px;
            overflow-y: auto;
            outline: none;
            line-height: 1.5;
            white-space: pre-wrap;
            word-break: break-word;
        }

        .message-input-editable:focus {
            outline: none;
            border-color: #666;
        }

        .message-input-editable:empty::before {
            content: attr(data-placeholder);
            color: #999;
            pointer-events: none;
        }

        .message-input-editable img.inline-emoji {
            height: 18px;
            vertical-align: middle;
            margin: 0 1px;
            display: inline-block;
            pointer-events: none;
        }

        /* Reports reply / DM reply / DM create composers -- these used to
           be plain <textarea>s (wrapping the selection in raw **/*/__/~~/`
           markup that you'd see as literal asterisks while typing). Now
           they're contenteditable divs (.report-composer-input /
           .dm-composer-input keep their existing box styling; this class
           adds what a <textarea> gave for free: wrapping, scroll, resize,
           the placeholder, and inline custom-emoji sizing matching
           .message-input-editable above) that render the real formatting
           and real emoji live -- see the big JS comment above
           composerPlainText() in index.html for the full design. */
        .composer-editable {
            white-space: pre-wrap;
            word-break: break-word;
            overflow-y: auto;
            overflow-x: hidden;
        }

        .composer-editable:empty::before {
            content: attr(data-placeholder);
            color: #999;
            pointer-events: none;
        }

        .composer-editable img.inline-emoji {
            height: 18px;
            vertical-align: middle;
            margin: 0 1px;
            display: inline-block;
            pointer-events: none;
        }

        .composer-editable code {
            background: #1a1a1a;
            border: 1px solid #3a3a3a;
            border-radius: 3px;
            padding: 1px 5px;
            font-size: 12px;
        }

        /* The raw markdown delimiters (**, *, __, ~~, `, "> ") stay visible
           but dimmed rather than disappearing once formatting "closes" --
           same principle as Discord's composer: you can always see and
           directly edit the real syntax, rather than a Typora-style
           hide/reveal-on-cursor mode needing a lot more state to get right. */
        .composer-fmt-marker {
            color: #666;
        }

        /* Live-typing equivalent of .report-quote-line/.dm-quote-line --
           identical look (this is the exact same border/padding/color/
           italic recipe those two already use for the real posted-message
           render), just under its own class since the live version also
           needs to show the dimmed "> " marker inline, which the final
           render strips entirely. */
        .composer-quote-line-live {
            display: block;
            border-left: 3px solid #4a4a4a;
            padding: 2px 0 2px 10px;
            margin: 4px 0;
            color: #999;
            font-style: italic;
        }

        .btn-send {
            padding: 8px 10px;
            background: transparent;
            color: #999;
            border: none;
            border-radius: 0;
            cursor: pointer;
            font-size: 12px;
            transition: all 0.2s;
            font-weight: 400;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .btn-send:hover {
            color: #ccc;
        }

        .btn-send.has-content {
            background: #3a3a3a;
            border-radius: 4px;
        }

        .btn-send.has-content:hover {
            background: #444;
        }

        .btn-send:disabled {
            opacity: 0.4;
            cursor: not-allowed;
            color: #444;
        }

        .sending {
            opacity: 0.5;
            pointer-events: none;
        }

        .cooldown-locked {
            opacity: 0.35;
            pointer-events: none;
        }

        /* Members is now a button-triggered slide-out panel at every viewport
           width — the same overlay the mobile version already used — instead
           of a permanent sidebar. That frees .chat-column (its only remaining
           flex sibling in .chat-main) to fill the full page width, which is
           also what makes the header and the news box below go edge-to-edge. */
        .members-column {
            width: 250px;
            /* Matches .chat-messages/.main-container's own #1a1a1a exactly
               now, at Björn's request: even the app's standard #2d2d2d
               panel tone (used elsewhere for modals/dropdowns) read as a
               separate, disconnected box sitting on top of the chat rather
               than a natural extension of it once this panel was open and
               filling a large area next to it. Border-top + the left-edge
               box-shadow below still mark the panel's edges, and
               .member-item's own #3a3a3a keeps each row individually
               readable -- so the panel boundary and its contents are still
               legible, just without the fill color itself jumping out. */
            background: #1a1a1a;
            display: flex;
            flex-direction: column;
            overflow: hidden;
            position: fixed;
            /* Starts right below the ad banners (0px extra when they're
               hidden, e.g. on Reports/Treuhand/DM) instead of always right
               below the header, so it doesn't cover the ads when open. */
            top: calc(var(--header-total-height) + var(--ads-section-height));
            right: 0;
            height: calc(100% - var(--header-total-height) - var(--ads-section-height));
            height: calc(100dvh - var(--header-total-height) - var(--ads-section-height));
            z-index: 250;
            transform: translateX(100%);
            transition: transform 0.25s ease, top 0.2s ease, height 0.2s ease;
            /* The -4px/16px-blur left-edge box-shadow that used to live here
               is gone, at Björn's request: it made sense back when this
               panel had its own lighter #2d2d2d fill (a normal "raised
               panel" drop-shadow), but now that the fill matches the chat's
               #1a1a1a exactly (see above), that same blurred shadow no
               longer reads as an edge cue -- it just shows up as an
               unexplained dark smudge bleeding into whatever sits at the
               boundary (most noticeably the message input row/send button
               at the bottom, which is what was flagged). A plain edge
               treatment is still needed below, though: .ads-section's own
               border-bottom (also 1px solid #444) sits at this exact same
               y-coordinate (both resolve from the same "header + ads
               height" calc) and is "permanently full-width, unaffected by
               the panel's state" (see .chat-main:has(#membersColumn...)
               below) -- but that's only true where the panel ISN'T
               covering it. Where it is, this edge treatment is the only
               thing marking the panel's own top boundary (and the only
               thing marking it at all when the ads section is hidden, e.g.
               Reports/Treuhand/DM, where there's nothing to line up with).
               This used to be a real border-top -- but with box-sizing:
               border-box, a border is painted INSIDE the box's own top
               edge, i.e. one pixel row below .ads-section's border-bottom
               row, not on top of it -- so instead of the two 1px lines
               "meeting" into one, they stacked into a visibly thicker 2px
               line specifically over the panel's width (confirmed by
               sampling the rendered pixels: two consecutive #444 rows
               under the panel, only one anywhere else along the same
               boundary), i.e. exactly the "doppelte Linie" Björn flagged
               -- normal 1px everywhere the panel doesn't reach, doubled
               right where it does, instead of one normal 1px line
               reaching all the way to the end. A box-shadow paints OUTSIDE
               the box edge instead of consuming a row inside it, so this
               one now lands in the exact same pixel row as .ads-section's
               border-bottom rather than the row after it -- the two
               genuinely coincide into a single 1px line, and it's not
               clipped by this element's own overflow:hidden above (that
               only clips children, never an element's own box-shadow). */
            box-shadow: 0 -1px 0 #444;
        }

        .members-column.mobile-open {
            transform: translateX(0);
        }

        /* .members-column is position:fixed, so opening it doesn't push or
           shrink anything by itself -- it just floats an opaque 250px-wide
           panel over whatever is already there. That's fine for a mobile
           drawer (the dimmed backdrop blocks interaction with what's
           underneath anyway), but on desktop, where it's open by default
           and the backdrop is switched off above, the chat column's own
           right-aligned controls (e.g. the send button at the end of
           .chat-input-form) would otherwise render right underneath the
           now-permanently-visible panel -- covered and unclickable, even
           though nothing is "wrong" about their z-index this time. Give the
           chat column real breathing room instead: reserve the same 250px
           on desktop whenever the column is actually open.

           Targets .chat-column's direct children individually (via >),
           excluding .ads-section, rather than margin-righting .chat-column
           itself: .ads-section sits entirely ABOVE where .members-column
           starts (top: calc(header + ads height) -- the two never overlap
           vertically), so it never needed the reservation. Shrinking it
           anyway was a side effect of margin-righting the whole column,
           and caused two regressions -- the ad banners visibly resize/
           recenter ("verrutschen") whenever the panel opens/closes since
           they lose 250px of the width they center within, and
           .ads-section's own border-bottom (the "Strich" separating it
           from the chat below) stopped 250px short of the right edge
           instead of reaching all the way to -- and so visually lining up
           with -- .members-column's top edge, which sits at that exact
           same y-coordinate. Excluding .ads-section keeps it (and that
           line) permanently full-width, unaffected by the panel's state,
           while #normalChatContent/#reportsContent/#treuhandContent/
           #dmContent (everything that actually renders underneath the
           panel) still get the same 250px inset as before. */
        @media (min-width: 769px) {
            .chat-main:has(#membersColumn.mobile-open) .chat-column > *:not(.ads-section) {
                margin-right: 250px;
            }
        }

        .chat-header-left {
            display: flex;
            align-items: baseline;
            gap: 14px;
            min-width: 0;
            overflow-x: auto;
            overflow-y: hidden;
        }

        /* Reports / Treuhand-Panel — back inline in the chrome header bar,
           next to the title (exact original recipe: transparent chip with
           the frosted hover overlay, same as the bell/members icon buttons). */
        .header-reports-btn {
            background: transparent;
            border: none;
            white-space: nowrap;
            flex-shrink: 0;
            color: #ffffff;
            font-weight: 700;
            cursor: pointer;
            padding: 6px 10px;
            font-size: 14px;
            font-family: inherit;
            border-radius: 3px;
            transition: background-color 0.2s, box-shadow 0.2s;
            forced-color-adjust: none;
            /* Exact .ipsNavBar_primary-inherited text-shadow (same literal
               value as .chat-header itself), not an invented weaker one. */
            text-shadow: rgba(0, 0, 0, 0.6) 0px 1px 2px;
        }

        .header-reports-btn:hover {
            /* Exact .ipsApp .ipsNavBar_primary > ul > li:hover > a recipe —
               a flat translucent white wash, NOT a restatement of the
               .nav-bar frosted-glass recipe (that combo belongs to the bar
               itself, not to hovering an item inside it). */
            background: rgba(255, 255, 255, 0.08);
            color: #ffffff;
        }

        .header-reports-btn.active {
            /* Exact .ipsApp .ipsNavBar_primary > ul > li[data-active] > a
               recipe — persistent highlight for whichever section (Reports /
               Treuhand-Panel) is currently open, same as the real forum
               keeps its current tab visibly selected instead of just
               reacting to the mouse. */
            background: rgba(255, 255, 255, 0.15);
            color: #ffffff;
        }

        .mobile-members-btn {
            display: flex;
            background: transparent;
            border: none;
            color: #ffffff;
            cursor: pointer;
            padding: 4px 6px;
            border-radius: 3px;
            transition: background-color 0.2s, box-shadow 0.2s;
            align-items: center;
            justify-content: center;
        }

        .mobile-members-btn:hover {
            /* Same correction as .bell-btn:hover / .header-reports-btn:hover
               — flat translucent white wash, exact .ipsApp .ipsNavBar_primary
               > ul > li:hover > a recipe. */
            background: rgba(255, 255, 255, 0.08);
            color: #ffffff;
        }

        .members-backdrop {
            display: block;
            position: fixed;
            top: calc(var(--header-total-height) + var(--ads-section-height));
            right: 0;
            bottom: 0;
            left: 0;
            background: rgba(0, 0, 0, 0.5);
            z-index: 240;
            opacity: 0;
            pointer-events: none;
            transition: opacity 0.25s ease, top 0.2s ease;
        }

        .members-backdrop.mobile-open {
            opacity: 1;
            pointer-events: auto;
        }

        /* The members column now opens by default above the mobile
           breakpoint (see login()'s toggleMobileMembers(true) call), acting
           as a plain sidebar rather than a temporary drawer there — so its
           dimming/click-blocking backdrop, which makes sense for a small
           screen's tap-to-open overlay, is switched back off above that
           width. Below it, .mobile-open above still dims/blocks as before:
           mobile keeps the original closed-by-default tap-to-open drawer. */
        @media (min-width: 769px) {
            .members-backdrop.mobile-open {
                opacity: 0;
                pointer-events: none;
            }
        }

        @media (max-width: 768px) {
            :root {
                /* .ips-masthead (79px) + .chat-header (~47px) + the same 4px
                   bottom strip as desktop, at mobile sizing — texture band
                   scaled up by the same factor as desktop (90→142, i.e.
                   ×1.578) since there's no mobile reference screenshot:
                   50px × 1.578 ≈ 79px. Net -6px+4px vs. the old 132px
                   (thinned header, then the new bottom strip added back). */
                --header-total-height: 130px;
            }

            .ips-masthead-logo {
                /* Matches .chat-header's own mobile margin-left (10px)
                   exactly, same reasoning as the desktop rule above --
                   padding-left is already 0 there, so nothing needs
                   overriding here for that part. */
                margin-left: 10px;
                /* The desktop 90px content height (+20px padding = 110px
                   box) doesn't fit the mobile masthead's much smaller 130px
                   total budget once .chat-header's own ~58px is reserved --
                   measured empirically to overflow past the masthead's top
                   edge otherwise. Shrunk to fit the remaining space with a
                   little headroom, padding tightened to match. */
                max-height: 46px;
                padding-top: 4px;
                padding-bottom: 4px;
            }

            .chat-header {
                padding: 4px 10px;
                /* 6% would eat too much of an already-tight header on phones
                   (Reports/Treuhand-Panel need the room) — a small fixed
                   gutter keeps "doesn't touch the edge" without the squeeze. */
                margin-left: 10px;
                margin-right: 10px;
            }

            .ipsfocus-globalMessage {
                margin-left: 10px;
                margin-right: 10px;
            }

            .chat-header-left {
                gap: 8px;
                /* At real phone widths (390px, iPhone 13) this row's content
                   (ChatRoom + Reports + "Treuhand-Panel (5%)") measures
                   ~315px against only ~194px available next to the header
                   icons -- even after the font-size/gap trims above, still
                   >100px short. The old fallback was overflow-x:auto
                   (unchanged base rule), which did let you reach the hidden
                   part by swiping, but with two real problems, confirmed
                   empirically with Playwright: (1) no visual affordance at
                   all hints this row scrolls (no fade/shadow edge, and
                   confirmed via getComputedStyle: no mask-image is applied)
                   -- it just looks like "Treuhand-Panel" is cut off/broken;
                   (2) tapping Reports or Treuhand-Panel auto-scrolls that
                   button into view, which pushes #chatroomTitle off the
                   LEFT edge (measured x:-101px, i.e. genuinely outside the
                   viewport) -- the one thing that navigates back to the
                   main chat becomes unreachable without first realizing you
                   can swipe the header itself back rightward. Wrapping
                   instead of scrolling means every item is simply always
                   on-screen -- title+Reports pack onto row 1 (158.8px, fits
                   the 194px column), Treuhand-Panel(5%) alone wraps to row 2
                   (148.6px, also fits) -- so nothing is ever hidden and
                   nothing needs discovering. This makes .chat-header-left
                   two lines tall instead of one on phones; the matching
                   --header-total-height/.chat-header min-height bump is
                   below, kept in the same lockstep the existing comment on
                   .chat-header already documents for this pair of values. */
                flex-wrap: wrap;
                overflow-x: visible;
                row-gap: 4px;
            }

            .chat-header h1,
            .header-reports-btn {
                font-size: 13px;
            }

            .header-right {
                gap: 4px;
            }

            .treuhand-wallet-bar {
                padding: 8px 10px;
            }

            .treuhand-balance {
                font-size: 12px;
            }

            .treuhand-wallet-btn {
                font-size: 11px;
                padding: 5px 9px;
            }

            .dm-avatar {
                width: 34px;
                height: 34px;
                min-width: 34px;
            }

            .dm-avatar-lg {
                width: 38px;
                height: 38px;
                min-width: 38px;
            }

            .mobile-members-btn,
            .bell-btn {
                min-width: 40px;
                min-height: 40px;
            }

            .user-info-text {
                display: none;
            }

            input[type="text"],
            input[type="password"],
            input[type="email"],
            input[type="number"],
            input[type="search"],
            textarea,
            [contenteditable="true"] {
                font-size: 16px !important;
            }

            .account-row {
                flex-direction: column;
                align-items: stretch !important;
                gap: 6px !important;
            }

            .account-row-label {
                width: auto;
                min-width: 0;
                text-align: left !important;
            }

            .donator-purchase-row {
                flex-wrap: wrap !important;
            }

            .donator-amount-input {
                min-width: 60px !important;
            }

            .members-column {
                /* Base rule already makes this a fixed slide-out panel at every
                   width; only the panel width itself needs to shrink here so it
                   doesn't overshoot narrow screens. */
                width: min(280px, 80vw);
            }

            .user-menu,
            .notif-dropdown,
            .context-menu,
            .emoji-picker {
                max-width: calc(100vw - 24px);
                min-width: 0;
            }
        }

        .members-header {
            height: 52px;
            padding: 6px 12px;
            border-bottom: 1px solid #444;
            color: #a3a3a3;
            font-size: 12px;
            font-weight: 400;
            flex: 0 0 auto;
            display: flex;
            align-items: center;
            justify-content: space-between;
        }

        .member-search-toggle {
            background: transparent;
            border: none;
            color: #888;
            cursor: pointer;
            padding: 2px;
            display: flex;
            align-items: center;
            transition: color 0.2s;
        }

        .member-search-toggle:hover {
            color: #ccc;
        }

        .member-search-bar {
            display: none;
            padding: 8px 12px;
            border-bottom: 1px solid #444;
            flex: 0 0 auto;
        }

        .member-search-bar.active {
            display: block;
        }

        .member-search-bar input {
            width: 100%;
            padding: 6px 8px;
            background: #1a1a1a;
            border: 1px solid #3a3a3a;
            border-radius: 2px;
            color: #b0b0b0;
            font-size: 12px;
        }

        .member-search-bar input:focus {
            outline: none;
            border-color: #666;
        }

        .members-list {
            flex: 1;
            overflow-y: auto;
            padding: 8px;
        }

        .member-item {
            padding: 8px;
            margin-bottom: 4px;
            background: #3a3a3a;
            border-radius: 2px;
            font-size: 12px;
            color: #b0b0b0;
            display: flex;
            align-items: center;
            gap: 8px;
            position: relative;
        }

        .member-item-banned {
            opacity: 0.55;
        }

        .member-rank-banned {
            color: #999;
            font-weight: 400;
            font-size: 10px;
        }

        .member-ban-btn {
            margin-left: auto;
            background: transparent;
            border: none;
            color: #666;
            cursor: pointer;
            font-size: 12px;
            padding: 2px 6px;
            transition: color 0.2s;
            flex-shrink: 0;
        }

        .member-ban-btn:hover {
            color: var(--btn-negative);
        }

        .member-item-text {
            display: flex;
            flex-direction: column;
            gap: 2px;
            min-width: 0;
            cursor: pointer;
        }

        .member-username {
            color: #d0d0d0;
            font-size: 12px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .member-rank {
            font-size: 10px;
            font-weight: 400;
            letter-spacing: 0.3px;
        }

        .member-badges-line {
            display: flex;
            flex-wrap: wrap;
            align-items: center;
        }

        .donator-badge {
            display: inline-block;
            margin-left: 6px;
            font-size: 10px;
            font-weight: 400;
            letter-spacing: 0.3px;
            color: #ffd700;
            text-shadow: 0 0 6px #ffd700, 0 0 10px #ffd700, 0 0 14px #ffb700;
        }

        .donator-purchase-box {
            display: flex;
            flex-direction: column;
            gap: 8px;
            width: 100%;
        }

        .donator-current {
            font-size: 12px;
            color: #ffd700;
            text-shadow: 0 0 4px #ffd700;
        }

        .donator-current:empty {
            display: none;
        }

        .donator-purchase-row {
            display: flex;
            align-items: center;
            gap: 6px;
        }

        .donator-euro-sign {
            color: #999;
            font-size: 13px;
        }

        .donator-amount-input {
            flex: 0 0 100px;
        }

        .donator-buy-btn {
            /* Same swap as .treuhand-wallet-btn: exact .ipsButton_primary grey
               (#484848 / #dddddd text) instead of .ipsButton_positive's green
               — this class covers every BTCPay button app-wide (Custom Rank,
               Donator, Treuhand top-up/withdraw, admin grant), so one change
               keeps all of them consistent with each other. */
            padding: 8px 14px;
            background-color: var(--btn-primary);
            border: 1px solid var(--btn-border);
            border-radius: var(--btn-radius);
            color: var(--btn-text);
            font-weight: 700;
            text-shadow: var(--btn-text-shadow);
            font-size: 12px;
            cursor: pointer;
            transition: all 0.1s linear;
            white-space: nowrap;
        }

        .donator-buy-btn:hover:not(:disabled) {
            background-image: var(--btn-hover-overlay);
        }

        .donator-buy-btn:active:not(:disabled) {
            background-image: var(--btn-active-overlay);
            box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.3) inset;
            border: 1px solid var(--btn-active-border);
        }

        .donator-buy-btn:disabled {
            opacity: 0.5;
            cursor: not-allowed;
        }

        .donator-hint {
            font-size: 11px;
            color: #777;
        }

        .custom-rank-box {
            display: flex;
            flex-direction: column;
            gap: 8px;
            width: 100%;
        }

        .custom-rank-label-row {
            display: flex;
            align-items: center;
            gap: 6px;
        }

        .custom-rank-label-row input {
            flex: 1;
        }

        .grant-custom-rank-row {
            display: flex;
            flex-direction: column;
            gap: 6px;
            margin-top: 16px;
            padding-top: 16px;
            border-top: 1px solid #444;
        }

        .member-avatar {
            width: 24px;
            height: 24px;
            border-radius: 2px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
            flex-shrink: 0;
            background-size: cover;
            background-position: center;
            background-repeat: no-repeat;
            cursor: pointer;
        }

        .context-menu {
            display: none;
            position: fixed;
            background: #2d2d2d;
            border: 1px solid #444;
            border-radius: 4px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.8);
            z-index: 300;
            min-width: 150px;
            overflow: hidden;
        }

        .context-menu.active {
            display: block;
        }

        .context-menu-item {
            padding: 10px 16px;
            color: #b0b0b0;
            cursor: pointer;
            border-bottom: 1px solid #3a3a3a;
            font-size: 13px;
        }

        .context-menu-item:last-child {
            border-bottom: none;
        }

        .context-menu-item:hover {
            background: #3a3a3a;
            color: #e0e0e0;
        }

        .context-menu-item-danger {
            color: #ff5c5c;
        }

        .context-menu-item-danger:hover {
            background: rgba(255, 92, 92, 0.15);
            color: #ff7b7b;
        }

        .rank-option-list {
            display: flex;
            flex-direction: column;
            gap: 8px;
        }

        .rank-option-btn {
            padding: 12px 16px;
            background: #2d2d2d;
            border: 1px solid #444;
            border-radius: 4px;
            cursor: pointer;
            font-size: 13px;
            font-weight: 400;
            text-align: left;
            transition: all 0.2s;
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .rank-option-btn input[type="checkbox"] {
            cursor: pointer;
        }

        .rank-option-btn:hover {
            background: #3a3a3a;
            border-color: #666;
        }

        .rank-option-btn.current {
            border-color: var(--btn-important);
            box-shadow: inset 0 0 0 1px var(--btn-important);
        }

        .rank-separator {
            color: #666;
            font-weight: 400;
        }

        .custom-rank-input-row {
            display: flex;
            gap: 8px;
            margin-top: 10px;
        }

        .custom-rank-input-row input {
            flex: 1;
            padding: 8px 10px;
            background: #1a1a1a;
            border: 1px solid #3a3a3a;
            border-radius: 2px;
            color: #b0b0b0;
            font-size: 13px;
        }

        .custom-rank-input-row input:focus {
            outline: none;
            border-color: #ffd23f;
        }

        .account-modal-overlay {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.6);
            z-index: 400;
            align-items: center;
            justify-content: center;
            padding: 20px;
        }

        .account-modal-overlay.active {
            display: flex;
        }

        .account-modal {
            background: #1a1a1a;
            border: 1px solid #444;
            border-radius: 6px;
            width: 100%;
            max-width: 700px;
            max-height: 90vh;
            overflow-y: auto;
        }

        .account-modal-title {
            padding: 20px 24px;
            font-size: 22px;
            color: #e0e0e0;
            font-weight: 400;
        }

        .account-modal-body {
            padding: 0 24px;
        }

        .account-row {
            display: flex;
            align-items: center;
            padding: 20px 0;
            border-top: 1px solid #333;
            gap: 20px;
        }

        .account-row-label {
            width: 120px;
            min-width: 120px;
            color: #999;
            font-size: 13px;
            text-align: right;
        }

        .premium-vendor-label {
            /* Same pink + glow as RANKS.Custom (#ff45c8) used when this rank
               is actually rendered next to a username, via renderRank()'s
               glowStyle formula (0 0 6px + 0 0 10px) — not a new invented
               pink, the same one this rank already renders in elsewhere. */
            color: #ff45c8;
            text-shadow: 0 0 6px #ff45c8, 0 0 10px #ff45c8;
        }

        .donator-label {
            /* Same gold + glow as .donator-badge (the real "★ Donator
               (€amount)" badge renderDonatorBadge() puts next to a paying
               user's name in chat/member list) -- not a new invented gold,
               the exact one this rank already renders in elsewhere. Mirrors
               .premium-vendor-label above doing the same for that rank. The
               label text itself stays the plain row name ("Donator:", no
               star/amount) at Björn's request -- just this settings-page
               preview, renderDonatorBadge()'s own real ★/amount elsewhere
               is untouched. */
            color: #ffd700;
            text-shadow: 0 0 6px #ffd700, 0 0 10px #ffd700, 0 0 14px #ffb700;
        }

        .account-row-value {
            flex: 1;
            display: flex;
            align-items: center;
            gap: 10px;
            color: #e0e0e0;
            font-size: 13px;
        }

        .account-checkbox-label {
            display: flex;
            align-items: center;
            gap: 8px;
            font-size: 13px;
            color: #d0d0d0;
            cursor: pointer;
        }

        .account-checkbox-label input[type="checkbox"] {
            cursor: pointer;
        }

        .account-input {
            flex: 1;
            padding: 8px 10px;
            background: #2d2d2d;
            border: 1px solid #444;
            border-radius: 4px;
            color: #e0e0e0;
            font-size: 13px;
        }

        .account-input:focus {
            outline: none;
            border-color: #666;
        }

        .account-change-btn {
            padding: 8px 16px;
            background: #3a3a3a;
            color: #e0e0e0;
            border: 1px solid #666;
            border-radius: 4px;
            cursor: pointer;
            font-size: 12px;
            font-weight: 400;
            white-space: nowrap;
            transition: all 0.2s;
        }

        .account-change-btn:hover {
            background: #454545;
        }

        .account-avatar-wrap {
            position: relative;
            width: 90px;
            height: 90px;
        }

        .account-avatar-preview {
            width: 90px;
            height: 90px;
            border-radius: 4px;
            background: #2d2d2d;
            border: 1px solid #444;
            background-size: cover;
            background-position: center;
        }

        .account-avatar-edit {
            position: absolute;
            bottom: -6px;
            right: -6px;
            width: 28px;
            height: 28px;
            border-radius: 4px;
            background: #3a3a3a;
            border: 1px solid #666;
            color: #e0e0e0;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 13px;
            transition: all 0.2s;
        }

        .account-avatar-edit:hover {
            background: #454545;
        }

        .account-modal-footer {
            padding: 20px 24px;
            border-top: 1px solid #333;
            display: flex;
            justify-content: center;
            gap: 12px;
        }

        .profile-modal {
            max-width: 380px;
        }

        .profile-card-header {
            display: flex;
            gap: 14px;
            padding: 22px 22px 16px 22px;
            align-items: flex-start;
        }

        .profile-card-avatar {
            width: 72px;
            height: 72px;
            min-width: 72px;
            border-radius: 8px;
            background-color: #2d2d2d;
            border: 1px solid #444;
            background-size: cover;
            background-position: center;
        }

        .profile-card-meta {
            display: flex;
            flex-direction: column;
            justify-content: center;
            gap: 5px;
            padding-top: 2px;
            min-width: 0;
        }

        .profile-card-name {
            font-size: 17px;
            font-weight: 400;
            color: #ececec;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .profile-card-rank {
            font-size: 11px;
            font-weight: 400;
        }

        .profile-dm-btn {
            border-radius: 4px;
            padding: 6px 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            margin-left: auto;
            flex-shrink: 0;
            align-self: flex-start;
        }

        .profile-card-line {
            font-size: 12px;
            color: #888;
        }

        .profile-card-line b {
            color: #ccc;
        }

        .profile-card-contacts {
            margin: 0 22px 20px 22px;
            background: #242424;
            border: 1px solid #3a3a3a;
            border-radius: 6px;
            overflow: hidden;
        }

        .profile-contact-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 10px 14px;
            border-bottom: 1px solid #333;
            font-size: 12px;
        }

        .profile-contact-row:last-child {
            border-bottom: none;
        }

        .profile-contact-label {
            color: #888;
            font-weight: 400;
        }

        .profile-contact-value {
            color: #ccc;
        }

        .profile-reviews-section {
            margin: 0 22px 20px 22px;
        }

        .profile-reviews-label {
            color: #888;
            font-size: 11px;
            margin-bottom: 8px;
        }

        .review-color-picker {
            display: flex;
            gap: 8px;
            margin-bottom: 8px;
        }

        .review-choice-btn {
            padding: 6px 12px;
            background: transparent;
            border: 1px solid #444;
            border-radius: 4px;
            cursor: pointer;
            font-size: 12px;
            font-weight: 400;
            transition: all 0.2s;
        }

        .review-choice-btn.positive { color: #6bbf6b; }
        .review-choice-btn.neutral { color: #999; }
        .review-choice-btn.negative { color: #d96b6b; }

        .review-choice-btn.positive:hover { border-color: #3ddc5c; }
        .review-choice-btn.neutral:hover { border-color: #999; }
        .review-choice-btn.negative:hover { border-color: #ff3b3b; }

        .review-choice-btn.selected.positive { background: rgba(61, 220, 92, 0.12); border-color: #3ddc5c; color: #3ddc5c; }
        .review-choice-btn.selected.neutral { background: rgba(153, 153, 153, 0.12); border-color: #999; color: #ccc; }
        .review-choice-btn.selected.negative { background: rgba(255, 59, 59, 0.12); border-color: #ff3b3b; color: #ff3b3b; }

        .review-comment-input {
            width: 100%;
            padding: 8px 10px;
            background: #2d2d2d;
            border: 1px solid #444;
            border-radius: 4px;
            color: #e0e0e0;
            font-size: 12px;
            font-family: inherit;
            resize: vertical;
            min-height: 44px;
            margin-bottom: 8px;
        }

        .review-comment-input:focus {
            outline: none;
            border-color: #666;
        }

        /* Exact .ipsButton_link recipe: transparent, #bdbdbd border/text. */
        .review-submit-btn {
            padding: 7px 12px;
            background: transparent;
            color: #bdbdbd;
            border: 1px solid #bdbdbd;
            border-radius: var(--btn-radius);
            cursor: pointer;
            font-size: 12px;
            font-weight: 700;
            transition: all 0.2s;
        }

        .review-submit-btn:hover { color: #ffffff; background-image: var(--btn-hover-overlay); }
        .review-submit-btn:disabled { opacity: 0.4; cursor: not-allowed; }

        .review-list {
            margin-top: 14px;
            display: flex;
            flex-direction: column;
            gap: 8px;
            max-height: 200px;
            overflow-y: auto;
        }

        .review-item {
            display: flex;
            gap: 8px;
            padding: 8px 10px;
            background: #242424;
            border: 1px solid #3a3a3a;
            border-radius: 4px;
            align-items: flex-start;
        }

        .review-item-dot {
            /* Bumped up from a plain 9px dot (was color-only) so a symbol
               actually fits and reads at a glance -- see the bar rules
               below. margin-top scaled down to match (was tuned to optically
               center a 9px dot against the review text's first line; keeps
               the same centering at the new size). position:relative makes
               this the anchor for the absolutely-centered bars. */
            position: relative;
            width: 14px;
            height: 14px;
            min-width: 14px;
            border-radius: 50%;
            margin-top: 2px;
        }

        /* Glow matches the exact "leuchtend in Rang-Farbe" recipe already
           used for rank labels (.premium-vendor-label / .donator-label:
           color X + text-shadow 0 0 6px X, 0 0 10px X) -- box-shadow here
           instead of text-shadow since the glowing element is a filled
           shape, not text, same radii/principle either way. */
        .review-item-dot.green { background: #3ddc5c; box-shadow: 0 0 6px #3ddc5c, 0 0 10px #3ddc5c; }
        .review-item-dot.gray { background: #999; box-shadow: 0 0 6px #999, 0 0 10px #999; }
        .review-item-dot.red { background: #ff3b3b; box-shadow: 0 0 6px #ff3b3b, 0 0 10px #ff3b3b; }

        /* One symbol per rating, on top of the color -- not color alone --
           at Björn's request: + for positive, / for neutral, − for negative.
           Drawn as small CSS bars (absolute + translate(-50%,-50%) off the
           dot's exact center) rather than font glyphs -- a font's own glyph
           box is not necessarily centered on its ink (a "/" in particular
           sits corner-to-corner, off-center against a circular dot), so
           this is the only way to guarantee all three sit dead-center and
           carry identical, matched stroke weight. Dark, not white -- still
           the better-contrast choice against all three fill colors above
           (checked against each with WCAG-style contrast math). */
        .review-item-dot::before,
        .review-item-dot::after {
            content: "";
            position: absolute;
            top: 50%;
            left: 50%;
            background: #1a1a1a;
            border-radius: 1px;
        }

        /* + : horizontal bar and vertical bar crossing at center */
        .review-item-dot.green::before { width: 8px; height: 2px; transform: translate(-50%, -50%); }
        .review-item-dot.green::after { width: 2px; height: 8px; transform: translate(-50%, -50%); }

        /* / : one bar, rotated to a forward-slash angle, centered the same
           way as the others -- same length/thickness so it carries the
           same visual weight as +/− instead of reading as the thin one. */
        .review-item-dot.gray::before { width: 2px; height: 9px; transform: translate(-50%, -50%) rotate(45deg); }

        /* − : proper minus-weight single horizontal bar (matches the +'s
           horizontal bar exactly, so + and − read as the same family) */
        .review-item-dot.red::before { width: 8px; height: 2px; transform: translate(-50%, -50%); }

        .review-item-body { flex: 1; min-width: 0; }

        .review-item-text {
            color: #ccc;
            font-size: 12px;
            line-height: 1.4;
            word-break: break-word;
        }

        .review-item-meta {
            color: #666;
            font-size: 10px;
            margin-top: 3px;
        }

        .review-item-author {
            color: #888;
            cursor: pointer;
        }

        .review-item-author:hover { color: #ccc; }

        .review-item-delete {
            background: transparent;
            border: none;
            color: #555;
            cursor: pointer;
            font-size: 12px;
            padding: 2px 4px;
            transition: color 0.2s;
        }

        .review-item-delete:hover { color: #ff5c5c; }

        .review-empty {
            color: #666;
            font-size: 12px;
            text-align: center;
            padding: 8px 0;
        }

        .account-close-btn {
            padding: 10px 12px;
            background: transparent;
            color: #666;
            border: none;
            border-radius: 0;
            cursor: pointer;
            font-size: 13px;
            transition: all 0.2s;
            font-weight: 400;
        }

        .account-close-btn:hover {
            color: #999;
        }

        .account-save-btn {
            padding: 10px 12px;
            background: transparent;
            color: var(--btn-text);
            border: none;
            border-radius: 0;
            cursor: pointer;
            font-size: 13px;
            font-weight: 700;
            transition: all 0.2s;
        }

        .account-save-btn:hover {
            color: #ffffff;
            background-image: var(--btn-hover-overlay);
        }

        .image-modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.8);
            z-index: 200;
            align-items: center;
            justify-content: center;
        }

        .image-modal.active {
            display: flex;
        }

        .image-modal img {
            max-width: 90vw;
            max-height: 90vh;
            border-radius: 4px;
        }

        ::-webkit-scrollbar {
            width: 10px;
        }

        ::-webkit-scrollbar-track {
            background: #2d2d2d;
        }

        ::-webkit-scrollbar-thumb {
            background: #444;
            border-radius: 4px;
        }

        ::-webkit-scrollbar-thumb:hover {
            background: #555;
        }
