/* =========================================================
   PRODUCT-ENTRANCE.CSS
   The scroll entrances for the four sections below the hero on
   every product page: the feature list, the article band, the
   specs row and the related-products band.

   ANIMATION ONLY -- opacity, transform and clip-path, none of
   which affect the box an element occupies, plus one border
   COLOUR that is handed straight back once its line has drawn.
   No layout, spacing, typography, colour, image or content is
   changed.

   NOT TOUCHED, anywhere in this file:
     - the page transition (its line, overlay, timings, script)
     - hero-entrance.css and everything it animates
     - every existing hover, listed one by one below

   ---------------------------------------------------------
   THE HOVER RULE
   A `transition` declaration REPLACES any earlier one on the
   same element, so nothing here may declare a transition on an
   element that already has one. What that rules out:

     .pr-related__track        carries the carousel's own
                               translateX AND its 450ms
                               transition, driven by the page's
                               script -- NOT touched at all.
     .pr-related-card          has `transition: background-color`
                               (the panel deepening). Its
                               entrance is a keyframe ANIMATION:
                               animation and transition are
                               separate properties and do not
                               overwrite each other.
     .pr-related-card__image   has `transition: transform` (the
                               1.04 zoom) -- NOT touched, so the
                               card thumbnails get no entrance
                               scale of their own.
     .pr-related__nav          has `transition: opacity, transform`
                               for its hover AND an opacity of
                               its own when [disabled] -- NOT
                               touched at all.
     .pr-related__all::after,
     .pr-article__link-icon,
     .pr-related__all-icon     all carry their own hover
                               transitions -- NOT touched. Only
                               their PARENTS fade in.

   SAFETY: nothing is hidden until js/product-entrance.js adds
   .is-armed to a section. If that script is missing or fails,
   no rule here matches and the whole page is simply there.
   Transitions live on the revealing rule, never on the arming
   one.
   ========================================================= */

:root {
  /* The same two curves as the home page's and the hero's
     entrances, restated so the files stay independent of each
     other's load order. */
  --px-ease: cubic-bezier(0.40, 0, 0.20, 1);
  --px-ease-media: cubic-bezier(0.45, 0, 0.15, 1);

  --px-head: 600ms;      /* a section heading */
  --px-at-rule: 100ms;   /* the brand line's start behind it */
  --px-red: 170ms;       /* red leads ... */
  --px-at-blue: 260ms;
  --px-blue: 320ms;      /* ... blue follows out of it */
  --px-text: 560ms;      /* body copy, specs, a card */
  --px-step: 70ms;       /* between members of one group */
  --px-line: 460ms;      /* one hairline drawing */
  --px-media: 820ms;     /* a photograph opening */
}

/* =========================================================
   SHARED — the blue/red brand line under a heading
   RED LEADS. Both rules are written red-first in the markup,
   and in this RTL page the first child lands physically right,
   so red is the short segment at the line's right end: it draws
   first and blue grows leftward out of it. transform-origin is
   PHYSICAL and is never flipped by direction.
   ========================================================= */

.pr-article.is-armed .pr-article__rule .pr-rule__segment,
.pr-related.is-armed .pr-related__rule .pr-rule__segment {
  transform: scaleX(0);
  transform-origin: right center;
}

.pr-article.is-armed.is-in .pr-article__rule .pr-rule__segment--red,
.pr-related.is-armed .pr-related__head.is-in .pr-rule__segment--red {
  transform: scaleX(1);
  transition: transform var(--px-red) var(--px-ease) var(--px-at-rule);
}

.pr-article.is-armed.is-in .pr-article__rule .pr-rule__segment--blue,
.pr-related.is-armed .pr-related__head.is-in .pr-rule__segment--blue {
  transform: scaleX(1);
  transition: transform var(--px-blue) var(--px-ease) var(--px-at-blue);
}

/* =========================================================
   1 — THE FEATURE LIST (01, 02, 03 ...)
   Each row is revealed as it reaches the viewport, on its own
   observation, so a long list does not run as one chain.
   ========================================================= */

/* The photograph here is a bled background behind a heavy wash,
   not a presented picture, so it gets depth rather than a clip
   reveal: a 2% settle and a fade, slowly, under everything.
   .pr-features__media has no transition of its own. */
.pr-features.is-armed .pr-features__media {
  opacity: 0;
  transform: scale(1.02);
}

.pr-features.is-armed.is-in .pr-features__media {
  opacity: 1;
  transform: scale(1);
  transition: opacity var(--px-media) var(--px-ease-media),
              transform var(--px-media) var(--px-ease-media);
}

