:root {
  --bg: #000000;
  --panel: #0a0a0a;
  --card: #141416;
  --card2: #1e1e20;
  --border: #28282c;
  --txt: #f0f0f0;
  --mute: #808085;
  --accent: #f0f0f0;
  --green: #4bd07a;
  --amber: #f2c14e;
  --red: #ff5a5a;
  --orange: #ff8a3d;
  --grey: #8a8a92;
  --row-h: 30px;
  /* Theme (light-bar + header-flash) colour. Overridden per-theme via JS
     setProperty on :root; default = Cyan Ice (matches the shipped light
     border). --skid-glow is 0 for "Off (dark)" to fully disable the effects
     without any JS branching in the animation CSS itself. */
  --skid-accent-rgb: 66, 232, 224;
  --skid-glow: 1;
}

* { box-sizing: border-box; }

/* ---------- animated light border (GPU-composited, ~0 cost) ----------
   A cyan/white light sweeps around the window edge (BMW-DRL style) plus a
   soft breathing glow. A large conic-gradient disc spins via transform:rotate
   (always compositor-accelerated), masked down to a thin ring at the window
   edge. Never touches the JS poll loop or the Python worker threads. */
#lightborder {
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  overflow: hidden;
  padding: 2.5px;                 /* = light-ring thickness */
  opacity: var(--skid-glow);
  transition: opacity 0.4s ease;
  /* mask so only the padding ring shows (hollow centre) */
  -webkit-mask:
     linear-gradient(#000 0 0) content-box,
     linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
}

/* the spinning light disc — larger than the window so its rotation covers
   every corner of the ring */
#lightborder::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 300vmax;
  height: 300vmax;
  margin-left: -150vmax;
  margin-top: -150vmax;
  background: conic-gradient(from 0deg,
      rgba(var(--skid-accent-rgb), 0.0)    0deg,
      rgba(var(--skid-accent-rgb), 0.0)    205deg,
      rgba(var(--skid-accent-rgb), 0.55)   258deg,
      rgba(var(--skid-accent-rgb), 0.95)   300deg,
      #ffffff                              324deg,
      rgba(var(--skid-accent-rgb), 0.95)   348deg,
      rgba(var(--skid-accent-rgb), 0.0)    360deg);
  will-change: transform;
  animation: skid-spin 3.2s linear infinite;
  animation-play-state: var(--skid-flash-state, running);
}

/* faint steady inner glow line under the moving light for depth */
#lightborder::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid rgba(var(--skid-accent-rgb), 0.12);
  animation: skid-breathe 3.2s ease-in-out infinite;
  animation-play-state: var(--skid-flash-state, running);
}

@keyframes skid-spin { to { transform: rotate(360deg); } }
@keyframes skid-breathe {
  0%, 100% { opacity: 0.30; }
  50%      { opacity: 0.85; }
}

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--txt);
  font-family: "Segoe UI", -apple-system, sans-serif;
  height: 100%;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}

#app {
  /* NOTE: deliberately no z-index here. #app used to have z-index:1, which
     creates a stacking context that traps EVERY descendant below it --
     meaning nothing inside #app could ever paint above #bgGlow (z-index:40)
     no matter what z-index a descendant declared. That's what was washing
     out the selected-row highlight: the glow (mix-blend-mode:screen) painted
     on top of the whole app uniformly, including selected rows. Leaving
     #app z-index:auto lets #tableWrap below opt out individually with its
     own z-index, while header/left panel (no z-index of their own) still
     sit under the glow same as before. */
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100vh;
}

/* ---------- ambient background: 4 selectable modes (GPU-composited) ----------
   #bgGlow sits ABOVE #app with mix-blend-mode:screen so it tints every
   panel directly (painting behind opaque panels was invisible). JS sets
   #bgGlow's class to mode-minimal/vivid/neon/matrix and builds whatever
   child elements that mode needs. Opacity gated by --skid-glow (the EFFECTS
   ON/OFF master switch, not the colour theme) so disabling effects removes
   this entirely regardless of which mode was selected. Every animation here
   is transform/opacity only -> compositor-only, costs nothing regardless of
   what the worker threads are doing. */
#bgGlow {
  position: fixed;
  inset: 0;
  z-index: 40;              /* above the app panels, below dropdown menus (50) */
  pointer-events: none;
  mix-blend-mode: screen;
  overflow: hidden;
  opacity: var(--skid-glow);
}

/* ---- Neon: pulsing inset glow frame + two breathing corner blooms ---- */
#bgGlow.mode-neon::before {
  content: "";
  position: absolute;
  inset: 10px;
  border-radius: 18px;
  box-shadow:
    inset 0 0 40px 4px rgba(var(--skid-accent-rgb), 0.55),
    inset 0 0 100px 14px rgba(var(--skid-accent-rgb), 0.28);
  animation: neon-frame-pulse 1.8s ease-in-out infinite;
  animation-play-state: var(--skid-flash-state, running);
}
@keyframes neon-frame-pulse {
  0%, 100% { opacity: 0.5; }
  50%      { opacity: 1; }
}
.neon-corner {
  position: absolute;
  width: 42vw; height: 42vw;
  border-radius: 50%;
  filter: blur(75px);
  background: radial-gradient(circle, rgba(var(--skid-accent-rgb), 0.6) 0%, rgba(var(--skid-accent-rgb), 0) 70%);
  will-change: transform, opacity;
  animation: neon-corner-pulse 2.6s ease-in-out infinite;
  animation-play-state: var(--skid-flash-state, running);
}
#bgGlow.mode-neon .neon-corner.nc1 { top: -16vw; left: -16vw; animation-delay: 0s; }
#bgGlow.mode-neon .neon-corner.nc2 { bottom: -16vw; right: -16vw; animation-delay: 1.3s; }
@keyframes neon-corner-pulse {
  0%, 100% { opacity: 0.25; transform: scale(0.9); }
  50%      { opacity: 0.75; transform: scale(1.2); }
}

/* ---- Grid Pulse: faint network grid + glowing scan nodes ---- */
#bgGlow.mode-gridpulse {
  background-image:
    repeating-linear-gradient(to right,  rgba(var(--skid-accent-rgb), 0.10) 0px, rgba(var(--skid-accent-rgb), 0.10) 1px, transparent 1px, transparent 64px),
    repeating-linear-gradient(to bottom, rgba(var(--skid-accent-rgb), 0.10) 0px, rgba(var(--skid-accent-rgb), 0.10) 1px, transparent 1px, transparent 64px);
}
.grid-node {
  position: absolute;
  width: 6px; height: 6px;
  margin: -3px 0 0 -3px;
  border-radius: 50%;
  background: rgb(var(--skid-accent-rgb));
  box-shadow: 0 0 10px 2px rgba(var(--skid-accent-rgb), 0.9);
  will-change: opacity, transform;
  animation-name: grid-node-pulse;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-play-state: var(--skid-flash-state, running);
}
@keyframes grid-node-pulse {
  0%, 100% { opacity: 0.15; transform: scale(0.7); }
  50%      { opacity: 1;    transform: scale(1.3); }
}
/* click extra: every node on screen flashes brighter, like the grid
   responding to a triggered scan */
.grid-node.fx-node-flash { animation-name: grid-node-flash; animation-duration: 0.5s !important; animation-iteration-count: 1 !important; }
@keyframes grid-node-flash {
  0%   { opacity: 1; transform: scale(2.2); box-shadow: 0 0 18px 5px rgba(var(--skid-accent-rgb), 1); }
  100% { opacity: 0.15; transform: scale(0.7); box-shadow: 0 0 10px 2px rgba(var(--skid-accent-rgb), 0.9); }
}

/* ---- Starfield: twinkling depth field + slow drift ---- */
#bgGlow.mode-starfield .star-field {
  position: absolute;
  inset: -10%;
  will-change: transform;
  animation: star-drift 40s linear infinite;
  animation-play-state: var(--skid-flash-state, running);
}
@keyframes star-drift {
  0%   { transform: translate(0, 0); }
  100% { transform: translate(-4%, -3%); }
}
.star {
  position: absolute;
  border-radius: 50%;
  background: rgb(var(--skid-accent-rgb));
  will-change: opacity;
  animation-name: star-twinkle;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-play-state: var(--skid-flash-state, running);
}
@keyframes star-twinkle {
  0%, 100% { opacity: 0.12; }
  50%      { opacity: var(--star-op, 0.9); }
}
/* click extra: a shooting-star streak flies out from the icon */
.streak {
  position: fixed;
  width: 46px;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, rgba(var(--skid-accent-rgb), 0) 0%, rgb(var(--skid-accent-rgb)) 70%, #fff 100%);
  box-shadow: 0 0 6px 1px rgba(var(--skid-accent-rgb), 0.9);
  transform-origin: 0% 50%;
  will-change: transform, opacity;
  animation: streak-fly 0.55s cubic-bezier(.15,.6,.25,1) forwards;
}
@keyframes streak-fly {
  0%   { transform: translate(0, 0) rotate(var(--streak-angle, 0deg)) scaleX(0.3); opacity: 1; }
  100% { transform: translate(var(--streak-dx, 60px), var(--streak-dy, 0px)) rotate(var(--streak-angle, 0deg)) scaleX(1); opacity: 0; }
}

/* ---------- header ---------- */
#header {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 14px 22px;
  flex: 0 0 auto;
}

#brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 0.5px;
  animation: skid-title-flash 2.6s ease-in-out infinite;
  animation-play-state: var(--skid-flash-state, running);
}
#brand img { width: 24px; height: 24px; }

#pills {
  display: flex;
  gap: 6px;
  flex: 1 1 auto;
  /* wrap to a second row instead of side-scrolling, and keep pills compact so
     all of them are visible at once (operator request: no horizontal scroll). */
  flex-wrap: wrap;
  row-gap: 6px;
}

.pill {
  display: flex;
  align-items: center;
  gap: 5px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 9px;
  padding: 6px 10px;
  white-space: nowrap;
  font-size: 12px;
  /* GPU-composited pulse: border colour + a soft accent glow "breathe" in
     sync with the light border. box-shadow repaints are cheap here — 6 small
     fixed-size elements, nowhere near the cost of the old per-frame canvas
     redraw that caused the original Tk lag. Each pill gets a slight phase
     offset (nth-child delay below) for a gentle wave instead of a flat strobe. */
  animation: skid-pill-flash 2.6s ease-in-out infinite;
  animation-play-state: var(--skid-flash-state, running);
}
.pill:nth-child(1) { animation-delay: 0s;    }
.pill:nth-child(2) { animation-delay: 0.15s; }
.pill:nth-child(3) { animation-delay: 0.3s;  }
.pill:nth-child(4) { animation-delay: 0.45s; }
.pill:nth-child(5) { animation-delay: 0.6s;  }
.pill:nth-child(6) { animation-delay: 0.75s; }
.pill .dot { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; }
.pill b { font-size: 13px; margin-right: 2px; }
.pill .lbl { color: var(--mute); }

@keyframes skid-pill-flash {
  0%, 100% {
    border-color: var(--border);
    box-shadow: 0 0 0 rgba(var(--skid-accent-rgb), 0);
  }
  50% {
    border-color: rgba(var(--skid-accent-rgb), calc(0.7 * var(--skid-glow)));
    box-shadow: 0 0 12px rgba(var(--skid-accent-rgb), calc(0.35 * var(--skid-glow)));
  }
}
@keyframes skid-title-flash {
  0%, 100% { text-shadow: 0 0 0 rgba(var(--skid-accent-rgb), 0); color: var(--txt); }
  50%      { text-shadow: 0 0 16px rgba(var(--skid-accent-rgb), var(--skid-glow));
             color: rgb(var(--skid-accent-rgb)); }
}

#langWrap, #themeWrap, #fxWrap { position: relative; flex: 0 0 auto; }
#langBtn, #themeBtn, #fxBtn {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--card);
  border: 1px solid var(--border);
  color: var(--txt);
  border-radius: 10px;
  padding: 10px 16px;
  font-size: 13px;
  cursor: pointer;
}
#langBtn svg, #themeBtn svg, #fxBtn svg { flex: 0 0 auto; opacity: 0.85; }
#langBtn:hover, #themeBtn:hover, #fxBtn:hover { background: var(--card2); }

/* Dark/Bright one-click toggle -- icon-only header button beside Theme. Shows
   the icon of the mode you'll switch TO: a sun while dark, a moon while bright. */
#modeBtn {
  display: flex; align-items: center; justify-content: center;
  background: var(--card); border: 1px solid var(--border); color: var(--txt);
  border-radius: 10px; padding: 10px 12px; cursor: pointer;
}
#modeBtn:hover { background: var(--card2); }
#modeBtn svg { display: block; opacity: 0.85; }
#modeBtn .ico-moon { display: none; }
:root[data-mode="light"] #modeBtn .ico-sun { display: none; }
:root[data-mode="light"] #modeBtn .ico-moon { display: block; }

/* ===== BRIGHT (light) mode: override the neutral tokens; the whole UI is
   variable-driven so surfaces/text flip together. Status colours are darkened
   a touch for contrast on light. Accent (--skid-accent-rgb) stays per-theme. */
:root[data-mode="light"] {
  --bg: #e7e9ed;
  --panel: #ffffff;
  --card: #f2f3f5;
  --card2: #e5e7ea;
  --border: #d2d6dc;
  --txt: #1b1d21;
  --mute: #676d76;
  --accent: #1b1d21;
  --green: #1f9d54;
  --amber: #b98400;
  --red: #d5362f;
  --orange: #cf6a1c;
  --grey: #767b84;
}

/* --- light/bright-mode fixes --- */
/* 1) the status-pills row scrolls when it overflows, but the native scrollbar
      is ugly (a fat grey bar in light mode). Hide it in every mode -- the row
      still scrolls by wheel/drag, it just has no visible bar. */
#pills { scrollbar-width: none; -ms-overflow-style: none; }
#pills::-webkit-scrollbar { width: 0; height: 0; display: none; }

/* 2) effects used mix-blend-mode:screen, which is invisible on a light
      background (screen over white = white). Multiply darkens the accent glow
      onto light surfaces, so the effects actually show in Bright mode too. */
:root[data-mode="light"] #bgGlow { mix-blend-mode: multiply; }

/* 3) in-progress rows set a near-white inline colour (#f0f0f0 checking /
      #808085 pending) that vanishes on a light/aluminium row. Override to a
      readable dark tone in Bright mode (covers flat-light AND retro-light). */
:root[data-mode="light"] .trow.checking,
:root[data-mode="light"] .trow.pending { color: #34373c !important; }
:root[data-mode="light"] .trow.checking .status-dot { background: #9a9da3 !important; }

/* Telegram/website header links -- icon-only buttons (tooltip via title=)
   so they cost the pills row as little width as possible; own rule instead
   of joining #langBtn/#themeBtn/#fxBtn so this stays a self-contained,
   easily removable block. */
#contactWrap { display: flex; gap: 8px; flex: 0 0 auto; }
#telegramBtn, #websiteBtn {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--card);
  border: 1px solid var(--border);
  color: var(--txt);
  border-radius: 10px;
  width: 36px;
  height: 36px;
  padding: 0;
  cursor: pointer;
}
#telegramBtn svg, #websiteBtn svg { flex: 0 0 auto; opacity: 0.85; }
#telegramBtn:hover, #websiteBtn:hover { background: var(--card2); }

/* License remaining-time badge, sits right beside the "3SKID" title inside
   #brand (already flex/gap:10px, so this just drops in as the next child). */
.license-badge {
  font-size: 12px;
  font-weight: 400;
  letter-spacing: normal;
  color: var(--mute);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 3px 8px;
  white-space: nowrap;
}
.license-badge.permanent { color: var(--green); }
.license-badge.expiring-soon { color: var(--amber); }

/* Update notices -- a non-blocking, dismissible toast (never a modal: an
   update is never urgent enough to interrupt whatever the operator is
   doing). Same element covers both triggers: the "restart to update"
   nudge fired while the app is already open, and the one-shot "updated to
   vX.Y.Z" note shown on the first launch after an update -- see app.js's
   bootUpdateNotices(). */
#updateNotice {
  position: fixed;
  top: 14px;
  left: 50%;
  transform: translateX(-50%) translateY(-160%);
  z-index: 10000;
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 14px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
  max-width: 480px;
  font-size: 13px;
  color: var(--txt);
  transition: transform 0.25s ease;
  pointer-events: none;
}
#updateNotice.open {
  transform: translateX(-50%) translateY(0);
  pointer-events: auto;
}
#updateNoticeIcon { flex: 0 0 auto; display: flex; color: rgb(var(--skid-accent-rgb)); }
#updateNoticeIcon svg { display: block; }
#updateNoticeText { flex: 1 1 auto; }
#updateNoticeDismiss {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  background: transparent;
  border: none;
  color: var(--mute);
  cursor: pointer;
  padding: 2px;
}
#updateNoticeDismiss:hover { color: var(--txt); }
.lang-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 6px;
  min-width: 150px;
  display: none;
  z-index: 50;
  box-shadow: 0 8px 24px rgba(0,0,0,0.5);
}
.lang-menu.open { display: block; }
.lang-item {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 9px 12px;
  border-radius: 7px;
  font-size: 13px;
  cursor: pointer;
}
.lang-item:hover { background: var(--card2); }
.lang-item.active { background: var(--card2); font-weight: 700; }
.theme-swatch {
  width: 12px; height: 12px; border-radius: 50%; flex: 0 0 auto;
  border: 1px solid rgba(255,255,255,0.25);
}
/* RTL: menu anchors to the left edge instead */
html[dir="rtl"] .lang-menu { right: auto; left: 0; }
html[dir="rtl"] #brand { flex-direction: row-reverse; }
/* Keep the RESULTS TABLE left-to-right even when the UI is RTL (Arabic). It's a
   wide, horizontally-scrolled flex grid of mostly-LTR data (emails, dates,
   region codes). Under dir=rtl the flex columns mirrored, but the header
   (overflow-x:hidden + JS scrollLeft-sync) and the body (overflow-x:auto) have
   different RTL scroll "start" offsets, so the header desynced from the body by
   the whole overflow width and columns no longer sat under their headers
   ("Arabic disturbed"). Forcing the grid LTR restores exact header↔body
   alignment; the Arabic header labels and any Arabic cell text still render
   correctly via the Unicode bidi algorithm inside each cell. */
html[dir="rtl"] #tableWrap { direction: ltr; }

