/* Design tokens consumed by the explicit component overrides below — not a full retheme, since Bootstrap 5.1 hardcodes hex/px rather than var(). */
:root {
  --radius-sm: 0.5rem;
  --radius-md: 0.75rem;
  --radius-lg: 1rem;
  --radius-pill: 999px;

  --shadow-1: 0 1px 2px rgba(16, 24, 40, 0.06), 0 1px 3px rgba(16, 24, 40, 0.10);
  --shadow-2: 0 2px 4px rgba(16, 24, 40, 0.06), 0 6px 16px rgba(16, 24, 40, 0.12);
  --shadow-3: 0 12px 32px rgba(16, 24, 40, 0.18);

  --border-subtle: #e2e5ea;
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
  
  --safe-top: max(env(safe-area-inset-top), 12px);
  /* Explicit 0px fallback: without one, env() is invalid where unsupported, which would take
     --nav-lift's calc down with it and leave the nav pill with no bottom offset at all. */
  --safe-bottom: env(safe-area-inset-bottom, 0px);

  /* How far .app-bottom-nav's pill floats above the screen edge. In standalone the
     home-indicator inset already provides most of that clearance, so only the shortfall is
     added rather than the whole inset on top of a fixed gap — which is what made the nav
     sit ~44px too high there. */
  --nav-lift: max(10px, calc(var(--safe-bottom) - 18px));
  --nav-height: 64px;

  /* Mobile clearance above .app-bottom-nav; shared by every fixed bottom bar (.reserve-bar,
     .route-nav-bar, .pd-action-bar). No gap is added on top: content stopping exactly at the
     pill's top edge is what lets rows slide under the glass while scrolling and still clear it
     at rest. */
  --bottom-clearance: calc(var(--nav-height) + var(--nav-lift));
}

/* Design tokens for the Property Details / Route redesign (Claude Design comp
   "CRM Door Knocking App Review"). Scoped to .pd-shell rather than :root: names are
   kept verbatim from the comp so its markup/CSS can be copy-pasted here again later,
   but generic names like --text/--bg/--card would otherwise leak into the global
   cascade. Applied on the Details/Route page wrappers only — --bs-primary, the app
   chrome (topbar/sidebar/bottom-nav) and body { font-family } are untouched by
   design; adopting this system app-wide is a separate, later decision. */
.pd-shell {
  --bg: oklch(97% 0.004 265);
  --card: #ffffff;
  --border: oklch(91% 0.006 265);
  --text: oklch(23% 0.02 265);
  --muted: oklch(52% 0.015 265);
  --faint: oklch(68% 0.012 265);
  --accent: oklch(56% 0.19 265);
  --accent-dark: oklch(47% 0.18 265);
  --accent-tint: oklch(95% 0.025 265);
  --accent-tint-text: oklch(45% 0.16 265);
  --chrome: oklch(24% 0.03 265);
  --chrome-muted: oklch(62% 0.02 265);
  --chrome-active: oklch(78% 0.11 265);
  --success: oklch(55% 0.13 150);
  --success-tint: oklch(95% 0.03 150);
  --warning: oklch(50% 0.15 70);
  --warning-tint: oklch(96% 0.05 80);
  --danger: oklch(55% 0.19 25);
  --danger-tint: oklch(95% 0.035 25);
  --neutral-bg: oklch(94% 0.007 265);
  --neutral-text: oklch(42% 0.012 265);
  --font-head: 'Outfit', sans-serif;
  --font-body: 'Source Sans 3', sans-serif;
}

html {
  font-size: 15px;
}

@media (min-width: 768px) {
  html {
    font-size: 16px;
  }
}

/* Height set 3x on html/body — 100% fallback, 100dvh modern, var(--vh100) JS override from _Layout.cshtml — each overrides the last only where supported, so keep all three. */
html {
  position: relative;
  height: 100%;
  height: 100dvh;
  height: var(--vh100, 100dvh);
}

body {
  display: flex;
  flex-direction: column;
  height: 100%;
  height: 100dvh;
  height: var(--vh100, 100dvh);
  overflow: hidden;
  background-color: #f4f5f7;
  /* Containing block for .app-bottom-nav's position:absolute (see that rule for why not fixed). */
  position: relative;
}

.app-scroll {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  /* The dark top bar this used to sit on is gone — content is the first thing under the
     status bar/notch now, so the safe-area clearance moved here instead of disappearing
     with it. */
  padding-top: var(--safe-top);
}

/* Sticky footer: app-main fills header-to-scroll-bottom even on short pages, so an empty My List doesn't show a gap above the fixed bottom nav. */
.app-main {
  flex: 1 0 auto;
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}

.btn-info {
  color: white;
}

.badge {
  border-radius: var(--radius-pill);
  font-weight: 600;
  letter-spacing: 0.01em;
  padding: 0.4em 0.75em;
}

