:root {
  --win-color: #2ecc71;
  --loss-color: #e74c3c;
  --text-color: #ffffff;
  --bg-color: rgba(0, 0, 0, 0.55);
  --accent: #f1c40f;
  --control-border: rgba(255, 255, 255, 0.25);
  --control-bg: rgba(255, 255, 255, 0.08);
  --control-bg-hover: rgba(255, 255, 255, 0.18);
  --panel-shadow: 0 4px 18px rgba(0, 0, 0, 0.35);
}

html[data-theme="light"] {
  --win-color: #16a34a;
  --loss-color: #dc2626;
  --text-color: #1f2937;
  --bg-color: rgba(255, 255, 255, 0.9);
  --accent: #d97706;
  --control-border: rgba(0, 0, 0, 0.2);
  --control-bg: rgba(0, 0, 0, 0.05);
  --control-bg-hover: rgba(0, 0, 0, 0.1);
  --panel-shadow: 0 4px 18px rgba(0, 0, 0, 0.18);
}

html[data-theme="neon"] {
  --win-color: #39ff88;
  --loss-color: #ff2e6c;
  --text-color: #e8faff;
  --bg-color: rgba(6, 6, 20, 0.6);
  --accent: #00e5ff;
  --control-border: rgba(0, 229, 255, 0.35);
  --control-bg: rgba(0, 229, 255, 0.08);
  --control-bg-hover: rgba(0, 229, 255, 0.18);
  --panel-shadow: 0 0 24px rgba(0, 229, 255, 0.25);
}

html[data-theme="minimal"] {
  --win-color: #4ade80;
  --loss-color: #f87171;
  --text-color: #ffffff;
  --bg-color: transparent;
  --accent: #facc15;
  --control-border: rgba(255, 255, 255, 0.4);
  --control-bg: rgba(0, 0, 0, 0.35);
  --control-bg-hover: rgba(0, 0, 0, 0.5);
  --panel-shadow: none;
}

html[data-theme="lightning"] {
  --win-color: #c6ff4d;
  --loss-color: #ff4d6d;
  --text-color: #eaf6ff;
  --bg-color: rgba(8, 13, 28, 0.82);
  --accent: #7dd3fc;
  --control-border: rgba(125, 211, 252, 0.35);
  --control-bg: rgba(125, 211, 252, 0.08);
  --control-bg-hover: rgba(125, 211, 252, 0.18);
  --panel-shadow: 0 0 22px rgba(56, 189, 248, 0.18);
}

html[data-theme="aurora"] {
  --win-color: #4ade80;
  --loss-color: #f472b6;
  --text-color: #eafff5;
  --bg-color: rgba(8, 14, 28, 0.75);
  --accent: #7dd3fc;
  --control-border: rgba(125, 211, 252, 0.35);
  --control-bg: rgba(125, 211, 252, 0.08);
  --control-bg-hover: rgba(125, 211, 252, 0.18);
  --panel-shadow: 0 0 30px rgba(94, 234, 212, 0.18);
}

html[data-theme="inferno"] {
  --win-color: #fb923c;
  --loss-color: #f43f5e;
  --text-color: #fff1e6;
  --bg-color: rgba(20, 6, 4, 0.82);
  --accent: #fbbf24;
  --control-border: rgba(251, 191, 36, 0.35);
  --control-bg: rgba(251, 146, 60, 0.08);
  --control-bg-hover: rgba(251, 146, 60, 0.2);
  --panel-shadow: 0 0 26px rgba(251, 146, 60, 0.25);
}

html[data-theme="synthwave"] {
  --win-color: #36f9c5;
  --loss-color: #ff4d9d;
  --text-color: #fdf0ff;
  --bg-color: rgba(26, 10, 46, 0.85);
  --accent: #ff6ac1;
  --control-border: rgba(255, 106, 193, 0.4);
  --control-bg: rgba(124, 58, 237, 0.12);
  --control-bg-hover: rgba(124, 58, 237, 0.25);
  --panel-shadow: 0 0 26px rgba(255, 106, 193, 0.3);
}

html[data-theme="bubblegum"] {
  --win-color: #22c55e;
  --loss-color: #fb7185;
  --text-color: #4a1d3f;
  --bg-color: rgba(255, 228, 245, 0.9);
  --accent: #ec4899;
  --control-border: rgba(236, 72, 153, 0.35);
  --control-bg: rgba(236, 72, 153, 0.1);
  --control-bg-hover: rgba(236, 72, 153, 0.22);
  --panel-shadow: 0 6px 22px rgba(236, 72, 153, 0.25);
}

html[data-theme="galaxy"] {
  --win-color: #67e8f9;
  --loss-color: #f472b6;
  --text-color: #e5e7ff;
  --bg-color: rgba(10, 8, 30, 0.88);
  --accent: #a78bfa;
  --control-border: rgba(167, 139, 250, 0.35);
  --control-bg: rgba(129, 140, 248, 0.1);
  --control-bg-hover: rgba(129, 140, 248, 0.22);
  --panel-shadow: 0 0 30px rgba(129, 140, 248, 0.28);
}

