/* Overlay Studio — artwork styles. Shared by the studio preview and the
   chromeless overlay so what you design is exactly what OBS captures. */
* { box-sizing: border-box; }

.ov-stage {
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: 100%;
}
.ov-fit { position: relative; transform-origin: center center; transition: opacity var(--idle-fade, 600ms) ease; }
.ov-fit.is-idle { opacity: 0; }
.ov-scale { position: relative; z-index: 1; transform-origin: center center; }

/* The overlay's own background: pinned to the browser source, under
   everything, and never in the way of a pointer. */
.ov-bg {
  position: absolute; left: 0; top: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center; z-index: 0;
  pointer-events: none; user-select: none;
}

/* ---------- image / GIF layers ----------
   Zero-sized anchors pinned to the centre of the artwork, which is also
   where a browser source centres itself — so a layer sits in the same place
   in the studio preview and on stream. */
.ov-layers { position: absolute; left: 50%; top: 50%; width: 0; height: 0; }
.ov-layers.back { z-index: 0; }  /* under .ov-scale, which sits at 1 */
.ov-layers.front { z-index: 3; }
.ov-layer {
  position: absolute; left: 0; top: 0; height: auto; max-width: none;
  transform-origin: center center; pointer-events: none; user-select: none;
}
/* draggable in the studio only; the overlay itself must never eat clicks */
.is-editing .ov-layer { pointer-events: auto; cursor: grab; }
.is-editing .ov-layer:hover { outline: 2px dashed rgba(124, 92, 255, .95); outline-offset: 3px; }
.is-editing .ov-layer.dragging { cursor: grabbing; outline-style: solid; }
/* the stand-in for an image painted onto the controller: it exists only to be
   grabbed, so it shows nothing until the pointer is on it */
.ov-proxy { background: transparent; }

/* ---------- the selected layer's transform box ----------
   Studio only. Corners resize about the opposite corner, the stalk above
   rotates; both keep the image's proportions, because a layer is stored as
   one width with its height following the artwork. */
.ov-frame {
  position: absolute; left: 0; top: 0; z-index: 999;
  outline: 1px solid rgba(120, 200, 255, .95);
  transform-origin: center center; pointer-events: none;
}
/* --hs undoes the preview's fit: the box scales with the artwork, its grips
   must not, or they would be specks on a scaled-down stage */
.ov-frame i { transform: scale(var(--hs, 1)); }
.ov-frame i {
  position: absolute; display: block; width: 11px; height: 11px; margin: -6px 0 0 -6px;
  background: #fff; border: 1px solid rgba(0, 0, 0, .55); border-radius: 3px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .6); pointer-events: auto;
}
.ov-frame i[data-h="nw"] { left: 0; top: 0; cursor: nwse-resize; }
.ov-frame i[data-h="ne"] { left: 100%; top: 0; cursor: nesw-resize; }
.ov-frame i[data-h="se"] { left: 100%; top: 100%; cursor: nwse-resize; }
.ov-frame i[data-h="sw"] { left: 0; top: 100%; cursor: nesw-resize; }
.ov-frame i[data-h="rot"] {
  left: 50%; top: calc(-26px * var(--hs, 1)); border-radius: 50%; cursor: grab;
  background: rgba(120, 200, 255, .95);
}
.ov-frame i[data-h="rot"]::before {
  content: ''; position: absolute; left: 50%; top: 100%; width: 1px; height: 20px;
  margin-left: -.5px; background: rgba(120, 200, 255, .8);
}
/* the skin renders in an iframe, which would otherwise swallow every click
   meant for a layer sitting behind or over it */
.is-editing .skin-frame { pointer-events: none; }
.is-editing .ov-proxy:hover { outline-color: rgba(69, 214, 255, .95); }
.is-editing .ov-proxy.dragging { outline-color: rgba(69, 214, 255, .95); }

/* ---------- controller ---------- */
.ctl {
  width: 100%; height: 100%; overflow: visible;
  --glow: #2f6bff; --glow-strength: 1; --fade: 140ms; --v: 1;
  --btn: #fff; --btn-text: #14161b; --accent: #16181d; --accent-text: #eef1f8;
  --plate-hi: #4a4f5c; --shell: #fff; --shell-lo: #ddd; --lightbar: #2f6bff;
  --edge: rgba(0,0,0,.22); --sheen: rgba(255,255,255,.5); --shading: .55;
}
.ctl .shell { filter: drop-shadow(0 6px 10px rgba(0,0,0,.45)); }
.ctl .shell > * { stroke: var(--edge); stroke-width: 1.4; }
.ctl .shading { opacity: var(--shading); mix-blend-mode: multiply; pointer-events: none; }
.ctl .details { pointer-events: none; }
.ctl.has-skin.hide-details .details { display: none; }
.ctl .skin-img { pointer-events: none; }

