:root {
  --ink: #1b1f23;
  --ink-soft: #565f68;
  --bg: #fbfaf8;
  --bg-alt: #f1ede6;
  --card: #ffffff;
  --brand: #b3792c;
  --brand-dark: #8c5c1e;
  --brand-soft: #f4e6d2;
  --line: #e6e1d8;
  --whatsapp: #25d366;
  --radius: 14px;
  --shadow: 0 8px 24px rgba(27, 31, 35, 0.08);
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color: var(--ink);
  background: var(--bg);
  line-height: 1.55;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
/* Sticky footer: on short pages (e.g. login.php) the footer sticks to the
   bottom of the viewport instead of trailing right after the content.
   Fixed-position elements (.scene, .whatsapp-float, #photo-lightbox) are
   unaffected since they're taken out of normal flow. */
.site-footer { margin-top: auto; }

.container {
  max-width: 1080px;
  margin: 0 auto;
  padding: 0 24px;
}

h1, h2, h3 { line-height: 1.2; margin: 0 0 12px; font-weight: 700; }
h2 { font-size: clamp(1.5rem, 2.5vw, 2.1rem); }
p { margin: 0 0 12px; color: var(--ink-soft); }

.section { padding: 64px 0; }
.section.alt { background: var(--bg-alt); }
.section-sub { max-width: 560px; margin-bottom: 32px; }

/* A full page section (not a .detail-card) that's collapsed by
   default — same ▾ chevron-rotate language as .detail-card--collapsible,
   adapted for an <h2>-level heading instead of a card title. Only the
   <summary> (heading) shows when collapsed; everything else — the
   subtitle and the actual content — lives in the body and hides. */
.section-collapsible > summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 10px;
}
.section-collapsible > summary h2 { margin-bottom: 0; }
.section-collapsible > summary::-webkit-details-marker { display: none; }
.section-collapsible > summary::after {
  content: '▾';
  color: var(--ink-soft);
  font-size: 1.1rem;
  font-weight: 400;
  transition: transform 0.15s ease;
  flex-shrink: 0;
}
.section-collapsible[open] > summary::after { transform: rotate(180deg); }
.section-collapsible > summary + * { margin-top: 24px; }

/* Login chooser — full-bleed dimmed photo backdrop behind a floating card.
   `flex: 1` (not a fixed height) lets it fill whatever space is left
   between the sticky header and footer, on any viewport. */
.auth-bg {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 48px 24px;
  background: linear-gradient(rgba(10, 12, 16, 0.6), rgba(10, 12, 16, 0.68)),
    url('../images/backgrounds/login-hallway.jpg') center/cover no-repeat;
}
.auth-card {
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35);
  padding: 36px 32px;
  width: 100%;
  max-width: 400px;
}
.auth-card h1 { margin-bottom: 6px; }
.auth-card .section-sub { margin-bottom: 24px; }

/* Header */
.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  background: rgba(251, 250, 248, 0.9);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}
.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-top: 14px;
  padding-bottom: 14px;
}
.logo {
  font-weight: 800;
  font-size: 1.1rem;
  color: var(--ink);
  text-decoration: none;
}
.logo span { color: var(--brand); }
/* Minimal header logo for utility/share-link pages (maintenance-status.php,
   document-upload.php) — the actual monogram image + "Bin Mahmoud" only,
   no "Rooms" wordmark or marketing copy, since these pages are for an
   outside party doing one specific task, not browsing listings. */
/* line-height: 1 — without it, the text's line-box inherits body's
   1.55 line-height, which is taller than the 28px logo image and (per
   normal font metrics) has more empty space below the glyphs than
   above; flexbox centers the two BOXES correctly, but the text still
   visually reads as sitting lower than the image. */
.logo--mark { display: inline-flex; align-items: center; gap: 8px; line-height: 1; }
.logo--mark img { border-radius: 6px; display: block; }
.quick-contact { display: flex; gap: 10px; flex-wrap: wrap; justify-content: flex-end; }
.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 600;
  text-decoration: none;
  border: 1px solid var(--line);
  color: var(--ink);
}
.pill-whatsapp { background: #e9fbf0; border-color: #bdeccb; color: #12793f; }
.pill-email:hover { background: var(--bg-alt); }
.ui-theme-toggle { background: #fff; cursor: pointer; font-family: inherit; }
.ui-theme-toggle:hover { background: var(--bg-alt); }

/* Hero */
.hero {
  padding: 72px 0 56px;
  background: linear-gradient(180deg, var(--brand-soft) 0%, var(--bg) 100%);
}
.eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--brand-dark);
  margin-bottom: 10px;
}
.hero h1 { font-size: clamp(2rem, 4.5vw, 3rem); max-width: 720px; }
.hero-sub { max-width: 560px; font-size: 1.05rem; }
.hero-note {
  max-width: 560px;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--brand-dark);
  background: var(--brand-soft);
  display: inline-block;
  padding: 8px 14px;
  border-radius: 999px;
  margin-bottom: 8px;
}
.hero-cta { display: flex; gap: 14px; flex-wrap: wrap; margin: 24px 0 40px; }