html[data-theme="forest"] {
  --win-color: #86efac;
  --loss-color: #fca5a5;
  --text-color: #ecfdf3;
  --bg-color: rgba(6, 24, 16, 0.85);
  --accent: #4ade80;
  --control-border: rgba(74, 222, 128, 0.3);
  --control-bg: rgba(34, 197, 94, 0.1);
  --control-bg-hover: rgba(34, 197, 94, 0.22);
  --panel-shadow: 0 0 26px rgba(34, 197, 94, 0.22);
}

html[data-theme="minimal"] #title,
html[data-theme="minimal"] .label,
html[data-theme="minimal"] .value,
html[data-theme="minimal"] .field-text,
html[data-theme="minimal"] .recent-game {
  text-shadow: 0 2px 6px rgba(0,0,0,0.9), 0 0 4px rgba(0,0,0,0.85);
}

html[data-theme="neon"] .box .value {
  text-shadow: 0 0 10px currentColor, 0 0 22px currentColor;
}

/* ---- Lightning: an electric theme built around a slow-rotating gradient
   border and a soft ambient glow instead of flat neon and literal bolt
   iconography scattered everywhere - same 4 independent toggles as before
   (Sweep/Pulse/Bolt/Flicker), redesigned for a calmer, more premium look. ---- */

/* Sweep: a light literally sweeping around the panel's edge. A ring-shaped
   pseudo-element (a conic gradient masked down to just its outer band via
   mask-composite: exclude) sits behind the content and is spun with
   `transform: rotate()` - a plain transform animates smoothly in every engine,
   unlike trying to animate an angle inside the gradient itself. */
html[data-theme="lightning"] #panel {
  border: 1px solid transparent;
  background: var(--bg-color);
}

html[data-theme="lightning"] #panel::after {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  padding: 1px;
  background: conic-gradient(#38bdf8, #818cf8, #7dd3fc, #38bdf8);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  animation-name: lightning-spin;
  animation-duration: var(--lightning-sweep-duration, 6s);
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  pointer-events: none;
}

/* Each effect can be switched off independently (Lightning Effects checkboxes)
   without touching the others. */
html[data-lightning-sweep="off"] #panel {
  border-color: rgba(125, 211, 252, 0.3);
}

html[data-lightning-sweep="off"] #panel::after {
  display: none;
}

@keyframes lightning-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

/* Pulse: a slow, soft breathing glow behind the panel - independent of the
   border sweep above, so either can be switched off on its own. */
html[data-theme="lightning"] #panel::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  animation-name: lightning-glow;
  animation-duration: 3.2s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  pointer-events: none;
  z-index: 0;
}

html[data-lightning-pulse="off"] #panel::before {
  animation: none;
}

@keyframes lightning-glow {
  0%, 100% { box-shadow: 0 0 18px rgba(56, 189, 248, 0.16), inset 0 0 22px rgba(56, 189, 248, 0.05); }
  50% { box-shadow: 0 0 34px rgba(129, 140, 248, 0.3), inset 0 0 30px rgba(129, 140, 248, 0.1); }
}

html[data-theme="lightning"] #title,
html[data-theme="lightning"] .field-text {
  text-shadow: 0 0 10px rgba(125, 211, 252, 0.45);
}

/* Bolt: a single small accent glyph at the separator - the one spot Lightning
   keeps a literal icon; everywhere else relies on the border/glow instead. */
html[data-theme="lightning"] #sep {
  font-size: 0;
}

html[data-theme="lightning"] #sep::before {
  content: "\26A1";
  font-size: 24px;
  background: linear-gradient(135deg, #7dd3fc, #818cf8);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  display: inline-block;
  filter: drop-shadow(0 0 6px rgba(125, 211, 252, 0.55));
  animation: lightning-bolt-glow 2.4s ease-in-out infinite;
}

html[data-lightning-bolt="off"] #sep::before {
  animation: none;
}

html[data-shape="bar"][data-theme="lightning"] #sep::before {
  font-size: 17px;
}

@keyframes lightning-bolt-glow {
  0%, 100% { filter: drop-shadow(0 0 5px rgba(125, 211, 252, 0.45)); opacity: 0.85; }
  50% { filter: drop-shadow(0 0 12px rgba(129, 140, 248, 0.75)); opacity: 1; }
}

/* Flicker: a slow, smooth shimmer across the score values instead of a harsh
   opacity cut - reads as a subtle energy pulse, not a failing light bulb. */
html[data-theme="lightning"] .box .value {
  text-shadow: 0 0 6px currentColor, 0 0 16px currentColor;
  animation: lightning-shimmer 3.6s ease-in-out infinite;
}

html[data-lightning-flicker="off"] .box .value {
  animation: none;
}

@keyframes lightning-shimmer {
  0%, 100% { filter: brightness(1); }
  50% { filter: brightness(1.22); }
}

/* ---- Aurora: a slow, drifting conic-gradient sweep (green/blue/violet) behind
   the panel plus a soft breathing glow - calmer and cooler than Lightning. ---- */

html[data-theme="aurora"] #panel {
  border: 1px solid rgba(148, 233, 214, 0.3);
  overflow: hidden;
  animation-name: aurora-glow;
  animation-duration: 5s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}

html[data-aurora-glow="off"] #panel {
  animation: none;
}

html[data-theme="aurora"] #panel::before {
  content: "";
  position: absolute;
  inset: -60%;
  background: conic-gradient(from 0deg, #34d399, #60a5fa, #a78bfa, #f472b6, #34d399);
  opacity: 0.16;
  filter: blur(30px);
  animation-name: aurora-wave;
  animation-duration: 14s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  pointer-events: none;
  z-index: 0;
}

