/* ==========================================================================
   Mouldshop info stripe — a gradient bar carrying one line of text that
   scrolls sideways forever. M4 / TASK-0073.

   ── MEASURED OFF LIVE, NOT DESIGNED ──────────────────────────────────────────────────
   Source: https://mouldshop-co-uk.dw10staging.dynamicweb-cms.com/ , read through the
   CSSOM at 1440, 1200, 768 and 390 on 2026-09-17. On live the component is
   `div.bon-promo-info-module`, a vendor Swift TEXT paragraph carrying a third-party
   class, sitting in a 1-column-full row directly above the N E W S divider.

     gradient   linear-gradient(145deg, #C4E0F2 0px, #6CB2DE 35%, #0A2878 100%)
     height     60px, overflow hidden
     text       Roboto 400, 20px / 30px, #FFFFFF, letter-spacing normal,
                text-transform none (live types its copy in capitals by hand)
                *** WE SHIP 300, NOT 400. Operator direction, 2026-09-17: the default is
                Roboto 300 and an emboldened run is Roboto 700. Live measures 400 and has
                no bold at all. The difference is deliberate and it is ONE TOKEN either
                way -- --ms-infostripe-weight. Recorded rather than absorbed, because
                live is a pinned source and this is the one place we knowingly leave it. ***
     speed      69 px/sec, constant, IDENTICAL at 1440 / 1200 / 390 — measured over
                four 1.5s windows: 103.5px per window, and a wrap sample that lands
                exactly one step back. It is not a CSS animation: live drives an
                inline `transform: translateX(...)` per frame, same family as ours.
     spacing    live forces every copy to a fixed 690px box and left-aligns the text
                in it. Natural text advance measured 488.6px, so the visible gap
                between phrases is 690 - 488.6 = 201.4px. Reproduced here as a CSS
                `gap` of 200px (see WHERE WE DIFFER, point 2).
     width      the stripe takes its column's width and sets none of its own:
                1288 @1440 / 1108 @1200 / 736 @768 / 358 @390. That is the vendor
                container ladder, which our rows already reproduce, so the component
                deliberately contributes no width rule at all.

   ── WHERE WE DELIBERATELY DIFFER, AND WHY ────────────────────────────────────────────
   1. HEIGHT IS CENTRED, NOT INHERITED-AND-CLIPPED. Live stacks padding-top 15px +
      line-height 30px + margin-bottom 16px = 61px of content inside a 60px box with
      `overflow: hidden`, so its text is clipped by one pixel and sits a pixel high.
      Here the box is 60px and the line is centred in it. Same picture, no off-by-one
      to inherit.
   2. SPACING IS A CSS `gap`, NEVER A FORCED COPY WIDTH. Live's 690px box is computed
      in JS from that particular sentence; edit the copy and the rhythm changes. A
      `gap` is measured back by the component at build time and folded into the step,
      so the loop stays seamless whatever the editor types. This is the Nickerson
      manual's rule (NICKERSON_TICKER_MANUAL.md section 4) and it is the reason the
      gap must not be expressed as margin or padding on the copy: those are not
      measured, and the loop desyncs silently.
   3. THE MASK IS ON THE OUTER BOX, NOT THE TRACK. `overflow: hidden` lives on
      `.ms-infostripe`. Manual section 6.2: move it to the track and the oversized
      track spills, which is a horizontal page scroll on every page that carries one.

   ── COLOUR: TWO OF THE THREE STOPS ARE OUR OWN TOKENS, ONE IS ONE UNIT OFF ───────────
     stop 1  #C4E0F2   no brand token exists; declared below as a component property.
     stop 2  #6CB2DE   IS `--ms-blue`, exactly, independently arrived at.
     stop 3  #0A2878   our `--ms-navy` is #0A2979 — one unit apart in green and blue,
                       which is below any perceptual threshold. Live's literal is used
                       so the stripe is 1:1 with the pinned source, and the difference
                       is recorded here rather than quietly absorbed.
   All three are custom properties, so a later brand pass retunes the component from
   one place.

   ── THIS FILE IS ONE OF FOUR REGISTRATIONS (Q-0050) ──────────────────────────────────
   The others: the item type XML (items/, copied in by restore-itemtypes.sh, DEC-0046),
   the Paragraph/Mouldshop_InfoStripe template mount, and the backing table DW builds
   on restart. Three of four renders nothing and looks entirely correct in admin.
   ========================================================================== */

