/* allmiibo-sync — NES-inspired skin, "Console Shell" palette.
   Dark only, by design: square corners, 2px borders, hard offset shadows,
   buttons that press in. Titles and chrome use Press Start 2P (vendored,
   SIL OFL); body and data stay on system stacks for legibility. */

@font-face {
  font-family: 'Press Start 2P';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/press-start-2p/PressStart2P-Regular.woff2') format('woff2');
}

/* Three switchable themes (Settings, persisted as allmiibo:theme on <html>
   data-theme). Default is "c" — Console Shell. */
:root {
  color-scheme: dark;
  --bg: #2b2b2a;      /* console shell */
  --panel: #3a3a39;
  --panel2: #4a4947;
  --border: #72706f;
  --fg: #c9c7c3;
  --muted: #9a938a;
  --accent: #9a2a26;  /* stripe red */
  --accent2: #6f6459; /* warm grey-brown for links */
  --ok: #3e8e3e;      /* green tuned to sit with the brick red */
  --warn: #c9a24a;
  --err: #c23a34;
  --shadow: #1a1a19;
  --pixel: 'Press Start 2P', monospace;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
:root[data-theme="a"] { /* CRT Indigo */
  --bg: #0f0f18; --panel: #1b1b2b; --panel2: #23233a; --border: #4a4a6a;
  --fg: #f4f4f4; --muted: #9a9ab5; --accent: #e23b2e; --accent2: #5a7be5;
  --ok: #6abe30; --warn: #f2c531; --err: #ff5c4d; --shadow: #000000;
}
:root[data-theme="b"] { /* Console Black */
  --bg: #0a0a0a; --panel: #161616; --panel2: #202020; --border: #3a3a3a;
  --fg: #eaeaea; --muted: #8a8a8a; --accent: #e5473b; --accent2: #4f8cff;
  --ok: #7ac943; --warn: #ffcf40; --err: #ff5347; --shadow: #000000;
}

/* Advanced mode: anything tagged .advanced-only exists only when the header
   toggle put data-mode="advanced" on <html>. Hidden by default. */
:root:not([data-mode="advanced"]) .advanced-only { display: none !important; }

* { box-sizing: border-box; }
/* The hidden attribute must always win, even over author display rules. */
[hidden] { display: none !important; }
body {
  margin: 0;
  padding: 1.5rem 1.25rem 3rem;
  background: var(--bg);
  color: var(--fg);
  font: 15px/1.5 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
}
main { max-width: 60rem; margin: 0 auto; }

h1 { font-family: var(--pixel); font-size: 1rem; line-height: 1.6; margin: 0 0 .5rem; color: #fff; }
p.sub { color: var(--muted); margin: 0 0 1.5rem; }
h2 { font-family: var(--pixel); font-size: .6rem; letter-spacing: .04em; color: var(--muted); margin: 0 0 .6rem; }
section { margin-bottom: 1.5rem; }
main nav { margin-bottom: 0; }
main nav a { font-family: var(--pixel); font-size: .55rem; color: var(--muted); text-decoration: none;
  display: inline-flex; align-items: center; gap: .4rem; }
main nav a .ico { margin: -.4rem 0; transform: translateY(-2px); } /* overhang + PS2P optical centre */
main nav a:hover { color: var(--fg); }
code { font-family: var(--mono); }

:focus-visible { outline: 3px solid var(--warn); outline-offset: 2px; }

.row { display: flex; flex-wrap: wrap; gap: .7rem; align-items: center; margin-bottom: 1rem; }

button {
  font-family: var(--pixel); font-size: .6rem; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  min-height: 2.4rem; padding: .5em 1em;
  border: 2px solid var(--border); border-radius: 0;
  background: var(--panel2); color: var(--fg);
  box-shadow: 3px 3px 0 var(--shadow);
  cursor: pointer; transition: border-color .1s;
}
button:hover:not(:disabled) { border-color: var(--accent); }
button:active:not(:disabled) { transform: translate(3px, 3px); box-shadow: none; }
button:disabled { opacity: .45; cursor: not-allowed; }
button.primary { background: var(--accent); border-color: var(--shadow); color: #fff; }
button.danger { background: transparent; border-color: var(--err); color: var(--err); }
button .ico { width: 1.1rem; height: 1.1rem; }

/* 8-bit icons (Pixelarticons, MIT + a hand-drawn bluetooth): pixel-crisp,
   sized in rem so they read larger than the small pixel-font labels. */
.ico { width: 1.35rem; height: 1.35rem; flex: none; display: inline-grid; place-items: center; }
.ico svg { width: 100%; height: 100%; display: block; image-rendering: pixelated; shape-rendering: crispEdges; }

label { color: var(--muted); display: inline-flex; align-items: center; gap: .35rem; }
input[type=number], input[type=text], input[type=search], select {
  font: inherit; padding: .35rem .5rem;
  border: 2px solid var(--border); border-radius: 0;
  background: var(--bg); color: var(--fg);
}
input[type=number] { width: 4.5rem; }
input[type=checkbox], input[type=radio] { accent-color: var(--accent); }

.status {
  padding: .55rem .75rem; border: 2px solid var(--border); border-radius: 0;
  background: var(--panel); margin-bottom: 1.25rem;
  font-variant-numeric: tabular-nums;
}
.status.ok { color: var(--ok); border-color: currentColor; }
.status.warn { color: var(--warn); border-color: currentColor; }
.status.err { color: var(--err); border-color: currentColor; }
/* An empty status chip (e.g. folder name before one is chosen) renders as a
   stray little box — hide it until it has content. */
.status:empty { display: none; }

pre, .logbox {
  margin: 0; padding: .75rem; border: 2px solid var(--border); border-radius: 0;
  background: var(--panel); overflow-x: auto;
  font: 12.5px/1.55 var(--mono);
  white-space: pre-wrap;
}
.logbox { max-height: 20rem; overflow-y: auto; white-space: pre; }
.line.ok { color: var(--ok); }
.line.warn { color: var(--warn); }
.line.err { color: var(--err); }
.line.info { color: var(--muted); }

.note {
  border-left: 5px solid var(--accent); border-radius: 0;
  padding: .6rem .8rem; background: var(--panel);
  color: var(--muted); font-size: .9rem;
}
.note.caution { border-left-color: var(--warn); }

progress { width: 100%; height: .6rem; margin-bottom: 1rem;
  accent-color: var(--accent); }

img { image-rendering: pixelated; }

/* ---- shared header (injected by js/header.js) --------------------------- */
.appHeader { max-width: 60rem; margin: 0 auto 1.5rem; }
.appBar {
  display: flex; align-items: center; gap: 1.1rem; flex-wrap: wrap;
  padding: .65rem .9rem;
  border: 2px solid var(--border); background: var(--panel);
  box-shadow: 4px 4px 0 var(--shadow);
}
.brand { display: inline-flex; align-items: center; gap: .6rem; color: inherit; text-decoration: none; }
.brand .wm { font-family: var(--pixel); font-size: .65rem; color: #fff; white-space: nowrap; }
.brand .wm .sfx { color: var(--err); } /* err = the brightest red in every theme */
.brand svg { display: block; shape-rendering: crispEdges; }
.appNav { display: flex; gap: 1rem; flex: 1; flex-wrap: wrap; align-items: center;
  margin-left: 1.4rem; }
.appNav a {
  font-family: var(--pixel); font-size: .55rem; color: var(--muted);
  text-decoration: none; display: inline-flex; align-items: center; gap: .4rem;
  padding: .35rem 0;
}
/* The icon is much taller than the pixel label; negative margins let it
   overhang so the link box (and the underline) hug the TEXT, not the icon. */
.appNav a .ico { margin: -.4rem 0; }
.appNav a:hover { color: var(--fg); }
/* The active underline is a box-shadow on the label span, not a border:
   zero layout impact, and it fits the TEXT — not the icon, not the grid cell. */
.appNav a.active { color: #fff; }
.appNav a.active .lbl { box-shadow: 0 3px 0 var(--accent); }

/* Narrow screens: free-wrapping turns the bar into a jumble, so lay it out as
   two deliberate rows — brand + settings on top, nav on its own line. */
@media (max-width: 640px) {
  /* Bottom edge = .2rem link padding + 3px underline + .15rem bar padding
     ≈ the .55rem top padding, so the frame reads symmetric. */
  .appBar { display: grid; grid-template-columns: 1fr auto; row-gap: .55rem;
            padding: .55rem .8rem .35rem; }
  .brand { grid-row: 1; grid-column: 1; }
  .settingsWrap { grid-row: 1; grid-column: 2; justify-self: end; }
  /* Nav as a tidy two-column menu (NES style) rather than a ragged wrap —
     matters once Advanced adds PROBE and WRITE TEST. */
  .appNav { grid-row: 2; grid-column: 1 / -1; border-top: 2px solid var(--border);
            padding-top: .55rem; display: grid; grid-template-columns: 1fr 1fr;
            gap: .45rem .8rem; margin-left: 0; }
  .appNav a { padding: .2rem 0; }
}
.advToggle {
  display: inline-flex; align-items: center; gap: .5rem;
  font-family: var(--pixel); font-size: .5rem; color: var(--muted);
  cursor: pointer; user-select: none; background: none; border: none;
  box-shadow: none; min-height: 0; padding: .2rem 0;
}
.advToggle:active { transform: none; }
.advToggle .sw { width: 2.4rem; height: 1.2rem; background: var(--panel2);
  border: 2px solid var(--border); position: relative; flex: none; }
.advToggle .knob { position: absolute; top: 1px; left: 1px; width: .85rem; height: .85rem;
  background: var(--muted); transition: left .1s, background .1s; }
:root[data-mode="advanced"] .advToggle:not(.hideToggle) { color: var(--fg); }
:root[data-mode="advanced"] .advToggle:not(.hideToggle) .sw { border-color: var(--accent); }
:root[data-mode="advanced"] .advToggle:not(.hideToggle) .knob { left: calc(100% - .85rem - 1px); background: var(--accent); }
.hideToggle[aria-pressed="true"] { color: var(--fg); }
.hideToggle[aria-pressed="true"] .sw { border-color: var(--accent); }
.hideToggle[aria-pressed="true"] .knob { left: calc(100% - .85rem - 1px); background: var(--accent); }

/* Settings panel (gear in the header). A plain popover under the bar. */
.settingsWrap { position: relative; display: flex; align-items: center; }
.settingsPanel {
  position: absolute; right: 0; top: calc(100% + .6rem); z-index: 10;
  width: min(21rem, 88vw);
  background: var(--panel); border: 2px solid var(--border);
  box-shadow: 5px 5px 0 var(--shadow); padding: .9rem 1rem 1.1rem;
}
.settingsPanel[hidden] { display: none; }
.settingsPanel h3 { font-family: var(--pixel); font-size: .55rem; color: var(--muted);
  margin: 0 0 .6rem; }
.settingsPanel h3 + .swRow { margin-bottom: 1rem; }
.swRow { display: flex; flex-wrap: wrap; gap: .45rem; }
.themeSw, .pirateSw {
  min-height: 0; padding: 0; border: 2px solid var(--border);
  box-shadow: 2px 2px 0 var(--shadow); background: none; cursor: pointer;
}
.themeSw { width: 3.4rem; height: 2.2rem; display: grid; place-items: center;
  font-family: var(--pixel); font-size: .5rem; }
.pirateSw { width: 2.9rem; height: 3.4rem; display: grid; place-items: center; }
.themeSw.selected, .pirateSw.selected { border-color: var(--warn); }
.settingsPanel .sDiv { border: none; border-top: 2px solid var(--border); margin: .9rem 0; }
.settingsPanel .advRow { align-items: center; gap: .7rem; margin-bottom: 1rem; }
.settingsPanel .advToggle .ico { width: 1.1rem; height: 1.1rem; }
.settingsPanel .advHint { font-size: .72rem; color: var(--muted); flex: 1; min-width: 9rem; }
.settingsPanel .dbgLink { display: flex; align-items: center; gap: .45rem;
  font-family: var(--pixel); font-size: .5rem;
  color: var(--muted); text-decoration: none; }
.settingsPanel .dbgLink:hover { color: var(--fg); }
.settingsPanel .dbgLink .ico { width: 1.1rem; height: 1.1rem; }
.themeSw:active, .pirateSw:active { transform: translate(2px, 2px); box-shadow: none; }

/* ---- shared footer ------------------------------------------------------ */
.siteFooter { border-top: 2px solid var(--border); margin-top: 2.5rem; }
.fInner { max-width: 60rem; margin: 0 auto; padding: 1.25rem 1.25rem 1.5rem;
          display: flex; flex-direction: column; gap: .75rem;
          font-size: .85rem; color: var(--muted); }
/* Scoped to the footer deliberately. This was an unqualified `.fRow` and the
   admin, reasonably, used the same name for its form rows — so every admin
   field inherited a horizontal flex row above 560px and put its label, input
   and error side by side. A single-class name in a stylesheet six pages share
   is a name nobody owns. */
.siteFooter .fRow { display: flex; flex-direction: column; align-items: center;
        justify-content: space-between; gap: .75rem; }
@media (min-width: 560px) { .siteFooter .fRow { flex-direction: row; } }
.siteFooter a { color: inherit; text-decoration: none; transition: color .15s; }
.siteFooter a:hover { color: var(--fg); }
.fAuthor { display: inline-flex; align-items: center; gap: .6rem; }
.fAuthor strong { font-weight: 600; color: var(--fg); }
.fGithub { display: inline-flex; align-items: center; gap: .4rem; }
.fMark { width: 1.25rem; height: 1.05rem; }
.fIcon { width: 1rem; height: 1rem; }
.fAttrib { margin: 0; font-size: .72rem; text-align: center; }
@media (min-width: 560px) { .fAttrib { text-align: left; } }
.fAttrib a { text-decoration: underline; }

/* ---- components (UX overhaul) ------------------------------------------- */
/* Interaction language: steps() easings, movement in 3px multiples, no blur. */

/* Sliding segmented toggle (view switch etc.) */
.segCtl { display: inline-grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  position: relative; border: 2px solid var(--border); background: var(--bg);
  box-shadow: 3px 3px 0 var(--shadow); --seg: 0; --n: 2; }
.segCtl input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.segCtl label { font-family: var(--pixel); font-size: .55rem; padding: .5rem .8rem;
  z-index: 1; color: var(--muted); cursor: pointer; display: inline-flex;
  align-items: center; justify-content: center; gap: .4rem; white-space: nowrap; }
.segCtl label .ico { width: 1.1rem; height: 1.1rem; margin: -.4rem 0; }
.segCtl:has(input:checked) label { color: var(--muted); }
.segCtl label:has(input:checked), .segCtl input:checked + label { color: var(--fg); }
.segCtl .thumb { position: absolute; top: 0; left: 0; height: 100%;
  width: calc(100% / var(--n)); background: var(--panel2);
  border-right: 2px solid var(--border); box-sizing: border-box;
  transform: translateX(calc(var(--seg) * 100%));
  transition: transform .16s steps(4, end); }
.segCtl:has(input:focus-visible) { outline: 3px solid var(--warn); outline-offset: 2px; }

/* Filter pills with counts */
.pillRow { display: flex; flex-wrap: wrap; gap: .45rem; }
.pill { font-family: var(--pixel); font-size: .5rem; padding: .45rem .6rem;
  border: 2px solid var(--border); background: var(--panel); color: var(--muted);
  box-shadow: 2px 2px 0 var(--shadow); cursor: pointer;
  display: inline-flex; align-items: center; gap: .45rem; }
.pill input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.pill:has(input:checked) { border-color: var(--accent); color: var(--fg); background: var(--panel2); }
.pill:hover { border-color: var(--accent); }
.pill:active { transform: translate(2px, 2px); box-shadow: none; }
.pill .n { font: 11px/1 var(--mono); color: var(--muted); }
.pill.zero { opacity: .5; }
.pill:has(input:focus-visible) { outline: 3px solid var(--warn); outline-offset: 2px; }

/* Search box */
.searchBox { display: inline-flex; align-items: center; gap: .4rem;
  border: 2px solid var(--border); background: var(--bg); padding: 0 .4rem; }
.searchBox .ico { color: var(--muted); }
.searchBox input { border: none; outline: none; background: none; color: var(--fg);
  font: inherit; padding: .4rem .1rem; min-width: 11rem; }
.searchBox input::-webkit-search-cancel-button { -webkit-appearance: none; }
.searchBox:focus-within { outline: 3px solid var(--warn); outline-offset: 2px; }
.searchBox .clear { min-height: 0; padding: .15rem; border: none; box-shadow: none;
  background: none; color: var(--muted); }
.searchBox .clear:hover { color: var(--fg); }
.searchBox .clear .ico { width: 1rem; height: 1rem; }

/* The panel recipe: a 2px border, the panel fill and a hard offset shadow.
   Hand-rolled in eight places before this existed. `raised` is the 4px rung of
   the shadow ladder, for something that sits above the page rather than in it. */
.panel { border: 2px solid var(--border); background: var(--panel);
  box-shadow: 3px 3px 0 var(--shadow); }
.panel.raised { box-shadow: 4px 4px 0 var(--shadow); }

/* A small pixel-font caption over a value. Chrome, so pixel font and CAPS in
   the markup, per the convention. */
.cap { font-family: var(--pixel); font-size: .45rem; color: var(--muted);
  letter-spacing: .05em; }

/* Stat tiles */
.statRow { display: grid; grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: .7rem; margin-bottom: 1.25rem; }
.statTile { border: 2px solid var(--border); background: var(--panel);
  box-shadow: 3px 3px 0 var(--shadow); padding: .6rem .8rem;
  display: grid; gap: .3rem; align-content: start; color: var(--fg); }
.statTile b { font-family: var(--pixel); font-size: .95rem;
  font-variant-numeric: tabular-nums; font-weight: 400; display: flex;
  align-items: center; gap: .45rem; }
.statTile b .of { color: var(--muted); font-size: .6rem; }
.statTile.ok b { color: var(--ok); }
.statTile.dev b { color: var(--accent2); }
.statTile.warn b { color: var(--warn); }
.statTile.err b { color: var(--err); }
button.statTile { cursor: pointer; text-align: left; min-height: 0; }
button.statTile:hover { border-color: var(--accent); }
.statTile.pending b { color: var(--muted); }

/* Capacity bar — 20-cell NES energy meter */
.capBar { display: grid; gap: .35rem; }
.capBar .track { height: 14px; border: 2px solid var(--border); background: var(--bg);
  position: relative; overflow: hidden; }
.capBar .fill { position: absolute; inset: 0 auto 0 0; background: var(--ok);
  transition: width .3s steps(6, end); }
.capBar.warn .fill { background: var(--warn); }
.capBar.err .fill { background: var(--err); }
.capBar .ghost { position: absolute; top: 0; bottom: 0; }
.capBar .ghost.up { background: repeating-linear-gradient(45deg, var(--warn) 0 3px, transparent 3px 6px); }
.capBar .ghost.free { background: repeating-linear-gradient(45deg, var(--ok) 0 3px, transparent 3px 6px); opacity: .5; }
.capBar.overflow .ghost.up { background: repeating-linear-gradient(45deg, var(--err) 0 3px, transparent 3px 6px); }
.capBar .track::after { content: ''; position: absolute; inset: 0;
  background: repeating-linear-gradient(90deg, transparent 0 calc(5% - 2px), var(--bg) calc(5% - 2px) 5%); }
.capBar .capLbl { display: flex; justify-content: space-between; gap: 1rem;
  font-size: .78rem; color: var(--muted); }
.capBar .capLbl .mono { font-family: var(--mono); }

/* Plan summary cards */
.planCard { border: 2px solid var(--border); background: var(--panel);
  box-shadow: 3px 3px 0 var(--shadow); padding: .55rem .7rem; cursor: pointer;
  display: grid; gap: .25rem; text-align: left; min-height: 0; color: var(--fg); }
.planCard b { font-family: var(--pixel); font-size: .8rem; font-weight: 400;
  display: flex; align-items: center; gap: .4rem; }
.planCard .cap { font-family: var(--pixel); font-size: .42rem; color: var(--muted); }
.planCard .sub { font: 11px/1 var(--mono); color: var(--muted); }
.planCard.err b { color: var(--err); }
.planCard.warn b { color: var(--warn); }
.planCard.muted b { color: var(--muted); }
.planCard:hover { border-color: var(--accent); }

/* Drawers (lazy file lists) */
.drawer { border: 2px solid var(--border); background: var(--panel); margin-bottom: .5rem; }
.drawer > summary { cursor: pointer; padding: .5rem .75rem; font-family: var(--pixel);
  font-size: .55rem; display: flex; align-items: center; gap: .5rem; list-style: none; }
.drawer > summary::-webkit-details-marker { display: none; }
.drawer > summary .chev { display: inline-flex; }
.drawer[open] > summary .chev { transform: rotate(90deg); }
.drawer > summary .n { font: 11px/1 var(--mono); color: var(--muted); margin-left: auto; }
.drawer .body { padding: 0 .75rem .6rem; }
/* A line of explanation above a drawer's list. Scoped, because "hint" on its
   own is the kind of name two pages would each claim. */
.drawer .hint { font-size: .85rem; color: var(--muted); margin: .2rem 0 .6rem; }
.drawer .fileList li { align-items: center; min-height: 2rem; }
.drawer .fileList li .acts { display: flex; gap: .4rem; flex: none; }
.drawer .fileList li button { min-height: 1.7rem; padding: .2rem .5rem; font-size: .42rem;
  box-shadow: none; }
.drawer .fileList li button:active { transform: none; }
.fileList { margin: 0; padding: 0; list-style: none; max-height: 18rem; overflow: auto;
  contain: content; font: 12.5px/1.7 var(--mono); }
.fileList li { display: flex; justify-content: space-between; gap: 1rem; padding: 0 .4rem; }
.fileList li:nth-child(odd) { background: var(--panel2); }
.fileList .sz { color: var(--muted); flex: none; }

/* Dialog */
dialog.nesDialog { border: 2px solid var(--border); background: var(--panel);
  color: var(--fg); box-shadow: 6px 6px 0 var(--shadow); padding: 1rem 1.1rem;
  max-width: 26rem; }
dialog.nesDialog::backdrop { background: rgb(0 0 0 / .6); }
dialog.nesDialog h2 { font-size: .65rem; color: var(--fg); display: flex;
  align-items: center; gap: .5rem; margin-bottom: .7rem; }
dialog.nesDialog .dIco { display: inline-flex; color: var(--warn); }
dialog.nesDialog .dIco .ico { width: 1.4rem; height: 1.4rem; }
dialog.nesDialog .dBody { font-size: .9rem; margin-bottom: .6rem; }
dialog.nesDialog .dDetail { font: 12.5px/1.7 var(--mono); color: var(--muted);
  margin-bottom: .8rem; }
dialog.nesDialog .dDetail[hidden] { display: none; }
dialog.nesDialog .dRow { display: flex; justify-content: flex-end; gap: .7rem; }

/* One question, several answers. Each choice is full width and carries its own
   consequence, so the difference between them is readable without a legend. */
dialog.nesDialog .dChoices { display: flex; flex-direction: column;
  gap: .5rem; margin-bottom: .9rem; }
dialog.nesDialog .dChoices[hidden] { display: none; }
dialog.nesDialog .dChoice { display: flex; flex-direction: column;
  align-items: flex-start; gap: .25rem; text-align: left;
  padding: .6rem .8rem; min-height: 0; }
dialog.nesDialog .dChoice .cLabel { font-family: var(--pixel); font-size: .5rem; }
dialog.nesDialog .dChoice .cHint { font: 12.5px/1.5 var(--mono);
  color: var(--muted); text-transform: none; }

/* Device folder picker */
dialog.devPicker { width: min(24rem, 92vw); }
dialog.devPicker .dTitle { font-family: var(--pixel); font-size: .6rem; }
dialog.devPicker .dHint { font-size: .82rem; color: var(--muted); margin: 0 0 .6rem; }
dialog.devPicker .dPath { font-family: var(--mono); font-size: .8rem; color: var(--fg); }
dialog.devPicker .dRowBtn svg { width: 1.1rem; height: 1.1rem; flex: none; }
dialog.devPicker .dMeta { font-size: .75rem; color: var(--muted); margin-bottom: .6rem; }
dialog.devPicker .dList { list-style: none; margin: 0 0 .9rem; padding: 0;
  max-height: 15rem; overflow-y: auto; border: 2px solid var(--border); }
dialog.devPicker .dRowBtn { width: 100%; min-height: 0; justify-content: flex-start;
  border: none; box-shadow: none; background: none; padding: .5rem .6rem;
  font-size: .55rem; gap: .5rem; }
dialog.devPicker .dRowBtn:hover { background: var(--panel2); border: none; }
dialog.devPicker .dRowBtn:active { transform: none; }
dialog.devPicker .dRowBtn .nm { flex: 1; text-align: left; }

dialog.devPicker li:nth-child(odd) .dRowBtn { background: var(--panel2); }
dialog.devPicker li:nth-child(odd) .dRowBtn:hover { background: var(--bg); }
dialog.devPicker .dEmpty { padding: .6rem; color: var(--muted); font-size: .8rem; }

/* Toasts */
.toastStack { position: fixed; right: 1rem; bottom: 1rem; z-index: 50;
  display: grid; gap: .5rem; justify-items: end; }
.toast { border: 2px solid var(--border); background: var(--panel); color: var(--fg);
  box-shadow: 3px 3px 0 var(--shadow); padding: .55rem .75rem;
  display: flex; align-items: center; gap: .5rem; font-size: .85rem;
  animation: toastIn .18s steps(3, end); }
.toast.ok { color: var(--ok); border-color: currentColor; }
.toast.warn { color: var(--warn); border-color: currentColor; }
.toast.err { color: var(--err); border-color: currentColor; }
.toast.info { color: var(--fg); }
.toast.out { animation: toastOut .14s steps(2, end) forwards; }
.toast .tClose { min-height: 0; padding: .1rem; border: none; box-shadow: none;
  background: none; color: inherit; }
@keyframes toastIn { from { transform: translateY(9px); opacity: 0; } }
@keyframes toastOut { to { transform: translateX(9px); opacity: 0; } }

/* Legend strip */
.legend { display: flex; flex-wrap: wrap; gap: .4rem 1.1rem; font-size: .72rem;
  color: var(--muted); padding: .4rem 0 .8rem; align-items: center; }
.legend > span { display: inline-flex; align-items: center; gap: .35rem; }

/* Progress bar system */
.pbar { display: grid; gap: .3rem; margin-bottom: 1rem; }
.pbar[hidden] { display: none; }
.pbar .track { height: 12px; border: 2px solid var(--border); background: var(--bg);
  position: relative; overflow: hidden; }
.pbar .track.sub { height: 6px; }
.pbar .fill { position: absolute; inset: 0 auto 0 0; width: 0; background: var(--accent);
  transition: width .15s steps(3, end); }
.pbar .track.sub .fill { background: var(--accent2); }
.pbar.busy .fill { width: 100%;
  background: repeating-linear-gradient(90deg, var(--accent) 0 9px, var(--panel2) 9px 18px);
  animation: march .5s steps(6) infinite; }
.pbar.active .fill::after { content: ''; position: absolute; inset: 0;
  background: repeating-linear-gradient(90deg, transparent 0 24px, rgb(255 255 255 / .25) 24px 27px);
  animation: march .9s steps(6) infinite; }
@keyframes march { to { background-position: 18px 0; } }
.pbar .pLbl { display: flex; justify-content: space-between; gap: 1rem;
  font-size: .78rem; color: var(--muted); }
.pbar .pLbl .right { font-family: var(--mono); flex: none; }

/* Empty states */
.empty { display: grid; justify-items: center; gap: .6rem; padding: 2.5rem 1rem;
  border: 2px dashed var(--border); color: var(--muted); text-align: center; }
.empty .ico { width: 2rem; height: 2rem; }
.empty .eTitle { font-family: var(--pixel); font-size: .6rem; color: var(--fg); }
.empty p { margin: 0; font-size: .9rem; }

/* Skeleton dither */
.skel { color: transparent !important;
  background: repeating-conic-gradient(var(--panel2) 0 25%, var(--panel) 0 50%) 0 0 / 6px 6px;
  animation: dither .6s steps(2) infinite; }
@keyframes dither { to { background-position: 6px 0; } }

/* Button loading */
button.loading .ico svg { animation: spin8 .8s steps(8) infinite; }
@keyframes spin8 { to { transform: rotate(360deg); } }

/* Pixel burst (celebration) */
.burst { position: absolute; inset: 0; pointer-events: none; overflow: visible; }
.burst i { position: absolute; left: 50%; top: 50%; width: 4px; height: 4px;
  animation: fly .45s steps(5, end) forwards; }
@keyframes fly {
  to { transform: translate(calc(var(--dx) * 1px), calc(var(--dy) * 1px)); opacity: 0; }
}

/* Chip buttons (source strip: folder/device state machines) */
/* The chip holders. Each can carry more than one chip — the folder slot offers
   both a folder and a loose-file picker — so they space and wrap their own
   contents rather than leaving the buttons flush against each other. */
#folderChip, #deviceChip { display: inline-flex; align-items: center; gap: .5rem; flex-wrap: wrap; }

.srcChip { display: inline-flex; align-items: center; gap: .5rem;
  border: 2px solid var(--border); background: var(--panel2); color: var(--fg);
  box-shadow: 3px 3px 0 var(--shadow); padding: .45rem .7rem;
  font-family: var(--pixel); font-size: .55rem; min-height: 2.4rem; }
.srcChip .sub { font: 11px/1 var(--mono); color: var(--muted); text-transform: none; }
.srcChip.primary { background: var(--accent); border-color: var(--shadow); color: #fff; }
.srcChip.warnState { border-color: var(--warn); color: var(--warn); }
.srcChip button { min-height: 0; padding: .15rem; border: none; box-shadow: none;
  background: none; color: var(--muted); }
.srcChip button:hover { color: var(--fg); }
.srcChip button:active { transform: none; }
.srcChip button .ico { width: 1rem; height: 1rem; }
button.srcChip { cursor: pointer; }
button.srcChip:hover { border-color: var(--accent); }
button.srcChip:active { transform: translate(3px, 3px); box-shadow: none; }
.srcChip .pulse { animation: pulse2 .3s steps(2) 2; }
.srcChip .chipSpin { display: inline-flex; }
.srcChip .chipSpin svg { width: 1.1rem; height: 1.1rem; animation: spin8 .8s steps(8) infinite; }
.srcChip.scanning { border-color: var(--accent); }
@keyframes pulse2 { 50% { border-color: var(--warn); } }

/* Micro-animations: enters and lifts, all steps() and 3px-quantized.
   The grid's own lifts moved to css/collection.css with the grid. */
.settingsPanel:not([hidden]) { animation: rise .12s steps(3, end); }
dialog.nesDialog[open] { animation: rise .14s steps(3, end); }
dialog.nesDialog::backdrop { animation: fadeIn .1s steps(2, end); }
@keyframes rise { from { opacity: 0; transform: translateY(6px); } }
@keyframes fadeIn { from { opacity: 0; } }


/* ---- guided tour ---------------------------------------------------------
   A spotlight over one control with a bubble beside it. The veil is a single
   element with a huge spread shadow rather than four panels, which keeps the
   hole exactly on the target with nothing to keep in sync. */
.tour { position: fixed; inset: 0; z-index: 60; }
:root.tourOn { overflow: hidden; }

.tour .tourVeil { position: absolute; inset: 0; cursor: pointer; }

.tour .tourSpot {
  position: fixed; pointer-events: none;
  border: 2px solid var(--accent);
  box-shadow: 0 0 0 9999px rgba(0, 0, 0, .72);
  transition: top .12s steps(3, end), left .12s steps(3, end),
              width .12s steps(3, end), height .12s steps(3, end);
}

/* Nothing is drawn until the first step has been measured and placed: an
   absolutely positioned element with no coordinates yet sits at the document
   origin, which showed up as a flash in the top-left corner. */
.tour:not(.ready) .tourSpot,
.tour:not(.ready) .tourBubble { visibility: hidden; }
.tour:not(.ready) .tourSpot { transition: none; }

.tour .tourBubble {
  position: fixed; max-width: min(26rem, calc(100vw - 1.5rem));
  border: 2px solid var(--border); background: var(--panel); color: var(--fg);
  box-shadow: 4px 4px 0 var(--shadow); padding: .85rem .9rem;
  animation: rise .14s steps(3, end);
}
.tour .tourBubble h2 { font-size: .95rem; margin: .15rem 0 .4rem; }
.tour .tourBubble p { margin: 0 0 .7rem; font-size: .82rem; line-height: 1.5; color: var(--fg); }
.tour .tourStep { font-size: .7rem; color: var(--muted); letter-spacing: .06em; }

.tour .tourRow { display: flex; align-items: center; gap: .4rem; }
.tour .tourRow .tourDots { display: flex; gap: .25rem; margin-right: auto; }
.tour .tourDot { width: 6px; height: 6px; background: var(--border); }
.tour .tourDot.on { background: var(--accent); }
/* An ordinary button like BACK, only muted. Stripping the border while leaving
   the base rule's drop shadow in place read as a broken edge. */
.tour .tourSkip { margin-right: auto; color: var(--muted); }
.tour .tourSkip:hover { color: var(--fg); }
.tour .tourNext { background: var(--accent); border-color: var(--shadow); color: #fff;
  display: inline-flex; align-items: center; gap: .3rem; }
.tour .tourNext svg, .tour .tourSkip svg { width: .9em; height: .9em; }

@media (max-width: 30rem) {
  .tour .tourBubble { left: .75rem !important; right: .75rem; max-width: none; }
  .tour .tourRow .tourDots { display: none; }
}

/* Reduced motion: kill everything */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}
