/* =========================================================================
 * OXP Breaking News Ticker — Frontend
 * Structure comes from .oxp-tkr--theme-{id}; color comes from CSS custom
 * properties injected inline by the renderer (single source of truth:
 * the Palettes PHP class). Custom palettes may inject gradients.
 * ========================================================================= */

.oxp-tkr,
.oxp-tkr * { box-sizing: border-box; }

/* ---------- Wrapper (consumes variables with fallbacks) ---------- */
.oxp-tkr {
  --oxp-tkr-radius: 0px;
  --oxp-tkr-shadow: 0 4px 14px rgba(0, 0, 0, .15);
  --oxp-tkr-transition: .6s;
  --oxp-tkr-ease: ease;
  /* The decoration token first, because it is the label colour that is
   * guaranteed solid: a gradient palette puts a linear-gradient() in
   * --oxp-tkr-tag-bg, and an outline cannot take one. */
  --oxp-tkr-focus: var(--oxp-tkr-tag-decoration, var(--oxp-tkr-tag-bg, currentColor));

  /* Mode-aware decorations. Themes paint their gloss and their control-strip
   * backdrop with these, so a light palette does not get washes designed to
   * sit on a dark bar. Overridden by .oxp-tkr--mode-light below. */
  --oxp-tkr-sheen:  rgba(255, 255, 255, .12);
  --oxp-tkr-chrome: rgba(255, 255, 255, .08);
  /* Hard, blur-free offset shadow. Comic uses it as printed ink; it is a
   * separate token from --oxp-tkr-shadow because that one is a soft drop
   * shadow under the whole bar and this one is a graphic device on top of it. */
  --oxp-tkr-ink:    rgba(0, 0, 0, .55);
  /* The lit top edge of a glossy body. Capsule and Galaxy draw their rim and
   * their label highlight with it. Brighter than the sheen on purpose: a sheen
   * is a wash across a surface, a rim is a line catching the light. */
  --oxp-tkr-rim:    rgba(255, 255, 255, .30);
  /* Diffuse light. Weaker than the sheen and much broader: this is the wash a
   * curved, glossy body picks up across its face, not a highlight on an edge. */
  --oxp-tkr-haze:   rgba(255, 255, 255, .10);

  display: flex;
  align-items: stretch;
  width: 100%;
  max-width: var(--oxp-tkr-max-width, none);
  margin-inline: auto;
  height: var(--oxp-tkr-height, 48px);
  background: var(--oxp-tkr-bg, #111827);
  color: var(--oxp-tkr-text, #f9fafb);
  overflow: hidden;
  font-family: var(--oxp-tkr-font-family, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif);
  font-size: var(--oxp-tkr-font-size, 15px);
  font-weight: var(--oxp-tkr-font-weight, 400);
  font-style: var(--oxp-tkr-font-style, normal);
  box-shadow: var(--oxp-tkr-shadow);
  border-radius: var(--oxp-tkr-radius);
}

/* ---------- Tag / label ---------- */
.oxp-tkr__tag {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  padding: 0 18px;
  background: var(--oxp-tkr-tag-bg, #dc2626);
  color: var(--oxp-tkr-tag-text, #ffffff);
  font-family: var(--oxp-tkr-tag-font-family, inherit);
  font-size: var(--oxp-tkr-tag-font-size, inherit);
  font-weight: var(--oxp-tkr-tag-font-weight, 700);
  font-style: var(--oxp-tkr-tag-font-style, normal);
  text-decoration: var(--oxp-tkr-tag-text-decoration, none);
  text-transform: var(--oxp-tkr-tag-text-transform, uppercase);
  letter-spacing: .04em;
  white-space: nowrap;
  position: relative;
}
.oxp-tkr__tag::after {
  content: "";
  position: absolute;
  right: -9.5px;
  top: 0;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: calc(var(--oxp-tkr-height, 48px) / 2) 0 calc(var(--oxp-tkr-height, 48px) / 2) 10px;
  border-color: transparent transparent transparent var(--oxp-tkr-tag-decoration, var(--oxp-tkr-tag-bg, #dc2626));
  z-index: 2;
}

/* ---------- Pulse dot ---------- */
.oxp-tkr__pulse {
  display: flex;
  position: relative;
  flex: 0 0 auto;
  align-self: center;
  width: 9px;
  height: 9px;
  margin-right: 9px;
  border-radius: 50%;
  background: var(--oxp-tkr-pulse, #ffffff);
}
.oxp-tkr__pulse::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--oxp-tkr-pulse, #ffffff);
  animation: oxp-tkr-pulse 1.6s ease-out infinite;
}
@keyframes oxp-tkr-pulse {
  0%   { transform: scale(1);   opacity: .7; }
  100% { transform: scale(3.2); opacity: 0; }
}

/* ---------- Label pulse dot as an icon (optional) ----------
 * The same element as the dot, so the label's layout does not change and the
 * themes that counter-skew or reposition `.oxp-tkr__pulse` keep working
 * without knowing which of the two is inside. What changes is that the shape
 * stops being the element's background and starts being an SVG in front of
 * it, painted with `color` because the icon strokes with `currentColor`.
 *
 * The breathing lives on the SVG rather than on the wrapper, and that is not
 * arbitrary: the Comic theme owns the wrapper's transform (it counter-shears
 * it), and an animation on the same property would silently win. */
.oxp-tkr__pulse--icon {
  width: auto;
  height: auto;
  background: none;
  color: var(--oxp-tkr-pulse, #ffffff);
}
.oxp-tkr__pulse--icon::after { display: none; }
.oxp-tkr__icon {
  display: block;
  /* Tracks the label's own type size instead of a fixed pixel value, so the
     icon stays proportional at every ticker height. */
  width: 1.25em;
  height: 1.25em;
  animation: oxp-tkr-icon-breathe 2.6s ease-in-out infinite;
}
@keyframes oxp-tkr-icon-breathe {
  0%, 100% { transform: scale(1);    opacity: 1; }
  50%      { transform: scale(1.11); opacity: .72; }
}

/* ---------- Per-headline pulse dot (optional) ---------- */
.oxp-tkr__item-pulse {
  display: inline-flex;
  position: relative;
  flex: 0 0 auto;
  align-self: center;
  width: 8px;
  height: 8px;
  margin-right: 10px;
  border-radius: 50%;
  background: var(--oxp-tkr-item-pulse, var(--oxp-tkr-tag-bg, #dc2626));
}
.oxp-tkr__item-pulse::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: inherit;
  animation: oxp-tkr-pulse 1.6s ease-out infinite;
}

/* ---------- Item date (optional) ---------- */
/* Secondary information: it rides the headline color — so it also follows the
 * hover color — at reduced strength, unless a custom palette pins a color of
 * its own. It never shrinks; the headline is what truncates. */
.oxp-tkr__date {
  flex: 0 0 auto;
  color: var(--oxp-tkr-date, inherit);
  opacity: var(--oxp-tkr-date-opacity, .7);
  font-family: var(--oxp-tkr-date-font-family, inherit);
  font-size: var(--oxp-tkr-date-font-size, .85em);
  font-weight: var(--oxp-tkr-date-font-weight, 400);
  font-style: var(--oxp-tkr-date-font-style, normal);
  text-decoration: var(--oxp-tkr-date-text-decoration, none);
  text-transform: var(--oxp-tkr-date-text-transform, none);
  white-space: nowrap;
  line-height: 1;
}
.oxp-tkr__date--before { margin-right: 10px; }
/* Rendered before the headline in the DOM (so it is announced after it) and
 * moved to the end visually. */
.oxp-tkr__date--after { order: 1; margin-left: 10px; }

/* The headline is the part that gives way when space runs out. */
.oxp-tkr__headline {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------- News area ---------- */
.oxp-tkr__news-area {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  margin: 0;
  padding: 0;
  list-style: none;
}
.oxp-tkr__news-item {
  position: absolute;
  inset: 0;
  /* Not decoration, and the reason is worth keeping.
   *
   * These are <li> elements, and plenty of stylesheets give a list item a
   * bottom margin: wp-admin does, which is where this was found. An absolutely
   * positioned box with `top: 0; bottom: 0` still has its margin subtracted
   * from the used height, so a six pixel margin made every headline forty-two
   * pixels tall inside a forty-eight pixel bar, pinned to the top. The text
   * then centred itself in the wrong box and sat three pixels high, on every
   * theme that styles list items. */
  margin: 0;
  padding: 0;
  min-width: 0;
  transform: translateX(100%);
  opacity: 0;
  pointer-events: none;
  transition: transform var(--oxp-tkr-transition) var(--oxp-tkr-ease),
              opacity   var(--oxp-tkr-transition) var(--oxp-tkr-ease);
}
.oxp-tkr__news-item.park-left  { transform: translateX(-100%); opacity: 0; }
.oxp-tkr__news-item.park-right { transform: translateX(100%);  opacity: 0; }
.oxp-tkr__news-item.park-up    { transform: translateY(-100%); opacity: 0; }
.oxp-tkr__news-item.park-down  { transform: translateY(100%);  opacity: 0; }
.oxp-tkr__news-item.is-active {
  transform: translateX(0);
  opacity: 1;
  pointer-events: auto;
}
.oxp-tkr__news-item.no-anim { transition: none !important; }

.oxp-tkr__news-link {
  display: flex;
  align-items: center;
  width: 100%;
  height: 100%;
  padding: 0 24px;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--oxp-tkr-text, inherit);
  text-decoration: var(--oxp-tkr-text-decoration, none);
  text-transform: var(--oxp-tkr-text-transform, none);
}
a.oxp-tkr__news-link:hover {
  color: var(--oxp-tkr-text-hover, #dc2626);
  text-decoration: var(--oxp-tkr-text-decoration, none);
}
a.oxp-tkr__news-link:focus-visible {
  outline: 2px solid var(--oxp-tkr-focus);
  outline-offset: -3px;
  text-decoration: underline;
}
.oxp-tkr__news-link--plain { cursor: default; }

/* ---------- Controls ---------- */
.oxp-tkr__controls {
  display: flex;
  align-items: stretch;
  flex: 0 0 auto;
}
.oxp-tkr__controls > button {
  border: 1px solid var(--oxp-tkr-btn-border, transparent);
  background: var(--oxp-tkr-btn-bg, transparent);
  color: var(--oxp-tkr-btn-icon, #f9fafb);
  min-width: 44px;
  padding: 0;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background .2s ease, color .2s ease, border-color .2s ease;
}
.oxp-tkr__controls > button:hover {
  background: var(--oxp-tkr-btn-bg-hover, rgba(127, 127, 127, .14));
  color: var(--oxp-tkr-btn-icon-hover, #f87171);
}
.oxp-tkr__controls > button:focus-visible {
  outline: 2px solid var(--oxp-tkr-focus);
  outline-offset: -3px;
}
.oxp-tkr__controls > button[disabled] { opacity: .4; cursor: default; }
.oxp-tkr__ctrl-icon { width: 18px; height: 18px; display: block; }

.oxp-tkr__controls--toggle .oxp-tkr__ctrl-icon--play  { display: none; }
.oxp-tkr__controls--toggle .oxp-tkr__ctrl-icon--pause { display: block; }
.oxp-tkr__controls--toggle:not(.is-playing) .oxp-tkr__ctrl-icon--pause { display: none; }
.oxp-tkr__controls--toggle:not(.is-playing) .oxp-tkr__ctrl-icon--play  { display: block; }

/* ---------- Optional edge fade ---------- */
/* Masks the news area so headlines fade out at its sides. A mask (instead of
 * gradient overlays) works over any background, including gradients. */
.oxp-tkr--edge-fade .oxp-tkr__news-area {
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 32px, #000 calc(100% - 32px), transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 32px, #000 calc(100% - 32px), transparent 100%);
}

/* ---------- Continuous marquee mode ---------- */
/* The area is a clipping viewport; the track is a strip with all items in a
 * row, animated with a CSS keyframe. JS measures the strip, clones it for a
 * seamless wrap, and sets --oxp-tkr-marquee-dist / --oxp-tkr-marquee-duration.
 * The animation ships paused so no-JS visitors get a static, readable strip. */
.oxp-tkr__news-area--marquee { display: flex; align-items: stretch; }
.oxp-tkr__track {
  display: flex;
  align-items: stretch;
  flex: 0 0 auto;
  min-width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
  will-change: transform;
  animation: oxp-tkr-marquee var(--oxp-tkr-marquee-duration, 30s) linear infinite;
  animation-play-state: paused;
}
.oxp-tkr__track.is-running { animation-play-state: running; }
.oxp-tkr__track--reverse { animation-direction: reverse; }
@keyframes oxp-tkr-marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(var(--oxp-tkr-marquee-dist, -100%)); }
}
.oxp-tkr--marquee .oxp-tkr__news-item {
  position: static;
  inset: auto;
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  transform: none;
  opacity: 1;
  pointer-events: auto;
  transition: none;
}
.oxp-tkr--marquee .oxp-tkr__news-link {
  width: auto;
  max-width: none;
  overflow: visible;
  text-overflow: clip;
  padding: 0 28px;
}
/* Nothing truncates in the strip: every headline is laid out at full width. */
.oxp-tkr--marquee .oxp-tkr__headline {
  overflow: visible;
  text-overflow: clip;
}

/* =========================================================================
 * COLOR MODE
 * ========================================================================= */
/* Every palette color arrives as an inline custom property, so the mode only
 * has to flip the decorations that are hard-coded for a dark bar: a white
 * gloss reads as nothing over a light background, and the drop shadows the
 * themes use are too heavy for one. */
.oxp-tkr--mode-light {
  --oxp-tkr-sheen:  rgba(0, 0, 0, .05);
  --oxp-tkr-chrome: rgba(0, 0, 0, .05);
  --oxp-tkr-ink:    rgba(0, 0, 0, .32);
  /* Both stay white and both get stronger. On a pale surface a white wash has
   * less room to work in, so it needs more of itself to register at all. */
  --oxp-tkr-rim:    rgba(255, 255, 255, .85);
  --oxp-tkr-haze:   rgba(255, 255, 255, .62);
}

/* =========================================================================
 * THEMES (structure only)
 * ========================================================================= */
/* Classic: uses the base values (straight bar, label with arrow). */

/* Modern: rounded, wide shadow, contained 'island' label. */
.oxp-tkr--theme-modern {
  --oxp-tkr-radius: 12px;
  --oxp-tkr-shadow: 0 10px 30px rgba(0, 0, 0, .18);
  position: relative;
}
.oxp-tkr--theme-modern::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(90deg, var(--oxp-tkr-sheen), transparent 40%);
}
.oxp-tkr--mode-light.oxp-tkr--theme-modern { --oxp-tkr-shadow: 0 10px 30px rgba(0, 0, 0, .08); }
.oxp-tkr--theme-modern .oxp-tkr__tag {
  align-self: center;
  height: calc(var(--oxp-tkr-height, 48px) - 10px);
  margin-left: 6px;
  border-radius: 8px;
}
.oxp-tkr--theme-modern .oxp-tkr__tag::after { display: none; }

/* Breaking: skewed bar with an offset label and wrapped controls. */
.oxp-tkr--theme-breaking {
  --oxp-tkr-radius: 8px;
  --oxp-tkr-shadow: 0 8px 24px rgba(0, 0, 0, .28);
  position: relative;
  overflow: visible;
  transform: skewX(-4deg);
}
.oxp-tkr--theme-breaking::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(100deg, var(--oxp-tkr-sheen), transparent 55%);
}
.oxp-tkr--mode-light.oxp-tkr--theme-breaking { --oxp-tkr-shadow: 0 8px 24px rgba(0, 0, 0, .12); }
/* Counter-skew inner content for readability. */
.oxp-tkr--theme-breaking .oxp-tkr__tag-text,
.oxp-tkr--theme-breaking .oxp-tkr__pulse,
.oxp-tkr--theme-breaking .oxp-tkr__news-link,
.oxp-tkr--theme-breaking .oxp-tkr__ctrl-icon { transform: skewX(4deg); }
/* Label: offset above and to the left. */
.oxp-tkr--theme-breaking .oxp-tkr__tag {
  align-self: center;
  height: calc(var(--oxp-tkr-height, 48px) - 10px);
  margin: 0 16px 0 7px;
  margin-left: -4px;
  border-radius: 6px;
  border-bottom: 3px solid var(--oxp-tkr-tag-border, rgba(0, 0, 0, .28));
  box-shadow: 0 4px 10px rgba(0, 0, 0, .3);
  z-index: 1;
}
.oxp-tkr--theme-breaking .oxp-tkr__tag::after { display: none; }
/* Controls: visual wrapper. */
.oxp-tkr--theme-breaking .oxp-tkr__controls {
  background: var(--oxp-tkr-chrome);
  border-radius: 0 8px 8px 0;
}

/* Minimalist: flat and airy — no chip, no shadow; the label becomes
 * accent-colored text followed by a hairline divider. */
.oxp-tkr--theme-minimal {
  --oxp-tkr-radius: 0;
  --oxp-tkr-shadow: none;
}
.oxp-tkr--theme-minimal .oxp-tkr__tag {
  background: transparent;
  padding: 0 16px;
  /* Readable fallback when background-clip: text is unsupported. */
  color: var(--oxp-tkr-text, #f9fafb);
}
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .oxp-tkr--theme-minimal .oxp-tkr__tag-text {
    /* Paint the label text with the tag color; also works with gradients. */
    background: var(--oxp-tkr-tag-bg, #dc2626);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}
/* The label pulse sits on the bar background here (not on the chip), so it
 * borrows the tag color to stay visible on any palette. */
.oxp-tkr--theme-minimal .oxp-tkr__pulse,
.oxp-tkr--theme-minimal .oxp-tkr__pulse::after {
  background: var(--oxp-tkr-tag-bg, #dc2626);
}
/* Arrow replaced by a hairline divider. */
.oxp-tkr--theme-minimal .oxp-tkr__tag::after {
  right: 0;
  top: 22%;
  width: 1px;
  height: 56%;
  border: 0;
  background: var(--oxp-tkr-text, currentColor);
  opacity: .3;
}

/* Comic: an action-comic panel.
 *
 * The brief was explicitly not "draw a fat black outline around everything",
 * which is what a comic theme usually turns out to be and which would also be
 * the one decoration guaranteed to fight thirteen different palettes. What
 * actually reads as an action comic is the printing, not the inking, so the
 * theme is built from three period-correct devices instead:
 *
 *   - impact rays fanning out from behind the label, the panel's focal point;
 *   - a halftone dot field over the rest of the bar, where a printed comic put
 *     its flat tone;
 *   - a burst-edged label sitting slightly crooked, like a slapped-on sticker.
 *
 * All three are painted with the palette's own --oxp-tkr-sheen, so they arrive
 * as light on a dark bar and as shade on a light one and never introduce a
 * color of their own. The only near-black in the theme is --oxp-tkr-ink, and
 * it is an offset shadow rather than a border: it reads as the ink
 * misregistration of cheap four-color printing, which is the point.
 */
.oxp-tkr--theme-comic {
  --oxp-tkr-radius: 10px;
  /* Soft ambient shadow under the bar, then the hard printed offset. Two
   * shadows, two jobs; the second one is what makes it a comic panel. */
  --oxp-tkr-shadow: 0 8px 22px rgba(0, 0, 0, .22), 5px 5px 0 var(--oxp-tkr-ink);
  position: relative;
  isolation: isolate;
  /* The label is pasted on top of the panel and hangs off its top-left
   * corner, so the bar cannot clip its own children. The news area does its
   * own clipping, which is the only place it was ever needed. */
  overflow: visible;
}
.oxp-tkr--mode-light.oxp-tkr--theme-comic {
  --oxp-tkr-shadow: 0 8px 22px rgba(0, 0, 0, .10), 5px 5px 0 var(--oxp-tkr-ink);
}

/* Impact rays. A repeating conic gradient centred behind the label throws a
 * fan of wedges across the left third; the mask fades them out before they
 * reach the headline, so the text never sits on a stripe. */
.oxp-tkr--theme-comic::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  /* The bar stopped clipping (see above), so each layer rounds its own
     corners or it would paint square ones over a rounded panel. */
  border-radius: inherit;
  background: repeating-conic-gradient(
    from 0deg at 10% 50%,
    var(--oxp-tkr-sheen) 0deg 3.5deg,
    transparent 3.5deg 11deg
  );
  -webkit-mask-image: linear-gradient(90deg, #000 0, rgba(0, 0, 0, .55) 22%, transparent 52%);
          mask-image: linear-gradient(90deg, #000 0, rgba(0, 0, 0, .55) 22%, transparent 52%);
}

/* Halftone. Two dot grids offset by half a cell give the staggered lattice a
 * screen-printed tone actually has; one grid alone reads as graph paper. The
 * mask hands the right-hand side of the bar over to it as the rays fade. */
.oxp-tkr--theme-comic::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  border-radius: inherit;
  background-image:
    radial-gradient(var(--oxp-tkr-sheen) 1.4px, transparent 1.5px),
    radial-gradient(var(--oxp-tkr-sheen) 1.4px, transparent 1.5px);
  background-size: 10px 10px, 10px 10px;
  background-position: 0 0, 5px 5px;
  -webkit-mask-image: linear-gradient(90deg, transparent 30%, #000 78%);
          mask-image: linear-gradient(90deg, transparent 30%, #000 78%);
}

/* The label: a sticker slapped onto the panel.
 *
 * Three things make it read as pasted on rather than built in, and all three
 * are cheap: a shear, so it disagrees with the rectangle behind it; a negative
 * offset up and to the left, so it overhangs the corner instead of sitting
 * inside it; and a hard, blur-free shadow, which is the ink misregistration of
 * cheap four-colour printing. The shear is `skewX` rather than `rotate` for
 * the same reason the Breaking theme uses it: a rotation makes the two
 * horizontal edges disagree with the bar's, and at 48 pixels tall that reads
 * as a mistake. A shear keeps them parallel.
 *
 * The chip is a plain rounded rectangle now. It carried a clip-path burst
 * edge, and the teeth fought both the rounded panel and every label longer
 * than one word. */
.oxp-tkr--theme-comic .oxp-tkr__tag {
  align-self: center;
  z-index: 2;
  height: calc(var(--oxp-tkr-height, 48px) - 4px);
  /* Negative left margin and a lifted transform: the chip hangs off the panel
     at the top-left. The right margin is what keeps the first headline clear
     of a chip that is now wider than its own box. */
  margin: 0 18px 0 -12px;
  padding: 0 20px;
  border-radius: 5px;
  letter-spacing: .07em;
  transform: translateY(-8px) skewX(-10deg);
  box-shadow: 4px 4px 0 var(--oxp-tkr-ink);
}
/* Counter-shear everything inside it, or the type leans too. */
.oxp-tkr--theme-comic .oxp-tkr__tag-text,
.oxp-tkr--theme-comic .oxp-tkr__pulse {
  transform: skewX(10deg);
}
/* The arrow belongs to Classic; this label has its own silhouette. */
.oxp-tkr--theme-comic .oxp-tkr__tag::after { display: none; }

/* Hand-lettering: a single hard offset under the glyphs, the same trick the
 * bar itself uses, at a size that survives an 11px sample in the editor. */
.oxp-tkr--theme-comic .oxp-tkr__tag-text {
  text-shadow: 1.5px 1.5px 0 var(--oxp-tkr-ink);
}

/* The pulse dots are the plain round ones every other theme uses. Comic used
 * to turn them into four-point sparkles, which was a shape decision hidden
 * inside a theme: it belonged to whoever wanted a sparkle, not to whoever
 * wanted this theme. That is now a setting of its own (see the label icon in
 * the Style tab, and Icons::all() for the set), and "sparkle" is one of the
 * icons in it. */

/* The headline sits above the tone so the dots never run through the type. */
.oxp-tkr--theme-comic .oxp-tkr__news-area { z-index: 1; }

/* Controls as press-in stickers: they lift towards the reader on hover and
 * leave their printed shadow behind, which is the same ink device again.
 * The background falls back to the palette's chrome only when no custom
 * button color was set, so a Custom palette still wins. */
.oxp-tkr--theme-comic .oxp-tkr__controls {
  position: relative;
  z-index: 1;
  align-items: center;
  gap: 5px;
  padding: 0 8px 0 4px;
}
.oxp-tkr--theme-comic .oxp-tkr__controls > button {
  min-width: 34px;
  height: calc(var(--oxp-tkr-height, 48px) - 16px);
  border-radius: 6px;
  background: var(--oxp-tkr-btn-bg, var(--oxp-tkr-chrome));
  transition: transform .15s ease, box-shadow .15s ease, background .2s ease, color .2s ease;
}
.oxp-tkr--theme-comic .oxp-tkr__controls > button:hover {
  transform: translate(-1px, -1px);
  box-shadow: 3px 3px 0 var(--oxp-tkr-ink);
}
.oxp-tkr--theme-comic .oxp-tkr__controls > button:active {
  transform: translate(1px, 1px);
  box-shadow: 0 0 0 var(--oxp-tkr-ink);
}

/* Capsule: one continuous curve, and soft light on it.
 *
 * The radius is not a rounded corner, it is the shape. Anything larger than
 * half the bar's height resolves to exactly half, so the ends are semicircles
 * whatever height the ticker is set to and the outline never has to be tuned:
 * a stadium at 48 pixels tall and a stadium at 90.
 *
 * Everything else is about making that shape read as a solid, glossy body
 * rather than a flat pill, and all of it is soft. There is no texture here on
 * purpose: a pattern would put an edge on the one theme whose whole point is
 * that it has none. Two things do the work instead.
 *
 * The rim comes first, because it is what a curved glossy surface actually
 * does: a bright line along the top where it turns towards the light, a
 * fainter one along the bottom where it turns away. Without them the capsule
 * is a shape; with them it has a front and a back.
 *
 * Then the light, in two layers: a broad gloss across the upper half, and
 * three very wide pools at different sizes along the length. The pools matter
 * more than they look. Evenly lit, a long capsule reads as printed; unevenly
 * lit, it reads as an object with a room around it.
 */
.oxp-tkr--theme-capsule {
  --oxp-tkr-radius: 999px;
  --oxp-tkr-shadow:
    0 10px 30px rgba(0, 0, 0, .20),
    inset 0 1px 0 var(--oxp-tkr-rim),
    inset 0 -1px 0 var(--oxp-tkr-sheen);
  position: relative;
  isolation: isolate;
}
.oxp-tkr--mode-light.oxp-tkr--theme-capsule {
  --oxp-tkr-shadow:
    0 10px 30px rgba(0, 0, 0, .10),
    inset 0 1px 0 var(--oxp-tkr-rim),
    inset 0 -1px 0 var(--oxp-tkr-sheen);
}

/* The gloss: strongest along the top and gone before halfway down, which is
 * where the light stops on a body this shape. */
.oxp-tkr--theme-capsule::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  border-radius: inherit;
  background: linear-gradient(180deg, var(--oxp-tkr-haze) 0%, transparent 58%);
}

/* The pools. Three, at three sizes, none of them centred and none the same
 * distance apart: regular spacing is the one thing that would give away that
 * this is a gradient and not a room. */
.oxp-tkr--theme-capsule::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  border-radius: inherit;
  background:
    radial-gradient(340px 120px at 15% 26%, var(--oxp-tkr-haze), transparent 70%),
    radial-gradient(260px  96px at 52% 84%, var(--oxp-tkr-haze), transparent 72%),
    radial-gradient(420px 136px at 89% 22%, var(--oxp-tkr-haze), transparent 70%);
}

/* The label repeats the shape at a smaller size, which is what makes the two
 * look designed together rather than stacked. Same lit top edge, and a soft
 * halo of its own colour so it reads as lit from within rather than printed
 * on. The halo takes the decoration token because that one is guaranteed solid
 * even when the label is a gradient. */
.oxp-tkr--theme-capsule .oxp-tkr__tag {
  align-self: center;
  z-index: 2;
  height: calc(var(--oxp-tkr-height, 48px) - 12px);
  /* Twelve, and it is not a guess: it is the number that makes the gap on the
     left exactly the gap above and below.
     
     Both shapes are stadiums, so the chip sits `g` pixels inside the bar all
     the way round only when the two end-cap centres are `g` apart. The chip is
     `2g` shorter than the bar (its height is height - 12, so g = 6), which
     puts its own cap centre at `margin + (H - 2g)/2` and the bar's at `H/2`.
     Setting those `g` apart gives margin = 2g, whatever the ticker's height
     is. Six above and below, twelve on the left, same gap. */
  margin: 0 12px;
  padding: 0 18px;
  border-radius: 999px;
  box-shadow:
    inset 0 1px 0 var(--oxp-tkr-rim),
    0 0 20px -6px var(--oxp-tkr-tag-decoration, var(--oxp-tkr-tag-bg));
}
.oxp-tkr--theme-capsule .oxp-tkr__tag::after { display: none; }

/* Above the light, so nothing washes across the type. */
.oxp-tkr--theme-capsule .oxp-tkr__news-area { z-index: 1; }

.oxp-tkr--theme-capsule .oxp-tkr__controls {
  position: relative;
  z-index: 1;
  align-items: center;
  gap: 4px;
  /* Same reason as the label's left margin, at the other end. */
  padding: 0 16px 0 4px;
}
.oxp-tkr--theme-capsule .oxp-tkr__controls > button {
  min-width: 32px;
  height: calc(var(--oxp-tkr-height, 48px) - 16px);
  border-radius: 999px;
  background: var(--oxp-tkr-btn-bg, var(--oxp-tkr-chrome));
  box-shadow: inset 0 1px 0 var(--oxp-tkr-rim);
}

/* Galaxy: a window onto deep space.
 *
 * A nebula is not a fog, it is structure: sheets and filaments lit from
 * inside, which is why a single blurred blob never looks like one. So the
 * cloud layer is built from stretched radial blooms for the sheets and a
 * shallow repeating gradient for the filaments running through them, and the
 * whole layer is blurred once at the end. Blurring after composing is what
 * fuses the two into something that looks photographed rather than drawn.
 *
 * Its colours are the palette's own accent and hover colour, at low strength,
 * so a nebula in Gold is warm and one in Arctic is cold without either being
 * told about it. The layer is inset past the edges because the blur would
 * otherwise fade out before reaching them and leave a visible border of bare
 * background; the bar clips the overspill.
 */
.oxp-tkr--theme-galaxy {
  --oxp-tkr-radius: 12px;
  --oxp-tkr-shadow: 0 12px 34px rgba(0, 0, 0, .30);
  position: relative;
  isolation: isolate;
}
.oxp-tkr--mode-light.oxp-tkr--theme-galaxy { --oxp-tkr-shadow: 0 12px 34px rgba(0, 0, 0, .12); }

.oxp-tkr--theme-galaxy::before {
  content: "";
  position: absolute;
  inset: -20px;
  z-index: 0;
  pointer-events: none;
  opacity: .6;
  filter: blur(6px);
  background:
    /* Filaments, threaded through the clouds below them. Two periods at
     * slightly different angles rather than one: a single repeating gradient
     * reads as diagonal stripes no matter how soft it is, and two that never
     * line up beat against each other into something irregular, which is what
     * blurs into filament structure instead of into a corduroy. */
    repeating-linear-gradient(104deg,
      transparent 0 9px,
      var(--oxp-tkr-rim) 9px 10.2px,
      transparent 10.2px 27px),
    repeating-linear-gradient(97deg,
      transparent 0 15px,
      var(--oxp-tkr-sheen) 15px 16px,
      transparent 16px 41px),
    /* the clouds: two accent-coloured sheets and one neutral one */
    radial-gradient(78% 220% at 14% 132%, var(--oxp-tkr-tag-decoration, var(--oxp-tkr-tag-bg)), transparent 58%),
    radial-gradient(66% 200% at 61% -42%, var(--oxp-tkr-text-hover, var(--oxp-tkr-sheen)), transparent 60%),
    radial-gradient(52% 185% at 89% 124%, var(--oxp-tkr-tag-decoration, var(--oxp-tkr-tag-bg)), transparent 62%),
    radial-gradient(42% 155% at 37% -24%, var(--oxp-tkr-sheen), transparent 70%);
}

/* Stars. Hand-placed rather than tiled, because an even scatter is the one
 * thing a real star field never is; the sizes vary for the same reason. They
 * are painted in the headline colour, so on a light palette they read as a
 * star chart on paper rather than disappearing. */
.oxp-tkr--theme-galaxy::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  border-radius: inherit;
  opacity: .9;
  background-image:
    radial-gradient(2.0px 2.0px at  7% 24%, var(--oxp-tkr-text), transparent 70%),
    radial-gradient(1.3px 1.3px at 13% 71%, var(--oxp-tkr-text), transparent 70%),
    radial-gradient(1.6px 1.6px at 21% 38%, var(--oxp-tkr-text), transparent 70%),
    radial-gradient(2.2px 2.2px at 29% 82%, var(--oxp-tkr-text), transparent 70%),
    radial-gradient(1.2px 1.2px at 36% 16%, var(--oxp-tkr-text), transparent 70%),
    radial-gradient(1.7px 1.7px at 44% 63%, var(--oxp-tkr-text), transparent 70%),
    radial-gradient(1.3px 1.3px at 52% 29%, var(--oxp-tkr-text), transparent 70%),
    radial-gradient(2.1px 2.1px at 59% 88%, var(--oxp-tkr-text), transparent 70%),
    radial-gradient(1.5px 1.5px at 67% 47%, var(--oxp-tkr-text), transparent 70%),
    radial-gradient(1.2px 1.2px at 74% 19%, var(--oxp-tkr-text), transparent 70%),
    radial-gradient(1.9px 1.9px at 81% 74%, var(--oxp-tkr-text), transparent 70%),
    radial-gradient(1.3px 1.3px at 88% 34%, var(--oxp-tkr-text), transparent 70%),
    radial-gradient(1.6px 1.6px at 94% 66%, var(--oxp-tkr-text), transparent 70%),
    radial-gradient(1.2px 1.2px at 97% 12%, var(--oxp-tkr-text), transparent 70%);
  animation: oxp-tkr-twinkle 5.2s ease-in-out infinite;
}
/* Slow and shallow. Stars do not blink; the atmosphere between them shifts. */
@keyframes oxp-tkr-twinkle {
  0%, 100% { opacity: .9; }
  50%      { opacity: .58; }
}

.oxp-tkr--theme-galaxy .oxp-tkr__tag {
  align-self: center;
  z-index: 2;
  height: calc(var(--oxp-tkr-height, 48px) - 12px);
  margin: 0 14px 0 7px;
  padding: 0 18px;
  border-radius: 8px;
  box-shadow:
    inset 0 1px 0 var(--oxp-tkr-rim),
    0 0 24px -4px var(--oxp-tkr-tag-decoration, var(--oxp-tkr-tag-bg));
}
.oxp-tkr--theme-galaxy .oxp-tkr__tag::after { display: none; }

.oxp-tkr--theme-galaxy .oxp-tkr__news-area { z-index: 1; }

.oxp-tkr--theme-galaxy .oxp-tkr__controls {
  position: relative;
  z-index: 1;
  align-items: center;
  gap: 4px;
  padding: 0 8px 0 4px;
}
.oxp-tkr--theme-galaxy .oxp-tkr__controls > button {
  min-width: 32px;
  height: calc(var(--oxp-tkr-height, 48px) - 16px);
  border-radius: 8px;
  background: var(--oxp-tkr-btn-bg, var(--oxp-tkr-chrome));
  box-shadow: inset 0 1px 0 var(--oxp-tkr-rim);
}

/* =========================================================================
 * FADE MODE (crossfade in place)
 * ========================================================================= */
/* The slide engine drives the same park/is-active classes; forcing the
 * transform off leaves opacity as the only animated property. */
.oxp-tkr--fade .oxp-tkr__news-item,
.oxp-tkr--fade .oxp-tkr__news-item.park-left,
.oxp-tkr--fade .oxp-tkr__news-item.park-right,
.oxp-tkr--fade .oxp-tkr__news-item.park-up,
.oxp-tkr--fade .oxp-tkr__news-item.park-down {
  transform: none;
}

/* =========================================================================
 * THEME: SKETCH (Premium)
 * =========================================================================
 * Drawn, not built. The other themes are all the same object with different
 * finishes; this one is a pen drawing of that object, and every rule below is
 * one of the three tells that say so.
 *
 * 1. NOTHING IS DRAWN ONCE. The panel carries a second outline that does not
 *    agree with the first, and so does the label. Two lines that nearly match
 *    is the single most recognisable mark of a hand, and it costs one pseudo
 *    element each.
 *
 * 2. NOTHING IS SYMMETRICAL. Every corner radius here is a different pair of
 *    numbers. The trick is the slash syntax: `border-radius: a b c d / e f g h`
 *    sets the horizontal and vertical radii of each corner separately, so a
 *    corner can be 255px wide and 15px tall, which no drawing tool produces and
 *    no hand avoids. The values are deliberately unroundable, and none of them
 *    is repeated between the panel, its ghost line and the label.
 *
 * 3. THE SHADOW IS HATCHED. A drawing has no blur to give: shade is a lot of
 *    parallel strokes at forty five degrees, packed tighter where it is darker.
 *    That is a repeating-linear-gradient, laid in an L along the bottom and
 *    right of the panel and entirely outside it, so no masking is needed and
 *    the panel's own background never has to know about it.
 *
 * THE PEN. The line colour is not a palette token because none of the existing
 * ones is a line: `--oxp-tkr-ink` is a shadow, dark in both modes, which on a
 * dark bar is invisible. A pen is the opposite of its paper, so it is declared
 * here per mode, in black and white only, exactly like the tokens it sits
 * beside. That keeps the theme working in all fifteen palettes and in a Custom
 * one nobody has built yet, which is the rule for every theme in this file.
 */
.oxp-tkr--theme-sketch {
  --oxp-tkr-pen:      rgba(255, 255, 255, .92);
  --oxp-tkr-pen-soft: rgba(255, 255, 255, .45);
  --oxp-tkr-radius: 0;
  /* No ambient shadow: the hatching is the shadow. */
  --oxp-tkr-shadow: none;
  position: relative;
  isolation: isolate;
  /* The ghost outline and the circled label both hang outside the panel. The
     news area does its own clipping, which is the only place it was needed. */
  overflow: visible;
  border: 3px solid var(--oxp-tkr-pen);
  /* The corners are the drawing. Each one is a different pair of radii, and
     the numbers are small on purpose: the well known "hand drawn box" recipe
     uses radii in the hundreds, which is right for a box a few hundred pixels
     across and invisible on a bar that is a thousand wide and forty eight
     tall. At this aspect ratio a 250px sweep is a straight line. These are
     sized so the curve happens within a corner's own width, where an eye
     reads it as a wobble rather than as a very slight taper. */
  border-radius: 26px 7px 20px 9px / 9px 18px 7px 24px;
}
.oxp-tkr--mode-light.oxp-tkr--theme-sketch {
  --oxp-tkr-pen:      rgba(17, 24, 39, .9);
  --oxp-tkr-pen-soft: rgba(17, 24, 39, .42);
}

/* The second pass of the pen: same box, traced again, missing it. Offset by a
   few pixels in each direction and rounded to a different set of corners, so
   the two lines cross somewhere along every edge instead of running parallel.
   Lighter than the first, because the hand pressed once and hesitated once. */
.oxp-tkr--theme-sketch::after {
  content: "";
  position: absolute;
  inset: -6px -4px -3px -5px;
  z-index: 0;
  pointer-events: none;
  border: 2px solid var(--oxp-tkr-pen-soft);
  border-radius: 8px 23px 9px 21px / 19px 8px 25px 7px;
}

/* Hatched shading, in an L down the right side and along the bottom.
 *
 * One element, shaped by its mask. The obvious implementations both fail: a
 * box offset behind the panel is not behind it at all (a negative z-index
 * child paints above its parent's background, and dropping the stacking
 * context only moves the problem up to the first ancestor with a background of
 * its own), and hanging the second strip off the news area means that area can
 * no longer clip, which lets long headlines run out under the controls.
 *
 * So the box does overlap the panel, and two mask layers cut it back to the L
 * that pokes out. Multiple mask layers add together, so a full-width strip
 * along the bottom plus a full-height strip down the right leaves exactly the
 * shading and nothing else. The two gradients meet at the corner without
 * lining up, which is what a hand doubling back over a corner does anyway. */
.oxp-tkr--theme-sketch::before {
  content: "";
  position: absolute;
  inset: 12px -11px -11px 12px;
  z-index: 0;
  pointer-events: none;
  border-bottom-right-radius: 14px;
  background-image: repeating-linear-gradient(
    45deg,
    var(--oxp-tkr-pen-soft) 0 1.7px,
    transparent 1.7px 5.5px
  );
  -webkit-mask-image: linear-gradient(#000, #000), linear-gradient(#000, #000);
          mask-image: linear-gradient(#000, #000), linear-gradient(#000, #000);
  -webkit-mask-size: 100% 11px, 11px 100%;
          mask-size: 100% 11px, 11px 100%;
  -webkit-mask-position: left bottom, right top;
          mask-position: left bottom, right top;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
}

/* THE LABEL. A box, but a box someone drew.
 *
 * It went through an ellipse on the way here and the ellipse was wrong: a
 * circled word is a lovely gesture and it is also a different object from the
 * bar it sits in, so the two never looked like one drawing. A rectangle keeps
 * the family resemblance to the panel, and everything that makes the panel
 * look hand made works on it at a smaller scale.
 *
 * So: the same trick, one third of the size. Four different corners, each with
 * its own pair of radii, none of them repeated from the panel's set. Around it
 * the same double line, the second one rotated the other way so the two are
 * furthest apart at the ends and nearly touch in the middle.
 *
 * The whole thing leans a degree and a half. That is enough to disagree with
 * the bar and not enough to look broken at 48 pixels tall, which is the same
 * limit the Breaking and Comic themes found for their shear. */
.oxp-tkr--theme-sketch .oxp-tkr__tag {
  align-self: center;
  z-index: 2;
  height: calc(var(--oxp-tkr-height, 48px) - 15px);
  margin: 0 22px 0 12px;
  padding: 0 15px;
  border: 2px solid var(--oxp-tkr-pen);
  border-radius: 13px 4px 10px 6px / 5px 11px 4px 12px;
  transform: rotate(-1.6deg);
}
.oxp-tkr--theme-sketch .oxp-tkr__tag::before {
  content: "";
  position: absolute;
  inset: -5px -6px;
  pointer-events: none;
  border: 1.5px solid var(--oxp-tkr-pen-soft);
  border-radius: 4px 12px 5px 10px / 11px 4px 13px 5px;
  transform: rotate(2.6deg);
}
/* The arrow belongs to Classic, and nothing circled has one. */
.oxp-tkr--theme-sketch .oxp-tkr__tag::after { display: none; }
/* Counter-rotate the type so the word stays level inside the tilted ring. */
.oxp-tkr--theme-sketch .oxp-tkr__tag-text,
.oxp-tkr--theme-sketch .oxp-tkr__pulse { transform: rotate(1.6deg); }

/* Headlines ride above the hatching. */
.oxp-tkr--theme-sketch .oxp-tkr__news-link { position: relative; z-index: 1; }

/* Controls as little pen boxes: outlined, transparent, each one rounded
   differently from its neighbour so a row of them never reads as a widget. */
.oxp-tkr--theme-sketch .oxp-tkr__controls {
  position: relative;
  z-index: 1;
  align-items: center;
  gap: 6px;
  padding: 0 12px 0 6px;
}
.oxp-tkr--theme-sketch .oxp-tkr__controls > button {
  min-width: 30px;
  height: 30px;
  border: 1.8px solid var(--oxp-tkr-pen);
  border-radius: 16px 5px 14px 6px / 6px 14px 5px 16px;
  background: transparent;
  color: var(--oxp-tkr-btn-icon, currentColor);
}
.oxp-tkr--theme-sketch .oxp-tkr__controls > button:nth-child(2n) {
  border-radius: 6px 15px 5px 17px / 15px 6px 16px 5px;
}
.oxp-tkr--theme-sketch .oxp-tkr__controls > button:hover {
  background: var(--oxp-tkr-pen-soft);
}

/* ---------- Responsive ---------- */
@media (max-width: 640px) {
  .oxp-tkr { font-size: 14px; }
  .oxp-tkr__tag { padding: 0 12px; }
  .oxp-tkr__news-link { padding: 0 16px; }
}

/* Sketch keeps the double line and the hatching, which are what it is, and
   gives up the overhang: a ghost outline six pixels wider than a bar that is
   already the width of the screen is a ghost outline off the screen. */
@media (max-width: 640px) {
  .oxp-tkr--theme-sketch::after { inset: -3px -2px -2px -3px; }
  .oxp-tkr--theme-sketch::before {
    inset: 8px -7px -7px 8px;
    -webkit-mask-size: 100% 7px, 7px 100%;
            mask-size: 100% 7px, 7px 100%;
  }
  .oxp-tkr--theme-sketch .oxp-tkr__tag { margin: 0 16px 0 8px; padding: 0 12px; }
  .oxp-tkr--theme-sketch .oxp-tkr__tag::before { inset: -3px -5px; }
}

@media (max-width: 480px) {
  .oxp-tkr { font-size: 13px; }
  .oxp-tkr__tag { padding: 0 10px; letter-spacing: .02em; }
  .oxp-tkr__news-link { padding: 0 12px; }
  .oxp-tkr__controls > button { min-width: 36px; }

  /* Narrower edge fade so headlines keep enough readable width. */
  .oxp-tkr--edge-fade .oxp-tkr__news-area {
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 18px, #000 calc(100% - 18px), transparent 100%);
            mask-image: linear-gradient(90deg, transparent 0, #000 18px, #000 calc(100% - 18px), transparent 100%);
  }

  /* Simplify the breaking theme on very small screens. */
  .oxp-tkr--theme-breaking {
    transform: none;
    overflow: hidden;
    border-radius: var(--oxp-tkr-radius);
  }
  .oxp-tkr--theme-breaking .oxp-tkr__tag { border-radius: 4px; }
  .oxp-tkr--theme-breaking .oxp-tkr__tag-text,
  .oxp-tkr--theme-breaking .oxp-tkr__pulse,
  .oxp-tkr--theme-breaking .oxp-tkr__news-link,
  .oxp-tkr--theme-breaking .oxp-tkr__ctrl-icon { transform: none; }

  /* Comic keeps its printing but drops the theatrics: at this width the tilt
   * costs more room than it is worth and the offset shadow would fall off the
   * viewport. The rays and the halftone carry the theme on their own. */
  .oxp-tkr--theme-comic {
    --oxp-tkr-shadow: 0 6px 16px rgba(0, 0, 0, .2), 3px 3px 0 var(--oxp-tkr-ink);
  }
  /* The overhang is the first thing to go: a chip hanging off the left of a
     bar that is already the width of the screen hangs off the screen. */
  .oxp-tkr--theme-comic .oxp-tkr__tag {
    height: calc(var(--oxp-tkr-height, 48px) - 8px);
    margin: 0 10px 0 5px;
    padding: 0 12px;
    transform: skewX(-8deg);
    box-shadow: 3px 3px 0 var(--oxp-tkr-ink);
  }
  .oxp-tkr--theme-comic .oxp-tkr__tag-text,
  .oxp-tkr--theme-comic .oxp-tkr__pulse { transform: skewX(8deg); }
  .oxp-tkr--theme-comic .oxp-tkr__controls > button { min-width: 30px; }
}

/* ---------- Reduced motion (WCAG 2.3.3 / 2.2.2) ---------- */
@media (prefers-reduced-motion: reduce) {
  .oxp-tkr__news-item {
    transition: opacity .2s ease !important;
    transform: none !important;
  }
  .oxp-tkr__news-item:not(.is-active) { opacity: 0; }
  .oxp-tkr__pulse::after,
  .oxp-tkr__item-pulse::after { animation: none; }
  .oxp-tkr__icon { animation: none; }
  .oxp-tkr--theme-galaxy::after { animation: none; }

  /* Marquee: freeze the strip; every item stays visible and readable. */
  .oxp-tkr__track { animation: none; }
  .oxp-tkr--marquee .oxp-tkr__news-item { opacity: 1; }
}
