/* Adaptive Digital Signs operator portal.
   Design system reproduced from design/portal-shell-mock/portal.css (the approved mock). Fonts are self-hosted
   and served from /portal/fonts/, so the portal still makes no external request of any kind. Layers, in order:
   fonts, tokens, base, shell, primitives, responsive, then the retained legacy layer that pages not yet moved
   onto the new primitives still depend on. */

@font-face { font-family: "Hanken Grotesk"; font-weight: 400; src: url(/portal/fonts/hanken-400.woff2) format("woff2"); font-display: swap; }
@font-face { font-family: "Hanken Grotesk"; font-weight: 500; src: url(/portal/fonts/hanken-500.woff2) format("woff2"); font-display: swap; }
@font-face { font-family: "Hanken Grotesk"; font-weight: 600; src: url(/portal/fonts/hanken-600.woff2) format("woff2"); font-display: swap; }
@font-face { font-family: "Hanken Grotesk"; font-weight: 700; src: url(/portal/fonts/hanken-700.woff2) format("woff2"); font-display: swap; }
@font-face { font-family: "Bricolage Grotesque"; font-weight: 200 800; src: url(/portal/fonts/bricolage-vf.woff2) format("woff2"); font-display: swap; }
@font-face { font-family: "Geist Mono"; font-weight: 100 900; src: url(/portal/fonts/geist-mono-vf.ttf) format("truetype"); font-display: swap; }

:root {
  --font-ui: "Hanken Grotesk", "Noto Sans", "DejaVu Sans", sans-serif;
  --font-title: "Bricolage Grotesque", "Hanken Grotesk", sans-serif;
  --font-mono: "Geist Mono", "Cascadia Mono", "DejaVu Sans Mono", monospace;

  --bg: oklch(0.975 0.004 160);
  --surface: oklch(0.995 0.001 160);
  --surface-2: oklch(0.955 0.006 160);
  --line: oklch(0.905 0.008 160);
  --line-strong: oklch(0.82 0.012 160);
  --ink: oklch(0.21 0.015 160);
  --ink-2: oklch(0.44 0.014 160);
  --ink-3: oklch(0.50 0.013 160);

  --rail: oklch(0.235 0.045 158);
  --rail-2: oklch(0.285 0.05 158);
  --rail-ink: oklch(0.93 0.01 158);
  --rail-ink-2: oklch(0.80 0.02 158);

  --accent: oklch(0.52 0.135 152);
  --accent-hover: oklch(0.46 0.13 152);
  --accent-pane: oklch(0.955 0.03 152);
  --accent-line: oklch(0.86 0.06 152);
  --on-accent: #fff;

  --ok: oklch(0.47 0.12 152);   --ok-pane: oklch(0.955 0.03 152);
  --warn: oklch(0.46 0.108 72); --warn-pane: oklch(0.965 0.045 85);
  --err: oklch(0.47 0.168 27);  --err-pane: oklch(0.96 0.03 27);
  --info: oklch(0.47 0.1 250);  --info-pane: oklch(0.96 0.02 250);

  --r-sm: 6px; --r-md: 10px; --r-lg: 14px; --r-pill: 999px;
  --shadow-1: 0 1px 2px oklch(0.3 0.02 160 / 0.08);
  --shadow-2: 0 8px 24px oklch(0.3 0.03 160 / 0.14), 0 1px 2px oklch(0.3 0.02 160 / 0.08);
  --ease: cubic-bezier(0.32, 0.72, 0, 1);
  --rail-w: 248px;
  /* Design-system lock: type scale, 4px spacing base, radii and control height. New shell rules use these. */
  --fs-12: 0.75rem; --fs-14: 0.875rem; --fs-16: 1rem; --fs-18: 1.125rem; --fs-21: 1.3125rem; --fs-28: 1.75rem;
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 20px; --sp-6: 24px; --sp-8: 32px;
  --radius-6: 6px; --radius-10: 10px; --radius-14: 14px; --radius-pill: 999px;
  --control-h: 44px;
  --z-rail: 30; --z-top: 20; --z-drawer: 40; --z-scrim: 39; --z-skip: 60;


  --font-display: var(--font-title);
  --font-body: var(--font-ui);

  --s-1: 0.25rem; --s-2: 0.5rem; --s-3: 0.75rem; --s-4: 1rem; --s-5: 1.5rem; --s-6: 2rem; --s-7: 3rem;
  --z-base: 0; --z-sticky: 100; --z-nav: 200; --z-skip-legacy: 300;
  --dur-fast: 150ms; --dur-base: 200ms; --dur-slow: 250ms;
}

/* ------------------------------------------------------------------------------------------------ base */

* { box-sizing: border-box; }
html { font-size: 15px; -webkit-text-size-adjust: 100%; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font-ui);
  color: var(--ink);
  background: var(--bg);
  line-height: 1.45;
  font-feature-settings: "tnum" 1, "cv11" 1;
  -webkit-font-smoothing: antialiased;
}
a { color: oklch(0.43 0.125 152); text-underline-offset: 2px; }
a:hover { color: oklch(0.40 0.12 152); }
button { font: inherit; }
h1, h2, h3 { margin: 0 0 var(--s-3); text-wrap: balance; font-family: var(--font-ui); font-weight: 600; color: var(--ink); }
h1 { font-family: var(--font-title); font-size: 26px; line-height: 1.1; letter-spacing: -0.015em; }
h2 { font-size: 1.1rem; line-height: 1.25; }
h3 { font-size: 1rem; line-height: 1.3; }
p { margin: 0 0 var(--s-3); }
code, pre, .mono, .ads-mono { font-family: var(--font-mono); font-size: 0.86em; }

a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible,
textarea:focus-visible, summary:focus-visible, [tabindex]:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: var(--z-skip);
  background: var(--ink); color: #fff; padding: var(--s-3) var(--s-4);
}
.skip-link:focus { left: var(--s-2); top: var(--s-2); }
.ads-sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* ------------------------------------------------------------------------------------------------ shell */

.shell { display: grid; grid-template-columns: var(--rail-w) 1fr; min-height: 100dvh; }
.rail {
  position: sticky; top: 0; height: 100dvh; background: var(--rail); color: var(--rail-ink);
  display: flex; flex-direction: column; padding: 14px 12px; gap: 6px; z-index: var(--z-rail); overflow-y: auto;
}
.rail > * { flex-shrink: 0; }
.brand { display: flex; align-items: center; gap: 10px; padding: 6px 8px 14px; text-decoration: none; color: inherit; }
.brand .mark { width: 30px; height: 30px; border-radius: 8px; background: var(--accent); display: grid; place-items: center; color: #fff; font: 700 14px var(--font-title); letter-spacing: -0.02em; flex: none; }
.brand .name { font: 600 15px/1.1 var(--font-title); letter-spacing: -0.01em; }
.brand .name small { display: block; font: 500 11px var(--font-ui); color: var(--rail-ink-2); letter-spacing: 0.02em; margin-top: 2px; }
.tenant {
  margin: 0 4px 10px; background: var(--rail-2); border: 1px solid oklch(1 0 0 / 0.14); border-radius: var(--r-md);
  padding: 8px 10px; display: flex; align-items: center; gap: 8px; color: var(--rail-ink); text-decoration: none; min-height: 44px;
}
.tenant .av { width: 24px; height: 24px; border-radius: 6px; background: oklch(0.72 0.1 80); color: oklch(0.2 0.02 80); font: 700 11px var(--font-ui); display: grid; place-items: center; flex: none; }
.tenant b { font-weight: 600; font-size: 13px; display: block; }
.tenant span { font-size: 11px; color: var(--rail-ink-2); display: block; }
/* wave3-shell */
.tenant { margin: 0 var(--sp-1) var(--sp-3); padding: var(--sp-2) var(--sp-3); gap: var(--sp-2); min-height: var(--control-h); border-radius: var(--radius-10); }
.tenant .av { border-radius: var(--radius-6); }
.tenant b { font-size: var(--fs-14); }
.tenant span { font-size: var(--fs-12); }
.scope { position: relative; }
.scope > summary { list-style: none; cursor: pointer; }
.scope > summary::-webkit-details-marker { display: none; }
.scope > summary:hover { background: var(--rail-2); border-color: oklch(1 0 0 / 0.3); }
.scope > summary:focus-visible { outline: 2px solid var(--rail-ink); outline-offset: 2px; }
.scope-text { flex: 1; min-width: 0; }
.scope-text b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.scope-caret { flex: none; color: var(--rail-ink-2); transition: transform 0.15s var(--ease); }
.scope[open] .scope-caret { transform: rotate(180deg); }
.scope-list { list-style: none; margin: 0 var(--sp-1) var(--sp-3); padding: var(--sp-1); background: var(--rail-2); border: 1px solid oklch(1 0 0 / 0.14); border-radius: var(--radius-10); max-height: 40vh; overflow-y: auto; }
.scope-list a { display: flex; align-items: center; min-height: var(--control-h); padding: 0 var(--sp-3); border-radius: var(--radius-6); color: var(--rail-ink); font-size: var(--fs-14); text-decoration: none; }
.scope-list a:hover { background: oklch(1 0 0 / 0.1); color: var(--rail-ink); }
.scope-list a[aria-current] { font-weight: 600; background: oklch(1 0 0 / 0.14); }
.scope-list a:focus-visible { outline: 2px solid var(--rail-ink); outline-offset: -2px; }
.app-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr)); gap: var(--sp-4); padding: var(--sp-4); }
.app-card { display: flex; flex-direction: column; gap: var(--sp-3); background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-14); padding: var(--sp-4); box-shadow: var(--shadow-1); }
.app-card-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.app-card-head h3 { margin: 0; font-size: var(--fs-16); }
.app-card .help { margin: 0; color: var(--ink-2); font-size: var(--fs-14); }
.app-card form { display: grid; gap: var(--sp-3); margin-top: auto; }
.app-card-act { margin-top: auto; }
.app-card .btn, .app-card button[type="submit"] { min-height: var(--control-h); }
.app-card-disabled { background: var(--surface-2); box-shadow: none; }
.app-added { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-4); }
.app-added .btn { min-height: var(--control-h); }
@media (max-width: 1100px) {
  .scope-caret { display: none; }
  .scope[open] .scope-list { position: fixed; left: calc(var(--rail-w) + var(--sp-2)); top: 72px; width: 240px; z-index: var(--z-drawer); box-shadow: var(--shadow-2); margin: 0; }
}
@media (max-width: 760px) {
  .rail:target .scope-caret, .rail[data-open] .scope-caret { display: block; }
  .rail:target .scope[open] .scope-list, .rail[data-open] .scope[open] .scope-list { position: static; width: auto; box-shadow: none; margin: 0 var(--sp-1) var(--sp-3); }
  .rail:target .scope-text b, .rail[data-open] .scope-text b { display: block; }
}
@media (prefers-reduced-motion: reduce) { .scope-caret { transition: none; } }
.group { font: 600 10.5px var(--font-ui); letter-spacing: 0.08em; text-transform: uppercase; color: var(--rail-ink-2); padding: 12px 10px 4px; }
.nav a {
  position: relative; display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 8px;
  text-decoration: none; font-weight: 500; font-size: 13.5px; color: var(--rail-ink); transition: background 150ms var(--ease);
}
.nav a:hover { background: oklch(1 0 0 / 0.07); color: var(--rail-ink); }
.nav a[aria-current] { background: oklch(1 0 0 / 0.14); font-weight: 600; }
.nav a .n { margin-left: auto; font-size: 11px; font-weight: 700; background: var(--err); color: #fff; padding: 1px 7px; border-radius: var(--r-pill); }
.nav svg { width: 20px; height: 20px; flex: none; stroke-width: 1.75; }
.rail .me { margin-top: auto; display: flex; align-items: center; gap: 10px; padding: 10px 8px; border-top: 1px solid oklch(1 0 0 / 0.14); font-size: 13px; flex-wrap: wrap; }
.rail .me .av { width: 30px; height: 30px; border-radius: 50%; background: oklch(0.85 0.05 152); color: oklch(0.2 0.03 152); font-weight: 700; display: grid; place-items: center; font-size: 12px; flex: none; }
.rail .me .who { min-width: 0; }
.rail .me .who b { display: block; font-weight: 600; overflow: hidden; text-overflow: ellipsis; }
.rail .me .who span { display: block; color: var(--rail-ink-2); font-size: 11.5px; }
.rail .me form { margin: 0; }
.rail .me button {
  min-height: 30px; padding: 0 10px; font-size: 12.5px; font-weight: 600; border-radius: 8px;
  background: transparent; color: var(--rail-ink); border: 1px solid oklch(1 0 0 / 0.28); cursor: pointer;
}
.rail .me button:hover { background: oklch(1 0 0 / 0.12); }

.main { min-width: 0; display: flex; flex-direction: column; }
.topbar {
  position: sticky; top: 0; z-index: var(--z-top); display: flex; align-items: center; gap: 10px;
  padding: 10px 24px; background: var(--surface); border-bottom: 1px solid var(--line);
}
.crumbs { font-size: 13px; color: var(--ink-2); display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.crumbs b { color: var(--ink); font-weight: 600; }
.crumbs a { text-decoration: none; }
.topbar form.search { margin: 0 0 0 auto; display: flex; align-items: center; gap: 6px; }
.topbar form.search input {
  width: 320px; max-width: 40vw; height: 44px; min-height: 44px; padding: 0 10px; font-size: 13px;
  border: 1px solid var(--line-strong); border-radius: var(--r-md); background: var(--surface); color: var(--ink);
}
.iconbtn {
  width: 44px; height: 44px; min-height: 44px; padding: 0; border-radius: var(--r-md); border: 1px solid var(--line-strong);
  background: var(--surface); display: grid; place-items: center; color: var(--ink-2); cursor: pointer; position: relative;
  text-decoration: none;
}
.iconbtn:hover { background: var(--surface-2); color: var(--ink); }
.iconbtn .dot { position: absolute; top: 7px; right: 8px; width: 7px; height: 7px; border-radius: 50%; background: var(--err); outline: 2px solid var(--surface); }
.iconbtn svg { width: 20px; height: 20px; stroke-width: 1.75; }
.burger { display: none; }

.page { padding: 22px 24px 96px; max-width: 1360px; width: 100%; }
.page-head { display: flex; align-items: flex-end; gap: 16px; margin-bottom: 18px; flex-wrap: wrap; }
.page-head h1 { margin: 0; }
.page-head p { margin: 4px 0 0; color: var(--ink-2); font-size: 13.5px; }
.page-head .actions { margin-left: auto; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

/* ------------------------------------------------------------------------------------------- primitives */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px; min-height: 44px; padding: 0 14px;
  border-radius: var(--r-md); border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink);
  font-family: var(--font-ui); font-weight: 600; font-size: 13.5px; cursor: pointer; text-decoration: none;
  transition: background 150ms var(--ease), border-color 150ms var(--ease); white-space: nowrap;
}
.btn:hover { background: var(--surface-2); color: var(--ink); }
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.btn.primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); color: var(--on-accent); }
.btn.quiet { border-color: transparent; background: transparent; color: oklch(0.43 0.125 152); }
.btn.quiet:hover { background: var(--accent-pane); }
.btn.danger { color: var(--err); border-color: oklch(0.86 0.062 27); }
.btn.danger:hover { background: var(--err-pane); border-color: var(--err); }
.btn.sm { min-height: 44px; height: 44px; padding: 0 10px; font-size: 12.5px; border-radius: 8px; }
.btn svg { width: 15px; height: 15px; }
.btn:disabled, .btn[aria-disabled="true"] { background: oklch(0.935 0.008 160); color: var(--ink-2); border-color: var(--line); cursor: not-allowed; }

