/* #region Product */
.lens-demo {
    position: relative;
    padding: var(--section-space) 0;
    border-bottom: 1px solid var(--section-divider);
    background: var(--surface-editorial);
}

.lens-demo-heading {
    width: min(90vw, var(--section-content-max));
    margin-inline: auto;
}

.lens-demo-heading {
    margin-bottom: clamp(3.5rem, 7vw, 6rem);
}

    .lens-demo-heading h2 {
        max-width: 14ch;
        margin: 0;
        color: var(--white);
        font-family: var(--font-display);
        font-size: var(--section-title-size);
        font-weight: 300;
        letter-spacing: -.04em;
        line-height: var(--section-title-line-height);
    }

        .lens-demo-heading h2 i {
            color: var(--gold);
            font-weight: 300;
        }

    .lens-demo-heading p {
        max-width: 34rem;
        margin: clamp(2rem, 3vw, 2.75rem) 0 0;
        color: var(--white-soft);
        font-size: clamp(1rem, 1.15vw, 1.12rem);
        font-weight: 300;
        line-height: 1.85;
    }

/* The four moments are the house's .journey — one photograph with the steps beside it, in
   product-sections.css — and not a row of four square tiles each with its own picture, number and card.
   That component's measure is written for `.journey > .container`, and this section is not a .journey,
   so the measure is restated here — with the places heading, which stands on a bare .container too. */
.lens-demo > .container,
.lens-places > .container {
    width: min(90vw, var(--section-content-max));
    max-width: none;
    margin-inline: auto;
    padding-inline: 0;
}

@media (max-width: 760px) {
    .lens-demo-heading p {
        max-width: 38rem;
    }
}

/* #endregion */

/* #region Artifacts */
.lens-art-header {
    margin-bottom: clamp(4rem, 8vw, 7.5rem);
}

.artifacts-section {
    position: relative;
    overflow: hidden;
    background: linear-gradient(135deg, transparent 0 68%, var(--hairline-faint) 68% 68.1%, transparent 68.1%), var(--surface-editorial);
}

    .artifacts-section::before {
        position: absolute;
        top: clamp(5rem, 10vw, 10rem);
        right: max(-11rem, -10vw);
        width: clamp(18rem, 34vw, 36rem);
        aspect-ratio: 1;
        border: 1px solid var(--hairline-faint);
        content: "";
        pointer-events: none;
        transform: rotate(45deg);
    }

/* Two objects, one weight. A „lead" figure filling a column beside a list of lesser ones is the right
   shape for one object and its companions, and the wrong one for a family of exactly two: the card stands a
   full column high, the anchor sits in a thumbnail a third of its size, and the heading over them reads
   „dwa przedmioty". */
.lens-art-exhibit {
    position: relative;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: clamp(3rem, 6vw, 6rem);
    align-items: start;
}

.lens-art-piece {
    min-width: 0;
    margin: 0;
}

/* The box holds a built object rather than a photograph, so it is also the model's measuring stick:
   `container-type: inline-size` is what lets every millimetre below be written in `cqw` and stay
   right in one column, in two, and inside the 48rem the piece is capped at on a phone. */
.lens-art-piece-visual {
    position: relative;
    display: grid;
    container-type: inline-size;
    overflow: hidden;
    width: 100%;
    aspect-ratio: 1;
    /* A single pool of light behind the object and nothing under it. A raised surface filling the
       box draws a lit square around a black object on a black page, so what the eye meets first is the
       panel rather than the piece standing on it. The light stays, because the shadow needs something
       to fall on. */
    background: radial-gradient(105% 85% at 50% 34%, var(--tint), transparent 66%);
    place-items: center;
}

.lens-art-piece-copy {
    margin-top: clamp(1.5rem, 2.5vw, 2.4rem);
    padding-top: clamp(1.6rem, 2.6vw, 2.4rem);
    border-top: 1px solid var(--hairline);
}

/* The house's eyebrow, in the one place that had invented its own: same face, size and tracking as
   .h-tag, so „Karta powitalna" over an object reads like „Obiekty dla miejsca" over the section.
   The margin stays this block's own — an eyebrow inside a caption sits closer than one over a
   section heading. The tracking is mirrored for the ™, exactly as .h-tag does it. */
.lens-art-stage {
    display: block;
    color: rgba(245, 245, 245, .52);
    font-family: var(--font-mono);
    font-size: .65rem;
    font-weight: 400;
    letter-spacing: 8px;
    --tm-tracking: 8px;
    line-height: 1.6;
    text-transform: uppercase;
}

    .lens-art-stage b {
        display: inline-block;
        min-width: 2.5rem;
        color: var(--white);
        font-weight: 500;
    }

.lens-art-piece h3 {
    margin: 1.1rem 0 1.15rem;
    color: var(--white);
    font-family: var(--font-display);
    font-size: clamp(1.6rem, 2.2vw, 2.3rem);
    font-weight: 300;
    letter-spacing: -.025em;
    line-height: 1.14;
}

