:root {
    --color-bg: #f7f5f7;
    --color-surface: #ffffff;
    --color-text: #2b2530;
    --color-text-muted: #837c88;
    --color-border: #ece6ea;
    --color-accent: #8c3350;
    --color-accent-hover: #79293f;
    --color-accent-soft: rgba(140, 51, 80, 0.12);
    --color-link: #6672d6;
    --color-link-hover: #525fc4;
    /* Incoming message bubbles (message-bubble--own uses --color-accent-soft
       instead — see .message-bubble below) — its own variable rather than
       reusing --color-surface, since a bubble needs to read as "raised"
       against --color-bg specifically, and the two have different
       relationships to each other in light vs dark mode (see the dark
       override below). */
    --color-bubble-other: #efedf1;
    --radius-lg: 16px;
    --radius-md: 12px;
    --radius-pill: 999px;
    --shadow-soft: 0 8px 24px rgba(43, 38, 32, 0.06);
    --shadow-soft-lg: 0 16px 40px rgba(43, 38, 32, 0.08);
    --font-sans: 'Nunito', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}

/*
 * Dark theme — same variable set as :root above, just remapped. Set on
 * <html> (not <body>) by the blocking script in partials/layout.php's
 * <head>, before custom.css even finishes loading, specifically so there's
 * no flash of the light theme on page load; the moon/sun toggle in the
 * app rail (chat-app-rail.php) flips this attribute + writes the choice
 * to localStorage from then on (see chat.php's rail click handler).
 *
 * Every selector elsewhere in this file that already reads a --color-*
 * variable repaints correctly for free. What's NOT remapped here: a
 * couple dozen one-off hardcoded colors (status pills, avatar-placeholder
 * gradients, plain "#fff" for text sitting on top of an accent-colored
 * background) that either read fine unchanged against either theme or are
 * cosmetic-only — worth a follow-up visual pass, not a functional gap.
 */
html[data-theme="dark"] {
    /* Tinted toward the brand maroon instead of a neutral gray-black, and
       the accent itself pushed bolder/more saturated than a straight
       lightness-bump of the light-mode value would give — a flat
       desaturated dark theme was reading as plain black rather than an
       iTeChat-branded one. */
    --color-bg: #1a1015;
    --color-surface: #241621;
    --color-text: #f1edf1;
    --color-text-muted: #b299a3;
    --color-border: #3a2530;
    --color-accent: #d1477a;
    --color-accent-hover: #e6689a;
    --color-accent-soft: rgba(209, 71, 122, 0.25);
    --color-link: #8891e8;
    --color-link-hover: #a0a8ee;
    /* Lighter than --color-surface (#241621) so an incoming bubble still
       reads as "raised" above the sidebar/panel surfaces around it, same
       relationship --color-bubble-other has to --color-bg in light mode. */
    --color-bubble-other: #362530;
    --shadow-soft: 0 8px 24px rgba(0, 0, 0, 0.35);
    --shadow-soft-lg: 0 16px 40px rgba(0, 0, 0, 0.45);
}

* {
    box-sizing: border-box;
}

html, body {
    height: 100%;
}

body {
    font-family: var(--font-sans);
    background-color: var(--color-bg);
    color: var(--color-text);
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

main {
    flex: 1;
    display: flex;
    flex-direction: column;
}

a {
    color: var(--color-link);
    text-decoration: none;
}

a:hover {
    color: var(--color-link-hover);
}

/* Nav */

.site-nav {
    background-color: var(--color-bg);
    border-bottom: 1px solid var(--color-border);
}

.site-nav__inner {
    max-width: 1100px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.site-nav__logo {
    display: flex;
    align-items: center;
    font-weight: 800;
    font-size: 1.25rem;
    color: var(--color-text);
}

.site-nav__logo:hover {
    color: var(--color-text);
}

.site-nav__logo-img {
    height: 100px;
    width: auto;
    display: block;
}

.site-nav__actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.site-nav__link {
    color: var(--color-text);
    font-weight: 600;
    text-decoration: none;
    padding: 0.5rem 1rem;
}

.site-nav__link:hover {
    color: var(--color-link);
}

.site-nav__cta {
    padding: 0.55rem 1.35rem;
}

/* Buttons */

.btn {
    font-family: var(--font-sans);
    font-weight: 700;
    border-radius: var(--radius-md);
    transition: box-shadow 0.2s ease, transform 0.2s ease, background-color 0.2s ease;
}

.btn-pill {
    border-radius: var(--radius-pill);
    padding-left: 1.75rem;
    padding-right: 1.75rem;
}

.btn-primary {
    background-color: var(--color-accent);
    border-color: var(--color-accent);
    color: #fff;
}

.btn-primary:hover,
.btn-primary:focus {
    background-color: var(--color-accent-hover);
    border-color: var(--color-accent-hover);
    box-shadow: 0 6px 16px rgba(140, 51, 80, 0.28);
    transform: translateY(-1px);
    color: #fff;
}

.btn-outline-secondary {
    background-color: transparent;
    border-color: var(--color-border);
    color: var(--color-text);
}

.btn-outline-secondary:hover {
    background-color: var(--color-surface);
    border-color: var(--color-border);
    color: var(--color-text);
    box-shadow: var(--shadow-soft);
    transform: translateY(-1px);
}

.btn-link {
    text-decoration: none;
    font-weight: 600;
}

.btn:focus,
.btn:focus-visible {
    box-shadow: 0 0 0 4px var(--color-accent-soft);
    outline: none;
}

/* Forms */

.form-label {
    font-weight: 700;
    font-size: 0.9rem;
    margin-bottom: 0.4rem;
}

.form-control {
    font-family: var(--font-sans);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: 0.75rem 1rem;
    font-size: 1rem;
    background-color: var(--color-surface);
}

.form-control::placeholder {
    color: #b7b0a4;
}

.form-control:focus {
    border-color: var(--color-accent);
    box-shadow: 0 0 0 4px var(--color-accent-soft);
}

/* Hero */

.hero {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 4rem 1.5rem;
}

.hero__grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: center;
    gap: 3.5rem;
    max-width: 1100px;
    width: 100%;
}

.hero__media-img {
    display: block;
    width: 100%;
    max-width: 420px;
    height: auto;
    margin: 0 auto;
}

.hero__content {
    text-align: left;
}

.hero__title {
    font-weight: 800;
    font-size: 2.75rem;
    line-height: 1.15;
    margin-bottom: 1rem;
}

.hero__subtitle {
    color: var(--color-text-muted);
    font-size: 1.15rem;
    margin-bottom: 2.25rem;
}

.hero__actions {
    display: flex;
    gap: 0.75rem;
    justify-content: flex-start;
    flex-wrap: wrap;
}

@media (max-width: 760px) {
    .hero__grid {
        grid-template-columns: 1fr;
        text-align: center;
    }

    .hero__content {
        text-align: center;
    }

    .hero__actions {
        justify-content: center;
    }
}

/* Auth pages */

.auth-page {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 3rem 1.5rem;
}

.auth-card {
    width: 100%;
    max-width: 420px;
    background-color: var(--color-surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-soft-lg);
    padding: 2.5rem 2.25rem;
}

.auth-card__title {
    font-weight: 800;
    font-size: 1.6rem;
    text-align: center;
    margin-bottom: 0.5rem;
}

.auth-card__subtitle {
    color: var(--color-text-muted);
    text-align: center;
    font-size: 0.95rem;
    margin-bottom: 2rem;
}

.auth-form__link {
    font-size: 0.9rem;
    font-weight: 600;
}

.auth-form__footer {
    text-align: center;
    color: var(--color-text-muted);
    font-size: 0.9rem;
    margin-top: 1.75rem;
    margin-bottom: 0;
}

.auth-form__footer a {
    font-weight: 700;
}

/* Chat app shell */

body.page-chat {
    /* 100vh on mobile Chrome/Safari is measured against the LARGEST
       possible viewport (as if the address bar were already hidden),
       not the actual visible area while it's still showing — so this
       box used to render taller than the real screen. Combined with
       overflow:hidden just below (needed so the page itself never
       scrolls; every inner panel scrolls on its own instead), that
       extra height wasn't just wasted, it was unreachable: the
       composer is the last flex child at the bottom of .chat-window,
       so it was the piece pushed below the real fold.
       100dvh tracks the actual visible viewport as the browser chrome
       shows/hides, so this box is never taller than what's really on
       screen. Kept the plain 100vh above it as a fallback for browsers
       old enough not to support dvh.
       min-height: 0 is doing real work here, not just tidiness — the
       base `body { min-height: 100vh; }` rule further up this file
       still applies to body.page-chat too (different property, so it's
       not "overridden" by the height declarations above at all), and
       min-height always wins over a smaller height. Without this, that
       inherited min-height:100vh silently forced this box back up to
       the taller "address bar hidden" size every time the address bar
       was actually showing — completely canceling the 100dvh fix above
       without it looking like anything was wrong in this rule itself. */
    height: 100vh;
    height: 100dvh;
    min-height: 0;
    overflow: hidden;
}

body.page-chat main {
    flex: 1;
    min-height: 0;
    overflow: hidden;
}

.chat-app {
    position: relative;
    flex: 1;
    min-height: 0;
    display: flex;
    overflow: hidden;
    background-color: var(--color-surface);
}

/* App rail (far-left icon sidebar) */

.app-rail {
    width: 72px;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.4rem;
    padding: 1rem 0;
    background-color: var(--color-surface);
    border-right: 1px solid var(--color-border);
}

.app-rail__item {
    width: 44px;
    height: 44px;
    border-radius: 14px;
    border: none;
    background: transparent;
    color: var(--color-text-muted);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.app-rail__item:hover {
    background-color: var(--color-bg);
    color: var(--color-text);
}

.app-rail__item.is-active {
    background-color: var(--color-accent-soft);
    color: var(--color-accent);
}

/* Settings cog (ceo_admin only) — pinned to the bottom of the desktop
   rail, separate from the section-switching buttons above it. Scoped to
   #appRail specifically so it doesn't affect the mobile tab bar's copy of
   the same button, which is a horizontal row (margin-top: auto there
   would just cross-axis-align it, not push it anywhere useful). */
#appRail .app-rail__item--settings {
    margin-top: auto;
}

/* Mobile bottom tab bar — same sections as .app-rail, shown instead of
   it below 900px (see the max-width:900px rules further down). Hidden
   here by default so it doesn't render as a stray block on desktop. */

.mobile-tab-bar {
    display: none;
}

/* Hamburger trigger (chat-sidebar.php's profile row) + the overflow
   drawer it opens (chat-app-rail.php). Both hidden by default so they
   never render as stray elements on desktop, where the full rail already
   shows Media/Theme/Settings directly — see the max-width:900px rules
   further down for their real, mobile-only layout. */
.mobile-menu-btn {
    display: none;
}

.mobile-menu-drawer {
    display: none;
}

/* Avatars & status dots */

.avatar-wrap {
    position: relative;
    flex-shrink: 0;
}

.avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background-color: var(--color-accent-soft);
    color: var(--color-accent);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 0.72rem;
    letter-spacing: 0.02em;
    overflow: hidden;
    flex-shrink: 0;
}

.avatar--lg {
    width: 40px;
    height: 40px;
    font-size: 0.82rem;
}

.avatar--sm {
    width: 22px;
    height: 22px;
    font-size: 0.6rem;
}

.avatar--channel {
    background-color: var(--color-border);
    color: var(--color-text-muted);
    font-weight: 800;
}