.btn {
  display: inline-block;
  padding: 13px 26px;
  border-radius: 10px;
  font-weight: 700;
  text-decoration: none;
  font-size: 0.95rem;
  cursor: pointer;
  border: 1px solid transparent;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.btn:hover { transform: translateY(-1px); }
.btn-primary { background: var(--brand); color: #fff; box-shadow: 0 6px 18px rgba(179, 121, 44, 0.35); }
.btn-primary:hover { background: var(--brand-dark); }
.btn-ghost { background: transparent; border-color: var(--ink); color: var(--ink); }
.btn-whatsapp { background: var(--whatsapp); color: #fff; box-shadow: 0 6px 18px rgba(37, 211, 102, 0.35); display: inline-flex; align-items: center; justify-content: center; gap: 8px; }
.btn-whatsapp:hover { background: #1fb855; }
.btn-block { width: 100%; text-align: center; }

/* Stat tiles used on the tenant welcome page (Room / Rent / Due Day) */
.hero-facts {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  max-width: 520px;
  padding: 0;
  margin: 0;
}
.hero-facts li {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px 8px;
  text-align: center;
}
.hero-facts strong { display: block; font-size: 1.3rem; color: var(--brand-dark); }
.hero-facts span { font-size: 0.75rem; color: var(--ink-soft); }

/* Unified stat strip used on the main site's hero (Rooms / Price / Open to All) */
.hero-stats {
  display: flex;
  align-items: center;
  max-width: 660px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 6px;
  box-shadow: var(--shadow);
}
.hero-stat {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1;
  min-width: 0;
  padding: 6px 14px;
}
.hero-stat__icon { font-size: 1.35rem; flex-shrink: 0; line-height: 1; }
.hero-stat strong {
  display: block;
  font-size: 0.98rem;
  color: var(--ink);
  line-height: 1.25;
  white-space: nowrap;
}
.hero-stat span { font-size: 0.7rem; color: var(--ink-soft); white-space: nowrap; }
.hero-stat-divider { width: 1px; height: 34px; background: var(--line); flex-shrink: 0; }

@media (max-width: 640px) {
  .hero-stats { flex-direction: column; border-radius: var(--radius); align-items: stretch; padding: 4px; }
  .hero-stat { width: 100%; }
  .hero-stat-divider { width: auto; height: 1px; margin: 0 14px; }
}

/* "At a Glance" quick-status strip on welcome.php — clickable cards
   jumping straight to whichever section needs attention, instead of
   scrolling through every section to find out. */
.quick-status {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px;
  max-width: 660px;
  margin-top: 14px;
}
.quick-status__item {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px 14px;
  text-decoration: none;
  color: inherit;
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.quick-status__item:hover { transform: translateY(-2px); box-shadow: var(--shadow); border-color: var(--brand); }
.quick-status__icon { font-size: 1.4rem; flex-shrink: 0; line-height: 1; }
.quick-status__label { font-size: 0.72rem; color: var(--ink-soft); display: block; }
.quick-status__value { font-size: 0.95rem; font-weight: 700; color: var(--ink); display: block; line-height: 1.3; }
.quick-status__item--attention { border-color: #f0c2c2; background: #fdf5f5; }
.quick-status__item--attention .quick-status__value { color: #b3261e; }
.quick-status__item--good .quick-status__value { color: #1e7a3d; }

@media (max-width: 640px) {
  .quick-status { grid-template-columns: 1fr 1fr; }
}

/* Netflix household-sharing card on welcome.php — a subtle brand-red
   accent (not a full takeover) since it's a promo/perk card, not a
   utility one like WiFi/Rent. */
.netflix-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-left: 3px solid #E50914;
  border-radius: var(--radius);
  padding: 20px;
  box-shadow: var(--shadow);
  max-width: 480px;
}
.netflix-card--active { border-left-color: #1e7a3d; }
.netflix-card__row { display: flex; justify-content: space-between; align-items: flex-end; gap: 16px; flex-wrap: wrap; }
.netflix-card__plan { margin: 0; font-size: 0.85rem; color: var(--ink-soft); }
.netflix-card__price { margin: 2px 0 0; font-size: 1.4rem; font-weight: 700; color: var(--ink); }
.netflix-card__price span { font-size: 0.75rem; font-weight: 400; color: var(--ink-soft); }
.netflix-card__slots { text-align: right; }
.netflix-card__slots-bar { width: 120px; height: 6px; border-radius: 999px; background: var(--line); overflow: hidden; margin-left: auto; }
.netflix-card__slots-fill { height: 100%; background: #E50914; border-radius: 999px; }
.netflix-card__slots span { display: block; margin-top: 4px; font-size: 0.72rem; color: var(--ink-soft); }

/* Gallery — horizontal scroll-snap row, same pattern as the community
   listings carousel, so users swipe/scroll through the photos. */
.gallery-grid {
  display: flex;
  gap: 14px;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  padding-bottom: 10px;
  -webkit-overflow-scrolling: touch;
}
.gallery-photo {
  position: relative;
  flex: 0 0 240px;
  height: 200px;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--card);
  scroll-snap-align: start;
}
.gallery-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.gallery-photo__caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 20px 14px 10px;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.65), rgba(0, 0, 0, 0));
  color: #fff;
  font-size: 0.85rem;
  font-weight: 700;
}

/* Rooms */
.room-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
}
.room-card {
  position: relative;
  height: 230px;
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow);
}
.room-card img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  z-index: 0;
  cursor: zoom-in;
}
/* Taken rooms: blur + desaturate the photo only, so available rooms stand
   out at a glance — the badge/caption stay fully crisp and legible. */
.room-card--taken img { filter: blur(5px) grayscale(0.4) brightness(0.85); }

/* Status badge floats independently at the top of the photo */
.room-card__badge {
  position: absolute;
  top: 12px;
  left: 12px;
  z-index: 2;
}

/* Caption: title/details directly on the photo, no heavy panel — just a
   short, light gradient plus text-shadow for legibility on any photo. */
.room-card__body {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  padding: 20px 14px 10px;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);
  pointer-events: none;
}
.room-card h3 {
  font-size: 1rem;
  margin: 0 0 2px;
  color: #fff;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.7);
}
.room-card p {
  margin: 0;
  font-size: 0.78rem;
  color: rgba(255, 255, 255, 0.92);
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.65);
}
/* Full-screen photo lightbox */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 500;
  background: rgba(10, 12, 16, 0.92);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px;
  cursor: zoom-out;
}
.lightbox[hidden] { display: none; }
.lightbox__img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: 8px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
  cursor: default;
}
.lightbox__close {
  position: absolute;
  top: 18px;
  right: 22px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.18);
  color: #fff;
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1;
}
.lightbox__close:hover { background: rgba(255, 255, 255, 0.3); }

/* Prev/next arrows — only shown when the tapped photo belongs to a
   multi-photo gallery (see js/lightbox.js's grouping logic); a
   single-photo lightbox never renders these at all. Swipe left/right
   does the same thing on touch devices; these are the visible,
   clickable fallback for desktop/mouse use. */
.lightbox__prev,
.lightbox__next {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.18);
  color: #fff;
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1;
}
.lightbox__prev:hover,
.lightbox__next:hover { background: rgba(255, 255, 255, 0.3); }
.lightbox__prev { left: 14px; }
.lightbox__next { right: 14px; }
@media (max-width: 640px) {
  .lightbox__prev, .lightbox__next { width: 38px; height: 38px; font-size: 1.3rem; }
  .lightbox__prev { left: 8px; }
  .lightbox__next { right: 8px; }
}

