/* ==========================================================================
   COMPONENT — .c-timeline / .c-entry
   The video index, read as a dated timeline.

   Every entry is a full-width row split in half down the centre: the frame on
   one side, the writing on the other. Consecutive rows SWAP those halves —
   video left / text right, then text left / video right — so the eye is
   handed back and forth down the page instead of tracking one rigid column.

   Every frame is identical in size. A record of 660 uploads should not have
   some rows shouting louder than others; the alternation does the work that
   varying sizes were doing badly.

   Sides come from :nth-child, so the rhythm survives sorting, filtering and
   searching — the script re-appends the visible set in order and the pattern
   re-forms on whatever is actually on screen.

   WP Phase 2 targets:
     template-parts/archive/timeline.php
     template-parts/card/entry-video.php
   ========================================================================== */

.c-timeline {
  position: relative;
  --col: calc((100% - 11 * var(--gutter)) / 12);
}

/* The spine runs down the gutter between the two halves. Drawn on the
   container, not per-entry, so filtering can never leave a gap or a stub. */
.c-timeline::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 50%;
  inline-size: var(--bw-hair);
  background: var(--c-line);
  transform: translateX(-50%);
  pointer-events: none;
}

.c-entry { display: block; }
.c-entry[hidden] { display: none; }

.c-entry__link {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  align-items: center;
  padding-block: var(--sp-6);
  border-block-end: var(--bw-hair) solid var(--c-line);
}

.c-entry:last-of-type .c-entry__link { border-block-end: 0; }

/* --------------------------------------------------------------------------
   THE SWAP
   Odd  — frame on the left  (1-6),  writing on the right (7-12)
   Even — writing on the left (1-6), frame on the right  (7-12)
   -------------------------------------------------------------------------- */

.c-entry:nth-child(odd) .c-entry__media { grid-row: 1; grid-column: 1 / span 6; }
.c-entry:nth-child(odd) .c-entry__text  { grid-row: 1; grid-column: 7 / span 6; padding-inline-start: var(--sp-6); }

.c-entry:nth-child(even) .c-entry__media { grid-row: 1; grid-column: 7 / span 6; }
.c-entry:nth-child(even) .c-entry__text  { grid-row: 1; grid-column: 1 / span 6; padding-inline-end: var(--sp-6); }

/* The writing is capped to a readable measure, so on an even row it would
   otherwise sit against the page edge with a void beside the spine. Push it
   across: the column mirrors, the text alignment does not. */
.c-entry__text > * { max-inline-size: none; }
.c-entry:nth-child(even) .c-entry__text > * { margin-inline-start: auto; }

/* The node marks the row on the spine, vertically centred on the frame. */
.c-entry__node {
  grid-row: 1;
  grid-column: 1 / -1;
  justify-self: center;
  align-self: center;
  inline-size: 9px;
  block-size: 9px;
  border-radius: var(--radius-pill);
  background: var(--c-bg);
  border: var(--bw-rule) solid var(--c-line-strong);
  pointer-events: none;
  transition:
    border-color var(--dur-base) var(--ease-out),
    background-color var(--dur-base) var(--ease-out),
    transform var(--dur-base) var(--ease-out);
}

.c-entry__link:hover .c-entry__node,
.c-entry__link:focus-visible .c-entry__node {
  border-color: var(--c-accent);
  background: var(--c-accent);
  transform: scale(1.4);
}

/* --------------------------------------------------------------------------
   THE FRAME — identical for every entry, whichever side it lands on.
   -------------------------------------------------------------------------- */

.c-entry__media {
  position: relative;
  aspect-ratio: var(--ar-wide);
  overflow: hidden;
  background: var(--slate-900);

  /* The ring is this padding. The picture fills the content box, so one
     hairline of the element's own background shows all the way round it,
     and that hairline is what gets lit. */
  padding: var(--bw-rule);
}

