/*
 * Mardi Gras World kiosk — shared component library.
 *
 * The canonical, reusable building blocks: buttons, the segmented control
 * dock, status dots, eyebrow type, the shared mode-shell chrome (top bar /
 * back pill / mode title / relation line), panels (title, subtitle, body),
 * the error/offline modal, the attract overlay and the text bubble.
 *
 * Component classes are namespaced `mgw-*` so they never collide with a
 * screen's own classes. The file also sets two kiosk-wide defaults: touch
 * tuning on html/body and slim scrollbars on every element. The launcher, the
 * idle and getting-ready screens and every mode except the simulation (which
 * mirrors the few rules it needs) load it, and new modes should reuse these
 * rather than reinventing chrome. Loaded AFTER brand.css (which provides the
 * tokens these rules reference).
 *
 * Accent discipline: yellow (--mgw-yellow) is the ONLY interactive accent —
 * active states, focus, and primary CTAs. Per-module colors are reserved for
 * decorative stage glow and never appear on a control.
 */

/* ── Global touch tuning (kiosk) ───────────────────────────────────────────
   Dropping the gray tap-highlight flash and the legacy ~300ms double-tap-zoom
   delay on every screen that loads this file makes touches feel immediate;
   `manipulation` still allows scroll where a screen needs it. The 3D
   canvases opt into `touch-action: none` themselves for raw orbit/drag.
   In the kiosk the preload overrides the root to `none` (see "Forgiving touch
   presses" in electron/preload.js) so a press that slides still reaches its
   button; overflow:auto/scroll containers keep panning regardless. */
html, body {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none;
  user-select: none;
}

/* ── Buttons ─────────────────────────────────────────────────────────────── */

/* Shared pill base. Min height keeps every control a comfortable touch target
   (≥58px) on the 4K wall display. */
.mgw-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.7em;
  min-height: 58px;
  padding: 1.1em 2.2em;
  border: 1px solid transparent;
  border-radius: var(--mgw-radius-pill);
  font: inherit;
  /* Controls are Futura, mixed case — the subheading role. `font: inherit`
     alone would take body Rooney, which reads as prose, not as a control. */
  font-family: var(--mgw-font-heading);
  font-weight: 600;
  letter-spacing: 0.02em;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease, transform 0.18s ease;
}
.mgw-btn:active { transform: translateY(1px); }
.mgw-btn svg { width: 1.2em; height: 1.2em; display: block; }

/* Primary — the single yellow call to action. */
.mgw-btn-primary {
  background: var(--mgw-yellow);
  color: var(--mgw-bg);
}
/* Brightened rather than a second, off-palette yellow. */
.mgw-btn-primary:hover { filter: brightness(1.08); }

/* Secondary — ghost pill on the dark surface. Yellow label: every control on
   the fleet reads yellow, and the primary carries it as a fill instead. */
.mgw-btn-secondary {
  background: rgba(255, 255, 255, 0.06);
  color: var(--mgw-instruction);
  border-color: rgba(255, 255, 255, 0.18);
}
.mgw-btn-secondary:hover { background: rgba(255, 255, 255, 0.1); }

/* Back / Home pill — ghost, leading left-arrow icon. */
.mgw-btn-back {
  background: rgba(255, 255, 255, 0.06);
  color: var(--mgw-instruction);
  border-color: var(--mgw-divider);
  padding: 1em 1.6em 1em 1.4em;
  font-weight: 500;
}
.mgw-btn-back:hover {
  background: rgba(255, 255, 255, 0.1);
  border-color: rgba(242, 178, 33, 0.55);
}

/* Round icon button — info (64px) and close (58px) variants. */
.mgw-btn-round {
  flex: none;
  width: 64px;
  height: 64px;
  min-height: 0;
  padding: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.06);
  color: var(--mgw-instruction);
  border-color: var(--mgw-divider);
}
.mgw-btn-round:hover {
  background: rgba(255, 255, 255, 0.1);
  border-color: rgba(242, 178, 33, 0.55);
}
.mgw-btn-round svg { width: 26px; height: 26px; }
.mgw-btn-close { width: 58px; height: 58px; }

/* ── Segmented control dock ──────────────────────────────────────────────── */

