/* ============================================================
   TownSuite eServices redesign — production stylesheet
   Source: Claude Design handoff bundle (eservices-redesign)
   Scope: brand tokens (light+dark), global shell (top bar +
   app switcher + per-product sidebar), form primitives,
   Time Off Request page (Option B, guided steps), responsive.
   Apply by adding class "ts-app" to <body> in _SiteLayout.
   Dark theme = body.ts-app.is-dark (toggled by townsuite-shell.js).
   ============================================================ */

/* ---------- brand type: Dax (Expedition skin) ---------- */
@font-face {
  font-family: 'Dax';
  src: url('/assets/fonts/dax-regular.ttf') format('truetype'),
       url('/assets/fonts/dax-regular.otf') format('opentype');
  font-weight: 400 900;
  font-style: normal;
  font-display: swap;
}

/* ---------- tokens (Expedition palette — townsuite.com 2026) ---------- */
body.ts-app {
  --bg: #EFF3F8; --side: #FFFFFF; --card: #FFFFFF; --inset: #F3F6FA;
  --line: #DCE4EC; --line-soft: #E8EEF4;
  --head: #13212D; --text: #44586A; --muted: #5C6A77; --faint: #5F6D77;
  --navy: #003C63; --navy-deep: #003C63;
  --blue: #00578E;
  --blue-soft: color-mix(in oklab, #00578E 10%, white);
  --blue-line: color-mix(in oklab, #00578E 28%, white);
  --green: #2DA343; --red: #CE2D32; --amber: #E48D1A;
  background: var(--bg); color: var(--text);
  font-family: 'Dax', 'Source Sans 3', 'Instrument Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-size: 14.5px; line-height: 1.45; font-feature-settings: 'tnum' 1;
  -webkit-font-smoothing: antialiased; color-scheme: light;
  margin: 0;
  --disabled-bg: #f1f4f7; --disabled-border: #eaebeb; --disabled-text: #7b8d9b; --disabled-placeholder: #94a3af;
  --disabled-radio-border: #adb5bd; --disabled-radio-label: #6c757d;
  --disabled-checkbox-label: #7b8790;
  --disabled-switch-bg: #d9dee2; --disabled-switch-border: #c5ccd2;
  --disabled-kendo-border: #eaebeb;
}
body.ts-app ::selection { background: #00578E; color: #fff; }
body.ts-app.is-dark {
  --bg: #071420; --side: #0A1B2A; --card: #0D2032; --inset: #122A3F;
  --line: #1C3850; --line-soft: #173049;
  --head: #E9F0F6; --text: #A8BBCA; --muted: #8597A6; --faint: #8294A3;
  --navy: #00578E;
  --blue: color-mix(in oklab, #00578E 52%, white);
  --blue-soft: color-mix(in oklab, #00578E 17%, #0D2032);
  --blue-line: color-mix(in oklab, #00578E 42%, #0D2032);
  --green: #44B25D; --red: #E5716D; --amber: #E8A14A;
  color-scheme: dark;
  --disabled-bg: #132c3e; --disabled-border: #223d52; --disabled-text: #6f808e; --disabled-placeholder: #6f808e;
  --disabled-radio-border: #2a3d4b; --disabled-radio-label: #6f808e;
  --disabled-checkbox-label: var(--head);
  --disabled-switch-bg: #586167; --disabled-switch-border: #2a3d4b;
  --disabled-kendo-border: #2a3d4b;
}

/* ---- "auto" theme: dark tokens follow the device, from CSS only ----
   This is deliberately NOT class-driven. body.ts-app.is-dark is added by JS
   (townsuite-shell.js, plus the snippet at the top of <body> in
   _SiteLayout.TownSuite.cshtml), and script that runs after the stylesheets
   cannot be relied on to beat the first paint — on iOS/Safari that showed up
   as a white flash on every navigation. Matching on the server-rendered
   auto-theme class inside a media query means the dark tokens are in effect
   for the first paint, with no script involved.

   .pg-landing.is-auto / .pg-auth.is-auto are the logged-out landing and auth
   pages: no saved user preference exists there, so the device preference is
   the only signal, and they mark it with is-auto instead of auto-theme. */
@media (prefers-color-scheme: dark) {
  body.ts-app.auto-theme,
  body.ts-app.pg-landing.is-auto,
  body.ts-app.pg-auth.is-auto {
    --bg: #071420; --side: #0A1B2A; --card: #0D2032; --inset: #122A3F;
    --line: #1C3850; --line-soft: #173049;
    --head: #E9F0F6; --text: #A8BBCA; --muted: #8597A6; --faint: #8294A3;
    --navy: #00578E; --blue: color-mix(in oklab, #00578E 52%, white);
    --blue-soft: color-mix(in oklab, #00578E 17%, #0D2032);
    --blue-line: color-mix(in oklab, #00578E 42%, #0D2032);
    --green: #44B25D; --red: #E5716D; --amber: #E8A14A;
    color-scheme: dark;
  }
}

/* ---- 2FA method status colours (Views/User/TwoFactorVerification) ----
   twoFactorAuthentication.ts applies these as an inline style via a Kendo
   `style:{color: …}` binding, so they cannot be overridden from CSS without
   !important — and CSS alone can't tell the verified state from the unverified
   one, since that lives in the view model. The .ts therefore emits
   var(--tfa-*) and the actual colours are defined here, which keeps them
   theme-aware.

   It previously emitted the literal "Red" (#FF0000 = 4.00:1 on white) and
   "#38E027" (1.80:1) — both under the 4.5:1 AA floor for body text. No single
   literal clears AA on the white card AND the dark card, which is exactly why
   these have to be tokens rather than fixed values. */
body.ts-app { --tfa-verified: #1A6B2C; --tfa-unverified: #B71C1C; }
body.ts-app.is-dark { --tfa-verified: var(--green); --tfa-unverified: var(--red); }

.ts-dia { display: inline-block; width: 7px; height: 7px; border-radius: 1.5px; transform: rotate(45deg); background: currentColor; flex: none; }

/* ---------- shell layout ---------- */
.ts-shell-row { display: flex; min-height: calc(100vh - 58px); align-items: stretch; }
.ts-maincol { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.ts-main { flex: 1; min-width: 0; }

/* ---------- top bar ---------- */
.ts-top { height: 58px; background: var(--card); border-bottom: 1px solid var(--line); display: flex; align-items: center; gap: 16px; padding: 0 15px; position: sticky; top: 0; z-index: 100; }
.ts-top-logo { display: flex; align-items: center; gap: 7px; cursor: pointer; text-decoration: none; }
.ts-logo-img { display: block; height: 36px; width: auto; max-width: 200px; object-fit: contain; }
.ts-top .ts-logo-img.is-on-dark { display: none; }
body.is-dark .ts-top .ts-logo-img.is-on-dark { display: block; }
body.is-dark .ts-top .ts-logo-img.is-on-light { display: none; }
.ts-logo-word { font-size: 17px; font-weight: 700; letter-spacing: -0.3px; color: var(--head); }
.ts-logo-dias { display: inline-flex; gap: 3px; align-items: center; }
.ts-logo-dias .ts-dia:nth-child(1) { color: #E48D1A; }
.ts-logo-dias .ts-dia:nth-child(2) { color: #2DA343; width: 5px; height: 5px; }
.ts-logo-dias .ts-dia:nth-child(3) { color: #E03A3E; width: 4px; height: 4px; }
.ts-top-sep { width: 1px; height: 22px; background: var(--line); }
.ts-top-right { margin-left: auto; display: flex; align-items: center; gap: 12px; }

@media (min-width: 1100px) {
  body.ts-sidebar-collapsed .ts-shell-row > .ts-side { display: none; }
}

/* app switcher */
.ts-switchwrap { position: relative; }
.ts-switch { height: 38px; display: inline-flex; align-items: center; gap: 10px; border: 1px solid var(--line); border-radius: 9px; background: var(--card); padding: 0 13px; font-size: 13.5px; font-weight: 600; color: var(--head); cursor: pointer; }
.ts-switch:hover { background: var(--inset); }
.ts-grid9 { display: grid; grid-template-columns: repeat(3, 3px); gap: 2.5px; }
.ts-grid9 span { width: 3px; height: 3px; border-radius: 1px; background: var(--blue); }
.ts-chev { width: 7px; height: 7px; border-right: 1.6px solid var(--muted); border-bottom: 1.6px solid var(--muted); transform: rotate(45deg) translateY(-2px); flex: none; }
.ts-pop { position: absolute; top: 46px; left: 0; width: min(384px, calc(100vw - 32px)); z-index: 170; background: var(--card); border: 1px solid var(--line); border-radius: 14px; box-shadow: 0 18px 50px rgba(12,44,73,0.18); padding: 16px; display: none; }
.ts-pop.is-open { display: block; }
.ts-pop-head { font-size: 12px; letter-spacing: 1.3px; text-transform: uppercase; color: var(--faint); font-weight: 600; margin: 0 4px 8px; }
.ts-pop-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; }
.ts-pop-app { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 8px; font-size: 13px; font-weight: 600; color: var(--text); cursor: pointer; text-decoration: none; }
.ts-pop-app:hover:not(.is-current) { background: var(--inset); }
.ts-pop-app .ts-dia { width: 7px; height: 7px; color: var(--faint); } /* was #B9C8D4 — 1.71:1 vs card, fails 3:1 */
.ts-pop-app.is-current { background: var(--blue-soft); color: var(--navy); }
.ts-pop-app.is-current .ts-dia, body.is-dark .ts-pop-app.is-current { color: var(--blue); }
.ts-pop-block + .ts-pop-block { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line-soft); }
.ts-pop-foot { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line-soft); display: flex; gap: 18px; font-size: 12.5px; }

/* icon buttons / badges / avatar / avatar menu */
.ts-iconbtn { width: 34px; height: 34px; border-radius: 8px; border: 1px solid var(--line); display: grid; place-items: center; position: relative; background: var(--card); cursor: pointer; }
.ts-iconbtn:hover { background: var(--inset); }
/* FontAwesome glyphs used in the top-bar icon buttons (Finance, Notifications) */
a.ts-iconbtn { text-decoration: none; }
.ts-iconbtn .fa { font-size: 15px; line-height: 1; color: var(--muted); }
.ts-iconbtn:hover .fa { color: var(--head); }
/* display:grid !important so the count stays centered even when BackgroundTasks()
   forces an inline display:block on #notification_fullcount / #cart_fullcount */
.ts-badge { position: absolute; top: -6px; right: -6px; min-width: 16px; height: 16px; border-radius: 999px; background: #CE2D32; color: #fff; font-size: 9.5px; font-weight: 700; display: grid !important; place-items: center; padding: 0 4px; border: 1.5px solid var(--side); }
/* CartCount()/BackgroundTasks() empty the badge when 0 — hide the empty badge */
.ts-badge:empty { display: none !important; }
@media (max-width: 640px) {
    .ts-badge {
        top: -2px;
    }
}
/* ---- notifications dropdown (bell) ---- */
.ts-notifwrap { position: relative; }
.ts-notif { position: absolute; right: 0; top: 44px; width: 300px; background: var(--card); border: 1px solid var(--line); border-radius: 12px; box-shadow: 0 18px 50px rgba(12,44,73,0.18); padding: 8px; z-index: 140; display: none; }
.ts-notif.is-open { display: block; }
.ts-notif-head { padding: 8px 10px 10px; border-bottom: 1px solid var(--line-soft); margin-bottom: 6px; font-size: 13.5px; font-weight: 700; color: var(--head); }
.ts-notif-item { display: flex; align-items: center; gap: 11px; padding: 9px 10px; border-radius: 8px; text-decoration: none; cursor: pointer; }
.ts-notif-item:hover { background: var(--inset); }
.ts-notif-ic { flex: 0 0 34px; width: 34px; height: 34px; border-radius: 9px; display: grid; place-items: center; }
.ts-notif-ic .fa { font-size: 15px; }
/* .is-news/.is-complaints iconography: the raw token color on its own translucent
   tint chip only cleared ~2.3-2.8:1 in light mode (the tint was too pale to give
   the icon glyph enough contrast against its own chip) — reuse the same
   AA-vetted colour pairs already established for .sr-status (below) instead of
   inventing new ones, with the lighter token-based version kept for dark mode. */
.ts-notif-ic.is-news { background: rgba(221,148,52,0.12); } .ts-notif-ic.is-news .fa { color: #875200; }
body.is-dark .ts-notif-ic.is-news { background: rgba(221,148,52,0.16); } body.is-dark .ts-notif-ic.is-news .fa { color: var(--amber); }
.ts-notif-ic.is-receipts { background: var(--blue-soft); } .ts-notif-ic.is-receipts .fa { color: var(--blue); }
.ts-notif-ic.is-complaints { background: #EAF5EE; } .ts-notif-ic.is-complaints .fa { color: #1A6B2C; }
body.is-dark .ts-notif-ic.is-complaints { background: rgba(63,168,110,0.14); } body.is-dark .ts-notif-ic.is-complaints .fa { color: var(--green); }
.ts-notif-tx { display: flex; flex-direction: column; min-width: 0; }
.ts-notif-t { font-size: 13px; font-weight: 600; color: var(--head); }
.ts-notif-s { font-size: 12px; color: var(--muted); }
.ts-notif-more { justify-content: space-between; border-top: 1px solid var(--line-soft); margin-top: 6px; border-radius: 0 0 8px 8px; }
.ts-notif-more small { font-size: 12.5px; font-weight: 600; color: var(--blue); }
.ts-notif-count { min-width: 18px; height: 18px; border-radius: 999px; background: #CE2D32; color: #fff; font-size: 10px; font-weight: 700; display: inline-grid; place-items: center; padding: 0 5px; }
.ts-notif-count:empty { display: none; }
.ts-cartic { width: 13px; height: 9px; border: 1.6px solid var(--muted); border-top: none; border-radius: 0 0 4px 4px; position: relative; margin-top: 5px; }
.ts-cartic::before { content: ''; position: absolute; top: -6px; left: 1.5px; right: 1.5px; height: 6px; border: 1.6px solid var(--muted); border-bottom: none; border-radius: 5px 5px 0 0; }
.ts-bell { width: 8px; height: 8px; border-radius: 50%; border: 2px solid var(--muted); }
.ts-avatar { width: 34px; height: 34px; border-radius: 50%; background: var(--navy); color: #fff; display: grid; place-items: center; font-size: 12px; font-weight: 600; cursor: pointer; }
.ts-avatarwrap { position: relative; }
.ts-usermenu { position: absolute; right: 0; top: 44px; width: 230px; background: var(--card); border: 1px solid var(--line); border-radius: 12px; box-shadow: 0 18px 50px rgba(12,44,73,0.18); padding: 8px; z-index: 140; display: none; }
.ts-usermenu.is-open { display: block; }
.ts-usermenu-head { padding: 8px 10px 10px; border-bottom: 1px solid var(--line-soft); margin-bottom: 6px; }
.ts-usermenu-name { font-size: 13.5px; font-weight: 700; color: var(--head); }
.ts-usermenu-mail { font-size: 12px; color: var(--muted); }
.ts-usermenu-roles { font-size: 12px; color: var(--text); }
.ts-usermenu-item { display: block; padding: 8px 10px; border-radius: 8px; font-size: 13px; font-weight: 500; color: var(--text); cursor: pointer; text-decoration: none; }
.ts-usermenu-item:hover { background: var(--inset); }
.ts-usermenu-item.is-danger { color: var(--red); }

/* ---- top-bar toggles are <button>s ----
   The shell toggles (burger, app switcher, language, theme, notifications,
   overflow, avatar) are real <button> elements rather than <span>s: iOS Safari
   only bubbles a tap's click event up to `document` — where townsuite-shell.js
   keeps its single delegated listener — for natively interactive elements, so
   as <span>s they were unresponsive on iPhone/iPad while the plain <a> icons
   beside them (Cart, Finance) kept working. Neutralise the UA button chrome
   the classes above don't already override, so nothing changes visually.
   Deliberately no `display` here: `.ts-burger`, `.ts-sidebar-toggle` and
   `.ts-oflow-solo` all toggle themselves off with class-level `display:none`
   rules, which a `button.ts-iconbtn` selector would outrank. */
button.ts-iconbtn, button.ts-avatar, button.ts-switch, button.ts-more-item {
  font-family: inherit; padding: 0; margin: 0; overflow: visible;
  appearance: none; -webkit-appearance: none;
  -webkit-tap-highlight-color: transparent;
}
button.ts-switch { padding: 0 13px; }
button.ts-avatar { border: 0; }
button.ts-more-item { width: 100%; border: 0; background: none; padding: 8px 10px; text-align: left; }
/* .ts-navgrouphead (the collapsible sidebar section headers) is a <button> for
   the same reason — it lives in the drawer, which on a phone is the only way
   the sidebar is reachable at all. Its own rule below already supplies
   display/padding/font-size/weight/colour, and author declarations beat the UA
   button stylesheet at any specificity, so only these need restating. */
button.ts-navgrouphead {
  width: 100%; border: 0; background: none; font-family: inherit; text-align: left;
  appearance: none; -webkit-appearance: none; -webkit-tap-highlight-color: transparent;
}

/* Theme cycle button icons — Font Awesome fa-sun-o / fa-moon-o, injected by
   townsuite-shell.js. These are the same glyphs the settings-menu theme picker
   uses, and they inherit .ts-iconbtn .fa / .ts-more-ic .fa for size and colour
   (including the hover colour, which the hand-rolled CSS shapes never picked
   up). ts-theme-ic is the slot the script rewrites; it needs to lay the glyph
   out the same way the grid of .ts-iconbtn would. */
.ts-theme-ic { display: grid; place-items: center; }

.ts-morewrap { display: none; position: relative; }
.ts-dots { display: flex; flex-direction: column; gap: 2.5px; align-items: center; }
.ts-dots i { display: block; width: 3.5px; height: 3.5px; border-radius: 50%; background: var(--muted); font-style: normal; }
.ts-more { position: absolute; right: 0; top: 44px; width: 200px; background: var(--card); border: 1px solid var(--line); border-radius: 12px; box-shadow: 0 18px 50px rgba(12,44,73,0.18); padding: 8px; z-index: 140; display: none; }
.ts-more.is-open { display: block; }
.ts-more-item { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 8px; font-size: 13px; font-weight: 500; color: var(--text); cursor: pointer; text-decoration: none; }
.ts-more-item { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 8px; font-size: 13px; font-weight: 500; color: var(--text); cursor: pointer; text-decoration: none; }
.ts-more-item:hover { background: var(--inset); }
.ts-more-item .ts-badge { position: static; margin-left: auto; border: none; }
.ts-more-ic { width: 20px; flex: none; display: grid; place-items: center; color: var(--muted); }
.ts-more-ic .fa { font-size: 14px; }
@media (max-width: 640px) {
  .ts-oflow-solo { display: none; }
  .ts-morewrap { display: inline-flex; }
  .ts-more {
    position: fixed;
    top: auto; left: 0; right: 0; bottom: 0;
    width: auto; max-width: none;
    max-height: 75vh;
    overflow-y: auto;
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -18px 50px rgba(12,44,73,0.22);
    padding: 10px 16px calc(16px + env(safe-area-inset-bottom, 0px));
    z-index: 180;
  }
  .ts-more.is-open { animation: tssheet .18s ease; }
  .ts-more::before {
    content: ''; display: block; width: 36px; height: 4px; margin: 0 auto 14px;
    background: var(--line); border-radius: 999px;
  }
}

/* ============================================================
   Unified-tree sidebar (Sidebar Menu Options — "Unified tree")
   Every product + its modules in one filterable accordion.
   ============================================================ */
.ts-side.sb-tree { width: 252px; padding: 14px 10px 12px; }
.sb-treehead { padding: 0 2px 10px; }
.sb-filter { position: relative; display: flex; align-items: center; }
.sb-filter-in {
  width: 100%; box-sizing: border-box; height: 38px; border-radius: 9px;
  border: 1px solid var(--line); background: var(--card); color: var(--text);
  font: inherit; font-size: 13px; padding: 0 12px 0 32px;
}
.sb-filter-in:focus { outline: none; border-color: var(--blue); box-shadow: 0 0 0 3px rgba(0,87,142,0.14); }
.sb-filter-in::placeholder { color: var(--faint); }
/* Bootstrap's .form-control placeholder (commonloggedinstyle bundle) is
   #B7BAC9 on white — 1.93:1, failing WCAG AA. Site-wide, since .form-control
   is the standard text-input class throughout the app. */
.ts-app .form-control::placeholder,
.ts-app .form-control::-webkit-input-placeholder { color: var(--faint); }
.sb-filter-ic {
  position: absolute; left: 11px; width: 12px; height: 12px; pointer-events: none;
  border: 2px solid var(--faint); border-radius: 50%; box-sizing: border-box;
}
.sb-filter-ic::after {
  content: ''; position: absolute; left: 9px; top: 9px; width: 6px; height: 2px;
  background: var(--faint); border-radius: 1px; transform: rotate(45deg); transform-origin: left center;
}
.sb-treenav { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.sb-scroll { overflow-y: auto; overflow-x: hidden; min-height: 0; }
.sb-grouplabel {
  font-size: 12px; letter-spacing: 1.2px; text-transform: uppercase;
  color: var(--faint); font-weight: 700; padding: 4px 10px 6px;
}
.sb-treeadmin-label { margin-top: 8px; padding-top: 10px; border-top: 1px solid var(--line-soft); }
.sb-empty { font-size: 12px; color: var(--faint); padding: 8px 10px; line-height: 1.5; }

/* monogram chip — scannable per-app identity. With ICON-001 the chip holds
   the real Expedition module icon; the 2-letter monogram remains the
   fallback for routes with no mapped icon. */
.sb-mono {
  width: 26px; height: 26px; border-radius: 7px; flex: none;
  display: grid; place-items: center; font-size: 12px; font-weight: 800; letter-spacing: 0.2px;
  background: var(--inset); color: var(--muted); border: 1px solid var(--line-soft);
}
.pr-appic { display: block; width: 16px; height: 16px; color: currentColor; flex: none; }
.sb-mono .pr-appic { width: 15px; height: 15px; }
.ts-pop-app .pr-appic { width: 15px; height: 15px; color: var(--muted); }
.ts-pop-app.is-current .pr-appic, body.is-dark .ts-pop-app.is-current .pr-appic { color: var(--blue); }
body.is-dark .ts-pop-app .pr-appic { color: var(--faint); }

.sb-treeapp { display: flex; flex-direction: column; }
.sb-treerow { display: flex; align-items: center; border-radius: 9px; transition: background 0.12s ease; }
.sb-treerow:hover { background: var(--inset); }
.sb-treerow.is-active { background: transparent; }
.sb-treerow-main {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px;
  border: none; background: transparent; cursor: pointer; text-decoration: none;
  padding: 6px 4px 6px 6px; font: inherit; text-align: left;
}
.sb-treerow-main:hover { text-decoration: none; }
.sb-treename { font-size: 13.5px; font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sb-treerow.is-active .sb-treename { color: var(--navy); }
body.is-dark .sb-treerow.is-active .sb-treename { color: var(--blue); }
.sb-treerow.is-active .sb-mono { background: var(--navy); color: #fff; border-color: var(--navy); }
body.is-dark .sb-treerow.is-active .sb-mono { color: #06131d; background: var(--blue); border-color: var(--blue); }
.sb-treetoggle {
  width: 30px; height: 32px; flex: none; border: none; background: transparent;
  display: grid; place-items: center; cursor: pointer; padding: 0;
}
.sb-treetoggle.is-leaf { cursor: default; }
.sb-treetoggle .ts-chev { transform: rotate(-45deg); transition: transform 0.15s ease; }
.sb-treetoggle.is-open .ts-chev { transform: rotate(45deg) translateY(-1px); }
.sb-treekids {
  display: flex; flex-direction: column; gap: 1px;
  margin: 1px 0 4px 17px; padding-left: 9px; border-left: 1.5px solid var(--line-soft);
}
.sb-treekids.is-collapsed { display: none; }
.sb-treekids .ts-navitem { padding: 6px 9px; font-size: 13px; }
.sb-treekids .ts-navitem span { white-space: nowrap; }

/* ============================================================
   Dual-rail sidebar (Sidebar Menu Options — "Dual rail")
   Persistent app icon-rail (every app one click away) + a panel
   showing the current product's own modules.
   ============================================================ */
.ts-side.sb-rail { width: 264px; padding: 0; flex-direction: row; align-items: stretch; }
.sb-railcol {
  width: 58px; flex: none; background: var(--inset);
  border-right: 1px solid var(--line-soft);
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 10px 0; overflow-y: auto;
}
/* 46x44 inside the 58px rail, not the old 70x60. The 60px box wrapped a 34px icon
   in 26px of dead space, which with the gap gave a 64px pitch — the icons read as
   unrelated rather than as one list. 70px was also wider than the 58px column, so
   every item overflowed and the active indicator at left:-9px landed outside the
   column, where .sb-railcol's overflow clips it (see the .sb-tip note below: one
   non-visible axis clips both). 44px keeps a comfortable target. */
.sb-railapp {
  position: relative; width: 46px; height: 44px; flex: none;
  border: none; background: transparent; border-radius: 10px;
  display: grid; place-items: center; cursor: pointer; padding: 0;
  transition: background 0.12s ease; text-decoration: none;
}
.sb-railapp .sb-mono { width: 34px; height: 34px; border-radius: 9px; background: var(--card); transition: all 0.12s ease; }
.sb-railapp:hover .sb-mono { border-color: var(--blue-line); color: var(--head); }
.sb-railapp.is-active { background: transparent; }
.sb-railapp.is-active .sb-mono { background: var(--navy); color: #fff; border-color: var(--navy); }
.sb-railapp.is-active::before {
  /* -6px puts the bar flush with the rail's left edge: the 46px item is centred in
     the 58px column, so its own left edge sits 6px in. */
  content: ''; position: absolute; left: -6px; top: 7px; bottom: 7px;
  width: 3px; border-radius: 0 3px 3px 0; background: var(--navy);
}
/* hover tooltip with the app's full name (the rail icon alone is ambiguous).
   position:fixed + JS-computed top/left (townsuite-shell.js) rather than
   position:absolute anchored to .sb-railapp — .sb-railcol scrolls
   (overflow-y:auto), and per the CSS overflow spec a container with only
   one axis set to a non-visible value computes BOTH axes as clipped, so an
   absolutely-positioned tip poking out to the right was silently cut off. */
.sb-tip {
  position: fixed; left: 0; top: 0;
  background: var(--head); color: var(--card); white-space: nowrap;
  font-size: 12px; font-weight: 600; padding: 5px 9px; border-radius: 7px;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity 0.12s ease, visibility 0.12s ease; z-index: 300;
  box-shadow: 0 6px 18px rgba(10, 25, 40, 0.22);
}
/* visibility (not just opacity) matters here: contrast-checking tools evaluate
   rendered colour regardless of aria-hidden, and an opacity:0 element still
   reads as "visible with near-zero contrast" to them — visibility:hidden is
   universally recognized as not-rendered and excluded from that check */
.sb-tip.is-shown { opacity: 1; visibility: visible; }
.sb-panelcol { flex: 1; min-width: 0; display: flex; flex-direction: column; padding: 16px 12px; }
.sb-panelcol .ts-prod { padding-top: 0; }

body.is-dark .sb-railcol { background: rgba(255, 255, 255, 0.02); }
body.is-dark .sb-railapp .sb-mono { background: var(--inset); }
/* active chip: the generic dark override above washes out the active state —
   restore the lifted fill so the icon pops (dark ink on light-blue chip).
   Must be var(--blue) (the light dark-mode tint), not var(--navy) — navy is
   only #00578E in dark mode, which gives the #06131d ink just 2.46:1 (fails AA) */
body.is-dark .sb-railapp.is-active .sb-mono {
  background: var(--blue); border-color: var(--blue); color: #06131d;
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--blue) 22%, transparent);
}
body.is-dark .sb-tip { background: #04111d; color: #E9F0F6; }

/* mobile drawer — the rail keeps its two-column layout inside the drawer */
.ts-side.sb-rail.is-drawer, body.ts-drawer-open .ts-side.sb-rail { flex-direction: row; padding: 0; }

/* ---------- product sidebar (reads from menunav) ---------- */
.ts-side { width: 224px; flex: none; background: var(--side); border-right: 1px solid var(--line); display: flex; flex-direction: column; padding: 16px 12px; }
.ts-prod { display: flex; align-items: center; gap: 11px; padding: 4px 8px 14px; border-bottom: 1px solid var(--line-soft); margin-bottom: 12px; }
.ts-prod-icon { width: 34px; height: 34px; border-radius: 9px; background: var(--blue-soft); display: grid; place-items: center; flex: none; }
.ts-prod-icon .ts-dia { width: 10px; height: 10px; border-radius: 2.5px; color: var(--blue); }
.ts-prod-name { font-size: 14.5px; font-weight: 700; color: var(--head); line-height: 1.2; }
.ts-prod-sub { font-size: 12px; letter-spacing: 1.2px; text-transform: uppercase; color: var(--faint); margin-top: 1px; }
.ts-nav { display: flex; flex-direction: column; gap: 1px; }
.ts-navitem { display: flex; align-items: center; gap: 11px; padding: 5px 10px; border-radius: 8px; color: var(--text); font-size: 13.5px; font-weight: 500; cursor: pointer; text-decoration: none; }
.ts-navitem:hover:not(.is-active) { background: var(--inset); }
/* Every menu row carries this one marker — the module glyphs (.pr-appic) stay on
   the products in the icon rail / app switcher / dashboard directory. Rows used to
   resolve a glyph from their own url, which lit up only the rows pointing at another
   module's route and left the rest on the diamond. */
.ts-navitem .ts-dia { width: 6px; height: 6px; color: var(--faint); } /* was #B9C8D4 light / #364755 dark — both ~1.7:1, fail 3:1; var(--faint) adapts per theme and clears it */
/* Selected page. Colour + weight alone (what this rule used to be) put --navy
   #003C63 beside --text #44586A at 13.5px — too small a difference to find the
   current row in a menu of twenty. Use the redesign's standard selected-row
   treatment instead (same as .rq-ib-row.is-active and the facility list's
   k-selected): a --blue-soft surface with a 3px left marker. Keeps every colour
   inside the row at the contrast it was designed for — active text 9.82:1 light
   (navy on #e7eef4), 5.83:1 dark; marker 7.63:1 / 6.84:1 against --side. The
   tint alone is only 1.17:1 against the sidebar, which is what makes it read as
   a slight highlight rather than a selection block — the marker is the cue that
   survives that, so keep both. */
.ts-navitem.is-active { color: var(--navy); font-weight: 600; background: var(--blue-soft); box-shadow: inset 3px 0 0 var(--blue); }
body.is-dark .ts-navitem.is-active { color: var(--blue); }
.ts-navitem.is-active .ts-dia { color: var(--blue); }
/* Current *product* (the Administration block's rows are products, not pages) —
   deliberately weaker than is-active above: colour and weight only, no tint and
   no marker. Two levels of "you are here" share this one list, so the tint +
   marker has to mean exactly one thing, and it means the current page. This row
   doesn't need to be findable on its own — .ts-prod already names the current
   product directly above, and the icon rail marks it a third time — it only
   needs to not compete. It also stays hoverable (it isn't excluded from the
   :hover rule the way is-active is), because unlike the current page it is
   still somewhere you can go. */
.ts-navitem.is-current { color: var(--navy); font-weight: 600; }
body.is-dark .ts-navitem.is-current { color: var(--blue); }
/* Vertical rhythm tightened after the menu builder began recursing to full depth:
   a menu that used to render as one group of flat links now renders as nested groups,
   so every extra level adds a header row and a margin. The gaps were never the problem
   (1-7px) — the row heights were, once there were half as many headers as items. */
.ts-navgroup { margin-top: 4px; }
.ts-navgrouphead { display: flex; align-items: center; justify-content: space-between; padding: 5px 10px 2px; font-size: 12px; letter-spacing: 1.2px; text-transform: uppercase; color: var(--faint); font-weight: 600; cursor: pointer; }
.ts-navgrouphead .ts-chev { transform: rotate(45deg); transition: transform .15s ease; }
.ts-navgrouphead.is-collapsed .ts-chev { transform: rotate(-45deg); }
.ts-navgroup.is-collapsed > *:not(.ts-navgrouphead) { display: none; }
.ts-navgroup .ts-navgroup { margin-top: 1px; margin-left: 12px; border-left: 1px solid var(--line-soft); }
.ts-navgroup .ts-navgroup > .ts-navgrouphead { text-transform: none; letter-spacing: normal; font-size: 13px; font-weight: 600; color: var(--text); padding-left: 10px; }
.ts-side-foot { margin-top: auto; border-top: 1px solid var(--line-soft); padding-top: 10px; }
.ts-side-foot .ts-navitem { color: var(--muted); font-size: 12.5px; }

/* burger + drawer */
.ts-burger { display: none; }
.ts-sidebar-toggle { display: grid; }
.ts-burger-bars { width: 14px; height: 2px; background: var(--muted); border-radius: 1px; position: relative; }
.ts-burger-bars::before, .ts-burger-bars::after { content: ''; position: absolute; left: 0; width: 14px; height: 2px; background: var(--muted); border-radius: 1px; }
.ts-burger-bars::before { top: -5px; } .ts-burger-bars::after { top: 5px; }
.ts-navoverlay { position: fixed; inset: 0; background: rgba(10,20,30,0.45); z-index: 90; display: none; cursor: pointer; }
body.ts-drawer-open .ts-navoverlay { display: block; animation: tsfade .15s ease; }
body.ts-drawer-open .ts-side { display: flex; position: fixed; top: 0; left: 0; bottom: 0; width: 264px; z-index: 170; box-shadow: 24px 0 60px rgba(0,0,0,0.25); overflow-y: auto; animation: tsdrawer .18s ease; }
body.ts-pop-open .ts-navoverlay { display: block; animation: tsfade .15s ease; }
@keyframes tsfade { from { opacity: 0; } }
@keyframes tsdrawer { from { transform: translateX(-30px); opacity: 0; } }
@keyframes tssheet { from { transform: translateY(24px); opacity: 0; } }

/* toast */
.ts-toast { position: fixed; bottom: 26px; left: 50%; transform: translateX(-50%); background: var(--head); color: var(--bg); padding: 11px 20px; border-radius: 10px; font-size: 13.5px; font-weight: 500; z-index: 200; box-shadow: 0 12px 34px rgba(0,0,0,0.28); animation: tstoast .18s ease; pointer-events: none; white-space: nowrap; }
@keyframes tstoast { from { opacity: 0; transform: translateX(-50%) translateY(8px); } }

/* ---------- form primitives ---------- */
.ts-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.ts-label { font-size: 12.5px; font-weight: 600; color: var(--head); display: flex; gap: 3px; margin: 0; }
.ts-req { color: var(--red); }
.ts-app .ts-input, .ts-app input.ts-input, .ts-app select.ts-input, .ts-app textarea.ts-input,
.ts-app .ts-formwrap .form-control, .ts-app .ts-formwrap .input-full-width,
.ts-app .ts-formwrap .k-input, .ts-app .ts-formwrap .k-picker {
  min-height: 40px; border: 1px solid var(--line); border-radius: 9px !important;
  background: var(--card); padding: 0 12px; font: inherit; font-size: 14px;
  color: var(--text); width: 100%; box-sizing: border-box;
}
/* This is the input focus ring, but Kendo puts .k-focus on whatever widget part
   currently holds focus — including the current CELL of a navigatable grid
   (grids default to navigatable, so every grid in the site). border-color then
   recoloured that td, and because a grid td only carries a 1px bottom border
   (and none on the inline-start edge when it is :first-child) it read as a
   stray blue line under the first column of the row you clicked or just
   inserted. Excluding the Kendo table cell classes keeps the ring on inputs,
   buttons, list items etc. exactly as-is while leaving grid/treelist cells to
   the vendor themes, which deliberately render no cell focus indicator. */
.ts-app .ts-formwrap .form-control:focus, .ts-app .ts-input:focus,
.ts-app .ts-formwrap .k-focus:not(.k-table-td):not(.k-table-th) { outline: none; border-color: var(--blue); box-shadow: 0 0 0 3px rgba(31,111,165,0.14); }
.ts-app textarea.ts-input { height: auto; min-height: 120px; padding: 10px 12px; resize: vertical; line-height: 1.5; }
.ts-check { display: flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--text); font-weight: 500; cursor: pointer; }
.ts-check input { width: 17px; height: 17px; accent-color: var(--navy); cursor: pointer; margin: 0; }
body.is-dark .ts-check input { accent-color: var(--blue); }

.ts-btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; height: 40px; padding: 0 18px; border-radius: 11px; font-size: 13.5px; font-weight: 700; border: 1px solid transparent; cursor: pointer; font-family: inherit; transition: filter .12s ease, background .12s ease, transform .06s ease; text-decoration: none; }
.ts-btn:active { transform: translateY(1px); }
.ts-btn.is-primary { background: var(--navy); color: #fff; box-shadow: 0 6px 16px rgba(0,87,142,0.16); }
.ts-btn.is-primary:hover { filter: brightness(1.12); }
body.is-dark .ts-btn.is-primary { color: #F2F7FB; box-shadow: none; }
.ts-btn.is-secondary { background: var(--card); color: var(--head); border-color: var(--line); }
.ts-btn.is-secondary:hover, .ts-btn.is-add:hover { background: var(--inset); }
.ts-btn.is-add { background: var(--card); color: var(--navy); border-color: var(--blue); } /* #C7D8E5 only cleared ~1.4:1 against the card — var(--blue) clears 3:1 for a UI-component border */
body.is-dark .ts-btn.is-add { color: var(--blue); border-color: var(--blue-line); }
.ts-btn.is-danger { background: var(--red); color: #fff; border-color: var(--red); }
.ts-btn.is-danger:hover { filter: brightness(1.08); }
.ts-btn.is-block { width: 100%; }
.ts-btn:disabled, .ts-btn[disabled], .ts-btn.is-disabled { opacity: .5; cursor: not-allowed; pointer-events: none; filter: none; box-shadow: none; transform: none; }
.ts-plus { font-size: 16px; font-weight: 600; line-height: 1; margin-top: -1px; }
.ts-arrow { font-size: 15px; line-height: 1; }
.ts-link { color: var(--blue); font-weight: 600; cursor: pointer; }
.ts-link:hover { text-decoration: underline; }
.m-0 { margin: 0; } 

.ts-leavechip { font-size: 12px; font-weight: 700; letter-spacing: .4px; color: var(--blue); background: var(--blue-soft); border: 1px solid var(--blue-line); padding: 3px 9px; border-radius: 6px; display: inline-block; }
.ts-tag { font-size: 12px; font-weight: 600; color: #1A6B2C; background: #EAF5EE; border: 1px solid #D3E8DB; padding: 3px 9px; border-radius: 999px; }
body.is-dark .ts-tag { color: #8FD4AC; background: rgba(63,168,110,0.14); border-color: rgba(63,168,110,0.35); }

/* ---------- Time Off Request — Option B (guided steps) ---------- */
.ob-main { flex: 1; padding: 28px 40px 36px; min-width: 0; max-width: 1150px; }
/* page header — branded banner card by default (the "Municipal info" hero,
   site-wide). Any page that renders an .ob-pagehead gets it; pages without
   a header gain nothing. is-hero adds the icon + subtitle extras. */
.ob-pagehead {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 18px 24px; margin-bottom: 26px; border-radius: 14px;
  background: linear-gradient(180deg, var(--inset), var(--card));
  border: 1px solid var(--line); box-shadow: 0 1px 2px rgba(12,44,73,0.04);
  position: relative; overflow: hidden;
}
.ob-pagehead::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
  background: linear-gradient(180deg, var(--navy), var(--blue));
}
.ob-h1 { font-size: 24px; font-weight: 700; letter-spacing: -0.4px; color: var(--head); margin: 0; line-height: 1.15; }
.ob-pagehead-actions { margin-left: auto; display: flex; gap: 10px; flex-wrap: wrap; }

/* ---- hero pagehead variant (adds icon tile + subtitle) ---- */
.ob-hero-icon {
  width: 46px; height: 46px; border-radius: 12px; flex: none;
  display: grid; place-items: center;
  background: var(--blue-soft); border: 1px solid var(--blue-line);
}
.ob-hero-icon .ts-dia { width: 13px; height: 13px; border-radius: 3px; color: var(--blue); }
.ob-hero-icon em { font-size: 19px; color: var(--blue); }
.ob-hero-text { display: flex; flex-direction: column; gap: 3px; flex: 1 1 220px; min-width: 0; overflow-wrap: break-word; }
.ob-pagehead.is-hero .ob-h1 { font-size: 24px; line-height: 1.1; }
.ob-hero-sub { font-size: 13px; color: var(--muted); }

@media (max-width: 640px) {
  /* hero page headers take a lot of vertical space on phones (icon tile +
     title + subtitle, all at desktop size) — shrink the whole banner. */
  .ob-pagehead { padding: 12px 14px; gap: 10px; margin-bottom: 16px; }
  .ob-h1, .ob-pagehead.is-hero .ob-h1 { font-size: 18px; }
  .ob-hero-text { flex-basis: 0; }
  .ob-pagehead-actions { flex-basis: 100%; }
  .ob-hero-icon { width: 36px; height: 36px; border-radius: 10px; }
  .ob-hero-icon em { font-size: 15px; }
  .ob-hero-icon .ts-dia { width: 11px; height: 11px; }
  .ob-hero-sub { font-size: 12px; }
}

/* form + summary rail layout (Time Off Request) */
.ob-main.has-aside { max-width: none; }
/* records review table: scroll horizontally rather than crushing columns */
.desktopViewPTO .table-responsive { overflow-x: auto; border: 0; }
.desktopViewPTO .ob-table { min-width: 720px; }
.ob-layout { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 28px; align-items: start; }
.ob-layout > form { min-width: 0; }
.ob-aside { position: sticky; top: 78px; min-width: 0; }
.ob-summary .pg-card-title { margin-bottom: 6px; }
.ob-sumrow { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--line-soft); font-size: 13.5px; }
.ob-sumlabel { color: var(--muted); flex: none; }
.ob-sumval { display: flex; align-items: center; gap: 8px; color: var(--head); font-weight: 600; text-align: right; min-width: 0; overflow-wrap: anywhere; }
.ob-sumavatar { width: 28px; height: 28px; border-radius: 50%; background: var(--blue); color: #fff; display: grid; place-items: center; font-size: 10.5px; font-weight: 700; flex: none; }
.ob-sumavatar:empty { display: none; }
.ob-sumpill { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; background: var(--navy); color: #fff; border-radius: 14px; padding: 18px 18px; margin: 16px 0; }
body.is-dark .ob-sumpill { color: #F2F7FB; }
.ob-sumpill-num { font-size: 30px; font-weight: 700; letter-spacing: -0.5px; line-height: 1; font-variant-numeric: tabular-nums; }
.ob-sumpill-label { font-size: 13px; font-weight: 600; opacity: 0.92; }
.ob-sumpill-range { margin-left: auto; font-size: 12.5px; font-weight: 600; opacity: 0.85; white-space: nowrap; }
.ob-sumnote { margin-top: 12px; text-align: center; font-size: 12px; color: var(--faint); }
@media (max-width: 1280px) {
  .ob-layout { grid-template-columns: 1fr; }
  .ob-aside { position: static; }
}

.ob-steps { display: flex; flex-direction: column; counter-reset: obstep; }
.ob-step { display: flex; gap: 22px; counter-increment: obstep; }
.ob-step-rail { width: 34px; flex: none; display: flex; flex-direction: column; align-items: center; }
.ob-step-num { width: 34px; height: 34px; border-radius: 50%; flex: none; background: var(--blue-soft); border: 1px solid var(--blue-line); color: var(--navy); display: grid; place-items: center; font-size: 14px; font-weight: 700; }
body.is-dark .ob-step-num { color: var(--blue); }
.ob-step-line { width: 1.5px; flex: 1; background: var(--line); margin: 6px 0; }
.ob-step-body { flex: 1; min-width: 0; padding-bottom: 26px; }
.ob-step:last-child .ob-step-body { padding-bottom: 0; }
.ob-step-title { font-size: 16.5px; font-weight: 700; color: var(--head); letter-spacing: -0.2px; padding-top: 5px; margin-bottom: 3px; }
.ob-step-hint { font-size: 12.5px; color: var(--muted); margin-bottom: 14px; }

.ob-card { background: var(--card); border: 1px solid var(--line); border-radius: 13px; padding: 22px 24px; box-shadow: 0 1px 2px rgba(12,44,73,0.04); }
.ob-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px 18px; }
.ob-grid .is-span2 { grid-column: span 2; }

.ob-composer { background: var(--card); border: 1px solid var(--line); border-radius: 13px; padding: 22px 24px; box-shadow: 0 1px 2px rgba(12,44,73,0.04); }
.ob-composer .ts-formwrap .form-control, .ob-composer .ts-input { background: var(--card); }
.ob-composer-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 14px; }
.ob-composer-grid.has-subcode { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
/* Date/time cells hold a full timestamp plus calendar and clock buttons, which
   don't fit in a single narrow grid track — the value was being clipped to
   "2026-08-...". Give them two tracks so the whole start/end date and time
   stays visible. Reset to one track on phones (single-column grid) below. */
.ob-composer-grid .ts-field.is-datetime { grid-column: span 2; }
.ob-composer-foot { display: flex; align-items: center; gap: 18px; margin-top: 15px; flex-wrap: wrap; }
.ob-duration { font-size: 12.5px; color: var(--muted); }
.ob-duration b { color: var(--head); }
.ob-composer-foot .ts-btn.is-add { margin-left: auto; }

/* records table */
.ob-table { width: 100%; border-collapse: collapse; }
.ob-table th { font-size: 12px; letter-spacing: 1px; text-transform: uppercase; font-weight: 600; color: var(--faint); text-align: left; padding: 4px 12px 10px; border-bottom: 1px solid var(--line); background: transparent; }
.ob-table td { padding: 13px 12px; font-size: 13.5px; color: var(--text); border-bottom: 1px solid var(--line-soft); vertical-align: middle; }
.ob-table tr:last-child td { border-bottom: none; }
.ob-table .is-right { text-align: right; }
.ob-units { font-weight: 700; color: var(--head); font-variant-numeric: tabular-nums; }
.ob-rowactions { display: flex; gap: 2px; justify-content: flex-end; }
.ob-rowaction { font-size: 12.5px; font-weight: 600; color: var(--blue); padding: 4px 7px; border-radius: 6px; cursor: pointer; border: none; background: none; font-family: inherit; }
.ob-rowaction:hover { background: var(--blue-soft); }
.ob-rowaction.is-danger { color: var(--red); }
.ob-rowaction.is-danger:hover { background: #F9ECEA; }
body.is-dark .ob-rowaction.is-danger:hover { background: rgba(210,101,92,0.15); }
.ob-table-foot { display: flex; align-items: center; gap: 6px; margin-top: 13px; padding-top: 13px; border-top: 1px solid var(--line-soft); font-size: 12.5px; color: var(--muted); }
.ob-table-foot b { color: var(--head); }
.ob-table-foot .ts-link { margin-left: auto; }

/* mobile record cards */
.ob-mobilerec { border: 1px solid var(--line); border-left: 4px solid var(--blue); border-radius: 10px; background: var(--card); padding: 12px 14px; margin-bottom: 10px; }
.ob-mobilerec-row { display: flex; justify-content: space-between; gap: 12px; padding: 4px 0; border-bottom: 1px dashed var(--line-soft); font-size: 13px; }
.ob-mobilerec-row:last-of-type { border-bottom: none; }
.ob-mobilerec-row b { color: var(--muted); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: .05em; }
.ob-mobilerec-actions { display: flex; justify-content: flex-end; gap: 6px; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line-soft); }

/* footer actions */
.ob-actions { display: flex; align-items: center; gap: 10px; margin-top: 26px; padding-top: 20px; border-top: 1px solid var(--line); flex-wrap: wrap; }
.ob-actions-note { font-size: 12.5px; color: var(--faint); margin-left: auto; }

/* step-3 empty state (no records added yet) */
.ob-emptystate { display: flex; align-items: center; justify-content: center; gap: 10px; padding: 26px 16px; font-size: 13.5px; color: var(--muted); text-align: center; }
.ob-emptystate .ts-dia { color: var(--faint); }

/* ---- reusable empty state (project-wide "no records" placeholder) ----
   Drop a `<div class="pg-empty">…</div>` anywhere; for JS-populated card lists
   place it right after the list container and it auto-shows when that list has
   no cards (no JS needed). Server/Knockout lists can use `data-bind="visible"`. */
.pg-empty {
  display: none; align-items: center; justify-content: center; gap: 10px;
  padding: 44px 16px; font-size: 14px; color: var(--muted); text-align: center;
  background: var(--card); border: 1px dashed var(--line); border-radius: 13px;
}
.pg-empty .ts-dia { color: var(--faint); }
/* show only once the list has finished loading (.pg-loaded) AND has no cards —
   so search-driven lists don't show "no records" before the user searches */
.reservation-list.pg-loaded:not(:has(.reservation-card)) + .pg-empty { display: flex; }

/* yes/no marks (carried over from current build) */
.ts-yes { color: #1A6B2C; font-weight: 700; }
body.is-dark .ts-yes { color: var(--green); }
.ts-no-x { color: var(--red); font-weight: 700; }
.ts-no { color: var(--muted); }

/* inputs nested inside Kendo widget wrappers must stay flat — the wrapper
   (.k-input/.k-picker) carries the border/background; without this the
   reskinned inner input paints its own white box outside the control */
.ts-app .ts-main .k-input input, .ts-app .ts-main .k-picker input,
.ts-app .ts-formwrap .k-input input, .ts-app .ts-formwrap .k-picker input,
.ts-app .ts-main .k-input .k-input-inner, .ts-app .ts-formwrap .k-input .k-input-inner {
    border: 0 !important;
    background: transparent !important;
    min-height: 0 !important;
    box-shadow: none !important;
    border-radius: 0 !important;
    width: 100%;
}

/* widgets inside Kendo toolbars (editor colour pickers, font dropdowns…)
   keep their natural size — the form-input treatment must not stretch them */
.ts-app .ts-main .k-toolbar .k-picker, .ts-app .ts-formwrap .k-toolbar .k-picker,
.ts-app .ts-main .k-toolbar .k-input, .ts-app .ts-formwrap .k-toolbar .k-input,
.ts-app .ts-main .k-toolbar .k-colorpicker, .ts-app .ts-formwrap .k-toolbar .k-colorpicker {
    width: auto;
    min-height: 0;
}

/* Kendo widget harmonisation inside redesigned forms */
.ts-app .ts-formwrap .k-editor { border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
.ts-app .ts-formwrap .table > thead > tr > th { border-bottom: 1px solid var(--line); }

/* ---------- responsive ---------- */
@media (max-width: 1099px) {
  .ts-burger { display: grid; }
  .ts-sidebar-toggle { display: none; }
  .ts-shell-row > .ts-side { display: none; }
  .ob-main { padding: 22px 24px 30px; }
  .ob-composer-grid, .ob-composer-grid.has-subcode { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 640px) {
  /* kill page-level horizontal panning — anything oversized must scroll
     inside its own container, otherwise the sticky top bar and headings
     pan off-screen to the left */
  body.ts-app { overflow-x: hidden; }
  .ts-app .ts-main { max-width: 100vw; overflow-x: hidden; }
  .ts-app .ts-main .k-editor, .ts-app .ts-main .k-editor iframe { max-width: 100%; }
  .ob-main { padding: 16px 14px 24px; }
  .ob-h1 { font-size: 22px; }
  .ts-top { padding: 0 10px; gap: 6px; }
  .ts-top-sep, .ts-logo-dias { display: none; }
  .ts-top-logo { gap: 4px; }
  .ts-logo-img { height: 28px; max-width: 90px; }
  .ts-logo-word { font-size: 15px; }
  .ts-switch { padding: 0 8px; gap: 6px; max-width: 25vw; min-width: 0; }
  .ts-switch > span:nth-child(2) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .ts-pop {
    position: fixed;
    top: auto; left: 0; right: 0; bottom: 0;
    width: auto; max-width: none;
    max-height: 75vh;
    overflow-y: auto;
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -18px 50px rgba(12,44,73,0.22);
    padding: 10px 16px calc(16px + env(safe-area-inset-bottom, 0px));
    z-index: 180;
  }
  .ts-pop.is-open { animation: tssheet .18s ease; }
  .ts-pop::before {
    content: ''; display: block; width: 36px; height: 4px; margin: 0 auto 14px;
    background: var(--line); border-radius: 999px;
  }
  .ts-top-right { gap: 8px; overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; -ms-overflow-style: none; }
  .ts-top-right::-webkit-scrollbar { display: none; }
  .ts-top-right > * { flex-shrink: 0; }
  /* .ts-top-right was never tuned for phone width: five-plus fixed-size
     icon buttons (theme/finance/notifications/cart/impersonate/avatar) plus
     the culture <select>, at the base 12px gap, routinely add up to more
     than a 375-430px viewport once the burger/logo/switch on the left are
     also accounted for — the rightmost icons were pushed clean off-screen
     with no way to reach them. Tighten gaps/sizes so the whole cluster
     actually fits; icons get flex:none so they shrink the switch's label
     (which already truncates) instead of squishing below a legible/
     tappable size. */
  .ts-top-right { gap: 3px; }
  .ts-iconbtn, .ts-avatar { width: 28px; height: 28px; flex: none; }
  .ts-notifwrap, .ts-avatarwrap, .ts-culturewrap { flex: none; }
  /* .ts-top-right became a horizontal scroller just above, and per the overflow
     spec `overflow-x:auto` computes `overflow-y` from visible to auto as well —
     so it clips its overflowing descendants on BOTH axes, at the ~28px height of
     the icon row. .ts-pop, .ts-more and .ts-culturepop already escape that with
     position:fixed overrides; .ts-notif and .ts-usermenu were left as
     position:absolute children of .ts-notifwrap/.ts-avatarwrap and so opened
     inside that clipping box — the toggle fired, the panel just never appeared.
     Anchor them to the viewport under the top bar like the other three. */
  .ts-notif, .ts-usermenu {
    position: fixed; top: 62px; right: 12px; left: auto;
    width: min(300px, calc(100vw - 24px));
    max-height: calc(100vh - 78px); overflow-y: auto;
  }
  /* .ts-pop (the app-switcher "Components" menu) is `position:absolute; left:0`
     relative to .ts-switchwrap, with width `min(384px, calc(100vw - 32px))` —
     that width formula assumes the popup starts near the viewport's left edge,
     but .ts-switchwrap actually sits well right of it (after the burger icon
     + logo), so the popup routinely ran off the right edge of the screen.
     Switch to position:fixed with explicit left/right insets so it's anchored
     to the viewport itself and always fits, regardless of where the switch is. */
  .ts-pop {
    position: fixed; top: 64px; left: 12px; right: 12px; width: auto; max-width: none;
    max-height: calc(100vh - 80px); overflow-y: auto;
  }
  .ob-grid, .ob-composer-grid, .ob-composer-grid.has-subcode { grid-template-columns: 1fr; }
  .ob-grid .is-span2 { grid-column: auto; }
  /* single-column grid on phones — date/time cells take the full row like
     everything else, so drop the two-track span to avoid overflow */
  .ob-composer-grid .ts-field.is-datetime { grid-column: auto; }
  /* drop the vertical number rail on phones — it pushed every card to the
     right; steps run full-width with the number folded into the title */
  .ob-step { display: block; }
  .ob-step-rail { display: none; }
  .ob-step-body > .ob-step-title::before { content: counter(obstep) ". "; color: var(--blue); }
  .ob-card { padding: 18px 16px; }
  .ob-card:has(.ob-table) { overflow-x: auto; }
  .ob-table { min-width: 540px; }
  .ob-composer-foot .ts-btn.is-add { margin-left: 0; }
  .ob-actions .ts-btn { width: 100%; }
}

/* ---------- Bootstrap modals reskinned (edit/duplicate entry) ---------- */
.ts-app .ts-modal .modal-content { background: var(--card); border: 1px solid var(--line); border-radius: 14px; box-shadow: 0 24px 70px rgba(0,0,0,0.3); overflow: hidden; color: var(--text); }
.ts-app .ts-modal .modal-header { background: var(--inset); border-bottom: 2px solid var(--blue); padding: 14px 20px; }
.ts-app .ts-modal .modal-title, .ts-app .ts-modal .h4-custom { color: var(--head); font-weight: 700; letter-spacing: -0.2px; }
.ts-app .ts-modal .close { opacity: .5; color: var(--head); text-shadow: none; }
.ts-app .ts-modal .close:hover { opacity: .9; }
.ts-app .ts-modal .modal-body { padding: 18px 20px 10px; }
.ts-app .ts-modal .modal-body label, .ts-app .ts-modal .modal-body b { font-weight: 600; color: var(--head); margin-bottom: 2px; display: inline-block; }
.ts-app .ts-modal .modal-body .row > [class*="col-"] { margin-bottom: 8px; }
.ts-app .ts-modal .modal-footer { border-top: 1px solid var(--line); padding: 12px 20px; }

/* table action icon cells (copy/edit/delete — ids & classes used by site JS) */
.ts-app td.copyControllers, .ts-app td.editControllers, .ts-app td.deleteControllers,
.ts-app .ob-mobilerec-actions .copyControllers, .ts-app .ob-mobilerec-actions .editControllers, .ts-app .ob-mobilerec-actions .deleteControllers {
  cursor: pointer; color: var(--muted); transition: color .15s ease, background .15s ease; text-align: center; vertical-align: middle;
}
.ts-app td.copyControllers, .ts-app td.editControllers, .ts-app td.deleteControllers { width: 40px; font-size: 14px; }
.ts-app .ob-mobilerec-actions > div { width: 40px; height: 40px; line-height: 40px; border-radius: 50%; border: 1px solid var(--line); font-size: 15px; }
.ts-app .copyControllers:hover, .ts-app .editControllers:hover { color: var(--blue); background: var(--blue-soft); }
.ts-app .deleteControllers:hover { color: #B71C1C; background: rgba(194,71,61,0.12); }
body.ts-app.is-dark .deleteControllers:hover { color: var(--red); }

/* hours-remaining pill (Knockout-bound) — hidden until it has text */
.ts-app .label-format.size_sm { display: inline-block; margin-top: 4px; padding: 2px 10px; border-radius: 999px; background: var(--blue-soft); color: var(--blue); font-size: 12px; font-weight: 600; }
.ts-app .label-format.size_sm:empty { display: none; }

/* manager-link warning banner */
.ts-app .ts-warnbanner { background: rgba(221,148,52,0.12); border: 1px solid rgba(221,148,52,0.4); border-radius: 12px; padding: 14px 18px; color: #875200; margin-bottom: 20px; }
body.is-dark.ts-app .ts-warnbanner { color: var(--amber); }

/* ---- Top-bar language selector (#ddlCulture / #ddlCultureMobile) ---- */
.ts-app .ts-culture {
    height: 32px;
    padding: 0 8px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--card);
    color: var(--text);
    font: inherit;
    font-size: 13px;
    max-width: 160px;
}
.ts-app .ts-culture:focus {
    outline: none;
    border-color: var(--blue);
    box-shadow: 0 0 0 3px rgba(31,111,165,0.14);
}
@media (max-width: 767px) {
    .ts-app select.ts-culture.hidden-xs { display: none; }
}
@media (max-width: 640px) {
    .ts-app select.ts-culture.visible-xs { display: none !important; }
}
.ts-more-culture { max-width: none; width: auto; min-width: 84px; margin-left: auto; height: 28px; }

/* ---- Top-bar language picker, mobile (.ts-culturewrap / .ts-culturepop) ----
   Same icon-button + popover pattern as .ts-notifwrap/.ts-notif above, and
   the same idea as the landing page mast-head's icon-triggered language
   dropdown — a plain always-visible <select> here (like #ddlCultureMobile
   used to be) has an unpredictable native width across browsers, which was
   one of the things pushing .ts-top-right past the viewport on phones.
   position:fixed (not absolute off .ts-culturewrap) for the same reason as
   .ts-pop's mobile override: the trigger isn't guaranteed to sit right at
   the viewport's edge, so anchor to the viewport itself. */
.ts-culturewrap { position: relative; }
.ts-culturepop {
  position: absolute; right: 0; top: 44px; width: 220px;
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: 0 18px 50px rgba(12,44,73,0.18); padding: 12px; z-index: 140; display: none;
}
.ts-culturepop.is-open { display: block; }
.ts-culturepop-head { padding: 0 2px 8px; font-size: 13.5px; font-weight: 700; color: var(--head); }
.ts-culturepop .ts-culture { width: 100%; max-width: none; height: 36px; font-size: 14px; }
@media (max-width: 640px) {
  .ts-culturepop { position: fixed; top: 62px; right: 12px; left: auto; width: min(220px, calc(100vw - 24px)); }
}

/* =====================================================================
   LEGACY PAGE RESKIN — applies the redesign's visual language to pages
   that still use Bootstrap/Angle markup. CSS only: no elements are added
   or removed; existing classes are restyled with the design tokens so
   every page follows the redesign in both themes. Scoped to .ts-main so
   the shell chrome and fully-converted (ob-/ts-) pages are unaffected.
   ===================================================================== */
.ts-app .ts-main { background: var(--bg); color: var(--text); }
/* legacy pages render straight into .ts-main with no page gutter of their own
   (converted pages bring .ob-main, which has its own padding) */
.ts-app .ts-main:not(:has(> .ob-main)) { padding: 24px 32px 36px; }
@media (max-width: 640px) {
  .ts-app .ts-main:not(:has(> .ob-main)) { padding: 16px 14px 24px; }
}
.ts-app .ts-main a:not(.btn):not(.ts-btn):not(.k-button):not(.ts-navitem) { color: var(--blue); }

/* ---- typography ---- */
.ts-app .ts-main h1, .ts-app .ts-main h2, .ts-app .ts-main h3,
.ts-app .ts-main h4, .ts-app .ts-main h5, .ts-app .ts-main legend,
.ts-app .ts-main .panel-title { color: var(--head); letter-spacing: -0.2px; }
/* brand type must survive legacy rules that pin their own font-family
   (.page-title 'Open Sans', Kendo widgets, event cards etc.) — everything
   under the shell inherits Dax from body.ts-app */
.ts-app .ts-main h1, .ts-app .ts-main h2, .ts-app .ts-main h3,
.ts-app .ts-main h4, .ts-app .ts-main h5, .ts-app .ts-main h6,
.ts-app .ts-main legend, .ts-app .ts-main .panel-title,
.ts-app .ts-main .page-title,
.ts-app .ts-main .k-widget, .ts-app .ts-main .k-input, .ts-app .ts-main .k-picker,
.ts-app .ts-main .k-button, .ts-app .ts-main .k-grid { font-family: inherit; }
.ts-app .ts-main label { color: var(--head); font-weight: 600; }
.ts-app .ts-main .text-muted, .ts-app .ts-main .text-muted-o1,
.ts-app .ts-main small { color: var(--muted); }

/* ---- panels as redesign cards ---- */
.ts-app .ts-main .panel, .ts-app .ts-main .well {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: 12px;
    box-shadow: 0 1px 2px rgba(0,0,0,0.05);
    color: var(--text);
}
.ts-app .ts-main .panel-heading {
    background: var(--inset);
    border-bottom: 1px solid var(--line);
    border-radius: 12px 12px 0 0;
    color: var(--head);
    font-weight: 600;
}
.ts-app .ts-main .panel-footer {
    background: var(--inset);
    border-top: 1px solid var(--line);
    border-radius: 0 0 12px 12px;
}
.ts-app .ts-main .panel-body { color: var(--text); }
.ts-app .ts-main .panel .panel-heading.panel-primary,
.ts-app .ts-main .panel-primary > .panel-heading {
    background: var(--blue-soft);
    color: var(--blue);
    border-color: var(--blue-line);
}

/* ---- buttons mapped onto the ts-btn language ---- */
.ts-app .ts-main .btn {
    border-radius: 9px;
    font-weight: 600;
    font-size: 13.5px;
    transition: filter .12s ease, background .12s ease;
}
.ts-app .btn-primary,
.ts-app .ts-main .btn-success {
    background: var(--blue);
    border-color: var(--blue);
    color: #fff;
    box-shadow: 0 1px 2px rgba(10,50,83,0.25);
}
.ts-app .btn-primary:hover, .ts-app .btn-primary:focus,
.ts-app .btn-primary:active, .ts-app .btn-primary:active:hover,
.ts-app .ts-main .btn-success:hover, .ts-app .ts-main .btn-success:focus,
.ts-app .ts-main .btn-success:active, .ts-app .ts-main .btn-success:active:hover {
    background: var(--blue);
    border-color: var(--blue);
    color: #fff;
    filter: brightness(1.12);
}
body.is-dark.ts-app .btn-primary, body.is-dark .ts-main .btn-success {
    background: var(--navy);
    border-color: var(--navy);
    color: #F2F7FB;
    box-shadow: none;
}

/* project-wide: any `btn btn-primary` uses the brand blue. !important is
   required to beat the legacy bootstrap/theme stylesheets that set
   .btn-primary with their own (often !important) background. */
.btn.btn-primary,
button.btn.btn-primary,
a.btn.btn-primary,
input.btn.btn-primary {
    background-color: #00578E !important;
    background-image: none !important;
    border-color: #00578E !important;
    color: #fff !important;
}
.btn.btn-primary:hover, .btn.btn-primary:focus,
.btn.btn-primary:active, .btn.btn-primary:active:hover,
.btn.btn-primary:focus:active {
    background-color: #014a79 !important;
    border-color: #014a79 !important;
    color: #fff !important;
}
/* Two fixes here, both surfaced by the Active/Inactive filter pair on the
   membership dashboard (`class="btn btn-default btn-primary"` / `"btn btn-default"`):

   1. :not(.btn-primary) — some buttons carry BOTH classes. This rule's
      `color: var(--head) !important` is (0,3,0) and so outranks the
      project-wide `.btn.btn-primary { color:#fff !important }` at (0,2,0),
      which painted dark text onto the navy primary fill: 2.15:1.
   2. background-color !important — the legacy theme pins .btn-default to a
      hard #fff, so the plain `background` shorthand lost. In dark mode that
      left a white button with light --head text at 1.15:1. Forcing the token
      makes the surface follow the theme. */
.ts-app .ts-main .btn-default:not(.btn-primary), .ts-app .ts-main .btn-info:not(.btn-primary) {
    background-color: var(--card) !important;
    background-image: none;
    border-color: var(--line);
    color: var(--head) !important;
}
/* Dark mode gets the surface as a literal rather than var(--card). Bootstrap's
   `.btn-default{background-color:#fff}` is the only other source and is not
   !important, so the token version above should win on its own — but it was
   still measuring #fff in dark during testing, so this states the dark surface
   outright. --head (already forced above) is light in dark mode, and light text
   on a leftover white button is 1.15:1, so this must not regress. */
body.is-dark .ts-main .btn-default:not(.btn-primary),
body.is-dark .ts-main .btn-info:not(.btn-primary) {
    background-color: #0D2032 !important;
}
.ts-app .ts-main .btn-default:hover, .ts-app .ts-main .btn-default:focus,
.ts-app .ts-main .btn-default:active, .ts-app .ts-main .btn-default:active:hover,
.ts-app .ts-main .btn-info:hover, .ts-app .ts-main .btn-info:focus {
    background: var(--inset);
    border-color: var(--line);
    color: var(--head);
}
.ts-app .ts-main .btn-danger {
    background: var(--red);
    border-color: var(--red);
    color: #fff;
}
.ts-app .ts-main .btn-danger:hover, .ts-app .ts-main .btn-danger:focus { filter: brightness(1.1); }
.ts-app .ts-main .btn-warning { border-radius: 9px; }
.ts-app .ts-main .k-button { border-radius: 8px; }
/* Kendo's trailing trigger button (dropdown caret, calendar/clock icon, etc.)
   reads as a proper flush action segment of the field — full height, right
   corners following the field's own curvature — instead of a floating chip
   sitting inset with dead space around it on every side. */
.ts-app .ts-main .k-input:has(> .k-input-button),
.ts-app .ts-main .k-picker:has(> .k-input-button),
.ts-app .ts-formwrap .k-input:has(> .k-input-button),
.ts-app .ts-formwrap .k-picker:has(> .k-input-button) {
    padding-right: 0;
}
.ts-app .ts-main .k-input-button,
.ts-app .ts-formwrap .k-input-button {
    align-self: stretch;
    height: auto;
    margin: 0;
    border-radius: 0 8px 8px 0;
}
/* Kendo primary buttons default to the theme's light blue — pull them onto the
   same navy as the branded primary so they match. Other Kendo button
   variants (flat / danger / neutral) are left as-is. */
.ts-app .ts-main .k-button-solid-primary,
.ts-app .ts-main .k-button.k-primary {
    background-color: var(--navy);
    border-color: var(--navy);
    color: #fff;
}
.ts-app .ts-main .k-button-solid-primary:hover,
.ts-app .ts-main .k-button-solid-primary:focus,
.ts-app .ts-main .k-button-solid-primary:active,
.ts-app .ts-main .k-button.k-primary:hover,
.ts-app .ts-main .k-button.k-primary:focus,
.ts-app .ts-main .k-button.k-primary:active {
    background-color: var(--navy);
    border-color: var(--navy);
    color: #fff;
    filter: brightness(1.12);
}
body.is-dark .ts-main .k-button-solid-primary,
body.is-dark .ts-main .k-button.k-primary {
    background-color: var(--navy);
    border-color: var(--navy);
    color: #F2F7FB;
}

/* ---- inputs: extend the ts-formwrap treatment to every page ---- */
.ts-app .ts-main .form-control,
.ts-app .ts-main .input-full-width,
.ts-app .ts-main select,
.ts-app .ts-main .k-input,
.ts-app .ts-main .k-picker {
    border: 1px solid var(--line);
    border-radius: 9px;
    background: var(--card);
    color: var(--text);
    font-family: inherit;
}
/* Kendo table cells excluded for the same reason as the .ts-formwrap rule near
   the form primitives above — .ts-main wraps every page, so a bare .k-focus
   leaked this ring onto every Kendo grid's current cell. */
.ts-app .ts-main .form-control:focus,
.ts-app .ts-main .k-focus:not(.k-table-td):not(.k-table-th),
.ts-app .ts-main select:focus {
    outline: none;
    border-color: var(--blue);
    box-shadow: 0 0 0 3px rgba(31,111,165,0.14);
}
.ts-app .ts-main .input-group-addon {
    background: var(--inset);
    border-color: var(--line);
    color: var(--muted);
    border-radius: 9px;
}
.ts-app .ts-main input[type="checkbox"], .ts-app .ts-main input[type="radio"] {
    accent-color: var(--navy);
}
body.is-dark .ts-main input[type="checkbox"], body.is-dark .ts-main input[type="radio"] {
    accent-color: var(--blue);
}

/* ---- tables: redesign header treatment + row hover ---- */
.ts-app .ts-main .table > thead > tr > th {
    font-size: 11px;
    letter-spacing: 0.08em;
    color: var(--muted);
    background: var(--inset);
    border-bottom: 2px solid var(--line);
}
.ts-app .ts-main .table > tbody > tr > td { border-color: var(--line); }
.ts-app .ts-main .table-striped > tbody > tr:nth-of-type(odd) { background: var(--inset); }
.ts-app .ts-main .table-hover > tbody > tr:hover,
.ts-app .ts-main .table > tbody > tr:hover { background: var(--blue-soft); }
body.is-dark table { background-color: transparent !important; color: inherit !important; }
body.is-dark .tab-content { background-color: var(--card) !important; }
body.is-dark .k-picker .k-input-button,
body.is-dark .k-input .k-input-button { background-color: transparent; border-color: transparent; color: var(--text); }
body.is-dark label.switch span { border-color: var(--line); }
body.is-dark label.switch input:not(:checked) + span { background-color: var(--inset); }
body.is-dark label.switch span::after { background-color: var(--muted); border-color: var(--line); }
body.is-dark .k-editor { background-color: var(--card); border-color: var(--line); }
body.is-dark .k-toolbar .k-button:not(.k-selected):not(.k-button-solid-primary) { background-color: var(--card); border-color: var(--line); color: var(--text); }
body.is-dark .k-toolbar .k-button:not(.k-selected):not(.k-button-solid-primary):hover { background-color: var(--inset); }
body.is-dark .nav-pills > li:not(.active) > a:not(.active) { background-color: transparent; }
body.is-dark .k-scheduler-datecolumn,
body.is-dark .k-scheduler-groupcolumn { background-color: transparent; }
body.is-dark .k-pager { background-color: var(--inset); color: var(--text); }
body.is-dark .k-pager .k-pager-numbers-wrap .k-pager-nav { background-color: var(--card) !important; border-color: var(--line); color: var(--blue); }
body.is-dark .k-chart-overlay { background-color: var(--inset); color: var(--text); }
body.is-dark .k-button.k-button-icontext,
body.is-dark .k-button.k-button-solid-base:not(.k-selected):not(.k-input-button) { background-color: var(--card); border-color: var(--line); color: var(--text); }
body.is-dark .k-button.k-button-icontext:hover,
body.is-dark .k-button.k-button-solid-base:not(.k-selected):not(.k-input-button):hover { background-color: var(--inset); }
body.is-dark .ts-main .k-editor iframe,
body.is-dark .ts-formwrap .k-editor iframe { background: #ffffff; }

/* ---- list groups, alerts, badges, pagination, tabs ---- */
.ts-app .ts-main .list-group-item {
    background: var(--card);
    border-color: var(--line);
    color: var(--text);
}
/* Dark theme: vendor theme-dark.css sets .list-group-item's background
   !important (var(--secondry-bg-text-color), a mid slate gray) which beats
   the --card background above, leaving the link text at only 4.36:1 (e.g.
   the Facility Dashboard's "Other Useful Links" card). Match !important to
   actually win. */
body.is-dark .ts-main .list-group-item { background-color: var(--card) !important; }
.ts-app .ts-main .list-group-item:first-child { border-top-left-radius: 12px; border-top-right-radius: 12px; }
.ts-app .ts-main .list-group-item:last-child { border-bottom-left-radius: 12px; border-bottom-right-radius: 12px; }
.ts-app .ts-main .alert { border-radius: 12px; }
.ts-app .ts-main .label, .ts-app .ts-main .badge {
    border-radius: 999px;
    font-weight: 600;
    letter-spacing: 0.03em;
}
.ts-app .ts-main .badge { background: var(--blue-soft); color: var(--blue); }
.ts-app .ts-main .pagination > li > a, .ts-app .ts-main .pagination > li > span {
    background: var(--card);
    border-color: var(--line);
    color: var(--text);
}
.ts-app .ts-main .pagination > .active > a, .ts-app .ts-main .pagination > .active > span {
    background: var(--navy);
    border-color: var(--navy);
    color: #fff;
}
.ts-app .ts-main .nav-tabs { border-color: var(--line); }
.ts-app .ts-main .nav-tabs > li > a { color: var(--muted); border-radius: 9px 9px 0 0; }
.ts-app .ts-main .nav-tabs > li.active > a,
.ts-app .ts-main .nav-tabs > li.active > a:hover,
.ts-app .ts-main .nav-tabs > li.active > a:focus {
    background: var(--card);
    border-color: var(--line);
    border-bottom-color: transparent;
    color: var(--head);
}
.ts-app .ts-main hr { border-color: var(--line); }

/* ---- modals (legacy pages don't carry the ts-modal class) ---- */
.ts-app .modal .modal-content {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: 14px;
    box-shadow: 0 24px 70px rgba(0,0,0,0.3);
    color: var(--text);
    overflow: hidden;
}
.ts-app .modal .modal-header {
    background: var(--inset);
    border-bottom: 2px solid var(--blue);
}
.ts-app .modal .modal-title { color: var(--head); font-weight: 700; }
.ts-app .modal .close { color: var(--head); opacity: .5; text-shadow: none; }
.ts-app .modal .close:hover { opacity: .9; }
.ts-app .modal .modal-footer { border-top: 1px solid var(--line); }

/* Bootstrap's default .close (black @ 20% opacity) is nearly invisible on the
   saturated .alert-success/info/warning/danger backgrounds — contrast ratio
   ~1.5:1. Match it to var(--head) at a higher opacity so it stays legible on
   every alert variant. */
.ts-app .alert .close { color: var(--head); opacity: .8; text-shadow: none; }
.ts-app .alert .close:hover { opacity: 1; }

/* The same saturated fills also ship WHITE body text, which measured
   success 2.36:1, info 2.34:1, warning 2.26:1, danger 3.52:1 — every variant
   fails the 4.5:1 AA floor. Restyle them as tinted panels with dark text,
   reusing the AA-vetted colour pairs already established for .ts-warnbanner
   and .ts-notif-ic.

   The tints are deliberately OPAQUE rather than rgba() over the page: a
   translucent tint would need a body.is-dark override to stay legible, and
   that class is absent on is-auto pages (see the note in AUTH PAGES), so a
   translucent version would silently fail there. Opaque panels are correct on
   any page background and in either theme with no class dependency. */
.ts-app .alert-success { background: #EAF5EE; border: 1px solid #D3E8DB; color: #1A6B2C; }
.ts-app .alert-info    { background: #E6F0F7; border: 1px solid #C9DDEB; color: #00578E; }
.ts-app .alert-warning { background: #FBF0DC; border: 1px solid #F0DDB8; color: #875200; }
.ts-app .alert-danger  { background: #FBEAEA; border: 1px solid #F0CFCF; color: #B71C1C; }
/* the vendor theme colours child text directly, so inherit explicitly */
.ts-app .alert-success p, .ts-app .alert-success span, .ts-app .alert-success li, .ts-app .alert-success strong, .ts-app .alert-success b,
.ts-app .alert-info p, .ts-app .alert-info span, .ts-app .alert-info li, .ts-app .alert-info strong, .ts-app .alert-info b,
.ts-app .alert-warning p, .ts-app .alert-warning span, .ts-app .alert-warning li, .ts-app .alert-warning strong, .ts-app .alert-warning b,
.ts-app .alert-danger p, .ts-app .alert-danger span, .ts-app .alert-danger li, .ts-app .alert-danger strong, .ts-app .alert-danger b { color: inherit; }
/* Links inside an alert must take the panel's dark text colour, not the global
   link blue — light-blue-on-tint measured 2.2:1. !important is needed because
   the broad legacy-reskin link rule above (`.ts-app .ts-main a:not(.btn)
   :not(.ts-btn):not(.k-button):not(.ts-navitem)`) carries four :not() classes,
   putting it at specificity (0,6,1) — no reasonable selector here outranks it.
   The underline is what keeps the link distinguishable once it shares the body
   colour, so it must not be dropped. */
.ts-app .alert-success a, .ts-app .alert-info a, .ts-app .alert-warning a, .ts-app .alert-danger a,
.ts-app .alert-success a:hover, .ts-app .alert-info a:hover, .ts-app .alert-warning a:hover, .ts-app .alert-danger a:hover,
.ts-app .alert-success a:focus, .ts-app .alert-info a:focus, .ts-app .alert-warning a:focus, .ts-app .alert-danger a:focus {
  color: inherit !important; text-decoration: underline; font-weight: 600;
}
/* .close inherits the alert's dark text now, so drop the light-on-dark tuning */
.ts-app .alert-success .close, .ts-app .alert-info .close,
.ts-app .alert-warning .close, .ts-app .alert-danger .close { color: inherit; opacity: .7; }

/* ---------- V3 kicker — tilted-square + tracked-uppercase overline ----------
   The Expedition section-header device (design suggestion 05); drop a
   .pg-kicker above any page h1 (see Dashboard.cshtml). */
.pg-kicker {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--navy);
}
.pg-kicker-sq { width: 8px; height: 8px; border-radius: 1.5px; transform: rotate(45deg); background: var(--amber); flex: none; }
body.is-dark .pg-kicker { color: var(--blue); }

/* ---------- Dashboard v2 layout (prototype "Your dashboard") ----------
   Plain stacked page head, main column (stats + apps directory), compact
   profile + activity feed rail. The older .pg-dash grid stays for the
   Your-account page, which shares it. */
.pg-dashhead { display: flex; align-items: center; gap: 14px; margin-bottom: 22px; flex-wrap: wrap; }
.pg-headmain { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.pg-dash-h1 { font-size: 27px; font-weight: 700; letter-spacing: -0.4px; color: var(--head); margin: 0; line-height: 1.15; }
/* align-items:flex-start — each column takes its natural height. The feed panel
   and transactions run their full length and the apps card stops under its own
   content, so neither is stretched to match the other. */
.pg-dashcols { display: flex; gap: 22px; align-items: flex-start; }
.pg-dashmain { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 22px; }
/* fluid rail: shrinks with the window so the two columns stay side-by-side
   down to ~900px viewports (DevTools docked, laptops) before stacking.
   Widened from clamp(320px, 34%, 430px) so the feed rows and the transactions
   table fit without wrapping or scrolling sideways; the main column is flex:1 so
   the apps directory absorbs the difference and narrows to suit. */
.pg-dashrail { width: clamp(360px, 42%, 540px); flex: none; display: flex; flex-direction: column; gap: 22px; }

/* apps & modules directory */
.pg-appdir-head { display: flex; align-items: center; gap: 14px; justify-content: space-between; margin-bottom: 14px; flex-wrap: wrap; }
/* .ts-app .ts-input sets width:100% at (0,2,0), which beat a bare
   .pg-appdir-filter (0,1,0) — the filter stretched to the full card width and
   wrapped onto its own line below the heading. Scoping through .pg-appdir-head
   gives (0,3,0) so the field keeps its fixed width and stays on the title row.
   .pg-card-title's default bottom margin is zeroed here too; with the flex row
   it was pushing the heading off-centre against the input. */
.ts-app .pg-appdir-head .pg-appdir-filter { width: 240px; min-height: 36px; flex: 0 0 auto; }
.pg-appdir-head .pg-card-title { margin: 0; }
.pg-appdir { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.pg-app {
  display: flex; align-items: center; gap: 12px; min-width: 0;
  border: 1px solid var(--line-soft); border-radius: 12px; padding: 11px 13px;
  text-decoration: none; color: var(--text);
  transition: box-shadow 0.15s ease, border-color 0.15s ease, background 0.12s ease;
}
.pg-app:hover { border-color: var(--blue-line); box-shadow: 0 4px 14px rgba(12, 44, 73, 0.08); background: var(--card); text-decoration: none; }
.pg-app-name { flex: 1; min-width: 0; font-size: 13.5px; font-weight: 700; color: var(--head); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pg-app .ts-chev { transform: rotate(-45deg); }
.pg-app:hover .pg-app-name { color: var(--blue); }
/* Live status badge on an app row (filled by the mirror script in
   Views/Home/Dashboard.cshtml from the stat-card values). flex:none so it never
   compresses — .pg-app-name is the flex:1 element that ellipsises instead.
   Colours are set on the span itself rather than inherited, so the broad
   .ts-main a:not(...) link rule on the parent .pg-app anchor can't reach them. */
.pg-app-badge {
  flex: none; white-space: nowrap;
  font-size: 11px; font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase;
  padding: 3px 8px; border-radius: 999px;
  background: var(--inset); border: 1px solid var(--line); color: var(--muted);
}
/* is-total keeps the neutral treatment above (--muted on --inset: 5.12:1 light,
   4.88:1 dark). The coloured variants reuse pairings already validated elsewhere
   in this sheet — var(--red)/var(--green)/var(--blue) on their own are far too
   light for text on a pale fill, so light mode needs the darker inks.
   is-due is RED (amount owing reads as an alert), matching .mp-pill.no. */
.pg-app-badge.is-due { background: #FEE2E2; border-color: #F7C9C9; color: #991B1B; }
.pg-app-badge.is-active { background: #E4F3E7; border-color: #C6E4CD; color: #1A6B2C; }
.pg-app-badge.is-avail { background: var(--blue-soft); border-color: var(--blue-line); color: var(--navy); }
/* Dark variants use OPAQUE fills rather than the rgba() tint used elsewhere in
   this sheet. These are the colours a low-alpha tint of --red/--green/--blue over
   --card composites to, so they look identical — but HTML_CodeSniffer (the runner
   behind tools/pa11y-ci) does not composite alpha, so with rgba() it compares the
   text against the tint treated as opaque and reports ~1:1. Keeping the fill
   opaque makes the measured ratio match the real one and keeps the page clean
   in CI. */
/* kept close to --card (#0D2032): a heavier red tint measured only 4.68:1 against
   var(--red), which passes AA but with no margin worth relying on. This is 5.03:1. */
body.ts-app.is-dark .pg-app-badge.is-due {
  background: #1C2636; border-color: #4A3138; color: var(--red);
}
body.ts-app.is-dark .pg-app-badge.is-active {
  background: #163739; border-color: #205241; color: var(--green);
}
body.ts-app.is-dark .pg-app-badge.is-avail {
  background: #16293A; border-color: #24425C; color: var(--blue);
}
.pg-appadmin { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line-soft); }
.pg-appadmin-head {
  font-size: 11px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase;
  color: var(--faint); margin-bottom: 10px;
}
.pg-appadmin-row { display: flex; flex-wrap: wrap; gap: 8px; }
.pg-appchip {
  display: inline-flex; align-items: center; gap: 8px; white-space: nowrap;
  font-size: 12.5px; font-weight: 600; color: var(--text); text-decoration: none;
  border: 1px solid var(--line); border-radius: 999px; padding: 6px 13px;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
.pg-appchip:hover { background: var(--blue-soft); border-color: var(--blue-line); color: var(--navy); text-decoration: none; }
body.is-dark .pg-appchip:hover { color: var(--blue); }
.pg-appdir-empty { font-size: 13.5px; color: var(--muted); padding: 18px 2px; }

/* compact profile card (rail) */
.pg-profile2-head { display: flex; align-items: center; gap: 13px; margin-bottom: 6px; }
.pg-profile2-avatar { width: 42px; height: 42px; border-radius: 50%; border: 2px solid var(--blue-soft); display: block; }
.pg-profile2-main { min-width: 0; flex: 1; }
.pg-profile2-name { font-size: 14px; font-weight: 700; color: var(--head); }
.pg-profile2-sub { font-size: 11.5px; color: var(--muted); margin-top: 1px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pg-profile2-head .ts-link { flex: none; font-size: 13px; }

/* rail feed: the event-transactions table scrolls inside the card instead of
   crushing its columns or spilling past the rounded edge */
.pg-dashrail .pg-feed .tab-content { overflow: hidden; }
.pg-dashrail .pg-feed .table-responsive { overflow-x: auto; border: 0; margin-bottom: 0; }
/* min-width dropped from 460px: that was sized for four columns and forced a
   sideways scrollbar inside the rail. With "Type" gone there are three, so the
   table can size to the (now wider) rail instead. overflow-x:auto above is kept
   as a fallback for very long transaction numbers. */
.pg-dashrail .pg-feed .table-responsive > .table { width: 100%; margin-bottom: 0; }
.pg-dashrail .pg-feed .table-responsive > .table td,
.pg-dashrail .pg-feed .table-responsive > .table th { white-space: nowrap; }
/* amount right-aligned as a number column; transaction # keeps its pill link */
.pg-dashrail .pg-feed .table-responsive > .table td:last-child,
.pg-dashrail .pg-feed .table-responsive > .table th:last-child { text-align: right; }

@media (max-width: 899px) {
  .pg-dashcols { flex-direction: column; align-items: stretch; }
  .pg-dashrail { width: 100%; }
}
@media (max-width: 640px) {
  .pg-appdir { grid-template-columns: 1fr; }
  /* must match the (0,3,0) selector above, otherwise the fixed width wins here */
  .ts-app .pg-appdir-head .pg-appdir-filter { width: 100%; }
}

/* ---------- Attention strip (pg-alerts) — side-by-side alert cards ----------
   Tilted-square status nodes (design suggestion 05); cards sit left-to-right
   across the top and wrap on narrow screens. Cards are passive; the explicit
   .pg-alert-go button is the only control. */
.pg-alerts { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 14px; margin-bottom: 22px; }
.pg-alert {
  display: flex; align-items: center; gap: 13px; min-width: 0;
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  padding: 12px 16px; box-shadow: 0 1px 2px rgba(12, 44, 73, 0.04);
}
.pg-alert-node {
  width: 11px; height: 11px; border-radius: 2px; transform: rotate(45deg);
  flex: none; margin: 0 4px;
}
.pg-alert-node.is-due { background: var(--red); box-shadow: 0 0 0 4px color-mix(in oklab, var(--red) 14%, transparent); }
.pg-alert-node.is-warn { background: var(--amber); box-shadow: 0 0 0 4px color-mix(in oklab, var(--amber) 16%, transparent); }
.pg-alert-node.is-info { background: var(--navy); box-shadow: 0 0 0 4px color-mix(in oklab, var(--navy) 14%, transparent); }
.pg-alert-node.is-good { background: var(--green); box-shadow: 0 0 0 4px color-mix(in oklab, var(--green) 14%, transparent); }
.pg-alert-main { min-width: 0; flex: 1; }
.pg-alert-title { font-size: 13.5px; font-weight: 700; color: var(--head); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pg-alert-title b { color: var(--red); }
.pg-alert-sub { font-size: 12px; color: var(--muted); margin-top: 1px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pg-alert-go { height: 32px; padding: 0 13px; flex: none; font-size: 12.5px; }
@media (max-width: 640px) {
  .pg-alert { flex-wrap: wrap; }
  .pg-alert-title, .pg-alert-sub { white-space: normal; }
}

/* =====================================================================
   EVENTS LISTING (Areas/Events/Views/Home/_Internals.cshtml) — search hero
   + toolbar + card/list layout, ported from the eservices-redesign handoff
   (proto-events.jsx). Card "pictures" are intentionally UNCHANGED: the
   .card-item wrapper, its <picture>, and the Free/Sold-out/Info-only/
   In-progress overlay badges keep their existing markup and classes.
   Those badges are position:absolute with no ancestor scoping of their
   own — they anchor off the legacy `.card .card-item{position:relative}`
   rule (app.css) — so the outer template wrapper KEEPS the `.card` class
   alongside the new `.evc-card` look; dropping `.card` would silently
   break every badge's position. Only the header/toolbar and the text
   content below each image (title, meta, category, tags) are restyled.
   ===================================================================== */
.ev-hero {
  position: relative; overflow: hidden;
  background: var(--navy-deep); border-radius: 16px; padding: 30px 32px 26px;
  margin-bottom: 20px;
}
.ev-hero-dia {
  position: absolute; border-radius: 24px; transform: rotate(45deg);
  background: rgba(255,255,255,0.05); pointer-events: none;
}
.ev-hero-dia.is-1 { width: 220px; height: 220px; right: -60px; top: -110px; }
.ev-hero-dia.is-2 { width: 140px; height: 140px; right: 170px; bottom: -90px; background: rgba(255,255,255,0.04); }
/* !important — the sitewide .ts-app .ts-main h2{color:var(--head)} reskin
   rule otherwise beats this (higher specificity), rendering the title in
   dark navy text on the dark navy hero: nearly invisible */
.ev-hero-title { font-size: 21px; font-weight: 700; letter-spacing: -0.3px; color: #fff !important; margin: 0 0 16px; position: relative; }

/* search row — same .input-group/.wrapper_ts_overlay/.input-group-btn markup
   as every other search box on the site (see the equivalent .md-welcome
   rules above); only the outer scope + sizing changes for the dark hero */
.ev-search-row { position: relative; display: flex; align-items: stretch; gap: 10px; }
.ev-search-row .wrapper_ts_overlay { flex: 1 1 auto; min-width: 0; }
.ev-search-row > .form-control,
.ev-search-row .wrapper_ts_overlay .form-control,
.ev-search-row .wrapper_ts_overlay .search_ts_overlay {
  height: 44px; border-radius: 10px; border: 1px solid transparent; box-sizing: border-box;
}
.ev-search-row .input-group-btn { width: auto; display: flex; }
.ev-search-row .input-group-btn .btn {
  height: 44px; border-radius: 10px; padding: 0 22px; display: inline-flex; align-items: center;
}

/* category/tags/sort dropdowns (_SearchFilters.cshtml, Kendo dropdownlists) —
   restyled as translucent pills so they read on the dark hero band; the
   filter logic/markup in the partial itself is untouched */
.ev-filters { margin-top: 12px; position: relative; }
.ev-filters .row { margin: 0 -6px; }
.ev-filters .row > div { padding: 0 6px; }
/* Near-opaque light pill — matches the interactive prototype's actual
   <select> treatment (rgba(255,255,255,.95) bg), NOT the separate decorative
   .ev-filter mockup class (12% opacity) mistakenly used here originally.
   Kendo's bundled skin (default-ocean-blue) assumes a light background for
   its own placeholder/value/chevron colors — fighting that with a dark
   translucent pill left several of Kendo's internal text states unreadably
   dark-on-dark. A light pill lets Kendo's own contrast-safe defaults work. */
/* !important on color too — the generic sitewide .ts-app .ts-main .k-picker
   reskin rule (3-class specificity) otherwise beats this 2-class selector */
.ev-filters .k-picker {
  width: 100% !important; height: 38px; border-radius: 9px; background: rgba(255,255,255,0.95) !important;
  border: 1px solid rgba(255,255,255,0.5) !important; color: var(--head) !important;
}
/* Kendo doesn't stretch the dropdownlist to its parent by default, so
   without an explicit width it collapses to just enough room for the
   chevron — no space left for the Category/Tags/Sort label to render */
.ev-filters .k-picker .k-input-value-text { flex: 1; min-width: 0; text-align: left; }
.ev-filters .k-picker .k-input-value-text { color: var(--head) !important; }
.ev-filters .k-picker .k-input-button, .ev-filters .k-picker .k-svg-icon { color: var(--muted) !important; }
.ev-filters .k-picker.k-focus, .ev-filters .k-picker:hover { border-color: transparent; }

/* results toolbar — count + segmented Category/Card/List switcher (same
   ids/data-bind as the buttons they replace, see OPT-005: one active state
   at a time, keyboard/mouse both just toggle the existing view flags) */
.ev-toolbar { display: flex; align-items: center; gap: 12px; margin-bottom: 18px; flex-wrap: wrap; }
.ev-count { font-size: 13px; color: var(--muted); }
/* No wrapping pill/track — just the three buttons in a row. Each one is
   independently rounded with its own hover/active state (see below), so
   nothing needs a shared container to look intentional. */
.ev-seg { display: flex; align-items: stretch; gap: 4px; margin-left: auto; }
/* !important — this page's vendored Bootstrap/Angle CSS resets bare
   <button> elements (appearance:button, its own line-height/box-sizing)
   and this is the third time a legacy rule on this exact page has silently
   beaten a plain-specificity rule (see the h2 title and k-picker fixes
   above), so these are hardened against that rather than left to chance. */
.ev-seg-item {
  flex: 1 1 0; min-width: 0; align-self: stretch;
  display: inline-flex; align-items: center; justify-content: center;
  box-sizing: border-box; height: 34px !important; white-space: nowrap;
  padding: 0 15px !important; font-size: 13px !important; font-weight: 600 !important;
  line-height: normal !important; color: var(--muted) !important;
  background: var(--card) !important; border: 1px solid var(--line) !important;
  border-radius: 9px !important; box-shadow: none !important; -webkit-appearance: none;
  cursor: pointer; font-family: inherit; transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.ev-seg-item:hover { background: var(--inset) !important; }
.ev-seg-item:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
/* btn-primary-custom is the class eventsearch.ts's css: binding actually
   toggles (kept unrenamed — see the comment in _Internals.cshtml). */
.ev-seg-item.btn-primary-custom {
  background: var(--blue-soft) !important; color: var(--navy) !important; border-color: var(--blue-line) !important;
}
body.is-dark .ev-seg-item.btn-primary-custom { color: var(--blue) !important; }

/* card grid — .evc-card layers onto the existing .card class (see note
   above); drops the legacy fixed 300px height (.viewevent) so the taller
   redesigned text block isn't clipped */
.evc-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
/* Category view reuses this grid, but there it sits on a Kendo ListView, which
   renders its tiles inside a .k-listview-content wrapper — the grid has to move
   down to that wrapper or every tile ends up on a row of its own. */
.evc-grid.category-list-view { display: block; }
.evc-grid.category-list-view > .k-listview-content {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px;
}
.evc-card.card {
  margin-bottom: 0; height: auto; display: flex; flex-direction: column;
  border: 1px solid var(--line); border-radius: 14px; background: var(--card); overflow: hidden;
  box-shadow: 0 1px 2px rgba(12,44,73,0.04); transition: box-shadow 0.15s ease;
}
.evc-card.card:hover { box-shadow: 0 8px 24px rgba(12,44,73,0.1); }
.evc-body { padding: 14px 16px 16px; display: flex; flex-direction: column; flex: 1; }
.evc-title { font-size: 15.5px; font-weight: 700; color: var(--head); letter-spacing: -0.2px; display: flex; align-items: center; gap: 8px; }
.evc-meta { font-size: 12.5px; color: var(--muted); margin-top: 4px; }
.evc-tags { margin-top: 8px; display: flex; flex-wrap: wrap; gap: 6px; }
.evc-tags .tag-text { font-size: 11.5px; color: var(--blue); text-decoration: none; }
.evc-tags .tag-text:hover { text-decoration: underline; }

/* date badge + category pill, overlaid on the card image (top-left/top-right) */
.evc-datebadge {
  position: absolute; top: 10px; left: 10px; z-index: 1;
  background: var(--card); border-radius: 10px; padding: 5px 9px;
  text-align: center; line-height: 1.05; box-shadow: 0 2px 8px rgba(12,44,73,0.18);
}
.evc-datebadge-day { display: block; font-size: 15px; font-weight: 800; color: var(--head); }
.evc-datebadge-mon { display: block; font-size: 9.5px; font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase; color: var(--muted); margin-top: 1px; }
.evc-catpill {
  position: absolute; top: 12px; right: 12px; z-index: 1;
  background: rgba(255,255,255,0.92); color: var(--head);
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase;
  padding: 5px 10px; border-radius: 999px;
}
body.is-dark .evc-catpill { background: rgba(13,32,50,0.85); color: var(--head); }

/* price + availability + register row, below the tags */
/* margin-top:auto pins the action row to the BOTTOM of .evc-body (which is
   flex:1 inside the column-flex card), so the price/status/register row lines
   up across every card in a row regardless of how much text each one carries.
   padding-top keeps a gap when the content is tall enough to consume the auto
   margin. Shared by the events, membership and facility card grids. */
.evc-foot { margin-top: auto; padding-top: 10px; display: flex; align-items: center; gap: 8px; }
.evc-price { font-size: 14.5px; font-weight: 700; color: var(--head); }
.evc-status { font-size: 10.5px; font-weight: 700; letter-spacing: 0.2px; text-transform: uppercase; padding: 3px 9px; border-radius: 999px; }
.evc-status.is-available { background: color-mix(in srgb, var(--green) 15%, transparent); color: var(--green); }
.evc-status.is-sold-out { background: color-mix(in srgb, var(--red) 15%, transparent); color: var(--red); }
.evc-status.is-info { background: var(--inset); color: var(--muted); }
.evc-status.is-progress { background: color-mix(in srgb, var(--amber) 18%, transparent); color: var(--amber); }
.evc-foot .evc-register { margin-left: auto; height: 32px; padding: 0 16px; font-size: 12.5px; }

/* Real photos: Bootstrap's .img-responsive is max-width:100%;height:auto —
   it caps overflow but never GROWS an image smaller than its box, so a
   proxy-resized photo (?w=465) sitting in a wider column left blank space
   with the price/status badge (position:absolute inside .card-item) then
   appearing to float in that gap instead of overlaying the photo, and gave
   every card a different height depending on its source image's own size.
   Force every image to fill the box uniformly; only touches sizing, not
   which photo shows — the .card-item/badge markup itself is untouched. */
.evc-card .card-item { height: 160px; }
.evc-card .card-item picture,
.evc-card .card-item img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* No source photo: the redesign's placeholder tile (proto.css .ph-tile-art)
   instead of whatever generic stock image the proxy falls back to */
.evc-img-fallback {
  width: 100%; height: 100%; display: grid; place-items: center;
  background: linear-gradient(135deg, color-mix(in srgb, var(--blue-soft) 45%, transparent), color-mix(in srgb, var(--blue-soft) 25%, transparent));
}
.evc-img-fallback .ts-dia { width: 26px; height: 26px; border-radius: 6px; color: var(--navy); opacity: 0.25; }
.evc-img-fallback-sm { height: 100px; width: 100px; border-radius: 4px; }
.evc-img-fallback-sm .ts-dia { width: 18px; height: 18px; }
body.is-dark .evc-img-fallback { background: linear-gradient(135deg, color-mix(in srgb, #15212C 55%, transparent), color-mix(in srgb, #1A2A3A 35%, transparent)); }
body.is-dark .evc-img-fallback .ts-dia { color: var(--blue); opacity: 0.6; }

/* list view — kept as a real <table> (the image <td> is untouched); only
   the text cell's typography is redesigned */
.evl-title { font-size: 14px; font-weight: 700; color: var(--head); }
.evl-meta { font-size: 12.5px; color: var(--muted); margin-top: 2px; }

/* empty state */
.ev-empty { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 58px 20px 62px; }
.ev-empty-art { display: flex; gap: 8px; margin-bottom: 20px; justify-content: center; }
.ev-empty-art .ts-dia { width: 14px; height: 14px; border-radius: 3.5px; color: #C7D8E5; }
.ev-empty-title { font-size: 17px; font-weight: 700; color: var(--head); margin-bottom: 5px; }
.ev-empty-sub { font-size: 13.5px; color: var(--muted); max-width: 420px; margin: 0 auto; }

@media (max-width: 1099px) {
  .evc-grid,
  .evc-grid.category-list-view > .k-listview-content { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .evc-grid,
  .evc-grid.category-list-view > .k-listview-content { grid-template-columns: 1fr; }
  .ev-search-row { flex-direction: column; }
  .ev-search-row .input-group-btn .btn { width: 100%; justify-content: center; }
  .ev-hero { padding: 22px 18px; }
  .ev-toolbar { gap: 10px; }
}

/* ---------- Dashboard (pg-dash) — profile + quick actions rail, tile grid ---------- */
.ob-main.is-wide { max-width: none; }
.pg-dash { display: grid; grid-template-columns: minmax(320px, 400px) minmax(0, 1fr); gap: 22px; align-items: start; }
.pg-quick-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pg-dash-col { display: flex; flex-direction: column; gap: 22px; min-width: 0; }
.pg-card { background: var(--card); border: 1px solid var(--line); border-radius: 13px; padding: 22px 24px; box-shadow: 0 1px 2px rgba(12,44,73,0.04); }
.pg-card-title { font-size: 16px; font-weight: 700; color: var(--head); letter-spacing: -0.2px; margin: 0 0 14px; display: flex; align-items: center; gap: 10px; }
.pg-card-title .ts-btn { margin-left: auto; height: 32px; padding: 0 12px; font-size: 12.5px; }
.pg-card-hint { font-size: 12.5px; font-weight: 500; color: var(--muted); margin-left: auto; }

/* ---------- eBills summary (Areas/Customer/Views/Home/Index.cshtml) ----------
   Balance hero + per-account-type rows, ported from the eservices-redesign
   handoff (proto-billing.jsx / redesign-pages.css). Values are populated
   client-side by summary2.ts via Kendo MVVM bindings — the classes below only
   restyle the same bound elements/ids, nothing here changes the view model. */
/* the old markup centered via Bootstrap's .container (margin:0 auto); this
   replaces it now that the page no longer wraps content in .container */
.eb-wrap { max-width: 860px; margin: 0 auto; }
.eb-hero {
  background: var(--navy-deep); border-radius: 16px; padding: 24px 28px;
  color: #fff; display: flex; align-items: center; gap: 20px; margin-bottom: 20px;
  position: relative; overflow: hidden;
}
body.is-dark .eb-hero { color: #F2F7FB; }
.eb-hero-dia {
  position: absolute; width: 190px; height: 190px; border-radius: 22px;
  transform: rotate(45deg); background: rgba(255,255,255,0.05);
  right: -50px; top: -90px; pointer-events: none;
}
.eb-hero-lbl { font-size: 12.5px; opacity: 0.72; position: relative; }
.eb-hero-num { font-size: 36px; font-weight: 700; letter-spacing: -0.7px; margin-top: 2px; position: relative; }
.eb-hero-actions { margin-left: auto; display: flex; gap: 10px; position: relative; }
/* both hero buttons share one height/padding so Statements and Pay Bills Now
   line up — only fill/color differ between the two variants */
.eb-hero-actions .ts-btn { height: 44px; padding: 0 22px; }
.eb-hero .ts-btn.is-pay { background: #fff; color: var(--navy-deep); }
.eb-hero .ts-btn.is-pay:hover { filter: brightness(0.96); }
.eb-hero .ts-btn.is-quiet { background: rgba(255,255,255,0.12); color: #fff; border-color: rgba(255,255,255,0.25); text-decoration: none; }
.eb-hero .ts-btn.is-quiet:hover { background: rgba(255,255,255,0.2); }
.eb-rows { display: flex; flex-direction: column; }
.eb-row { display: flex; align-items: center; gap: 16px; padding: 16px 2px; cursor: pointer; }
.eb-row:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; border-radius: 8px; }
.eb-row + .eb-row { border-top: 1px solid var(--line-soft); }
.eb-row-icon {
  width: 38px; height: 38px; border-radius: 10px; background: var(--inset);
  border: 1px solid var(--line-soft); display: grid; place-items: center; flex: none;
}
.eb-row-icon .ts-dia { width: 9px; height: 9px; color: var(--muted); }
.eb-row-main { min-width: 0; flex: 1; }
.eb-row-title { font-size: 14px; font-weight: 700; color: var(--head); display: flex; align-items: center; gap: 10px; }
.eb-row-desc { font-size: 12.5px; color: var(--muted); margin-top: 1px; }
.eb-row-desc .ts-link { font-size: 12.5px; }
.eb-row-amt { font-size: 15px; font-weight: 700; color: var(--head); flex: none; }
.eb-row-amt.is-zero { color: var(--faint); font-weight: 600; }
.eb-row .ts-chev { flex: none; }
.eb-paid {
  font-size: 11px; font-weight: 600; color: #1A6B2C; /* var(--green) is only 2.92:1 on this tint — fails AA */
  background: #EAF5EE; border: 1px solid #D3E8DB; border-radius: 999px; padding: 2px 8px;
}
body.is-dark .eb-paid { color: var(--green); background: rgba(63,168,110,0.14); border-color: rgba(63,168,110,0.35); }
/* per-item sub-lines (tax sources / meters) inside a row's kendo template */
.eb-subrow { display: flex; align-items: center; gap: 10px; margin-top: 6px; font-size: 12.5px; }
.eb-subrow-name { color: var(--muted); }
@media (max-width: 640px) {
  .eb-hero { flex-wrap: wrap; padding: 20px; }
  .eb-hero-actions { margin-left: 0; width: 100%; }
  .eb-hero-actions .ts-btn { flex: 1; }
  .eb-row { flex-wrap: wrap; }
}

/* profile card */
.pg-profile { text-align: center; }
.pg-profile-avatar { width: 84px; height: 84px; border-radius: 50%; border: 3px solid var(--blue-soft); margin: 10px auto 0; display: block; }
.pg-profile-name { font-size: 19px; font-weight: 700; color: var(--head); letter-spacing: -0.3px; margin: 12px 0 16px; }
.pg-chips { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-bottom: 16px; }
.pg-chip { font-size: 12px; font-weight: 600; color: var(--muted); background: var(--inset); border: 1px solid var(--line); border-radius: 999px; padding: 4px 11px; }

/* quick actions list */
.pg-quick { display: flex; flex-direction: column; }
.pg-quick-item { display: flex; align-items: center; gap: 13px; width: 100%; padding: 11px 4px; border: 0; border-top: 1px solid var(--line-soft); background: none; font: inherit; text-align: left; color: var(--text); text-decoration: none; cursor: pointer; }
.pg-quick-item:first-child { border-top: 0; }
.pg-quick-ic { width: 34px; height: 34px; border-radius: 9px; background: var(--blue-soft); display: grid; place-items: center; flex: none; color: var(--blue); }
.pg-quick-name { font-size: 13.5px; font-weight: 600; color: var(--head); }
.pg-quick-item:hover .pg-quick-name { color: var(--blue); }
.pg-quick-item .ts-chev { margin-left: auto; transform: rotate(-45deg); }

/* link tiles */
.pg-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 14px; }
.pg-tiles > #nonpayroll:empty { display: none; }
.pg-tile { display: block; background: var(--card); border: 1px solid var(--line); border-radius: 13px; padding: 18px 20px; text-decoration: none; box-shadow: 0 1px 2px rgba(12,44,73,0.04); transition: border-color .12s ease, box-shadow .12s ease; }
.pg-tile:hover { border-color: var(--blue-line); box-shadow: 0 4px 14px rgba(12,44,73,0.08); text-decoration: none; }
.pg-tile-ic { display: block; font-size: 18px; color: var(--blue); margin-bottom: 10px; }
.pg-tile-name { display: block; font-size: 14.5px; font-weight: 700; color: var(--head); letter-spacing: -0.2px; margin-bottom: 4px; }
.pg-tile-link { display: block; font-size: 12.5px; font-weight: 600; color: var(--blue); }

/* account rows (citizen profile card) — count badges + status pill */
.pg-quick-item .pg-count { margin-left: auto; min-width: 24px; height: 24px; border-radius: 999px; background: var(--navy); color: #fff; font-size: 12px; font-weight: 700; display: grid; place-items: center; padding: 0 8px; }
body.is-dark .pg-quick-item .pg-count { background: var(--blue); color: #0D1318; }
.pg-quick-item .pg-pill-warn { margin-left: auto; font-size: 12px; font-weight: 600; color: #875200; background: rgba(221,148,52,0.12); border: 1px solid rgba(221,148,52,0.4); border-radius: 999px; padding: 3px 10px; }
body.is-dark .pg-quick-item .pg-pill-warn { color: var(--amber); }
.pg-quick-item .pg-pill-warn:empty, .pg-quick-item .pg-count + .ts-chev, .pg-quick-item .pg-pill-warn + .ts-chev { margin-left: 10px; }

/* Citizen dashboard stat counters. The visible cards were removed from
   Views/Home/Dashboard.cshtml (not part of the template) — this now only hides
   the value holder that dashboard.ts still writes into and that the apps-directory
   badges and the attention strip read back out. display:none is safe for both:
   jQuery .text() and MutationObserver work on hidden nodes, and it keeps the
   holder out of the accessibility tree and out of pa11y's scope.
   The old .pg-stats/.pg-stat/.pg-stat-num/.pg-stat-label/.pg-stat-link rules were
   dropped with the markup — nothing else in the repo referenced them (.pg-stattabs
   further down is a separate class and is still in use by
   Areas/Admin/Views/Issue/Dashboard.cshtml). */
.pg-statdata { display: none; }

/* overlap guards: quick rows, feed footer, filter widgets, useful links */
.pg-quick-name { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.pg-quick-item .pg-count, .pg-quick-item .pg-pill-warn { flex: none; }
/* Footer: mark-all-read on the left, view-more on the right. The #feedsort
   ComboBox that used to occupy its own full-width row here was removed from the
   markup, so the rules that reserved space for it are gone with it. */
.pg-feed .panel-footer .pg-feed-btn {
  flex: 0 0 auto; min-width: 0; margin: 0;
  display: inline-flex; align-items: center; justify-content: center;
  height: 34px; padding: 0 14px; border-radius: 9px;
  font-family: inherit; font-size: 12.5px; font-weight: 700; line-height: 1;
  background: var(--card); color: var(--head); border: 1px solid var(--line);
  appearance: none; -webkit-appearance: none; cursor: pointer;
  transition: background .12s ease, border-color .12s ease;
}
.pg-feed .panel-footer .pg-feed-btn:hover { background: var(--inset); }
/* the quiet (mark-all-read) action reads as a link, the primary one keeps the
   button chrome; margin-left:auto on the LAST child pushes it to the right edge
   whichever buttons the tab happens to render */
.pg-feed .panel-footer .pg-feed-btn.is-quiet {
  background: transparent; border-color: transparent; color: var(--blue); padding-left: 0;
}
.pg-feed .panel-footer .pg-feed-btn.is-quiet:hover { background: transparent; text-decoration: underline; }
.pg-feed .panel-footer .pg-feed-btn:last-child { margin-left: auto; }
.pg-filtergrid select, .pg-filtergrid .k-dropdownlist, .pg-filtergrid .k-combobox, .pg-filtergrid .k-picker { width: 100% !important; }
.usefull-links .row { margin: 0 0 10px; display: flex; align-items: center; gap: 10px; }
.usefull-links .row > a.deleteControllers { float: none; flex: none; width: 34px; height: 34px; border-radius: 50%; border: 1px solid var(--line); padding: 0 !important; margin: 0; display: flex; align-items: center; justify-content: center; line-height: 1; }
.usefull-links .row > a.deleteControllers::before { display: block; }
.usefull-links .row > div { flex: 1; min-width: 0; padding: 0; float: none; width: auto; }
.usefull-links .list-group-item { border-radius: 10px !important; border: 1px solid var(--line); }

/* tab strips (segmented control on top of legacy .nav-tabs markup) — the tabs
   share one enclosing track so they read as a single control rather than a row
   of independent buttons. Wraps cleanly for any tab count, so 2-tab and 12-tab
   pages share one consistent look.

   inline-flex keeps the track hugging its tabs instead of running the full
   width of the page; vertical-align stops the inline box picking up the
   parent's line-height as trailing whitespace. The track colour is mixed from
   --line rather than taken straight from --inset because --inset (#F3F6FA) and
   the page --bg (#EFF3F8) are within a hair of each other in light mode, which
   would leave the track invisible on every page that sits on --bg. */
.ts-app .ts-main .pg-tabs {
  display: inline-flex; vertical-align: top; flex-wrap: wrap; gap: 2px; border-bottom: 0;
  margin: 0 0 18px; padding: 3px; list-style: none; max-width: 100%;
  background: color-mix(in oklab, var(--line) 40%, var(--inset));
  border: 1px solid var(--line); border-radius: 12px;
}
.ts-app .ts-main .pg-tabs > li { float: none; display: block; width: auto; margin: 0; }
.ts-app .ts-main .pg-tabs > li > a,
.ts-app .ts-main .pg-tabs > li.active > a,
.ts-app .ts-main .pg-tabs > li.active > a:hover,
.ts-app .ts-main .pg-tabs > li.active > a:focus {
  display: block; border: 1px solid transparent; border-radius: 9px; background: transparent;
  padding: 7px 15px; margin: 0; font-size: 13.5px; font-weight: 600; color: var(--text);
  white-space: nowrap; line-height: 1.3; text-decoration: none;
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}
/* bootstrap underlines a:hover globally; a tab is a control, not a link. The
   underline was also the only thing marking :focus here, so dropping it means
   spelling out a real focus ring (same treatment as .ev-seg-item et al).
   The !important is load-bearing: app.css (vendor) carries a blanket
   `:focus{outline:0!important}` and `a{outline:0!important}`, so without it
   these tabs have no visible keyboard focus indicator at all. */
.ts-app .ts-main .pg-tabs > li > a:hover,
.ts-app .ts-main .pg-tabs > li > a:focus { text-decoration: none; }
.ts-app .ts-main .pg-tabs > li > a:focus-visible {
  outline: 2px solid var(--blue) !important; outline-offset: 1px;
}
.ts-app .ts-main .pg-tabs > li > a:hover { color: var(--head); background: color-mix(in oklab, var(--card) 62%, transparent); border-color: transparent; }
/* active tab = raised chip on the track (card surface, navy text) — deliberately
   NOT a solid navy fill, so it reads as a selected nav state and stays distinct
   from solid-navy action buttons (tabs vs buttons hierarchy, site-wide) */
.ts-app .ts-main .pg-tabs > li.active > a,
.ts-app .ts-main .pg-tabs > li.active > a:hover,
.ts-app .ts-main .pg-tabs > li.active > a:focus {
  background: var(--card); border-color: var(--line); color: var(--navy) !important; font-weight: 700;
  box-shadow: 0 1px 2px rgba(19,33,45,0.09);
}
body.is-dark .ts-main .pg-tabs > li.active > a,
body.is-dark .ts-main .pg-tabs > li.active > a:hover,
body.is-dark .ts-main .pg-tabs > li.active > a:focus { color: #DCEBF6 !important; }
/* dark mode: --card is DARKER than the track, so a plain card-surface chip would
   read as pressed-in rather than raised, and the drop shadow registers as
   nothing on a dark surface. Every surface in the dark palette sits between
   L 0.006 and 0.027, so no fill can put 3:1 between the chip and its track —
   the outline has to carry the selected state instead. --blue at 75% measures
   3.34:1 against both the track and the chip, clearing the WCAG 1.4.11 floor
   for non-text state indication; the older #00578E mix was 1.21:1. */
body.is-dark .ts-main .pg-tabs > li.active > a {
  background: color-mix(in oklab, #00578E 30%, #0D2032);
  border-color: color-mix(in oklab, var(--blue) 75%, var(--card)); box-shadow: none;
}
/* inactive tab labels also out-rank the legacy link colour. --text rather than
   --muted: on the track, --muted lands at 4.63:1 in dark mode — over the AA
   floor but with no margin — where --text clears 6:1 in both themes. */
.ts-app .ts-main .pg-tabs > li > a { color: var(--text) !important; }
.ts-app .ts-main .pg-tabs > li > a:hover { color: var(--head) !important; }

/* feed list + footer inside the feed card */
.pg-feed .tab-content { padding: 0; }
.pg-feed .list-group { margin: 0; }
.pg-feed .list-group-item { border-left: 0; border-right: 0; border-radius: 0 !important; }
.pg-feed .list-group-item:first-child { border-top: 0; }
/* vendor theme-dark.css sets .list-group-item-info color !important (#5EADED,
   only 4.60:1 on this row's dark background — right at the AA edge across every
   feed entry) — need !important here too to win; a lighter tint clears AA (5.53:1) */
body.is-dark .pg-feed .list-group-item-info { color: #7EBDF1 !important; }
.pg-feed .panel-footer { background: var(--inset); border: 1px solid var(--line-soft); border-radius: 10px; margin-top: 14px; padding: 12px 14px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.pg-feed .table-responsive { border: 0; }

/* calendar / filter card */
.pg-filtergrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px 18px; margin-bottom: 16px; text-align: left; }
.pg-cal-toolbar { display: flex; justify-content: flex-end; margin-bottom: 10px; }

@media (max-width: 1280px) {
  .pg-dash { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .pg-filtergrid { grid-template-columns: 1fr; }
  .pg-card { padding: 18px 16px; }
}

/* ---- Kendo chrome: align widget surfaces with the tokens ---- */
.ts-app .ts-main .k-grid, .ts-app .ts-main .k-listview {
    border-color: var(--line);
    border-radius: 12px;
    overflow: hidden;
}
.ts-app .ts-main .k-grid-header { background: var(--inset); }
.ts-app .ts-main .k-grid-header .k-header {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--muted);
}
/* Kendo grid pager page numbers. theme-light.css (vendor, under assets/externals —
   do not edit) sets
     .k-pager .k-pager-numbers-wrap .k-pager-numbers .k-button { color: #428bca; }
   which is Bootstrap 3's default link blue: 3.63:1 on the white pager background,
   failing WCAG AA (4.5:1) on every Kendo grid pager in the site. var(--blue) is
   7.63:1 on white and matches the rest of the redesign's link colour.

   Two deliberate exclusions:
   - :not(.k-selected) — the current page is white on #0077BF (4.77:1, already
     passing). Recolouring it would put dark blue text on a blue chip.
   - :not(.is-dark) — theme-dark.css already overrides these to #ced4da (8.82:1),
     so dark mode is not broken and must be left alone; forcing the lighter
     dark-mode var(--blue) onto it would only lower a passing ratio. */
body.ts-app:not(.is-dark) .ts-main .k-pager .k-pager-numbers-wrap .k-pager-numbers .k-button:not(.k-selected) {
    color: var(--blue);
}
/* Kendo adaptive actionsheet section headers (the mobile/narrow-viewport column
   menu, e.g. the "Photo" / "Customer info" groups on /admin/actionlog). The
   dynamically-bundled "darktheme" stylesheet applies .dropdown-header { color:
   #a1a2a3 } in BOTH themes; in dark mode theme-dark.css's equal-specificity
   .k-header rule comes later and wins (#ced4da), but in light mode nothing
   overrides it, leaving #a1a2a3 on the #f7f8f9 header for 2.4:1. Scoped to the
   actionsheet so ordinary Bootstrap dropdown headers elsewhere are untouched. */
body.ts-app:not(.is-dark) .k-actionsheet .dropdown-header,
body.ts-app:not(.is-dark) .k-actionsheet .dropdown-header > span {
    color: var(--muted);
}
/* Same actionsheet, dark mode — separate rules because the surfaces differ.
   Kendo gives .dropdown-header a blue (#0463A8) fill in dark, where the
   inherited #ced4da is only 4.19:1 and var(--muted) would be far worse (2.08:1);
   var(--head) is 5.44:1. The .k-actionsheet-subtitle (the AutoComplete's
   "Start typing to find a customer" hint) keeps Kendo's #666 in dark for 2.3:1
   on #2A3137 — var(--muted) is still short of AA there at 4.38:1, so this one
   also needs var(--head) (11.46:1). Light mode already passes for the subtitle
   (#666 on white, 5.74:1) and is deliberately left alone. */
body.ts-app.is-dark .k-actionsheet .dropdown-header,
body.ts-app.is-dark .k-actionsheet .dropdown-header > span,
body.ts-app.is-dark .k-actionsheet .k-actionsheet-subtitle {
    color: var(--head);
}
/* Work Order Time Sheets grid (Areas/Employee/Views/WorkOrderTimesheet/WorkOrderTimeSheetsHistory.cshtml
   — #gridwotimesheet, built by workordertimesheetlist.ts). The global Kendo-grid header treatment
   above (uppercase / 11px / muted colour) made this grid's column titles read poorly. Restore a
   clean, mixed-case header for this grid only — the #id gives (1,4,0) specificity, beating the
   (0,4,0) rule above, so the rest of the site's grids keep the redesign treatment. */
.ts-app .ts-main #gridwotimesheet .k-grid-header .k-header {
    font-size: 13px;
    text-transform: none;
    letter-spacing: normal;
    color: var(--text);
}
/* Work Order Timesheet Details banner (Areas/Employee/Views/WorkOrderTimesheet/WorkOrderTimeSheetDetails.cshtml
   — #issueDescription .bg-info). app.css themes .bg-info as a bright cyan (#23b7e5, color:#fff!important)
   that clashes with the redesign. Re-tint this one banner to a soft-blue redesign card in both themes;
   the colour needs !important to beat app.css's forced #fff. Scoped to #issueDescription so every other
   .bg-info on the site keeps its styling. */
.ts-app .ts-main #issueDescription .bg-info {
    background: var(--blue-soft);
    border: 1px solid var(--blue-line);
    border-radius: 12px;
    color: var(--text) !important;
}
.ts-app .ts-main #issueDescription .bg-info h3 { color: var(--head); }
.ts-app .ts-main .k-toolbar { background: var(--inset); border-color: var(--line); }
.ts-app .ts-main .k-editor { border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
.ts-app .ts-main .k-editor .k-editor-content,
.ts-app .ts-formwrap .k-editor .k-editor-content,
.ts-app .ts-main .k-editor iframe,
.ts-app .ts-formwrap .k-editor iframe { background: var(--card); color-scheme: light; }
/* ---- Inline Kendo editors must keep their own scrollbar ----
   The overflow:hidden above exists to clip the toolbar's square corners inside the 10px
   radius. That is safe for the classic (textarea-initialized) editor, where the toolbar and
   a separate .k-editor-content scroller are children of .k-editor. But an editor initialized
   from a div is *inline*: Kendo makes that div itself contenteditable (.k-editor-inline) and
   the div IS the scrolling content box — Kendo's own overflow:auto on it is what produces the
   scrollbar. Our (0,3,0) rule beat that (0,1,0) default and clipped it, so tall templates had
   no scrollbar and no wheel scrolling; only caret movement (arrow keys) scrolled the box.
   Affects the fixed-height template editors — event certificate (#EditCertificateTemplate),
   event sub category tickets, POS receipt, membership card, and the waiver editor. */
body.ts-app .ts-main .k-editor.k-editor-inline,
body.ts-app .ts-formwrap .k-editor.k-editor-inline { overflow: auto; }

/* ---- Service Request / Issue view action toolbar (Areas/Issue/Views/View/Index.cshtml — h3.sr-toolbar) ----
   The action controls (Create New / Edit / Delete / Select-a-Work-Request dropdown / reply / settings /
   Export to Work Request / Assign Inspector / View Feedback / kanban export) use nested Bootstrap float
   (pull-right / clearfix) markup. The floats overflow the <h3>'s box and spill DOWN onto the details card
   below (the overlap), and scatter across several rows. Make the bar a flex container so it contains its
   own controls (no overflow → no overlap) and lays them out as one tidy, right-aligned, wrapping row: each
   legacy wrapper becomes an inline-flex group and the floats + !important utility margins are reset. Works
   for every request type / role — the many display:none controls take no space until JS reveals them. */
.ts-app .ts-main h3.sr-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    margin: 0 0 32px;
    padding: 0;
    font-size: 14px;
    font-weight: 400;
    line-height: 1.4;
}
/* drop the .row/.clearfix pseudo-cells that would otherwise become stray flex items */
.ts-app .ts-main h3.sr-toolbar::before,
.ts-app .ts-main h3.sr-toolbar::after { content: none; }
/* status badges anchor the left edge; everything else is pushed right.
   NOTE the class collision: on the /issue listing .sr-status IS the status pill
   (rounded border, tinted background, a ::before dot). Here it is the <div> that
   *wraps* the Status* badges, so it was picking up that pill treatment and drawing a
   second outline plus a stray dot around the real badge. Strip it back to a bare
   flex container. */
.ts-app .ts-main h3.sr-toolbar > .sr-status {
    display: inline-flex; align-items: center; flex-wrap: wrap; gap: 6px;
    margin-right: auto;
    padding: 0; border: 0; border-radius: 0;
    background: none; color: inherit;
    font-size: inherit; font-weight: inherit; letter-spacing: normal; text-transform: none;
}
.ts-app .ts-main h3.sr-toolbar > .sr-status::before { content: none; }
.ts-app .ts-main h3.sr-toolbar .sr-status .badge { margin: 0 !important; }
/* lay every legacy float wrapper out as an inline-flex group — each contains its own buttons,
   so nothing floats out of the toolbar */
.ts-app .ts-main h3.sr-toolbar .manage-issues,
.ts-app .ts-main h3.sr-toolbar .display-block,
.ts-app .ts-main h3.sr-toolbar span.clearfix,
.ts-app .ts-main h3.sr-toolbar span.pull-right {
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    float: none !important;
    margin: 0 !important;
    padding: 0;
}
/* ...and drop their clearfix pseudo-elements for the same reason the <h3>'s own are dropped
   above: `content: " "` blockifies into a real flex item once the wrapper is a flex container,
   so a group whose buttons are all display:none still measured ~8px per pseudo. That phantom
   width sat on the right end of the bar and held the visible buttons ~56px off the edge they
   are supposed to be flush with — most obviously on time off and timesheets, where every
   control in .display-block is hidden. */
.ts-app .ts-main h3.sr-toolbar .manage-issues::before,
.ts-app .ts-main h3.sr-toolbar .manage-issues::after,
.ts-app .ts-main h3.sr-toolbar .display-block::before,
.ts-app .ts-main h3.sr-toolbar .display-block::after,
.ts-app .ts-main h3.sr-toolbar span.clearfix::before,
.ts-app .ts-main h3.sr-toolbar span.clearfix::after,
.ts-app .ts-main h3.sr-toolbar span.pull-right::before,
.ts-app .ts-main h3.sr-toolbar span.pull-right::after { content: none; }
/* the controls themselves (reset the float + the !important utility margins) */
.ts-app .ts-main h3.sr-toolbar .btn { margin: 0 !important; float: none !important; }

/* Request details load-in overlap fix. When site animations are on, the details card
   (#refreshThisData → _ViewDetails.cshtml:62 wrapper) animates in with fadeInDown, which starts the
   tall card at translate3d(0,-100%,0) — directly over the toolbar above — and slides it DOWN through
   the action buttons on load, overlapping them until the animation settles (or a scroll forces a
   repaint). Swap the slide for an opacity-only fade (own keyframe, so it doesn't depend on a stock
   fadeIn): the staged delay/reveal stays, but nothing sweeps over the toolbar. */
@keyframes ts-fade-in-place { from { opacity: 0; } to { opacity: 1; } }
.ts-app .ts-main #refreshThisData .fadeInDown { animation-name: ts-fade-in-place; }

/* ---- Issue / Service Request timeline (Areas/Issue/Views/View/_Comments|_CmmsStatus|_TimeSheetTracking,
   ul.timeline-alt) ----
   Restyle the Angle-theme timeline to match the redesign: rounded card entries, a token-coloured rail +
   date-separator pill, and soft-tinted status icon chips in place of the flat saturated circles. The
   pop-over speech-bubble arrow is dropped (redesign cards don't use it). CSS-only, scoped to .timeline-alt,
   adapts to both themes via tokens + color-mix. */
.ts-app .ts-main .timeline-alt:before { background: var(--line); }

/* entry content → redesign card */
.ts-app .ts-main .timeline-alt > li > .timeline-panel .popover {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: 12px;
    box-shadow: 0 1px 2px rgba(12,44,73,0.05);
    padding: 12px 16px;
    color: var(--text);
}
.ts-app .ts-main .timeline-alt .popover .arrow { display: none !important; }
.ts-app .ts-main .timeline-alt .popover .popover-title {
    background: transparent; border: 0; padding: 0 0 6px;
    color: var(--head); font-weight: 700; font-size: 14px;
}
.ts-app .ts-main .timeline-alt .popover .popover-content { padding: 0; color: var(--text); }

/* avatar badge → clean round image */
.ts-app .ts-main .timeline-alt > li > img.timeline-badge {
    border-radius: 50%; border: 2px solid var(--line);
    object-fit: cover; background: var(--card);
}

/* event icon badges → soft-tinted chips with a coloured glyph (matches the redesign icon tiles) */
.ts-app .ts-main .timeline-alt > li > div.timeline-badge {
    display: flex; align-items: center; justify-content: center;
    border: 1px solid var(--line); background: var(--inset); color: var(--muted);
    box-shadow: none;
}
.ts-app .ts-main .timeline-alt > li > div.timeline-badge em,
.ts-app .ts-main .timeline-alt > li > div.timeline-badge .fa { font-size: 15px; line-height: 1; }
.ts-app .ts-main .timeline-alt > li > div.timeline-badge.primary,
.ts-app .ts-main .timeline-alt > li > div.timeline-badge.info {
    background: var(--blue-soft); border-color: var(--blue-line); color: var(--blue);
}
.ts-app .ts-main .timeline-alt > li > div.timeline-badge.success,
.ts-app .ts-main .timeline-alt > li > div.timeline-badge.green {
    background: color-mix(in oklab, var(--green) 15%, var(--card));
    border-color: color-mix(in oklab, var(--green) 32%, var(--card)); color: var(--green);
}
.ts-app .ts-main .timeline-alt > li > div.timeline-badge.warning,
.ts-app .ts-main .timeline-alt > li > div.timeline-badge.yellow {
    background: color-mix(in oklab, var(--amber) 16%, var(--card));
    border-color: color-mix(in oklab, var(--amber) 34%, var(--card)); color: var(--amber);
}
.ts-app .ts-main .timeline-alt > li > div.timeline-badge.danger {
    background: color-mix(in oklab, var(--red) 14%, var(--card));
    border-color: color-mix(in oklab, var(--red) 32%, var(--card)); color: var(--red);
}

/* date separator → token pill */
.ts-app .ts-main .timeline-alt > li.timeline-separator:before {
    background: var(--inset); color: var(--muted);
    border: 1px solid var(--line); border-radius: 999px;
    font-size: 12px; font-weight: 600; line-height: 28px;
}

/* =====================================================================
   EVENTS PAGES RESKIN — CSS-only. The events home (banner, search,
   view toggles, event cards) keeps its Knockout/Kendo markup; these
   rules retheme it with the design tokens in both themes.
   ===================================================================== */

/* banner: events / facility / membership keep their own original background
   images (reverted from the brand-gradient treatment). Only the shared
   headline + flush placement remain, matching the membership banner. */
.ts-app .ts-main .md-welcome { margin: 0; }
.ts-app .ts-main .search-area-text { color: #fff; font-weight: 700; letter-spacing: -0.3px; }

/* booking search bars (facility / events / membership home): Bootstrap's
   .input-group renders the search field and the Submit/More buttons as one
   connected control, flush against each other. On the redesigned banners the
   field and buttons are individually rounded, so sitting edge-to-edge read as
   cramped. Lay the group out as a flex row with a gap between the field and the
   buttons, and give each its own rounded corners — same idiom as .pg-eventsearch. */
.ts-app .ts-main .md-welcome .input-group { display: flex; align-items: stretch; gap: 10px; }
.ts-app .ts-main .md-welcome .input-group > .form-control,
.ts-app .ts-main .md-welcome .input-group > .wrapper_ts_overlay { flex: 1 1 auto; min-width: 0; }
.ts-app .ts-main .md-welcome .input-group > .input-group-btn { width: auto; }
.ts-app .ts-main .md-welcome .input-group > .form-control,
.ts-app .ts-main .md-welcome .input-group .wrapper_ts_overlay .form-control,
.ts-app .ts-main .md-welcome .input-group .wrapper_ts_overlay .search_ts_overlay { border-radius: 9px; }
/* round the outer corners of the button group (single button rounds fully;
   the facility Submit + More pair rounds at the two outer ends only) */
.ts-app .ts-main .md-welcome .input-group-btn > .btn:first-child { border-top-left-radius: 9px; border-bottom-left-radius: 9px; }
.ts-app .ts-main .md-welcome .input-group-btn > .btn:last-child { border-top-right-radius: 9px; border-bottom-right-radius: 9px; }

/* view toggle buttons: segmented-control look on the tokens */
.ts-app .ts-main .btn.btn-default-custom {
    color: var(--head);
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: 9px;
    font-weight: 600;
    font-size: 13.5px;
}
.ts-app .ts-main .btn.btn-default-custom:hover { background: var(--inset); }
.ts-app .ts-main .btn.btn-primary-custom,
.ts-app .ts-main .btn.btn-default-custom.btn-primary-custom {
    background: var(--navy);
    border-color: var(--navy);
    color: #fff;
}
body.is-dark .ts-main .btn.btn-primary-custom,
body.is-dark .ts-main .btn.btn-default-custom.btn-primary-custom {
    background: var(--navy);
    border-color: var(--navy);
    color: #F2F7FB;
}

/* event cards intentionally untouched — the card image/colour is town-uploaded content */

/* ---- My Tickets (events/participant/courses) ---- */
/* the legacy theme paints .tab-content as a white panel — make it a plain
   transparent region so the cards inside provide the surfaces */
.pg-tickets .tab-content {
    background: transparent !important;
    border: 0 !important;
    box-shadow: none !important;
    padding: 18px 0 0 !important;
    margin: 0;
}
.pg-tickets .tab-content > .tab-pane { background: transparent; padding: 0; }
/* each event's ticket group is a distinct card */
.pg-tickets .tab-content .panel-group .panel,
.pg-tickets .tab-content .panel {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: 13px;
    box-shadow: 0 1px 2px rgba(12,44,73,0.04);
    overflow: hidden;
}
.pg-tickets .tab-content .panel-heading {
    background: var(--navy);
    border-bottom: 1px solid var(--navy);
    border-radius: 0;
}
.pg-tickets .tab-content .panel-heading .panel-title,
.ts-app .ts-main .pg-tickets .tab-content .panel-heading .panel-title a,
.ts-app .ts-main .pg-tickets .tab-content .panel-heading a {
    color: #fff;
    font-weight: 700;
    text-decoration: none;
}
body.is-dark .ts-main .pg-tickets .tab-content .panel-heading .panel-title a,
body.is-dark .ts-main .pg-tickets .tab-content .panel-heading a {
    color: #F2F7FB;
}
.ts-app .ts-main .pg-tickets .tab-content .panel-heading a:hover { opacity: 0.85; }
.pg-tickets .nav-tabs.pg-tabs { margin-bottom: 0; }

/* tabbed form card (e.g. edit sub account) */
.pg-formtabs .tab-content {
    background: transparent !important;
    border: 0 !important;
    box-shadow: none !important;
    padding: 18px 0 0 !important;
    margin: 0;
}
.pg-formtabs .tab-content > .tab-pane { background: transparent; }
.pg-formtabs-actions { display: flex; justify-content: flex-end; gap: 10px; flex-wrap: wrap; }
.ts-app .ts-main .k-textbox, .ts-app .ts-main input.k-textbox {
    border: 1px solid var(--line);
    border-radius: 9px;
    background: var(--card);
    color: var(--text);
    min-height: 40px;
    padding: 0 12px;
    font-family: inherit;
}
.ts-app .ts-main textarea.k-textbox { min-height: 100px; padding: 10px 12px; }
.ts-app .ts-main .k-textbox:focus { outline: none; border-color: var(--blue); box-shadow: 0 0 0 3px rgba(0,87,142,0.14); }
@media (max-width: 640px) {
  .pg-tickets .tab-content .panel-heading { padding: 11px 14px; }
  .pg-tickets .tab-content .panel-body { padding: 14px; }
}
/* purchased tickets: very light green hue (token green over the card surface,
   so it stays subtle in dark mode too) */
.ts-app .ts-main .genaralTicketing .table tr.success > td,
.ts-app .ts-main .tab-content .table > tbody > tr.success > td,
.ts-app .ts-main .tab-content .table tr.success > td {
    background: color-mix(in srgb, var(--green) 8%, var(--card)) !important;
    color: var(--text);
    border-color: color-mix(in srgb, var(--green) 16%, var(--card));
}
/* ticket accordion panels: proper card padding */
.pg-tickets .tab-content .panel { margin-bottom: 14px; }
.pg-tickets .tab-content .panel-group { margin-bottom: 0; }
.pg-tickets .tab-content .panel-heading { padding: 13px 20px; }
.pg-tickets .tab-content .panel-body { padding: 18px 20px; }
.pg-tickets .tab-content .panel-body .table { margin: 10px 0 0; }
.pg-tickets .tab-content .panel-body .table td { padding: 10px 12px; vertical-align: middle; }
.ts-app .ts-main .tab-content .table tr.blank-space > td {
    background: transparent !important;
    border: 0;
    padding: 4px;
    line-height: 4px;
}
.ts-app .ts-main .pg-tickets .btn-reset,
.ts-app .ts-main .btn.btn-reset {
    background: var(--card);
    border: 1px solid var(--line);
    color: var(--head);
    border-radius: 9px;
    font-weight: 600;
    margin-left: 10px;
}
.ts-app .ts-main .btn.btn-reset:hover { background: var(--inset); }
/* bigger search: wider group + taller field */
.ts-app .ts-main .pg-tickets .input-group.max-w-500 { max-width: 100%; width: 100%; }
.ts-app .ts-main .pg-tickets .input-group .k-autocomplete,
.ts-app .ts-main .pg-tickets .input-group #eventSeatch-autoComplete { border-radius: 9px; }
.ts-app .ts-main .pg-tickets .input-group .k-autocomplete .k-input-inner,
.ts-app .ts-main .pg-tickets .input-group #eventSeatch-autoComplete { min-height: 46px; font-size: 15px; }
.ts-app .ts-main .pg-tickets .input-group .input-group-btn { width: auto; }
.ts-app .ts-main .pg-tickets .btn-reset { min-height: 40px; padding: 0 20px; font-size: 14px; }

/* ---- service request filter bar + dropdown (/issue) ----
   Layout of the input-group + absolutely-positioned search overlay is left to
   servicerequest.css; we only restyle the Filters buttons' appearance and the
   dropdown menu (the part that was the ask). No flex/position changes here. */
.ts-app .ts-main .servicerequest-filter .input-group-btn .btn-default {
  background: var(--card); color: var(--head); font-weight: 600; font-size: 13.5px;
  height: 40px; display: inline-flex; align-items: center;
}
.ts-app .ts-main .servicerequest-filter .input-group-btn .btn-default:hover { background: var(--inset); }
/* match the search field height so the buttons sit inline with it */
.ts-app .ts-main .servicerequest-filter .wrapper_ts_overlay .form-control,
.ts-app .ts-main .servicerequest-filter #issue-search { height: 40px; }
.ts-app .ts-main .servicerequest-filter .input-group-btn .caret { color: var(--muted); }

/* ---- Manage Events search bar (Areas/Admin/Events) ----
   Default input-group left the Filters dropdown and search button shorter than
   the redesigned .form-control, so the boxes looked different sizes. Lay the
   Filters group, search input and search button out as one equal-height row
   with flush inner edges and rounded outer corners (one cohesive control). */
.ts-app .ts-main .pg-eventsearch { display: flex; align-items: stretch; width: 100%; }
.ts-app .ts-main .pg-eventsearch > .input-group-btn { display: flex; width: auto; }
.ts-app .ts-main .pg-eventsearch .form-control { flex: 1; min-width: 0; height: 40px; border-radius: 0; }
.ts-app .ts-main .pg-eventsearch .btn { height: 40px; margin: 0; border-radius: 0; display: inline-flex; align-items: center; }
.ts-app .ts-main .pg-eventsearch > .input-group-btn:first-child .btn:first-child { border-top-left-radius: 9px; border-bottom-left-radius: 9px; }
.ts-app .ts-main .pg-eventsearch > .input-group-btn:last-child .btn:last-child { border-top-right-radius: 9px; border-bottom-right-radius: 9px; }

/* ---- Facility System Configuration (Areas/Admin/FacilitySysConfig/Setup) ----
   Tidy the legacy "numbered block" settings form: clean section headers (round
   number chip + heading + divider, left-aligned instead of the odd g-cell
   offset/centering), consistent label/control rhythm, real fieldset legends and
   dividers. CSS-only + scoped to #setupContainer so the form's ids / data-bind /
   Kendo widgets / required hooks are untouched. */
body.ts-app .ts-main #setupContainer .pg-card { padding: 20px 24px; }
/* Inner padding for every section card. Was padding:0, which (a) let the numbered
   header sit flush against the card's top edge (the 28px chip then clipped on the
   border) and (b) let labels / inputs / grids touch the left & right edges. Pad all
   four sides equally (24px, matching the .pg-card padding used elsewhere) so the
   content sits the same comfortable distance from every edge. */
body.ts-app .ts-main #setupContainer .panel-body { padding: 24px; }

/* numbered section headers */
body.ts-app .ts-main #setupContainer .number-block { margin: 0 0 14px; }
/* Centre the round number chip against its title (progressive enhancement — the
   panel-body top padding above is what actually un-clips the header; this just
   tidies vertical alignment where :has() is supported). */
body.ts-app .ts-main #setupContainer div:has(> .ico-box) {
  display: flex; align-items: center;
}
body.ts-app .ts-main #setupContainer .number-block .g-cell {
  width: auto; max-width: none; margin: 0; padding: 0; float: none; left: 0;
}
body.ts-app .ts-main #setupContainer .box-center { display: block; }
body.ts-app .ts-main #setupContainer .box-center-row {
  display: flex; align-items: center; gap: 11px;
  padding-bottom: 10px; border-bottom: 1px solid var(--line);
}
body.ts-app .ts-main #setupContainer .ico-box {
  flex: none; width: 28px; height: 28px; border-radius: 50%;
  background: var(--blue-soft); color: var(--blue);
  display: inline-grid; place-items: center; vertical-align: middle;
  font-weight: 700; font-size: 13px; line-height: 1; padding: 0; margin: 0 8px 0 0;
}
body.ts-app .ts-main #setupContainer .text-large {
  /* facility/subfacilitysetup.css sets .text-large { display: table-cell; line-height: 35px }.
     We override font/colour above but NOT display/line-height, so those leaked: the table-cell
     title dropped onto its own line below the chip and the 35px line collided with the
     .line-break hr, clipping the heading. Pin display/line-height so the chip + title sit
     inline and the divider clears them. */
  display: inline-block; line-height: 1.2;
  font-size: 15.5px; font-weight: 700; color: var(--head); letter-spacing: -0.2px; padding: 0; margin: 0;
  vertical-align: middle;
}

/* label / control rhythm + alignment */
body.ts-app .ts-main #setupContainer .label-format,
body.ts-app .ts-main #setupContainer label.control-label {
  display: inline-block; color: var(--text); font-weight: 600; padding-top: 7px; margin-bottom: 0;
}
body.ts-app .ts-main #setupContainer .form-group > .row,
body.ts-app .ts-main #setupContainer form > .row,
body.ts-app .ts-main #setupContainer fieldset .row { margin-bottom: 12px; }
body.ts-app .ts-main #setupContainer .w-100 { width: 100%; }

/* fieldset legends as clean sub-headings.
   A native <legend> straddles the fieldset's top-border gap, so on the facility
   Setup form (which shares this #setupContainer hook) the section labels —
   "Locker Room Setup", "Payments Settings", etc. — sat on top of / overlapped
   the content below them. Floating the legend (width:100%) drops that special
   rendering and makes it a normal block heading; the next element clears it.
   Same fix already used for .pg-smtp legends below. */
body.ts-app .ts-main #setupContainer fieldset > legend {
  float: left; width: 100%;
  font-size: 14px; font-weight: 700; color: var(--head);
  border: 0; border-bottom: 1px solid var(--line); padding-bottom: 8px; margin: 20px 0 14px;
}
body.ts-app .ts-main #setupContainer fieldset > legend + * { clear: both; }

/* dividers + save button */
/* The Angle theme ships `.line-break { margin-top: -21px }` (app.css) and this form
   wraps every section divider in <div class="line-break">. That -21px hauls the
   divider — and the grid/content below it — UP into the header row, so the hr sliced
   straight through each title (the real "smushed header" cause, in every section).
   Cancel it here so the divider sits below the header where it belongs. */
body.ts-app .ts-main #setupContainer .line-break { margin-top: 0; }
body.ts-app .ts-main #setupContainer .line-break hr { border-top: 1px solid var(--line); margin: 6px 0 0; }
body.ts-app .ts-main #setupContainer .btn[data-role="msave"] { border-radius: 11px; }

/* ---- Issue / Complaints Configurations (Areas/Admin/Issue/Configurations) ----
   Body was unstyled rows on the page background with raw h3/h4 headings and
   unstyled user-assignment boxes. Sectioned into pg-cards in the view; this
   styles the headings, labels, recipient boxes and the column separator.
   Scoped to .pg-issueconfig. */
body.ts-app .ts-main .pg-issueconfig .pg-card { padding: 20px 24px; margin-bottom: 18px; }
body.ts-app .ts-main .pg-issueconfig h3 {
  font-size: 16px; font-weight: 700; color: var(--head); letter-spacing: -0.2px;
  margin: 0 0 16px; padding-bottom: 10px; border-bottom: 1px solid var(--line);
}
body.ts-app .ts-main .pg-issueconfig h4 { font-size: 14px; font-weight: 700; color: var(--head); margin: 0 0 10px; }
body.ts-app .ts-main .pg-issueconfig label { color: var(--text); font-weight: 600; }
body.ts-app .ts-main .pg-issueconfig .user-lbl {
  display: block; margin-bottom: 8px; color: var(--muted); font-weight: 600; font-size: 12.5px;
}
body.ts-app .ts-main .pg-issueconfig .user-section {
  border: 1px solid var(--line); border-radius: 10px; background: var(--inset);
  min-height: 220px; max-height: 340px; overflow-y: auto; padding: 8px;
}
body.ts-app .ts-main .pg-issueconfig .UserAssigntemplateCSS {
  background: var(--card); border: 1px solid var(--line); border-radius: 8px;
  padding: 8px 11px; margin-bottom: 8px; cursor: grab;
}
body.ts-app .ts-main .pg-issueconfig .UserAssigntemplateCSS p { margin: 0; font-size: 12.5px; color: var(--text); }
body.ts-app .ts-main .pg-issueconfig .UserAssigntemplateCSS strong { color: var(--head); }
/* vertical divider between the two notification columns; becomes horizontal on stack */
body.ts-app .ts-main .pg-issueconfig .separator-left { border-left: 1px solid var(--line); }
@media (max-width: 991px) {
  body.ts-app .ts-main .pg-issueconfig .separator-left {
    border-left: 0; border-top: 1px solid var(--line); margin-top: 18px; padding-top: 18px;
  }
}

/* ---- Staff employee-member lists (Areas/Admin/Staff Index "edit employees"
   + DepartmentAssignStaff "assign employees") ----
   The Kendo .k-block list items were content-box sized, so their padding/border
   added on top of width:100% and the items overflowed (right edge clipped) their
   column. border-box + full width makes them fit; also gives them a clean,
   consistent card look on both pages. */
body.ts-app .ts-main .move.k-block {
  box-sizing: border-box;
  width: 100%;
  max-width: 100%;
  margin: 0 0 6px;
  padding: 7px 11px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--card);
  color: var(--text);
  line-height: 1.35;
  cursor: move;
}
/* keep the normal pointer on the action buttons in the right-hand list */
body.ts-app .ts-main .move.k-block .btn { cursor: pointer; }
body.ts-app .ts-main .move.k-block b { color: var(--head); }
body.ts-app .ts-main .move.k-block .user-details { color: var(--muted); font-size: 12px; word-break: break-word; }
/* the listview wrappers shouldn't add a border/padding that eats into the items */
body.ts-app .ts-main #allStaff_listview .k-listview,
body.ts-app .ts-main #selectedStaff_listview .k-listview,
body.ts-app .ts-main #allusers_listview .k-listview,
body.ts-app .ts-main #selectedusers_listview .k-listview {
  border: 0; padding: 0; background: transparent;
}

/* ---- Admin SMTP + SMS settings (Areas/Admin/Smtp + Areas/Admin/SMS) ----
   Both share the same tabbed fieldset/legend form (.pg-smtp hook). Card each
   fieldset, turn legends into section titles, and normalise label/field styling
   (several fields use a plain `w-100` input and missed the redesign field look). */
/* the tab container carries `tab-content wrapper p pg-formtabs` all on one
   element, so the descendant `.pg-formtabs .tab-content` rule never matches and
   the legacy `.wrapper` panel (straight edges) shows behind the rounded cards.
   Flatten it here so the cards sit on the page background like other pages. */
body.ts-app .ts-main .pg-smtp .tab-content {
  background: transparent !important; border: 0 !important; box-shadow: none !important;
  padding: 0 !important; margin: 0;
}
body.ts-app .ts-main .pg-smtp fieldset {
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
  padding: 16px 20px 20px; margin: 0 0 16px;
}
/* A <legend> normally renders in the fieldset's top-border gap, so it sat on /
   above the rounded card edge. Floating it (width:100%) drops the special
   rendering and makes it a normal heading inside the card padding; the content
   below clears it. */
body.ts-app .ts-main .pg-smtp fieldset > legend {
  float: left; width: 100%;
  font-size: 14px; font-weight: 700; color: var(--head);
  border: 0; margin: 0 0 14px; padding: 0;
}
body.ts-app .ts-main .pg-smtp fieldset > legend + * { clear: both; }
/* Bootstrap rows carry -15px side margins; inside the carded fieldset that
   pushed labels/fields out past the rounded edge. Zero them so content stays
   within the card padding. */
body.ts-app .ts-main .pg-smtp fieldset .row { margin-left: 0; margin-right: 0; }
body.ts-app .ts-main .pg-smtp label {
  color: var(--text); font-weight: 600; padding-top: 7px; margin-bottom: 0;
}
body.ts-app .ts-main .pg-smtp .row.mt { margin-bottom: 4px; }
body.ts-app .ts-main .pg-smtp input[type="text"],
body.ts-app .ts-main .pg-smtp input[type="email"],
body.ts-app .ts-main .pg-smtp input[type="password"],
body.ts-app .ts-main .pg-smtp input[type="number"] {
  width: 100%; min-height: 38px; padding: 6px 11px;
  border: 1px solid var(--line); border-radius: 9px;
  background: var(--card); color: var(--text);
}
body.ts-app .ts-main .pg-smtp input:focus {
  outline: none; border-color: var(--blue); box-shadow: 0 0 0 3px rgba(0,87,142,0.14);
}

/* ---- Municipal Info (Areas/Admin/Town) ----
   Same one-element `tab-content wrapper pg-formtabs` quirk as the SMTP page, so
   the descendant flatten rule misses it and the legacy `.wrapper` square panel
   shows. Flatten that, then make each tab panel a rounded card like the rest. */
body.ts-app .ts-main .pg-municipal .tab-content {
  background: transparent !important; border: 0 !important; box-shadow: none !important;
  padding: 0 !important; margin: 0;
}
body.ts-app .ts-main .pg-municipal .tab-content > .tab-pane {
  background: var(--card); border: 1px solid var(--line); border-radius: 13px;
  padding: 22px 24px; box-shadow: 0 1px 2px rgba(12,44,73,0.04);
}
/* Images tab: each field used to be its own nested .panel.panel-default —
   a bordered/shadowed box inside the already-bordered .tab-pane card above,
   so every field showed a redundant pair of border lines where its box met
   the next one's. A plain bottom divider (removed on the last row) groups
   the fields without the doubled outline. */
body.ts-app .ts-main .pg-municipal .pg-imagerow {
  padding-bottom: 20px; margin-bottom: 20px; border-bottom: 1px solid var(--line);
}
body.ts-app .ts-main .pg-municipal .pg-imagerow.pg-imagerow-last {
  padding-bottom: 0; margin-bottom: 0; border-bottom: 0;
}

/* ---- Edit/Assign Employees filter selectors (Areas/Admin/Staff) ----
   First Name / Last Name / Email / User ID are a .btn-group of .filterbtn
   buttons — one choice out of four, which is what a segmented control is for.
   Matches the .pg-tabs treatment above so the two read as one component;
   see that block for why the track colour is mixed rather than plain --inset.

   Everything here fights a bootstrap rule, hence the !important run: .btn-block
   forces display:block/width:100%, .btn-group floats its children and strips
   the radius off the middle ones, .btn-default paints its own active fill, and
   the markup in DepartmentAssignStaff.cshtml puts w-25 on each button. */
body.ts-app .ts-main .pg-filtertabs {
  display: inline-flex !important; vertical-align: top; flex-wrap: wrap; gap: 2px;
  width: auto !important; max-width: 100%; margin-bottom: 14px; padding: 3px;
  background: color-mix(in oklab, var(--line) 40%, var(--inset));
  border: 1px solid var(--line); border-radius: 12px; box-shadow: none;
}
body.ts-app .ts-main .pg-filtertabs .filterbtn {
  display: inline-flex !important; align-items: center; width: auto !important; flex: 0 0 auto;
  border: 1px solid transparent !important; border-radius: 9px !important;
  background: transparent !important; color: var(--text) !important;
  font-weight: 600; font-size: 13.5px; line-height: 1.3;
  padding: 7px 15px !important; margin: 0 !important; box-shadow: none !important;
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}
body.ts-app .ts-main .pg-filtertabs .filterbtn:hover {
  background: color-mix(in oklab, var(--card) 62%, transparent) !important; color: var(--head) !important;
}
/* as with .pg-tabs, the !important beats app.css's blanket
   `:focus{outline:0!important}` — and .btn carries its own `outline:0!important`
   on top of that, so these buttons are doubly stripped without it. */
body.ts-app .ts-main .pg-filtertabs .filterbtn:focus-visible {
  outline: 2px solid var(--blue) !important; outline-offset: 1px;
}
body.ts-app .ts-main .pg-filtertabs .filterbtn.active {
  background: var(--card) !important; border-color: var(--line) !important;
  color: var(--navy) !important; font-weight: 700;
  box-shadow: 0 1px 2px rgba(19,33,45,0.09) !important;
}
/* dark mode: same inversion as .pg-tabs — no fill can separate the chip from
   the track, so the outline carries the selected state (3.34:1). */
body.is-dark.ts-app .ts-main .pg-filtertabs .filterbtn.active {
  background: color-mix(in oklab, #00578E 30%, #0D2032) !important;
  border-color: color-mix(in oklab, var(--blue) 75%, var(--card)) !important;
  color: #DCEBF6 !important; box-shadow: none !important;
}

/* ---- Cancellation Policy setup (Areas/Admin/CancellationPolicy/Setup) ----
   Content sits in pg-card sections (the legacy .panel didn't render as a card
   here). Spacing + the Kendo editor and labels are styled below. */
body.ts-app .ts-main .pg-cancelsetup .pg-card { margin-bottom: 16px; }
/* Clean, self-contained section headers (number badge + title) — deliberately
   NOT using the legacy .ico-box/.text-large/.number-block classes, which carry
   display:table-cell + big line-heights from the old wizard layout and were
   rendering into the card. */
body.ts-app .ts-main .pg-cancelsetup .pg-formsection {
  display: flex; align-items: center; gap: 10px; margin: 22px 0 12px;
}
body.ts-app .ts-main .pg-cancelsetup .pg-formsection-num {
  flex: none; width: 26px; height: 26px; border-radius: 50%;
  background: var(--blue-soft); color: var(--blue);
  display: grid; place-items: center; font-weight: 700; font-size: 13px; line-height: 1;
}
body.ts-app .ts-main .pg-cancelsetup .pg-formsection-title {
  margin: 0; font-size: 15.5px; font-weight: 700; color: var(--head); letter-spacing: -0.2px; line-height: 1.3;
}
/* Description is turned into a Kendo rich-text editor at runtime
   ($(".ui-text-area").kendoEditor) — style the editor, not the hidden textarea. */
body.ts-app .ts-main .pg-cancelsetup .k-editor {
  border: 1px solid var(--line); border-radius: 9px; overflow: hidden; background: var(--card);
}
body.ts-app .ts-main .pg-cancelsetup .k-editor .k-toolbar,
body.ts-app .ts-main .pg-cancelsetup .k-editor .k-editor-toolbar {
  background: var(--inset); border-color: var(--line);
}
body.ts-app .ts-main .pg-cancelsetup .k-editor .k-editor-content { background: var(--card); }
body.ts-app:not(.is-dark) .ts-main .pg-cancelsetup .k-editor iframe { background: var(--card); }
body.ts-app .ts-main .pg-cancelsetup .form-group label,
body.ts-app .ts-main .pg-cancelsetup label[for] { color: var(--text); font-weight: 600; }

/* ---- Service request "fill out" form (Areas/Issue/Views/New/_Yourself …) ----
   Style the Kendo body editor and soften the orange "allowed file types" bar
   into a subtle info note that matches the redesign. */
body.ts-app .ts-main .pg-srform .k-editor { border: 1px solid var(--line); border-radius: 9px; overflow: hidden; }
body.ts-app .ts-main .pg-srform .k-editor .k-toolbar,
body.ts-app .ts-main .pg-srform .k-editor .k-editor-toolbar { background: var(--inset); border-color: var(--line); }
body.ts-app .ts-main .pg-srform .alert-warning {
  background: var(--blue-soft); border: 1px solid var(--blue-line); color: var(--text);
  border-radius: 9px; font-size: 12.5px; padding: 9px 12px;
}
body.ts-app .ts-main .pg-srform .alert-warning p { margin: 0; }

/* FAQ side panel: the faqtemplate renders .panel.widget items with an indigo
   background — restyle them into clean, left-aligned list items inside the card. */
body.ts-app .ts-main .pg-faqpanel .panel.widget { box-shadow: none; border: 0; margin: 0 0 8px; background: transparent; }
body.ts-app .ts-main .pg-faqpanel .panel.widget .panel-body {
  background: var(--inset) !important; color: var(--head);
  border: 1px solid var(--line); border-radius: 10px; text-align: left; padding: 10px 12px;
}
body.ts-app .ts-main .pg-faqpanel .panel.widget .text-white { color: var(--blue) !important; margin-top: 4px; font-weight: 600; }

/* ---- Role access (Areas/Admin/Security/RolesAccess) ----
   A Kendo PanelBar of permission rows with On/Off toggle buttons. Tidy the
   toolbar and soften the tree to match the redesign. */
body.ts-app .ts-main .pg-roleaccess .pg-roleaccess-toolbar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 4px;
}
body.ts-app .ts-main .pg-roleaccess .pg-roleaccess-toolbar .pg-roleaccess-btns { margin-left: auto; display: flex; gap: 8px; }
body.ts-app .ts-main .pg-roleaccess #TextRoleList { min-width: 280px; }
/* the injected panelbar tree */
body.ts-app .ts-main .role-access-controls #organizer,
body.ts-app .ts-main .role-access-controls .k-panelbar { border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
body.ts-app .ts-main .role-access-controls .k-panelbar > .k-item > .k-link { background: var(--inset); color: var(--head); font-weight: 700; }
body.ts-app .ts-main .role-access-controls li > strong,
body.ts-app .ts-main .role-access-controls li > a > strong,
body.ts-app .ts-main .role-access-controls li > a > dfn { color: var(--head); font-style: normal; }
body.ts-app .ts-main .role-access-controls li > a { display: flex; align-items: center; padding: 8px 12px !important; }
/* the generated markup adds trailing <br><br> after the button group; in a flex
   row those steal the right edge — drop them and push the toggle group right. */
body.ts-app .ts-main .role-access-controls li > a br { display: none; }
body.ts-app .ts-main .role-access-controls li > a .btn-group { margin-left: auto; float: none !important; }
/* On / Off toggle buttons inside the tree — shape/size only; leave their
   on/off colours to the existing b1/b0 classes + roleaccess.js toggle state. */
body.ts-app .ts-main .role-access-controls .btn-group .btn { border-radius: 7px !important; height: 30px; padding: 0 12px; font-size: 12.5px; font-weight: 600; margin: 0 0 0 6px; float: none !important; }
/* Dark theme: the inactive side of a Yes/No or On/Off toggle-button pair
   (roleaccess.js, Roles grid editor, Event Categories, ...) ends up as an
   input with no colour class of its own — some pages mark it with the b0/b1
   convention, others (Event Categories' Archive/Request toggles) strip down
   to a bare .btn — so either way it falls back to the dark bundle's generic
   `input { background-color: var(--main-border-color) }`, only 4.45:1
   against the theme's forced light-gray .btn text (theme-dark.css
   `.btn { color: ... !important }`). Target by value rather than by class so
   every inactive Yes/No/On/Off toggle is covered regardless of which classes
   a given page's JS leaves on it. */
body.is-dark input.btn[value="Yes"]:not(.btn-success),
body.is-dark input.btn[value="On"]:not(.btn-success),
body.is-dark input.btn[value="No"]:not(.btn-danger),
body.is-dark input.btn[value="Off"]:not(.btn-danger) { background: var(--inset); }

/* Dark theme: theme-dark.css forces every Kendo picker/dropdown (grid pager
   page-size and page-number pickers, dropdownlists, comboboxes, ...) to
   `background-color: var(--main-border-color) !important`, paired with that
   same stylesheet's muted --main-txt-color — only 3.42:1, failing WCAG AA.
   Site-wide, since every Kendo grid has a pager. Override with the --card
   token already used for k-picker form controls, matching !important since
   that's the only way to actually win the cascade against theme-dark.css. */
body.is-dark .k-picker, body.is-dark .k-picker-solid { background-color: var(--card); border-color: transparent; }
body.is-dark .k-picker:hover, body.is-dark .k-picker-solid:hover { border-color: transparent; }
body.is-dark .k-color-preview-mask::before { background-color: var(--inset) !important; }

/* Dark theme: theme-dark.css also sets `.k-listview { background-color:
   var(--main-bg-color) }` — a slate gray that only gives 4.38:1 against the
   app's --muted small/caption text (e.g. the Facility Dashboard's "Top 5
   Facilities" list). Bring it in line with the same --card panel background
   used everywhere else. */
body.is-dark .k-listview { background-color: var(--card); }

/* Facility Dashboard "Facilities" list (Areas/Admin/Facility/FacilityDashboard).
   That ListView is data-selectable, and theme-light.css (vendor, under
   assets/externals — do not edit) paints any selected element with
     .k-selected { color: var(--text-white) !important;
                   background-color: var(--primary-color) !important }
   so a clicked row is filled solid #0077bf. Only the row's own inherited text
   turns white with it — everything that carries its own colour keeps it and
   lands on the blue fill: the category/location captions (var(--muted), 1.16:1),
   the Book/Edit links (var(--blue), 1.59:1) and the status badge. Nothing reads
   the selection either (facilitydashboard.ts has no change handler), so the
   fill is pure decoration at the cost of the whole row's contrast.
   Use the redesign's own selected-row treatment instead (same as
   .rq-ib-row.is-active): a --blue-soft surface with a left marker, which keeps
   the row visibly selected while every colour inside it stays at the contrast
   it was designed for — muted 4.74:1, links 6.51:1 in light; 4.95:1 / higher in
   dark. !important is required to beat the vendor rule above. */
body.ts-app .ts-main #facilityDataListView .k-listview-content > .k-selected {
    color: inherit !important;
    background-color: var(--blue-soft) !important;
    border-color: var(--blue-line) !important;
    box-shadow: inset 3px 0 0 var(--blue);
}
/* the status badge is itself a --blue-soft chip, so on the tinted row it would
   lose its chip shape — put it back on the panel surface. */
body.ts-app .ts-main #facilityDataListView .k-listview-content > .k-selected .badge {
    background: var(--card);
}

/* ---- Complaints dashboard (Areas/Admin/Issue/Dashboard) ----
   Soften the bright green widget card headers, and slim the bulky stat tabs. */
body.ts-app .ts-main .pg-issuedash .card-heading.bg-green {
  background: transparent !important; border-bottom: 1px solid var(--line);
  display: flex; align-items: center; gap: 10px; padding: 13px 16px;
}
body.ts-app .ts-main .pg-issuedash .card-heading .card-icon {
  width: 30px; height: 30px; border-radius: 8px; flex: none;
  background: var(--blue-soft); color: var(--blue); display: grid; place-items: center; font-size: 14px;
}
body.ts-app .ts-main .pg-issuedash .card-heading .card-title { color: var(--head); font-weight: 700; margin: 0; }
body.ts-app .ts-main .pg-issuedash .card-footer { border-top: 1px solid var(--line-soft); }
/* the stat-tabs card used to be wrapped in a bootstrap .panel, whose
   margin-bottom:20px separated it from the widget cards below — removing
   that wrapper dropped the gap too, so restore it directly on the card. */
.ts-app .pg-formtabs { margin-bottom: 24px; }
/* stat tabs (Ticket stats / Satisfaction rate / Opened / Reports) — plain
   underline tabs instead of bootstrap's boxed nav-tabs, since bootstrap's
   nav-tabs/nav-justified fought the two-line title+subtitle content and the
   sitewide .pg-tabs segmented style (built for single-line labels). Functionality
   (tabactive.js) only depends on .showSingle/target/.targetDiv — none of
   which this touches. */
.ts-app .pg-stattabs { display: flex; margin: 0 0 4px; padding: 0 8px; list-style: none; border-bottom: 1px solid var(--line); }
.ts-app .pg-stattabs > li { flex: 1; min-width: 0; text-align: center; }
.ts-app .pg-stattabs > li > a {
  display: block; padding: 14px 12px; margin-bottom: -1px; text-decoration: none; cursor: pointer;
  border-bottom: 2px solid transparent;
}
.ts-app .pg-stattabs > li > a:hover { background: var(--inset); text-decoration: none; }
.ts-app .pg-stattabs > li > a h4 { font-size: 13.5px; font-weight: 700; color: var(--head); margin: 0 0 2px; }
.ts-app .pg-stattabs > li > a small { font-size: 11.5px; color: var(--muted); display: block; }

/* "Reports" tab — was a bare <p> + button */
.ts-app .pg-reportsnote { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 14px; padding: 40px 20px; }
.ts-app .pg-reportsnote-icon {
  width: 44px; height: 44px; border-radius: 12px; flex: none;
  background: var(--blue-soft); color: var(--blue); display: grid; place-items: center; font-size: 18px;
}
.ts-app .pg-reportsnote-text { font-size: 13.5px; color: var(--muted); max-width: 380px; margin: 0; }
.ts-app .pg-stattabs > li.active > a { border-bottom-color: var(--blue); }
.ts-app .pg-stattabs > li.active > a h4 { color: var(--blue); }

/* ---- Kanban dashboard (Areas/Admin/Kanban/Dashboard) ----
   The "Resources Utilization" panel is `.panel-primary`, whose heading the
   redesign tints blue-soft — but its `.card-title`/`small` keep the legacy
   theme's near-white colour (meant for the old dark-blue header), so the text
   was invisible on the light tint. Give this panel a clean neutral header with
   dark, readable text. */
/* !important is required: the legacy theme sets
   `.panel-primary>.panel-heading{background-color:#1976d2!important}`, so
   without it the header stayed vendor blue while the rules below darkened its
   text — leaving dark-on-blue at 3.56:1, i.e. this fix made the contrast worse
   rather than better. With the neutral background actually applied, the title
   and description clear AA comfortably. */
body.ts-app .ts-main .pg-kanbandash .panel-primary > .panel-heading {
  background: var(--inset) !important; border-color: var(--line);
}
body.ts-app .ts-main .pg-kanbandash .panel-heading,
body.ts-app .ts-main .pg-kanbandash .panel-heading .card-title,
body.ts-app .ts-main .pg-kanbandash .panel-heading strong {
  color: var(--head);
}
body.ts-app .ts-main .pg-kanbandash .panel-heading small { color: var(--muted); }

/* ---- Custom theme editor (Areas/Admin/CustomTheme) ----
   Bare textarea + loose buttons + raw code snippets; carded in the view, styled
   here: the CSS editor as a monospace field, the example snippets as inset code
   blocks, and a tidy button row. */
body.ts-app .ts-main .pg-customtheme #cssThemeEditor {
  width: 100%; padding: 12px 14px; resize: vertical;
  border: 1px solid var(--line); border-radius: 9px;
  background: var(--inset); color: var(--text);
  font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 13px; line-height: 1.5;
}
body.ts-app .ts-main .pg-customtheme #cssThemeEditor:focus {
  outline: none; border-color: var(--blue); box-shadow: 0 0 0 3px rgba(0,87,142,0.14);
}
body.ts-app .ts-main .pg-customtheme .checkbox { margin: 14px 0; }
body.ts-app .ts-main .pg-customtheme pre {
  background: var(--inset); border: 1px solid var(--line); border-radius: 8px;
  padding: 10px 12px; margin: 0 0 12px; overflow: auto;
}
body.ts-app .ts-main .pg-customtheme pre code {
  background: transparent; color: var(--text); padding: 0;
  font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12px;
}

/* ---- Mapping layers (Areas/Mapping/Layers/Admin) ----
   Plain bootstrap tabs + bare tab panes; round the panels like the rest. */
body.ts-app .ts-main .pg-maplayers .tab-content {
  background: transparent; border: 0; box-shadow: none; padding: 0; margin: 0;
}
body.ts-app .ts-main .pg-maplayers .tab-content > .tab-pane {
  background: var(--card); border: 1px solid var(--line); border-radius: 13px;
  padding: 22px 24px; box-shadow: 0 1px 2px rgba(12,44,73,0.04);
}

/* ---- Create User Account (Areas/Admin/AddAccount) ----
   The tab panel is a pg-card. Rather than fight Bootstrap's row(-15)/col(+15)
   margins (which cancel out so every nesting level aligns at the container's
   padding edge), just give the card more horizontal padding — content then sits
   comfortably inset AND stays aligned across headings, fields, nested rows and
   the Linked Account list boxes. */
body.ts-app .ts-main #x1.tab-content { padding: 22px 36px; }
/* syntax-highlight search overlay: the highlight div (text_ts_overlay, behind)
   and the semi-transparent input (search_ts_overlay, on top) never register
   perfectly under the redesign font, so the query text doubles. Hide the
   highlight layer's text/background and show a single clean opaque input. */
.ts-app .ts-main .servicerequest-filter .wrapper_ts_overlay .text_ts_overlay,
.ts-app .ts-main .servicerequest-filter .wrapper_ts_overlay .text_ts_overlay * {
  color: transparent !important; background: transparent !important;
}
.ts-app .ts-main .servicerequest-filter .wrapper_ts_overlay .text_ts_overlay { height: 40px; }
.ts-app .ts-main .servicerequest-filter .wrapper_ts_overlay .search_ts_overlay {
  opacity: 1 !important; color: var(--text) !important; height: 40px;
  left: 0; top: 0; width: 100%; padding: 0 12px; box-sizing: border-box;
}
/* the dropdown menu itself: proper token card */
.ts-app .ts-main .servicerequest-filter .dropdown-menu {
  background: var(--card); border: 1px solid var(--line); border-radius: 11px;
  box-shadow: 0 18px 50px rgba(12,44,73,0.18); padding: 6px; margin-top: 6px; min-width: 230px;
}
.ts-app .ts-main .servicerequest-filter .dropdown-menu > li > a {
  display: block; padding: 8px 12px; border-radius: 8px; color: var(--text);
  font-size: 13.5px; font-weight: 500; line-height: 1.3;
}
.ts-app .ts-main .servicerequest-filter .dropdown-menu > li > a:hover,
.ts-app .ts-main .servicerequest-filter .dropdown-menu > li > a:focus { background: var(--inset); color: var(--head); }
.ts-app .ts-main .servicerequest-filter .dropdown-menu .divider { height: 1px; background: var(--line-soft); margin: 6px 4px; }
/* filter action row (spinner + save query + grid/list view) aligned right */
.ts-app .ts-main .servicerequest-filter .row.mb-lg { display: flex; flex-wrap: wrap; align-items: center; margin-top: 12px; }
.ts-app .ts-main .servicerequest-filter .row.mb-lg .pull-right { float: none !important; }
.ts-app .ts-main .servicerequest-filter .row.mb-lg .col-md-6:last-child { margin-left: auto; display: flex; gap: 8px; justify-content: flex-end; align-items: center; flex: 1; }

/* ---- facility card overlay: rate / capacity / full-sub badge tweak ----
   scoped to the facility listing so events cards are untouched. The overlay
   becomes a clean glassy info panel; rates become readable pills. */
.ts-app .ts-main .pg-facility-results .card.viewevent .card-item { position: relative; }
.ts-app .ts-main .pg-facility-results .card.viewevent .card-label {
    background: rgba(8, 22, 36, 0.62);
    -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
    color: #fff; border-radius: 11px; padding: 9px 12px; top: 12px; right: 12px; left: auto;
    font-size: 12.5px; line-height: 1.5; box-shadow: 0 4px 14px rgba(0,0,0,0.22);
    display: flex; flex-direction: column; gap: 2px;
}
.ts-app .ts-main .pg-facility-results .card.viewevent .card-label > div {
    display: flex; align-items: center; justify-content: space-between; gap: 10px; white-space: nowrap;
}
.ts-app .ts-main .pg-facility-results .card.viewevent .card-label > div > span:first-child { opacity: 0.85; font-weight: 500; }
.ts-app .ts-main .pg-facility-results .card.viewevent .card-label .badge.bg-info {
    background: rgba(255,255,255,0.18); color: #fff; border-radius: 999px;
    font-size: 12px !important; font-weight: 700; padding: 2px 9px;
}
/* description tooltip pill, top-left */
.ts-app .ts-main .pg-facility-results .card.viewevent .facility-dec {
    top: 12px; left: 12px; background: rgba(8,22,36,0.62); color: #fff; border-radius: 8px;
    -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); box-shadow: 0 4px 14px rgba(0,0,0,0.22);
}
/* facility type pill: top-right is already the rate/capacity panel and
   top-left is the description tooltip, so this sits bottom-right instead */
.ts-app .ts-main .pg-facility-results .card.viewevent .evc-catpill {
    top: auto; bottom: 10px; right: 10px;
    background: rgba(8,22,36,0.62); color: #fff;
    -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
}
/* full / sub facility chips along the bottom of the image */
.ts-app .ts-main .pg-facility-results .card.viewevent .facility-type {
    position: absolute; bottom: 10px; left: 10px; margin: 0;
    display: inline-flex; align-items: center; gap: 6px;
    background: rgba(8,22,36,0.62); color: #fff; border-radius: 999px; padding: 3px 11px;
    -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
}
.ts-app .ts-main .pg-facility-results .card.viewevent .facility-type small { color: #fff; }
.ts-app .ts-main .pg-facility-results .card.viewevent .facility-type .subfacility-icon { width: 16px; height: 16px; }
/* facility card body runs tighter to the edge than events/membership since
   the address/type text is longer here; a bit more breathing room on the
   price + View row without widening the other two card types */
.ts-app .ts-main .pg-facility-results .card.viewevent .evc-body { padding: 14px 18px 18px; }

/* ---- facility "Your Reservations" cards + filter dropdown ---- */
.ts-app .ts-main .reservation-list .reservation-card .card {
    background: var(--card); border: 1px solid var(--line); border-radius: 13px;
    box-shadow: 0 1px 2px rgba(12,44,73,0.05); overflow: hidden; height: 100%;
    transition: border-color .12s ease, box-shadow .12s ease;
}
.ts-app .ts-main .reservation-list .reservation-card .card:hover { border-color: var(--blue-line); box-shadow: 0 6px 18px rgba(12,44,73,0.09); }
.ts-app .ts-main .reservation-list .card-block { padding: 18px 20px; }
.ts-app .ts-main .reservation-list .product-deatil .name { font-size: 16px; font-weight: 700; color: var(--head); margin: 0 0 4px; }
.ts-app .ts-main .reservation-list .price-container { font-size: 20px; font-weight: 700; color: var(--head); margin: 0 0 8px; }
.ts-app .ts-main .reservation-list .description { border-top: 1px solid var(--line-soft); padding-top: 10px; margin-top: 10px; color: var(--text); font-size: 13px; }
.ts-app .ts-main .reservation-list .description .blockquote { display: inline-block; margin-top: 4px; font-size: 12px; color: var(--muted); border: 0; padding: 0; }
.ts-app .ts-main .reservation-list .product-info { border-top: 1px solid var(--line-soft); padding-top: 12px; margin-top: 10px; }
.ts-app .ts-main .reservation-list .product-info .btn { margin: 0 6px 6px 0; border-radius: 8px; }
.ts-app .ts-main .reservation-list .tag1 { margin-left: 6px; }
/* filter dropdown on this page (token card) */
.ts-app .ts-main .filter-dropdown.dropdown-menu {
    background: var(--card); border: 1px solid var(--line); border-radius: 11px;
    box-shadow: 0 18px 50px rgba(12,44,73,0.18); padding: 12px; min-width: 260px;
}
.ts-app .ts-main .filter-dropdown.dropdown-menu .form-group { margin-bottom: 10px; }
.ts-app .ts-main .filter-dropdown.dropdown-menu label, .ts-app .ts-main .filter-dropdown .label-format { color: var(--head); font-weight: 600; font-size: 12.5px; }

/* ---- manage events filter pills (Live / Draft / Past / Archived) ---- */
.ts-app .ts-main .pg-eventtabs { align-items: center; margin: 18px 0; }
.ts-app .ts-main .pg-eventtabs .pg-eventtabs-sort { margin-left: auto; }
.ts-app .ts-main .pg-eventtabs .pg-eventtabs-sort .manage-events-sort {
    min-width: 180px; height: 38px; border: 1px solid var(--line); border-radius: 9px;
    background: var(--card); color: var(--text);
}
.ts-app .ts-main .pg-eventtabs .pg-eventtabs-spinner { display: flex; align-items: center; }
/* Manage Events (Areas/Admin/Events): the hero and event grid already align at
   the page edge; the filter and tabs were the outliers (filter pushed right by
   .col-sm-8 padding, tabs pulled left by the .row negative margin). Bring both
   back to the same left/right edge as the hero. */
.ts-app .ts-main .pg-eventsadmin .pg-eventtabs { margin-left: 15px; margin-right: 15px; }
.ts-app .ts-main .pg-eventsadmin .form-group > .col-sm-8 { padding-left: 0; }

/* Align tabs + tab content with the hero on admin list pages whose content is
   wrapped in a `.container-fluid` (adds ~15px gutter) with `.tab-pane.p-lg`
   (extra padding) — Manage Approvals / Manage Refunds / Manage Bookings. Zero
   the wrapper + tab-pane horizontal padding so everything sits flush at the
   hero's edge (the row>col content cancels to the same edge). */
.ts-app .ts-main .pg-flushwrap { padding-left: 0; padding-right: 0; }
.ts-app .ts-main .pg-flushwrap > .tab-content > .tab-pane { padding-left: 0; padding-right: 0; }

/* events category view: hide the Kendo breadcrumb root "home" icon */
.ts-app .ts-main .category-breadcrumb .k-breadcrumb-root-item .k-icon,
.ts-app .ts-main .category-breadcrumb .k-breadcrumb-root-item .k-button-icon,
.ts-app .ts-main .category-breadcrumb .k-i-home,
.ts-app .ts-main .category-breadcrumb .k-svg-i-home { display: none; }

/* ---- Kendo scheduler (events calendar) on the tokens ---- */
.ts-app .ts-main .k-scheduler {
    background: var(--card);
    color: var(--text);
    border-color: var(--line);
    border-radius: 12px;
    overflow: hidden;
}
.ts-app .ts-main .k-scheduler-toolbar, .ts-app .ts-main .k-scheduler-footer {
    background: var(--inset);
    border-color: var(--line);
    color: var(--text);
}
.ts-app .ts-main .k-scheduler-header, .ts-app .ts-main .k-scheduler-header-wrap {
    background: var(--inset);
    border-color: var(--line);
    color: var(--muted);
}
.ts-app .ts-main .k-scheduler-table td, .ts-app .ts-main .k-scheduler-table th { border-color: var(--line-soft); }
.ts-app .ts-main .k-scheduler .k-other-month, .ts-app .ts-main .k-scheduler .k-nonwork-hour { background: var(--inset); }
.ts-app .ts-main .k-scheduler .k-today { background: var(--blue-soft); }
.ts-app .ts-main .k-scheduler .k-event { border-radius: 7px; background: var(--blue); border-color: var(--blue); color: #fff; }

/* ---- sub-account cards (profile cards, not town-uploaded event cards) ----
   NOTE: do NOT set display:grid on .manage-subacc-listview or on
   .k-listview-content. userrelationships.ts builds this with
   height:65vh + scrollable:"auto", so Kendo owns the layout of those two
   elements as a scroll container — overriding their display collapses every
   card into one narrow overlapping column. The Bootstrap float columns in the
   template are left alone for the same reason; only the card surface below is
   restyled. */
.ts-app .ts-main .manage-subacc-listview { background: transparent; border: 0; }
.ts-app .ts-main .manage-subacc-listview .card.viewevent {
    /* legacy app.css pins .viewevent to height:300px. A sub-account with long
       details (business name, mailing address, email) overflowed that fixed
       box, and the Edit/Delete buttons — the last elements in .card-body —
       spilled past the card's bottom edge onto the panel beneath it. Letting
       the card grow keeps them inside, with the body's padding below them.
       Margin is deliberately not touched — the template's own `m` utility
       provides the spacing between cards. */
    height: auto;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: 13px;
    box-shadow: 0 1px 2px rgba(12,44,73,0.04);
    color: var(--text);
    transition: border-color .12s ease, box-shadow .12s ease;
}
.ts-app .ts-main .manage-subacc-listview .card.viewevent:hover { border-color: var(--blue-line); box-shadow: 0 4px 14px rgba(12,44,73,0.08); }
.ts-app .ts-main .manage-subacc-listview .card-body { color: var(--text); text-align: center; padding: 18px; }
.ts-app .ts-main .manage-subacc-listview .card-body label, .ts-app .ts-main .manage-subacc-listview .label-format { color: var(--head); }
.ts-app .ts-main .manage-subacc-listview .img-circle { border: 3px solid var(--blue-soft); }
.ts-app .ts-main .manage-subacc-listview .btn { margin-top: 8px; }
/* long unbroken values (emails, addresses) must wrap rather than stretch the
   card past its column */
.ts-app .ts-main .manage-subacc-listview .card-body span,
.ts-app .ts-main .manage-subacc-listview .card-body label { overflow-wrap: anywhere; }

/* ticket report area: keep the printable content on a white surface in both themes */
.ts-app .ts-main #full_ticket #ticket-report { background: #fff; border-radius: 9px; }

/* ---- reservation date-range groups in dark mode ----
   theme-dark.css hardcodes a pale-green highlight on both the reservation form's
   From/To picker group (#fullDayTime, facility reservation page) and the scheduler
   setup block (#div-resavationTimes):
       #div-resavationTimes,#fullDayTime { background-color:#c4d6c6; ... }
   On the light theme's white form that green reads as a soft highlight, but in dark
   mode it renders as a jarring bright box inside the dark .panel (--card) and pairs
   the light-green fill with a light text colour, failing contrast. Re-tint to the
   dark inset surface so the group still reads as a softly raised block but matches
   the surrounding panels. Scoped to .is-dark only, so light mode keeps its green. */
body.ts-app.is-dark #fullDayTime,
body.ts-app.is-dark #div-resavationTimes {
  background-color: var(--inset);
  color: var(--text);
  border-radius: 10px;
}

/* ---- Facility reservation page (Areas/Facility/Info/Index): panel padding ----
   The page's cards had their headers jammed into the top edge. The plain Bootstrap
   panels (reservation form / Booked Dates / Attachments) use tight defaults
   (10px heading, 15px body), and the Facility Info / Location cards wrap a
   `.responsive-accordion` whose desktop rule goes further:
       .responsive-accordion .panel-default > .panel-heading { padding: 0 0 10px }  (zero top)
       …+ .panel-collapse > .panel-body { padding: 0 }
   Under the redesign's rounded --inset header-bar treatment the titles sat hard in
   the top corner. Give every panel header AND body matching, comfortable padding
   (same rhythm as .pg-tickets). They must share the horizontal value: a Bootstrap
   `.row` inside the body carries -15px margins that cancel the column's +15px, so
   row content lands at the body's padding value and stays aligned under the header.
   Padding only, so it applies in both themes. Scoped to #reservationInfoView. */
.ts-app .ts-main #reservationInfoView .panel-heading { padding: 14px 20px; }
.ts-app .ts-main #reservationInfoView .panel-body { padding: 18px 20px; }

/* The "Reservation Day" date-range callout (#fullDayTime — the From/To box whose
   highlight is re-tinted above) only had facility.css's padding:12px, which felt
   tight against the roomier panels. Give it matching, symmetric padding so it reads
   as a comfortable card. Both themes (the light-mode green fill and the dark --inset
   fill); the id-heavy selector beats facility.css's `#fullDayTime`. */
.ts-app .ts-main #reservationInfoView #fullDayTime { padding: 16px 18px; }

/* ---- Facility reservation: Kendo expansion panels (Reservation Day / Notes /
   Extra Items) ----
   These sections are Kendo expansionpanels (.main-expansion-panel → .k-expander).
   The redesign restyled .panel but never .k-expander, so they kept the Kendo theme's
   grey fill (rgb 42,49,55) — a grey block sitting on the navy reservation card.
   Blend each into the card (transparent) and treat its header as a clean section
   divider with comfortable padding. Horizontal padding stays 0 so the header text,
   the form rows (Bootstrap .row -15px margins cancel the column +15px) and the
   #fullDayTime callout all line up at the card's content edge. Both themes. */
.ts-app .ts-main #reservationInfoView .main-expansion-panel.k-expander,
.ts-app .ts-main #reservationInfoView .main-expansion-panel .k-expander-header,
.ts-app .ts-main #reservationInfoView .main-expansion-panel .k-expander-content {
  background: transparent;
}
.ts-app .ts-main #reservationInfoView .main-expansion-panel .k-expander-header {
  padding: 14px 0; border-bottom: 1px solid var(--line);
}
.ts-app .ts-main #reservationInfoView .main-expansion-panel .k-expander-content {
  padding: 16px 0 0;
}

/* The Gross / Tax / Grand Total summary is a floated .pull-right inside .panel-footer,
   with the action buttons beside it. The footer had no float containment, so it
   collapsed and the totals table spilled out below the card ("outside the panel").
   flow-root makes the footer wrap its float again. */
.ts-app .ts-main #reservationInfoView .panel-footer { display: flow-root; }

/* ---- Cart: Facility Reservation line item (Views/Cart/_ItemBreakout.cshtml
   → Areas/Facility/Views/Info/_ReservationCart.cshtml) ----
   The section icon tile (.ico-box, wrapping an SVG letter glyph — "F" for
   Facility Reservation, reused by the Pending Approvals / Contract Sign-in /
   Internal Reservations partials too) got its background from the legacy
   theme bundle: #1298d3 in light mode, #00a8f2 in the old dark themes —
   neither is a brand token. Recolour to the site's actual blue everywhere
   it's used, not just this card. */
.ts-app .ts-main .ico-box { background-color: var(--blue) !important; color: #fff !important; }

/* The reservation summary (reservationHeaderTemplate, a Kendo template
   rendered into #grdReservations) is a bare, unstyled Bootstrap <table> —
   no card surface, and .due-amount uses a fragile `position:relative;
   top:-35px` hack to visually lift the price, which throws off vertical
   alignment against the tax/discount breakdown next to it. Give the row a
   proper inset card and fix the price in normal flow instead. */
.ts-app .ts-main #reservationInfo .list-group-item {
  background: var(--inset); border: 1px solid var(--line); border-radius: 12px; padding: 18px 20px;
  margin-top: 14px;
}
.ts-app .ts-main .facility-reservation-portrait { width: 100%; }
.ts-app .ts-main .facility-reservation-portrait > thead > tr > th { vertical-align: top; padding: 0 10px; }
.ts-app .ts-main .facility-reservation-portrait > thead > tr > th:first-child { padding-left: 0; }
.ts-app .ts-main .facility-reservation-portrait .customer-info { color: var(--muted); font-size: 13px; line-height: 1.7; margin-top: 4px; }
.ts-app .ts-main .facility-reservation-portrait .due-amount { position: static; top: auto; font-size: 17px; font-weight: 700; color: var(--head); margin-bottom: 8px; }
.ts-app .ts-main .facility-reservation-portrait .tbl-tax { color: var(--muted); }
.ts-app .ts-main .facility-reservation-portrait .tbl-tax tr > td:first-child { color: var(--muted); font-weight: 500; }

/* =====================================================================
   ASK TOWNSUITE DOCK — ported from the Expedition homepage chat
   (.ts-chatfab / .ts-chat via the prototype's proto-ask.css).
   Markup built by assets/typescript/townsuite-ask.ts; follows tokens + dark mode.
   ===================================================================== */
.pr-askfab {
  position: fixed; right: 22px; bottom: 22px; z-index: 140;
  display: flex; align-items: center; gap: 10px;
  min-height: 54px; padding: 0 21px 0 16px; border-radius: 100px;
  border: none; cursor: pointer;
  background: var(--navy); color: #fff;
  font-family: inherit; font-weight: 700; font-size: 15px;
  box-shadow: 0 14px 36px color-mix(in srgb, var(--navy) 22%, transparent), 0 2px 6px rgba(7, 25, 40, 0.12);
  transition: transform 0.2s, box-shadow 0.2s;
}
.pr-askfab:hover { transform: translateY(-3px); }
.pr-askfab .spark { width: 21px; height: 21px; flex: none; }
body.is-dark .pr-askfab { color: #F2F7FB; }

.pr-ask {
  position: fixed; right: 22px; bottom: 22px; z-index: 160;
  width: min(382px, calc(100vw - 32px));
  max-height: min(640px, calc(100svh - 44px));
  display: flex; flex-direction: column; overflow: hidden;
  border-radius: 22px; background: var(--card);
  border: 1.5px solid var(--line);
  box-shadow: 0 8px 24px rgba(7, 25, 40, 0.14), 0 32px 80px rgba(7, 25, 40, 0.18);
  animation: praskpop 0.2s ease;
  font-size: 14.5px; line-height: 1.5;
}
@keyframes praskpop { from { opacity: 0; transform: translateY(10px) scale(0.98); } }

.pr-ask__head {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 17px; background: var(--navy); color: #fff; flex: none;
}
body.is-dark .pr-ask__head { color: #F2F7FB; }
.pr-ask__badge {
  width: 36px; height: 36px; border-radius: 11px; flex: none;
  background: rgba(255, 255, 255, 0.16); display: grid; place-items: center;
}
.pr-ask__badge svg { width: 21px; height: 21px; color: currentColor; }
.pr-ask__head b { font-size: 15.5px; display: block; line-height: 1.15; }
.pr-ask__head small { font-size: 11.5px; opacity: 0.85; display: flex; align-items: center; gap: 6px; }
.pr-ask__head small .maple { width: 11px; height: 11px; fill: currentColor; }

/* context line — the dock says what it's helping with */
.pr-ask__ctx {
  display: flex; align-items: center; gap: 8px; flex: none;
  padding: 8px 17px; font-size: 12px; font-weight: 600; color: var(--text);
  background: color-mix(in oklab, var(--green) 8%, var(--card));
  border-bottom: 1px solid var(--line);
}
.pr-ask__ctx .dot {
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--green); box-shadow: 0 0 0 3px color-mix(in oklab, var(--green) 22%, transparent);
}
.pr-ask__new, .pr-ask__x {
  flex: none; width: 32px; height: 32px; border: none; border-radius: 10px;
  background: rgba(255, 255, 255, 0.16); color: inherit;
  cursor: pointer; font-family: inherit; padding: 0;
  display: grid; place-items: center;
  transition: background 0.15s;
}
.pr-ask__new { margin-left: auto; }
.pr-ask__new svg, .pr-ask__x svg { width: 17px; height: 17px; }
.pr-ask__new:hover, .pr-ask__x:hover { background: rgba(255, 255, 255, 0.28); }

.pr-ask__log {
  flex: 1; min-height: 170px; overflow-y: auto;
  padding: 16px; display: flex; flex-direction: column; gap: 11px;
}
.pr-bubble {
  max-width: 88%; border-radius: 15px; padding: 11px 15px;
  font-size: 13.8px; line-height: 1.5;
}
.pr-bubble.is-user {
  align-self: flex-end; background: var(--navy); color: #fff;
  border-bottom-right-radius: 5px;
}
body.is-dark .pr-bubble.is-user { color: #F2F7FB; }
.pr-bubble.is-bot {
  align-self: flex-start; background: var(--card); color: var(--text);
  border: 1px solid var(--line); border-bottom-left-radius: 5px;
  box-shadow: 0 1px 2px rgba(7, 25, 40, 0.05);
}
.pr-bubble.is-bot b { color: var(--navy); }
body.is-dark .pr-bubble.is-bot b { color: var(--blue); }
.pr-bubble .pr-ask-cta {
  display: inline-flex; align-items: center; gap: 7px;
  margin-top: 9px; min-height: 34px; padding: 0 14px;
  border: 1px solid var(--blue-line); border-radius: 100px;
  background: var(--blue-soft); color: var(--navy);
  font-family: inherit; font-size: 12.8px; font-weight: 700; cursor: pointer;
  text-decoration: none; transition: filter 0.15s;
}
.pr-bubble .pr-ask-cta:hover { filter: brightness(0.96); text-decoration: none; }
body.is-dark .pr-bubble .pr-ask-cta { color: var(--blue); }

.pr-ask__typing { display: inline-flex; gap: 6px; align-items: center; padding: 13px 16px; }
.pr-ask__typing i {
  width: 7px; height: 7px; border-radius: 1.5px; display: block;
  transform: rotate(45deg); animation: praskblink 1.1s infinite;
}
.pr-ask__typing i:nth-child(1) { background: #E48D1A; }
.pr-ask__typing i:nth-child(2) { background: #2DA343; animation-delay: 0.18s; }
.pr-ask__typing i:nth-child(3) { background: #E03A3E; animation-delay: 0.36s; }
@keyframes praskblink {
  0%, 70%, 100% { opacity: 0.25; transform: translateY(0) rotate(45deg); }
  35% { opacity: 1; transform: translateY(-3px) rotate(45deg); }
}

/* "Try asking" prompt chips */
.pr-ask__sug { flex: none; padding: 0 16px 12px; }
.pr-ask__suglbl {
  display: block; margin-bottom: 7px;
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--faint);
}
.pr-ask__chips { display: flex; flex-wrap: wrap; gap: 8px; flex: none; }
.pr-ask__chips button {
  border: 1px solid var(--blue-line); background: var(--card); color: var(--navy);
  font-family: inherit; font-weight: 600; font-size: 12.8px;
  border-radius: 100px; min-height: 36px; padding: 0 14px; cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}
.pr-ask__chips button:hover { background: var(--blue-soft); }
body.is-dark .pr-ask__chips button { color: var(--blue); }

.pr-ask__composer {
  display: flex; align-items: center; gap: 8px; flex: none;
  padding: 10px 12px; border-top: 1px solid var(--line);
}
.pr-ask__composer input {
  flex: 1; min-width: 0; min-height: 40px; padding: 0 15px;
  font-family: inherit; font-size: 13.8px; color: var(--head);
  background: var(--inset); border: 1px solid var(--line); border-radius: 100px;
  outline: none; transition: border-color 0.18s;
}
.pr-ask__composer input::placeholder { color: var(--faint); }
.pr-ask__composer input:focus { border-color: var(--blue); box-shadow: none; }
.pr-ask__composer button {
  flex: none; width: 40px; min-height: 40px; border: none; border-radius: 50%;
  background: var(--navy); color: #fff; font-size: 17px; line-height: 1;
  cursor: pointer; display: flex; align-items: center; justify-content: center;
  font-family: inherit; transition: filter 0.18s, transform 0.18s;
}
.pr-ask__composer button:hover { filter: brightness(1.12); transform: translateX(2px); }
body.is-dark .pr-ask__composer button { color: #F2F7FB; }

.pr-ask__foot {
  flex: none; padding: 10px 16px; border-top: 1px solid var(--line);
  display: flex; align-items: center; gap: 8px;
  font-size: 11.2px; color: var(--muted);
}
.pr-ask__foot .maple { width: 12px; height: 12px; fill: #E03A3E; flex: none; }

@media (max-width: 560px) {
  .pr-askfab .lbl { display: none; }
  .pr-askfab { padding: 0; width: 54px; justify-content: center; }
}

/* ---- Site footer (Views/Shared/_SiteLayout.TownSuite.cshtml and
   Views/Home/Index.cshtml both render this same .pr-footer component, so
   the landing page footer matches the rest of the site) ----
   Just the TownSuite signature (copyright + made-with-heart-in-Canada,
   ~/Views/Shared/_TownSuiteSignature.cshtml) on the left, version on the
   right. */
.pr-footer {
  width: 100%; display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap;
  gap: 6px 16px; padding: 14px 32px; border-top: 1px solid var(--line);
  background: var(--card); font-size: 12.5px; color: var(--muted);
}
.pr-footer a { color: var(--muted); }
.pr-footer-version { flex: none; font-weight: 600; color: var(--head); }
/* .pr-footer--fab reserves room on the right so the fixed Ask TownSuite
   button (.pr-askfab, bottom-right) never sits on top of the footer text. */
.pr-footer--fab { padding-right: 210px; }
@media (max-width: 640px) {
  .pr-footer { padding: 12px 14px; }
  .pr-footer--fab { padding-right: 210px; }
}
@media (max-width: 560px) {
  /* matches .pr-askfab's own breakpoint, where it shrinks to a 54px icon-only button */
  .pr-footer--fab { padding-right: 90px; }
}

/* =====================================================================
   GLOBAL CONSISTENCY PASS
   ===================================================================== */

/* every panel-like surface shares the same curve as pg-card/ob-card */
.ts-app .ts-main .panel, .ts-app .ts-main .well, .ts-app .ts-main .card,
.ts-app .ts-main .k-grid, .ts-app .ts-main .k-listview,
.ts-app .ts-main .k-tabstrip > .k-content, .ts-app .ts-main .k-block {
    border-radius: 13px;
}
.ts-app .k-window { border-radius: 14px; }

/* text selection must always be readable, light + dark, on any surface */
body.ts-app *::selection { background: #00578E !important; color: #FFFFFF !important; }
body.ts-app.is-dark *::selection { background: #7FB4D6 !important; color: #071420 !important; }

/* ---- admin dashboard ---- */
/* year filter strip (kendo tabstrip themed to the underline-tab language) */
.pg-yeartabs.filtering-tabs { border: 0; background: none; }
.pg-yeartabs .k-tabstrip-items { padding: 0; gap: 4px; }
.pg-yeartabs .k-item {
    border: 0; margin: 0; padding: 0 0 4px; text-align: center; cursor: pointer;
    background: none; border-bottom: 3px solid var(--line);
    font-size: 13.5px; font-weight: 600; line-height: 2em; color: var(--muted);
    flex: 1;
}
.pg-yeartabs .k-item.k-state-hover, .pg-yeartabs .k-item.k-hover { color: var(--head); background: none; }
.pg-yeartabs .k-item.k-state-active, .pg-yeartabs .k-item.k-active {
    padding: 0 0 4px; color: var(--navy); border-bottom-color: var(--blue); background: none;
}
body.is-dark .pg-yeartabs .k-item.k-state-active, body.is-dark .pg-yeartabs .k-item.k-active { color: var(--blue); }
.pg-yeartabs .k-link { padding: 0; color: inherit; }

/* chart cards */
.pg-chartcard { margin-bottom: 22px; }
.pg-chartcard .chart-wrapper { margin: auto; }
.pg-chartcard .k-chart { border-radius: 10px; }

/* compact, scrollable action-log feed (rows are injected as .alert.alert-info) */
.pg-actionlog { max-height: 320px; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; }
.ts-app .ts-main .pg-actionlog .alert.alert-info {
    background: var(--inset);
    border: 1px solid var(--line-soft);
    color: var(--text);
    border-radius: 9px;
    padding: 8px 12px;
    margin: 0;
    font-size: 12.5px;
    line-height: 1.45;
}
.ts-app .ts-main .pg-actionlog .alert.alert-info a,
.ts-app .ts-main .pg-actionlog .alert-info-a { color: var(--blue); font-weight: 600; }

/* slim link-row card (e.g. "View User Report") */
.pg-linkrow { display: flex; align-items: center; gap: 12px; padding: 14px 20px; margin-bottom: 22px; }
.pg-linkrow a { font-weight: 600; }

/* search toolbar row (input grows, button keeps natural width) */
.pg-searchrow { display: flex; gap: 10px; align-items: center; }
.pg-searchrow .k-textbox, .pg-searchrow input[type="text"] { flex: 1; min-width: 0; margin: 0; }
@media (max-width: 640px) {
  .pg-searchrow { flex-direction: column; align-items: stretch; }
}

/* ---- Preferences page (Views/User/Preference) ----
   Its .tab-content took the legacy square-cornered panel look. Give it the same
   card surface as .pg-card elsewhere. The square top-left corner and the
   margin-bottom:0 that used to butt the tab strip against this card are gone:
   .pg-tabs is a self-contained segmented control now, so it sits above the card
   on its own like every other tab strip rather than merging into it. */
.ts-app .ts-main .pg-preference .tab-content {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 13px;
  box-shadow: 0 1px 2px rgba(12,44,73,0.04);
  padding: 4px 0 0;
}
.ts-app .ts-main .pg-preference .tab-content > .tab-pane { background: transparent; }

/* tab panes with their own heading row (payments dashboard etc.) */
.pg-formtabs .pg-card-title { margin-top: 4px; }
.pg-formtabs .pg-card-title .ts-btn.is-add { margin-left: auto; height: 32px; padding: 0 12px; font-size: 12.5px; }

/* =====================================================================
   PUBLIC LANDING PAGE (Views/Home/Index.cshtml) — scoped reskin.
   CSS-only over the existing markup; town logo + uploaded card images
   and all JS hooks are untouched. Activated by body.ts-app.pg-landing.
   ===================================================================== */
/* auto-theme dark tokens for this page (and the auth pages) are defined once
   with the rest of the tokens at the top of this file. */

body.pg-landing { background: var(--bg) !important; color: var(--text); min-height: 100vh; }
body.pg-landing .wrapper { background: var(--bg); }

/* ---- top bar ----
   Layout is left to the original home.css (floats position logo left /
   controls right and it worked). We only restyle colours, borders and the
   button/logo appearance — no display/float/order/position changes. */
body.pg-landing .mast-head {
  background: var(--card); border-bottom: 1px solid var(--line);
}
body.pg-landing .townsuite-logo a { color: var(--head); text-decoration: none; }
body.pg-landing .townsuite-logo img { border-radius: 9px; }
body.pg-landing .culture-input, body.pg-landing .culture-input-container select {
  border: 1px solid var(--line); border-radius: 9px; background: var(--card);
  color: var(--text); font-size: 13.5px;
}
body.pg-landing #sign-in {
  background: var(--navy); color: #fff !important; font-weight: 700; border-radius: 11px;
  padding: 8px 18px; text-decoration: none;
}
body.pg-landing.is-dark #sign-in { color: #F2F7FB !important; }
body.pg-landing #sign-in:hover { filter: brightness(1.1); }
body.pg-landing #your_dashboard_link, body.pg-landing #your_dashboard_link-icon {
  background: var(--navy); border-color: var(--navy); color: #fff; border-radius: 11px;
}
body.pg-landing .ts-learn-more { color: var(--blue); font-weight: 600; text-decoration: none; }

/* ---- main content width ----
   Only constrain width + centre horizontally. Do NOT override vertical
   padding/margin — the page's own .header/.p-lg classes reserve the top
   clearance for the CDN's positioned mast-head; overriding it tucks the
   top cards under the header. */
body.pg-landing #mainContent { max-width: 1320px; margin-left: auto; margin-right: auto; }
body.pg-landing #mainContent > .container-events { padding: 0; width: auto; max-width: none; }

/* ---- news card ---- */
body.pg-landing .news.card, body.pg-landing card.news {
  display: block; background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: 0 1px 2px rgba(12,44,73,0.05); padding: 22px 24px; margin-bottom: 30px; position: relative;
}
body.pg-landing .news .h3, body.pg-landing card.news .h3 {
  font-size: 18px; font-weight: 700; color: var(--head); margin: 0 0 6px; letter-spacing: -0.2px;
}
body.pg-landing .news .list-group { margin: 0; }
body.pg-landing .news .list-group-item {
  background: transparent; border: 0; border-top: 1px solid var(--line-soft);
  border-radius: 0; padding: 14px 0; display: block;
}
body.pg-landing .news .list-group-item:first-of-type { border-top: 0; }
body.pg-landing .news .media-box-heading { color: var(--blue); font-weight: 700; font-size: 14.5px; }
body.pg-landing .news .mediabox-description, body.pg-landing .news .mediabox-description small { color: var(--muted); }
body.pg-landing .news .media-box-body .pull-right { color: var(--faint); font-size: 12px; }
body.pg-landing .news .circle-success {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--green);
  margin-right: 8px; vertical-align: middle;
}
/* "View more" text + RSS icon (DOM order: text, then icon). They follow the news
   items in the markup, so keep them in normal flow — rendered on their own row
   after the list, matching the pre-redesign layout. The earlier absolute
   positioning pinned them to the card's top-right corner, where they overlapped
   the first news item's link and date. */
body.pg-landing .news .view-more {
  display: inline-block; margin: 8px 8px 0 0; color: var(--blue);
  font-weight: 600; font-size: 13px; text-decoration: none; vertical-align: middle;
}
body.pg-landing .news .view-more:hover { text-decoration: underline; }

/* ---- "Available eServices" heading ---- */
body.pg-landing .container-events > card.news, body.pg-landing .container-events > .news {
  border: 0; background: none; box-shadow: none; padding: 0; margin: 0 0 16px;
}
body.pg-landing .container-events > card.news .h3 { font-size: 22px; }

/* ---- service card grid ----
   Fixed-size cards (260 x 280) in a wrapping flex row. Every card gets a fixed
   flex-basis of 260px with grow/shrink disabled, so wide preview widgets
   (weather / schedule) can't stretch a card — every card is an identical
   260px box and rows wrap and center however many fit per row.
   NOTE: this used to be `display: grid` with `grid-template-columns:
   repeat(auto-fill, 260px)` + `justify-content: center`. WebKit/Safari
   (iOS) has a bug where `justify-content: center` on an auto-fill grid
   doesn't reliably keep every track pinned at the fixed size — leftover
   space gets redistributed unevenly, so cards render at different widths
   depending on which photo/content is inside them. Chrome/Firefox render
   the same grid correctly, so this only showed up on iOS. Flexbox with an
   explicit fixed flex-basis has no such ambiguity and is well-supported
   everywhere, including old WebKit. */
/* !important is required here: the original landing stylesheet (CDN home-*.css)
   styles .row.ng-scope as a flex row too, but without a fixed basis the cols
   shrink-to-content and cards come out different widths (e.g. ePermitting
   narrower than the rest). */
body.pg-landing #mainContent .row.ng-scope {
  display: flex !important;
  flex-wrap: wrap !important;
  justify-content: center !important;
  gap: 22px; margin: 0;
}
body.pg-landing #mainContent .row.ng-scope > [class*="col-"] {
  width: 260px !important; max-width: none !important; min-width: 0 !important;
  flex: 0 0 260px !important;
  padding: 0 !important; margin: 0 !important; float: none !important; position: relative; display: flex;
}
/* Bootstrap's `.row` adds ::before/::after clearfix pseudo-elements
   (content:" "; display:table). Remove them so they don't render as stray
   empty flex items in the row. */
body.pg-landing .row.ng-scope::before,
body.pg-landing .row.ng-scope::after { content: none; display: none; }
/* also drop any stray non-card child just in case */
body.pg-landing .row.ng-scope > :not([class*="col-"]) { display: none; }
body.pg-landing .viewevent.card {
  display: flex !important; flex-direction: column !important; width: 100% !important; height: 280px !important; min-width: 0;
  background: var(--card);
  border: 1px solid var(--line); border-radius: 14px; overflow: hidden;
  box-shadow: 0 1px 2px rgba(12,44,73,0.05); transition: transform .14s ease, box-shadow .14s ease, border-color .14s ease;
}
body.pg-landing a:hover .viewevent.card { transform: translateY(-3px); box-shadow: 0 14px 34px rgba(12,44,73,0.12); border-color: var(--blue-line); }
/* background covers the box when an image fails to load (broken-icon-on-white
   looks like an error; a filled placeholder box reads as intentional) */
body.pg-landing .viewevent .card-item { position: relative; line-height: 0; height: 150px !important; flex: 0 0 150px !important; width: 100% !important; overflow: hidden !important; background: var(--inset); }
/* <picture> is display:inline by default — force it to fill so the inner img
   can't let the picture's natural size dictate the card width */
body.pg-landing .viewevent .card-item picture { display: block !important; width: 100% !important; height: 150px !important; }
body.pg-landing .viewevent .card-item img { display: block !important; width: 100% !important; height: 150px !important; object-fit: cover !important; max-width: none !important; }
body.pg-landing .viewevent .card-label {
  position: absolute; top: 12px; right: 12px; background: var(--card); color: var(--head);
  border: 1px solid var(--line); border-radius: 999px; padding: 4px 12px; font-size: 11px;
  font-weight: 700; line-height: 1.4; box-shadow: 0 2px 8px rgba(12,44,73,0.12); text-align: center;
}
body.pg-landing .viewevent .card-offset { display: none; }
body.pg-landing .viewevent .card-body { padding: 16px 18px; flex: 1 1 auto; min-height: 0; overflow: hidden; }
body.pg-landing .viewevent .card-body h2 {
  font-size: 17px; font-weight: 700; color: var(--head); margin: 0 0 5px; letter-spacing: -0.2px;
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;
}
body.pg-landing .viewevent .card-body .text-muted {
  color: var(--muted); font-size: 13px;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
body.pg-landing .viewevent .text-tag { margin: 0; }
/* width:100% is required, not just height — the column (`[class*="col-"]`)
   is `display:flex` with no flex-direction, so this <a> is itself a row-flex
   item with an `auto` flex-basis. With no explicit width, that basis falls
   back to shrink-to-fit the <a>'s content instead of filling the fixed
   260px column: a card whose image fails to load has much less intrinsic
   content width than one with a loaded photo, so that one card (and only
   that one) renders visibly narrower than its siblings — the "misaligned
   grid" symptom. Pinning width:100% gives every card the same definite,
   content-independent basis regardless of whether its image loads. */
body.pg-landing .row.ng-scope a { text-decoration: none; display: block; width: 100%; height: 100%; }
body.pg-landing .change-picture {
  position: absolute; top: 18px; left: 18px; z-index: 4; border-radius: 8px;
  background: var(--card); border: 1px solid var(--line); color: var(--head); font-size: 12px; padding: 4px 10px;
}

@media (max-width: 640px) {
  body.pg-landing .mast-head { padding: 0 14px; gap: 10px; min-height: 56px; }
  body.pg-landing #mainContent { padding: 18px 14px 30px; }
  /* cards stay fixed-size; on very narrow screens center them so the fixed
     260px width doesn't sit lopsided against the edge */
  body.pg-landing .row.ng-scope { justify-content: center; }
  /* Vendor CSS centers .townsuite-logo (width:200px) via `margin:13px auto`
     + the parent's `text-align:center`, but the actual <img> inside is
     display:block (Bootstrap's .img-responsive) — an ancestor's text-align
     has no effect on a block-level child, so centering was really coming
     from incidental inline whitespace around the <img>/<a> in the markup,
     which doesn't reliably land dead-center (measured ~10px off in testing).
     Force a hard center on both the outer box (vs. .mast-head, its
     position:fixed containing block) and the inner content (flex,
     immune to markup whitespace), independent of the vendor mechanism. */
  body.pg-landing .townsuite-logo {
    position: absolute; left: 50%; top: 13px; margin: 0;
    transform: translateX(-50%);
    display: flex; justify-content: center; align-items: center;
  }
}

/* =====================================================================
   YOUR ACCOUNT page (Views/User/Index.cshtml) — profile rail + setting
   cards, from the "Your account" design. Built on pg-dash + tokens.
   ===================================================================== */
/* cap + centre the page so the short content doesn't spread across full-bleed width */
.ts-app .ts-main .ob-main.pg-account { max-width: 1180px; margin-left: auto; margin-right: auto; }
/* settings cards in two columns (per the design), collapsing to one when narrow */
.pg-account .ac-grid { grid-template-columns: 1fr 1fr; }
@media (max-width: 900px) { .pg-account .ac-grid { grid-template-columns: 1fr; } }
.pg-account .ac-tagline { font-size: 13px; color: var(--muted); text-align: center; margin: 4px 0 16px; line-height: 1.5; }

/* ---- identity banner: avatar | name + roles | stats ----
   Full width above the settings grid (was a card in a left rail). */
.ac-profilebar {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  padding: 18px 24px; margin-bottom: 18px;
}
.ac-avatar {
  width: 56px; height: 56px; flex: none; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--navy);
  /* !important: this is an <a>, so the broad legacy-reskin link rule
     (`.ts-app .ts-main a:not(.btn):not(.ts-btn):not(.k-button):not(.ts-navitem)`,
     specificity (0,6,1) thanks to its four :not() classes) otherwise paints the
     initials --blue on the navy chip — 1.51:1. Same trap as the alert links. */
  color: #fff !important;
  font-size: 17px; font-weight: 700; letter-spacing: 0.5px;
  text-decoration: none;
}
.ac-avatar:hover { text-decoration: none; filter: brightness(1.15); }
.ac-identity { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1 1 200px; }
.ac-name { font-size: 19px; font-weight: 700; color: var(--head); letter-spacing: -0.3px; line-height: 1.2; }
.ac-roles { font-size: 12.5px; color: var(--muted); line-height: 1.45; }

/* ---- settings grid + help rail ---- */
.ac-layout { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 18px; align-items: start; }
@media (max-width: 1099px) { .ac-layout { grid-template-columns: 1fr; } }
.ac-rail { min-width: 0; }

/* help card as a navy promo panel */
.ac-help.is-promo {
  background: var(--navy-deep); border-color: var(--navy-deep); text-align: left;
}
.ac-help.is-promo .ac-help-title { color: #fff; font-size: 16px; margin-bottom: 14px; }
/* on the navy panel the button inverts: white fill, navy label */
.ac-help.is-promo .ac-help-btn {
  background: #fff; color: var(--navy-deep); border-color: #fff; width: 100%;
}
.ac-help.is-promo .ac-help-btn:hover { background: #EAF1F7; color: var(--navy-deep); text-decoration: none; }

/* profile stat row */
.ac-stats { display: flex; gap: 8px; border-top: 1px solid var(--line-soft); padding-top: 14px; }
/* inside the banner the stats sit inline on the right with divider rules
   instead of being a bordered row under the profile */
.ac-profilebar .ac-stats {
  border-top: 0; padding-top: 0; margin-left: auto; flex: none; gap: 0;
}
.ac-profilebar .ac-stat { padding: 2px 22px; border-left: 1px solid var(--line-soft); border-radius: 0; }
.ac-profilebar .ac-stat:first-child { border-left: 0; }
.ac-profilebar .ac-stat:hover { background: transparent; }
.ac-profilebar .ac-stat-num { font-size: 25px; }
@media (max-width: 640px) {
  .ac-profilebar { padding: 14px 16px; gap: 12px; }
  .ac-profilebar .ac-stats { margin-left: 0; width: 100%; }
  .ac-profilebar .ac-stat { flex: 1; padding: 2px 10px; }
  .ac-avatar { width: 46px; height: 46px; font-size: 15px; }
  .ac-name { font-size: 17px; }
}
.ac-stat { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 6px 4px; border-radius: 10px; text-decoration: none; transition: background .12s ease; }
.ac-stat:hover { background: var(--inset); text-decoration: none; }
.ac-stat-num { font-size: 22px; font-weight: 700; color: var(--head); letter-spacing: -0.4px; line-height: 1.1; font-variant-numeric: tabular-nums; }
.ac-stat-lbl { font-size: 12px; color: var(--muted); text-align: center; line-height: 1.3; }

/* help card */
.ac-help { text-align: center; }
.ac-help-title { font-size: 15px; font-weight: 700; color: var(--head); margin-bottom: 12px; }

/* setting cards grid */
.ac-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 14px; }
.ac-item {
  display: flex; align-items: flex-start; gap: 13px; padding: 16px 18px;
  background: var(--card); border: 1px solid var(--line); border-radius: 13px;
  box-shadow: 0 1px 2px rgba(12,44,73,0.04); text-decoration: none;
  transition: border-color .12s ease, box-shadow .12s ease, transform .12s ease;
}
.ac-item:hover { border-color: var(--blue-line); box-shadow: 0 6px 18px rgba(12,44,73,0.09); transform: translateY(-2px); text-decoration: none; }
.ac-item-icon {
  width: 38px; height: 38px; flex: none; border-radius: 10px;
  display: grid; place-items: center; background: var(--blue-soft); color: var(--blue);
  font-size: 16px;
}
body.is-dark .ac-item-icon { color: var(--blue); }
.ac-item-main { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.ac-item-title { font-size: 14.5px; font-weight: 700; color: var(--head); letter-spacing: -0.2px; }
.ac-item-desc { font-size: 12.5px; color: var(--muted); line-height: 1.45; }
.ac-item-desc:empty { display: none; }
/* title + status badge on one line */
.ac-item-titlerow { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; }
.ac-item-badge {
  font-size: 11px; font-weight: 700; line-height: 1.5; white-space: nowrap;
  padding: 1px 9px; border-radius: 999px;
  background: rgba(221,148,52,0.14); border: 1px solid rgba(221,148,52,0.4); color: #875200;
}
body.is-dark .ac-item-badge { color: var(--amber); }
.ac-item-badge:empty { display: none; }
/* trailing chevron, marking each row as drilling into its own page */
.ac-item::after {
  content: ''; flex: none; align-self: center; margin-left: 4px;
  width: 7px; height: 7px;
  border-right: 1.6px solid var(--muted); border-bottom: 1.6px solid var(--muted);
  transform: rotate(-45deg);
}
.ac-item:hover::after { border-color: var(--blue); }

/* ---- position management: contain the Kendo OrgChart / matrix so a wide tree
   scrolls inside the card instead of breaking the page layout. Do NOT override
   box-sizing on the chart's descendants — the OrgChart widget measures each
   node's rendered size to position nodes and connectors, so it must stay on the
   site's global border-box or the layout mis-aligns. ---- */
.ts-app .ts-main #currentOrganizationChart,
.ts-app .ts-main #matrixReport { max-width: 100%; overflow: auto; }

/* =====================================================================
   SweetAlert2 — theme the popups to the design tokens. SA2 appends its
   container to <body>, which carries ts-app + is-dark, so light/dark both
   resolve from the tokens. !important is needed where SA2 sets colours inline
   via its own stylesheet.
   ===================================================================== */
body.ts-app .swal2-popup {
  background: var(--card) !important;
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 16px;
  font-family: 'Dax', 'Source Sans 3', system-ui, sans-serif;
}
body.ts-app .swal2-title { color: var(--head); font-weight: 700; letter-spacing: -0.2px; }
body.ts-app .swal2-html-container,
body.ts-app .swal2-html-container b { color: var(--text); }
body.ts-app .swal2-html-container b { color: var(--head); }
body.ts-app .swal2-close { color: var(--muted); }
body.ts-app .swal2-close:hover { color: var(--head); }

/* buttons */
body.ts-app .swal2-styled.swal2-confirm {
  background: var(--navy) !important; color: #fff !important;
  border-radius: 11px; font-weight: 700; box-shadow: 0 6px 16px rgba(0,87,142,0.16);
}
body.ts-app.is-dark .swal2-styled.swal2-confirm { color: #F2F7FB !important; }
body.ts-app .swal2-styled.swal2-confirm:focus { box-shadow: 0 0 0 3px rgba(0,87,142,0.3); }
body.ts-app .swal2-styled.swal2-cancel {
  background: var(--card) !important; color: var(--head) !important;
  border: 1px solid var(--line) !important; border-radius: 11px; font-weight: 700;
}
body.ts-app .swal2-styled.swal2-deny {
  background: var(--red) !important; color: #fff !important; border-radius: 11px; font-weight: 700;
}
body.ts-app .swal2-styled:focus { outline: none; }

/* inputs inside swal */
body.ts-app .swal2-input, body.ts-app .swal2-textarea, body.ts-app .swal2-select {
  background: var(--inset); border: 1px solid var(--line); border-radius: 9px;
  color: var(--text); box-shadow: none;
}
body.ts-app .swal2-input:focus, body.ts-app .swal2-textarea:focus, body.ts-app .swal2-select:focus {
  border-color: var(--blue); box-shadow: 0 0 0 3px rgba(0,87,142,0.14);
}
body.ts-app .swal2-validation-message { background: var(--inset); color: var(--text); }
body.ts-app .swal2-footer { border-top-color: var(--line-soft); color: var(--muted); }
/* semantic icon colours (success/error/warning/info) are left as SA2 defaults */

/* =====================================================================
   TsMessage toasts (UIkit notify) — the bottom-right popups raised by
   TsMessage.ShowError / ShowSuccess / ShowWarning / ShowInformation.
   Markup: .uk-notify (container) > .uk-notify-message.alert.alert-{status}.
   Reskinned to a rounded card with a status accent bar + icon, on the
   redesign tokens (light/dark resolve automatically under body.ts-app).
   ===================================================================== */
body.ts-app .uk-notify { box-sizing: border-box; }
body.ts-app .uk-notify-message {
  position: relative;
  min-width: 280px; max-width: 400px;
  margin-bottom: 12px;
  padding: 14px 38px 14px 46px;
  border: 1px solid var(--line);
  border-left: 4px solid var(--blue);
  border-radius: 12px;
  background: var(--card) !important;
  color: var(--head) !important;
  box-shadow: 0 12px 32px rgba(12,44,73,0.20);
  font-family: inherit; font-size: 13.5px; line-height: 1.45; font-weight: 500;
}
body.ts-app .uk-notify-message > div { color: var(--head); }
/* status icon */
body.ts-app .uk-notify-message::before {
  font-family: FontAwesome; position: absolute; left: 16px; top: 14px;
  font-size: 17px; line-height: 1.2; color: var(--blue);
}
body.ts-app .uk-notify-message.alert-danger  { border-left-color: var(--red); }
body.ts-app .uk-notify-message.alert-danger::before  { content: "\f06a"; color: var(--red); }
body.ts-app .uk-notify-message.alert-success { border-left-color: var(--green); }
body.ts-app .uk-notify-message.alert-success::before { content: "\f058"; color: var(--green); }
body.ts-app .uk-notify-message.alert-warning { border-left-color: var(--amber); }
body.ts-app .uk-notify-message.alert-warning::before { content: "\f071"; color: var(--amber); }
body.ts-app .uk-notify-message.alert-info    { border-left-color: var(--blue); }
body.ts-app .uk-notify-message.alert-info::before    { content: "\f05a"; color: var(--blue); }
/* close button */
body.ts-app .uk-notify-message .close {
  position: absolute; top: 9px; right: 11px;
  font-size: 18px; font-weight: 600; line-height: 1;
  color: var(--muted); opacity: .85; text-shadow: none; text-decoration: none;
}
body.ts-app .uk-notify-message .close:hover { color: var(--head); opacity: 1; }

/* =====================================================================
   Dark-mode contrast fixes (WCAG AA)
   In dark mode the --blue token flips to a LIGHT accent blue (#83a6c5) and
   --red to a light red (#E5716D). Several solid buttons/badges kept these as
   their *background* under white/near-white text, dropping to ~2.4–3.4:1.
   Re-point those backgrounds at the dark --navy (#00578E, white ≈7.6:1) and a
   fixed accessible red so the on-button text passes. (Light theme unaffected —
   these are body.is-dark only.)
   ===================================================================== */
body.is-dark.ts-app .btn-primary:hover, body.is-dark.ts-app .btn-primary:focus,
body.is-dark.ts-app .btn-primary:active, body.is-dark.ts-app .btn-primary:active:hover,
body.is-dark .ts-main .btn-success:hover, body.is-dark .ts-main .btn-success:focus,
body.is-dark .ts-main .btn-success:active, body.is-dark .ts-main .btn-success:active:hover,
body.is-dark .ob-sumavatar,
body.is-dark .ts-main .k-scheduler .k-event {
    background: var(--navy);
    border-color: var(--navy);
    color: #F2F7FB;
}
body.is-dark .ts-btn.is-danger,
body.is-dark .ts-main .btn-danger,
body.ts-app.is-dark .swal2-styled.swal2-deny {
    background: #CE2D32 !important;   /* dark --red (#E5716D) gives white only ~3:1 */
    border-color: #CE2D32 !important;
    color: #fff !important;
}

/* =====================================================================
   REQUEST LISTS — shared row/toolbar language for the citizen Service
   Requests list (Areas/Issue/Views/Home) and the staff Employee Requests
   list (Areas/Employee/Views/PayrollView). Both pages render the same
   "mb-mail"-era kendo template + bootstrap filter bar; these classes
   replace that presentation only — every data-bind/id/class the TS
   controllers (complaintsview.ts, payrollview.ts) rely on is untouched.
   ===================================================================== */
.ts-app .sr-filterbar { display: flex; gap: 10px; margin-bottom: 18px; align-items: flex-start; flex-wrap: wrap; }
/* .sr-searchgroup wraps the original, untouched .input-group (Filters dropdown +
   .wrapper_ts_overlay). That inner markup keeps bootstrap's table/table-cell
   display so the absolutely-positioned syntax-highlight overlay (search_overlay.css)
   still has a sized, positioned ancestor — see the comment on .servicerequest-filter
   above. We only let it grow inside the new flex toolbar and restyle the buttons. */
.ts-app .sr-filterbar .sr-searchgroup { display: table; flex: 1 1 320px; min-width: 220px; }
.ts-app .sr-filterbar .wrapper_ts_overlay .form-control,
.ts-app .sr-filterbar #issue-search,
.ts-app .sr-filterbar #payroll-search { border-radius: 0 10px 10px 0; height: 42px; }
.ts-app .sr-filterbar .input-group-btn > .btn { height: 42px; border: 1px solid var(--line); background: var(--card); color: var(--text); }
.ts-app .sr-filterbar .input-group-btn > .btn:first-child { border-radius: 10px 0 0 10px; }
.ts-app .sr-filterbar .input-group-btn > .btn:last-child { border-radius: 0; border-left: none; }
.ts-app .sr-spinner:empty { display: none; }
.ts-app .sr-viewtoggle { display: flex; border: 1px solid var(--line); border-radius: 9px; overflow: hidden; background: var(--card); flex: none; align-self: center; }
.ts-app .sr-viewtoggle .btn {
  border: none; border-radius: 0; box-shadow: none; margin: 0; padding: 10px 16px;
  font-size: 13px; font-weight: 600; background: var(--card); color: var(--muted);
}
.ts-app .sr-viewtoggle .btn + .btn { border-left: 1px solid var(--line); }
.ts-app .sr-viewtoggle .btn.btn-info { background: var(--blue-soft); color: var(--navy); }
.ts-app .sr-filterbar .sr-savequery { height: 42px; border: 1px solid var(--line); border-radius: 10px; background: var(--card); color: var(--text); font-size: 13px; font-weight: 600; padding: 0 16px; align-self: center; }

.ts-app .servicerequest-panel {
  background: var(--card); border: 1px solid var(--line); border-radius: 13px;
  box-shadow: 0 1px 2px rgba(12,44,73,0.04); overflow: hidden;
}
.ts-app .servicerequest-panel .panel-body { padding: 0; }
.ts-app .servicerequest-panel #issuesearchresults { margin: 0; }
.ts-app .servicerequest-panel #issuesearchresults > tbody > tr > td { padding: 0; border-top: none; }
.ts-app .servicerequest-panel .table-hover > tbody > tr:hover { background: none; }

.ts-app .sr-rows { padding: 6px 0; }
.ts-app .sr-row { display: flex; align-items: flex-start; gap: 16px; padding: 14px 20px; text-decoration: none !important; }
.ts-app .sr-row:hover { background: var(--inset); }
.ts-app .sr-row + .sr-row { border-top: 1px solid var(--line-soft); }
.ts-app .sr-thumb {
  width: 44px; height: 44px; border-radius: 10px; flex: none; margin-top: 2px;
  display: grid; place-items: center; border: 1px solid var(--line-soft); background: var(--inset);
  overflow: hidden;
}
.ts-app .sr-thumb img { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
.ts-app .sr-main { min-width: 0; flex: 1; }
.ts-app .sr-title { font-size: 14.5px; font-weight: 700; color: var(--head); }
.ts-app .sr-owner { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
/* WAVE flagged .sr-owner/.sr-age/.sr-id specifically in dark mode (48 of the
   reported 50 "very low contrast" errors) — var(--muted)/var(--faint) render
   too dim in practice at this small a font size against the card surface.
   var(--text) carries much more margin (~8:1 vs --card) without affecting
   light mode, which wasn't flagged. */
body.ts-app.is-dark .sr-owner,
body.ts-app.is-dark .sr-age { color: var(--text); }
.ts-app .sr-chips { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; align-items: center; }
.ts-app .sr-status {
  font-size: 11px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase;
  border-radius: 999px; padding: 3px 9px; display: inline-flex; align-items: center; gap: 6px; flex: none;
  color: #1A6B2C; background: #EAF5EE; border: 1px solid #D3E8DB; /* var(--green) is only 2.92:1 here — fails AA */
}
.ts-app .sr-status::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.ts-app .sr-status.is-pending { color: var(--blue); background: var(--blue-soft); border-color: var(--blue-line); }
.ts-app .sr-status.is-solved  { color: var(--muted); background: var(--inset); border-color: var(--line); }
.ts-app .sr-status.is-closed,
.ts-app .sr-status.is-declined { color: #B71C1C; background: #FBE9E8; border-color: #F3CFCD; } /* var(--red) is 4.43:1 — fails AA at this weight/size */
.ts-app .sr-status.is-approved { color: var(--navy); background: var(--blue-soft); border-color: var(--blue-line); }
.ts-app .sr-status.is-unsubmitted { color: #875200; background: #FBF2E1; border-color: #F0DFB8; } /* var(--amber) is only 2.33:1 here — fails AA */
/* --blue-soft/--inset re-tint for dark mode automatically, but these three use fixed light
   tints and a hardcoded light-mode-only text colour above — need an explicit dark pairing */
body.ts-app.is-dark .sr-status { color: var(--green); background: rgba(63,168,110,0.14); border-color: rgba(63,168,110,0.35); }
body.ts-app.is-dark .sr-status.is-closed,
body.ts-app.is-dark .sr-status.is-declined { color: var(--red); background: rgba(210,101,92,0.16); border-color: rgba(210,101,92,0.35); }
body.ts-app.is-dark .sr-status.is-approved { color: var(--blue); }
body.ts-app.is-dark .sr-status.is-unsubmitted { color: var(--amber); background: rgba(221,148,52,0.16); border-color: rgba(221,148,52,0.35); }
.ts-app .sr-tag {
  font-size: 11px; font-weight: 600; color: var(--muted);
  background: var(--inset); border: 1px solid var(--line-soft);
  border-radius: 999px; padding: 3px 9px; flex: none;
}
.ts-app .sr-tag.is-attach { display: inline-flex; align-items: center; gap: 4px; }
.ts-app .sr-meta { margin-left: auto; text-align: right; flex: none; padding-left: 12px; }
.ts-app .sr-date { font-size: 13px; font-weight: 600; color: var(--head); }
.ts-app .sr-age { font-size: 12px; color: var(--muted); margin-top: 1px; }
.ts-app .sr-id { font-size: 11.5px; color: var(--faint); margin-top: 1px; font-family: ui-monospace, 'SF Mono', Menlo, monospace; }
body.ts-app.is-dark .sr-id { color: var(--text); }
/* SLA breach highlight (was an inline row background-color) now reads as a left accent bar instead
   of a full-row wash, which stayed legible with the new card surface */
.ts-app .sr-row.is-sla12 { box-shadow: inset 3px 0 0 var(--amber); }
.ts-app .sr-row.is-sla24 { box-shadow: inset 3px 0 0 #E38A3D; }
.ts-app .sr-row.is-sla48 { box-shadow: inset 3px 0 0 var(--red); }

/* =====================================================================
   MANAGE EVENTS (Admin) — Areas/Admin/Views/Events/Index. Search bar and
   tabs already carry the redesign (.pg-eventsearch/.pg-tabs); this covers
   the pagehead, the event list (now a plain table instead of stacked
   cards) and the sidebar (legend/stats/useful links). All ids
   (eventName_/eventDate_/fbpostImg_/fbStatus_/registrationChart/
   revenueChart) and kendo bindings that manageEvents.ts reads are kept
   exactly as-is — only the surrounding markup/classes changed.
   ===================================================================== */
.ts-app .evm-card { background: var(--card); border: 1px solid var(--line); border-radius: 13px; box-shadow: 0 1px 2px rgba(12,44,73,0.04); overflow: hidden; padding: 4px 0; }
.ts-app .evm-table { width: 100%; border-collapse: collapse; }
.ts-app .evm-table th {
  text-align: left; font-size: 11px; font-weight: 700; letter-spacing: .4px; text-transform: uppercase;
  color: var(--faint); padding: 12px 24px; border-bottom: 1px solid var(--line-soft);
}
.ts-app .evm-table th.is-right { text-align: right; }
.ts-app .evm-row > td { padding: 16px 24px; border-top: 1px solid var(--line-soft); vertical-align: middle; }
.ts-app .evm-row:first-child > td { border-top: none; }
.ts-app .evm-col-event { max-width: 0; width: 40%; }
.ts-app .evm-title { font-size: 14.5px; font-weight: 600; color: var(--head); text-decoration: none; }
.ts-app .evm-title:hover { color: var(--blue); text-decoration: none; }
.ts-app .evm-rowlinks { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 5px; }
.ts-app .evm-rowlinks a { font-size: 12px; font-weight: 600; color: var(--muted); text-decoration: none; }
.ts-app .evm-rowlinks a:hover { color: var(--blue); text-decoration: none; }
.ts-app .evm-col-starts, .ts-app .evm-col-cat { font-size: 13.5px; color: var(--text); white-space: nowrap; }
.ts-app .evm-notsched { color: var(--muted); font-style: italic; text-decoration: none; }
.ts-app .evm-col-reg { font-size: 13.5px; color: var(--text); white-space: nowrap; }
.ts-app .evm-col-reg.is-right, .ts-app .evm-col-status.is-right { text-align: right; }
.ts-app .evm-regwrap { display: inline-flex; flex-direction: column; align-items: flex-end; gap: 5px; width: 90px; }
.ts-app .evm-fraction { font-size: 12.5px; color: var(--muted); }
.ts-app .evm-bar.progress { width: 100%; height: 6px; border-radius: 999px; background: var(--inset); box-shadow: none; overflow: hidden; margin: 0; display: flex; }
.ts-app .evm-bar .progress-bar { box-shadow: none; float: none; }
.ts-app .evm-pill {
  font-size: 12px; font-weight: 700; border-radius: 999px; padding: 4px 12px; display: inline-block;
  color: #1A6B2C; background: #EAF5EE; /* var(--green) is only 2.92:1 here — fails AA */
}
.ts-app .evm-pill.is-draft { color: #875200; background: #FBF2E1; } /* var(--amber) is only 2.33:1 here — fails AA */
.ts-app .evm-pill.is-past { color: var(--muted); background: var(--inset); }
.ts-app .evm-pill.is-archived { color: var(--faint); background: var(--inset); }
body.ts-app.is-dark .evm-pill { color: var(--green); background: rgba(63,168,110,0.14); }
body.ts-app.is-dark .evm-pill.is-draft { color: var(--amber); background: rgba(221,148,52,0.16); }
.ts-app .evm-foot { padding: 13px 24px; border-top: 1px solid var(--line-soft); font-size: 12.5px; color: var(--muted); }
.ts-app .evm-foot b { color: var(--head); }

.ts-app .evm-legend { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; padding: 14px 18px; }
.ts-app .evm-legend-title { font-size: 13px; font-weight: 700; color: var(--head); flex: none; }
.ts-app .evm-legend-row { display: flex; gap: 8px; flex-wrap: wrap; }
.ts-app .evm-legend-chip {
  font-size: 11px; font-weight: 700; letter-spacing: .3px; text-transform: uppercase;
  border-radius: 999px; padding: 3px 10px; display: inline-flex; align-items: center; gap: 6px;
}
.ts-app .evm-legend-chip::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.ts-app .evm-legend-chip.is-danger { color: #B71C1C; background: #FBE9E8; } /* var(--red) is 4.43:1 — fails AA at this weight/size */
.ts-app .evm-legend-chip.is-success { color: #1A6B2C; background: #EAF5EE; } /* var(--green) is only 2.92:1 here — fails AA */
.ts-app .evm-legend-chip.is-warning { color: #875200; background: #FBF2E1; } /* var(--amber) is only 2.33:1 here — fails AA */
body.ts-app.is-dark .evm-legend-chip.is-danger { color: var(--red); background: rgba(210,101,92,0.16); }
body.ts-app.is-dark .evm-legend-chip.is-success { color: var(--green); background: rgba(63,168,110,0.14); }
body.ts-app.is-dark .evm-legend-chip.is-warning { color: var(--amber); background: rgba(221,148,52,0.16); }
.ts-app .evm-stats { margin-top: 14px; padding: 6px 18px; }
.ts-app .evm-stat { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 12px 0; }
.ts-app .evm-stat + .evm-stat { border-top: 1px solid var(--line-soft); }
.ts-app .evm-stat-num { font-size: 20px; font-weight: 700; color: var(--head); line-height: 1.2; }
.ts-app .evm-stat-label { font-size: 12px; color: var(--muted); margin-top: 2px; }
.ts-app .evm-stat-chart { flex: none; }
.ts-app .evm-links { margin-top: 14px; padding: 6px 6px; }
.ts-app .evm-links-title { font-size: 13px; font-weight: 700; color: var(--head); padding: 8px 14px; }
.ts-app .evm-links-list { display: flex; flex-direction: column; }
.ts-app .evm-link {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 14px; font-size: 13.5px; font-weight: 600; color: var(--text);
  text-decoration: none; border-radius: 9px;
}
.ts-app .evm-link:hover { background: var(--inset); color: var(--head); text-decoration: none; }
.ts-app .evm-link .ts-arrow { color: var(--muted); font-size: 14px; }
.card-footer:last-child { border-radius: 0 0 12px 12px; }

/* =====================================================================
   AUTH PAGES (body.ts-app.pg-auth) — split screen: the form column on the
   left, the town photo + welcome message on the right.

   Applies to the views that share ~/Views/Shared/_SiteLayoutLogin.cshtml
   (sign in, sign up, resend verification, reset password, verify).

   What this styles is deliberately the ORIGINAL login markup with new
   classes layered on: every element id, name, data-* and aria-* is
   preserved, because login.ts / forgotpassword.ts / createuser.ts and a
   Kendo validator all bind by id (and Site/CLAUDE.md forbids changing
   ids). So these rules mostly re-layout existing nodes rather than
   assuming a clean new DOM.

   The page also still loads the legacy CDN login-light/login-dark.css and
   /bundles/loginpagestyle, because the not-yet-converted sign-up form
   needs them — so several rules here are scoped under body.pg-auth purely
   to win specificity against that older sheet.
   ===================================================================== */
body.pg-auth { background: var(--bg); color: var(--text); min-height: 100vh; margin: 0; }

/* ---- split shell ---- */
body.pg-auth .au-split { display: flex; align-items: stretch; min-height: 100svh; }
/* the column takes the page background tone so the form card (below) reads as
   a panel sitting on it — a --card panel on a --card column would be invisible */
body.pg-auth .au-formcol {
  flex: 1 1 50%; min-width: 0; display: flex; flex-direction: column;
  background: var(--bg);
}

/* ---- form column: header ---- */
body.pg-auth .au-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 18px 28px; flex: none;
}
body.pg-auth .au-brand { display: flex; align-items: center; gap: 11px; text-decoration: none; min-width: 0; }
body.pg-auth .au-brand-logo { display: block; height: 40px; width: auto; max-width: 168px; object-fit: contain; }
body.pg-auth .au-brand-tx { display: flex; flex-direction: column; min-width: 0; }
body.pg-auth .au-brand-name {
  font-size: 14.5px; font-weight: 700; color: var(--head); letter-spacing: -0.2px;
  line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
body.pg-auth .au-brand-sub { font-size: 12px; color: var(--muted); line-height: 1.25; }
body.pg-auth .au-head-right { display: flex; align-items: center; gap: 10px; flex: none; }
body.pg-auth .au-back {
  font-size: 13px; font-weight: 600; color: var(--muted); text-decoration: none; white-space: nowrap;
}
body.pg-auth .au-back:hover { color: var(--head); text-decoration: none; }

/* ---- IMPORTANT: the is-dark class does NOT exist on these pages ----
   Auth pages are logged out, so there is no saved theme to render server-side.
   They get dark TOKENS from `body.ts-app.pg-auth.is-auto` inside a
   @media (prefers-color-scheme: dark) block, but nothing ever adds the is-dark
   CLASS. Any rule written as `body.is-dark .foo` therefore silently does not
   apply here — which is a real trap, because several such rules exist purely to
   fix contrast in dark mode. Anything auth pages rely on must either use tokens
   (which do flip) or be duplicated for .is-auto inside the media block below.

   .pg-kicker was the casualty: its base colour is --navy and the dark-mode
   correction to --blue lives on `body.is-dark .pg-kicker`, so in auto-dark the
   kicker stayed #00578E on a #0D2032 card — roughly 2.2:1, failing AA.
   --blue clears AA against BOTH surfaces (~7.6:1 on white, ~7:1 on the dark
   card), so using it unconditionally here fixes dark without a class
   dependency and without touching .pg-kicker anywhere else in the site. */
body.pg-auth .pg-kicker { color: var(--blue); }
/* same trap, same fix: the dark-mode accent correction lives on
   `body.is-dark .ts-check input`, so in auto-dark these controls kept the light
   --navy fill against a dark surface. --blue reads correctly on both. */
body.pg-auth .ts-check input { accent-color: var(--blue); }

/* ---- form column: body ----
   Vertically centred, with a comfortable reading measure. The panes are
   width-capped individually rather than through one shared wrapper because
   the sign-up form (still on the legacy markup) needs more room than the
   sign-in form. */
body.pg-auth .au-body {
  flex: 1 1 auto; display: flex; flex-direction: column; justify-content: center;
  padding: 8px 28px 32px; min-width: 0;
}
body.pg-auth #LoginPage,
body.pg-auth #login,
body.pg-auth #success_message { width: 100%; max-width: 400px; margin: 0 auto; }

/* ---- the form panel ----
   Each auth pane sits in a card, matching the panels the sign-up screens get
   from their legacy .panel markup. Targeted by id because #login / #forgot are
   shown and hidden by login.ts (jQuery .toggle()), so they must not be given a
   display value here — only surface styling. */
body.pg-auth .au-body #login,
body.pg-auth .au-body #forgot,
body.pg-auth .au-body #success_message {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 26px 24px;
  box-shadow: 0 1px 2px rgba(12,44,73,0.05);
}
/* the card already provides the top gutter */
body.pg-auth .au-body #login > :first-child,
body.pg-auth .au-body #forgot > :first-child { margin-top: 0; }
@media (max-width: 640px) {
  body.pg-auth .au-body #login,
  body.pg-auth .au-body #forgot,
  body.pg-auth .au-body #success_message { padding: 20px 16px; }
}
body.pg-auth #SignUpPage { width: 100%; max-width: 620px; margin: 0 auto; }
/* #LoginPage already caps its own width; don't cap the nested #login again or
   the two margins compound */
body.pg-auth #LoginPage #login { max-width: none; margin: 0; }

/* The culture <select> is populated by internationalization.js after DOM ready.
   Keep it out of sight until it has options so it never flashes as an empty
   control. (Progressive: browsers without :has() just show it immediately.) */
body.pg-auth #ddlCulture:not(:has(option)) { visibility: hidden; }

/* the legacy centring/width helpers on the panes are redundant now that
   .au-body centres them, and their fixed widths fight the caps above */
body.pg-auth .block-center, body.pg-auth .wd-login, body.pg-auth .mt-login {
  width: auto; max-width: none; margin-left: 0; margin-right: 0; margin-top: 0;
}

/* ---- headings ---- */
body.pg-auth .au-h1 {
  font-size: clamp(23px, 2.5vw, 29px); font-weight: 700; letter-spacing: -0.5px;
  line-height: 1.16; color: var(--head); margin: 12px 0 8px;
}
body.pg-auth .au-sub { font-size: 14px; color: var(--muted); line-height: 1.5; margin: 0 0 22px; }

/* ---- fields ----
   .au-inputwrap is a new primitive: the design system had no "icon inside a
   text input" component. The old markup used Bootstrap's .has-feedback +
   .form-control-feedback, which is tied to Bootstrap's own form-group
   geometry and cannot be reused on a .ts-field. */
body.pg-auth .au-form { display: flex; flex-direction: column; gap: 15px; margin: 0 0 18px; }
body.pg-auth .au-inputwrap { position: relative; display: block; }
body.pg-auth .au-inputwrap > input { padding-right: 40px; }
body.pg-auth .au-inputic {
  position: absolute; top: 50%; right: 13px; transform: translateY(-50%);
  font-size: 14px; line-height: 1; color: var(--muted); pointer-events: none;
  z-index: 2;
}

/* ---- Kendo AutoComplete fields inside .au-inputwrap ----
   #inputForgotEmail (forgot password) and #EmailaddressVerify (resend
   verification) are Kendo AutoComplete widgets: forgotpassword.ts:54 and
   resendemailverification.ts:30 call .kendoAutoComplete() on them.

   Kendo moves the <input> into a wrapper <span class="k-input k-input-solid
   k-input-md ..."> which carries the border/background, while the input keeps
   whatever classes it already had and gains .k-input-inner. So .ts-input on
   the input drew a SECOND border inside Kendo's wrapper — a visible
   box-in-a-box on both of those screens.

   Fix: make the Kendo wrapper the field (restyled to the design tokens) and
   flatten the inner input. .ts-input is deliberately left on the markup so the
   field still looks correct in the moment before Kendo initialises, and if the
   widget never initialises at all. */
body.pg-auth .au-inputwrap .k-input {
  display: flex; align-items: center;
  min-height: 40px; width: 100%; box-sizing: border-box;
  border: 1px solid var(--line); border-radius: 9px;
  background: var(--card); color: var(--text);
  font: inherit; font-size: 14px; padding: 0; box-shadow: none;
}
body.pg-auth .au-inputwrap .k-input:focus-within {
  border-color: var(--blue); box-shadow: 0 0 0 3px rgba(31,111,165,0.14);
}
/* .ts-input carries `border-radius: ... !important`, so overriding it here
   needs !important too */
body.pg-auth .au-inputwrap .k-input .ts-input,
body.pg-auth .au-inputwrap .k-input .k-input-inner {
  border: 0 !important; border-radius: 0 !important;
  background: transparent; box-shadow: none; outline: none;
  min-height: 38px; width: 100%;
  padding: 0 40px 0 12px; /* right gap clears .au-inputic */
  font: inherit; font-size: 14px; color: var(--text);
}
body.pg-auth .au-inputwrap .k-input .ts-input:focus,
body.pg-auth .au-inputwrap .k-input .k-input-inner:focus {
  border: 0 !important; box-shadow: none; outline: none;
}
/* The suggestion popup is appended at body level (outside .au-inputwrap), so it
   needs its own token-based styling — otherwise it renders in Kendo's light
   default theme over a dark page. */
body.pg-auth .k-list-container, body.pg-auth .k-popup {
  background: var(--card); border: 1px solid var(--line); border-radius: 10px;
  color: var(--text); box-shadow: 0 14px 34px rgba(12,44,73,0.18);
}
body.pg-auth .k-list-item { color: var(--text); }
body.pg-auth .k-list-item.k-hover, body.pg-auth .k-list-item:hover,
body.pg-auth .k-list-item.k-focus, body.pg-auth .k-list-item.k-selected {
  background: var(--inset); color: var(--head);
}
/* label row with a trailing action (e.g. "Forgot your password?") */
body.pg-auth .au-labelrow { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
body.pg-auth .au-minilink {
  font-size: 12.5px; font-weight: 600; color: var(--blue); cursor: pointer;
  text-decoration: none; background: none; border: 0; padding: 0;
}
body.pg-auth .au-minilink:hover { text-decoration: underline; color: var(--blue); }
/* checkbox + trailing link on one line */
body.pg-auth .au-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin: -2px 0 4px;
}
/* The legacy login sheet follows the Angle theme pattern of hiding the native
   checkbox and drawing a styled .indicator span in its place. The redesigned
   markup drops .indicator and styles the real control via .ts-check
   (accent-color), so force the native box back into view in case any of those
   older rules still reach it. */
body.pg-auth .ts-check input[type="checkbox"] {
  opacity: 1; position: static; margin: 0;
  width: 17px; height: 17px; -webkit-appearance: checkbox; appearance: checkbox;
}
body.pg-auth .ts-check { margin: 0; }

/* "I agree to the Terms of Service and Privacy Policy" row. The links used to
   sit INSIDE the <label>, so clicking either one also toggled the checkbox;
   they are siblings now (ids unchanged, so the JS handlers still bind). */
body.pg-auth .au-agree {
  display: flex; align-items: center; flex-wrap: wrap; gap: 3px 6px;
  font-size: 13.5px; color: var(--text);
}
body.pg-auth .au-agree a { color: var(--blue); font-weight: 600; cursor: pointer; text-decoration: none; }
body.pg-auth .au-agree a:hover { text-decoration: underline; }
/* password strength / match-validation messages */
body.pg-auth #passwordStrength, body.pg-auth #matchPasswords { font-size: 12.5px; }
body.pg-auth #matchPasswords { color: var(--red); }

/* "next step" link lists on the verification / confirmation pages (these
   replace Bootstrap's .list-group, which is not part of the design system) */
body.pg-auth .au-linklist { list-style: none; margin: 18px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
body.pg-auth .au-linklist li { margin: 0; }
body.pg-auth .au-linklist a {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 12px 14px; border: 1px solid var(--line); border-radius: 10px;
  background: var(--card); color: var(--head);
  font-size: 13.5px; font-weight: 600; text-decoration: none;
}
body.pg-auth .au-linklist a::after { content: '\2192'; color: var(--muted); font-weight: 400; }
body.pg-auth .au-linklist a:hover { background: var(--inset); border-color: var(--blue-line); text-decoration: none; }

/* ---- buttons ---- */
body.pg-auth .au-btnstack { display: flex; flex-direction: column; gap: 10px; }
body.pg-auth .au-btnrow { display: flex; gap: 10px; }
body.pg-auth .au-btnrow > * { flex: 1 1 0; min-width: 0; }
body.pg-auth .au-btnsm { height: 36px; padding: 0 12px; font-size: 12.5px; }

/* =====================================================================
   SIGN-UP (#SignUpPage, Views/Login/_Signup.cshtml)
   Still on the legacy Bootstrap markup — ~40 element ids are bound by
   createuser.ts and a Kendo validator rooted at #DesktopLoginFields, and
   Site/CLAUDE.md forbids changing ids, so this is a CSS-only reskin.

   The guest / resident-or-business option buttons in particular CANNOT be
   restyled from markup: createuser.ts ConfigureSignupOptions() injects them
   into the empty #DivOptionSignUpContent at runtime as
   `.btn.btn-primary.btn-large.btn-block` separated by <br>.
   ===================================================================== */

/* legacy .panel chrome -> design-system card */
body.pg-auth #SignUpPage .panel {
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: 0 1px 2px rgba(12,44,73,0.05); margin: 0;
}
body.pg-auth #SignUpPage .panel-heading {
  background: transparent; border: 0; border-bottom: 1px solid var(--line-soft);
  border-radius: 14px 14px 0 0; padding: 16px 18px;
  color: var(--head); font-size: 16px; font-weight: 700; letter-spacing: -0.2px;
}
body.pg-auth #SignUpPage .panel-heading .modal-title,
body.pg-auth #SignUpPage .panel-heading h4 {
  margin: 0; font-size: 17px; font-weight: 700; color: var(--head); letter-spacing: -0.2px;
}
body.pg-auth #SignUpPage .panel-body { padding: 18px; }
body.pg-auth #SignUpPage .panel-footer {
  background: transparent; border: 0; border-top: 1px solid var(--line-soft);
  border-radius: 0 0 14px 14px; padding: 14px 18px;
  display: flex; justify-content: flex-end; gap: 10px;
}

/* ---- the guest / resident-or-business option list ----
   Styled as a stack of pickable options (outline + trailing arrow, matching
   .au-linklist) rather than a stack of primary buttons: this is a "choose one"
   step, so no single option should read as the confirmed action. */
/* NB: the injected options ship with `.btn.btn-primary` on them, and the
   project-wide rule near the top of this file paints ANY .btn.btn-primary navy
   with `!important` (it has to, to beat the legacy theme sheets). So the colour
   properties here need !important too — specificity alone loses to it, however
   many ids the selector carries. Layout properties override normally. */
body.pg-auth #SignUpPage #DivOptionSignUpContent { display: flex; flex-direction: column; gap: 10px; }
body.pg-auth #SignUpPage #DivOptionSignUpContent br { display: none; }
body.pg-auth #SignUpPage #DivOptionSignUpContent .btn {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; height: auto; margin: 0; float: none; text-align: left;
  min-height: 48px; padding: 11px 16px;
  border: 1px solid var(--line) !important; border-radius: 11px;
  background-color: var(--card) !important; background-image: none !important;
  color: var(--head) !important;
  font-family: inherit; font-size: 14px; font-weight: 700; line-height: 1.35;
  white-space: normal; text-shadow: none; box-shadow: none;
  transition: background-color .12s ease, border-color .12s ease;
}
body.pg-auth #SignUpPage #DivOptionSignUpContent .btn::after {
  content: '\2192'; color: var(--muted); font-weight: 400; flex: none;
}
body.pg-auth #SignUpPage #DivOptionSignUpContent .btn:hover,
body.pg-auth #SignUpPage #DivOptionSignUpContent .btn:focus {
  background-color: var(--inset) !important;
  border-color: var(--blue-line) !important;
  color: var(--head) !important;
}
body.pg-auth #SignUpPage #DivOptionSignUpContent .btn:active { transform: translateY(1px); }

/* ---- ordinary sign-up buttons (Close / Sign up / Register) ---- */
body.pg-auth #SignUpPage .btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 40px; padding: 0 18px; border-radius: 11px;
  font-family: inherit; font-size: 13.5px; font-weight: 700;
  border: 1px solid var(--line); background: var(--card); color: var(--head);
  text-shadow: none; box-shadow: none; float: none;
}
body.pg-auth #SignUpPage .btn:hover { background: var(--inset); color: var(--head); }
body.pg-auth #SignUpPage .btn.btn-primary {
  background: var(--navy); border-color: var(--navy); color: #fff;
  box-shadow: 0 6px 16px rgba(0,87,142,0.16);
}
body.pg-auth #SignUpPage .btn.btn-primary:hover { filter: brightness(1.12); background: var(--navy); color: #fff; }
body.pg-auth #SignUpPage .btn:disabled, body.pg-auth #SignUpPage .btn[disabled] {
  opacity: .5; box-shadow: none; filter: none;
}

/* ---- radios + checkboxes ----
   The legacy Angle pattern hides the native control and draws a styled
   .indicator span instead. Show the real control (accent-color, as .ts-check
   does elsewhere) and drop the indicator so sign-up matches the other pages.
   Note #spambot's checkbox is injected by createuser.ts with the same
   .indicator markup, so this covers it too. */
body.pg-auth #SignUpPage input[type="checkbox"],
body.pg-auth #SignUpPage input[type="radio"] {
  opacity: 1; position: static; margin: 0 8px 0 0; flex: none;
  width: 17px; height: 17px; appearance: auto; -webkit-appearance: auto;
  /* --blue, not --navy: see the is-dark note in the AUTH PAGES header — a
     dark-mode-only correction would never apply on these pages */
  accent-color: var(--blue); cursor: pointer;
}
body.pg-auth #SignUpPage .indicator { display: none; }
body.pg-auth #SignUpPage .radio-inline label,
body.pg-auth #SignUpPage .radio label,
body.pg-auth #SignUpPage .checkbox label {
  display: flex; align-items: center; margin: 0; padding: 0;
  font-size: 13.5px; font-weight: 500; color: var(--text); cursor: pointer;
}
body.pg-auth #SignUpPage .radio-inline, body.pg-auth #SignUpPage .radio,
body.pg-auth #SignUpPage .checkbox { margin: 0; padding: 0; }

/* ---- field labels + helper text ---- */
body.pg-auth #SignUpPage label { font-size: 12.5px; font-weight: 600; color: var(--head); }
body.pg-auth #SignUpPage .help-block { font-size: 12.5px; color: var(--muted); }
body.pg-auth #SignUpPage .k-invalid-msg, body.pg-auth #SignUpPage .k-tooltip-validation { color: var(--red); font-size: 12.5px; }

/* ---- right-hand panel: town photo + welcome message ---- */
/* copy sits at the TOP of the panel, not vertically centred, so it reads as a
   masthead over the photo rather than floating in the middle of it */
body.pg-auth .au-panel {
  flex: 1 1 50%; min-width: 0; position: relative; overflow: hidden;
  display: flex; flex-direction: column; justify-content: flex-start;
  padding: 48px 52px; background: var(--navy-deep);
}
/* #bg carries the town uploaded login photo. _SiteLayoutLogin.cshtml sets only
   the background-image inline (it owns the URL); the sizing lives here so the
   six auth views no longer each need their own #bg <style> block. */
body.pg-auth .au-panel #bg {
  position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%;
  background-repeat: no-repeat; background-position: center center; background-size: cover;
}
/* navy scrim so white copy stays legible over an arbitrary town photo */
/* 20% navy scrim — the photo reads at ~80% strength. Light enough that the
   welcome copy no longer gets its contrast from the scrim alone, so the text
   carries a shadow (see .au-panel-tx) to stay legible over a bright photo. */
body.pg-auth .au-panel::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: rgba(0,40,66,0.2);
}
body.pg-auth .au-panel-tx {
  position: relative; z-index: 2; max-width: 470px;
  text-shadow: 0 1px 4px rgba(0,18,32,0.6);
}
/* !important here deliberately overrides TWO other colour sources, both of
   which predate the navy scrim and are unreadable against it:
     1. Town-authored HTML in TownWelcomeMessage, whose inline colours were
        picked for the old light background.
     2. login.ts colorstuff(), which samples the average RGB of the town photo,
        inverts it, and sets the result as an inline style on
        #the_login_welcome. That was how contrast used to be achieved when the
        text sat directly on the photo; the scrim now guarantees contrast, so
        the computed colour is redundant and its result is intentionally
        neutralised here. (A stylesheet !important beats a non-important inline
        style, so this wins.) The JS still runs harmlessly — it is left in
        place because the shipped file is the compiled login.js. */
body.pg-auth .au-panel-tx, body.pg-auth .au-panel-tx * { color: #fff !important; }
body.pg-auth .au-panel-tx h1, body.pg-auth .au-panel-tx h2 {
  font-size: clamp(26px, 3.1vw, 37px); font-weight: 700; letter-spacing: -0.7px;
  line-height: 1.13; margin: 0 0 14px;
}
body.pg-auth .au-panel-tx .welcom-msg, body.pg-auth .au-panel-tx p {
  display: block; font-size: 15px; line-height: 1.55; margin: 0;
}
body.pg-auth .au-panel-tx .welcom-msg * { font-size: inherit; }
/* .pg-kicker is navy by default — unreadable on the navy panel */
body.pg-auth .au-panel .pg-kicker { color: #fff; margin-bottom: 14px; }

/* ---- footer: the shared .pr-footer sits at the base of the form column ---- */
body.pg-auth .au-formcol .pr-footer { flex: none; background: transparent; }

/* ---- responsive ----
   The panel is decorative plus the welcome message; the original markup
   already hid both below Bootstrap's md breakpoint (.visible-md.visible-lg
   on #bg, .hidden-xs on #the_login_welcome), so keep that behaviour and
   give the form the full width. */
@media (max-width: 991px) {
  body.pg-auth .au-panel { display: none; }
  body.pg-auth .au-formcol { flex: 1 1 100%; }
}
@media (max-width: 640px) {
  body.pg-auth .au-head { padding: 14px 16px; gap: 8px; }
  body.pg-auth .au-brand-logo { height: 32px; max-width: 120px; }
  body.pg-auth .au-body { padding: 4px 16px 24px; }
  body.pg-auth .au-h1 { font-size: 22px; }
  body.pg-auth .au-back { font-size: 12px; }
}

/* ============================================================
   MAP PROFILES ADMIN (Areas/Mapping/Views/Profiles/Admin.cshtml)
   Page was on the legacy _SiteLayout with an inline <style> block; moved onto
   _SiteLayout.TownSuite + the tokens here. .mp-pill is emitted by
   map-profiles-admin.ts (buildGrid), so that class name must not be renamed.
   ============================================================ */
/* Vendor sheets paint .tab-content as a solid slab with no radius, which put a
   big square panel behind the cards. The .pg-card sections supply their own
   surfaces, so the tab body itself must be transparent.
   !important is required, not just specificity: theme-light.css sets
   `background: var(--bg-white)` (beatable at (0,5,1)) but theme-dark.css sets
   `.tab-content { background: var(--main-panel-color) !important }`, so without
   it the slab reappeared in dark mode only. */
body.ts-app .ts-main .tab-content.mp-tabcontent {
  background: transparent !important;
  border: 0;
  padding: 16px 0 0;
}

/* main / preview split — mirrors the old col-md-7 + col-md-5 proportions */
.mp-cols { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: 16px; align-items: start; }
.mp-col-main, .mp-col-side { min-width: 0; }
.mp-card-gap { margin-top: 16px; }

.mp-btnrow { display: flex; flex-wrap: wrap; gap: 8px; }
.mp-hint { font-size: 12.5px; line-height: 1.5; color: var(--muted); margin: 0 0 12px; }
.mp-rule { border: 0; border-top: 1px solid var(--line-soft); margin: 18px 0 14px; }
.mp-msg:not(:empty) { margin-top: 12px; }

/* Form rows are flex with flex-end alignment so the action buttons sit level
   with the inputs beside them. The old markup faked this with
   <label>&nbsp;</label> spacers, which registered as empty form labels. */
/* Flex bases are kept deliberately small: a flex line breaks on the sum of the
   items' flex-basis (shrinking only happens afterwards, within a line), so
   generous bases pushed the action button onto a row of its own. 150+110+110+125
   plus gaps fits the ~573px main column, then flex-grow shares out the slack. */
.mp-formrow { display: flex; flex-wrap: wrap; gap: 12px 14px; align-items: flex-end; }
.mp-formrow > * { flex: 1 1 110px; min-width: 0; }
.mp-formrow > .mp-field-wide { flex: 1.6 1 150px; }
.mp-formrow > .mp-actionfield { flex: 0 1 125px; }
/* let a long action label ("Generate service area") wrap instead of overflowing
   its 40px pill; align-items:flex-end keeps the bottom edge level with the inputs */
.mp-actionfield .ts-btn { height: auto; min-height: 40px; padding: 9px 14px; line-height: 1.25; white-space: normal; }

.mp-picktoggle {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
  font-size: 13px; font-weight: 600; color: var(--head); margin: 0 0 8px;
}
.mp-mapframe { border: 1px solid var(--line); border-radius: 10px; overflow: hidden; line-height: 0; }
.mp-mapframe iframe { display: block; }

/* modals: these render at body level, outside .ts-main/.ts-formwrap, so the
   design-system form rules don't reach them. Scoped to .mp-modal rather than
   .modal so every other modal in the site is left alone. */
.ts-app .mp-modal .modal-content { border-radius: 13px; border: 1px solid var(--line); background: var(--card); }
.ts-app .mp-modal .modal-header, .ts-app .mp-modal .modal-footer { border-color: var(--line-soft); }
.ts-app .mp-modal .modal-title { font-size: 16px; font-weight: 700; color: var(--head); }
.ts-app .mp-modal .form-control {
  background: var(--card); border: 1px solid var(--line); color: var(--head);
  border-radius: 9px; box-shadow: none;
}
.ts-app .mp-modal .form-control:focus { border-color: var(--blue); box-shadow: 0 0 0 3px var(--blue-soft); }
.ts-app .mp-modal .close { color: var(--head); opacity: .75; text-shadow: none; }
.ts-app .mp-modal .close:hover { opacity: 1; color: var(--head); }
.mp-modalfield { margin-bottom: 14px; }
.mp-modalfield:last-of-type { margin-bottom: 0; }
.mp-checklabel {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
  font-weight: 600; color: var(--head); margin: 0;
}
.mp-narrow { max-width: 130px; }
.mp-modalfoot { display: flex; justify-content: flex-end; gap: 8px; }
.mp-guide { font-size: 12.5px; line-height: 1.6; margin-bottom: 14px; }

/* Yes/No pills in the assigned-layers grid. Light values were already AA
   (6.86:1 / 6.80:1) so they carry over; dark needs its own pairing. The dark
   fills are OPAQUE on purpose — HTML_CodeSniffer (pa11y's runner) does not
   composite alpha, so an rgba() tint reads as ~1:1 to it even when the rendered
   result is fine. These are the composited equivalents. */
.mp-pill { display: inline-block; padding: 2px 9px; border-radius: 999px; font-size: 11.5px; font-weight: 700; }
.mp-pill.yes { background: #D1FAE5; color: #065F46; }
.mp-pill.no  { background: #FEE2E2; color: #991B1B; }
body.ts-app.is-dark .mp-pill.yes { background: #163739; color: var(--green); }
body.ts-app.is-dark .mp-pill.no  { background: #272A39; color: var(--red); }

@media (max-width: 1199px) {
  .mp-cols { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .mp-formrow > *, .mp-formrow > .mp-field-wide, .mp-formrow > .mp-actionfield { flex: 1 1 100%; }
  .mp-modalfoot { flex-wrap: wrap; }
}

/* ============================================================
   DASHBOARD FEED PANEL (Views/Home/Dashboard.cshtml rail)
   Underlined text tabs, uniform row markers and a level bottom edge with the
   apps directory card, per the dashboard design.
   ============================================================ */

/* --- the feed and transactions run their natural length ---
   No flex sizing or internal scrolling: the list shows every row it has loaded
   and the panel grows with it, which is why the rail is free to be taller than
   the apps card. */
/* background:transparent !important for the same reason as .mp-tabcontent on the
   map-profiles page: theme-dark.css sets `.tab-content { background:
   var(--main-panel-color) !important }`, which laid a grey #313D46 slab inside
   the navy card. It also dropped the row age text to 3.70:1, because the rows
   themselves are transparent so that slab was the effective backdrop; against
   the card it is 5.50:1. */
.pg-dashrail .pg-feed > .tab-content { background: transparent !important; }
/* the footer also carries the legacy `.wrapper` class, which sets
   `min-height: 100%`; neutralised so it can never claim more than its content
   (it previously collapsed the list to 0px when this panel was flex-sized) */
.pg-dashrail .pg-feed .panel-footer { min-height: 0; }

/* Tab strip: this panel uses the shared .pg-tabs segmented control (see the
   "tab strips" section further up) rather than a bespoke style, so it matches
   the Admin areas.
   The custom .pg-feedtabs underline treatment that used to live here was removed
   with it — .pg-tabs already sets border-bottom:0, so nothing draws a rule under
   the tabs. */

/* --- feed rows ---
   FeedPanel.ts renders each row as
     <a class="list-group-item …"><span class="badge text-bg-primary pull-right">AGE</span>
      <em class="fa fa-fw fa-…"></em> TEXT</a>
   so the age chip and per-type glyph are restyled in place rather than by
   changing the script (which would need a TypeScript rebuild). */
.pg-feed #feedbody .list-group-item {
  display: flex; align-items: baseline; gap: 10px;
  padding: 11px 2px; border: 0; border-bottom: 1px solid var(--line-soft) !important;
  border-radius: 0 !important; background: transparent !important;
  font-size: 13px; color: var(--text);
}
.pg-feed #feedbody .list-group-item:last-child { border-bottom: 0 !important; }
.pg-feed #feedbody .list-group-item:hover { background: var(--inset) !important; }
/* uniform tilted-square marker, matching .pg-kicker-sq / .pg-alert-node */
/* !important on the box: .fa-fw sets an em-based width, and the glyph classes
   bring their own line-height, so without it the marker sized itself off the
   font rather than the 7px square the design uses */
.pg-feed #feedbody .list-group-item > em.fa {
  flex: none; width: 7px !important; height: 7px !important; margin: 0;
  font-size: 0; line-height: 0; align-self: center;
  background: var(--blue); transform: rotate(45deg);
}
.pg-feed #feedbody .list-group-item > em.fa::before { content: none; }
/* The relative age is plain muted text on the right, not a pill. Clearing the
   background and colour alone left a blue outlined capsule behind: `.label` in the
   commonloggedinstyle bundle carries `border: 1px solid`, .label-primary tints that
   border blue, and the 999px radius comes from this sheet's own
   `.ts-app .ts-main .label` rule — so the border and radius have to be reset too.
   The #feedbody id puts this at (1,3,0), which beats all three without !important. */
.pg-feed #feedbody .list-group-item > .label,
.pg-feed #feedbody .list-group-item > .badge {
  float: none !important; order: 99; margin-left: auto; flex: none;
  background: transparent !important; color: var(--muted) !important;
  border: 0; border-radius: 0; box-shadow: none;
  padding: 0; font-size: 11.5px; font-weight: 600; white-space: nowrap;
}

/* No stacked-layout override is needed any more: the feed is at its natural
   height in both layouts, so the ≤899px single-column case needs nothing beyond
   the .pg-dashcols flex-direction change further up. */

/* --- Event transactions: same visual language as the feed list ---
   Still a real <table> so the columns keep their <th> labels for screen readers,
   but the bordered/striped chrome and the navy pill buttons are dropped in favour
   of the feed's dividers, typography and diamond marker. Scoped to #profile (the
   transactions tab pane) so the feed tab is untouched. */
/* !important is required: theme-light.css and theme-dark.css both declare
   `.table-bordered { border: 1px solid #eee !important }`, which drew a box right
   around the whole table — the "outer panel" the feed tab doesn't have. Plain
   specificity cannot beat it however deeply the selector is scoped. */
.pg-dashrail .pg-feed #profile .table-responsive > .table,
.pg-dashrail .pg-feed #profile .table-responsive > .table > tbody,
.pg-dashrail .pg-feed #profile .table-responsive > .table > thead { border: 0 !important; }
/* column labels: the same 11px uppercase muted treatment the Kendo grid headers
   use elsewhere in this sheet, instead of a filled header bar. The left padding
   matches the 7px marker + 10px gap added to the first body cell below, so the
   heading sits over its column. */
.pg-dashrail .pg-feed #profile .table > thead > tr > th {
  border: 0; border-bottom: 1px solid var(--line); background: transparent;
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--muted); padding: 0 0 9px;
}
.pg-dashrail .pg-feed #profile .table > thead > tr > th:first-child { padding-left: 17px; }
.pg-dashrail .pg-feed #profile .table > tbody > tr > td {
  border: 0; border-bottom: 1px solid var(--line-soft);
  background: transparent; vertical-align: middle;
  padding: 11px 0; font-size: 13px; color: var(--text);
}
/* Two backgrounds have to be cleared for the rows to sit on the card colour:
   - the zebra shading, which this sheet applies at the <tr> level via
     `.ts-app .ts-main .table-striped > tbody > tr:nth-of-type(odd)` — clearing it
     on the <td> alone left the row tinted with --inset underneath;
   - the <table> itself, which theme-dark.css fills with
     `table { background: var(--main-bg-color) !important }`, a grey #2A3137 slab
     (the same problem as .tab-content). That needs !important to undo, and it was
     dragging the header and date text to 4.38:1 — against the card they are 5.50:1. */
.pg-dashrail .pg-feed #profile .table-responsive > .table { background: transparent !important; }
.pg-dashrail .pg-feed #profile .table-striped > tbody > tr:nth-of-type(odd),
.pg-dashrail .pg-feed #profile .table-striped > tbody > tr:nth-of-type(odd) > td,
.pg-dashrail .pg-feed #profile .table-hover > tbody > tr:hover > td { background: transparent; }
.pg-dashrail .pg-feed #profile .table > tbody > tr:last-child > td { border-bottom: 0; }
.pg-dashrail .pg-feed #profile .table-hover > tbody > tr:hover > td { background: var(--inset); }
/* uniform marker on the first cell, matching .pg-feed #feedbody rows */
.pg-dashrail .pg-feed #profile .table > tbody > tr > td:first-child::before {
  content: ""; display: inline-block; flex: none;
  width: 7px; height: 7px; margin-right: 10px; vertical-align: middle;
  background: var(--blue); transform: rotate(45deg);
}
/* transaction number reads as a link, not a solid navy pill. !important is needed
   for the background/border: the project-wide .btn.btn-primary rule sets those
   with !important. */
.pg-dashrail .pg-feed #profile .table td .btn {
  background: none !important; background-image: none !important;
  border: 0 !important; box-shadow: none !important;
  padding: 0 !important; height: auto; min-height: 0; border-radius: 0;
  color: var(--blue) !important; font-size: 13px; font-weight: 600;
}
.pg-dashrail .pg-feed #profile .table td .btn:hover { text-decoration: underline; }
/* date muted like the feed's age text, amount emphasised as the value column */
.pg-dashrail .pg-feed #profile .table > tbody > tr > td:nth-child(2) { color: var(--muted); font-size: 12.5px; }
.pg-dashrail .pg-feed #profile .table > tbody > tr > td:last-child { font-weight: 700; color: var(--head); font-variant-numeric: tabular-nums; }

/* ============================================================
   EVENT INFO (Areas/Events/Views/Info/Index.cshtml + partials)
   Scoped to .pg-eventinfo so the page's legacy .panel markup is restyled as
   cards in place — every id, data-bind, data-testid and Kendo template on this
   heavily-bound page is left untouched.
   ============================================================ */

/* ---- legacy .panel -> card, page-wide ---- */
.pg-eventinfo .panel {
  background: var(--card); border: 1px solid var(--line); border-radius: 13px;
  box-shadow: 0 1px 2px rgba(12,44,73,0.04); margin-bottom: 18px; overflow: hidden;
}
/* nested panels (e.g. #pnlSignUpIndDays) sit inside a card already — keep them
   flat so cards don't stack borders inside cards */
.pg-eventinfo .panel .panel { border-radius: 10px; box-shadow: none; margin-bottom: 0; }
.pg-eventinfo .panel > .panel-heading {
  background: transparent; border: 0; border-bottom: 1px solid var(--line-soft);
  padding: 16px 20px; font-size: 15px; font-weight: 700; color: var(--head);
}
.pg-eventinfo .panel > .panel-heading .panel-title,
.pg-eventinfo .panel > .panel-heading h3,
.pg-eventinfo .panel > .panel-heading h4 { margin: 0; font-size: 15px; font-weight: 700; color: var(--head); }
.pg-eventinfo .panel > .panel-heading .bb { border: 0; }
.pg-eventinfo .panel > .panel-body { padding: 18px 20px; }
/* label/value rows in the program-information card */
.pg-eventinfo .col-lg-5 .panel-body > .row {
  display: flex; flex-wrap: wrap; gap: 4px 12px; margin: 0;
  padding: 9px 0; border-bottom: 1px solid var(--line-soft);
}
.pg-eventinfo .col-lg-5 .panel-body > .row:last-child { border-bottom: 0; }
.pg-eventinfo .col-lg-5 .panel-body > .row > [class*="col-sm-4"] { flex: 0 0 40%; padding: 0; font-size: 12.5px; color: var(--muted); }
.pg-eventinfo .col-lg-5 .panel-body > .row > [class*="col-sm-8"] { flex: 1 1 45%; padding: 0; font-size: 13px; color: var(--head); }
.pg-eventinfo .col-lg-5 .panel-body > .row strong { font-weight: 600; }

/* ---- rail order: share last ---- */
.pg-eventinfo .col-lg-5 { display: flex; flex-direction: column; }
/* rail order: share, then availability, then when-and-where, then program info */
.pg-eventinfo .col-lg-5 > .panel { order: 2; }
.pg-eventinfo .col-lg-5 > .evi-share { order: 0; }
.pg-eventinfo .col-lg-5 > .evi-seats { order: 1; }
/* Share is a single-row bar: caption left, icons right. It was a full card — a
   heading row with its own bottom border plus a padded body — for five 34px icon
   buttons, which is a lot of height for a secondary action. Collapsing the heading
   and body onto one flex line drops it to roughly a third. */
.pg-eventinfo .evi-share { display: flex; align-items: center; gap: 14px; padding: 0 16px; }
.pg-eventinfo .evi-share > .panel-heading {
  border: 0; padding: 0; flex: none;
  font-size: 11px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; color: var(--muted);
}
.pg-eventinfo .evi-share > .panel-body { padding: 9px 0; flex: 1 1 auto; min-width: 0; }
.pg-eventinfo .evi-share .panel-body > .row { margin: 0; }
.pg-eventinfo .evi-share .panel-body > .row > [class*="col-xs-12"] { padding: 0; }
.pg-eventinfo .evi-share .btn-group { justify-content: flex-end; gap: 6px; }
.pg-eventinfo .evi-share .btn-group > .btn { height: 30px; padding: 0 10px; }
/* availability card: big seat count, the % ring canvas kept but sized down */
.pg-eventinfo .evi-seats .panel-body h2 { font-size: 15px; font-weight: 600; color: var(--muted); margin: 0 0 6px; line-height: 1.35; }
.pg-eventinfo .evi-seats .panel-body h2 #avaiableSeats {
  display: block; font-family: inherit; font-size: 30px; font-weight: 700;
  color: var(--head); letter-spacing: -0.5px; font-variant-numeric: tabular-nums;
}
.pg-eventinfo .evi-seats ul { list-style: none; margin: 0; padding: 0; font-size: 12.5px; color: var(--muted); }
/* The canvas bitmap is 130x130 (set as width/height attributes by the page), so a
   120px CSS box resampled it down and softened the ring. Sizing the box to the
   bitmap keeps it crisp — 1 CSS px per device px at 1x. */
.pg-eventinfo .evi-seats #canvas-ticketAutoRefresh {
  width: 130px; height: 130px; max-width: 130px; display: block; margin: 0 auto;
}
/* the ring and its caption read as one unit rather than two stranded columns */
.pg-eventinfo .evi-seats .panel-body > .row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 18px; }
.pg-eventinfo .evi-seats .panel-body > .row > [class*="col-sm-5"] { flex: 0 0 auto; width: auto; padding: 0; }
.pg-eventinfo .evi-seats .panel-body > .row > [class*="col-sm-7"] { flex: 1 1 160px; width: auto; padding: 0; }
.pg-eventinfo .evi-seats-pct { margin: 4px 0 0; font-size: 12.5px; color: var(--muted); list-style: none; }
.pg-eventinfo .evi-seats-pct #lblPresantage { font-weight: 700; color: var(--head); }
.pg-eventinfo .evi-share .btn-group { display: flex; flex-wrap: wrap; gap: 8px; }
.pg-eventinfo .evi-share .btn-group > .btn {
  float: none; border-radius: 9px !important; border: 1px solid var(--line);
  background: var(--card); color: var(--head); height: 34px;
  display: inline-flex; align-items: center; justify-content: center; padding: 0 12px;
}
.pg-eventinfo .evi-share .btn-group > .btn:hover { background: var(--inset); }
.pg-eventinfo .evi-share .btn .fa { color: var(--muted); }

/* ---- map ---- */
.pg-eventinfo .map { border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }

/* Leaflet popup + attribution in dark mode. The plugin ships a fixed white
   popup with dark text and a pale grey attribution bar; on a dark page the
   inherited text colour left the venue name at 1.98:1, the close button at
   2.93:1 and the "Leaflet" credit at 1.58:1. Not scoped to one page — the same
   map is embedded from the mapping profiles admin and elsewhere. */
body.ts-app.is-dark .leaflet-popup-content-wrapper,
body.ts-app.is-dark .leaflet-popup-tip {
  background: var(--card); color: var(--head); border: 1px solid var(--line);
}
body.ts-app.is-dark .leaflet-popup-content,
body.ts-app.is-dark .leaflet-popup-content b { color: var(--head); }
/* the close button is a SIBLING of .leaflet-popup-content-wrapper, positioned over
   it, so it inherits no popup background and its contrast was being measured
   against the map tiles behind. Giving it the card colour makes it deterministic
   (var(--head) on var(--card) = 14.4:1) instead of dependent on the tile below. */
/* light mode too — Leaflet's default close-button grey is 4.42:1 on the popup */
body.ts-app .leaflet-popup-close-button {
  color: var(--head) !important; background: var(--card) !important; border-radius: 0 11px 0 0;
}
body.ts-app.is-dark .leaflet-popup-close-button {
  color: var(--head) !important; background: var(--card) !important; border-radius: 0 11px 0 0;
}
body.ts-app.is-dark .leaflet-popup-close-button:hover { color: var(--blue) !important; }
body.ts-app.is-dark .leaflet-control-attribution {
  background: var(--card) !important; color: var(--muted) !important;
}
body.ts-app.is-dark .leaflet-control-attribution a { color: var(--blue) !important; }

/* ---- ticket picker cards (_IndexRegisterSection.cshtml) ---- */
.evi-tickets { border: 0; padding: 0; margin: 0 0 20px; min-width: 0; display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.evi-tickets-legend {
  border: 0; margin: 0 0 12px; padding: 0; width: auto; float: none;
  font-size: 11px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; color: var(--muted);
  grid-column: 1 / -1;
}
.evi-ticket {
  position: relative; display: flex; flex-direction: column; gap: 3px; margin: 0; cursor: pointer;
  border: 1px solid var(--line); border-radius: 12px; padding: 14px 15px;
  background: var(--card); font-weight: 400;
  transition: border-color .12s ease, box-shadow .12s ease, background .12s ease;
}
.evi-ticket:hover { border-color: var(--blue-line); }
.evi-ticket.is-disabled { opacity: .55; cursor: not-allowed; }
/* the radio itself is visually replaced by .evi-ticket-mark but stays focusable
   and hit-testable, so keyboard and screen-reader behaviour is native */
.evi-ticket-radio { position: absolute; opacity: 0; width: 0; height: 0; margin: 0; }
.evi-ticket-top { display: flex; align-items: center; gap: 10px; }
.evi-ticket-name { flex: 1; min-width: 0; font-size: 13.5px; font-weight: 600; color: var(--head); }
.evi-ticket-mark {
  flex: none; width: 16px; height: 16px; border-radius: 50%;
  border: 1px solid var(--line); background: var(--card); position: relative;
}
.evi-ticket-price { font-size: 21px; font-weight: 700; color: var(--head); letter-spacing: -0.4px; font-variant-numeric: tabular-nums; }
.evi-ticket-covers { font-size: 12.5px; color: var(--muted); }
.evi-ticket-avail { font-size: 11.5px; color: var(--faint); }
/* selected state */
.evi-ticket-radio:checked ~ .evi-ticket-price,
.evi-ticket-radio:checked ~ .evi-ticket-top .evi-ticket-name { color: var(--navy); }
body.ts-app.is-dark .evi-ticket-radio:checked ~ .evi-ticket-price,
body.ts-app.is-dark .evi-ticket-radio:checked ~ .evi-ticket-top .evi-ticket-name { color: var(--head); }
.evi-ticket:has(.evi-ticket-radio:checked) { border-color: var(--blue); background: var(--blue-soft); box-shadow: 0 0 0 1px var(--blue); }
.evi-ticket-radio:checked ~ .evi-ticket-top .evi-ticket-mark { border-color: var(--blue); border-width: 5px; }
/* keyboard focus has to be visible even though the input is clipped */
.evi-ticket:has(.evi-ticket-radio:focus-visible) { outline: 2px solid var(--blue); outline-offset: 2px; }

/* ---- participant rows: match the feed/list treatment ---- */
.pg-eventinfo #ticketView .list-group { margin: 0; }
.pg-eventinfo #ticketView .list-group-item {
  border: 0; border-bottom: 1px solid var(--line-soft) !important; border-radius: 0 !important;
  background: transparent !important; padding: 11px 2px;
}
.pg-eventinfo #ticketView .list-group-item:last-child { border-bottom: 0 !important; }
.pg-eventinfo #ticketView .list-group-item:hover { background: var(--inset) !important; }
.pg-eventinfo #ticketView .list-group-item .thumb48 {
  width: 34px; height: 34px; border-radius: 50%; border: 1px solid var(--line);
}
.pg-eventinfo #ticketView .media-box-heading { font-size: 13.5px; font-weight: 600; color: var(--head); }
.pg-eventinfo #ticketView .list-group-item p { font-size: 12.5px; color: var(--muted); margin: 2px 0 0; }
/* availability summary line under the picker */
.pg-eventinfo #ticketAvaliability, .pg-eventinfo #totalTicketAvaliability { font-size: 12.5px; color: var(--muted); }
/* The legacy select (and its label) stay in the DOM for Kendo but are taken out of
   view once the cards are live. Applied as a class ON those elements by the sync
   script — an earlier sibling selector (.evi-tickets.is-live ~ h4 > …) silently
   failed, so this does not depend on the surrounding markup staying put.
   !important because Kendo's `visible` binding writes inline display on the select. */
.evi-srhide {
  position: absolute !important; width: 1px !important; height: 1px !important;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; margin: 0 !important; padding: 0 !important;
}

/* ---- compressed ticket cards ----
   Was a 4-row stack (name / price / covers / availability) at 282x124. The card
   becomes a wrapping flex row so price, covers and availability share one line
   under the name, separated by middots — roughly half the height, same content. */
.evi-tickets { gap: 10px; grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); }
.evi-ticket { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 7px; row-gap: 2px; padding: 10px 12px; }
.evi-ticket-top { flex: 1 1 100%; }
.evi-ticket-name { font-size: 13px; }
.evi-ticket-mark { width: 15px; height: 15px; }
.evi-ticket-radio:checked ~ .evi-ticket-top .evi-ticket-mark { border-width: 4px; }
.evi-ticket-price { flex: none; font-size: 17px; letter-spacing: -0.2px; }
.evi-ticket-covers { flex: none; font-size: 12px; }
.evi-ticket-avail { flex: none; font-size: 11.5px; }
.evi-ticket-covers::before, .evi-ticket-avail::before {
  content: "\00b7"; margin-right: 6px; color: var(--faint); font-weight: 700;
}

/* ---- pricing card (Areas/Events/Views/Info/_Pricing.cshtml) ----
   Restyled, not rewritten: eventcustomerview.ts reads the #TicketType{n} hidden
   inputs and the stepped rows carry PersonCount / PriceCost ids that JS hooks onto.
   Each ticket is wrapped in .evi-pricerow (added in the partial) so the name/covers
   block and the rate share one row behind one divider. A grid on the panel body
   could not do this: every child was auto-placed onto its own row, dropping the
   rate below the name and splitting the rule into two stubs. */
.pg-eventinfo #tblTicketPriceBreaking { display: block; }
.pg-eventinfo .evi-pricerow {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 12px 0; border-bottom: 1px solid var(--line-soft);
}
.pg-eventinfo .evi-pricerow:last-of-type { border-bottom: 0; padding-bottom: 0; }
.pg-eventinfo .evi-pricerow:first-of-type { padding-top: 0; }
.pg-eventinfo .evi-pricerow-main { min-width: 0; }
.pg-eventinfo .evi-pricerow-rate { flex: none; text-align: right; }
.pg-eventinfo .evi-price-name { margin: 0; font-size: 13.5px; font-weight: 600; color: var(--head); }
.pg-eventinfo .evi-price-covers { display: block; margin-top: 2px; font-size: 12.5px; color: var(--muted); }
/* strip the table chrome, the empty col-sm-2 spacer and the placeholder
   <thead><th>Empty</th> the partial emits around every rate */
.pg-eventinfo .evi-pricerow-rate .row { display: block; margin: 0; }
.pg-eventinfo .evi-pricerow-rate [class*="col-sm-2"] { display: none; }
.pg-eventinfo .evi-pricerow-rate [class*="col-sm-10"] { width: auto; padding: 0; float: none; }
.pg-eventinfo .tbl-price-breaking { background: transparent !important; border: 0 !important; margin: 0; width: auto; }
.pg-eventinfo .tbl-price-breaking thead { display: none; }
.pg-eventinfo .tbl-price-breaking td {
  border: 0 !important; background: transparent !important; padding: 0;
  text-align: right; white-space: nowrap;
  font-size: 20px; font-weight: 700; letter-spacing: -0.4px;
  color: var(--navy); font-variant-numeric: tabular-nums;
}
/* --navy is a dark blue: fine on the white card, unreadable on the dark one, so
   dark mode uses the lighter --blue token instead */
body.ts-app.is-dark .pg-eventinfo .tbl-price-breaking td { color: var(--blue); }
/* "per ticket" reads as a secondary qualifier, on its own line under the figure */
.pg-eventinfo .tbl-price-breaking td b { display: block; font-size: 11.5px; font-weight: 500; color: var(--muted); }
.pg-eventinfo .tbl-price-breaking td b .lead { display: none; }
/* stepped pricing has two cells per row (threshold + rate) — keep both readable */
.pg-eventinfo .tbl-price-breaking tr td:first-child:not(:only-child) {
  text-align: left; font-size: 12.5px; font-weight: 500; color: var(--muted); padding-right: 14px;
}
.pg-eventinfo .tbl-price-breaking tr td:first-child:not(:only-child) b { display: inline; }
/* stepped / matrix discount label */
.pg-eventinfo span[id^="discountType"] { display: block; font-size: 11.5px; font-weight: 600; color: var(--blue); margin-bottom: 4px; }

/* Slimming the share bar, applied with body.ts-app so it outranks the earlier
   .pg-eventinfo .evi-share rules in this section — those set the icon buttons to
   34px and the panel body to 18px/20px padding, and at equal specificity the
   earlier declaration was winning on source order. */
body.ts-app .pg-eventinfo .evi-share { padding: 0 16px; }
body.ts-app .pg-eventinfo .evi-share > .panel-body { padding: 7px 0; }
body.ts-app .pg-eventinfo .evi-share .btn-group > .btn { height: 28px; padding: 0 9px; font-size: 12.5px; }
body.ts-app .pg-eventinfo .evi-share .btn-group > .btn .fa { font-size: 12.5px; }


/* Ticket cards: a 2x2 grid (name / price on row 1, covers / availability on row 2)
   with the radio dot pinned top-right and out of flow, so the flex row above cannot
   wrap into a third and fourth line. Keeps all four values while halving the height
   (124px -> 63px). Re-added after a stylesheet cleanup removed it by mistake. */
.evi-ticket {
  position: relative; display: grid; grid-template-columns: 1fr auto;
  column-gap: 10px; row-gap: 1px; align-items: baseline; padding: 9px 34px 9px 12px;
}
.evi-ticket-top { grid-column: 1; grid-row: 1; display: block; }
.evi-ticket-price { grid-column: 2; grid-row: 1; text-align: right; }
.evi-ticket-covers { grid-column: 1; grid-row: 2; }
.evi-ticket-avail { grid-column: 2; grid-row: 2; text-align: right; white-space: nowrap; }
.evi-ticket-covers::before, .evi-ticket-avail::before { content: none; margin: 0; }
.evi-ticket-mark { position: absolute; top: 9px; right: 11px; }
/* An event with one ticket type renders one card. auto-fit collapses the empty
   tracks, which would stretch that lone card edge to edge and leave its price
   stranded; auto-fill keeps them, so it is exactly as wide as a card in a full
   grid — and still goes full width once only one track fits. */
.evi-tickets:has(> .evi-ticket:only-of-type) { grid-template-columns: repeat(auto-fill, minmax(215px, 1fr)); }

/* =====================================================================
   SERVICE REQUEST DETAIL — SPLIT INBOX (Areas/Issue/Views/View/Index.cshtml
   + _ViewDetails.cshtml)
   Ported from the eServices prototype's RqLayoutInbox. The queue column stays
   beside the request so staff can work a run of them without going back to the
   list; the detail pane scrolls independently.

   All colour comes from the tokens, so both themes are covered without a
   separate dark block except where a token would not carry enough contrast.

   Note on visibility: viewdetails.ts shows/hides many of these controls with
   jQuery .show()/.hide(), which writes an inline `display`. Nothing below sets
   `display` on an element the JS toggles (#ExportToTaskBtn, #SelectDropDown,
   #TaskContainer, the Status* badges, the PTO buttons ...) — only on their
   wrappers — so the role/CMMS gating keeps working untouched.
   ===================================================================== */

.ts-app .ts-main .rq-ib { padding: 0; }
.ts-app .ts-main .rq-ib-cols {
  display: grid;
  grid-template-columns: 340px minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}
@media (min-width: 1600px) {
  .ts-app .ts-main .rq-ib-cols { grid-template-columns: 380px minmax(0, 1fr); }
}

/* ---------- queue column ---------- */
.ts-app .ts-main .rq-ib-queue {
  position: sticky; top: 72px;
  display: flex; flex-direction: column;
  max-height: calc(100vh - 96px);
  background: var(--card); border: 1px solid var(--line);
  border-radius: 13px; box-shadow: 0 1px 2px rgba(12,44,73,0.04);
  /* NOT overflow:hidden — the focus-expanded filter below deliberately breaks out
     over the detail pane, and an ancestor clip would cut it off (z-index cannot
     escape overflow). Nothing here needs the clip: scrolling is already contained by
     .rq-ib-rows, and no child paints into the rounded corners — the head and hint are
     transparent, and row hover backgrounds sit inside the rows container's padding. */
  overflow: visible;
}
.ts-app .ts-main .rq-ib-qhead {
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
  padding: 14px 16px; border-bottom: 1px solid var(--line-soft);
}
.ts-app .ts-main .rq-ib-qtitle {
  font-weight: 700; color: var(--head); font-size: 14.5px;
  display: inline-flex; align-items: center; gap: 7px; margin-right: auto;
}
.ts-app .ts-main .rq-ib-qcount {
  font-size: 12px; font-weight: 600; color: var(--muted);
  background: var(--inset); border: 1px solid var(--line);
  border-radius: 999px; padding: 1px 8px; font-variant-numeric: tabular-nums;
}

/* ---- queue filter bar: preset dropdown + free-text box ----
   Same preset queries as the /issue listing's Filters dropdown, restyled to fit the
   narrow queue column instead of Bootstrap's input-group. */
.ts-app .ts-main .rq-ib-filterbar { padding: 12px 14px 10px; }
.ts-app .ts-main .rq-ib-presets { position: relative; margin-bottom: 8px; }
.ts-app .ts-main .rq-ib-presetbtn {
  display: inline-flex; align-items: center; gap: 7px;
  height: 32px; padding: 0 12px;
  border: 1px solid var(--line); border-radius: 9px;
  background: var(--card); color: var(--head);
  font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.ts-app .ts-main .rq-ib-presetbtn:hover { background: var(--inset); }
.ts-app .ts-main .rq-ib-presetbtn .caret { border-top-color: var(--muted); }
.ts-app .ts-main .rq-ib-presetmenu {
  display: none; position: absolute; z-index: 20; top: calc(100% + 4px); left: 0;
  min-width: 240px; margin: 0; padding: 6px; list-style: none;
  background: var(--card); border: 1px solid var(--line); border-radius: 11px;
  box-shadow: 0 8px 24px rgba(12,44,73,0.14);
}
.ts-app .ts-main .rq-ib-presetmenu.is-open { display: block; }
.ts-app .ts-main .rq-ib-presetmenu > li { margin: 0; }
/* the payroll groups ship hidden and requestqueue.ts reveals the matching one; be
   explicit so a legacy "li { display: block }" rule cannot defeat the attribute */
.ts-app .ts-main .rq-ib-presetmenu > li[hidden] { display: none; }
.ts-app .ts-main .rq-ib-presetmenu > li > a {
  display: block; padding: 7px 10px; border-radius: 7px;
  color: var(--text); font-size: 13px; text-decoration: none !important;
}
.ts-app .ts-main .rq-ib-presetmenu > li > a:hover,
.ts-app .ts-main .rq-ib-presetmenu > li > a:focus-visible {
  background: var(--inset); color: var(--head);
}
.ts-app .ts-main .rq-ib-presetsep {
  height: 1px; margin: 5px 4px; background: var(--line-soft);
}

.ts-app .ts-main .rq-ib-searchwrap { position: relative; }
.ts-app .ts-main .rq-ib-searchic {
  position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
  color: var(--muted); font-size: 13px; pointer-events: none;
}
.ts-app .ts-main input.rq-ib-filter {
  width: 100%; height: 36px; padding: 0 12px 0 32px;
  border: 1px solid var(--line); border-radius: 9px;
  background: var(--inset); color: var(--text); font-family: inherit; font-size: 13.5px;
}
/* ---- focus-expanded filter ----
   The column leaves the field roughly 266px of text width (~38 characters), but the
   payroll presets alone run to 39 ("is:openTimeoffrequestAssigned sort:desc"), so a
   query fills it before any free text is typed. On focus the field breaks out of the
   column over the detail pane and collapses again on blur, which costs no permanent
   layout space. Paired with query chips this would rarely be needed — see the note on
   .rq-ib-filterbar. */
/* The COLUMN has to be raised, not just the field. .rq-ib-queue is position:sticky,
   which creates a stacking context, so a z-index on the field only ordered it against
   its siblings inside the column — the column itself stayed at z-index:auto against the
   detail pane that follows it in the DOM, and the expanded field vanished behind the
   request panel.
   1000 rather than a small number because the request panel carries legacy Angle theme
   and Kendo widget rules that set their own z-indexes; this has to clear all of them.
   Deliberately still below Kendo's popup range (~10002) so dropdowns and modals opened
   from the request panel continue to sit above the filter. Scoped to the expanded state
   so the column does not otherwise overlap the detail pane. */
.ts-app .ts-main .rq-ib-queue.is-filterexpanded { z-index: 1000; }
/* only needs to beat its siblings inside the column; the column above does the real
   work of getting out from behind the request panel */
.ts-app .ts-main .rq-ib-searchwrap.is-expanded { z-index: 1; }
.ts-app .ts-main .rq-ib-searchwrap.is-expanded input.rq-ib-filter {
  position: absolute; top: 0; left: 0;
  width: 470px; max-width: calc(100vw - 48px);
  height: 42px; font-size: 14px;
  background: var(--card);
  box-shadow: 0 10px 28px rgba(12,44,73,0.18);
}
/* below the stacking breakpoint the column is already full width, so expanding gains
   nothing and would risk running off a narrow viewport */
@media (max-width: 1100px) {
  .ts-app .ts-main .rq-ib-searchwrap.is-expanded input.rq-ib-filter {
    position: static; width: 100%; height: 36px; font-size: 13.5px; box-shadow: none;
  }
}

.ts-app .ts-main input.rq-ib-filter:focus {
  outline: none; background: var(--card);
  border-color: var(--blue); box-shadow: 0 0 0 3px rgba(0,87,142,0.14);
}

.ts-app .ts-main .rq-ib-rows { flex: 1; min-height: 0; overflow-y: auto; padding: 0 8px 8px; }
.ts-app .ts-main .rq-ib-row {
  display: block; padding: 11px 12px; margin-bottom: 3px;
  border: 1px solid transparent; border-radius: 10px;
  text-decoration: none !important; color: var(--text); cursor: pointer;
}
.ts-app .ts-main .rq-ib-row:hover { background: var(--inset); }
.ts-app .ts-main .rq-ib-row:focus-visible {
  outline: none; border-color: var(--blue); box-shadow: 0 0 0 3px rgba(0,87,142,0.14);
}
/* current request: tinted surface plus a left marker, so it reads as selected
   without relying on colour alone */
.ts-app .ts-main .rq-ib-row.is-active {
  background: var(--blue-soft); border-color: var(--blue-line);
  box-shadow: inset 3px 0 0 var(--blue);
}
.ts-app .ts-main .rq-ib-rowtop {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
}
.ts-app .ts-main .rq-ib-rowid {
  font-size: 11.5px; font-weight: 700; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.ts-app .ts-main .rq-ib-rowdate { font-size: 11.5px; color: var(--faint); white-space: nowrap; }
.ts-app .ts-main .rq-ib-rowtitle {
  margin: 2px 0 1px;
  font-size: 13.5px; font-weight: 600; color: var(--head); line-height: 1.35;
  overflow: hidden; text-overflow: ellipsis; display: -webkit-box;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.ts-app .ts-main .rq-ib-rowsub {
  display: block; font-size: 12px; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ts-app .ts-main .rq-ib-rowtags {
  display: flex; flex-wrap: wrap; align-items: center; gap: 5px; margin-top: 7px;
}
.ts-app .ts-main .rq-ib-rowtags .sr-status,
.ts-app .ts-main .rq-ib-rowtags .sr-tag { font-size: 11px; padding: 1px 7px; }
.ts-app .ts-main .rq-ib-rowtag {
  max-width: 130px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ts-app .ts-main .rq-ib-empty { padding: 26px 14px; text-align: center; }
.ts-app .ts-main .rq-emptynote { color: var(--muted); font-size: 13px; margin: 0; }
.ts-app .ts-main .rq-ib-hint {
  margin: 0; padding: 8px 14px; border-top: 1px solid var(--line-soft);
  font-size: 11.5px; color: var(--faint); font-variant-numeric: tabular-nums;
}

/* ---------- detail pane ---------- */
.ts-app .ts-main .rq-ib-detail { min-width: 0; }
/* The .rq-ib-bar card that sat above the details card is gone — its id chip, kicker,
   status and action toolbar moved into the details card's own head, which already
   carried the same title. .rq-th-idchip and .rq-ib-kicker keep their names in the
   new home; .rq-ib-bar / -barmain / -bartitle went with the markup. */
/* Right-hand column of the card head: id chip, kicker, then the action toolbar.
   The toolbar lives here rather than on a row of its own so the title occupies the
   width beside it — on its own row the buttons sat right and left a band of empty
   card next to them. flex: none keeps the column at the buttons' natural width and
   hands everything else to the title. */
.ts-app .ts-main .rq-idmeta {
  display: flex; flex-direction: column; align-items: flex-end; gap: 5px;
  margin-left: auto; flex: none; text-align: right;
}
.ts-app .ts-main .rq-th-idchip {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  background: var(--inset); border: 1px solid var(--line); border-radius: 999px;
  padding: 3px 11px; font-size: 12.5px; font-weight: 700; color: var(--head);
  font-variant-numeric: tabular-nums;
}
.ts-app .ts-main .rq-th-idchip .fa { color: var(--blue); font-size: 12px; }
.ts-app .ts-main .rq-ib-kicker {
  font-size: 12px; font-weight: 600; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.06em;
}
/* The toolbar keeps its own layout rules (h3.sr-toolbar, above). In the head column it
   needs its 32px bottom margin dropped; margin:0 also neutralises the .row negative
   gutters the markup still carries, which would otherwise pull it past the card edge.
   No divider — .rq-idhead's own bottom border closes the block. */
.ts-app .ts-main .rq-idmeta h3.sr-toolbar { margin: 3px 0 0; justify-content: flex-end; }
/* the status badges lose their margin-right:auto here: the column is only as wide as
   the buttons, so there's no free space to push against and they'd overlap them */
.ts-app .ts-main .rq-idmeta h3.sr-toolbar > .sr-status { margin-right: 0; }

.ts-app .ts-main .rq-ib-scroll { display: flex; flex-direction: column; gap: 16px; }
/* #refreshThisData holds the Kendo-rendered detail cards; its inner wrapper is a
   Bootstrap .row whose negative gutters would pull the cards past the column edge */
.ts-app .ts-main .rq-ib-scroll #refreshThisData > .row {
  margin-left: 0; margin-right: 0;
  display: flex; flex-direction: column; gap: 16px;
}
.ts-app .ts-main .rq-ib-scroll #refreshThisData > .row::before,
.ts-app .ts-main .rq-ib-scroll #refreshThisData > .row::after { content: none; }

/* ---------- "What was reported" card ---------- */
.ts-app .ts-main .pg-card-titletext {
  font-size: 16px; font-weight: 700; color: var(--head); letter-spacing: -0.2px;
}
.ts-app .ts-main .rq-idhead {
  display: flex; align-items: flex-start; gap: 14px;
  padding-bottom: 16px; border-bottom: 1px solid var(--line-soft); margin-bottom: 16px;
}
.ts-app .ts-main .rq-idavatar { flex: none; display: block; }
.ts-app .ts-main .rq-idavatar img {
  width: 46px; height: 46px; border-radius: 50%;
  border: 1px solid var(--line); object-fit: cover; background: var(--inset);
}
.ts-app .ts-main .rq-idhead-main { min-width: 0; }
.ts-app .ts-main h3.rq-idtitle {
  margin: 0; font-size: 17px; font-weight: 700;
  color: var(--head); letter-spacing: -0.2px; line-height: 1.35;
}
.ts-app .ts-main .rq-idroles { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }
.ts-app .ts-main .rq-idrole {
  font-size: 11px; font-weight: 600; color: var(--blue);
  background: var(--blue-soft); border: 1px solid var(--blue-line);
  border-radius: 999px; padding: 1px 8px;
}

.ts-app .ts-main .rq-idgrid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 14px 20px;
}
.ts-app .ts-main .rq-idcell { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.ts-app .ts-main .rq-fieldk {
  font-size: 11.5px; font-weight: 700; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.06em;
}
/* Sized up a step from the 14px it started at: with a request's cells spread over the
   full card these are the only text in a wide band, and at the old size they read as
   fine print under their captions rather than as the request's own facts. */
.ts-app .ts-main .rq-fieldv {
  font-size: 15.5px; font-weight: 600; color: var(--head);
  line-height: 1.35; overflow-wrap: anywhere;
}
.ts-app .ts-main .rq-fieldv.is-empty { font-weight: 500; color: var(--faint); font-style: italic; }
.ts-app .ts-main .rq-idsub { font-size: 13px; color: var(--muted); overflow-wrap: anywhere; }

/* "View location" sits in the identity grid beside the address. Bottom-aligned so it
   lines up with the value text of the cells next to it rather than floating against
   their labels, and given a real touch target (the old header placement was a 32px
   mini button tucked in a card title). */
.ts-app .ts-main .rq-idcell-action { justify-content: flex-end; }

/* Time off / timesheet placement of the action toolbar (_ViewDetails.cshtml —
   RenderRequestToolbar): a footer under the identity grid rather than a cell in it,
   so the buttons keep to one right-aligned line at the card's own edge and the grid
   is left free to stretch its cells. The toolbar's own margin is zeroed the same way
   the head column zeroes it — that also neutralises the .row negative gutters the
   markup still carries, which would pull it past the card edge. */
.ts-app .ts-main .rq-idfoot { margin-top: 14px; }
.ts-app .ts-main .rq-idfoot h3.sr-toolbar { margin: 0; justify-content: flex-end; }
.ts-app .ts-main .rq-idfoot h3.sr-toolbar > .sr-status { margin-right: 0; }
.ts-app .ts-main .btn.rq-locationbtn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  min-height: 40px; padding: 0 18px; align-self: flex-start;
  font-size: 13.5px; font-weight: 600;
  border-radius: 9px; border: 1px solid var(--blue-line);
  background: var(--blue-soft); color: var(--blue);
}
.ts-app .ts-main .btn.rq-locationbtn:hover,
.ts-app .ts-main .btn.rq-locationbtn:focus {
  background: var(--blue); border-color: var(--blue); color: #fff;
}
@media (max-width: 640px) {
  /* full width on small screens so it is comfortably tappable */
  .ts-app .ts-main .btn.rq-locationbtn { width: 100%; align-self: stretch; }
}

/* ---- report card body ----
   The body is legacy Bootstrap: .row wrappers carrying -15px gutters and columns
   carrying 15px padding. Inside a padded card that pushed content past both edges
   and left the body misaligned with the header and identity grid above it. Flatten
   the grid here so every block lines up on the card's own padding. */
.ts-app .ts-main .rq-reportcard .card-body {
  padding: 0; margin-top: 18px;
  border-top: 1px solid var(--line-soft); padding-top: 18px;
}
.ts-app .ts-main .rq-reportcard .card-body .row { margin-left: 0; margin-right: 0; }
.ts-app .ts-main .rq-reportcard .card-body .row > [class*="col-"] { padding-left: 0; padding-right: 0; }
.ts-app .ts-main .rq-reportcard .card-body > .row + .row { margin-top: 14px; }
.ts-app .ts-main .rq-reportcard .card-body hr { margin: 20px 0; border-top-color: var(--line-soft); }
.ts-app .ts-main .rq-reportcard .card-body > .clearfix.mb-lg { margin-bottom: 0; }
.ts-app .ts-main .rq-reportcard #dataIssue { float: none !important; }
.ts-app .ts-main .rq-reportcard #dataIssue > *:last-child { margin-bottom: 0; }
.ts-app .ts-main .rq-reportcard fieldset legend {
  font-size: 13px; font-weight: 700; color: var(--head);
  border: 0; margin-bottom: 10px; padding: 0; width: auto;
}
/* attachments */
.ts-app .ts-main .rq-reportcard .remv-list-style-type {
  list-style: none; padding-left: 0; margin: 16px 0 0;
  display: flex; flex-wrap: wrap; gap: 8px;
}
.ts-app .ts-main .rq-reportcard .remv-list-style-type > li { margin-bottom: 0; }
.ts-app .ts-main .rq-reportcard .remv-list-style-type > li > a {
  display: inline-flex; align-items: center; gap: 7px;
  border: 1px solid var(--line); border-radius: 9px; padding: 7px 12px;
  background: var(--inset); color: var(--head); font-size: 13px; font-weight: 600;
  text-decoration: none !important;
}
.ts-app .ts-main .rq-reportcard .remv-list-style-type > li > a:hover { border-color: var(--blue-line); }

/* ---------- labels card ----------
   Label colours are town-configured and arrive as an inline background, so the chips
   need enough padding and a big enough type size to stay legible against whatever
   colour a town picks — the 11px .sr-tag size used in the dense queue rows is too
   tight here. */
.ts-app .ts-main .rq-labels { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.ts-app .ts-main .rq-label {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 12.5px; padding: 5px 12px; line-height: 1.5;
}
.ts-app .ts-main .rq-labelx {
  color: inherit; opacity: 0.7; text-decoration: none !important;
  font-size: 11px; line-height: 1;
}
.ts-app .ts-main .rq-labelx:hover,
.ts-app .ts-main .rq-labelx:focus-visible { opacity: 1; }
/* The chips now live in an .rq-idcell in the identity grid, so they line up with
   the department's value rather than starting a card. The row wraps within the
   cell; no min-height, so a request with one label doesn't reserve two lines. */
.ts-app .ts-main .rq-idcell .rq-labels { margin-top: 1px; }
.ts-app .ts-main .ed-mini { height: 32px; padding: 0 12px; font-size: 12.5px; }

/* ---------- tools / timeline / respond cards ---------- */
.ts-app .ts-main .rq-toolcard { padding: 10px 14px; }
.ts-app .ts-main .rq-timelinecard .pg-card-title { flex-wrap: wrap; }
.ts-app .ts-main .rq-timelinetoggle { margin: 0 0 0 auto; }
.ts-app .ts-main .rq-timelinetoggle label { font-size: 13px; font-weight: 500; color: var(--muted); margin: 0; }

.ts-app .ts-main .rq-filetypes { font-size: 12.5px; padding: 9px 13px; margin-bottom: 12px; }
.ts-app .ts-main .rq-filetypes p { margin: 0; }
.ts-app .ts-main .rq-uploadrow { margin-bottom: 12px; }
.ts-app .ts-main .rq-respondcard textarea#editor { min-height: 120px; }
.ts-app .ts-main .rq-respondcard .row.p { padding: 14px 0 0; margin: 0; }

/* ---------- responsive: stack the queue above the request ---------- */
@media (max-width: 1100px) {
  .ts-app .ts-main .rq-ib-cols { grid-template-columns: minmax(0, 1fr); }
  .ts-app .ts-main .rq-ib-queue { position: static; max-height: 420px; }
}
@media (max-width: 640px) {
  /* the meta column drops below the title and spreads out rather than squeezing
     a full button row into the width a phone leaves beside it */
  .ts-app .ts-main .rq-idhead { flex-wrap: wrap; }
  .ts-app .ts-main .rq-idmeta { width: 100%; flex-direction: row; align-items: center; flex-wrap: wrap; margin-left: 0; text-align: left; }
  .ts-app .ts-main .rq-idmeta h3.sr-toolbar { width: 100%; justify-content: flex-start; }
  .ts-app .ts-main .rq-idgrid { grid-template-columns: minmax(0, 1fr); }
}

/* ============================================================
   Timesheet entry list — Areas/Issue/Views/View/_ViewDetails.cshtml
   ============================================================
   One list for every width, replacing a 12-column table plus a separate
   under-768px stacked block. Four of the twelve values carry the approval
   decision (code, when, hours recorded, status) and stay in aligned columns;
   the rest sit on a meta line carrying their own captions. That's what lets
   the header wording stay as-is — a caption can't wrap when it isn't in a
   column heading. Twelve columns in ~1130px is what wrapped four of them.
   ============================================================ */
.ts-app .ts-main .tse-list {
    container-type: inline-size;
    list-style: none; margin: 0; padding: 0;
    display: flex; flex-direction: column; gap: 1px;
    background: var(--line-soft);
    border: 1px solid var(--line); border-radius: 12px; overflow: hidden;
}
.ts-app .ts-main .tse-empty { background: var(--card); padding: 22px; text-align: center; color: var(--muted); }
.ts-app .ts-main .tse-row {
    background: var(--card);
    display: grid;
    /* Only the first column is elastic; the when column sizes to its content over
       a floor, so a short single date still gets a column wide enough to sit
       centred in and the dates line up down the list. Spare width past that
       (including what the hidden List button used to float over) goes to the code
       and description rather than padding out the dates. */
    grid-template-columns: minmax(170px, 1fr) minmax(190px, auto) 92px auto;
    align-items: center; gap: 6px 18px; padding: 13px 18px;
}
.ts-app .ts-main .tse-row:hover { background: var(--blue-soft); }

/* Time off's two row states. The table filled the whole row rgb(255,85,85,.85)
   or rgb(0,227,247,.85) — literals that predate the palette and read as alarming
   next to a card list, with no dark-mode variant. Same two meanings, re-rendered
   as a left stripe over a light tint. Class names are the legacy ones so the
   markup keeps its existing hook; the old rules in employee/employee-portal.css
   still load but lose on specificity.
   Note this state is conveyed by colour alone, in the table as well as here —
   fixing that needs a visible label, and there's no resource string for either
   state to use, so it's left as-is rather than invented. */
.ts-app .ts-main .tse-row.time-off-tr-wating { background: color-mix(in oklab, var(--red) 8%, var(--card)); box-shadow: inset 3px 0 0 var(--red); }
.ts-app .ts-main .tse-row.time-off-tr-wating:hover { background: color-mix(in oklab, var(--red) 14%, var(--card)); }
.ts-app .ts-main .tse-row.time-off-tr-approved { background: color-mix(in oklab, var(--blue) 8%, var(--card)); box-shadow: inset 3px 0 0 var(--blue); }
.ts-app .ts-main .tse-row.time-off-tr-approved:hover { background: color-mix(in oklab, var(--blue) 14%, var(--card)); }
/* the legacy sheet forces .btnDecline to #000 for contrast on the old red fill */
.ts-app .ts-main .tse-row.time-off-tr-wating .btnDecline { color: var(--red); }

.ts-app .ts-main .tse-what { min-width: 0; }
.ts-app .ts-main .tse-code { display: block; font-size: 15px; font-weight: 700; color: var(--head); }
.ts-app .ts-main .tse-desc { display: block; font-size: 13px; color: var(--muted); }

/* The date on top, what happened on it underneath — a time range or "all day".
   The date carries the same weight as the hours figure across the row: those two
   are what an entry is read by, so neither should be the small print. Left to
   wrap rather than nowrap, since a date range breaks cleanly at its dash and a
   town date format containing spaces would otherwise overflow the column. */
.ts-app .ts-main .tse-when { text-align: center; font-variant-numeric: tabular-nums; }
.ts-app .ts-main .tse-day {
    display: block; font-size: 18px; font-weight: 700;
    color: var(--head); line-height: 1.2;
}
.ts-app .ts-main .tse-span { display: block; font-size: 12.5px; color: var(--muted); }

/* Hours recorded is the number the decision rests on, so it's the loudest thing
   on the row — everything else in the entry supports reading this one value. */
.ts-app .ts-main .tse-recorded { text-align: right; }
.ts-app .ts-main .tse-recorded b { display: block; font-size: 19px; font-weight: 700; color: var(--head); line-height: 1.15; font-variant-numeric: tabular-nums; }
.ts-app .ts-main .tse-recorded span { display: block; font-size: 10.5px; letter-spacing: 0.07em; text-transform: uppercase; color: var(--faint); font-weight: 600; }

.ts-app .ts-main .tse-decision { display: flex; align-items: center; justify-content: flex-end; gap: 10px; }
.ts-app .ts-main .tse-status { font-size: 11.5px; font-weight: 700; border-radius: 999px; padding: 2px 9px; white-space: nowrap; border: 1px solid var(--line); color: var(--muted); }
/* Literal inks, not var(--red)/(--green)/(--amber): those are tuned for text on
   the card, and none of them clears 4.5:1 on its own 13%-tinted fill. */
.ts-app .ts-main .tse-status.is-wait { color: #7A4A05; background: color-mix(in oklab, var(--amber) 14%, white); border-color: var(--amber); }
.ts-app .ts-main .tse-status.is-ok { color: #14612A; background: color-mix(in oklab, var(--green) 13%, white); border-color: var(--green); }
.ts-app .ts-main .tse-status.is-no { color: #8A1F22; background: color-mix(in oklab, var(--red) 11%, white); border-color: var(--red); }
body.is-dark .ts-main .tse-status.is-wait,
body.is-dark .ts-main .tse-status.is-ok,
body.is-dark .ts-main .tse-status.is-no { color: var(--head); background: var(--inset); }
/* pull-left on the buttons is inherited from the table markup; floats don't
   apply to flex items, but clear the margins Bootstrap gives them. */
.ts-app .ts-main .tse-actions { display: flex; gap: 4px; }
.ts-app .ts-main .tse-actions .btn { float: none; margin: 0; }

.ts-app .ts-main .tse-meta {
    grid-column: 1 / -1;
    display: flex; flex-wrap: wrap; gap: 3px 16px;
    margin: 4px 0 0; padding-top: 8px;
    border-top: 1px dashed var(--line); font-size: 12.5px;
}
.ts-app .ts-main .tse-f { display: flex; gap: 5px; white-space: nowrap; }
.ts-app .ts-main .tse-f dt { color: var(--muted); font-weight: 400; }
.ts-app .ts-main .tse-f dd { margin: 0; color: var(--head); font-weight: 600; font-variant-numeric: tabular-nums; }

/* One column: the decision stays on the right, everything else stacks.
   Declared twice on purpose — the container query is the one that matters
   (this column also narrows when the product sidebar opens, which a viewport
   query can't see), the media query is the floor for browsers without
   container query support, at the 768px breakpoint the page already used. */
@media (max-width: 767px) {
    .ts-app .ts-main .tse-row { grid-template-columns: minmax(0, 1fr) auto; gap: 4px 14px; }
    .ts-app .ts-main .tse-when, .ts-app .ts-main .tse-recorded { grid-column: 1; text-align: left; }
    .ts-app .ts-main .tse-recorded { display: flex; align-items: baseline; gap: 7px; }
    .ts-app .ts-main .tse-recorded b, .ts-app .ts-main .tse-recorded span { display: inline; }
    .ts-app .ts-main .tse-decision { grid-column: 2; grid-row: 1 / span 3; flex-direction: column; align-items: flex-end; justify-content: flex-start; }
}
@container (max-width: 720px) {
    .ts-app .ts-main .tse-row { grid-template-columns: minmax(0, 1fr) auto; gap: 4px 14px; }
    .ts-app .ts-main .tse-when, .ts-app .ts-main .tse-recorded { grid-column: 1; text-align: left; }
    .ts-app .ts-main .tse-recorded { display: flex; align-items: baseline; gap: 7px; }
    .ts-app .ts-main .tse-recorded b, .ts-app .ts-main .tse-recorded span { display: inline; }
    .ts-app .ts-main .tse-decision { grid-column: 2; grid-row: 1 / span 3; flex-direction: column; align-items: flex-end; justify-content: flex-start; }
}

/* =====================================================================
   YTD TOTALS PANEL
   ---------------------------------------------------------------------
   Areas/Employee/Views/Shared/_YTDTotalGrid.cshtml (the time off request
   form, the timesheet entry page and /employee/details/pto) and the inline
   copy of the same block in Areas/Issue/Views/View/_ViewDetails.cshtml.

   The markup kept bootstrap's .nav-tabs / .nav-pills structure because the
   tab ids and data-toggle wiring are read by the payroll scripts, so this
   restyles that structure rather than replacing it: .pg-tabs (defined
   above) supplies the segmented treatment already used by every other tab
   strip on the redesign, and the rules here only handle the panel's own
   furniture — head row, per-tab toolbar and the empty-code notice.
   ===================================================================== */
/* wrap-reverse, not wrap: the year picker follows the tab strip in the markup,
   so once the two stop fitting on one row it would drop between the tabs and
   the sub-tabs below them, splitting the tab strip from its own second level.
   Reversing the line order floats it above the tabs instead. This has to key
   off the wrap itself rather than a breakpoint — where the row gives out
   depends on the tab labels, and those are a good deal longer in French. */
.ts-app .ts-main .ytd-head {
    display: flex; flex-wrap: wrap-reverse; align-items: center; gap: 10px 18px; margin-bottom: 4px;
}
.ts-app .ts-main .ytd-head .pg-tabs { margin-bottom: 0; }
.ts-app .ts-main .ytd-year { display: flex; align-items: center; gap: 10px; margin-left: auto; }
.ts-app .ts-main .ytd-year label {
    margin: 0; font-size: 13px; font-weight: 600; color: var(--muted); white-space: nowrap;
}
.ts-app .ts-main .ytd-year .k-datepicker, .ts-app .ts-main .ytd-year .k-picker { width: 148px; }

/* sub-tabs (main / sub accumulator codes) read as a second level, so they sit
   a step smaller than the tabs above them. The active state needs spelling out:
   .pg-tabs sizes its own `> li.active > a`, which out-specifies a rule written
   only against `> li > a` and would leave the selected sub-tab a size larger
   than its neighbours.

   --ytd-subtab-offset indents the row so "Main codes" starts at the left edge
   of the "Accumulator code" tab it belongs to. Nothing in CSS can see that
   tab's position — it depends on the width of the two labels before it, which
   changes with language — so EmployeePTODetails.AlignSubTabs measures it and
   sets the property on .ytd-panel. It stays 0 until measured, and drops back
   to 0 whenever the strip wraps to more than one row (the parent tab is then
   no longer directly above, and an indent would point at the wrong tab). */
.ts-app .ts-main .ytd-subtabs {
    margin: 0 0 0 var(--ytd-subtab-offset, 0px);
    /* .pg-tabs caps itself at 100%, which takes no account of the indent — the
       track would run past the panel edge. Subtracting the offset makes the
       sub-tabs wrap within their track instead. */
    max-width: calc(100% - var(--ytd-subtab-offset, 0px));
}
.ts-app .ts-main .ytd-subtabs > li > a,
.ts-app .ts-main .ytd-subtabs > li.active > a,
.ts-app .ts-main .ytd-subtabs > li.active > a:hover,
.ts-app .ts-main .ytd-subtabs > li.active > a:focus { padding: 6px 13px; font-size: 12.5px; }

.ts-app .ts-main .ytd-panel > .tab-content {
    background: var(--card) !important;
    border: 1px solid var(--line);
    border-radius: 13px;
    box-shadow: 0 1px 2px rgba(12,44,73,0.04);
    padding: 0 20px 18px;
    margin-top: 12px;
}

.ts-app .ts-main .ytd-panel .tab-pane { padding-top: 16px; }
/* the sub-tabs are the only thing in this pane and belong to the tab above
   them, so they sit tighter than a pane holding a toolbar and a grid */
.ts-app .ts-main .ytd-panel #AccumilatorCodeSection { padding-top: 8px; }
.ts-app .ts-main .ytd-panel #MainSubSection { padding-top: 0; }
.ts-app .ts-main .ytd-panel #MainSubSection > .tab-pane { padding-top: 12px; }

.ts-app .ts-main .ytd-toolbar {
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-bottom: 12px;
    min-height: 32px;
}
.ts-app .ts-main .ytd-toolbar-actions {
    display: flex; align-items: center; gap: 8px; margin-left: auto;
}
.ts-app .ts-main .ytd-statebtn { height: 32px; padding: 0 12px; font-size: 12.5px; border-radius: 9px; }

/* "no codes linked to your account for <year>" is an informational empty
   state, not a failure — and it sits directly above the grid's own empty
   row, so the full-width red .alert-danger it used to carry stated the same
   thing twice and at alarm volume. The scripts toggle this by text content,
   leaving it present but empty whenever there are records, hence :empty. */
.ts-app .ts-main .ytd-note {
    display: inline-flex; align-items: center; padding: 6px 12px; border-radius: 9px;
    background: var(--inset); border: 1px solid var(--line-soft);
    font-size: 12.5px; color: var(--muted);
}
.ts-app .ts-main .ytd-note:empty { display: none; }

@media (max-width: 640px) {
    .ts-app .ts-main .ytd-panel > .tab-content { padding: 0 14px 16px; }
    .ts-app .ts-main .ytd-year { margin-left: 0; width: 100%; }
    .ts-app .ts-main .ytd-year .k-datepicker, .ts-app .ts-main .ytd-year .k-picker { width: auto; flex: 1; }
    .ts-app .ts-main .ytd-toolbar-actions { margin-left: 0; }
}

/* ---------- ePermitting: permit status detail (Kendo window body) ----------
   Kendo relocates the window element to <body>, which takes it outside
   .ts-main — so the .ts-app .ts-main .panel/.table rules never match here.
   These components are unscoped for that reason. */
.epermit-win { background: var(--bg); }
.ep-detail { display: flex; flex-direction: column; gap: 16px; }
.ep-cardnote { font-size: 12.5px; color: var(--muted); margin: -6px 0 14px; }
.ep-tablewrap { overflow-x: auto; }
.ep-tablewrap .ob-table { min-width: 720px; }
.ep-nodata { color: var(--faint); }

.ep-status { display: inline-block; font-size: 12px; font-weight: 600; padding: 3px 10px; border-radius: 999px; border: 1px solid; white-space: nowrap; }
.ep-status.is-approved { color: #1A6B2C; background: #EAF5EE; border-color: #D3E8DB; }
.ep-status.is-refused { color: #A12A22; background: #FDECEA; border-color: #F2C2BD; }
.ep-status.is-neutral { color: var(--muted); background: var(--inset); border-color: var(--line); }
body.is-dark .ep-status.is-approved { color: #8FD3A2; background: rgba(45,163,67,0.16); border-color: rgba(45,163,67,0.40); }
body.is-dark .ep-status.is-refused { color: var(--red); background: rgba(206,45,50,0.16); border-color: rgba(206,45,50,0.40); }

.ep-upload { height: 30px; padding: 0 11px; font-size: 12px; border-radius: 8px; }

/* the filename list is read back and rewritten as comma-separated text by
   ePermittingStatus.ts, so only the container may carry styling */
.ep-files { display: block; font-size: 11.5px; font-weight: 600; color: var(--blue); background: var(--blue-soft); border: 1px solid var(--blue-line); border-radius: 8px; padding: 3px 9px; margin-bottom: 6px; overflow-wrap: anywhere; }
.ep-files:empty { display: none; }
.ep-currentfiles { display: block; font-size: 12.5px; font-weight: 600; color: var(--blue); background: var(--blue-soft); border: 1px solid var(--blue-line); border-radius: 8px; padding: 6px 11px; margin-top: 12px; overflow-wrap: anywhere; }
.ep-currentfiles:empty { display: none; }

.ep-drop { display: flex; align-items: center; gap: 12px; padding: 16px 18px; border: 1px dashed var(--line); border-radius: 12px; background: var(--inset); flex-wrap: wrap; }
.ep-drop-ic { font-size: 22px; color: var(--blue); }
.ep-drop-tx { font-size: 13px; color: var(--muted); }
.ep-drop-tx b { display: block; color: var(--head); font-size: 13.5px; }
.ep-drop .ts-btn { margin-left: auto; }

.ep-feetotal { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; margin-top: 14px; padding-top: 14px; border-top: 2px solid var(--line); }
.ep-feetotal-lb { font-size: 13.5px; font-weight: 600; color: var(--muted); }
.ep-feetotal-nm { font-size: 26px; font-weight: 700; color: var(--head); font-variant-numeric: tabular-nums; letter-spacing: -0.5px; }

.ep-empty { display: none; align-items: center; justify-content: center; gap: 10px; padding: 30px 16px; font-size: 13.5px; color: var(--muted); text-align: center; }
.ep-card:not(:has(tbody tr)) .ep-empty { display: flex; }
.ep-card:not(:has(tbody tr)) .ep-tablewrap,
.ep-card:not(:has(tbody tr)) .ep-feetotal { display: none; }

@media (max-width: 768px) {
  .ep-detail { gap: 12px; }
  .ep-drop .ts-btn { margin-left: 0; width: 100%; }
  .ep-feetotal-nm { font-size: 22px; }
}

/* =====================================================================
   PRINT — the shell is screen furniture; the page body is the document
   ---------------------------------------------------------------------
   Print / "Save as PDF" should produce the page's own content and nothing
   else. Two inherited behaviours had to be undone for that:

   1. The only print rule the site ever had comes from the legacy Angle
      theme (app.css + app-dark.css, loaded as the light/dark theme
      bundles):

          @media print { .btn,.offsidebar,.sidebar,.topnavbar { display:none!important } }

      Those class names belong to the old TopNavbar.cshtml / Menu.cshtml
      markup. This shell uses none of them, so after the r06 rewrite
      nothing hid it and every printout led with the top bar, the product
      sidebar, the site footer and the Ask dock, laid over the content
      underneath. `.btn` is NOT repeated below — that half of the legacy
      rule still matches, so buttons keep printing as nothing.

   2. Bootstrap 3's print reset (bundled in /bundles/commonloggedinstyle)
      appends every link's target to its own text:

          a[href]:after { content: " (" attr(href) ")" }

      With the top bar printing, that is what interleaved "(/)" and
      "(/financial/Home)" through cart receipts. It's a convention for
      printed prose, where a reader can't click; on an app screen it only
      ever adds noise, so it is off site-wide rather than just in the
      chrome.

   Sitewide by design: every page on this layout wants the same thing from
   a printer. Pages needing more (an itemised report, a POS receipt) still
   layer their own @media print on top — see itemprint.css,
   pos-receipt-print.css, bookingReportPrint.css.
   ===================================================================== */
@media print {
    /* ---- shell chrome ---- */
    .ts-top,
    .ts-side,
    .ts-navoverlay,
    .ts-toast,
    .pr-footer,
    .pr-askfab,
    .pr-ask { display: none !important; }

    /* ---- layout frame. On screen the shell is a viewport-tall flex frame
       with its own scroll containers; on paper that clips content to the
       first page, so unwind it back to ordinary block flow and let the
       content break across pages by itself. ---- */
    body.ts-app { overflow: visible !important; }
    .ts-shell-row { display: block !important; min-height: 0 !important; }
    .ts-maincol { display: block !important; }
    .ts-app .ts-main { display: block !important; max-width: none !important; overflow: visible !important; }

    /* ---- no href/title text glued onto links and abbreviations (see 2.) ---- */
    a[href]:after,
    abbr[title]:after { content: "" !important; }
}
.ts-main .tab-content code { font-size: 12px; }
.form-control:disabled,
.form-control[disabled] {
    background-color: var(--disabled-bg) !important;
    border-color: var(--disabled-border) !important;
    color: var(--disabled-text) !important;
    opacity: 1;
}
.form-control:disabled::placeholder,
.form-control[disabled]::placeholder {
    color: var(--disabled-placeholder);
    opacity: 1;
}
.radio-inline input:checked:disabled + .indicator:before {
    border-color: #3e9983;
    background: #3e9983;
}
input[type="radio"]:disabled + .indicator {
    border-color: var(--disabled-radio-border);
    opacity: 0.7;
}
label:has(input[type="radio"]:disabled) {
    color: var(--disabled-radio-label);
}
.checkbox input[type="checkbox"]:disabled + .indicator {
    opacity: 0.8;
}
.checkbox label:has(input[type="checkbox"]:disabled) {
    color: var(--disabled-checkbox-label);
}
.checkbox input:checked + .indicator:before {
    border-color: var(--primary-color) !important;
    background: var(--primary-color) !important;
    color: var(--text-white) !important;
}
.checkbox input[type="checkbox"]:checked:disabled + .indicator::after {
    border-color: var(--card);
}
input[type="radio"]:disabled + .indicator,
.checkbox label:has(input[type="checkbox"]:disabled),
.switch input:disabled + span {
    cursor: not-allowed;
}
.switch input:disabled + span {
    background-color: var(--disabled-switch-bg);
    border-color: var(--disabled-switch-border);
    opacity: 0.75;
}
.switch input:checked:disabled + span {
    background-color: #398b77 !important;
    border-color: #398b77 !important;
}
.switch input:disabled + span::before {
    background-color: var(--card);
    opacity: 0.9;
}
.btn:disabled,
.k-button:disabled {
    opacity: 0.6 !important;
}
.k-input.k-disabled,
.k-input.k-disabled .k-input-inner,
.k-picker.k-disabled,
.k-textbox[disabled],
.k-textbox:disabled {
    background-color: var(--disabled-bg) !important;
    border-color: var(--disabled-kendo-border) !important;
    color: var(--disabled-text) !important;
    opacity: 1;
}
.k-input.k-disabled .k-input-inner::placeholder {
    color: var(--disabled-text) !important;
    opacity: 1;
}