html[data-aurora-wave="off"] #panel::before {
  display: none;
}

html[data-theme="aurora"] #title,
html[data-theme="aurora"] .field-text {
  text-shadow: 0 0 10px rgba(148, 233, 214, 0.35);
}

@keyframes aurora-glow {
  0%, 100% { box-shadow: 0 0 16px rgba(94, 234, 212, 0.15), inset 0 0 20px rgba(94, 234, 212, 0.04); border-color: rgba(148, 233, 214, 0.3); }
  50% { box-shadow: 0 0 34px rgba(167, 139, 250, 0.3), inset 0 0 30px rgba(96, 165, 250, 0.08); border-color: rgba(167, 139, 250, 0.55); }
}

@keyframes aurora-wave {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

/* ---- Inferno: rising ember specks plus a pulsing heat-glow border - warmer
   and more aggressive than Lightning, built for a "hot streak" feel. ---- */

html[data-theme="inferno"] #panel {
  border: 1px solid rgba(251, 146, 60, 0.4);
  overflow: hidden;
  animation-name: inferno-pulse;
  animation-duration: 2.6s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}

html[data-inferno-pulse="off"] #panel {
  animation: none;
}

html[data-theme="inferno"] #panel::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(circle, rgba(251, 191, 36, 0.9) 0%, transparent 70%),
    radial-gradient(circle, rgba(251, 146, 60, 0.8) 0%, transparent 70%),
    radial-gradient(circle, rgba(248, 113, 113, 0.85) 0%, transparent 70%);
  background-size: 6px 6px, 5px 5px, 7px 7px;
  background-position: 20% 100%, 55% 100%, 80% 100%;
  background-repeat: no-repeat;
  animation-name: inferno-embers;
  animation-duration: 3.2s;
  animation-timing-function: ease-in;
  animation-iteration-count: infinite;
  pointer-events: none;
  z-index: 0;
}

html[data-inferno-ember="off"] #panel::before {
  display: none;
}

html[data-theme="inferno"] .box .value {
  text-shadow: 0 0 8px currentColor, 0 0 18px currentColor;
}

html[data-theme="inferno"] #title::after {
  content: " \1F525";
}

@keyframes inferno-pulse {
  0%, 100% { box-shadow: 0 0 4px rgba(251, 146, 60, 0.3), 0 0 20px rgba(251, 146, 60, 0.2); border-color: rgba(251, 146, 60, 0.4); }
  50% { box-shadow: 0 0 10px rgba(251, 191, 36, 0.55), 0 0 36px rgba(251, 146, 60, 0.4); border-color: rgba(251, 191, 36, 0.8); }
}

@keyframes inferno-embers {
  0% { background-position: 20% 100%, 55% 105%, 80% 110%; opacity: 0; }
  15% { opacity: 1; }
  100% { background-position: 15% -20%, 60% -30%, 75% -15%; opacity: 0; }
}

/* ---- Synthwave: retro-80s neon sunset. A magenta/cyan gradient border glow
   plus a scrolling perspective "grid floor" drifting up behind the content. ---- */
html[data-theme="synthwave"] #panel {
  border: 1px solid rgba(255, 106, 193, 0.5);
  overflow: hidden;
}

html[data-theme="synthwave"] #panel::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background:
    repeating-linear-gradient(transparent 0 22px, rgba(54, 249, 197, 0.14) 22px 23px),
    repeating-linear-gradient(90deg, transparent 0 22px, rgba(255, 106, 193, 0.12) 22px 23px);
  background-size: 100% 46px, 46px 100%;
  animation: synthwave-grid 3s linear infinite;
  pointer-events: none;
  z-index: 0;
  mask-image: linear-gradient(to top, #000 0%, transparent 75%);
  -webkit-mask-image: linear-gradient(to top, #000 0%, transparent 75%);
}

html[data-theme="synthwave"] .box .value,
html[data-theme="synthwave"] #title {
  text-shadow: 0 0 8px var(--accent), 0 0 18px rgba(255, 106, 193, 0.6);
}

@keyframes synthwave-grid {
  0% { background-position: 0 0, 0 0; }
  100% { background-position: 0 46px, 0 0; }
}

/* ---- Bubblegum: bright pastel (light theme). Soft drifting radial blobs. ---- */
html[data-theme="bubblegum"] #panel { overflow: hidden; }

html[data-theme="bubblegum"] #panel::before {
  content: "";
  position: absolute;
  inset: -40%;
  background:
    radial-gradient(circle at 30% 30%, rgba(236, 72, 153, 0.25), transparent 45%),
    radial-gradient(circle at 70% 60%, rgba(139, 92, 246, 0.22), transparent 45%),
    radial-gradient(circle at 50% 80%, rgba(56, 189, 248, 0.2), transparent 45%);
  filter: blur(14px);
  animation: bubblegum-drift 12s ease-in-out infinite;
  pointer-events: none;
  z-index: 0;
}

@keyframes bubblegum-drift {
  0%, 100% { transform: translate(0, 0) rotate(0deg); }
  50% { transform: translate(4%, -3%) rotate(8deg); }
}