/* --------------------------------------------------------------------------
   THE HOVER RING TRAVELS ROUND THE FRAME

   It was an `outline`, which is painted outside the border box and was being
   clipped by an ancestor — so on hover the ring appeared on three sides and
   not the fourth. An outline cannot be gradient-filled either, so it could
   only ever have been a flat line.

   A conic gradient on a pseudo-element under the picture instead: one bright
   arc in an otherwise transparent sweep, rotating. What shows through the
   hairline gutter is that arc going round the frame clockwise.

   Rotated with `transform`, not with an animated `<angle>` custom property.
   The custom-property version is tidier to read but needs `@property` to
   interpolate, and where that is missing the gradient freezes with a red arc
   stuck on one edge — which looks like the bug this is replacing. A rotate
   either animates or does not, and if it does not the ring is simply still.

   Inset -60% so the square is larger than the frame's diagonal; a smaller
   one sweeps its own corners through the picture.
   -------------------------------------------------------------------------- */

.c-entry__media::before {
  content: "";
  position: absolute;
  inset: -60%;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease-out);
  background: conic-gradient(
    from 0deg,
    transparent 0deg 186deg,
    color-mix(in oklab, #FF0000 28%, transparent) 276deg,
    #FF0000 338deg,
    #FF8478 354deg,
    transparent 360deg);
}

.c-entry__link:hover .c-entry__media::before,
.c-entry__link:focus-visible .c-entry__media::before { opacity: 1; }

@media (prefers-reduced-motion: no-preference) {
  .c-entry__link:hover .c-entry__media::before,
  .c-entry__link:focus-visible .c-entry__media::before {
    animation: entry-ring 2.8s linear infinite;
  }
}