/* Bootstrap 5.1 lacks .text-bg-* (added in 5.1.3); solid colors, not tinted, since this app is read outdoors and pastel badges wash out in direct sun. */
.text-bg-primary   { color: #fff; background-color: var(--bs-primary); }
.text-bg-secondary { color: #fff; background-color: #6c757d; }
.text-bg-success   { color: #fff; background-color: #198754; }
.text-bg-danger    { color: #fff; background-color: #dc3545; }
.text-bg-dark      { color: #fff; background-color: #212529; }
.text-bg-warning   { color: #423400; background-color: #ffc107; }
.text-bg-info      { color: #04414d; background-color: #0dcaf0; }
.text-bg-light     { color: #495057; background-color: #eef0f3; border: 1px solid var(--border-subtle); }

/* --- App chrome --- */
/* Leave room for the fixed bottom nav on phones (plus iPhone home indicator). */
@media (max-width: 767.98px) {
  .app-main {
    padding-bottom: var(--bottom-clearance);
  }
}

/* position:absolute, not fixed — on-device, this WKWebView's fixed containing block falls short of the true screen bottom by ~the top safe-area inset; anchoring to body instead reaches it, since body is sized off --vh100 (screen.height in this scenario, see _Layout.cshtml) and never scrolls itself (.app-scroll does, as a sibling of this nav, not a parent). */
/* A floating glass pill rather than an edge-to-edge strip: content runs past it on both
   sides and slides under it, which is what makes a phone screen read as taller than the
   nav's own height. Inset by 1rem to line up with .route-nav-bar, the pill this follows.
   Its height and its offset from the screen edge are --nav-height/--nav-lift, so the bars that
   have to clear it derive their position from the same two numbers instead of restating them. */
.app-bottom-nav {
  position: absolute;
  bottom: var(--nav-lift);
  left: 1rem;
  right: 1rem;
  z-index: 1030;
  display: flex;
  /* Keeps the active capsule clear of the pill's rounded ends, and packs the items in
     toward the middle. The width it takes comes back off the items' own padding rather than
     off the labels, which have none to spare. */
  padding: 0 10px;
  border-radius: var(--radius-pill);
  background-color: #1a1d29;
  box-shadow: var(--shadow-3);
  /* Clips the active capsule and the sheen to the pill's own corners. */
  overflow: hidden;
}

/* The glass itself, opt-in so the solid #1a1d29 above stays the fallback. Blur plus a
   saturation boost is the frosted half of the material; the rim highlight and the hairline
   are what read as a lit edge. The refraction Apple gets at that edge needs an SVG
   displacement map in backdrop-filter, which Safari and Firefox do not support — on the
   phones this nav exists for it would render as nothing, so it is deliberately not here. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .app-bottom-nav {
    background-color: rgba(26, 29, 41, 0.50);
    -webkit-backdrop-filter: blur(3px);
    backdrop-filter: blur(3px);
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.14),
      0 0 0 0.5px rgba(255, 255, 255, 0.08),
      0 10px 30px rgba(16, 24, 40, 0.30);
  }
}

.app-bottom-nav::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0.10), rgba(255, 255, 255, 0) 55%);
}

/* iOS/Android "reduce transparency" is an accessibility setting, and a nav sitting over a
   dense list is exactly what it is turned on for. */
@media (prefers-reduced-transparency: reduce) {
  .app-bottom-nav {
    background-color: #1a1d29;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }

  .app-bottom-nav::before {
    display: none;
  }
}

/* The item fills the pill's full height so the tap target is the whole 64px; the active
   capsule is drawn by ::before rather than as this element's own background, so its width is
   free of the label's. */
.app-bottom-nav .app-bottom-nav-item {
  position: relative;
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  /* No horizontal padding: at this label size "Properties" needs nearly the whole 1/5 share
     of the pill, and the breathing room at the ends comes from the nav's padding instead. */
  padding: 0;
  min-height: var(--nav-height);
  color: #ffffff;
  text-decoration: none;
  font-size: 0.75rem;
  /* "Properties" is within a few px of its share of the pill. Wrapping would push the item
     past the --nav-height the pill is sized from, so it clips rather than reflows. */
  white-space: nowrap;
}

/* Overrides the width/height attributes on each inline <svg> in _Layout.cshtml, so the icon
   size is set here beside the label size rather than five times in the markup. */
.app-bottom-nav .app-bottom-nav-item svg {
  width: 24px;
  height: 24px;
}

.app-bottom-nav .app-bottom-nav-item:hover,
.app-bottom-nav .app-bottom-nav-item:focus {
  color: #ffffff;
}

/* The label stays white in both states so the active colour only ever has to be legible as a
   22px glyph, never as 10px text — which is what a blue strong enough to read as "selected"
   costs when currentColor drives both. A rule matching the <span> directly beats the item's
   inherited colour whatever the active rule's specificity, so the order of these two is free. */
.app-bottom-nav .app-bottom-nav-item span {
  color: #ffffff;
}

.app-bottom-nav .app-bottom-nav-item.active {
  color: var(--bs-primary, #0d6efd);
  font-weight: 600;
}

/* Deliberately wider than the item it sits in: only one is ever active, so the 2px of overhang
   costs its neighbours nothing and gives the label room to breathe inside the capsule. The
   distance from the pill's own ends comes from the nav's padding instead. */
.app-bottom-nav .app-bottom-nav-item.active::before {
  content: "";
  position: absolute;
  inset: 5px -2px;
  z-index: -1;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.14);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14);
}

/* .app-bottom-nav-item is shared by <a> tabs and the "More" trigger, which has
   to be a <button> since it opens a sheet instead of navigating. */
button.app-bottom-nav-item {
  background: transparent;
  border: 0;
  font-family: inherit;
}

/* Desktop-only left sidebar, replacing the top navbar at md+ (mobile keeps the top bar + bottom nav above, untouched). */
.app-sidebar {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  z-index: 1030;
  width: 220px;
  background-color: #1a1d29;
  padding: 1.25rem 0 1rem;
  overflow-y: auto;
}

.app-sidebar-brand {
  display: block;
  padding: 0 1.25rem 1.25rem;
  color: #ffffff;
  font-weight: 600;
  font-size: 1.15rem;
  text-decoration: none;
}

.app-sidebar-nav {
  display: flex;
  flex-direction: column;
}

.app-sidebar-item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 1.25rem;
  border-left: 3px solid transparent;
  color: #9aa0b5;
  text-decoration: none;
  font-size: 0.9rem;
}

.app-sidebar-item:hover,
.app-sidebar-item:focus {
  color: #ffffff;
}

.app-sidebar-item.active {
  color: #4da3ff;
  font-weight: 600;
  border-left-color: #4da3ff;
  background-color: rgba(77, 163, 255, 0.08);
}

.app-sidebar-footer {
  padding: 1rem 1.25rem 0;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
}

.app-sidebar-user-link {
  display: block;
  color: #9aa0b5;
  font-size: 0.85rem;
  text-decoration: none;
}

.app-sidebar-user-link:hover,
.app-sidebar-user-link:focus {
  color: #ffffff;
}

/* A labelled band of sidebar links that belong to a different tier than the ones
   above them. Each link reuses .app-sidebar-item's layout; only the label color
   and the active state distinguish one group from another. */
.app-sidebar-group {
  margin-top: 0.5rem;
  padding-top: 0.875rem;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.app-sidebar-group-label {
  padding: 0 1.25rem 0.5rem;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.45);
}

/* Platform tools (Sub-Accounts/Usage/Plans): a distinct tier of access, not just
   more nav items — gold, matching the "Admin Console Screens" comp. Gold means
   "one tier above this company", so no other group may borrow it. */
.app-sidebar-platform .app-sidebar-group-label {
  color: #e8b93f;
}

.app-sidebar-platform .app-sidebar-item.active {
  color: #ffffff;
  font-weight: 600;
  border-left-color: #e8b93f;
  background-color: rgba(232, 185, 63, 0.1);
}

@media (min-width: 768px) {
  .app-main-with-sidebar {
    margin-left: 220px;
    width: calc(100% - 220px);
  }

  .reserve-bar,
  .route-nav-bar {
    left: 220px;
  }
}

/* Settings hub. Desktop reads as a second sidebar beside the primary one (mockup #16); below md
   the sub-nav is replaced entirely by a "← Company Settings" back link to the grouped mobile menu
   (Views/CompanySettings/Menu.cshtml) — a phone has no room for a nav-beside-content layout. */
.settings-shell {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
}

.settings-heading {
  display: none;
}

.settings-back-link {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0 1rem;
  color: var(--muted);
  text-decoration: none;
  font-weight: 600;
  font-size: 0.9rem;
}

.settings-back-link:hover,
.settings-back-link:focus {
  color: var(--accent);
}

.settings-nav {
  display: flex;
  gap: 0.5rem;
  overflow-x: auto;
  padding-bottom: 0.25rem;
  -webkit-overflow-scrolling: touch;
}

.settings-nav-item {
  flex: 0 0 auto;
  padding: 0.5rem 0.9rem;
  border: 1px solid #dee2e6;
  border-radius: 999px;
  color: #495057;
  text-decoration: none;
  font-size: 0.9rem;
  white-space: nowrap;
}

.settings-nav-item:hover,
.settings-nav-item:focus {
  color: #0d6efd;
  border-color: #9ec5fe;
}

.settings-nav-item.active {
  color: #ffffff;
  background-color: #0d6efd;
  border-color: #0d6efd;
  font-weight: 600;
}

.settings-content-header {
  margin-bottom: 1rem;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid #dee2e6;
}

/* Forms in the hub read better capped than stretched across a wide monitor; tables keep the full content width. */
.settings-form {
  max-width: 560px;
}

/* The cap is a page-layout concern and the partials carrying it serve both a page and a modal
   fragment. Inside a dialog .modal-dialog has already set the measure, and 560px only leaves a
   modal-lg one padded out with empty space. */
.modal-content .settings-form {
  max-width: none;
}

/* Drag-to-reorder rows (Lead Statuses, Custom Fields, a field's Options) — see wwwroot/js/reorder-list.js. */
.reorder-handle-cell {
  width: 1%;
  white-space: nowrap;
}

.settings-drag-handle {
  cursor: grab;
  color: var(--muted);
  /* Without this, a touch drag on the handle is read as a page scroll first. */
  touch-action: none;
  padding: 0 0.5rem;
}

.settings-drag-handle:active {
  cursor: grabbing;
}

.settings-reorder-ghost {
  opacity: 0.4;
  background-color: #f1f3f5;
}

.settings-reorder-chosen td {
  background-color: #eef4ff;
}

@media (min-width: 768px) {
  .settings-shell {
    grid-template-columns: 210px minmax(0, 1fr);
    gap: 0;
    align-items: start;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: hidden;
  }

  .settings-aside {
    background: var(--card);
    border-right: 1px solid var(--border);
    padding: 1.5rem 0 1.5rem;
    align-self: stretch;
  }

  .settings-content {
    padding: 1.75rem 2rem;
  }

  .settings-heading {
    display: block;
    padding: 0 1.25rem 0.75rem;
    font-size: 1.1rem;
    font-weight: 700;
  }

  /* Vertical list on desktop, filled accent background on the active row (mockup #16) rather
     than the primary sidebar's left-border marker — this is a lighter, white-panel chrome. */
  .settings-nav {
    flex-direction: column;
    gap: 0;
    overflow-x: visible;
  }

  .settings-nav-item {
    padding: 0.65rem 1.25rem;
    border: 0;
    border-radius: 0;
    font-family: var(--font-body, inherit);
  }

  .settings-nav-item.active {
    color: #ffffff;
    background-color: var(--accent);
    font-weight: 600;
  }
}

/* --- Settings hub on a phone (Claude Design comp "16 Settings Mobile") ---------------------

   .hub-* is the card language the hub's list pages use below md, where seven of the eight
   sections were a .table-responsive around a four-to-seven column table with three to six
   btn-sm buttons per row. Each list now renders twice — the table stays for md and up, a card
   list beside it takes the phone — and the row's buttons collapse into one overflow sheet.

   No new token block: the hub is already wrapped in .pd-shell (_SettingsLayout) and the comp's
   :root set is that same one verbatim, so this follows the .pw-* precedent below rather than
   declaring a fourth *-shell. .settings-* above stays the desktop shell layout; the prefixes are
   deliberately unrelated so a grep for one never returns the other.

   Everything visual here is inside a max-width query, and the markup that uses it is d-md-none,
   so desktop renders exactly as it did before. */

@media (max-width: 767.98px) {
  /* Empty now that the back link sits in the content header: the heading is display:none and
     the sub-nav is d-none, so leaving it in the grid only buys an empty row and a gap. */
  .settings-aside {
    display: none;
  }

  /* The comp's section header: back link, title, the SettingsActions button and the description
     in one white block. Full-bleed against .app-main's px-2 and main's py-3, and sticky so the
     section you are in stays named while a long list scrolls under it. */
  .settings-content-header {
    position: sticky;
    top: 0;
    z-index: 3;
    margin: -1rem -0.5rem 0.75rem;
    padding: 0.25rem 1rem 0.75rem;
    background: var(--card);
    border-bottom: 1px solid var(--border);
  }

  .settings-back-link {
    padding: 0.3rem 0 0.15rem;
    min-height: 40px;
    color: var(--accent);
    font-size: 0.85rem;
  }

  .hub-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }

  .hub-card {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.75rem 0.875rem;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 14px;
  }

  /* Deactivated users, archived definitions: present, legible, visibly not live. */
  .hub-card-dim {
    background: var(--neutral-bg);
  }

  .hub-card-faded {
    opacity: 0.72;
  }

  /* A card whose facts don't fit one line: title row on top, badges and history below it. */
  .hub-card-stacked {
    flex-direction: column;
    align-items: stretch;
    gap: 0.5rem;
  }

  .hub-card-row {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
  }

  .hub-card-foot {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.375rem;
  }

  /* A webhook error is already truncated server-side; two lines is what a card can carry. */
  .hub-card-error {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-size: 0.75rem;
    line-height: 1.45;
    color: var(--danger);
    word-break: break-word;
  }

  .hub-card-foot-end {
    margin-left: auto;
    font-size: 0.72rem;
    color: var(--faint);
  }

  .hub-card-body {
    flex: 1;
    min-width: 0;
  }

  .hub-card-title {
    font-weight: 600;
    font-size: 0.925rem;
    color: var(--text);
    text-decoration: none;
  }

  .hub-card-meta {
    margin-top: 0.15rem;
    font-size: 0.75rem;
    line-height: 1.45;
    color: var(--muted);
  }

  .hub-card-meta-1 {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* The key is what an importer has to match character for character, so it keeps the monospace
     treatment the desktop table gives it rather than folding into the meta line. */
  .hub-card-key {
    margin-top: 0.15rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.7rem;
    color: var(--faint);
  }

  /* Both sit over the card's stretched link, the same rule .property-card states for its own
     buttons — without it the link's overlay swallows the tap. */
  .hub-grip,
  .hub-more {
    position: relative;
    z-index: 2;
    flex: 0 0 auto;
  }

  /* Always visible rather than revealed by a reorder mode: the grip is the only thing that
     starts a drag (Sortable's handle option), so the rest of the card stays a tap-to-edit
     target and the two gestures never compete. */
  .hub-grip {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    min-height: 44px;
    margin: -0.5rem 0 -0.5rem -0.375rem;
    color: var(--faint);
    cursor: grab;
    /* Without this a touch drag on the handle is read as a page scroll first. */
    touch-action: none;
  }

  .hub-grip:active {
    cursor: grabbing;
  }

  /* reorder-list.js's chosenClass is written for table rows (.settings-reorder-chosen td); a
     card needs its own lift. */
  .hub-card.settings-reorder-chosen {
    border-color: var(--accent);
    box-shadow: 0 8px 20px rgba(16, 24, 40, 0.12);
  }

  .hub-more {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    margin: -0.5rem -0.5rem -0.5rem 0;
    padding: 0;
    border: 0;
    border-radius: 10px;
    background: transparent;
    color: var(--muted);
  }

  .hub-more:active {
    background: var(--neutral-bg);
  }

  /* Parked on its own card until the sheet borrows it — see wwwroot/js/hub-sheet.js. */
  .hub-actions {
    display: none;
  }

  .hub-empty {
    padding: 1.25rem 0.25rem;
    color: var(--muted);
    font-size: 0.85rem;
  }

  .hub-note {
    padding: 0 0.15rem;
    font-size: 0.72rem;
    line-height: 1.55;
    color: var(--muted);
  }

  .hub-seatbar {
    height: 6px;
    border-radius: 3px;
    background: var(--neutral-bg);
    overflow: hidden;
  }

  .hub-seatbar-fill {
    display: block;
    height: 100%;
    background: var(--accent);
  }

  .hub-seatbar-over {
    background: var(--warning);
  }

  .hub-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem;
    margin-top: 0.625rem;
  }

  .hub-chip {
    padding: 0.35rem 0.85rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--card);
    color: var(--muted);
    font-size: 0.78rem;
    font-weight: 600;
  }

  .hub-chip[aria-pressed="true"] {
    background: var(--accent);
    border-color: var(--accent);
    color: #ffffff;
  }

  /* Save above the tab bar, so a long form never hides its own submit. Same clearance rule as
     .pd-action-bar and .imp-footer-bar; .hub-dock-pad is the companion the content must carry
     or the dock covers its last field. */
  .hub-dock {
    position: fixed;
    left: 0;
    right: 0;
    bottom: var(--bottom-clearance);
    z-index: 1029;
    display: flex;
    gap: 0.5rem;
    padding: 0 1rem 0.625rem;
  }

  .hub-dock .btn:not(.btn-link) {
    flex: 1;
    min-height: 52px;
    border-radius: 16px;
    font-family: var(--font-head);
    font-weight: 600;
    box-shadow: 0 8px 20px rgba(40, 30, 120, 0.24);
  }

  .hub-dock .btn-outline-secondary:not(.btn-link) {
    flex: 0 0 auto;
    background: var(--card);
    box-shadow: none;
  }

  .hub-dock-pad {
    padding-bottom: 84px;
  }

  /* A page concern, switched off inside a dialog rather than removed from the partial: the same
     partials carry it to both, and there is no dock in a modal to clear. */
  .modal-content .hub-dock-pad {
    padding-bottom: 0;
  }

  /* Nullable number, made explicit: the toggle owns "no limit" and the stepper owns the value,
     so neither answer needs a keyboard. One input throughout — a second control with the same
     name would post twice. */
  .hub-stepper {
    display: flex;
    align-items: center;
    gap: 0.5rem;
  }

  .hub-stepper .form-control {
    text-align: center;
    font-family: var(--font-head);
    font-weight: 600;
  }

  .hub-stepper .form-control::-webkit-outer-spin-button,
  .hub-stepper .form-control::-webkit-inner-spin-button {
    appearance: none;
    margin: 0;
  }

  .hub-stepper-btn {
    flex: 0 0 auto;
    width: 48px;
    min-height: 48px;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--card);
    color: var(--muted);
    font-family: var(--font-head);
    font-size: 1.25rem;
    font-weight: 600;
  }

  /* Bootstrap's 16px box is a miss on a phone; the label and its description are part of the
     same tap target. Permissions is 13 of these across 7 groups. */
  .hub-check .form-check-input {
    width: 1.6rem;
    height: 1.6rem;
    margin-top: 0.1rem;
    border-radius: 7px;
  }

  .hub-check .form-check-label {
    padding-left: 0.4rem;
  }
}

/* The row-actions sheet every hub card list shares. It sits at body level beside #formModal
   because .offcanvas-bottom is position:absolute (see that rule for the WKWebView reason) and
   body is the containing block it anchors to. That puts it outside every .pd-shell, so — like
   #moreSheet — it carries its own small token set: the card's action node is *moved* in here
   rather than serialised, and has to keep resolving the same names on the way. */
#hubSheet {
  --card: #ffffff;
  --border: oklch(91% 0.006 265);
  --text: oklch(23% 0.02 265);
  --muted: oklch(52% 0.015 265);
  --faint: oklch(68% 0.012 265);
  --accent: oklch(56% 0.19 265);
  --danger: oklch(55% 0.19 25);
  --font-head: 'Outfit', sans-serif;
}

#hubSheet .hub-actions {
  display: flex;
  flex-direction: column;
}

.hub-sheet-head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding-bottom: 0.5rem;
}

.hub-sheet-title {
  font-family: var(--font-head);
  font-size: 1rem;
  font-weight: 600;
  color: var(--text);
}

.hub-sheet-sub {
  font-size: 0.75rem;
  color: var(--muted);
}

.hub-sheet-item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  min-height: 52px;
  padding: 0.5rem 0;
  border: 0;
  border-top: 1px solid var(--border);
  background: transparent;
  color: var(--text);
  font-family: inherit;
  font-size: 0.925rem;
  font-weight: 600;
  text-align: left;
  text-decoration: none;
}

.hub-sheet-item > span:first-child {
  flex: 1;
}

/* Why an action is unavailable, as text. The desktop button says it in a title attribute, which
   no phone has ever shown — and hiding the row instead sends an admin hunting for a page that
   would let them. */
.hub-sheet-note {
  display: block;
  margin-top: 0.1rem;
  font-size: 0.72rem;
  font-weight: 400;
  line-height: 1.45;
  color: var(--muted);
}

/* Rows that navigate get the same chevron the menu rows use; drawn rather than inlined seven
   times over. */
.hub-sheet-item-nav::after {
  content: "";
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  border-top: 1.6px solid currentColor;
  border-right: 1.6px solid currentColor;
  transform: rotate(45deg);
  opacity: 0.45;
}

.hub-sheet-item-danger {
  color: var(--danger);
}

.hub-sheet-item-disabled {
  color: var(--faint);
  cursor: default;
}

.hub-sheet-cancel {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 52px;
  margin-top: 0.75rem;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--card);
  color: var(--text);
  font-family: inherit;
  font-size: 0.875rem;
  font-weight: 600;
}

.hub-sheet-grabber {
  width: 36px;
  height: 4px;
  margin: 0.375rem auto 0.75rem;
  border-radius: 2px;
  background: var(--border);
}

/* The whole card is a stretched-link to Details; raise action buttons (e.g. "Knock") above its overlay to keep them tappable. */
.property-card .card-body .btn {
  position: relative;
  z-index: 2;
}

/* Same trick for the multi-select checkbox so it stays tappable over the card link. */
.property-card .card-body .reserve-check {
  position: relative;
  z-index: 2;
  width: 1.4rem;
  height: 1.4rem;
  margin-top: 0.1rem;
  cursor: pointer;
}

/* Select mode: the checkbox stays hidden and the whole card becomes the tap target (click handler intercepts stretched-link navigation, see Index.cshtml). */
.property-list.select-mode .selectable-card {
  cursor: pointer;
}

.property-list .selectable-card.selected {
  border-color: var(--bs-primary);
  background-color: rgba(13, 110, 253, 0.08);
}

/* Reserved cards have no checkbox, so their Details link goes inert (pointer-events: none) while picking leads to reserve; normal browsing is untouched. */
.property-list.select-mode .property-card:not(.selectable-card) .stretched-link {
  pointer-events: none;
}

/* Sticky "Reserve for today" action bar; sits above the phone bottom nav. */
.reserve-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1029;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.75rem 1rem;
  background-color: #ffffff;
  border-top: 1px solid #dee2e6;
}

@media (max-width: 767.98px) {
  .reserve-bar {
    bottom: var(--bottom-clearance);
  }
}

/* Previous/Full Route/Next bar — a floating rounded pill (Claude Design's
   "EminenceCRM UI Review" comp, "03 · Route planner"), not an edge-to-edge strip.
   Fixed-width Prev/Next slots (empty <span> placeholders hold the slot when
   hidden) keep "Full Route" centered; 1px dividers separate the three sections
   instead of a gap, matching the comp. Sits above .app-bottom-nav;
   .pd-action-bar-stacked (on the .pd-action-bar above it, Route page only) adds
   its own extra offset to clear it. */
