/* ==========================================================================
   IX · LINKS — hover underline system.

   Variants (body[data-rbs-links]):
     underline    hairline fades in — the shipped decision, refined (no pop)
     draw         draws left→right on enter, exits toward the right
     exit-return  resting underline slides out right while a fresh one
                  enters from the left — one continuous gesture
     highlight    a tinted band wipes in BEHIND the words; the hairline
                  stands down and the text colour never moves
     bracket      mono [ ] close in on either side of the label; the two
                  pseudo-elements are re-cast, so nothing enters the line box
     lift         the label rises off a hairline that fades in and holds its
                  absolute position — the quietest option on the list

   The line itself is a ::after hairline. Arrow links and nav links get their
   text wrapped in .rbs-link-label at runtime (js/areas/links.js) so the line
   sits under the words only — never under the arrow or chevron glyph.
   Footer links are plain text, so the line hangs off the anchor directly.

   Nav rail links (small, high-frequency) are capped to the quietest
   treatment — a pure opacity fade — regardless of variant.

   Knobs: --rbs-link-thickness (1–2px) · --rbs-link-offset (2–6px)
          --rbs-link-dur (160–420ms; fades run at 0.65×)
          --rbs-link-tint (6–28%, highlight band strength)
          --rbs-link-bracket-travel (2–12px) · --rbs-link-bracket-idle (0–0.45)
          --rbs-link-rise (0.5–3px, lift)
   Knob attribute written by js/areas/links.js apply():
          body[data-rbs-links-band="rise"] — highlight only; absent = wipe

   All of this is FEEDBACK, so none of it is gated on the motion level.
   Movement (draw / slide / wipe / bracket travel / lift / arrow nudge) is
   gated to fine pointers with no reduced-motion preference; everyone else
   gets the fade — gentler, not dead. No body attribute (JS absent) → this
   whole file is inert and the shipped text-decoration hover from
   05-components/footer.css still applies.
   ========================================================================== */

/* --- Geometry, shared by every variant ---------------------------------- */

body[data-rbs-links] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label,
body[data-rbs-links] :is(.rb-footer__link, .rb-footer__legal-link) {
  position: relative;
}

body[data-rbs-links] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label::after,
body[data-rbs-links] :is(.rb-footer__link, .rb-footer__legal-link)::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: calc(3px - var(--rbs-link-offset, 3px));
  height: var(--rbs-link-thickness, 1px);
  background: currentColor;
  opacity: 0;
  pointer-events: none;
  /* Fade is the base behaviour for every variant — it is also the coarse-
     pointer and reduced-motion fallback for draw / exit-return. */
  transition: opacity calc(var(--rbs-link-dur, 280ms) * 0.65) ease;
}

body[data-rbs-links] :is(.rb-arrow-link, .rb-nav__panel-link):is(:hover, :focus-visible, .rbs-link-demo) .rbs-link-label::after,
body[data-rbs-links] :is(.rb-footer__link, .rb-footer__legal-link):is(:hover, :focus-visible, .rbs-link-demo)::after {
  opacity: 1;
}

/* Retire the shipped text-decoration pop once the system is active. */
body[data-rbs-links] :is(.rb-arrow-link, .rb-footer__link, .rb-footer__legal-link):hover {
  text-decoration: none;
}

/* --- Exit & return keeps a resting line even where movement can't run ---- */

body[data-rbs-links="exit-return"] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label::after,
body[data-rbs-links="exit-return"] :is(.rb-footer__link, .rb-footer__legal-link)::after {
  opacity: 0.45;
}

body[data-rbs-links="exit-return"] :is(.rb-arrow-link, .rb-nav__panel-link):is(:hover, :focus-visible, .rbs-link-demo) .rbs-link-label::after,
body[data-rbs-links="exit-return"] :is(.rb-footer__link, .rb-footer__legal-link):is(:hover, :focus-visible, .rbs-link-demo)::after {
  opacity: 1;
}

/* --- Nav rail: quietest treatment, capped at a fade in EVERY variant ----- */

