/* =====================================================================
   components-fx.css -- the physics layer (owner: FX)
   Theme: rar-broadsheet. Design intent: docs/SPEC.md sections 7, 9, 11,
   13. Mechanics: docs/DESIGN-SYSTEM.md sections 3, 4, 5, 8, 9.

   CONTENTS
     1. Press photo: period print filter, halftone screen, the color snap
     2. Editorial cartoon variant: halftone fade only, no color state
     3. Torn slip pull quote (lean modifiers, cellophane tape)
     4. Tier 2, the reader's hand: paper stir, ink-rule links, glyph re-ink
     5. Tier 1, newsroom air (gated behind prefers-reduced-motion:
        no-preference so reduced motion is the default-off path)
     6. Reduced-motion kill block (the only sanctioned !important)

   Color references resolve through the theme aliases (--ink, --paper,
   --paper-slip, --paper-shade) with the exact DESIGN-SYSTEM section 3
   hex values as fallbacks. Every rgba() below is either ink #1a1712 at
   an alpha, the spec's own shadow blacks, or the spec's tape white.
   House rules honored: no rounded corners, no zooming transforms
   (rotate/translate/skew only; grayscale() is a filter function, not a
   transform), no catch-all transitions, hover rules gated behind
   (hover: hover) so touch devices rely on the .revealed class instead
   of sticky emulated hover.
   ===================================================================== */


/* ---------------------------------------------------------------------
   1. PRESS PHOTO (SPEC section 9, Appendix A4)

   Expected markup from pattern owners (amendment 14.3: featured images
   render with isLink true, so the img normally arrives wrapped in an
   anchor; the bare-img form stays legal for hand-placed cuts):

     <figure class="rar-press-photo">
       <a href="/permalink/"><img src="color-original.jpg" alt="..."></a>
       <figcaption>MARCHERS AT SELMA, 1965.<br>PHOTO: ASSOCIATED PRESS</figcaption>
     </figure>

   KEYBOARD REVEAL PATH (14.3): that anchor is the figure's focusable
   element. Focus on ANY descendant (image link, caption credit link)
   makes the figure match the :focus-within selectors below, which run
   the same reveal as hover: color snap for photos, halftone fade for
   cartoons. No extra selector is needed for the link form; :focus-
   within and the descendant `img` selectors already reach through the
   anchor. TOUCH: main.js owns the two-tap pattern on the image link
   (first tap reveals, second navigates); the CSS side only ever sees
   the .revealed class either way.

   The figure is a one-column grid. Pseudo-elements of a grid container
   are laid out as grid items, so the halftone screen (::after) and the
   curled corner flap (::before, section 5) are pinned to the image cell
   exactly, and the caption row below stays clean of dots. This avoids
   the classic bug of an inset overlay bleeding over the figcaption.
   ------------------------------------------------------------------- */
/* P7 -- NO MARGIN DECLARATION LIVES HERE ANY MORE, deliberately.
   This rule used to carry "margin: 0". At (0,1,1) it outranked the
   article body's figure rule, core's layout gap and .rar-press-photo's
   own seating rule, so every cut on a dossier page computed margin 0
   top and bottom and its CREDIT line ran flush into the next paragraph
   (owner-reported with screenshots, measured on staging 2026-07-27).
   Figure block margins now belong exclusively to the vertical rhythm
   ladder: components-article.css on the article side, components-
   front.css inside a teaser or the lead band. This file keeps the
   MATERIAL of a press cut (border, screen, snap, curl) and nothing
   about where it sits. */
figure.rar-press-photo,
figure.rar-cartoon {
  display: grid;
  grid-template-columns: 100%;
  position: relative;
  isolation: isolate; /* keep the multiply blend inside the figure */
}

/* The image (bare, link-wrapped, or with A4's optional overlay span)
   occupies the first grid cell. */
.rar-press-photo > a,
.rar-press-photo > img,
.rar-press-photo > span,
.rar-cartoon > a,
.rar-cartoon > img,
.rar-cartoon > span {
  grid-area: 1 / 1;
}