/* Doc variant of the lightbox (rental agreement PDF) — a rectangular
   iframe instead of a contained image, and no zoom-out cursor since the
   viewer needs normal scroll/click interaction inside it. */
.lightbox--doc { cursor: default; }
.lightbox__doc {
  width: 100%;
  max-width: 900px;
  height: 100%;
  max-height: 100%;
  border: none;
  border-radius: 8px;
  background: #fff;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}
@media (max-width: 640px) {
  .lightbox--doc { padding: 16px; }
}

.share-btn {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: #fff;
  color: var(--ink-soft);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
  transition: background 0.15s ease, color 0.15s ease;
}
.share-btn:hover { background: var(--brand-soft); color: var(--brand-dark); }
.share-btn svg { width: 15px; height: 15px; }

.share-btn--hero {
  position: static;
  width: 46px;
  height: 46px;
  flex-shrink: 0;
}
.share-btn--hero svg { width: 18px; height: 18px; }

.share-toast {
  position: fixed;
  left: 50%;
  bottom: 28px;
  transform: translate(-50%, 12px);
  background: var(--ink);
  color: #fff;
  padding: 10px 18px;
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 600;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
  z-index: 200;
}
.share-toast.is-visible { opacity: 1; transform: translate(-50%, 0); }

@keyframes card-highlight-pulse {
  0%, 100% { box-shadow: var(--shadow); }
  30% { box-shadow: 0 0 0 4px var(--brand), var(--shadow-float, var(--shadow)); }
}
.is-highlighted { animation: card-highlight-pulse 1.3s ease-in-out 2; }

.badge {
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #12793f;
  background: #e9fbf0;
  border: 1px solid #bdeccb;
  border-radius: 999px;
  padding: 3px 10px;
}
.badge--taken { color: #b3261e; background: #fdecea; border-color: #f5c6cb; }
.badge--reserved { color: #8c5c1e; background: #fff3e0; border-color: #f0d9b5; }

/* Which month a rent payment counts toward — see
   rent_payment_month_tags_for_tenant() in php/rent_helpers.php. A
   lump-sum payment can carry more than one of these. */
.rent-tag {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 0.7rem;
  font-weight: 700;
  color: #7a5416;
  background: #f6efe2;
  border: 1px solid #ecdfc4;
  border-radius: 999px;
  padding: 2px 9px 2px 7px;
  margin: 0 4px 4px 0;
}

/* Details */
.details-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px;
  align-items: start;
}
.detail-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 20px;
  box-shadow: var(--shadow);
  /* A long unbroken string (an email, a token) can only wrap at a
     browser's default break points (spaces/hyphens) — without this, one
     could stretch the card past the viewport on a narrow phone instead
     of wrapping mid-word. */
  overflow-wrap: break-word;
}
.detail-card h3 { font-size: 0.95rem; color: var(--brand-dark); margin-bottom: 6px; }
.detail-card p { margin: 0; font-size: 0.95rem; }

/* Pending-action badge — same warning-amber treatment already used
   for "Invited"/"Awaiting" badges elsewhere in this project, now a
   reusable class instead of a one-off inline style. */
.badge--pending { background: #fff3e0; border-color: #f0d9b5; color: #8c5c1e; }

/* Collapsible variant of .detail-card (a <details> element) — for
   sections that are optional or already resolved, so they don't
   compete for attention with the ones that actually need input.
   <summary> carries the same title styling .detail-card h3 normally
   would, plus a rotating disclosure arrow. */
.detail-card--collapsible { padding: 0; }
.detail-card--collapsible > summary {
  list-style: none;
  cursor: pointer;
  padding: 20px;
  font-size: 0.95rem;
  color: var(--brand-dark);
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.detail-card--collapsible > summary::-webkit-details-marker { display: none; }
.detail-card--collapsible > summary::after {
  content: '▾';
  color: var(--ink-soft);
  font-weight: 400;
  transition: transform 0.15s ease;
  flex-shrink: 0;
}
.detail-card--collapsible[open] > summary::after { transform: rotate(180deg); }
.detail-card--collapsible > summary .detail-card__summary-note {
  font-size: 0.78rem;
  font-weight: 500;
  color: var(--ink-soft);
  margin-left: auto;
  margin-right: 4px;
}
.detail-card--collapsible > .detail-card--collapsible__body { padding: 0 20px 20px; overflow-x: hidden; }
.detail-card--collapsible > .detail-card--collapsible__body p { margin: 0; font-size: 0.95rem; }

/* Highlight for a card that needs the tenant's input or attention —
   same amber family as .badge--pending, applied to the whole card
   (not just its badge) so it stands out even collapsed, or even with
   no badge at all (e.g. the gas "Next Up" card just changes color
   when it's this tenant's own turn). Works on both a plain
   .detail-card and the collapsible .detail-card--collapsible variant.
   For a collapsible card, the PHP only ever renders this class while
   its condition is unresolved (e.g. no signature yet) — once
   resolved, that card is swapped for its plain resolved-tier
   equivalent, so this never needs to be toggled off. */
.detail-card--pending {
  background: #fffaf0;
  border-color: #f0d9b5;
}
.detail-card--collapsible.detail-card--pending > summary {
  color: #8c5c1e;
}

.copy-btn--inline {
  display: inline-flex;
  align-items: center;
  font-size: 0.7rem;
  font-weight: 700;
  padding: 2px 9px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: #fff;
  color: var(--ink-soft);
  cursor: pointer;
  text-decoration: none;
  margin-left: 6px;
  vertical-align: middle;
  transition: background 0.15s ease, color 0.15s ease;
}
.copy-btn--inline:hover { background: var(--bg-alt); color: var(--brand-dark); }

.payment-qr {
  display: block;
  width: 100%;
  max-width: 200px;
  height: auto;
  margin: 12px auto 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: #fff;
  padding: 8px;
}

/* Payment-method toggle (CBQ / Fawran) — swaps which QR image is shown
   instead of stacking two, so adding a second payment method costs no
   extra vertical space. See js/welcome.js for the swap logic. */
.payment-method-toggle {
  display: flex;
  width: fit-content;
  gap: 4px;
  background: var(--bg-alt);
  border-radius: 999px;
  padding: 3px;
  margin: 12px auto 0;
}
.payment-method-toggle__btn {
  border: none;
  background: transparent;
  padding: 5px 16px;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--ink-soft);
  cursor: pointer;
}
.payment-method-toggle__btn.is-active { background: var(--brand); color: #fff; }

.kv-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.kv-list li {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  font-size: 0.9rem;
  border-bottom: 1px dashed var(--line);
  padding-bottom: 6px;
}
.kv-list li:last-child { border-bottom: none; padding-bottom: 0; }
/* flex-shrink:0 on the label used to force it onto one line at its full
   natural width no matter how narrow the row got — fine for a short
   fixed label like "Amount Paid," but a long dynamic one (a tenant's
   full name) had nowhere to go but push the value straight off the
   card's edge. min-width:0 lets the label actually shrink and wrap
   instead of refusing to. */
.kv-list li > span { min-width: 0; overflow-wrap: break-word; }
.kv-list > li > span:first-child { color: var(--ink-soft); }
.kv-list strong { color: var(--ink); font-weight: 700; text-align: right; }
.kv-list .kv-value {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 6px;
  text-align: right;
}

/* Inline receipt expand (welcome.php Payment History) — a receipt
   viewable in-page from data already on the page (no extra request,
   no PDF/iframe), with a real PDF download still offered alongside
   for anyone who wants the file. Deliberately a plain text-link
   disclosure, not the bigger .detail-card--collapsible treatment,
   since this lives nested inside an already-a-card listing item. */
.receipt-inline { margin-top: 10px; }
.receipt-inline > summary {
  cursor: pointer;
  color: var(--brand-dark);
  font-weight: 600;
  font-size: 0.85rem;
  list-style: none;
}
.receipt-inline > summary::-webkit-details-marker { display: none; }
.receipt-inline > summary::before { content: '▸ '; }
.receipt-inline[open] > summary::before { content: '▾ '; }
.receipt-inline__body {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--line);
}

/* Click-to-play inline video (YouTube) — shows a thumbnail facade, only
   loads the actual iframe/player once tapped, so the page doesn't pull in
   YouTube's iframe for videos nobody plays. */
.video-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 14px;
}
.video-embed {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius);
  overflow: hidden;
  background: #000;
  cursor: pointer;
}
.video-embed img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  opacity: 0.82;
}
.video-embed__play {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.62);
  color: #fff;
  border: none;
  font-size: 1.3rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 0 0 3px;
}
.video-embed__label {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 8px 10px;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.72), rgba(0, 0, 0, 0));
  color: #fff;
  font-size: 0.78rem;
  font-weight: 700;
}
.video-embed iframe {
  width: 100%;
  height: 100%;
  border: none;
  display: block;
}

