/* =====================================================================
   BetaChat — Owner dashboard, tabbed layout
   Loaded AFTER css/style.css and css/theme.css, so it inherits every
   theme token (--t-*) and works in dark, light and all festive skins.

   What this file changes: only the chrome of #modal-owner-dashboard-backdrop.
   The controls inside (broadcast, themes, storage, bot…) keep their original
   markup and styling — this layer just groups them and gives each group a
   titled card, a tab bar, and a footer that always shows the last result.
   ===================================================================== */

/* ---------- 1. Shell: pinned tabs + ONE scroll region + pinned footer ----------
   v87: the sheet used to be a fixed-height flex column with `overflow: hidden`
   and only the body scrolling, so everything above and below the body (title,
   five status cards, the tab strip, the footer) was taken out of the body's
   height. On a short window that left the body about two rows tall and System
   status was cut off with no way to reach the rest of it — the body had nothing
   left to scroll through. Now the SHEET scrolls and the body is never squeezed:
   the tab strip and the footer stay put, and every panel is reachable by
   scrolling the sheet. Same markup, same controls, presentation only. */
#modal-owner-dashboard-backdrop .owner-dashboard-modal {
  display: flex;
  flex-direction: column;
  width: min(560px, 94vw);
  max-height: min(92dvh, 820px);
  overflow-y: auto;                 /* the sheet scrolls; the body is never clipped */
  overscroll-behavior: contain;
  padding: 18px 18px 14px;
}

#modal-owner-dashboard-backdrop .owner-titlebar {
  position: static;                 /* the sheet header is pinned by flex, not sticky */
  align-items: flex-start;
  gap: 10px;
  padding: 0 0 10px;
  background: none;
}
#modal-owner-dashboard-backdrop .owner-titlebar h3 { font-size: 21px; line-height: 1.15; }
.owner-titlebar-right { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.owner-scope-chip {
  padding: 4px 9px; border-radius: 999px; border: 1px solid var(--t-border);
  background: var(--t-accent-soft); color: var(--t-accent);
  font-size: 10px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; white-space: nowrap;
}

/* ---------- 2. Tab bar (wraps, and stays put while the sheet scrolls) ---------- */
.owner-tabs {
  display: flex; gap: 6px; flex: 0 0 auto; flex-wrap: wrap;
  padding: 0 0 10px; margin-bottom: 12px;
  border-bottom: 1px solid var(--t-border);
  /* v84 gave the strip a sideways scroller and a 6px scrollbar to hint that AI and
     Administration were off-screen. It still read as a progress bar, and two tabs
     were only discoverable by dragging. v87 wraps the pills instead: six of them fit
     in two tidy rows on any width, so all six are visible at once with nothing hidden
     behind an edge. It is pinned to the top of the sheet so switching tabs never
     means scrolling back up first. */
  position: sticky; top: 0; z-index: 3;
  background: var(--surface);
  overflow: visible;
}
.owner-tab {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 7px;
  min-height: 38px; padding: 8px 13px;
  border: 1px solid var(--t-border); border-radius: 999px;
  background: var(--t-surface-2); color: var(--t-text-2);
  font: inherit; font-size: 13px; font-weight: 600; white-space: nowrap; cursor: pointer;
  transition: background .16s ease, color .16s ease, border-color .16s ease;
}
.owner-tab:hover { color: var(--t-text); border-color: var(--t-accent); }
.owner-tab[aria-selected="true"] { background: var(--t-accent); border-color: var(--t-accent); color: var(--t-accent-ink); }
html[data-skin] .owner-tab[aria-selected="true"] { background: var(--party-grad); border-color: transparent; color: #fff; }
.owner-tab-icon { font-size: 14px; line-height: 1; }
.owner-tab:focus-visible, .owner-panel:focus-visible { outline: 2px solid var(--t-accent); outline-offset: 2px; }
.owner-panel:focus-visible { outline-offset: 1px; }

/* ---------- 3. Scrolling body ---------- */
#modal-owner-dashboard-backdrop #owner-dashboard.owner-dashboard {
  display: block;
  flex: 0 0 auto; min-height: 0;
  margin: 0; padding: 2px 2px 2px 0;
  border: 0; border-radius: 0; background: none;
  overflow: visible;                /* v87: the sheet scrolls, so nothing here is cut off */
}

.owner-panel { display: block; animation: owner-panel-in .18s ease-out both; }
.owner-panel[hidden] { display: none !important; }
@keyframes owner-panel-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* Cards: reuse the existing .bday-admin look, just fix the flow spacing. */
.owner-panel > .owner-card { margin: 0 0 12px; }
.owner-panel > .owner-card:last-child { margin-bottom: 2px; }
.owner-panel-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.owner-panel-head h4 { margin: 0; font-family: 'Fraunces', serif; font-size: 16px; font-weight: 600; color: var(--t-text); }
.owner-subhead {
  margin: 14px 0 6px; color: var(--t-text-3);
  font-size: 10px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
}

/* ---------- 4. Overview: stats + system status ---------- */
.owner-status-list { display: flex; flex-direction: column; }
.owner-status-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  min-height: 34px; padding: 6px 0;
  border-top: 1px solid var(--t-border-soft);
  font-size: 13px;
}
.owner-status-row:first-child { border-top: 0; }
.owner-status-key { color: var(--t-text-2); flex: 1 1 auto; min-width: 0; }
.owner-status-value { flex: 0 1 auto; max-width: 62%; text-align: right; color: var(--t-text); font-weight: 600; overflow-wrap: anywhere; }
.owner-status-value.is-pending { color: var(--t-text-3); font-weight: 500; }
.owner-status-value.is-warn { color: var(--t-warn); }
.owner-status-value.is-off { color: var(--t-text-3); }

