/* film-look — the client's own film. No JavaScript. Every photo gets the same grade, so a site made of phone
   pictures looks shot on one roll: gentle contrast, a touch less saturation, shadows tinted toward the
   client's darkest colour, highlights toward their warm one, and a living grain over the whole page.

   Markup: put class "film" on a figure (or on any section: every <figure> inside is graded too).
     <figure class="film"><img src="..." alt="..."></figure>      <section class="film"> ... <figure><img></figure> ... </section>
   Tokens (all optional): --film-contrast 1.06  --film-sat .92  --film-shadow (= --ground)  --film-light (= --light)
     --film-shadow-amount .9  --film-light-amount .2  --film-edge  --film-sepia .1  --grain .10  --material-blend luminosity
   Not here: the .material rule itself. A url() written in a custom property resolves against the stylesheet that
   USES it, so the identity file (osteria.css) owns .material and --material; this file only adds the blend. */

.film, .film figure { position: relative; isolation: isolate; overflow: hidden; }
.film img, .film video { filter: contrast(var(--film-contrast, 1.06)) saturate(var(--film-sat, .92)) sepia(var(--film-sepia, .1)); }
/* shadows toward the client's darkest colour: "lighten" lifts every black up to that colour (the faded, warm black of
   film); highlights toward their warm colour: "multiply" turns a white wall to cream and warms the mid-tones; the
   inset shadow on that layer is the lens falloff at the edges (a shadow, not a gradient) */
figure.film::before, .film figure::before { content: ""; position: absolute; inset: 0; z-index: 1; background: var(--film-shadow, var(--ground, #1b1410)); mix-blend-mode: lighten; opacity: var(--film-shadow-amount, .9); pointer-events: none; }
figure.film::after, .film figure::after { content: ""; position: absolute; inset: 0; z-index: 1; background: color-mix(in srgb, var(--film-light, var(--light, #ffb05a)) calc(var(--film-light-amount, .2) * 100%), transparent); mix-blend-mode: multiply; box-shadow: inset 0 0 9vw var(--film-edge, rgba(0, 0, 0, .55)); pointer-events: none; }

/* grain: SVG noise, fixed over everything, never blocks a tap; it stirs a little (steps, not a glide) */
body::after {
  content: ""; position: fixed; top: -50%; left: -50%; width: 200%; height: 200%; z-index: 9999; pointer-events: none;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .5 0 0 0 0 .5 0 0 0 0 .5 0 0 0 1.2 -.1'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E") 0 0 / 220px 220px;
  mix-blend-mode: overlay; opacity: var(--grain, .10);
}
@media (prefers-reduced-motion: no-preference) {
  body::after { animation: film-grain .9s steps(1) infinite; }
  @keyframes film-grain { 0% { transform: translate(0, 0); } 20% { transform: translate(-60px, 40px); } 40% { transform: translate(50px, -70px); } 60% { transform: translate(-30px, -50px); } 80% { transform: translate(70px, 30px); } }
}

/* the material ground: the identity's .material (the client's stone/wood), blended with the ground colour */
.material::before { background-color: var(--ground, #1b1410); background-blend-mode: var(--material-blend, luminosity); }