/* House rules — single column, since rules are full sentences of varying
   length; a multi-column grid (fine for short tags) made long and short
   rules wrap unevenly and left ragged blank space next to short ones. */
.rules-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  max-width: 720px;
}
.rules-list li {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 14px 0;
  border-bottom: 1px solid var(--line);
  font-size: 0.98rem;
  line-height: 1.55;
  color: var(--ink);
}
.rules-list li:last-child { border-bottom: none; }
.rules-list .rule-num {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--brand);
  color: #fff;
  font-size: 0.8rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 1px;
}

/* Highlights */
.highlights-section .coming-soon-badge { margin-bottom: 10px; }
.highlights-list {
  list-style: none;
  padding: 0;
  margin: 16px 0 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 14px 24px;
}
.highlights-list li {
  display: flex;
  align-items: center;
  gap: 12px;
  font-weight: 600;
  font-size: 1rem;
  color: var(--ink);
}
.highlights-list .check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: #e9fbf0;
  color: #12793f;
  font-weight: 700;
  flex-shrink: 0;
}

/* Map */
.map-embed {
  width: 100%;
  height: 420px;
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--bg-alt);
  position: relative;
  z-index: 1;
}
.amenity-marker span {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  font-size: 1.1rem;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35), 0 0 0 3px #fff;
}
.amenity-tooltip {
  background: var(--ink);
  color: #fff;
  border: none;
  border-radius: 6px;
  padding: 3px 8px;
  font-size: 0.72rem;
  font-weight: 700;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
}
.amenity-tooltip::before { border-top-color: var(--ink); }
.map-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 14px;
}
.google-maps-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--brand-dark);
  text-decoration: none;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 7px 14px;
  flex-shrink: 0;
  transition: background 0.15s ease;
}
.google-maps-link:hover { background: var(--brand-soft); }
.map-legend {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  padding: 0;
  margin: 0;
}
.map-legend li {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ink-soft);
}
.map-legend__dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  flex-shrink: 0;
}

/* Interested? + More Rooms, side by side */
.interest-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 48px;
  align-items: start;
}
.community-col .listing-grid { margin-top: 20px; }
@media (max-width: 900px) {
  .interest-grid { grid-template-columns: 1fr; gap: 40px; }
}

/* Form */
.interest-form {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 28px;
  max-width: 620px;
  box-shadow: var(--shadow);
}
.form-row { margin-bottom: 16px; }
.form-row.two-col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
.form-row.three-col {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  gap: 16px;
  align-items: center;
}
.form-row.four-col {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr 1fr;
  gap: 16px;
  align-items: center;
}
label { display: block; font-size: 0.85rem; font-weight: 700; margin-bottom: 6px; }
input, textarea, select {
  width: 100%;
  max-width: 100%;
  padding: 11px 13px;
  border-radius: 8px;
  border: 1px solid var(--line);
  font-size: 0.95rem;
  font-family: inherit;
  background: #fff;
}
/* iOS Safari's native date/time picker control can ignore width:100%
   and overflow its container by a few px (a long-standing WebKit
   quirk) — -webkit-appearance:none drops Safari's own native chrome
   for these so they're sized purely by our own CSS instead. */
input[type="date"], input[type="time"], input[type="datetime-local"] {
  -webkit-appearance: none;
  appearance: none;
}
input:focus, textarea:focus, select:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(179, 121, 44, 0.15);
}
.hp-field { position: absolute; left: -9999px; top: -9999px; }

