/* ============================================================
 * PHA CMS Admin app-level styles (ported from Apps Monger).
 *
 * External on purpose: served under a strict `style-src 'self'` CSP, so nothing
 * here may move inline. Keep it small; reusable components belong in the PBW
 * design system (synced by scripts/sync-design-system.sh), not here.
 * ============================================================ */

/* One control height scale for the shell and the modal. The DS .btn carries marketing padding (51.5px tall,
   41.6px small) while Bootstrap inputs are 38px / 31px, so buttons beside inputs, in input groups and in
   table rows never lined up. Buttons follow the input heights here; padding-block is dropped so the
   height is exact whatever the font. */
:root { --control-h: 38px; --control-h-sm: 31px; }
:is(.admin-content, #app-modal) .btn:not(.btn-close, .p-0) {
  min-height: var(--control-h);
  padding-block: 0;
  padding-inline: 16px;
  justify-content: center;
  line-height: 1.2;
}
:is(.admin-content, #app-modal) :is(.btn-sm, .btn-group-sm > .btn):not(.btn-close, .p-0) {
  min-height: var(--control-h-sm);
  padding-inline: 12px;
  font-size: .875rem;
  gap: 7px;
}
:is(.admin-content, #app-modal) :is(.form-control, .form-select):not(textarea, [multiple], [size]) { min-height: var(--control-h); }
:is(.admin-content, #app-modal) :is(.form-control-sm, .form-select-sm):not(textarea, [multiple], [size]) { min-height: var(--control-h-sm); }
/* The DS lifts buttons on hover; inside an input group or table row that breaks the shared edge. */
:is(.input-group, .row-actions) > .btn:hover,
.row-actions > form > .btn:hover { transform: none; }

/* The DS .btn sets `border: 1px solid transparent`, which erases Bootstrap's outline-button borders. Outline
   buttons are tonal in this app instead: a soft tint of the variant with a hairline border, solid on hover.
   They then sit beside a solid button as a quieter button, not as floating text. */
.btn[class*="btn-outline-"] { border-color: var(--bs-btn-border-color); }
.btn[class*="btn-outline-"]:hover { border-color: var(--bs-btn-hover-border-color); }
.btn-outline-primary {
  --bs-btn-bg: var(--bs-primary-bg-subtle); --bs-btn-color: var(--bs-primary-text-emphasis); --bs-btn-border-color: var(--bs-primary-border-subtle);
  --bs-btn-hover-bg: var(--primary-solid); --bs-btn-hover-border-color: var(--primary-solid); --bs-btn-hover-color: #fff;
  --bs-btn-active-bg: var(--primary-solid-h); --bs-btn-active-border-color: var(--primary-solid-h); --bs-btn-active-color: #fff;
  --bs-btn-disabled-bg: var(--bs-primary-bg-subtle); --bs-btn-disabled-color: var(--bs-primary-text-emphasis); --bs-btn-disabled-border-color: var(--bs-primary-border-subtle);
}
.btn-outline-secondary {
  --bs-btn-bg: var(--white); --bs-btn-color: var(--ink); --bs-btn-border-color: var(--line);
  --bs-btn-hover-bg: var(--mist); --bs-btn-hover-border-color: var(--line); --bs-btn-hover-color: var(--ink);
  --bs-btn-active-bg: var(--mist); --bs-btn-active-border-color: var(--line); --bs-btn-active-color: var(--ink);
}
.btn-outline-danger {
  --bs-btn-bg: color-mix(in srgb, var(--danger) 8%, var(--white)); --bs-btn-color: var(--danger); --bs-btn-border-color: color-mix(in srgb, var(--danger) 30%, var(--white));
  --bs-btn-hover-bg: var(--danger-solid); --bs-btn-hover-border-color: var(--danger-solid); --bs-btn-hover-color: #fff;
  --bs-btn-active-bg: var(--danger-solid-h); --bs-btn-active-border-color: var(--danger-solid-h); --bs-btn-active-color: #fff;
}
/* Segmented filters (btn-check radios) and view toggles (tab buttons): unselected options stay neutral, the selected one is solid. */
:is(.btn-group > .btn-check + .btn-outline-primary, .btn-group[role="tablist"] > .btn-outline-primary) { --bs-btn-bg: var(--white); --bs-btn-color: var(--ink); --bs-btn-border-color: var(--line); --bs-btn-hover-bg: var(--mist); --bs-btn-hover-color: var(--ink); --bs-btn-hover-border-color: var(--line); }

/* Row actions in a table cell: same height, one gap, end-aligned. Icon-only buttons are square. */
.row-actions { display: inline-flex; align-items: center; justify-content: flex-end; gap: 6px; vertical-align: middle; }
.row-actions > form { display: contents; }
:is(.admin-content, #app-modal) .btn.btn-icon { padding-inline: 0; width: var(--control-h); }
:is(.admin-content, #app-modal) .btn-sm.btn-icon { width: var(--control-h-sm); }

/* HTMX request indicator. htmx's injected <style> is disabled
   (includeIndicatorStyles:false) because it would need style-src 'unsafe-inline'. */
.htmx-indicator { opacity: 0; transition: opacity 150ms ease-in; }
.htmx-request .htmx-indicator { opacity: 1; }
.htmx-request.htmx-indicator { opacity: 1; }

/* Sidebar note for an account with no AdminUI role. The sidebar stays dark in both
   colour modes, so use the sidebar's own tokens rather than .text-muted. */
.admin-nav-note {
  margin: 0;
  padding: 0 10px .5rem;
  color: var(--sidebar-label);
  font-size: .8rem;
  line-height: 1.45;
}

/* Role badges in the account menu. */
.admin-role-list {
  display: flex;
  flex-wrap: wrap;
  gap: .3rem;
  max-width: 18rem;
}

/* Programmatic focus lands on the panel heading so the swap is announced. That
   is a landing spot, not a control, and a focus ring drawn around a heading
   reads as a text box. Keyboard users still get a ring via :focus-visible,
   which browsers do not match for scripted .focus(). */
[data-panel][tabindex="-1"]:focus,
[data-panel] :is(h1, h2, h3)[tabindex="-1"]:focus {
  outline: none;
}

[data-panel][tabindex="-1"]:focus-visible,
[data-panel] :is(h1, h2, h3)[tabindex="-1"]:focus-visible {
  outline: 2px solid var(--azure);
  outline-offset: 3px;
}


/* ============================================================
 * Page heading strip.
 *
 * The design system styles `.admin-pagehead`, but its gutters are scoped to the
 * top-nav shell (`.admin-top`). AdminUI uses the sidebar shell, so the strip needs
 * to pick up the same horizontal rhythm as `.admin-content` or the title sits
 * flush against the sidebar while the content below it is inset.
 * ============================================================ */
.admin-pagehead {
  padding-inline: 16px;
}

@media (min-width: 721px) {
  .admin-pagehead {
    padding-inline: 22px;
  }
}

.admin-pagehead .admin-heading {
  display: flex;
  align-items: center;
  gap: 1rem;
}

/* h1 now, not a <p>. Same size as the design system's title — this is a heading
   change for the document outline, not a visual one. */
.admin-pagehead .admin-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.05rem;
  color: var(--ink);
  margin: 0;
}

/* Breadcrumb. Rebuilt from the page on every navigation (app.js 3); styled as a quiet
   trail: muted, chevron-separated steps leading to the current page, which is the one
   solid element. Long names are cut short
   rather than wrapping the page head onto two lines; the full name is the heading beside. */
.admin-pagehead .breadcrumb {
  --bs-breadcrumb-divider: "›";
  --bs-breadcrumb-divider-color: var(--muted);
  --bs-breadcrumb-item-padding-x: .4rem;
  flex-wrap: nowrap;
  align-items: center;
  min-width: 0;
  font-size: .8125rem;
  margin: 0;
}

.admin-pagehead nav[aria-label="Breadcrumb"] { min-width: 0; }

.admin-pagehead .breadcrumb-item {
  display: flex;
  align-items: center;
  min-width: 0;
  white-space: nowrap;
}

.admin-pagehead .breadcrumb-item + .breadcrumb-item::before {
  font-size: 1rem;
  line-height: 1;
  opacity: .7;
}

.admin-pagehead .breadcrumb-item > a {
  display: inline-flex;
  align-items: center;
  padding: .2rem .45rem;
  border-radius: 6px;
  color: var(--muted);
  text-decoration: none;
  transition: color .15s ease, background-color .15s ease;
}

.admin-pagehead .breadcrumb-item > a:hover {
  color: var(--azure);
  background: color-mix(in srgb, var(--azure) 9%, transparent);
}

.admin-pagehead .breadcrumb-item > a:focus-visible {
  outline: 2px solid var(--azure);
  outline-offset: 1px;
}

/* The current page is the one crumb that is not a destination. */
.admin-pagehead .breadcrumb-item.active > span {
  display: inline-block;
  max-width: 22rem;
  overflow: hidden;
  text-overflow: ellipsis;
  padding: .2rem .55rem;
  border-radius: 6px;
  background: var(--tint);
  color: var(--ink);
  font-weight: 600;
}

/* Only the home crumb carries an icon; on its own it needs no label to be understood. */
.admin-pagehead .breadcrumb-item .fa-house { font-size: .8em; }


/* ---------------------------------------------------------------------------
   Public pages — sign-out and anything else seen without an account.

   Standalone by design: no sidebar, no topbar, no breadcrumb, because none of
   those mean anything to someone who is not signed in. See _PublicLayout.
   --------------------------------------------------------------------------- */
.public-body { background: var(--paper); }

.public-shell {
    min-height: 100dvh;
    display: grid;
    place-items: center;
    padding: 24px;
}

.public-card {
    width: 100%;
    max-width: 30rem;
    background: var(--white);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 40px 36px 32px;
    text-align: center;
}

.public-brand {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 28px;
    color: var(--ink);
    font-family: var(--font-display);
    font-weight: 600;
}

.public-ico {
    width: 60px;
    height: 60px;
    margin: 0 auto 20px;
    display: grid;
    place-items: center;
    border-radius: 16px;
    background: var(--mist);
    color: var(--azure);
    font-size: 1.45rem;
}

.public-title {
    font-size: 1.35rem;
    font-family: var(--font-display);
    color: var(--ink);
    margin-bottom: 10px;
}

.public-lead {
    color: var(--muted);
    max-width: 34ch;
    margin: 0 auto 26px;
}

.public-action { min-width: 12rem; }

.public-note {
    margin: 20px 0 0;
    font-size: .86rem;
    color: var(--muted);
}

/* Sign-in landing backdrop (opt-in: ViewData["PublicBodyClass"] = "is-hero").
   Always light, whatever the theme: a bright paper base with soft azure, teal and
   sky glows drifting slowly (::before) and a faint grid fading out from the
   centre (::after). Pure CSS, so nothing for the CSP to allow. The light tokens
   are pinned here so the card's text keeps its AA contrast in dark mode too. */
.public-body.is-hero,
[data-bs-theme="dark"] .public-body.is-hero {
    --paper: #FBFCFD;
    --white: #fff;
    --mist:  #EEF1F5;
    --ink:   #0E1622;
    --text:  #1C2530;
    --muted: #5A6675;
    --line:  #E0E4EB;
    --azure: #3F6DA6;
    --vector:#4E9A93;
    color-scheme: light;
    color: var(--text);

    position: relative;
    isolation: isolate;
    overflow-x: hidden;
    background: linear-gradient(165deg, #F7F9FC 0%, #EEF3F9 55%, #EAF4F2 100%);
}

.public-body.is-hero::before,
.public-body.is-hero::after {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
}

.public-body.is-hero::before {
    inset: -20%;
    background:
        radial-gradient(36% 40% at 20% 25%, rgba(63, 109, 166, .30), transparent 70%),
        radial-gradient(34% 38% at 82% 75%, rgba(78, 154, 147, .28), transparent 70%),
        radial-gradient(28% 32% at 75% 15%, rgba(140, 180, 230, .32), transparent 70%),
        radial-gradient(30% 30% at 15% 85%, rgba(170, 210, 205, .30), transparent 70%);
    filter: blur(50px);
    animation: hero-drift 30s ease-in-out infinite alternate;
}

.public-body.is-hero::after {
    background-image:
        linear-gradient(rgba(14, 22, 34, .045) 1px, transparent 1px),
        linear-gradient(90deg, rgba(14, 22, 34, .045) 1px, transparent 1px);
    background-size: 44px 44px;
    -webkit-mask-image: radial-gradient(ellipse 70% 60% at 50% 45%, #000 15%, transparent 72%);
    mask-image: radial-gradient(ellipse 70% 60% at 50% 45%, #000 15%, transparent 72%);
}

@keyframes hero-drift {
    0%   { transform: translate3d(0, 0, 0) rotate(0deg) scale(1); }
    50%  { transform: translate3d(3%, -2%, 0) rotate(8deg) scale(1.06); }
    100% { transform: translate3d(-3%, 3%, 0) rotate(-6deg) scale(1.02); }
}

.is-hero .public-card {
    position: relative;
    background: rgba(255, 255, 255, .78);
    border: 1px solid rgba(255, 255, 255, .9);
    border-radius: 18px;
    box-shadow:
        0 0 0 1px rgba(14, 22, 34, .05),
        0 24px 60px -28px rgba(31, 52, 82, .35),
        0 0 100px -40px rgba(63, 109, 166, .45);
    -webkit-backdrop-filter: blur(16px) saturate(160%);
    backdrop-filter: blur(16px) saturate(160%);
}

/* A thin azure→teal edge light along the top of the card. */
.is-hero .public-card::before {
    content: "";
    position: absolute;
    inset: 0 24px auto;
    height: 2px;
    border-radius: 2px;
    background: linear-gradient(90deg, transparent, var(--azure), var(--vector), transparent);
}

.is-hero .public-ico {
    background: linear-gradient(140deg, var(--azure), var(--vector));
    color: #fff;
    box-shadow: 0 12px 26px -12px rgba(63, 109, 166, .7);
}

@media (prefers-reduced-motion: reduce) {
    .public-body.is-hero::before { animation: none; }
}

@media (prefers-reduced-transparency: reduce) {
    .is-hero .public-card { background: #fff; -webkit-backdrop-filter: none; backdrop-filter: none; }
}


/* /account/claims */
.claims-kpi-text { font-family: var(--font-display); font-weight: 600; font-size: 1.1rem; color: var(--ink); margin-top: 14px; line-height: 1.25; }
.claims-kpi-of { font-size: 1rem; font-weight: 500; color: var(--muted); }
.claims-dl { display: grid; grid-template-columns: max-content 1fr; gap: 10px 20px; }
.claims-dl dt { font-weight: 500; color: var(--muted); }
.claims-dl dd { margin: 0; word-break: break-all; }
.claims-roles li { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--line); color: var(--muted); }
.claims-roles li:last-child { border-bottom: 0; }
.claims-roles li.is-held { color: var(--ink); font-weight: 500; }
.claims-roles li.is-held .fa-circle-check { color: var(--success); }
.claims-table td { vertical-align: top; }
.claims-table tr.is-role > td { background: color-mix(in srgb, var(--success) 8%, transparent); }
.claims-copy.is-copied .claims-copy-label::after { content: " ✓"; }
@media (max-width: 560px) { .claims-dl { grid-template-columns: 1fr; gap: 2px; } .claims-dl dd { margin-bottom: 8px; } }

/* The sidebar is a fixed-height flex column. With the full menu it is taller than the viewport, and flex items
   shrink by default, which crushed the section labels and brand into each other. Keep their natural height and let
   the sidebar scroll (it already has overflow-y: auto). */
.admin-sidebar > * { flex-shrink: 0; }

/* Build stamp at the foot of the sidebar. margin-top:auto pushes it to the bottom of the
   flex column; the sidebar's own tokens keep it legible on the always-dark background.
   Quiet on purpose — it is for support calls, not for navigation. */
.admin-build {
  margin-top: auto;
  padding-top: .75rem;
  border-top: 1px solid rgba(255, 255, 255, .14);
}

.admin-build a {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 10px;
  border-radius: 9px;
  color: var(--sidebar-label);
  font-size: .75rem;
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
}

.admin-build a:hover { background: var(--sidebar-hover); color: #fff; }

.admin-build .ico { flex-shrink: 0; width: 20px; display: grid; place-items: center; }

.admin-build-version { font-family: var(--font-mono); }

.admin-build-commit {
  margin-left: .4rem;
  padding: .05rem .35rem;
  border-radius: 4px;
  background: rgba(255, 255, 255, .12);
  font-family: var(--font-mono);
  font-size: .7rem;
}

.admin.is-collapsed .admin-build a,
.admin.admin-app .admin-build a { justify-content: flex-start; }

@media (min-width: 721px) {
  .admin.is-collapsed .admin-build a { justify-content: center; gap: 0; padding-inline: 0; }
}

/* Wider than the DS default (256px) so the longest labels ("Categories / Subcategories",
   "Business Opportunities") fit. Collapsed/tablet states keep their own 76px override. */
.admin { --sb-w: 288px; }

/* The shell must never scroll itself: with overflow:hidden, focus() or scrollIntoView() can still shift it and crop
   the sidebar. clip cannot be scrolled programmatically; #content and the sidebar keep their own scrolling. */
.admin { overflow: clip; }

/* Dashboard quick-access tiles (the legacy home page tiles, read from AdminMenu.Featured). */
.dash-tiles { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px; }
.dash-tile {
    display: flex; flex-direction: column; gap: 6px; height: 100%;
    padding: 20px; background: var(--white); border: 1px solid var(--line); border-radius: var(--radius);
    box-shadow: var(--shadow); color: var(--text); text-decoration: none;
    transition: border-color .15s ease, transform .15s ease;
}
.dash-tile:hover, .dash-tile:focus-visible { border-color: var(--azure); color: var(--text); transform: translateY(-1px); }
.dash-tile-ico {
    width: 44px; height: 44px; margin-bottom: 8px; display: grid; place-items: center;
    border-radius: 12px; background: var(--mist); color: var(--azure); font-size: 1.15rem;
}
.dash-tile-title { font-family: var(--font-display); font-weight: 600; color: var(--ink); }
.dash-tile-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; font-size: .84rem; color: var(--muted); }
@media (prefers-reduced-motion: reduce) { .dash-tile { transition: none; } .dash-tile:hover { transform: none; } }

/* Public email confirmation (/Validate/*) outcome icons. */
.public-ico.is-success { color: var(--success); background: color-mix(in srgb, var(--success) 12%, transparent); }
.public-ico.is-warning { color: var(--warning); background: color-mix(in srgb, var(--warning) 14%, transparent); }

/* Read-only record details (e.g. the Youthbuild application): label beside value, stacked on narrow screens. */
.app-dl { display: grid; grid-template-columns: minmax(9rem, 14rem) 1fr; gap: .5rem 1rem; margin: 0; }
.app-dl dt { font-weight: 600; color: var(--muted); }
.app-dl dd { margin: 0; overflow-wrap: anywhere; }
/* In a half-width card (the modal's fraud report) the label column only takes what its longest label needs. */
.app-dl-compact { grid-template-columns: minmax(5.5rem, max-content) 1fr; }
@media (max-width: 575.98px) {
  .app-dl { grid-template-columns: 1fr; gap: .125rem; }
  .app-dl dd { margin-bottom: .5rem; }
}
@media print {
  .app-dl { grid-template-columns: 12rem 1fr; }
}

/* Rich-text editor (Syncfusion, js/editor.js). Its stylesheet loads on demand after this one, so the
   rules are scoped under .admin to win and re-skin the editor with the admin tokens (light and dark). */
.admin .app-editor.e-richtexteditor {
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--white); overflow: hidden;
}
.admin .app-editor.e-richtexteditor.e-focused,
.admin .app-editor.e-richtexteditor:focus-within { border-color: var(--azure); box-shadow: 0 0 0 3px color-mix(in srgb, var(--azure) 20%, transparent); }
.admin .app-editor .e-toolbar,
.admin .app-editor .e-toolbar .e-toolbar-items,
.admin .app-editor .e-toolbar .e-toolbar-item .e-tbar-btn,
.admin .app-editor .e-toolbar .e-hor-nav,
.admin .app-editor .e-toolbar .e-toolbar-pop { background: var(--mist); color: var(--text); }
.admin .app-editor .e-toolbar { border-bottom: 1px solid var(--line); }
.admin .app-editor .e-toolbar .e-toolbar-item .e-tbar-btn .e-icons,
.admin .app-editor .e-toolbar .e-toolbar-item .e-tbar-btn .e-btn-icon,
.admin .app-editor .e-toolbar .e-toolbar-item .e-tbar-btn .e-tbar-btn-text { color: var(--text); }
/* Dropdown and split (colour, list, code block) buttons paint with Syncfusion's theme variables, so the toolbar's
   button background follows --mist, and dark mode remaps the light-only theme (popups and dialogs live on <body>).
   :root[...] outranks the theme's own :root, which editor.js injects after this file. */
.admin .app-editor { --color-sf-content-bg-color-alt1: var(--mist); }
.admin .app-editor .e-toolbar .e-toolbar-item .e-btn .e-icons,
.admin .app-editor .e-toolbar .e-toolbar-item .e-btn .e-caret,
.admin .app-editor .e-toolbar .e-toolbar-item .e-btn .e-rte-dropdown-btn-text { color: var(--text); }
:root[data-bs-theme="dark"] {
    --color-sf-content-bg-color: var(--white);
    --color-sf-content-bg-color-alt1: var(--mist);
    --color-sf-content-bg-color-alt2: var(--mist);
    --color-sf-content-bg-color-alt3: var(--line);
    --color-sf-content-bg-color-hover: var(--mist);
    --color-sf-content-bg-color-pressed: var(--mist);
    --color-sf-content-bg-color-focus: var(--mist);
    --color-sf-content-bg-color-disabled: var(--mist);
    --color-sf-flyout-bg-color: var(--white);
    --color-sf-flyout-bg-color-hover: var(--mist);
    --color-sf-flyout-bg-color-focus: var(--mist);
    --color-sf-flyout-border: var(--line);
    --color-sf-content-text-color: var(--text);
    --color-sf-content-text-color-alt1: var(--muted);
    --color-sf-content-text-color-alt2: var(--muted);
    --color-sf-content-text-color-hover: var(--ink);
    --color-sf-content-text-color-focus: var(--ink);
    --color-sf-content-text-color-disabled: var(--muted);
    --color-sf-placeholder-text-color: var(--muted);
    --color-sf-icon-color: var(--text);
    --color-sf-icon-color-hover: var(--ink);
    --color-sf-icon-color-pressed: var(--ink);
    --color-sf-close-icon-color: var(--muted);
    --color-sf-close-icon-color-hover: var(--text);
    --color-sf-border-light: var(--line);
    --color-sf-border: var(--line);
    --color-sf-border-hover: var(--line);
    --color-sf-border-pressed: var(--line);
    --color-sf-border-disabled: var(--line);
    --color-sf-tab-border: var(--line);
}
.admin .app-editor .e-toolbar .e-toolbar-item .e-tbar-btn:hover,
.admin .app-editor .e-toolbar .e-toolbar-item .e-tbar-btn.e-active,
.admin .app-editor .e-toolbar .e-toolbar-item.e-active .e-tbar-btn { background: var(--white); }
.admin .app-editor .e-toolbar .e-toolbar-item .e-tbar-btn:hover .e-icons,
.admin .app-editor .e-toolbar .e-toolbar-item.e-active .e-tbar-btn .e-icons { color: var(--azure); }
.admin .app-editor .e-rte-content,
.admin .app-editor .e-rte-content .e-content { background: var(--white); color: var(--text); }
.admin .app-editor .e-rte-content .e-content { padding: 12px 14px; font-family: inherit; font-size: 1rem; }
.admin .app-editor .e-rte-content .e-content a { color: var(--azure); }
/* Tables: the editor sizes them with style="" (blocked by the CSP, stripped on save), so the layout lives here. */
.admin .app-editor .e-rte-content .e-content table { width: 100%; border-collapse: collapse; margin-bottom: 1rem; }
.admin .app-editor .e-rte-content .e-content :is(th, td) { border: 1px solid var(--line); padding: 6px 8px; vertical-align: top; }
.admin .app-editor .e-rte-srctextarea { background: var(--ink); color: var(--white); font-family: ui-monospace, Menlo, Consolas, monospace; }
.admin .app-editor .e-dialog { color: var(--text); }

/* Global modal (#app-modal): the fragment may wrap body and footer in a <form>, or in .app-modal-sheet when it only
   shows something, so the scrollable dialog's flex column is carried through that wrapper and .modal-body still scrolls. */
.app-modal-body, .app-modal-body > form, .app-modal-body > .app-modal-sheet { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }

/* Free text typed by the public (Interactive submissions): long URLs and words must not widen the modal. */
.app-submission-text { overflow-wrap: anywhere; }

/* The design system's .eyebrow as a section label inside a card, where .card h3 would otherwise enlarge it. */
.card .eyebrow { font-size: .76rem; margin-bottom: .75rem; }

/* Filters above a DataTable (app.js, section 11): a row of labelled controls that wraps on narrow screens. */
.app-filter-bar { display: flex; flex-wrap: wrap; align-items: flex-end; gap: .75rem 1.25rem; margin-bottom: 1rem; }
.app-filter-bar > fieldset { margin: 0; }
.app-filter { display: flex; flex-direction: column; gap: .25rem; min-width: 12rem; }

/* Idle sign-out warning: above the modal and its backdrop, so it shows whatever is open. */
.session-warning {
  position: fixed; top: 16px; left: 50%; transform: translateX(-50%); z-index: 1090;
  display: flex; align-items: center; flex-wrap: wrap; gap: 12px; width: max-content; max-width: calc(100vw - 32px); margin: 0;
}
.session-warning[hidden] { display: none; }
.session-warning-actions { display: flex; gap: 8px; }

/* Upload progress (form[data-upload], app.js section 10). <progress> keeps its value off style="". */
[data-upload-progress] { display: flex; align-items: center; gap: 10px; margin-top: 8px; font-size: .9rem; }
[data-upload-progress][hidden] { display: none; }
[data-upload-progress] progress { flex: 0 1 220px; accent-color: var(--azure); }
[data-upload-progress][data-upload-failed] { color: var(--danger); }
[data-upload-progress][data-upload-failed] progress { display: none; }

/* Knowledge Base (KBase area): category cards, their SVG icon chip, and the helpfulness meter. */
.kbase-cards { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; }
.kbase-card {
    display: flex; flex-direction: column; gap: 10px; padding: 18px;
    background: var(--white); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow);
}
.kbase-card.is-inactive { background: var(--tint); }
.kbase-card.is-inactive .kbase-icon { opacity: .55; }
.kbase-card-head { display: flex; align-items: flex-start; gap: 12px; }
.kbase-card-name { min-width: 0; }
.kbase-card-title { margin: 0 0 4px; font-family: var(--font-display); font-size: 1rem; font-weight: 600; color: var(--ink); overflow-wrap: anywhere; }
.kbase-card-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: .8rem; color: var(--muted); }
.kbase-card-text { margin: 0; font-size: .875rem; color: var(--muted); }
.kbase-card-counts { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 0; font-size: .84rem; color: var(--text); }
.kbase-card-counts i { color: var(--azure); margin-right: 4px; }
.kbase-card-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: auto; }

/* The icon sits on a white chip: the stored SVGs are drawn in currentColor (black inside an <img>). */
.kbase-icon { flex: none; width: 44px; height: 44px; display: grid; place-items: center; border-radius: 12px; background: #fff; border: 1px solid var(--line); }
.kbase-icon img { width: 26px; height: 26px; }
.kbase-icon-lg { width: 64px; height: 64px; }
.kbase-icon-lg img { width: 40px; height: 40px; }
.kbase-icon-field { display: flex; align-items: flex-start; gap: 12px; }
.kbase-icon-field textarea { flex: 1; }

.kbase-meter { display: flex; align-items: center; gap: 8px; min-width: 9rem; }
.kbase-meter-bar { flex: 1; height: 8px; appearance: none; border: 0; border-radius: 999px; background: var(--mist); overflow: hidden; }
.kbase-meter-bar::-webkit-progress-bar { background: var(--mist); border-radius: 999px; }
.kbase-meter-bar::-webkit-progress-value { background: var(--success); border-radius: 999px; }
.kbase-meter-bar::-moz-progress-bar { background: var(--success); border-radius: 999px; }
.kbase-meter-bar.is-low::-webkit-progress-value { background: var(--warning); }
.kbase-meter-bar.is-low::-moz-progress-bar { background: var(--warning); }

/* Agency Properties (AgencyProperties area): property photo cards by category, the editor's previews, the gallery
   grid, demographics bars and the payment standards grid. */
.property-group + .property-group { margin-top: 28px; }
.property-group-title { display: flex; align-items: center; gap: 8px; margin: 0 0 12px; font-family: var(--font-display); font-size: 1rem; font-weight: 600; color: var(--ink); }
.property-group-count { font-size: .78rem; font-weight: 600; color: var(--muted); background: var(--tint); border: 1px solid var(--line); border-radius: 999px; padding: 1px 9px; }
.property-cards { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 18px; }
.property-card { display: flex; flex-direction: column; overflow: hidden; background: var(--white); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); }
.property-photo { position: relative; aspect-ratio: 16 / 10; background: var(--mist); }
.property-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.property-card.is-inactive .property-photo img { filter: grayscale(1); opacity: .7; }
.property-status { position: absolute; top: 10px; left: 10px; }
.property-body { display: flex; flex-direction: column; gap: 6px; flex: 1; padding: 14px 16px 16px; }
.property-name { margin: 0; font-family: var(--font-display); font-size: 1rem; font-weight: 600; color: var(--ink); overflow-wrap: anywhere; }
.property-address { margin: 0; font-size: .85rem; color: var(--muted); }
.property-address i { color: var(--azure); margin-right: 4px; }
.property-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: auto; padding-top: 8px; }

.property-legend { font-family: var(--font-mono); font-size: .72rem; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); margin-bottom: 4px; }
.property-preview { display: block; width: 100%; aspect-ratio: 16 / 10; object-fit: cover; border-radius: var(--radius); border: 1px solid var(--line); }
.property-map { display: block; width: 100%; height: 220px; border: 1px solid var(--line); border-radius: var(--radius); }