/* ---------- 5. Footer: last result + Close (always reachable) ---------- */
#modal-owner-dashboard-backdrop .owner-footer {
  flex: 0 0 auto; display: flex; flex-direction: column; gap: 9px;
  margin-top: 12px; padding-top: 11px;
  border-top: 1px solid var(--t-border);
  /* v87: pinned to the bottom of the sheet, so the last-result line and Close stay
     on screen (and reachable) whatever the window height and however far the panel
     is scrolled. */
  position: sticky; bottom: 0; z-index: 3;
  background: var(--surface);
}
#modal-owner-dashboard-backdrop #owner-dashboard-status {
  max-height: 54px; overflow-y: auto;
  font-size: 12px; line-height: 1.4; color: var(--t-text-2);
}
#modal-owner-dashboard-backdrop #owner-dashboard-status:empty { display: none; }
#modal-owner-dashboard-backdrop .owner-footer .button { margin-top: 0; }
/* The shimmer used while metrics load now lives on the footer line, because the
   status text moved out of #owner-dashboard (see js/app.js paintOwnerMetrics). */
#modal-owner-dashboard-backdrop #owner-dashboard.metrics-loading ~ .owner-footer #owner-dashboard-status {
  color: transparent !important; border-radius: 5px; min-height: 14px;
  background: linear-gradient(90deg, #dbece6 20%, #f2f8f5 45%, #dbece6 70%);
  background-size: 220% 100%; animation: dashboard-shimmer 1.15s linear infinite;
}
[data-theme="dark"] #modal-owner-dashboard-backdrop #owner-dashboard.metrics-loading ~ .owner-footer #owner-dashboard-status {
  background: linear-gradient(90deg, #294144, #395559, #294144); background-size: 220% 100%;
}

/* ---------- 6. Administration: admins roster ---------- */
.owner-roster { display: flex; flex-direction: column; gap: 8px; margin: 10px 0 12px; }
.owner-roster-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border: 1px solid var(--t-border); border-radius: 12px; background: var(--t-surface-2);
}
.owner-roster-avatar {
  flex: 0 0 auto; width: 34px; height: 34px; overflow: hidden;
  display: grid; place-items: center; border-radius: 50%;
  color: #fff; font-size: 12px; font-weight: 700;
}
.owner-roster-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.owner-roster-name {
  flex: 1 1 auto; min-width: 0; color: var(--t-text); font-size: 13.5px; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.owner-roster-name .member-row-status { margin-top: 2px; }
.owner-role-chip {
  flex: 0 0 auto; padding: 3px 9px; border: 1px solid var(--t-border); border-radius: 999px;
  color: var(--t-text-3); font-size: 10px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
}
.owner-role-chip.role-owner { border-color: var(--t-accent); background: var(--t-accent-soft); color: var(--t-accent); }
.owner-roster-empty { padding: 10px 2px; color: var(--t-text-3); font-size: 12.5px; }

/* ---------- 7. Administration: permissions matrix ---------- */
.owner-perm { display: flex; flex-direction: column; font-size: 12.5px; }
.owner-perm-row {
  display: grid; grid-template-columns: minmax(0, 1.9fr) 52px 68px 56px;
  gap: 6px; align-items: center;
  padding: 8px 2px; border-top: 1px solid var(--t-border-soft);
}
.owner-perm-head { border-top: 0; color: var(--t-text-3); font-size: 10px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; }
.owner-perm-row > span:first-child { color: var(--t-text); }
.owner-perm-row > span:not(:first-child) { text-align: center; }
.owner-perm-head > span:not(:first-child) { text-align: center; }
.owner-perm .perm-yes { color: var(--t-accent); font-weight: 800; }
.owner-perm .perm-no { color: var(--t-text-3); }
.owner-perm .perm-limited { color: var(--t-warn); font-size: 10.5px; font-weight: 700; line-height: 1.15; }
#owner-panel-administration code { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 11px; }
#owner-audit-list { max-height: 190px; }

/* ---------- 8. Phones: full-height sheet, tabs stay put ---------- */
@media (max-width: 720px) {
  #modal-owner-dashboard-backdrop .owner-dashboard-modal {
    width: 100%; max-width: 100%;
    height: min(94dvh, 100%);
    max-height: 94dvh;
    border-radius: 20px 20px 0 0;
    padding: 16px 14px 10px;
    padding-bottom: 10px;
  }
  #modal-owner-dashboard-backdrop .owner-titlebar h3 { font-size: 19px; }
  .owner-tabs { margin-bottom: 10px; padding-bottom: 9px; }
  .owner-tab { min-height: 40px; padding: 9px 12px; }
  #modal-owner-dashboard-backdrop .owner-footer { padding-bottom: max(10px, env(safe-area-inset-bottom)); }
  .owner-perm-row { grid-template-columns: minmax(0, 1.6fr) 42px 62px 46px; font-size: 12px; }
}
@media (max-width: 420px) {
  .owner-perm-head > span:not(:first-child) { font-size: 9px; letter-spacing: 0; }
  .owner-perm .perm-limited { font-size: 9.5px; }
}