/* Resting state: screened newsprint repro over the original color file.
   Filter values are SPEC A4 verbatim. The .45s ease is the SLOW leg of
   the asymmetric snap: the past settling back over the image. Images
   fill their column measure, as set newspaper cuts do; the 1px ink
   border is part of the print furniture. */
.rar-press-photo img,
.rar-cartoon img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--ink, #1a1712);
  filter: grayscale(1) contrast(1.12) brightness(1.02) sepia(.08);
  transition: filter .45s ease;
}

/* Halftone dot screen: ink dots on a 3.5px pitch, multiplied over the
   image so photos read as screened newsprint repro. Fading its opacity
   is the second half of the reveal. */
.rar-press-photo::after,
.rar-cartoon::after {
  content: "";
  grid-area: 1 / 1;
  z-index: 1;
  pointer-events: none;
  background-image: radial-gradient(circle, rgba(26, 23, 18, .55) 28%, transparent 30%);
  background-size: 3.5px 3.5px;
  mix-blend-mode: multiply;
  opacity: 1;
  transition: opacity .45s ease;
}

/* THE COLOR SNAP (Tier 2 flagship). The photograph snaps to full color
   in .16s ease-out (a jolt of the present breaking through the print)
   and settles back at the .45s declared above. The asymmetry is
   deliberate: keep it. Cartoons are excluded from the filter cut via
   :not(.rar-cartoon); they are ink drawings with no color state.
   .revealed mirrors the whole reveal for touch (toggled by main.js). */
@media (hover: hover) {
  .rar-press-photo:not(.rar-cartoon):hover img {
    filter: none;
    transition: filter .16s ease-out;
  }
}

.rar-press-photo:not(.rar-cartoon):focus-within img,
.rar-press-photo:not(.rar-cartoon).revealed img {
  filter: none;
  transition: filter .16s ease-out;
}

/* Halftone screen fade applies to photos AND cartoons: for a cartoon
   the screen lifting to show clean linework is the entire reveal. */
@media (hover: hover) {
  .rar-press-photo:hover::after,
  .rar-cartoon:hover::after {
    opacity: 0;
    transition: opacity .16s ease-out;
  }
}

.rar-press-photo:focus-within::after,
.rar-press-photo.revealed::after,
.rar-cartoon:focus-within::after,
.rar-cartoon.revealed::after {
  opacity: 0;
  transition: opacity .16s ease-out;
}

/* Courier caption and credit line beneath every image (SPEC section 9:
   every image on the site carries a credit line; it is both the
   aesthetic and the ethic). Credit goes on its own line in caps,
   PHOTO: ASSOCIATED PRESS, 1948 style; cartoons carry the mandated
   EDITORIAL CARTOON -- COMMISSIONED ILLUSTRATION line here. */