/* ---------- Effects menu: master on/off + mode picker ---------- */
.fx-menu { min-width: 210px; }

/* Right-click context menu on the results table: positioned at the click
   point (JS sets left/top in viewport coordinates), not anchored under a
   header button like the other dropdowns. */
.ctx-menu {
  position: fixed;
  top: 0; left: 0; right: auto;
  min-width: 170px;
  z-index: 60;
}
/* Results-grid context menu: the "Paste accounts" item shows ONLY when the grid
   is empty (ctx-empty-mode); row-only items show only when there are rows. */
#tableCtxMenu .ctx-when-empty { display: none; }
#tableCtxMenu.ctx-empty-mode .ctx-when-empty { display: block; }
#tableCtxMenu.ctx-empty-mode .lang-item:not(.ctx-when-empty),
#tableCtxMenu.ctx-empty-mode .fx-sep-line { display: none; }
.fx-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 10px 10px 10px;
  font-size: 13px;
  cursor: pointer;
}
.fx-switch { position: relative; display: inline-block; width: 34px; height: 19px; flex: 0 0 auto; }
.fx-switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.fx-switch-track {
  position: absolute; inset: 0;
  background: var(--border);
  border-radius: 999px;
  transition: background 0.15s ease;
}
.fx-switch-track::before {
  content: "";
  position: absolute;
  top: 2px; left: 2px;
  width: 15px; height: 15px;
  border-radius: 50%;
  background: var(--txt);
  transition: transform 0.15s ease;
}
.fx-switch input:checked ~ .fx-switch-track { background: rgb(var(--skid-accent-rgb)); }
.fx-switch input:checked ~ .fx-switch-track::before { transform: translateX(15px); background: #000; }
.fx-sep-line { height: 1px; background: var(--border); margin: 4px 6px 6px 6px; padding: 0; cursor: default; }
.fx-mode-item {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 8px 10px;
  border-radius: 7px;
  font-size: 13px;
  cursor: pointer;
}
.fx-mode-item:hover { background: var(--card2); }
.fx-mode-item.active { background: var(--card2); font-weight: 700; }
.fx-mode-item.disabled-look { opacity: 0.4; pointer-events: none; }
.fx-mode-dot {
  width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto;
  background: var(--border);
  align-self: center;
}
.fx-mode-item.active .fx-mode-dot { background: rgb(var(--skid-accent-rgb)); }
.fx-mode-sub { color: var(--mute); font-size: 10.5px; font-weight: 400; margin-left: auto; }

/* ---------- main layout ---------- */
#main {
  flex: 1 1 auto;
  display: flex;
  gap: 22px;
  padding: 0 22px 18px 22px;
  min-height: 0;
}

#left {
  width: 320px;
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 0;
}
/* Everything ABOVE the action buttons scrolls in its own region;
   #leftActions (Start/Stop, Export CSV/TXT, Delete Selected) is a fixed
   flex: 0 0 auto sibling below it, so it's always visible regardless of
   how long the Functions checklist grows -- it used to be the last thing
   inside #left's own scroll, which pushed it below the fold on anything
   but a tall window once enough function checkboxes existed. */
#leftScroll {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
  overflow-y: auto;
  padding-right: 4px;
}
#leftActions {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

h3.section {
  margin: 0 0 4px 0;
  font-size: 15px;
  font-weight: 700;
}
.hint {
  color: var(--mute);
  font-size: 11.5px;
  line-height: 1.5;
  margin: 0 0 8px 0;
}

/* "Mac code" opt-in checkbox above the accounts paste box. Sits inline with a
   small label so it does not shove the textarea down. */
.macCodeRow {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 6px 0;
  font-size: 12px;
  color: var(--txt);
  cursor: pointer;
  user-select: none;
}
.macCodeRow input[type="checkbox"] {
  margin: 0;
  cursor: pointer;
}

#accounts {
  width: 100%;
  height: 210px;
  resize: vertical;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--txt);
  font-family: Consolas, monospace;
  /* Match the results-table row font EXACTLY (.trow: 12px Consolas) so the paste
     box and the results read as one size, just bold here for emphasis/legibility. */
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
  padding: 10px;
}
#accounts:focus { outline: 1px solid var(--mute); }

.field-label {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 13px;
  margin-bottom: 6px;
}
.field-label b { font-weight: 700; }
.field-label .num {
  background: var(--card2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 2px 8px;
  font-size: 12px;
  width: 54px;
  text-align: center;
  color: var(--txt);
}
input.txt {
  width: 100%;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--txt);
  font-size: 12px;
  padding: 8px 10px;
  margin-bottom: 6px;
  font-family: Consolas, monospace;
}

/* Native <select> styled to match the app theme (region + language dropdowns).
   The rule above targets input.txt ONLY, so <select class="txt"> fell back to
   the raw browser control (the unstyled white popup). Style the closed control
   with a custom chevron + theme the option popup (WebView2/Chromium honors
   option background/color). */
select.txt {
  width: 100%;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--txt);
  font-size: 12px;
  padding: 8px 30px 8px 10px;
  margin-bottom: 6px;
  font-family: Consolas, monospace;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238a8a92' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat: no-repeat;
  background-position: right 10px center;
}
select.txt:hover { border-color: var(--grey); }
select.txt:focus { outline: none; border-color: var(--green); }
select.txt option {
  background: var(--card);
  color: var(--txt);
  padding: 6px 10px;
}
select.txt option:checked { background: var(--card2); font-weight: 700; }
input.txt:focus { outline: 1px solid var(--mute); }
.opt-block {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px;
}
/* Moved (via JS, see refreshOptionPanels) to sit directly under its own
   function's checkbox inside #functions -- a bit of breathing room so it
   reads as "belongs to the row above" rather than just the next row in
   the list, since #functions' own gap (2px) is tuned for checkbox rows. */
.func-opt { margin: 2px 0 8px; }
.mini-check {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  cursor: pointer;
}
.mini-check input { accent-color: var(--txt); width: 15px; height: 15px; }
.mini-check.disabled { opacity: 0.35; cursor: not-allowed; }
.mini-check.disabled input { cursor: not-allowed; }

/* Run-scope options ("Only Selected" / "Only Unprocessed") relocated to sit
   directly under the progress bar -- laid out side by side, wrapping on narrow
   widths. */
#runScopeRow {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 28px;
  margin: 8px 4px 2px;
}
#runScopeRow .mini-check { margin: 0; }

input[type=range] {
  width: 100%;
  accent-color: var(--txt);
}
.slider-hint { color: var(--mute); font-size: 11px; margin-top: 4px; }

#functions {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.func-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 4px;
  border-radius: 8px;
  font-size: 13.5px;
  cursor: pointer;
}
.func-row.disabled { opacity: 0.35; cursor: not-allowed; }
/* Locked function rows: shown when "Mac code" is ticked, for the modes Apple's
   device-code (trusted-Mac) session can't service. Dimmed + not-allowed cursor
   so the operator can see the mode exists but can't select it. The checkbox is
   also set disabled in JS (applyMacCodeExclusions) -- this is the visual half. */
.func-row.mac-code-excluded { opacity: 0.35; cursor: not-allowed; }
.func-row.mac-code-excluded input { cursor: not-allowed; }
.func-row input { accent-color: var(--txt); width: 15px; height: 15px; }
.func-sep { height: 1px; background: var(--border); margin: 9px 4px; }

/* Grouped function-section headings ("Checking options" / "Account info
   modification" / "App Store functions" / "Other functions"). Themed: the
   text takes the live theme accent with a neon glow, and a gradient rule
   fades out under it -- so every heading reacts to the current Theme like the
   rest of the app's neon accents (rgb(var(--skid-accent-rgb)) is the same
   theme colour used for the lit checkbox icons). */
.func-group-title {
  margin: 16px 4px 8px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgb(var(--skid-accent-rgb, 240, 240, 240));
  /* No blur glow: a 10px text-shadow on 11px uppercase text made the headings
     look fuzzy/low-quality. The themed feel comes from the accent colour + the
     gradient underline (::after), both crisp. */
  user-select: none;
}
.func-group-title:first-child { margin-top: 2px; }
.func-group-title::after {
  content: "";
  display: block;
  height: 1px;
  margin-top: 5px;
  background: linear-gradient(90deg, rgba(var(--skid-accent-rgb, 240, 240, 240), 0.6), transparent);
}
html[dir="rtl"] .func-group-title::after {
  background: linear-gradient(270deg, rgba(var(--skid-accent-rgb, 240, 240, 240), 0.6), transparent);
}

/* ---------- per-function click effect: HUD target-lock ----------
   A precision "lock-on" read, not a party burst: a thin ring pings out from
   the icon, the row's FRAME (not fill) flashes a hairline outline like a
   reticle snapping into place, and the icon glows briefly. ONE consistent
   colour language -- the active theme accent, same as the light border and
   header pulse -- ties every animated element in the app together instead of
   rainbow-coding each button. All transform/opacity/box-shadow, fired by
   toggling a class after a forced reflow -> compositor-only, never touches
   the poll loop or worker threads. */
