:root {
  --vp-navy: #1b4332;        /* now the brand's dark green (kept the variable name to avoid touching every template) */
  --vp-navy-dark: #0f2a1f;   /* deepest green, sidebar gradient bottom */
  --vp-navy-light: #2d6a4f;  /* mid green, hover states */
  --vp-gold: #95d5b2;        /* light green (replaces the old gold accent) */
  --vp-gold-light: #b7e4c7;  /* lighter green hover */
  --vp-green-text: #1b4332;  /* dark green text used on light-green buttons/badges */
  --vp-green-border: #40916c; /* outline-button border: dark enough to read as an edge */
  --vp-bg: #f4f6f9;
  --vp-card-border: #e3e7ee;
  --vp-text-muted: #6b7280;
  --vp-danger: #c0392b;
  --vp-success: #1f8a4c;
  --vp-warning: #b8860b;
}

body {
  background-color: var(--vp-bg);
  font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  color: #1f2937;
}

.vp-sidebar {
  background-color: var(--vp-navy);
  /* Kimberly's own branded wallpaper — the same clover artwork as the sign-in panel, with
     the white logo badge painted out of the image so the sidebar's own brand block isn't
     competing with a second logo behind it.

     The overlay on top runs the OPPOSITE way to the artwork, and that is the whole trick.
     The wallpaper starts light mint and ends near-black, so a uniform (or downward-
     increasing) dark overlay does the wrong thing at both ends: white text is barely
     readable at the top where the art is lightest, and the bottom third turns to mud with
     the clovers invisible. Strongest at the top and weakest at the bottom instead cancels
     the artwork's own gradient out, giving one steady brand green from top to bottom —
     white text stays readable the whole way down, and the clovers stay visible in the
     lower half where they used to disappear.

     Measured on the rendered sidebar rather than guessed: the lightest patch of wallpaper
     behind a nav link sits at 5.15:1 against white, above the 4.5:1 WCAG AA asks for.
     Raise all three numbers together to darken it — 0.62/0.44/0.20 and 0.72/0.56/0.32
     are the two steps that were compared against this one. */
  background-image:
    linear-gradient(180deg,
      rgba(10, 40, 27, 0.50) 0%,
      rgba(10, 40, 27, 0.32) 45%,
      rgba(10, 40, 27, 0.10) 100%),
    url("../img/sidebar_wallpaper.jpg");
  background-repeat: no-repeat, no-repeat;
  background-position: top center, top center;
  background-size: cover, cover;
  /* NOT background-attachment: fixed. That was the reason none of this artwork was
     visible: `fixed` sizes a background against the VIEWPORT, so `cover` scaled the
     772x1998 wallpaper to fill 1400x900-odd of screen and the 240px sidebar showed a
     hugely magnified sliver of it — one blurred clover edge, which read as a smudge
     rather than as a clover. Sized against the sidebar itself, the artwork appears at
     the scale it was drawn for. `cover` still handles a sidebar taller than the window,
     which is what `fixed` was there to solve. */
  min-height: 100vh;
  color: #e8ecf3;
  width: 240px;
  flex-shrink: 0;
}

.vp-sidebar .brand {
  font-weight: 700;
  font-size: 1.35rem;
  letter-spacing: 0.5px;
  color: #fff;
  padding: 1.25rem 1.25rem 0.25rem;
  display: flex;
  align-items: center;
  gap: 0.55rem;
}

.vp-sidebar .brand .brand-text {
  display: flex;
  flex-direction: column;
}

.vp-sidebar .brand .tagline {
  display: block;
  font-size: 0.68rem;
  font-weight: 400;
  color: var(--vp-gold-light);
  letter-spacing: 0.4px;
  margin-top: 2px;
}

/* Every small upper-case label in the sidebar — the "MY HOME" / "TREASURY" section
   headers and the "MY COMMUNITY" label above the association picker. One rule for both,
   because they were three inline `color:#7c8aa5` styles left over from the navy theme:
   a grey-blue that reads as barely-there against the green wallpaper, and that no amount
   of editing style.css would have changed. */
.vp-sidebar .nav-section,
.vp-sidebar .nav-label {
  text-transform: uppercase;
  font-size: 0.7rem;
  letter-spacing: 0.6px;
  color: #9fb8ab;
}

.vp-sidebar .nav-section {
  padding: 1rem 1.25rem 0.35rem;
}

/* The label sits inside its own padded block above the picker, so it carries only the
   small gap beneath itself. */
.vp-sidebar .nav-label {
  display: block;
  margin-bottom: 0.25rem;
}