.chip {
  display: inline-flex; align-items: center; gap: 6px; min-height: 24px; padding: 0 9px 0 7px; border-radius: var(--r-pill);
  font-size: 12px; font-weight: 600; border: 1px solid transparent; white-space: nowrap;
}
.chip::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; }
.chip.ok { color: var(--ok); background: var(--ok-pane); border-color: var(--accent-line); }
.chip.warn { color: var(--warn); background: var(--warn-pane); border-color: oklch(0.858 0.075 78); }
.chip.err { color: var(--err); background: var(--err-pane); border-color: oklch(0.86 0.062 27); }
.chip.info { color: var(--info); background: var(--info-pane); border-color: oklch(0.862 0.044 248); }
.chip.muted { color: var(--ink-2); background: var(--surface-2); border-color: var(--line); }
.chip.muted::before { background: var(--ink-2); }

.tag { display: inline-block; font-size: 11.5px; font-weight: 600; color: var(--ink-2); background: var(--surface-2); border: 1px solid var(--line); border-radius: 6px; padding: 1px 7px; }

.grid { display: grid; gap: 16px; }
.grid.two { grid-template-columns: minmax(0, 1.9fr) minmax(300px, 1fr); }
.panel { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); box-shadow: var(--shadow-1); overflow: hidden; margin-bottom: 16px; }
.panel-head { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.panel-head h2 { margin: 0; font: 600 14.5px var(--font-ui); }
.panel-head .sub { color: var(--ink-2); font-size: 12.5px; }
.panel-head .actions { margin-left: auto; display: flex; gap: 6px; }
.panel-body { padding: 14px 16px; }
.panel-body > :last-child { margin-bottom: 0; }

.attention { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 10px; margin-bottom: 16px; }
.alert { display: flex; gap: 12px; align-items: flex-start; padding: 12px 14px; border-radius: var(--r-md); border: 1px solid var(--line); background: var(--surface); text-decoration: none; color: var(--ink); transition: border-color 150ms var(--ease); }
.alert:hover { border-color: var(--line-strong); color: var(--ink); }
.alert .ic { width: 32px; height: 32px; border-radius: 8px; display: grid; place-items: center; flex: none; }
.alert.err .ic { background: var(--err-pane); color: var(--err); }
.alert.warn .ic { background: var(--warn-pane); color: var(--warn); }
.alert.info .ic { background: var(--info-pane); color: var(--info); }
.alert b { display: block; font-size: 13.5px; font-weight: 600; }
.alert span { font-size: 12.5px; color: var(--ink-2); }
.alert .go { margin-left: auto; align-self: center; color: var(--ink-2); }

.fleetline { display: flex; flex-wrap: wrap; gap: 6px 22px; padding: 12px 16px; border-bottom: 1px solid var(--line); background: var(--surface-2); font-size: 13px; color: var(--ink-2); }
.fleetline span { display: inline-flex; align-items: baseline; gap: 4px; }
.fleetline b { color: var(--ink); font-weight: 600; font-size: 15px; }
.fleetline i { font-style: normal; display: inline-block; width: 8px; height: 8px; border-radius: 50%; vertical-align: 1px; }
.fleetline i.ok { background: var(--ok); }
.fleetline i.warn { background: var(--warn); }
.fleetline i.err { background: var(--err); }

.panel .filters { display: flex; gap: 8px; padding: 10px 16px; border-bottom: 1px solid var(--line); flex-wrap: wrap; align-items: flex-end; }
.panel .filters .ads-field { margin: 0; max-width: 14rem; min-width: 9rem; }

.panel table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.panel table:not(.table) td.detail { display: none; }
.panel thead th { text-align: left; font-size: 11.5px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-2); padding: 9px 16px; border-bottom: 1px solid var(--line); background: var(--surface); }
.panel tbody td { padding: 11px 16px; border-bottom: 1px solid var(--line); vertical-align: middle; }
.panel tbody tr:last-child td { border-bottom: 0; }
.panel td.name { min-width: 240px; }
.panel td.name a { font-weight: 600; text-decoration: none; }
.panel td.name a:hover { text-decoration: underline; }
.panel td.name small { display: block; color: var(--ink-2); font-size: 12px; margin-top: 1px; }
.panel td.meta { max-width: 220px; color: var(--ink-2); }
.panel th.r, .panel td.r { text-align: right; }
.panel .cell { display: flex; align-items: center; gap: 10px; }
.panel td.hide-sm details { display: block; margin-top: 2px; }
.panel td details > summary { min-height: 44px; display: inline-flex; align-items: center; padding: 0 6px; cursor: pointer; }
.rowmenu { display: inline-block; }
.rowmenu > summary { list-style: none; width: 44px; height: 44px; border-radius: 8px; border: 1px solid transparent; color: var(--ink-2); cursor: pointer; display: grid; place-items: center; }
.rowmenu > summary::-webkit-details-marker { display: none; }
.rowmenu > summary:hover { border-color: var(--line); background: var(--surface); color: var(--ink); }
.rowmenu:not([open]) .rowmenu-body { display: none; }
.rowmenu .rowmenu-body { display: grid; gap: 6px; padding: 8px; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); box-shadow: var(--shadow-1); margin-top: 4px; text-align: left; }

.feed { list-style: none; margin: 0; padding: 4px 0; }
.feed li { display: grid; grid-template-columns: 28px 1fr auto; gap: 10px; padding: 10px 16px; border-bottom: 1px solid var(--line); font-size: 13px; align-items: start; }
.feed li:last-child { border-bottom: 0; }
.feed .who { width: 28px; height: 28px; border-radius: 50%; background: var(--surface-2); color: var(--ink-2); display: grid; place-items: center; font-size: 11px; font-weight: 700; }
.feed .who.sys { background: var(--accent-pane); color: oklch(0.43 0.125 152); }
.feed b { font-weight: 600; }
.feed span { color: var(--ink-2); display: block; font-size: 12.5px; }
.feed time { color: var(--ink-2); font-size: 12px; white-space: nowrap; }