/* The number and the text move together as one row -- never a
   separate animation per cell. */
.pr-features.is-armed .pr-feature {
  opacity: 0;
  transform: translateY(8px);
}

.pr-features.is-armed .pr-feature.is-in {
  opacity: 1;
  transform: translateY(0);
  transition: opacity var(--px-text) var(--px-ease) var(--px-delay, 0ms),
              transform var(--px-text) var(--px-ease) var(--px-delay, 0ms);
}

/* The row's hairline is a border, and a border cannot be scaled.
   While the section is armed the border is held at `transparent`
   -- its WIDTH is untouched, so nothing moves -- and this bar
   draws in its place, same colour, same pixel. The script hands
   the real border back the instant the bar lands and hides the
   bar in the same frame, so the row is left exactly as it was
   found. There is deliberately no `transition` on .pr-feature
   itself for the colour: the swaps are instant. */
.pr-features.is-armed .pr-feature {
  border-block-start-color: transparent;
}

.pr-features.is-armed .pr-feature::before {
  content: "";
  position: absolute;
  /* PHYSICAL left/right, not inset-inline: the direction of
     travel is set by transform-origin and must not depend on
     the row's RTL inline axis. */
  left: 0;
  right: 0;
  top: -1px;                  /* the border's own pixel */
  height: 1px;
  background-color: #BAB9B8;  /* the row's own hairline colour */
  transform: scaleX(0);
  transform-origin: right center;
  pointer-events: none;
}

.pr-features.is-armed .pr-feature.is-in::before {
  transform: scaleX(1);
  transition: transform var(--px-line) var(--px-ease) var(--px-delay, 0ms);
}

.pr-features.is-armed .pr-feature.is-lined {
  border-block-start-color: #BAB9B8;
}

.pr-features.is-armed .pr-feature.is-lined::before {
  opacity: 0;
}

/* =========================================================
   2 — THE ARTICLE BAND
   One unit: the photograph opens while the heading, its rule,
   the body and the link arrive behind it.
   ========================================================= */

/* The picture opens from the physical RIGHT, with the reading.
   inset() is PHYSICAL (top right bottom left): a left inset of
   100% leaves a zero-width sliver at the frame's right edge,
   and shrinking it to 0 opens the picture leftward from there.
   The frame never moves -- clip-path has no effect on layout. */
.pr-article.is-armed .pr-article__media {
  clip-path: inset(0 0 0 100%);
}

.pr-article.is-armed.is-in .pr-article__media {
  clip-path: inset(0 0 0 0);
  transition: clip-path var(--px-media) var(--px-ease-media);
}

/* The settle rides on the image inside the frame, which has no
   hover and no transition of its own; the frame's own box is
   never scaled. */
.pr-article.is-armed .pr-article__image {
  transform: scale(1.02);
}

.pr-article.is-armed.is-in .pr-article__image {
  transform: scale(1);
  transition: transform var(--px-media) var(--px-ease-media);
}

.pr-article.is-armed .pr-article__heading {
  opacity: 0;
  transform: translateY(10px);
}

.pr-article.is-armed.is-in .pr-article__heading {
  opacity: 1;
  transform: translateY(0);
  transition: opacity var(--px-head) var(--px-ease),
              transform var(--px-head) var(--px-ease);
}

.pr-article.is-armed .pr-article__body,
.pr-article.is-armed .pr-article__link {
  opacity: 0;
  transform: translateY(7px);
}

.pr-article.is-armed.is-in .pr-article__body {
  opacity: 1;
  transform: translateY(0);
  transition: opacity var(--px-text) var(--px-ease) calc(var(--px-step) * 3),
              transform var(--px-text) var(--px-ease) calc(var(--px-step) * 3);
}

/* The link last. Its chevron's own hover (interactions.css) is
   on the icon inside and is not touched. */
.pr-article.is-armed.is-in .pr-article__link {
  opacity: 1;
  transform: translateY(0);
  transition: opacity var(--px-text) var(--px-ease) calc(var(--px-step) * 4),
              transform var(--px-text) var(--px-ease) calc(var(--px-step) * 4);
}

/* =========================================================
   3 — THE SPECS ROW
   Three columns, one step apart in reading order. Each column
   is one unit: its label and its text never animate separately.
   ========================================================= */

.pr-specs.is-armed .pr-specs__col {
  opacity: 0;
  transform: translateY(7px);
}

.pr-specs.is-armed.is-in .pr-specs__col {
  opacity: 1;
  transform: translateY(0);
  transition: opacity var(--px-text) var(--px-ease) var(--px-col, 0ms),
              transform var(--px-text) var(--px-ease) var(--px-col, 0ms);
}

