/* ── Palette tokens now live in themes.css (six theme x mode blocks).
      This file keeps STRUCTURE + component styling and consumes those tokens;
      it must never hardcode a color again. ── */

body {
    color: var(--cw-body-text);
    background-color: var(--cw-body-bg);
    font-family: "Segoe UI", Helvetica, Arial, sans-serif;
}

h1, h2, h3, h4, h5, h6 {
    color: var(--cw-heading-text);
}

a {
    color: var(--cw-link);
}

a:hover {
    color: var(--cw-link-hover);
}

/* ── Navbar (verbatim pattern from cw-2026 public site) ───────────── */
.navbar-cw {
    background-color: var(--cw-navbar-bg);
}

.navbar-cw .navbar-brand {
    display: flex;
    align-items: center;
}

.navbar-cw .nav-link {
    color: var(--cw-navbar-text);
    font-size: .92rem;
}

.navbar-cw .nav-link:hover,
.navbar-cw .nav-link:focus {
    color: var(--cw-navbar-text-hover);
}

/* Desktop tool-switcher navbar: dev-reference only, hidden below lg */
.desktop-navbar .navbar-nav {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    column-gap: 1.25rem;
}

/* ── Brand text lockup: "CW" (light) + tool name (bold) ───────────── */
.brand-cw,
.brand-tool {
    font-size: 1.5rem;
    line-height: 1;
}

.brand-cw {
    color: var(--cw-brand-text);
    font-weight: 300;
}

.brand-tool {
    color: var(--cw-brand-accent);
    font-weight: 700;
    margin-left: .15rem;
}

/* ── Mobile topbar: brand + sidebar toggle, replaces the hidden nav ── */
.mobile-topbar {
    border-bottom: 1px solid var(--cw-navbar-border);
}

.mobile-topbar .brand-cw,
.mobile-topbar .brand-tool {
    font-size: 1.1rem;
}

/* ── Sidebar / responsive offcanvas nav ────────────────────────────── */
.sidebar-col {
    --bs-offcanvas-width: 280px;
}

@media (max-width: 991.98px) {
    .sidebar-col.show,
    .sidebar-col.showing:not(.hiding) {
        transform: none;
    }
}

@media (min-width: 992px) {
    .sidebar-col {
        flex: 0 0 auto;
        width: 260px;
        margin-right: 1.5rem;
    }

    .sidebar-col .offcanvas-body {
        padding: 0;
    }
}

.sidebar-col .list-group-item {
    background-color: var(--cw-sidebar-bg);
}

.sidebar-col .list-group-item:not(.list-group-item-secondary):nth-child(even) {
    background-color: var(--cw-table-stripe);
}

.sidebar-col .list-group-item-secondary {
    font-size: .78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    background-color: var(--cw-sidebar-header-bg);
    color: var(--cw-sidebar-header-text);
}

.sidebar-col .list-group-item a {
    color: var(--cw-sidebar-text);
    text-decoration: none;
    display: block;
}

.sidebar-col .list-group-item a:hover {
    color: var(--cw-sidebar-link-hover);
}

/* Zebra-striped list-group, for use outside the sidebar (e.g. Node Detail's Events/Alarms).
   Both rows get an explicit opaque background so the stripe reads on any surface: a flush (or
   plain) list-group otherwise paints each item with --bs-list-group-bg, i.e. --bs-body-bg, which
   themes.css bridges to each skin's own (often tinted/parchment) --cw-body-bg -- so an unstyled
   list inside a white card looks like it has no background at all. Odd rows take the card
   surface, even rows the same --cw-table-stripe token every .table-striped already bridges to. */
.list-group-striped .list-group-item {
    background-color: var(--cw-surface);
}

.list-group-striped .list-group-item:nth-child(even) {
    background-color: var(--cw-table-stripe);
}