.route-nav-bar {
  position: fixed;
  left: 1rem;
  right: 1rem;
  bottom: 0;
  z-index: 1029;
  height: 52px;
  display: flex;
  align-items: center;
  background: var(--chrome, #1a1d29);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-2);
}

.route-nav-bar-step {
  /* Wider than tall on purpose: Prev/Next flank the "Full Route" label with only a 1px divider
     between them, and 52px (matching the bar's height) was too easy to overshoot into the label. */
  flex: 0 0 76px;
  height: 52px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  color: #fff;
  padding: 0;
}

.route-nav-bar-step.route-nav-bar-next {
  color: var(--chrome-active, #fff);
}

.route-nav-bar-divider {
  flex: 0 0 1px;
  width: 1px;
  height: 22px;
  background: rgba(255, 255, 255, 0.18);
}

.route-nav-bar-label {
  flex: 1 1 auto;
  background: transparent;
  border: 0;
  color: #fff;
  font-weight: 600;
  font-family: var(--font-head, inherit);
  font-size: 0.85rem;
  text-align: center;
}

@media (max-width: 767.98px) {
  .route-nav-bar {
    /* Small gap above the bottom nav so the pill visibly floats, rather than
       sitting flush against it like the old edge-to-edge bar did. */
    bottom: calc(var(--bottom-clearance) + 8px);
  }
}

/* Keep the last card visible above the fixed route bars (.pd-action-bar +
   .route-nav-bar stacked). */
.route-page {
  padding-bottom: 168px;
}

/* Same idea as .route-page, but only one fixed bar (.pd-action-bar) sits below it. */
.property-actions-page {
  padding-bottom: 100px;
}

/* Street View photo (shared partial, Route page too); fixed height so the page doesn't jump while the proxy fetches from Google. */
.street-view-photo {
  width: 100%;
  height: 200px;
  object-fit: cover;
  background-color: #eef0f3;
}

/* --- Property Details / Route redesign components (.pd-shell tokens) --- */

/* .pd-header holds .pd-headline (photo + address, the card on phones) and .pd-header-content
   (the fact strip). Below md the card is its own grid, collapsed or open; at md+ the card is
   display:contents so .pd-header's grid lays the same parts out as comp 10h's two columns. */
.pd-header-content {
  min-width: 0;
}

.pd-hero {
  position: relative;
  overflow: hidden;
  background-color: var(--border, #eef0f3);
}

.pd-hero .street-view-photo {
  height: 100%;
  border-radius: 0;
}

/* --- The phone card (comps 10l collapsed / 10m expanded) --- */

@media (max-width: 767.98px) {
  .pd-headline {
    --pd-hero-thumb: 72px;
    --pd-hero-open-height: 250px;
    position: relative;
    display: grid;
    grid-template-columns: var(--pd-hero-thumb) minmax(0, 1fr);
    grid-template-areas:
      "media title"
      "media meta"
      "media chips";
    align-content: start;
    column-gap: 10px;
    /* Right gutter for the corner toggle, which the text must not run under; left gutter for
       .pd-headline-back, which sits in front of the thumbnail rather than in a grid column of
       its own. */
    padding: 10px 42px 10px 40px;
    margin-bottom: 0.75rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: #fff;
    overflow: hidden;
  }

  .pd-headline .pd-hero {
    grid-area: media;
    align-self: start;
    width: var(--pd-hero-thumb);
    height: var(--pd-hero-thumb);
    border-radius: var(--radius-md);
  }

  .pd-headline-title {
    grid-area: title;
  }

  .pd-headline .pd-meta {
    grid-area: meta;
    margin-top: 2px;
  }

  .pd-headline-chips {
    grid-area: chips;
    margin-top: 8px;
  }

  .pd-headline-open {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "media"
      "title"
      "meta";
    padding: 0 12px 10px;
  }

  /* Full-bleed to the card's border, which its own overflow:hidden rounds off. */
  .pd-headline-open .pd-hero {
    width: auto;
    height: var(--pd-hero-open-height);
    margin: 0 -12px;
    border-radius: 0;
  }

  .pd-headline-open .pd-headline-title {
    margin-top: 10px;
  }

  /* Same grid area as the photo rather than absolutely positioned, so the chips sit on the
     image without either one needing to know where the other ends. */
  .pd-headline-open .pd-headline-chips {
    grid-area: media;
    align-self: end;
    justify-self: start;
    z-index: 1;
    margin: 0 0 8px -4px;
  }

  .pd-headline-open .pd-headline-chips .badge {
    background: rgba(20, 20, 35, 0.55);
    color: #fff;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
  }

  /* The whole card is the control, so the button covers it and only the circle is painted. This is
     also why nothing else inside the card may become interactive at this width — .pd-headline-back
     below is the one exception, given a higher z-index to punch through this cover. */
  .pd-headline-toggle {
    position: absolute;
    inset: 0;
    z-index: 2;
    padding: 0;
    border: 0;
    background: transparent;
  }

  .pd-headline-toggle-icon {
    position: absolute;
    right: 10px;
    /* Level with the thumbnail's bottom edge. Measured off the top because the toggle animates
       the card's height, and an icon anchored to the bottom would ride that animation as well as
       its own. Card padding + thumbnail, less the icon's own 26px. */
    top: calc(10px + var(--pd-hero-thumb) - 26px);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border: 1px solid var(--border);
    border-radius: 50%;
    background: var(--bg, #f6f7f9);
    color: var(--muted);
  }

  /* Same relationship to the photo, which here is the full width of the card. */
  .pd-headline-open .pd-headline-toggle-icon {
    top: calc(var(--pd-hero-open-height) - 34px);
    right: 8px;
    border-color: transparent;
    background: rgba(20, 20, 35, 0.55);
    color: #fff;
  }

  .pd-headline-toggle .pd-icon-collapse,
  .pd-headline-open .pd-headline-toggle .pd-icon-expand {
    display: none;
  }

  .pd-headline-open .pd-headline-toggle .pd-icon-collapse {
    display: block;
  }

  /* Comps 10p/10r: a chevron in the card's left gutter when collapsed, a translucent pill on the
     photo when expanded. Same absolute-over-the-cover-button trick as .pd-headline-toggle-icon,
     but this one is a real link (not paint-only), so it needs its own stacking context above the
     toggle button's z-index: 2 to stay tappable. */
  .pd-headline-back {
    position: absolute;
    left: 6px;
    top: 10px;
    z-index: 3;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: var(--pd-hero-thumb);
    color: var(--accent);
    text-decoration: none;
  }

  .pd-headline-back-label {
    display: none;
  }

  .pd-headline-open .pd-headline-back {
    left: 8px;
    top: 10px;
    width: auto;
    height: 32px;
    padding: 0 12px;
    gap: 5px;
    border-radius: 999px;
    background: rgba(20, 20, 35, 0.45);
    color: #fff;
  }

  .pd-headline-open .pd-headline-back-label {
    display: inline;
    font: 600 12.5px var(--font-body);
  }
}

@media (min-width: 768px) {
  .pd-header {
    display: grid;
    grid-template-columns: 300px minmax(0, 1fr);
    grid-template-areas:
      "media title"
      "media meta"
      "media chips"
      "media rest";
    column-gap: 20px;
    align-content: start;
  }

  /* The card chrome is a phone treatment; here the same children become items of .pd-header. */
  .pd-headline {
    display: contents;
  }

  .pd-hero {
    grid-area: media;
    align-self: start;
    height: 186px;
    border-radius: var(--radius-lg);
  }

  .pd-headline-title {
    grid-area: title;
    margin-bottom: 0.25rem;
  }

  /* Scoped: .pd-meta is the app's general muted-line class, used well outside this header. */
  .pd-headline .pd-meta {
    grid-area: meta;
  }

  .pd-headline-chips {
    grid-area: chips;
    margin-top: 0.25rem;
  }

  .pd-header-content {
    grid-area: rest;
  }

  /* On the strip rather than the chips above it, which don't render on every lead. */
  .pd-fact-strip {
    margin-top: 1rem;
  }

  /* Buttons next to the title (comp 10h), same rounded-rect treatment as .pd-actions-row .btn. */
  .pd-header-actions .btn {
    border-radius: var(--radius-md);
  }
}

.pd-title {
  font-family: var(--font-head);
  font-weight: 700;
}

.pd-meta {
  color: var(--muted);
}

/* The support diagnostics block. Wraps rather than scrolls: a user agent string is long and a
   horizontal scrollbar on a phone hides half of what they are being asked to copy. */
.pd-diagnostics {
  background-color: var(--bg);
  border: 1px solid var(--border);
  border-radius: 0.5rem;
  padding: 0.75rem;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  color: var(--muted);
}

.pd-headline-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
  color: var(--muted);
}

/* Tint modifiers layer on top of the existing .badge base (pill radius/weight already set above). */
.pd-tint-accent {
  background-color: var(--accent-tint);
  color: var(--accent-tint-text);
}

.pd-tint-success {
  background-color: var(--success-tint);
  color: var(--success);
}

.pd-tint-warning {
  background-color: var(--warning-tint);
  color: var(--warning);
}

.pd-tint-danger {
  background-color: var(--danger-tint);
  color: var(--danger);
}

.pd-tint-neutral {
  background-color: var(--neutral-bg);
  color: var(--neutral-text);
}

/* Restyles the existing native <select> (Lead Status) as a pill — same element,
   same onchange/form submit, appearance only. */
.pd-status-select {
  appearance: none;
  -webkit-appearance: none;
  background-color: var(--accent-tint);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' width='12' height='8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23453a80' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.6rem center;
  color: var(--accent-tint-text);
  border: 0;
  border-radius: var(--radius-pill);
  font-weight: 600;
  font-size: 0.85rem;
  padding: 0.4rem 1.75rem 0.4rem 0.9rem;
}

.pd-actions-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  flex-wrap: wrap;
}

/* Share/Edit are the rounded-rect (not full-pill) style from the comp's Status/Share/Edit row. */
.pd-actions-row .btn {
  border-radius: var(--radius-md);
}

/* Owner card's primary-phone marker — Phones[0] is already the primary number
   (PropertyContactVm doc comment), not a fabricated presence signal. */
.pd-primary-star {
  color: var(--accent);
}

.pd-info-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 0.875rem;
  background: var(--card);
}

.pd-info-label {
  font-family: var(--font-head);
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--faint);
  margin-bottom: 0.5rem;
}

/* Added alongside the existing .nav.nav-tabs classes on #detailsTabs (its only usage app-wide). */
.pd-tabs {
  border-bottom-color: var(--border);
}

.pd-tabs .nav-link {
  font-family: var(--font-head);
  font-weight: 600;
  color: var(--faint);
  border: 0;
  border-bottom: 2px solid transparent;
}

.pd-tabs .nav-link.active {
  color: var(--accent);
  background: transparent;
  border-bottom-color: var(--accent);
}

/* Fixed bottom bar (Directions/Knock/Zillow), replacing the folding FAB — phone only.
   .pd-action-bar-stacked (Route page only, see ViewData["ShowsWayfindingBar"] in
   _PropertyDetails.cshtml) adds the extra offset for .route-nav-bar sitting below it.
   At md+ the same three buttons render inline next to the title instead (.pd-header-actions,
   comp 10h) and this bar is hidden — unlike .reserve-bar/.route-nav-bar it was never given a
   left:220px sidebar-clearance offset, because on desktop it isn't meant to exist at all. */
.pd-action-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1029;
  display: flex;
  gap: 0.5rem;
  padding: 0.75rem 1rem;
}

@media (max-width: 767.98px) {
  .pd-action-bar {
    bottom: var(--bottom-clearance);
  }
}

@media (min-width: 768px) {
  .pd-action-bar {
    display: none;
  }
}

.pd-action-bar.pd-action-bar-stacked {
  bottom: 68px;
}

@media (max-width: 767.98px) {
  .pd-action-bar.pd-action-bar-stacked {
    bottom: calc(var(--bottom-clearance) + 68px);
  }
}

.pd-action-bar .btn {
  flex: 1;
  min-height: 52px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  border: 0;
  border-radius: var(--radius-lg);
  font-family: var(--font-head);
  font-weight: 600;
  background-color: var(--accent-tint);
  color: var(--accent-tint-text);
}

.pd-action-bar .btn-primary {
  flex: 1.15;
  background-color: var(--accent);
  color: #fff;
  box-shadow: 0 8px 20px rgba(40, 30, 120, 0.28);
}

/* Properties Index (Views/Properties/Index.cshtml) — full redesign, not just the
   filter-preset placeholders: persistent search bar, 44px icon-only Filter button,
   single-pill property cards. */
.pd-filter-btn {
  position: relative;
  width: 44px;
  padding: 0;
}

.pd-filter-dot {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
}

.pd-select-pill {
  background-color: var(--accent-tint);
  color: var(--accent-tint-text);
  border: 0;
  border-radius: var(--radius-pill);
  font-weight: 600;
}

.pd-property-card {
  border-radius: var(--radius-lg);
}

.pd-property-card .pd-title {
  font-size: 1rem;
}

/* Positioned badge (e.g. "Reserved") pinned to a .pd-property-card's top-right
   corner, for cards whose header row doesn't already reserve space for it. */
.pd-property-card-badge {
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
}

/* Circular initials avatar (Contacts list). Size is a custom property so a
   caller can override it inline (style="--pd-avatar-size:32px") without a
   parallel size-modifier class. */
.pd-avatar {
  --pd-avatar-size: 40px;
  width: var(--pd-avatar-size);
  height: var(--pd-avatar-size);
  border-radius: 50%;
  background-color: var(--accent-tint);
  color: var(--accent-tint-text);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: calc(var(--pd-avatar-size) * 0.34);
}

/* Contact/case role badge — same visual language as .pd-tint-neutral but named
   for what it is so People-tab/Contacts-list markup reads clearly. */
.pd-role-pill {
  display: inline-flex;
  align-items: center;
  background-color: var(--neutral-bg);
  color: var(--neutral-text);
  font-weight: 600;
  font-size: 0.7rem;
  padding: 0.2rem 0.6rem;
  border-radius: var(--radius-pill);
}

/* Phone number rendered as a pill with a leading status dot (green = a number
   is on file, faint = none). Wraps a tel: link when a number exists. */
.pd-phone-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 0.35rem 0.7rem;
  font-weight: 600;
  font-size: 0.8rem;
  color: var(--accent);
  text-decoration: none;
}

.pd-phone-pill-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--success);
  flex: 0 0 auto;
}

.pd-phone-pill-muted {
  color: var(--faint);
}

/* Icon-only circular call button (Contacts list row) — distinct from .pd-phone-pill,
   which shows the digits themselves (People tab). Green tint when a number is on
   file, neutral/inert when not. */
.pd-call-btn {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  background: var(--success-tint);
  color: var(--success);
}

.pd-call-btn.pd-call-btn-muted {
  background: var(--neutral-bg);
  color: var(--faint);
}

.pd-phone-pill-muted .pd-phone-pill-dot {
  background: var(--faint);
}