.call-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 10px;
  cursor: pointer;
  user-select: none;
  animation: call-toggle-in 0.25s ease;
}
.call-toggle[hidden] { display: none; }
.call-toggle input[type="checkbox"] {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}
.call-toggle__track {
  flex-shrink: 0;
  width: 40px;
  height: 22px;
  border-radius: 999px;
  background: var(--line);
  position: relative;
  transition: background 0.2s ease;
}
.call-toggle__thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  transition: transform 0.2s ease;
}
.call-toggle input:checked + .call-toggle__track { background: var(--whatsapp); }
.call-toggle input:checked + .call-toggle__track .call-toggle__thumb { transform: translateX(18px); }
.call-toggle input:focus-visible + .call-toggle__track { outline: 2px solid var(--brand); outline-offset: 2px; }
.call-toggle__label { font-size: 0.85rem; font-weight: 600; color: var(--ink-soft); }

@keyframes call-toggle-in {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: translateY(0); }
}

.form-status { margin-top: 14px; font-size: 0.9rem; font-weight: 600; min-height: 1.2em; }
.form-status.success { color: #12793f; }
.form-status.error { color: #b3261e; }

/* House-rules agreement checkbox (welcome page) */
.rules-agree {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 4px 0 6px;
  cursor: pointer;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--ink);
}
.rules-agree input[type="checkbox"] {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  margin-top: 1px;
  accent-color: var(--brand);
}
.tenant-add-form input[readonly] { background: var(--bg-alt); }

/* Footer */
.site-footer {
  background: var(--ink);
  color: #d8d4cc;
  padding: 34px 0;
}
/* Only pages with the fixed-position .whatsapp-float bubble (index.html,
   post-room.html) need extra room below the footer so the bubble
   doesn't sit on top of the footer text — every other page using
   .site-footer (room.php, welcome.php, login.php, etc.) has no such
   bubble and was inheriting this as pure dead space. */
.site-footer--with-float { margin-bottom: 70px; }
.footer-inner {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
  font-size: 0.85rem;
}
/* The global `p { margin: 0 0 12px }` rule would otherwise stack an
   extra 12px under the location line on top of this flex gap — only
   noticeable once the row wraps (mobile), where it made the vertical
   rhythm between the 3 stacked lines uneven. Letting `gap` be the one
   source of spacing here keeps it consistent at every width. */
.footer-inner p:not(.footer-copyright) { margin: 0; }
.footer-links { display: flex; gap: 18px; align-items: center; }
.footer-links a { color: #fff; text-decoration: none; font-weight: 600; }
.footer-copyright { margin-top: 14px; padding-top: 14px; border-top: 1px solid rgba(255, 255, 255, 0.1); font-size: 0.75rem; opacity: 0.5; }
.footer-admin-link {
  opacity: 0.45;
  font-size: 0.78rem;
  font-weight: 500 !important;
  border-left: 1px solid rgba(255, 255, 255, 0.25);
  padding-left: 18px;
}
.footer-admin-link:hover { opacity: 0.85; }

/* WhatsApp float */
.whatsapp-float {
  position: fixed;
  bottom: 22px;
  right: 22px;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--whatsapp);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 8px 20px rgba(37, 211, 102, 0.45);
  z-index: 30;
  text-decoration: none;
}

/* Back button injected only inside the native app wrapper (see
   js/capacitor-nav.js) — bottom-left, mirroring .whatsapp-float's
   bottom-right, so the two never collide. z-index must stay above
   .lightbox (500) — it's the way out of a full-screen modal like the
   rental-agreement viewer, so it can never end up hidden beneath one. */
.capacitor-back-btn {
  position: fixed;
  bottom: 22px;
  left: 22px;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  z-index: 600;
  background: var(--ink);
  color: #fff;
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  line-height: 1;
  box-shadow: 0 8px 20px rgba(27, 31, 35, 0.35);
  z-index: 30;
  cursor: pointer;
  padding: 0;
}
.capacitor-back-btn:active { opacity: 0.85; }

@media (max-width: 720px) {
  /* Keep the fixed WhatsApp bubble from sitting on top of full-width
     submit buttons once they scroll into that corner of the viewport. */
  .interest-form button[type="submit"],
  #listing-form button[type="submit"] {
    width: calc(100% - 66px);
    margin-right: 66px;
  }
  .interest-form { padding-bottom: 44px; }

  .hero-facts { grid-template-columns: repeat(2, 1fr); }
  .form-row.two-col,
  .form-row.three-col,
  .form-row.four-col { grid-template-columns: 1fr; }
  .header-inner { flex-direction: column; gap: 10px; padding: 12px 0; }
  .quick-contact { justify-content: center; }
  .pill { padding: 7px 12px; font-size: 0.8rem; }
}

/* Community listings */
.community-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 8px;
}
/* Horizontal scroll-snap row — as more community listings come in over
   time, they extend sideways instead of growing the page downward. */
.listing-grid {
  display: flex;
  gap: 16px;
  margin-top: 24px;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scroll-padding-left: 4px;
  padding-bottom: 10px;
  -webkit-overflow-scrolling: touch;
}
.listing-grid .listing-card,
.listing-grid .skeleton-card {
  flex: 0 0 260px;
  scroll-snap-align: start;
}
.listing-grid .empty-listings { flex: 1 1 100%; }
.listing-card {
  position: relative;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow);
  display: flex;
  flex-direction: column;
}
.listing-card-body { padding: 16px; }
.listing-card h3 { font-size: 1rem; margin-bottom: 4px; }
.listing-card .listing-meta { font-size: 0.8rem; color: var(--ink-soft); margin-bottom: 8px; }
.listing-card .listing-rent { font-weight: 700; color: var(--brand-dark); margin-bottom: 8px; }
.listing-card .listing-desc { font-size: 0.88rem; margin-bottom: 0; }

/* Photo variant: title/type/rent overlaid on the photo like a caption
   (frosted-glass style, both themes); the free-form description stays in
   a normal panel below since community-submitted text is variable-length
   and would be unreadable overlaid on a photo. */