/* ---------- 9. Small niceties ---------- */
.owner-panel .link-btn { min-height: 32px; }
.owner-panel .audit-head .link-btn { margin-left: auto; }
.owner-panel .botpersona-head { margin-top: 0; }
@media (prefers-reduced-motion: reduce) {
  .owner-panel { animation: none; }
}

/* =====================================================================
   10. Permission model (js/permissions.js)
   The matrix and the two "what an Admin gets" lists are generated from the
   capability table, so they are styled here rather than hand-written in HTML.
   ===================================================================== */
.owner-scope-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 4px; }
.owner-scope-card { padding: 12px; border: 1px solid var(--t-border); border-radius: 13px; background: var(--t-surface-2); }
.owner-scope-card.can { border-color: color-mix(in srgb, var(--t-accent) 45%, var(--t-border)); }
.owner-scope-card.cannot { border-color: color-mix(in srgb, var(--t-text-3) 45%, var(--t-border)); }
.owner-scope-card h5 { margin: 0 0 8px; color: var(--t-text); font-size: 12px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; }
.owner-scope-card.cannot h5 { color: var(--t-text-2); }
.owner-scope-card h5 em { font-style: normal; font-weight: 600; text-transform: none; letter-spacing: 0; color: var(--t-text-3); }
.owner-scope-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.owner-scope-list li { display: flex; gap: 7px; font-size: 12.5px; line-height: 1.35; }
.owner-scope-list li.scope-yes { color: var(--t-text); }
.owner-scope-list li.scope-no { color: var(--t-text-2); }
.owner-scope-list li > span { min-width: 0; }
.owner-scope-list li small { display: block; margin-top: 2px; color: var(--t-text-3); font-size: 11px; line-height: 1.35; }
.owner-scope-list li.scope-no small { opacity: .8; }
.owner-scope-foot { margin: 10px 0 0; padding-top: 8px; border-top: 1px solid var(--t-border-soft); color: var(--t-text-3); font-size: 11px; line-height: 1.4; }

.owner-perm-group { padding: 12px 2px 5px; border-top: 1px solid var(--t-border); color: var(--t-text-3);
  font-size: 10px; font-weight: 800; letter-spacing: .07em; text-transform: uppercase; }
.owner-perm-group:first-child { border-top: 0; padding-top: 4px; }
.owner-perm-group + .owner-perm-row { border-top: 0; }
.owner-perm .perm-label { display: flex; align-items: baseline; gap: 6px; }
.owner-perm .perm-marker { flex: 0 0 auto; font-size: 10px; line-height: 1; opacity: .85; cursor: help; }
.owner-perm .perm-none { color: var(--t-text-3); opacity: .55; }
.owner-legend { display: flex; flex-wrap: wrap; gap: 6px 12px; margin: 10px 0 2px; color: var(--t-text-3); font-size: 11px; }
.owner-legend span { display: inline-flex; align-items: center; gap: 4px; }
.owner-legend b { color: var(--t-text-2); font-weight: 800; }
.owner-legend em { font-style: normal; }

@media (max-width: 720px) {
  .owner-scope-grid { grid-template-columns: 1fr; }
  .owner-perm .perm-marker { display: none; }
}

/* =====================================================================
   11. Phones: sections become expandable rows (the §17 mobile layout)
   js/owner-ui.js re-parents the real buttons and panels into .owner-acc-item
   rows inside the scrolling body — nothing is cloned, so every id, every
   listener app.js bound and every aria-* reference keeps working at any width.
   ===================================================================== */