.pd-contact-card,
.pd-case-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 0.875rem;
}

.pd-contact-card + .pd-contact-card,
.pd-case-card + .pd-case-card {
  margin-top: 0.625rem;
}

.pd-contact-card.pd-contact-card-destination {
  border-color: var(--accent);
}

/* Activity-tab timeline marker. Color modifiers map to the same tint palette
   used elsewhere rather than inventing new colors per event/outcome. */
.pd-timeline-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--neutral-text);
  flex: 0 0 auto;
  margin-top: 5px;
}

.pd-timeline-dot-accent { background: var(--accent); }
.pd-timeline-dot-warning { background: var(--warning); }
.pd-timeline-dot-success { background: var(--success); }
.pd-timeline-dot-danger { background: var(--danger); }

/* "+" icon-button style replacing plain text "Add X" buttons (Add person/Add
   case/Add contact-row actions). */
.pd-icon-btn-add {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  gap: 0.35rem;
  height: 36px;
  padding: 0 0.9rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--accent);
  font-weight: 600;
  font-size: 0.8125rem;
}

/* Small icon-only edit/delete affordance replacing plain "Edit"/"Unlink" text
   links, same tap target size as other .btn-sm controls in these tabs. */
.pd-edit-pencil {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  color: var(--faint);
  background: transparent;
  border: 0;
}

.pd-edit-pencil:hover,
.pd-edit-pencil:focus {
  color: var(--muted);
  background: var(--neutral-bg);
}

/* My List (Views/Properties/MyList.cshtml) — icon-only remove button replacing the old text
   "Remove" button; same position/z-index trick as .property-card .card-body .btn so it stays
   tappable above the card's stretched-link. */
.pd-list-remove-btn {
  position: relative;
  z-index: 2;
  width: 28px;
  height: 28px;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--card);
  color: var(--muted);
  padding: 0;
}

.pd-list-remove-btn:hover,
.pd-list-remove-btn:focus {
  color: var(--danger);
  border-color: var(--danger);
}

/* My Account (Views/Profile/Index.cshtml) — inert placeholder rows for Edit profile/Change
   password: no <a>, no chevron-click affordance, real functionality is future work. */
.pd-list-row-disabled {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.8rem 1rem;
  border-bottom: 1px solid var(--border-subtle);
  color: var(--faint);
  cursor: not-allowed;
}

.pd-list-row-disabled-last {
  border-bottom: 0;
}

/* Mobile Company Settings menu (Views/CompanySettings/Menu.cshtml) — same list-row language as
   .pd-more-sheet-item, but not coupled to #moreSheet's locally-scoped token set since this page
   is wrapped in .pd-shell directly and has its own tokens already. */
.pd-settings-menu-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.8rem 1rem;
  border-bottom: 1px solid var(--border-subtle);
  color: var(--text);
  text-decoration: none;
  font-size: 0.95rem;
  font-weight: 600;
}

.pd-settings-menu-item:hover,
.pd-settings-menu-item:focus {
  color: var(--accent);
}

.pd-settings-menu-item-last {
  border-bottom: 0;
}

/* The row's current setting, read-only: the label keeps the left, the chevron keeps the right. */
.pd-settings-menu-value {
  flex: 0 1 auto;
  min-width: 0;
  margin-right: 0.625rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--faint);
}

/* "More" bottom-nav sheet. _Layout.cshtml isn't .pd-shell-wrapped app-wide, so
   #moreSheet carries its own small scoped token set instead (smallest blast
   radius) — see the .pd-shell doc comment above for why full adoption is a
   separate decision. */
#moreSheet {
  --accent: oklch(56% 0.19 265);
  --accent-tint: oklch(95% 0.025 265);
  --accent-tint-text: oklch(45% 0.16 265);
  --font-head: 'Outfit', sans-serif;
}

.pd-more-sheet-item {
  display: flex;
  align-items: center;
  gap: 0.875rem;
  padding: 0.8rem 0.25rem;
  color: inherit;
  text-decoration: none;
  background: transparent;
  border: 0;
  width: 100%;
  text-align: left;
  font-size: 0.95rem;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
}

/* A divider between two rows, drawn as border-top on the second one rather than
   border-bottom + :last-child on the first: :last-child is scoped to the item's
   own parent, so once Team/Platform wrap their rows in .pd-more-sheet-section,
   "last child of the sheet" and "last child of the section" stop being the same
   element and that approach either doubles or drops the line at each boundary.
   These two rules key off what's structurally true regardless of nesting: a row
   right after another row gets a line, and a row right after a labelled section
   gets one too (the section's own border-top is a second, deliberately larger
   gap that marks the section itself, not a divider between two rows). */
.pd-more-sheet-item + .pd-more-sheet-item,
.pd-more-sheet-section + .pd-more-sheet-item {
  border-top: 1px solid var(--border-subtle);
}

.pd-more-sheet-item.text-danger {
  color: var(--bs-danger, #dc3545);
}

.pd-more-sheet-icon {
  width: 36px;
  height: 36px;
  border-radius: 10px;
  background: var(--accent-tint);
  color: var(--accent-tint-text);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}

/* Labels the Team/Platform bands in the More sheet, same idea as .app-sidebar-group
   but themed for the sheet's light, locally-scoped tokens. Only these two labelled
   groups get the divider — the plain rep-visible items above and below stay a flat
   list, so nothing but an actual section break gets extra vertical space. */
.pd-more-sheet-section {
  margin-top: 0.5rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border-subtle);
}

.pd-more-sheet-section-label {
  padding: 0 0.25rem 0.35rem;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
}

/* Platform tools: the same gold as the sidebar's Platform group — "one tier
   above this company", so no other section label may borrow it. */
.pd-more-sheet-section-label-platform {
  color: #b8860b;
}

/* Quick-filter chips (My Knocks / Activity History "All"/"Converted" tabs) — compact, left-aligned
   pill toggle links. Deliberately not the same class as .settings-nav-item (Settings hub sub-nav,
   a different control in a different context that happens to look similar) or .pd-period-item
   (Leaderboard's period switcher, which stretches to fill its row — these chips must not). */
.pd-chip-row {
  display: flex;
  gap: 0.5rem;
}

.pd-chip {
  padding: 0.4rem 0.9rem;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--muted);
  font-weight: 600;
  font-size: 0.8125rem;
  text-decoration: none;
}

.pd-chip.active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

/* Leaderboard (Views/Leaderboard/Index.cshtml). */
.pd-period-row {
  display: flex;
  gap: 0.5rem;
}

.pd-period-item {
  flex: 1;
  text-align: center;
  padding: 0.5rem 0;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--muted);
  font-weight: 600;
  font-size: 0.85rem;
  text-decoration: none;
}

.pd-period-item.active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

.pd-leaderboard-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 0.75rem 0.875rem;
}

/* Current rep's own row — always tinted, even outside the top 3. */
.pd-leaderboard-row-you {
  background: var(--accent-tint);
  border-color: var(--accent);
}

.pd-leaderboard-rank {
  width: 1.75rem;
  text-align: center;
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--faint);
  flex: 0 0 auto;
}

/* Gold/silver/bronze on the top 3 only — everyone else stays neutral (.pd-rank-plain inherits
   the base .pd-leaderboard-rank color) so the list doesn't turn into a color soup. */
.pd-rank-gold { color: #b8860b; }
.pd-rank-silver { color: #8a92a1; }
.pd-rank-bronze { color: #a9713f; }

.pd-leaderboard-name {
  flex: 1 1 auto;
  font-weight: 600;
  font-size: 0.95rem;
}

.pd-leaderboard-sublabel {
  font-size: 0.65rem;
  color: var(--faint);
}

/* Route page stop-progress header (Views/Route/Index.cshtml). */
.pd-route-segment {
  flex: 1;
  height: 5px;
  border-radius: 3px;
  background: var(--border);
}

.pd-route-segment.pd-route-segment-filled {
  background: var(--accent);
}

/* Typeahead dropdown in the Create Route popup. */
/* position:fixed is set by route-autocomplete.js, which also places it: the capped modal body
   scrolls, and an absolutely-positioned panel would be clipped by it. z-index clears the modal's
   own 1055. */
.route-suggestions {
  position: fixed;
  z-index: 1060;
  max-height: 220px;
  overflow-y: auto;
}

/* --- Field-friendly touch targets --- */

@media (max-width: 767.98px) {
  .form-control, .form-select {
    min-height: 44px;
  }

  /* min-height alone leaves button text top-aligned; flex centering fixes it (skip .btn-link so inline text links stay compact). */
  .btn:not(.btn-link) {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
}

/* Square 44px tap target on any viewport for icon buttons (Share, tel:). */
.btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
}

/* --- Loading overlay (site.js): shows on every link/form navigation by default. --- */

/* z-index above Bootstrap's modal (1055) so it covers the Create Route popup. */
.loading-overlay {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  background: rgba(255, 255, 255, 0.85);
}

.loading-overlay.show {
  display: flex;
}

/* --- PWA install banner (site.js pwa-install.js) --- */

.pwa-install-banner {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  /* Above .app-bottom-nav (1030): safe since this only renders in a regular browser tab, never the standalone WKWebView the bottom-nav's absolute-positioning workaround targets. */
  z-index: 1035;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  padding-bottom: calc(0.75rem + var(--safe-bottom));
  background-color: #1a1d29;
  color: #fff;
  box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.25);
}

.pwa-install-icon {
  border-radius: var(--radius-sm);
  flex: 0 0 auto;
}

.pwa-install-text {
  flex: 1 1 auto;
  font-size: 0.85rem;
  line-height: 1.3;
}

.pwa-install-banner .btn-close {
  filter: invert(1);
  flex: 0 0 auto;
}

/* --- Full Route modal map (Views/Route/Index.cshtml, route-map.js) --- */

#route-map {
  height: 60vh;
}

/* Fullscreen modal on phones: map fills the space above unmapped rows/footer, never fully collapsing when the list underneath is long. */
@media (max-width: 575.98px) {
  #routeModal .modal-body {
    display: flex;
    flex-direction: column;
  }

  #route-map {
    flex: 1 1 auto;
    height: auto;
    min-height: 45vh;
  }
}

/* Shared elevation/radius system for cards/buttons/forms/dropdowns/modals/alerts/tables. Shadows are additive to borders (a shadow alone washes out in direct sun); .card avoids transform/filter since that would create a new containing block that could re-parent a nearby position:fixed sibling (.property-actions, .reserve-bar, .route-nav-bar). */

.card {
  border-color: var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-1);
}

.card > .card-header:first-child {
  border-radius: var(--radius-md) var(--radius-md) 0 0;
}

.btn {
  border-radius: var(--radius-sm);
  transition: background-color 0.15s var(--ease-standard), border-color 0.15s var(--ease-standard),
    box-shadow 0.15s var(--ease-standard), color 0.15s var(--ease-standard);
}

.btn-primary, .btn-success, .btn-danger, .btn-warning, .btn-info, .btn-dark {
  box-shadow: var(--shadow-1);
}

.btn-icon {
  border-radius: var(--radius-sm);
}

.form-control, .form-select {
  border-radius: var(--radius-sm);
  border-color: #d7dbe3;
}

.dropdown-menu {
  border-color: var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-2);
}

.modal-content {
  border: 0;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-3);
}

.modal {
  padding-top: var(--safe-top);
  padding-bottom: var(--safe-bottom);
}

/* Every dialog stops at 70% of the viewport, so a dimmed, tappable margin stays above and below it
   however long the form gets. The body is what scrolls; header and footer stay put. dvh so an open
   iOS keyboard shrinks the card instead of pushing the footer past the bottom of the screen.
   modal-fullscreen-* opts out, having asked for the opposite. */
.modal-dialog:not([class*="modal-fullscreen"]) .modal-content {
  max-height: 70vh;
  max-height: 70dvh;
  overflow: hidden;
}

/* min-height:0 is what lets a flex item shrink past its content: without it the body refuses to
   scroll and the card grows past the cap instead. Same pair Bootstrap's own modal-dialog-scrollable
   uses. */
.modal-content .modal-body {
  overflow-y: auto;
  min-height: 0;
}

/* Most form partials wrap the whole chrome in <form>, which makes the form, not the header/body/
   footer, the flex item .modal-content sizes. A plain block there is both unshrinkable and opaque
   to the height, so the body never scrolls and overflow:hidden clips the footer instead. The four
   partials that put <form-chrome> outermost (Properties, Cases, Custom Fields, Assign plan) always
   worked, which is what this makes universal. */
