/* The app shell: sidebar on desktop, slide-in drawer on mobile. Visual language carried
   over from the IONOS site's header.php so the transition doesn't feel like a new tool. */

body { display: flex; min-height: 100vh; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }

/* Revenue estimates are provenance, not performance status. Keep them visibly distinct even
   in the owner theme, which deliberately neutralizes ordinary warning colors. */
.estimated-value, .owner-view .estimated-value { color: #b45309; font-weight: 700; }
.estimated-value sup { font-size: .72em; margin-left: 1px; }
.estimate-note, .owner-view .estimate-note { color: #92400e; }

.sidebar {
  width: 220px; background: var(--navy); min-height: 100vh; display: flex; flex-direction: column;
  flex-shrink: 0; position: fixed; top: 0; left: 0; bottom: 0; z-index: 100;
}
.sidebar-logo { padding: 20px 18px 16px; border-bottom: 1px solid rgba(255,255,255,.08); }
.sidebar-logo img { width: 160px; height: auto; display: block; }
.sidebar-logo .app-name { font-size: 11px; font-weight: 600; color: rgba(255,255,255,.4); margin-top: 8px; letter-spacing: .3px; }
.sidebar-nav { padding: 14px 10px; flex: 1; overflow-y: auto; }
.nav-label { font-size: 10px; font-weight: 700; color: rgba(255,255,255,.25); text-transform: uppercase; letter-spacing: .8px; padding: 8px 10px 4px; }
.sidebar-nav a, .sidebar-bottom a {
  display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-radius: 8px;
  color: rgba(255,255,255,.55); font-size: 13.5px; font-weight: 500; text-decoration: none;
  margin-bottom: 2px; transition: all .15s;
}
.sidebar-nav a svg, .sidebar-bottom a svg { width: 16px; height: 16px; flex-shrink: 0; }
.sidebar-nav a:hover, .sidebar-bottom a:hover { background: rgba(255,255,255,.07); color: rgba(255,255,255,.9); }
.sidebar-nav a.active { background: var(--cyan); color: #fff; }
.sidebar-bottom { padding: 14px 10px; border-top: 1px solid rgba(255,255,255,.08); }
.whoami { font-size: 12px; color: rgba(255,255,255,.35); padding: 4px 12px 8px; }

.main-content { margin-left: 220px; flex: 1; min-width: 0; }

.menu-toggle { display: none; }
.sidebar-scrim { display: none; }

/* Mobile: sidebar becomes a drawer behind a hamburger. */
@media (max-width: 800px) {
  .sidebar { transform: translateX(-100%); transition: transform .2s ease; }
  .sidebar.open { transform: translateX(0); }
  .main-content { margin-left: 0; }
  .menu-toggle {
    display: block; position: fixed; top: 10px; left: 10px; z-index: 120;
    background: var(--navy); color: #fff; border: 0; border-radius: 8px;
    font-size: 18px; padding: 8px 12px; cursor: pointer;
  }
  .sidebar-scrim.open {
    display: block; position: fixed; inset: 0; background: rgba(0,0,0,.4); z-index: 90;
  }
  /* Make room for the hamburger above the page title. */
  .corp-wrap { padding-top: 52px; }
}

/* ---------------------------------------------------------------------------
   PHONES: STICKY FIRST COLUMN + STICKY HEADER in table scrollers (2026-08-18)
   Every dashboard page wraps its big table in .table-scroll (the Corporate
   Summary's .table-wrap gets the same treatment in corporate.css). On a phone
   the table scrolls both ways, so the identity column (facility name) and the
   header row are pinned. `screen and` keeps this out of print, where a scroll
   box would clip the table. Sticky cells need their own opaque background;
   the colors re-stated here are the ones every page's local styles use
   (th #f4f7fa, hover #fafcff, .total-row #f8fafc).
   --------------------------------------------------------------------------- */
@media screen and (max-width: 768px) {
  .table-scroll { max-height: 75vh; overflow: auto; }
  .table-scroll thead th { position: sticky; top: 0; z-index: 2; }
  .table-scroll thead th:first-child,
  .table-scroll tbody td:first-child {
    position: sticky;
    left: 0;
    box-shadow: 2px 0 4px rgba(15, 23, 42, .06);
  }
  .table-scroll tbody td:first-child { z-index: 1; background: var(--card); }
  .table-scroll thead th:first-child { z-index: 3; }
  .table-scroll tbody tr:hover td:first-child { background: var(--soft); }
  .table-scroll tbody tr.total-row td:first-child { background: var(--soft); }
}

/* ---------------------------------------------------------------------------
   SEARCHABLE PICKER SHEET (phones) — see the data-searchable enhancement in
   shell.js. Hidden until .open; sits above the drawer chrome (z 120).
   --------------------------------------------------------------------------- */
#pick-sheet { display: none; }
#pick-sheet.open { display: block; }
#pick-sheet .pick-scrim {
  position: fixed; inset: 0; background: rgba(0, 0, 0, .4); z-index: 200;
}
#pick-sheet .pick-panel {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 201;
  background: var(--card); border-radius: 14px 14px 0 0;
  box-shadow: 0 -4px 24px rgba(15, 23, 42, .25);
  max-height: 75vh; display: flex; flex-direction: column;
  padding: 12px 12px calc(12px + env(safe-area-inset-bottom));
}
#pick-sheet .pick-search {
  /* 16px matters: smaller inputs make iOS Safari zoom the page on focus. */
  font-size: 16px; padding: 10px 12px; margin-bottom: 8px;
  border: 1px solid var(--rule); border-radius: 8px; outline-offset: 2px;
}
#pick-sheet .pick-list { overflow-y: auto; }
#pick-sheet .pick-item {
  display: block; width: 100%; text-align: left; cursor: pointer;
  background: none; border: 0; border-bottom: 1px solid var(--rule-2);
  font-size: 16px; color: var(--ink); padding: 13px 10px; /* ≥44px tap height */
}
#pick-sheet .pick-item:last-child { border-bottom: 0; }
/* display:block above would silently defeat the hidden attribute the filter sets. */
#pick-sheet .pick-item[hidden] { display: none; }
#pick-sheet .pick-item.current { font-weight: 700; color: var(--navy); background: var(--cyan-wash); }
#pick-sheet .pick-item:active { background: var(--cyan-wash); }