.rar-press-photo figcaption,
.rar-cartoon figcaption {
  font-family: "Courier Prime", "Courier New", Courier, monospace;
  font-size: 13px;
  line-height: 1.45;
  color: var(--ink, #1a1712);
  text-align: left;
  /* One tight rhythm step, so the credit reads as part of the cut. The
     gap to whatever FOLLOWS is the figure's own bottom margin, set by
     the rhythm ladder, never by this caption. */
  margin: var(--rar-tight, 8px) 0 0;
  padding: 0;
}


/* ---------------------------------------------------------------------
   3. TORN SLIP PULL QUOTE (SPEC section 7, Appendix A5)

   Expected markup (DESIGN-SYSTEM section 7):

     <div class="rar-torn-slip lean-l">        (group block)
       <p>"They typed the quote here."</p>     (Special Elite, via base)
       <p>-- STROM THURMOND, JULY 17, 1948</p> (Courier, via p + p)
       <p>SOURCE: ...</p>                      (Courier, via p + p)
     </div>

   ARCHITECTURE NOTE: the torn silhouette is clipped on a ::before
   background layer, not on the slip itself, because clip-path clips
   everything the element paints, including any shadow. Keeping the clip
   on the layer and casting the shadow with filter: drop-shadow() on the
   slip gives the spec's 3px 4px 8px rgba(0,0,0,.18) shadow the shape of
   the TORN edge rather than a clean rectangle, which is what a real
   paper scrap throws. Same offsets, same blur, same color as specified.

   SEATING IS NOT SET HERE (P7). The slip carries no block margins of
   its own: on the article side components-article.css gives it the full
   --rar-section step top and bottom, sized against the rotation arc,
   the drop shadow and the tape corner so nothing this file draws can
   touch the copy around it. In the wire feed the brick keeps the
   column's own 26px. Adding a margin here would fight both.
   ------------------------------------------------------------------- */
.rar-torn-slip {
  position: relative;
  padding: 21px 26px; /* spacing scale; top/bottom clear the tear depth */
  font-family: "Special Elite", "Courier Prime", monospace;
  font-size: 19px;
  line-height: 1.5;
  color: rgba(26, 23, 18, .9); /* typewriter ribbon is never full black */
  text-align: left;            /* ragged right on purpose */
  hyphens: none;
  transform: rotate(var(--lean, 0deg));
  filter: drop-shadow(3px 4px 8px rgba(0, 0, 0, .18));
  transition: transform 250ms ease, filter 250ms ease;
}

/* The slip of lighter paper with irregular torn top and bottom edges.
   TORN-EDGE POLYGON, documented: 39 vertices. X positions are
   percentages so the tears distribute across any slip width; Y offsets
   are fixed px (1px to 8px amplitude) so the tear depth stays at true
   paper scale on any slip height. Vertices 1-20 rip the TOP edge left
   to right; vertex 21 drops down the RIGHT edge (straight, torn from a
   wider sheet per SPEC section 7); vertices 22-39 rip the BOTTOM edge
   right to left; the polygon closes up the straight LEFT edge. */
.rar-torn-slip::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1; /* under the type; the slip's own filter and transform
                  create a local stacking context, so -1 cannot escape
                  behind the page */
  background: var(--paper-slip, #faf6ea);
  clip-path: polygon(
    0 7px, 4% 3px, 9% 8px, 13% 2px, 18% 6px, 24% 1px, 29% 7px,
    34% 3px, 40% 8px, 46% 2px, 52% 6px, 58% 1px, 63% 7px, 69% 3px,
    74% 8px, 80% 2px, 85% 6px, 91% 1px, 96% 5px, 100% 8px,
    100% calc(100% - 6px),
    95% calc(100% - 1px), 90% calc(100% - 7px), 84% calc(100% - 2px),
    78% calc(100% - 6px), 72% calc(100% - 1px), 66% calc(100% - 8px),
    60% calc(100% - 3px), 54% calc(100% - 7px), 48% calc(100% - 2px),
    42% calc(100% - 6px), 36% calc(100% - 1px), 30% calc(100% - 7px),
    25% calc(100% - 3px), 19% calc(100% - 8px), 14% calc(100% - 2px),
    9% calc(100% - 6px), 4% calc(100% - 1px), 0 calc(100% - 7px)
  );
}

/* Lean modifiers: no two adjacent slips should lean the same way.
   Pattern owners cycle these (DESIGN-SYSTEM section 8, item 3). */
.rar-torn-slip.lean-l { --lean: -1.5deg; }
.rar-torn-slip.lean-r { --lean: 1.2deg; }
.rar-torn-slip.lean-x { --lean: .6deg; }

/* Tier 2 lift: a paper scrap being picked up. Shadow deepens to
   5px 7px 14px and the rotation eases about half a degree toward
   level, 250ms (transition declared on the base rule above). */
@media (hover: hover) {
  .rar-torn-slip:hover {
    filter: drop-shadow(5px 7px 14px rgba(0, 0, 0, .18));
  }
  .rar-torn-slip.lean-l:hover { --lean: -1deg; }
  .rar-torn-slip.lean-r:hover { --lean: .7deg; }
  .rar-torn-slip.lean-x:hover { --lean: .1deg; }
}

/* Type inside the slip: first paragraph is the quotation (Special
   Elite from the base rule, quotation marks typed straight in the
   content, never curly). Every paragraph AFTER the first is a Courier
   line: attribution in caps beginning with "--", then the smaller
   source citation. Convention: one quote paragraph per slip. */
.rar-torn-slip p {
  margin: 0;
}

.rar-torn-slip p + p {
  margin-top: 13px;
  font-family: "Courier Prime", "Courier New", Courier, monospace;
  font-size: 13px;
  line-height: 1.5;
  letter-spacing: .04em;
}

/* Cellophane tape across one top corner: use on SOME slips, not all
   (add rar-tape beside the slip classes). Semi-transparent strip with
   a faint edge, its own slight rotation, hanging over the torn top
   edge. It is unclipped (the clip lives on ::before) and, at half
   alpha, throws a believable soft shadow through the slip's filter. */
.rar-torn-slip.rar-tape::after {
  content: "";
  position: absolute;
  top: -9px;
  right: 9%;
  width: 74px;
  height: 24px;
  background: rgba(255, 252, 240, .5);
  border: 1px solid rgba(26, 23, 18, .08);
  transform: rotate(-4deg);
  pointer-events: none;
}


/* ---------------------------------------------------------------------
   4. TIER 2, THE READER'S HAND (SPEC section 11, section 13)
   Interaction-triggered only. Displacement and rotation only: never a
   zoom, never a lift into card-land.
   ------------------------------------------------------------------- */

/* The paper stir: hovering a story block nudges it as a physical
   sheet, as if your hand's draft caught the clipping. Transform only,
   200ms out and back. Applies to rar-teaser--2col via the base class. */
.rar-teaser {
  transition: transform 200ms ease;
}

@media (hover: hover) {
  .rar-teaser:hover {
    transform: translate(1px, -2px) rotate(.4deg);
  }
}

/* Ink-rule link hover: the underline thickens from 1px to 2px, ink
   pressed harder. No color change. Baseline thickness is pinned here
   so the thicken has a defined start; the decoration line itself
   belongs to THEME-CORE. */
.rar-paper a {
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
  transition: text-decoration-thickness 120ms ease;
}

.rar-paper a:focus-visible {
  text-decoration-thickness: 2px;
}

@media (hover: hover) {
  .rar-paper a:hover {
    text-decoration-thickness: 2px;
  }
}

/* Glyph re-ink (SPEC section 13): the hand-inked share glyphs rest a
   shade light (ink at 82%) and re-ink to full black with a fast press
   feel, about 100ms, plus a fraction of a degree of rotation, a rubber
   stamp pressed again. Covers the copy-link button as well as the
   share anchors. */
.rar-clip-share a,
.rar-clip-share button {
  display: inline-block;
  opacity: .82;
  transition: opacity 100ms ease, transform 100ms ease;
}

.rar-clip-share a:focus-visible,
.rar-clip-share button:focus-visible {
  opacity: 1;
  transform: rotate(.5deg);
}

@media (hover: hover) {
  .rar-clip-share a:hover,
  .rar-clip-share button:hover {
    opacity: 1;
    transform: rotate(.5deg);
  }
}


/* ---------------------------------------------------------------------
   5. TIER 1, NEWSROOM AIR (SPEC section 11, Appendix A6)

   The curled corner FLAP is static geometry and lives outside the
   motion gate: the corner is curled even for reduced-motion readers;
   only its flutter is ambient motion. It rides ::before because ::after
   is the halftone screen (SPEC A4 and A6 both claim ::after on the same
   figure; the halftone keeps it, the flap moves to ::before, z-index 2
   lifts the raised paper corner above the dot screen). */
.rar-press-photo.has-curl::before,
.rar-cartoon.has-curl::before {
  content: "";
  grid-area: 1 / 1;
  justify-self: end;
  align-self: end;
  width: 64px;
  height: 64px;
  z-index: 2;
  pointer-events: none;
  transform-origin: 100% 100%;
  /* 315deg runs the gradient out of the bottom-right corner toward the
     top-left: bright paper back at the corner, deepening across the
     flap, a dark crease along the diagonal fold, transparent beyond.
     Reads as the corner lifted off the page, showing the sheet's back. */
  background: linear-gradient(
    315deg,
    var(--paper-slip, #faf6ea) 0%,
    var(--paper-shade, #eae3d2) 42%,
    rgba(26, 23, 18, .22) 49%,
    rgba(26, 23, 18, 0) 52%
  );
}

/* Static steam treatment (the wisp artwork itself is the DESK owner's;
   this class supplies the material: heavy blur, 4% opacity). Motion is
   added inside the gate below. */
.rar-prop--steam {
  filter: blur(3px);
  opacity: .04;
  pointer-events: none;
}

/* ALL Tier 1 motion sits inside the no-preference gate, so reduced
   motion is the default-off path, not an override (Appendix A6). Hard
   limits per SPEC section 11: no more than two ambient elements moving
   in any viewport; periods 4s and up; amplitudes tiny. */
@media (prefers-reduced-motion: no-preference) {

  /* The curled corner flutters gently: rotation/skew excursion inside
     the 2-4 degree band, period per instance via --fd (pattern owners
     emit one of five canned values, 4s to 7s, DESIGN-SYSTEM section 8
     item 4, so no two corners flutter in sync). */
  @keyframes rar-flutter {
    0%, 100% { transform: rotate(0deg) skewY(0deg); }
    50%      { transform: rotate(-3deg) skewY(1.5deg); }
  }

  .rar-press-photo.has-curl::before,
  .rar-cartoon.has-curl::before {
    animation: rar-flutter var(--fd, 5.5s) ease-in-out infinite;
  }

  /* The loose clipping: AT MOST ONE front-page element, drifting almost
     imperceptibly, plus or minus 1px and 0.3deg over 8s, paper not
     quite held down. The keyframes fold in --lean so a leaning torn
     slip keeps its resting rotation while drifting (an animation's
     transform would otherwise override the lean entirely). */
  @keyframes rar-drift {
    0%, 100% { transform: rotate(var(--lean, 0deg)) translate(0, 0); }
    50%      { transform: rotate(calc(var(--lean, 0deg) + .3deg)) translate(1px, -1px); }
  }

  .rar-loose {
    animation: rar-drift 8s ease-in-out infinite;
  }

  /* A hand resting on the page holds the paper still. */
  .rar-loose:hover {
    animation-play-state: paused;
  }

  /* Coffee steam: a barely-there wisp on a slow 7s loop. Transform
     only; the blur and opacity are static, above. If this animates it
     counts against the two-ambient-elements-per-viewport cap. */
  @keyframes rar-steam-drift {
    0%, 100% { transform: translate(0, 0); }
    50%      { transform: translate(2px, -6px); }
  }

  .rar-prop--steam {
    animation: rar-steam-drift 7s ease-in-out infinite;
  }
}


/* ---------------------------------------------------------------------
   6. REDUCED MOTION KILL BLOCK (SPEC section 11; DESIGN-SYSTEM
   section 9). Tier 1 is already absent (gated above). Tier 2 state
   changes land instantly with no easing: the color reveal, the touch
   reveal, the underline, the re-ink all still FUNCTION, they just do
   not animate. This block is the only sanctioned use of !important in
   the build.
   ------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .rar-press-photo img,
  .rar-cartoon img,
  .rar-press-photo::after,
  .rar-cartoon::after,
  .rar-torn-slip,
  .rar-teaser,
  .rar-clip-share a,
  .rar-clip-share button,
  .rar-paper a {
    transition: none !important;
  }

  /* Belt and braces on the Tier 1 hooks. */
  .rar-press-photo.has-curl::before,
  .rar-cartoon.has-curl::before,
  .rar-loose,
  .rar-prop--steam {
    animation: none !important;
  }
}