.gallery-upload { padding: 16px; background: var(--tint); border: 1px dashed var(--line); border-radius: var(--radius); }
.gallery-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 14px; }
.gallery-item { display: flex; flex-direction: column; overflow: hidden; background: var(--white); border: 1px solid var(--line); border-radius: var(--radius); }
.gallery-item img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; background: var(--mist); }
.gallery-item a:focus-visible { outline: 3px solid var(--azure); outline-offset: -3px; }
.gallery-item-foot { display: flex; align-items: center; justify-content: space-between; gap: 6px; padding: 8px 10px; }

.news-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; padding: 14px 16px; background: var(--tint); border: 1px solid var(--line); border-radius: var(--radius); }
.news-thumb { display: block; width: 96px; aspect-ratio: 4 / 3; object-fit: cover; background: var(--mist); border: 1px solid var(--line); border-radius: var(--radius); }
.news-featured { display: grid; grid-template-columns: minmax(0, 240px) minmax(0, 1fr); gap: 18px; align-items: start; }
.news-featured img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; background: var(--mist); border: 1px solid var(--line); border-radius: var(--radius); }
@media (max-width: 575.98px) { .news-featured { grid-template-columns: 1fr; } }

/* Events Calendar: the category names are long; the filter keeps to the row instead of pushing the others down. */
.events-category-filter { width: 12rem; }