.avatar--project {
    background-color: rgba(102, 114, 214, 0.14);
    color: var(--color-link);
    font-weight: 800;
}

/* Org-wide "group chat" (everyone in the organization) — same treatment
   as a regular DM avatar (colored initials circle, not a "#" channel
   icon), just its own tint so it's still visually distinct from a
   one-on-one DM at a glance. */
.avatar--group {
    background-color: rgba(76, 158, 116, 0.16);
    color: #2f8a5c;
    font-weight: 800;
}

.status-dot {
    position: absolute;
    bottom: -1px;
    right: -1px;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    border: 2px solid var(--color-surface);
}

.status-dot--online {
    background-color: #45b57e;
}

.status-dot--away {
    background-color: #e3a13c;
}

.status-dot--offline {
    background-color: #c9c3cc;
}

/* Icon buttons */

.icon-btn {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    background: transparent;
    color: var(--color-text-muted);
    flex-shrink: 0;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.icon-btn:hover {
    background-color: var(--color-bg);
    color: var(--color-text);
}

/* Sidebar */

.chat-sidebar {
    width: 280px;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    background-color: var(--color-surface);
    border-right: 1px solid var(--color-border);
    min-height: 0;
}

.chat-sidebar__profile {
    position: relative;
    display: flex;
    align-items: center;
    border-bottom: 1px solid var(--color-border);
    flex-shrink: 0;
}

.chat-sidebar__profile-toggle {
    display: flex;
    align-items: center;
    flex: 1;
    min-width: 0;
    gap: 0.75rem;
    padding: 1.1rem 1.25rem;
    border: none;
    background: transparent;
    font: inherit;
    color: inherit;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 0.15s ease;
}

.chat-sidebar__profile-toggle:hover {
    background-color: var(--color-bg);
}

.chat-sidebar__profile-info {
    flex: 1;
    min-width: 0;
}

.chat-sidebar__profile-name {
    font-weight: 700;
    font-size: 0.9rem;
    margin: 0;
}

.chat-sidebar__search {
    padding: 0.9rem 1.1rem 0.5rem;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.chat-sidebar__search .search-field {
    flex: 1;
    min-width: 0;
}

.chat-sidebar__new-btn {
    flex-shrink: 0;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    border: none;
    background-color: var(--color-accent);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    box-shadow: var(--shadow-soft);
    transition: background-color 0.15s ease;
}

.chat-sidebar__new-btn:hover {
    background-color: var(--color-accent-hover);
}

.search-field {
    position: relative;
    display: flex;
    align-items: center;
}

.search-field__icon {
    position: absolute;
    left: 0.85rem;
    color: var(--color-text-muted);
    pointer-events: none;
}

.search-field__input {
    width: 100%;
    font-family: var(--font-sans);
    border: 1px solid var(--color-border);
    background-color: var(--color-bg);
    border-radius: var(--radius-pill);
    padding: 0.55rem 0.9rem 0.55rem 2.4rem;
    font-size: 0.85rem;
    color: var(--color-text);
}

.search-field__input::placeholder {
    color: #b0a8b6;
}

.search-field__input:focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 4px var(--color-accent-soft);
    background-color: var(--color-surface);
}

.sidebar-section {
    display: none;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 0.4rem 0.6rem 1rem;
    flex-direction: column;
    gap: 0.15rem;
}

.sidebar-section.is-active {
    display: flex;
}

.sidebar-empty {
    padding: 2.5rem 1.25rem;
    text-align: center;
    color: var(--color-text-muted);
}

.sidebar-empty p {
    margin: 0 0 0.3rem;
    font-size: 0.9rem;
}

.sidebar-empty__hint {
    font-size: 0.78rem;
}

/* Admin-only "Notices you've sent" section at the top of the sidebar's
   Notifications tab (see chat-sidebar.php) — reuses .notice-card and
   .settings-list/.settings-empty-state as-is from the Settings → Notices
   styling above, just adds the section heading/divider around them. */

.sidebar-notices {
    padding: 0.85rem 1rem 0;
}

.sidebar-notices .settings-list {
    gap: 0.6rem;
}

.sidebar-notices__heading {
    margin: 0 0 0.6rem;
    font-size: 0.72rem;
    font-weight: 800;
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.sidebar-notices__divider {
    margin: 1rem 1rem 0.4rem;
    font-size: 0.72rem;
    font-weight: 800;
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    padding-top: 0.75rem;
    border-top: 1px solid var(--color-border);
}

.notification-row {
    display: flex;
    align-items: flex-start;
    gap: 0.65rem;
    padding: 0.6rem 0.65rem;
    border-radius: var(--radius-md);
}

.notification-row.is-unread {
    background-color: var(--color-accent-soft);
}

.notification-row__icon {
    flex-shrink: 0;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background-color: var(--color-surface);
    color: var(--color-accent);
    display: flex;
    align-items: center;
    justify-content: center;
}

.notification-row__meta {
    flex: 1;
    min-width: 0;
}

.notification-row__message {
    margin: 0;
    font-size: 0.82rem;
    line-height: 1.35;
    display: flex;
    align-items: baseline;
    gap: 0.3rem;
}

.notification-row__time {
    font-size: 0.7rem;
    color: var(--color-text-muted);
}

.notification-row--expandable {
    cursor: pointer;
}

.notification-row__chevron {
    font-size: 0.68rem;
    color: var(--color-text-muted);
    transition: transform 0.15s ease;
    flex-shrink: 0;
}

.notification-row--expandable.is-expanded .notification-row__chevron {
    transform: rotate(180deg);
}

.notification-row__body {
    margin: 0.35rem 0 0;
    font-size: 0.8rem;
    color: var(--color-text);
    line-height: 1.45;
}

/* Unread dot on the Notifications bell — shared by the desktop rail and
   the mobile tab bar (see chat-app-rail.php), both of which need
   position: relative for it to anchor correctly. */
.app-rail__item {
    position: relative;
}

.rail-badge {
    position: absolute;
    top: 1px;
    right: 1px;
    min-width: 17px;
    height: 17px;
    padding: 0 4px;
    box-sizing: border-box;
    border-radius: var(--radius-pill);
    background-color: var(--color-accent);
    border: 2px solid var(--color-surface);
    color: #fff;
    font-size: 0.62rem;
    font-weight: 800;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
}

.rail-badge--tab-bar {
    top: -3px;
    right: calc(50% - 20px);
    /* The mobile tab bar itself is solid --color-accent (see the
       max-width:900px rules), so the default accent-on-white badge would
       vanish against it — invert to accent-on-white instead. */
    background-color: #fff;
    border-color: var(--color-accent);
    color: var(--color-accent);
}

/* Moon/sun theme toggle (chat-app-rail.php, under the Refresh button).
   Both icons are always in the DOM; which one shows is a pure CSS read of
   <html data-theme>, set before paint by layout.php's blocking script —
   so the right icon is correct on first paint too, not just after a click
   swaps a class. Shows the icon for the mode a click would switch *to*
   (moon while light, sun while dark), same convention chat.php's JS
   mirrors when it updates the button's aria-label on toggle. */
.theme-toggle-icon--sun {
    display: none;
}

html[data-theme="dark"] .theme-toggle-icon--moon {
    display: none;
}

html[data-theme="dark"] .theme-toggle-icon--sun {
    display: block;
}

.chat-sidebar__logout {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    padding: 0.55rem 0.65rem;
    border: none;
    background: transparent;
    border-radius: var(--radius-md);
    color: var(--color-text-muted);
    font-family: inherit;
    font-weight: 600;
    font-size: 0.85rem;
    text-align: left;
    cursor: pointer;
}

.chat-sidebar__logout:hover,
.chat-sidebar__logout:focus {
    background-color: var(--color-bg);
    color: var(--color-accent);
}

.chat-sidebar__footer {
    flex-shrink: 0;
    padding: 0.6rem;
    border-top: 1px solid var(--color-border);
}

.chat-sidebar__footer form {
    margin: 0;
}

/* PWA push-notification toggle — same row treatment as .chat-sidebar__logout
   (they share the footer), plus a small pill switch on the right so the
   on/off state reads at a glance. Hidden by default in markup; JS
   (initPushToggle() in chat.php) reveals it only when the browser
   actually supports the Push API. */
.chat-sidebar__push-toggle {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    padding: 0.55rem 0.65rem;
    border: none;
    background: transparent;
    border-radius: var(--radius-md);
    color: var(--color-text-muted);
    font-family: inherit;
    font-weight: 600;
    font-size: 0.85rem;
    text-align: left;
    cursor: pointer;
}

.chat-sidebar__push-toggle:hover,
.chat-sidebar__push-toggle:focus {
    background-color: var(--color-bg);
    color: var(--color-accent);
}

.chat-sidebar__push-toggle-label {
    flex: 1;
}

.chat-sidebar__push-toggle-switch {
    position: relative;
    width: 30px;
    height: 18px;
    flex-shrink: 0;
    border-radius: 999px;
    background-color: var(--color-border);
    transition: background-color 0.15s ease;
}

.chat-sidebar__push-toggle-switch::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background-color: #fff;
    transition: transform 0.15s ease;
}

.chat-sidebar__push-toggle.is-on .chat-sidebar__push-toggle-switch {
    background-color: var(--color-accent);
}

.chat-sidebar__push-toggle.is-on .chat-sidebar__push-toggle-switch::after {
    transform: translateX(12px);
}

.chat-sidebar__push-toggle:disabled {
    opacity: 0.6;
    cursor: default;
}

.conversation-row {
    display: flex;
    align-items: flex-start;
    gap: 0.7rem;
    width: 100%;
    text-align: left;
    padding: 0.6rem 0.65rem;
    border: none;
    background: transparent;
    border-radius: var(--radius-md);
    cursor: pointer;
    font-family: var(--font-sans);
    color: inherit;
}

.conversation-row:hover {
    background-color: var(--color-bg);
}

.conversation-row.is-active {
    background-color: var(--color-accent-soft);
}

.conversation-row__meta {
    flex: 1;
    min-width: 0;
}

.conversation-row__top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
}

