/* app.css — the application shell and its shared components (Expocity look).
   ═══════════════════════════════════════════════════════════════════════════
   Direction, taken from the Expocity ("21 Experiences") dashboard and the SAFF
   port of this same codebase (swpl-dashboard 4791397): a floating dark sidebar
   that opens to 264px and collapses to an 84px icon rail; soft 22px cards on a
   quiet grey page; pill tab bar on a phone.

   LOAD ORDER on every page — it is the whole contract:

       design-system.css   tokens (never edited for a page)
       app.css             THIS FILE: shell + shared components
       <style> inline      the page's own legacy rules (wins ties over this file)
       items/<item>.css    one file per restyle item (wins ties over everything)

   So: a class defined here is the default; the page's inline <style> still
   beats it on equal specificity until that legacy rule is removed; and an
   item stylesheet beats both. Item stylesheets scope everything to their own
   root (#panel-zones, #panel-people, … or body.page-overview / body.page-login)
   so eight of them can be written in parallel without touching each other.

   Tokens come from design-system.css; only meaning-level aliases live here.
   The shared sheet's old `.pl-tabs` rail is NOT used any more: the sidebar
   below replaces it, and its `html body{padding-left}` gutter is cancelled in
   the base rules.

   Football has no Arabic/RTL, so the SAFF right-to-left additions are not
   here; logical properties are kept anyway because they cost nothing.
   ═══════════════════════════════════════════════════════════════════════════ */