.func-row {
  position: relative;
  overflow: hidden;
}
.func-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  color: var(--mute);
  position: relative;
  z-index: 1;
}
.func-icon svg { display: block; }
.func-row input:checked ~ .func-icon { color: rgb(var(--skid-accent-rgb)); }
.func-icon.fx-play {
  animation: fx-icon-glow 0.5s ease-out both;
}
.func-ripple {
  position: absolute;
  left: 24px;
  top: 50%;
  width: 14px;
  height: 14px;
  margin-top: -7px;
  border-radius: 50%;
  border: 1.5px solid rgba(var(--skid-accent-rgb), 0.9);
  background: transparent;
  opacity: 0;
  pointer-events: none;
  z-index: 0;
}
.func-ripple.fx-play {
  animation: fx-ring-ping 0.55s cubic-bezier(.22,.61,.36,1) both;
}
.func-row.fx-flash-row {
  animation: fx-row-lock 0.5s ease-out both;
}
@keyframes fx-ring-ping {
  0%   { transform: scale(0.4); opacity: 0.85; border-width: 2px; }
  100% { transform: scale(7);   opacity: 0;    border-width: 0.5px; }
}
@keyframes fx-row-lock {
  0%   { box-shadow: inset 0 0 0 1px rgba(var(--skid-accent-rgb), 0.85);
         background-color: rgba(var(--skid-accent-rgb), 0.05); }
  100% { box-shadow: inset 0 0 0 1px rgba(var(--skid-accent-rgb), 0);
         background-color: transparent; }
}
@keyframes fx-icon-glow {
  0%   { transform: scale(1);   filter: drop-shadow(0 0 0 rgba(var(--skid-accent-rgb), 0)); }
  40%  { transform: scale(1.2); filter: drop-shadow(0 0 5px rgba(var(--skid-accent-rgb), 0.85)); }
  100% { transform: scale(1);   filter: drop-shadow(0 0 0 rgba(var(--skid-accent-rgb), 0)); }
}

/* ---- Neon mode: the same ring/lock/glow, just BIGGER and brighter ---- */
.func-ripple.fx-play.fx-big { animation-name: fx-ring-ping-big; }
.func-row.fx-flash-row.fx-big { animation-name: fx-row-lock-big; }
.func-icon.fx-play.fx-big { animation-name: fx-icon-glow-big; }
@keyframes fx-ring-ping-big {
  0%   { transform: scale(0.4); opacity: 1; border-width: 3px; }
  100% { transform: scale(13);  opacity: 0; border-width: 0.5px; }
}
@keyframes fx-row-lock-big {
  0%   { box-shadow: inset 0 0 0 2px rgba(var(--skid-accent-rgb), 1), 0 0 22px rgba(var(--skid-accent-rgb), 0.55);
         background-color: rgba(var(--skid-accent-rgb), 0.12); }
  100% { box-shadow: inset 0 0 0 2px rgba(var(--skid-accent-rgb), 0), 0 0 0 rgba(var(--skid-accent-rgb), 0);
         background-color: transparent; }
}
@keyframes fx-icon-glow-big {
  0%   { transform: scale(1);    filter: drop-shadow(0 0 0 rgba(var(--skid-accent-rgb), 0)); }
  45%  { transform: scale(1.55); filter: drop-shadow(0 0 10px rgba(var(--skid-accent-rgb), 1)); }
  100% { transform: scale(1);    filter: drop-shadow(0 0 0 rgba(var(--skid-accent-rgb), 0)); }
}

/* ---- Vivid mode: colour spark burst layer ---- */
#fxLayer {
  position: fixed;
  inset: 0;
  z-index: 45;
  pointer-events: none;
  overflow: hidden;
}
textarea.txt-area-small {
  width: 100%;
  height: 68px;
  resize: none;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--txt);
  font-size: 12px;
  font-family: Consolas, monospace;
  padding: 8px 10px;
  margin-bottom: 6px;
}
textarea.txt-area-small:focus { outline: 1px solid var(--mute); }
.func-row .soon {
  margin-left: auto;
  font-size: 10px;
  color: var(--mute);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 1px 6px;
}

.actions { display: flex; gap: 10px; margin-top: 6px; }
button.primary, button.stop, button.danger, button.secondary {
  flex: 1;
  border: none;
  border-radius: 10px;
  padding: 11px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
/* Export CSV/TXT -- same neutral weight as .stop (not primary/glowing, not
   destructive/red), since exporting is a routine, non-committal action. */
button.secondary {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  background: var(--card2);
  color: var(--txt);
  border: 1px solid var(--border);
}
/* Import button sits directly under the accounts paste box -- give it a little
   breathing room from the textarea above it. */
#importBtn { margin-top: 8px; }
/* export-scope dropdown (All / Success only / Failed only) -- its own full-width row above the
   Export CSV/TXT buttons, styled to match the secondary buttons. */
select.export-mode {
  width: 100%;
  height: 40px;
  padding: 0 12px;
  background: var(--card2);
  color: var(--txt);
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
select.export-mode:focus { outline: none; border-color: rgba(var(--skid-accent-rgb), .6); }
/* Export CSV/TXT: equal-width, side-by-side, single line (no wrap) in the narrow left column. */
#exportCsvBtn, #exportTxtBtn { flex: 1; white-space: nowrap; }
button.secondary svg { flex: 0 0 auto; }
button.secondary:hover { background: var(--border); }
button.secondary:disabled { opacity: 0.35; cursor: not-allowed; }
button.danger {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  background: var(--card2);
  color: #ff8a8a;
  border: 1px solid rgba(255, 90, 90, 0.35);
}
button.danger svg { flex: 0 0 auto; }
button.danger:hover { background: rgba(255, 90, 90, 0.12); }
button.danger:disabled { opacity: 0.35; cursor: not-allowed; }
button.primary {
  /* text = var(--bg), the OPPOSITE of the button's var(--txt) fill, so the
     "Start" label always contrasts: dark-on-light in Dark mode, light-on-dark
     in Bright mode (a hardcoded #000 vanished on the dark Bright-mode button). */
  background: var(--txt); color: var(--bg);
  position: relative;
  /* breathing accent-glow ring while idle+ready so the eye is drawn to it */
  animation: btn-ready-glow 2.4s ease-in-out infinite;
  animation-play-state: var(--skid-flash-state, running);
}
button.primary:disabled {
  background: var(--card2); color: var(--mute); cursor: not-allowed;
  animation: none; box-shadow: none;
}
@keyframes btn-ready-glow {
  0%, 100% { box-shadow: 0 0 0 rgba(var(--skid-accent-rgb), 0); }
  50%      { box-shadow: 0 0 18px 1px rgba(var(--skid-accent-rgb), calc(0.6 * var(--skid-glow))); }
}
button.stop { background: var(--card2); color: var(--txt); border: 1px solid var(--border); }
button.stop:disabled { opacity: 0.35; cursor: not-allowed; }
/* Stop button pulses red-hot while a run is active (JS toggles .running) */
button.stop.running {
  border-color: rgba(255, 90, 90, 0.7);
  color: #ff8a8a;
  animation: btn-stop-pulse 1.1s ease-in-out infinite;
}
@keyframes btn-stop-pulse {
  0%, 100% { box-shadow: 0 0 0 rgba(255, 90, 90, 0); }
  50%      { box-shadow: 0 0 16px 1px rgba(255, 90, 90, 0.55); }
}

/* ---------- right column ---------- */
#right {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-width: 0;
  gap: 10px;
}

#progressBar {
  background: var(--panel);
  border-radius: 12px;
  padding: 10px 14px;
  display: flex;
  align-items: center;
  gap: 12px;
}
#pbarTrack {
  flex: 1;
  height: 8px;
  background: var(--card);
  border-radius: 6px;
  overflow: hidden;
}
#pbarFill {
  height: 100%;
  width: 0%;
  background:
    linear-gradient(90deg,
      rgba(255,255,255,0) 0%,
      rgba(255,255,255,0.45) 50%,
      rgba(255,255,255,0) 100%) ,
    rgb(var(--skid-accent-rgb));
  background-size: 40px 100%, 100% 100%;
  transition: width 0.12s linear;
}
/* animated diagonal shimmer sweeping along the fill while a run is active */
#pbarFill.running {
  animation: pbar-shimmer 0.9s linear infinite;
}
@keyframes pbar-shimmer {
  0%   { background-position: -40px 0, 0 0; }
  100% { background-position: 200px 0, 0 0; }
}
#pct { color: var(--mute); font-size: 11px; font-weight: 700; min-width: 32px; text-align: right; }

/* Collapse/expand the whole left panel so the results table goes full-width
   (a "focus the working area" toggle). The button lives inside #progressBar,
   which stays in #right, so it's always reachable even when #left is hidden. */
#collapseLeftBtn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  margin-right: 2px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--mute);
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}
#collapseLeftBtn:hover { color: var(--txt); border-color: rgb(var(--skid-accent-rgb)); }
#collapseLeftBtn svg { display: block; transition: transform 0.2s ease; }
/* rotate the chevrons to point the other way once the panel is hidden */
#main.left-collapsed #collapseLeftBtn svg { transform: rotate(180deg); }
#main.left-collapsed #left { display: none; }
/* RTL: #main's row reverses so #left sits on the right -- mirror the chevron so
   it still points toward the panel it hides. */
html[dir="rtl"] #collapseLeftBtn svg { transform: scaleX(-1); }
html[dir="rtl"] #main.left-collapsed #collapseLeftBtn svg { transform: scaleX(-1) rotate(180deg); }

/* Compact Stop shown in the progress bar ONLY while a run is active AND the
   left panel is collapsed -- so the sole abort control is never hidden in
   focus mode. Expanded runs use the normal Stop button in #leftActions. */
