/* APPI Admin - hand-written CSS (the shared parts are COPIED from SportPerfect, UI_VERSION 15), no framework, built on the TOKENS below (appi/docs/UI_GUIDE.md section 7): no raw colours, font sizes or ad-hoc spacing outside this block.
   An app overrides ONLY the accent (--p-* in the palette rules); the neutrals, type scale, radii, spacing and motion are shared.
   One layout for every form factor: a bottom tab bar under 860px, a side rail from 860px; modals are full-screen sheets under 640px. */
:root {
  /* the accent: a light and a dark value, chosen by the palette (data-palette); the default palette is 'pitch' */
  --p-brand: #b03a08; --p-brand-fg: #ffffff; --p-soft: #ffe8d9; --p-brand-d: #ff9150; --p-brand-fg-d: #2a1000; --p-soft-d: #3d2112;
  /* neutrals, light */
  --brand: var(--p-brand); --brand-fg: var(--p-brand-fg); --brand-soft: var(--p-soft);
  --bg: #f5f7f7; --panel: #ffffff; --fg: #14191b; --muted: #596366; --line: #dce2e4;
  --good: #1a7f45; --bad: #c0392b; --warn: #8a5500; --warn-bg: #fff1cc;
  --shadow: 0 1px 2px rgb(20 25 27 / .06), 0 4px 14px rgb(20 25 27 / .05); --shadow-pop: 0 12px 40px rgb(0 0 0 / .3);
  --scrim: rgb(0 0 0 / .45); --media-bg: #000000; --media-fg: #ffffff;
  /* type: three sizes */
  --font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --text-sm: .85rem; --text-md: 1rem; --text-lg: 1.4rem;
  /* spacing (4px scale), radii (12 / 16, and 6 for tiny parts), tap target */
  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 24px; --space-6: 32px;
  --radius: 12px; --radius-lg: 16px; --radius-xs: 6px; --radius-pill: 999px; --gap: var(--space-4); --tap: 44px;
  /* motion: three durations and three easings (animate transform and opacity only) */
  --dur-1: 120ms; --dur-2: 200ms; --dur-3: 320ms; --ease: cubic-bezier(.2, .7, .2, 1); --ease-spring: cubic-bezier(.34, 1.4, .64, 1); --ease-exit: cubic-bezier(.4, 0, 1, 1);
  /* RHYTHM (UI guide, "Rhythm and type"; the sign-in card is the baseline): bands in a surface 16, titled sections 24, items in a group 8, a title and its subtitle 4; cards pad 24, inset blocks 16 */
  --stack: var(--space-4); --stack-section: var(--space-5); --stack-tight: var(--space-2); --stack-snug: var(--space-1); --pad-card: var(--space-5); --pad-inset: var(--space-4);
  --control: 52px; --avatar: 32px; --measure: 860px;
  --shade-1: rgb(0 0 0 / .38); --shade-2: rgb(0 0 0 / .55); --shade-3: rgb(0 0 0 / .62); --shade-4: rgb(0 0 0 / .75); --veil: rgb(255 255 255 / .45);
  --nav-h: 64px; --top-h: 52px;
  --scroll-thumb: color-mix(in srgb, var(--muted) 45%, transparent); --scroll-thumb-hover: color-mix(in srgb, var(--muted) 75%, transparent);
  --z-nav: 5; --z-top: 6; --z-modal: 40; --z-confirm: 50; --z-toast: 60;
  color-scheme: light dark;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-mode=light]) {
    --brand: var(--p-brand-d); --brand-fg: var(--p-brand-fg-d); --brand-soft: var(--p-soft-d);
    --bg: #0f1213; --panel: #171b1d; --fg: #e9eef0; --muted: #94a0a4; --line: #272e31;
    --good: #5ee59a; --bad: #ff8a7a; --warn: #f0c24f; --warn-bg: #3a3112; --shadow: none;
  }
}
:root[data-mode=light] { color-scheme: light; }
:root[data-mode=dark] {
  color-scheme: dark;
  --brand: var(--p-brand-d); --brand-fg: var(--p-brand-fg-d); --brand-soft: var(--p-soft-d);
  --bg: #0f1213; --panel: #171b1d; --fg: #e9eef0; --muted: #94a0a4; --line: #272e31;
  --good: #5ee59a; --bad: #ff8a7a; --warn: #f0c24f; --warn-bg: #3a3112; --shadow: none;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body { margin: 0; background: var(--bg); color: var(--fg); font: var(--text-md)/1.5 var(--font); }
h1, h2 { line-height: 1.15; margin: 0; letter-spacing: -.01em; }
h1 { font-size: var(--text-lg); font-weight: 700; } h2 { font-size: var(--text-md); font-weight: 700; }      /* TITLE = lg 700 (the app and the page); a section heading = md 700 */
p { margin: 0; } small, .muted { color: var(--muted); }
/* META = sm, muted: the line under a title, hints, helper text, captions, footers (one role, one size, wherever it appears) */
.lead, .hint, p.muted, small, .field-hint, .gate-foot, .empty p, .row-sub { font-size: var(--text-sm); }
.lead { color: var(--muted); margin-top: var(--stack-snug); }
button, input, select, textarea { font: inherit; color: inherit; }
:focus-visible { outline: 3px solid var(--brand); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; scroll-behavior: auto !important; } }