.vp-sidebar .nav-link {
  color: #d3e3da;
  padding: 0.5rem 1.25rem;
  border-radius: 0;
  font-size: 0.92rem;
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.vp-sidebar .nav-link:hover {
  background: rgba(255, 255, 255, 0.08);
  color: #fff;
}

.vp-sidebar .nav-link.active {
  background: rgba(149, 213, 178, 0.18);
  color: var(--vp-gold-light);
  border-left: 3px solid var(--vp-gold);
  font-weight: 600;
}

.vp-sidebar .badge-count {
  margin-left: auto;
  background: var(--vp-gold);
  color: var(--vp-green-text);
  font-weight: 700;
}

/* Community switcher — a custom dropdown standing in for a native <select>, so we get
   full control over hover/active colors instead of the browser's default blue. */
.community-switcher-toggle {
  background: rgba(255,255,255,0.08);
  color: #fff;
  border: 1px solid rgba(255,255,255,0.2);
  font-weight: 600;
  font-size: 0.85rem;
}
.community-switcher-toggle:hover,
.community-switcher-toggle:focus,
.community-switcher-toggle:active {
  background: rgba(255,255,255,0.14);
  color: #fff;
  border-color: rgba(255,255,255,0.3);
}
.community-switcher-menu {
  background: var(--vp-navy-dark);
  border: 1px solid rgba(255,255,255,0.15);
  padding: 0.25rem;
  max-height: 320px;
  overflow-y: auto;
}
.community-switcher-item {
  color: #dfe6ee;
  border-radius: 4px;
  font-size: 0.85rem;
  padding: 0.45rem 0.75rem;
}
.community-switcher-item:hover,
.community-switcher-item:focus {
  background: var(--vp-navy-light);
  color: #fff;
}
.community-switcher-item.active {
  background: var(--vp-gold);
  color: var(--vp-green-text);
  font-weight: 600;
}

/* Folder dropdown — same idea as the community switcher above (a custom dropdown
   instead of a native <select>, no default browser blue highlight), but styled for a
   light card/page background instead of the dark top bar. Used on Documents. */
.folder-dropdown-toggle {
  background: #fff;
  color: var(--vp-navy);
  border: 1px solid var(--vp-card-border);
  font-weight: 600;
  font-size: 0.85rem;
}
.folder-dropdown-toggle:hover,
.folder-dropdown-toggle:focus,
.folder-dropdown-toggle:active {
  background: #f4f6f9;
  color: var(--vp-navy);
  border-color: var(--vp-navy-light);
}
.folder-dropdown-menu {
  background: #fff;
  border: 1px solid var(--vp-card-border);
  padding: 0.25rem;
  max-height: 360px;
  overflow-y: auto;
}
.folder-dropdown-item {
  color: var(--vp-navy);
  border-radius: 4px;
  font-size: 0.85rem;
  padding: 0.45rem 0.75rem;
}
.folder-dropdown-item:hover,
.folder-dropdown-item:focus {
  background: var(--vp-gold-light);
  color: var(--vp-green-text);
}
.folder-dropdown-item.active {
  background: var(--vp-gold);
  color: var(--vp-green-text);
  font-weight: 600;
}

.vp-topbar {
  background: #fff;
  border-bottom: 1px solid var(--vp-card-border);
  padding: 0.6rem 1.5rem;
}

/* --- top bar: title, then search and the account menu, hard right --------- */
/* The page title takes the slack so the two tools stay pinned to the corner at every
   width, instead of drifting left as the title gets shorter. */
.vp-topbar-title { flex: 1 1 auto; min-width: 0; }

.vp-topbar-tools {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex: 0 0 auto;
}

.vp-search { position: relative; }

.vp-search-icon {
  position: absolute;
  left: 0.65rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-secondary);
  font-size: 0.85rem;
  pointer-events: none;            /* the icon must never eat a click meant for the box */
}

.vp-search-input {
  width: 19rem;
  max-width: 34vw;
  padding: 0.38rem 0.7rem 0.38rem 2rem;
  border: 1px solid var(--vp-card-border);
  border-radius: 999px;
  background: #f7f8fa;
  font-size: 0.85rem;
  line-height: 1.3;
  transition: width 0.15s ease, background 0.15s ease, border-color 0.15s ease;
}

.vp-search-input:focus {
  outline: none;
  width: 23rem;
  background: #fff;
  border-color: var(--vp-navy);
  box-shadow: 0 0 0 3px rgba(27, 67, 50, 0.12);
}

/* Safari draws its own cancel button and a rounded inner field; both fight the pill. */
.vp-search-input::-webkit-search-decoration,
.vp-search-input::-webkit-search-results-button { -webkit-appearance: none; }

.vp-account-btn {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background: none;
  border: 1px solid transparent;
  border-radius: 999px;
  padding: 0.25rem 0.6rem 0.25rem 0.25rem;
  cursor: pointer;
  color: inherit;
}

.vp-account-btn:hover,
.vp-account-btn[aria-expanded="true"] {
  background: #f2f4f2;
  border-color: var(--vp-card-border);
}

.vp-account-avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--vp-navy);
  color: #fff;
  font-weight: 700;
  font-size: 0.85rem;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}