/* Bottom-center floating dock of pills; exactly one is active (yellow). */
.mgw-dock {
  display: inline-flex;
  gap: 10px;
  padding: 12px;
  background: rgba(27, 10, 46, 0.8);
  border: 1px solid var(--mgw-divider);
  border-radius: var(--mgw-radius-pill);
  box-shadow: var(--mgw-shadow-md);
  backdrop-filter: blur(18px);
}
.mgw-dock-btn {
  min-height: 58px;
  padding: 0 1.7em;
  background: transparent;
  color: var(--mgw-ink);
  border: 1px solid transparent;
  border-radius: var(--mgw-radius-pill);
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease;
}
.mgw-dock-btn:hover {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.18);
}
.mgw-dock-btn.is-active {
  background: var(--mgw-yellow);
  color: var(--mgw-bg);
  font-weight: 600;
}

/* ── Status ──────────────────────────────────────────────────────────────── */

/* Status line: a colored dot + uppercase label. Dim by default; the dot color
   carries the meaning. ready=green, fallback=orange, syncing=gray. */
.mgw-status {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--mgw-ink-faint);
}
.mgw-status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--mgw-light-grey);   /* syncing (default) */
  transition: background 0.3s ease;
}
.mgw-status-dot.is-ready { background: var(--mgw-green); }
.mgw-status-dot.is-fallback { background: var(--mgw-orange); }
.mgw-status-dot.is-syncing { background: var(--mgw-light-grey); }

/* ── Eyebrow / label type ────────────────────────────────────────────────── */

.mgw-eyebrow {
  font-family: var(--mgw-font-heading);
  font-weight: 600;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--mgw-instruction);
}

/* ── Shared mode shell ───────────────────────────────────────────────────── */

/* Top bar: gradient scrim, back pill (left), eyebrow + title (center/stretch),
   optional round info button (right). pointer-events let drags pass to the
   mode's canvas in the gaps between controls. */
.mgw-topbar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  gap: 28px;
  padding: 30px 40px;
  background: linear-gradient(180deg, rgba(27, 10, 46, 0.9), rgba(27, 10, 46, 0));
  z-index: 20;
  pointer-events: none;
}
.mgw-topbar > * { pointer-events: auto; }
.mgw-topbar-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.2rem; }
.mgw-topbar-info .mgw-eyebrow { font-size: 0.85rem; }
.mgw-mode-title {
  font-family: var(--mgw-font-display);
  font-weight: 900;
  font-size: clamp(1.6rem, 2.4vw, 2.3rem);
  line-height: 1.1;
  color: var(--mgw-ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.mgw-relation {
  font-weight: 500;
  font-size: 0.8rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--mgw-ink-dim);
}

/* ── Overlays ────────────────────────────────────────────────────────────── */

/* Info side-panel — about-this-sculpt card. */
.mgw-panel {
  border: 1px solid var(--mgw-divider);
  border-radius: var(--mgw-radius-lg);
  padding: 28px 30px;
  background: rgba(27, 10, 46, 0.78);
  box-shadow: var(--mgw-shadow-md);
  backdrop-filter: blur(18px);
}
.mgw-panel-title {
  font-family: var(--mgw-font-heading);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: 1.6rem;
  line-height: 1.12;
  color: var(--mgw-ink);
}
.mgw-panel-body { font-size: 1rem; line-height: 1.5; color: var(--mgw-ink-dim); }

/* Error / offline modal — top accent rule, orange unless the mode recolors it
   per error type (the STL viewer's .stl-error.error-* rules). */
.mgw-modal {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--mgw-divider);
  border-radius: var(--mgw-radius-lg);
  padding: 40px 40px 34px;
  background: var(--mgw-surface);
  box-shadow: var(--mgw-shadow-lg);
  text-align: center;
}
.mgw-modal::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: var(--mgw-orange);   /* default: warning/offline */
}
.mgw-modal-title {
  font-family: var(--mgw-font-display);
  font-weight: 900;
  font-size: 1.75rem;
  line-height: 1.1;
  color: var(--mgw-ink);
}
.mgw-modal-body { font-size: 1.05rem; line-height: 1.4; color: var(--mgw-ink-dim); margin-top: 0.5em; }

/* ── Attract overlay (attract-refinements) — a demonstrative moving-hand
      gesture over the lightly-dimmed scene: the hand drags side-to-side along
      a faint trail ("you can move this"), one short line beneath, and an
      optional bouncing callout pill above a mode's bottom control dock. The
      WHOLE overlay is pointer-events:none so the waking touch reaches the
      canvas in the same gesture. ── */
