/* Cichocki Advisory — rotating hero metaphors
   Ten frames, one every 10s, crossfaded. Each frame argues the same claim a
   different way, so a visitor who stays a moment gets the point from a second
   angle rather than the same picture louder.

   WHY TWO LAYERS AND NOT TEN
   A ten-layer CSS keyframe carousel needs every image decoded before the first
   frame is right, which is ~645 KB of hero artwork on a marketing page. Two
   layers ping-pong instead: one holds what you see, the other loads what is
   next and fades in over it. Exactly one image is fetched per turn.

   WHY THE <img> STAYS
   The existing hero <img> carries srcset + fetchpriority=high and is the LCP
   element. It is untouched, so first paint is byte-identical to before the
   rotator existed. These layers sit ON TOP of it and only ever fade in after
   load. With JS off, or reduced-motion set, the page is exactly what it was.

   WHY NOTHING SHOWS THROUGH
   The incoming layer is moved to the end of the container and fades in while
   the outgoing layer stays fully opaque beneath it. An earlier version faded
   both at once, so mid-transition the base <img> was briefly visible through
   the pair — Jan caught it. Ordering is done with appendChild rather than
   z-index precisely because the scrim below must keep painting last.

   WHY THE SCRIM STILL WINS
   The scrim lives on .sov-hero-art::after. A pseudo-element generates as the
   last child, so it paints above these layers no matter how many there are —
   text protection cannot be undercut by adding frames. Every frame is
   nonetheless contrast-tested individually; see the deploy gate. */

/* The frame image arrives as a custom property rather than as background-image
   directly, so CSS can compose a wash OVER it per breakpoint. Setting
   background-image from the script would leave no room for that.

   Declared on the PARENT, used on the child: a custom property set in the same
   rule that consumes it cannot be overridden by a more specific ancestor rule
   (this is exactly what silently disabled the keystone scrim in the section
   work). Declaring it here keeps per-breakpoint and future per-frame overrides
   working. */
.sov-hero-art{
  /* DESKTOP. The static hero was tuned for ONE image; ten frames include
     brighter ones. Measured against the lead paragraph, the three brightest
     (controls-engaged, fixed-reference, designed-model) landed at 4.09-4.38
     against a 4.5 floor -- a real failure, not an artefact.

     Every frame is composed right-of-centre by design, so damping the copy
     column and letting the right side run clear costs almost no artwork. */
  --rot-wash:linear-gradient(90deg,
    rgba(10,11,15,.48) 0%,
    rgba(10,11,15,.43) 55%,
    rgba(10,11,15,.16) 80%,
    rgba(10,11,15,0)   100%);
  --rot-pos:76% 42%;
}

.sov-hero-art .ca-rot{
  position:absolute;
  inset:0;
  z-index:0;
  opacity:0;
  pointer-events:none;
  background-image:var(--rot-wash), var(--rot-src, none);
  background-repeat:no-repeat,no-repeat;
  background-size:cover,cover;
  /* matches the <img> object-position exactly, so a crossfade does not shift
     the subject sideways mid-transition */
  background-position:var(--rot-pos),var(--rot-pos);
  transition:opacity 1400ms ease-in-out;
  will-change:opacity;
}

.sov-hero-art .ca-rot.is-on{opacity:1}

/* MOBILE. The copy runs full width and the headline sits at the top, so a
   frame with a bright subject near the top centre lands directly behind it.
   Measured: the balance-scale frame put its brass beam under the h1 at 2.63:1
   against a 3.0 floor, and the attestation-seal frame at 2.30:1 -- its gold
   highlight is effectively blown out, so the background under the headline
   sits at ~0.41 relative luminance and needs roughly 0.82 wash to clear.
   Hence .86 at the very top, tapering to nothing by 88%: the band behind the
   headline is crushed, the lower two thirds of the frame still read.
   A wash on the rotating layer fixes every frame rather than one image. */
@media (max-width:720px){
  .sov-hero-art{
    --rot-pos:68% 45%;
    --rot-wash:linear-gradient(180deg,
      rgba(10,11,15,.86) 0%,
      rgba(10,11,15,.64) 30%,
      rgba(10,11,15,.28) 56%,
      rgba(10,11,15,0)   88%);
  }
}