/* ---- Galaxy: deep space. Twinkling starfield + slow nebula drift. ---- */
html[data-theme="galaxy"] #panel { overflow: hidden; }

html[data-theme="galaxy"] #panel::before {
  content: "";
  position: absolute;
  inset: -30%;
  background:
    radial-gradient(circle at 20% 30%, rgba(167, 139, 250, 0.28), transparent 40%),
    radial-gradient(circle at 80% 70%, rgba(103, 232, 249, 0.22), transparent 40%);
  filter: blur(18px);
  animation: galaxy-nebula 16s linear infinite;
  pointer-events: none;
  z-index: 0;
}

html[data-theme="galaxy"] #panel::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background-image:
    radial-gradient(1px 1px at 15% 25%, #fff, transparent),
    radial-gradient(1px 1px at 45% 70%, #fff, transparent),
    radial-gradient(1px 1px at 70% 20%, #fff, transparent),
    radial-gradient(1px 1px at 85% 55%, #fff, transparent),
    radial-gradient(1px 1px at 30% 85%, #fff, transparent),
    radial-gradient(1px 1px at 60% 40%, #fff, transparent);
  animation: galaxy-twinkle 3.5s ease-in-out infinite;
  pointer-events: none;
  z-index: 0;
}

@keyframes galaxy-nebula {
  0% { transform: rotate(0deg) scale(1); }
  100% { transform: rotate(360deg) scale(1); }
}

@keyframes galaxy-twinkle {
  0%, 100% { opacity: 0.35; }
  50% { opacity: 0.9; }
}

/* ---- Forest: calm nature. A gentle green dappled-light sway. ---- */
html[data-theme="forest"] #panel { overflow: hidden; }

html[data-theme="forest"] #panel::before {
  content: "";
  position: absolute;
  inset: -30%;
  background:
    radial-gradient(circle at 25% 20%, rgba(74, 222, 128, 0.22), transparent 42%),
    radial-gradient(circle at 75% 65%, rgba(16, 185, 129, 0.2), transparent 42%);
  filter: blur(16px);
  animation: forest-sway 10s ease-in-out infinite;
  pointer-events: none;
  z-index: 0;
}

@keyframes forest-sway {
  0%, 100% { transform: translateX(0) scale(1); }
  50% { transform: translateX(3%) scale(1.04); }
}

html, body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%; /* required so any %-based height (Custom Height, grid row heights) has a real box to resolve against - percentage heights are otherwise ignored by CSS when no ancestor has a definite height */
  background: transparent;
  overflow: visible;
  font-family: "Segoe UI", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  user-select: none;
}

#panel {
  position: relative;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 18px 26px;
  background: var(--bg-color);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 14px;
  color: var(--text-color);
  box-shadow: var(--panel-shadow), inset 0 1px 0 rgba(255, 255, 255, 0.05);
  min-width: 320px;
  box-sizing: border-box;
  text-align: center;
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
}

/* The "no chrome, just text over gameplay" theme shouldn't get a glass panel. */
html[data-theme="minimal"] #panel {
  border-color: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* Only the score display scales with size - the gear icon and settings panel
   stay at a fixed, predictable scale. Nesting an "un-zoomed" element inside a
   zoomed ancestor (the previous approach) corrupts its position in Chromium. */
#display {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  zoom: 1;
}

html[data-size="small"] #display { zoom: 0.7; }
html[data-size="medium"] #display { zoom: 1; }
html[data-size="large"] #display { zoom: 1.4; }
html[data-size="xl"] #display { zoom: 1.85; }

/* Bar shape: a very short, full-width one-liner - built for the width of a
   vertical (portrait) OBS canvas, where a boxy panel wastes screen space. */
html[data-shape="bar"] #panel {
  width: 100%;
  min-width: 0;
  padding: 13px 20px;
  border-radius: 9px;
}

/* Vertical: the complementary orientation to Bar - a narrow strip that fills
   the full HEIGHT of its Browser Source instead of the full width. Built for
   sitting along the left/right edge of a vertical (portrait) stream layout,
   where Bar (a horizontal band) would instead go across the top or bottom. */
html[data-shape="vertical"] #panel {
  height: 100%;
  width: auto;
  min-width: 0;
  max-width: 100%;
  padding: 20px 14px;
  border-radius: 9px;
  box-sizing: border-box;
}

html[data-shape="bar"] #title { display: none; }

html[data-shape="bar"] #score-row { gap: 10px; }

html[data-shape="bar"] .box {
  flex-direction: row;
  align-items: baseline;
  gap: 5px;
  padding: 0;
  background: none !important;
  border: none !important;
}

html[data-shape="bar"] .box .label { display: none; }

html[data-shape="bar"] .box .value { font-size: 22px; }

html[data-shape="bar"] #sep { font-size: 18px; }

html[data-shape="bar"] #status-row {
  margin-top: 0;
  max-width: none;
}

html[data-shape="bar"] #recent-games-label { display: none; }

html[data-shape="bar"] #recent-games-row { margin-top: 0; }

/* #field-list holds every visible widget field (summoner name, score,
   rank, etc.) in the order/visibility the Control Panel's "Widget Fields"
   editor was set to - see winloss.js renderFieldStructure(). Panel shape
   stacks fields as a column; Bar shape flows them in a row and wraps only
   where the user explicitly added a line-break after a field. */
#field-list {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