/* ---------------------------------------------------------------------------
   PHONES: TAP-SIZE AND ZOOM-PROOFING FLOOR (2026-08-18)
   44px minimum targets (Apple HIG; Material wants 48dp) and 16px text inside
   form fields — below 16px, iOS Safari zooms the whole page when a field
   focuses. The !important is deliberate: every page carries its own inline
   <style> block which loads after this sheet, and this is an accessibility
   floor those page styles shouldn't sink under, not a theme choice.
   Checkboxes/radios are excluded — a 44px-tall checkbox balloons; their row
   is the target instead.
   --------------------------------------------------------------------------- */
@media screen and (max-width: 768px) {
  .main-content select,
  .main-content textarea,
  .main-content input:not([type="checkbox"]):not([type="radio"]) {
    font-size: 16px !important;
    min-height: 44px;
  }
  .main-content button,
  .main-content .range-btn {
    min-height: 44px;
  }
  .menu-toggle { min-width: 44px; min-height: 44px; }
  /* Drawer links: 9px padding + 13.5px text ≈ 36px — stretch to a full target. */
  .sidebar-nav a, .sidebar-bottom a { min-height: 44px; }
}

/* ---------------------------------------------------------------------------
   BOTTOM TAB BAR (phones) — injected by shell.js; body gets .has-tabbar.
   Bottom-center is the thumb's natural zone; the drawer stays as the "More"
   surface. Desktop never sees it. Manager sessions have the bar removed in
   shell.js and fall back to the hamburger, so every .has-tabbar rule below is
   inert for them once /app/me resolves.
   --------------------------------------------------------------------------- */