/* Rendered-Markdown body content (any app's sanitize-then-render pipeline -- CWTicket's
   data/richtext.render_body is the first user): keep block spacing tidy inside a card.
   overflow-wrap: anywhere is load-bearing, not cosmetic -- raw customer/email content routinely
   contains long unbroken runs with no natural break point (a "====...====" ASCII divider line, an
   unbroken URL, a hash) that the browser's default word-wrapping can't break; without this, one
   such line stretches its card -- and the whole page -- wider than the viewport instead of
   wrapping. Originally CWTicket-page-local CSS; promoted here once a second and third template
   needed the identical rules (Conversation posts, Ticket Fields body-type values, and the
   Reply/Send Email pages' outgoing-message preview all render through the same pipeline). */
.post-body { overflow-wrap: anywhere; min-width: 0; max-width: 100%; }
.post-body > :first-child { margin-top: 0; }
.post-body > :last-child { margin-bottom: 0; }
.post-body p { margin-bottom: .5rem; }
.post-body ul, .post-body ol { margin-bottom: .5rem; padding-left: 1.5rem; }
.post-body blockquote { margin: .5rem 0; padding-left: .75rem; border-left: 3px solid var(--bs-border-color); color: var(--bs-secondary-color); overflow-wrap: anywhere; }
/* A <pre> (a fenced code block, or an email's preformatted quote) defaults to white-space: pre, which
   never wraps -- the parent's overflow-wrap can't help it -- so one long line used to push the
   whole main column wider than the viewport. pre-wrap keeps real line breaks/indentation while
   wrapping long lines; overflow-wrap: anywhere covers a run with no break point (a URL, a hash).
   max-width keeps the block inside its card; overflow-x stays as a last resort. */
.post-body pre { padding: .5rem .75rem; background: var(--bs-tertiary-bg); border-radius: .25rem; overflow-x: auto;
                 white-space: pre-wrap; overflow-wrap: anywhere; max-width: 100%; }
.post-body pre code { white-space: inherit; overflow-wrap: inherit; }
.post-body table { width: auto; margin-bottom: .5rem; }
.post-body table th, .post-body table td { padding: .25rem .5rem; border: 1px solid var(--bs-border-color); }

/* Raw plain-text quote block (e.g. CWTicket Reply's "Show original" ticket-field summary) -- a
   bare <pre> defaults to white-space: pre, which never wraps at all (unlike ordinary text, which
   at least breaks at spaces by default), so the exact same long unbroken "====...====" banner line
   that motivated .post-body's overflow-wrap above stretches this element -- and the page -- just
   as wide, only worse, since nothing in a <pre> wraps to begin with. pre-wrap keeps real line
   breaks/indentation intact while still allowing wrapping; overflow-wrap: anywhere then covers the
   no-natural-break-point case pre-wrap alone can't. */
.quote-block { white-space: pre-wrap; overflow-wrap: anywhere; }

/* ── Cards / tables ─────────────────────────────────────────────────── */
.card {
    --bs-card-bg: var(--cw-surface);
    border-color: var(--cw-border);
    border-radius: 6px;
    box-shadow: 0 1px 4px rgba(0, 0, 0, .06);
}

.card-header {
    background-color: var(--cw-card-header-bg, var(--cw-surface-alt));
    color: var(--cw-card-header-text, var(--cw-body-text));
    border-bottom-color: var(--cw-border);
    font-weight: 600;
}

/* Headings inside a card-header (e.g. login.html's <h5>) should take the
   header's own color -- which already accounts for .login-card-header's
   .text-white override or a theme's --cw-card-header-text -- not the
   page-title --cw-heading-text below, which is a different, unrelated
   role. */
.card-header h1, .card-header h2, .card-header h3,
.card-header h4, .card-header h5, .card-header h6 {
    color: inherit;
    font-weight: 600;
}

.login-card-header {
    background-color: var(--cw-primary);
}

/* ── Ticket priority accents (CWTicket's queue priority-group cards) ─────────────
   Emergency = danger/red, High = warning/amber. Colour is built from the --cw-*-rgb
   tokens themes.css bridges to --bs-*-rgb, so it tracks the active skin and light/dark
   mode the same way .btn-primary / the badges do -- no hardcoded hex here. Normal / Low
   carry the .priority-card / .priority-normal / .priority-low hooks but get no accent. */
.priority-emergency {
    border-color: rgba(var(--cw-danger-rgb), .45);
    border-left: 4px solid rgb(var(--cw-danger-rgb));
    background-color: rgba(var(--cw-danger-rgb), .05);
}