#pbarStopBtn {
  flex: 0 0 auto;
  display: none;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  background: rgba(255, 90, 90, 0.12);
  border: 1px solid rgba(255, 90, 90, 0.5);
  border-radius: 8px;
  color: #ff5a5a;
  cursor: pointer;
  transition: background 0.15s;
}
#pbarStopBtn:hover { background: rgba(255, 90, 90, 0.22); }
#pbarStopBtn svg { display: block; }
#main.is-running.left-collapsed #pbarStopBtn { display: inline-flex; }

/* Visible reason a gated Start is disabled (a disabled <button> shows no native
   tooltip in WebView2) -- e.g. "Enter at least one 16-character gift-card code". */
#startHint {
  color: var(--amber);
  font-size: 11.5px;
  line-height: 1.4;
}

#tableWrap {
  flex: 1 1 auto;
  background: var(--panel);
  border-radius: 14px;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  /* No z-index here on purpose: #bgGlow (40) is left free to paint over the
     table like every other panel, so the active effect is actually visible
     across the whole app instead of looking like it stops dead at the
     table's edge. This used to be elevated above the glow to fix a washed-
     out selection highlight, but that highlight's real cause turned out to
     be an unrelated layout bug (#tableSpacer collapsing every row to 1px
     wide -- see #tableRows below); .trow.selected's own fill + box-shadow
     bar are strong enough to stay readable under the glow's screen blend
     without needing to opt the whole table out of it. */
}

#tableHead {
  display: flex;
  border-bottom: 1px solid var(--border);
  flex: 0 0 auto;
  font-size: 12px;
  font-weight: 700;
  color: var(--txt);
  /* No native scrollbar here -- its horizontal position is driven by JS
     (synced to #tableViewport's scrollLeft on scroll) so the header stays
     aligned with the columns as the operator scrolls the rows sideways. */
  overflow-x: hidden;
  /* Positioning context for #acctResizeHandle below (position:absolute
     needs an ancestor other than the initial containing block). */
  position: relative;
}
#tableHead > div {
  padding: 10px 10px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#tableHead > div.sortable {
  cursor: pointer;
  user-select: none;
}
#tableHead > div.sortable:hover {
  color: rgb(var(--skid-accent-rgb));
}

#tableViewport {
  flex: 1 1 auto;
  overflow-y: auto;
  overflow-x: auto;
  position: relative;
  /* Opaque backing on THIS scroll layer. will-change:transform below promotes
     the viewport to its own GPU layer; a composited layer only gets crisp LCD
     subpixel text (ClearType) when it has an opaque background -- without this
     the layer was transparent, so WebView2 fell back to grayscale AA and
     COLOURED text (green "Success", themed headings) rendered soft while white
     stayed legible. Same colour as the #tableWrap behind it, so no visual
     change -- just crisp text. */
  background: var(--panel);
  /* GPU compositing hint: promote to its own layer so scroll doesn't
     repaint siblings -- this + WebView2's Chromium compositor is what
     actually delivers smooth scroll, unlike Tk's software rasterizer. */
  will-change: transform;
  contain: strict;
  /* tabindex="0" in the HTML makes this focusable, so Ctrl+C/Delete/Ctrl+A
     reliably route to our keydown handler once the operator has clicked
     into the table, instead of depending on whatever WebView2 decided has
     focus when the window first opened. No visible focus ring needed --
     row selection itself is the visual feedback. */
  outline: none;
}
/* No position/width here on purpose: #tableSpacer only exists so JS can set
   its `height` (total virtualized scroll length). It used to also have
   `position: relative`, which made it the containing block for #tableRows
   below (position:absolute; left:0; right:0) -- so #tableRows, and every row
   inside it, was sized against #tableSpacer's own box instead of the full
   viewport width. That capped every row (including .trow.selected) to 1px
   wide: text still rendered because overflow spills out of a 1px box, but
   the selected-row background fill had almost nothing to paint into, leaving
   only the inset box-shadow sliver visible. Leaving position unset here lets
   #tableRows's absolute positioning resolve against #tableViewport (which
   does have position:relative) instead, giving it the correct full width. */
#tableSpacer { width: 1px; }
#tableRows {
  position: absolute;
  top: 0; left: 0;
  /* min-width keeps rows filling the full viewport (and .trow.selected's
     background painting correctly) when columns fit; width:max-content lets
     the row grow past the viewport when they don't (a wide Account column,
     long URLs, etc.) instead of clipping -- #tableViewport's overflow-x:auto
     then gives that extra width an actual horizontal scrollbar. */
  min-width: 100%;
  width: max-content;
  /* No will-change:transform here on purpose: it used to promote #tableRows to
     its OWN (transparent) composited layer, which forced grayscale text AA and
     softened coloured text. Letting the rows paint into #tableViewport's opaque
     layer instead restores crisp LCD subpixel rendering. The viewport already
     composites the scroll, so smoothness is unaffected. */
}