.listing-photo-wrap { position: relative; }
.listing-photo-wrap img {
  width: 100%;
  height: 180px;
  object-fit: cover;
  display: block;
}
.listing-card-caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 32px 14px 12px;
  background: linear-gradient(to top, rgba(10, 12, 16, 0.82) 0%, rgba(10, 12, 16, 0.5) 55%, rgba(10, 12, 16, 0) 100%);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.listing-card-caption h3 { color: #fff; margin-bottom: 2px; }
.listing-card-caption .listing-meta { color: rgba(255, 255, 255, 0.85); margin-bottom: 2px; }
.listing-card-caption .listing-rent { color: #fff; margin-bottom: 0; }

/* Skeleton "more coming" placeholders */
.skeleton-card {
  background: var(--card);
  border: 1px dashed #c9c2b4;
  border-radius: var(--radius);
  padding: 20px;
  min-height: 220px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 10px;
  color: #b7ae9e;
}
.skeleton-bar { background: #efe9df; border-radius: 6px; height: 12px; width: 70%; }
.skeleton-bar.short { width: 45%; }
.empty-listings {
  text-align: center;
  padding: 40px 20px;
  background: var(--card);
  border: 1px dashed #c9c2b4;
  border-radius: var(--radius);
}
.coming-soon-badge {
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--brand-dark);
  background: var(--brand-soft);
  border-radius: 999px;
  padding: 4px 12px;
  margin-bottom: 10px;
}

/* Admin */
.admin-wrap {
  /* body is a flex column (for the sticky footer); a flex item with
     auto side-margins (for centering) doesn't stretch to fill the
     cross axis by default, so without an explicit width it sizes to
     its content's shrink-to-fit width instead of the viewport. That's
     invisible on desktop but on narrow screens it lets a child grid's
     minmax() column floor (e.g. .details-grid's 220px tracks) force
     this wrapper wider than the viewport, causing horizontal overflow.
     An explicit width keeps it filling the viewport (up to max-width)
     like a normal block, regardless of that quirk — but flex items
     also have an implicit min-width:auto (floor = content's own
     min-content size), which still overrides an explicit width if a
     descendant's minmax() column floor is wider than the viewport, so
     min-width:0 removes that floor too. */
  width: 100%;
  min-width: 0;
  max-width: 420px;
  margin: 80px auto;
  padding: 0 20px;
}
.admin-wrap.wide { max-width: 1080px; margin: 40px auto; }
.admin-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 28px;
  box-shadow: var(--shadow);
  overflow-wrap: break-word;
}
.admin-card h1 { font-size: 1.3rem; }
.admin-header {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-bottom: 20px;
  /* Sticky so the nav / "← Back to X" link stays reachable while
     scrolling a long page (tenant cards, entry lists, etc.) instead of
     only being available at the very top — same pattern as the public
     site's .site-header. */
  position: sticky;
  top: 0;
  z-index: 20;
  background: rgba(251, 250, 248, 0.92);
  backdrop-filter: blur(8px);
  padding: 14px 0;
  border-bottom: 1px solid var(--line);
}
.admin-header h1 { margin-bottom: 0; }
/* On a narrow phone the header's title block + "← Back" button don't
   fit on one row (even with flex-wrap), so it wraps to two full rows
   and gets tall enough to visibly cover whatever card happens to
   scroll underneath it — sticky is doing exactly what it's supposed
   to, it's just that a stuck header this tall eats too much of a
   small screen and makes scrolled-past content look clipped/glitchy.
   Simplest fix: don't stick it on mobile at all — the in-page
   .admin-tabs pill nav already covers "jump anywhere" without needing
   an always-visible header, so losing that on a phone costs little. */
@media (max-width: 640px) {
  .admin-header { position: static; backdrop-filter: none; }
}
/* The persistent cross-page nav (Listings/Rooms/Tenants/.../Log Out) —
   wraps onto its own row(s) instead of overflowing the viewport, since
   at mobile widths there isn't room for the page title and 5 nav pills
   on one line. */
.admin-nav { display: flex; flex-wrap: wrap; gap: 10px; }
.admin-nav .btn { padding: 8px 14px; font-size: 0.85rem; white-space: nowrap; }
/* Global search — see admin_render_nav() in php/admin_nav_helpers.php,
   which renders this as its own pill, paired with (but separate from)
   the icon-nav pill inside a shared .admin-nav-row wrapper — mixing it
   directly into the same wrapping icon row made it read as just one
   more cramped icon among a dozen-plus others. .admin-nav-row is
   allowed to wrap the two pills onto separate lines at narrow widths,
   but .admin-search-bar itself never wraps internally — its input and
   button always stay on one line, at any width, which is the specific
   bug this replaced (the box and its button splitting onto two rows). */
.admin-nav-row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.admin-search-bar {
  position: relative;
  display: block;
  padding: 6px;
  border-radius: 999px;
  flex-shrink: 0;
}
.admin-search-bar input[type="search"] {
  width: 150px;
  min-width: 80px;
  height: 40px;
  padding: 0 32px 0 14px;
  border-radius: 999px;
  border: 1px solid var(--line);
  font-size: 0.82rem;
  background: rgba(255, 255, 255, 0.7);
  box-sizing: border-box;
}
/* Overlaid inside the input's right edge instead of sitting beside it
   as its own flex item — the input's own right padding above keeps
   typed text from running under it. */
.admin-search-bar button {
  position: absolute;
  top: 50%;
  right: 10px;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: none;
  border-radius: 999px;
  background: transparent;
  font-size: 0.9rem;
  cursor: pointer;
}
.admin-search-bar button:hover { background: rgba(255, 255, 255, 0.85); }
@media (max-width: 640px) {
  .admin-search-bar input[type="search"] { width: 110px; }
}

/* ============================================================
   LIQUID GLASS pill treatment — adapted from "glassy style nav"
   by Leon Lin (https://codepen.io/LeonLinBuild/pen/emdgRJj), MIT
   License (see docs/THIRD_PARTY_LICENSES.md). Applied to
   .admin-nav (every admin page's icon nav bar) and .hero-stats
   (the tenant welcome page's top info pill) — both are already
   rounded pill-capsule containers holding a row of icon items,
   the same shape the original pen's nav bar has. Only the frosted
   background/shadow/hover-glare visual language is ported — the
   pen's sliding "active tab" pill and its light/dark toggle button
   don't apply here (this nav is server-rendered multi-page links,
   not a client-side single-page tab switcher, and neither
   component has a matching dark-mode concept of its own). */
.liquid-glass {
  position: relative;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.55);
  backdrop-filter: blur(24px) saturate(180%);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  box-shadow:
    0 20px 40px -16px rgba(0, 0, 0, 0.16),
    0 4px 14px -6px rgba(0, 0, 0, 0.08),
    inset 0 1px 1px rgba(255, 255, 255, 0.7),
    inset 0 0 0 1px rgba(255, 255, 255, 0.45);
  transition: box-shadow 0.4s ease, background 0.4s ease;
}
/* The interactive light glint that follows the cursor — js/liquid-glass.js
   feeds --glass-x/--glass-y as the mouse moves; without JS (or before
   the first mousemove) it just centers, which still reads fine as a
   plain hover glow. */