/* Forms Center: the same long category names in its filter. Landing Slides: the home page's 16:9 slides. */
.forms-category-filter { width: 14rem; }
.slide-thumb { display: block; width: 128px; aspect-ratio: 16 / 9; object-fit: cover; background: var(--mist); border: 1px solid var(--line); border-radius: var(--radius); }
.slide-preview { display: block; width: 100%; max-width: 480px; aspect-ratio: 16 / 9; object-fit: cover; background: var(--mist); border: 1px solid var(--line); border-radius: var(--radius); }

/* Awarded Employees: the 3:4 employee photo (600 x 800) as a table thumb and an editor preview, and the award history chips. */
.employee-cell { display: flex; align-items: center; gap: 10px; }
.employee-thumb { display: flex; align-items: center; justify-content: center; flex: none; width: 40px; aspect-ratio: 3 / 4; font-size: .625rem; object-fit: cover; color: var(--muted); background: var(--mist); border: 1px solid var(--line); border-radius: var(--radius); }
.employee-photo-current { display: flex; align-items: center; gap: 12px; padding: 10px 12px; background: var(--tint); border: 1px solid var(--line); border-radius: var(--radius); }
.employee-photo { display: block; flex: none; width: 56px; aspect-ratio: 3 / 4; object-fit: cover; background: var(--mist); border: 1px solid var(--line); border-radius: var(--radius); }
.award-history { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 4px; }