.detail { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(320px, 1fr); gap: 16px; }
.preview { aspect-ratio: 16 / 9; background: oklch(0.2 0.02 160); border-radius: var(--r-md); position: relative; overflow: hidden; margin: 16px; }
.preview img { width: 100%; height: 100%; object-fit: contain; display: block; }
.preview .stamp { position: absolute; left: 12px; bottom: 10px; color: #fff; font: 500 11.5px var(--font-mono); background: oklch(0 0 0 / 0.6); padding: 3px 8px; border-radius: 6px; }
.kv { display: grid; grid-template-columns: 150px 1fr; gap: 8px 14px; padding: 14px 16px; font-size: 13.5px; margin: 0; }
.kv dt { color: var(--ink-2); margin: 0; }
.kv dd { margin: 0; font-weight: 500; overflow-wrap: anywhere; }
.ops { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; padding: 14px 16px; }
.ops form { margin: 0; }
.ops .btn { justify-content: flex-start; width: 100%; min-height: 40px; }
.ops .help { grid-column: 1 / -1; font-size: 12.5px; color: var(--ink-2); margin: 0; }
.tabs { display: flex; gap: 2px; padding: 0 16px; border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.tabs a { padding: 11px 12px; font-size: 13.5px; font-weight: 600; color: var(--ink-2); text-decoration: none; border-bottom: 2px solid transparent; margin-bottom: -1px; }
.tabs a[aria-current] { color: oklch(0.43 0.125 152); border-color: var(--accent); }

.emptystate { padding: 20px 16px; }
.emptystate h2, .emptystate h3 { margin: 0 0 4px; font-size: 1rem; }
.emptystate p { color: var(--ink-2); font-size: 13.5px; margin: 0 0 var(--s-3); }
.emptystate > :last-child { margin-bottom: 0; }

/* Drawer. Without script it is a :target panel: the primary button is a link to #id, so the form is still
   rendered, reachable and submittable. With script app.js toggles [data-open], traps focus and handles Escape. */
.drawer {
  position: fixed; inset: 0 0 0 auto; width: min(460px, 100vw); background: var(--surface); box-shadow: var(--shadow-2);
  z-index: var(--z-drawer); display: none; flex-direction: column; overflow: auto;
}
.drawer:target, .drawer[data-open] { display: flex; }
.drawer > header { display: flex; align-items: center; gap: 10px; padding: 16px 20px; border-bottom: 1px solid var(--line); }
.drawer > header h2 { margin: 0; font: 600 17px var(--font-title); letter-spacing: -0.01em; }
.drawer > header .close { margin-left: auto; }
.drawer form { padding: 18px 20px; display: grid; gap: 14px; margin: 0; }
.drawer form .ads-field { margin: 0; max-width: none; }
.drawer .foot { display: flex; gap: 8px; justify-content: flex-end; padding: 14px 20px; border-top: 1px solid var(--line); background: var(--surface-2); }
.drawer-scrim { display: none; position: fixed; inset: 0; background: oklch(0.2 0.02 160 / 0.35); z-index: var(--z-scrim); }
.rail-close { display: none; }
@media (max-width: 760px) {
  .rail-close {
    display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; min-height: 44px;
    margin: 0 0 6px; padding: 0 10px; border-radius: 8px; border: 1px solid oklch(1 0 0 / 0.28); background: transparent;
    color: var(--rail-ink); font: 600 13.5px var(--font-ui); cursor: pointer;
  }
  .rail-close svg { width: 18px; height: 18px; stroke-width: 1.75; }
  .rail-close:hover { background: oklch(1 0 0 / 0.12); }
}
/* Row-detail disclosure: app.js moves any column a phone would otherwise drop (td.hide-sm or anything beyond
   name/status/meta) into this toggle, so audit, users, layouts, billing and reports keep every value reachable
   on a phone instead of silently dropping it. */
.ads-row-detail { grid-column: 1 / -1; margin-top: 2px; }
.ads-row-detail > summary { list-style: none; cursor: pointer; color: var(--accent); font-size: 12.5px; font-weight: 600; min-height: 32px; display: flex; align-items: center; }
.ads-row-detail > summary::-webkit-details-marker { display: none; }
.ads-row-detail dl { display: grid; grid-template-columns: minmax(96px, 40%) 1fr; gap: 4px 10px; margin: 6px 0 2px; font-size: 12.5px; }
.ads-row-detail dt { color: var(--ink-2); font-weight: 600; }
.ads-row-detail dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.drawer[data-open] ~ .drawer-scrim, .drawer:target ~ .drawer-scrim { display: block; }

.tabbar { display: none; }
.fab { display: none; }

/* ------------------------------------------------------------------------------------------- responsive */

@media (max-width: 1100px) {
  :root { --rail-w: 72px; }
  .rail { padding: 14px 10px; }
  .brand .name, .tenant b, .tenant span, .group, .rail .me .who { display: none; }
  .nav a > span:not(.n) { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .tenant { justify-content: center; padding: 8px; }
  .nav a { justify-content: center; padding: 10px; }
  .nav a .n { position: absolute; margin: 0; transform: translate(14px, -10px); }
  .rail .me { justify-content: center; flex-direction: column; gap: 6px; }
  .rail .me button { width: 100%; min-width: 44px; min-height: 44px; padding: 0 4px; font-size: 11px; }
}

@media (max-width: 760px) {
  .shell { grid-template-columns: 1fr; }
  .rail { display: none; position: fixed; inset: 0 auto 0 0; width: 260px; box-shadow: var(--shadow-2); }
  :root { --rail-w: 0px; }
  .rail:target, .rail[data-open] { display: flex; }
  .rail:target .brand .name, .rail[data-open] .brand .name,
  .rail:target .tenant b, .rail[data-open] .tenant b,
  .rail:target .tenant span, .rail[data-open] .tenant span,
  .rail:target .group, .rail[data-open] .group,
  .rail:target .me .who, .rail[data-open] .me .who { display: block; }
  .rail:target .nav a > span:not(.n), .rail[data-open] .nav a > span:not(.n) {
    position: static; width: auto; height: auto; margin: 0; overflow: visible; clip-path: none; white-space: normal;
    display: block;
  }
  .rail:target .nav a, .rail[data-open] .nav a { justify-content: flex-start; padding: 8px 10px; }
  .rail:target .tenant, .rail[data-open] .tenant { justify-content: flex-start; padding: 8px 10px; }
  .rail:target .me, .rail[data-open] .me { flex-direction: row; justify-content: flex-start; gap: 10px; }
  .rail:target .me button, .rail[data-open] .me button { width: auto; padding: 0 12px; font-size: 12.5px; }
  .rail:target .brand .name small, .rail[data-open] .brand .name small { display: block; }
  .rail:target .me, .rail[data-open] .me { flex-direction: row; justify-content: flex-start; gap: 10px; }
  .rail:target .me button, .rail[data-open] .me button { width: auto; padding: 0 12px; font-size: 12.5px; }
  .rail:target .brand .name small, .rail[data-open] .brand .name small { display: block; }
  .burger { display: grid; }
  .topbar { padding: 10px 14px; }
  .topbar form.search input { width: 100%; max-width: none; }
  .page { padding: 16px 14px 96px; }
  .page-head h1 { font-size: 22px; }
  .grid.two, .detail { grid-template-columns: 1fr; }
  /* Two-line phone rows apply to contract tables only; legacy table.table editors keep their own data-label collapse. */
  .panel table:not(.table) thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .panel table:not(.table), .panel table:not(.table) tbody, .panel table:not(.table) tr, .panel table:not(.table) td { display: block; }
  .panel table:not(.table) tbody tr { padding: 10px 14px; border-bottom: 1px solid var(--line); display: grid; grid-template-columns: 1fr auto; gap: 4px 10px; }
  .panel table:not(.table) tbody td { padding: 0; border: 0; }
  .panel table:not(.table) td.name { grid-column: 1; grid-row: 1; min-width: 0; }
  .panel table:not(.table) td.status { grid-column: 2; grid-row: 1; justify-self: end; }
  .panel table:not(.table) td.meta { grid-column: 1 / -1; color: var(--ink-2); font-size: 12.5px; max-width: none; }
  .panel table:not(.table) td.detail { display: block; grid-column: 1 / -1; }
  .panel table:not(.table) td.hide-sm, .hide-sm, .panel table:not(.table) td.r,
  .panel table:not(.table) tbody td:not(.name):not(.status):not(.meta) { display: none; }
  .kv { grid-template-columns: 120px 1fr; }
  .tabbar {
    position: fixed; left: 0; right: 0; bottom: 0; display: grid; grid-template-columns: repeat(4, 1fr);
    background: var(--rail); color: var(--rail-ink-2); padding: 6px 6px calc(6px + env(safe-area-inset-bottom));
    z-index: var(--z-rail);
  }
  .tabbar a { display: grid; justify-items: center; gap: 3px; padding: 6px 4px; text-decoration: none; font-size: 11px; font-weight: 600; border-radius: 10px; color: inherit; }
  .tabbar a[aria-current] { color: #fff; background: oklch(1 0 0 / 0.12); }
  .tabbar svg { width: 20px; height: 20px; }
  .tabbar a { min-height: 44px; position: relative; align-content: center; }
  .tabbar .n { position: absolute; top: 2px; left: calc(50% + 6px); min-width: 18px; height: 18px; padding: 0 5px; border-radius: 999px; background: #fff; color: #111; font-size: 11px; line-height: 18px; text-align: center; }
  .drawer { width: 100vw; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 1ms; animation-iteration-count: 1; transition-duration: 1ms; }
}

@media print {
  .rail, .topbar, .tabbar, .skip-link, .ads-print-hide { display: none; }
  body { background: #fff; }
}

/* ------------------------------------------------------------------------------- retained legacy layer
   Pages not yet moved onto the primitives above still render this markup. The rules are unchanged apart
   from the palette and typeface, which now come from the tokens at the top of this file. */

.ads-shell { max-width: 1100px; margin: 0 auto; padding: 0 var(--s-4) var(--s-6); }
.ads-back { display: inline-block; font-size: var(--fs-14); padding-top: var(--s-4); }
.ads-section { margin-bottom: var(--s-6); }
.ads-section > h2 { padding-bottom: var(--s-2); border-bottom: 1px solid var(--line); }
.ads-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--s-5); margin-bottom: var(--s-5); }
.ads-panel { background: var(--surface-2); border-radius: var(--r-lg); padding: var(--s-4); margin-bottom: var(--s-5); }

button, .ads-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2); min-height: 44px;
  padding: var(--s-2) var(--s-4); font-family: var(--font-ui); font-size: var(--fs-16); font-weight: 600;
  line-height: 1.2; white-space: nowrap; border-radius: var(--r-md); border: 1px solid var(--accent);
  background: var(--accent); color: var(--on-accent); text-decoration: none; cursor: pointer;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
button:hover, .ads-btn:hover { background: var(--accent-hover); border-color: var(--accent-hover); color: var(--on-accent); }
button.ads-secondary, .ads-btn.ads-secondary { background: var(--surface); color: var(--ink); border-color: var(--line-strong); }
button.ads-secondary:hover, .ads-btn.ads-secondary:hover { background: var(--surface-2); border-color: var(--ink-2); color: var(--ink); }
button.ads-quiet { background: transparent; color: oklch(0.43 0.125 152); border-color: transparent; padding-inline: var(--s-2); }
button.ads-quiet:hover { background: var(--accent-pane); border-color: transparent; color: oklch(0.43 0.125 152); }
button.ads-danger, .ads-btn.ads-danger { background: var(--surface); color: var(--err); border-color: oklch(0.86 0.062 27); }
button.ads-danger:hover, .ads-btn.ads-danger:hover { background: var(--err-pane); border-color: var(--err); color: var(--err); }
button:disabled, button[aria-disabled="true"], .ads-ops form[aria-disabled="true"] button {
  background: oklch(0.935 0.008 160); color: var(--ink-2); border-color: var(--line); cursor: not-allowed;
}
button.ads-cta { font-size: var(--fs-18); min-height: 52px; }
.ads-nav-long { display: inline; }
.ads-nav-short { display: none; }

.ads-actions { display: flex; gap: var(--s-2); flex-wrap: wrap; align-items: flex-start; }
.ads-actions form { margin: 0; }

.field, .ads-field { margin-bottom: var(--s-4); max-width: 30rem; }
.field > label, .ads-field label { display: block; font-weight: 600; font-size: var(--fs-14); margin-bottom: var(--s-1); }
.field input, .field select, .field textarea,
.ads-field input, .ads-field select, .ads-field textarea,
label > input[type="text"], label > input[type="email"], label > input[type="password"],
label > input[type="number"], label > select,
.panel select, .panel input[type="date"], .panel input[type="datetime-local"], .panel input[type="time"],
.sd select, .sd input[type="date"], .sd input[type="datetime-local"], .sd input[type="time"],
.sd input[type="text"], .sd input[type="number"] {
  width: 100%; padding: var(--s-2) var(--s-3); min-height: 44px; font-size: var(--fs-16); font-family: var(--font-ui);
  color: var(--ink); background: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--r-md);
}
.field input[type="checkbox"], .ads-field input[type="checkbox"] { width: auto; min-height: 0; }
.field input[type="datetime-local"], .ads-field input[type="datetime-local"],
.field input[type="date"], .ads-field input[type="date"] { width: 100%; max-width: 100%; min-width: 0; }
.field input::placeholder, .ads-field input::placeholder { color: var(--ink-2); }
.field input:hover, .ads-field input:hover { border-color: var(--ink-2); }
.field-help, .ads-hint { color: var(--ink-2); font-size: var(--fs-14); margin-top: var(--s-1); }
.ads-hint.bad { color: var(--err); font-weight: 600; }
.field-error { color: var(--err); font-size: var(--fs-14); font-weight: 600; margin-top: var(--s-1); }
.field input[aria-invalid="true"], .ads-field input[aria-invalid="true"] { border-color: var(--err); border-width: 2px; }
.claim-code { font-family: var(--font-mono); font-size: 32px; letter-spacing: 0.2em; text-align: center; margin: 12px 0; overflow-wrap: anywhere; }
.ads-field .code { font-family: var(--font-mono); letter-spacing: 0.18em; text-transform: uppercase; font-size: 16px; }

.notice, .ads-notice, .ads-error {
  display: block; border: 1px solid oklch(0.862 0.044 248); background: var(--info-pane); color: var(--ink);
  border-radius: var(--r-md); padding: var(--s-3) var(--s-4); margin: 0 0 var(--s-4); font-size: var(--fs-14);
}
.notice-ok, .ads-notice { border-color: var(--accent-line); background: var(--ok-pane); }
.notice-warn { border-color: oklch(0.858 0.075 78); background: var(--warn-pane); }
.notice-error, .ads-error { border-color: oklch(0.86 0.062 27); background: var(--err-pane); }
.notice strong, .ads-notice strong, .ads-error strong { font-weight: 700; }

span.status, .ads-pill {
  display: inline-flex; align-items: center; padding: 2px var(--s-2); border-radius: var(--r-pill);
  font-size: var(--fs-12); font-weight: 700; border: 1px solid transparent; white-space: nowrap;
}
.status-ok, .ads-pill-online { background: var(--ok-pane); border-color: var(--accent-line); color: var(--ok); }
.status-warn, .ads-pill-offline { background: var(--warn-pane); border-color: oklch(0.858 0.075 78); color: var(--warn); }
.status-error, .ads-pill-revoked { background: var(--err-pane); border-color: oklch(0.86 0.062 27); color: var(--err); }
.status-info { background: var(--info-pane); border-color: oklch(0.862 0.044 248); color: var(--info); }
.ads-pill-dot { display: none; }

table.table { width: 100%; border-collapse: collapse; }
table.table th, table.table td { text-align: left; padding: var(--s-3) var(--s-2); border-bottom: 1px solid var(--line); }
table.table thead th { font-size: var(--fs-12); font-weight: 700; color: var(--ink-2); background: var(--surface-2); border-bottom: 1px solid var(--line-strong); }
table.table tbody tr:hover { background: var(--surface-2); }
td .ads-actions { gap: var(--s-1); }
.table-wrap { border: 1px solid var(--line); border-radius: var(--r-lg); overflow-x: auto; overflow-y: hidden; background: var(--surface); max-width: 100%; min-width: 0; position: relative; }
.ops .opsgroup { display: block; min-width: 0; }
@media (max-width: 760px) {
  .ops { grid-template-columns: 1fr; }
}
.table-wrap:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.ads-table td > details:not([open]) { height: 1.5rem; overflow: hidden; }
.ads-table td > details > summary { line-height: 1.5rem; }
.row-attention { background: var(--warn-pane); }
.row-attention:hover { background: var(--warn-pane); }

.filters { display: flex; gap: var(--s-3); flex-wrap: wrap; align-items: flex-end; padding: var(--s-3) 0 var(--s-4); }
.filters .field, .filters .ads-field { margin: 0; max-width: 14rem; min-width: 10rem; }
.summary-line { color: var(--ink-2); font-size: var(--fs-14); margin: 0 0 var(--s-3); }

.empty { border: 1px dashed var(--line-strong); border-radius: var(--r-lg); background: var(--surface-2); padding: var(--s-5); text-align: left; }
.empty h2, .empty h3 { margin-bottom: var(--s-1); }
.empty h2 { font-size: var(--fs-18); }
.empty p { color: var(--ink-2); margin-bottom: var(--s-3); }

.auth-wrap { max-width: 26rem; margin: 0 auto; padding: var(--s-6) var(--s-4) var(--s-7); }
.auth-lockup { display: flex; justify-content: center; align-items: center; gap: 10px; margin-bottom: var(--s-5); }
.auth-lockup .mark { width: 34px; height: 34px; border-radius: 9px; background: var(--accent); display: grid; place-items: center; color: #fff; font: 700 16px var(--font-title); }
.auth-lockup .name { font: 600 19px/1.1 var(--font-title); letter-spacing: -0.015em; }
.auth-lockup .name small { display: block; font: 500 11.5px var(--font-ui); color: var(--ink-2); margin-top: 2px; }
.auth-wrap h1 { font-size: 1.5rem; }
.auth-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--s-5); box-shadow: var(--shadow-1); }
.auth-card .field, .auth-card .ads-field { max-width: none; }
.auth-card button[type="submit"] { width: 100%; }
.auth-foot { font-size: var(--fs-14); margin: var(--s-4) 0 0; }

.ads-qr { background: var(--surface); padding: var(--s-3); border: 1px solid var(--line); border-radius: var(--r-md); display: inline-block; }
.ads-qr svg { display: block; width: 180px; height: 180px; }
.ads-copy { display: flex; gap: var(--s-2); align-items: flex-end; }
.ads-copy input { font-family: var(--font-mono); font-size: var(--fs-14); }
.ads-codes { display: grid; grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr)); gap: var(--s-2); list-style: none; padding: 0; margin: 0 0 var(--s-4); }
.ads-codes li { font-family: var(--font-mono); font-size: var(--fs-14); background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-sm); padding: var(--s-2); text-align: center; }