html[data-shape="panel"] #field-list {
  flex-direction: column;
  width: 100%;
}

html[data-shape="bar"] #field-list {
  flex-direction: row;
  flex-wrap: wrap;
  gap: 14px;
  row-gap: 10px;
}

html[data-shape="vertical"] #display {
  height: 100%;
  justify-content: center;
}

html[data-shape="vertical"] #field-list {
  flex-direction: column;
  width: 100%;
  gap: 10px;
}

/* Grid shape: #field-list becomes a CSS grid whose column/row tracks (fixed px)
   come from the user's saved layout, applied inline by renderGridStructure().
   The panel sizes to the grid. Each .grid-cell centers its one field. */
html[data-shape="grid"] #panel {
  width: auto;
  min-width: 0;
  padding: 10px;
  border-radius: 10px;
}

html[data-shape="grid"] #title { display: none; }

/* Row-based grid: #field-list is a vertical flex stack of .grid-row rows;
   each row is a horizontal flex of fixed-width .grid-cell boxes. This is what
   lets different rows have different column counts. */
html[data-shape="grid"] #field-list {
  display: flex;
  flex-direction: column;
  /* 100% (not auto) so a percent-sized column/row (see renderGridStructure)
     has a real box to resolve against. Safe for pure-px grids too - a
     percentage width doesn't affect #panel's shrink-to-fit computation
     (browsers use the intrinsic/content size for that pass), so #panel still
     shrink-wraps to the widest row exactly as before. */
  width: 100%;
  /* stretch (not center) - #field-list's children (.grid-row) are flex ITEMS
     here, and a non-stretch align-items shrinks each row to its own content
     width instead of filling #field-list. That breaks percent-width cells
     (they'd resolve against the shrunk width, not the real one) AND makes
     #panel's own shrink-to-fit sizing behave oddly for pure-px grids. Each
     row's own `justify-content: center` (below) still centers a narrower
     row's cells within the full stretched width, so a single-column row
     still visually centers exactly as before. */
  align-items: stretch;
}

.grid-row {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  justify-content: center;
}

.grid-cell {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  overflow: hidden;
  box-sizing: border-box;
  flex-shrink: 0;
}

/* Container for multiple instances within a single grid cell.
   Allows instances to stack/flow (flex-wrap) while respecting cell bounds. */
.grid-instances-container {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  gap: 4px;
  overflow: hidden;
}

/* Individual instance wrapper within a cell (used in multi-instance layout). */
.grid-instance {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 1 1 auto;
  min-width: 0;
}

/* Per-instance size control (see gridInstanceMarkup in winloss.js) - a zoomed
   wrapper the same size as its cell, so a media/announcement instance's
   `width/height:100%` still resolves against the cell rather than shrinking
   to content. `zoom` overflows the cell (not the grid) when scaled above
   100%, which #grid-cell's `overflow:hidden` clips intentionally. */
.grid-instance-scale {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* In a fixed cell the score row shouldn't force its own min-width; let it fit. */
html[data-shape="grid"] #score-row { gap: 6px; }
html[data-shape="grid"] .box { flex-direction: row; align-items: baseline; gap: 4px; padding: 0; background: none !important; border: none !important; }
html[data-shape="grid"] .box .label { display: none; }
html[data-shape="grid"] #recent-games-viewport { max-width: 100%; }

/* Announcement instance: user free text, line breaks preserved. */
.grid-announcement {
  width: 100%;
  max-height: 100%;
  overflow: hidden;
  white-space: pre-wrap;
  word-break: break-word;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.25;
}

/* Media instance: image or video filling its cell. */
.grid-media {
  width: 100%;
  height: 100%;
  display: block;
  border-radius: 6px;
}

/* A field-list child inserted only when the user explicitly asked for a line
   break after that field (Bar shape only) - unlike the old Lines 1/2/3 preset,
   breaks can go after any field in any combination. */
.line-break {
  flex-basis: 100%;
  width: 0;
  height: 0;
  overflow: hidden;
}

#title {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 4px;
  text-transform: uppercase;
  opacity: 0.6;
}

.field-text {
  font-size: 13px;
  opacity: 0.85;
  white-space: nowrap;
}

/* A narrow vertical strip can't afford nowrap - long stream titles/usernames
   need to wrap onto a second line and stay centered rather than overflowing
   or forcing the whole panel wide. */
html[data-shape="vertical"] .field-text {
  white-space: normal;
  overflow-wrap: break-word;
  word-break: break-word;
  text-align: center;
  max-width: 100%;
}

.field-sep {
  opacity: 0.35;
}

/* Every field already sits on its own line in Vertical shape, so an inline
   bullet between them (meant for a horizontal run of text) has nothing to
   visually separate - just adds noise. */
html[data-shape="vertical"] .field-sep {
  display: none;
}

#summoner-label {
  font-weight: 700;
  opacity: 1;
  font-size: 13px;
}

#timeframe-label {
  font-size: 11.5px;
  opacity: 0.7;
}

#score-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
}

/* Side-by-side WIN/LOSS boxes are too wide for a narrow vertical strip -
   stack them instead, same spirit as Bar rotating everything into a row. */
html[data-shape="vertical"] #score-row {
  flex-direction: column;
  gap: 8px;
}

html[data-shape="vertical"] .box {
  padding: 6px 16px;
}