.demographic-scopes { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 18px; }
.demographic-card { padding: 18px; background: var(--white); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); }
.demographic-card-head { display: flex; align-items: center; min-height: 28px; justify-content: space-between; gap: 8px; margin-bottom: 12px; }
.demographic-card-title { margin: 0; font-family: var(--font-display); font-size: 1rem; font-weight: 600; color: var(--ink); }
.demographic-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.demographic-row { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; grid-template-areas: "label value edit" "bar bar bar"; align-items: center; column-gap: 8px; row-gap: 4px; }
.demographic-row.is-inactive { opacity: .65; }
.demographic-label { grid-area: label; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: .9rem; color: var(--text); }
.demographic-value { grid-area: value; font-family: var(--font-display); font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }
.demographic-row .btn { grid-area: edit; }
.demographic-bar { grid-area: bar; width: 100%; height: 8px; appearance: none; border: 0; border-radius: 999px; background: var(--mist); overflow: hidden; }
.demographic-bar::-webkit-progress-bar { background: var(--mist); border-radius: 999px; }
.demographic-bar::-webkit-progress-value { background: var(--azure); border-radius: 999px; }
.demographic-bar::-moz-progress-bar { background: var(--azure); border-radius: 999px; }

.ps-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 14px; }

/* File pickers: the browser's "Choose files" button, in the design system's quiet button style. */
.form-control[type="file"] { cursor: pointer; }
.form-control[type="file"]::file-selector-button { font: inherit; font-weight: 600; color: var(--azure); background: var(--tint); border: 0; border-inline-end: 1px solid var(--line); margin-block: -.375rem; margin-inline: -.75rem .75rem; padding: .375rem .9rem; cursor: pointer; transition: background-color .15s; }
.form-control[type="file"]:hover::file-selector-button { background: var(--mist); }

