/* =======================================================================
   Rules — Live Rule Evaluation animation. Self-contained, scoped stylesheet.

   Every selector is namespaced under `.sift-rules-liveeval`. The bundle's JS mounts
   a <div class="sift-rules-liveeval demo-stage">…</div> root, so no rule in this
   file can match anything outside the widget — and nothing in the host
   page's stylesheet can override widget internals unless it ALSO scopes
   under `.sift-rules-liveeval`.

   The host page only needs to:
     1. Provide an element with id="rules-liveeval-root" for React to mount into.
     2. Load React 18 + ReactDOM 18 BEFORE animation-2.js.
     3. Load IBM Plex Sans + IBM Plex Mono. This file imports them from
        Google Fonts; remove the @import below if you self-host the fonts.

   No other dependencies. No shared CSS. No other animation files referenced.
   ======================================================================= */

@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans:wght@400;500;600;700&display=swap");

/* -----------------------------------------------------------------------
   Tokens — scoped to the widget root. Declared on .sift-rules-liveeval rather than
   :root so they cascade only to descendants of the widget and never collide
   with the host page's design tokens.
   ----------------------------------------------------------------------- */
.sift-rules-liveeval {
  /* Brand */
  --sift-orange:        #F04A01;
  --sift-orange-bright: #FF5722;
  --sift-orange-deep:   #EE4120;
  --rubber-black:       #1B1D1F;
  --vanta:              #000000;
  --steel:              #726E6E;
  --titanium:           #E1D7D0;
  --ceramic:            #EEEFEC;
  --lunar:              #848582;

  /* Gray scale */
  --gray-100: #111111;
  --gray-90:  #222222;
  --gray-80:  #353534;
  --gray-70:  #4B4C4A;
  --gray-60:  #6A6B68;
  --gray-50:  #848582;
  --gray-40:  #9E9F9C;
  --gray-30:  #BABAB6;
  --gray-20:  #D4D4D0;
  --gray-10:  #EEEFEC;

  /* Channels — telemetry plot lines. RW_Speed_X reads as red; RW_Speed_Z
     reads as a distinct warm orange so it doesn't collide with the brand
     orange used for annotations & "live". */
  --ch-red:    #FA4D56;
  --ch-orange: #F89E37;

  /* Yellow — the "Live" chip on the rule row. Soft yellow ground with a
     darker yellow ink so the chip reads as a status, not as fire. */
  --yellow-bg: #FCEFA8;
  --yellow-ink: #7A6300;

  /* Recording dot — the live indicator above the plot. Slightly warmer
     than channel red so they don't read as the same swatch. */
  --rec-red: #E62325;
}

/* Inherit-safe box model inside the widget only. */
.sift-rules-liveeval,
.sift-rules-liveeval *,
.sift-rules-liveeval *::before,
.sift-rules-liveeval *::after {
  box-sizing: border-box;
}

/* -----------------------------------------------------------------------
   Stage frame — the dark canvas the animation draws onto.
   `.sift-rules-liveeval.demo-stage` covers the common case where the React root
   div carries BOTH classes; `.sift-rules-liveeval .demo-stage` covers a future
   layout where the wrapper sits outside the stage element.
   ----------------------------------------------------------------------- */
.sift-rules-liveeval.demo-stage,
.sift-rules-liveeval .demo-stage {
  background: #131416;
  border: 1px solid #2A2C2E;
  border-radius: 0;
  aspect-ratio: 16 / 9;
  width: 100%;
  position: relative;
  overflow: hidden;
  color: var(--ceramic);
  font-family: "IBM Plex Sans", system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  container-type: inline-size;
}

/* Dot grid behind everything — 32px spacing, low-opacity ceramic dots. */
.sift-rules-liveeval.demo-stage::before,
.sift-rules-liveeval .demo-stage::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(rgba(255, 255, 255, 0.14) 1px, transparent 1px);
  background-size: 32px 32px;
  background-position: center center;
  pointer-events: none;
}

/* Generic clip transition wrapper — fades content groups in/out as clips swap. */
.sift-rules-liveeval .clip {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 480ms cubic-bezier(0.2, 0, 0, 1);
}
.sift-rules-liveeval .clip.in {
  opacity: 1;
  pointer-events: auto;
}