/* ---- controls ---- */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); min-height: var(--tap); padding: 0 var(--space-4); border-radius: var(--radius); border: 1px solid var(--line); background: var(--panel); cursor: pointer; }
.btn.primary { background: var(--brand); border-color: var(--brand); color: var(--brand-fg); font-weight: 600; }
.btn.ghost { background: transparent; border-color: transparent; }
.btn.danger { color: var(--bad); } .btn.wide { width: 100%; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.icon-btn { padding: 0 var(--space-3); } .icon { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; flex: none; }
.link { background: none; border: 0; color: var(--brand); cursor: pointer; padding: var(--space-2) 0; min-height: var(--tap); }
input, select, textarea { font-size: var(--text-md); width: 100%; min-height: var(--tap); padding: var(--space-2) var(--space-3); border: 1px solid var(--line); border-radius: var(--radius); background: var(--bg); }
textarea { resize: vertical; }
.field { display: flex; flex-direction: column; gap: var(--space-1); font-size: var(--text-sm); color: var(--muted); min-width: 0; } .field.inline { flex-direction: row; align-items: center; justify-content: space-between; gap: var(--space-3); } .field.inline input { max-width: 160px; }
.row { display: flex; gap: var(--space-2); flex-wrap: wrap; align-items: center; margin-top: var(--space-3); }
.chip { display: inline-block; padding: var(--space-1) var(--space-3); border-radius: var(--radius-pill); background: var(--brand-soft); color: var(--brand); font-size: var(--text-sm); }

/* ---- shell: bottom bar on phones, side rail on wide screens ---- */
.app { min-height: 100dvh; display: flex; flex-direction: column; }
.nav { position: fixed; inset: auto 0 0 0; z-index: 5; display: flex; background: var(--panel); border-top: 1px solid var(--line); padding-bottom: env(safe-area-inset-bottom); }
.nav .brand, .nav .nav-foot { display: none; }
.tab { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-1); min-height: var(--nav-h); background: none; border: 0; color: var(--muted); font-size: var(--text-sm); cursor: pointer; }
.tab.current { color: var(--brand); font-weight: 600; }
.content { flex: 1; width: 100%; max-width: 1080px; margin: 0 auto; padding: var(--gap) var(--gap) calc(var(--nav-h) + var(--gap) + env(safe-area-inset-bottom)); }
.update { position: sticky; top: 0; z-index: 6; display: flex; gap: var(--space-3); align-items: center; justify-content: center; padding: var(--space-2); background: var(--brand); color: var(--brand-fg); flex-wrap: wrap; }
.update .btn { min-height: 34px; background: var(--brand-fg); color: var(--brand); }
@media (min-width: 860px) {
  .app { flex-direction: row; flex-wrap: wrap; }
  .update { flex: 1 0 100%; position: static; }
  .nav { position: sticky; top: 0; inset: auto; height: 100dvh; flex: none; flex-direction: column; gap: var(--space-1); padding: var(--space-3); border-top: 0; border-right: 1px solid var(--line); }
  .nav .brand { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-4); white-space: nowrap; } .nav .nav-foot { display: flex; align-items: center; gap: var(--space-2); margin-top: auto; padding: var(--space-2); }
  .tab { flex: none; flex-direction: row; justify-content: flex-start; gap: var(--space-3); min-height: var(--tap); padding: 0 var(--space-3); border-radius: var(--radius); font-size: var(--text-sm); }
  .tab.current { background: var(--brand-soft); }
  .content { flex: 1; min-width: 0; padding: var(--space-5) var(--space-6) var(--space-6); }
}
.dot { width: 9px; height: 9px; border-radius: 50%; background: var(--muted); } .dot.on { background: var(--good); } .dot.off { background: var(--bad); }
.logo { display: grid; place-items: center; width: 56px; height: 56px; border-radius: var(--radius-lg); background: var(--brand); color: var(--brand-fg); font-weight: 800; font-size: var(--text-lg); } .logo.small { width: 34px; height: 34px; border-radius: var(--radius); font-size: var(--text-sm); }

/* ---- onboarding ---- */
.gate { min-height: 100dvh; display: grid; place-items: center; padding: var(--gap); }
.gate-card { width: min(420px, 100%); background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: var(--pad-card); display: flex; flex-direction: column; gap: var(--stack); box-shadow: var(--shadow); }
.gate-card .lead { margin: 0; } .hint { font-size: var(--text-sm); color: var(--muted); }
.banner { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); } .banner .btn.icon-only { border-color: transparent; background: transparent; } .banner, .banner-inline { padding: var(--space-3) var(--space-4); border-radius: var(--radius); background: var(--brand-soft); margin-bottom: var(--gap); } .banner.bad, .banner-inline.bad { background: var(--warn-bg); color: var(--bad); }