.mgw-attract {
  position: absolute;
  inset: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: radial-gradient(1100px 750px at 50% 46%, rgba(15, 5, 26, 0.30), rgba(15, 5, 26, 0.62));
  pointer-events: none;
  animation: mgw-attract-fade 0.5s ease;
}
.mgw-attract * { pointer-events: none; }
@keyframes mgw-attract-fade { from { opacity: 0; } to { opacity: 1; } }
.mgw-attract-invite {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.1rem;
}
.mgw-attract-hand {
  width: 92px;
  height: 92px;
  color: var(--mgw-yellow);
  filter: drop-shadow(0 6px 24px rgba(0, 0, 0, 0.5));
  /* Quantized to ~24fps: steps() applies per keyframe SEGMENT, so 34 steps
     on each 1.4s half is one step every ~41ms (not the ~12fps of 34 steps
     over the whole 2.8s, as this once said). This overlay ships in every
     R3F mode and runs through the whole attract window — up to ~45s per
     abandoned session — and in the STL viewer for table-cut models it is the
     ONLY thing keeping the GPU awake, because attract turns the spin off
     there. The glide is broad and slow, so stepping it is hard to catch. */
  animation: mgw-attract-drag 2.8s steps(34, end) infinite;
}
.mgw-attract-hand svg { width: 100%; height: 100%; }
@keyframes mgw-attract-drag {
  0%   { transform: translateX(-64px) rotate(-10deg); }
  50%  { transform: translateX(64px)  rotate(10deg); }
  100% { transform: translateX(-64px) rotate(-10deg); }
}
.mgw-attract-trail {
  width: 230px;
  height: 0;
  border-bottom: 3px dotted rgba(255, 255, 255, 0.45);
  border-radius: 999px;
}
.mgw-attract-title {
  font-family: var(--mgw-font-heading);
  font-weight: 900;
  letter-spacing: 0.01em;
  font-size: clamp(1.9rem, 3vw, 2.8rem);
  color: var(--mgw-ink);
  text-align: center;
  text-shadow: 0 4px 24px rgba(0, 0, 0, 0.55);
}
/* Controls callout — same display treatment as .mgw-attract-title (it's the
   second half of one message, not a footnote) with a marching cascade of three
   chevrons aimed at the controls. Parked ABOVE robot-viewer's Easy Drive deck
   (deck ≈ 21rem tall incl. its 1.6rem inset — mirror its geometry the same way
   the 'side' variant mirrors the jog panel's). */
.mgw-attract-callout {
  position: absolute;
  bottom: 23rem;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  color: var(--mgw-ink);
}
.mgw-attract-callout-text {
  font-family: var(--mgw-font-heading);
  font-weight: 900;
  /* nowrap below — caps must not add width this line cannot give back. */
  letter-spacing: 0.01em;
  font-size: clamp(1.9rem, 3vw, 2.8rem);
  text-align: center;
  text-shadow: 0 4px 24px rgba(0, 0, 0, 0.55);
  white-space: nowrap;
}
.mgw-attract-callout-arrows {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.mgw-attract-callout-chevron {
  width: 26px;
  height: 26px;
  margin: -8px 0;
  border-right: 4px solid var(--mgw-yellow);
  border-bottom: 4px solid var(--mgw-yellow);
  transform: rotate(45deg);
  filter: drop-shadow(0 3px 10px rgba(0, 0, 0, 0.5));
  animation: mgw-attract-march-y 1.5s steps(18, end) infinite; /* ~24fps, see mgw-attract-drag */
}
/* The stagger sits ON the step grid (18 steps per 0.75s half = 1/24s): 4 and
   8 steps. At 0.18s / 0.36s the three chevrons stepped on three different
   phases — ~72 distinct repaints a second, i.e. every vsync — where on the
   grid they change together, 24 times a second. */
.mgw-attract-callout-chevron:nth-child(2) { animation-delay: 0.1667s; }
.mgw-attract-callout-chevron:nth-child(3) { animation-delay: 0.3333s; }
@keyframes mgw-attract-march-y {
  0%, 100% { opacity: 0.25; transform: translateY(0) rotate(45deg); }
  50%      { opacity: 1;    transform: translateY(8px) rotate(45deg); }
}
/* 'side' callout variant — points at a right-hand control column instead of a
   bottom dock: text + right-marching chevrons parked just left of the column
   at mid-height. The offset mirrors robot-viewer's jog panel geometry
   (right 1.5rem, width clamp(320px, 24vw, 420px)). */
.mgw-attract-callout.is-side {
  bottom: auto;
  /* Upper third, not center: the jog panel's slider stack fills the upper part
     of the column, and center would collide with the invite title. */
  top: 30%;
  left: auto;
  right: calc(1.5rem + clamp(320px, 24vw, 420px) + 1.2rem);
  transform: translateY(-50%);
  flex-direction: row;
  gap: 1rem;
}
.mgw-attract-callout.is-side .mgw-attract-callout-arrows {
  flex-direction: row;
}
.mgw-attract-callout.is-side .mgw-attract-callout-chevron {
  margin: 0 -8px;
  transform: rotate(-45deg);
  animation-name: mgw-attract-march-x;
}
@keyframes mgw-attract-march-x {
  0%, 100% { opacity: 0.25; transform: translateX(0) rotate(-45deg); }
  50%      { opacity: 1;    transform: translateX(8px) rotate(-45deg); }
}
@media (prefers-reduced-motion: reduce) {
  .mgw-attract-hand,
  .mgw-attract-callout-chevron { animation: none; }
}

/* ── Scrollbars (kiosk-updates brief, 3D sculpt viewer §2) ──────────────────
   Chromium's default scrollbar is a gray desktop artifact on the branded
   purple surfaces (About panel, Browse grid, any overflowing card). Restyle
   it everywhere the shared stylesheet reaches: slim rail, no buttons, a
   soft ink thumb that brightens under the finger. */
* {
  scrollbar-width: thin;                                  /* future-Chromium/Firefox path */
  scrollbar-color: rgba(255, 255, 255, 0.22) transparent;
}
*::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
*::-webkit-scrollbar-track {
  background: transparent;
}
*::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.22);
  border-radius: 999px;
  /* Transparent border shrinks the visible pill inside the rail so it floats
     like the rest of the pill chrome instead of touching the panel edge. */
  border: 2px solid transparent;
  background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover,