/* Procurement (vendor review modal): the header facts, the document list, the action column and the timeline. */
.vendor-head { display: flex; flex-direction: column; gap: 12px; padding-bottom: 16px; margin-bottom: 16px; border-bottom: 1px solid var(--line); }
.vendor-facts { display: flex; flex-wrap: wrap; gap: 12px 32px; margin: 0; }
.vendor-facts dt { font-family: var(--font-mono); font-size: .7rem; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); font-weight: 500; }
.vendor-facts dd { margin: 2px 0 0; color: var(--ink); }
.vendor-blockers ul { font-size: .9rem; }
.vendor-tabs { border-bottom: 1px solid var(--line); }
.vendor-text { white-space: pre-line; overflow-wrap: anywhere; }
.vendor-docs { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.vendor-doc { border: 1px solid var(--line); border-radius: var(--radius); padding: 12px 14px; background: var(--white); }
.vendor-doc-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; }
.vendor-doc-file { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; margin-top: 8px; }
.vendor-doc-review { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 8px; margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--line); }
.vendor-doc-review > .alert { flex-basis: 100%; }
.vendor-doc-review > input[name="Note"] { flex: 1 1 240px; }
.vendor-card { border: 1px solid var(--line); border-radius: var(--radius); padding: 14px; background: var(--tint); }
.vendor-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.vendor-actions { position: sticky; top: 0; display: grid; gap: 14px; padding: 14px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--tint); }
.vendor-action + .vendor-action { padding-top: 14px; border-top: 1px solid var(--line); }
.vendor-action h4 { font-family: var(--font-display); font-size: .95rem; font-weight: 600; color: var(--ink); margin: 0 0 6px; }
.vendor-timeline { list-style: none; margin: 0; padding: 0 0 0 18px; border-left: 2px solid var(--line); display: grid; gap: 14px; }
.vendor-timeline li { position: relative; }
.vendor-timeline li::before { content: ""; position: absolute; left: -24px; top: 6px; width: 10px; height: 10px; border-radius: 50%; background: var(--azure); box-shadow: 0 0 0 3px var(--white); }
.kpi.kpi-alert .kpi-ico { background: color-mix(in srgb, var(--danger) 14%, transparent); color: var(--danger); }
.kpi.kpi-alert .kpi-value { color: var(--danger); }
.kpi.kpi-warn .kpi-ico { background: color-mix(in srgb, var(--warning) 14%, transparent); color: var(--warning); }
/* Dialogs (SweetAlert2, app.js section 6): design-system type, colour, radius and buttons. */
.swal2-container { z-index: 2000; }
.swal2-popup.app-dialog { width: 28rem; padding: 28px 24px 22px; font-family: var(--font-body); color: var(--text); background: var(--white); border-radius: var(--radius); box-shadow: var(--shadow-lg); }
.app-dialog .app-dialog-title { padding: 0 8px; font-family: var(--font-display); font-size: 1.25rem; font-weight: 600; color: var(--ink); }
.app-dialog .app-dialog-text { margin: 10px 8px 0; padding: 0; font-size: .95rem; line-height: 1.5; color: var(--muted); }
.app-dialog .app-dialog-actions { gap: 8px; margin-top: 22px; }
.app-dialog .app-dialog-actions .btn { min-width: 7rem; margin: 0; }
.app-dialog .swal2-icon { margin-top: 4px; transform: scale(.8); }
.app-dialog .swal2-icon.swal2-question { color: var(--azure); border-color: var(--azure); }
.app-dialog .swal2-icon.swal2-info { color: var(--info); border-color: var(--info); }
.app-dialog .swal2-icon.swal2-warning { color: var(--warning-solid); border-color: var(--warning-solid); }
.app-dialog .swal2-icon.swal2-error { color: var(--danger); border-color: var(--danger); }
.app-dialog .swal2-icon.swal2-error [class^="swal2-x-mark-line"] { background-color: var(--danger); }
.app-dialog .swal2-input.form-control { width: auto; margin: 16px 8px 0; font-family: var(--font-mono); font-size: .875rem; box-shadow: none; }