.box {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 8px 22px;
  border-radius: 12px;
  border: 1px solid transparent;
}

html:not([data-theme="minimal"]) #win-box {
  background: color-mix(in srgb, var(--win-color) 10%, transparent);
  border-color: color-mix(in srgb, var(--win-color) 22%, transparent);
}

html:not([data-theme="minimal"]) #loss-box {
  background: color-mix(in srgb, var(--loss-color) 10%, transparent);
  border-color: color-mix(in srgb, var(--loss-color) 22%, transparent);
}

.box .label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 2px;
  opacity: 0.8;
}

.box .value {
  font-size: 46px;
  font-weight: 800;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
}

#win-box .value { color: var(--win-color); }
#loss-box .value { color: var(--loss-color); }

#sep {
  font-size: 28px;
  font-weight: 300;
  opacity: 0.35;
}

#streak.positive { color: var(--win-color); }
#streak.negative { color: var(--loss-color); }

#status-row {
  font-size: 11px;
  color: var(--loss-color);
  margin-top: 4px;
  max-width: 260px;
  text-align: center;
}

#status-row:empty { display: none; }

.section-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  opacity: 0.45;
  margin-top: 6px;
  width: 100%;
  text-align: center;
}

/* The viewport clips to a fixed size only while the ticker is actively
   cycling (set inline by JS - see setupRecentGamesTicker in winloss.js);
   otherwise it's unconstrained and #recent-games-row just displays every
   chip statically, exactly as before this feature existed. */
#recent-games-viewport {
  overflow: hidden;
  max-width: 100%;
}

#recent-games-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px;
  margin-top: 2px;
}

#recent-games-row:empty { display: none; }

/* Ticker mode: a single continuous line/column of chips that JS slides via
   `transform`, rather than wrapping - the viewport's fixed size is what
   limits how many are visible at once. */
#recent-games-row.ticker-horizontal {
  flex-wrap: nowrap;
  justify-content: flex-start;
}

#recent-games-row.ticker-vertical {
  flex-direction: column;
  flex-wrap: nowrap;
  justify-content: flex-start;
}

#recent-games-row.ticker-active {
  transition: transform 0.6s ease;
}

.recent-game {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 8px 3px 3px;
  border-radius: 20px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.game-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  font-size: 9px;
  font-weight: 800;
  background: rgba(255, 255, 255, 0.2);
}

html[data-theme="light"] .game-num {
  background: rgba(0, 0, 0, 0.12);
}

.game-kda {
  font-size: 12px;
  font-weight: 700;
}

/* Champion portrait cropped into a circle. The source art has padding/corners,
   so we scale it up slightly and center-crop with object-fit to fill the disc. */
.game-champ-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  overflow: hidden;
  flex-shrink: 0;
  background: rgba(255, 255, 255, 0.12);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.25);
}

html[data-theme="light"] .game-champ-icon {
  background: rgba(0, 0, 0, 0.08);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2);
}

.game-champ-icon img {
  width: 138%;
  height: 138%;
  object-fit: cover;
  display: block;
}

.game-champ-name {
  font-size: 11px;
  font-weight: 600;
  opacity: 0.9;
}

.game-date {
  font-size: 10px;
  font-weight: 400;
  opacity: 0.75;
}

.recent-game.win {
  background: color-mix(in srgb, var(--win-color) 18%, transparent);
  color: var(--win-color);
}

.recent-game.loss {
  background: color-mix(in srgb, var(--loss-color) 18%, transparent);
  color: var(--loss-color);
}

#gear-btn {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1px solid var(--control-border);
  background: var(--control-bg);
  color: var(--text-color);
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.15s ease, background 0.15s ease;
}

#panel:hover #gear-btn,
#gear-btn.active {
  opacity: 1;
}

#gear-btn:hover { background: var(--control-bg-hover); }

#settings-panel {
  display: none;
  position: absolute;
  top: 32px;
  right: 6px;
  background: rgba(20, 20, 24, 0.97);
  border: 1px solid var(--control-border);
  border-radius: 10px;
  padding: 10px 12px;
  z-index: 10;
  box-shadow: 0 6px 20px rgba(0,0,0,0.4);
  width: 260px;
  box-sizing: border-box;
}

#settings-panel.open { display: block; }

#settings-panel .row {
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin-bottom: 8px;
}

#settings-panel .row:last-child { margin-bottom: 0; }

/* .row's own `display: flex` outranks the UA default [hidden] rule (same
   specificity tier, but ours loads later) - without this override, a hidden
   row would stay visible despite the `hidden` attribute. */
#settings-panel .row[hidden] { display: none; }

.hint-inline {
  font-size: 10px;
  opacity: 0.6;
  line-height: 1.4;
}

#settings-panel .row-label {
  font-size: 10px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: #ffffff;
  opacity: 0.6;
}

#settings-panel select,
#settings-panel input,
#settings-panel button {
  font-size: 12px;
  padding: 5px 6px;
  border-radius: 5px;
  border: 1px solid var(--control-border);
  background: var(--control-bg);
  color: #ffffff;
}

#settings-panel select:hover,
#settings-panel button:hover {
  background: var(--control-bg-hover);
  cursor: pointer;
}

/* Without this, Chrome/Edge on Windows renders the dropdown's OPEN option list
   with the OS default (white) background while still inheriting our light text
   color - unreadable until an option is hovered/highlighted. */