*::-webkit-scrollbar-thumb:active {
  background: rgba(242, 178, 33, 0.6); /* --mgw-yellow: interactive state */
  background-clip: padding-box;
}
*::-webkit-scrollbar-corner {
  background: transparent;
}

/* ── Panel subtitle ──────────────────────────────────────────────────────────
   Optional mixed-case subheading under a .mgw-panel-title. The title names the
   subject of the card ("About the Project"); this carries the specific thing it
   is about (the sculpt's name). Subheading role: Futura, mixed case — so it is
   explicitly NOT uppercased the way the h1–h3 heading rule does. */
.mgw-panel-subtitle {
  margin: 0.25rem 0 0;
  font-family: var(--mgw-font-heading);
  font-weight: 700;
  font-size: 1.15rem;
  line-height: 1.2;
  letter-spacing: 0.01em;
  text-transform: none;
  color: var(--mgw-ink-dim);
}

/* ── Text bubble ─────────────────────────────────────────────────────────────
   A speech-bubble aside for explaining something sitting next to it — "why is
   this like that?" copy that belongs beside content rather than inside a card.
   Fleet-wide, so any mode can explain itself the same way.

   Composition:
     .mgw-bubble                the bubble
     .mgw-bubble-title          its heading (yellow, it is a note)
     .mgw-bubble.is-left        tail on the LEFT edge (bubble sits right of its subject)
     .mgw-bubble.is-top         tail on the TOP edge (bubble sits below its subject)
   Default (no modifier) draws no tail — use when it floats free. */
.mgw-bubble {
  position: relative;
  padding: 1rem 1.15rem;
  border-radius: var(--mgw-radius-lg);
  background: rgba(102, 45, 145, 0.32);
  border: 1px solid rgba(242, 178, 33, 0.35);
  color: var(--mgw-ink-dim);
  font-family: var(--mgw-font-body);
  font-size: 0.95rem;
  line-height: 1.45;
}
.mgw-bubble-title {
  display: block;
  margin-bottom: 0.4rem;
  font-family: var(--mgw-font-heading);
  font-weight: 700;
  font-size: 1rem;
  letter-spacing: 0.02em;
  color: var(--mgw-instruction);
}
.mgw-bubble p { margin: 0; }
.mgw-bubble p + p { margin-top: 0.6rem; }

/* Tails are drawn as a rotated square straddling the border, so the bubble's
   own border/background carry through and only the outer two edges show. */
.mgw-bubble.is-left::before,
.mgw-bubble.is-top::before {
  content: "";
  position: absolute;
  width: 14px;
  height: 14px;
  background: inherit;
  border: inherit;
  transform: rotate(45deg);
}
.mgw-bubble.is-left::before {
  left: -8px;
  top: 2.1rem;
  border-right: none;
  border-top: none;
}
.mgw-bubble.is-top::before {
  top: -8px;
  left: 2.1rem;
  border-right: none;
  border-bottom: none;
}
