/* ==================== App shell (owner/manager: sidebar + topbar) ==================== */
/* dvh, not vh: on iOS Safari the address bar collapsing changes vh mid-scroll
   and the layout jumps. */
body[data-role="staff"] { display: flex; min-height: 100dvh; }

.sidebar {
  width: var(--sidebar-w); flex-shrink: 0; background: hsl(var(--petrol-900)); color: hsl(0 0% 100% / 0.72);
  display: flex; flex-direction: column; position: sticky; top: 0; height: 100dvh; overflow: hidden;
  transition: width var(--dur-base) var(--ease-out);
}
.sidebar-brand {
  display: flex; align-items: center; gap: var(--space-2); padding: var(--space-4) var(--space-5); height: var(--topbar-h);
  font-weight: 800; font-size: 16px; color: white; letter-spacing: -0.02em;
}
.sidebar-brand .brand-mark, .mobile-topbar .brand-mark {
  width: 26px; height: 26px; border-radius: 8px; background: hsl(var(--accent)); flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 800;
  color: hsl(var(--accent-foreground));
}
.sidebar-nav { display: flex; flex-direction: column; gap: 2px; padding: var(--space-3); flex: 1; }
.sidebar-section-label {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em;
  color: hsl(0 0% 100% / 0.58); padding: var(--space-4) var(--space-3) var(--space-1);
}
.sidebar-link {
  display: flex; align-items: center; gap: var(--space-3); padding: 9px var(--space-3); border-radius: var(--radius-md);
  font-size: 13.5px; font-weight: 500; color: hsl(0 0% 100% / 0.72); position: relative;
  transition: background-color var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
}
.sidebar-link svg { width: 17px; height: 17px; flex-shrink: 0; }
.sidebar-link:hover { background: hsl(0 0% 100% / 0.06); color: white; }
.sidebar-link.is-active { background: hsl(0 0% 100% / 0.1); color: white; }
.sidebar-link.is-active::before {
  content: ""; position: absolute; left: -12px; top: 50%; transform: translateY(-50%);
  width: 3px; height: 18px; border-radius: var(--radius-full); background: hsl(var(--accent));
}
.sidebar-link .badge-count {
  margin-left: auto; background: hsl(var(--accent)); color: hsl(var(--accent-foreground)); font-size: 10.5px; font-weight: 700;
  border-radius: var(--radius-full); min-width: 17px; height: 17px; display: flex; align-items: center; justify-content: center; padding: 0 5px;
}
.sidebar-footer { padding: var(--space-3); border-top: 1px solid hsl(0 0% 100% / 0.08); }
/* Now a <button> (it opens a menu, so it has to be focusable and operable
   from the keyboard) — these three lines replace what the <div> got for free. */
.sidebar-account-switch {
  display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3); border-radius: var(--radius-md);
  font-size: 12.5px; color: hsl(0 0% 100% / 0.6); cursor: pointer; transition: background-color var(--dur-base) var(--ease-out);
  width: 100%; text-align: left; font-family: inherit;
}
/* Nav rows the current user has no access to. Replaces an inline
   opacity/cursor pair plus a title= tooltip that keyboard users could
   never reach — the explanation now lives in visually-hidden text. */
.sidebar-link.is-locked { opacity: 0.45; cursor: not-allowed; }
.sidebar-link.is-locked:hover { background: none; color: hsl(0 0% 100% / 0.72); }
.sidebar-account-switch:hover { background: hsl(0 0% 100% / 0.06); }
/* The name/email block must be allowed to shrink below its content's natural
   width (flex items default to min-width:auto, which fights truncation) —
   otherwise a long email pushes the trailing chevron flush against the
   sidebar's edge instead of leaving it room to breathe. */