body[data-rbs-links] .rb-nav__rail .rb-nav__link .rbs-link-label {
  position: relative;
}

body[data-rbs-links] .rb-nav__rail .rb-nav__link .rbs-link-label::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: calc(3px - var(--rbs-link-offset, 3px));
  height: var(--rbs-link-thickness, 1px);
  background: currentColor;
  opacity: 0;
  pointer-events: none;
  transition: opacity calc(var(--rbs-link-dur, 280ms) * 0.65) ease;
}

body[data-rbs-links] .rb-nav__rail .rb-nav__link:is(:hover, :focus-visible, .rbs-link-demo) .rbs-link-label::after {
  opacity: 1;
}

/* --- Arrow nudge: every variant, 4px right, 220ms swift ------------------ */

body[data-rbs-links] .rb-arrow-link svg {
  transition: transform var(--rb-sys-duration-2) var(--rb-sys-ease-swift);
}

/* --- HIGHLIGHT: a tinted band behind the words --------------------------
   The hairline stands down — the band is the whole gesture. It is mixed out
   of currentColor rather than a fixed tint so one rule reads as a marker on
   the light sections and as a wash on the dark footer, with no second token
   and no contrast risk: the text colour is untouched either way.

   The band insets from the link's own box rather than taking a fixed em
   height, because footer directory links wrap: a fixed band would stripe
   through the middle line of a three-line link, where an inset one covers
   the whole run. Every target is an align-items:center flex box whose
   height is its line box, so 2px of inset lands the same on all of them —
   17px around the arrow label, 20px inside the footer's 24px hit area.  */

body[data-rbs-links="highlight"] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label::after,
body[data-rbs-links="highlight"] :is(.rb-footer__link, .rb-footer__legal-link)::after {
  content: none;
}

body[data-rbs-links="highlight"] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label,
body[data-rbs-links="highlight"] :is(.rb-footer__link, .rb-footer__legal-link) {
  z-index: 0;   /* own stacking context, so the -1 band stays inside the link */
}

body[data-rbs-links="highlight"] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label::before,
body[data-rbs-links="highlight"] :is(.rb-footer__link, .rb-footer__legal-link)::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset-block: var(--rbs-link-band-inset, 2px);
  inset-inline: -0.2em;
  height: auto;
  background: color-mix(in srgb, currentColor var(--rbs-link-tint, 14%), transparent);
  opacity: 0;
  pointer-events: none;
  /* Fade is the base behaviour, and the coarse-pointer / reduced-motion
     fallback for the wipe below. */
  transition: opacity calc(var(--rbs-link-dur, 280ms) * 0.65) ease;
}

body[data-rbs-links="highlight"] :is(.rb-arrow-link, .rb-nav__panel-link):is(:hover, :focus-visible, .rbs-link-demo) .rbs-link-label::before,
body[data-rbs-links="highlight"] :is(.rb-footer__link, .rb-footer__legal-link):is(:hover, :focus-visible, .rbs-link-demo)::before {
  opacity: 1;
}

/* --- BRACKET: mono [ ] close in around the label ------------------------
   Both marks are pseudo-elements — ::after is re-cast from hairline to "]",
   ::before becomes "[" — so no node is added to the DOM and nothing can
   reflow. They are absolutely positioned OUTSIDE the text box, which means
   the line box never changes width whatever the travel knob says.

   The one static concession: the arrow link's gap opens from 8px to 12px in
   this variant so the "]" is not sitting on the chevron. That happens once,
   at variant-switch time — never during a hover.                          */

body[data-rbs-links="bracket"] .rb-arrow-link { gap: var(--rb-ref-space-3); }