.conversation-row__name {
    flex: 1;
    min-width: 0;
    font-weight: 700;
    font-size: 0.87rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.conversation-row__time {
    font-size: 0.7rem;
    color: var(--color-text-muted);
    flex-shrink: 0;
}

.conversation-row__preview {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-top: 0.15rem;
}

.conversation-row__preview-text {
    flex: 1;
    min-width: 0;
    font-size: 0.8rem;
    color: var(--color-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.conversation-row__badge {
    flex-shrink: 0;
    background-color: var(--color-accent);
    color: #fff;
    font-size: 0.68rem;
    font-weight: 700;
    border-radius: var(--radius-pill);
    min-width: 18px;
    height: 18px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 5px;
}

/* WhatsApp-style "you were mentioned" chip — sits alongside the unread
   count badge above (see chat_message_to_row()'s reply/mention handling
   and MessageRepository::hasUnreadMention()), a distinct green rather
   than the app's own accent color so it reads as its own signal even
   when both are showing on the same row. Same green as
   .status-dot--online, for one consistent "this is a live/active signal"
   color across the app. */
.conversation-row__mention {
    flex-shrink: 0;
    background-color: #45b57e;
    color: #fff;
    font-size: 0.66rem;
    font-weight: 800;
    border-radius: 50%;
    width: 18px;
    height: 18px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
}

/* Chat window (center) */

.chat-window {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    background-color: var(--color-bg);
}

.chat-window__header {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.8rem 1.5rem;
    background-color: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
}

.chat-window__back {
    display: none;
}

.chat-window__header-info {
    flex: 1;
    min-width: 0;
}

.chat-window__title {
    font-weight: 800;
    font-size: 0.98rem;
    margin: 0;
}

.chat-window__subtitle {
    font-size: 0.76rem;
    color: var(--color-text-muted);
    margin: 0;
}

.chat-window__subtitle--clickable {
    cursor: pointer;
    width: fit-content;
}

.chat-window__subtitle--clickable:hover,
.chat-window__subtitle--clickable:focus-visible {
    text-decoration: underline;
    color: var(--color-text);
}

.chat-window__actions {
    display: flex;
    align-items: center;
    gap: 0.15rem;
}

.chat-window__actions .icon-btn.is-active {
    background-color: var(--color-accent-soft);
    color: var(--color-accent);
}

/* Best-effort in-conversation search bar (see runChatSearch() in
   chat.php) — a second row under the header rather than replacing it,
   so title/avatar/other actions stay put while it's open. */
.chat-search-bar {
    display: none;
    align-items: center;
    gap: 0.6rem;
    flex-shrink: 0;
    padding: 0.55rem 1.5rem;
    background-color: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    color: var(--color-text-muted);
}

.chat-search-bar:not([hidden]) {
    display: flex;
}

.chat-search-bar__icon {
    flex-shrink: 0;
}

.chat-search-bar__input {
    flex: 1;
    min-width: 0;
    border: none;
    background: transparent;
    font: inherit;
    color: var(--color-text);
    outline: none;
}

.chat-search-bar__count {
    flex-shrink: 0;
    font-size: 0.78rem;
    white-space: nowrap;
}

.chat-search-bar__nav[disabled] {
    opacity: 0.35;
    cursor: default;
}

.chat-search-bar__nav[disabled]:hover {
    background-color: transparent;
    color: var(--color-text-muted);
}

mark.chat-search-mark {
    background-color: #ffe58a;
    /* Fixed dark text, not "inherit" — this stays the same light yellow in
       both themes (a highlight color doesn't really have a "dark mode"),
       so inheriting --color-text would pair it with near-white text once
       that variable flips dark, same unreadable-bubble bug as
       .message-bubble had. */
    color: #2b2530;
    border-radius: 2px;
    padding: 0 1px;
    cursor: pointer;
}

mark.chat-search-mark.is-current {
    background-color: var(--color-accent);
    color: #fff;
}

.message-list {
    flex: 1;
    /* Without this, a flex child defaults to min-height:auto — it won't
       shrink below its own content's height, so once a conversation has
       enough messages this box just grows to fit all of them instead of
       clipping to its allotted space and scrolling internally.
       .chat-window has no overflow of its own to catch that overflow
       either, so the excess (message list content + everything below
       it, including the composer) just renders past the bottom of the
       screen — unreachable, since the only scrollable ancestor is the
       page body, which is deliberately overflow:hidden on mobile (see
       body.page-chat) so each panel scrolls on its own instead. */
    min-height: 0;
    overflow-y: auto;
    padding: 1.1rem 1.5rem;
}

.message-panel {
    display: none;
    flex-direction: column;
    min-height: 100%;
}

.message-panel.is-active {
    display: flex;
}

.message-list__empty {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-text-muted);
    font-size: 0.95rem;
    text-align: center;
}

.system-message {
    text-align: center;
    color: var(--color-text-muted);
    font-size: 0.76rem;
    margin: 1.1rem 0;
}

.date-separator {
    display: flex;
    justify-content: center;
    margin: 1.1rem 0 0.75rem;
}

.date-separator span {
    background-color: var(--color-bg);
    color: var(--color-text-muted);
    font-size: 0.72rem;
    font-weight: 700;
    padding: 0.3rem 0.85rem;
    border-radius: 999px;
    border: 1px solid var(--color-border);
}

.message-group {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}

.message-group.is-own {
    flex-direction: row-reverse;
}

.message-group__avatar {
    width: 32px;
    flex-shrink: 0;
}

.message-group__body {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    max-width: 60%;
}

.message-group.is-own .message-group__body {
    align-items: flex-end;
}

.message-group__sender {
    font-size: 0.76rem;
    font-weight: 700;
    margin-bottom: 0.25rem;
}

.message-group__item {
    display: flex;
    flex-direction: column;
    position: relative;
}

.message-group.is-own .message-group__item {
    align-items: flex-end;
}

.message-group__item + .message-group__item {
    margin-top: 0.15rem;
}

.message-bubble {
    background-color: var(--color-bubble-other);
    color: var(--color-text);
    padding: 0.4rem 0.7rem;
    border-radius: 16px;
    font-size: 0.83rem;
    line-height: 1.4;
    word-break: break-word;
}

.message-bubble--own {
    background-color: var(--color-accent-soft);
}

.message-bubble--deleted {
    background-color: transparent;
    border: 1px dashed var(--color-border);
    color: var(--color-text-muted);
    font-size: 0.8rem;
    padding: 0.35rem 0.7rem;
}

/* WhatsApp-style quoted reply preview, shown inside a bubble above its
   own content (see message-bubble.php / replyQuoteHtml() in chat.php).
   A slightly darker/lighter overlay of the bubble's own background
   (rather than a fixed color) so it reads correctly on both the own-
   message and other-message bubble colors. */
.message-reply-quote {
    display: flex;
    flex-direction: column;
    gap: 0.05rem;
    padding: 0.3rem 0.55rem;
    margin-bottom: 0.35rem;
    border-left: 3px solid var(--color-accent);
    border-radius: 6px;
    background-color: rgba(0, 0, 0, 0.05);
    cursor: pointer;
    max-width: 260px;
}

.message-bubble--own .message-reply-quote {
    background-color: rgba(255, 255, 255, 0.35);
}

/* Own bubbles are var(--color-accent-soft) — a translucent pink already,
   not a solid color — so the light-mode overlay above (rgba white, meant
   to lighten a solid light-pink bubble) instead washes dark mode's bubble
   out to a pale grayish-pink box, on top of which both the sender name
   (--color-accent, a bright pink) and preview (--color-text-muted, a
   mid-tone mauve) read as low-contrast. A dark overlay instead deepens
   the bubble toward black, which both of those colors already have
   plenty of contrast against. */
html[data-theme="dark"] .message-bubble--own .message-reply-quote {
    background-color: rgba(0, 0, 0, 0.3);
}

.message-reply-quote__sender {
    font-size: 0.72rem;
    font-weight: 700;
    color: var(--color-accent);
}

.message-reply-quote__preview {
    font-size: 0.76rem;
    color: var(--color-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Briefly flashed on the original message when its quoted reply is
   clicked (see the .message-reply-quote click handler in chat.php) —
   fades back out on its own rather than needing a second click. */
.message-group__item--highlight .message-bubble {
    animation: message-highlight-flash 1.6s ease;
}

@keyframes message-highlight-flash {
    0% { box-shadow: 0 0 0 3px var(--color-accent-soft); }
    70% { box-shadow: 0 0 0 3px var(--color-accent-soft); }
    100% { box-shadow: 0 0 0 0 transparent; }
}

.mention {
    color: var(--color-accent);
    font-weight: 700;
    background-color: var(--color-accent-soft);
    border-radius: 4px;
    padding: 0 0.15rem;
}

.message-link {
    color: inherit;
    text-decoration: underline;
    text-decoration-color: currentColor;
    word-break: break-all;
}

.message-link:hover,
.message-link:focus {
    opacity: 0.8;
}

/* Rich text formatting inside message bubbles */

.message-bubble__text strong {
    font-weight: 700;
}

.message-bubble__text em {
    font-style: italic;
}

.msg-code {
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    font-size: 0.8em;
    background-color: rgba(0, 0, 0, 0.07);
    border-radius: 4px;
    padding: 0.1em 0.35em;
}

.message-bubble--own .msg-code {
    background-color: rgba(0, 0, 0, 0.1);
}

.msg-blockquote {
    margin: 0.2rem 0;
    padding: 0.15rem 0.6rem;
    border-left: 3px solid var(--color-accent);
    color: var(--color-text-muted);
    font-style: italic;
}

.msg-list {
    margin: 0.2rem 0 0.2rem 1.1rem;
    padding: 0;
}

.msg-list li {
    margin-bottom: 0.1rem;
}

.message-attachment {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    width: 220px;
    height: 140px;
    border-radius: 14px;
    background: linear-gradient(135deg, #ece6ea, #e2dbe6);
    color: var(--color-text-muted);
    font-size: 0.78rem;
}

.message-reactions {
    display: flex;
    gap: 0.3rem;
    margin-top: 0.3rem;
}

.reaction-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    padding: 0.15rem 0.55rem;
    font-size: 0.76rem;
    box-shadow: var(--shadow-soft);
}

.message-bubble__footer {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    margin-top: 0.2rem;
    opacity: 0;
    transition: opacity 0.15s ease;
}

.message-group__item:hover .message-bubble__footer,
.message-group__item--last .message-bubble__footer,
.message-group__item--failed .message-bubble__footer {
    opacity: 1;
}

.message-bubble__time {
    font-size: 0.66rem;
    color: var(--color-text-muted);
}

.message-edited-label {
    font-size: 0.66rem;
    color: var(--color-text-muted);
    font-style: italic;
}

/* Optimistic sends — appended the instant you hit send, before the
   server has confirmed anything (see sendMessage()/reconcilePendingMessage()
   in chat.php). Dimmed + a small clock instead of a timestamp until the
   real message comes back; a thin red outline and a click-to-retry label
   if it never does. */
.message-bubble--pending {
    opacity: 0.65;
}

.message-bubble__time--pending {
    display: inline-flex;
    align-items: center;
    color: var(--color-text-muted);
}

.message-bubble--failed {
    border: 1px solid rgba(217, 83, 79, 0.45);
}

.message-group__item--failed {
    cursor: pointer;
}

.message-failed-label {
    font-size: 0.66rem;
    color: #c0392b;
    font-weight: 700;
}

/* Own-message hover actions — a small chevron trigger (shown on hover,
   same affordance WhatsApp uses) that opens a dropdown menu of whichever
   actions apply to this message (reply / reply privately / edit / delete
   — the exact same set message-bubble.php already computed), instead of a
   row of always-visible icon buttons. Deliberately styled like
   .attach-menu/.attach-menu__item below — same dropdown-menu visual
   language (surface bg, border, shadow, icon + label rows) already used
   elsewhere in this app. */

.message-actions {
    position: absolute;
    top: -0.4rem;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.12s ease;
}

.message-group.is-own .message-actions {
    left: -0.4rem;
}

.message-group:not(.is-own) .message-actions {
    right: -0.4rem;
}

.message-group__item:hover .message-actions,
.message-actions.is-open {
    opacity: 1;
    pointer-events: auto;
}

.message-actions__trigger {
    width: 22px;
    height: 22px;
    border: 1px solid var(--color-border);
    border-radius: 50%;
    background-color: var(--color-surface);
    color: var(--color-text-muted);
    box-shadow: var(--shadow-soft);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

.message-actions__trigger:hover,
.message-actions.is-open .message-actions__trigger {
    background-color: var(--color-bg);
    color: var(--color-text);
}

.message-actions__menu {
    display: none;
    position: absolute;
    top: calc(100% + 0.3rem);
    flex-direction: column;
    min-width: 10rem;
    padding: 0.35rem;
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-soft-lg);
    z-index: 5;
}

.message-group.is-own .message-actions__menu {
    right: 0;
}

.message-group:not(.is-own) .message-actions__menu {
    left: 0;
}

.message-actions.is-open .message-actions__menu {
    display: flex;
}

.message-actions__menu-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.6rem;
    border-radius: var(--radius-md);
    background: transparent;
    border: none;
    text-align: left;
    font-size: 0.82rem;
    color: var(--color-text);
    cursor: pointer;
    white-space: nowrap;
}

.message-actions__menu-item:hover {
    background-color: var(--color-bg);
}

.message-actions__menu-icon {
    flex-shrink: 0;
    color: var(--color-text-muted);
}

/* Attachments — inline image thumbnail or a file card */

.attachment-image {
    display: block;
    max-width: 220px;
    max-height: 220px;
    border-radius: 12px;
    object-fit: cover;
    cursor: pointer;
    background-color: var(--color-border);
}

.attachment-file {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.6rem;
    border-radius: 12px;
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    color: var(--color-text);
    max-width: 220px;
}

.attachment-file:hover {
    border-color: var(--color-accent);
}

.attachment-file__icon {
    font-size: 1.2rem;
    flex-shrink: 0;
}

.attachment-file__meta {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.attachment-file__name {
    font-size: 0.78rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.attachment-file__size {
    font-size: 0.68rem;
    color: var(--color-text-muted);
}

.attachment-audio {
    display: block;
    width: 220px;
    max-width: 100%;
    height: 36px;
}

.attachment-audio__unavailable {
    display: block;
    font-size: 0.78rem;
    color: var(--color-text-muted);
    font-style: italic;
}

.message-bubble .attachment-image + .message-bubble__text,
.message-bubble .attachment-file + .message-bubble__text,
.message-bubble .attachment-audio + .message-bubble__text {
    margin-top: 0.4rem;
}

.typing-indicator {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0 1.5rem 0.6rem;
    color: var(--color-text-muted);
    font-size: 0.78rem;
}

.typing-dots {
    display: inline-flex;
    gap: 3px;
}

.typing-dots span {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background-color: var(--color-text-muted);
    animation: typing-bounce 1.2s infinite ease-in-out;
}

.typing-dots span:nth-child(2) {
    animation-delay: 0.15s;
}

.typing-dots span:nth-child(3) {
    animation-delay: 0.3s;
}

@keyframes typing-bounce {
    0%, 60%, 100% {
        transform: translateY(0);
        opacity: 0.5;
    }
    30% {
        transform: translateY(-4px);
        opacity: 1;
    }
}

.chat-composer {
    flex-shrink: 0;
    display: flex;
    align-items: flex-end; /* buttons stay pinned to the bottom as the textarea grows, instead of re-centering on every keystroke */
    gap: 0.5rem;
    padding: 0.85rem 1.5rem;
    padding-bottom: max(0.85rem, env(safe-area-inset-bottom));
    background-color: var(--color-surface);
    border-top: 1px solid var(--color-border);
}

/* Auto-growing composer: a <textarea rows="1"> sized by JS
   (autosizeComposer() in chat.php) rather than CSS alone, since "grow to
   fit content, cap at N lines, then scroll" isn't expressible in pure
   CSS. min-height matches the send button's 40px so a single empty line
   lines up pixel-for-pixel with it; max-height caps growth at roughly 6
   lines before the box starts scrolling internally instead of pushing
   the rest of the composer row (and the message list above it) around
   indefinitely. resize:none replaces the browser's native drag-handle —
   this box resizes itself. */
.chat-composer__input {
    flex: 1;
    font-family: var(--font-sans);
    font-size: 0.9rem;
    line-height: 1.35;
    border: 1px solid var(--color-border);
    background-color: var(--color-bg);
    border-radius: var(--radius-pill);
    padding: 0.65rem 1.1rem;
    color: var(--color-text);
    min-height: 40px;
    max-height: 160px;
    resize: none;
    overflow-y: hidden;
    transition: border-radius 0.1s ease;
}

/* Swapped in by JS once the content wraps past a single line — a full
   pill radius looks fine at one line but reads as an odd stadium shape
   once the box is several lines tall, so it steps down to a regular
   rounded-rect radius instead (same pattern WhatsApp/Slack use). */
.chat-composer__input.chat-composer__input--grown {
    border-radius: var(--radius-lg);
}

.chat-composer__input::placeholder {
    color: #b0a8b6;
}

.chat-composer__input:focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 4px var(--color-accent-soft);
    background-color: var(--color-surface);
}

.chat-composer__send {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: none;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background-color: var(--color-accent);
    color: #fff;
    transition: background-color 0.15s ease, transform 0.15s ease;
}

.chat-composer__send:not(:disabled):hover {
    background-color: var(--color-accent-hover);
    transform: translateY(-1px);
}

.chat-composer__send:disabled {
    background-color: var(--color-border);
    color: var(--color-text-muted);
    cursor: not-allowed;
}

/* Composer popovers: attach dropup, emoji picker, @mention suggestions.
   All anchored the same way — a relatively-positioned wrapper around the
   trigger, a popover absolutely positioned above it ("dropup", since the
   composer sits at the bottom of the window). */

.composer-popover-anchor {
    position: relative;
    flex-shrink: 0;
    display: flex;
}

/* position: fixed, not absolute — chat.php's positionComposerPopover()
   sets top/right/bottom/left inline from the trigger button's real
   getBoundingClientRect() every time one of these opens, instead of
   trusting this being nested inside .composer-popover-anchor
   (position:relative) to land it in the right spot. See that function's
   own comment for why: the absolute+relative version broke on some
   mobile browsers. No static bottom/right here anymore since JS always
   sets them before un-hiding either element. */
.attach-menu,
.emoji-picker {
    position: fixed;
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-soft-lg);
    z-index: 20;
}

.attach-menu {
    display: flex;
    flex-direction: column;
    padding: 0.35rem;
    min-width: 160px;
}

.attach-menu__item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.6rem;
    border-radius: var(--radius-md);
    background: transparent;
    border: none;
    text-align: left;
    font-size: 0.85rem;
    color: var(--color-text);
}

.attach-menu__item:hover {
    background-color: var(--color-bg);
}

.attach-menu__icon {
    display: inline-flex;
    width: 1.1rem;
    justify-content: center;
    font-size: 1rem;
    color: var(--color-text-muted);
}

.emoji-picker {
    /* Fixed number of columns visible (6) and rows (4) — extra emoji past
       that get their own implicit column further right (grid-auto-flow:
       column fills each explicit row-slot top-to-bottom before starting a
       new column), revealed by scrolling the picker sideways instead of
       growing it downward off the bottom of the screen. */
    display: grid;
    grid-auto-flow: column;
    grid-template-rows: repeat(4, 1fr);
    grid-template-columns: repeat(6, minmax(0, 1fr));
    grid-auto-columns: minmax(0, 1fr);
    gap: 0.15rem;
    padding: 0.5rem;
    width: 260px;
    height: 168px;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x proximity;
}

.emoji-picker__item {
    border: none;
    background: transparent;
    border-radius: 8px;
    font-size: 1.1rem;
    line-height: 1;
    padding: 0.35rem;
    cursor: pointer;
    scroll-snap-align: start;
}

.emoji-picker__item:hover {
    background-color: var(--color-bg);
}

.composer-input-wrap {
    position: relative;
    flex: 1;
    display: flex;
    /* Without this, a flex item defaults to min-width:auto — it won't
       shrink below the textarea's own intrinsic content width, so on a
       narrow screen the whole .chat-composer row overflows instead of
       the input shrinking to fit, pushing the send button off-screen
       entirely (see the max-width:900px composer rules further down for
       the rest of the small-screen fit). */
    min-width: 0;
}

/* Voice note recording — mic button + the bar that takes over
   .composer-input-wrap's spot while a recording is in progress (see
   startVoiceRecording()/enterRecordingUi() in chat.php). */

#chatVoiceBtn.is-recording {
    background-color: #fdecee;
    color: #d33a4b;
}

.voice-recorder {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 0.55rem;
    padding: 0 0.3rem;
}

.voice-recorder__dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background-color: #d33a4b;
    flex-shrink: 0;
    animation: voice-recorder-pulse 1.2s ease-in-out infinite;
}