.trow {
  display: flex;
  height: var(--row-h);
  align-items: center;
  font-size: 12px;
  font-family: Consolas, monospace;
  border-bottom: 1px solid rgba(255,255,255,0.03);
  /* Selection here is a JS-tracked row model (see selectedRows), not raw
     browser text selection -- disable native text-drag so a plain click+drag
     reads as "select these rows" (like a Treeview) instead of highlighting
     characters underneath it. Full account text is still one Ctrl+C away. */
  user-select: none;
  -webkit-user-select: none;
  -webkit-user-drag: none;
  cursor: default;
}
.trow > div {
  padding: 0 10px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.trow.checking .c-status { color: var(--accent); }
/* Strong, unmistakable highlight -- solid-ish fill + left accent bar -- so
   selection reads clearly even under the Neon/Vivid background glow layered
   on top of the table (a subtle tint alone was getting washed out there). */
.trow.selected {
  background: rgba(var(--skid-accent-rgb), 0.32);
  box-shadow: inset 3px 0 0 rgb(var(--skid-accent-rgb));
}

.col-idx { width: 48px; flex: 0 0 auto; color: var(--mute); }
/* Account column: matches the original's 380px width + stretch=True (the
   only tree column that grows to absorb extra space) -- was 180px min here,
   which truncated far more aggressively than the original ever did. */
/* User-resizable (drag #acctResizeHandle): a fixed width driven by
   --acct-col-width, not flex-grow, so a drag reliably sets an exact size
   instead of fighting the flex algorithm. Defaults wider than the original's
   380px since the operator asked to read full accounts, not just more of
   them; persisted to localStorage so the choice survives a relaunch. */
.col-account { flex: 0 0 var(--acct-col-width, 520px); width: var(--acct-col-width, 520px); min-width: 160px;
  /* the account line in each result/processing row -- bold + larger so it's
     easy to read while a batch runs (both Dark and Bright modes). */
  font-size: 14px; font-weight: 700; }
/* position:absolute (not a flex child) so it takes ZERO space in the header's
   flex layout -- the data rows have no equivalent element between Account
   and Status, so as a normal flex child this pushed every header from
   Status onward out of alignment with its data column. Worse than the
   nominal 6px flex-basis suggests: it also inherits #tableHead > div's
   padding:10px 10px, and flexbox's default min-width:auto won't let a flex
   item shrink below its own padding even with box-sizing:border-box, so it
   was rendering at a full 20px wide, not 6px -- confirmed via
   getBoundingClientRect() (20px measured offset between every header and
   its data column). Taking it out of flow entirely and positioning it
   exactly on the Account/Status boundary fixes both the width AND the
   offset in one change, rather than just shrinking the offset. */
/* #tableHead > #acctResizeHandle (ID+ID, specificity 200), not the plain
   #acctResizeHandle (ID-only, 100) used above for the layout-critical
   rules -- #tableHead > div's generic padding:10px 10px has specificity
   101 (ID + type), which otherwise wins over a bare ID selector and
   silently keeps this at the old oversized 20px even with padding:0
   written right here. */
#tableHead > #acctResizeHandle {
  position: absolute;
  top: 0; bottom: 0;
  left: calc(48px + var(--acct-col-width, 520px) - 3px);
  width: 6px;
  padding: 0;
  cursor: col-resize;
  z-index: 2;
}
#acctResizeHandle::after {
  content: "";
  position: absolute;
  top: 20%; bottom: 20%; left: 2px;
  width: 2px;
  background: var(--border);
  border-radius: 2px;
}
#acctResizeHandle:hover::after, #acctResizeHandle.resizing::after {
  background: rgb(var(--skid-accent-rgb));
}
.col-status { width: 210px; flex: 0 0 auto; font-weight: 600; }
.col-region { width: 80px; flex: 0 0 auto; }
.col-created { width: 150px; flex: 0 0 auto; }
.col-pwchg { width: 110px; flex: 0 0 auto; }
.col-family { width: 70px; flex: 0 0 auto; }
.col-rescue { width: 100px; flex: 0 0 auto; }
.col-devices { width: 160px; flex: 0 0 auto; }
.col-store { width: 110px; flex: 0 0 auto; }
.col-icloud { width: 180px; flex: 0 0 auto; }
.col-phfirst { width: 110px; flex: 0 0 auto; }
.col-phlast { width: 120px; flex: 0 0 auto; }
.col-phcountry { width: 80px; flex: 0 0 auto; }
.col-phbalance { width: 110px; flex: 0 0 auto; }
.col-giftcheck { width: 200px; flex: 0 0 auto; }
.col-gift { width: 160px; flex: 0 0 auto; }
.col-iclean { width: 150px; flex: 0 0 auto; }
.col-purchases { width: 320px; flex: 0 0 auto; text-align: left;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.col-rmpay { width: 120px; flex: 0 0 auto; }
.col-rmsub { width: 140px; flex: 0 0 auto; }
.col-rmdev { width: 120px; flex: 0 0 auto; }
.col-lang { width: 180px; flex: 0 0 auto; }
.col-rmresc { width: 130px; flex: 0 0 auto; }

/* Dynamic columns: show only the data the run's ticked functions produce.
   These classes are toggled on #tableWrap (applyColumnVisibility in app.js),
   and because both #tableHead and every .trow live inside #tableWrap, the
   header and body columns hide/show together and stay aligned. */
#tableWrap:not(.show-region) .col-region { display: none; }
#tableWrap:not(.show-enrich) .col-created,
#tableWrap:not(.show-enrich) .col-pwchg,
#tableWrap:not(.show-enrich) .col-family,
#tableWrap:not(.show-enrich) .col-rescue,
#tableWrap:not(.show-enrich) .col-devices { display: none; }
#tableWrap:not(.show-store) .col-store { display: none; }
#tableWrap:not(.show-icloud) .col-icloud { display: none; }
#tableWrap:not(.show-purchases) .col-purchases { display: none; }
#tableWrap:not(.show-iclean) .col-iclean { display: none; }
#tableWrap:not(.show-gift) .col-gift { display: none; }
#tableWrap:not(.show-giftcheck) .col-giftcheck { display: none; }
#tableWrap:not(.show-phinfo) .col-phfirst,
#tableWrap:not(.show-phinfo) .col-phlast,
#tableWrap:not(.show-phinfo) .col-phcountry,
#tableWrap:not(.show-phinfo) .col-phbalance { display: none; }
#tableWrap:not(.show-rmpay) .col-rmpay { display: none; }
#tableWrap:not(.show-rmsub) .col-rmsub { display: none; }
#tableWrap:not(.show-rmdev) .col-rmdev { display: none; }
#tableWrap:not(.show-lang) .col-lang { display: none; }
#tableWrap:not(.show-rmresc) .col-rmresc { display: none; }

/* Center the value columns' text under their headers (both #tableHead and
   .trow share the .col-* classes, so header + body line up). Account and
   Status stay left-aligned (Status has its leading status dot). */
#tableHead > .col-region, #tableHead > .col-created, #tableHead > .col-pwchg,
#tableHead > .col-family, #tableHead > .col-rescue, #tableHead > .col-devices,
#tableHead > .col-store, #tableHead > .col-icloud,
#tableHead > .col-phfirst, #tableHead > .col-phlast,
#tableHead > .col-phcountry, #tableHead > .col-phbalance,
#tableHead > .col-rmpay, #tableHead > .col-rmsub, #tableHead > .col-rmdev,
#tableHead > .col-lang, #tableHead > .col-rmresc,
.trow > .col-region, .trow > .col-created, .trow > .col-pwchg,
.trow > .col-family, .trow > .col-rescue, .trow > .col-devices,
.trow > .col-store, .trow > .col-icloud,
.trow > .col-phfirst, .trow > .col-phlast,
.trow > .col-phcountry, .trow > .col-phbalance, .trow > .col-iclean, .trow > .col-gift,
.trow > .col-giftcheck, #tableHead > .col-giftcheck,
#tableHead > .col-iclean, #tableHead > .col-gift,
.trow > .col-rmpay, .trow > .col-rmsub, .trow > .col-rmdev,
.trow > .col-lang, .trow > .col-rmresc { text-align: center; }

.status-dot {
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  margin-right: 7px;
}

/* Themed scrollbars (WebView2/Chromium). One consistent look across the table,
   the left panel, and every text well (accounts paste box, gift/2FA fields) --
   a panel-coloured thumb on a transparent track, lit to the live theme accent on
   hover, so it reads as part of the app chrome, not a raw grey OS scrollbar. */
#tableViewport::-webkit-scrollbar, #leftScroll::-webkit-scrollbar,
#accounts::-webkit-scrollbar, .txt-area-small::-webkit-scrollbar,
#giftcodeBox::-webkit-scrollbar { width: 10px; height: 10px; }
#tableViewport::-webkit-scrollbar-thumb, #leftScroll::-webkit-scrollbar-thumb,
#accounts::-webkit-scrollbar-thumb, .txt-area-small::-webkit-scrollbar-thumb,
#giftcodeBox::-webkit-scrollbar-thumb {
  background: var(--card2);
  border: 2px solid transparent;
  background-clip: padding-box;
  border-radius: 7px;
}
#tableViewport::-webkit-scrollbar-thumb:hover, #leftScroll::-webkit-scrollbar-thumb:hover,
#accounts::-webkit-scrollbar-thumb:hover, .txt-area-small::-webkit-scrollbar-thumb:hover,
#giftcodeBox::-webkit-scrollbar-thumb:hover { background: rgb(var(--skid-accent-rgb)); }
#tableViewport::-webkit-scrollbar-track, #leftScroll::-webkit-scrollbar-track,
#accounts::-webkit-scrollbar-track, .txt-area-small::-webkit-scrollbar-track,
#giftcodeBox::-webkit-scrollbar-track { background: transparent; }
/* retro (iTunes) theme: brushed-metal thumb to match the beveled chrome */
:root[data-theme="retro"] #tableViewport::-webkit-scrollbar-thumb,
:root[data-theme="retro"] #leftScroll::-webkit-scrollbar-thumb,
:root[data-theme="retro"] #accounts::-webkit-scrollbar-thumb {
  background: linear-gradient(var(--r-btn-top), var(--r-btn-bot));
  border: 1px solid var(--r-btn-line);
}

/* ---------- styled confirmation modal (re-process guard, backup failure) ----
   Replaces native window.confirm()/alert(), which would look completely out
   of place -- matches the app's own dark/card design instead. */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.62);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 200;
}
.modal-overlay.open { display: flex; }
.modal-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 22px 24px;
  max-width: 460px;
  width: 90%;
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.65);
}
.modal-title { font-size: 16px; font-weight: 700; margin-bottom: 12px; color: var(--txt); }
.modal-body {
  font-size: 13px;
  color: var(--txt);
  white-space: pre-wrap;
  line-height: 1.55;
  margin-bottom: 20px;
}
.modal-actions { display: flex; gap: 10px; justify-content: flex-end; }
.modal-actions button {
  padding: 9px 18px;
  border-radius: 8px;
  border: none;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
}
.modal-actions button.primary { background: var(--txt); color: var(--bg); }
.modal-actions button.secondary { background: var(--card2); color: var(--txt); border: 1px solid var(--border); }
.modal-actions button.cancel { background: transparent; color: var(--mute); }
.modal-actions button.secondary:hover { background: var(--border); }
.modal-actions button.cancel:hover { color: var(--txt); }

/* ---------- themed scrollbars (WebView2 = Chromium) ----------------------------
   Match the active theme's palette instead of the default grey OS bar; adapts to
   light/dark automatically since it's driven off the theme CSS variables. The
   intentionally-hidden bars (#pills) keep their own display:none rule (ID wins). */
* { scrollbar-width: thin; scrollbar-color: var(--border) transparent; }
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 8px;
  border: 3px solid transparent;
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover {
  background: rgba(var(--skid-accent-rgb), 0.75);
  background-clip: padding-box;
}
::-webkit-scrollbar-corner { background: transparent; }

/* ---------- online-update countdown banner (non-blocking) ---------------------- */
.update-banner {
  display: none;
  position: fixed;
  top: 16px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 5000;
  align-items: center;
  gap: 14px;
  max-width: 92vw;
  padding: 10px 15px;
  border-radius: 10px;
  background: var(--card);
  border: 1px solid rgba(var(--skid-accent-rgb), 0.55);
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.45);
  color: var(--txt);
  font-size: 13px;
}
.update-banner.show { display: flex; }
.update-banner-msg { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.update-banner #updateCountdown {
  font-variant-numeric: tabular-nums;
  color: rgb(var(--skid-accent-rgb));
  font-weight: 700;
  min-width: 46px;
  text-align: center;
}
.update-now-btn {
  border: none;
  border-radius: 8px;
  padding: 7px 15px;
  font-weight: 700;
  cursor: pointer;
  background: rgb(var(--skid-accent-rgb));
  color: #06181c;
  white-space: nowrap;
}
.update-now-btn:hover { filter: brightness(1.08); }
.update-now-btn:disabled { opacity: 0.6; cursor: default; }

/* #licenseGate reuses .modal-overlay/.modal-card verbatim (see index.html);
   these are the two license-specific tweaks on top of that shared shell. */
.license-key-input { text-align: center; letter-spacing: 0.5px; margin-top: 4px; }
.license-error {
  font-size: 12.5px;
  color: var(--red);
  min-height: 16px;
  margin: 6px 0 4px;
}

/* ---------- buy-license (crypto) panel -- reuses .modal-overlay/.modal-card,
   adds its own picker/payment-screen bits on top. */