#settings-panel select option {
  background: rgba(20, 20, 24, 0.97);
  color: #ffffff;
}

.inline-fields {
  display: flex;
  gap: 6px;
}

.inline-fields select { flex-shrink: 0; width: 88px; }
.inline-fields input { flex: 1; min-width: 0; }

.split-date-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
}

.split-date-row .split-num {
  flex-shrink: 0;
  width: 44px;
  font-size: 11px;
  opacity: 0.75;
}

.split-date-row .split-to {
  flex-shrink: 0;
  font-size: 10px;
  opacity: 0.6;
}

.split-date-row input[type="date"] {
  flex: 1;
  min-width: 0;
  width: auto;
}

/* Per-field timeframe: three compact labelled selects stacked in the panel. */
.pf-tf-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.pf-tf-row label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  font-size: 11px;
  opacity: 0.85;
}
.pf-tf-row select { width: 130px; flex-shrink: 0; }

#settings-panel select,
#settings-panel input:not(.inline-fields input):not([type="checkbox"]):not([type="range"]) {
  width: 100%;
  box-sizing: border-box;
}

.checkbox-group {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
}

.checkbox-group label {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  color: #ffffff;
  cursor: pointer;
}

#settings-panel .checkbox-group input[type="checkbox"] {
  width: auto;
  padding: 0;
  border: none;
  background: none;
  accent-color: var(--accent);
  cursor: pointer;
}

#settings-panel input[type="range"] {
  padding: 0;
  accent-color: var(--accent);
  cursor: pointer;
}

/* ---- Widget Fields editor: toggle + reorder + line-break-after, one row per
   field in FIELD_DEFS (public/fields.js) - see renderFieldOrderEditor() in
   winloss.js. Fully data-driven so a future field needs no new CSS here. ---- */

.field-order-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.field-order-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  padding: 4px 6px;
  border-radius: 6px;
  background: var(--control-bg);
  border: 1px solid var(--control-border);
  border-top: 2px solid transparent;
  cursor: grab;
}

.field-order-item.dragging {
  opacity: 0.4;
}

.field-order-item.drag-over {
  border-top-color: var(--accent);
}

.field-order-grip {
  flex-shrink: 0;
  opacity: 0.45;
  font-size: 12px;
  line-height: 1;
}

.field-order-check {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 11px;
  color: #ffffff;
  cursor: pointer;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.field-order-check input[type="checkbox"] {
  width: auto;
  flex-shrink: 0;
  accent-color: var(--accent);
}

.field-order-controls {
  display: flex;
  align-items: center;
  gap: 3px;
  flex-shrink: 0;
}

.field-order-controls button {
  width: 20px;
  height: 20px;
  padding: 0;
  font-size: 9px;
  line-height: 1;
  cursor: pointer;
}

.field-order-break {
  display: flex;
  align-items: center;
  gap: 2px;
  font-size: 13px;
  color: #ffffff;
  cursor: pointer;
  opacity: 0.85;
}

.field-order-break input[type="checkbox"] {
  width: auto;
  accent-color: var(--accent);
}

.field-order-break[hidden] { display: none; }

#session-info {
  font-size: 10.5px;
  opacity: 0.7;
}

#settings-panel .btn-group {
  display: flex;
  gap: 4px;
}

#settings-panel .btn-group button {
  flex: 1;
}

#settings-panel .btn-group button.selected {
  background: var(--accent);
  color: #1a1a1a;
  border-color: var(--accent);
  font-weight: 700;
}

.save-bar {
  flex-direction: row !important;
  align-items: center !important;
  gap: 8px !important;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--control-border);
}

.save-btn {
  background: var(--accent);
  color: #1a1a1a;
  border: none;
  font-weight: 700;
  flex-shrink: 0;
}

.save-btn:hover:not(:disabled) { background: var(--control-bg-hover); filter: brightness(1.1); }

.save-btn:disabled {
  background: var(--control-bg);
  color: var(--text-color);
  opacity: 0.6;
  cursor: default;
  font-weight: 600;
}

/* ---- Broadcast polish: loading shimmer, reconnect indicator, streak/rank
   celebrations, rank-delta badge. Plain DOM elements (not ::before/::after)
   so they never collide with the per-theme pseudo-elements Lightning/Aurora/
   Inferno already use for their own glow/sweep effects. ---- */

#loading-shimmer {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  z-index: 2;
  opacity: 0;
  background: linear-gradient(100deg, transparent 30%, rgba(255, 255, 255, 0.12) 50%, transparent 70%);
  background-size: 250% 100%;
  background-position: 150% 0%;
}

#panel.loading #loading-shimmer {
  opacity: 1;
  animation: loading-shimmer-sweep 1s ease-in-out infinite;
}

@keyframes loading-shimmer-sweep {
  0% { background-position: 150% 0%; }
  100% { background-position: -50% 0%; }
}

#reconnect-dot {
  position: absolute;
  top: 6px;
  left: 6px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #f59e0b;
  opacity: 0;
  pointer-events: none;
  z-index: 2;
  box-shadow: 0 0 6px rgba(245, 158, 11, 0.6);
}

#panel.reconnecting #reconnect-dot {
  opacity: 1;
  animation: reconnect-pulse 1.6s ease-in-out infinite;
}