.modal-content > form {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.offcanvas {
  padding-top: var(--safe-top);
  padding-bottom: var(--safe-bottom);
}

/* Bootstrap's offcanvas-bottom defaults to height:30vh and is position:fixed —
   both wrong here: our sheets (More menu, filter drawer) need to size to content
   up to a cap, and .app-bottom-nav below documents a WKWebView PWA defect where
   fixed-position elements fall short of the true screen bottom by ~the top
   safe-area inset. Match that same position:absolute workaround here. */
.offcanvas-bottom {
  position: absolute;
  height: auto;
  /* Measured against the same height body is sized off, not the viewport: in the standalone
     WKWebView those differ by ~the top safe-area inset, and the sheet is positioned inside body. */
  max-height: calc(var(--vh100, 100dvh) * 0.6);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  /* Base .offcanvas reserves --safe-top for top-anchored drawers clearing the
     notch/status bar — a bottom sheet has no reason to reserve that space at
     its own top, but inherits the rule above unless reset here. */
  padding-top: 0;
  /* The home-indicator inset is reserved inside the scrolling body instead (below), so it
     scrolls away with the content rather than costing the sheet 34px of its cap. */
  padding-bottom: 0;
}

/* ⚠️ min-height: 0 is load-bearing, exactly as on .modal-body. .offcanvas is a flex column and
   Bootstrap gives this flex-grow:1 + overflow-y:auto but no min-height, so its default
   min-height:auto refuses to shrink below its content: the body never scrolls, overflows the
   max-height above, and — since the sheet is pinned bottom:0 — spills straight off the bottom of
   the screen. The filter drawer is the only sheet long enough to have shown it. */
.offcanvas-bottom .offcanvas-body {
  min-height: 0;
  overflow-y: auto;
  padding-bottom: calc(1rem + var(--safe-bottom));
}

/* Hidden-checkbox/radio + styled-label pill toggle. The input keeps its normal
   name/value/asp-for wiring (form submission, tag-helper hidden-input pairing for
   bool props) — only the label's appearance communicates checked state, via the
   sibling combinator below. Always pair a <label for="..."> with the input's id. */
.pd-pill-check {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  pointer-events: none;
}

.pd-pill-label {
  display: inline-flex;
  align-items: center;
  cursor: pointer;
  background-color: #fff;
  border: 1px solid var(--border, var(--border-subtle));
  color: var(--muted, #6b7280);
  font-weight: 600;
  font-size: 0.8125rem;
  padding: 0.4rem 0.9rem;
  border-radius: var(--radius-pill);
  white-space: nowrap;
  user-select: none;
}

.pd-pill-check:checked + .pd-pill-label {
  background-color: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

.pd-pill-check:focus-visible + .pd-pill-label {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.pd-pill-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* Chip groups that collapse to one line and expand in place — property-chip-filters.js
   measures actual rendered widths, so this class only ever gets toggled by JS, never
   hardcoded server-side (a name-only allow list can't know how many chips fit a line). */
.pd-pill-hidden {
  display: none !important;
}

/* The toggle slot is a flex sibling of .pd-pill-row, not one of the row's own wrapping
   children — top-aligned so it sits at a fixed spot beside line 1 regardless of how many
   lines the row grows to when expanded. Narrows the row's available width automatically
   (no manual "does the toggle also fit" measurement needed), and means every tap to
   collapse lands in the same place it took to expand. */
.pd-chip-group-body {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
}

.pd-chip-group-body > .pd-pill-row {
  flex: 1 1 auto;
  min-width: 0;
}

.pd-chip-group-body > [data-chip-toggle-slot] {
  flex: 0 0 auto;
}

/* Marks the first chip past the quick-line cut when a group is expanded, so there's a
   visible break between "stays visible" and "goes away on Show less" — plain .pd-pill-row
   gap alone reads as one continuous list. Extra top margin only: it's the first chip of a
   wrapped line, so this reads as space above that line rather than an indent. */
.pd-pill-expand-start {
  margin-top: 0.5rem;
}

.pd-chip-toggle {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  cursor: pointer;
  background-color: #fff;
  border: 1px dashed var(--border, var(--border-subtle));
  color: var(--accent);
  font-weight: 600;
  font-size: 0.8125rem;
  padding: 0.4rem 0.9rem;
  border-radius: var(--radius-pill);
  white-space: nowrap;
}

.pd-chip-toggle svg {
  transition: transform 0.15s ease;
}

.pd-chip-toggle[aria-expanded="true"] svg {
  transform: rotate(180deg);
}

/* The county-only "+N more" chip past the expanded cap — focuses the search box rather
   than revealing more chips, so it reads as a link, not another toggle. */
.pd-chip-overflow {
  display: inline-flex;
  align-items: center;
  cursor: pointer;
  background-color: #fff;
  border: 1px solid var(--border, var(--border-subtle));
  color: var(--muted, #6b7280);
  font-weight: 600;
  font-size: 0.8125rem;
  padding: 0.4rem 0.9rem;
  border-radius: var(--radius-pill);
  white-space: nowrap;
}

.alert {
  border: 0;
  border-radius: var(--radius-md);
}

.alert-success {
  background-color: #e6f4ea;
  color: #1e4620;
}

.alert-warning {
  background-color: #fff3cd;
  color: #4d3800;
}

.alert-danger {
  background-color: #fbe7e9;
  color: #5c141c;
}

.table > thead {
  background-color: #f8f9fb;
}

.table > thead th {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #6b7280;
  border-bottom: 1px solid var(--border-subtle);
}

.app-sidebar-item,
.app-bottom-nav-item,
.settings-nav-item {
  transition: color 0.15s var(--ease-standard), background-color 0.15s var(--ease-standard),
    border-color 0.15s var(--ease-standard);
}

/* --- Admin Console (Platform: Sub-Accounts / Usage / Plans / Billing, plus Legal
   and the tenant-facing Adjust Seats screens) redesign components (.plat-shell
   tokens, Claude Design comp "EminenceCRM Admin Console Screens"). Same token
   values as .pd-shell (Property Details/Route) but kept as its own scope, not
   merged: the two are separate comps and a shared name would blur which comp a
   future edit should match. Everything under this scope traces back to a screen
   in that one comp file, whether the audience is SuperAdmin-only (Sub-Accounts,
   Usage, Plans, Migrate, Legal) or a tenant admin (CompanySettings/Billing/Seats
   and SeatsReview) — the scope tracks the comp, not the permission level. */
.plat-shell {
  --bg: oklch(97% 0.004 265);
  --card: #ffffff;
  --border: oklch(91% 0.006 265);
  --text: oklch(23% 0.02 265);
  --muted: oklch(52% 0.015 265);
  --faint: oklch(68% 0.012 265);
  --accent: oklch(56% 0.19 265);
  --accent-dark: oklch(47% 0.18 265);
  --accent-tint: oklch(95% 0.025 265);
  --accent-tint-text: oklch(45% 0.16 265);
  --success: oklch(55% 0.13 150);
  --success-tint: oklch(95% 0.03 150);
  --warning: oklch(50% 0.15 70);
  --warning-tint: oklch(96% 0.05 80);
  --danger: oklch(55% 0.19 25);
  --danger-tint: oklch(95% 0.035 25);
  --neutral-bg: oklch(94% 0.007 265);
  --neutral-text: oklch(42% 0.012 265);
  --font-head: 'Outfit', sans-serif;
  --font-body: 'Source Sans 3', sans-serif;
  font-family: var(--font-body);
  color: var(--text);
}

.plat-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1.25rem;
}

.plat-header h1 {
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 1.5rem;
  margin: 0 0 0.35rem;
  color: var(--text);
}

.plat-header p {
  font-size: 0.85rem;
  color: var(--muted);
  line-height: 1.55;
  margin: 0;
  max-width: 640px;
}

/* Breadcrumb replacing a plain "← Back" link on drill-down pages (e.g. Billing). */
.plat-breadcrumb {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  font-size: 0.8rem;
  color: var(--muted);
  margin-bottom: 0.35rem;
}

.plat-breadcrumb a {
  color: var(--muted);
  text-decoration: none;
}

.plat-breadcrumb a:hover {
  color: var(--accent);
}

.plat-breadcrumb-sep {
  color: var(--faint);
}

.plat-breadcrumb-current {
  color: var(--text);
  font-weight: 600;
}

.plat-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 1rem;
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(20, 20, 60, .03), 0 6px 16px rgba(20, 20, 60, .04);
}

.plat-card-body {
  padding: 1.25rem 1.5rem;
}

/* Card title bar with an optional right-aligned action (e.g. each document editor's
   "Preview" link) — the header/body split .plat-card-body alone doesn't give. */
.plat-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.75rem 1.25rem;
  border-bottom: 1px solid var(--border);
  font-family: var(--font-head);
  font-weight: 600;
  font-size: 0.85rem;
}

/* Definition-list summary (Billing page): label column + value column. */
.plat-summary {
  display: grid;
  grid-template-columns: 130px 1fr;
  gap: 0.85rem 0;
  font-size: 0.875rem;
  margin: 0;
}

.plat-summary dt {
  color: var(--faint);
  font-weight: 400;
}

.plat-summary dd {
  margin: 0;
}

.plat-table > thead th {
  font-family: var(--font-head);
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--faint);
  border-bottom: 1px solid var(--border);
  background: transparent;
  padding: 0.85rem 1.25rem;
}

.plat-table > tbody > tr > td {
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
  font-size: 0.875rem;
  color: var(--text);
}

.plat-table > tbody > tr:last-child > td {
  border-bottom: 0;
}

/* Checkout picker: the plan closest to solving an at-/over-cap account's problem
   gets the same accent-tint row treatment as the mock's highlighted Growth row. */
.plat-table > tbody > tr.table-plat-suggested > td {
  background-color: var(--accent-tint);
}

.plat-table-name {
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--text);
}

.plat-table-meta {
  font-size: 0.78rem;
  color: var(--muted);
  margin-top: 0.15rem;
}

/* Status/tag pills — tint modifiers on a shared pill base, same idea as .pd-tint-*. */
.plat-pill {
  display: inline-block;
  padding: 0.22rem 0.65rem;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 600;
  line-height: 1.4;
  white-space: nowrap;
}

.plat-pill-success { background-color: var(--success-tint); color: var(--success); }
.plat-pill-warning { background-color: var(--warning-tint); color: var(--warning); }
.plat-pill-danger  { background-color: var(--danger-tint);  color: var(--danger); }
.plat-pill-neutral { background-color: var(--neutral-bg);   color: var(--neutral-text); }
.plat-pill-accent  { background-color: var(--accent-tint);  color: var(--accent-tint-text); }

/* Button reskin: Bootstrap's default (blue) .btn-primary becomes the comp's indigo
   accent inside this scope only — same technique as .pd-action-bar .btn-primary. */
.plat-shell .btn {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.85rem;
  border-radius: 0.625rem;
}

.plat-shell .btn-primary {
  background-color: var(--accent);
  border-color: var(--accent);
}

.plat-shell .btn-primary:hover,
.plat-shell .btn-primary:focus {
  background-color: var(--accent-dark);
  border-color: var(--accent-dark);
}

.plat-shell .btn-outline-primary {
  color: var(--accent);
  border-color: var(--border);
}

.plat-shell .btn-outline-primary:hover,
.plat-shell .btn-outline-primary:focus {
  color: #fff;
  background-color: var(--accent);
  border-color: var(--accent);
}

.plat-shell .btn-outline-secondary {
  color: var(--text);
  border-color: var(--border);
}

.plat-shell .btn-outline-secondary:hover,
.plat-shell .btn-outline-secondary:focus {
  color: var(--text);
  background-color: var(--neutral-bg);
  border-color: var(--border);
}

.plat-shell .btn-outline-danger {
  border-color: var(--border);
}

/* Overflow ("⋮") action menu — Bootstrap's dropdown component, restyled. */
.plat-kebab {
  width: 2.25rem;
  height: 2.25rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  line-height: 1;
}

.plat-kebab::after {
  display: none;
}

.plat-shell .dropdown-menu {
  border-color: var(--border);
  border-radius: 0.75rem;
  box-shadow: 0 6px 16px rgba(20, 20, 60, .1);
  padding: 0.35rem;
  font-size: 0.85rem;
}

.plat-shell .dropdown-item {
  border-radius: 0.5rem;
  padding: 0.5rem 0.75rem;
}

.plat-shell .dropdown-item:hover,
.plat-shell .dropdown-item:focus {
  background-color: var(--accent-tint);
  color: var(--accent-tint-text);
}

.plat-shell .dropdown-item.text-danger:hover,
.plat-shell .dropdown-item.text-danger:focus {
  background-color: var(--danger-tint);
  color: var(--danger);
}

.plat-shell .dropdown-item:disabled,
.plat-shell .dropdown-item.disabled {
  color: var(--faint);
}

/* Forms (Create/Edit/AssignPlan), wrapped in .plat-card for visual consistency
   with the four mocked list/detail pages. */
.plat-shell .form-label {
  font-weight: 600;
  font-size: 0.85rem;
  color: var(--text);
}

.plat-shell .form-control,
.plat-shell .form-select {
  border-color: var(--border);
  border-radius: 0.625rem;
}

.plat-shell .form-control:focus,
.plat-shell .form-select:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 0.2rem var(--accent-tint);
}

.plat-shell .form-text {
  color: var(--muted);
}

/* Markdown source inside a .plat-card (Legal documents editor) — the shaded, monospace
   look of a code block, while staying a real, editable textarea. */
.plat-shell .legal-editor {
  background: var(--neutral-bg);
  border: none;
  border-radius: 0;
  padding: 1rem 1.25rem;
  min-height: 320px;
  width: 100%;
  resize: vertical;
}

.plat-shell .legal-editor:focus {
  box-shadow: none;
  background: #fff;
}

.plat-shell h2.plat-subhead {
  font-family: var(--font-head);
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--faint);
  margin: 0 0 0.75rem;
}

/* Tab strip shared by the /SubAccounts/Legal pages (_LegalDocumentTabs.cshtml): sits
   under the breadcrumb, above the page's own h1, so a super-admin can move between the
   editor and the version history without leaving the section. */
.plat-tabs {
  display: flex;
  gap: 0.25rem;
  border-bottom: 1px solid var(--border);
  margin: 0.6rem 0 1.25rem;
  overflow-x: auto;
}

.plat-tabs-item {
  padding: 0.55rem 0.85rem;
  margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  font-weight: 600;
  font-size: 0.85rem;
  color: var(--muted);
  white-space: nowrap;
}

.plat-tabs-item:hover {
  color: var(--text);
}

.plat-tabs-item.active {
  color: var(--text);
  border-bottom-color: var(--accent);
}

/* Side-by-side "current vs. target" comparison, e.g. Migrate. The target card gets
   the accent tint so it reads as the destination, not just a second identical card. */
.plat-compare {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}

.plat-card-highlight {
  background: var(--accent-tint);
  border-color: var(--accent);
}

.plat-card-highlight .plat-card-body dt {
  color: var(--accent-tint-text);
  opacity: .75;
}

.plat-card-highlight .plat-card-body dd {
  color: var(--accent-tint-text);
}

/* Seat-count stepper (Adjust seats). The number input stays the real form control —
   these buttons only nudge its value, so keyboard entry and validation are untouched. */
.plat-stepper {
  display: flex;
  align-items: center;
  gap: 1.1rem;
}

.plat-stepper-btn {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 0.625rem;
  border: 1px solid var(--border);
  background: #fff;
  color: var(--accent);
  font-size: 1.1rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}

.plat-stepper-btn:hover {
  background: var(--accent-tint);
}

.plat-stepper input[type="number"] {
  width: 4rem;
  text-align: center;
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 1.5rem;
  border: none;
  background: transparent;
  padding: 0;
  -moz-appearance: textfield;
}

.plat-stepper input[type="number"]::-webkit-inner-spin-button,
.plat-stepper input[type="number"]::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* --- Import flow (Claude Design comp "22 Import") ------------------------- */

/* Tokens repeated rather than shared with .pd-shell/.plat-shell for the reason given
   above those blocks: the names come verbatim from the comp so its markup can be
   pasted back in, and generic names like --text/--card must not leak to :root.
   --info/--info-tint and --violet/--violet-tint are new here — the preview's
   "new case on existing property" tile and contact slot 4 need a fifth and sixth
   hue that neither existing scope defines. */