body[data-rbs-links="bracket"] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label::before,
body[data-rbs-links="bracket"] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label::after,
body[data-rbs-links="bracket"] :is(.rb-footer__link, .rb-footer__legal-link)::before,
body[data-rbs-links="bracket"] :is(.rb-footer__link, .rb-footer__legal-link)::after {
  position: absolute;
  inset-block: 0;              /* replaces the hairline's baseline offset */
  inset-inline: auto;          /* …and its full-width stretch */
  display: flex;
  align-items: center;
  height: auto;
  background: none;            /* the hairline's fill, retired */
  color: inherit;
  font-family: var(--rb-sys-font-label);
  font-size: 0.94em;
  font-weight: var(--rb-ref-weight-regular);
  line-height: 1;
  opacity: var(--rbs-link-bracket-idle, 0);
  pointer-events: none;
  transition: opacity calc(var(--rbs-link-dur, 280ms) * 0.65) ease;
}

body[data-rbs-links="bracket"] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label::before,
body[data-rbs-links="bracket"] :is(.rb-footer__link, .rb-footer__legal-link)::before {
  content: "[";
  right: 100%;
  margin-right: 1px;
}

body[data-rbs-links="bracket"] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label::after,
body[data-rbs-links="bracket"] :is(.rb-footer__link, .rb-footer__legal-link)::after {
  content: "]";
  left: 100%;
  margin-left: 1px;
}

body[data-rbs-links="bracket"] :is(.rb-arrow-link, .rb-nav__panel-link):is(:hover, :focus-visible, .rbs-link-demo) .rbs-link-label::before,
body[data-rbs-links="bracket"] :is(.rb-arrow-link, .rb-nav__panel-link):is(:hover, :focus-visible, .rbs-link-demo) .rbs-link-label::after,
body[data-rbs-links="bracket"] :is(.rb-footer__link, .rb-footer__legal-link):is(:hover, :focus-visible, .rbs-link-demo)::before,
body[data-rbs-links="bracket"] :is(.rb-footer__link, .rb-footer__legal-link):is(:hover, :focus-visible, .rbs-link-demo)::after {
  opacity: 1;
}