@keyframes voice-recorder-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.25; }
}

.voice-recorder__time {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    font-size: 0.85rem;
    color: var(--color-text);
    flex-shrink: 0;
}

.voice-recorder__hint {
    font-size: 0.82rem;
    color: var(--color-text-muted);
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.voice-recorder__discard {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    background: transparent;
    color: var(--color-text-muted);
    flex-shrink: 0;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.voice-recorder__discard:hover {
    background-color: var(--color-bg);
    color: #d33a4b;
}

.voice-recorder__stop {
    flex-shrink: 0;
    border: none;
    border-radius: var(--radius-pill);
    padding: 0.4rem 0.9rem;
    font-size: 0.8rem;
    font-weight: 600;
    background-color: var(--color-accent);
    color: #fff;
    transition: background-color 0.15s ease;
}

.voice-recorder__stop:hover {
    background-color: var(--color-accent-hover);
}

.mention-suggestions {
    position: absolute;
    bottom: calc(100% + 0.5rem);
    left: 0;
    right: 0;
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-soft-lg);
    z-index: 20;
    overflow: hidden;
}

.mention-suggestions__item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    padding: 0.5rem 0.7rem;
    border: none;
    background: transparent;
    text-align: left;
    font-size: 0.85rem;
    color: var(--color-text);
}

.mention-suggestions__item.is-active,
.mention-suggestions__item:hover {
    background-color: var(--color-accent-soft);
}

/* Editing banner + attachment-picked preview, shown above the composer.
   :not([hidden]) matters a lot more here than it looks — without it,
   this rule's `display: flex` ties in specificity with the browser's own
   `[hidden] { display: none }` rule, and being declared later in this
   stylesheet, WINS. That means both of these were rendering as visible,
   padded, bordered empty bars on every single page load regardless of
   the `hidden` attribute in chat-window.php's markup — not just when
   actually mid-edit or mid-attach. Same bug, same fix, as
   .composer-reply-banner just below. Three empty ~35-40px bars stacked
   between the message list and the composer (this pair plus the reply
   banner) easily adds up to 100px+ of dead space eating into the
   composer's visible room on a short mobile screen — see chat.php's
   own list of things checked for the "composer not visible on mobile"
   report this fixes. */
.composer-editing-banner:not([hidden]),
.attachment-preview:not([hidden]) {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem 0.6rem;
    padding: 0.5rem 1.5rem;
    /* Multi-select can queue up several chips — cap how tall this grows
       before scrolling instead of pushing the message list off screen. */
    max-height: 140px;
    overflow-y: auto;
    background-color: var(--color-bg);
    border-top: 1px solid var(--color-border);
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

.composer-editing-banner button {
    border: none;
    background: transparent;
    color: var(--color-accent);
    font-weight: 700;
    font-size: 0.78rem;
    cursor: pointer;
}

/* "Replying to X" banner — same slot/row as .composer-editing-banner
   above (the two are mutually exclusive, see startReplyingToMessage()/
   startEditingMessage() in chat.php), but its own layout: a left accent
   bar plus a two-line sender/preview block, closer to WhatsApp's actual
   reply-composer treatment than the plain text+Cancel editing banner. */
.composer-reply-banner:not([hidden]) {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.5rem 1.5rem;
    background-color: var(--color-bg);
    border-top: 1px solid var(--color-border);
}

.composer-reply-banner__bar {
    align-self: stretch;
    width: 3px;
    border-radius: 2px;
    background-color: var(--color-accent);
    flex-shrink: 0;
}

.composer-reply-banner__body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.05rem;
    /* The whole banner is a click target now — see the replyBanner click
       listener in chat.php — same "this jumps to the original" affordance
       as .message-reply-quote already has. */
    cursor: pointer;
}