.imp-shell {
  --bg: oklch(97% 0.004 265);
  --card: #ffffff;
  --border: oklch(91% 0.006 265);
  --text: oklch(23% 0.02 265);
  --muted: oklch(52% 0.015 265);
  --faint: oklch(68% 0.012 265);
  --accent: oklch(56% 0.19 265);
  --accent-dark: oklch(47% 0.18 265);
  --accent-tint: oklch(95% 0.025 265);
  --accent-tint-text: oklch(45% 0.16 265);
  --success: oklch(55% 0.13 150);
  --success-tint: oklch(95% 0.03 150);
  --warning: oklch(50% 0.15 70);
  --warning-tint: oklch(96% 0.05 80);
  --danger: oklch(55% 0.19 25);
  --danger-tint: oklch(95% 0.035 25);
  --info: oklch(58% 0.14 230);
  --info-tint: oklch(95% 0.025 230);
  --violet: oklch(55% 0.16 305);
  --violet-tint: oklch(95% 0.025 305);
  --neutral-bg: oklch(94% 0.007 265);
  --neutral-text: oklch(42% 0.012 265);
  --font-head: 'Outfit', sans-serif;
  --font-body: 'Source Sans 3', sans-serif;
  font-family: var(--font-body);
  color: var(--text);
}

.imp-shell h1 {
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 25px;
  margin: 0;
  color: var(--text);
}

.imp-lede {
  font-size: 13.5px;
  color: var(--muted);
  margin: 6px 0 0;
}

.imp-back {
  font-size: 12.5px;
  color: var(--muted);
  text-decoration: none;
}

.imp-back:hover {
  color: var(--accent);
}

.imp-file-pill {
  font: 600 12.5px var(--font-body);
  background: var(--neutral-bg);
  color: var(--neutral-text);
  padding: 4px 11px;
  border-radius: var(--radius-pill);
}

.imp-rowcount {
  font-size: 12.5px;
  color: var(--faint);
}

/* Step tracker — the comp's one structural addition, on all four screens so the
   flow stops reading as four unrelated pages. Rendered by _ImportSteps.cshtml. */
.imp-steps {
  display: flex;
  align-items: center;
  max-width: 760px;
}

.imp-step {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}

.imp-step-dot {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: #fff;
  border: 1.5px solid var(--border);
  color: var(--faint);
  display: flex;
  align-items: center;
  justify-content: center;
  font: 600 13px var(--font-body);
}

.imp-step-dot.is-done,
.imp-step-dot.is-current {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

/* Only the current step gets the halo, so "where am I" survives a glance at a
   tracker whose earlier dots carry the same fill. */
.imp-step-dot.is-current {
  box-shadow: 0 0 0 4px var(--accent-tint);
}

.imp-step-label {
  font: 600 12px var(--font-body);
  color: var(--faint);
  white-space: nowrap;
}

.imp-step.is-done .imp-step-label,
.imp-step.is-current .imp-step-label {
  color: var(--text);
}

/* Bottom margin, not centring: the connector aligns with the dots, which sit
   above their labels. */
.imp-step-line {
  flex: 1;
  height: 2px;
  background: var(--border);
  margin: 0 8px 20px;
}

.imp-step-line.is-done {
  background: var(--accent);
}

@media (max-width: 575.98px) {
  .imp-step-label {
    font-size: 10.5px;
  }

  .imp-step-line {
    margin: 0 4px 20px;
  }
}

/* Grids. Every one collapses to a single or two-up column on phones: Import is
   admin work done on a laptop, but a squashed five-across grid is unreadable
   rather than merely cramped. */
.imp-upload-grid {
  display: grid;
  gap: 24px;
}

@media (min-width: 992px) {
  .imp-upload-grid {
    grid-template-columns: 1.15fr 1fr;
    align-items: start;
  }
}

.imp-grid-5,
.imp-grid-3 {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 768px) {
  .imp-grid-3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (min-width: 992px) {
  .imp-grid-5 {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }
}

/* Upload */

.imp-dropzone {
  background: #fff;
  border: 1.5px dashed var(--border);
  border-radius: 16px;
  padding: 56px 32px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 14px;
  cursor: pointer;
  transition: border-color 0.15s var(--ease-standard), background-color 0.15s var(--ease-standard);
}

.imp-dropzone:hover,
.imp-dropzone:focus-visible {
  border-color: var(--accent);
  outline: none;
}

.imp-dropzone.is-dragover {
  border-color: var(--accent);
  background: var(--accent-tint);
}

.imp-dropzone-icon {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--accent-tint);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.imp-dropzone-title {
  font: 600 16px var(--font-head);
}

.imp-dropzone-or {
  font-size: 13.5px;
  color: var(--muted);
}

.imp-dropzone-hint {
  font-size: 12px;
  color: var(--faint);
  margin-top: 4px;
}

.imp-dropzone-rule {
  width: 100%;
  height: 1px;
  background: var(--border);
  margin: 18px 0 2px;
}

@media (max-width: 767.98px) {
  .imp-dropzone {
    padding: 36px 20px;
  }
}

.imp-card {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 18px 20px;
}

.imp-card-head {
  font: 600 13px var(--font-head);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--faint);
}

.imp-chip {
  font: 600 12.5px var(--font-body);
  background: var(--success-tint);
  color: var(--success);
  padding: 6px 12px;
  border-radius: var(--radius-pill);
}

.imp-callout {
  background: var(--accent-tint);
  border-radius: 14px;
  padding: 16px 20px;
  font-size: 13px;
  line-height: 1.55;
  color: var(--accent-tint-text);
}

.imp-callout-danger {
  background: var(--danger-tint);
  color: var(--danger);
  border-radius: 12px;
  padding: 14px 18px;
  font-size: 13.5px;
}

/* "Also supported" scan rows — the label column is fixed so the values line up. */
.imp-deflist {
  display: flex;
  gap: 14px;
  font-size: 13px;
}

.imp-deflist-term {
  flex: 0 0 90px;
  font: 600 12.5px var(--font-body);
  color: var(--muted);
}

/* Contact slots. The best idea on the old screen, pushed further by the comp: the
   slot's colour is carried by the role card's top bar AND by the tint of every
   row mapped into it, so one person's columns read as a group. Colours are
   assigned by slot number, so .imp-slot-N and .imp-row-slot-N must stay in step
   with the regex in Map.cshtml's script. */
.imp-slot-card {
  background: #fff;
  border: 1px solid var(--border);
  border-top: 3px solid var(--border);
  border-radius: 12px;
  padding: 12px 14px;
}

.imp-slot-card-title {
  font: 600 12.5px var(--font-body);
  color: var(--text);
  margin-bottom: 8px;
}

.imp-slot-1 { border-top-color: var(--accent); }
.imp-slot-2 { border-top-color: var(--success); }
.imp-slot-3 { border-top-color: var(--warning); }
.imp-slot-4 { border-top-color: var(--violet); }
.imp-slot-5 { border-top-color: var(--danger); }

/* Tables. Kept as real <table>s rather than the comp's flex rows: they carry the
   header association a flex grid loses, and .table-responsive gives the phone
   fallback for free. The <colgroup> widths reproduce the comp's flex ratios. */
.imp-table {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 14px;
  overflow: hidden;
}

.imp-table table {
  margin: 0;
  font-size: 13px;
  color: var(--text);
}

.imp-table thead th {
  font: 600 11.5px var(--font-head);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--faint);
  border-bottom: 1px solid var(--border);
  padding: 11px 12px;
  white-space: nowrap;
}

.imp-table thead th:first-child { padding-left: 20px; }
.imp-table thead th:last-child { padding-right: 20px; }

.imp-table tbody td {
  padding: 11px 12px;
  border-bottom: 1px solid var(--border);
  border-top: 0;
  vertical-align: middle;
}

.imp-table tbody td:first-child { padding-left: 17px; }
.imp-table tbody td:last-child { padding-right: 20px; }

.imp-table tbody tr:last-child td { border-bottom: 0; }

/* The 3px status stripe rides the first cell rather than the <tr>: a border on a
   row is dropped under border-collapse, which every Bootstrap table uses. */
.imp-table tbody td:first-child {
  border-left: 3px solid transparent;
}

.imp-col-name { font: 600 13px var(--font-body); }
.imp-col-samples { color: var(--muted); }

.imp-row-required td { background: var(--success-tint); }
.imp-row-required td:first-child { border-left-color: var(--success); }

.imp-row-error td { background: var(--danger-tint); }
.imp-row-error td:first-child { border-left-color: var(--danger); }

/* The preview's Note column: muted commentary on an ordinary row, the reason for
   the rejection on an error one. */
.imp-note { color: var(--muted); }
.imp-row-error .imp-note { color: var(--danger); }

.imp-row-slot-1 td { background: var(--accent-tint); }
.imp-row-slot-1 td:first-child { border-left-color: var(--accent); }
.imp-row-slot-2 td { background: var(--success-tint); }
.imp-row-slot-2 td:first-child { border-left-color: var(--success); }
.imp-row-slot-3 td { background: var(--warning-tint); }
.imp-row-slot-3 td:first-child { border-left-color: var(--warning); }
.imp-row-slot-4 td { background: var(--violet-tint); }
.imp-row-slot-4 td:first-child { border-left-color: var(--violet); }
.imp-row-slot-5 td { background: var(--danger-tint); }
.imp-row-slot-5 td:first-child { border-left-color: var(--danger); }

/* Status pills */
.imp-pill {
  display: inline-block;
  font: 600 12px var(--font-body);
  padding: 4px 10px;
  border-radius: var(--radius-pill);
  white-space: nowrap;
}

.imp-pill-new { background: var(--success-tint); color: var(--success); }
.imp-pill-case { background: var(--info-tint); color: var(--info); }
.imp-pill-updated { background: var(--warning-tint); color: var(--warning); }
.imp-pill-unchanged { background: var(--neutral-bg); color: var(--neutral-text); }
/* White, not danger-tint: this one pill sits on a danger-tinted row. */
.imp-pill-error { background: #fff; color: var(--danger); }

/* Stat tiles */
.imp-stat {
  background: #fff;
  border: 1px solid var(--border);
  border-top: 3px solid var(--border);
  border-radius: 12px;
  padding: 14px 16px;
}

.imp-stat-value {
  font: 700 24px var(--font-head);
}

.imp-stat-label {
  font-size: 12.5px;
  color: var(--muted);
  margin-top: 2px;
}

.imp-stat-success { border-top-color: var(--success); }
.imp-stat-info { border-top-color: var(--info); }
.imp-stat-warning { border-top-color: var(--warning); }
.imp-stat-neutral { border-top-color: var(--faint); }
.imp-stat-danger { border-top-color: var(--danger); }

.imp-stat-muted {
  background: var(--neutral-bg);
}

.imp-stat-muted .imp-stat-value {
  color: var(--neutral-text);
}

.imp-done-icon {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--success-tint);
  display: flex;
  align-items: center;
  justify-content: center;
}

.imp-done-title {
  font: 700 26px var(--font-head);
}

/* Sticky action bar. Fixed rather than sticky so it clears the sidebar the same
   way .reserve-bar/.route-nav-bar do (see the md+ left:220px rule above); the
   .imp-shell-with-bar padding is what stops it covering the last table row. */
.imp-footer-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1029;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 14px 1rem;
  background: #fff;
  border-top: 1px solid var(--border);
}

@media (min-width: 768px) {
  .imp-footer-bar {
    left: 220px;
    padding: 14px 40px;
  }
}

@media (max-width: 767.98px) {
  .imp-footer-bar {
    bottom: var(--bottom-clearance);
  }
}

.imp-shell-with-bar {
  padding-bottom: 88px;
}

.imp-footer-note {
  font-size: 12.5px;
  color: var(--faint);
}

.imp-footer-ok {
  font-size: 12.5px;
  color: var(--success);
  display: flex;
  align-items: center;
  gap: 6px;
}

.imp-footer-warn {
  font-size: 12.5px;
  color: var(--danger);
  display: flex;
  align-items: center;
  gap: 6px;
}

/* Buttons — same reskin technique as .plat-shell: Bootstrap's blue .btn-primary
   becomes the comp's indigo accent inside this scope only. The footer bar is a
   sibling of .imp-shell (it is fixed), so it is listed alongside it throughout. */
.imp-shell .btn,
.imp-footer-bar .btn {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 13.5px;
  border-radius: 10px;
  padding: 11px 22px;
}

.imp-shell .btn-primary,
.imp-footer-bar .btn-primary {
  background-color: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

.imp-shell .btn-primary:hover,
.imp-shell .btn-primary:focus,
.imp-footer-bar .btn-primary:hover,
.imp-footer-bar .btn-primary:focus {
  background-color: var(--accent-dark);
  border-color: var(--accent-dark);
}

.imp-shell .btn-outline-secondary,
.imp-footer-bar .btn-outline-secondary {
  color: var(--text);
  border-color: var(--border);
  background: #fff;
}

.imp-shell .btn-outline-secondary:hover,
.imp-shell .btn-outline-secondary:focus,
.imp-footer-bar .btn-outline-secondary:hover,
.imp-footer-bar .btn-outline-secondary:focus {
  color: var(--text);
  background-color: var(--neutral-bg);
  border-color: var(--border);
}

.imp-shell .form-select,
.imp-shell .form-control {
  font-family: var(--font-body);
  font-size: 12.5px;
  border-color: var(--border);
  border-radius: 8px;
  padding: 6px 10px;
}

.imp-shell .form-select:focus,
.imp-shell .form-control:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 0.2rem var(--accent-tint);
}

/* Duplicate-target marker from Map.cshtml's script — restyled to stay legible
   against the row tints, which Bootstrap's own .is-invalid treatment is not. */
.imp-shell .form-select.is-invalid {
  border-color: var(--danger);
  box-shadow: 0 0 0 0.15rem var(--danger-tint);
  background-image: none;
  padding-right: 10px;
}


/* --- Desktop Properties workspace (Views/Properties/_DesktopIndex.cshtml) ---

   Claude Design "10 Properties · 10g". No new token scope: the comp's :root set is the same one
   .pd-shell already declares verbatim, and this is the same area, so the partial wraps itself in
   .pd-shell and only the .pw-* components below are new. A fourth token block would be a second copy
   to keep in step for nothing.

   Everything here is inside .pd-shell and the partial itself is d-none d-md-block, so none of it
   applies on a phone — the card list is untouched. */
.pw-desk {
  font-family: var(--font-body);
  color: var(--text);
}

.pw-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.pw-title {
  font: 700 1.375rem var(--font-head);
  margin: 0;
}

.pw-subhead {
  font-size: 0.8125rem;
  color: var(--muted);
  margin-top: 2px;
}

.pw-head-actions {
  display: flex;
  gap: 0.5rem;
  flex-shrink: 0;
}

.pw-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  border-radius: 9px;
  padding: 0.5rem 0.875rem;
  font: 600 0.8125rem var(--font-body);
  border: 1px solid transparent;
  text-decoration: none;
  white-space: nowrap;
}

.pw-btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