/* DOM order is reading order here: in this RTL row the first
   column lands on the physical right. */
.pr-specs.is-armed .pr-specs__col:nth-child(2) { --px-col: var(--px-step); }
.pr-specs.is-armed .pr-specs__col:nth-child(3) { --px-col: calc(var(--px-step) * 2); }

/* The two column dividers are vertical, so they draw downward,
   the same way the stat-band dividers on Contact and Downloads
   already do. They are ::before on the column, independent of
   the column's own transform. */
.pr-specs.is-armed .pr-specs__col--colour::before,
.pr-specs.is-armed .pr-specs__col--packaging::before {
  transform: scaleY(0);
  transform-origin: top center;
}

.pr-specs.is-armed.is-in .pr-specs__col--colour::before,
.pr-specs.is-armed.is-in .pr-specs__col--packaging::before {
  transform: scaleY(1);
  transition: transform var(--px-line) var(--px-ease) var(--px-col, 0ms);
}

/* =========================================================
   4 — RELATED PRODUCTS
   The head and the card row are watched separately, so the
   cards are not dragged in by the heading.
   ========================================================= */

.pr-related.is-armed .pr-related__heading {
  opacity: 0;
  transform: translateY(10px);
}

.pr-related.is-armed .pr-related__head.is-in .pr-related__heading {
  opacity: 1;
  transform: translateY(0);
  transition: opacity var(--px-head) var(--px-ease),
              transform var(--px-head) var(--px-ease);
}

/* The "all products" link fades only. Its hairline ::after and
   its chevron keep their own hover transitions untouched. */
.pr-related.is-armed .pr-related__all {
  opacity: 0;
}

.pr-related.is-armed .pr-related__head.is-in .pr-related__all {
  opacity: 1;
  transition: opacity var(--px-text) var(--px-ease) calc(var(--px-step) * 2);
}

/* A keyframe animation, NOT a transition: .pr-related-card
   already carries `transition: background-color` for its hover.
   `backwards`, never `both` -- backwards holds the from-state
   through the delay and then releases, so nothing stays locked.

   The cards are staged by nth-child rather than observed one by
   one: they sit in a horizontally clipped carousel track, where
   a card scrolled out of the viewport would never intersect and
   would stay hidden for good. */
@keyframes px-card-rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

.pr-related.is-armed .pr-related-card {
  opacity: 0;
  transform: translateY(10px);
}

.pr-related.is-armed .pr-related__viewport.is-in .pr-related-card {
  opacity: 1;
  transform: translateY(0);
  animation: px-card-rise var(--px-text) var(--px-ease)
             var(--px-card, 0ms) backwards;
}

.pr-related.is-armed .pr-related-card:nth-child(2) { --px-card: var(--px-step); }
.pr-related.is-armed .pr-related-card:nth-child(3) { --px-card: calc(var(--px-step) * 2); }
.pr-related.is-armed .pr-related-card:nth-child(4) { --px-card: calc(var(--px-step) * 3); }
.pr-related.is-armed .pr-related-card:nth-child(n+5) { --px-card: calc(var(--px-step) * 4); }

/* =========================================================
   REDUCED MOTION — everything present, nothing moves
   ========================================================= */
@media (prefers-reduced-motion: reduce) {
  .pr-features.is-armed .pr-features__media,
  .pr-features.is-armed .pr-feature,
  .pr-article.is-armed .pr-article__heading,
  .pr-article.is-armed .pr-article__body,
  .pr-article.is-armed .pr-article__link,
  .pr-article.is-armed .pr-article__image,
  .pr-specs.is-armed .pr-specs__col,
  .pr-related.is-armed .pr-related__heading,
  .pr-related.is-armed .pr-related__all,
  .pr-related.is-armed .pr-related-card {
    opacity: 1;
    transform: none;
    animation: none;
    transition: none;
  }

  .pr-article.is-armed .pr-article__rule .pr-rule__segment,
  .pr-related.is-armed .pr-related__rule .pr-rule__segment,
  .pr-specs.is-armed .pr-specs__col--colour::before,
  .pr-specs.is-armed .pr-specs__col--packaging::before {
    transform: none;
    transition: none;
  }

  .pr-article.is-armed .pr-article__media {
    clip-path: inset(0 0 0 0);
    transition: none;
  }

  .pr-features.is-armed .pr-feature {
    border-block-start-color: #BAB9B8;
  }

  .pr-features.is-armed .pr-feature::before {
    opacity: 0;
  }
}