.buy-license-actions { justify-content: space-between; align-items: center; }
button.link-btn {
  background: none;
  border: none;
  color: var(--mute);
  font-size: 12.5px;
  cursor: pointer;
  padding: 9px 0;
  text-decoration: underline;
}
button.link-btn:hover { color: var(--txt); }

/* #buyLicensePanel shows exactly one of .buy-step-pick/.buy-step-pay,
   selected by the card's own data-step attribute -- avoids a second,
   separate modal-overlay stacking on top of this one for the second screen. */
.buy-step { display: none; }
#buyLicensePanel[data-step="pick"] .buy-step-pick { display: block; }
#buyLicensePanel[data-step="pay"] .buy-step-pay { display: block; }

.buy-option-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 14px;
}
.buy-option {
  flex: 1 1 calc(50% - 8px);
  background: var(--card2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 9px 12px;
  font-size: 12.5px;
  color: var(--txt);
  cursor: pointer;
  text-align: center;
  user-select: none;
}
.buy-option:hover { background: var(--border); }
.buy-option.selected { border-color: var(--txt); background: var(--border); font-weight: 600; }
.buy-option .buy-option-sub { display: block; color: var(--mute); font-size: 11px; margin-top: 2px; }
.buy-option-logo {
  width: 20px;
  height: 20px;
  vertical-align: middle;
  margin-right: 6px;
  flex: 0 0 auto;
}
.buy-option-inner { display: flex; align-items: center; justify-content: center; gap: 0; }
.buy-option-badge-wrap { position: relative; display: inline-flex; flex: 0 0 auto; margin-right: 6px; }
.buy-option-badge-wrap .buy-option-logo { margin-right: 0; }
.buy-option-badge {
  position: absolute;
  right: -5px;
  bottom: -5px;
  width: 12px;
  height: 12px;
}

.buy-pay-qr-row { display: flex; gap: 16px; margin-bottom: 6px; align-items: flex-start; }
.buy-pay-qr {
  flex: 0 0 auto;
  width: 108px;
  height: 108px;
  background: #fff;
  border-radius: 8px;
  padding: 6px;
}
.buy-pay-fields { flex: 1; min-width: 0; }
#buyOpenBinanceBtn { width: 100%; margin-top: 4px; }

.buy-pay-field { margin-bottom: 14px; }
.buy-pay-label { display: block; font-size: 11.5px; color: var(--mute); margin-bottom: 4px; }
.buy-pay-value-row { display: flex; align-items: center; gap: 8px; }
.buy-pay-value {
  flex: 1;
  background: var(--card2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 10px;
  font-size: 13px;
  word-break: break-all;
  color: var(--txt);
}
.buy-pay-address { font-size: 12px; }
.buy-pay-range { font-size: 11px; color: var(--mute); margin-top: 4px; }
button.copy-btn {
  flex: 0 0 auto;
  background: var(--card2);
  border: 1px solid var(--border);
  color: var(--txt);
  border-radius: 8px;
  padding: 8px 12px;
  font-size: 12px;
  cursor: pointer;
}
button.copy-btn:hover { background: var(--border); }
.buy-pay-status {
  font-size: 12.5px;
  color: var(--mute);
  margin-bottom: 4px;
  min-height: 16px;
}
.buy-pay-status.success { color: var(--green); }
.buy-pay-status.error { color: var(--red); }

/* ============================================================================
   RETRO (iTunes / iPhone 4) — skeuomorphic theme. Selected from the Theme menu
   (sets data-theme="retro"); renders graphite metal in Dark mode and brushed
   aluminium in Bright mode. Scoped so it never touches any other theme.
   ========================================================================== */
:root[data-theme="retro"][data-mode="dark"] {
  --r-app-top:#3a3d42; --r-app-bot:#1c1d20; --r-pin:rgba(255,255,255,.02);
  --r-bar-top:#575b61; --r-bar-bot:#2e3136; --r-bar-line:#0c0d0f; --r-bar-hi:rgba(255,255,255,.18);
  --r-panel-top:#303338; --r-panel-bot:#26282c; --r-panel-hi:rgba(255,255,255,.08); --r-panel-line:#111214;
  --r-well-top:#141518; --r-well-bot:#1c1e21; --r-well-line:#000; --r-well-hi:rgba(255,255,255,.06);
  --r-txt:#e9eaec; --r-mute:#9a9da3; --r-emboss:rgba(0,0,0,.7);
  --r-row-a:#2b2d31; --r-row-b:#26282c; --r-row-sep:rgba(0,0,0,.45); --r-row-hi:rgba(255,255,255,.045);
  --r-btn-top:#5b5f65; --r-btn-bot:#34373c; --r-btn-line:#101113; --r-btn-hi:rgba(255,255,255,.28);
}
:root[data-theme="retro"][data-mode="light"] {
  --r-app-top:#e2e5ea; --r-app-bot:#c2c6cd; --r-pin:rgba(0,0,0,.015);
  --r-bar-top:#f4f6f8; --r-bar-bot:#cdd1d7; --r-bar-line:#9298a0; --r-bar-hi:rgba(255,255,255,.9);
  --r-panel-top:#fbfcfd; --r-panel-bot:#e7eaee; --r-panel-hi:rgba(255,255,255,.95); --r-panel-line:#b7bcc3;
  --r-well-top:#ffffff; --r-well-bot:#f2f4f6; --r-well-line:#b7bcc3; --r-well-hi:rgba(255,255,255,1);
  --r-txt:#20242a; --r-mute:#6c727a; --r-emboss:rgba(255,255,255,.9);
  --r-row-a:#ffffff; --r-row-b:#eef1f4; --r-row-sep:rgba(0,0,0,.12); --r-row-hi:rgba(255,255,255,.9);
  --r-btn-top:#ffffff; --r-btn-bot:#d6dae0; --r-btn-line:#9298a0; --r-btn-hi:rgba(255,255,255,1);
}
:root[data-theme="retro"] body,
:root[data-theme="retro"] #main {
  font-family:"Helvetica Neue","Lucida Grande","Segoe UI",Arial,sans-serif;
}
:root[data-theme="retro"] body {
  background:
    repeating-linear-gradient(var(--r-pin), var(--r-pin) 1px, transparent 1px, transparent 3px),
    linear-gradient(var(--r-app-top), var(--r-app-bot)) fixed;
  color:var(--r-txt);
}
/* brushed-metal header + embossed brand */
:root[data-theme="retro"] #header {
  background:linear-gradient(var(--r-bar-top), var(--r-bar-bot));
  border-bottom:1px solid var(--r-bar-line);
  box-shadow: inset 0 1px 0 var(--r-bar-hi), 0 2px 5px rgba(0,0,0,.25);
}
:root[data-theme="retro"] #brand > span:first-child {
  color:var(--r-txt); text-shadow:0 1px 0 var(--r-emboss); letter-spacing:.5px;
}
/* glossy status pills with glowing LED dots */
:root[data-theme="retro"] .pill {
  color:var(--r-txt); text-shadow:0 1px 0 var(--r-emboss);
  background:linear-gradient(var(--r-btn-top), var(--r-btn-bot));
  border:1px solid var(--r-btn-line);
  box-shadow: inset 0 1px 0 var(--r-btn-hi), 0 1px 2px rgba(0,0,0,.3);
}
:root[data-theme="retro"] .pill .dot {
  box-shadow: inset 0 1px 1px rgba(255,255,255,.6), 0 1px 1px rgba(0,0,0,.4);
}
/* glossy header buttons */
:root[data-theme="retro"] #fxBtn,
:root[data-theme="retro"] #themeBtn,
:root[data-theme="retro"] #langBtn,
:root[data-theme="retro"] #modeBtn {
  color:var(--r-txt); text-shadow:0 1px 0 var(--r-emboss);
  background:linear-gradient(var(--r-btn-top), var(--r-btn-bot));
  border:1px solid var(--r-btn-line);
  box-shadow: inset 0 1px 0 var(--r-btn-hi), 0 1px 2px rgba(0,0,0,.3);
}
:root[data-theme="retro"] h3.section { text-shadow:0 1px 0 var(--r-emboss); }
:root[data-theme="retro"] .func-group-title { text-shadow:0 1px 0 var(--r-emboss); }
/* inset "well" textarea + inputs */
:root[data-theme="retro"] #accounts,
:root[data-theme="retro"] .txt,
:root[data-theme="retro"] .txt-area-small,
:root[data-theme="retro"] #giftcodeBox {
  color:var(--r-txt);
  background:linear-gradient(var(--r-well-top), var(--r-well-bot));
  border:1px solid var(--r-well-line);
  box-shadow: inset 0 2px 5px rgba(0,0,0,.5), inset 0 -1px 0 var(--r-well-hi);
}
/* beveled panels + table */
:root[data-theme="retro"] #tableWrap,
:root[data-theme="retro"] #progressBar {
  background:linear-gradient(var(--r-panel-top), var(--r-panel-bot));
  border:1px solid var(--r-panel-line);
  box-shadow: inset 0 1px 0 var(--r-panel-hi), 0 2px 6px rgba(0,0,0,.28);
}
:root[data-theme="retro"] #tableViewport { background:transparent; }
/* glossy function rows */
:root[data-theme="retro"] .func-row {
  text-shadow:0 1px 0 var(--r-emboss);
  background:linear-gradient(var(--r-row-a), var(--r-row-b));
  border:1px solid var(--r-panel-line);
  box-shadow: inset 0 1px 0 var(--r-row-hi), 0 1px 2px rgba(0,0,0,.2);
}
/* glossy buttons (Start green / Stop red / secondary / danger) */
:root[data-theme="retro"] .primary,
:root[data-theme="retro"] .stop,
:root[data-theme="retro"] .secondary,
:root[data-theme="retro"] .danger {
  border:1px solid var(--r-btn-line); text-shadow:0 -1px 0 rgba(0,0,0,.35);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.4), 0 2px 4px rgba(0,0,0,.3);
}
:root[data-theme="retro"] .primary { color:#fff; background:linear-gradient(#7ed36a,#3f9a34); border-color:#2c7422; }
/* Start button while a run is in flight (disabled): must NOT keep the lit green
   "clickable" look. Fall back to the neutral metal button face, dimmed, with a
   not-allowed cursor -- clearly inert. */
:root[data-theme="retro"] .primary:disabled {
  color: var(--r-mute); cursor: not-allowed; opacity: .6; text-shadow: none;
  background: linear-gradient(var(--r-btn-top), var(--r-btn-bot));
  border-color: var(--r-btn-line);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.25);
}
:root[data-theme="retro"] .stop { color:#fff; background:linear-gradient(#f08a7a,#c33a2a); border-color:#8f2418; }
:root[data-theme="retro"] .secondary,
:root[data-theme="retro"] .danger { color:var(--r-txt); text-shadow:0 1px 0 var(--r-emboss); background:linear-gradient(var(--r-btn-top), var(--r-btn-bot)); }
/* iTunes list header + rows */
:root[data-theme="retro"] #tableHead {
  color:var(--r-mute); text-shadow:0 1px 0 var(--r-emboss);
  background:linear-gradient(var(--r-bar-top), var(--r-bar-bot));
  border-bottom:1px solid var(--r-bar-line); box-shadow: inset 0 1px 0 var(--r-bar-hi);
}
:root[data-theme="retro"] .trow {
  text-shadow:0 1px 0 var(--r-emboss);
  border-bottom:1px solid var(--r-row-sep); box-shadow: inset 0 1px 0 var(--r-row-hi);
  background:linear-gradient(var(--r-row-a), var(--r-row-b));
}
:root[data-theme="retro"] .trow:nth-child(even) { background:linear-gradient(var(--r-row-b), var(--r-row-a)); }
:root[data-theme="retro"] .trow.selected {
  color:#fff !important;
  background:linear-gradient(#5aa2f0, #2f6fc0);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.35);
}
/* progress fill = classic candy stripe */
:root[data-theme="retro"] #pbarFill {
  background:
    repeating-linear-gradient(45deg, rgba(255,255,255,.18) 0 10px, rgba(255,255,255,0) 10px 20px),
    linear-gradient(#8fd0ff, #3d86d6);
}
:root[data-theme="retro"] #pbarTrack {
  background:linear-gradient(var(--r-well-top), var(--r-well-bot));
  border:1px solid var(--r-well-line); box-shadow: inset 0 1px 3px rgba(0,0,0,.5);
}
/* dropdown menus + modal in retro metal */
:root[data-theme="retro"] .lang-menu,
:root[data-theme="retro"] .modal {
  background:linear-gradient(var(--r-panel-top), var(--r-panel-bot));
  border:1px solid var(--r-panel-line);
  box-shadow: inset 0 1px 0 var(--r-panel-hi), 0 8px 24px rgba(0,0,0,.5);
}
:root[data-theme="retro"] .lang-item { text-shadow:0 1px 0 var(--r-emboss); }