.vp-account-name {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 1.15;
}

.vp-account-who { font-size: 0.83rem; font-weight: 600; }
.vp-account-role { font-size: 0.7rem; color: var(--text-secondary); }
.vp-account-caret { font-size: 0.7rem; color: var(--text-secondary); }

.vp-main {
  flex: 1;
  min-width: 0;
}

.vp-content {
  padding: 1.75rem;
}

.card {
  border: 1px solid var(--vp-card-border);
  border-radius: 10px;
}

/* ------------------------------------------------------------------ field rows
   A row of form fields sitting side by side.

   These used to be `row g-2 align-items-end`, which lines up the BOTTOM edge of
   every column. That is fine while the columns are the same shape, and wrong the
   moment one of them carries a line of help text under its box — "Accepted: PDF,
   DOC, …" under a file picker, say. That column grows downward, and aligning the
   bottoms lifts its label and its box ABOVE everything beside it. Kimberly's
   words for it: the invoice file box is up in the air. Same thing on the utility
   and insurance forms, and a dozen other places, because the pattern was copied.

   The fix is to line the columns up at the TOP, hold every label to one line's
   height so the boxes still start on the same line, and let help text hang below
   the box it belongs to, which is where a reader looks for it anyway.

   A column holding nothing but a button or a tickbox has no label to reserve
   that height, so it would climb up level with the labels. `vp-field-align`
   gives the height back. It is opt-in rather than automatic on every button
   because plenty of these rows end with a button on a line of its own, where a
   top margin would only push it away from the form. */
.vp-field-row {
  align-items: flex-start;
}

.vp-field-row .form-label {
  margin-bottom: 0.25rem;
  line-height: 1.2rem;
  min-height: 1.2rem;
}

/* 1.2rem of label + 0.25rem beneath it — the same two numbers as above, so the
   control lands exactly on the top of the boxes next to it. */
.vp-field-row .vp-field-align {
  margin-top: 1.45rem;
}

/* A tickbox sharing its line with a submit button and nothing else. A tickbox is
   a shorter thing than a button, so top-aligning the two leaves the sentence
   riding high above it; half the difference brings them level. Skipped where the
   column is already carrying the label offset above, or the two would stack. */
.vp-field-row > [class*="col-"]:not(.vp-field-align) > .form-check:only-child {
  margin-top: 0.3rem;
}

.stat-card {
  border-radius: 12px;
  padding: 1.1rem 1.3rem;
  background: #fff;
  border: 1px solid var(--vp-card-border);
  height: 100%;
}

.stat-card .stat-value {
  font-size: 1.7rem;
  font-weight: 700;
  color: var(--vp-navy);
}