/* Real Estate: the listing's front photo as a table thumb, the photo cards' edit area, the feature checklists and multi-line lead text. */
.listing-thumb { display: flex; align-items: center; justify-content: center; width: 72px; aspect-ratio: 4 / 3; object-fit: cover; color: var(--muted); background: var(--mist); border: 1px solid var(--line); border-radius: var(--radius); }
.gallery-item-body { display: grid; gap: 8px; padding: 8px 10px 0; }
.feature-checks { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 2px 12px; }
.lead-questions { white-space: pre-line; }
.listing-photos { grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }

/* Sidebar scrollbar. A native scrollbar takes its width from the menu whenever a mouse is attached, so the sidebar
   hides it and app.js (section 18) draws an overlay thumb that takes no space: it shows while scrolling or while the
   pointer is over the sidebar, and can be dragged. Wheel, touch and keyboard scrolling are unchanged. */
.admin-sidebar { scrollbar-width: none; }
.admin-sidebar::-webkit-scrollbar { display: none; }
@media (min-width: 721px) { .admin-sidebar { position: relative; } }
.sidebar-thumb {
  position: absolute; top: 0; inset-inline-end: 2px; z-index: 1;
  width: 6px; min-height: 24px; border-radius: 3px;
  background: rgba(255, 255, 255, .32);
  opacity: 0; transition: opacity .25s ease, width .15s ease, background-color .15s ease;
  cursor: grab; touch-action: none;
}
.sidebar-thumb[hidden] { display: none; }
.admin-sidebar:hover > .sidebar-thumb { opacity: .6; }
.admin-sidebar.is-scrolling > .sidebar-thumb,
.sidebar-thumb:hover,
.sidebar-thumb.is-dragging { opacity: 1; }
.sidebar-thumb:hover,
.sidebar-thumb.is-dragging { width: 8px; background: rgba(255, 255, 255, .5); }
.sidebar-thumb.is-dragging { cursor: grabbing; }
@media (prefers-reduced-motion: reduce) { .sidebar-thumb { transition: none; } }