/* ---- views ---- */
.view { display: flex; flex-direction: column; gap: var(--stack-section); }
.view-head.row-head { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--space-3); flex-wrap: wrap; }
.section-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--space-2); }
section { display: flex; flex-direction: column; gap: var(--stack-tight); }
.card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--space-4); box-shadow: var(--shadow); display: flex; flex-direction: column; gap: var(--space-3); text-align: left; }
.empty { padding: var(--space-5); border: 1px dashed var(--line); border-radius: var(--radius); color: var(--muted); display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-3); } .empty.tall { min-height: 40vh; justify-content: center; align-items: center; text-align: center; }
.quick { display: flex; gap: var(--space-2); }
.stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-3); }
.stat { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--space-3); display: flex; flex-direction: column; } .stat strong { font-size: var(--text-lg); line-height: 1.1; } .stat span { color: var(--muted); font-size: var(--text-sm); } .stat.good strong { color: var(--good); } .stat.bad strong { color: var(--bad); }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr)); gap: var(--space-3); }
.card.metric { cursor: pointer; font: inherit; color: inherit; }
.card.metric:hover { border-color: var(--brand); }
.metric-head { display: flex; justify-content: space-between; gap: var(--space-2); } .metric-value { font-size: var(--text-lg); font-weight: 700; line-height: 1; } .metric-value small { font-size: var(--text-sm); font-weight: 400; }
.bar { height: 8px; border-radius: var(--radius-pill); background: var(--line); overflow: hidden; } .bar.big { height: 12px; } .bar span { display: block; height: 100%; background: var(--brand); border-radius: inherit; }
.list { display: flex; flex-direction: column; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel); overflow: hidden; }
.row-item { display: flex; flex-direction: row; gap: var(--space-3); align-items: center; text-align: left; padding: var(--space-3) var(--space-4); background: none; border: 0; border-bottom: 1px solid var(--line); cursor: pointer; width: 100%; min-height: var(--tap); }
.row-item:last-child { border-bottom: 0; } .row-item.active { background: var(--brand-soft); } .row-item .muted { display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row-item.flat { flex-direction: row; align-items: center; justify-content: space-between; cursor: default; } .row-item.flat .row-main { flex: 1; } .row-item.flat .row-main .muted { flex: none; text-align: left; padding: 0; } .row-item.flat .muted { flex: 1; text-align: right; padding: 0 var(--space-2); }
.row-meta { display: flex; gap: var(--space-2); align-items: center; }
.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--space-3); } .form-row { display: grid; grid-template-columns: 1fr 1fr auto; gap: var(--space-3); align-items: end; }
@media (max-width: 520px) { .form-row { grid-template-columns: 1fr 1fr; } .form-row .btn { grid-column: 1 / -1; } }
.facts { margin: 0; padding-left: var(--space-4); color: var(--muted); display: flex; flex-direction: column; gap: var(--space-1); }

/* ONE button language: actions are icon-only (tooltip + accessible name), the same size and shape everywhere */
.btn.icon-only { width: var(--tap); min-width: var(--tap); padding: 0; gap: 0; flex: none; }
.btn.icon-only .icon { width: 22px; height: 22px; }
.btn.icon-only.primary { background: var(--brand); border-color: var(--brand); color: var(--brand-fg); }
.btn.icon-only.danger { color: var(--bad); }
.btn.icon-only.danger:hover:not(:disabled) { background: color-mix(in srgb, var(--bad) 10%, transparent); }
.btn.icon-only.primary.danger { background: var(--bad); border-color: var(--bad); color: var(--media-fg); }
.btn.icon-only:disabled { opacity: .45; cursor: default; }
.btn.icon-only.wide { width: 100%; }
.btn.icon-only:focus-visible, .kind:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.vc-pick { position: relative; cursor: pointer; }
.vc-pick .file { position: absolute; inset: 0; opacity: 0; cursor: pointer; width: 100%; }
.wdot { display: block; border-radius: 50%; background: currentColor; }
.vn-width.primary .wdot { background: var(--brand-fg); }
.gate-others { display: grid; gap: var(--space-2); }
/* a collapsible section (ui.js disclosure): the chevron turns when it opens */
.disclosure-head { display: flex; align-items: center; gap: var(--space-2); width: 100%; min-height: var(--tap); background: none; border: 0; padding: var(--space-1) var(--space-1); color: var(--muted); font: inherit; text-align: left; cursor: pointer; border-radius: var(--radius); }
.disclosure-head:hover { color: var(--fg); }
.disclosure-head .icon { transition: transform var(--dur-1) var(--ease); }
.disclosure.open > .disclosure-head .icon { transform: rotate(90deg); }
.disclosure-body { display: grid; gap: var(--space-2); }
/* a row that is one button (optionRow): the text and its icon, hover and press feedback over the whole row */
.option-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); width: 100%; min-height: calc(var(--tap) + 2 * var(--space-1)); padding: var(--space-1) var(--space-1) var(--space-1) var(--space-3); border: 0; border-radius: var(--radius); background: transparent; color: var(--muted); font: inherit; text-align: left; cursor: pointer; transition: background-color var(--dur-1) var(--ease), transform var(--dur-1) var(--ease); }
.option-row:hover { background: color-mix(in srgb, var(--brand-soft) 55%, transparent); color: var(--fg); }
.option-row:active { background: var(--brand-soft); color: var(--fg); transform: scale(.98); }
.option-row-icon { display: inline-flex; align-items: center; justify-content: center; flex: none; width: var(--tap); height: var(--tap); border-radius: var(--radius-xs); color: var(--fg); }
.option-row:hover .option-row-icon, .option-row:active .option-row-icon { color: var(--brand); }
.option-row-icon .icon { width: 22px; height: 22px; }
.option-row.danger .option-row-icon { color: var(--bad); }
.kind-picker { display: flex; gap: var(--space-3); align-items: center; }
.kind-picker .kind { width: 64px; height: 64px; min-height: 64px; padding: 0; display: grid; place-items: center; }
.kind-picker .kind .icon { width: 30px; height: 30px; }
.kind-picker .kind-cancel { margin-left: auto; }
.section-head .btn.icon-only { min-height: 36px; width: 36px; min-width: 36px; }

/* the "are you sure" dialog */
.confirm-backdrop { position: fixed; inset: 0; z-index: var(--z-confirm); display: grid; place-items: center; padding: var(--space-4); background: var(--scrim); animation: fade var(--dur-2) var(--ease); }
.confirm { width: min(360px, 100%); display: grid; gap: var(--space-3); padding: var(--space-5); border-radius: var(--radius-lg); background: var(--panel); color: inherit; border: 1px solid var(--line); box-shadow: var(--shadow-pop); animation: pop var(--dur-3) var(--ease-spring); }
.confirm-message { margin: 0; font-weight: 600; }
.confirm-detail { margin: 0; }
.confirm-actions { display: flex; justify-content: flex-end; gap: var(--space-3); } .confirm-actions .btn { min-width: 96px; } .btn.primary.danger { background: var(--bad); border-color: var(--bad); color: var(--bg); }