.owner-dashboard-modal.owner-accordion .owner-tabs { display: none; }   /* buttons moved into the body */
.owner-acc-item {
  margin-bottom: 8px; border: 1px solid var(--t-border); border-radius: 14px;
  background: var(--t-surface-2); overflow: hidden;
}
.owner-acc-item[aria-expanded="true"] {
  border-color: color-mix(in srgb, var(--t-accent) 45%, var(--t-border));
  background: var(--t-surface);
}
.owner-acc-item .owner-tab {
  display: flex; width: 100%; min-height: 50px; padding: 13px 14px;
  border: 0; border-radius: 0; background: transparent; color: var(--t-text);
  font-size: 14.5px; font-weight: 600; text-align: left;
}
.owner-acc-item .owner-tab:hover { background: var(--t-surface-3); border-color: transparent; }
.owner-acc-item .owner-tab::after {                       /* chevron */
  content: "⌄"; margin-left: auto; font-size: 16px; line-height: 1; color: var(--t-text-2);
  transition: transform .16s ease;
}
.owner-acc-item[aria-expanded="true"] .owner-tab::after { transform: rotate(180deg); }
.owner-acc-item[aria-expanded="true"] .owner-tab { color: var(--t-accent); }
html[data-skin] .owner-acc-item[aria-expanded="true"] .owner-tab { color: var(--t-text); }
.owner-acc-item .owner-tab:focus-visible { outline: 2px solid var(--t-accent); outline-offset: -2px; }
.owner-acc-item .owner-tab-icon { font-size: 16px; }
.owner-acc-item > .owner-panel { padding: 2px 12px 12px; }
.owner-acc-item > .owner-panel[hidden] { display: none !important; }
.owner-acc-item .owner-card { margin-bottom: 10px; }
.owner-acc-item .owner-card:last-child { margin-bottom: 0; }
@media (prefers-reduced-motion: reduce) { .owner-acc-item .owner-tab::after { transition: none; } }

/* =====================================================================
   12. Audit log (Owner dashboard → Administration → Audit log)
   The timeline the review asked for: stamp, role badge, action title, then the
   detail lines. Rendering lives in js/audit-log.js; this is only the skin.
   ===================================================================== */
.audit-filters { display: flex; flex-wrap: wrap; gap: 6px; margin: 2px 0 10px; }
.audit-chip {
  display: inline-flex; align-items: center; gap: 6px; min-height: 30px; padding: 5px 10px;
  border: 1px solid var(--t-border); border-radius: 999px; background: var(--t-surface-2);
  color: var(--t-text-2); font: inherit; font-size: 11.5px; font-weight: 600; white-space: nowrap; cursor: pointer;
  transition: background .14s ease, color .14s ease, border-color .14s ease;
}
.audit-chip:hover { color: var(--t-text); border-color: var(--t-accent); }
.audit-chip[aria-selected="true"] { background: var(--t-accent-soft); border-color: var(--t-accent); color: var(--t-accent); }
.audit-chip[data-empty="1"] { opacity: .55; }
.audit-chip-count {
  display: inline-grid; place-items: center; min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: 999px; background: var(--t-surface-3); color: var(--t-text-2); font-size: 10px; font-weight: 700;
}
.audit-chip[aria-selected="true"] .audit-chip-count { background: var(--t-accent); color: var(--t-accent-ink); }

#owner-audit-list.owner-audit-list {
  max-height: 300px; overflow-y: auto; border-top: 1px solid var(--t-border-soft);
  padding: 4px 2px 0; font-size: 12px; scrollbar-width: thin;
}
#owner-audit-list.owner-audit-list::-webkit-scrollbar { width: 7px; }
#owner-audit-list.owner-audit-list::-webkit-scrollbar-thumb { background: var(--t-scroll); border-radius: 99px; }

