/* TWR Suite shared design tokens — one file, every app, light + dark.
   Bootstrap 5.3's own components (cards, buttons, forms, navs, tables) already
   restyle automatically from [data-bs-theme="dark"] — these tokens are for the
   custom, non-Bootstrap pieces (message bubbles, avatars, pill nav) so they stay
   in sync with whichever theme is active. */

:root {
    --twr-radius: 12px;
    --twr-radius-lg: 16px;
    --twr-shadow-sm: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
    --twr-shadow: 0 4px 16px rgba(0,0,0,0.08), 0 1px 4px rgba(0,0,0,0.04);
    --twr-transition: 0.18s ease;

    /* Each app may override --twr-accent-rgb (and, if the default hover shade
       doesn't suit it, --twr-accent-hover-rgb) in its own app.css to keep a
       distinct identity while sharing every other token — e.g. TheFamilyInfo's
       blue vs. MyMedical's teal. Defaults to Bootstrap's own primary blue. */
    --twr-accent-rgb: 13, 110, 253;
    --twr-accent: rgb(var(--twr-accent-rgb));
    --twr-accent-bg: rgba(var(--twr-accent-rgb), 0.12);
    --twr-accent-fg: var(--twr-accent);
    --twr-accent-hover-rgb: 11, 94, 215;
    --twr-accent-hover: rgb(var(--twr-accent-hover-rgb));

    /* --twr-bg is the outer page background; --twr-surface is what sits on top of
       it (cards, modals, dialogs) — kept one step lighter (light mode) / lighter-
       than-page (dark mode) so surfaces read as "raised" against the page. */
    --twr-bg: #f3f4f8;
    --twr-surface: #ffffff;
    --twr-surface-muted: #f4f5f7;
    --twr-text: #111827;
    --twr-text-muted: #6c757d;
    --twr-border: rgba(0, 0, 0, 0.08);

    --twr-bubble-mine-bg: var(--twr-accent-bg);
    --twr-bubble-mine-fg: var(--twr-accent-fg);
    --twr-bubble-theirs-bg: var(--twr-surface-muted);
    --twr-bubble-theirs-fg: #212529;

    --twr-avatar-bg: rgba(var(--twr-accent-rgb), 0.16);
    --twr-avatar-fg: var(--twr-accent);
}

[data-bs-theme="dark"] {
    --twr-accent-bg: rgba(var(--twr-accent-rgb), 0.22);

    --twr-bg: #16181c;
    --twr-surface: #1e2126;
    --twr-surface-muted: #2a2e35;
    --twr-text: #e8eaed;
    /* #9aa1ab initially, brightened after testing MyMedical's dark mode live --
       still de-emphasized relative to --twr-text, but no longer reads as
       illegible gray-on-near-black. */
    --twr-text-muted: #c1c7cf;
    /* 0.08 initially, brightened after testing -- form controls/dropdowns need
       a visible outline, not just a hint of one, against a dark surface. */
    --twr-border: rgba(255, 255, 255, 0.16);
    --twr-shadow-sm: 0 1px 3px rgba(0,0,0,0.3), 0 1px 2px rgba(0,0,0,0.2);
    --twr-shadow: 0 4px 16px rgba(0,0,0,0.4), 0 1px 4px rgba(0,0,0,0.2);

    --twr-bubble-theirs-fg: #e8eaed;

    /* The default --twr-bubble-mine-fg (= --twr-accent-fg, a medium-saturated blue)
       doesn't have enough contrast against --twr-bubble-mine-bg in dark mode —
       give the "mine" bubble its own light pastel blue text instead. */
    --twr-bubble-mine-fg: #cfe2ff;

    --twr-avatar-bg: rgba(var(--twr-accent-rgb), 0.28);

    /* Bootstrap's contextual .bg-light utility is literal by design and never
       flips with [data-bs-theme="dark"] on its own -- every app in the suite
       uses it for "a shade lighter than the surrounding surface" (card headers,
       badges, highlighted rows), so redefine it here once rather than per-app.
       --bs-dark-rgb is NOT safe to redefine the same way: .bg-dark and .text-dark
       both read that one variable, and .text-dark is also used on bright
       bg-warning/bg-info badges (and .bg-dark text-white bars) that need to STAY
       genuinely dark for contrast, regardless of theme. See the scoped
       .bg-light.text-dark override below instead. */
    --bs-light-rgb: 42, 46, 53;   /* --twr-surface-muted (dark) as RGB */

    /* Same story for --bs-danger/--bs-success: Bootstrap keeps them identical
       in both themes, which reads as washed-out against a near-black surface
       (Sign Out, Cancel buttons, delete icons, "Add" buttons, etc.). This only
       brightens icon-level usage (.text-danger, .bg-danger, etc., which derive
       from these -rgb tokens) -- .btn-outline-danger/.btn-outline-success bake
       their own literal hex colors and need their own override below. */
    --bs-danger-rgb: 255, 92, 92;
    --bs-success-rgb: 46, 204, 113;
}

