/* pattern-tape - a full-bleed ruled strip carrying a drifting repeating pattern (checkerboard or a row of flat shapes).
   <div class="ptape" aria-hidden="true"></div>                            checker (CSS only)
   <div class="ptape" data-ptape="shapes" aria-hidden="true"></div>        shapes (part.js draws the tile)
   The pattern lives on ::before, which is the strip's width + one loop wide and slides one loop per --ptape-dur, linear,
   forever. --ptape-loop is a whole number of pattern periods, so the wrap is invisible at any width. */
.ptape {
  --ptape-h: 32px;                 /* pattern height (rules sit outside it) */
  --ptape-cell: 16px;              /* checker square */
  --ptape-a: #000;                 /* checker colour at the top-left */
  --ptape-b: #fff;                 /* the other checker colour */
  --ptape-bg: transparent;         /* band fill behind shapes */
  --ptape-loop: 1472px;            /* travel per cycle = source's half-track (1.5 x 981px tiles) */
  --ptape-dur: 40s;                /* time per loop: 1472px / 40s = 36.8 px/s */
  --ptape-rule-top: 0px;
  --ptape-rule-bottom: 1px;
  --ptape-rule-color: #000;
  position: relative;
  display: block;
  width: 100%;
  height: var(--ptape-h);
  overflow: hidden;
  background: var(--ptape-bg);
  border-style: solid;
  border-color: var(--ptape-rule-color);
  border-width: var(--ptape-rule-top) 0 var(--ptape-rule-bottom);
  box-sizing: content-box;
  contain: paint;
  pointer-events: none;
}
.ptape::before {
  content: "";
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: calc(100% + var(--ptape-loop));
  /* checker: TL = a, TR = b, BR = a, BL = b (conic quadrants run clockwise from the top) */
  background-image: var(--ptape-img, repeating-conic-gradient(var(--ptape-b) 0 25%, var(--ptape-a) 0 50%));
  background-size: var(--ptape-tile-w, calc(var(--ptape-cell) * 2)) var(--ptape-tile-h, calc(var(--ptape-cell) * 2));
  background-repeat: repeat;
  background-position: 0 0;
  animation: ptape-drift var(--ptape-dur) linear infinite;   /* source: translateX(-50%) -> 0, drifts RIGHT */
  will-change: transform;
}
@keyframes ptape-drift {
  from { transform: translate3d(calc(-1 * var(--ptape-loop)), 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}
.ptape[data-ptape-dir="left"]::before { animation-direction: reverse; }
.ptape[data-ptape-paused]::before { animation-play-state: paused; }

/* shapes band: 64px total (62 + two 1px rules), shapes 38px on a 59px pitch (the source's 47/72 at 40/49 scale) */
.ptape[data-ptape="shapes"] {
  --ptape-h: 62px;
  --ptape-rule-top: 1px;
  --ptape-loop: 3676px;            /* source: 1.5 x 2451px tiles per 40s = 91.9 px/s */
  --ptape-bg: #fffcf5;
}
.ptape[data-ptape="shapes"]::before { background-repeat: repeat-x; background-position: 0 50%; }
.ptape[data-ptape-rules="none"] { --ptape-rule-top: 0px; --ptape-rule-bottom: 0px; }
.ptape[data-ptape-rules="both"] { --ptape-rule-top: 1px; --ptape-rule-bottom: 1px; }
.ptape[data-ptape-rules="top"] { --ptape-rule-top: 1px; --ptape-rule-bottom: 0px; }
.ptape[data-ptape-rules="bottom"] { --ptape-rule-top: 0px; --ptape-rule-bottom: 1px; }

@media (prefers-reduced-motion: reduce) {
  .ptape::before { animation: none; transform: none; }
}