/* ============================================================
   Dark mode fixes. The design system files (styles.css, bootstrap-bridge.css) are synced, so the app's overrides
   live here.
   ============================================================ */

/* Smooth colour-mode switch (app.js section 19): colours ease for the length of the switch only. */
@media (prefers-reduced-motion: no-preference) {
  .theme-switching,
  .theme-switching *,
  .theme-switching *::before,
  .theme-switching *::after {
    transition: background-color .3s ease, color .3s ease, border-color .3s ease, fill .3s ease, box-shadow .3s ease !important;
  }
}

/* Bootstrap's light badge is a fixed #f8f9fa with black text: lost on the light page, a glaring chip on the dark one.
   The neutral count and status pills follow the surface tokens in both modes. */
.text-bg-light { color: var(--ink) !important; background-color: var(--mist) !important; }

/* The bridge tunes the state colours for white text on a fill; as text on the dark surfaces they fall to ~3:1. Dark
   mode uses the design system's lighter text tokens for .text-* (Delete menu items, statuses, notes). */
[data-bs-theme="dark"] .text-danger  { color: var(--danger) !important; }
[data-bs-theme="dark"] .text-success { color: var(--success) !important; }
[data-bs-theme="dark"] .text-info    { color: var(--info) !important; }
[data-bs-theme="dark"] .text-warning { color: var(--warning) !important; }

/* Theme menu: the active item is filled azure with white text, so its azure check vanished. Follow the text. */
[data-theme-set].active .chk { color: inherit; }