.priority-emergency > .card-header {
    background-color: rgba(var(--cw-danger-rgb), .16);
    color: var(--cw-danger);
}

.priority-high {
    border-color: rgba(var(--cw-warning-rgb), .5);
    border-left: 4px solid rgb(var(--cw-warning-rgb));
    background-color: rgba(var(--cw-warning-rgb), .06);
}

.priority-high > .card-header {
    background-color: rgba(var(--cw-warning-rgb), .2);
    color: var(--cw-warning);
}

/* Per-row priority accent, for a listing that MIXES priorities in one card (CWTicket's Completed /
   Archived box drill, sorted by last-modified only). Same colours as the group-card accents above.
   .priority-row reserves a transparent 4px left border so Normal / Low rows don't sit narrower than
   accented ones. Qualified with `.list-group-flush >` to beat Bootstrap's
   `.list-group-flush > .list-group-item { border-width: 0 0 1px }`. */
.list-group-flush > .list-group-item.priority-row {
    border-left: 4px solid transparent;
}

.list-group-flush > .list-group-item.priority-row-emergency {
    border-left-color: rgb(var(--cw-danger-rgb));
}

.list-group-flush > .list-group-item.priority-row-high {
    border-left-color: rgb(var(--cw-warning-rgb));
}

/* A ticket's status comment on a queue row (CWTicket's thread_row.html): the tech's one-line note on
   where the ticket stands, which is what a scanning tech most needs to read. A callout -- a faint tint
   of the skin's primary plus a primary left rule, body-colour text at normal size -- so it holds its own
   beside the badge lines under it. Built from --bs-primary-rgb (bridged to the active skin) so it follows
   skin + light/dark; the tint is low enough that body text keeps its normal contrast on top of it. */
.ticket-status-comment {
    margin-top: .4rem;
    padding: .3rem .6rem;
    border-left: 3px solid rgb(var(--bs-primary-rgb));
    border-radius: 0 .25rem .25rem 0;
    background-color: rgba(var(--bs-primary-rgb), .09);
    font-weight: 500;
    overflow-wrap: anywhere;
}

/* CWTicket queue row: a short excerpt of the ticket's own message. Deliberately quieter than
   .ticket-status-comment (muted text, neutral rule) and capped at 3 lines whatever the width. */
.ticket-body-preview {
    margin-top: .4rem;
    padding-left: .6rem;
    border-left: 3px solid var(--bs-border-color);
    font-size: .875rem;
    color: var(--bs-secondary-color);
    overflow-wrap: anywhere;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    overflow: hidden;
}

/* ── Detail-page sections + jump-nav (see root CLAUDE.md's "Detail-Page Sections") ─────────── */
.section-jump-link {
    text-decoration: none;
}

/* Chevron on a collapsible detail_section.html heading (collapsible=True) -- most sections are
   plain, always-visible cards with no chevron at all; this only applies to the rare section that
   opts into a collapse toggle. */
.section-toggle-icon {
    transition: transform 0.2s ease;
}

.btn-link.collapsed .section-toggle-icon {
    transform: rotate(0deg);
}

.btn-link:not(.collapsed) .section-toggle-icon {
    transform: rotate(180deg);
}

/* A <button> used as a popover trigger (see static/js/popovers.js), styled to read like any
   other in-content link -- themed colour + hover, no native button chrome. A <button> is used so
   the trigger never submits a surrounding form and never jumps the page the way an <a href="#">
   would. cwticket's partials/customer_popover.html is the reference usage. */
.cw-popover-link {
    color: var(--cw-link);
    text-decoration: none;
    cursor: pointer;
}

.cw-popover-link:hover {
    color: var(--cw-link-hover);
    text-decoration: underline;
}

/* Opt-in wider popover (Bootstrap's default max-width is 276px). Set on a trigger via
   data-bs-custom-class="cw-cust-popover" -- used by cwticket's customer info popover, which can
   list several accounts. */
.popover.cw-cust-popover {
    --bs-popover-max-width: 340px;
}

.stat-tile .stat-value {
    font-size: 2rem;
    font-weight: 700;
    color: var(--cw-primary-dark);
}

