/* ==========================================================================
   AI Readiness Framework — component layout
   All geometry is taken directly from the Figma node (component set
   6868:4978, variants "step 1".."step 5") in *design pixels*, canvas
   986 × 1196. Every child is positioned with calc(var(--u) * <design-px>),
   where --u is 1 design pixel expressed in container-query width units —
   same fixed-composition scaling technique used across the other LEAP
   prototypes in this project (see leap-pillars-prototype/css/components.css).
   ========================================================================== */

.framework-stage {
  position: relative;
  width: min(100%, 720px);
  aspect-ratio: 986 / 1196;
  margin-inline: auto;
  container-type: inline-size;
  --u: calc(100cqw / 986);
  isolation: isolate;
  /* The diagram's OWN dark backdrop — independent of the page's own
     background (which is intentionally transparent, for embedding; see
     styles.css). Every background-circle asset is a big-but-not-quite-
     edge-to-edge SVG, and the ring labels/descriptions render in white at
     80% opacity: with no backdrop of their own, a moment where nothing
     opaque has painted yet (a hover firing before that step's SVGs have
     finished loading, for instance — this diagram's six-shape composite
     backgrounds for steps 2/3 are considerably heavier than the flattened
     ones) shows through to whatever the host page looks like there. On a
     light host page that reads as the whole diagram "breaking" — labels
     and descriptions going near-illegible — even though every class/state
     is actually correct underneath. This is that guaranteed dark base
     layer, always present regardless of asset load timing.
     Figma's own frame clips its contents to the 986×1196 canvas by
     default, and this needs to match that: the outermost background
     shape's shadow bleed (see .bg-shape--06) runs past the canvas's own
     bottom edge by design. Without clipping it here, that bleed — even
     while fully transparent at rest, since it's still in normal layout —
     was inflating the page's scrollHeight past the diagram's actual
     visible height, which is exactly what the postMessage height-
     reporting script in index.html measures for embedding. */
  background: var(--color-stage-bg);
  overflow: hidden;
}

/* ---------------------------------------------------------------------- */
/* Decorative orbit ring — the small dashed arc-and-arrow motif that      */
/* circles the AI icon. Persists identically across all five states.     */
/* ---------------------------------------------------------------------- */

.orbit-ring {
  position: absolute;
  left: calc(var(--u) * 390);
  top: calc(var(--u) * 105);
  width: calc(var(--u) * 204.714);
  height: calc(var(--u) * 204.056);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: var(--z-orbit);
  pointer-events: none;
}

.orbit-ring__inner {
  position: relative;
  width: calc(var(--u) * 170.313);
  height: calc(var(--u) * 169.428);
  transform: rotate(166.7deg);
  animation: orbit-spin var(--motion-orbit) linear infinite;
  transform-origin: center center;
}

.orbit-ring__arc {
  position: absolute;
  width: calc(var(--u) * 82.696);
  height: calc(var(--u) * 82.696);
  display: block;
}

.orbit-ring__arc--tl { left: 0; top: 0; }
.orbit-ring__arc--tr { left: calc(var(--u) * 88.34); top: 0; transform: rotate(90deg); }
.orbit-ring__arc--bl { left: 0; top: calc(var(--u) * 86.73); transform: rotate(-90deg); }
.orbit-ring__arc--br { left: calc(var(--u) * 88.34); top: calc(var(--u) * 86.73); transform: rotate(180deg); }

@keyframes orbit-spin {
  from { transform: rotate(166.7deg); }
  to   { transform: rotate(526.7deg); }
}

/* ---------------------------------------------------------------------- */
/* Background circle artwork — five states cross-fade via opacity.        */
/* Steps 1, 4 and 5 are single flattened Figma exports; steps 2 and 3     */
/* are six separately-exported ring shapes stacked at their Figma         */
/* positions (Figma kept those two variants unflattened; reproduced      */
/* faithfully rather than re-flattened by hand — see QA-REPORT.md).      */
/* ---------------------------------------------------------------------- */