/* .btn-outline-danger/.btn-outline-success (and their solid/active/hover
   states) hardcode Bootstrap's default hex colors directly in --bs-btn-*
   rather than deriving from --bs-danger-rgb/--bs-success-rgb above, so
   brightening those tokens alone doesn't reach these buttons at all --
   confirmed by checking bootstrap.min.css directly, not assumed. Every
   outline-danger/outline-success button in every app (Sign Out, Cancel,
   Delete, the page-header "Add X" buttons) gets the same brighter colors. */
[data-bs-theme="dark"] .btn-outline-danger {
    --bs-btn-color: rgb(var(--bs-danger-rgb));
    --bs-btn-border-color: rgb(var(--bs-danger-rgb));
    --bs-btn-hover-bg: rgb(var(--bs-danger-rgb));
    --bs-btn-hover-border-color: rgb(var(--bs-danger-rgb));
    --bs-btn-active-bg: rgb(var(--bs-danger-rgb));
    --bs-btn-active-border-color: rgb(var(--bs-danger-rgb));
}

[data-bs-theme="dark"] .btn-outline-success {
    --bs-btn-color: rgb(var(--bs-success-rgb));
    --bs-btn-border-color: rgb(var(--bs-success-rgb));
    --bs-btn-hover-bg: rgb(var(--bs-success-rgb));
    --bs-btn-hover-border-color: rgb(var(--bs-success-rgb));
    --bs-btn-active-bg: rgb(var(--bs-success-rgb));
    --bs-btn-active-border-color: rgb(var(--bs-success-rgb));
}

/* The one real pattern in the suite that DOES want .text-dark to read as light
   in dark mode: a muted bg-light "chip" explicitly paired with text-dark (ward/
   member-count badges, category badges, a plaintext form control). Scoping the
   --bs-dark-rgb override to only this compound selector fixes those chips
   without touching plain .bg-dark bars or bright bg-warning/bg-info badges,
   which also read text-dark but need to stay genuinely dark for contrast. */
[data-bs-theme="dark"] .bg-light.text-dark {
    --bs-dark-rgb: 232, 234, 237; /* --twr-text (dark) as RGB */
}

/* .btn-outline-secondary bakes Bootstrap's default mid-gray hex directly into
   its own --bs-btn-* variables (same story as outline-danger/outline-success
   above), so it stays the same washed-out gray in dark mode regardless of
   --bs-secondary-rgb. Used constantly across every app -- dialog Cancel/Close
   buttons, secondary page actions, whole accordion sections of nav buttons --
   so this is a global fix, not scoped to one header. (Doesn't touch badges/
   text using .bg-secondary/.text-secondary -- those are separate classes and
   are fine staying muted; this is specifically the outline BUTTON variant.) */
[data-bs-theme="dark"] .btn-outline-secondary {
    --bs-btn-color: #fff;
    --bs-btn-border-color: #fff;
    --bs-btn-hover-color: var(--twr-bg);
    --bs-btn-hover-bg: #fff;
    --bs-btn-hover-border-color: #fff;
}

/* .table-light bakes its own literal hex --bs-table-* variables directly onto
   the class (unlike .bg-light, which derives from the already-overridden
   --bs-light-rgb) -- Bootstrap never designed table color variants to flip
   with [data-bs-theme=dark] on their own. Used constantly suite-wide for
   table/thead headers (19 files across every app as of this writing), so
   this is a global fix, not scoped to one page. */