/* A rotating background is motion. Someone who has asked for less of it gets
   the single static hero.

   The layers ARE created (the script must keep its matchMedia listener live so
   that turning reduce off mid-session still works), but they are display:none
   here and the script never assigns them an image — no turn is ever scheduled.
   So: mounted, hidden, and zero bytes fetched. The script enforces the same
   thing; this rule is the belt to its braces. */
@media (prefers-reduced-motion:reduce){
  .sov-hero-art .ca-rot{
    display:none !important;
    transition:none !important;
  }
}

/* Printing a fading background is meaningless and costs ink. */
@media print{
  .sov-hero-art .ca-rot{display:none !important}
}

/* ── pause control (WCAG 2.2.2) ─────────────────────────────────────────
   The first draft had no control and argued the rotator was decorative and
   therefore exempt. Codex rejected that reasoning (consult 20260802T183439Z):
   the background auto-updates indefinitely alongside page content, and
   prefers-reduced-motion only covers people who have set it. So: a real
   button, reachable by keyboard, labelled by state, remembered across visits.

   It is injected by the script, so it exists only when something is actually
   moving — a pause button next to a static image would be a lie.

   Placed bottom-LEFT, not bottom-right. The site's chat launcher is
   position:fixed at the bottom-right of the VIEWPORT, so anything anchored to
   the hero's bottom-right corner collides with it at every window size — the
   first attempt did exactly that and the control ended up underneath the
   launcher. The left gutter is the darkest part of the hero and is free. */
.sov-hero{position:relative}

.ca-rot-toggle{
  position:absolute;
  left:24px;
  bottom:22px;
  z-index:3;                      /* above the artwork AND the scrim */
  width:36px;
  height:36px;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  padding:0;
  border-radius:999px;
  cursor:pointer;
  color:rgba(232,234,240,.72);
  background:rgba(10,11,15,.62);
  border:1px solid rgba(216,190,134,.28);
  -webkit-backdrop-filter:blur(6px);
  backdrop-filter:blur(6px);
  transition:color .18s ease, border-color .18s ease, background-color .18s ease;
}
.ca-rot-toggle svg{width:15px;height:15px;fill:currentColor;display:block}

.ca-rot-toggle:hover{
  color:#D8BE86;
  border-color:rgba(216,190,134,.62);
  background:rgba(10,11,15,.80);
}

/* Never rely on hover alone: the control must be obvious to a keyboard user. */
.ca-rot-toggle:focus-visible{
  outline:2px solid #D8BE86;
  outline-offset:3px;
  color:#D8BE86;
}

@media (max-width:720px){
  .ca-rot-toggle{left:16px;bottom:16px;width:40px;height:40px}   /* 40px touch target */
}

@media print{ .ca-rot-toggle{display:none !important} }

/* ── frame number badge — TEMPORARY REVIEW AID (2026-08-02) ─────────────
   Added so Jan can score each frame by number. REMOVE with the matching
   REVIEW block in the script once the review is finished; ?frames=0 hides
   it without a deploy in the meantime.

   Upper-RIGHT as asked. It sits above the scrim (z-index 3, same tier as the
   pause control) so it stays readable over every frame, and it carries its own
   solid ground rather than relying on whatever artwork is behind it. */
.ca-rot-badge{
  position:absolute;
  top:18px;
  right:18px;
  z-index:3;
  display:flex;
  align-items:baseline;
  gap:4px;
  padding:7px 12px 7px 13px;
  border-radius:999px;
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  line-height:1;
  color:#E8EAF0;
  background:rgba(10,11,15,.86);
  border:1px solid rgba(216,190,134,.45);
  -webkit-backdrop-filter:blur(6px);
  backdrop-filter:blur(6px);
  pointer-events:none;
  white-space:nowrap;
}
.ca-rot-badge b{font-size:19px;font-weight:700;color:#D8BE86;letter-spacing:.02em}
.ca-rot-badge span{font-size:12px;color:rgba(232,234,240,.55)}
.ca-rot-badge i{
  font-style:normal;
  font-size:11px;
  letter-spacing:.06em;
  text-transform:uppercase;
  color:rgba(232,234,240,.78);
  margin-left:7px;
  padding-left:9px;
  border-left:1px solid rgba(232,234,240,.20);
}

@media (max-width:720px){
  .ca-rot-badge{top:12px;right:12px;padding:6px 10px}
  .ca-rot-badge b{font-size:16px}
  .ca-rot-badge i{display:none}          /* number only; no room for the name */
}

@media print{ .ca-rot-badge{display:none !important} }