/* profiles: the account bar in the rail and the settings card */
.nav-account { padding: var(--space-2) 0 0; border-top: 1px solid var(--line); }      /* no bottom padding: the profile row's own padding matches the title row's, so the gap below it equals the gap above the title */
.profile-card { display: grid; gap: var(--space-3); }
.gate-card .profiles { margin: var(--space-1) 0; }
@media (max-width: 859px) { .nav-account { display: none; } }
@media (min-width: 860px) { .nav .nav-account { margin-top: auto; } .nav .nav-account + .nav-foot { margin-top: 0; } .nav-account .account-bar { flex-wrap: wrap; } }

/* ---- the sign-in card: brand on one line, the password and its button side by side ---- */
.gate-card { position: relative; }
.gate-brand { display: flex; align-items: center; gap: var(--space-4); padding-right: calc(var(--tap) + var(--space-2)); }
.gate-brand .mode-toggle { position: absolute; top: 14px; right: 14px; }
.gate-row { display: flex; align-items: flex-end; gap: var(--space-3); } .gate-row .field { flex: 1; }



/* ============================================================================================================================================================================
   THE UI LAYER (ui.fd1fc882d9.js): shell, modal, toast, states, fields, rows, motion. Everything uses the tokens; animate transform and opacity only.
   ============================================================================================================================================================================ */
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes pop { from { opacity: 0; transform: translateY(12px) scale(.97); } to { opacity: 1; transform: none; } }
@keyframes sheet { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: none; } }
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes flash { 0%, 40% { background-color: var(--brand-soft); } 100% { background-color: transparent; } }
@keyframes toast-in { from { opacity: 0; transform: translateY(16px) scale(.96); } to { opacity: 1; transform: none; } }
@keyframes row-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes shimmer { from { opacity: .45; } to { opacity: .9; } }
@keyframes page-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: var(--dur-2); animation-timing-function: var(--ease); }
@media (prefers-reduced-motion: reduce) { ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; } }
.spin { animation: spin 1s linear infinite; }
.btn { transition: background-color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease), transform var(--dur-1) var(--ease); }
.btn:active:not(:disabled) { transform: scale(.95); }
.view { animation: page-in var(--dur-3) var(--ease) both; }

/* ---- the shell: a header (title, search, sync status, settings) above the page; the content leaves room for it and for the bottom bar ---- */
.content { --pad-x: var(--gap); --pad-y: var(--gap); padding: var(--pad-y) var(--pad-x) calc(var(--nav-h) + var(--gap) + env(safe-area-inset-bottom)); }
@media (min-width: 860px) { .content { --pad-x: var(--space-6); --pad-y: 28px; padding: var(--pad-y) var(--pad-x) var(--space-6); } }
.topbar { position: sticky; top: 0; z-index: var(--z-top); display: flex; align-items: center; gap: var(--space-1); min-height: var(--top-h); padding: var(--space-1) var(--pad-x); margin: calc(-1 * var(--pad-y)) calc(-1 * var(--pad-x)) var(--pad-y); background: color-mix(in srgb, var(--bg) 90%, transparent); backdrop-filter: blur(10px); border-bottom: 1px solid var(--line); }
.topbar .spacer, .pane-head .spacer, .modal-foot .spacer { flex: 1; }
.topbar-title { font-size: var(--text-md); }
.topbar-logo { margin-right: var(--space-2); }
@media (min-width: 860px) { .topbar-logo { display: none; } }
.topbar .btn.icon-only { border-color: transparent; background: transparent; }
.status-chip.synced { color: var(--good); } .status-chip.attention { color: var(--warn); } .status-chip.offline, .status-chip.local { color: var(--muted); }
.tab { transition: color var(--dur-1) var(--ease); }
.tab .icon { transition: transform var(--dur-2) var(--ease-spring); } .tab.current .icon { transform: translateY(-1px) scale(1.08); }

/* ---- the modal: three sizes, a full-screen sheet on phones, a sticky footer ---- */
html.modal-open { overflow: hidden; }
.modal-backdrop { position: fixed; inset: 0; z-index: var(--z-modal); display: grid; place-items: center; padding: var(--space-4); background: var(--scrim); animation: fade var(--dur-2) var(--ease); }
.modal { width: min(520px, 100%); max-height: min(92dvh, 100%); display: flex; flex-direction: column; border-radius: var(--radius-lg); background: var(--panel); color: inherit; border: 1px solid var(--line); box-shadow: var(--shadow-pop); overflow: hidden; animation: pop var(--dur-3) var(--ease-spring); }
.modal.wide { width: min(980px, 100%); }
.modal.screen { width: 100%; height: 100%; max-height: none; border-radius: 0; border: 0; }
.modal-backdrop:has(.modal.screen) { padding: 0; }
.modal-form { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.modal-head { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4); border-bottom: 1px solid var(--line); min-height: 56px; }
.modal-head h2 { flex: 1; margin: 0; font-size: var(--text-md); }
.modal-head .btn.icon-only { border-color: transparent; background: transparent; }
.modal-body { display: flex; flex-direction: column; gap: var(--stack); padding: var(--space-4); overflow-y: auto; flex: 1; min-height: 0; }
.modal.screen .modal-body > * { width: min(860px, 100%); margin-inline: auto; }
.modal.screen .modal-head, .modal.screen .modal-foot { padding-inline: max(var(--space-4), calc((100% - var(--measure)) / 2)); }
.modal.screen .rich-editor-wrap { display: flex; flex-direction: column; flex: 1; } .modal.screen .rich-toolbar { order: 2; position: sticky; bottom: 0; background: var(--panel); padding: var(--space-2) 0; border-top: 1px solid var(--line); }
.modal-foot { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-3) var(--space-4) calc(var(--space-3) + env(safe-area-inset-bottom)); border-top: 1px solid var(--line); background: var(--panel); }
@media (max-width: 640px) {
  .modal-backdrop { padding: 0; place-items: stretch; }
  .modal, .modal.wide, .modal.screen { width: 100%; height: 100%; max-height: none; border-radius: 0; border: 0; animation: sheet var(--dur-3) var(--ease); }
}