.tabbar { display: none; }
@media screen and (max-width: 800px) {
  body.has-tabbar .tabbar {
    display: flex;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 110;
    background: var(--navy);
    /* Lift the icons and labels clear of the display's curved corners — the
       outer two tabs sit exactly where the radius bites, and 8px was not enough
       (Isaiah's phone, 2026-08-18). A real 22px floor, or the device's own inset
       when that is larger. max() rather than a sum, so a home-indicator phone in
       standalone mode doesn't end up with a 56px-deep gutter under the labels. */
    padding-bottom: max(22px, env(safe-area-inset-bottom));
    box-shadow: 0 -2px 12px rgba(0, 0, 0, .25);
  }
  .tabbar a, .tabbar .tabbar-more {
    flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px;
    padding: 11px 2px 6px; min-height: 58px; box-sizing: border-box;
    background: none; border: 0; cursor: pointer;
    color: rgba(255, 255, 255, .55); font-size: 11.5px; font-weight: 600;
    font-family: inherit; text-decoration: none; letter-spacing: .2px;
  }
  .tabbar svg { width: 24px; height: 24px; }
  .tabbar a.active { color: #fff; }
  .tabbar a.active svg { color: var(--cyan-bright); }
  /* The bar replaces the top-left hamburger (More opens the same drawer),
     so reclaim the padding that made room for it. */
  body.has-tabbar .menu-toggle { display: none; }
  body.has-tabbar .corp-wrap { padding-top: 16px; }
  /* Keep the last rows of content reachable above the fixed bar (~80px tall, more
     on a device reporting a bottom inset). Must stay ahead of the bar's height. */
  body.has-tabbar .main-content { padding-bottom: calc(96px + env(safe-area-inset-bottom)); }
}

/* ---------------------------------------------------------------------------
   LOADING SKELETON + OFFLINE NOTICE (2026-08-18)
   .loading-note.skeleton: the initial "Loading…" placeholder renders as a
   shimmer sketch of table rows instead of a word. Opt-in via .skeleton —
   the bare .loading-note class keeps carrying real text (errors, empty
   states) everywhere else.
   #offline-note: fixed strip shown when a response was served from the
   service worker's cache (see fetchJson in render-util.js) — the figures on
   screen are the last successfully loaded ones, never silently stale.
   --------------------------------------------------------------------------- */
.loading-note.skeleton {
  color: transparent !important;
  overflow: hidden;
  height: 200px;
  margin: 12px;
  border-radius: 6px;
  background:
    linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,255,255,.75) 50%, rgba(255,255,255,0) 100%) 0 0 / 200% 100% no-repeat,
    repeating-linear-gradient(#eef2f6 0 28px, #fff 28px 40px);
  animation: ps-shimmer 1.2s infinite;
}
@keyframes ps-shimmer {
  from { background-position: -100% 0, 0 0; }
  to   { background-position: 200% 0, 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .loading-note.skeleton { animation: none; }
}

#offline-note {
  position: fixed; left: 0; right: 0; top: 0; z-index: 300;
  background: #92400e; color: #fff;
  font-size: 13px; font-weight: 600; text-align: center;
  padding: 10px 14px;
  padding-top: calc(10px + env(safe-area-inset-top));
  box-shadow: 0 2px 8px rgba(0, 0, 0, .25);
}

/* ---------------------------------------------------------------------------
   CHART CHROME (2026-08-19) — shared by every page that draws a PS.charts
   figure (Property Performance had these in its inline styles first; the
   design overhaul put charts on Daily Numbers, Occupancy, Unit Mix and Rate
   Increases too, so the support styles live here once). Pages that already
   declare these locally simply agree with this copy.
   --------------------------------------------------------------------------- */
.legend { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 10px; }
.legend span { font-size: 12px; color: var(--ink-2); font-weight: 600; }
.legend i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 5px; vertical-align: -1px; }
.chart-svg { width: 100%; height: auto; display: block; }
#chart-tip { position: fixed; display: none; background: #0f172a; color: #fff; font-size: 12px;
  font-weight: 600; padding: 5px 10px; border-radius: 6px; pointer-events: none; z-index: 50;
  box-shadow: 0 2px 8px rgba(0,0,0,.25); white-space: nowrap; }