.stat-tile .stat-label {
    font-size: .82rem;
    color: var(--cw-text-muted);
    text-transform: uppercase;
    letter-spacing: .03em;
}

/* ── Footer: developer/technical info, not marketing links ─────────── */
.site-footer-tool {
    background-color: var(--cw-footer-bg);
    color: var(--cw-footer-text);
    padding: 2rem 0 1.5rem;
    margin-top: 2rem;
    font-family: "Segoe UI", Helvetica, Arial, sans-serif;
}

.site-footer-tool h6 {
    color: var(--cw-footer-heading);
    font-weight: 600;
    font-size: .78rem;
    letter-spacing: .05em;
    text-transform: uppercase;
    margin-bottom: .75rem;
}

.footer-meta {
    font-size: .82rem;
    font-family: "Consolas", "SFMono-Regular", Menlo, monospace;
    color: var(--cw-footer-text);
    margin-bottom: .3rem;
    /* Debug values (Referrer, Query, Path...) are long, unbroken strings that
       would otherwise push the page wider than a phone viewport. */
    overflow-wrap: anywhere;
    word-break: break-word;
}

.footer-bottom-tool {
    background-color: var(--cw-footer-bottom-bg);
    color: var(--cw-footer-bottom-text);
    font-size: .78rem;
    font-family: "Consolas", "SFMono-Regular", Menlo, monospace;
    padding: .7rem 0;
}

.footer-bottom-tool span {
    overflow-wrap: anywhere;
}

/* `.main-content` is a flex item (`.col`), whose default `min-width: auto` lets any wide
   unbreakable child -- a long <pre> line, a wide table -- stretch the whole column past the
   viewport instead of wrapping/scrolling inside its own card. 0 lets it shrink to its share. */
.main-content { min-width: 0; }

/* Slightly wider than the desktop navbar's own `.container` (maxes out at 1320px at the xxl
   breakpoint) so the page never reads as dramatically wider than the nav above it on large
   displays. A max-width + auto margins only ever caps/centers this wrapper -- it never
   overrides Bootstrap's own narrower breakpoint widths below 1400px, so shrinking on smaller
   viewports and the offcanvas sidebar's mobile behavior are both untouched. The sidebar itself
   keeps its fixed 260px width (see .sidebar-col above) either way, since only the space left
   over for .main-content changes. */
.content-shell {
    max-width: 1470px;
    margin-left: auto;
    margin-right: auto;
    padding-bottom: 1rem;
}

/* ── Reports: CSS-only bar charts (no charting library) ─────────────── */
.chart-bars {
    display: flex;
    align-items: flex-end;
    gap: 3px;
    height: 140px;
}

.chart-bar {
    flex: 1 1 auto;
    background-color: var(--cw-primary);
    border-radius: 2px 2px 0 0;
    min-height: 2px;
}

/* ── Graph builder line-color swatch ─────────────────────────────────── */
.color-swatch {
    display: inline-block;
    width: 14px;
    height: 14px;
    border-radius: 3px;
    border: 1px solid var(--cw-border);
}

/* ── NOC view: dense status-tile board ──────────────────────────────── */
.noc-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: .5rem;
}

.noc-tile {
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: .75rem;
    border-radius: 6px;
    color: #fff;
    text-decoration: none;
    min-height: 64px;
}

.noc-tile:hover {
    opacity: .88;
    color: #fff;
}