.bg-field {
  position: absolute;
  left: calc(var(--u) * 16.88);
  top: calc(var(--u) * 133.8);
  width: calc(var(--u) * 952.249);
  height: calc(var(--u) * 1031.202);
  z-index: var(--z-background);
}

.bg-layer {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity var(--motion-step) var(--ease-standard);
}

.bg-layer.is-visible { opacity: 1; }

.bg-layer--flat img {
  position: absolute;
  display: block;
  max-width: none;
  /* Each state below sets top/left plus an explicit width/height —
     deliberately NOT a 4-sided `inset`. For an absolutely positioned
     replaced element (an <img>), setting all four inset sides at once is
     an over-constrained box: browsers resolve that by discarding the
     computed size entirely and falling back to the image's raw intrinsic
     pixel size (986 × 1194.67, unscaled by --u), which rendered the
     artwork at a fixed, un-responsive size instead of the intended bleed
     size — visible as the ring strokes cutting through the ring labels
     instead of sitting between them. Pinning size directly via
     width/height (both already expressed in --u) avoids that conflict.
     See QA-REPORT.md. */
}

/* The width/height/position below encode Figma's percentage bleed of the
   952.249 × 1031.202 background box, pre-resolved to design px
   (percentage × the box's own width/height, then added back to the box's
   own dimensions) so each still scales uniformly with --u like every
   other measurement on the stage. Source percentages, for traceability:
     step 1  inset(-12.93%  -1.77%  -2.92%  -1.77%)
     step 4  inset(-12.93%  -1.77%  -5.84%  -1.77%)
     step 5  inset(-12.93%  -3.87%  -6.80%  -3.87%)               */
.bg-layer[data-bg-for="1"] img { top: calc(var(--u) * -133.33); left: calc(var(--u) * -16.85); width: calc(var(--u) * 985.95); height: calc(var(--u) * 1194.64); }
.bg-layer[data-bg-for="4"] img { top: calc(var(--u) * -133.33); left: calc(var(--u) * -16.85); width: calc(var(--u) * 985.95); height: calc(var(--u) * 1224.75); }
.bg-layer[data-bg-for="5"] img { top: calc(var(--u) * -133.33); left: calc(var(--u) * -36.85); width: calc(var(--u) * 1025.95); height: calc(var(--u) * 1234.65); }

.bg-shape {
  position: absolute;
  display: block;
  max-width: none;
}

/* Each shape wrapper in Figma has an INNER element carrying its own
   percentage bleed inset (drop-shadow/blur bounding box), exactly like
   the flat step 1/4/5 backgrounds — this was missed on the first pass:
   only the outer (un-bled) wrapper box size was used, which rendered
   every circle smaller than intended and shifted its boundary onto the
   ring label below it. Values here are that inset pre-resolved to design
   px (percentage × the wrapper's own width/height, added back to the
   wrapper's own size and position) so they still scale with --u. Shapes
   06/05/02 carry the same bleed in both step 2 and step 3; 04/03/01
   differ because whichever one is the "solid, currently active" circle
   gets a bigger shadow than when it's a plain outline. */
.bg-shape--06 { width: calc(var(--u) * 986.08); height: calc(var(--u) * 1012.52); left: calc(var(--u) * -16.92); top: calc(var(--u) * 78.99); }
.bg-shape--05 { width: calc(var(--u) * 816.03); height: calc(var(--u) * 842.54); left: calc(var(--u) * 68.11); top: calc(var(--u) * 78.95); }
.bg-shape--02 { width: calc(var(--u) * 624.65); height: calc(var(--u) * 644.54); left: calc(var(--u) * 174.65); top: calc(var(--u) * -133.33); }

.bg-layer--composite[data-bg-for="2"] .bg-shape--04 { width: calc(var(--u) * 644.87); height: calc(var(--u) * 671.42); left: calc(var(--u) * 153.69); top: calc(var(--u) * 78.94); }
.bg-layer--composite[data-bg-for="2"] .bg-shape--03 { width: calc(var(--u) * 507.10); height: calc(var(--u) * 507.10); left: calc(var(--u) * 221.07); top: calc(var(--u) * 75.32); }
.bg-layer--composite[data-bg-for="2"] .bg-shape--01 { width: calc(var(--u) * 286.90); height: calc(var(--u) * 286.90); left: calc(var(--u) * 331.48); top: calc(var(--u) * 75.33); }