[data-bs-theme="dark"] .table-light {
    --bs-table-color: var(--twr-text);
    --bs-table-bg: var(--twr-surface-muted);
    --bs-table-border-color: var(--twr-border);
    --bs-table-striped-bg: var(--twr-surface);
    --bs-table-striped-color: var(--twr-text);
    --bs-table-active-bg: var(--twr-surface);
    --bs-table-hover-bg: var(--twr-surface);
    --bs-table-hover-color: var(--twr-text);
}

/* Same story for the semantic .table-success/-danger/-warning/-info row
   variants (highlighted rows -- an alert row, a paid transaction, an
   audit-log severity row) -- each bakes its own literal light-mode hex into
   --bs-table-*, and Bootstrap only ships a dark override for --bs-*-bg-subtle/
   --bs-*-text-emphasis (used by badges/alerts), not for the table variants.
   Route them through those same already-dark-aware tokens so the semantic
   color still reads clearly against a dark surface instead of staying a
   stark, blown-out light patch. */
[data-bs-theme="dark"] .table-success {
    --bs-table-color: var(--bs-success-text-emphasis);
    --bs-table-bg: var(--bs-success-bg-subtle);
    --bs-table-border-color: var(--twr-border);
}

[data-bs-theme="dark"] .table-danger {
    --bs-table-color: var(--bs-danger-text-emphasis);
    --bs-table-bg: var(--bs-danger-bg-subtle);
    --bs-table-border-color: var(--twr-border);
}

[data-bs-theme="dark"] .table-warning {
    --bs-table-color: var(--bs-warning-text-emphasis);
    --bs-table-bg: var(--bs-warning-bg-subtle);
    --bs-table-border-color: var(--twr-border);
}

[data-bs-theme="dark"] .table-info {
    --bs-table-color: var(--bs-info-text-emphasis);
    --bs-table-bg: var(--bs-info-bg-subtle);
    --bs-table-border-color: var(--twr-border);
}

/* ── Reusable pieces used by shared components (MessagingPanel, etc.) ── */

.twr-pill-nav-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    border-radius: var(--twr-radius);
    color: var(--twr-text-muted);
    text-decoration: none;
    border: none;
    background: transparent;
    width: 100%;
    text-align: left;
}

.twr-pill-nav-item:hover {
    background: var(--twr-surface-muted);
}

.twr-pill-nav-item.active {
    background: var(--twr-accent-bg);
    color: var(--twr-accent-fg);
    font-weight: 500;
}

.twr-avatar {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--twr-avatar-bg);
    color: var(--twr-avatar-fg);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 500;
    font-size: 0.8rem;
    flex-shrink: 0;
}

.twr-bubble {
    max-width: 75%;
    padding: 10px 14px;
    border-radius: 14px;
}

.twr-bubble-mine {
    background: var(--twr-bubble-mine-bg);
    color: var(--twr-bubble-mine-fg);
    border-radius: 14px 14px 4px 14px;
}

.twr-bubble-theirs {
    background: var(--twr-bubble-theirs-bg);
    color: var(--twr-bubble-theirs-fg);
    border-radius: 14px 14px 14px 4px;
}

/* An attachment link previously used Bootstrap's link-light/link-primary utility classes,
   which know nothing about --twr-bubble-*-fg's own per-theme contrast tuning (light mode "mine"
   bubbles are a pale accent tint, dark mode uses a specifically brightened blue -- see this
   file's own comment above --twr-bubble-mine-fg's dark-mode override) -- the result read as
   low-contrast/washed-out in both themes. Inheriting the bubble's own foreground color, which is
   already tuned for contrast against its own background, plus an underline so it still reads as
   a link, fixes both themes at once with no separate color to maintain. */
.twr-bubble-attachment-link {
    color: inherit;
    text-decoration: underline;
    font-weight: 600;
}

.twr-bubble-attachment-link:hover,
.twr-bubble-attachment-link:focus {
    color: inherit;
    opacity: 0.85;
}

/* ── Thread polish: date dividers, per-message avatars, grouped bubbles, image thumbnails ── */

.twr-date-divider {
    display: flex;
    justify-content: center;
    margin: 8px 0 4px;
}

.twr-date-divider span {
    background: var(--twr-surface-muted);
    color: var(--twr-text-muted);
    font-size: 0.75rem;
    font-weight: 500;
    padding: 3px 12px;
    border-radius: 999px;
}

