/* ===========================================================================
   Text Scroller
   ===========================================================================
   Everything is scoped under .scroller, and every colour has a fallback, so
   this works dropped into a page that has none of the site's custom
   properties.

   The motion is a plain CSS animation rather than a timer, which means pausing
   is a one-line animation-play-state change and costs nothing while stopped.

   The track holds two identical sets of the text and travels exactly -50%, so
   the end of the loop lands on the same pixel it started from and the repeat
   is invisible. scroller.js builds the copies and works out the duration from
   the measured width -- a fixed duration would make short text crawl and long
   text race.
   =========================================================================== */

.scroller {
  display: block;
  position: relative;
  /* Room for the pause button, so it never sits on top of the words. */
  padding-right: 2.3rem;
}

.scroller-viewport {
  display: block;
  overflow: hidden;
  /* Softens both ends so the text appears and leaves rather than being
     chopped off against a hard edge. */
  mask-image: linear-gradient(to right,
              transparent 0, #000 1.5rem,
              #000 calc(100% - 1.5rem), transparent 100%);
}

.scroller-track {
  display: flex;
  width: max-content;
}

.scroller-item {
  display: block;
  white-space: nowrap;
  padding-right: var(--scroller-gap, 48px);
}

/* is-live is added by the script once it has measured a real width. Before
   that the text simply sits still, so a failed or slow script leaves something
   readable rather than an empty box. */
.scroller.is-live .scroller-track { will-change: transform; }

/* The keyframes below are a FALLBACK, and only a browser with no Web Animations
   API ever reaches them -- that is what is-css marks. Everywhere else the
   script owns the motion directly.
   
   The reason is pausing. Stopping a CSS animation means overriding
   animation-play-state from a class, and Safari responded to that by rebuilding
   the animation rather than holding it, so hovering threw the text back to the
   start instead of freezing it in place. scroller.js explains the rest. */
.scroller.is-css .scroller-track {
  animation: scroller-move var(--scroller-duration, 24s) linear infinite;
}
.scroller.is-css[data-direction="right"] .scroller-track {
  animation-name: scroller-move-rtl;
}
.scroller.is-css.is-paused .scroller-track {
  animation-play-state: paused;
}

@keyframes scroller-move {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
@keyframes scroller-move-rtl {
  from { transform: translateX(-50%); }
  to   { transform: translateX(0); }
}

/* --- The pause / play control ----------------------------------------------
   WCAG 2.2.2 (Pause, Stop, Hide) applies to anything that moves by itself for
   more than five seconds, and this moves forever. prefers-reduced-motion alone
   is not enough: plenty of people are bothered by moving text without having
   ever found that setting. So there is always a real control.

   It stays faint until the block is hovered or the button is focused, so it
   does not compete with the content -- but it is always there, and always
   reachable by keyboard. */
.scroller-toggle {
  position: absolute;
  top: 50%;
  right: 0;
  translate: 0 -50%;
  width: 1.8rem;
  height: 1.8rem;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--text-muted, currentColor);
  opacity: .45;
  cursor: pointer;
  transition: opacity .2s ease, color .2s ease, background-color .2s ease;
}
.scroller:hover .scroller-toggle,
.scroller-toggle:focus-visible { opacity: 1; }
.scroller-toggle:hover {
  color: var(--brand, #53abea);
  background: var(--surface, rgba(127, 127, 127, .14));
}
.scroller-toggle:focus-visible {
  outline: 2px solid var(--brand, #53abea);
  outline-offset: 2px;
}

/* Drawn rather than set in a font: two bars for pause, a triangle for play.
   No icon library, nothing to load, and it cannot arrive as a missing glyph. */
.scroller-toggle::before {
  content: "";
  display: block;
  width: .56rem;
  height: .62rem;
  background: linear-gradient(to right,
              currentColor 0 36%, transparent 36% 64%, currentColor 64% 100%);
}
.scroller-toggle[aria-pressed="true"]::before {
  width: .52rem;
  background: currentColor;
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}

/* --- Reduced motion --------------------------------------------------------
   Not a degraded version: the text stops moving AND stops being a single
   clipped line, so the whole message is readable at once. Nothing is lost,
   which is the point -- hiding content from someone who asked for less
   animation would be the worse failure.

   The script removes the button too. A pause control beside text that never
   moves is worse than no control at all. */
@media (prefers-reduced-motion: reduce) {
  .scroller { padding-right: 0; }
  .scroller-viewport { overflow: visible; mask-image: none; }
  .scroller-track { display: block; width: auto; animation: none; }
  .scroller-item { white-space: normal; padding-right: 0; }
  .scroller-toggle { display: none; }
}