.pw-btn-primary:hover {
  background: var(--accent-dark);
  border-color: var(--accent-dark);
  color: #fff;
}

.pw-btn-primary:disabled {
  opacity: 0.55;
}

.pw-btn-ghost {
  background: var(--card);
  border-color: var(--border);
  color: var(--text);
}

.pw-btn-ghost:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* --- Stat strip --- */
.pw-stats {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 0.75rem;
  margin-top: 1.125rem;
}

.pw-stat {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 0.875rem 1rem;
}

.pw-stat-label {
  font: 600 0.65rem var(--font-head);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--faint);
}

.pw-stat-value {
  font: 700 1.625rem var(--font-head);
  margin-top: 6px;
}

.pw-stat-warning { color: var(--warning); }
.pw-stat-success { color: var(--success); }

.pw-stat-note {
  font-size: 0.7188rem;
  color: var(--muted);
  margin-top: 2px;
}

/* --- Saved-view tabs --- */
.pw-views {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-top: 1.25rem;
  border-bottom: 1px solid var(--border);
}

.pw-view {
  display: inline-block;
  padding: 0.625rem 0.75rem;
  font: 600 0.8438rem var(--font-head);
  color: var(--muted);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}

.pw-view:hover { color: var(--text); }

.pw-view.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.pw-view-count {
  color: var(--faint);
  font-weight: 400;
}

/* A shared view carries a dot rather than a word: the tab row is tight, and the title attribute
   carries the meaning for anyone who needs it spelled out. */
.pw-view-shared {
  font-size: 0.5rem;
  vertical-align: middle;
  color: var(--accent);
}

.pw-view-wrap {
  display: inline-flex;
  align-items: center;
}

.pw-view-remove {
  border: 0;
  background: none;
  color: var(--faint);
  font-size: 1rem;
  line-height: 1;
  padding: 0 0.25rem;
  opacity: 0;
}

.pw-view-wrap:hover .pw-view-remove,
.pw-view-remove:focus-visible {
  opacity: 1;
}

.pw-view-remove:hover { color: var(--danger); }

.pw-view-save {
  margin-left: auto;
  border: 0;
  background: none;
  color: var(--accent);
  font: 500 0.7812rem var(--font-body);
  padding: 0.5rem 0;
}

/* --- Filter chip bar --- */
.pw-filters {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  padding-top: 0.875rem;
}

.pw-search {
  display: flex;
  max-width: 300px;
  flex: 1 1 220px;
}

.pw-search-icon {
  border: 1px solid var(--border);
  border-right: 0;
  border-radius: 8px 0 0 8px;
  padding: 0 0.625rem;
  display: flex;
  align-items: center;
  color: var(--muted);
  background: var(--card);
}

.pw-search-input {
  flex: 1;
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: 0 8px 8px 0;
  height: 34px;
  padding: 0 0.625rem;
  font-size: 0.8125rem;
  background: var(--card);
  color: var(--text);
}

.pw-search-input:focus,
.pw-select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 0.15rem var(--accent-tint);
}

.pw-chip {
  border: 1px solid var(--border);
  background: var(--card);
  border-radius: 999px;
  padding: 0.4375rem 0.8125rem;
  font: 600 0.7812rem var(--font-body);
  color: var(--muted);
  white-space: nowrap;
}

.pw-chip.active,
.pw-chip:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* An applied value, removable. The href drops just this one filter and re-indexes the rest —
   see WithoutValue in the partial. */
.pw-chip-applied {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  background: var(--accent);
  border: 1px solid var(--accent);
  color: #fff;
  border-radius: 999px;
  padding: 0.4375rem 0.8125rem;
  font: 600 0.7812rem var(--font-body);
  text-decoration: none;
  white-space: nowrap;
}

.pw-chip-applied:hover {
  background: var(--accent-dark);
  border-color: var(--accent-dark);
  color: #fff;
}

.pw-applied {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  padding-top: 0.625rem;
}

.pw-chip-clear {
  font-size: 0.7812rem;
  color: var(--muted);
  text-decoration: none;
}

.pw-chip-clear:hover { color: var(--danger); }

.pw-chip-menu {
  padding: 0.75rem;
  min-width: 220px;
  border-color: var(--border);
}

.pw-chip-menu-wide { min-width: 300px; }

.pw-chip-menu-scroll {
  max-height: 340px;
  overflow-y: auto;
}

.pw-check {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8125rem;
  padding: 0.25rem 0;
  cursor: pointer;
}

.pw-field-label {
  font: 600 0.65rem var(--font-head);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 0.625rem 0 0.25rem;
}

.pw-field-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.375rem;
}

.pw-field-pair input {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.25rem 0.5rem;
  font-size: 0.8125rem;
  min-width: 0;
  background: var(--card);
  color: var(--text);
}

.pw-select {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.25rem 0.5rem;
  font-size: 0.8125rem;
  background: var(--card);
  color: var(--text);
}

.pw-sort {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.7812rem;
  color: var(--muted);
}

.pw-assign-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  background: var(--accent-tint);
  color: var(--accent-tint-text);
  border-radius: 10px;
  padding: 0.625rem 0.875rem;
  margin-top: 0.875rem;
  font-size: 0.8125rem;
}

/* --- Table --- */
.pw-table-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 14px;
  margin-top: 0.875rem;
  /* The comp's card clips its own header/footer rows; the table's own borders do the rest. */
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(20, 20, 60, 0.03), 0 6px 16px rgba(20, 20, 60, 0.04);
}

.pw-table {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
  margin: 0;
}

.pw-table thead th {
  font: 600 0.65rem var(--font-head);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--faint);
  padding: 0.625rem 0.5rem;
  border-bottom: 1px solid var(--border);
  text-align: left;
}

.pw-table thead th:first-child,
.pw-table tbody td:first-child { padding-left: 1rem; }

.pw-table thead th:last-child,
.pw-table tbody td:last-child { padding-right: 1rem; }

.pw-table tbody td {
  padding: 0.75rem 0.5rem;
  border-bottom: 1px solid var(--border);
  font-size: 0.8125rem;
  vertical-align: top;
  overflow-wrap: anywhere;
}

.pw-table tbody tr:last-child td { border-bottom: 0; }

.pw-row:hover { background: var(--bg); }

.pw-row-selected,
.pw-row-selected:hover { background: var(--accent-tint); }

/* Reserved rows stay visible and readable — they are excluded from selection, not from the list.
   Hiding them is the ExcludeReserved filter's job, and it is the rep's choice. */
.pw-row-reserved .pw-address { color: var(--muted); }

.pw-address {
  font: 600 0.8438rem var(--font-body);
  color: var(--text);
  text-decoration: none;
}

.pw-address:hover { color: var(--accent); }

.pw-address-sub {
  font-size: 0.75rem;
  color: var(--muted);
  margin-top: 2px;
}

.pw-row-note {
  font-size: 0.7188rem;
  color: var(--faint);
}

.pw-muted { color: var(--muted); }
.pw-dash { color: var(--faint); }
.pw-never { color: var(--success); }

/* Sheriff sale inside 30 days — the only value in the table that earns a colour, matching the
   stat tile above it. */
.pw-urgent {
  color: var(--warning);
  font-weight: 600;
}

.pw-pill {
  display: inline-block;
  border-radius: 999px;
  padding: 0.25em 0.6em;
  font: 600 0.6875rem var(--font-body);
  background: var(--neutral-bg);
  color: var(--neutral-text);
}

.pw-pill-accent {
  background: var(--accent-tint);
  color: var(--accent-tint-text);
}

.pw-pill-danger {
  background: var(--danger-tint);
  color: var(--danger);
}

.pw-tag {
  display: inline-block;
  border-radius: 999px;
  padding: 0.2em 0.5em;
  font: 600 0.625rem var(--font-body);
  margin-left: 0.375rem;
  vertical-align: middle;
}

.pw-tag-danger { background: var(--danger); color: #fff; }
.pw-tag-dark { background: #212529; color: #fff; }
.pw-tag-warning { background: var(--warning-tint); color: var(--warning); }

.pw-row-menu {
  border: 0;
  background: none;
  color: var(--faint);
  padding: 0 0.375rem;
  line-height: 1;
  font-size: 1rem;
}

.pw-row-menu:hover { color: var(--text); }

.pw-empty {
  text-align: center;
  color: var(--muted);
  padding: 3rem 1rem;
}

/* --- Bulk toolbar --- */
.pw-bulk {
  display: none;
  align-items: center;
  gap: 0.75rem;
  background: var(--card);
  border: 1px solid var(--accent);
  border-radius: 12px;
  padding: 0.625rem 0.875rem;
  margin-top: 0.75rem;
  box-shadow: 0 6px 20px rgba(20, 20, 60, 0.08);
}

.pw-bulk.show { display: flex; }

.pw-bulk-over {
  border-color: var(--danger);
  background: var(--danger-tint);
}

.pw-bulk-count {
  font: 600 0.8438rem var(--font-body);
}

.pw-bulk-assign {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.8125rem;
  color: var(--muted);
  margin: 0;
}

/* --- Footer --- */
.pw-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 0.875rem;
  font-size: 0.7812rem;
  color: var(--muted);
}

.pw-pager {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* --- Desktop Property Details: five tabs become three columns (Claude Design "10 Properties · 10h") ---

   One markup for both, not a desktop-only view. _PropertyDetails is shared with the Route page, so a
   fork would be two arrangements to keep in step and a second Street View proxy request per page load.

   The show/hide toggle is depth-independent: `.tab-pane` / `.tab-pane.active` below match any tab-pane
   regardless of how deeply it's nested, so it doesn't matter whether a pane sits directly under
   .tab-content or inside a grouping wrapper — unlike an earlier version keyed to one exact DOM path
   (`.pd-detail-grid > .pd-detail-col > .tab-pane`), which broke the moment that path stopped matching
   exactly. #detailsTabs/.tab-pane is the only nav-tabs usage app-wide (site-wide grep), so this doesn't
   risk colliding with some other tab component. Bootstrap's own `.tab-content > .tab-pane` rule simply
   doesn't match once a pane has a wrapper parent, so there's no specificity fight with it either. */
.tab-pane {
  display: none;
}

.tab-pane.active {
  display: block;
}

/* .pd-detail-col groups a column's pane(s) (Views/Shared/_PropertyDetails.cshtml) — a plain block below
   md (invisible to phone layout, since it has no border/padding of its own) and its own flex column at
   md+, so each column's content stacks to its own natural height instead of being forced into shared
   grid row tracks with the other two columns (that forcing is what previously left gaps above shorter
   cards — e.g. Custom fields floating below a shorter People column while Cases ran longer). */
/* Compound selector (not just .pd-detail-col-wide) so this beats the plain .pd-detail-col{flex:1 1 0}
   inside the md+ block below regardless of source order — same specificity otherwise, and that rule
   comes later in the file. */
.pd-detail-col.pd-detail-col-wide {
  flex: 1.15 1 0;
}

/* Fact strip beside the hero — Bootstrap's own d-none/.d-md-grid utilities do the showing. */
.pd-fact-strip {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.625rem;
}

.pd-fact {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 11px;
  padding: 0.6875rem 0.8125rem;
}

.pd-fact-value {
  font: 700 1.0625rem var(--font-head);
  margin-top: 5px;
}

.pd-fact-urgent { color: var(--warning); }
.pd-fact-empty { color: var(--faint); }

.pd-fact-note {
  font-size: 0.7188rem;
  color: var(--muted);
}

/* Lead status card: the .pd-status-select pill dropdown in place of the label/value/note stack every
   other fact card uses — same live <select>/form as the (mobile-only) .pd-actions-row copy. */
.pd-fact-status .pd-status-select {
  width: 100%;
}

/* Card header titles + flat "+ Add X" text-link (comp 10h) — desktop only; mobile keeps the bordered
   icon+text pill button (.pd-icon-btn-add) and no title, since the tab label above already names the
   pane. Card markup/class is shared with mobile (Views/Shared/_PropertyDetails.cshtml), so only the
   md+ half of this changes anything there. */
.pd-card-header-title {
  font-family: var(--font-head);
  font-weight: 600;
  font-size: 0.84375rem;
}

/* Trash icon, distinguished from the (still grey) pencil edit icon it used to share a look with —
   the only two icon-button affordances .pd-edit-pencil covers on this page. */
.pd-delete-icon {
  color: var(--danger);
}

.pd-delete-icon:hover,
.pd-delete-icon:focus {
  color: var(--danger);
  background: var(--danger-tint);
}

/* Breadcrumb + Prev/Next lead (Views/Properties/Details.cshtml). */
.pd-crumb {
  align-items: baseline;
  gap: 0.5rem;
  font-size: 0.7812rem;
  color: var(--muted);
  margin-bottom: 0.75rem;
}

.pd-crumb a { color: var(--accent); text-decoration: none; }
.pd-crumb a:hover { color: var(--accent-dark); }
.pd-crumb-sep { color: var(--faint); }
.pd-crumb-current { font-weight: 600; color: var(--text); }

.pd-crumb-nav {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* An end-of-list edge renders the label greyed rather than removing it, so the pair does not
   jump sideways as a rep walks the list. */
.pd-crumb-off { color: var(--faint); }

@media (min-width: 768px) {
  /* Tabs are the phone affordance; on a laptop there is no reason to tap through five panes. */
  .pd-shell .pd-tabs { display: none; }

  .pd-detail-grid {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
  }

  .pd-detail-col {
    display: flex;
    flex-direction: column;
    flex: 1 1 0;
    min-width: 0;
  }

  /* Every pane visible at once — .fade leaves the inactive ones at opacity 0, and the base .tab-pane
     rule above would otherwise hide every pane but the phone's active one. */
  .pd-detail-col > .tab-pane,
  .pd-detail-col > .tab-pane.fade {
    display: block;
    opacity: 1;
  }

  /* Column one is People then Overview (which at this point is just the Custom fields card — see
     .pd-overview-summary below), per the comp. The overview pane is second in the DOM (its tab is
     first on a phone), so it's reordered here rather than moved — moving it would change nothing on
     desktop and everything about the phone's default tab. */
  #overview-pane { order: 2; }

  /* Overview's other three cards are each said in full by a column of its own here. */
  .pd-overview-summary { display: none; }

  /* Card header titles + flat text-link "Add" affordance (comp 10h), replacing the mobile bordered
     icon+text pill button — the same .pd-icon-btn-add markup, restyled only at this breakpoint. */
  .pd-card-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.75rem 1rem !important;
    border-bottom: 1px solid var(--border) !important;
  }

  .pd-card-header .pd-icon-btn-add {
    height: auto;
    padding: 0;
    border: 0;
    background: transparent;
  }
}

/* --- Legal pages (Views/Legal) --- */
/* Minimal chrome for a HideNav page reachable both anonymously and while signed in — no sidebar,
   just the brand and (when authenticated) a way back. */
.legal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-bottom: 1rem;
  margin-bottom: 1rem;
  border-bottom: 1px solid var(--border-subtle);
}

.legal-brand {
  font-family: 'Outfit', sans-serif;
  font-weight: 700;
  font-size: 1.1rem;
  color: inherit;
}

/* A prose column, narrower than the app's full-width grids: these are read, not scanned. */
.legal-page {
  max-width: 46rem;
  margin: 0 auto 3rem;
  line-height: 1.65;
}

.legal-footer {
  margin-top: 2.25rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border-subtle);
  font-size: 0.875rem;
  color: var(--muted, #6c757d);
}

.legal-title {
  font-size: 1.75rem;
  margin-bottom: 0.25rem;
}

.legal-meta {
  color: var(--muted);
  font-size: 0.875rem;
  margin-bottom: 2rem;
}

.legal-page h2 {
  font-size: 1.125rem;
  margin-top: 2.25rem;
  margin-bottom: 0.75rem;
}

.legal-page h3 {
  font-size: 1rem;
  font-weight: 600;
  margin-top: 1.5rem;
  margin-bottom: 0.5rem;
}

.legal-page p,
.legal-page li {
  font-size: 0.9375rem;
}

.legal-page ul {
  padding-left: 1.25rem;
}

.legal-page li {
  margin-bottom: 0.4rem;
}

/* Wide on a phone by nature, so it scrolls inside itself rather than widening the page. */
.legal-table-wrap {
  overflow-x: auto;
}

.legal-table {
  width: 100%;
  min-width: 34rem;
  border-collapse: collapse;
  margin: 1rem 0 1.5rem;
  font-size: 0.875rem;
}

.legal-table th,
.legal-table td {
  border: 1px solid var(--border);
  padding: 0.5rem 0.625rem;
  text-align: left;
  vertical-align: top;
}

.legal-table th {
  background: #f6f7f9;
  font-weight: 600;
}

/* Markdown source, not prose: a monospace column so a lawyer's pasted text keeps its shape. */
.legal-editor {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.8125rem;
  line-height: 1.5;
}

/* --- Share composer (Views/Properties/_ShareModal.cshtml, property-share.js) --- */

.pd-share-tiles {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.5rem;
}

.pd-share-tile {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.125rem;
  position: relative;
  padding: 0.625rem 0.625rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  cursor: pointer;
  min-height: 60px;
}

.pd-share-tile:has(.pd-share-tile-check:disabled) {
  cursor: default;
  opacity: 0.55;
}

.pd-share-tile-check {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  margin: 0;
}

.pd-share-tile-name {
  font-family: var(--font-head);
  font-weight: 600;
  font-size: 0.875rem;
  padding-right: 1.25rem;
}

.pd-share-tile-count {
  font-size: 0.75rem;
  color: var(--faint);
}

/* On, so its content is in the message. Matches .pd-chip.active, which already means "on" here. */
.pd-share-tile.active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

.pd-share-tile.active .pd-share-tile-count {
  color: rgba(255, 255, 255, 0.75);
}

/* Open, so the row below belongs to this tile. Reads whether or not the tile is on. */
.pd-share-tile-open::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -9px;
  transform: translateX(-50%);
  border: 8px solid transparent;
  border-top-color: var(--border);
}