/* ---- the toast and the row highlight ---- */
.toast-region { position: fixed; left: 0; right: 0; bottom: calc(var(--nav-h) + var(--space-4) + env(safe-area-inset-bottom)); z-index: var(--z-toast); display: flex; justify-content: center; padding: 0 var(--space-4); pointer-events: none; }
@media (min-width: 860px) { .toast-region { bottom: var(--space-5); } }
.toast { display: flex; align-items: center; gap: var(--space-2); max-width: 480px; padding: var(--space-3) var(--space-4); border-radius: var(--radius); background: var(--fg); color: var(--bg); box-shadow: var(--shadow-pop); animation: toast-in var(--dur-3) var(--ease-spring); }
.toast .icon { color: var(--good); }
.flash { animation: flash 1.8s var(--ease); }

/* ---- the three states ---- */
.empty { align-items: center; text-align: center; padding: var(--space-5); gap: var(--space-3); } .empty .icon { width: 32px; height: 32px; opacity: .7; }
.skeleton { display: flex; flex-direction: column; gap: var(--space-2); }
.skeleton-row { height: 56px; border-radius: var(--radius); background: var(--line); animation: shimmer .9s ease-in-out infinite alternate; }
.error-notice { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); border-radius: var(--radius); background: var(--warn-bg); color: var(--warn); } .error-notice p { flex: 1; }

/* ---- form fields: the label above, helper text below, errors in red under the field ---- */
.field-label { font-size: var(--text-sm); color: var(--muted); }
.field-hint { font-size: var(--text-sm); } .field-error { font-size: var(--text-sm); color: var(--bad); }
.field.has-error input, .field.has-error select, .field.has-error textarea { border-color: var(--bad); }
.field.toggle { flex-direction: row; align-items: center; gap: var(--space-3); min-height: var(--tap); color: var(--fg); font-size: var(--text-md); }
input[type=checkbox][role=switch] { appearance: none; width: 46px; min-width: 46px; height: 28px; min-height: 28px; padding: 0; border-radius: var(--radius-pill); border: 1px solid var(--line); background: var(--line); position: relative; cursor: pointer; transition: background-color var(--dur-2) var(--ease); }
input[type=checkbox][role=switch]::after { content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; border-radius: 50%; background: var(--panel); box-shadow: var(--shadow); transition: transform var(--dur-2) var(--ease-spring); }
input[type=checkbox][role=switch]:checked { background: var(--brand); border-color: var(--brand); }
input[type=checkbox][role=switch]:checked::after { transform: translateX(18px); }
.chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.chip-choice { min-height: var(--tap); padding: 0 var(--space-4); border-radius: var(--radius-pill); border: 1px solid var(--line); background: var(--panel); cursor: pointer; transition: background-color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease); }
.chip-choice.on { background: var(--brand-soft); border-color: var(--brand); color: var(--brand); font-weight: 600; }

/* ---- the one list row: leading part, title + one subline + chips, trailing part ---- */
.list-row { animation: row-in var(--dur-2) var(--ease) both; transition: background-color var(--dur-1) var(--ease); }
.list-row:hover { background: color-mix(in srgb, var(--brand-soft) 55%, transparent); }
.row-lead { display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; border-radius: var(--radius); background: var(--brand-soft); color: var(--brand); flex: none; overflow: hidden; }
.row-lead img { width: 100%; height: 100%; object-fit: cover; }
.row-main { display: flex; flex-direction: column; gap: var(--space-1); flex: 1; min-width: 0; }
.row-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row-sub { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row-trail { display: flex; align-items: center; color: var(--muted); flex: none; }
.row-trail .spark { width: 84px; height: 28px; }
.list-row.flash { animation: flash 1.8s var(--ease); }

/* ---- search, settings, the gate's steps ---- */
.search-bar { display: flex; gap: var(--space-2); align-items: center; } .search-bar input { flex: 1; }
.search-groups { display: flex; flex-direction: column; gap: var(--space-4); }
.search-group h2 { font-size: var(--text-sm); color: var(--muted); margin-bottom: var(--space-2); }
.settings-group { display: flex; flex-direction: column; gap: var(--space-2); }
.settings-group > h2 { font-size: var(--text-sm); color: var(--muted); padding: 0 var(--space-1); }
.settings-group.danger > h2 { color: var(--bad); }
.gate-steps { display: flex; justify-content: center; gap: var(--space-2); }
.gate-step { width: 8px; height: 8px; border-radius: 50%; background: var(--line); transition: background-color var(--dur-2) var(--ease), transform var(--dur-2) var(--ease-spring); }
.gate-step.on { background: var(--brand); transform: scale(1.3); }
.gate-head { display: flex; align-items: center; gap: var(--space-2); }

/* ---- the shared player controls (player.js): a bar over the bottom of the stage, hidden while it plays, back on a tap ---- */
.vc-stage, .vn-stage { position: relative; }      /* the stage the controls sit on (the controls are the last child of it) */
.pl-controls { position: absolute; left: 0; right: 0; bottom: 0; display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3); background: linear-gradient(transparent, var(--shade-4)); color: var(--media-fg); transition: opacity var(--dur-2) var(--ease); }
.pl-controls.pl-hidden { opacity: 0; pointer-events: none; }
.pl-controls .btn.icon-only { background: transparent; border-color: transparent; color: var(--media-fg); }
.pl-range { flex: 1; min-width: 0; padding: 0; min-height: 28px; accent-color: var(--brand); background: transparent; border: 0; }
.pl-time { font-size: var(--text-sm); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ---- THIN SCROLLBARS everywhere (standard properties first, WebKit for older browsers) ---- */
* { scrollbar-width: thin; scrollbar-color: var(--scroll-thumb) transparent; }
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--scroll-thumb); border-radius: var(--radius-pill); border: 2px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-thumb:hover { background: var(--scroll-thumb-hover); background-clip: content-box; }
::-webkit-scrollbar-corner { background: transparent; }