.lens-art-piece p {
    margin: 0;
    color: var(--text-muted);
    font-size: 1rem;
    font-weight: 300;
    line-height: 1.8;
}
/* #endregion */

/* #region Artifact models */
/* The two objects on this page are built, not photographed, and the build is what makes them honest:
   every length below is the workshop's own millimetre count read through one `--mm` unit per model —
   63 × 89 mm for the welcome card, 120 × 120 mm for the anchor with a 20 mm oak profile around a
   100 × 100 mm window. Change a dimension in the workshop and exactly one number changes here.

   It is pure CSS in 3D: no library, no canvas, nothing extra to download. Script does two things and
   neither is the animation: it follows the pointer, and it puts .is-live on a model that is actually
   on screen — the site's own .reveal-elem fires once and never takes itself back, so a model gated
   on that would keep turning for the rest of the page. Every animation here therefore starts paused,
   which is also what a browser with no scripting gets: the objects in their opening pose, still. */

/* Gold has no light of its own: what a gilded letter does is turn the light in the room back at
   whoever is standing there, and it does it only at the angle that sends it their way. So there is
   no timer on any reflection here. One number — the angle the object is standing at — carries every
   highlight on both objects, and it is the same number the turn is made of: the keyframes animate
   --lens-turn beside the transform, the pointer adds its own tilt to it, and each surface reads the
   sum. Turn the card and the light crosses it; hold it still and the light holds still with it.

   --lens-turn is registered so it can be interpolated at all; a browser that does not know
   @property still gets the turn (the transform is written out in the keyframes) and simply steps the
   highlight between poses instead of sliding it. */
@property --lens-turn {
    syntax: "<number>";
    inherits: true;
    initial-value: 0;
}

.lens-model {
    /* One grain for both objects — the card's stock and the anchor's paper are the same black
       dyed through, and a single data URI is decoded once however many surfaces use it. */
    --lens-grain: url('data:image/svg+xml,%3Csvg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg"%3E%3Cfilter id="noise"%3E%3CfeTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="4" stitchTiles="stitch"/%3E%3C/filter%3E%3Crect width="100%25" height="100%25" filter="url(%23noise)"/%3E%3C/svg%3E');
    /* The champagne foil, from the house gold rather than a print literal: --gold is the shade the
       gilding on these cards was matched to, and --white is the glint that crosses it. */
    --lens-foil: linear-gradient(135deg, var(--gold) 0%, var(--gold-bright) 34%, var(--white) 50%, var(--gold-bright) 66%, var(--gold) 100%);
}

.lens-model-scene {
    position: relative;
    display: grid;
    width: 100%;
    height: 100%;
    place-items: center;
    perspective: 150cqw;
    perspective-origin: 50% 42%;
}

/* Two layers, two jobs: the tilt follows the pointer, the turn runs on its own. Kept apart so a
   visitor moving the mouse never fights the animation for the same transform. */
/* The tilt is kept as plain degrees rather than an angle, because the highlights have to add it to
   the turn and read the sum as one number. */
.lens-model-tilt {
    transform: rotateX(calc(var(--lens-tilt-x, 0) * 1deg)) rotateY(calc(var(--lens-tilt-y, 0) * 1deg));
    transform-style: preserve-3d;
    transition: transform 1s var(--ease-house);
}

.lens-model:hover .lens-model-tilt {
    transform: rotateX(calc(var(--lens-tilt-x, 0) * 1deg)) rotateY(calc(var(--lens-tilt-y, 0) * 1deg)) scale(1.03);
}

.lens-model-turn {
    animation: lens-card-turn 26s cubic-bezier(.7, 0, .3, 1) infinite;
    animation-play-state: paused;
    transform-style: preserve-3d;
    will-change: transform;
}

.lens-model.is-live .lens-model-turn {
    animation-play-state: running;
}

/* The card shows its face, turns to the side a guest touches with a phone, and comes back. -14deg
   and 346deg are the same angle, which is what makes the loop seamless. */
@keyframes lens-card-turn {
    0%, 26% {
        --lens-turn: -14;
        transform: rotateY(-14deg) rotateX(3deg);
    }

    46%, 72% {
        --lens-turn: 166;
        transform: rotateY(166deg) rotateX(3deg);
    }

    92%, 100% {
        --lens-turn: 346;
        transform: rotateY(346deg) rotateX(3deg);
    }
}

/* The anchor hangs on a wall, so it sways instead of turning: its back is a wall's business. */
.lens-model-anchor .lens-model-turn {
    animation-name: lens-anchor-sway;
    animation-duration: 18s;
    animation-timing-function: ease-in-out;
}

@keyframes lens-anchor-sway {
    0%, 100% {
        --lens-turn: -20;
        transform: rotateY(-20deg) rotateX(4deg);
    }

    50% {
        --lens-turn: 20;
        transform: rotateY(20deg) rotateX(-3deg);
    }
}