.ads-row { display: flex; align-items: center; gap: var(--s-3); }
.ads-grow { flex: 1 1 auto; min-width: 0; }
.ads-playlist-row { display: flex; align-items: flex-end; gap: var(--s-3); padding: var(--s-3); border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.ads-playlist-row:last-of-type { border-bottom: 0; }
.ads-playlist-row img { width: 64px; height: 36px; object-fit: contain; border-radius: var(--r-sm); background: oklch(0.935 0.008 160); }
.ads-playlist-row label { font-size: var(--fs-12); font-weight: 600; color: var(--ink-2); display: block; }
.ads-dur-input, .ads-playlist-row input[type="number"] {
  width: 5.5rem; min-height: 44px; padding: var(--s-2); font-size: var(--fs-16); font-family: var(--font-ui);
  color: var(--ink); background: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--r-sm);
}

.ads-asset-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)); gap: var(--s-3); }
.ads-asset-tile { border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; background: var(--surface); display: flex; flex-direction: column; }
.ads-asset-tile img { width: 100%; height: 6.25rem; object-fit: contain; display: block; background: oklch(0.935 0.008 160); }
.ads-asset-tile .ads-asset-meta { padding: var(--s-2); font-size: var(--fs-14); display: grid; gap: var(--s-2); }
.ads-asset-name { font-weight: 600; word-break: break-word; }

.ads-ops { display: flex; gap: var(--s-3); flex-wrap: wrap; align-items: flex-start; }
.ads-ops form { margin: 0; width: 12rem; display: flex; flex-direction: column; gap: var(--s-1); }
.ads-ops .ads-hint { display: block; margin-top: 0; }
.ads-oplist { list-style: none; padding: 0; margin: 0; }
.ads-oplist li { display: flex; gap: var(--s-3); align-items: center; flex-wrap: wrap; padding: var(--s-2) 0; border-bottom: 1px solid var(--line); font-size: var(--fs-14); }
.ads-oplist time, .ads-when { color: var(--ink-2); font-size: var(--fs-14); }
td .ads-ops { gap: var(--s-2); }
td .ads-ops form { width: 11rem; }
td .ads-ops .ads-hint { font-size: var(--fs-12); }

footer.ads-footer { color: var(--ink-2); font-size: var(--fs-14); text-align: center; padding: var(--s-6) 0 var(--s-4); }

.ads-pw { position: relative; }
.ads-pw input { padding-right: 52px; }
.ads-pw-toggle {
  position: absolute; right: 2px; top: 50%; transform: translateY(-50%); width: 44px; height: 44px; min-height: 44px;
  padding: 0; background: transparent; border: 0; color: var(--ink-2); display: inline-flex; align-items: center; justify-content: center;
}
.ads-pw-toggle:hover { background: transparent; color: var(--ink); }
.ads-pw-toggle:focus-visible { outline: 3px solid var(--accent); outline-offset: -3px; }
.ads-pw-toggle[hidden] { display: none; }
.ads-pw-slash { display: none; }
.ads-pw-toggle[aria-pressed="true"] .ads-pw-slash { display: inline; }
.ads-forgot { margin: var(--s-4) 0 0; font-size: var(--fs-14); }