@keyframes reconnect-pulse {
  0%, 100% { opacity: 0.5; transform: scale(0.9); }
  50% { opacity: 1; transform: scale(1.15); }
}

/* Win-streak celebration: a brief radial glow burst behind the content plus a
   handful of small particles, toggled on for one shot via JS (see
   triggerCelebration() in winloss.js) rather than looping. */
#panel.celebrate-streak::after {
  content: "";
  position: absolute;
  inset: -20%;
  border-radius: inherit;
  background: radial-gradient(circle, color-mix(in srgb, var(--win-color) 55%, transparent) 0%, transparent 60%);
  animation: celebration-burst 1.4s ease-out;
  pointer-events: none;
  z-index: 1;
}

/* Promotion celebration: same mechanic, wider/brighter burst using --accent
   so it reads as a bigger deal than a streak tick. */
#panel.celebrate-promotion::after {
  content: "";
  position: absolute;
  inset: -30%;
  border-radius: inherit;
  background: radial-gradient(circle, color-mix(in srgb, var(--accent) 65%, transparent) 0%, transparent 65%);
  animation: celebration-burst 2s ease-out;
  pointer-events: none;
  z-index: 1;
}

@keyframes celebration-burst {
  0% { opacity: 0; transform: scale(0.6); }
  25% { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1.35); }
}

/* ============================================================================
   Winning-streak theme

   `--winstreak-intensity` is set by applyWinStreakTheme() in winloss.js every
   render, as (current win streak / configured threshold) - 0 with no streak,
   climbing to 1 right at the threshold, and drifting up to 2 the longer a
   streak runs past it.

   Below the threshold (`data-winstreak="off"`) this only adds a glow on top
   of #panel using the ACTIVE THEME'S OWN --win-color - it never touches any
   theme's colors or layout, so it reads as "this theme is warming up," not a
   different look layered in. At/above the threshold (`data-winstreak="on"`)
   a dedicated gold palette + shimmer takes over, the same way switching
   data-theme would, but without ever touching settings.theme - so dropping
   back below threshold (a loss) restores the previously-selected theme
   exactly, with nothing to undo.
   ========================================================================= */
:root { --winstreak-intensity: 0; }

html:not([data-winstreak="on"]) #panel {
  transition: box-shadow 0.5s ease, filter 0.5s ease;
  box-shadow:
    var(--panel-shadow),
    inset 0 1px 0 rgba(255, 255, 255, 0.05),
    0 0 calc(16px + min(var(--winstreak-intensity), 1) * 26px)
      calc(min(var(--winstreak-intensity), 1) * 4px)
      color-mix(in srgb, var(--win-color) calc(min(var(--winstreak-intensity), 1) * 70%), transparent);
  filter:
    saturate(calc(1 + min(var(--winstreak-intensity), 1) * 0.25))
    brightness(calc(1 + min(var(--winstreak-intensity), 1) * 0.06));
}

html[data-winstreak="on"] {
  --win-color: #ffd700;
  --accent: #ffb700;
  --panel-shadow: 0 0 46px rgba(255, 199, 0, 0.55), 0 0 90px rgba(255, 165, 0, 0.25);
}

html[data-winstreak="on"] #panel {
  border-color: rgba(255, 215, 0, 0.5);
  animation: winstreak-shimmer 2.6s ease-in-out infinite;
}

/* Slow rotating gold sweep behind the content, mirroring the Aurora
   wave/Lightning sweep pattern each theme already uses for its own #panel
   pseudo-element. z-index 0 keeps it behind #display (z-index 1). */
html[data-winstreak="on"] #panel::before {
  content: "";
  position: absolute;
  inset: -40%;
  border-radius: inherit;
  background: conic-gradient(from 0deg, transparent 0deg, rgba(255, 235, 140, 0.35) 40deg, transparent 90deg, transparent 360deg);
  animation: winstreak-rotate 5s linear infinite;
  pointer-events: none;
  z-index: 0;
}

@keyframes winstreak-shimmer {
  0%, 100% { box-shadow: var(--panel-shadow), inset 0 1px 0 rgba(255, 255, 255, 0.05); }
  50% { box-shadow: 0 0 60px rgba(255, 215, 0, 0.65), 0 0 110px rgba(255, 165, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.08); }
}

@keyframes winstreak-rotate {
  to { transform: rotate(360deg); }
}

/* Rank Status is a normal Widget Field (reorderable/hideable like any other),
   styled as a small persistent pill rather than plain text - it never
   auto-hides, it just gets overwritten the next time the rank changes. */
#rank-status-label {
  display: inline-flex;
  align-items: center;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.4px;
  padding: 2px 8px;
  border-radius: 20px;
  background: var(--control-bg);
  border: 1px solid var(--control-border);
  white-space: nowrap;
  min-height: 1em;
}

#rank-status-label:empty { padding: 2px 0; border-color: transparent; background: transparent; }

#rank-status-label.positive { color: var(--win-color); border-color: color-mix(in srgb, var(--win-color) 50%, transparent); }
#rank-status-label.negative { color: var(--loss-color); border-color: color-mix(in srgb, var(--loss-color) 50%, transparent); }
#rank-status-label.promoted { color: var(--accent); border-color: var(--accent); }
#rank-status-label.demoted { color: var(--text-color); opacity: 0.85; }