.bg-layer--composite[data-bg-for="3"] .bg-shape--04 { width: calc(var(--u) * 684.88); height: calc(var(--u) * 684.88); left: calc(var(--u) * 133.68); top: calc(var(--u) * 75.36); }
.bg-layer--composite[data-bg-for="3"] .bg-shape--03 { width: calc(var(--u) * 467.08); height: calc(var(--u) * 467.08); left: calc(var(--u) * 241.08); top: calc(var(--u) * 74.08); }
.bg-layer--composite[data-bg-for="3"] .bg-shape--01 { width: calc(var(--u) * 286.90); height: calc(var(--u) * 313.40); left: calc(var(--u) * 331.48); top: calc(var(--u) * 78.95); }

/* ---------------------------------------------------------------------- */
/* Intro node — always visible, unaffected by step state.                 */
/* ---------------------------------------------------------------------- */

.intro-node {
  position: absolute;
  left: calc(var(--u) * 389.34);
  top: calc(var(--u) * 154.29);
  width: calc(var(--u) * 205.517);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--u) * 19.286);
  padding: calc(var(--u) * 10.848);
  z-index: var(--z-intro);
  text-align: center;
}

.intro-node__badge {
  width: calc(var(--u) * 86.645);
  height: calc(var(--u) * 86.645);
  border-radius: 999px;
  background: #fff;
  border: calc(var(--u) * 6.027) solid var(--color-intro-ring);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.intro-node__badge img {
  width: calc(var(--u) * 38.339);
  height: calc(var(--u) * 38.339);
}

/* Figma nests title+description in their own inner wrapper with a
   smaller gap (10.848) than the gap between the badge and that wrapper
   (19.286) — the intro-node's flat flex gap had been applying the larger
   value to BOTH, pushing the description an extra ~8.4 design units
   lower than intended and past the circle it's meant to sit inside. */
.intro-node__text {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--u) * 10.848);
  width: 100%;
}

.intro-node__title {
  margin: 0;
  font-family: var(--font-family);
  font-weight: var(--font-weight-regular);
  font-size: calc(var(--u) * 22.3 * var(--intro-scale, 1));
  line-height: calc(var(--u) * 27.121 * var(--intro-scale, 1));
  letter-spacing: calc(var(--u) * -0.669);
  color: var(--color-text-active);
  text-transform: capitalize;
  transition: font-size var(--motion-label) var(--ease-standard), line-height var(--motion-label) var(--ease-standard);
}

.intro-node__desc {
  margin: 0;
  font-family: var(--font-family);
  font-weight: var(--font-weight-medium);
  font-size: calc(var(--u) * 9.643 * var(--intro-scale, 1));
  line-height: calc(var(--u) * 13.259 * var(--intro-scale, 1));
  color: var(--color-text-desc);
  max-width: calc(var(--u) * 182.615);
  transition: font-size var(--motion-label) var(--ease-standard), line-height var(--motion-label) var(--ease-standard);
}

/* ---------------------------------------------------------------------- */
/* Ring nodes — the four clickable steps.                                 */
/* ---------------------------------------------------------------------- */

.ring-node {
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: calc(var(--u) * 8);
  padding: calc(var(--u) * 9) calc(var(--u) * 10.976) calc(var(--u) * 4);
  background: none;
  border: 0;
  cursor: pointer;
  font: inherit;
  color: inherit;
  text-align: center;
  border-radius: calc(var(--u) * 6.1);
  z-index: var(--z-rings);
}

.ring-node[data-ring="enterprise-architecture"] { left: calc(var(--u) * 388.13); top: calc(var(--u) * 471.91); width: calc(var(--u) * 207.928); }
.ring-node[data-ring="trusted-data"]             { left: calc(var(--u) * 389.34); top: calc(var(--u) * 665.37); width: calc(var(--u) * 205.517); }
.ring-node[data-ring="operations"]               { left: calc(var(--u) * 383.91); top: calc(var(--u) * 844.97); width: calc(var(--u) * 216.366); }
.ring-node[data-ring="people"]                   { left: calc(var(--u) * 383.91); top: calc(var(--u) * 1010.11); width: calc(var(--u) * 216.366); }