/* Sized down from the roster's 40px avatar -- next to a bubble, the roster's size reads as too
   dominant relative to the text it's labeling. */
.twr-bubble-avatar {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
}

/* Reserves the same width as .twr-bubble-avatar for a grouped (avatar-hidden) message, so
   consecutive bubbles from the same sender stay left-aligned with each other instead of the
   bubble jumping left every time the avatar is hidden. */
.twr-bubble-avatar-spacer {
    width: 28px;
    flex-shrink: 0;
}

.twr-attachment-thumb {
    display: block;
    max-width: 220px;
    max-height: 220px;
    border-radius: 10px;
    object-fit: cover;
    cursor: pointer;
}

.twr-composer-textarea {
    resize: none;
    /* auto, not hidden -- twrAutoResizeTextarea grows the box up to max-height below, but once a
       message is longer than that, hidden would make everything past the cap invisible with no way
       to scroll to it and see what was actually typed (the text is still there and still sends
       correctly -- only the ability to *see* it while typing was the gap). */
    overflow-y: auto;
    max-height: 160px;
    padding-top: 6px;
    padding-bottom: 6px;
    line-height: 1.4;
}

.twr-theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    border: none;
    background: transparent;
    color: var(--twr-text-muted);
    cursor: pointer;
}

.twr-theme-toggle:hover {
    background: var(--twr-surface-muted);
}

/* ── MessagingPanel responsive sidebar ──────────────────────────────────
   Below 768px the sidebar (Direct Messages / Alerts / System / Settings)
   becomes an off-canvas flyout instead of a fixed 220px column, so the
   conversation/thread content gets the full width on narrow viewports. */

.twr-messaging-toggle {
    display: none;
}

.twr-messaging-backdrop {
    display: none;
}

/* Desktop: the conversation list stays visible while the thread scrolls -- including when the thread is scrolled to its
   newest message, which is exactly when the list used to be off the top of the screen (Tim, 2026-09-17).

   Sticky rather than capping the panel: the thread keeps growing the page and pinning to its newest message as it
   always has, and this works wherever the panel sits on the page -- the Portal's Messages tab starts a long way down,
   below the launch cards and tabs, so a viewport-height cap would have left the panel's bottom below the fold and the
   list would still have scrolled away. align-self keeps the column from stretching, and the max-height keeps a long
   roster scrolling inside itself rather than growing past the window. Phones are excluded: there the list is an
   off-canvas drawer, not a column. */
@media (min-width: 768.02px) {
    .twr-messaging-sidebar {
        position: sticky;
        top: 1rem;
        align-self: flex-start;
        max-height: calc(100vh - 2rem);
        max-height: calc(100dvh - 2rem);
        overflow-y: auto;
    }
}

@media (max-width: 768px) {
    .twr-messaging-sidebar {
        position: fixed;
        top: 0;
        left: 0;
        bottom: 0;
        width: 260px;
        max-width: 80vw;
        background: var(--twr-surface);
        z-index: 1050;
        padding: 16px;
        overflow-y: auto;
        box-shadow: 2px 0 16px rgba(0, 0, 0, 0.2);
        transform: translateX(-100%);
        transition: transform 0.2s ease-in-out;
    }

    .twr-messaging-sidebar.open {
        transform: translateX(0);
    }

    .twr-messaging-toggle {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 36px;
        height: 36px;
        border-radius: 50%;
        border: none;
        background: transparent;
        color: var(--twr-text-muted);
        cursor: pointer;
        flex-shrink: 0;
    }

    .twr-messaging-toggle:hover {
        background: var(--twr-surface-muted);
    }

    .twr-messaging-backdrop.open {
        display: block;
        position: fixed;
        inset: 0;
        background: rgba(0, 0, 0, 0.4);
        z-index: 1040;
    }
}

/* ── Phone "list first" messaging (MessagingPanel PhoneListFirst, Tim 2026-10-16) ─────────────────
   Below 768px the conversation list is the home screen, like Google Messages: it fills the screen; tapping a row swaps it for the chat
   (the panel adds .twr-phone-detail while anything other than the list is open), and the back arrow swaps it back. Start chat floats
   over the list only. Wide screens are untouched, and so is every host that does not turn PhoneListFirst on. */
.twr-start-chat-fab,
.twr-phone-only {
    display: none;
}

