/* ==========================================================================
   Cover  (.pf-cover)
   A standardized case-study cover: a per-project GRADIENT backdrop + a mild
   film GRAIN, with a transparent-background device mockup on top. Composited in
   CSS (not baked into the image), so:
     • the gradient shape + intensity are identical on every cover — only the
       color changes, via --pf-cover-color (consistency by construction);
     • padding/breathing room is a CSS property, never a re-export;
     • the device layer zooms on hover while the gradient + grain stay put.

   Usage — provide ONE asset: a device+screenshot cut out on transparency.
     <div class="pf-cover" style="--pf-cover-color:#2b6fff;">
       <img class="pf-cover__device" src="…device.webp" width="…" height="…" alt="…">
     </div>
   Drop it inside .pf-project__media (card) or a .pf-figure__frame (case study).
   ========================================================================== */

.pf-cover {
  /* Two explicit gradient stops per project — pick the exact hexes (rich, not
     washed) rather than deriving from one color, which muted the hue. Keep a
     consistent light→dark range across projects (Figma ref: L≈68 → L≈47) so the
     set feels unified. Defaults = the Figma blue. */
  --pf-cover-from: oklch(0.79 0.12 250); /* light stop — top-right (L 0.79 fixed) */
  --pf-cover-to: oklch(0.60 0.15 250);   /* dark stop — bottom-left. Dark L is tuned per hue in
                                            the cover-gradient-maker (~0.60–0.66): the same L reads
                                            darker on some hues, so match by eye, not by number. */
  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  min-height: inherit;
  overflow: hidden;
  /* Dynamic diagonal: light top-right → dark bottom-left. A fixed 244deg stays
     consistent across cover shapes. Positioned stops (not 0→100) shape the sweep:
     a light field to 50%, then a gradual transition into a dark bottom-left corner
     across the second half (50%→100%) — a directional wash, not an even blend. One
     shared geometry across covers (per-cover tuning stays in the stop colors). */
  background: linear-gradient(244deg, var(--pf-cover-from) 50%, var(--pf-cover-to) 100%);
  /* Inner shadow — a tight inset edge-darkening (negative spread hugs the border) that
     the flat CSS cover was missing vs the old baked images; gives the panel depth.
     box-shadow is R1-exempt (shadowExemptProperties). */
  box-shadow: inset 0 0 25px -13px rgba(0, 0, 0, 0.33);
}

/* Film grain — very mild, static (no animation → no reduced-motion concern).
   Self-contained SVG fractal-noise data URI; tiled and blended low. */
.pf-cover::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
  background-size: 180px 180px;
  opacity: 0.1;
  mix-blend-mode: overlay;
  pointer-events: none;
}

/* The device mockup (transparent PNG/WebP, or inline SVG). Width caps give the
   breathing room; centering handles vertical padding. */
.pf-cover__device {
  position: relative;
  width: min(82%, 900px);
  max-height: 80%;
  height: auto;
  object-fit: contain;
  /* Fully opaque by default. Machine translucency (the gradient tinting the device
     body/bezel while the screen stays solid) is the ASSET's job — bake it into the
     PNG's alpha: transparent machine parts, opaque screen. Do NOT use element opacity
     for that: CSS opacity is uniform across the whole element, so any value below 1
     also washes the opaque screen and the gradient bleeds through the UI. The
     --pf-cover-device-opacity knob remains for a deliberate per-cover wash (a scalar,
     not a color — no token file needed), but it must stay 1 for any cover with a
     screen that has to read clearly. */
  opacity: var(--pf-cover-device-opacity, 1);
  /* Tighter, slightly directional elevation (matched to the Figma spec:
     ~2.6px offset, ~16px blur, 25% black — scaled a touch to our render size). */
  filter: drop-shadow(3px 4px 14px rgba(0, 0, 0, 0.25));
  /* Force a compositing layer so WebKit re-rasterizes the drop-shadow once the device
     image finishes decoding — without it the shadow paints at half coverage until a
     scroll/resize forces a repaint (Safari-16 target). Same fix as .pf-figure--raised. */
  backface-visibility: hidden;
  transition: transform var(--pf-dur-slow) var(--pf-ease);
}
/* Zoom on hover (standalone use, e.g. a case-study figure). The project card
   wires .pf-project:hover so the whole card triggers it — see project-card.css. */
.pf-cover:hover .pf-cover__device {
  transform: scale(1.04);
}

/* Page hero (opt-in, v0.9.76): the same cover as a FULL-BLEED band, the first thing in a case
   study, flush under the nav (Louis, 2026-09-29: nothing above it). Edge to edge at
   --pf-cover-hero-h; the device stays centered on the reading axis and capped by the band's
   height, so on a wide screen the gradient wings widen while the device holds. It is not a link,
   so no hover zoom. Drop it directly inside <main>, before the .pf-container article. */
.pf-cover--hero {
  height: var(--pf-cover-hero-h);
  min-height: 0;
}
.pf-cover--hero .pf-cover__device {
  max-height: calc(var(--pf-cover-hero-h) * 0.8);   /* definite px, not % (WebKit, see --tall) */
}
.pf-cover--hero:hover .pf-cover__device {
  transform: none;
}
/* A portrait device in the hero bottom-bleeds at most of the band's height instead of the
   card's 371px cap, so the pane fills the band rather than sitting small at its foot. (0,3,0)
   so it also beats the ≤768 --tall rule below. */
.pf-cover--hero.pf-cover--tall .pf-cover__device {
  max-height: calc(var(--pf-cover-hero-h) * 0.9);
}

/* Tall / portrait device — opt-in (add .pf-cover--tall to .pf-cover). A portrait
   screenshot (e.g. an Outlook add-in task pane) fits the landscape cover box by
   HEIGHT, not width, so the whole pane shows instead of overflowing top/bottom. The
   default device rule above is width-bound (width: min(82%, 900px)), which clips a
   tall asset. Here both max dimensions bind while width/height stay auto, so the
   device is contained within the smaller bound and centered by the cover's
   place-items. Wired from a `cover_tall: true` card front-matter flag (renderCards). */
.pf-cover--tall {
  align-items: end; /* bottom-bleed the portrait device; horizontal centering kept */
}
.pf-cover--tall .pf-cover__device {
  width: auto;
  height: auto;
  max-width: 66%;
  /* A definite px cap, NOT a percentage: a stretched grid item's height reads as
     indefinite in WebKit, so a % max-height on the device never resolves and the pane
     renders near its natural (too-tall) size. ~0.93× the 400px card height, so the pane
     fills most of the card and only a thin gradient band shows above the bleed. */
  max-height: 371px;
  /* No bottom margin: the device sits flush on the lower edge and bleeds off it. Author
     the asset with square (un-rounded) bottom corners so the bleed reads clean. */
  margin-block-end: 0;
}
@media (max-width: 768px) {
  /* Stacked (phone): the card becomes a height-capped banner (project-card.css caps the media
     at 300px). Size the bleeding device by the VIEWPORT so it scales down small phones, but
     cap it under the banner's 300px so the whole pane stays inside the box (a bare 52vw would
     be ~399px at 768 and overflow the capped banner). Absolute cap (px/vw), not a %, so it
     resolves inside the grid-placed cover. */
  .pf-cover--tall .pf-cover__device {
    max-height: min(52vw, 264px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .pf-cover__device {
    transition: none;
  }
  .pf-cover:hover .pf-cover__device {
    transform: none;
  }
}