.noc-tile-name {
    font-weight: 600;
    font-size: .85rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.noc-tile-status {
    font-size: .75rem;
    text-transform: uppercase;
    letter-spacing: .03em;
    opacity: .9;
}

/* ── Calendar grid ───────────────────────────────────────────────────── */
.calendar-table th {
    text-align: center;
    background-color: var(--cw-table-header-bg);
    color: var(--cw-table-header-text);
    font-size: .8rem;
}

.calendar-table td {
    width: 14.28%;
    height: 100px;
    vertical-align: top;
    padding: .4rem;
}

.calendar-day-number {
    font-weight: 600;
    font-size: .85rem;
    margin-bottom: .25rem;
}

.calendar-event {
    font-size: .72rem;
    color: var(--cw-primary-dark);
    background-color: var(--cw-accent-soft);
    border-radius: 3px;
    padding: .1rem .3rem;
    margin-bottom: .2rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.calendar-today {
    background-color: var(--cw-accent-soft);
}

/* ── Bootstrap component color bridges (color only) ─────────────────── */
/* --cw-primary-contrast is each theme's own curated answer to "what text color reads on top of
   --cw-primary" -- most themes already pick white here, but a theme whose --cw-primary is itself
   light/bright (Steampowered's old-gold #bfba50, and every theme's brightened dark-mode primary)
   correctly picks a dark color instead, the same reasoning the reference twp-steampowered.css
   theme uses for its own .btn-primary/.btn-warning/.page-item.active. Amber (cwmonitor) is the one
   deliberate exception: its --cw-primary-contrast is pinned to equal --cw-brand-text in themes.css
   (not overridden here) so its buttons read the same light text as its badges. Don't reintroduce a
   blanket --cw-brand-text swap here -- that was tried and broke every theme whose primary is light
   enough to need dark text (Steampowered chief among them). */
.btn-primary {
    --bs-btn-bg: var(--cw-primary);
    --bs-btn-border-color: var(--cw-primary);
    --bs-btn-color: var(--cw-primary-contrast);
    --bs-btn-hover-bg: var(--cw-primary-dark);
    --bs-btn-hover-border-color: var(--cw-primary-dark);
    --bs-btn-hover-color: var(--cw-primary-contrast);
    --bs-btn-active-bg: var(--cw-primary-dark);
    --bs-btn-active-border-color: var(--cw-primary-dark);
    --bs-btn-active-color: var(--cw-primary-contrast);
    --bs-btn-disabled-bg: var(--cw-primary);
    --bs-btn-disabled-border-color: var(--cw-primary);
    --bs-btn-disabled-color: var(--cw-primary-contrast);
}

.btn-outline-primary {
    --bs-btn-color: var(--cw-primary);
    --bs-btn-border-color: var(--cw-primary);
    --bs-btn-hover-bg: var(--cw-primary);
    --bs-btn-hover-border-color: var(--cw-primary);
    --bs-btn-hover-color: var(--cw-primary-contrast);
    --bs-btn-active-bg: var(--cw-primary);
    --bs-btn-active-border-color: var(--cw-primary);
    --bs-btn-active-color: var(--cw-primary-contrast);
}

/* Bootstrap pairs its lighter bg-* badge variants (warning, info, light) with a `.text-dark`
   utility class for contrast, which renders as low-contrast black-on-yellow and reads poorly.
   `.text-dark` sets its color via !important, so it has to be defeated the same way here --
   every badge in this project should read as light text regardless of its bg-* variant.
   --cw-brand-text is reused rather than a flat #fff because it's the one token every theme
   defines identically across both its light and dark mode blocks (unlike --cw-primary-contrast
   or --cw-heading-text, which invert to a dark color in dark mode) -- it's already each theme's
   answer to "light text on a colored surface," so most themes get pure white but a few (Amber,
   Parchment, Steampowered) get their own subtly warmer near-white instead. */
.badge {
    color: var(--cw-brand-text);
}

.badge.text-dark {
    color: var(--cw-brand-text) !important;
}

/* CW Blue solid fill -- skin-INVARIANT (see themes.css "Skin-INVARIANT brand colour"): the same
   #4a77b4 on every skin and in both modes, so it is what a component uses when it must read as
   Cyber Wurx blue regardless of the active theme. Pure white text, not --cw-brand-text: a few skins'
   brand text is a warm near-white (Parchment's #f5f2ea is 4.10:1 on this blue; pure white is 4.58:1). */
.bg-cw-blue {
    background-color: rgb(var(--cw-brand-blue-fill-rgb)) !important;
}

.badge.bg-cw-blue {
    color: #ffffff;
}

.table {
    --bs-table-bg: var(--cw-surface);
    --bs-table-color: var(--cw-body-text);
    --bs-table-border-color: var(--cw-border);
    --bs-table-striped-bg: var(--cw-table-stripe);
    --bs-table-striped-color: var(--cw-body-text);
    --bs-table-hover-bg: var(--cw-accent-soft);
    --bs-table-hover-color: var(--cw-body-text);
}

.table > thead {
    --bs-table-bg: var(--cw-table-header-bg);
    --bs-table-color: var(--cw-table-header-text);
}

.dropdown-menu {
    --bs-dropdown-bg: var(--cw-dropdown-bg);
    --bs-dropdown-color: var(--cw-dropdown-text);
    --bs-dropdown-link-color: var(--cw-dropdown-text);
    --bs-dropdown-link-hover-bg: var(--cw-primary);
    --bs-dropdown-link-hover-color: var(--cw-primary-contrast);
    --bs-dropdown-border-color: var(--cw-border);
}

.pagination {
    --bs-pagination-color: var(--cw-primary);
    --bs-pagination-bg: var(--cw-surface);
    --bs-pagination-border-color: var(--cw-border);
    --bs-pagination-hover-color: var(--cw-primary-dark);
    --bs-pagination-hover-bg: var(--cw-accent-soft);
    --bs-pagination-hover-border-color: var(--cw-border);
    --bs-pagination-active-color: var(--cw-primary-contrast);
    --bs-pagination-active-bg: var(--cw-primary);
    --bs-pagination-active-border-color: var(--cw-primary);
    --bs-pagination-disabled-color: var(--cw-text-muted);
    --bs-pagination-disabled-bg: var(--cw-surface);
    --bs-pagination-disabled-border-color: var(--cw-border);
}

/* Bootstrap's compiled .progress bakes a literal #0d6efd bar + #e9ecef track, neither derived
   from --bs-primary at runtime -- bridge both to theme tokens (same --cw-primary /
   --cw-primary-contrast pair .btn-primary uses) so progress bars follow the skin + light/dark. */
.progress {
    --bs-progress-bg: var(--cw-surface-alt);
    --bs-progress-bar-bg: var(--cw-primary);
    --bs-progress-bar-color: var(--cw-primary-contrast);
}

/* Accordion inherits --bs-accordion-bg/--bs-accordion-color from --bs-body-bg/--bs-body-color (already
   bridged above), which reads flush against the page instead of as its own panel -- give it the same
   surface/header treatment as .card/.card-header instead. --bs-accordion-btn-icon/--active-icon bake a
   literal Bootstrap gray/blue hex into the chevron's SVG data URI, which can't be parameterized with a
   --cw-* var -- disabled here and replaced by a mask-based chevron below (shape via mask-image, color via
   background-color) so it can follow --cw-body-text/--cw-primary-dark like every other themed icon.
   --bs-accordion-active-bg/--active-color and the focus border/box-shadow are Bootstrap's own compiled
   primary-subtle/emphasis colors and a hardcoded #86b7fe -- none of those derive from --bs-primary at
   runtime, so all three need the same explicit override .form-control's focus ring already gets below. */
.accordion {
    --bs-accordion-bg: var(--cw-surface);
    --bs-accordion-color: var(--cw-body-text);
    --bs-accordion-border-color: var(--cw-border);
    --bs-accordion-btn-bg: var(--cw-card-header-bg, var(--cw-surface-alt));
    --bs-accordion-btn-color: var(--cw-card-header-text, var(--cw-body-text));
    --bs-accordion-btn-icon: none;
    --bs-accordion-btn-active-icon: none;
    --bs-accordion-active-bg: var(--cw-accent-soft);
    --bs-accordion-active-color: var(--cw-primary-dark);
    --bs-accordion-btn-focus-border-color: var(--cw-primary-light);
    --bs-accordion-btn-focus-box-shadow: 0 0 0 .25rem rgba(var(--cw-primary-rgb), .25);
}

.accordion-button::after {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3E%3C/svg%3E");
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: var(--bs-accordion-btn-icon-width);
    mask-size: var(--bs-accordion-btn-icon-width);
    background-color: var(--cw-card-header-text, var(--cw-body-text));
}

.accordion-button:not(.collapsed)::after {
    background-color: var(--cw-primary-dark);
}

.external-link i {
    margin-left: .25rem;
    font-size: .85em;
}

.offcanvas,
.offcanvas-lg {
    --bs-offcanvas-bg: var(--cw-body-bg);
    --bs-offcanvas-color: var(--cw-sidebar-text);
}

/* Form controls default to Bootstrap's --bs-body-bg, which is fine when body-bg
   is near-white/near-black (every theme but Win95) but breaks badly for a
   saturated non-neutral body-bg (Win95's teal desktop) -- pin them to the card
   surface instead, with a --cw-input-bg override point for a theme (Win95) that
   needs an authentically different "edit control" color from its card chrome. */
.form-control,
.form-select,
.form-check-input:not(:checked) {
    background-color: var(--cw-input-bg, var(--cw-surface));
    color: var(--cw-body-text);
    border-color: var(--cw-border);
    box-shadow: inset 1px 1px 2px rgba(0, 0, 0, .15);
}

.form-control::placeholder {
    color: var(--cw-text-muted);
}

/* Every textarea auto-grows to fit its text (js/textarea-autogrow.js), so it never needs a
   scrollbar, and its manual drag handle would only fight that. rows="N" stays the minimum height.
   Opt a textarea out with data-no-autogrow. */
textarea:not([data-no-autogrow]) {
    overflow-y: hidden;
    resize: none;
}

.form-control:focus,
.form-select:focus {
    background-color: var(--cw-input-bg, var(--cw-surface));
    color: var(--cw-body-text);
    border-color: var(--cw-primary-light);
    box-shadow: 0 0 0 .25rem rgba(var(--cw-primary-rgb), .25);
}

/* Bootstrap's checked checkbox/switch fill is a Sass-compiled literal color,
   not driven by any --bs-* custom property, so the theme bridge above never
   reaches it -- every theme showed the same stock Bootstrap blue regardless
   of --cw-primary until this explicit override. */
.form-check-input:checked {
    background-color: var(--cw-primary);
    border-color: var(--cw-primary);
}

.form-check-input:focus {
    border-color: var(--cw-primary-light);
    box-shadow: 0 0 0 .25rem rgba(var(--cw-primary-rgb), .25);
}

/* ── Win95's classic chunky grey scrollbar. Scoped to this one theme --
      every other theme keeps the browser/OS default scrollbar, this is a
      deliberate one-theme retro touch, not a general feature. Track uses
      --cw-surface-alt (the lighter bevel-highlight grey) and the thumb/
      buttons use --cw-surface (the window-face grey) with a white/gray
      "outset" bevel border, the same convention as .form-control's border
      elsewhere in this file. --cw-surface/--cw-surface-alt/--cw-border(-light)
      are identical between win95 light and dark, so this looks the same in
      both modes automatically. ─────────────────────────────────────────── */
[data-cw-theme="win95"] {
    scrollbar-color: var(--cw-surface) var(--cw-surface-alt);
    scrollbar-width: auto;
}

[data-cw-theme="win95"] ::-webkit-scrollbar {
    width: 16px;
    height: 16px;
}

[data-cw-theme="win95"] ::-webkit-scrollbar-track {
    background-color: var(--cw-surface-alt);
}

[data-cw-theme="win95"] ::-webkit-scrollbar-thumb,
[data-cw-theme="win95"] ::-webkit-scrollbar-button {
    background-color: var(--cw-surface);
    border-top: 1px solid var(--cw-border-light);
    border-left: 1px solid var(--cw-border-light);
    border-bottom: 1px solid var(--cw-border);
    border-right: 1px solid var(--cw-border);
}

[data-cw-theme="win95"] ::-webkit-scrollbar-button {
    height: 16px;
    width: 16px;
}

[data-cw-theme="win95"] ::-webkit-scrollbar-corner {
    background-color: var(--cw-surface-alt);
}

/* A one-shot flash message (base.html) may span several lines: a successful operation that has more than one
   thing to report passes ONE message with "\n" between the lines. Jinja autoescapes it, so this is plain text with
   line breaks -- no markup. pre-line keeps real newlines but still collapses runs of spaces and wraps long lines, so a
   message with no newline renders exactly as it did before. */
.flash-message { white-space: pre-line; }
