/* ══════════════════════════════════════════════════════════════════════════
   css/bleed.css, PHOTOGRAPHS WITH NO EDGE
   service.tnaado.ca

   Ethan, 2026-09-14: "make the site way cleaner better usu i dotn wanna see
   photo edgs they should be layerined into the abckgorund, backed layers
   folowing a flow".

   Every photograph on this site is currently a `.fp-fig`: an aspect-ratio box
   with `object-fit: cover`, which is a rectangle with four hard edges sitting
   on the page. This file is the alternative. A photograph keeps its box for
   layout, and loses its edges to the ground it sits on.

   THIS IS THE ONE PLACE THE TREATMENT IS DEFINED. Eight people working on
   twenty-five pages will otherwise produce eight versions of "layered into the
   background" and the site will read as eight sites. If a page needs a feather
   this file does not have, the variant belongs HERE and the page uses it by
   name. Do not write a gradient in a page.

   ── FEATHERED WITH A MASK, NOT SHAPED WITH A GRADIENT ────────────────────
   Carried from the sibling site's backdrop.css, which learned it by shipping
   the wrong one. The obvious implementation is a radial gradient sized to the
   element. A radial large enough to cover a wide box has NOT reached its
   transparent stop by the time it hits the edge of its own box, so the box
   clips it mid-gradient and renders a HARD-EDGED RECTANGLE: exactly the thing
   being removed, now with a gradient inside it. Shrinking the radial does not
   help either, because to cover a wide column the ellipse must be wider than
   half the box, so it always clips.

   The answer is two opposed linear gradients INTERSECTED, which is a
   soft-edged rectangle. It reaches zero on all four sides, it covers the
   corners (an inscribed ellipse does not), and it has no findable edge
   anywhere.

   ── WHY MASK AND NOT AN OVERLAY ──────────────────────────────────────────
   An overlay in the page's own colour would work only while the photograph
   sits on that exact colour. These bands sit on ink, on plate and on the
   storm; a mask makes the photograph itself fade to nothing, so it dissolves
   into whatever is behind it rather than into an assumption about it.

   ── MOTION ───────────────────────────────────────────────────────────────
   None here. The flow Ethan is describing is layout and depth, not movement,
   and this file adds no animation to a site that already runs a WebGL storm.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 1. THE BASE. Add `fp-bleed` to a .fp-fig and its edges go. ─────────── */