.sidebar-account-switch .flex-1 { min-width: 0; }
.sidebar-account-switch .flex-1 > div { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sidebar-account-switch svg { flex-shrink: 0; }

.app-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.topbar {
  height: var(--topbar-h); border-bottom: 1px solid hsl(var(--border)); background: hsl(var(--surface) / 0.9);
  backdrop-filter: blur(8px); position: sticky; top: 0; z-index: 30;
  display: flex; align-items: center; justify-content: space-between; padding: 0 var(--space-6); gap: var(--space-4);
}
.topbar-title { font-size: 16px; font-weight: 700; letter-spacing: -0.01em; }
.topbar-actions { display: flex; align-items: center; gap: var(--space-2); }
.topbar-search {
  display: flex; align-items: center; gap: var(--space-2); height: 34px; padding: 0 var(--space-3); width: 260px;
  border-radius: var(--radius-md); background: hsl(var(--surface-sunken)); color: hsl(var(--fg-muted)); font-size: 13px;
}
.topbar-search svg { width: 15px; height: 15px; flex-shrink: 0; }
.topbar-search input { background: none; border: none; outline: none; width: 100%; font-size: 13px; color: hsl(var(--fg)); }
/* Search isn't built yet. A disabled <input> looked like a broken control and
   put an unlabelled form field on every page; this is honest static text. */
.topbar-search.is-placeholder { cursor: default; user-select: none; }
.topbar-search.is-placeholder span { font-size: 13px; color: hsl(var(--fg-subtle)); }

.page { padding: var(--space-6); max-width: var(--content-max); width: 100%; margin-inline: auto; }
.page-header { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); margin-bottom: var(--space-6); flex-wrap: wrap; }
.page-header .eyebrow { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: hsl(var(--fg-muted)); margin-bottom: 4px; }
.page-header h1 { margin: 0; }
.page-header p.subtitle { color: hsl(var(--fg-muted)); font-size: 13.5px; margin-top: 4px; }

.mobile-topbar { display: none; }
.mobile-nav-scrim { display: none; }

@media (max-width: 900px) {
  body[data-role="staff"] { display: block; }
  .sidebar {
    position: fixed; left: 0; top: 0; z-index: 80; transform: translateX(-100%);
    transition: transform var(--dur-slow) var(--ease-drawer); box-shadow: var(--shadow-modal);
  }
  .sidebar.is-open { transform: translateX(0); }
  .mobile-nav-scrim {
    display: block; position: fixed; inset: 0; background: hsl(190 32% 6% / 0.45); z-index: 70;
    opacity: 0; pointer-events: none; transition: opacity var(--dur-base) var(--ease-out);
  }
  .mobile-nav-scrim.is-open { opacity: 1; pointer-events: auto; }
  .topbar { display: none; }
  .mobile-topbar {
    display: flex; align-items: center; height: var(--topbar-h); padding: 0 var(--space-4); gap: var(--space-3);
    border-bottom: 1px solid hsl(var(--border)); background: hsl(var(--surface)); position: sticky; top: 0; z-index: 30;
  }
  .page { padding: var(--space-4); }
  /* viewport-fit=cover (see partials/_head.html) puts the page under the
     notch in landscape unless the horizontal insets are added back. */
  .page, .mobile-topbar {
    padding-left: calc(var(--space-4) + env(safe-area-inset-left));
    padding-right: calc(var(--space-4) + env(safe-area-inset-right));
  }
}

/* ==================== Cleaner shell (phone-first, bottom nav) ==================== */
body[data-role="cleaner"] { padding-bottom: calc(var(--bottomnav-h) + env(safe-area-inset-bottom)); background: hsl(var(--surface-sunken)); }
.cleaner-shell-main { display: flex; flex-direction: column; min-width: 0; }
.cleaner-topbar {
  position: sticky; top: 0; z-index: 30; background: hsl(var(--petrol-900)); color: white;
  padding: calc(var(--space-4) + env(safe-area-inset-top)) var(--space-4) var(--space-5);
  border-radius: 0 0 var(--radius-xl) var(--radius-xl);
}
.cleaner-topbar .greeting { font-size: 12.5px; color: hsl(0 0% 100% / 0.65); font-weight: 500; }
.cleaner-topbar h1 { font-size: 20px; color: white; margin-top: 2px; }
.cleaner-topbar__row { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); }
.cleaner-topbar__actions { display: flex; align-items: center; gap: var(--space-2); }
.cleaner-topbar__avatar { background: hsl(0 0% 100% / 0.14); color: white; font-weight: 700; }
.cleaner-topbar__logout {
  display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; flex-shrink: 0;
  border-radius: var(--radius-md); color: hsl(0 0% 100% / 0.72);
  transition: background-color var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out), transform 140ms cubic-bezier(0.23,1,0.32,1);
}
.cleaner-topbar__logout:hover { background: hsl(0 0% 100% / 0.1); color: white; }
.cleaner-topbar__logout:active { transform: scale(0.93); }
.cleaner-topbar__logout svg { width: 19px; height: 19px; }
@media (prefers-reduced-motion: reduce) {
  .cleaner-topbar__logout:active { transform: none; }
}
.cleaner-page { max-width: 560px; margin-inline: auto;
  padding: var(--space-4) calc(var(--space-4) + env(safe-area-inset-right)) var(--space-4) calc(var(--space-4) + env(safe-area-inset-left)); padding-bottom: calc(var(--bottomnav-h) + var(--space-6) + env(safe-area-inset-bottom)); display: flex; flex-direction: column; gap: var(--space-4); width: 100%; }