/* --------------------------------------------------------------------------
   Movement — fine pointers, no reduced-motion preference. These override the
   base fade at equal specificity by cascade order. Transitions retarget
   mid-flight, so a hover that reverses halfway simply turns around.
   -------------------------------------------------------------------------- */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {

  body[data-rbs-links] .rb-arrow-link:is(:hover, :focus-visible, .rbs-link-demo) svg {
    transform: translateX(var(--rb-ref-space-1));
  }

  /* DRAW — scaleX 0→1 from the left; origin snaps to the right on leave so
     the line departs the way it never came: out the right side. */
  body[data-rbs-links="draw"] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label::after,
  body[data-rbs-links="draw"] :is(.rb-footer__link, .rb-footer__legal-link)::after {
    opacity: 1;
    transform: scaleX(0);
    transform-origin: 100% 50%;
    transition: transform var(--rbs-link-dur, 280ms) var(--rb-sys-ease-swift);
  }

  body[data-rbs-links="draw"] :is(.rb-arrow-link, .rb-nav__panel-link):is(:hover, :focus-visible, .rbs-link-demo) .rbs-link-label::after,
  body[data-rbs-links="draw"] :is(.rb-footer__link, .rb-footer__legal-link):is(:hover, :focus-visible, .rbs-link-demo)::after {
    transform: scaleX(1);
    transform-origin: 0 50%;
  }

  /* EXIT & RETURN — one ::after, a 300% three-segment track:
     [line][gap][line]. Sliding background-position 100%→0% pushes the
     resting line out the right edge exactly as the fresh one clears the
     left — a single continuous gesture. (Deliberate exception to the
     transform/opacity-only rule: the painted area is a hairline.) */
  body[data-rbs-links="exit-return"] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label::after,
  body[data-rbs-links="exit-return"] :is(.rb-footer__link, .rb-footer__legal-link)::after {
    opacity: 1;
    background: linear-gradient(
      90deg,
      currentColor 0 33.3%,
      transparent 33.3% 66.7%,
      currentColor 66.7% 100%
    ) no-repeat;
    background-size: 300% 100%;
    background-position: 100% 0;
    transition: background-position var(--rbs-link-dur, 280ms) var(--rb-sys-ease-morph);
  }

  body[data-rbs-links="exit-return"] :is(.rb-arrow-link, .rb-nav__panel-link):is(:hover, :focus-visible, .rbs-link-demo) .rbs-link-label::after,
  body[data-rbs-links="exit-return"] :is(.rb-footer__link, .rb-footer__legal-link):is(:hover, :focus-visible, .rbs-link-demo)::after {
    background-position: 0% 0;
  }

  /* HIGHLIGHT — the band is a solid fill, so scaling it reads as a wipe with
     no distortion to correct for. The origin flips on exit exactly as DRAW's
     does: the band leaves out the right instead of rewinding to where it
     came from. Enter is expo and unhurried (~320ms), exit swift (~196ms). */
  body[data-rbs-links="highlight"] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label::before,
  body[data-rbs-links="highlight"] :is(.rb-footer__link, .rb-footer__legal-link)::before {
    opacity: 1;
    transform: scaleX(0);
    transform-origin: 100% 50%;
    transition: transform calc(var(--rbs-link-dur, 280ms) * 0.7) var(--rb-sys-ease-swift);
  }

  body[data-rbs-links="highlight"] :is(.rb-arrow-link, .rb-nav__panel-link):is(:hover, :focus-visible, .rbs-link-demo) .rbs-link-label::before,
  body[data-rbs-links="highlight"] :is(.rb-footer__link, .rb-footer__legal-link):is(:hover, :focus-visible, .rbs-link-demo)::before {
    transform: scaleX(1);
    transform-origin: 0 50%;
    transition-duration: calc(var(--rbs-link-dur, 280ms) * 1.15);
    transition-timing-function: var(--rb-sys-ease-expo);
  }

  /* Band knob = rise: the band grows up off the baseline rather than across
     the words. Two attributes on the body, so this pair wins over the wipe
     pair regardless of source order. */
  body[data-rbs-links="highlight"][data-rbs-links-band="rise"] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label::before,
  body[data-rbs-links="highlight"][data-rbs-links-band="rise"] :is(.rb-footer__link, .rb-footer__legal-link)::before {
    transform: scaleY(0);
    transform-origin: 50% 100%;
  }

  body[data-rbs-links="highlight"][data-rbs-links-band="rise"] :is(.rb-arrow-link, .rb-nav__panel-link):is(:hover, :focus-visible, .rbs-link-demo) .rbs-link-label::before,
  body[data-rbs-links="highlight"][data-rbs-links-band="rise"] :is(.rb-footer__link, .rb-footer__legal-link):is(:hover, :focus-visible, .rbs-link-demo)::before {
    transform: scaleY(1);
    transform-origin: 50% 100%;
  }

  /* BRACKET — the pair starts wide of the label and closes in on it. Coarse
     pointers never see this block: they get the brackets parked at their
     final position, fading. The closer trails the opener by one beat (40ms)
     on the way in and leaves with it on the way out. */
  body[data-rbs-links="bracket"] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label::before,
  body[data-rbs-links="bracket"] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label::after,
  body[data-rbs-links="bracket"] :is(.rb-footer__link, .rb-footer__legal-link)::before,
  body[data-rbs-links="bracket"] :is(.rb-footer__link, .rb-footer__legal-link)::after {
    transition: opacity   calc(var(--rbs-link-dur, 280ms) * 0.65) ease,
                transform calc(var(--rbs-link-dur, 280ms) * 0.7)  var(--rb-sys-ease-swift);
  }

  body[data-rbs-links="bracket"] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label::before,
  body[data-rbs-links="bracket"] :is(.rb-footer__link, .rb-footer__legal-link)::before {
    transform: translateX(calc(-1 * var(--rbs-link-bracket-travel, 6px)));
  }

  body[data-rbs-links="bracket"] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label::after,
  body[data-rbs-links="bracket"] :is(.rb-footer__link, .rb-footer__legal-link)::after {
    transform: translateX(var(--rbs-link-bracket-travel, 6px));
  }

  body[data-rbs-links="bracket"] :is(.rb-arrow-link, .rb-nav__panel-link):is(:hover, :focus-visible, .rbs-link-demo) .rbs-link-label::before,
  body[data-rbs-links="bracket"] :is(.rb-arrow-link, .rb-nav__panel-link):is(:hover, :focus-visible, .rbs-link-demo) .rbs-link-label::after,
  body[data-rbs-links="bracket"] :is(.rb-footer__link, .rb-footer__legal-link):is(:hover, :focus-visible, .rbs-link-demo)::before,
  body[data-rbs-links="bracket"] :is(.rb-footer__link, .rb-footer__legal-link):is(:hover, :focus-visible, .rbs-link-demo)::after {
    transform: none;
    transition-duration: calc(var(--rbs-link-dur, 280ms) * 0.65), var(--rbs-link-dur, 280ms);
  }

  body[data-rbs-links="bracket"] :is(.rb-arrow-link, .rb-nav__panel-link):is(:hover, :focus-visible, .rbs-link-demo) .rbs-link-label::after,
  body[data-rbs-links="bracket"] :is(.rb-footer__link, .rb-footer__legal-link):is(:hover, :focus-visible, .rbs-link-demo)::after {
    transition-delay: 0ms, 40ms;
  }

  /* LIFT — the label rises by --rbs-link-rise off a hairline that stays put.
     The line is a descendant of the thing that moves, so it counter-
     translates by the same amount and holds its absolute position: the text
     separates from the rule rather than dragging it along. Nothing here runs
     on a coarse pointer or under reduced motion, where LIFT collapses to the
     plain hairline fade the base rules already provide.

     The transition list restates opacity and color because footer.css owns
     those on the same elements and a bare `transition: transform` would
     snap the footer's 0.85→1 fade and the legal link's colour change. */
  body[data-rbs-links="lift"] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label,
  body[data-rbs-links="lift"] :is(.rb-footer__link, .rb-footer__legal-link) {
    transition: transform calc(var(--rbs-link-dur, 280ms) * 0.55) var(--rb-sys-ease-swift),
                opacity   var(--rb-sys-duration-2) ease,
                color     var(--rb-sys-duration-2) ease;
  }

  body[data-rbs-links="lift"] :is(.rb-arrow-link, .rb-nav__panel-link):is(:hover, :focus-visible, .rbs-link-demo) .rbs-link-label,
  body[data-rbs-links="lift"] :is(.rb-footer__link, .rb-footer__legal-link):is(:hover, :focus-visible, .rbs-link-demo) {
    transform: translateY(calc(-1 * var(--rbs-link-rise, 1px)));
    transition-duration: var(--rb-sys-duration-2);
  }

  body[data-rbs-links="lift"] :is(.rb-arrow-link, .rb-nav__panel-link) .rbs-link-label::after,
  body[data-rbs-links="lift"] :is(.rb-footer__link, .rb-footer__legal-link)::after {
    transition: opacity   calc(var(--rbs-link-dur, 280ms) * 0.65) ease,
                transform calc(var(--rbs-link-dur, 280ms) * 0.55) var(--rb-sys-ease-swift);
  }

  body[data-rbs-links="lift"] :is(.rb-arrow-link, .rb-nav__panel-link):is(:hover, :focus-visible, .rbs-link-demo) .rbs-link-label::after,
  body[data-rbs-links="lift"] :is(.rb-footer__link, .rb-footer__legal-link):is(:hover, :focus-visible, .rbs-link-demo)::after {
    transform: translateY(var(--rbs-link-rise, 1px));
    transition-duration: calc(var(--rbs-link-dur, 280ms) * 0.65), var(--rb-sys-duration-2);
  }

  /* The arrow rides the lift so the link travels as one object. */
  body[data-rbs-links="lift"] .rb-arrow-link:is(:hover, :focus-visible, .rbs-link-demo) svg {
    transform: translate(var(--rb-ref-space-1), calc(-1 * var(--rbs-link-rise, 1px)));
  }
}