.ctl .lightbar > * {
  fill: var(--lightbar);
  filter: drop-shadow(0 0 4px var(--lightbar)) drop-shadow(0 0 12px var(--lightbar));
  opacity: .45; transition: opacity .3s ease;
}
.ctl.live .lightbar > * { opacity: .9; }

/* --- parts --- */
.ctl .part { color: var(--btn-text); }
.ctl .part .hit { stroke: var(--edge); stroke-width: 1.2; }
.ctl .part .recess { fill: rgba(0,0,0,.26); }
.ctl .part .glyph { pointer-events: none; opacity: .75; }

/* face buttons + d-pad sit slightly proud of the shell */
.ctl .part-face .hit, .ctl .part-dpad .hit { filter: drop-shadow(0 1.5px 1px rgba(0,0,0,.4)); }
.ctl .part-dpad .hit { stroke-width: 0.8; }

/* shoulder + trigger bodies live behind the shell */
.ctl .parts.back .hit { stroke: var(--edge); stroke-width: 1.4; }
.ctl .part-trigger-back .hit { stroke: rgba(0,0,0,.35); }
.ctl .part-bumper { color: var(--btn-text); }
.ctl .part-bumper .glyph { opacity: .45; }

/* touchpad, small buttons, paddles */
.ctl .part-pad .hit { stroke: var(--edge); stroke-width: 1.6; filter: drop-shadow(0 1px 1px rgba(0,0,0,.25)); }
.ctl .part-small .hit { opacity: .9; stroke: none; }
.ctl .part-small { color: var(--accent-text); }
.ctl .part-paddle .hit { opacity: .92; stroke: none; }
.ctl .part-paddle { color: var(--accent-text); }