.composer-reply-banner__sender {
    font-size: 0.78rem;
    font-weight: 700;
    color: var(--color-accent);
}

.composer-reply-banner__preview {
    font-size: 0.78rem;
    color: var(--color-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.composer-reply-banner__cancel {
    flex-shrink: 0;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: none;
    background: transparent;
    color: var(--color-text-muted);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.75rem;
    cursor: pointer;
}

.composer-reply-banner__cancel:hover {
    background-color: var(--color-surface);
    color: var(--color-text);
}

.attachment-preview__chip {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    padding: 0.3rem 0.5rem;
}

.attachment-preview__thumb {
    width: 28px;
    height: 28px;
    border-radius: 8px;
    object-fit: cover;
}

.attachment-preview__icon {
    font-size: 1rem;
}

/* Audio needs more room for a native player than the compact pill layout
   above allows — two rows instead of one, less pill-like radius. */
.attachment-preview__chip--audio {
    flex-direction: column;
    align-items: stretch;
    gap: 0.35rem;
    border-radius: var(--radius-md);
    padding: 0.5rem 0.6rem;
}

.attachment-preview__audio {
    width: 260px;
    max-width: 100%;
    height: 34px;
}

.attachment-preview__chip-footer {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

.attachment-preview__chip-footer .attachment-preview__name {
    flex: 1;
}

.attachment-preview__name {
    font-size: 0.78rem;
    color: var(--color-text);
    max-width: 220px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.attachment-preview__remove {
    border: none;
    background: transparent;
    color: var(--color-text-muted);
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
    padding: 0 0.15rem;
}

.attachment-preview__remove:hover {
    color: var(--color-text);
}

/* Details panel (right) */

.chat-details {
    display: none;
    width: 260px;
    flex-shrink: 0;
    flex-direction: column;
    background-color: var(--color-surface);
    border-left: 1px solid var(--color-border);
    overflow-y: auto;
}

.chat-details.is-open {
    display: flex;
}

.chat-details__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--color-border);
    flex-shrink: 0;
}

.chat-details__title {
    font-weight: 800;
    font-size: 0.88rem;
    margin: 0;
}

.chat-details__section {
    padding: 1rem 0.5rem 1.25rem;
}

/* One .member-details-panel per channel is now always in the DOM (see
   chat-details-panel.php) — same hidden-unless-active pattern as
   .message-panel/.message-panel.is-active above, so switching
   conversations (activateConversation() in chat.php) is a pure
   client-side swap instead of needing a hard refresh to show the right
   channel's members. */
.member-details-panel {
    display: none;
}

.member-details-panel.is-active {
    display: block;
}

.chat-details__section-title {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-muted);
    padding: 0 0.75rem;
    margin-bottom: 0.5rem;
}

/* Scoped to #chatDetails (the conversation-details panel — see
   chat-details-panel.php) rather than the bare .member-row/.member-row__*
   classes: those same class names get redefined further down for the
   Settings → Members table (a differently-shaped row — avatar + name/email
   + a role pill, no click-to-open-modal, no remove icon). Same specificity,
   later-in-file wins, so leaving these unscoped would have the settings
   table's padding/background/border silently win here too. Scoping under
   #chatDetails (ID + class beats a bare class) makes this block's rules
   win regardless of source order — same technique #appRail
   .app-rail__item--settings uses above for the same reason. */
#chatDetails .member-row {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    padding: 0.4rem 0.5rem;
    border-radius: var(--radius-md);
    margin-bottom: 0.35rem;
    /* Every row opens the member-details modal on click (see chat.php's
       details.addEventListener('click', ...) — not just admin rows, not
       just other people's rows). */
    cursor: pointer;
}

#chatDetails .member-row:last-child {
    margin-bottom: 0;
}

#chatDetails .member-row:hover {
    background-color: var(--color-bg);
}

#chatDetails .member-row:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: -2px;
}

#chatDetails .member-row__meta {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
}

#chatDetails .member-row__name {
    font-size: 0.84rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

#chatDetails .member-row__role {
    font-size: 0.72rem;
    color: var(--color-text-muted);
}

/* Inline remove icon (admin-only — see chat-details-panel.php), a sibling
   of .member-row__meta rather than nested in it so .member-row__meta's own
   flex: 1 pushes this to the row's trailing edge regardless of how long
   the name/role text is. A plain <button>, not part of the row's own
   role="button" click target — removeMemberBtn's click handler in
   chat.php stops the click from bubbling up and opening the details
   modal too. */
#chatDetails .member-row__remove {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    background: transparent;
    color: var(--color-text-muted);
    flex-shrink: 0;
    transition: background-color 0.15s ease, color 0.15s ease;
}

#chatDetails .member-row__remove:hover {
    background-color: rgba(220, 53, 69, 0.12);
    color: #dc3545;
}

/* "New message" picker (chat-new-message-modal.php) — a scrollable list
   of colleagues, one .new-message-row per person, deliberately styled
   like .member-row above (same avatar + name/subtitle layout) since
   it's the same "pick a person" pattern, just as plain <button>s instead
   of the details-panel's clickable <div>s. */