.audit-entry { padding: 11px 2px 12px; border-bottom: 1px solid var(--t-border-soft); }
.audit-entry:last-child { border-bottom: 0; }
.audit-entry-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.audit-stamp { color: var(--t-text-2); font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 11.5px; letter-spacing: .02em; }
.audit-role {
  padding: 2px 7px; border-radius: 999px; border: 1px solid var(--t-border);
  font-size: 9.5px; font-weight: 800; letter-spacing: .07em; text-transform: uppercase;
}
.audit-role-owner { border-color: var(--t-accent); background: var(--t-accent-soft); color: var(--t-accent); }
.audit-role-admin { border-color: var(--t-warn); background: color-mix(in srgb, var(--t-warn) 14%, transparent); color: var(--t-warn); }
.audit-role-system { border-color: var(--t-border); background: var(--t-surface-3); color: var(--t-text-2); }
.audit-entry-title { color: var(--t-text); font-size: 13.5px; font-weight: 700; line-height: 1.3; }
.audit-line { margin-top: 3px; color: var(--t-text-2); font-size: 12.5px; line-height: 1.45; overflow-wrap: anywhere; }
.audit-line b { color: var(--t-text); font-weight: 700; }
.audit-entry-who { margin-top: 5px; color: var(--t-text-3); font-size: 11px; }
.audit-empty { padding: 16px 4px; color: var(--t-text-3); font-size: 12.5px; line-height: 1.5; }
.audit-empty span { color: var(--t-text-3); opacity: .85; }
.audit-actions { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
.audit-actions .button { margin-top: 0; }
@media (max-width: 720px) { #owner-audit-list.owner-audit-list { max-height: 42vh; } }

/* §12b — the audit card says so when the database refuses to store entries.
   Silence would read as "nothing has happened", which is the wrong story. */
.audit-warn { margin: 6px 0 8px; padding: 8px 10px; border: 1px solid #d9a441; border-radius: 9px;
  background: rgba(217,164,65,.12); color: #8a6413; font-size: 11.5px; line-height: 1.45; font-weight: 600; }
.audit-warn code { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 11px; background: rgba(0,0,0,.06); padding: 1px 4px; border-radius: 4px; }
[data-theme="dark"] .audit-warn { border-color: #a8823a; background: rgba(217,164,65,.16); color: #f0cd85; }
[data-theme="dark"] .audit-warn code { background: rgba(255,255,255,.1); }

/* ============================================================================
   §13 — Admin dashboard (shares the owner dashboard's classes on purpose: one
   visual language, one place to change it, and the phone accordion comes free).
   Everything here is additive; no owner rule is restyled.
   ============================================================================ */

#modal-admin-dashboard-backdrop #admin-dashboard.owner-dashboard { max-height: min(62vh, 560px); overflow-y: auto; padding-right: 2px; }
#modal-admin-dashboard-backdrop #admin-dashboard.owner-dashboard::-webkit-scrollbar { width: 7px; }
#modal-admin-dashboard-backdrop #admin-dashboard.owner-dashboard::-webkit-scrollbar-thumb { background: var(--t-scroll); border-radius: 99px; }

/* "Admin · moderation" chip — same shape as the owner one, different colour so the
   two sheets are never mistaken for each other. */
.owner-scope-chip.admin-scope-chip { color: #2f6fb0; background: rgba(47,111,176,.12); border-color: rgba(47,111,176,.34); }
[data-theme="dark"] .owner-scope-chip.admin-scope-chip { color: #8fc3f5; background: rgba(47,111,176,.2); border-color: rgba(120,180,240,.4); }

/* the four counters */
.admin-tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.admin-tile { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding: 10px 11px;
  border: 1px solid var(--t-border); border-radius: 11px; background: var(--t-surface-2); }
.admin-tile-num { font: 700 21px/1 'Fraunces', Georgia, serif; color: var(--t-text); }
.admin-tile-label { font-size: 10.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--t-text-3); overflow-wrap: anywhere; }
/* the sheet title must never be squeezed by the scope chip next to it */
#admin-dashboard-title { flex: 0 0 auto; white-space: nowrap; }
@media (max-width: 560px) { .admin-tiles { grid-template-columns: repeat(2, 1fr); } }

/* oldest-first preview list on Overview */
.admin-mini-list { display: flex; flex-direction: column; gap: 6px; }
.admin-mini-row { display: flex; flex-direction: column; gap: 2px; width: 100%; padding: 9px 11px; text-align: left;
  border: 1px solid var(--t-border); border-radius: 10px; background: var(--t-surface-2); color: var(--t-text);
  font: inherit; cursor: pointer; }
.admin-mini-row:hover { border-color: var(--t-accent); }
.admin-mini-row strong { font-size: 13px; }
.admin-mini-row span { font-size: 12px; color: var(--t-text-2); }
.admin-mini-row small { font-size: 10.5px; color: var(--t-text-3); }

/* the hosts that receive the real Reports / bot-conversation lists */
.admin-host { min-height: 80px; }
.admin-host > .reports-list, .admin-host > .manageusers-list { max-height: none; }

/* member lookup */
.admin-member-list { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; max-height: 300px; overflow-y: auto; }
.admin-member-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 9px 11px;
  border: 1px solid var(--t-border); border-radius: 10px; background: var(--t-surface-2); }
.admin-member-who { display: flex; align-items: center; gap: 6px; min-width: 0; flex-wrap: wrap; }
.admin-member-who strong { font-size: 13.5px; color: var(--t-text); }
.admin-member-key { font-size: 11px; color: var(--t-text-3); }
.admin-tag { padding: 1px 6px; border-radius: 999px; font-size: 10px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; }
.admin-tag-admin { color: #2f6fb0; background: rgba(47,111,176,.14); }
.admin-tag-owner { color: #8a6413; background: rgba(217,164,65,.18); }
[data-theme="dark"] .admin-tag-admin { color: #8fc3f5; background: rgba(47,111,176,.24); }
[data-theme="dark"] .admin-tag-owner { color: #f0cd85; background: rgba(217,164,65,.22); }

/* the "My scope" tab reuses the permission cards from the owner dashboard */
#admin-panel-scope .owner-scope { margin-top: 0; }

/* phone: the accordion from §11 is reused, so only the host padding differs */
@media (max-width: 720px) {
  .owner-acc-item .admin-host { padding: 0; }
  .admin-member-row { flex-direction: column; align-items: flex-start; }
  .admin-member-row .button { align-self: flex-end; }
}

/* =====================================================================
   14. Phones: crowding fixes (v31)
   The six accordion rows from §11 keep the dashboard navigable, but two
   things still made it heavy at 320–420px: wordy explanations pushing the
   controls off-screen, and labels the header/clip squeezed into an ellipsis.
   Nothing here changes what a wide screen shows.
   ===================================================================== */

/* The section you are inside announces itself while you scroll it. The 5.4k-px
   Administration panel is ten screens tall — without this the owner scrolls
   blind and cannot see which row to tap to collapse. `.owner-acc-item` must not
   clip (a clipping ancestor becomes the sticky scrollport and pinning dies), so
   the rounded top corner is given to the row header itself. */
.owner-acc-item { overflow: visible; }
.owner-acc-item > .owner-tab { border-radius: 13px 13px 0 0; }
@media (max-width: 720px) {
  .owner-accordion .owner-acc-item[aria-expanded="true"] > .owner-tab {
    position: sticky; top: 0; z-index: 3;
    background: var(--t-surface); border-bottom: 1px solid var(--t-border-soft);
  }
  html[data-skin] .owner-accordion .owner-acc-item[aria-expanded="true"] > .owner-tab { background: var(--t-surface); }
}

/* Explanations over ~3 lines fold behind "More" — added by js/owner-ui.js, which
   only runs in the phone layout. On a wide screen the toggle stays hidden and
   no text is clamped anywhere. */
.owner-hint-more { display: none; }
@media (max-width: 720px) {
  .owner-card .owner-hint-long.is-folded {
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
  }
  .owner-card .owner-hint-more {
    display: flex; align-items: center; min-height: 34px; margin: -2px 0 2px;
    padding: 0; border: 0; background: none; color: var(--t-accent);
    font: inherit; font-size: 12.5px; font-weight: 700; letter-spacing: .01em;
    cursor: pointer;
  }
  .owner-card .owner-hint-more:hover { text-decoration: underline; }
  .owner-card .owner-hint-more:focus-visible { outline: 2px solid var(--t-accent); outline-offset: 2px; border-radius: 6px; }
}

/* Real names were being cut to "ahsanul-ari…" beside a 34px avatar and a role
   chip. On a phone the name gets its own wrapping line instead of an ellipsis. */
@media (max-width: 420px) {
  .owner-roster-name { white-space: normal; overflow: visible; text-overflow: clip; overflow-wrap: anywhere; line-height: 1.25; }
  .owner-perm-row { grid-template-columns: minmax(0, 1fr) 44px 48px 42px; gap: 4px; }
  .owner-perm-head { font-size: 9.5px; letter-spacing: .02em; }
  .owner-perm .perm-limited { font-size: 9.5px; }
}

/* The sheet title is the name of the sheet — it should read on one line in the
   title bar at every supported width (§16 starts at 320px), with the scope chip
   and the close button beside it. 19px wrapped to two lines at 320px. */
@media (max-width: 400px) {
  #modal-owner-dashboard-backdrop .owner-titlebar { gap: 8px; }
  #modal-owner-dashboard-backdrop .owner-titlebar h3 {
    font-size: 15.5px; white-space: nowrap; overflow: visible;
  }
  .owner-scope-chip { padding: 3px 7px; font-size: 9.5px; }
}

/* =====================================================================
   17. Skeleton loaders
   The dashboard used to greet an owner with text placeholders — "Loading
   activity…" in the audit card, "—" in every statistic and status row. Those
   are honest but they read as broken, and the tiles flicker as the numbers
   land. Now the same boxes shimmer instead, in the shape of the value that is
   coming, and are swapped for the real thing the moment it arrives.

   Rules of the house:
     * a skeleton is ALWAYS replaced — by data, by an error message, or by the
       give-up sweep in js/owner-ui.js after SKELETON_GIVE_UP_MS. Nothing
       shimmers forever.
     * labels stay real. Only the placeholder value shimmers, so the panel still
       says what it is about.
     * the animation is one keyframe set (dashboard-shimmer, css/style.css) and
       it stops dead under prefers-reduced-motion.
   ===================================================================== */
.owner-skel-hide-text,
.owner-stats.is-loading strong,
.admin-tiles.is-loading .admin-tile-num,
.owner-status-value.is-pending {
  color: transparent !important;
  background-color: color-mix(in srgb, var(--t-text-3) 22%, transparent);
  background-image: linear-gradient(90deg,
    transparent 20%,
    color-mix(in srgb, var(--t-text-3) 42%, transparent) 45%,
    transparent 70%);
  background-size: 220% 100%;
  background-repeat: no-repeat;
  border-radius: 5px;
  animation: dashboard-shimmer 1.15s linear infinite;
}
/* the three statistic tiles: bar where the number will be, label left alone */
.owner-stats.is-loading strong { width: 42px; height: 18px; margin: 0 auto 5px; }
/* the same treatment inside the Admin dashboard's four tiles */
.admin-tiles.is-loading .admin-tile-num { display: block; width: 34px; height: 20px; margin: 0 auto 4px; }
/* status rows: the value column (Connection, Dashboard data, storage, …) */
.owner-status-value.is-pending { display: inline-block; width: 62px; height: 11px; }

/* audit card: three entries, two lines each — the shape of a real entry */
#owner-audit-list.owner-audit-list[aria-busy="true"] { display: block; }
.owner-skel-entry { padding: 9px 2px 11px; border-bottom: 1px solid var(--t-border-soft); }
.owner-skel-entry:last-child { border-bottom: 0; }
.owner-skel-bar {
  display: block; height: 12px; border-radius: 5px;
  background-color: color-mix(in srgb, var(--t-text-3) 22%, transparent);
  background-image: linear-gradient(90deg,
    transparent 20%,
    color-mix(in srgb, var(--t-text-3) 42%, transparent) 45%,
    transparent 70%);
  background-size: 220% 100%; animation: dashboard-shimmer 1.15s linear infinite;
}
.owner-skel-bar + .owner-skel-bar { margin-top: 7px; height: 9px; }
.owner-skel-bar.w-78 { width: 78%; }
.owner-skel-bar.w-52 { width: 52%; }
.owner-skel-bar.w-64 { width: 64%; }
.owner-skel-bar.w-38 { width: 38%; }
/* a staggered start reads as "several things loading", not one flashing block */
.owner-skel-entry:nth-child(2) .owner-skel-bar { animation-delay: .12s; }
.owner-skel-entry:nth-child(3) .owner-skel-bar { animation-delay: .24s; }

@media (prefers-reduced-motion: reduce) {
  .owner-skel-bar,
  .owner-stats.is-loading strong,
  .admin-tiles.is-loading .admin-tile-num,
  .owner-status-value.is-pending { animation: none; }
}

/* =====================================================================
   18. 💗 Love surprise (Owner dashboard → Appearance, + the recipient's reveal)
   The card is built from the same .bday-* pieces as the theme cards above, so it
   sits in the panel without any new layout. Only the gift-specific bits live here.
   ===================================================================== */
.love-gift-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 8px 0 0; }
.love-gift-label { color: var(--t-text-2); font-size: 12.5px; font-weight: 600; }
.love-gift-select { flex: 0 1 auto; min-width: 0; max-width: 220px; margin: 0; }
#love-admin #love-note { margin-top: 8px; }
#love-admin .bday-add-row { margin-top: 8px; }
.love-gift-list { margin-top: 10px; display: flex; flex-direction: column; gap: 8px; }
.love-gift-item {
  display: flex; align-items: flex-start; gap: 10px; flex-wrap: wrap;
  padding: 9px 11px; border: 1px solid color-mix(in srgb, #cf2f68 32%, var(--t-border));
  border-radius: 12px; background: color-mix(in srgb, #cf2f68 7%, var(--t-surface));
}
.love-gift-who { flex: 1 1 160px; min-width: 0; color: var(--t-text); font-size: 13px; font-weight: 600; overflow-wrap: anywhere; }
.love-gift-meta { display: block; margin-top: 3px; color: var(--t-text-3); font-size: 11px; font-weight: 500; }
.love-gift-note { flex: 1 1 100%; color: var(--t-text-2); font-size: 12.5px; font-style: italic; overflow-wrap: anywhere; }
.love-gift-item .button { flex: 0 0 auto; }
.manageusers-tag.love {
  border-color: color-mix(in srgb, #cf2f68 45%, var(--t-border));
  background: color-mix(in srgb, #cf2f68 12%, transparent); color: #cf2f68;
}
[data-theme="dark"] .manageusers-tag.love { color: #ff9dc0; }

/* the reveal: deliberately the one screen in the app that is not dressed like an
   admin panel — a heart, the note, and two honest choices. */
.love-reveal {
  max-width: 400px; margin: auto; padding: 26px 22px 20px; text-align: center;
  border-color: color-mix(in srgb, #cf2f68 38%, var(--t-border));
}
.love-reveal-heart { font-size: 54px; line-height: 1; animation: love-beat 1.6s ease-in-out infinite; }
@keyframes love-beat { 0%, 100% { transform: scale(1); } 18% { transform: scale(1.14); } 36% { transform: scale(1); } }
.love-reveal h3 { margin: 12px 0 6px; font-size: 20px; color: var(--t-text); }
.love-reveal-from { margin: 0 0 4px; color: var(--t-accent); font-size: 13.5px; font-weight: 700; }
.love-reveal-note {
  margin: 12px 0 0; padding: 11px 13px; border-radius: 12px; font-size: 14px; line-height: 1.5;
  background: var(--t-accent-soft); color: var(--t-text); overflow-wrap: anywhere;
}
.love-reveal-hint { margin: 14px 0 0; color: var(--t-text-3); font-size: 11.5px; line-height: 1.5; }
.love-reveal-actions { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-top: 18px; }
.love-reveal-actions .button { min-width: 130px; }
@media (prefers-reduced-motion: reduce) { .love-reveal-heart { animation: none; } }


/* =====================================================================
   19. Overview → the last seven days of messages
   Bars scaled to the busiest day of the week; today is the solid one.
   A quiet week still draws the row, so the card never looks broken.
   ===================================================================== */
.owner-spark-wrap { max-width: 320px; margin: 8px auto 0; }
.owner-spark-wrap.hidden { display: none; }
.owner-spark { display: flex; align-items: flex-end; gap: 6px; height: 46px; }
.owner-spark-bar {
  flex: 1 1 0; min-width: 6px; height: var(--h, 6%); min-height: 3px;
  border-radius: 4px 4px 2px 2px;
  background: color-mix(in srgb, var(--t-accent) 42%, transparent);
}
.owner-spark-bar.is-today { background: var(--t-accent); }
.owner-spark-caption { display: block; margin-top: 6px; text-align: center; font-size: 11.5px; color: var(--t-text-3); }
@media (prefers-reduced-motion: reduce) { .owner-spark-bar { transition: none; } }

/* ---------- Owner dashboard: headline summary cards ---------- */
/* One row above the tabs. Each card is a number plus one line of context, and
   the detailed controls stay inside the tab that owns them. Storage and AI copy
   their own section's summary chip (see data-owner-mirror), so every card still
   has a single source of truth rather than a second guess. */
/* v84: five equal columns inside a 560px sheet left ~73px of text each, so values
   and even labels broke mid-word ("BROADCAST S", "On · ft6zwh 07", "All system s
   operati onal"). Three columns give every card ~160px - enough for a short state
   on one line and a detail line under it - and the row becomes two tidy rows. */
.owner-status-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; padding: 10px 12px 4px; }
/* A real <button>: the whole card opens the tab it summarises, so the keyboard
   can reach it too. Styling is reset so it still looks like a card. */
.owner-status-card { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding: 10px 11px;
  border: 1px solid var(--t-border); border-radius: 11px; background: var(--t-surface-2);
  font: inherit; color: inherit; text-align: left; appearance: none; cursor: pointer;
  transition: border-color .16s ease, background .16s ease, transform .16s ease; }
.owner-status-card:hover { border-color: color-mix(in srgb, var(--t-accent) 55%, var(--t-border)); }
.owner-status-card:active { transform: translateY(1px); }
.owner-status-card:focus-visible { outline: 2px solid var(--t-accent); outline-offset: 2px; }
.owner-status-card-label { font-size: 10.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--t-text-3); overflow-wrap: break-word; }
.owner-status-card-value { display: flex; align-items: center; gap: 6px; min-height: 22px;
  font: 700 17px/1.2 'Fraunces', Georgia, serif; color: var(--t-text); overflow-wrap: break-word; }
/* status dot: themed accent while healthy, muted when a feature is simply off,
   the warning colour when the owning section reports a fault */
.owner-status-card-value::before { content: ""; flex: 0 0 auto; width: 8px; height: 8px; border-radius: 50%;
  background: var(--t-accent); }
.owner-status-card-value.is-off::before { background: var(--t-text-3); }
.owner-status-card-value.is-warn::before { background: var(--t-warn); }
.owner-status-card-value.is-warn { color: var(--t-warn); }
.owner-status-card-value.is-off { color: var(--t-text-3); }
/* v85: one plain line when something could not be read, with a retry. Amber,
   never red: it is "try again", not "something is broken". */
.owner-sys-alert { display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  margin: 8px 0 2px; padding: 8px 11px; border-radius: 10px; font-size: 12.5px;
  border: 1px solid color-mix(in srgb, var(--t-warn) 45%, var(--t-border));
  background: color-mix(in srgb, var(--t-warn) 12%, var(--t-surface-2)); color: var(--t-text); }
.owner-sys-alert[hidden] { display: none; }
.owner-sys-alert-retry { font: inherit; font-weight: 700; color: var(--t-accent);
  background: none; border: 0; padding: 0 2px; cursor: pointer; text-decoration: underline; }
.owner-sys-alert-retry:focus-visible { outline: 2px solid var(--t-accent); outline-offset: 2px; border-radius: 6px; }

.owner-status-card-note { font-size: 11px; color: var(--t-text-3); overflow-wrap: break-word; }
/* while a value is still arriving, show the shape of it instead of a dash */
.owner-status-card-value.is-pending::before { display: none; }
.owner-status-card-value.is-pending { color: transparent !important;
  background-color: color-mix(in srgb, var(--t-text-3) 22%, transparent);
  background-image: linear-gradient(90deg, transparent 20%,
    color-mix(in srgb, var(--t-text-3) 42%, transparent) 45%, transparent 70%);
  background-size: 220% 100%; background-repeat: no-repeat; border-radius: 5px;
  animation: dashboard-shimmer 1.15s linear infinite; }
/* Below ~400px a phone's full-width sheet gives three columns less than a
   label's worth of room, so the row becomes two columns. */
@media (max-width: 400px) { .owner-status-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (prefers-reduced-motion: reduce) { .owner-status-card-value.is-pending { animation: none; } }