@media (max-width: 767.98px) {
    .twr-phone-first .twr-messaging-sidebar {
        position: static;
        transform: none;
        width: 100% !important;
        max-width: 100%;
        padding: 0 !important;
        margin: 0 !important;
        box-shadow: none;
        overflow: visible;
        z-index: auto;
    }

    .twr-phone-first .twr-messaging-toggle,
    .twr-phone-first .twr-messaging-backdrop {
        display: none !important;
    }

    /* !important: the sidebar and content columns carry Bootstrap's d-flex, which is itself !important */
    .twr-phone-first.twr-phone-detail .twr-messaging-sidebar {
        display: none !important;
    }

    .twr-phone-first:not(.twr-phone-detail) .twr-phone-content {
        display: none !important;
    }

    .twr-phone-first .twr-phone-only {
        display: inline-flex;
    }

    /* A tap focuses the row and the hover Archive button would pop up under the finger (Tim archived Diane by accident);
       on the phone the swipe is the way to archive. */
    .twr-phone-first .twr-roster-archive-btn-hover {
        display: none !important;
    }

    .twr-phone-first:not(.twr-phone-detail) .twr-messaging-sidebar {
        padding-bottom: 150px !important;   /* the last conversations stay clear of the Start chat button */
    }

    .twr-phone-first:not(.twr-phone-detail) .twr-start-chat-fab {
        display: inline-flex;
        align-items: center;
        position: fixed;
        right: 16px;
        bottom: 72px;
        z-index: 1030;
        border: none;
        border-radius: 28px;
        padding: 14px 20px;
        font-weight: 500;
        background: var(--twr-primary, #0d6efd);
        color: #fff;
        box-shadow: 0 4px 14px rgba(0, 0, 0, 0.3);
    }
}

/* ── Swipe-to-archive + icon-corner unread badge (Phase 4 of issue #286) ──────────────────
   Each roster row is wrapped in a position:relative div carrying three stacked children: the
   archive strip (revealed on swipe, sits behind), the row button itself (on top, in normal flow,
   slid left by JS during a drag), and a desktop-only hover/focus archive button (on top of
   everything, shown via CSS only). See TWR.Shared.Components.lib.module.js's
   twrRegisterSwipeToArchive for the drag logic that toggles twr-roster-row-swiping/-open. */

.twr-roster-row-wrap {
    position: relative;
}

.twr-roster-row {
    position: relative;
    z-index: 2;
    width: 100%;
    background: var(--twr-surface);
    touch-action: pan-y; /* only horizontal drag is captured by JS; vertical list scroll still works */
}

.twr-roster-archive-btn {
    border: none;
    cursor: pointer;
    color: #fff;
    background: var(--bs-danger, #dc3545);
}

.twr-roster-archive-strip {
    position: absolute;
    inset: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.35rem;
    padding-right: 16px;
    border-radius: var(--twr-radius, 0.75rem);
    font-size: 0.85rem;
}

.twr-roster-row-wrap:not(:has(.twr-roster-row-swiping, .twr-roster-row-open)) .twr-roster-archive-strip {
    visibility: hidden; /* avoids a sliver showing through rounded row corners while fully closed */
}

.twr-roster-archive-btn-hover {
    position: absolute;
    /* Vertically centered on the row rather than pinned to the top-right corner -- a review found
       top:6px/right:6px landed exactly on top of the row's own LastActivityAt date text, hiding it
       whenever a user hovered/focused the row to read it. Centered, it overlaps the row's less
       critical (already-truncated, muted) preview line instead. */
    top: 50%;
    right: 6px;
    transform: translateY(-50%);
    z-index: 3;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease-in-out;
}

.twr-roster-row-wrap:hover .twr-roster-archive-btn-hover,
.twr-roster-row-wrap:focus-within .twr-roster-archive-btn-hover {
    opacity: 1;
    pointer-events: auto;
}

/* Icon-corner unread badge -- replaces the roster row's old trailing pill entirely. */
.twr-roster-badge {
    position: absolute;
    bottom: -2px;
    right: -2px;
    min-width: 18px;
    height: 18px;
    padding: 0 4px;
    border-radius: 9px;
    font-size: 0.68rem;
    line-height: 18px;
    text-align: center;
    color: #fff;
    border: 2px solid var(--twr-surface);
}