/* ---- WIDE SCREENS: the side menu stays put and only the main view scrolls; the menu collapses to icons ---- */
@media (min-width: 860px) {
  .app { display: grid; grid-template-columns: max-content minmax(0, 1fr); grid-template-rows: auto auto minmax(0, 1fr); height: 100dvh; overflow: hidden; }      /* the menu is as wide as its widest item (the app's title): nothing fixed, so any app's title fits */
  .app > .update, .app > .proxy-job { grid-column: 1 / -1; position: static; }
  .app > .nav { grid-row: 3; position: static; height: auto; width: auto; overflow-x: hidden; overflow-y: auto; }
  .app > .content { grid-row: 3; grid-column: 2; min-height: 0; overflow-y: auto; }
  .nav.collapsed { padding-inline: var(--space-2); align-items: center; }
  .nav.collapsed .app-brand-text, .nav.collapsed .tab-label, .nav.collapsed .nav-foot small { display: none; }
  .nav.collapsed .brand { justify-content: center; } .nav.collapsed .brand-toggle { padding: var(--space-3) 0; width: var(--tap); }
  .nav.collapsed .tab { justify-content: center; padding: 0; width: var(--tap); }
  .nav.collapsed .nav-account { width: 100%; }
  .nav.collapsed .profile-row { justify-content: center; padding: var(--space-3) 0; } .nav.collapsed .profile-row-name { display: none; }
}
@media (min-width: 860px) {
  .app > .content { max-width: none; margin: 0; }
  .app > .content > :not(.topbar) { max-width: 1080px; margin-inline: auto; }
}
@media (min-width: 860px) { .topbar { top: calc(-1 * var(--pad-y)); } }      /* the main view is its own scroller: its padding is above the header's stuck position */