.lens-model-shadow {
    position: absolute;
    right: 0;
    bottom: 9%;
    left: 0;
    width: 54%;
    height: 5%;
    margin: 0 auto;
    border-radius: 50%;
    background: radial-gradient(50% 50% at 50% 50%, rgba(5, 5, 5, .8), transparent 70%);
    animation: lens-model-shadow-breathe 26s ease-in-out infinite;
    animation-play-state: paused;
    pointer-events: none;
}

.lens-model-anchor .lens-model-shadow {
    width: 62%;
    animation-duration: 18s;
}

.lens-model.is-live .lens-model-shadow {
    animation-play-state: running;
}

@keyframes lens-model-shadow-breathe {
    0%, 100% {
        opacity: .85;
        transform: scaleX(1);
    }

    50% {
        opacity: .55;
        transform: scaleX(.82);
    }
}

/* One mark for both objects, drawn once in _LensMark.cshtml and gilded the same way in each: on the
   paper inside the frame and on the reverse of the card. What differs is only how large whatever
   holds it lets it be. */
/* One gold, brightened and dimmed by the angle the object is standing at — nothing else on either
   surface moves with it, because nothing else on either surface is gilded. */
.lens-mark {
    width: 100%;
    height: 100%;
    color: var(--gold);
    filter: brightness(var(--lens-glint, 1));
}

/* #region Welcome card */
.lens-card {
    /* 63 × 89 mm — a poker card, and the one scale factor for everything printed on it. The face is
       set at 10 px on a 315 px proof, so one text unit is the card's width / 31.5, which is 2 mm. */
    --mm: .72cqw;
    /* 3.6 mm at the corners, a poker card's own radius. Named here because the faces are rounded by
       it and the strips that close the card's profile have to stop short of it by exactly as much. */
    --radius: calc(3.6 * var(--mm));
    /* Where the light is, in the card's own reckoning: the angle it is turned to, plus the pointer's
       tilt counted heavier, because a hand moving over the card is a small movement that ought to
       show. Every highlight on the card is a function of this and of nothing else. */
    --lens-light: calc(var(--lens-turn, 0) + var(--lens-tilt-y, 0) * 2.5);
    /* The same angle read as a brightness, for gilding that is a shape rather than a line of type:
       the lettering carries its own foil and slides it, the mark and the corner rules are single
       colours and can only take the light as more or less of it. */
    --lens-glint: calc(1.12 + .38 * sin(var(--lens-light) * 1deg));
    position: relative;
    width: calc(63 * var(--mm));
    height: calc(89 * var(--mm));
    font-family: 'Montserrat', sans-serif;
    font-size: calc(2 * var(--mm));
    transform-style: preserve-3d;
}

.lens-card-face {
    position: absolute;
    display: flex;
    box-sizing: border-box;
    overflow: hidden;
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
    padding: 9em 7em;
    border: .05em solid #222;
    border-radius: var(--radius);
    backface-visibility: hidden;
    background: var(--black);
    box-shadow: 0 calc(6 * var(--mm)) calc(14 * var(--mm)) rgba(5, 5, 5, .55);
    inset: 0;
}

    /* Stock dyed through: the grain is the paper, the sheen is the light on it. */
    .lens-card-face::before {
        position: absolute;
        background-image: var(--lens-grain);
        content: "";
        inset: 0;
        opacity: .06;
        pointer-events: none;
    }

    /* Nothing lies over the face. Stock dyed through has no shine to catch — only the gilding does,
       and each gilded element carries its own reflection, so a band of light across the whole card
       would be light coming off black paper. */

.lens-card-front {
    transform: translateZ(calc(.4 * var(--mm)));
}

/* The reverse holds the mark and one instruction in three languages, on the front's own rhythm: a
   line at the head, the mark where the phone goes, two lines at the foot. */
.lens-card-back {
    transform: rotateY(180deg) translateZ(calc(.4 * var(--mm)));
}

/* 0.8 mm of card, seen from the side. Four strips, each centred on the card and pushed out to its
   own edge — the standard way to close a CSS box, and the only way the card reads as an object
   rather than a picture when it turns through its own profile.

   Each stops a radius short of the corner, and that is not a detail: a strip run to the full height
   sticks out past the rounding, and four of them draw a sharp rectangle around a card whose corners
   are round. The gap left in each corner is 0.8 mm of nothing, seen edge-on at most. */