.liquid-glass::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  opacity: 0;
  pointer-events: none;
  background: radial-gradient(circle 140px at var(--glass-x, 50%) var(--glass-y, 50%), rgba(255, 255, 255, 0.55), transparent 70%);
  mix-blend-mode: overlay;
  transition: opacity 0.3s ease;
  z-index: 1;
}
.liquid-glass:hover::before { opacity: 1; }

.admin-nav.liquid-glass {
  padding: 6px;
  border-radius: 999px;
  gap: 4px;
}
.admin-nav.liquid-glass .nav-icon-btn {
  border-color: transparent;
  border-radius: 999px;
  transition: transform 0.2s cubic-bezier(0.34, 1.2, 0.64, 1), background 0.25s ease;
}
.admin-nav.liquid-glass .nav-icon-btn:hover { background: rgba(255, 255, 255, 0.7); transform: translateY(-1px); }
.admin-nav.liquid-glass .nav-icon-btn:active { transform: scale(0.9); }
/* Current-page marker — a persistent tinted ring, not a hover-only
   fill, so it stays visibly different from the other ("inactive")
   icons without shifting position or size the way :active does. */
.admin-nav.liquid-glass .nav-icon-btn.is-current {
  background: rgba(179, 121, 44, 0.16);
  box-shadow: inset 0 0 0 2px var(--brand);
}
.admin-nav.liquid-glass .nav-icon-btn.is-current:hover { background: rgba(179, 121, 44, 0.24); }
@media (max-width: 640px) {
  .admin-nav.liquid-glass { border-radius: var(--radius); }
}
/* Icon-only nav — same links, just the emoji instead of emoji+label,
   so all 12 items fit in roughly a third of the space and stay on one
   row even at mobile widths. title="" carries the label as a tooltip
   (and for screen readers) instead of visible text. */
.nav-icon-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0 !important;
  font-size: 1.1rem;
}
.nav-badge {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 17px;
  height: 17px;
  padding: 0 4px;
  border-radius: 999px;
  background: #b3261e;
  color: #fff;
  font-size: 0.62rem;
  font-weight: 700;
  line-height: 17px;
  text-align: center;
}
.admin-tabs { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 20px; }
.admin-tabs a {
  padding: 8px 16px;
  border-radius: 8px;
  text-decoration: none;
  color: var(--ink-soft);
  font-weight: 600;
  font-size: 0.9rem;
  border: 1px solid var(--line);
}
.admin-tabs a.active { background: var(--brand); color: #fff; border-color: var(--brand); }
.admin-listing-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 16px;
  align-items: start;
}
.admin-listing-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px;
  box-shadow: var(--shadow);
  overflow-wrap: break-word;
}
.admin-thumb { width: 100%; height: 140px; object-fit: cover; border-radius: 8px; margin-bottom: 10px; }
/* Multiple photos per maintenance request/issue — a small grid of
   thumbnails, each opening a lightbox (.gallery-photo, paired with a
   page-local #...-lightbox — see admin/maintenance.php,
   maintenance-status.php, welcome.php, room.php). */
.maintenance-gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(90px, 1fr)); gap: 6px; margin-bottom: 10px; }
.maintenance-gallery .admin-thumb { height: 90px; margin-bottom: 0; }
.gallery-photo { cursor: zoom-in; }
.admin-listing-card h3 { font-size: 1rem; }
.admin-listing-card p { font-size: 0.85rem; margin: 0 0 6px; }
/* A card that navigates on click (see js/clickable-card.js) — same
   hover-lift language as .btn:hover, just more pronounced since a
   whole card lifting should read as a bigger target than a button. */