/* the brand toggles the menu (wide screens); the profile row opens the Profile window, where switching and logging out live */
.brand-toggle { background: none; border: 0; color: inherit; font: inherit; text-align: left; cursor: default; width: 100%; padding: var(--space-3); }
@media (min-width: 860px) { .brand-toggle { cursor: pointer; border-radius: var(--radius); } .brand-toggle:hover { background: color-mix(in srgb, var(--brand-soft) 55%, transparent); } }
.profile-row { display: flex; align-items: center; justify-content: flex-start; gap: var(--space-2); width: 100%; min-height: var(--tap); padding: var(--space-3); background: none; border: 0; border-radius: var(--radius); color: inherit; font: inherit; cursor: pointer; text-align: left; }
.profile-row:hover { background: color-mix(in srgb, var(--brand-soft) 55%, transparent); }
.profile-row-name { flex: 1; min-width: 0; text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* wide menu: the icon column stays where it is; the text column takes the rest of the row and centres its text */
@media (min-width: 860px) { .nav:not(.collapsed) .tab .tab-label { flex: 1; text-align: center; } }

/* the sign-in screen's profiles: the choices and the add button in one wrapping row */
.gate-card .profiles { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
.gate-card .profile-list, .gate-card .profile-actions { display: contents; }
.gate-card .profile-list { list-style: none; margin: 0; padding: 0; }

/* every window has an icon before its title; the profile window's name is edited in place */
.modal-head .modal-icon { color: var(--brand); flex: none; }
.profile-head { display: flex; align-items: center; gap: 0; } .profile-head .spacer { flex: 1; }      /* the name's own padding supplies the 8 px after the avatar */
.inline-text { display: inline-flex; align-items: center; gap: var(--space-2); min-height: var(--tap); padding: 0 var(--space-2); background: none; border: 0; border-radius: var(--radius); color: inherit; font: inherit; font-weight: 600; cursor: text; min-width: 0; }
.inline-text:hover { background: color-mix(in srgb, var(--brand-soft) 55%, transparent); }
.inline-text .icon { width: 16px; height: 16px; opacity: .55; flex: none; }
.inline-text-value { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.inline-text-input { flex: 1; min-width: 0; font-weight: 600; }

.topbar-icon { color: var(--brand); flex: none; margin-right: var(--space-2); }

/* ---- the label rule: floating labels for text fields (the label sits inside and moves up on focus or when filled); plain = placeholder only ---- */
.field.float { position: relative; gap: 0; color: var(--fg); font-size: var(--text-md); }
.field.float input, .field.float textarea { padding-top: var(--space-5); padding-bottom: var(--space-1); min-height: var(--control); }
.field.float textarea { min-height: 96px; }
.field.float .field-label { position: absolute; left: 13px; top: 26px; transform: translateY(-50%); transform-origin: left top; font-size: var(--text-md); color: var(--muted); pointer-events: none; transition: transform var(--dur-2) var(--ease), top var(--dur-2) var(--ease), color var(--dur-2) var(--ease); max-width: calc(100% - 26px); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.field.float.area .field-label { top: 24px; }
.field.float input:focus + .field-label, .field.float input:not(:placeholder-shown) + .field-label, .field.float input:-webkit-autofill + .field-label,
.field.float textarea:focus + .field-label, .field.float textarea:not(:placeholder-shown) + .field-label { top: 7px; transform: translateY(0) scale(.78); color: var(--brand); }
.field.float input:not(:focus):not(:placeholder-shown) + .field-label, .field.float textarea:not(:focus):not(:placeholder-shown) + .field-label { color: var(--muted); }
.field.float input::placeholder, .field.float textarea::placeholder { color: transparent; }
.field.float input:focus::placeholder, .field.float textarea:focus::placeholder { color: var(--muted); opacity: .8; }
.field.float.has-error .field-label { color: var(--bad); }
.field.float .field-hint, .field.float .field-error { margin-top: var(--space-1); }
.field.plain { gap: var(--space-1); }

/* the action inside the input (see ui.js field({ action })): the label of a floating field stops before it; the quick note and chat boxes are one field */
.field.float.has-action .field-label { max-width: calc(100% - 26px - 52px); }
.gate-card .profile-form { flex: 1 1 100%; margin-top: var(--space-4); }      /* the same air between the chips and what follows as in every other mode */
.quick > .field { flex: 1; min-width: 0; }
.gate-card .field.has-action { width: 100%; }

/* the app card (ui.js appBrand): icon, title and subtitle as one unit; the subtitle sits under the title, beside the icon */
.app-brand { display: flex; align-items: center; gap: var(--space-3); min-width: 0; }
.app-brand-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.2; }
.app-brand-title { margin: 0; font-size: var(--text-md); font-weight: 700; white-space: nowrap; }
.app-brand-subtitle { margin-top: var(--space-1); font-size: var(--text-sm); color: var(--muted); line-height: 1.3; }
.app-brand.large .logo { width: 56px; height: 56px; flex: none; font-size: var(--text-lg); }
.app-brand.large .app-brand-title { font-size: var(--text-lg); letter-spacing: -.01em; }
.app-brand.compact .logo { width: 34px; height: 34px; flex: none; border-radius: var(--radius); font-size: var(--text-sm); }

/* the sign-in card's pacing: air around the profile chips, and a quiet line at the bottom that anchors the card */
.gate-card { gap: var(--space-4); }
.gate-card .profiles { margin-block: var(--space-2); }
.gate-foot { margin: var(--space-2) 0 0; padding-top: var(--space-4); border-top: 1px solid var(--line); text-align: center; font-size: var(--text-sm); color: var(--muted); }

/* PROFILE IDENTITY (UI guide, section 7b): the same everywhere a profile is shown - the sign-in chip, the Profile window and the menu row: a 32 px avatar, the name in body size (md) at weight 600, 8 px between them */
.avatar { width: var(--avatar); height: var(--avatar); font-size: var(--text-md); font-weight: 700; }
.profile .profile-name, .profile-row-name, .inline-text, .inline-text-input { font-size: var(--text-md); font-weight: 600; }
.profile, .profile-row { gap: var(--space-2); }

/* THE WAY BACK: a plain chevron and the parent's name (never a boxed button). In the header it replaces the section title on that page; in a card it sits at the top. */
.topbar-back, .back-link { display: inline-flex; align-items: center; gap: var(--space-1); min-height: var(--tap); padding: 0 var(--space-2) 0 0; background: none; border: 0; color: var(--brand); font: inherit; font-weight: 600; cursor: pointer; min-width: 0; }
.topbar-back span, .back-link span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topbar-back:hover, .back-link:hover { text-decoration: underline; }
.topbar-title-wrap { display: inline-flex; align-items: center; min-width: 0; }
.topbar.has-back .topbar-title-wrap { display: none; }
@media (max-width: 859px) { .topbar.has-back-phone .topbar-title-wrap { display: none; } }
@media (min-width: 860px) { .topbar-back.phone-only { display: none; } }
.gate-head { display: flex; flex-direction: column; align-items: flex-start; gap: var(--stack-snug); }
.gate-step-title { font-size: var(--text-lg); }

/* ---- NARROW WINDOWS AND PHONES: the same structure as wide screens - the main view is its own scroller and the bottom bar is a row of its own, so the scroll bar ends above the bar instead of running behind it ---- */
@media (max-width: 859px) {
  .app { display: grid; grid-template-rows: auto auto minmax(0, 1fr) auto; height: 100dvh; overflow: hidden; }
  .app > .update, .app > .proxy-job { position: static; }
  .app > .nav { position: static; grid-row: 4; }
  .app > .content { grid-row: 3; min-height: 0; overflow-y: auto; padding-bottom: var(--pad-y); }
  .topbar { top: calc(-1 * var(--pad-y)); }
}

/* sync problems (the Sync window): enough to debug - the document, the error code, the detail, the node's raw answer */
.sync-problems { display: flex; flex-direction: column; gap: var(--stack-tight); }
.problem { display: flex; flex-direction: column; gap: var(--stack-snug); padding: var(--space-3); border-radius: var(--radius); background: var(--warn-bg); min-width: 0; }
.problem-name { overflow-wrap: anywhere; } .problem-code { color: var(--warn); font-weight: 600; } .problem-detail { color: var(--fg); overflow-wrap: anywhere; }
.problem-raw summary { cursor: pointer; font-size: var(--text-sm); color: var(--muted); }
.problem-raw pre { margin: var(--space-2) 0 0; font: var(--text-sm)/1.4 var(--mono); white-space: pre-wrap; overflow-wrap: anywhere; }

.sync-notes { display: flex; flex-direction: column; gap: var(--stack-snug); overflow-wrap: anywhere; }

.problem-hint { overflow-wrap: anywhere; }

/* the node's health in the Sync window: version, the administrator's message, an update notice that matters, the download link */
.node-info { display: flex; flex-direction: column; gap: var(--stack-snug); }
.node-message { overflow-wrap: anywhere; }
.update-notice { display: flex; align-items: flex-start; gap: var(--space-2); padding: var(--space-3); border-radius: var(--radius); background: var(--warn-bg); color: var(--warn); font-size: var(--text-sm); } .update-notice.critical { color: var(--bad); }
.download-link { display: inline-flex; align-items: center; gap: var(--space-2); min-height: var(--tap); color: var(--brand); font-weight: 600; text-decoration: none; } .download-link:hover { text-decoration: underline; }
.download-sum { overflow-wrap: anywhere; }


/* ---- APPI Admin: the install window, the file picker, the gate's second steps ---- */
.file-pick { justify-content: flex-start; width: 100%; }
.install-form { grid-template-columns: 1fr; }
.install-preview { display: grid; gap: var(--stack-snug); padding: var(--pad-inset); border: 1px solid var(--line); border-radius: var(--radius); background: var(--brand-soft); }
.gate-device { display: grid; gap: var(--stack); }

/* ---- the dashboard: meters, bars, usage rows, the log ---- */
.meter { display: block; }
.meter-track { height: var(--space-2); border-radius: var(--radius-pill); background: var(--line); overflow: hidden; }
.meter-fill { height: 100%; border-radius: var(--radius-pill); background: var(--brand); transition: width var(--dur-2) var(--ease); }
.meter.warn .meter-fill { background: var(--warn); }
.meter.bad .meter-fill { background: var(--bad); }
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; /* ui-lint-ignore: visually hidden text */ padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
.chart-figure { margin: 0; display: grid; gap: var(--stack-tight); }
.bars { width: 100%; height: 96px; display: block; }
.bar-a { fill: var(--brand); } .bar-b { fill: var(--bad); }
.chart-caption { display: flex; justify-content: space-between; gap: var(--space-2); font-size: var(--text-sm); color: var(--muted); }
.usage-row { display: grid; gap: var(--space-1); }
.usage-head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; }
.chip.bad { background: color-mix(in srgb, var(--bad) 14%, transparent); color: var(--bad); }
.chip.warn { background: var(--warn-bg); color: var(--warn); }
.mono { font-family: var(--mono); font-size: var(--text-sm); } .wrap { overflow-wrap: anywhere; }
.head-actions { display: inline-flex; gap: var(--space-1); margin-left: auto; }
.attention { gap: var(--space-2); }
.attention-item { display: flex; align-items: center; gap: var(--space-3); min-height: var(--tap); padding: 0 var(--space-3); border: 1px solid var(--line); border-radius: var(--radius); background: var(--warn-bg); color: var(--fg); text-align: left; cursor: pointer; }
.attention-item span { flex: 1; }
.log { list-style: none; margin: 0; padding: 0; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel); max-height: 420px; overflow: auto; }
.log-line { display: flex; gap: var(--space-3); padding: var(--space-1) var(--space-3); border-bottom: 1px solid var(--line); font-family: var(--mono); font-size: var(--text-sm); overflow-wrap: anywhere; }
.log-line.bad { color: var(--bad); } .log-time { color: var(--muted); flex: none; } .log-event { flex: none; font-weight: 600; } .log-detail { color: var(--muted); min-width: 0; }
.quick .field { flex: 1; }
@media (max-width: 859px) { .stats { grid-template-columns: repeat(2, 1fr); } }
/* MAINTENANCE (2026-11-05): the scheduled window on the overview card; a window in force uses the warning colours */
.maint-status { display: flex; align-items: center; gap: var(--space-2); color: var(--muted); }
.maint-status.active { color: var(--warn); font-weight: 600; }
/* DOCUMENTS (2026-11-06): a guide from appi/docs/node, rendered by @appi/markdown; running text at the reading measure, tables and code scroll sideways on a phone */
.doc-view .md { max-width: var(--measure); line-height: 1.55; overflow-wrap: anywhere; }
.md h1 { font-size: var(--text-lg); margin: 0 0 var(--space-3); }
.md h2 { font-size: var(--text-md); margin: var(--space-6) 0 var(--space-2); }
.md h3, .md h4 { font-size: var(--text-md); margin: var(--space-5) 0 var(--space-2); color: var(--muted); }
.md p, .md ul, .md ol, .md blockquote { margin: 0 0 var(--space-3); }
.md ul, .md ol { padding-left: var(--space-5); }
.md li { margin: var(--space-1) 0; }
.md li > p, .md li > ul, .md li > ol, .md li > pre { margin: var(--space-1) 0; }
.md code { font-family: var(--mono); font-size: var(--text-sm); background: color-mix(in srgb, var(--line) 55%, transparent); padding: 0 4px; border-radius: var(--radius-xs); }
.md pre.md-code { margin: 0 0 var(--space-3); padding: var(--space-3); overflow-x: auto; background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius-xs); }
.md pre.md-code code { background: none; padding: 0; overflow-wrap: normal; white-space: pre; }
.md blockquote { padding-left: var(--space-3); border-left: 4px solid var(--line); color: var(--muted); }
.md hr { border: 0; border-top: 1px solid var(--line); margin: var(--space-5) 0; }
.md a { color: var(--brand); }
.md .md-table { overflow-x: auto; margin: 0 0 var(--space-3); }
.md table { border-collapse: collapse; font-size: var(--text-sm); min-width: 100%; }
.md th, .md td { text-align: left; vertical-align: top; padding: var(--space-2); border-bottom: 1px solid var(--line); }
.md th { color: var(--muted); font-weight: 600; }
.md td code { overflow-wrap: normal; white-space: nowrap; }
.md h1, .md h2, .md h3 { scroll-margin-top: var(--space-4); }