/* =======================================================================
   Clip 1 — zoomed-in rule row + Live toggle.
   Sits at "zoom level 2": only Name + Asset + the Enable-Live row are
   visible at this zoom. The expression column is hidden.
   ======================================================================= */
.sift-rules-liveeval .c1-stack {
  width: 100%;
  color: var(--ceramic);
  /* Indent the content from the left so the rule sits where it would in
     the actual rule list, but let the row's border-bottom extend all the
     way to the stage's right edge — rows look like they're being cropped
     by the camera. */
  padding-left: 11%;
  padding-right: 0;
}
.sift-rules-liveeval .c1-list { width: 100%; }

.sift-rules-liveeval .c1-header {
  display: grid;
  /* Two left-aligned content columns + a flexible spacer. The header's
     border-bottom spans the full row width. */
  grid-template-columns: minmax(0, max-content) max-content 1fr;
  column-gap: 56px;
  padding: 0 0 14px;
  border-bottom: 1px solid #2A2C2E;
}
.sift-rules-liveeval .c1-header > span {
  font-family: "IBM Plex Mono", monospace;
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--lunar);
}

.sift-rules-liveeval .c1-row {
  display: grid;
  grid-template-columns: minmax(0, max-content) max-content 1fr;
  column-gap: 56px;
  align-items: center;
  padding: 16px 0;
  border-bottom: 1px solid #1F2123;
}

.sift-rules-liveeval .c1-name {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  font-family: "IBM Plex Sans", sans-serif;
  font-weight: 500;
  font-size: 16px;
  line-height: 1.25;
  color: var(--ceramic);
  min-width: 0;
}
.sift-rules-liveeval .c1-name-text {
  min-width: 0;
  text-wrap: balance;
}

.sift-rules-liveeval .c1-chip {
  display: inline-flex;
  align-items: center;
  padding: 4px 8px;
  font-family: "IBM Plex Mono", monospace;
  font-size: 11px;
  color: var(--gray-30);
  background: #2A2C2E;
  border-radius: 4px;
  letter-spacing: 0.04em;
  flex: 0 0 auto;
}

/* Yellow "Live" chip — tertiary yellow ground, primary yellow ink. */
.sift-rules-liveeval .c1-chip.live-chip {
  color: var(--yellow-ink);
  background: var(--yellow-bg);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 500;
  font-size: 10px;
  padding: 3px 7px;
  opacity: 0;
  transform: scale(0.6);
  transform-origin: left center;
  transition: opacity 280ms cubic-bezier(0.2, 0, 0, 1),
              transform 320ms cubic-bezier(0.2, 0, 0, 1);
}
.sift-rules-liveeval .c1-chip.live-chip.show {
  opacity: 1;
  transform: scale(1);
}

/* Expression column suppressed at this zoom level (kept in DOM if rendered). */
.sift-rules-liveeval .c1-expr { display: none; }

/* The "Enable Live Rule Evaluation" detail row sits under the rule. */
.sift-rules-liveeval .c1-detail {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 18px 0 0 0;
}
.sift-rules-liveeval .c1-check {
  width: 18px;
  height: 18px;
  border: 1.5px solid var(--steel);
  border-radius: 4px;
  background: transparent;
  display: grid;
  place-items: center;
  cursor: pointer;
  flex: 0 0 auto;
  transition: background 140ms cubic-bezier(0.2, 0, 0, 1),
              border-color 140ms cubic-bezier(0.2, 0, 0, 1);
}
.sift-rules-liveeval .c1-check.hover:not(.checked) {
  border-color: #B0AAA8;
  background: #1D1F21;
}
.sift-rules-liveeval .c1-check.checked {
  background: var(--sift-orange);
  border-color: var(--sift-orange);
}
.sift-rules-liveeval .c1-check svg {
  opacity: 0;
  transform: scale(0.4);
  transition: opacity 180ms cubic-bezier(0.2, 0, 0, 1),
              transform 220ms cubic-bezier(0.2, 0, 0, 1);
}
.sift-rules-liveeval .c1-check.checked svg {
  opacity: 1;
  transform: scale(1);
}
.sift-rules-liveeval .c1-detail-label {
  font-family: "IBM Plex Sans", sans-serif;
  font-size: 13px;
  color: var(--ceramic);
  line-height: 18px;
  user-select: none;
}