.ads-paging { display: flex; gap: var(--s-2); flex-wrap: wrap; align-items: center; }
.ads-exports { display: flex; gap: var(--s-4); flex-wrap: wrap; align-items: center; }
.ads-filter datalist { display: none; }
.ads-filter .ads-field button { width: 100%; }
.ads-filter { display: grid; grid-template-columns: 1fr; gap: var(--s-3); align-items: start; padding: var(--s-3) 0 var(--s-4); }
.ads-filter .ads-field, .ads-filter .field { margin: 0; max-width: none; min-width: 0; }
.ads-filter .field-help, .ads-filter .ads-hint { min-height: 1.25rem; }
.ads-filter > .ads-field:last-child { align-self: end; }
@media (min-width: 600px) { .ads-filter { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 900px) { .ads-filter { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.panel .filters.ads-filter { display: grid; grid-template-columns: 1fr; align-items: start; padding: 10px 16px 14px; }
.panel .filters.ads-filter .ads-field { max-width: none; min-width: 0; }
@media (min-width: 600px) { .panel .filters.ads-filter { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 900px) { .panel .filters.ads-filter { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

fieldset.plain { border: 0; padding: 0; margin: 0; min-width: 0; }
fieldset.plain:disabled { opacity: 0.7; }
fieldset.ads-panel { border: 1px solid var(--line); }
fieldset.ads-panel legend { font-family: var(--font-ui); font-weight: 700; font-size: var(--fs-14); padding: 0 var(--s-2); }

.map-preview, .zone-canvas { border: 1px solid var(--line); border-radius: 6px; padding: 8px; margin: 12px 0; overflow: hidden; }
.map-cell-box, .zone-box-rect { fill: var(--surface-2); stroke: var(--accent); stroke-width: 2; }
.map-bezel { fill: var(--ink); opacity: 0.55; }
.map-cell-name, .zone-box-name { fill: var(--ink); font-size: 14px; font-weight: 600; }
.map-cell-size, .zone-box-kind { fill: var(--ink-2); font-size: 12px; }
.notice-list { list-style: none; margin: 8px 0; padding: 0; display: grid; gap: 6px; }
.notice-item { display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline; padding: 8px 10px; border-left: 3px solid var(--line); }
.notice-item.notice-blocking { border-left-color: var(--err); }
.notice-item.notice-warning { border-left-color: var(--warn); }
.ads-tabs { display: flex; gap: 16px; margin: 8px 0 16px; flex-wrap: wrap; }
.ads-tabs a[aria-current="page"] { font-weight: 700; text-decoration: underline; }
.ads-inline-form { display: grid; gap: 6px; }
.ads-slot { border: 1px solid var(--line); border-radius: 6px; padding: 10px 12px; margin: 10px 0; }
.ads-subsection { margin-top: 16px; }
.ads-pager { display: flex; gap: 16px; }
.ads-wrap { white-space: normal; overflow-wrap: anywhere; word-break: break-word; max-width: 24rem; }

@media (max-width: 599px) {
  .table-wrap { border: 0; background: transparent; }
  table.table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  table.table tbody tr {
    display: block; background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-lg); padding: var(--s-2) var(--s-3); margin-bottom: var(--s-3);
  }
  table.table tbody tr:hover { background: var(--surface); }
  table.table tbody td {
    display: flex; gap: var(--s-3); justify-content: space-between; align-items: baseline;
    border-bottom: 1px solid var(--line); padding: var(--s-2) 0; min-width: 0; overflow-wrap: anywhere; text-align: left;
  }
  table.table tbody tr td:last-child { border-bottom: 0; }
  table.table tbody td[data-label]::before {
    content: attr(data-label); font-size: var(--fs-12); font-weight: 700; color: var(--ink-2); flex: 0 0 8rem;
  }
  .ads-ops form, .ads-ops { width: 100%; max-width: none; }
  .ads-ops form button { width: 100%; }
  .filters .field, .filters .ads-field { max-width: none; flex: 1 1 100%; }
}

/* The remote-operations grid uses the legacy secondary button, so give it the grid cell's geometry. */
.ops form { display: block; width: auto; }
.ops button.ads-secondary {
  width: 100%; min-height: 40px; justify-content: flex-start; font-size: 13.5px;
  border-radius: var(--r-md); font-family: var(--font-ui);
}
.ops .ads-hint { display: block; margin-top: 0; }

/* ---------------------------------------------------------------- builder D2: cards, thumbs, panel ops ---- */
.cards {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--s-3); padding: var(--s-3);
}
.card {
  position: relative; display: flex; flex-direction: column;
  background: var(--surface, #fff); border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden;
}
.card .thumb {
  aspect-ratio: 16 / 10; background: var(--surface-2); display: grid; place-items: center; overflow: hidden;
  border-bottom: 1px solid var(--line);
}
.card .thumb { position: relative; }
.card .thumb img, .card .thumb video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
.card-body { padding: var(--s-2) var(--s-3) var(--s-3); display: grid; gap: var(--s-2); min-width: 0; }
.card-name { font-weight: 600; font-size: 13.5px; overflow-wrap: anywhere; }
.card-meta { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.card-meta small { color: var(--ink-2); font-size: 12px; }
.card-menu { position: absolute; top: 6px; right: 6px; }
.panel-body.ops { display: grid; gap: var(--s-2); }
@media (max-width: 599px) { .cards { grid-template-columns: 1fr; } }

/* ------------------------------------------------------------------- playlists and multi-file content intake */

.dropzone {
  position: relative; border: 2px dashed var(--line-strong); border-radius: var(--r-md); padding: 22px 18px;
  text-align: center; background: var(--surface);
  transition: background-color 180ms var(--ease), border-color 180ms var(--ease);
}
.dropzone[data-over] { border-color: var(--accent); background: var(--accent-pane); }
.dropzone form { display: block; margin: 0; padding: 0; }
.dropzone p { margin: 0 0 10px; color: var(--ink-2); font-size: 13.5px; }
.dropzone input[type="file"] {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}
.dropzone input[type="file"]:focus-visible + label { outline: 2px solid var(--accent); outline-offset: 2px; }
.dropzone label.btn { cursor: pointer; }

.uplist { list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 8px; text-align: left; }
.uplist li {
  display: grid; grid-template-columns: 1fr auto; gap: 4px 10px; align-items: center;
  padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--r-sm); font-size: 13px;
}
.uplist li { grid-template-columns: 1fr auto auto; }
.uplist .nm { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.uplist .sz { color: var(--ink-2); font-size: 12.5px; font-variant-numeric: tabular-nums; }
.uplist .res { grid-column: 1 / -1; color: var(--ink-2); font-size: 12.5px; }
.uplist .res.bad { color: var(--err); }
.uplist .bar { grid-column: 1 / -1; height: 4px; border-radius: var(--r-pill); background: var(--surface-2); overflow: hidden; }
.uplist .bar > i { display: block; height: 100%; width: 0; background: var(--accent); transition: width 180ms var(--ease); }

.pl-items { list-style: none; margin: 0; padding: 0; }
.pl-items > li {
  display: grid; grid-template-columns: 56px 1fr auto; gap: 12px; align-items: center;
  padding: 10px 16px; border-bottom: 1px solid var(--line);
}
.pl-items > li:last-child { border-bottom: 0; }
.pl-items > li[data-dragging] { background: var(--accent-pane); }
.pl-items > li[data-droptarget] { box-shadow: inset 0 2px 0 var(--accent); }
.pl-items .pl-name { overflow: hidden; }
.pl-items .pl-name b { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pl-thumb { display: block; width: 64px; height: 36px; border-radius: var(--r-sm); background: var(--surface-2); object-fit: contain; }
.pl-thumb-label { display: flex; align-items: center; justify-content: center; font-size: 11px; color: var(--ink-2); }
.pl-row-ctl { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.pl-row-ctl input[type="number"] { width: 74px; }
.pl-row-ctl select { max-width: 100%; min-height: 32px; }
/* The row thumb is a 16:9 screen in miniature, so the crop or bars a fit makes show here the moment it is picked. */
.pl-items li[data-fit="contain"] .pl-thumb { object-fit: contain; }
.pl-items li[data-fit="fill"] .pl-thumb { object-fit: fill; }
.pl-items li[data-fit="native"] .pl-thumb { object-fit: none; }
.pl-row-ctl label { display: inline-flex; gap: 4px; align-items: center; font-size: 13px; color: var(--ink-2); }

.pickgrid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px;
  max-height: 340px; overflow: auto; padding: 16px;
}
.picktile {
  display: block; border: 1px solid var(--line); border-radius: var(--r-md); padding: 8px; font-size: 12.5px;
  cursor: pointer; transition: border-color 160ms var(--ease), background-color 160ms var(--ease);
}
.picktile:hover { border-color: var(--line-strong); }
.picktile:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }
.picktile:has(input:checked) { border-color: var(--accent); background: var(--accent-pane); }
.picktile img, .picktile video { width: 100%; height: 84px; object-fit: contain; border-radius: var(--r-sm); background: var(--surface-2); }
.picktile .nm { display: block; margin-top: 6px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

dialog.preview { border: 1px solid var(--line); border-radius: var(--r-md); padding: 0; background: var(--surface); max-width: 94vw; }
dialog.preview [data-preview-body] { width: min(90vw, calc(72vh * 16 / 9)); aspect-ratio: 16 / 9; background: #000; position: relative; }
dialog.preview img, dialog.preview video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; display: block; }
dialog.preview { overflow: hidden; }
dialog.preview .foot { position: absolute; top: 8px; right: 8px; z-index: 2; padding: 0; border: 0; display: flex; }
dialog.preview .foot .btn { background: rgba(0,0,0,.72); color: #fff; border: 1px solid rgba(255,255,255,.5); }

details.confirm > summary { cursor: pointer; padding: 6px 0; font-size: 13.5px; font-weight: 600; }

@media (prefers-reduced-motion: reduce) {
  .dropzone, .uplist .bar > i, .picktile { transition: none; }
}

@media (max-width: 480px) {
  .dropzone { padding: 18px 12px; }
  .pl-items > li { grid-template-columns: 56px 1fr; }
  .pl-items .pl-row-ctl { grid-column: 1 / -1; }
  .pickgrid { grid-template-columns: repeat(3, 1fr); padding: 12px; }
}

/* A control that only works through fetch. It is rendered but hidden until app.js marks the document, so a
   reader with scripting off meets the reason sentence beside it instead of a button that would do nothing. */
/* A button class sets its own display, which otherwise outranks the hidden attribute and leaves a control
   on screen that script has already retired. */
[hidden] { display: none !important; }

.jsonly { display: none; }
[data-js] .jsonly { display: contents; }
/* A radio label is a flex item in its fieldset, so display:contents would dissolve its box and let the radio and
   its words land as two separately-gapped items. It keeps its own layout once script reveals it. */
[data-js] .sc-choice label.jsonly { display: inline-flex; align-items: center; gap: 6px; }
[data-js] noscript { display: none; }

.rename > summary { cursor: pointer; }
.rename form { display: grid; gap: 6px; padding: 8px 0 2px; }
.rename label { font-size: 12.5px; color: var(--ink-2); }

/* Preview. The stage keeps the layout's own proportions, so a caption never has to explain where a zone sits. */
/* --pv-player-bg is the player's own field colour (Background in Cloud.Player/OutputWindows.cs, 0x101114): letterbox
   bars and the canvas between zones are that colour on the wall, so they are that colour here. */
.pv-stage { --pv-player-bg: #101114; position: relative; width: 100%; aspect-ratio: 16 / 9; overflow: hidden;
  background: var(--pv-player-bg); border: 1px solid var(--line); border-radius: var(--r-md); }
.pv-zone { position: absolute; overflow: hidden; background: var(--pv-player-bg);
  border: 1px solid var(--line); }
/* One definite track, so a full-size original (the thumb route serves the asset itself) cannot stretch the grid
   past the zone and turn object-fit into a crop of the wrong box. */
.pv-media { width: 100%; height: 100%; display: grid; grid-template: minmax(0, 1fr) / minmax(0, 1fr); place-items: center; }
.pv-media img, .pv-media video { min-width: 0; min-height: 0; }
.pv-media img, .pv-media video { width: 100%; height: 100%; object-fit: cover; }
/* A picture with no fit of its own (no data-fit) inherits its zone's fit, as the player does: contain, cover,
   fill, or native (original size, centered, not scaled). :not([data-fit]) keeps these from outranking an item's choice. */
.pv-zone[data-pv-fit="contain"] .pv-media img:not([data-fit]), .pv-zone[data-pv-fit="contain"] .pv-media video:not([data-fit]) { object-fit: contain; }
.pv-zone[data-pv-fit="fill"] .pv-media img:not([data-fit]), .pv-zone[data-pv-fit="fill"] .pv-media video:not([data-fit]) { object-fit: fill; }
.pv-zone[data-pv-fit="native"] .pv-media img:not([data-fit]), .pv-zone[data-pv-fit="native"] .pv-media video:not([data-fit]) { object-fit: none; object-position: center; }
/* An item's own fit beats its zone's: the player draws a picture by the fit its item carries, when it carries one. */
.pv-zone .pv-media [data-fit="cover"] { object-fit: cover; }
.pv-zone .pv-media [data-fit="contain"] { object-fit: contain; }
.pv-zone .pv-media [data-fit="fill"] { object-fit: fill; }
.pv-zone .pv-media [data-fit="native"] { object-fit: none; width: 100%; height: 100%; }
.pv-idle, .pv-url { padding: 8px; text-align: center; font-size: 13px; color: var(--ink-3); }
.pv-zone-name { position: absolute; left: 6px; top: 6px; padding: 1px 6px; font-size: 11.5px;
  color: var(--ink-2); background: var(--surface); border-radius: var(--r-sm); }
.pv-draft { position: absolute; right: 8px; top: 8px; }
.pv-at { margin: 8px 0 0; font-size: 13px; color: var(--ink-2); }
.pv-caps { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 6px; }
.pv-caps li { display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline;
  font-size: 13.5px; color: var(--ink-2); }
.pv-caps b { color: var(--ink); }
.pv-left { font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: var(--ink); }
.pv-est { font-size: 12.5px; color: var(--ink-3); }
.pv-why { margin-top: 12px; }
.pv-why > summary { cursor: pointer; }
.pv-why ul { margin: 8px 0 0; padding-left: 18px; font-size: 13.5px; color: var(--ink-2); }
.pv-note { margin: 8px 0 0; font-size: 13.5px; color: var(--ink-2); }
.pv-note a { color: var(--accent); }
.pv-tl-wrap { margin-top: 16px; }
.pv-tl-head { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.pv-tl-head label { font-size: 12.5px; color: var(--ink-2); }
.pv-tl-scroll { overflow-x: auto; margin-top: 8px; }
/* One minute per unit at every width, so the hour labels stay upright instead of being squeezed by a stretched
   viewBox; the wrapper scrolls, and the script parks the strip on the current hour. */
.pv-tl { height: 40px; min-width: 1440px; border: 1px solid var(--line); border-radius: var(--r-sm);
  overflow: hidden; }
.pv-tl-svg { display: block; width: 1440px; height: 40px; }
.pv-tl-grid { stroke: var(--line); stroke-width: 1; }
.pv-tl-label { fill: var(--ink-3); font-size: 10px; }
.pv-tl-now { stroke: var(--ink); stroke-width: 2; }
.pv-seg { cursor: pointer; transition: opacity 180ms var(--ease); }
.pv-seg:hover { opacity: 0.8; }
.pv-seg:focus-visible { outline: 2px solid var(--ink); outline-offset: -2px; }
.pv-seg.scheduled { fill: var(--accent); }
.pv-seg.fallback { fill: var(--ink-3); }
.pv-seg.interrupt { fill: var(--err); }
.pv-seg.idle { fill: var(--line); }
.pv-sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; }
.pv-sim { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 14px; }
.pv-sim label { font-size: 12.5px; color: var(--ink-2); }
.pv-msg { width: 100%; margin: 0; font-size: 13.5px; color: var(--err); }
.pv-msg:empty { display: none; }
@media (max-width: 560px) {
  .pv-caps li { gap: 4px; }
}

/* ------------------------------------------------------------------------------------- scheduling surfaces */

.sc-choice { display: flex; flex-wrap: wrap; gap: 10px 18px; border: 0; padding: 0; margin: 0 0 14px; }
.sc-choice legend { font-size: 12.5px; color: var(--ink-2); padding: 0; margin-bottom: 6px; }
.sc-choice label { display: inline-flex; align-items: center; gap: 6px; font-size: 14px; color: var(--ink); }
.sc-zones, .sc-affects { list-style: none; margin: 0; padding: 0; }
.sc-zone { display: grid; grid-template-columns: minmax(120px, 1fr) auto minmax(160px, 2fr) auto;
  align-items: center; gap: 10px; padding: 12px 16px; border-top: 1px solid var(--line); }
.sc-zone:first-child { border-top: 0; }
.sc-zone-pick { font-size: 12.5px; color: var(--ink-2); }
.sc-zone [data-sc-zone-err] { grid-column: 1 / -1; margin: 0; color: var(--err); }
.sc-affects li { padding: 10px 16px; border-top: 1px solid var(--line); }
.sc-affects li:first-child { border-top: 0; }
.sc-affects a { color: var(--accent); }
[data-sc-rows] td.status small, [data-sc-rows] td.meta small { display: block; color: var(--ink-3);
  font-size: 12.5px; margin-top: 2px; }
[data-sc-notice].bad, [data-sc-formerr], [data-sc-zone-err] { color: var(--err); }

@media (max-width: 560px) {
  .sc-zone { grid-template-columns: 1fr auto; row-gap: 6px; }
  .sc-zone-name { grid-column: 1 / -1; }
  [data-sc-rows] td.name small { display: block; }
}

/* A name cell stacks its links, and at body size each one is an 18px tall target. Every panel list gets the same
   24px box so pointer targets clear WCAG 2.2 target size instead of relying on the gap between them. */
.panel td.name a {
  display: inline-block;
  min-height: 24px;
  padding-block: 3px;
}

/* ---- emergency messages. The one surface that leans on --err: a message on every screen is not a quiet act. */
.em-act { display: grid; gap: 12px; margin: 0 0 20px; }
.em-reach { margin: 0; font-size: 1.05rem; line-height: 1.45; color: var(--ink); max-width: 62ch; }
.em-act > .btn, .em-act > .jsonly { justify-self: start; }
.em-act > .jsonly > .btn { width: auto; }
.em-strip {
  display: grid; gap: 8px; justify-items: start;
  padding: 14px 16px; border-radius: var(--r-md);
  background: var(--err-pane); border: 1px solid var(--err); color: var(--ink);
}
.em-strip p { margin: 0; }
.em-strip .help { color: var(--ink-2); }
.em-ack { display: flex; flex-wrap: wrap; gap: 8px; align-items: end; }
.em-ack input[type="text"] { min-width: 18rem; }
.em-dialog {
  border: 1px solid var(--line-strong); border-radius: var(--r-lg); padding: 20px;
  max-width: 34rem; background: var(--surface); color: var(--ink); box-shadow: var(--shadow-2);
}
.em-dialog::backdrop { background: oklch(0.21 0.015 160 / 0.45); }
.em-dialog h2 { font-family: var(--font-title); margin: 0 0 8px; font-size: 1.15rem; }
.em-dialog p { margin: 0 0 12px; color: var(--ink-2); }
.em-preview { display: flex; gap: 8px; align-items: center; margin: 0 0 16px; }
.em-dialog .foot { display: flex; gap: 8px; justify-content: flex-end; }
.em-dialog[open] { animation: em-rise 180ms var(--ease) both; }
@keyframes em-rise { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .em-dialog[open] { animation: none; } }

@media (max-width: 560px) {
  .em-act { gap: 10px; }
  .em-act > .btn, .em-act > .jsonly, .em-act > .jsonly > .btn,
  .em-strip .btn, .em-dialog .foot .btn { width: 100%; }
  .em-strip { width: 100%; justify-items: stretch; }
  .em-ack { display: grid; }
  .em-ack input[type="text"] { min-width: 0; width: 100%; }
  .em-dialog .foot { display: grid; }
}

/* ---- Weather app. Three full-width looks to choose from, then the ZIP, units and duration. The mockups are
   static sample data; their type scales with the frame (container units) so one set of rules serves 390 and 1280. */
.wx-form { display: grid; gap: 24px; max-width: 72rem; }
.wx-form fieldset { border: 0; margin: 0; padding: 0; min-width: 0; }
.wx-form legend { font: 600 1.05rem var(--font-title); padding: 0; margin: 0 0 12px; color: var(--ink); }
.wx-looks { display: grid; gap: 16px; }
.wx-look { position: relative; }
.wx-radio { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; pointer-events: none; }
.wx-card {
  display: grid; gap: 0; cursor: pointer; overflow: hidden;
  background: var(--surface); border: 2px solid var(--line); border-radius: var(--r-lg);
  transition: border-color 160ms var(--ease), transform 160ms var(--ease);
}
.wx-card:hover { border-color: var(--line-strong); }
.wx-card:active { transform: scale(0.995); }
.wx-radio:checked + .wx-card { border-color: var(--accent); background: var(--accent-pane); }
.wx-radio:focus-visible + .wx-card { outline: 3px solid var(--accent); outline-offset: 3px; }
.wx-cap { display: grid; gap: 2px; padding: 12px 16px 14px; }
.wx-name { font: 700 1.1rem var(--font-title); color: var(--ink); }
.wx-name::after { content: ""; }
.wx-radio:checked + .wx-card .wx-name::after { content: " (selected)"; font: 600 0.8rem var(--font-ui); color: var(--ok); }
.wx-blurb { color: var(--ink-2); max-width: 64ch; line-height: 1.45; }

.wx-screen {
  container-type: inline-size; display: grid; position: relative; overflow: hidden;
  aspect-ratio: 16 / 7; min-height: 11rem; color: #fff; font-family: var(--font-ui);
}
.wx-screen > * { min-width: 0; }
.wx-big { font: 700 22cqw/0.9 var(--font-title); letter-spacing: -0.02em; }
.wx-city { font: 600 4.2cqw/1.1 var(--font-ui); }
.wx-cond { font: 500 3.2cqw/1.1 var(--font-ui); }
/* real SVG weather symbols (no CSS-shape stand-ins); color carries the condition via currentColor */
.wx-sun { width: 11cqw; height: 11cqw; display: block; color: oklch(0.86 0.17 88); }
.wx-sun-sm { width: 7cqw; height: 7cqw; }
.wx-sun svg, .wx-dot svg { display: block; width: 100%; height: 100%; }
.wx-dot { display: block; width: 5cqw; height: 5cqw; }
.wx-d-sun { color: oklch(0.86 0.17 88); }
.wx-d-cloud { color: oklch(0.84 0.02 240); }
.wx-d-rain { color: oklch(0.72 0.1 240); }

/* now: one giant number on a deep slate field */
.wx-now {
  background: oklch(0.27 0.05 245);
  grid-template-columns: auto 1fr; grid-template-rows: 1fr auto auto; align-items: center;
  column-gap: 4cqw; padding: 4cqw 6cqw;
}
.wx-now .wx-sun { grid-row: 1 / 3; align-self: center; }
.wx-now .wx-big { grid-column: 2; grid-row: 1 / 3; align-self: center; }
.wx-now .wx-city { grid-column: 1 / -1; }
.wx-now .wx-cond { grid-column: 1 / -1; color: oklch(0.9 0.02 245); }

/* week: current conditions on the left, five days across the bottom */
.wx-week {
  background: oklch(0.24 0.045 255);
  grid-template-rows: 1fr auto; padding: 4cqw 5cqw 3.5cqw; row-gap: 3cqw;
}
.wx-wk-now { display: grid; grid-template-columns: auto auto 1fr; align-items: center; column-gap: 3cqw; }
.wx-wk-now .wx-sun { grid-row: 1 / 3; }
.wx-wk-temp { font: 700 12cqw/0.9 var(--font-title); grid-row: 1 / 3; }
.wx-wk-now .wx-city { align-self: end; }
.wx-wk-now .wx-cond { align-self: start; color: oklch(0.9 0.02 255); }
.wx-strip { display: grid; grid-template-columns: repeat(5, 1fr); gap: 1.5cqw; }
.wx-day {
  display: grid; justify-items: center; gap: 0.8cqw; padding: 1.6cqw 0.8cqw;
  background: oklch(0.33 0.05 255); border-radius: 1.4cqw; font-size: 2.3cqw; line-height: 1.15;
}
.wx-day b { font-weight: 700; font-size: 2.7cqw; }
.wx-day > span { color: oklch(0.92 0.015 255); white-space: nowrap; }

/* sky: a flat deep-slate field with one restrained warm accent, not a dusk gradient. */
.wx-sky {
  background:
    radial-gradient(120% 90% at 82% 4%, oklch(0.86 0.17 88 / 0.16), transparent 58%),
    #142b38;
  grid-template-rows: 1fr auto; padding: 4cqw 5cqw 3.5cqw; row-gap: 3cqw;
}
.wx-sky-top { display: grid; grid-template-columns: auto 1fr; align-items: center; column-gap: 4cqw; }
.wx-sky-top .wx-big { grid-row: 1 / 3; font-size: 18cqw; }
.wx-sky-top .wx-city { align-self: end; }
.wx-sky-top .wx-cond { align-self: start; color: oklch(0.95 0.02 285); }
.wx-hours { display: grid; grid-template-columns: repeat(6, 1fr); gap: 1.2cqw; }
.wx-hr {
  display: grid; justify-items: center; gap: 0.6cqw; padding: 1.4cqw 0.6cqw; font-size: 2.6cqw; line-height: 1.15;
  background: oklch(0.2 0.06 280 / 0.55); border-radius: 1.4cqw;
}
.wx-hr b { font-weight: 600; font-size: 2.2cqw; color: oklch(0.95 0.015 285); white-space: nowrap; }

/* the form under the cards */
.wx-where { display: grid; gap: 16px; max-width: 28rem; }
.wx-where .ads-field input[type="text"], .wx-where .ads-field input[type="number"] { width: 100%; max-width: 14rem; }
.wx-units { display: grid; gap: 8px; }
.wx-units legend { font: 600 0.9rem var(--font-ui); margin: 0 0 6px; }
.wx-choice { display: flex; align-items: center; gap: 10px; min-height: 40px; cursor: pointer; }
.wx-choice input { width: 20px; height: 20px; accent-color: var(--accent); }
.wx-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.wx-actions .help { flex: 1 1 100%; margin: 0; max-width: 64ch; }
.wx-summary { display: grid; gap: 8px; margin: 0; max-width: 32rem; }
.wx-summary > div { display: flex; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--line); }
.wx-summary dt { flex: 0 0 6.5rem; color: var(--ink-2); }
.wx-summary dd { margin: 0; font-weight: 600; }
.wx-confirm .ads-field select { width: 100%; max-width: 28rem; }
.wx-empty { max-width: 56ch; color: var(--ink); }
@media (prefers-reduced-motion: reduce) {
  .wx-card { transition: none; }
  .wx-card:active { transform: none; }
}
@media (max-width: 560px) {
  .wx-actions .btn { width: 100%; }
  /* #44: the real output is 16/7 everywhere it plays, so the preview keeps that ratio on a phone too instead of
     switching to 4/3, which used to recompose the same look differently depending on the viewport. */
  .wx-screen { min-height: 9rem; }
  .wx-big { font-size: 26cqw; }
  .wx-city { font-size: 6cqw; }
  .wx-cond { font-size: 4.6cqw; }
  .wx-day { font-size: 3.2cqw; padding-inline: 0; }
  .wx-day b { font-size: 3.6cqw; }
  .wx-hr { font-size: 3.4cqw; }
  .wx-hr b { font-size: 2.8cqw; }
  .wx-wk-temp { font-size: 15cqw; }
  .wx-sky-top .wx-big { font-size: 22cqw; }
}

.sc-window { margin: 0 0 14px; }
.sc-days { margin-bottom: 10px; }
.sc-pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 0 16px; }
.sc-pair input[type="time"], .sc-pair input[type="date"] { width: 100%; }

/* wave3-screen-detail */
.sd { margin-top: var(--s-4); }
.sd-tabs { display: flex; gap: var(--s-1); border-bottom: 1px solid var(--line); margin-bottom: var(--s-4); overflow-x: auto; }
.sd-tabs [role="tab"] {
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 var(--s-4); font-weight: 600; font-size: var(--fs-16);
  color: var(--ink-2); text-decoration: none; border-bottom: 3px solid transparent; margin-bottom: -1px; white-space: nowrap;
}
.sd-tabs [role="tab"]:hover { color: var(--ink); background: var(--surface-2); }
.sd-tabs [role="tab"][aria-selected="true"] { color: var(--ink); border-bottom-color: var(--accent); }
.sd-tabs [role="tab"]:focus-visible, .sd-panel:focus-visible { outline: 3px solid var(--accent); outline-offset: -3px; }
.sd-panel[hidden] { display: none; }
.sd-panelname { font-size: var(--fs-21); margin: 0 0 var(--s-3); }
html[data-js] .sd-panelname { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
html:not([data-js]) .sd-tabs { display: none; }
html:not([data-js]) .sd-panel { margin-bottom: var(--s-6, 2rem); }
.sd-now { padding: var(--s-4); display: grid; gap: var(--s-2); }
.sd-now-state { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; }
.sd-now-text { margin: 0; font-size: var(--fs-18); font-weight: 600; }
.sd-badge {
  display: inline-flex; align-items: center; min-height: 32px; padding: 0 var(--s-3); border-radius: var(--r-pill);
  background: var(--warn-pane); color: var(--warn); border: 1px solid oklch(0.858 0.075 78); font-size: var(--fs-14); font-weight: 600; text-decoration: none;
}
.sd-badge:hover { border-color: var(--warn); }
.sd-danger { margin-top: var(--s-6, 2rem); border-top: 1px solid oklch(0.86 0.062 27); padding-top: var(--s-4); }
.sd .rowmenu > summary, .sd .btn.sm, .sd details > summary, .sd button, .sd .btn, .sd .ops .btn, .sd .ops button { min-height: 44px; }
.sd td a:not(.btn), .sd .panel-head a { display: inline-flex; align-items: center; min-height: 44px; }
@media (min-width: 761px) and (pointer: fine) { .sd td a:not(.btn), .sd .panel-head a { min-height: 32px; } }
.sd .rowmenu > summary { min-width: 44px; }
.sd details > summary { display: inline-flex; align-items: center; cursor: pointer; padding-inline: var(--s-2); }
.sd select, .sd input[type="date"] { min-height: 44px; max-width: 100%; color-scheme: light; }
.sd select { appearance: auto; }
.sd select:focus-visible, .sd input:focus-visible { outline: 3px solid var(--accent); outline-offset: 1px; }
.sd .ads-playlist-row { display: flex; gap: var(--s-3); flex-wrap: wrap; align-items: flex-end; margin-bottom: var(--s-3); }
.sd .ads-playlist-row > .ads-grow { flex: 1 1 14rem; }
@media (min-width: 761px) and (pointer: fine) {
  .sd .btn.sm, .sd .rowmenu > summary, .sd details > summary, .sd button, .sd .ops .btn, .sd .ops button, .sd select, .sd input[type="date"] { min-height: 36px; }
  .sd .rowmenu > summary { min-width: 36px; }
}
@media (prefers-reduced-motion: reduce) { .sd-tabs [role="tab"] { transition: none; } }

/* wave3-users-audit-claim */
.role-pick { border: 0; margin: 0; padding: 0; display: grid; gap: 8px; min-width: 0; }
.role-pick legend { font-weight: 600; padding: 0; margin-bottom: 6px; }
.role-opt { position: relative; }
.role-opt input { position: absolute; opacity: 0; inset: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.role-opt label { display: grid; gap: 2px; min-height: 44px; padding: 10px 12px 10px 40px; border: 1px solid var(--line-strong); border-radius: 8px; background: var(--surface); cursor: pointer; position: relative; }
.role-opt label::before { content: ""; position: absolute; left: 12px; top: 14px; width: 16px; height: 16px; border-radius: 50%; border: 2px solid var(--line-strong); background: var(--surface); }
.role-opt label small { color: var(--ink-2, inherit); opacity: 0.8; font-size: 0.85em; line-height: 1.35; }
.role-opt input:checked + label { border-color: var(--accent); background: var(--accent-pane); }
.role-opt input:checked + label::before { border-color: var(--accent); background: radial-gradient(circle, var(--accent) 0 4px, var(--surface) 5px); }
.role-opt input:focus-visible + label { outline: 3px solid var(--accent); outline-offset: 2px; }
.ads-filter { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; }
.ads-filter .ads-field { margin: 0; min-width: 180px; flex: 1 1 200px; }
.ads-filter .ads-filter-go { flex: 0 0 auto; min-width: 0; display: flex; gap: 8px; align-items: center; }
.ads-filter .ads-filter-go button, .ads-filter .ads-filter-go .btn { min-height: 44px; width: auto; padding: 0 22px; }
.audit-advanced { flex: 1 1 100%; }
.audit-advanced > summary { display: inline-flex; align-items: center; min-height: 44px; padding: 0 4px; cursor: pointer; font-weight: 600; }
.audit-advanced > summary:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.audit-advanced-grid { display: flex; flex-wrap: wrap; gap: 12px; padding: 6px 0 4px; }
.audit-advanced-grid .ads-field { flex: 1 1 200px; min-width: 180px; margin: 0; }
.claim-retry-head { font-size: 1rem; margin: 18px 0 4px; }
.claim-retry { display: grid; gap: 12px; margin-top: 8px; }
.claim-code-input { text-transform: uppercase; letter-spacing: 0.18em; font-size: 1.125rem; min-height: 44px; }
.claim-retry .btn, .auth-card .btn { min-height: 44px; }
.field-opt { font-weight: 400; opacity: 0.75; }
@media (max-width: 640px) { .ads-filter .ads-field { flex-basis: 100%; } }
.filters.ads-filter { display: flex; flex-wrap: wrap; }
.filters.ads-filter > .audit-advanced { flex: 0 0 100%; width: 100%; grid-column: 1 / -1; order: 3; }
.audit-advanced-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }

/* Live view. Black stage letterboxed to the layout canvas; the header stays slim so the stage gets the room. */
.pv-live { margin: 0 0 10px; display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: center; }
.lv-body { margin: 0; height: 100dvh; display: flex; flex-direction: column; background: #000; color: #f1f3f2; }
.lv-body .skip-link:focus { color: var(--ink); }
.lv-head { display: flex; flex-wrap: wrap; gap: 4px 20px; align-items: baseline; padding: 10px 16px;
  background: #101312; border-bottom: 1px solid #2a2f2d; }
.lv-title { display: flex; flex-wrap: wrap; gap: 0 12px; align-items: baseline; }
.lv-head h1 { margin: 0; font-size: 18px; color: #fff; }
.lv-kicker { margin: 0; font-size: 13px; color: #c3cbc8; }
.lv-meta { margin: 0 0 0 auto; display: flex; flex-wrap: wrap; gap: 4px 16px; font-size: 13px; color: #c3cbc8;
  font-variant-numeric: tabular-nums; }
.lv-why { margin: 0; flex-basis: 100%; font-size: 13px; line-height: 1.45; color: #d6dcda; max-width: 80ch; }
.lv-frame { flex: 1; min-height: 0; display: grid; place-items: center; container-type: size; background: #000; }
.lv-frame .lv-stage { width: min(100cqw, calc(100cqh * 16 / 9)); max-width: 100%; border: 0; border-radius: 0;
  background: #000; }
.lv-zone { background: var(--pv-player-bg, #101114); border: 0; }
.lv-media img, .lv-media video { width: 100%; height: 100%; object-fit: cover; display: block; }
.pv-zone[data-pv-fit="contain"] .lv-media img:not([data-fit]), .pv-zone[data-pv-fit="contain"] .lv-media video:not([data-fit]) { object-fit: contain; }
.pv-zone[data-pv-fit="fill"] .lv-media img:not([data-fit]), .pv-zone[data-pv-fit="fill"] .lv-media video:not([data-fit]) { object-fit: fill; }
.pv-zone[data-pv-fit="native"] .lv-media img:not([data-fit]), .pv-zone[data-pv-fit="native"] .lv-media video:not([data-fit]) { object-fit: none; object-position: center; }
.pv-zone .lv-media [data-fit="cover"] { object-fit: cover; }
.pv-zone .lv-media [data-fit="contain"] { object-fit: contain; }
.pv-zone .lv-media [data-fit="fill"] { object-fit: fill; }
.pv-zone .lv-media [data-fit="native"] { object-fit: none; }
.lv-urlbox { position: relative; width: 100%; height: 100%; }
.lv-urlbox iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; background: transparent; }
.lv-idle, .lv-empty { display: grid; place-items: center; height: 100%; padding: 12px; text-align: center;
  color: #c3cbc8; font-size: clamp(14px, 2.2cqw, 28px); }
.lv-empty p { margin: 4px 0; }
.lv-tile { display: grid; place-content: center; gap: 6px; width: 100%; height: 100%; padding: 12px;
  text-align: center; background: #1b2120; color: #e8ecea; }
.lv-tile b { font-size: clamp(14px, 2.6cqw, 32px); }
.lv-tile small { font-size: clamp(12px, 1.6cqw, 18px); color: #c3cbc8; }
.lv-weather { display: grid; place-content: center; gap: 4px; width: 100%; height: 100%; padding: 12px;
  text-align: center; color: #fff; background: linear-gradient(160deg, #123a56, #1e6b8c 60%, #3a8fb0); }
.lv-weather b { font-size: clamp(20px, 6cqw, 72px); }
.lv-weather span { font-size: clamp(13px, 2.4cqw, 30px); }
.lv-weather small { font-size: clamp(12px, 1.6cqw, 18px); color: #dcecf3; }
.lv-frame :focus-visible, .lv-head :focus-visible { outline: 3px solid #8fd0ff; outline-offset: 2px; }
@media (max-width: 480px) { .lv-head { padding: 8px 12px; } .lv-meta { margin-left: 0; } }

.addon-form { display: grid; gap: 12px; max-width: 34rem; }
.addon-form fieldset { border: 0; margin: 0; padding: 0; display: grid; gap: 8px; }
.addon-form legend { font-weight: 600; padding: 0; margin-bottom: 4px; }
.addon-form textarea { width: 100%; box-sizing: border-box; font: inherit; padding: 8px 10px; border: 1px solid var(--line, oklch(0.8 0.01 160)); border-radius: 8px; }
.addon-form .em-preview { display: flex; gap: 10px; align-items: center; min-height: 44px; }
.ads-oplist li { padding-inline: 16px; }

/* wave1-B */
.pop-range { max-width: none; flex: 1 1 100%; }
.pop-range-inputs { display: flex; gap: 10px; flex-wrap: wrap; }
.pop-range-inputs .ads-field { margin: 0; }
.pop-presets { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }

/* wave2-A */
/* A quiet button carried no border at all and read as plain text next to real buttons. */
.btn.quiet { border-color: var(--line-strong); }

/* The zone name input had no width rule of its own and clipped against the table's mobile stacked layout; give
   it the same sizing contract every other zone field already has. Selects get a floor width so Kind and Fit
   are never squeezed down to a sliver. */
#zones table.table td input[type="text"].ads-zone-name {
  width: 100%; min-width: 0; min-height: 44px; box-sizing: border-box; font-size: var(--fs-16);
  font-family: var(--font-ui); color: var(--ink); background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--r-sm); padding: 0 var(--s-2);
}
#zones table.table td select.ads-zone-select { min-width: 8rem; min-height: 44px; }
@media (max-width: 599px) {
  #zones table.table td input[type="text"].ads-zone-name,
  #zones table.table td select.ads-zone-select { flex: 1 1 auto; }
}

/* Plain-language help for the cryptic zone columns, under the table rather than crammed into a header. */
.zone-help { display: grid; gap: 2px; margin: 10px 0 0; padding: 10px 12px; border: 1px solid var(--line);
  border-radius: var(--r-md); background: var(--surface-2); font-size: var(--fs-12); color: var(--ink-2); }
.zone-help dt { font-weight: 700; color: var(--ink); }
.zone-help dd { margin: 0 0 6px; }

/* Practical split presets, shown only while a layout has no zones yet. */
.zone-presets { display: flex; gap: 8px; flex-wrap: wrap; margin: 0 0 10px; }

/* The interactive zone editor canvas: pointer drag, resize handles, and a focus ring for the keyboard path. */
.zone-canvas { position: relative; }
.zone-canvas svg { display: block; width: 100%; touch-action: none; }
.zone-box { cursor: move; }
.zone-box:focus-visible .zone-box-rect { outline: 3px solid var(--accent); outline-offset: 2px; }
.zone-box-rect { fill: oklch(0.65 0.14 200 / 18%); stroke: var(--accent); stroke-width: 2; }
.zone-box-name { font: 700 13px / 1 var(--font-ui); fill: var(--ink); }
.zone-box-kind { font: 500 11px / 1 var(--font-ui); fill: var(--ink-2); }
.zone-handle { fill: var(--accent); stroke: var(--surface); stroke-width: 1.5; cursor: nwse-resize; }
.zone-handle[data-zone-handle="ne"], .zone-handle[data-zone-handle="sw"] { cursor: nesw-resize; }
.zone-canvas-help { margin: 8px 0 0; font-size: var(--fs-12); color: var(--ink-2); }

/* wave3-B */
/* The MFA challenge screen: a centred ~400px card, the account identity, and the recovery path as a secondary
   disclosure rather than a second form, since one field already accepts either kind of code. */
.ads-mfa-challenge { max-width: 400px; margin: 0 auto; padding: 24px; text-align: center; }
.ads-mfa-brand { font-weight: 700; letter-spacing: 0.02em; color: var(--ink-2); font-size: var(--fs-14);
  text-transform: uppercase; margin-bottom: 8px; }
.ads-mfa-challenge h1 { margin: 0 0 8px; }
.ads-nowrap { white-space: nowrap; }
.ads-mfa-identity { color: var(--ink-2); margin: 0 0 20px; }
.ads-mfa-challenge .auth-card { text-align: left; }
.ads-mfa-challenge #code { text-align: center; font-size: 1.3rem; letter-spacing: 0.2em; font-family: var(--font-mono); }
.ads-mfa-recovery { margin-top: 16px; }
.ads-mfa-recovery summary { cursor: pointer; font-weight: 600; color: oklch(0.43 0.125 152); }
.ads-mfa-exit { margin-top: 16px; }

/* The terms-acceptance screen: the checkbox gates Continue until it is checked, enforced again server-side. */
.ads-terms-card { text-align: left; }
.ads-terms-check { display: flex; gap: 10px; align-items: flex-start; margin: 0 0 var(--s-4); cursor: pointer; }
.ads-terms-check input[type="checkbox"] { margin-top: 3px; width: auto; min-height: 0; }

/* A password field with its show/hide control inline, used wherever a password input appears. */
.ads-pw-wrap { position: relative; }
.ads-pw-wrap input { padding-right: 44px; }
.ads-pw-wrap .ads-pw-toggle { position: absolute; right: 4px; top: 50%; transform: translateY(-50%); }

/* A one-button form sitting inside the Security panel body, not inside a drawer or a table row. */
.ads-ops .ads-inline-form { margin: 0 0 var(--s-3); }
.ads-ops .ads-inline-form:last-child { margin-bottom: 0; }

/* wave4-A */
/* The upload queue row's own Cancel/Retry, shown only in the state that needs them (see app.js setRowState). */
.uplist .ups-actions { grid-column: 1 / -1; display: flex; gap: 8px; justify-content: flex-end; }
.uplist .res[data-state="done"] { color: var(--ok); }
/* Weather preview cards: a sample-data tag over each mockup, and the chosen-ZIP-and-units summary under the
   fieldset legend (the previews never move, so they must say so and never look live). */
.wx-sample {
  position: absolute; inset: auto 3.2cqw 3cqw auto; font: 600 2.1cqw var(--font-ui);
  color: oklch(0.95 0.01 255 / 0.78); letter-spacing: 0.02em; text-align: right;
}
.wx-choice-summary {
  margin: 0 0 14px; font-size: var(--fs-14); color: var(--ink-2); max-width: 64ch;
}
.wx-choice-summary b { color: var(--ink); font-weight: 600; }

/* Media Store app cards: a disabled-looking blocked state still carries one real next action. */
.app-card-blocked-action { margin-top: 10px; }

/* The assets upload panel: a single dropzone replaces the three competing controls, with accepted-types and
   per-type size limits stated up front instead of discovered on rejection. */
.ads-upload-zone {
  border: 2px dashed var(--line); border-radius: var(--r-md); padding: 28px 20px; text-align: center;
  display: grid; gap: 10px; justify-items: center; transition: border-color 0.15s ease-out, background 0.15s ease-out;
}
.ads-upload-zone.is-dragover { border-color: var(--accent); background: oklch(0.65 0.14 200 / 7%); }
.ads-upload-accept { font-size: var(--fs-14); color: var(--ink-2); max-width: 48ch; }
.ads-upload-legal { font-size: var(--fs-12); color: var(--ink-2); margin-top: 6px; max-width: 56ch; }
.ads-upload-quota { font-size: var(--fs-12); color: var(--ink-2); }

/* The upload queue: per-file row with state, progress, and the actions that match the state. */
.ads-upload-queue { list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 8px; }
.ads-upload-row {
  display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 4px 12px;
  padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--r-sm);
}
.ads-upload-name { font-weight: 600; font-size: var(--fs-14); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ads-upload-state { font-size: var(--fs-12); color: var(--ink-2); grid-column: 1; }
.ads-upload-state[data-state="failed"] { color: var(--err); }
.ads-upload-state[data-state="done"] { color: var(--ok); }
.ads-upload-actions { grid-column: 2; grid-row: 1 / 3; display: flex; gap: 6px; align-self: center; }
.ads-upload-bar {
  grid-column: 1 / -1; height: 6px; border-radius: 3px; background: var(--line); overflow: hidden;
}
.ads-upload-bar > span { display: block; height: 100%; background: var(--accent); transition: width 0.12s linear; }

/* wave5-B */
/* #27: the layout detail canvas and its inspector sit side by side at 1024px and up, instead of one narrow
   column with the canvas preview stacked above a settings panel the full width of the page. Below 1024px they
   stack, canvas first, inspector (Layout settings) after -- same order as before this change, so nothing moves
   for a phone reader. */
.layout-canvas-grid { display: grid; grid-template-columns: 1fr; gap: var(--s-5); align-items: start; }
.layout-canvas-main { display: grid; gap: var(--s-5); min-width: 0; }
.layout-canvas-inspector { display: grid; gap: var(--s-5); min-width: 0; }
@media (min-width: 1024px) {
  .layout-canvas-grid { grid-template-columns: minmax(0, 1fr) 340px; }
  .layout-canvas-inspector { position: sticky; top: var(--s-5); }
}

/* #43: the Media Store tiles now name the verified plan ("Included in Pro") instead of the vague "your
   package"; no new selector needed there, just the string change in PortalAppStorePages.cs. */

/* wave5-A */
/* #20: the ordered setup checklist in the new-rule drawer, shown only while a fresh tenant is missing a
   screen, media, a playlist or a layout. */
.sc-prereqs { border: 1px solid var(--line); background: var(--surface-2); border-radius: var(--r-md); padding: var(--sp-4); margin: 0 0 var(--sp-4); }
.sc-prereq-list { list-style: none; margin: var(--sp-2) 0 0; padding: 0; display: grid; gap: var(--sp-2); }
.sc-prereq-step { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) 0; border-bottom: 1px solid var(--line); }
.sc-prereq-step:last-child { border-bottom: 0; }
.sc-prereq-n {
  display: grid; place-items: center; flex: none; width: 24px; height: 24px; border-radius: var(--r-pill);
  background: var(--surface); border: 1px solid var(--line-strong); font: 600 var(--fs-12) var(--font-mono); color: var(--ink-2);
}
.sc-prereq-done .sc-prereq-n { background: var(--ok-pane); border-color: var(--accent-line); color: var(--ok); }
.sc-prereq-label { flex: 1 1 auto; font-size: var(--fs-14); }
.sc-prereq-done .sc-prereq-label { color: var(--ink-2); text-decoration: line-through; }

.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; }

/* #44: the weather look picker -- a compact vertical list of thumbnails beside one larger preview of the
   selected look, instead of three near-full-width previews stacked above the ZIP and duration fields. The
   larger preview is swapped with :has(), reading the same radios the thumbnails use, so it needs no script. */
.wx-picker { display: grid; grid-template-columns: 1fr; gap: var(--sp-4); align-items: start; }
.wx-option-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.wx-option-row { position: relative; }
.wx-option {
  display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2); cursor: pointer;
  border: 2px solid var(--line); border-radius: var(--r-md); background: var(--surface);
}
.wx-option:hover { border-color: var(--line-strong); }
.wx-radio:checked + .wx-option { border-color: var(--accent); background: var(--accent-pane); }
.wx-radio:focus-visible + .wx-option { outline: 3px solid var(--accent); outline-offset: 3px; }
.wx-radio:checked + .wx-option .wx-name::after { content: " (selected)"; font: 600 0.8rem var(--font-ui); color: var(--ok); }
.wx-option-thumb { flex: none; width: 160px; aspect-ratio: 16 / 7; border-radius: var(--r-sm); overflow: hidden; }
.wx-option-thumb .wx-screen { width: 100%; height: 100%; min-height: 0; aspect-ratio: auto; }
.wx-preview-large { display: none; }
.wx-preview-pane { display: none; }
.wx-preview-pane .wx-screen { border-radius: var(--r-lg); }
@media (min-width: 760px) {
  .wx-picker { grid-template-columns: 280px 1fr; }
  .wx-preview-large { display: block; }
}
/* Looks.length is fixed at three in PortalWeatherPages.cs; add a rule here if a fourth look is ever added. */
.wx-picker:has(input[name="style"][value="now"]:checked) .wx-preview-pane[data-wx-pane="now"] { display: block; }
.wx-picker:has(input[name="style"][value="week"]:checked) .wx-preview-pane[data-wx-pane="week"] { display: block; }
.wx-picker:has(input[name="style"][value="sky"]:checked) .wx-preview-pane[data-wx-pane="sky"] { display: block; }

/* #33: one upload area in the Library and Media Store dropzones, limits shown inline, legal text secondary. */
.ads-dropzone-limits { font-size: var(--fs-12); color: var(--ink-2); margin: 0 0 var(--sp-2); }
.ads-dropzone-legal { font-size: var(--fs-12); color: var(--ink-3); margin: var(--sp-2) 0 0; }

/* #44: the Media Store app preview chooser -- a compact vertical list of looks beside one larger preview. */
.ads-preview-picker { display: grid; grid-template-columns: 1fr; gap: var(--sp-4); align-items: start; }
.ads-preview-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.ads-preview-option {
  display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2); border: 1px solid var(--line);
  border-radius: var(--r-md); cursor: pointer; background: var(--surface);
}
.ads-preview-option:hover { border-color: var(--line-strong); }
.ads-preview-option.is-selected { border-color: var(--accent); background: var(--accent-pane); }
.ads-preview-thumb {
  flex: none; width: 160px; aspect-ratio: 16 / 7; border-radius: var(--r-sm); overflow: hidden; background: var(--surface-2);
  display: grid; place-items: center;
}
.ads-preview-thumb img, .ads-preview-thumb svg { width: 100%; height: 100%; object-fit: contain; }
.ads-preview-option-body { display: grid; gap: 2px; min-width: 0; }
.ads-preview-option-name { font-weight: 600; font-size: var(--fs-14); }
.ads-preview-option-desc { font-size: var(--fs-12); color: var(--ink-2); }
.ads-preview-large {
  border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; background: var(--surface-2);
  aspect-ratio: 16 / 7; display: grid; place-items: center;
}
.ads-preview-large img, .ads-preview-large svg { width: 100%; height: 100%; object-fit: contain; }
@media (min-width: 760px) {
  .ads-preview-picker { grid-template-columns: 220px 1fr; }
}

/* #42: cut dashboard/library card density -- one primary empty-state action, compact Media Store rows. */
.ads-approw {
  display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3); border-bottom: 1px solid var(--line);
}
.ads-approw:last-child { border-bottom: 0; }
.ads-approw-glyph {
  flex: none; width: 36px; height: 36px; border-radius: var(--r-sm); background: var(--surface-2);
  display: grid; place-items: center; color: var(--ink-2);
}
.ads-approw-body { flex: 1 1 auto; min-width: 0; display: grid; gap: 2px; }
.ads-approw-name { font-weight: 600; font-size: var(--fs-14); }
.ads-approw-desc { font-size: var(--fs-12); color: var(--ink-2); }

/* wave6-A */

/* #42: the compact Media Store rows (.ads-approw above) need a container with no extra card chrome, and a
   trailing link that never wraps to its own line on narrow viewports. */
.ads-approw-list { border-top: 1px solid var(--line); }
.ads-approw .btn { flex: none; }

/* #42: the header "actions" cluster (.page-head .actions) sits flush right next to the title and, once it
   wraps on a narrow screen, reads as an awkward half-width row rather than a deliberate stack. Below 560px it
   drops the right alignment and becomes a full-width column instead. */
@media (max-width: 560px) {
  .page-head .actions { margin-left: 0; width: 100%; flex-direction: column; align-items: stretch; }
  .page-head .actions > * { width: 100%; text-align: center; }
}

/* #33: the Choose files control and the inline size limits sit side by side until the dropzone narrows, then
   stack like every other control group on a phone. */
.ads-dropzone-row { display: flex; align-items: baseline; gap: var(--sp-3); flex-wrap: wrap; margin: 0 0 var(--sp-2); }
.ads-dropzone-row .ads-dropzone-limits { margin: 0; }
@media (max-width: 480px) {
  .ads-dropzone-row { flex-direction: column; align-items: stretch; gap: var(--sp-1); }
}

/* wave7a-A */

/* Scheduled player upgrades: the three-way choice (now / tonight / a date and time), stacked one per row so the
   time control that belongs to each radio sits right beside it instead of in a separate, easy-to-miss field. */
.sd-schedule-fields { display: grid; gap: var(--sp-2); }
.sd-radio { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-14); }
.sd-radio input[type="time"], .sd-radio input[type="datetime-local"] { margin-left: var(--sp-1); }
.sd-reschedule { margin-top: var(--sp-2); }
.sd-reschedule summary { cursor: pointer; color: var(--ink-2); font-size: var(--fs-12); }
.sd-reschedule .sd-schedule-fields { margin-top: var(--sp-2); }

/* wave7b-B */

/* Wave 7a's schedule choice (customer /upgrade/schedule panel, and the same markup reused in the operator
   Send/Reschedule fieldsets) crowded at phone width: the native time/datetime-local control sat on the same
   flex row as its radio and label text, and inside a table row the "Schedule" data-label pseudo-element ate
   a fixed 8rem before the form even started, squeezing the fieldset into a sliver. Give the choice rows real
   breathing room and let the control drop to its own line once the row can't hold it, instead of overflowing. */
.sd-schedule-fields { gap: var(--sp-3); }
.sd-radio { flex-wrap: wrap; row-gap: var(--sp-1); min-height: 32px; }
.sd-radio input[type="radio"] { flex: 0 0 auto; }
.sd-radio input[type="time"], .sd-radio input[type="datetime-local"] {
  min-height: 32px; flex: 1 1 auto; min-width: 9rem; max-width: 100%;
}

@media (max-width: 480px) {
  .sd-radio input[type="time"], .sd-radio input[type="datetime-local"] {
    flex-basis: 100%; margin-left: 0; margin-top: var(--sp-1);
  }
}

/* A table row whose "Schedule" cell holds this form needs its full card width at phone size: stack the
   data-label caption above the fieldset instead of squeezing the form beside it in the same flex row. */
@media (max-width: 599px) {
  table.table tbody td:has(> .sd-schedule-form) {
    flex-direction: column; align-items: stretch; gap: var(--s-1);
  }
  table.table tbody td:has(> .sd-schedule-form)::before { flex: 0 0 auto; }
  table.table tbody td:has(> .sd-schedule-form) .sd-schedule-form { width: 100%; }
}

/* Visible focus on the radio itself, not just the browser default, which native time/datetime-local controls
   already draw via the generic input:focus-visible rule near the top of this file. */
.sd-radio input[type="radio"]:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

/* wave7c-B */

/* #43 remainder: the rail's sign-out row becomes a real account menu (Account, Help, Sign out) built on native
   <details>/<summary> so it works with scripting off, is reachable and operable by keyboard alone, and needs no
   JS to open or close. Structure mirrors .scope above it: a summary row carries the avatar/name/caret, the menu
   itself is a plain list of links and one form. */
.rail .me { margin-top: auto; border-top: 1px solid oklch(1 0 0 / 0.14); position: relative; }
.rail .me > summary {
  display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 10px 8px; list-style: none;
  cursor: pointer; font-size: 13px; border-radius: var(--radius-6);
}
.rail .me > summary::-webkit-details-marker { display: none; }
.rail .me > summary:hover { background: oklch(1 0 0 / 0.1); }
.rail .me > summary:focus-visible { outline: 2px solid var(--rail-ink); outline-offset: 2px; }
.rail .me .av { width: 30px; height: 30px; border-radius: 50%; background: oklch(0.85 0.05 152); color: oklch(0.2 0.03 152); font-weight: 700; display: grid; place-items: center; font-size: 12px; flex: none; }
.rail .me .who { min-width: 0; flex: 1; }
.rail .me .who b { display: block; font-weight: 600; overflow: hidden; text-overflow: ellipsis; }
.rail .me .who span { display: block; color: var(--rail-ink-2); font-size: 11.5px; }
.rail .me .scope-caret { flex: none; color: var(--rail-ink-2); transition: transform 0.15s var(--ease); }
.rail .me[open] .scope-caret { transform: rotate(180deg); }
.me-menu {
  list-style: none; margin: 2px var(--sp-1) var(--sp-3); padding: var(--sp-1); background: var(--rail-2);
  border: 1px solid oklch(1 0 0 / 0.14); border-radius: var(--radius-10);
}
.me-menu li { margin: 0; }
.me-menu li form { margin: 0; }
.me-menu a, .me-menu button {
  display: flex; align-items: center; width: 100%; min-height: 44px; padding: 0 var(--sp-3); border-radius: var(--radius-6);
  color: var(--rail-ink); font: 600 13px var(--font-ui); text-decoration: none; text-align: left; background: none;
  border: none; cursor: pointer;
}
.me-menu a:hover, .me-menu button:hover { background: oklch(1 0 0 / 0.1); }
.me-menu a:focus-visible, .me-menu button:focus-visible { outline: 2px solid var(--rail-ink); outline-offset: -2px; }
.me-menu a[aria-current] { font-weight: 700; background: oklch(1 0 0 / 0.14); }

/* The verified plan, named once beside the breadcrumb instead of repeated as "Included" on every card. */
.topbar-plan {
  flex: none; margin-left: auto; padding: 3px 10px; border-radius: var(--radius-full, 999px);
  background: var(--surface-2); border: 1px solid var(--line); color: var(--ink-2); font-size: 12px; font-weight: 600;
  white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) { .rail .me .scope-caret { transition: none; } }

@media (max-width: 1100px) {
  .rail .me .who { display: none; }
  .rail .me { flex-direction: column; }
  .rail .me[open] .me-menu { position: fixed; left: calc(var(--rail-w) + var(--sp-2)); bottom: var(--sp-2); width: 200px; z-index: var(--z-drawer); box-shadow: var(--shadow-2); margin: 0; }
}

@media (max-width: 760px) {
  .rail:target .me .who, .rail[data-open] .me .who { display: block; }
  .rail:target .me[open] .me-menu, .rail[data-open] .me[open] .me-menu { position: static; width: auto; box-shadow: none; margin: 2px var(--sp-1) var(--sp-3); }
  .topbar-plan { font-size: 11px; padding: 2px 8px; }
}

/* wave7c-A */
.lv-youtube { width: 100%; height: 100%; border: 0; background: #000; }
.ads-note { font-size: 12px; color: var(--ink-2); }

/* ---- a playlist row the server refused (web safety filter, allow-list, typo). Text says why; the tint and full
   outline only point at the row, so the reason never rides on color alone. */
[data-pl-item][data-refused] { background: var(--err-pane); outline: 1px solid var(--err); outline-offset: -1px; }
.pl-items > li > [data-pl-rowerr] { grid-column: 1 / -1; margin: 0; color: var(--err); font-weight: 600; max-width: 75ch; }
[data-pl-rowerr]:focus { outline: 2px solid var(--err); outline-offset: 2px; }
.ads-asset-tile .thumb img, .ads-asset-tile .thumb video { cursor: zoom-in; }

.ads-orgpick-dead { display: flex; align-items: center; gap: var(--s-2); width: 100%; min-height: 44px; cursor: not-allowed; border-color: oklch(0.45 0.17 27); color: oklch(0.42 0.17 27); background: oklch(0.97 0.02 27); }
.ads-orgpick-dead s { text-decoration-thickness: 2px; text-decoration-color: oklch(0.45 0.17 27); }
.ads-orgpick-dead strong { margin-left: auto; font-weight: 700; }
.ads-orgpick-suspended { margin-bottom: var(--s-2); }

.pager { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); flex-wrap: wrap; padding: var(--s-3) 16px; border-top: 1px solid var(--line); }
.pager .sub { color: var(--ink-2, inherit); }

.audit-kv { display: grid; grid-template-columns: max-content 1fr; gap: 2px var(--s-3); margin: 6px 0 0; font-size: 0.875rem; }
.audit-kv dt { color: var(--ink-2, inherit); }
.audit-kv dd { margin: 0; overflow-wrap: anywhere; }
.pl-just-added { outline: 2px solid var(--accent, currentColor); outline-offset: -2px; }