.admin-listing-card--clickable {
  cursor: pointer;
  transition: box-shadow 0.15s ease, transform 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
/* Made deliberately bold rather than subtle — a faint 1px border-color
   shift on a plain white card read as "no visible difference at all"
   in practice, so hovering combines a warm brand-tinted background, a
   clearly thicker-reading brand border, and a real lift+shadow rather
   than relying on any single cue alone. */
.admin-listing-card--clickable:hover {
  transform: translateY(-3px);
  box-shadow: 0 14px 32px rgba(179, 121, 44, 0.22), 0 4px 10px rgba(27, 31, 35, 0.1);
  border-color: var(--brand);
  background: #fff8ec;
}
/* Pressed feedback while actually clicking/tapping — previously the
   card only ever showed the :hover lift, so a tap on a touch device
   (which never sees a hover state at all) gave no visual response
   until the page had already navigated away. */
.admin-listing-card--clickable:active {
  transform: translateY(0) scale(0.98);
  box-shadow: 0 2px 8px rgba(27, 31, 35, 0.1);
  background: #f5e9d3;
  transition: box-shadow 0.08s ease, transform 0.08s ease, background 0.08s ease;
}
.admin-meta { color: #a39a8b; font-size: 0.75rem; }
/* A tenant's full payment list on admin/rent.php — every payment is
   shown (not just the last few), but capped to a fixed height with
   its own internal scroll so a tenant with 30 payments doesn't turn
   the whole card into a long page scroll. */
.payment-history-scroll {
  max-height: 220px;
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 8px 10px;
  margin-top: 4px;
}
.payment-history-scroll p:last-child { margin-bottom: 0; }
/* Small-print explainer for a card whose heading carries an icon —
   kept out of the card itself (see admin/analytics.php's Occupancy /
   Paid in Advance cards) so the card can just show its numbers,
   with the "what does this mean" text collected here instead. */
.admin-page-footnote {
  margin-top: 24px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  color: #a39a8b;
  font-size: 0.68rem;
  line-height: 1.6;
}
/* Attached bill/receipt/document filenames can run long (phone camera
   names, "Kahramaa_Electricity_Bill_July_2026.pdf") — truncate with an
   ellipsis instead of overflowing the card; `title` on the element
   carries the full name for hover/long-press. */
.attachment-link { display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }

/* Drag-and-drop file picker with a live pre-send preview — see
   document-upload.php. Click or drop swaps the "prompt" state for the
   "preview" state (thumbnail for images, an icon for PDFs) so the
   sender can confirm it's the right file before hitting Send. */
.dropzone {
  border: 2px dashed var(--line);
  border-radius: var(--radius);
  padding: 24px 16px;
  text-align: center;
  cursor: pointer;
  transition: border-color 0.15s, background-color 0.15s;
  background: var(--bg-alt);
}
.dropzone:hover, .dropzone:focus-visible { border-color: var(--brand); outline: none; }
.dropzone--active { border-color: var(--brand); background: var(--brand-soft); }
.dropzone--error { border-color: #b3261e; }
.dropzone__icon { font-size: 2rem; display: block; margin-bottom: 6px; }
.dropzone__prompt p { margin: 4px 0; }
.dropzone__browse { color: var(--brand-dark); font-weight: 700; text-decoration: underline; }
/* :not([hidden]) rather than a bare .dropzone__preview{display:flex} —
   otherwise this class's own display:flex would outrank the `hidden`
   attribute's UA display:none (author styles beat UA styles at equal
   specificity), showing the preview even while hidden. */
.dropzone__preview:not([hidden]) { display: flex; align-items: center; gap: 12px; text-align: left; }
.dropzone__thumb { width: 56px; height: 56px; object-fit: cover; border-radius: 8px; border: 1px solid var(--line); background: var(--card); flex-shrink: 0; }
.dropzone__file-icon:not([hidden]) { width: 56px; height: 56px; border-radius: 8px; background: var(--card); border: 1px solid var(--line); display: flex; align-items: center; justify-content: center; font-size: 1.6rem; flex-shrink: 0; }
.dropzone__filemeta { flex: 1; min-width: 0; }
.dropzone__filename { margin: 0; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dropzone__filesize { margin: 2px 0 0; }
.dropzone__remove { flex-shrink: 0; padding: 6px 12px !important; font-size: 0.8rem !important; }

.sent-files-list { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.sent-files-list li { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border: 1px solid var(--line); border-radius: 10px; background: var(--card); }
.sent-files-list .file-icon { font-size: 1.2rem; flex-shrink: 0; }
.sent-files-list .file-info { flex: 1; min-width: 0; }
.sent-files-list .file-name { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.88rem; font-weight: 600; }
.sent-files-list .file-meta { font-size: 0.75rem; color: #a39a8b; }
.sent-files-list a.btn { padding: 6px 12px; font-size: 0.78rem; flex-shrink: 0; }

/* Small, tasteful entrance/attention animations — opt-in via class so
   they don't retroactively affect the many existing .admin-card /
   .form-status instances elsewhere in the app. */
@keyframes fade-in-up { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: translateY(0); } }
.fade-in-up { animation: fade-in-up 0.45s ease-out both; }
.fade-in-up--delay { animation-delay: 0.1s; }

@keyframes pop-in { from { opacity: 0; transform: scale(0.94); } to { opacity: 1; transform: scale(1); } }
.pop-in { animation: pop-in 0.25s ease-out; }

@media (prefers-reduced-motion: reduce) {
  .fade-in-up, .pop-in { animation: none !important; }
}
.admin-actions { display: flex; gap: 10px; margin-top: 12px; flex-wrap: wrap; }
.admin-actions > a,
.admin-actions > form { flex: 1 1 auto; min-width: 110px; }
/* `.admin-actions > a` IS one of the flex items above — giving it its own
   width:100% here (rather than reusing `.admin-actions .btn`, which also
   matches it) would make it claim the full row as its flex-basis and
   never pair up with a sibling on the same line. `<form>` doesn't have
   this problem since the .btn is a child of the form, not the flex item
   itself, so width:100% there just fills its own flex-sized slot. */
.admin-actions > a { padding: 9px 14px; font-size: 0.85rem; text-align: center; }
.admin-actions > form > .btn { width: 100%; padding: 9px; font-size: 0.85rem; }

/* Tap-to-reveal — hides sensitive figures (rent, balance) behind a blur
   until tapped, so nothing shows plainly if someone glances at a
   tenant's phone. Re-blurs itself after a few seconds (see welcome.js),
   the same way OTP codes are often shown. */
.blur-reveal {
  position: relative;
  display: inline-block;
  cursor: pointer;
}
.blur-reveal__value {
  filter: blur(6px);
  transition: filter 0.15s ease;
  user-select: none;
}
.blur-reveal.is-revealed .blur-reveal__value { filter: none; }
.blur-reveal__hint {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.65rem;
  font-weight: 700;
  color: var(--ink-soft);
  background: rgba(255, 255, 255, 0.4);
  border-radius: 6px;
  white-space: nowrap;
  pointer-events: none;
}
.blur-reveal.is-revealed .blur-reveal__hint { display: none; }

/* Duplicate-check confirmation popup (js/duplicate-check.js) — shared
   by the Expenses, Other Balances, and Appliances "Add" forms. */
.dup-check-modal {
  position: fixed;
  inset: 0;
  background: rgba(27, 31, 35, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  z-index: 500;
}
.dup-check-modal[hidden] { display: none; }
.dup-check-modal__box {
  background: #fff;
  border-radius: 14px;
  padding: 20px;
  max-width: 420px;
  width: 100%;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.25);
}
.dup-check-modal__title { margin: 0 0 8px; font-weight: 700; font-size: 1rem; color: var(--ink); }
.dup-check-modal__existing { margin: 0 0 16px; font-size: 0.9rem; color: var(--ink-soft); }
.dup-check-modal__actions { display: flex; flex-wrap: wrap; gap: 8px; }