.ring-node__icon {
  width: calc(var(--u) * 56.05);
  height: calc(var(--u) * 56.05);
  border-radius: 999px;
  background: var(--color-icon-badge);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.ring-node__icon img {
  width: calc(var(--u) * 23.003);
  height: calc(var(--u) * 23.003);
}

.ring-node__label {
  margin: 0;
  font-family: var(--font-family);
  font-weight: var(--font-weight-medium);
  font-size: calc(var(--u) * 19.286);
  line-height: calc(var(--u) * 21.094);
  text-transform: capitalize;
  background: linear-gradient(90deg, var(--color-text-idle-from), var(--color-text-idle-to));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  transition: font-size var(--motion-label) var(--ease-standard),
              line-height var(--motion-label) var(--ease-standard),
              letter-spacing var(--motion-label) var(--ease-standard),
              color var(--motion-label) var(--ease-standard);
}

.ring-node[data-ring="enterprise-architecture"] .ring-node__label,
.ring-node[data-ring="trusted-data"] .ring-node__label { letter-spacing: calc(var(--u) * -0.5786); }

/* Auto-height reveal via the grid-rows 0fr -> 1fr technique: this expands
   to exactly the description's natural height (which varies per ring and
   per rendered font) instead of a guessed max-height, so the panel below
   is never overlapped regardless of copy length or font metrics. */
.ring-node__desc-wrap {
  display: grid;
  grid-template-rows: 0fr;
  width: 100%;
  opacity: 0;
  transition: grid-template-rows var(--motion-desc) var(--ease-standard),
              opacity var(--motion-desc) var(--ease-standard);
}

.ring-node__desc {
  display: block;
  overflow: hidden;
  margin: 0;
  font-family: var(--font-family);
  font-weight: var(--font-weight-medium);
  font-size: calc(var(--u) * 9.643);
  line-height: calc(var(--u) * 13.259);
  color: var(--color-text-desc);
  max-width: calc(var(--u) * 214);
  margin-inline: auto;
}

.ring-node[data-ring="enterprise-architecture"] .ring-node__desc { font-size: calc(var(--u) * 9.756); line-height: calc(var(--u) * 13.415); max-width: calc(var(--u) * 184.757); }
.ring-node[data-ring="trusted-data"] .ring-node__desc { max-width: calc(var(--u) * 193.463); }
.ring-node[data-ring="operations"] .ring-node__desc,
.ring-node[data-ring="people"] .ring-node__desc { max-width: calc(var(--u) * 213.955); }

/* Every ring drops its icon while it's the current (hovered/focused) step
   — confirmed against the Figma source for all four rings, not just
   three: each ring's own icon is conditioned on the idle branch only, so
   it disappears the moment that ring becomes current and reappears once
   it's idle or (ring 1 only) persisted after moving on. This is also what
   gives the label + description room to fit inside that ring's own
   circle band instead of spilling into the ring below (see QA-REPORT.md). */
.ring-node.is-current .ring-node__icon {
  display: none;
}

.ring-node.is-active .ring-node__label {
  background: none;
  -webkit-text-fill-color: initial;
  color: var(--color-text-active);
  font-weight: var(--font-weight-regular);
  font-size: calc(var(--u) * 21.951);
  line-height: calc(var(--u) * 25.61);
  letter-spacing: calc(var(--u) * -0.6585);
}

.ring-node.is-current .ring-node__desc-wrap {
  grid-template-rows: 1fr;
  opacity: 1;
  margin-top: calc(var(--u) * 8);
}

.ring-node:focus-visible {
  outline: 2px solid var(--color-intro-ring);
  outline-offset: 4px;
}

.ring-node:hover .ring-node__icon,
.ring-node:focus-visible .ring-node__icon {
  box-shadow: 0 0 0 calc(var(--u) * 3) rgba(238, 255, 64, 0.35);
}