/* ═══════════════════════════════════════════════════════════════════════════
   LIGHT VERSION  (:root[data-lite="1"])  —  toggled from the Theme menu.
   A deliberately plain "classic Windows / old Internet Explorer" skin whose
   real purpose is SPEED. It strips every GPU/paint-heavy effect the normal
   themes layer on — the spinning conic light border, the bgGlow starfield/
   neon field, all ~45 CSS animations, 38 box-shadows, 15 text-shadows, every
   filter/transition and rounded corner. At high thread counts the results grid
   repaints constantly; removing per-frame shadow/animation/composite work is
   what actually makes the UI feel fast. This changes only colour, border and
   effects — layout (flex/grid/sizing) is untouched, and the virtualised table
   renderer (requestAnimationFrame) is left alone so results still draw, just
   far cheaper per row. */

/* 1) classic Win9x/IE palette — override the design tokens once and every
      surface that reads --bg/--panel/--card/--border/--txt/--accent flips. */
:root[data-lite="1"] {
  --bg:      #c0c0c0;   /* silver dialog background (ButtonFace)   */
  --panel:   #ffffff;   /* white content area, like an IE page     */
  --card:    #c0c0c0;   /* gray toolbar/card                       */
  --card2:   #d4d0c8;   /* classic "3D objects" gray               */
  --border:  #808080;   /* 3D shadow edge                          */
  --txt:     #000000;
  --mute:    #404040;
  --accent:  #000080;   /* navy — the classic Windows highlight    */
  --green:   #008000;
  --amber:   #808000;
  --red:     #b00000;
  --orange:  #a83c00;
  --grey:    #606060;
  --skid-accent-rgb: 0, 0, 128;
  --skid-glow: 0;       /* belt-and-braces: light border fully off */
}

/* 2) kill every animation / shadow / filter / rounded corner in one sweep —
      the bulk of the speed win: WebView2 stops compositing and re-painting
      decorative layers on each result-row update. */
:root[data-lite="1"] *,
:root[data-lite="1"] *::before,
:root[data-lite="1"] *::after {
  animation: none !important;
  transition: none !important;
  box-shadow: none !important;
  text-shadow: none !important;
  filter: none !important;
  -webkit-filter: none !important;
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
  border-radius: 0 !important;
  will-change: auto !important;
  mix-blend-mode: normal !important;
}

/* 3) drop the two pure-decoration layers entirely so they cost nothing. */
:root[data-lite="1"] #lightborder,
:root[data-lite="1"] #bgGlow { display: none !important; }

/* 4) plain system typography — the old MS Sans Serif / Tahoma dialog font. */
:root[data-lite="1"] body,
:root[data-lite="1"] button,
:root[data-lite="1"] input,
:root[data-lite="1"] textarea,
:root[data-lite="1"] select {
  font-family: Tahoma, "MS Sans Serif", "Segoe UI", sans-serif;
  letter-spacing: 0 !important;
}
:root[data-lite="1"] body { background: #c0c0c0; }

/* 5) 3D bevels: raised gray buttons + sunken white fields — the unmistakable
      Win9x/IE control look. Bevel colours are drawn on the border itself
      (top/left light, bottom/right dark) since box-shadow bevels are killed. */
:root[data-lite="1"] button,
:root[data-lite="1"] .primary,
:root[data-lite="1"] .stop,
:root[data-lite="1"] .link-btn,
:root[data-lite="1"] .copy-btn {
  background: #c0c0c0 !important;
  color: #000000 !important;
  border: 2px solid !important;
  border-color: #ffffff #808080 #808080 #ffffff !important;
  border-radius: 0 !important;
}
:root[data-lite="1"] button:active:not(:disabled),
:root[data-lite="1"] .primary:active:not(:disabled),
:root[data-lite="1"] .stop:active:not(:disabled) {
  border-color: #808080 #ffffff #ffffff #808080 !important;
}
:root[data-lite="1"] button:disabled { color: #808080 !important; }

:root[data-lite="1"] input,
:root[data-lite="1"] textarea,
:root[data-lite="1"] select {
  background: #ffffff !important;
  color: #000000 !important;
  border: 2px solid !important;
  border-color: #808080 #ffffff #ffffff #808080 !important;
  border-radius: 0 !important;
}

/* 6) classic navy selection + active menu rows. */
:root[data-lite="1"] ::selection { background: #000080; color: #ffffff; }
:root[data-lite="1"] .lang-item.active,
:root[data-lite="1"] .theme-item.active { background: #000080 !important; color: #ffffff !important; }

/* 7) chunky beveled scrollbars in place of the themed thin ones. */
:root[data-lite="1"] ::-webkit-scrollbar { width: 16px; height: 16px; background: #c0c0c0; }
:root[data-lite="1"] ::-webkit-scrollbar-thumb {
  background: #c0c0c0; border: 2px solid;
  border-color: #ffffff #808080 #808080 #ffffff; border-radius: 0;
}
:root[data-lite="1"] ::-webkit-scrollbar-track { background: #dcdcdc; }

/* Purchase history: clickable "(+N)" opens the full list in a modal.
   The whole list is already on the client (purchase_detail) — no re-fetch. */
.col-purchases .ph-more {
  color: rgb(var(--skid-accent-rgb, 66, 232, 224));
  cursor: pointer;
  text-decoration: underline;
  white-space: nowrap;
}
.col-purchases .ph-more:hover { opacity: .8; }
.ph-modal-list {
  max-height: 55vh;
  overflow: auto;
  text-align: left;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
}
.ph-modal-line {
  padding: 5px 10px;
  font-size: 12px;
  white-space: pre;
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
  color: var(--txt);
  border-bottom: 1px solid var(--border);
}
.ph-modal-line:first-child { position: sticky; top: 0; background: var(--card2); font-weight: 600; z-index: 1; }
.ph-modal-line:last-child { border-bottom: none; }