/* sticks */
.ctl .part-stick .well-rim { fill: rgba(0,0,0,.35); }
.ctl .part-stick .well { stroke: rgba(0,0,0,.35); stroke-width: 1.5; }
.ctl .part-stick .hit { stroke: rgba(0,0,0,.45); stroke-width: 1.5; filter: drop-shadow(0 2px 3px rgba(0,0,0,.5)); }
.ctl .part-stick .cap-dish { fill: rgba(0,0,0,.22); }
.ctl .part-stick .cap-shine { fill: #fff; opacity: .1; }
.ctl .part-stick .cap { transition: transform 40ms linear; }

/* analog trigger meters */
.ctl .part-trigger .hit { stroke: rgba(255,255,255,.1); }
.ctl .part-trigger .glyph, .ctl .part-small .glyph { opacity: 1; }
.ctl .part-trigger { color: var(--accent-text); }
.ctl .part-trigger .ring {
  fill: none; stroke: var(--glow); stroke-width: 6; stroke-linecap: round;
  transition: stroke-dashoffset 60ms linear; filter: drop-shadow(0 0 6px var(--glow));
}

/* press glow — a duplicate of each shape faded in on top */
.ctl .glowlayer { fill: var(--glow); opacity: 0; pointer-events: none; transition: opacity var(--fade) ease; }
.ctl .part.on .glowlayer { opacity: calc(var(--v) * var(--glow-strength)); }
.ctl.glow-full .part.on .glowlayer {
  filter: drop-shadow(0 0 calc(10px * var(--glow-strength)) var(--glow))
          drop-shadow(0 0 calc(26px * var(--glow-strength)) var(--glow));
}
.ctl.glow-outline .glowlayer { fill: none; stroke: var(--glow); stroke-width: 5; }
.ctl.glow-outline .part.on .glowlayer { filter: drop-shadow(0 0 10px var(--glow)); }
.ctl.glow-halo .part.on .glowlayer {
  opacity: calc(var(--v) * var(--glow-strength) * .35);
  filter: drop-shadow(0 0 calc(18px * var(--glow-strength)) var(--glow))
          drop-shadow(0 0 calc(40px * var(--glow-strength)) var(--glow));
}
.ctl.glow-pulse .part.on .glowlayer { animation: ov-pulse 900ms ease-out infinite; }
.ctl.glow-flat .part.on .glowlayer { filter: none; }
@keyframes ov-pulse {
  0% { opacity: calc(var(--v) * var(--glow-strength)); filter: drop-shadow(0 0 4px var(--glow)); }
  60% { opacity: calc(var(--v) * var(--glow-strength) * .55); filter: drop-shadow(0 0 26px var(--glow)); }
  100% { opacity: calc(var(--v) * var(--glow-strength)); filter: drop-shadow(0 0 4px var(--glow)); }
}
.ctl .part.on .glyph { opacity: 1; color: #fff; }

/* ---------- eyes ---------- */
.ctl .eyes .eye-white { fill: #fbfbfd; stroke: rgba(0,0,0,.35); stroke-width: 2; }
.ctl .eyes .pupil { fill: #10121a; }
.ctl .eyes .shine { fill: #fff; opacity: .85; }
.ctl .eyes .pupil-g { transition: transform 60ms linear; }
.ctl .eyes .brow { display: none; stroke: #10121a; stroke-width: 9; stroke-linecap: round; }
.ctl .eyes .lid { fill: var(--shell); transform-box: fill-box; transform-origin: center; transform: scaleY(0); transition: transform 70ms ease; }
.ctl .eyes.blink .lid { transform: scaleY(1); }
.ctl .eyes-angry .brow { display: block; }
.ctl .eyes-dot .eye-white { display: none; }
.ctl .eyes-dot .shine { display: none; }
.ctl .eyes-dot .pupil { r: 16; fill: #10121a; }
.ctl .eyes-anime .eye-white { rx: 40px; ry: 52px; }
.ctl .eyes-anime .pupil { fill: var(--glow); }

/* ---------- calibration ---------- */
.ctl .calib { display: none; pointer-events: none; }
.ctl.calibrating .calib { display: block; }
.ctl.calibrating .part { cursor: move; }
.ctl.calibrating .calib-box {
  fill: none; stroke: #4ad3ff; stroke-width: 2.5; stroke-dasharray: 7 6;
  opacity: .9;
}
.ctl.calibrating .calib-dot { fill: #4ad3ff; filter: drop-shadow(0 0 8px #4ad3ff); }
.ctl.calibrating .eyes { cursor: move; }

/* ---------- keyboard ---------- */
.kb-host { --u: 62px; --gap: 8px; --radius: 10px; }
.kb-wrap { display: flex; align-items: flex-end; gap: calc(var(--gap) * 3); }
.kb-wrap.mouse-left { flex-direction: row-reverse; }
.kb-block { display: flex; flex-direction: column; gap: var(--gap); }
.kb-row { display: flex; gap: var(--gap); }
.kb-key {
  position: relative; height: var(--u); border-radius: var(--radius);
  background: var(--key); border: 2px solid var(--key-edge); color: var(--key-text);
  display: flex; align-items: center; justify-content: center; overflow: hidden;
  font: 700 clamp(11px, calc(var(--u) * .26), 22px)/1 Inter, "Segoe UI", system-ui, sans-serif;
  letter-spacing: .04em; transition: background 90ms ease, color 90ms ease, box-shadow 90ms ease, transform 90ms ease;
}
.kb-key .kb-cap { position: relative; z-index: 2; padding: 0 4px; text-align: center; }
.kb-key.long .kb-cap { font-size: .8em; }
.kb-key.xlong .kb-cap { font-size: .66em; letter-spacing: 0; }
.kb-key.on {
  background: var(--key-on); color: var(--key-text-on); transform: translateY(2px);
  box-shadow: 0 0 12px var(--key-on), 0 0 30px var(--key-on);
}
.kb-key .kb-hold { position: absolute; inset: auto 0 0 0; height: 100%; background: var(--key-on); opacity: .35; transform: scaleY(var(--held, 0)); transform-origin: bottom; display: none; }
.show-hold .kb-key .kb-hold { display: block; }
/* a key carrying its own pressed colour keeps a hint of it at rest, so the
   highlight is visible before anyone touches the keyboard */
.kb-key.is-tinted { border-color: color-mix(in srgb, var(--key-on) 55%, var(--key-edge)); }
.is-editing .kb-key { cursor: pointer; }

.kb-mouse { width: calc(var(--u) * 2.4); height: auto; }
.kb-mouse .ms-body { fill: var(--key); stroke: var(--key-edge); stroke-width: 4; }
.kb-mouse .ms { fill: var(--key); stroke: var(--key-edge); stroke-width: 4; transition: fill 90ms ease, filter 90ms ease; }
.kb-mouse .ms.on { fill: var(--key-on); filter: drop-shadow(0 0 10px var(--key-on)); }
.kb-mouse .ms-wheel .ms { fill: var(--key-edge); }
.kb-mouse .ms-wheel { transition: transform 90ms ease; }
.kb-mouse .ms-wheel.on { transform: translateY(calc(var(--dir, 0) * 5px)); }

/* ---------- skins rendered in an isolated frame ---------- */
/* color-scheme must stay 'normal' here: a dark scheme on the embedder makes
   Chromium paint an opaque base canvas inside the frame, killing OBS transparency */
.skin-frame { display: block; border: 0; background: transparent; overflow: hidden; color-scheme: normal; }

/* ---------- image skins (GamepadViewer format) ---------- */
.skin-host { position: relative; }
.skin-gamepad { position: relative; }
.skin-gamepad, .skin-gamepad .controller {
  position: relative;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}
.skin-gamepad .clear { clear: both; display: block; }
/* optional press glow layered over the skin's own pressed artwork */
.skin-gamepad.glow-on [data-pressed="true"] {
  filter: drop-shadow(0 0 calc(8px * var(--glow-strength, 1)) var(--glow))
          drop-shadow(0 0 calc(20px * var(--glow-strength, 1)) var(--glow));
}
.skin-missing {
  color: #9aa3b8; font: 500 14px Inter, "Segoe UI", system-ui, sans-serif;
  padding: 40px; text-align: center;
}