.pd-share-panel {
  margin-top: 1rem;
  padding: 0.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--bg);
  max-height: 34vh;
  overflow-y: auto;
}

.pd-share-row {
  padding: 0.375rem 0.25rem;
}

.pd-share-row + .pd-share-row {
  border-top: 1px solid var(--border);
}

.pd-share-check {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  cursor: pointer;
  font-size: 0.875rem;
}

.pd-share-check .form-check-input {
  margin-top: 0.2rem;
  flex-shrink: 0;
}

.pd-share-line,
.pd-share-when {
  display: block;
}

.pd-share-line {
  font-weight: 600;
}

.pd-share-when,
.pd-share-role {
  font-size: 0.75rem;
  color: var(--muted);
}

.pd-share-numbers {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  padding: 0.375rem 0 0.125rem 1.625rem;
}

.pd-share-number {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.8125rem;
  cursor: pointer;
}

.pd-share-number .form-check-input {
  margin: 0;
}

/* The one place the message is legible before it is sent, so it keeps its own line breaks. */
.pd-share-preview {
  margin: 0.25rem 0 0;
  padding: 0.625rem 0.75rem;
  border-radius: var(--radius-lg);
  background: var(--neutral-bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 0.8125rem;
  line-height: 1.45;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 30vh;
  overflow-y: auto;
}

.pd-share-copied {
  margin-right: auto;
  font-size: 0.8125rem;
  color: var(--success);
}

/* --- Drag-to-reorder phone rows on the contact forms (phone-rows.js) --- */

/* The rows post as repeated name="Phones" and bind in document order, so dragging one is the whole
   edit: no re-indexing, nothing to save separately. */
.phone-row .phone-handle {
  display: flex;
  align-items: center;
  padding: 0 0.625rem;
  border: 1px solid var(--bs-border-color);
  border-right: 0;
  border-radius: 0.375rem 0 0 0.375rem;
  background: var(--bs-tertiary-bg);
  color: var(--bs-secondary-color);
  cursor: grab;
  /* Without this, a touch drag on the handle is read as a page scroll first. */
  touch-action: none;
}

.phone-row .phone-handle:active {
  cursor: grabbing;
}

.phone-row-ghost {
  opacity: 0.4;
}

.phone-row-chosen {
  box-shadow: 0 0 0 2px var(--bs-primary);
  border-radius: 0.375rem;
}

/* --- Folded field groups (TagHelpers/FieldGroupTagHelper.cs, field-group.js) --- */

/* Secondary fields collapse to one row carrying a live summary, so a twelve-field form opens
   showing two or three inputs and still fits the modal cap above without scrolling. Deliberately
   not scoped to a shell: #formModal sits at body level, outside every .pd-shell, so var(--accent)
   and friends resolve to nothing here. */
.fg {
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: #fff;
  margin-bottom: 0.5rem;
}

.fg[open] {
  border-color: var(--bs-primary);
}

.fg-head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: 56px;
  padding: 0.5rem 0.75rem;
  cursor: pointer;
  border-radius: calc(var(--radius-md) - 1px);
  list-style: none;
}

.fg-head::-webkit-details-marker {
  display: none;
}

.fg-head:focus-visible {
  outline: 2px solid var(--bs-primary);
  outline-offset: -2px;
}

.fg[open] .fg-head {
  background: rgba(var(--bs-primary-rgb), 0.07);
  border-radius: calc(var(--radius-md) - 1px) calc(var(--radius-md) - 1px) 0 0;
}

.fg-icon {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: var(--radius-sm);
  background: rgba(var(--bs-primary-rgb), 0.1);
  color: var(--bs-primary);
}

.fg[open] .fg-icon {
  background: #fff;
}

.fg-icon svg {
  width: 16px;
  height: 16px;
}

.fg-icon-glyph {
  font-weight: 700;
  font-size: 0.95rem;
  line-height: 1;
}

.fg-text {
  flex: 1 1 auto;
  min-width: 0;
}

.fg-label {
  display: block;
  font-weight: 600;
  color: #212529;
}

.fg[open] .fg-label {
  color: var(--bs-primary);
}

/* One line: a group with several values filled in would otherwise wrap the row to three lines and
   undo the space the fold just saved. */
.fg-summary {
  display: block;
  font-size: 0.8rem;
  color: #6c757d;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.fg[open] .fg-summary {
  display: none;
}

.fg-chevron {
  flex: 0 0 auto;
  width: 10px;
  height: 6px;
  color: #6c757d;
  transition: transform 0.15s var(--ease-standard);
}

.fg[open] .fg-chevron {
  transform: rotate(180deg);
  color: var(--bs-primary);
}

.fg-body {
  padding: 0.75rem;
}

/* The last field in a group carries the group's own bottom padding, so its margin would double it. */
.fg-body > :last-child {
  margin-bottom: 0 !important;
}

/* A quiet row rather than a button competing with Cancel and Save in the footer. */
.fg-danger-row {
  border-top: 1px solid var(--border-subtle);
  padding-top: 0.75rem;
  margin-top: 1rem;
}

/* --- Help (Claude Design comp "15 Help", Views/Help/Index.cshtml) --- */

/* No new token scope: the comp's :root set is the one .pd-shell already declares verbatim, and
   Help was already wrapped in it. Same ruling as the desktop Properties workspace above. */
/* Centred like .legal-page, which is linked from the same login footer: signed out there is no
   sidebar, so without this the page sits against the left edge of a wide monitor. */
.help-shell {
  max-width: 1100px;
  margin-inline: auto;
}

.help-back {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  /* A 44px target, but the text sits flush with the title below it rather than floating. */
  min-height: 44px;
  margin-bottom: -0.25rem;
  font-weight: 600;
  font-size: 0.875rem;
  color: var(--accent);
  text-decoration: none;
}

.help-back:hover,
.help-back:focus {
  color: var(--accent-dark);
}

.help-heading {
  font-size: 1.5rem;
  margin-bottom: 0.125rem;
}

.help-lede {
  margin-bottom: 1rem;
}

.help-destinations {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
}

.help-destination {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: 60px;
  padding: 0.75rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  color: var(--text);
  text-decoration: none;
  transition: border-color 0.15s var(--ease-standard), box-shadow 0.15s var(--ease-standard);
}

.help-destination:hover,
.help-destination:focus {
  color: var(--text);
  border-color: var(--accent);
  box-shadow: var(--shadow-1);
}

/* The one accented row: the help centre is the only destination that answers a question without
   a person on the other end. The two report links stay level with each other, so a reader
   guessing between "bug" and "request" isn't nudged by styling. */
/* Hover is listed here too, or .help-destination:hover outranks it and the accented card loses
   its colour and drops a step of elevation on the way past. */
.help-destination-primary,
.help-destination-primary:hover,
.help-destination-primary:focus {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  box-shadow: var(--shadow-2);
}

.help-destination-icon {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: var(--radius-sm);
  font-family: var(--font-head);
  font-weight: 600;
  font-size: 0.9375rem;
  line-height: 1;
}

.help-destination-primary .help-destination-icon {
  background: rgba(255, 255, 255, 0.18);
  color: #fff;
}

.help-destination-text {
  flex: 1 1 auto;
  min-width: 0;
}

.help-destination-title {
  display: block;
  font-family: var(--font-head);
  font-weight: 600;
  font-size: 0.9375rem;
}

.help-destination-sub {
  display: block;
  font-size: 0.75rem;
  color: var(--muted);
}

.help-destination-primary .help-destination-sub {
  color: rgba(255, 255, 255, 0.72);
}

.help-destination-go {
  flex: 0 0 auto;
  color: var(--faint);
}

.help-destination-primary .help-destination-go {
  color: rgba(255, 255, 255, 0.72);
}

.help-layout {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.help-main {
  min-width: 0;
}

.help-aside {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  min-width: 0;
}

.help-eyebrow {
  font-family: var(--font-head);
  font-weight: 600;
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 0.5rem;
}

/* One card of stacked rows rather than separate cards: the topics are a list, and hairlines
   between them read as one place to look. */
.help-topics {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}

.help-topic + .help-topic {
  border-top: 1px solid var(--border);
}

.help-topic-summary {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  min-height: 52px;
  padding: 0.75rem 1rem;
  cursor: pointer;
  list-style: none;
}

/* Safari draws its own disclosure triangle unless both of these are set. */
.help-topic-summary::-webkit-details-marker {
  display: none;
}

.help-topic-summary::marker {
  content: '';
}

.help-topic-title {
  flex: 1 1 auto;
  font-weight: 600;
  font-size: 0.875rem;
}

/* Hidden on a phone, where the row has no width to spare for it. */
.help-topic-hint {
  display: none;
  font-size: 0.78125rem;
  color: var(--faint);
}

.help-topic-chevron {
  flex: 0 0 auto;
  color: var(--faint);
  transition: transform 0.15s var(--ease-standard);
}

.help-topic[open] > .help-topic-summary {
  background: var(--bg);
}

.help-topic[open] > .help-topic-summary .help-topic-title {
  color: var(--accent-tint-text);
}

.help-topic[open] > .help-topic-summary .help-topic-chevron {
  transform: rotate(180deg);
  color: var(--accent);
}

.help-topic-body {
  padding: 0 1rem 1rem;
  background: var(--bg);
  font-size: 0.8125rem;
  line-height: 1.65;
  color: var(--muted);
}

/* The measure goes on the paragraphs, never the container: the container carries the open row's
   tint, and capping that would leave a white strip down the right of every opened topic. */
.help-topic-body p {
  max-width: 60ch;
  margin-bottom: 0.625rem;
}

.help-topic-body p:last-of-type {
  margin-bottom: 0;
}

/* A footnote under the answer, not a replacement for it: the reader is here because the portal
   was the long way round. */
.help-topic-more {
  display: inline-block;
  margin-top: 0.75rem;
  font-weight: 600;
  font-size: 0.8125rem;
}

.help-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 0.875rem 1rem 1rem;
}

.help-ask-admin {
  border-color: transparent;
  background: var(--neutral-bg);
}

.help-ask-admin .pd-diagnostics {
  background-color: var(--card);
}

.help-card-title {
  font-weight: 600;
  font-size: 0.9375rem;
  margin-bottom: 0.25rem;
}

.help-card-note {
  font-size: 0.78125rem;
  line-height: 1.6;
  color: var(--muted);
  margin-bottom: 0;
}

.help-card .pd-diagnostics {
  margin-bottom: 0.625rem;
}

.help-copy-row {
  display: flex;
  align-items: center;
  gap: 0.625rem;
}

.help-copy-row + .help-card-note {
  margin-top: 0.75rem;
}

@media (min-width: 768px) {
  /* auto-fit, not repeat(3): each destination is configured on its own, so one or two of them is
     a real state and a fixed three-column track would leave a lone card a third of a row wide. */
  .help-destinations {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    align-items: stretch;
  }

  /* Stacked on a laptop: icon, title, subtitle, per comp 15e. The chevron is a phone-row
     affordance and has nothing to point at once the cards sit side by side. */
  .help-destination {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 1.125rem;
  }

  .help-destination-go {
    display: none;
  }

  .help-destination-sub {
    font-size: 0.78125rem;
  }

  .help-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: 1.5rem;
    align-items: start;
  }

  .help-topic-hint {
    display: block;
  }
}