.fp-bleed {
  /* How far in from each edge the photograph has fully arrived. Per-edge so a
     frame that meets a hard boundary on one side (a section seam, a column
     gutter) can keep that side square and still dissolve the other three. */
  --bleed-t: 14%;
  --bleed-r: 12%;
  --bleed-b: 16%;
  --bleed-l: 12%;

  -webkit-mask-image:
    linear-gradient(to right, transparent 0%, #000 var(--bleed-l), #000 calc(100% - var(--bleed-r)), transparent 100%),
    linear-gradient(to bottom, transparent 0%, #000 var(--bleed-t), #000 calc(100% - var(--bleed-b)), transparent 100%);
  mask-image:
    linear-gradient(to right, transparent 0%, #000 var(--bleed-l), #000 calc(100% - var(--bleed-r)), transparent 100%),
    linear-gradient(to bottom, transparent 0%, #000 var(--bleed-t), #000 calc(100% - var(--bleed-b)), transparent 100%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}

/* The image's own background plate has to go with the edges. `.fp-fig img`
   carries `background: var(--plate-2)` so a slow image shows a grey rectangle
   rather than nothing, which is right for a framed photo and is precisely a
   visible edge here: the plate is opaque and the mask fades the IMAGE, so the
   plate would outlive it and draw the rectangle back. */
.fp-bleed img { background: none; }

/* ANY OPAQUE FRAME AROUND A FEATHERED PHOTO REDRAWS THE RECTANGLE. The mask
   fades the IMAGE; a background, a border, a shadow or a ::before on the
   FIGURE outlives it and draws the edge straight back around the hole the
   feather just made. .fp-fig img's plate was the first instance and .plate is
   the second, found on /technology where the frame sits directly on the storm.

   Switched off only for a figure that has asked for the feather, and every
   line here turns an existing property off rather than inventing a value.
   If a third frame class turns up, it belongs on this list, not in a page. */
.plate.fp-bleed {
  background: none;
  border-color: transparent;
  box-shadow: none;
}
.plate.fp-bleed::before { content: none; }

/* ── 2. DIRECTION. Which edges dissolve. ────────────────────────────────── */

/* Meets a column of type on the left: keep that edge, open the other three. */
.fp-bleed--from-left  { --bleed-l: 0%; }
.fp-bleed--from-right { --bleed-r: 0%; }
/* Sits at the top or bottom of a band and should run into the seam. */
.fp-bleed--from-top    { --bleed-t: 0%; }
.fp-bleed--from-bottom { --bleed-b: 0%; }

/* ── 3. DEPTH. How far the photograph is behind the page. ───────────────── */

/* The default is a picture the reader is meant to look at. */
.fp-bleed--deep {
  --bleed-t: 22%; --bleed-r: 20%; --bleed-b: 24%; --bleed-l: 20%;
  opacity: .82;
}
/* Ground: a frame carrying atmosphere behind copy rather than content of its
   own. Do NOT put type over one of these without checking the composite: the
   sibling site has a whole file of measured numbers about why that fails. */
.fp-bleed--ground {
  --bleed-t: 30%; --bleed-r: 28%; --bleed-b: 32%; --bleed-l: 28%;
  opacity: .55;
}

/* ── 4. FLOW. Consecutive frames read as one run, not a row of tiles. ───── */

/* Applied to a container of frames: each one sits slightly differently in its
   own box, so a grid of photographs reads as a drift rather than a tile grid.
   Nothing moves; this is a static offset, and it is the "flow" in Ethan's
   note. */
/* THE CHILD IS USUALLY A WRAPPER, NOT THE FIGURE. This was
   `.fp-flow > *:nth-child(n)` setting the custom properties on the direct
   child, and in this markup that child is a .fp-shot or a grid cell with the
   .fp-fig inside it. The properties inherited down correctly and were then
   BEATEN by the figure's own .fp-bleed--deep declaration, so the whole thing
   computed as if it were not there. Verified by measuring a rendered page:
   injecting fp-flow changed the wrapper to 20% and left the figure at 22%.

   Targeting the figure itself, at any depth, is what makes it take effect. */
.fp-flow > *:nth-child(2n) .fp-bleed,
.fp-flow > .fp-bleed:nth-child(2n) { --bleed-t: 20%; --bleed-b: 12%; }
.fp-flow > *:nth-child(3n) .fp-bleed,
.fp-flow > .fp-bleed:nth-child(3n) { --bleed-l: 18%; --bleed-r: 8%; }

/* ── 5. THE TWO CASES THAT MUST NOT FEATHER ─────────────────────────────── */

/* A screenshot is a document. Feathering the edge of a user interface makes it
   look like a photograph of a screen rather than the screen, and it eats the
   corners of the thing being shown. Marked explicitly so the exception is
   visible rather than being an omission someone later "fixes". */
/* [data-shot] MATCHED NOTHING. It was written from the sibling site's
   vocabulary; this repo marks a screen capture with .shot and a sheet frame
   with data-sheet-frame. A guard that matches nothing is worse than no guard,
   because it reads as protection that is not there. */
.fp-bleed--none,
.shot.fp-bleed--none,
[data-sheet-frame].fp-bleed--none { -webkit-mask-image: none; mask-image: none; }

/* Reduced motion does not apply to a mask, and reduced TRANSPARENCY does. A
   reader who has asked for less of it gets the square frame back rather than a
   dissolve they cannot resolve against the ground. */
@media (prefers-reduced-transparency: reduce) {
  .fp-bleed { -webkit-mask-image: none; mask-image: none; opacity: 1; }
  .fp-bleed img { background: var(--plate-2); }
}