/* =======================================================================
   Clips 2 & 3 — telemetry plot.
   ======================================================================= */
.sift-rules-liveeval .plot-stack {
  width: 82%;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.sift-rules-liveeval .plot-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 22px;
}
.sift-rules-liveeval .plot-bar-left {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Segmented control — LIVE / TIME RANGE. */
.sift-rules-liveeval .seg {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px;
  font-family: "IBM Plex Mono", monospace;
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--gray-50);
  background: transparent;
  border: 1px solid #2A2C2E;
  border-radius: 4px;
  cursor: pointer;
  transition: color 140ms cubic-bezier(0.2, 0, 0, 1),
              background 140ms cubic-bezier(0.2, 0, 0, 1),
              border-color 140ms cubic-bezier(0.2, 0, 0, 1);
}
.sift-rules-liveeval .seg.active,
.sift-rules-liveeval .seg.live-on {
  color: var(--ceramic);
  background: #1F2123;
  border-color: #3A3B38;
}
.sift-rules-liveeval .seg .rec-dot {
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: var(--gray-60);
  transition: background 200ms ease, box-shadow 200ms ease;
}
.sift-rules-liveeval .seg.live-on .rec-dot {
  background: var(--rec-red);
  box-shadow: 0 0 0 0 rgba(230, 35, 37, 0.45);
  animation: sift-rules-liveeval-rec-pulse 1.4s infinite;
}

/* X-axis time labels — drawn as SVG <text> inside the plot SVG, in the
   PAD_BOTTOM strip below the data plot. Mono ink, low contrast. */
.sift-rules-liveeval .axis-time {
  font-family: "IBM Plex Mono", monospace;
  font-size: 10px;
  fill: var(--gray-40);
  letter-spacing: 0.04em;
}

/* Plot foot — sits below the SVG; holds the channel legend. */
.sift-rules-liveeval .plot-foot {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding: 4px 2px 0;
}

/* Channel legend — square swatches, mono caps. */
.sift-rules-liveeval .plot-legend {
  display: flex;
  align-items: center;
  gap: 14px;
  font-family: "IBM Plex Mono", monospace;
  font-size: 10px;
  letter-spacing: 0.08em;
  color: var(--gray-40);
}
.sift-rules-liveeval .plot-legend .ch-key {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
.sift-rules-liveeval .plot-legend .swatch {
  width: 9px;
  height: 9px;
  border-radius: 2px;
  flex: 0 0 auto;
}

/* Plot panel — tab + body, matches the panel vocabulary used in the
   Root Cause Analysis · Sync animation. The tab attaches visually to
   the top of the data box; the seam is hidden by a 1px negative
   margin so the body's top border doesn't draw through the tab. */
.sift-rules-liveeval .plot-panel {
  display: flex;
  flex-direction: column;
  width: 100%;
}
.sift-rules-liveeval .plot-head {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  padding: 5px 12px;
  background: #0E0F11;
  border-top: 1px solid #2A2C2E;
  border-left: 1px solid #2A2C2E;
  border-right: 1px solid #2A2C2E;
  margin-bottom: -1px;
  position: relative;
  z-index: 2;
  flex-shrink: 0;
}
.sift-rules-liveeval .plot-name {
  font-family: "IBM Plex Mono", monospace;
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--gray-30);
  white-space: nowrap;
}
.sift-rules-liveeval .plot-name .plot-tag {
  margin-left: 6px;
  color: var(--gray-60);
}

/* SVG plot wrapper. Square corners; the tab sits flush on top. */
.sift-rules-liveeval .plot-wrap {
  position: relative;
  width: 100%;
  background: #0E0F11;
  border: 1px solid #2A2C2E;
  border-radius: 0;
  aspect-ratio: 580 / 250;
  overflow: hidden;
}
.sift-rules-liveeval .plot-svg {
  width: 100%;
  height: 100%;
  display: block;
  overflow: hidden;
}