.lens-card-edge {
    position: absolute;
    background: linear-gradient(#3b3325, #050505 45%, #2b261c);
}

.lens-card-edge-left,
.lens-card-edge-right {
    top: var(--radius);
    left: calc(50% - .4 * var(--mm));
    width: calc(.8 * var(--mm));
    height: calc(100% - 2 * var(--radius));
}

.lens-card-edge-left {
    transform: rotateY(-90deg) translateZ(calc(31.5 * var(--mm)));
}

.lens-card-edge-right {
    transform: rotateY(90deg) translateZ(calc(31.5 * var(--mm)));
}

.lens-card-edge-top,
.lens-card-edge-bottom {
    top: calc(50% - .4 * var(--mm));
    left: var(--radius);
    width: calc(100% - 2 * var(--radius));
    height: calc(.8 * var(--mm));
}

.lens-card-edge-top {
    transform: rotateX(90deg) translateZ(calc(44.5 * var(--mm)));
}

.lens-card-edge-bottom {
    transform: rotateX(-90deg) translateZ(calc(44.5 * var(--mm)));
}

/* The corner rules are gilded too, so they take the same light — filtered on the group rather than
   on each of the four, which is one filter instead of four for the same result. */
.lens-card-corners {
    position: absolute;
    z-index: 1;
    inset: 3.5em;
    filter: brightness(var(--lens-glint, 1));
    pointer-events: none;
}

.lens-card-corner {
    position: absolute;
    width: 1.5em;
    height: 1.5em;
    border: .1em solid var(--gold);
}

.lens-card-corner-tl {
    top: 0;
    left: 0;
    border-right: none;
    border-bottom: none;
}

.lens-card-corner-tr {
    top: 0;
    right: 0;
    border-bottom: none;
    border-left: none;
}

.lens-card-corner-bl {
    bottom: 0;
    left: 0;
    border-top: none;
    border-right: none;
}

.lens-card-corner-br {
    right: 0;
    bottom: 0;
    border-top: none;
    border-left: none;
}

.lens-card-block {
    position: relative;
    z-index: 2;
    width: 100%;
}

.lens-card-monolith {
    display: flex;
    flex-direction: column;
    gap: 1.2em;
}

/* Every row is justified across the card, letter by letter, exactly as it is stamped. */
.lens-card-row {
    display: flex;
    overflow: visible;
    align-items: baseline;
    justify-content: space-between;
    width: 100%;
    line-height: .8;
    text-transform: uppercase;
}

    .lens-card-row span {
        position: relative;
        display: inline-block;
        margin-bottom: -.2em;
        padding-bottom: .2em;
    }

.lens-card-row + .lens-card-row {
    margin-top: 1em;
}

.lens-card-monolith .lens-card-row + .lens-card-row {
    margin-top: 0;
}

.lens-card-micro {
    font-size: 1em;
    font-weight: 500;
}

.lens-card-line-small {
    font-size: 2.6em;
    font-weight: 400;
}

.lens-card-line-large {
    font-size: 3.8em;
    font-weight: 300;
}

/* Hot foil: the gradient is the metal, the sweep is a light crossing it once per turn. */
.lens-card-foil {
    background: var(--lens-foil);
    background-clip: text;
    background-position: calc(50% - var(--lens-light) * .8%) 0;
    background-size: 280% 100%;
    -webkit-background-clip: text;
    color: transparent;
}

/* The mark on the reverse, sized in the card's own units so it holds its place whatever the card is
   scaled to. It is 10 mm — a stamp between two lines of type, not the subject of the side: at 30 mm
   it filled the text column and read as a logo page rather than a card. */
.lens-card-mark {
    position: relative;
    z-index: 2;
    display: grid;
    width: 5em;
    aspect-ratio: 1;
    place-items: center;
}
/* #endregion */

/* #region Frame anchor */
.lens-anchor {
    /* 130 × 130 mm of solid oak showing a 15 mm profile, so the window is 100 × 100 mm — the three
       numbers the workshop cuts to, and the only ones to change here. Depth is the one dimension
       nobody has fixed; 20 mm is a solid-oak profile's usual. */
    --side: 130;
    --frame: 15;
    --depth: 20;
    --mm: .46cqw;
    /* The same reckoning as the card's, weighted differently: this object sways through 40 degrees
       where the card turns through 360, so the light has to move much further per degree or a frame
       on a wall would look painted. */
    --lens-light: calc(var(--lens-turn, 0) * 4.5 + var(--lens-tilt-y, 0) * 3);
    /* Dimmer than the card's, and deliberately so. The card is held in a hand and catches a lamp;
       this hangs on a wall in a room the page keeps dark, and the card's peak reads as a lit prop here.
       The floor is the card's; it is the brightest quarter of the swing that is pulled back. */
    --lens-glint: calc(1.02 + .26 * sin(var(--lens-light) * 1deg));
    position: relative;
    width: calc(var(--side) * var(--mm));
    height: calc(var(--side) * var(--mm));
    transform-style: preserve-3d;
}

.lens-anchor-face {
    position: absolute;
    box-sizing: border-box;
    backface-visibility: hidden;
    inset: 0;
}

/* The oak is the photographed board the Art frames are built from, so an anchor and a framed work
   are cut from the same wood on the screen as they are in the workshop. */
.lens-anchor-front {
    display: grid;
    border: calc(var(--frame) * var(--mm)) solid transparent;
    border-image: url('/img/art/frame-wood.webp') 30% round;
    background: var(--black);
    box-shadow: 0 calc(8 * var(--mm)) calc(18 * var(--mm)) rgba(5, 5, 5, .6);
    place-items: center;
    transform: translateZ(calc(var(--depth) * var(--mm) / 2));
}

    /* The board's photograph comes out of the camera lit for a studio, and the back and the four
       edges each carry a dark gradient over it, the face included: left at full exposure the wood is the
       brightest thing on this page's black. The veil is
       drawn as a border rather than a fill so it lands on the oak alone and leaves the window and
       the gilded mark inside it untouched; the negative inset is what reaches out over the border
       box, since an absolute child is otherwise held to the padding box. */
    .lens-anchor-front::after {
        position: absolute;
        border: calc(var(--frame) * var(--mm)) solid rgba(5, 5, 5, .3);
        content: "";
        inset: calc(var(--frame) * var(--mm) * -1);
        pointer-events: none;
    }

.lens-anchor-back {
    background-image: linear-gradient(to bottom, rgba(5, 5, 5, .55), rgba(5, 5, 5, .8)), url('/img/art/frame-wood.webp');
    background-size: cover;
    transform: rotateY(180deg) translateZ(calc(var(--depth) * var(--mm) / 2));
}

.lens-anchor-edge {
    position: absolute;
    background-image: linear-gradient(rgba(5, 5, 5, .3), rgba(5, 5, 5, .62)), url('/img/art/frame-wood.webp');
    background-size: cover;
}

.lens-anchor-edge-left,
.lens-anchor-edge-right {
    top: 0;
    left: calc(50% - var(--depth) * var(--mm) / 2);
    width: calc(var(--depth) * var(--mm));
    height: 100%;
}

.lens-anchor-edge-left {
    transform: rotateY(-90deg) translateZ(calc(var(--side) * var(--mm) / 2));
}

.lens-anchor-edge-right {
    transform: rotateY(90deg) translateZ(calc(var(--side) * var(--mm) / 2));
}

.lens-anchor-edge-top,
.lens-anchor-edge-bottom {
    top: calc(50% - var(--depth) * var(--mm) / 2);
    left: 0;
    width: 100%;
    height: calc(var(--depth) * var(--mm));
}

.lens-anchor-edge-top {
    transform: rotateX(90deg) translateZ(calc(var(--side) * var(--mm) / 2));
}

.lens-anchor-edge-bottom {
    transform: rotateX(-90deg) translateZ(calc(var(--side) * var(--mm) / 2));
}

/* Black paper dyed through, set in the window. The shadow the profile drops along the rebate is
   what says the window has depth rather than being a black square painted on the board. */
.lens-anchor-paper {
    position: relative;
    display: grid;
    overflow: hidden;
    width: 100%;
    height: 100%;
    background: radial-gradient(120% 120% at 32% 18%, #121212, var(--black) 68%);
    box-shadow: inset 0 0 calc(7 * var(--mm)) rgba(5, 5, 5, .95), inset calc(1.5 * var(--mm)) calc(1.5 * var(--mm)) calc(3 * var(--mm)) rgba(5, 5, 5, .8);
    place-items: center;
}

    .lens-anchor-paper::before {
        position: absolute;
        background-image: var(--lens-grain);
        content: "";
        inset: 0;
        opacity: .07;
        pointer-events: none;
    }

.lens-anchor-paper .lens-mark {
    width: 58%;
    height: 58%;
}
/* #endregion */
/* #endregion */

/* #region Places */
/* WHERE THE TWO OBJECTS STAND. The section above builds them to the millimetre, which answers what
   they are; this answers the question every venue asks next — where would that go in my space? —
   and it is the first imagery on this page that shows a room rather than a product.

   Eight squares, ALL ONE SIZE, one measure between them. Two decisions and each has a reason: the
   house's system is 1:1, and the anchor is printed inside each photograph, so a tile of another
   shape crops the object the gallery exists to show. Equal size also refuses to rank the places —
   which wall matters is the venue's judgement, and we are showing possibilities, not a favourite.

   IT IS A BELT, AND IT DRIFTS. As a four-column grid with a caption under every tile it is a contact sheet:
   sixteen lines of uppercase type competing with eight photographs, each set too small to read the room it
   shows. So there are no captions — they name what the picture already shows, and the section's own heading
   says what all eight are — and the tiles are large enough for
   the anchor in them to be legible. The strip runs edge to edge and moves slowly and continuously,
   which is what keeps the page alive — a still grid of renders reads as dead. The motion is the same
   idiom as the Filmable callout's own strip, not a new one, and it stops under the cursor so a reader
   can look. */
.lens-places {
    position: relative;
    /* The section had no vertical rhythm of its own at all, so it sat against the one above it. The
       bottom rule is also the hairline the next section needs over its heading — the same border
       the demo section draws, rather than a second mechanism for one line. */
    padding: var(--section-space) 0;
    border-bottom: 1px solid var(--section-divider);
}

/* The shared measure PLUS air. What argues for it is what follows: a band of photographs running
   edge to edge, opening with a hard top rule. `--section-head-gap` is set for content that begins
   with something light, and at that distance alone the lead sat on the belt — the same reason the
   artist wall on the Art page carries the measure plus an addition of its own. */
.lens-places-header {
    margin-bottom: calc(var(--section-head-gap) + clamp(1.4rem, 2.8vh, 2.4rem));
}

/* A BAND, not a loose row of squares. Two hairlines and the air between them make the strip an
   object on the page — the same move the plate on the Space stage makes — and the fade at the ends
   takes the rules with it, so the band dissolves rather than stopping at a cut edge. The vertical
   padding keeps the tiles' shadows inside the band. */
.lens-places-belt {
    position: relative;
    padding-block: clamp(1.4rem, 2.6vh, 2.2rem);
    border-top: 1px solid var(--hairline);
    border-bottom: 1px solid var(--hairline);
    overflow: hidden;
    /* The ends fade rather than being cut, so the strip reads as continuing past the page instead of
       stopping at a hard edge two-thirds of a tile in. */
    mask-image: linear-gradient(90deg, transparent, #050505 7%, #050505 93%, transparent);
}

/* The duration is a SPEED, so it is computed rather than nudged. The animation travels one run — eight
   tiles plus their gaps, about three thousand pixels at the largest tile size — so 42s is roughly seventy
   pixels a second, and a tile takes some five seconds to cross the frame. At 110s that is twenty-seven
   pixels a second and thirteen seconds a tile, slow enough that the strip looks stuck rather than calm;
   much past a hundred pixels a second it stops being a drift and starts being a carousel. */
.lens-places-drift {
    display: flex;
    width: max-content;
    animation: lens-places-drift 42s linear infinite;
    will-change: transform;
}

    /* Held under the cursor: the whole point of the tiles being this size is that somebody can study
       one, and a picture that walks away while it is being read is worse than a still grid. */
    .lens-places-belt:hover .lens-places-drift {
        animation-play-state: paused;
    }

.lens-places-run {
    --places-gap: clamp(14px, 1.6vw, 26px);
    display: flex;
    gap: var(--places-gap);
    padding-right: var(--places-gap);
}

/* Each tile is a MOUNTED PRINT rather than a photograph laid on the page: the frame's own hairline,
   a second one set in from it — the passe-partout the oak frame and the Space plate both draw — and
   a shadow underneath, so the tile has a body and sits above the band instead of being printed on
   it. That is the whole difference between a strip of renders and a wall of framed work, and this
   product is sold to people who hang things. */
.lens-place {
    position: relative;
    width: clamp(15rem, 22vw, 22rem);
    margin: 0;
    aspect-ratio: 1;
    flex: none;
    border: 1px solid var(--hairline);
    box-shadow: 0 1rem 2.4rem rgba(5, 5, 5, .45);
    overflow: hidden;
    transition: border-color var(--motion) var(--ease-house);
}

    .lens-place::after {
        content: "";
        position: absolute;
        inset: clamp(8px, .9vw, 14px);
        border: 1px solid var(--photo-frame);
        pointer-events: none;
        z-index: 1;
        transition: border-color var(--motion) var(--ease-house);
    }

    .lens-place img {
        display: block;
        width: 100%;
        height: 100%;
        object-fit: cover;
        /* The house's resting grade while it drifts, full brightness under the cursor — which is
           also the moment the belt stops. One gesture, three answers: it holds still, it lights up,
           and its mount warms to gold. */
        filter: var(--photo-at-rest);
        transition: transform 1.8s var(--ease-house), filter var(--motion-slow) var(--ease-house);
    }

    .lens-place:hover {
        border-color: var(--hairline-strong);
    }

        .lens-place:hover::after {
            border-color: var(--photo-frame-hover);
        }

        .lens-place:hover img {
            filter: var(--photo-lifted);
            transform: scale(1.025);
        }

/* Exactly one run's width, because the drift holds the eight tiles twice: at half the total the
   second run stands where the first began and the loop has no seam. */
@keyframes lens-places-drift {
    from {
        transform: translateX(0);
    }

    to {
        transform: translateX(-50%);
    }
}

@media (prefers-reduced-motion: reduce) {
    /* No drift for a reader who asked for none — and then the strip has to be reachable by hand,
       or six of the eight placements are simply unreachable. */
    .lens-places-drift {
        animation: none;
    }

    .lens-places-belt {
        overflow-x: auto;
    }

    .lens-place,
    .lens-place::after,
    .lens-place img {
        transition: none;
    }

        .lens-place:hover img {
            transform: none;
        }
}
/* #endregion */

/* #region Results */
.res-header {
    margin-bottom: 10vh;
}

.results-section {
    position: relative;
    background: var(--hero-surface);
}

/* Four consequences of one film, hung from a single rule instead of boxed four times over. The
   boxes are the whole trouble: a border each says these are four separate offers, at a quarter of the band's
   width the words have nowhere to go, and a title in the site's eyebrow style — 0.8rem, uppercase, three
   pixels of tracking — is doing a heading's work.

   The rule belongs to the entries rather than to the row, so it draws itself left to right as they
   arrive, and the figures sit on it. */
.res-thread {
    --res-pad: clamp(1.5rem, 2.4vw, 2.8rem);
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    /* No gap, and it is load-bearing: the four top borders have to meet, or the thread reads as
       four separate rules. What keeps the columns apart is the hairline between them. */
    gap: 0;
    max-width: none;
    margin: 0 auto;
}

.res-entry {
    --res-start: var(--res-pad);
    position: relative;
    /* ONE DISTANCE FOR ALL FOUR. Pushing each entry down a further .9rem — a staircase, on the
       argument that four columns of one length read as a table — produces four different top margins
       under one rule: the numerals stop lining up and the band reads as a fault rather than a
       composition. The rule above them is the line they share, and the entries hang from it at the
       same height. */
    padding: clamp(2.8rem, 4.5vh, 3.8rem) var(--res-pad) 0;
    border-top: 1px solid var(--hairline);
}

    .res-entry:first-child {
        --res-start: 0rem;
        padding-left: 0;
    }

    .res-entry:last-child {
        padding-right: 0;
    }

    .res-entry + .res-entry {
        border-left: 1px solid var(--section-divider);
    }

    /* The gold answering a pointer is drawn over the rule rather than recolouring it, so the
       line's weight never changes as it lights. */
    .res-entry::before {
        position: absolute;
        top: -1px;
        right: 0;
        left: 0;
        height: 1px;
        background: var(--gold);
        content: "";
        opacity: 0;
        transition: opacity var(--motion) var(--ease-house);
    }

    .res-entry:hover::before {
        opacity: .7;
    }

    /* The reveal is staggered per entry, so the rule assembles from the left rather than appearing
       whole. Every component on the site names its own delays — there is no shared .delay-n. */
    .res-entry.delay-1 {
        transition-delay: .2s;
    }

    .res-entry.delay-2 {
        transition-delay: .4s;
    }

    .res-entry.delay-3 {
        transition-delay: .6s;
    }

.res-num {
    position: absolute;
    top: 0;
    left: var(--res-start);
    padding-right: .8rem;
    /* The section's own ground, so the figure cuts the rule instead of standing under it. There is
       no second colour to keep in step with the background, because it is the background. */
    background: var(--hero-surface);
    color: rgba(245, 245, 245, .5);
    font-family: var(--font-display);
    font-size: clamp(1.9rem, 2.6vw, 2.6rem);
    font-style: italic;
    line-height: 1;
    transform: translateY(-50%);
    transition: color var(--motion-quick) var(--ease-house);
}

/* Gold arrives on the numeral with the rule above it. */
.res-entry:hover .res-num {
    color: var(--gold);
}

.res-title {
    margin-bottom: 1.6vh;
    color: var(--white);
    font-family: var(--font-display);
    font-size: clamp(1.15rem, 1.5vw, 1.5rem);
    font-weight: 300;
    letter-spacing: -.01em;
    line-height: 1.25;
}

.res-text {
    max-width: 34ch;
    color: var(--text-muted);
    font-size: .95rem;
    font-weight: 200;
    line-height: 1.8;
}
/* #endregion */

/* #region Seasonality
   The notes about the bill do not stand in four columns like the results above them: the same shape
   one screen apart makes the page say „four of something" twice and neither says it well. What answers
   „mniejszy ruch, niższy rachunek" is not a fourth card but the ladder itself, read downwards as the
   account it is — how many films, and what is owed for them. */
.lens-seasonal-body {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
    align-items: start;
    gap: clamp(2.5rem, 6vw, 6rem);
    max-width: none;
    margin: 0 auto;
}

.lens-ledger {
    padding: clamp(2rem, 3vw, 3rem);
    border: 1px solid var(--hairline);
    background: linear-gradient(160deg, var(--tint), transparent 55%), var(--surface-card);
}

.lens-ledger-title {
    display: block;
    margin-bottom: clamp(1.6rem, 3vh, 2.4rem);
    color: rgba(245, 245, 245, .5);
    font-size: .62rem;
    font-weight: 500;
    letter-spacing: .28em;
    text-transform: uppercase;
}

.lens-ledger-rows {
    margin: 0;
    padding: 0;
    list-style: none;
}

    .lens-ledger-rows li {
        display: grid;
        grid-template-columns: auto minmax(1.5rem, 1fr) auto;
        align-items: center;
        gap: .9rem;
        padding: 1.15rem 0;
        border-bottom: 1px solid var(--section-divider);
    }

    .lens-ledger-rows li:first-child {
        border-top: 1px solid var(--section-divider);
    }

/* The leader is what makes four amounts read as an account rather than as a table: the eye walks
   the dots across instead of crossing empty space and losing the row. */
.lens-ledger-leader {
    height: 1px;
    border-top: 1px dotted var(--hairline-strong);
}

.lens-ledger-label {
    color: var(--text-muted);
    font-size: .92rem;
    font-weight: 200;
}

.lens-ledger-amount {
    color: var(--white);
    font-family: var(--font-display);
    font-size: clamp(1.05rem, 1.5vw, 1.35rem);
    font-weight: 300;
    white-space: nowrap;
}

    /* The first bracket is the one that makes the seasonal promise true, and what it says is that
       nothing is owed — so it is set as a statement, not as an amount that happens to be nothing. */
    .lens-ledger-rows li:first-child .lens-ledger-amount {
        color: var(--text-muted);
        font-family: var(--font-sans);
        font-size: .72rem;
        font-weight: 300;
        letter-spacing: .16em;
        text-transform: uppercase;
    }

.lens-ledger-foot {
    margin-top: clamp(1.4rem, 2.6vh, 2rem);
    color: var(--text-muted);
    font-size: .8rem;
    font-weight: 200;
    line-height: 1.7;
}

    /* The two amounts in this note, marked the way the house marks money in small print — full white
       at weight 500. The note is deliberately muted, and a charge left in that grey is one the eye
       slides past; against 200 the 500 reads as emphasis without turning the line into a heading. */
    .lens-ledger-foot b {
        color: var(--white);
        font-weight: 500;
    }

.lens-seasonal-points {
    display: grid;
}

.lens-point {
    padding: clamp(1.5rem, 2.6vh, 2.1rem) 0;
    border-bottom: 1px solid var(--section-divider);
}

    .lens-point.delay-1 {
        transition-delay: .15s;
    }

    .lens-point.delay-2 {
        transition-delay: .3s;
    }

    .lens-point.delay-3 {
        transition-delay: .45s;
    }

    .lens-point:first-child {
        padding-top: 0;
    }

    .lens-point:last-child {
        padding-bottom: 0;
        border-bottom: 0;
    }

    .lens-point h3 {
        margin-bottom: .7rem;
        color: var(--white);
        font-family: var(--font-display);
        font-size: clamp(1.05rem, 1.3vw, 1.3rem);
        font-weight: 300;
        line-height: 1.25;
    }

    .lens-point p {
        color: var(--text-muted);
        font-size: .92rem;
        font-weight: 200;
        line-height: 1.8;
    }
/* #endregion */

/* #region Responsive */
@media (max-width: 1000px) {
    /* One under the other, both still the same size as each other. */
    .lens-art-exhibit {
        grid-template-columns: 1fr;
        gap: clamp(4rem, 9vw, 7rem);
    }

    .lens-art-piece {
        max-width: 48rem;
    }

    /* Two abreast on tablets — four columns straight into one long stack wasted the whole band.
       Both the step down the row and the hairline between columns have to be redealt: the third
       entry starts a row here, it does not continue one. */
    .res-thread {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    /* Nothing to switch off here any more: the entries share one top distance at every width. */
    .res-thread .res-entry {
        padding-bottom: clamp(2rem, 4vh, 3rem);
    }

    .res-thread .res-entry:nth-child(odd) {
        --res-start: 0rem;
        padding-left: 0;
        border-left: 0;
    }

    .res-thread .res-entry:nth-child(even) {
        --res-start: var(--res-pad);
        padding-right: 0;
        padding-left: var(--res-pad);
        border-left: 1px solid var(--section-divider);
    }

    .lens-seasonal-body {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 640px) {
    .res-thread {
        grid-template-columns: 1fr;
    }

    /* One column: every entry starts at the container's edge, and the hairline that separated two
       of them would now cut across a stack. */
    .res-thread .res-entry,
    .res-thread .res-entry:nth-child(odd),
    .res-thread .res-entry:nth-child(even) {
        --res-start: 0rem;
        padding-right: 0;
        padding-left: 0;
        border-left: 0;
    }

    .res-text {
        max-width: none;
    }
}

@media (max-width: 600px) {
    .lens-art-piece h3 {
        margin: .8rem 0 .8rem;
        font-size: 1.35rem;
    }

    .lens-art-piece p {
        font-size: .92rem;
        line-height: 1.7;
    }
}

/* At 320px the first ledger row — label, leader and the tracked „bez dopłaty" — is wider than the
   ledger. The leader goes and the label may wrap. */
@media (max-width: 420px) {
    .lens-ledger {
        padding: 1.25rem;
    }

    .lens-ledger-rows li {
        grid-template-columns: minmax(0, 1fr) auto;
    }

    .lens-ledger-leader {
        display: none;
    }
}

/* Nothing turns for a visitor who asked for stillness: both objects hold the angle they are read
   best at, and the card holds its face — the side that says what it is. */
@media (prefers-reduced-motion: reduce) {
    /* Written against .lens-model rather than the classes alone, so these carry the same weight as
       the .is-live and .lens-model-anchor rules above and win by coming after them. */
    .lens-model .lens-model-turn,
    .lens-model .lens-model-shadow,
    .lens-model-anchor .lens-model-turn {
        animation: none;
    }

    /* The angle is set by hand here, so the highlights land where a still object's would. */
    .lens-model .lens-model-turn {
        --lens-turn: -14;
        transform: rotateY(-14deg) rotateX(3deg);
    }

    .lens-model-anchor .lens-model-turn {
        --lens-turn: -16;
        transform: rotateY(-16deg) rotateX(3deg);
    }

    .lens-model-tilt,
    .lens-model:hover .lens-model-tilt {
        transform: none;
        transition: none;
    }

    .res-entry::before,
    .res-num {
        transition: none;
    }
}
/* #endregion */