:root{
  --signal: light-dark(var(--poodle-primary), var(--poodle-40));
  --signal-tint: light-dark(rgb(126 5 232 / .10), rgb(177 105 241 / .18));
  --good-tint: light-dark(rgb(48 187 71 / .12), rgb(48 187 71 / .20));
  --warn-ink: light-dark(#815D37, #F5B642);
  --warn-tint: light-dark(rgb(255 131 0 / .14), rgb(255 131 0 / .20));
  --alert-ink: light-dark(#A63F46, #FF8A92);
  --alert-tint: light-dark(rgb(249 54 67 / .10), rgb(249 54 67 / .18));
  --r-card: 22px;
  --r-ctl: 14px;
  --sw: 264px;                                   /* sidebar width, open */
  --side-bg: linear-gradient(180deg, var(--aussie-95) 0%, var(--aussie-100) 100%);
  --side-line: var(--aussie-80);
  --side-mute: var(--aussie-30);
  --on-dark: var(--aussie-0);
  --brand-grad: linear-gradient(135deg, var(--poodle-primary) 0%, var(--poodle-60) 100%);
  --hero-grad: linear-gradient(135deg,
      color-mix(in srgb, var(--poodle-primary) 52%, var(--aussie-100)) 0%,
      var(--poodle-primary) 58%, var(--poodle-60) 100%);
  --glow: color-mix(in srgb, var(--poodle-primary) 38%, transparent);
  --lift: 0 1px 2px light-dark(rgb(15 15 21 / .05), rgb(0 0 0 / .4));
  --lift-2: 0 10px 30px light-dark(rgb(30 10 60 / .10), rgb(0 0 0 / .5));
  --main-max: 1480px;                            /* Overview; Settings narrows it */
}

/* ── base ───────────────────────────────────────────────────────────────── */
*{ box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html{ background: var(--bg-secondary); }
/* (0,0,2), and loaded after design-system.css: cancels the old rail's
   `html body{padding-left}` gutter. Every page's inline `html,body{padding:0}`
   is (0,0,1) and could not. */
html body{
  margin: 0; padding: 0;
  background: var(--bg-secondary);
  color: var(--content-primary);
  font-family: var(--font);
  -webkit-font-smoothing: antialiased;
}
/* A page with no shell (login) keeps a breathing gutter. `:where()` keeps this
   at (0,0,2) so items/login.css can restate `html body` and win. */
html body:where(:not(:has(> .shell))){ padding: 24px; }
/* One rule for the trap this project has hit four times: an author `display`
   outranks the browser's own [hidden]. Nothing here may beat it. */
[hidden]{ display: none !important; }
.sr-only{
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.light-only{ display: block; }
.dark-only{ display: none; }
html[data-theme="dark"] .light-only{ display: none; }
html[data-theme="dark"] .dark-only{ display: block; }

/* ── shell ──────────────────────────────────────────────────────────────── */
/* `.shell.app` because each page's inline <style> still carries the old
   `.app{max-width:1180px; margin:0 auto; padding:…}` and loads after this. */
.shell, .shell.app{
  display: flex; min-height: 100dvh;
  max-width: none; margin: 0; padding: 0;
}
.stage{ flex: 1; min-width: 0; display: flex; flex-direction: column; }
.shell main{
  outline: none; width: 100%; max-width: var(--main-max); margin: 0 auto;
  padding: 8px 32px 56px; flex: 1 0 auto;
}
.shell[data-page="settings"]{ --main-max: 1180px; }  /* a form wants a measure */

/* ── the top header ─────────────────────────────────────────────────────── *
 * Sticky, and painted from y=0 with the inset inside its own padding — the
 * space above the bar belongs to the bar (see header.test.js). Opaque, in the
 * page colour, so at rest it is indistinguishable from the Expocity header and
 * pinned it still hides what scrolls under it. `.is-stuck` (nav.js) adds the
 * one shadow that says it is a layer. */
.top{
  position: sticky; top: 0; z-index: 30;
  display: flex; align-items: center; justify-content: space-between; gap: 12px 16px;
  padding: calc(var(--safe-top) + 14px) 32px 10px;
  background: var(--bg-secondary);
  transition: box-shadow .15s ease;
}
.top.is-stuck{ box-shadow: 0 6px 16px -10px light-dark(rgb(15 15 21 / .35), rgb(0 0 0 / .8)); }
.top-title{ display: flex; align-items: center; gap: 6px 16px; flex-wrap: wrap; min-width: 0; }
.top h1{
  margin: 0; padding: 0; display: block;
  font: 700 30px/1 var(--font-accent); letter-spacing: .01em; text-transform: uppercase;
  color: var(--content-primary);
}
.top h1::after{ content: none; display: none; }   /* the old 42px underline */
.top-sub{ margin: 0; flex-basis: 100%; font-size: 13.5px; line-height: 1.45; color: var(--content-secondary); }
.top-r{ display: flex; align-items: center; gap: 10px; margin-inline-start: auto; min-width: 0; }
.top-btns{ display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }

/* The logo in the header: only when the sidebar is not showing one. */
.mlogo{ display: none; align-items: center; text-decoration: none; min-width: 0; flex: 0 0 auto; }
.mlogo img{ height: 26px; width: auto; }
.mlogo .light-only, .mlogo .dark-only{ display: none; }
html:not([data-theme="dark"]) .mlogo .light-only{ display: block; }
html[data-theme="dark"] .mlogo .dark-only{ display: block; }
.shell[data-side="collapsed"] .top .mlogo{ display: flex; }

/* The source line ("Refreshed 6 min ago"). Its class is rewritten by the page
   script (`badge` / `badge demo`), so it is addressed by id. */
.top #sourceBadge{
  display: inline-flex; align-items: center; gap: 6px; min-height: 30px; padding: 0 12px;
  border-radius: 999px; border: 1px solid var(--bg-border-hover); background: var(--bg-default);
  color: var(--content-secondary); font: 600 12px/1 var(--font); letter-spacing: 0;
  text-transform: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 100%; min-width: 0; margin: 0; order: 0;
}
.top #sourceBadge.demo{ border-color: var(--signal); background: var(--signal-tint); color: var(--signal); }

/* The bell's count, on the header's icon button. */
.iconbtn.bell{ position: relative; }
.iconbtn .bell-badge{
  position: absolute; top: -5px; inset-inline-end: -5px; min-width: 19px; height: 19px;
  padding: 0 5px; border-radius: 10px; background: var(--accent-alert); color: #fff;
  font: 800 10.5px/19px var(--font); text-align: center;
  box-shadow: 0 0 0 2px var(--bg-secondary);
}
.iconbtn.bell.has-alerts{ border-color: var(--accent-alert); color: var(--alert-ink); }
.iconbtn.bell.has-alerts .bell-icon{ animation: bell-swing 2.4s ease-in-out infinite; transform-origin: 50% 10%; }
@keyframes bell-swing{
  0%,88%,100%{ transform: rotate(0); }
  90%{ transform: rotate(11deg); } 93%{ transform: rotate(-9deg); }
  96%{ transform: rotate(5deg); }  98%{ transform: rotate(-3deg); }
}
.bell-icon{ display: grid; place-items: center; }

/* ── sidebar ────────────────────────────────────────────────────────────── */
/* The wrapper pins the sidebar and centres it; the sidebar is only as tall as
   its buttons. In normal flow, so the page is inset by construction. */
.sidewrap{
  position: sticky; top: 0; align-self: flex-start; flex: 0 0 auto;
  height: 100dvh; display: flex; align-items: center;
  padding-block: 16px; padding-inline: 16px 0;
  z-index: 35;
}
.side{
  flex: 0 0 auto; width: var(--sw); height: auto; max-height: calc(100dvh - 32px);
  overflow-y: auto; scrollbar-width: none;
  padding: 16px 14px 14px; display: flex; flex-direction: column; gap: 6px;
  border-radius: 30px; color: var(--on-dark);
  background: var(--side-bg); border: 1px solid var(--side-line);
  box-shadow: 0 18px 50px color-mix(in srgb, var(--aussie-100) 40%, transparent);
  transition: width .22s ease;
}
.side::-webkit-scrollbar{ display: none; }
.side svg{ display: block; }
.side-top{ display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 4px 4px 10px; }
.logo{ display: flex; min-height: 44px; align-items: center; gap: 11px; text-decoration: none; min-width: 0; color: inherit; }
.lock{ display: inline-flex; flex-direction: column; gap: 0; --pl-logo-w: 150px; }
.lock .wm{ width: var(--pl-logo-w); height: auto; display: block; }
.lock .sub{
  font: 600 calc(var(--pl-logo-w) * .088)/1.2 var(--font); color: var(--side-mute);
  padding-inline-start: calc(var(--pl-logo-w) * .19); margin-top: 2px; letter-spacing: 0;
}
.logomark{
  display: none; flex: 0 0 42px; width: 42px; height: 42px; border-radius: 14px;
  background: var(--brand-grad); place-items: center; box-shadow: 0 6px 18px var(--glow);
}
.side-toggle{
  flex: 0 0 32px; width: 32px; height: 32px; border-radius: 11px; padding: 0;
  border: 1px solid var(--side-line); background: var(--aussie-90); color: var(--on-dark);
  display: grid; place-items: center; cursor: pointer;
}
.side-toggle:hover{ background: var(--aussie-80); }
.side-toggle svg{
  width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2.2;
  stroke-linecap: round; stroke-linejoin: round; transition: transform .22s ease;
}

.me{
  display: flex; align-items: center; gap: 12px; padding: 12px; margin: 2px 0 8px;
  border-radius: 20px; background: var(--aussie-90); border: 1px solid var(--side-line); min-width: 0;
  position: relative;
}
.avatar{
  position: relative; flex: 0 0 42px; width: 42px; height: 42px; border-radius: 50%;
  display: grid; place-items: center; font: 700 15px var(--font); color: var(--on-dark);
  background: linear-gradient(135deg, var(--poodle-40), var(--poodle-primary));
  text-transform: uppercase;
}
.avatar::after{
  content: ""; position: absolute; inset-inline-end: 0; bottom: 0; width: 11px; height: 11px;
  border-radius: 50%; background: var(--accent-success); border: 2px solid var(--aussie-95);
}
.me-t{ display: flex; flex-direction: column; min-width: 0; }
.me-t b{ font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.me-t small{ font-size: 11.5px; color: var(--side-mute); text-transform: capitalize; }
.side-label{
  font: 600 10.5px/1 var(--font); letter-spacing: .18em; text-transform: uppercase;
  color: var(--side-mute); padding: 12px 12px 6px;
}
.nav{ display: flex; flex-direction: column; gap: 4px; }
.nav-item, .side-btn{
  position: relative; display: flex; align-items: center; gap: 14px; min-height: 48px;
  padding: 0 14px; border-radius: 16px; color: var(--aussie-20); text-decoration: none;
  border: 0; background: none; width: 100%; text-align: start; font: 600 14.5px var(--font);
  cursor: pointer;
}
.nav-item:hover, .side-btn:hover{ background: var(--aussie-90); color: var(--on-dark); }
.nav-item[aria-current="page"]{
  color: var(--on-dark); background: var(--brand-grad); box-shadow: 0 6px 16px var(--glow);
}
.nav-item:focus-visible, .side-btn:focus-visible, .side-toggle:focus-visible{
  outline: 2px solid var(--poodle-40); outline-offset: 2px;
}
.ni{ flex: 0 0 22px; width: 22px; height: 22px; display: grid; place-items: center; }
.ni svg{
  width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
.nl{ white-space: nowrap; }
.nav-item .count{
  margin-inline-start: auto; min-width: 20px; height: 20px; border-radius: 10px; padding: 0 6px;
  background: var(--accent-alert); color: var(--aussie-100); font: 700 11px/20px var(--font);
  text-align: center;
}
.side-foot{
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--side-line);
  display: flex; flex-direction: column; gap: 4px;
}
.side-foot .side-btn{ min-height: 44px; font-weight: 500; font-size: 14px; }

.shell[data-side="collapsed"]{ --sw: 84px; }
.shell[data-side="collapsed"] .side{ padding-inline: 12px; align-items: stretch; }
.shell[data-side="collapsed"] .side .logomark{ display: grid; }
.shell[data-side="collapsed"] .side-top{ flex-direction: column; padding-inline: 0; gap: 10px; }
.shell[data-side="collapsed"] .side .lock,
.shell[data-side="collapsed"] .side .me-t,
.shell[data-side="collapsed"] .side-label{ display: none; }
/* The labels a collapsed rail cannot show stay in the accessibility tree —
   clipped, not removed — or five links are announced by their href alone. */
.shell[data-side="collapsed"] .side .nl{
  position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}
.shell[data-side="collapsed"] .side .me{ padding: 8px; justify-content: center; background: none; border-color: transparent; }
.shell[data-side="collapsed"] .side .nav-item,
.shell[data-side="collapsed"] .side-btn{ justify-content: center; padding: 0; }
.shell[data-side="collapsed"] .side-toggle svg{ transform: rotate(180deg); }
/* The label a collapsed rail cannot show on hover: the rail scrolls
   (overflow-y:auto), which clips any tooltip drawn outside it, so nav.js
   mirrors each item's `data-tip` into `title` while collapsed and removes it
   when open (an open item's label is already on screen). */

/* ── chips, buttons, notes ──────────────────────────────────────────────── */
.chip{
  display: inline-flex; align-items: center; gap: 6px; min-height: 28px; padding: 0 11px;
  border-radius: 999px; border: 1px solid var(--bg-border-hover); background: var(--bg-default);
  font-size: 12px; font-weight: 600; white-space: nowrap; color: var(--content-primary);
}
.chip.ok{ border-color: var(--accent-success); color: var(--accent-success-ink); background: var(--good-tint); }
.chip.warn{ border-color: var(--accent-warning); color: var(--warn-ink); background: var(--warn-tint); }
.chip.bad{ border-color: var(--accent-alert); color: var(--alert-ink); background: var(--alert-tint); }
.chip.brand{ border-color: var(--signal); color: var(--signal); background: var(--signal-tint); }
.chip.quiet{ color: var(--content-secondary); }

.iconbtn{
  position: relative; flex: 0 0 auto;
  width: 46px; height: 46px; padding: 0; display: inline-grid; place-items: center; border-radius: 16px;
  border: 1px solid var(--bg-border); background: var(--bg-default); color: var(--content-primary);
  box-shadow: var(--lift); cursor: pointer; font: inherit;
}
.iconbtn:hover{ border-color: var(--bg-border-hover); }
.iconbtn:focus-visible{ outline: 2px solid var(--signal); outline-offset: 2px; }
.iconbtn svg{
  display: block; width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.9;
  stroke-linecap: round; stroke-linejoin: round;
}
.iconbtn[disabled]{ opacity: .5; cursor: default; }
.iconbtn.spin svg{ animation: pl-spin .8s linear infinite; }
@keyframes pl-spin{ to{ transform: rotate(360deg); } }

.btn{
  display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 48px;
  padding: 0 22px; border-radius: var(--r-ctl); border: 1px solid transparent;
  background: var(--brand-grad); color: var(--on-dark); font: 600 15px var(--font);
  text-decoration: none; cursor: pointer; box-shadow: 0 8px 20px rgb(126 5 232 / .30);
}
.btn.ghost{ background: var(--bg-default); color: var(--content-primary); border-color: var(--bg-border-hover); box-shadow: var(--lift); }
.btn.sm, .btn.small{ min-height: 40px; padding: 0 16px; font-size: 13.5px; border-radius: 12px; }
.btn.danger{ background: var(--bg-default); color: var(--alert-ink); border-color: var(--accent-alert); box-shadow: none; }
.btn[disabled], .btn:disabled{ opacity: .5; cursor: default; box-shadow: none; }

/* Only the coloured variants are boxes. A bare `.note` is the small grey caption
   the Settings tools use, and it must stay one. */
.note.warn, .note.bad, .note.ok, .note.brandn{ margin: 10px 0 0; padding: 12px 16px; border-radius: 16px; font-size: 13px; font-weight: 600; }
.note.warn{ border: 1px solid var(--accent-warning); background: var(--warn-tint); color: var(--warn-ink); }
.note.bad{ border: 1px solid var(--accent-alert); background: var(--alert-tint); color: var(--alert-ink); }
.note.ok{ border: 1px solid var(--accent-success); background: var(--good-tint); color: var(--accent-success-ink); }
.note.brandn{ border: 1px solid var(--signal); background: var(--signal-tint); color: var(--signal); }
.note.bad b, .note.warn b{ display: block; margin-bottom: 2px; }

/* ── sections ───────────────────────────────────────────────────────────── */
.sechead{
  display: flex; align-items: center; gap: 10px; margin: 6px 2px 2px;
  font: 700 11.5px/1 var(--font); letter-spacing: .14em; text-transform: uppercase;
  color: var(--content-secondary);
}

/* ── cards, tiles, rings ────────────────────────────────────────────────── */
.card{
  background: var(--bg-default); border: 1px solid var(--bg-border); border-radius: var(--r-card);
  padding: 22px; box-shadow: var(--lift);
}
.kpis{ display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; margin: 0; }
.kpi{
  display: flex; flex-direction: column; gap: 10px; padding: 18px; border-radius: var(--r-card);
  background: var(--bg-default); border: 1px solid var(--bg-border); box-shadow: var(--lift); min-width: 0;
}
.kpi .kic{
  width: 38px; height: 38px; border-radius: 13px; display: grid; place-items: center;
  background: var(--signal-tint); color: var(--signal);
}
.kpi .kic svg{ width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.kpi small{ font: 600 11px/1 var(--font); letter-spacing: .12em; text-transform: uppercase; color: var(--content-secondary); }
.kpi b{ font: 700 32px/1.05 var(--font-accent); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }

/* A progress ring: <span class="ring"><svg viewBox="0 0 58 58"><circle class="rt" …/>
   <circle class="ra" …/></svg><b>69%</b></span>. Arc length is the caller's maths. */
.ring{ position: relative; flex: 0 0 58px; width: 58px; height: 58px; display: inline-block; }
.ring svg{ display: block; width: 58px; height: 58px; transform: rotate(-90deg); }
.ring .rt{ fill: none; stroke: var(--bg-border-hover); stroke-width: 6; }
.ring .ra{ fill: none; stroke: var(--signal); stroke-width: 6; stroke-linecap: round; transition: stroke-dashoffset .6s ease-out; }
.ring b{ position: absolute; inset: 0; display: grid; place-items: center; font: 700 13px var(--font); font-variant-numeric: tabular-nums; }
.ring.big{ flex-basis: 132px; width: 132px; height: 132px; }
.ring.big svg{ width: 132px; height: 132px; }
.ring.big b{ font: 700 30px var(--font-accent); }
.ring.big .rt, .ring.big .ra{ stroke-width: 9; }

/* ── forms ──────────────────────────────────────────────────────────────── */
label.f{ display: block; font: 600 12.5px var(--font); color: var(--content-secondary); margin-top: 14px; }
label.f:first-child{ margin-top: 0; }
/* 16px is not a style choice: iOS zooms on a focused control under 16px. */
.inp{
  display: block; width: 100%; min-height: 48px; margin-top: 7px; padding: 10px 14px;
  border-radius: var(--r-ctl); border: 1px solid var(--bg-border-hover); background: var(--bg-wash);
  color: var(--content-primary); font: 500 16px var(--font);
}
.inp:focus{ outline: 2px solid var(--signal); outline-offset: 1px; background-color: var(--bg-default); }
select.inp{
  appearance: none; -webkit-appearance: none; padding-inline-end: 42px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%239999AC' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 14px center;
}
/* A toggle row: <label class="sw">Label <input type="checkbox" class="tg"></label> */
.sw{
  display: flex; align-items: center; justify-content: space-between; gap: 14px; min-height: 48px;
  cursor: pointer; font: 500 14.5px var(--font); color: var(--content-primary); padding: 4px 0;
  border-top: 1px solid var(--bg-border);
}
.sw:first-child{ border-top: 0; }
input.tg{
  appearance: none; -webkit-appearance: none; flex: 0 0 48px; width: 48px; height: 28px;
  border-radius: 999px; background: var(--bg-border-hover); position: relative; cursor: pointer;
  transition: background .15s; margin: 0;
}
input.tg::after{
  content: ""; position: absolute; top: 3px; inset-inline-start: 3px; width: 22px; height: 22px;
  border-radius: 50%; background: var(--aussie-0); transition: transform .15s;
  box-shadow: 0 1px 3px color-mix(in srgb, var(--aussie-100) 35%, transparent);
}
input.tg:checked{ background: var(--brand-grad); }
input.tg:checked::after{ transform: translateX(20px); }

/* Pill filters / segmented choice: <div class="segs"><button aria-pressed="true">… */
.segs{ display: flex; gap: 8px; overflow-x: auto; scrollbar-width: none; padding: 2px 0 14px; }
.segs::-webkit-scrollbar{ display: none; }
.segs button{
  flex: 0 0 auto; min-height: 44px; padding: 0 20px; border-radius: 999px;
  border: 1px solid var(--bg-border); background: var(--bg-default); color: var(--content-primary);
  font: 600 13.5px var(--font); white-space: nowrap; box-shadow: var(--lift); cursor: pointer;
}
.segs button[aria-pressed="true"], .segs button[aria-selected="true"]{
  border-color: transparent; background: var(--brand-grad); color: var(--on-dark);
  box-shadow: 0 8px 20px var(--glow);
}

/* ── overlays ───────────────────────────────────────────────────────────── */
.scrim{
  position: fixed; inset: 0; background: var(--bg-fade); z-index: 90;
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
}
/* A bottom sheet: <div class="sheet" role="dialog" aria-modal="true">. */
.sheet{
  position: fixed; inset-inline: 0; bottom: 0; z-index: 91; max-width: 560px; margin-inline: auto;
  background: var(--bg-default); border-radius: 28px 28px 0 0;
  padding: 18px 18px calc(22px + var(--safe-bottom)); border: 1px solid var(--bg-border-hover);
  max-height: 75dvh; overflow: auto; scrollbar-width: none; overscroll-behavior: contain; box-shadow: var(--lift-2);
}

/* ── Settings: the shared panel chrome ──────────────────────────────────────
   The sub-tab strip, the panel card and the headings inside panels are shared
   by all six Settings items, so they live here and NOT in an item sheet.
   `.shell`-prefixed because settings.html's inline <style> still declares the
   legacy versions and loads after this file. Panel INTERIORS belong to
   items/<panel>.css. */
.shell .sub-tabs{
  display: flex; gap: 8px; margin: 0 0 18px; padding: 2px 2px 4px;
  background: none; border: 0; border-radius: 0;
  overflow-x: auto; scrollbar-width: none;
}
.shell .sub-tabs::-webkit-scrollbar{ display: none; }
.shell .sub-tabs button{
  flex: 0 0 auto; min-height: 44px; padding: 0 20px; border-radius: 999px;
  border: 1px solid var(--bg-border); background: var(--bg-default); color: var(--content-primary);
  font: 600 13.5px var(--font); white-space: nowrap; box-shadow: var(--lift); cursor: pointer;
}
.shell .sub-tabs button:hover{ border-color: var(--bg-border-hover); }
.shell .sub-tabs button[aria-selected="true"]{
  border-color: transparent; background: var(--brand-grad); color: var(--on-dark);
  box-shadow: 0 8px 20px var(--glow);
}
.shell .sub-tabs button:focus-visible{ outline: 2px solid var(--signal); outline-offset: 2px; }
.shell .sub-tabs[hidden]{ display: none !important; }

.shell .panel{
  background: var(--bg-default); border: 1px solid var(--bg-border); border-radius: var(--r-card);
  padding: 22px; box-shadow: var(--lift); min-width: 0;
}
.shell .panel > .section-title:first-child{ margin-top: 0; }
/* Headings inside a panel: the old mono caps line, in the Expocity voice. */
.shell .panel .section-title{
  font: 700 11.5px/1.2 var(--font); letter-spacing: .14em; text-transform: uppercase;
  color: var(--content-secondary); margin: 26px 2px 12px;
}

/* ── the nav is held invisible for the one cold session fetch (nav.js) ───── */
/* Only the phone's tab bar: it is centred and shrink-wrapped, so it would paint
   narrow and visibly grow. The desktop sidebar is NOT held back — its width
   does not depend on the item count, and hiding it would leave a blank column
   with no way out of the page for up to 1.2s (desktop-nav.test.js). */
.tabbar{ transition: opacity .15s ease; }
@keyframes pl-reveal{ to{ opacity: 1; visibility: visible; } }
/* The animation is the net under nav.js's own timeout: if the script never runs,
   the nav still comes back rather than staying hidden for ever. */
.shell.is-pending .tabbar{ opacity: 0; visibility: hidden; animation: pl-reveal 0s 2.5s forwards; }

/* ── footer ─────────────────────────────────────────────────────────────── */
.pagefoot{
  display: flex; align-items: center; justify-content: center; gap: 8px; padding: 8px 16px 36px;
  font-size: 12px; color: var(--content-secondary);
}
.pagefoot img{ height: 14px; width: auto; }
.pagefoot b{ font: 700 9px var(--font-accent); color: var(--signal); margin-top: -6px; letter-spacing: .04em; }
.pagefoot .light-only, .pagefoot .dark-only{ display: none; }
html:not([data-theme="dark"]) .pagefoot .light-only{ display: block; }
html[data-theme="dark"] .pagefoot .dark-only{ display: block; }

/* ── phone & tablet ─────────────────────────────────────────────────────── */
.tabbar{ display: none; }
.mobile-only{ display: none; }

@media (max-width: 899px){
  .sidewrap{ display: none; }
  .mobile-only{ display: inline-grid; }
  .top .mlogo{ display: flex; }
  .shell main{ padding: 6px 16px 12px; }
  .pagefoot{ padding-bottom: 120px; }
  .iconbtn{ width: 42px; height: 42px; border-radius: 14px; }
  .shell .panel{ padding: 16px; border-radius: 20px; }

  /* The header on a phone is a three-row GRID, and the source line has a row
     to itself — Arif's call, 2026-09-09, kept through the restyle:

         logo                         [ 🌙 ] [ 🔔 ] [ ↺ ]
         MATCH CONTROL                         Round 5 ▾
         Refreshed 6 min ago · loading 4 of 7

     It is the one variable-width thing in the bar and every arrangement that
     gave it a neighbour squeezed it. `display: contents` dissolves the title
     and right-hand wrappers so each piece is placed by area. */
  .top{
    display: grid; grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "logo  btns"
      "title picker"
      "badge badge"
      "sub   sub";
    align-items: center; gap: 6px 10px;
    padding: calc(var(--safe-top) + 12px) 16px 10px;
  }
  .top-title, .top-r{ display: contents; }
  .top .mlogo{ grid-area: logo; }
  .top h1{ grid-area: title; font-size: 22px; }
  .top .round-picker{ grid-area: picker; justify-self: end; }
  .top-btns{ grid-area: btns; justify-self: end; gap: 8px; }
  .top #sourceBadge{ grid-area: badge; justify-self: start; }
  .top-sub{ grid-area: sub; font-size: 13px; }
  /* The picker is at the right edge now, so its menu anchors right or it runs
     off the screen (reported 2026-09-08 at 375px; this covers 601-899 too). */
  .top .round-menu{ left: auto; right: 0; min-width: 0; width: max-content; max-width: calc(100vw - 28px); }

  .tabbar{
    /* The Expocity floating pill, low on the screen at a CONSTANT 20px — NOT
       built on env(safe-area-inset-bottom). On a real iPhone the same build
       reported that inset as 34px on one page and 0px on another, which put the
       bar 44px up on one and 10px on the other; four attempts to be clever about
       it each became the thing that moved it. 20px clears the home indicator.
       (A docked full-width bar was tried and rejected on 2026-10-09 — Arif
       wants the pill.) See tests/ui/mobile.test.js. */
    position: fixed; z-index: 40; left: 50%; transform: translateX(-50%);
    bottom: 20px; display: flex; flex-direction: row; gap: 4px; padding: 7px;
    border-radius: 999px; background: color-mix(in srgb, var(--aussie-95) 90%, transparent);
    -webkit-backdrop-filter: blur(18px) saturate(1.5); backdrop-filter: blur(18px) saturate(1.5);
    border: 1px solid var(--aussie-80);
    box-shadow: 0 16px 40px color-mix(in srgb, var(--aussie-100) 45%, transparent);
    max-width: calc(100vw - 16px);
  }
  .tabbar svg{ display: block; }
  .tabbar .nav-item{
    width: auto; min-height: 52px; min-width: 52px; padding: 0 15px; justify-content: center; gap: 8px;
    border-radius: 999px; color: var(--aussie-30);
  }
  .tabbar .nav-item[aria-current="page"]{ color: var(--on-dark); }
  .tabbar .nl{ max-width: 0; overflow: hidden; opacity: 0; transition: max-width .22s ease, opacity .18s ease; font-size: 14px; }
  .tabbar .nav-item[aria-current="page"] .nl{ max-width: 96px; opacity: 1; }
  /* Past four items the OTHER items go icon-only and tighter, but the current
     one keeps its label in the purple pill, as on Expocity. Items size to
     their content rather than sharing the width equally — shared, the current
     one stretched into a wide purple oval. Under 360px even the current label
     goes; names stay in the accessibility tree (clipped, not removed). */
  .tabbar.is-wide .nav-item{ min-width: 48px; flex: 0 0 auto; padding: 0 12px; }
  @media (max-width: 360px){
    .tabbar.is-wide .nl{
      position: absolute; width: 1px; height: 1px; max-width: none; margin: -1px; opacity: 1;
      overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
    }
  }
  /* A field has focus, so the keyboard is up and the bar would ride on top of it. */
  .tabbar.is-typing{ display: none; }
}
@media (max-width: 420px){
  .top h1{ font-size: 20px; }
}
@media (prefers-reduced-motion: reduce){
  .side, .side-toggle svg, .sidewrap, .tabbar, .tabbar .nl, .top, .ring .ra{ transition: none !important; }
  .iconbtn.bell.has-alerts .bell-icon, .iconbtn.spin svg{ animation: none !important; }
}
.sheet::-webkit-scrollbar{ display: none; }
.sheet:focus{ outline: none; }