/* Axis lines + grid + tick text — all targeted by class, inside the SVG. */
.sift-rules-liveeval .axis-tick {
  font-family: "IBM Plex Mono", monospace;
  font-size: 11px;
  fill: var(--gray-50);
  letter-spacing: 0.06em;
}
.sift-rules-liveeval .axis-line {
  stroke: #2A2C2E;
  stroke-width: 1;
}
.sift-rules-liveeval .grid-line {
  stroke: rgba(255, 255, 255, 0.04);
  stroke-width: 1;
}

/* =======================================================================
   Annotation — rule-break highlight box + rotated tab.
   The whole annotation pops in together when the rule's evaluator
   confirms the break. The keyed remount in the JSX fires the animation.

   The rect itself just fades in (it lives inside a transformed group,
   where extra CSS transforms compose unpredictably); the tab gets the
   scale-pop because it sits outside that transform group.
   ======================================================================= */
.sift-rules-liveeval .anno-tab-rect { fill: var(--sift-orange); }
.sift-rules-liveeval .anno-tab-text {
  font-family: "IBM Plex Mono", monospace;
  font-size: 9px;
  letter-spacing: 0.02em;
  fill: #FFFFFF;
  font-weight: 500;
}
.sift-rules-liveeval .anno-pop-host {
  animation: sift-rules-liveeval-anno-pop 280ms cubic-bezier(0.2, 0, 0, 1);
}
.sift-rules-liveeval .anno-tab-host {
  transform-box: fill-box;
  transform-origin: 50% 0%;
  animation: sift-rules-liveeval-tab-pop 320ms cubic-bezier(0.2, 0, 0, 1);
}

/* =======================================================================
   Demo cursor — lifted from animation 1.
   ======================================================================= */
.sift-rules-liveeval .cursor {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  opacity: 0;
  z-index: 50;
  pointer-events: none;
  transition: transform 760ms cubic-bezier(0.2, 0, 0, 1),
              opacity 280ms ease-out;
}
.sift-rules-liveeval .cursor.fast {
  transition: transform 420ms cubic-bezier(0.2, 0, 0, 1),
              opacity 220ms ease-out;
}
.sift-rules-liveeval .cursor.visible { opacity: 1; }

.sift-rules-liveeval .cursor-icon {
  position: absolute;
  pointer-events: none;
  filter: drop-shadow(0 2px 2px rgba(0, 0, 0, 0.55));
}
.sift-rules-liveeval .cursor-icon.arrow {
  width: 44px;
  height: 44px;
  top: -9.625px;
  left: -13.75px;
  display: block;
  /* Tip of the cursor is at (13.75, 9.625) inside the 44×44 box —
     set transform-origin there so click-scale pivots from the tip. */
  transform-origin: 13.75px 9.625px;
}

/* Click scale-down-up — fires while .cursor has .clicking; runs once,
   ~220ms total. No ripple ring — the icon itself dips and returns. */
.sift-rules-liveeval .cursor.clicking .cursor-icon.arrow {
  animation: sift-rules-liveeval-cursor-click 220ms cubic-bezier(0.2, 0, 0, 1);
}

/* =======================================================================
   Keyframes — top-level (animation names cannot be scoped inside a
   selector). All names prefixed with `sift-rules-liveeval-` so they can't collide
   with keyframes the host page or other animations define.
   ======================================================================= */
@keyframes sift-rules-liveeval-rec-pulse {
  0%   { box-shadow: 0 0 0 0   rgba(230, 35, 37, 0.55); }
  70%  { box-shadow: 0 0 0 5px rgba(230, 35, 37, 0); }
  100% { box-shadow: 0 0 0 0   rgba(230, 35, 37, 0); }
}
@keyframes sift-rules-liveeval-anno-pop {
  0%   { opacity: 0; }
  100% { opacity: 1; }
}
@keyframes sift-rules-liveeval-tab-pop {
  0%   { opacity: 0; transform: scale(0.5); }
  100% { opacity: 1; transform: scale(1); }
}
@keyframes sift-rules-liveeval-cursor-click {
  0%   { transform: scale(1); }
  45%  { transform: scale(0.82); }
  100% { transform: scale(1); }
}