.new-message-list {
    max-height: 18rem;
    overflow-y: auto;
    margin-top: 0.5rem;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.new-message-row {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    padding: 0.5rem 0.6rem;
    border: none;
    background: none;
    width: 100%;
    text-align: left;
    font: inherit;
    color: inherit;
    border-radius: var(--radius-md);
    cursor: pointer;
}

.new-message-row:hover,
.new-message-row:focus-visible {
    background-color: var(--color-bg);
    outline: none;
}

.new-message-row__meta {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.new-message-row__name {
    font-size: 0.84rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.new-message-row__email {
    font-size: 0.72rem;
    color: var(--color-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.add-member-btn {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: calc(100% - 0.5rem);
    margin: 0.4rem 0.25rem 0;
    padding: 0.5rem 0.75rem;
    border-radius: var(--radius-md);
    border: 1px dashed var(--color-border);
    background: transparent;
    color: var(--color-text-muted);
    font-family: var(--font-sans);
    font-size: 0.84rem;
    font-weight: 600;
    cursor: pointer;
}

.add-member-btn:hover {
    border-color: var(--color-accent);
    color: var(--color-accent);
}

.add-member-btn__icon {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background-color: var(--color-bg);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
}


.chat-backdrop {
    display: none;
}

/* Chat app — mobile */

@media (max-width: 900px) {
    .app-rail {
        display: none;
    }

    /* Log out lives in #mobileMenuDrawer at this width instead (see
       chat-app-rail.php's .mobile-menu-drawer__item--logout) — no need
       for the footer's copy too. */
    .chat-sidebar__footer {
        display: none;
    }

    .mobile-tab-bar {
        display: flex;
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 15;
        align-items: stretch;
        justify-content: space-around;
        /* Solid brand color instead of a near-white tint, with white
           icons/labels on top — reads as a distinct bar rather than
           blending into the white sidebar content sitting above it. */
        background-color: var(--color-accent);
        box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.12);
        padding-bottom: env(safe-area-inset-bottom);
    }

    /* Switching sections only means something while the sidebar itself
       is showing — once a conversation is open the composer owns the
       bottom of the screen instead. */
    .chat-app.conversation-active .mobile-tab-bar {
        display: none;
    }

    .mobile-tab-bar__item {
        flex: 1;
        width: auto;
        height: auto;
        min-height: 56px;
        border-radius: 0;
        flex-direction: column;
        justify-content: center;
        gap: 0.15rem;
        padding: 0.4rem 0;
        color: rgba(255, 255, 255, 0.75);
    }

    .mobile-tab-bar__item:hover {
        background-color: rgba(255, 255, 255, 0.1);
        color: #fff;
    }

    .mobile-tab-bar__item.is-active {
        background-color: rgba(255, 255, 255, 0.16);
        color: #fff;
    }

    .mobile-tab-bar__label {
        font-size: 0.62rem;
        font-weight: 600;
    }

    .mobile-menu-btn {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 34px;
        height: 34px;
        border-radius: 50%;
        border: none;
        background: transparent;
        color: var(--color-text-muted);
        flex-shrink: 0;
        margin-left: 0.75rem;
        cursor: pointer;
        transition: background-color 0.15s ease, color 0.15s ease;
    }

    .mobile-menu-btn:hover {
        background-color: var(--color-bg);
        color: var(--color-text);
    }

    /* Overflow drawer: backdrop + a panel that slides in from the left,
       same is-open/aria-hidden toggle pattern as every other modal in
       this app (see chat.php's openMobileMenu()/closeMobileMenu()). Sits
       above both the mobile tab bar (z-index 15) and the sidebar's own
       slide transform, so it can open regardless of which conversation
       state the sidebar is in. */
    .mobile-menu-drawer {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 40;
        visibility: hidden;
    }

    .mobile-menu-drawer.is-open {
        visibility: visible;
    }

    .mobile-menu-drawer__backdrop {
        position: absolute;
        inset: 0;
        background-color: rgba(0, 0, 0, 0.45);
        opacity: 0;
        transition: opacity 0.2s ease;
    }

    .mobile-menu-drawer.is-open .mobile-menu-drawer__backdrop {
        opacity: 1;
    }

    .mobile-menu-drawer__panel {
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        width: 78%;
        max-width: 300px;
        background-color: var(--color-surface);
        box-shadow: var(--shadow-soft-lg);
        padding: 1.1rem 0.75rem;
        display: flex;
        flex-direction: column;
        gap: 0.2rem;
        transform: translateX(-100%);
        transition: transform 0.25s ease;
        padding-top: calc(1.1rem + env(safe-area-inset-top));
    }

    .mobile-menu-drawer.is-open .mobile-menu-drawer__panel {
        transform: translateX(0);
    }

    .mobile-menu-drawer__header {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0 0.5rem 0.75rem;
        margin-bottom: 0.4rem;
        border-bottom: 1px solid var(--color-border);
    }

    .mobile-menu-drawer__title {
        font-weight: 700;
        font-size: 1rem;
        margin: 0;
    }

    /* Full standalone styling (not just overrides on top of
       .app-rail__item) since the logout row below uses this class
       without app-rail__item — see its own comment for why. */
    .mobile-menu-drawer__item {
        display: flex;
        align-items: center;
        width: 100%;
        height: auto;
        border: none;
        background: transparent;
        border-radius: var(--radius-md);
        flex-direction: row;
        justify-content: flex-start;
        gap: 0.85rem;
        padding: 0.75rem 0.5rem;
        color: var(--color-text-muted);
        text-decoration: none;
        font-family: inherit;
        font-size: 0.88rem;
        font-weight: 600;
        cursor: pointer;
        transition: background-color 0.15s ease, color 0.15s ease;
    }

    .mobile-menu-drawer__item:hover {
        background-color: var(--color-bg);
        color: var(--color-text);
    }

    .mobile-menu-drawer__divider {
        border: none;
        border-top: 1px solid var(--color-border);
        margin: 0.5rem 0;
    }

    .mobile-menu-drawer__logout-form {
        margin: 0;
    }

    /* Muted like the other rows at rest (not alarmist red just for being
       in the list) but shifts to the accent color on hover/focus, same
       as the desktop footer's .chat-sidebar__logout — a little warning
       color right as you're about to tap it, not before. */
    .mobile-menu-drawer__item--logout:hover,
    .mobile-menu-drawer__item--logout:focus {
        color: var(--color-accent);
    }

    .chat-sidebar {
        position: absolute;
        inset: 0;
        z-index: 10;
        width: 100%;
        padding-bottom: calc(56px + env(safe-area-inset-bottom));
        transform: translateX(0);
        transition: transform 0.25s ease;
    }

    .chat-app.conversation-active .chat-sidebar {
        transform: translateX(-100%);
        pointer-events: none;
    }

    .chat-window {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        min-height: 100%;
        width: 100%;
        z-index: 12;
        transform: translateX(100%);
        transition: transform 0.25s ease;
    }

    .chat-window__header {
        position: sticky;
        top: 0;
        z-index: 5;
    }

    .chat-app.conversation-active .chat-window {
        transform: translateX(0);
    }

    .chat-window__back {
        display: inline-flex;
    }

    .message-group__body {
        max-width: 78%;
    }

    .chat-details {
        position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        width: 85%;
        max-width: 320px;
        z-index: 30;
        transform: translateX(100%);
        transition: transform 0.25s ease;
        box-shadow: var(--shadow-soft-lg);
    }

    .chat-details.is-open {
        display: flex;
        transform: translateX(0);
    }

    .chat-details.is-open ~ .chat-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        background-color: rgba(20, 16, 22, 0.35);
        z-index: 25;
    }

    /* Composer: same buttons as desktop (attach, input, emoji, voice,
       send) but with much less width to fit them into — desktop's
       1.5rem side padding and 0.5rem gaps between 4 fixed-width buttons
       eat into that badly on a phone. Tighter padding/gap plus slightly
       smaller icon buttons here keeps every control (send included —
       see .composer-input-wrap's min-width:0 fix above for why it was
       disappearing entirely) on screen without scrolling. */
    .chat-composer {
        gap: 0.3rem;
        padding: 0.6rem 0.6rem;
        padding-bottom: max(0.6rem, env(safe-area-inset-bottom));
    }

    .chat-composer .icon-btn {
        width: 30px;
        height: 30px;
    }

    .chat-composer__input {
        padding: 0.55rem 0.85rem;
    }

    .chat-composer__send {
        width: 36px;
        height: 36px;
    }
}

/* 404 */

.error-page {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 4rem 1.5rem;
}

.error-page__code {
    font-weight: 800;
    font-size: 1rem;
    letter-spacing: 0.1em;
    color: var(--color-accent);
    margin-bottom: 0.5rem;
}

.error-page__title {
    font-weight: 800;
    font-size: 2rem;
    margin-bottom: 0.5rem;
}

.error-page__subtitle {
    color: var(--color-text-muted);
    margin-bottom: 2rem;
}

/* Legal pages (privacy / terms / conditions) */

.legal-page {
    flex: 1;
    display: flex;
    justify-content: center;
    padding: 3.5rem 1.5rem;
}

.legal-page__inner {
    max-width: 720px;
    width: 100%;
}

.legal-page__title {
    font-weight: 800;
    font-size: 2rem;
    margin-bottom: 0.35rem;
}

.legal-page__updated {
    color: var(--color-text-muted);
    font-size: 0.85rem;
    margin-bottom: 2rem;
}

.legal-page__inner h2 {
    font-weight: 800;
    font-size: 1.15rem;
    margin-top: 2rem;
    margin-bottom: 0.6rem;
}

.legal-page__inner p {
    color: var(--color-text-muted);
    line-height: 1.65;
}

.legal-page__inner a {
    color: var(--color-link);
}

/* Footer */

.site-footer {
    text-align: center;
    padding: 1.5rem;
    color: var(--color-text-muted);
    font-size: 0.85rem;
}

.site-footer__links {
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.5rem 1.25rem;
    margin-bottom: 0.6rem;
}

.site-footer__links a {
    color: var(--color-text-muted);
    text-decoration: none;
}

.site-footer__links a:hover {
    color: var(--color-link);
    text-decoration: underline;
}

/* Media / docs / links modal */

.media-modal {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 50;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
}

.media-modal.is-open {
    display: flex;
}

.media-modal__backdrop {
    position: absolute;
    inset: 0;
    background-color: rgba(20, 16, 22, 0.45);
}

.media-modal__panel {
    position: relative;
    width: 100%;
    max-width: 720px;
    max-height: 85vh;
    background-color: var(--color-surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-soft-lg);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.media-modal__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.25rem 1.5rem 0.5rem;
    flex-shrink: 0;
}

.media-modal__title {
    font-weight: 800;
    font-size: 1.05rem;
    margin: 0;
}

.media-modal__subtitle {
    font-size: 0.8rem;
    color: var(--color-text-muted);
    margin: 0.15rem 0 0;
}

.media-modal__header-actions {
    display: flex;
    gap: 0.15rem;
    flex-shrink: 0;
}

.media-modal__header-actions .icon-btn.is-active {
    background-color: var(--color-accent-soft);
    color: var(--color-accent);
}

.media-modal__search {
    display: none;
    padding: 0 1.5rem;
    margin-top: 0.75rem;
    flex-shrink: 0;
}

.media-modal__search.is-open {
    display: block;
}

.media-modal__tabs {
    display: flex;
    padding: 1rem 1.5rem 0;
    border-bottom: 1px solid var(--color-border);
    flex-shrink: 0;
}

.media-modal__tab {
    border: none;
    background: transparent;
    padding: 0.55rem 0.1rem;
    margin-right: 1.5rem;
    font-family: var(--font-sans);
    font-weight: 700;
    font-size: 0.85rem;
    color: var(--color-text-muted);
    border-bottom: 2px solid transparent;
    cursor: pointer;
}

.media-modal__tab.is-active {
    color: var(--color-accent);
    border-bottom-color: var(--color-accent);
}

.media-modal__storage {
    padding: 0.9rem 1.5rem 0;
    flex-shrink: 0;
}

.media-modal__storage-bar {
    height: 6px;
    border-radius: var(--radius-pill);
    background-color: var(--color-border);
    overflow: hidden;
}

.media-modal__storage-bar span {
    display: block;
    height: 100%;
    background-color: var(--color-accent);
    border-radius: var(--radius-pill);
    transition: width 0.25s ease;
}

.media-modal__storage-label {
    font-size: 0.75rem;
    color: var(--color-text-muted);
    margin: 0.4rem 0 0;
}

.media-modal__body {
    flex: 1;
    overflow-y: auto;
    padding: 1rem 1.5rem 1.5rem;
}

.media-modal__section {
    display: none;
}

.media-modal__section.is-active {
    display: block;
}

.media-modal__empty {
    color: var(--color-text-muted);
    font-size: 0.88rem;
    text-align: center;
    padding: 2rem 0;
}

.media-modal__group-label {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-muted);
    margin: 1.1rem 0 0.5rem;
}

.media-modal__group-label:first-child {
    margin-top: 0;
}

.media-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 0.6rem;
}

.media-tile {
    position: relative;
    border-radius: var(--radius-md);
    overflow: hidden;
    background-color: var(--color-bg);
    transition: opacity 0.15s ease;
    cursor: pointer;
}

.media-tile__thumb {
    width: 100%;
    aspect-ratio: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, #ece6ea, #e2dbe6);
    color: var(--color-text-muted);
}

.media-tile__thumb--video {
    background: linear-gradient(135deg, #e4dde8, #d8cfe0);
}

.media-tile__thumb-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.media-tile__label {
    display: block;
    font-size: 0.72rem;
    color: var(--color-text-muted);
    padding: 0.35rem 0.5rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.media-tile__delete {
    position: absolute;
    top: 0.4rem;
    right: 0.4rem;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: none;
    background-color: rgba(20, 16, 22, 0.55);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transition: opacity 0.15s ease;
    cursor: pointer;
}

.media-tile:hover .media-tile__delete {
    opacity: 1;
}

.media-tile__checkbox {
    position: absolute;
    top: 0.4rem;
    left: 0.4rem;
    display: none;
    margin: 0;
}

.media-modal.is-selecting .media-tile__checkbox {
    display: block;
}

.media-modal.is-selecting .media-tile__delete {
    display: none;
}

.media-tile__checkbox input {
    position: absolute;
    opacity: 0;
    width: 22px;
    height: 22px;
    margin: 0;
    cursor: pointer;
}

.media-tile__checkbox span {
    display: block;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 2px solid #fff;
    background-color: rgba(20, 16, 22, 0.35);
}

.media-tile__checkbox input:checked + span {
    background-color: var(--color-accent);
    border-color: var(--color-accent);
}

.media-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.65rem 0.4rem;
    border-radius: var(--radius-md);
    transition: opacity 0.15s ease;
}

.media-row:hover {
    background-color: var(--color-bg);
}

.media-row__checkbox {
    position: static;
    display: none;
    flex-shrink: 0;
}

.media-modal.is-selecting .media-row__checkbox {
    display: block;
}

.media-row__checkbox span {
    display: block;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    border: 2px solid var(--color-border);
    background-color: var(--color-surface);
}

.media-row__checkbox input {
    position: absolute;
    opacity: 0;
    width: 20px;
    height: 20px;
    margin: 0;
    cursor: pointer;
}

.media-row__checkbox input:checked + span {
    background-color: var(--color-accent);
    border-color: var(--color-accent);
}

.media-row__icon {
    width: 38px;
    height: 38px;
    border-radius: 10px;
    background-color: var(--color-bg);
    color: var(--color-text-muted);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.media-row__icon--link {
    color: var(--color-link);
    background-color: rgba(102, 114, 214, 0.1);
}

.media-row__meta {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.media-row__meta--link {
    color: inherit;
    text-decoration: none;
    cursor: pointer;
}

.media-row__meta--link:hover .media-row__name {
    color: var(--color-link);
    text-decoration: underline;
}

.media-row__name {
    font-size: 0.85rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.media-row__sub {
    font-size: 0.74rem;
    color: var(--color-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.media-row__delete {
    flex-shrink: 0;
    opacity: 0;
}

.media-row:hover .media-row__delete {
    opacity: 1;
}

.media-modal.is-selecting .media-row__delete {
    display: none;
}

.media-modal__selection-bar {
    display: none;
    align-items: center;
    justify-content: space-between;
    padding: 0.85rem 1.5rem;
    border-top: 1px solid var(--color-border);
    flex-shrink: 0;
}

.media-modal.has-selection .media-modal__selection-bar {
    display: flex;
}

.media-modal__selection-bar span {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--color-text-muted);
}

@media (max-width: 640px) {
    .media-modal {
        padding: 0;
    }

    .media-modal__panel {
        max-width: 100%;
        max-height: 100%;
        height: 100%;
        border-radius: 0;
    }
}

/* Media preview (lightbox) */

.media-preview {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 60;
    align-items: center;
    justify-content: center;
    padding: 2rem;
}

.media-preview.is-open {
    display: flex;
}

.media-preview__backdrop {
    position: absolute;
    inset: 0;
    background-color: rgba(15, 12, 17, 0.82);
}

.media-preview__panel {
    position: relative;
    width: 100%;
    max-width: 520px;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.media-preview__close {
    position: absolute;
    top: -3rem;
    right: 0;
    color: #fff;
}

.media-preview__close:hover {
    background-color: rgba(255, 255, 255, 0.15);
    color: #fff;
}

.media-preview__nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 42px;
    height: 42px;
    border-radius: 50%;
    border: none;
    background-color: rgba(255, 255, 255, 0.12);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background-color 0.15s ease;
}

.media-preview__nav:hover {
    background-color: rgba(255, 255, 255, 0.22);
}

.media-preview__nav--prev {
    left: -3.25rem;
}

.media-preview__nav--next {
    right: -3.25rem;
}

.media-preview__nav[hidden] {
    display: none;
}

/* Zoom toolbar — mirrors .media-preview__close's positioning (top of the
   panel, floating above the stage) rather than sitting inside it, so it
   never gets clipped by the stage's own overflow:hidden (needed to keep
   a panned/zoomed image from spilling outside its rounded corners). */
.media-preview__zoom {
    position: absolute;
    top: -3rem;
    left: 0;
    display: flex;
    align-items: center;
    gap: 0.15rem;
    background-color: rgba(255, 255, 255, 0.12);
    border-radius: var(--radius-pill);
    padding: 0.2rem;
}

.media-preview__zoom[hidden] {
    display: none;
}

.media-preview__zoom-btn {
    color: #fff;
}

.media-preview__zoom-btn:hover:not(:disabled) {
    background-color: rgba(255, 255, 255, 0.18);
    color: #fff;
}

.media-preview__zoom-btn:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}

.media-preview__zoom-level {
    border: none;
    background: transparent;
    color: #fff;
    font-size: 0.78rem;
    font-weight: 600;
    padding: 0 0.5rem;
    min-width: 3.2rem;
    cursor: pointer;
}

.media-preview__zoom-level:hover {
    text-decoration: underline;
}

.media-preview__stage {
    position: relative;
    width: 100%;
    aspect-ratio: 4 / 3;
    border-radius: var(--radius-lg);
    overflow: hidden;
    box-shadow: var(--shadow-soft-lg);
}

.media-preview__thumb {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, #ece6ea, #e2dbe6);
    color: var(--color-text-muted);
}

.media-preview__thumb.is-video {
    background: linear-gradient(135deg, #e4dde8, #d8cfe0);
}

.media-preview__image {
    width: 100%;
    height: 100%;
    object-fit: contain;
    cursor: zoom-in;
    /* transform (scale + pan) is set inline by applyPreviewTransform() in
       chat.php — every drag/wheel event updates it, so no CSS transition
       here (it'd lag a step behind the pointer); zoom/reset button clicks
       get their own short JS-driven easing feel via the browser's default
       instant redraw instead, which reads as snappy rather than janky. */
    user-select: none;
    -webkit-user-drag: none;
}

.media-preview__thumb.is-zoomed .media-preview__image {
    cursor: grab;
}

.media-preview__thumb.is-panning .media-preview__image {
    cursor: grabbing;
}

.media-preview__caption {
    margin-top: 1rem;
    text-align: center;
    color: #fff;
}

.media-preview__name {
    display: block;
    font-weight: 700;
    font-size: 0.95rem;
}

.media-preview__meta {
    display: block;
    font-size: 0.8rem;
    color: rgba(255, 255, 255, 0.7);
    margin-top: 0.2rem;
}

@media (max-width: 640px) {
    .media-preview {
        padding: 1.25rem;
    }

    .media-preview__nav--prev {
        left: 0.25rem;
    }

    .media-preview__nav--next {
        right: 0.25rem;
    }

    .media-preview__close {
        top: 0.5rem;
        right: 0.5rem;
    }

    .media-preview__zoom {
        top: 0.5rem;
        left: 0.5rem;
    }
}

/* ------------------------------------------------------------------
 * Admin settings page (/settings) — design/UI pass, see settings.php's
 * docblock for what's real (Members) vs. mock (Notices/Permissions/
 * Projects). Mirrors the chat app shell's full-viewport treatment
 * (body.page-settings, set in layout.php) rather than the marketing
 * site's centered-content look.
 * ------------------------------------------------------------------ */

body.page-settings {
    /* Same 100vh-on-mobile fix as body.page-chat above, including the
       min-height:0 override — see its comment for why that part matters
       just as much as the height itself. */
    height: 100vh;
    height: 100dvh;
    min-height: 0;
    overflow: hidden;
}

body.page-settings main {
    flex: 1;
    min-height: 0;
    overflow: hidden;
}

.settings-app {
    height: 100%;
    display: flex;
    flex-direction: column;
    background-color: var(--color-bg);
}

.settings-header {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 0.85rem;
    padding: 0.9rem 1.5rem;
    background-color: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
}

.settings-header__back {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-text-muted);
    background-color: var(--color-bg);
    flex-shrink: 0;
}

.settings-header__back:hover {
    color: var(--color-text);
}

.settings-header__titles {
    flex: 1;
    min-width: 0;
}

.settings-header__title {
    margin: 0;
    font-weight: 800;
    font-size: 1.05rem;
}

.settings-header__subtitle {
    margin: 0;
    font-size: 0.78rem;
    color: var(--color-text-muted);
}

.settings-header__badge {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background-color: var(--color-accent-soft);
    color: var(--color-accent);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 0.78rem;
    flex-shrink: 0;
}

.settings-body {
    flex: 1;
    min-height: 0;
    display: flex;
    overflow: hidden;
}

.settings-tabs {
    width: 220px;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    padding: 1.25rem 1rem;
    background-color: var(--color-surface);
    border-right: 1px solid var(--color-border);
    overflow-y: auto;
}

.settings-tabs__item {
    text-align: left;
    border: none;
    background: transparent;
    padding: 0.65rem 0.9rem;
    border-radius: var(--radius-md);
    font-weight: 700;
    font-size: 0.88rem;
    color: var(--color-text-muted);
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.settings-tabs__item:hover {
    background-color: var(--color-bg);
    color: var(--color-text);
}

.settings-tabs__item.is-active {
    background-color: var(--color-accent-soft);
    color: var(--color-accent);
}

.settings-panels {
    flex: 1;
    min-width: 0;
    overflow-y: auto;
    padding: 1.75rem 2rem 3rem;
}

.settings-panel {
    display: none;
}

.settings-panel.is-active {
    display: block;
}

.settings-panel__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.25rem;
}

.settings-panel__title {
    margin: 0 0 0.15rem;
    font-weight: 800;
    font-size: 1.15rem;
}

.settings-panel__desc {
    margin: 0;
    font-size: 0.82rem;
    color: var(--color-text-muted);
    max-width: 46ch;
}

.settings-panel__header .btn[disabled] {
    opacity: 0.55;
    cursor: not-allowed;
}

.settings-panel__header-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-shrink: 0;
}

.settings-list {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    max-width: 720px;
}

/* Profile page (resources/views/profile.php) — Account Info's read-only
   rows and the Profile/Security tabs' editable forms. Forms reuse
   .create-channel-modal__label/__input/__hint as-is (already styled for
   exactly this "label, then input, repeat" rhythm); these are just the
   pieces that don't already exist elsewhere. */

.profile-info-list {
    display: flex;
    flex-direction: column;
    max-width: 560px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    overflow: hidden;
}

.profile-info-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--color-border);
}

.profile-info-row:last-child {
    border-bottom: none;
}

.profile-info-row__label {
    font-size: 0.78rem;
    font-weight: 700;
    color: var(--color-text-muted);
    flex-shrink: 0;
}

.profile-info-row__value {
    font-size: 0.88rem;
    color: var(--color-text);
    display: flex;
    align-items: center;
    gap: 0.4rem;
    text-align: right;
    word-break: break-word;
}

.profile-info-row__lock {
    font-size: 0.7rem;
    color: var(--color-text-muted);
}

.profile-form {
    max-width: 420px;
}

.profile-form .btn {
    margin-top: 1.25rem;
}

.profile-form__success {
    color: #2f8f5b;
}

/* Notices */

.notice-card {
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: 1rem 1.15rem;
    box-shadow: var(--shadow-soft);
}

.notice-card--pinned {
    border-color: var(--color-accent-soft);
    background-color: rgba(140, 51, 80, 0.03);
}

.notice-card__top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
}

.notice-card__title {
    margin: 0;
    font-weight: 700;
    font-size: 0.92rem;
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

.notice-card__title .bi-pin-angle-fill {
    color: var(--color-accent);
    font-size: 0.8rem;
}

.notice-card__date {
    font-size: 0.74rem;
    color: var(--color-text-muted);
    flex-shrink: 0;
}

.notice-card__body {
    margin: 0.4rem 0 0.6rem;
    font-size: 0.85rem;
    color: var(--color-text);
    line-height: 1.5;
}

.notice-card__audience {
    display: inline-block;
    font-size: 0.7rem;
    font-weight: 700;
    color: var(--color-accent);
    background-color: var(--color-accent-soft);
    padding: 0.2rem 0.55rem;
    border-radius: var(--radius-pill);
}

.notice-card__bottom {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.notice-card__delete {
    color: var(--color-text-muted);
}

.notice-card__delete:hover {
    color: #c0392b;
}

.settings-empty-state {
    font-size: 0.85rem;
    color: var(--color-text-muted);
    padding: 1rem 0;
}

/* Create-notice modal — same overlay/backdrop/panel shell as
   .create-channel-modal (chat-create-channel-modal.php), reused directly
   for the header/body/footer classes; only the parts unique to notices
   (recipient checklist, pinned checkbox) get their own rules below. */

.create-notice-modal {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 50;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
}

.create-notice-modal.is-open {
    display: flex;
}

.create-notice-modal__backdrop {
    position: absolute;
    inset: 0;
    background-color: rgba(20, 16, 22, 0.45);
}

.create-notice-modal__panel {
    position: relative;
    width: 100%;
    max-width: 480px;
    max-height: 85vh;
    background-color: var(--color-surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-soft-lg);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.notice-modal__textarea {
    resize: vertical;
    min-height: 90px;
    font-family: inherit;
}

.notice-recipient-picker {
    margin-top: 0.5rem;
}

.notice-recipient-list {
    max-height: 160px;
    overflow-y: auto;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background-color: var(--color-bg);
}

.notice-recipient-row {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--color-border);
    cursor: pointer;
    font-size: 0.82rem;
}

.notice-recipient-row:last-child {
    border-bottom: none;
}

.notice-recipient-row input {
    flex-shrink: 0;
}

.notice-recipient-row__name {
    font-weight: 700;
    flex-shrink: 0;
}

.notice-recipient-row__email {
    color: var(--color-text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.notice-pinned-check {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 1.1rem;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
}

#createNoticeError {
    color: #c0392b;
    font-weight: 600;
    margin-top: 0.6rem;
}

/* Invite-member modal — same overlay/backdrop/panel shell as
   .create-notice-modal, reused for the same reason that one reused
   .create-channel-modal's header/body/footer classes. */

.invite-member-modal {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 50;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
}

.invite-member-modal.is-open {
    display: flex;
}

.invite-member-modal__backdrop {
    position: absolute;
    inset: 0;
    background-color: rgba(20, 16, 22, 0.45);
}

.invite-member-modal__panel {
    position: relative;
    width: 100%;
    max-width: 440px;
    max-height: 85vh;
    background-color: var(--color-surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-soft-lg);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

#inviteMemberError {
    color: #c0392b;
    font-weight: 600;
}

/* Member details modal — same overlay/backdrop/panel shell as
   .invite-member-modal above, reusing .create-channel-modal's
   header/body/footer classes for the chrome; the rules below are just
   the parts unique to this modal (profile header, detail rows). */

.member-details-modal {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 50;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
}

.member-details-modal.is-open {
    display: flex;
}

.member-details-modal__backdrop {
    position: absolute;
    inset: 0;
    background-color: rgba(20, 16, 22, 0.45);
}

.member-details-modal__panel {
    position: relative;
    width: 100%;
    max-width: 400px;
    max-height: 85vh;
    background-color: var(--color-surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-soft-lg);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* Call + Remove: .create-channel-modal__footer defaults to
   align-items:stretch, so both buttons take on the height of whichever
   is tallest. "Remove from channel" used to wrap to two lines at this
   modal's width, stretching "Call" right along with it into an
   oversized pill even though its own text never wrapped — shortening
   the label to "Remove" (see chat-member-modal.php) mostly fixes that,
   center-aligning here belt-and-suspenders so a long label never does
   that again, plus a bit less padding than the site-wide .btn-pill
   default since this footer only ever holds two short actions. */
.member-details-modal__panel .create-channel-modal__footer {
    align-items: center;
}

.member-details-modal__panel .btn-pill {
    padding: 0.55rem 1.15rem;
    font-size: 0.85rem;
}

.member-details-modal__profile {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    margin-bottom: 1.1rem;
}

.member-details-modal__profile-meta {
    min-width: 0;
}

.member-details-modal__name {
    font-weight: 800;
    font-size: 1rem;
    margin: 0 0 0.15rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.member-details-modal__role {
    font-size: 0.78rem;
    color: var(--color-text-muted);
    margin: 0;
}

.member-details-modal__rows {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.member-details-modal__row {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.6rem 0;
    border-bottom: 1px solid var(--color-border);
}

.member-details-modal__row:last-child {
    border-bottom: none;
}

.member-details-modal__icon {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background-color: var(--color-bg);
    color: var(--color-accent);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.9rem;
}

.member-details-modal__field {
    min-width: 0;
}

.member-details-modal__label {
    font-size: 0.7rem;
    font-weight: 700;
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    margin: 0 0 0.1rem;
}

.member-details-modal__value {
    font-size: 0.85rem;
    color: var(--color-text);
    margin: 0;
    word-break: break-word;
}

.member-details-modal__empty {
    font-size: 0.82rem;
    color: var(--color-text-muted);
    margin: 0.4rem 0 0;
}

/* No width:100% — that dated from when Call was the only button in this
   footer (full-width made sense solo); now that Remove sits next to it,
   forcing Call full-width was what made it balloon out huge while
   Remove stayed compact. Sized to content like every other pill button,
   so the two now match. */
#memberDetailsCallBtn {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    justify-content: center;
}

/* Permissions */

.permission-group {
    margin-bottom: 1.75rem;
    max-width: 720px;
}

.permission-group__title {
    margin: 0 0 0.6rem;
    font-weight: 800;
    font-size: 0.9rem;
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.permission-table {
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    overflow: hidden;
}

.permission-table__row {
    display: grid;
    grid-template-columns: 1fr 70px 100px 70px;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 1rem;
    border-bottom: 1px solid var(--color-border);
    font-size: 0.82rem;
}

.permission-table__row:last-child {
    border-bottom: none;
}

.permission-table__row--head {
    color: var(--color-text-muted);
    font-weight: 700;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    text-align: center;
}

.permission-table__row--head .permission-table__label {
    text-align: left;
}

.permission-table__label {
    font-weight: 600;
}

.permission-toggle {
    justify-self: center;
    position: relative;
    display: inline-flex;
    width: 34px;
    height: 20px;
    cursor: not-allowed;
}

.permission-toggle input {
    opacity: 0;
    width: 0;
    height: 0;
}

.permission-toggle span {
    position: absolute;
    inset: 0;
    background-color: var(--color-border);
    border-radius: var(--radius-pill);
    transition: background-color 0.15s ease;
}

.permission-toggle span::before {
    content: '';
    position: absolute;
    width: 16px;
    height: 16px;
    left: 2px;
    top: 2px;
    background-color: #fff;
    border-radius: 50%;
    transition: transform 0.15s ease;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}

.permission-toggle input:checked + span {
    background-color: var(--color-accent);
}

.permission-toggle input:checked + span::before {
    transform: translateX(14px);
}

/* Projects table */

.settings-table {
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    max-width: 720px;
}

.settings-table__row {
    display: grid;
    grid-template-columns: 1fr 110px 90px 44px;
    align-items: center;
    gap: 0.75rem;
    padding: 0.7rem 1rem;
    border-bottom: 1px solid var(--color-border);
    font-size: 0.85rem;
}

.settings-table__row:last-child {
    border-bottom: none;
}

.settings-table__row--head {
    color: var(--color-text-muted);
    font-weight: 700;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.settings-table__name {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    font-weight: 700;
}

.settings-table__actions {
    display: flex;
    justify-content: flex-end;
}

.status-pill {
    display: inline-block;
    font-size: 0.72rem;
    font-weight: 700;
    padding: 0.2rem 0.6rem;
    border-radius: var(--radius-pill);
}

.status-pill--active {
    color: #2f8f5b;
    background-color: rgba(47, 143, 91, 0.12);
}

.status-pill--archived {
    color: var(--color-text-muted);
    background-color: var(--color-border);
}

/* Members */

.member-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: 0.65rem 1rem;
}

.member-row__meta {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.member-row__name {
    font-weight: 700;
    font-size: 0.88rem;
}

.member-row__email {
    font-size: 0.76rem;
    color: var(--color-text-muted);
}

.role-pill {
    flex-shrink: 0;
    font-size: 0.72rem;
    font-weight: 700;
    padding: 0.22rem 0.65rem;
    border-radius: var(--radius-pill);
    background-color: var(--color-accent-soft);
    color: var(--color-accent);
}

.role-pill--staff {
    background-color: rgba(102, 114, 214, 0.12);
    color: var(--color-link);
}

.role-pill--receptionist {
    background-color: var(--color-border);
    color: var(--color-text-muted);
}

/* FinLite's own free-text role label (users.fin_role) — deliberately
   plainer/quieter than .role-pill above (no per-value color variants,
   since fin_role is arbitrary text, not a fixed enum) so it always reads
   as secondary metadata, never mistaken for this app's own role. */
.fin-role-pill {
    flex-shrink: 0;
    font-size: 0.72rem;
    font-weight: 600;
    padding: 0.22rem 0.65rem;
    border-radius: var(--radius-pill);
    background: transparent;
    border: 1px solid var(--color-border);
    color: var(--color-text-muted);
}

@media (max-width: 900px) {
    .settings-tabs {
        width: 76px;
        padding: 1rem 0.4rem;
        align-items: center;
    }

    .settings-tabs__item {
        text-align: center;
        font-size: 0.68rem;
        padding: 0.55rem 0.3rem;
    }

    .settings-panels {
        padding: 1.25rem 1rem 2.5rem;
    }

    .permission-table__row,
    .settings-table__row {
        grid-template-columns: 1fr 50px 60px 50px;
        font-size: 0.74rem;
    }
}

/* ------------------------------------------------------------------
 * "Create a channel" modal — design/UI pass, see
 * chat-create-channel-modal.php's docblock for what's real vs. mock.
 * Same overlay/backdrop/panel structure as .media-modal.
 * ------------------------------------------------------------------ */

.create-channel-modal {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 50;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
}

.create-channel-modal.is-open {
    display: flex;
}

.create-channel-modal__backdrop {
    position: absolute;
    inset: 0;
    background-color: rgba(20, 16, 22, 0.45);
}

.create-channel-modal__panel {
    position: relative;
    width: 100%;
    max-width: 460px;
    max-height: 85vh;
    background-color: var(--color-surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-soft-lg);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.create-channel-modal__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.25rem 1.5rem 0.75rem;
    flex-shrink: 0;
}

.create-channel-modal__title {
    font-weight: 800;
    font-size: 1.05rem;
    margin: 0 0 0.15rem;
}

.create-channel-modal__subtitle {
    font-size: 0.8rem;
    color: var(--color-text-muted);
    margin: 0;
}

.create-channel-modal__body {
    padding: 0 1.5rem 1.25rem;
    overflow-y: auto;
}

.create-channel-modal__label {
    font-size: 0.76rem;
    font-weight: 700;
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    margin: 1.1rem 0 0.5rem;
}

.create-channel-modal__label:first-child {
    margin-top: 0;
}

.create-channel-modal__input {
    width: 100%;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: 0.6rem 0.85rem;
    font-family: inherit;
    font-size: 0.88rem;
    background-color: var(--color-bg);
    color: var(--color-text);
}

.create-channel-modal__input:focus {
    outline: none;
    border-color: var(--color-accent);
}

.create-channel-modal__hint {
    font-size: 0.72rem;
    color: var(--color-text-muted);
    margin: 0.5rem 0 0;
}

.channel-type-options {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.channel-type-card {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    text-align: left;
    border: 1.5px solid var(--color-border);
    background-color: var(--color-bg);
    border-radius: var(--radius-md);
    padding: 0.65rem 0.85rem;
    cursor: pointer;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}

.channel-type-card:hover {
    border-color: var(--color-accent-soft);
}

.channel-type-card.is-selected {
    border-color: var(--color-accent);
    background-color: var(--color-accent-soft);
}

.channel-type-card__icon {
    flex-shrink: 0;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    background-color: var(--color-surface);
    color: var(--color-accent);
    display: flex;
    align-items: center;
    justify-content: center;
}

.channel-type-card__meta {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
}

.channel-type-card__name {
    font-weight: 700;
    font-size: 0.88rem;
}

.channel-type-card__desc {
    font-size: 0.74rem;
    color: var(--color-text-muted);
    line-height: 1.35;
}

.channel-type-card__check {
    flex-shrink: 0;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    border: 1.5px solid var(--color-border);
    background-color: var(--color-surface);
    color: transparent;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.channel-type-card.is-selected .channel-type-card__check {
    background-color: var(--color-accent);
    border-color: var(--color-accent);
    color: #fff;
}

.invite-link-row {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

.invite-link-row__input {
    flex: 1;
    min-width: 0;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: 0.55rem 0.75rem;
    font-family: inherit;
    font-size: 0.8rem;
    color: var(--color-text-muted);
    background-color: var(--color-bg);
}

.create-channel-modal__footer {
    display: flex;
    justify-content: flex-end;
    gap: 0.6rem;
    padding: 1rem 1.5rem;
    border-top: 1px solid var(--color-border);
    flex-shrink: 0;
}

@media (max-width: 640px) {
    .create-channel-modal {
        padding: 0.75rem;
    }
}

/* ---- Confirm / alert modal (chat-confirm-modal.php) ---- */
.confirm-modal {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 60;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
}

.confirm-modal.is-open {
    display: flex;
}

.confirm-modal__backdrop {
    position: absolute;
    inset: 0;
    background-color: rgba(20, 16, 22, 0.45);
}

.confirm-modal__panel {
    position: relative;
    width: 100%;
    max-width: 380px;
    background-color: var(--color-surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-soft-lg);
    padding: 1.5rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.confirm-modal__title {
    font-weight: 800;
    font-size: 1rem;
    margin: 0;
}

.confirm-modal__body {
    font-size: 0.85rem;
    color: var(--color-text-muted);
    margin: 0;
    line-height: 1.5;
}

.confirm-modal__body:empty {
    display: none;
}

.confirm-modal__footer {
    display: flex;
    justify-content: flex-end;
    gap: 0.6rem;
    margin-top: 0.75rem;
}