.ms-infostripe {
  --ms-infostripe-from:  #C4E0F2;
  --ms-infostripe-mid:   #6CB2DE;  /* == --ms-blue */
  --ms-infostripe-to:    #0A2878;  /* --ms-navy is #0A2979; see header */
  --ms-infostripe-angle: 145deg;
  --ms-infostripe-mid-stop: 35%;
  --ms-infostripe-height: 60px;
  --ms-infostripe-gap: 200px;
  --ms-infostripe-color: var(--ms-white, #FFFFFF);
  --ms-infostripe-weight: 300;         /* operator direction; live measures 400 */
  --ms-infostripe-weight-strong: 700;  /* what Bold in the editor produces */

  display: flex;
  align-items: center;
  overflow: hidden;                 /* the mask — load-bearing, see header point 3 */
  min-height: var(--ms-infostripe-height);
  background-image: linear-gradient(
    var(--ms-infostripe-angle),
    var(--ms-infostripe-from) 0px,
    var(--ms-infostripe-mid) var(--ms-infostripe-mid-stop),
    var(--ms-infostripe-to) 100%
  );
  color: var(--ms-infostripe-color);
}

.ms-infostripe-track {
  display: flex;
  align-items: center;
  gap: var(--ms-infostripe-gap);    /* read back by the component; never margin */
  white-space: nowrap;
  will-change: transform;
  transform: translate3d(0, 0, 0);
}

.ms-infostripe-copy {
  margin: 0;
  font-family: var(--ms-font-body, Roboto, system-ui, sans-serif);
  font-size: 20px;
  font-weight: var(--ms-infostripe-weight);
  line-height: 30px;
  letter-spacing: normal;
  color: inherit;
}

/* THE EDITOR'S BOLD, AND THE ONLY FORMATTING THIS COMPONENT HONOURS. The template reduces
   the field to these four tags and nothing else, so this rule is the whole of what a
   formatted run can look like -- no colour change, no size change, no family change.

   BOTH WEIGHTS COME FROM ONE FILE. Roboto here is the self-hosted VARIABLE face declared
   in mouldshop-fonts.css (font-weight: 100 900), so 300 and 700 are real cuts off the same
   woff2 -- no second download, and no faux bold synthesised from a light face, which is
   the defect TASK-0063 was written to end. */
.ms-infostripe-copy strong,
.ms-infostripe-copy b {
  font-weight: var(--ms-infostripe-weight-strong);
  color: inherit;
}

/* Italic stays italic and nothing more: same weight as its surroundings, same colour. */
.ms-infostripe-copy em,
.ms-infostripe-copy i {
  font-weight: inherit;
  font-style: italic;
  color: inherit;
}

/* Reduced motion: one static copy, no rAF loop. The component enforces this too —
   this rule only makes sure nothing here reintroduces movement. Manual section 6.5. */
@media (prefers-reduced-motion: reduce) {
  .ms-infostripe-track {
    transition: none;
    animation: none;
  }
}

/* ==========================================================================
   LINK + VIP MOMENT (operator, 2026-09-25). Template: Paragraph/Mouldshop_InfoStripe/Default.cshtml.
   Motion: mouldshop-info-stripe-vip.js.

   LINK: a stretched anchor over the whole stripe, so the ticker's cloned DOM is untouched.
   VIP: a layer over the stripe - white, a navy 2px border drawn INSIDE (inset shadow, so the
   stripe's height never changes) - holding the message one word per span, all stacked in the
   centre. Hidden (opacity 0, no clicks) until the script raises it; .is-vip gives it the clicks.
   Words: Montserrat, navy, 500; a word bolded with the B button is 900, the navbar VIP pill's
   weight. Under reduced motion the words sit side by side instead (.is-vip-static).
   ========================================================================== */
.ms-infostripe { position: relative; }

.ms-infostripe-link {
  position: absolute;
  inset: 0;
  z-index: 1;
}
.ms-infostripe-link:focus-visible {
  outline: 2px solid var(--ms-white, #FFFFFF);
  outline-offset: -4px;
}

.ms-infostripe-vip {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--ms-white, #FFFFFF);
  box-shadow: inset 0 0 0 2px var(--ms-navy, #0A2979);
  color: var(--ms-navy, #0A2979);
  opacity: 0;
  pointer-events: none;
  overflow: hidden;
}
.ms-infostripe.is-vip .ms-infostripe-vip { pointer-events: auto; }

.ms-infostripe-vip-link {
  position: absolute;
  inset: 0;
  z-index: 1;
}

.ms-infostripe-vip-word {
  position: absolute;
  opacity: 0;
  white-space: nowrap;
  font-family: var(--ms-font-head, Montserrat, system-ui, sans-serif);
  font-size: 22px;
  font-weight: 500;
  line-height: 30px;
  letter-spacing: .04em;
  pointer-events: none;
  will-change: transform, opacity, filter;
}
.ms-infostripe-vip-word strong { font-weight: 900; }

/* Reduced motion: the whole message, side by side, no movement. */
.ms-infostripe.is-vip-static .ms-infostripe-vip { gap: .35em; }
.ms-infostripe.is-vip-static .ms-infostripe-vip-word { position: static; }

/* The screen-reader / keyboard copy of the VIP message, when it is a link and gains focus. */
.ms-infostripe-vip-sr:focus {
  position: absolute !important;
  inset: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--ms-white, #FFFFFF);
  color: var(--ms-navy, #0A2979);
  font-weight: 700;
}