.stat-card .stat-label {
  font-size: 0.8rem;
  color: var(--vp-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}

.stat-card .stat-icon {
  width: 42px;
  height: 42px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.2rem;
  background: rgba(27, 67, 50, 0.08);
  color: var(--vp-navy);
}

/* Every dynamic status/stage/priority string used anywhere in the app is covered here —
   Bootstrap's base .badge rule sets white text with no background of its own, so any
   status class without a matching rule below renders as invisible/near-invisible white
   text (this is the bug that made Inspections statuses unreadable). */
.badge-status-pending, .badge-status-open, .badge-status-scheduled, .badge-status-courtesy-reminder,
.badge-status-pending-approval, .badge-status-not-connected, .badge-status-draft, .badge-status-unpaid {
  background: #fdf1d6; color: var(--vp-warning);
}
.badge-status-approved, .badge-status-resolved, .badge-status-closed, .badge-status-cured,
.badge-status-passed, .badge-status-current, .badge-status-done, .badge-status-paid,
.badge-status-connected, .badge-status-delivered, .badge-status-completed {
  background: #e3f5e9; color: var(--vp-success);
}
.badge-status-denied, .badge-status-fined, .badge-status-failed, .badge-status-ended,
.badge-status-rejected, .badge-status-urgent, .badge-status-high, .badge-status-legal-referral,
.badge-status-lien-filed {
  background: #fbe4e1; color: var(--vp-danger);
}
.badge-status-in-progress, .badge-status-more-info-needed, .badge-status-appealed,
.badge-status-follow-up-needed, .badge-status-upcoming, .badge-status-queued,
.badge-status-sent-to-provider, .badge-status-formal-demand, .badge-status-demo-mode,
.badge-status-partially-paid, .badge-status-payment-plan, .badge-status-medium,
.badge-status-conditional-approval,
/* Insurance claim stages — a claim in the carrier's hands, with money still expected. */
.badge-status-reported-to-carrier, .badge-status-adjuster-assigned,
.badge-status-estimate-received {
  background: #e4ecfb; color: #2352a5;
}
/* A claim the association decided not to pursue. Grey rather than red: nothing failed,
   it was withdrawn on purpose, and colouring it as a denial would misreport the file. */
.badge-status-withdrawn { background: #eef0f3; color: #55606e; }
.badge-status-low { background: #eef0f3; color: #55606e; }
.badge-status-active { background: #e3f5e9; color: var(--vp-success); }
.badge-status-paused { background: #eef0f3; color: #55606e; }

.btn-vp-primary {
  background: var(--vp-navy);
  border-color: var(--vp-navy);
  color: #fff;
}
.btn-vp-primary:hover { background: var(--vp-navy-light); border-color: var(--vp-navy-light); color: #fff; }

.btn-vp-gold {
  background: var(--vp-gold);
  border-color: var(--vp-gold);
  color: var(--vp-green-text);
  font-weight: 600;
}
.btn-vp-gold:hover { background: var(--vp-gold-light); border-color: var(--vp-gold-light); color: var(--vp-green-text); }

/* A row of secondary record actions — Edit, Log Violation, Welcome Packet, and so on.
   Outline rather than solid because none of them is the main thing to do on the page, and
   green rather than grey because grey buttons in a green product read as disabled.

   The border is deliberately #40916c and not the pale --vp-gold: a 1px edge that light
   against white is nearly invisible, and a button whose boundary you cannot see is a
   button people do not press.

   nowrap is load-bearing. Without it "Welcome Packet" and "Log Violation" break across two
   lines, every button in the row grows to match the tallest, and a tidy row turns into a
   block of ragged boxes. */
.btn-vp-outline {
  background: #fff;
  border: 1px solid var(--vp-green-border);
  color: var(--vp-green-text);
  font-weight: 500;
  white-space: nowrap;
}
.btn-vp-outline:hover {
  background: var(--vp-gold-light);
  border-color: var(--vp-navy-light);
  color: var(--vp-green-text);
}
.btn-vp-outline:active,
.btn-vp-outline:focus {
  background: var(--vp-gold);
  border-color: var(--vp-navy-light);
  color: var(--vp-green-text);
}
.btn-vp-outline:focus-visible {
  box-shadow: 0 0 0 0.2rem rgba(45, 106, 79, 0.3);
}
/* Icons a step lighter than the label, so the words stay the thing you read. */
.btn-vp-outline .bi { color: var(--vp-navy-light); }

.table thead th {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--vp-text-muted);
  border-bottom-width: 1px;
}

.login-wrapper {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--vp-navy);
  background-image:
    linear-gradient(180deg, var(--vp-gold-light) 0%, var(--vp-navy) 35%, var(--vp-navy-dark) 100%),
    url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='260'%20height='260'%20viewBox='0%200%20260%20260'%3E%3Cg%20fill='%2395d5b2'%20fill-opacity='0.12'%3E%3Ccircle%20cx='95'%20cy='95'%20r='34'/%3E%3Ccircle%20cx='163'%20cy='95'%20r='34'/%3E%3Ccircle%20cx='95'%20cy='163'%20r='34'/%3E%3Ccircle%20cx='163'%20cy='163'%20r='34'/%3E%3Cpath%20d='M129%20163%20Q133%20195%20122%20222'%20stroke='%2395d5b2'%20stroke-width='6'%20fill='none'/%3E%3C/g%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='130'%20height='130'%20viewBox='0%200%20130%20130'%3E%3Cg%20fill='%2395d5b2'%20fill-opacity='0.07'%3E%3Ccircle%20cx='48'%20cy='48'%20r='16'/%3E%3Ccircle%20cx='82'%20cy='48'%20r='16'/%3E%3Ccircle%20cx='48'%20cy='82'%20r='16'/%3E%3Ccircle%20cx='82'%20cy='82'%20r='16'/%3E%3Cpath%20d='M65%2082%20Q67%2098%2062%20111'%20stroke='%2395d5b2'%20stroke-width='3'%20fill='none'/%3E%3C/g%3E%3C/svg%3E");
  background-repeat: no-repeat, repeat, repeat;
  background-position: 0 0, 0 0, 65px 65px;
}

.login-card {
  background: #fff;
  border-radius: 14px;
  padding: 2.5rem;
  width: 100%;
  max-width: 400px;
  box-shadow: 0 20px 60px rgba(0,0,0,0.35);
}

.login-logo-badge {
  width: 88px;
  height: 88px;
  border-radius: 50%;
  background: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto;
  box-shadow: 0 6px 18px rgba(0,0,0,0.15);
}

.balance-positive { color: var(--vp-danger); font-weight: 700; }
.balance-zero { color: var(--vp-success); font-weight: 700; }

.thread-bubble {
  max-width: 75%;
  padding: 0.65rem 0.95rem;
  border-radius: 12px;
  margin-bottom: 0.6rem;
}
.thread-bubble.staff { background: #eef2f9; margin-right: auto; }
.thread-bubble.homeowner { background: var(--vp-navy); color: #fff; margin-left: auto; }

.vp-clover-icon { flex-shrink: 0; }

/* ==========================================================================
   Phones and tablets
   --------------------------------------------------------------------------
   Everything above this point is the desktop layout and is deliberately left
   alone — these rules only take effect below 992px, so nothing changes on the
   machine Kimberly works at all day.

   The one real problem on a phone is the sidebar: it's a fixed 240px column in
   a flex row, which on a 390px screen leaves 150px for actual content. Below
   992px it comes out of the flow entirely and slides in over the page from a
   hamburger button, the way every phone app does it.
   ========================================================================== */

/* The hamburger and the backdrop don't exist on desktop. */
.vp-nav-toggle,
.vp-sidebar-backdrop { display: none; }

/* `screen and`, not a bare max-width, and every phone breakpoint in this file carries it
   for the same reason. A printed letter sheet has a CSS viewport of about 816px, so a
   bare `(max-width: 991.98px)` fires ON PAPER as well as on a phone — every printed page
   in this app was being laid out for a phone. The visible symptom was the reserve
   summary: `.card > .table { min-width: 620px }` below made a four-column table wider
   than the column holding it, and the card clipped its Balance figures off the sheet. */
@media screen and (max-width: 991.98px) {

  /* --- sidebar becomes a slide-in drawer ---------------------------------- */
  .vp-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    z-index: 1045;                 /* above content, below Bootstrap modals (1055) */
    width: 82vw;
    max-width: 300px;
    transform: translateX(-100%);
    transition: transform 0.22s ease-out;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    /* A fixed background attachment is janky-to-broken on mobile Safari; let it
       scroll with the drawer instead. */
    background-attachment: scroll, scroll;
    min-height: 100%;
  }
  .vp-sidebar.is-open { transform: translateX(0); }

  .vp-sidebar-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 1040;
    background: rgba(0, 0, 0, 0.45);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.22s ease-out;
  }
  .vp-sidebar-backdrop.is-open { opacity: 1; pointer-events: auto; }

  /* Stop the page scrolling behind an open drawer. */
  body.vp-nav-open { overflow: hidden; }

  /* --- main column takes the full width ---------------------------------- */
  .vp-main { width: 100%; min-width: 0; }

  .vp-topbar {
    position: sticky;              /* the way back to the menu is always in reach */
    top: 0;
    z-index: 1030;
    gap: 0.5rem;
    padding: 0.6rem 0.85rem;
  }
  .vp-topbar .fw-semibold {
    font-size: 0.98rem;
    line-height: 1.2;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* The name/role caption is the first thing to go — the title matters more. */
  .vp-topbar > .text-muted { display: none; }

  /* On a phone the search box collapses to its icon and expands when tapped, and the
     account button keeps only its avatar. Both stay REACHABLE — the whole reason they
     moved up here — while the page title keeps the room it needs to be readable. */
  .vp-topbar-tools { gap: 0.35rem; }
  .vp-search-input {
    width: 2.2rem;
    max-width: none;
    padding-right: 0.3rem;
    background: transparent;
    border-color: transparent;
    cursor: pointer;
  }
  .vp-search-input:focus {
    width: 62vw;
    background: #fff;
    border-color: var(--vp-navy);
    cursor: text;
  }
  .vp-account-name, .vp-account-caret { display: none; }
  .vp-account-btn { padding: 0.2rem; }

  .vp-nav-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 42px;                   /* 42px square clears the 44px-ish tap target */
    height: 42px;
    flex: 0 0 auto;
    border: 1px solid var(--vp-card-border);
    border-radius: 8px;
    background: #fff;
    color: var(--vp-navy);
    font-size: 1.2rem;
    line-height: 1;
  }
  .vp-nav-toggle:active { background: var(--vp-bg); }

  /* Three bars, drawn with borders — no icon font, so it can't render as a blank box. */
  .vp-nav-toggle-bars,
  .vp-nav-toggle-bars::before,
  .vp-nav-toggle-bars::after {
    display: block;
    width: 19px;
    height: 0;
    border-top: 2px solid currentColor;
    border-radius: 2px;
  }
  .vp-nav-toggle-bars { position: relative; }
  .vp-nav-toggle-bars::before,
  .vp-nav-toggle-bars::after {
    content: "";
    position: absolute;
    left: 0;
  }
  .vp-nav-toggle-bars::before { top: -6px; }
  .vp-nav-toggle-bars::after  { top: 6px; }

  .vp-content { padding: 0.85rem; }

  /* --- room to breathe ---------------------------------------------------- */
  .card { border-radius: 10px; }
  .stat-card { padding: 0.85rem; }
  .stat-value { font-size: 1.5rem; }

  /* Any table wide enough to overflow scrolls inside its own card rather than
     pushing the whole page sideways — a horizontally scrolling page is the
     single most common way a desktop layout breaks on a phone. */
  .card > .table,
  .card > .table-responsive > .table { min-width: 620px; }
  .card:has(> .table) { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .table-responsive { -webkit-overflow-scrolling: touch; }

  /* Fingers, not mouse pointers. */
  .btn-sm { padding: 0.38rem 0.7rem; font-size: 0.86rem; }
  .form-control, .form-select { font-size: 16px; }  /* < 16px makes iOS zoom on focus */
  .form-control-sm, .form-select-sm { font-size: 16px; padding: 0.4rem 0.6rem; }

  /* Filter bars and button rows stack instead of squeezing. */
  .d-flex.gap-2 > .btn,
  .d-flex.gap-1 > .btn { flex: 1 1 auto; }
}

@media screen and (max-width: 575.98px) {
  .vp-content { padding: 0.7rem 0.6rem; }
  .stat-value { font-size: 1.35rem; }
  /* Stacked cards in a row lose their gutters otherwise. */
  .row.g-2 > [class*="col-"], .row.g-3 > [class*="col-"] { margin-bottom: 0.15rem; }
}

/* Standalone / Add-to-Home-Screen: the OS status bar sits over the page, so the
   sticky topbar needs to clear it. */
@media (display-mode: standalone) {
  .vp-topbar { padding-top: calc(0.6rem + env(safe-area-inset-top)); }
  .vp-content { padding-bottom: calc(1rem + env(safe-area-inset-bottom)); }
}

/* ---------------------------------------------------------------------------
   Sidebar sections (management sidebar only).

   Closed on arrival, one open at a time. On a wide screen the open section flies
   out beside the sidebar so the nav never grows; below 992px it drops inline,
   because a panel flying out of a drawer that is itself sliding over the page has
   nowhere to go.

   The grouping is assembled by JavaScript at runtime — see base.html for why the
   markup is left alone. Without the script the sidebar is the flat list it was.
   --------------------------------------------------------------------------- */

.vp-sidebar .nav-sec { position: relative; }

.vp-sidebar .nav-section.nav-section-toggle {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  cursor: pointer;
  user-select: none;
  width: 100%;
  background: none;
  border: 0;
  text-align: left;
  font: inherit;
  text-transform: uppercase;
  font-size: 0.7rem;
  letter-spacing: 0.6px;
  color: #9fb8ab;
}

.vp-sidebar .nav-section.nav-section-toggle:hover,
.vp-sidebar .nav-section.nav-section-toggle:focus-visible {
  color: #fff;
  background: rgba(255, 255, 255, 0.06);
}

.vp-sidebar .nav-section-toggle[aria-expanded="true"] {
  color: #fff;
  background: rgba(255, 255, 255, 0.10);
}

.vp-sidebar .nav-section-toggle .nav-caret {
  margin-left: auto;
  font-size: 0.7rem;
  transition: transform 0.18s ease;
}

/* Closed: the caret points the way the menu will open. Sideways on desktop, since
   that is where the panel appears; the media query below turns it downward. */
.vp-sidebar .nav-section-toggle[aria-expanded="false"] .nav-caret {
  transform: rotate(-90deg);
}

/* A dot beside the section holding the page you are on. With everything closed by
   default this is the only thing telling you where you are. */
.vp-sidebar .nav-sec.has-active .nav-here {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--vp-gold);
  flex-shrink: 0;
}

.vp-sidebar .nav-group[hidden] { display: none; }

/* Flyout, wide screens only. */
@media (min-width: 992px) {
  .vp-sidebar .nav-group {
    position: absolute;
    left: 100%;
    top: 0;
    z-index: 1080;
    min-width: 250px;
    padding: 0.35rem 0;
    /* Solid, not translucent: this floats over page content, and a see-through menu
       with a table behind it is unreadable. */
    background: #10281c;
    border: 1px solid rgba(255, 255, 255, 0.10);
    border-radius: 0 8px 8px 0;
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.38);
    overflow-y: auto;
  }
  .vp-sidebar .nav-group .nav-link { white-space: nowrap; }
}

/* Below 992px the sidebar is a drawer — drop the section inline instead. */
@media screen and (max-width: 991.98px) {
  .vp-sidebar .nav-group {
    position: static;
    background: rgba(0, 0, 0, 0.16);
    overflow-y: auto;
  }
  .vp-sidebar .nav-section-toggle[aria-expanded="false"] .nav-caret {
    transform: rotate(0deg);
  }
  .vp-sidebar .nav-section-toggle[aria-expanded="true"] .nav-caret {
    transform: rotate(180deg);
  }
}

/* ---------------------------------------------------------------------------
   All Communities (portfolio) dashboard.

   Two visual languages on one tile, kept apart on purpose:
     red   — a queue where someone is waiting on you. Can reach zero.
     grey  — what is true about the association. Never an alarm, because these
             figures never reach zero and would keep every tile permanently red.
   Amber sits between: unfinished, not urgent.
   --------------------------------------------------------------------------- */

.vp-portfolio .tnum { font-variant-numeric: tabular-nums; }

.pf-summary {
  background: #fff; border: 1px solid var(--vp-card-border); border-radius: 10px;
  padding: 1rem 1.25rem; margin-bottom: 1.25rem;
  display: flex; flex-wrap: wrap; gap: 1.5rem; align-items: center;
}
.pf-lead { font-size: 1.15rem; font-weight: 600; }
.pf-lead b { color: var(--vp-danger); }
.pf-lead.pf-clear { color: var(--vp-success); }
.pf-subLead { font-size: .86rem; color: #96271b; margin-top: .15rem; }
.pf-metrics { display: flex; flex-wrap: wrap; gap: 1.75rem; margin-left: auto; }
.pf-metric .k {
  display: block; font-size: .68rem; text-transform: uppercase;
  letter-spacing: .5px; color: var(--vp-text-muted);
}
.pf-metric .v { display: block; font-size: 1.05rem; font-weight: 600; }

.pf-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); gap: 1rem; }

.pf-tile {
  background: #fff; border: 1px solid var(--vp-card-border); border-radius: 10px;
  /* State carried by the stripe as well as the number, so a tile that needs you
     reads before a single digit has been parsed. */
  border-left: 4px solid var(--vp-card-border);
  display: flex; flex-direction: column; overflow: hidden;
}
.pf-tile.is-needs { border-left-color: var(--vp-danger); }
.pf-tile.is-quiet { border-left-color: var(--vp-success); }
.pf-tile.is-setup { border-left-color: var(--vp-warning); }

.pf-head { padding: .9rem 1rem .7rem; display: flex; align-items: flex-start; gap: .6rem; }
.pf-name { font-weight: 600; font-size: 1rem; line-height: 1.25; }
.pf-name a { color: var(--vp-navy); text-decoration: none; }
.pf-name a:hover { text-decoration: underline; }
.pf-meta { font-size: .74rem; color: var(--vp-text-muted); margin-top: .15rem; }
.pf-id { font-family: ui-monospace, "Cascadia Mono", Consolas, monospace; }

.pf-count {
  margin-left: auto; flex-shrink: 0;
  min-width: 30px; height: 30px; padding: 0 .5rem; border-radius: 999px;
  background: var(--vp-danger); color: #fff; font-weight: 700; font-size: .92rem;
  display: inline-flex; align-items: center; justify-content: center;
}

.pf-todo { list-style: none; margin: 0; padding: 0 .55rem .55rem; }
.pf-todo a {
  display: flex; align-items: center; gap: .55rem;
  padding: .4rem .45rem; border-radius: 6px;
  color: #1f2937; text-decoration: none; font-size: .88rem;
}
.pf-todo a:hover, .pf-todo a:focus-visible { background: #f0f4f2; }
.pf-n {
  min-width: 22px; height: 22px; padding: 0 .35rem; border-radius: 5px;
  background: #fdecea; color: var(--vp-danger); font-weight: 700; font-size: .78rem;
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
}
/* A held payment is not a routine queue item — it is money the association may not
   lawfully take. Solid, not pale. */
.pf-n.is-critical { background: var(--vp-danger); color: #fff; }
.pf-go { margin-left: auto; color: #b6bec9; font-size: .8rem; }

.pf-allclear {
  display: flex; align-items: center; gap: .4rem;
  padding: .1rem 1rem .9rem; font-size: .88rem;
  color: var(--vp-success); font-weight: 600;
}

/* Conditions. Never counted in the badge — the badge counts tasks and has to be
   able to reach zero. */
.pf-alarm {
  display: flex; gap: .5rem; align-items: flex-start;
  margin: 0 .55rem .5rem; padding: .5rem .6rem;
  border-radius: 6px; font-size: .82rem; line-height: 1.35;
}
.pf-alarm i { flex-shrink: 0; margin-top: .1rem; }
.pf-alarm.is-crit  { background: #fdecea; color: #96271b; border-left: 3px solid var(--vp-danger); }
.pf-alarm.is-watch { background: #fdf6e3; color: #8a6508; border-left: 3px solid var(--vp-warning); }
.pf-alarm b { font-variant-numeric: tabular-nums; }

.pf-figs {
  margin-top: auto; border-top: 1px solid var(--vp-card-border);
  background: #fafbfc; padding: .65rem 1rem;
  display: grid; grid-template-columns: 1fr 1fr 1fr; gap: .5rem;
}
.pf-figs .k {
  display: block; font-size: .64rem; text-transform: uppercase;
  letter-spacing: .5px; color: var(--vp-text-muted);
}
.pf-figs .v { display: block; font-size: .95rem; font-weight: 600; line-height: 1.3; }
.pf-figs .sub { display: block; font-size: .7rem; color: var(--vp-text-muted); line-height: 1.3; }
.pf-figs .v.is-warn { color: var(--vp-danger); }

.pf-books {
  margin-top: 1.25rem; background: #fff; border: 1px solid var(--vp-card-border);
  border-radius: 10px; border-left: 4px solid var(--vp-navy);
  padding: .9rem 1rem; display: flex; align-items: center; gap: 1rem;
  text-decoration: none; color: #1f2937;
}
.pf-books:hover { background: #f7f9f8; color: #1f2937; }
.pf-books-name { font-weight: 600; }
.pf-tag {
  font-size: .66rem; text-transform: uppercase; letter-spacing: .5px;
  background: var(--vp-navy); color: #fff; padding: .12rem .45rem; border-radius: 4px;
}

@media screen and (max-width: 575.98px) {
  .pf-figs { grid-template-columns: 1fr 1fr; }
  .pf-metrics { margin-left: 0; gap: 1.25rem; }
}


/* ---------------------------------------------------------------- board access

   A homeowner who also serves on the board signs in to their OWN portal — their lot,
   their dues, their violations. The board's records live behind one link, and if that
   link is not obvious the person concludes the software simply doesn't have them.

   It used to be rgba(255,255,255,0.12) on the dark green sidebar: about a 1.2:1 contrast
   against its own background, which is to say invisible unless you already knew it was
   there. Solid light green instead — the same accent the app uses for its "do this"
   buttons — so it reads as the one action in a column of navigation. */
.btn-vp-board {
  background: var(--vp-gold);
  border: 1px solid var(--vp-gold);
  color: var(--vp-green-text);
  font-weight: 600;
  white-space: normal;
  text-align: left;
  line-height: 1.25;
}
.btn-vp-board:hover,
.btn-vp-board:focus {
  background: var(--vp-gold-light);
  border-color: #fff;
  color: var(--vp-green-text);
}

/* Shown once, on the portal dashboard, which is where a board member lands after signing
   in. Deliberately NOT on every page: a banner that follows you around stops being read
   by the second day, and this one only has to work at the moment of arrival. */
.vp-board-banner {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  padding: 0.7rem 1.1rem;
  background: var(--vp-gold-light);
  border: 1px solid var(--vp-navy);
  border-left-width: 5px;
  border-radius: 6px;
  color: var(--vp-green-text);
}
.vp-board-banner-title { font-weight: 700; }
.vp-board-banner-sub { opacity: 0.85; font-size: 0.88rem; }
.vp-board-banner-btn {
  background: var(--vp-navy);
  border: 1px solid var(--vp-navy);
  color: #fff;
  font-weight: 600;
  white-space: nowrap;
}
.vp-board-banner-btn:hover { background: var(--vp-navy-light); border-color: var(--vp-navy-light); color: #fff; }

/* ---------------------------------------------------------------- how-to guides
   The walkthrough cards on Ask-Knox's sibling page. A card that is a link needs to
   look like one on hover; without this it reads as a dead panel and people don't
   click it. */
.vp-help-card {
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.vp-help-card:hover {
  border-color: var(--vp-green-border);
  box-shadow: 0 2px 10px rgba(27, 67, 50, 0.08);
}
/* Numbered steps read better with room around the number and the text not wrapping
   underneath it. */
.vp-help-steps {
  padding-left: 1.35rem;
  line-height: 1.55;
}
.vp-help-steps > li::marker {
  color: var(--vp-navy-light);
  font-weight: 600;
}

/* ------------------------------------------------------------------ screen-only notes
   A note written for whoever is RUNNING the app, not for whoever is handed the paper.

   Several report pages carry two very different kinds of small print. One kind belongs on
   the report: a CD matured, this figure is over budget, this disclosure is required by
   statute. The other kind is the software talking to its operator — "code these on the
   Bank Register", "set that under Treasury → Reserves", "nothing on this page is posted
   anywhere". That second kind is useful on screen and embarrassing in a board packet: it
   tells a director about a screen they will never see, and it reads as the report
   apologising for itself.

   So it is marked, not deleted. `.screen-note` keeps the note where staff can read it and
   takes it off the page the moment anyone prints, and the tag above it says so, so nobody
   has to print a test page to find out which notes survive.

   `!important` on the print rule because these notes sit inside report pages that carry
   their own `@media print` blocks; without it, a later rule in the page's own print
   section could put one back on paper. */
.screen-note {
  border-left: 2px solid var(--vp-gold, #c9a227);
  padding-left: 0.6rem;
}
.screen-note::before {
  /* Literal em dash rather than \2014: a CSS hex escape swallows one following space as
     its terminator, so "\2014 not" renders as "—not". */
  content: "Screen only — not printed";
  display: block;
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--vp-text-muted, #8a8f98);
  margin-bottom: 0.2rem;
}
/* When a whole section is staff-only — a "Reserve fund funding statement" heading with
   nothing under it but "go and fill this in" — wrap the heading and its body together in
   one `.screen-note` so the heading goes too. A heading printed over an absence is worse
   than either. */
@media print {
  .screen-note { display: none !important; }
}
