/* ==========================================================================
   FRONTLINE21 — THE TWENTY FRAMES

   Twenty 9:16 photographs, one every three seconds, sixty seconds for a
   cycle, each carrying one declaration from the twenty one days in the
   printed ink. It stands where a single photograph stood in the Homefront.

   THE RATIO IS THE COMPOSITION
   The frames are 9:16 everywhere, desktop included. A portrait sequence
   stretched into a landscape banner is a different picture, and the men in
   these are framed head to foot. So the plate keeps its ratio and the layout
   gives it four columns of eight, with the argument in three beside it.

   HOW A FRAME IS HELD
   Every frame is in the document and stacked in the same box. The one showing
   has .is-on; the rest are transparent and aria-hidden, and none of them is
   display:none, because a frame that is display:none cannot decode its image
   in advance and the carousel would show an empty plate on its first turn.
   The box holds its own aspect ratio, so nothing moves when a frame changes.

   THE QUOTE IS ART-DIRECTED, NOT DROPPED ON
   The declaration sits at the foot of the frame over a gradient that darkens
   only the bottom third. Faces are in the upper two thirds of all twenty by
   construction, and the controls sit above the type in their own row, so
   neither covers the other. There is no opaque box over a photograph.
   ========================================================================== */

.carousel {
  position: relative;
  width: 100%;
}

.carousel__stage {
  position: relative;
  aspect-ratio: 9 / 16;
  overflow: hidden;
  background: var(--ink-raised);
  border: 1px solid var(--ink-line);
}

.frame {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  /* Inside the three second cadence, not added to it: 520ms of the interval,
     never twenty extra delays. */
  transition: opacity 520ms var(--ease-out);
  pointer-events: none;
}

.frame.is-on {
  opacity: 1;
  pointer-events: auto;
}

.frame__plate,
.frame__plate img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.frame__plate img {
  object-fit: cover;
  object-position: 50% 38%;
  display: block;
}

/* The ground under the words. Bottom third only, so the photograph keeps its
   own blacks and the men in it are never behind a panel. */
.frame__truth {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: clamp(56px, 14%, 120px) clamp(14px, 4.5%, 28px) clamp(14px, 4.5%, 26px);
  background: linear-gradient(to top,
    rgba(9, 11, 11, 0.88) 0%,
    rgba(9, 11, 11, 0.72) 34%,
    rgba(9, 11, 11, 0.28) 68%,
    rgba(9, 11, 11, 0) 100%);
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  line-height: 0.94;
  letter-spacing: 0.005em;
  font-size: clamp(19px, 6.4cqw, 40px);
}

/* Container query units so the type is set against the frame's own width,
   not the viewport's: the same plate reads the same at four columns on a
   desktop and full width on a phone. */
.carousel__stage { container-type: inline-size; }

/* The printed surface must be a block. ink.css paints the ink by clipping a
   background to the text, and it gives that treatment block display only for
   the elements it knows about — a heading or a paragraph. Left inline here,
   the clip fragmented across the line boxes and painted nothing: the
   declaration was transparent on every screen wide enough to use the wide
   line breaks, which is every screen but a phone. */
.frame__wide,
.frame__narrow {
  display: block;
  overflow: visible;
}

.frame__truth .ink span {
  display: block;
}

/* Two authored line breaks per declaration, one for a wide frame and one for
   a narrow one, both from the Wall of Truth source. Only one is ever drawn. */
.frame__narrow { display: none; }

@container (max-width: 380px) {
  .frame__wide { display: none; }
  .frame__narrow { display: block; }
}

/* --- The controls, inside the image ---------------------------------------
   Upper right, above the type, on a quiet plate rather than a solid bar. The
   count is part of the same group so a reader knows where they are without a
   caption under the picture. */

.carousel__controls {
  position: absolute;
  top: clamp(10px, 3%, 18px);
  right: clamp(10px, 3%, 18px);
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 4px 4px 4px 8px;
  background: rgba(9, 11, 11, 0.62);
  border: 1px solid rgba(244, 245, 244, 0.16);
  backdrop-filter: none;
}

.carousel__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--paper);
  font-size: 15px;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out),
    background-color var(--dur-fast) var(--ease-out);
}

.carousel__btn:hover,
.carousel__btn:focus-visible {
  color: var(--f21-red-hi);
  background: rgba(244, 245, 244, 0.08);
}

.carousel__count {
  margin: 0 6px 0 2px;
  color: var(--paper-faint);
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  white-space: nowrap;
}

.carousel__count b {
  color: var(--paper);
  font-weight: 700;
}

/* Play or pause, never both. The stopped state is the one that shows Play. */
.carousel__play { display: none; }
.carousel.is-paused .carousel__pause { display: none; }
.carousel.is-paused .carousel__play { display: inline-block; }