/* Ranked-bar chart rows (PS.charts.rankBars). */
.rankbars { padding: 4px 0 2px; }
.rankbar-legend { font-size: 11px; color: var(--ink-2); font-weight: 600; margin-bottom: 8px; }
.rankbar-goalmark { display: inline-block; width: 2px; height: 12px; background: var(--ink-2); vertical-align: -2px; margin-right: 5px; }
.rankbar-row { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; }
.rankbar-label { flex: 0 0 110px; text-align: right; font-size: 11.5px; font-weight: 600; color: var(--ink-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rankbar-track { flex: 1; position: relative; height: 13px; background: var(--card-2); border-radius: 3px; }
.rankbar-fill { display: block; height: 100%; border-radius: 3px; }
.rankbar-goal { position: absolute; top: -2px; bottom: -2px; width: 2px; background: var(--ink-2); opacity: .55; }
.rankbar-value { flex: 0 0 52px; font-size: 11.5px; font-weight: 700; font-variant-numeric: tabular-nums; text-align: right; }
@media screen and (max-width: 768px) {
  .rankbar-label { flex-basis: 84px; font-size: 10.5px; }
  .rankbar-value { flex-basis: 46px; font-size: 10.5px; }
}

/* Dumbbell chart rows (PS.charts.dumbbell). */
.dumbbells { padding: 4px 0 2px; }
.dumbbell-row { display: flex; align-items: center; gap: 10px; margin-bottom: 7px; }
.dumbbell-label { flex: 0 0 84px; text-align: right; font-size: 11.5px; font-weight: 600; color: var(--ink-2); white-space: nowrap; }
.dumbbell-track { flex: 1; position: relative; height: 14px; background: var(--card-2); border-radius: 3px; }
.dumbbell-join { position: absolute; top: 5px; height: 4px; background: var(--rule); border-radius: 2px; }
.dumbbell-dot { position: absolute; top: 2px; width: 10px; height: 10px; border-radius: 50%; margin-left: -5px; border: 1.5px solid var(--card); }
.dumbbell-dot.inplace { background: var(--cyan); z-index: 1; }
.dumbbell-dot.street { background: var(--ink-3); }
.dumbbell-value { flex: 0 0 46px; font-size: 11.5px; font-weight: 700; text-align: right; color: var(--ink-2); font-variant-numeric: tabular-nums; }

/* Age-band columns (PS.charts.bucketColumns). */
.bucketcols { display: flex; gap: 12px; align-items: stretch; padding: 6px 2px 0; }
.bucketcol { flex: 1; display: flex; flex-direction: column; align-items: center; min-width: 0; }
.bucketcol-count { font-size: 12px; font-weight: 700; color: var(--ink); margin-bottom: 4px; font-variant-numeric: tabular-nums; }
.bucketcol-barbox { height: 130px; width: 100%; max-width: 72px; display: flex; align-items: flex-end; }
.bucketcol-bar { display: flex; flex-direction: column; justify-content: flex-end; width: 100%; background: var(--cyan); border-radius: 4px 4px 0 0; overflow: hidden; }
.bucketcol-never { display: block; background: var(--cyan-ink); }
.bucketcol-label { font-size: 10.5px; font-weight: 700; color: var(--ink-2); margin-top: 6px; text-align: center; }
.bucketcol-sub { font-size: 10px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
@media screen and (max-width: 768px) {
  .bucketcols { gap: 6px; }
  .bucketcol-count { font-size: 10.5px; }
  .bucketcol-label { font-size: 9px; }
  .bucketcol-sub { font-size: 8.5px; }
}

/* Facility GROUPS (api/facility-groups.js) — the strip that says a combined view is a view.
   Styled here rather than per page because five pages show it and `.note` is defined inline,
   differently, on each of them. Its own hue (the categorical violet, not a status colour):
   picking a group is a choice, not a warning. */
.group-note-body {
  font-size: 12px;
  line-height: 1.55;
  color: var(--ink-2);
  background: var(--accent-violet-wash);
  border: 1px solid var(--accent-violet);
  border-radius: 8px;
  padding: 10px 14px;
  margin: 0 0 16px;
}
.group-note-body strong { color: var(--accent-violet-ink); }

/* Report view (2026-08-26) — the strip that says a filtered dashboard is filtered.
   Same reasoning as the group note above, same categorical violet: a chosen subset is a
   choice, not a warning — but it MUST be impossible to miss while it is on, because a
   filtered total screenshotted without this strip would read as the whole portfolio. */
.rv-strip {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font-size: 12.5px; line-height: 1.5; color: var(--ink-2);
  border-radius: 8px; padding: 9px 14px; margin: 0 0 14px;
}
.rv-strip.on { background: var(--accent-violet-wash); border: 1px solid var(--accent-violet); }
.rv-strip.on .rv-text b { color: var(--accent-violet-ink); }
.rv-strip.idle { background: var(--card-2, #f8fafc); border: 1px dashed #cbd5e1; }
.rv-strip .rv-text { flex: 1; min-width: 200px; }
.rv-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--accent-violet); flex-shrink: 0; }
.rv-btn {
  padding: 5px 12px; border-radius: 7px; border: 1px solid #cbd5e1; background: #fff;
  color: var(--ink-2); font-weight: 600; font-size: 12px; cursor: pointer;
}
.rv-btn:hover { background: #f8fafc; }
.rv-link { color: var(--accent-violet-ink); font-weight: 600; }
/* Never on paper — print stamps the .rh-meta headers instead (report-view.js). */
@media print { .rv-strip { display: none; } }