.section-label { font-size: 12.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: hsl(var(--fg-muted)); margin: var(--space-2) 4px; }
.bottom-nav {
  position: fixed; bottom: 0; left: 0; right: 0; height: calc(var(--bottomnav-h) + env(safe-area-inset-bottom));
  padding-bottom: env(safe-area-inset-bottom);
  background: hsl(var(--surface));
  border-top: 1px solid hsl(var(--border)); display: flex; z-index: 40; max-width: 560px; margin-inline: auto;
  box-shadow: 0 -2px 12px hsl(190 32% 11% / 0.05);
}
.bottom-nav-item {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  font-size: 10.5px; font-weight: 600; color: hsl(var(--fg-subtle)); position: relative;
  min-height: 44px;
  transition: color var(--dur-base) var(--ease-out);
}
.bottom-nav-item svg { width: 21px; height: 21px; transition: transform var(--dur-fast) var(--ease-out); }
.bottom-nav-item.is-active { color: hsl(var(--primary)); }
.bottom-nav-item:active svg { transform: scale(0.9); }
.bottom-nav-item .dot-badge { position: absolute; top: 4px; right: calc(50% - 16px); width: 7px; height: 7px; border-radius: 50%; background: hsl(var(--accent)); }

@media (min-width: 561px) {
  body[data-role="cleaner"] { background: hsl(var(--surface-sunken)); }
  .bottom-nav { border-radius: var(--radius-xl) var(--radius-xl) 0 0; }
}

/* ---- Cleaner shell: desktop sidebar (>=1080px) ----
   Below 1080px the phone layout (petrol topbar + bottom nav) stays exactly
   as-is; the sidebar is simply not rendered. At/above it we swap to a
   sidebar + wide content area, same pattern as the owner shell's .sidebar. */
.cleaner-sidebar { display: none; }
@media (min-width: 1080px) {
  body[data-role="cleaner"] { display: flex; padding-bottom: 0; }
  .cleaner-sidebar { display: flex; }
  .cleaner-topbar, .bottom-nav { display: none; }
  .cleaner-shell-main { flex: 1; min-width: 0; }
  .cleaner-page {
    max-width: var(--content-max); padding: var(--space-8) var(--space-8) var(--space-10); padding-bottom: var(--space-10);
  }
}

/* Topbar "sync now" button — icon-only, so the spinning icon plus disabled
   state (shell.js) is the only in-progress feedback it has room for. */
#topbar-sync-btn.is-syncing svg, #mobile-sync-btn.is-syncing svg { animation: topbar-sync-spin 0.8s linear infinite; }
@keyframes topbar-sync-spin { to { transform: rotate(360deg); } }
/* The --dur-* override in tokens.css can't reach a hardcoded duration, so the
   looping spinner has to opt out explicitly. The disabled state still reads as
   "in progress" without the motion. */
@media (prefers-reduced-motion: reduce) {
  #topbar-sync-btn.is-syncing svg, #mobile-sync-btn.is-syncing svg { animation: none; opacity: 0.55; }
}

/* ---- Owner tab bar (phones) ----
   Same .bottom-nav as the cleaner shell, shown only where the sidebar is
   hidden. "More" opens the sidebar drawer. */
.bottom-nav--staff { display: none; }
.bottom-nav-item { background: none; border: 0; font-family: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
.bottom-nav-item:focus-visible { outline: 2px solid hsl(var(--ring)); outline-offset: calc(var(--space-1) * -1); border-radius: var(--radius-md); }
/* Active tab gets a short bar above the icon, so the state is not carried by
   colour alone. */
.bottom-nav-item.is-active::before {
  content: ""; position: absolute; top: 0; left: 50%; width: var(--space-6); height: var(--space-0-5);
  transform: translateX(-50%); border-radius: 0 0 var(--radius-sm) var(--radius-sm); background: hsl(var(--primary));
}
.bottom-nav-count {
  position: absolute; top: var(--space-1); left: calc(50% + var(--space-1));
  min-width: var(--space-4); height: var(--space-4); padding: 0 var(--space-1); border-radius: var(--radius-full);
  background: hsl(var(--accent)); color: hsl(var(--accent-foreground));
  font-size: var(--text-3xs); font-weight: 700; line-height: var(--space-4); text-align: center;
  font-variant-numeric: tabular-nums; box-shadow: 0 0 0 var(--space-0-5) hsl(var(--surface));
}
@media (max-width: 900px) {
  .bottom-nav--staff { display: flex; max-width: none; }
  body[data-role="staff"] .app-main { padding-bottom: calc(var(--bottomnav-h) + env(safe-area-inset-bottom)); }
  .mobile-topbar .brand-mark { text-decoration: none; }
}