/* A frame the reader is inside gets a visible edge, so a keyboard user can
   see what the arrows are addressing. */
.carousel:focus-within .carousel__stage {
  border-color: var(--paper-mute);
}

@media (prefers-reduced-motion: reduce) {
  .frame { transition: none; }
}

/* Order on a phone: the plate, then the argument. The declaration's type is
   already scaled to the frame, so nothing here changes it. */
@media (max-width: 767px) {
  .carousel__btn { width: 44px; height: 44px; }
}


/* ==========================================================================
   THE OTHER TWO SEQUENCES, 8 September, second pass.

   The Moral Courage plate in the Code and the twenty scene strip in the Code
   in Action share the carousel's frames, its printed ink, its controls and its
   clock, and are allowed to differ in composition: one is a plate that is
   16:9 on a desktop and 9:16 on a phone, the other is a track that moves
   right to left.
   ========================================================================== */

/* --- The plate ----------------------------------------------------------- */

.carousel--plate .carousel__stage {
  aspect-ratio: 16 / 9;
}

/* The discipline plates follow the Code's own rules: a shallow band between
   the phone and the desktop, and not drawn at all on a phone, where the
   section is the formation and the argument. The 9:16 counterparts are in the
   markup for the day that changes. */
@media (min-width: 768px) and (max-width: 1023px) {
  .carousel--plate .carousel__stage { aspect-ratio: 21 / 9; }
}

@media (max-width: 767px) {
  .carousel--plate .carousel__stage { aspect-ratio: 9 / 16; }
}

/* Focal position per orientation, authored per scene on the figure. */
.frame--plate .frame__plate img,
.frame--card .frame__plate img {
  object-position: var(--focal-l, 50% 45%);
}

@media (max-width: 767px) {
  .frame--plate .frame__plate img,
  .frame--card .frame__plate img {
    object-position: var(--focal-p, 50% 40%);
  }
}

/* A landscape plate has less height to give the words, so they are set
   smaller than the 9:16 carousel's and sit closer to the edge. A portrait
   card on a phone has the height back and takes the carousel's own scale. */
.frame--plate .frame__truth,
.frame--card .frame__truth {
  padding: clamp(40px, 12%, 96px) clamp(14px, 4%, 26px) clamp(12px, 3.6%, 22px);
  font-size: clamp(17px, 4.2cqw, 30px);
  line-height: 0.96;
}

@media (max-width: 767px) {
  .frame--card .frame__truth {
    padding: clamp(56px, 14%, 120px) clamp(14px, 4.5%, 28px) clamp(14px, 4.5%, 26px);
    font-size: clamp(19px, 6.4cqw, 34px);
  }
}

.frame__discipline {
  display: block;
  margin-bottom: 6px;
  font-family: var(--font-text);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--paper-faint);
}

/* --- The strip ------------------------------------------------------------ */

.strip {
  position: relative;
  width: 100%;
  /* The card measure. A desktop shows three and the edge of a fourth; a
     phone shows one and a glimpse of the next. */
  --card: clamp(260px, 29vw, 480px);
  --gap: 10px;
}

@media (max-width: 767px) {
  .strip { --card: 82vw; --gap: 8px; }
}

.strip__viewport {
  overflow: hidden;
  container-type: inline-size;
}

.strip__track {
  display: flex;
  gap: var(--gap);
  will-change: transform;
  /* The slide is inside the interval, never added to it: 640ms of the 3000. */
  transition: transform 640ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.strip__track.is-instant { transition: none; }

.frame--card {
  position: relative;
  flex: 0 0 var(--card);
  width: var(--card);
  aspect-ratio: 16 / 9;
  margin: 0;
  opacity: 1;
  pointer-events: auto;
  inset: auto;
  background: var(--ink-raised);
  border: 1px solid var(--ink-line);
  overflow: hidden;
  /* The card's own width is what its type is set against. */
  container-type: inline-size;
}

@media (max-width: 767px) {
  .frame--card { aspect-ratio: 9 / 16; }
}

.frame--card .frame__plate,
.frame--card .frame__plate img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* A card that is a transient seam clone: drawn, never read, never focused. */
.frame--card.is-seam { visibility: visible; }

/* Upper right, as in the carousel: the declarations live at the foot of the
   cards, and a control plate over the foot covered whichever one was third. */
.strip__controls {
  top: clamp(10px, 2.5%, 18px);
  right: clamp(10px, 2.5%, 18px);
}

/* The strip's count sits with the controls; the leading card carries is-on
   for the script and nothing visual, because a strip has no single "shown"
   frame. */
.frame--card.is-on { outline: none; }

@media (prefers-reduced-motion: reduce) {
  .strip__track { transition: none; }
}