@keyframes entry-ring {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* Everything the frame holds sits above the sweep. */
.c-entry__image,
.c-entry__duration,
.c-entry__play { position: relative; z-index: 1; }

.c-entry__image {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  transform: scale(1.001);
  transition: transform var(--dur-slow) var(--ease-out), filter var(--dur-base) var(--ease-out);
}

.c-entry__link:hover .c-entry__image,
.c-entry__link:focus-visible .c-entry__image { transform: scale(1.05); filter: brightness(0.88); }

.c-entry__duration {
  position: absolute;
  inset-block-end: var(--sp-3);
  inset-inline-end: var(--sp-3);
  padding: 0.15rem var(--sp-2);
  /* No backdrop-filter. See the note in base.css on the washes — same
     complaint, same cause. A backdrop blur makes the browser read back
     everything already painted behind the element and blur it again, and it
     has to redo that whenever the backdrop moves. On a page that scrolls past
     video, that is every frame.

     The opacity is raised to compensate: a blur and a slightly darker plate
     are doing the same job here, which is stopping the picture behind from
     competing with the type in front. Only one of them costs anything. */
  background: color-mix(in oklab, #0A0E10 88%, transparent);
  font-family: var(--ff-mono);
  font-size: var(--fs-mono-xs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--tr-mono);
  color: var(--stone-50);
  line-height: 1.5;
}

.c-entry__play {
  position: absolute;
  inset-block-end: var(--sp-3);
  inset-inline-start: 0;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 0.3rem var(--sp-4);
  background: var(--c-accent);
  color: var(--c-accent-on);
  font-family: var(--ff-mono);
  font-size: var(--fs-mono-xs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--tr-mono);
  text-transform: uppercase;
  line-height: 1.5;
  transform: translateX(-101%);
  transition: transform var(--dur-base) var(--ease-out);
}

.c-entry__link:hover .c-entry__play,
.c-entry__link:focus-visible .c-entry__play { transform: none; }

.c-entry__play svg { inline-size: 0.55em; block-size: auto; }

/* --------------------------------------------------------------------------
   THE WRITING — always left-aligned. Mirroring the text as well as the frame
   would trade legibility for symmetry, and the frame already carries the swap.
   -------------------------------------------------------------------------- */

.c-entry__stamp {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  margin-block-end: var(--sp-4);
  font-family: var(--ff-mono);
  font-size: var(--fs-mono-xs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--tr-mono);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  line-height: 1;
}

.c-entry__stamp b { font-weight: var(--fw-medium); color: var(--c-ink); }
.c-entry__no { color: var(--c-accent-text); }

.c-entry__stamp::after {
  content: "";
  flex: 1;
  block-size: var(--bw-hair);
  background: var(--c-line);
}

.c-entry__topic {
  display: inline-block;
  margin-block-end: var(--sp-3);
  font-family: var(--ff-mono);
  font-size: var(--fs-mono-xs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--tr-mono);
  text-transform: uppercase;
  color: var(--c-ink-muted);
}

.c-entry__title {
  font-family: var(--ff-display);
  font-optical-sizing: auto;
  font-variation-settings: "SOFT" 0, "WONK" 0;
  font-weight: var(--fw-regular);
  font-size: var(--fs-lg);
  line-height: var(--lh-tight);
  letter-spacing: var(--tr-tight);
  color: var(--c-ink);
  /* A YouTube title is third-party text of any length. It gets ONE line;
     the full string stays in data-title and on the link itself. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.c-entry__title span {
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.c-entry__title span {
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% var(--bw-hair);
  transition: background-size var(--dur-base) var(--ease-out);
  padding-block-end: 0.06em;
}

.c-entry__link:hover .c-entry__title span,
.c-entry__link:focus-visible .c-entry__title span { background-size: 100% var(--bw-hair); }

.c-entry__dek {
  margin-block-start: var(--sp-4);
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
  color: var(--c-ink-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.c-entry__foot {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-block-start: var(--sp-5);
  font-family: var(--ff-mono);
  font-size: var(--fs-mono-xs);
  letter-spacing: var(--tr-mono);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  line-height: 1;
}

.c-entry__foot svg {
  inline-size: 1.5rem;
  block-size: auto;
  color: var(--c-accent-text);
  transition: transform var(--dur-base) var(--ease-out);
}

.c-entry__link:hover .c-entry__foot svg { transform: translateX(0.35rem); }

/* --------------------------------------------------------------------------
   RESPONSIVE — the halves stop alternating and stack.
   -------------------------------------------------------------------------- */

@media (max-width: 60rem) {
  .c-timeline::before { display: none; }
  .c-entry__node { display: none; }

  .c-entry__link {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--sp-5);
    padding-block: var(--sp-6);
    align-items: start;
  }

  .c-entry:nth-child(odd) .c-entry__media,
  .c-entry:nth-child(even) .c-entry__media { grid-row: 1; grid-column: 1 / -1; }

  .c-entry:nth-child(odd) .c-entry__text,
  .c-entry:nth-child(even) .c-entry__text {
    grid-row: 2;
    grid-column: 1 / -1;
    padding-inline: 0;
  }

  .c-entry__title { font-size: var(--fs-lg); }
}

/* Long archives: skip laying out offscreen entries entirely. */
@supports (content-visibility: auto) {
  .c-entry {
    content-visibility: auto;
    contain-intrinsic-size: auto 320px;
  }
}

/* --------------------------------------------------------------------------
   Reorder reveal — capped by the script, so cost never scales with N.
   -------------------------------------------------------------------------- */

.c-timeline[data-reordered] > .c-entry[style*="--reveal-i"] {
  animation: entry-reveal var(--dur-base) var(--ease-out) both;
  animation-delay: calc(var(--reveal-i, 0) * 22ms);
}

@keyframes entry-reveal {
  from { opacity: 0; transform: translateY(0.6rem); }
  to   { opacity: 1; transform: none; }
}


/* --------------------------------------------------------------------------
   TOUCH: the play chip

   The chip is parked at translateX(-101%) and slides in on hover. There is
   no hover on a touch screen, so on a phone it sat permanently off the left
   edge of its card — present in the layout, invisible to the reader, and
   measured at -56px.

   Keyed on the POINTER, not the viewport width: a small window on a laptop
   still has a cursor and should still get the slide.
   -------------------------------------------------------------------------- */

@media (hover: none) {
  .c-entry__play {
    position: static;
    transform: none;
    inline-size: fit-content;
    margin-block-start: var(--sp-4);
    padding-block: var(--sp-2);
  }
}

/* --------------------------------------------------------------------------
   PHONE: the title and dek wrap rather than truncate

   One line is right on a wide screen — a full line holds the whole title, so
   nothing is lost. At 375px a line holds about thirty characters, and
   "10 Things You Should AVOID Doing in Malta" became "10 Things You Should
   AVOID…". That is a worse read than two lines, and the no-wrap rule was
   about layouts that looked broken, not about hiding what a video is called.

   Two lines, hard ceiling: a long title still cannot push a card out of shape.
   -------------------------------------------------------------------------- */

@media (max-width: 44rem) {
  .c-entry__title,
  .c-entry__title span,
  .c-entry__dek {
  white-space: normal;
  text-wrap: pretty;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  }
}
