/* Michal Kašpar — case page blocks
   ──────────────────────────────────────────────────────────
   Built from the Figma "projekty-detail" frame (Coqui). Every
   block is self-contained: a page is a list of blocks in any
   order, so other clients reuse the same set.
   Reused from the live site, not redefined here:
   - tokens, fonts, nav, footer      → shared.css + page chrome
   - line / decode / image reveal,
     parallax, cursor labels         → line-reveal.js,
                                       decode-reveal.js, shared.js
   - gallery slider                  → .lab-slider* (Lab)
   Client colours come in per page via --pb-brand / --pb-card.
   Spacing uses the site tokens only (shared.css + the Lab/About
   :root); the aliases below just name their job here.
   Layout sits on the Lab 12-column grid (no gutters, invisible
   here). The main column is exactly the grid box (--grid-left …
   --grid-right from shared.js), so 12 × 1fr tracks land on the
   grid lines and halves meet on --grid-center. */

.pb {
  /* client colours: neutral here, each page sets its own on .pb */
  --pb-brand: #2E2D37;
  --pb-card:  #E6E5EA;
  --pb-on-accent: var(--color-text-secondary);   /* text on --accent / --pb-card */
  --pb-sheet: var(--color-text-primary);   /* behind whole pictures */
  --pb-tint:  rgb(255 255 255 / 0.1);      /* behind transparent PNGs */
  --pb-sheet-inset: 6%;                    /* picture inside its sheet */
  --pb-strip-mobile: 86vw;                 /* strip panel on a phone */
  --pb-strip-h-mobile: calc(var(--pb-strip-mobile) * 1.25);   /* one height for the strip row: a 4:5 sheet */
  --pb-slide-mobile: 78%;                  /* gallery photo on a phone */
  --pb-gallery-head: 74px;                 /* the arrows and the gap under them */
  --pb-title-mobile: clamp(48px, 14vw, 80px);
  --pb-claim-mobile: 50dvh;                /* claim block on a phone */
  --pb-fill-length: 200dvh;                /* extra scroll through a filling claim */
  --pb-fill-from: 0.1;                     /* its letters before they are reached */
  --pb-fill-rise: 0.16em;                  /* how far each letter rises as it fills */
  --pb-fill-grow: 0.94;                    /* the whole claim settles from this scale */
  --pb-fill-spacing: -0.035em;             /* its letters sit closer than body headings */
  --pb-fill-size: calc(var(--text-2xl) * 2);   /* a filling claim fills the screen */
  --pb-fill-blur: 0.06em;                  /* focus variant: how soft the letters start */
  --pb-fill-track: 0.08em;                 /* focus variant: how far apart they start */
  --pb-more-row: 31px;                     /* All projects row, More Projects */
  --pb-more-gap: 20dvh;                    /* air under the More Projects heading, always */
  --pb-cursor-size: clamp(220px, 23.2vw, 600px);   /* 330 / 445 / 599 at 1440 / 1920 / 2560 */
  --pb-cursor-in:  760ms;                  /* card arrives */
  --pb-cursor-out: 420ms;                  /* card leaves */
  --pb-fade: 160ms;                        /* quick cross-fade */
  --pb-pill-h: 28px;                       /* homepage outro pills */
  --pb-pill-text: 12px;
  --pb-hl-1: var(--color-bg-secondary);    /* homepage outro pill palette */
  --pb-hl-2: #FF44E0;
  --pb-hl-3: #00FF4A;
  --pb-hl-4: #FFB100;
  --pb-gap:   var(--lab-edge-l);   /* small gap: strip pages, stacked items */
  --pb-space: var(--lab-rhythm);   /* block rhythm, as Lab/About sections */
  --pb-text-inset: clamp(20px, 3vw, 48px);   /* text beside an image, as Lab .lab-pair */
  --pb-col: var(--grid-col, calc((100vw - var(--navbar-width) - 2 * var(--lab-edge-l)) / 12));
  --radius-card: 12px;
  position: relative;
  z-index: 2;
}
.pb-block { position: relative; }
.pb-block + .pb-block { margin-top: var(--pb-space); }

/* Screen blocks — the block plus the rhythm gap above it fill one
   viewport (Lab does the same with its claims: 80vh + the gap);
   the content sits in the middle unless the block says otherwise */
.pb-screen {
  min-height: calc(100vh - var(--pb-space));
  min-height: calc(100dvh - var(--pb-space));
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* The footer stays hidden on the block pages for now: like the
   hero before it, its lines stop 15 px short of the nav wherever
   the scrollbar takes space (live site too). Fix the shared footer
   first, then drop this rule (Michal, 29 Oct 2026). */

/* Display type — the geometric ss01 cut used for big site claims */
.pb-display {
  font-family: var(--font-sans);
  font-weight: 500;
  font-feature-settings: "ss01";
  letter-spacing: -0.025em;
  line-height: 1.0;
  margin: 0;
}
/* Plain cut — quotes and panel titles in Figma */
.pb-plain {
  font-family: var(--font-sans);
  font-weight: 500;
  letter-spacing: -0.02em;
  margin: 0;
}
.pb-body {
  font-size: var(--text-base);
  line-height: 1.5;
  color: var(--fg);
  max-width: 46ch;
  margin: 0;
}
.pb-media {
  position: relative;
  overflow: hidden;
  background: color-mix(in srgb, var(--color-text-primary) 12%, var(--color-bg-primary));
}
.pb-media picture { display: contents; }
.pb-media iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; pointer-events: none; }
.pb-media img,
.pb-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Parallax (decode-reveal.js drifts the img ±6 %) — oversize the
   image so the drift never shows an edge */
.pb-media[data-parallax] img,
.pb-media[data-parallax] video {
  position: absolute;
  left: 0;
  top: -8%;
  height: 116%;
}

/* 01 · Hero — full bleed (edge to the side nav), full viewport ─
   Sized off 100vw, not the main column: the page scrolls inside
   body, whose scrollbar (hidden under the nav) would otherwise
   leave a gap before the nav where scrollbars take space. */
.pb-hero {
  margin-left: calc(var(--lab-edge-l) * -1);
  width: calc(100vw - var(--navbar-width));
}
.pb-hero .pb-media { height: 100vh; height: 100dvh; }
/* press and hold for sound (blocks.js): no text selection, and no
   long-press menu on phones */
.pb-hero[data-pb-sound] { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
body.pb-sound-held #cursor-label { opacity: 0; transition: opacity var(--dur-1) ease; }
/* while held the picture is alone: the title steps aside */
.pb-hero[data-pb-sound] h1 { transition: opacity var(--dur-1) ease; }
body.pb-sound-held .pb-hero[data-pb-sound] h1 { opacity: 0; }
/* the viewfinder corners, as on the homepage reels */
.pb-hero .crosshair {
  position: absolute;
  z-index: 3;
  width: 18px;
  height: 18px;
  border: 1px solid color-mix(in srgb, var(--color-text-primary) 18%, transparent);
  pointer-events: none;
}
.pb-hero .crosshair.tl { top: var(--frame-y); left: var(--frame-x); border-right: none; border-bottom: none; }
.pb-hero .crosshair.tr { top: var(--frame-y); right: var(--frame-x); border-left: none; border-bottom: none; }
.pb-hero .crosshair.bl { bottom: var(--frame-y); left: var(--frame-x); border-right: none; border-top: none; }
.pb-hero .crosshair.br { bottom: var(--frame-y); right: var(--frame-x); border-left: none; border-top: none; }
@media (max-width: 760px), (max-width: 1024px) and (orientation: portrait) {
  .pb-hero .crosshair { display: none; }
}
/* text glitching in (blocks.js): a word never breaks */
.pb-glitch-word { display: inline-block; white-space: nowrap; }
.pb-glitch-char { display: inline-block; text-align: center; }
.is-armed .pb-glitch-char { visibility: hidden; }
/* small one-line caption in the middle of the video;
   the type of the homepage service prices (.service-price), in white */
.pb-hero h1 {
  position: absolute;
  top: 50%;
  left: var(--lab-edge-l);
  right: var(--lab-edge-l);
  z-index: 2;
  margin: 0;
  transform: translateY(-50%);
  color: var(--color-pure-white);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0.14em;
  line-height: 1.3;
  text-align: center;
  text-transform: uppercase;
  pointer-events: none;
}

/* A claim on the client's card colour, on the grid like every block.
   Works on any text block (04, 06, 07): the text turns dark. */
.pb-block--tint {
  background: var(--pb-card);
  color: var(--pb-on-accent);
}

/* 02 · Intro — one screen: services · years · client on its top
   edge, the project description on its bottom edge. Straight
   under the hero, so no gap above it. ───────────────────── */
.pb-hero + .pb-intro { margin-top: 0; }
.pb-intro { justify-content: space-between; gap: var(--pb-space); }
.pb-meta {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: start;
  gap: var(--pb-gap);
  padding-top: var(--frame-y);
  font-size: var(--text-base);
  line-height: 1.3;
}
.pb-meta ul { list-style: none; margin: 0; padding: 0; }
.pb-meta .pb-years { justify-self: center; }
.pb-meta .pb-client { justify-self: end; }
/* the description starts on the grid centre (as the Lab hero lede) */
.pb-desc {
  display: grid;
  grid-template-columns: repeat(var(--lab-cols), minmax(0, 1fr));
  column-gap: 0;
  padding-bottom: var(--edge-y);
  border-bottom: 1px solid var(--line);
}
.pb-desc .pb-body { grid-column: 7 / -1; max-width: 52ch; }

/* 03 · Media window — one photo or video loop in a wide window
   (1404 : 640, the brand-slide format; 4:5 on mobile) across the
   whole grid, centred in its screen. A <picture> can bring its own
   crop for mobile. ───────────────────────────────────────── */
.pb-window .pb-media { aspect-ratio: 1404 / 640; }
/* footage that needs its height: a full 16:9 (square on mobile like the rest) */
.pb-window .pb-media--film { aspect-ratio: 16 / 9; }

/* 04 · Statement — centred display line ─────────────────── */
.pb-statement {
  text-align: center;
  max-width: 18ch;
  margin-inline: auto;
  font-size: var(--text-xl);
  line-height: 1.05;
}
/* the lines as written in the markup, wherever they run to */
.pb-statement--lines { max-width: none; white-space: nowrap; }

/* 05 · Split — one half pins while the other scrolls; when that
   runs out both leave together (plain CSS sticky, no JS). The
   pinned half is a 4:5 photo, or the text on a card in the client
   colour. Halves of the grid meet on --grid-center with no gutter,
   so pictures touch there, as on Lab.
   With a pinned photo the scrolling half opens with the text panel,
   exactly as tall as the photo: heading on its top edge, copy on
   its bottom edge. Only 4:5 pictures follow, in both variants, the
   same size as the pinned box. Every 4:5 box keeps half
   the grid width but never grows taller than the screen. ─── */
.pb-split {
  --pb-tall: calc(100vh - 2 * var(--pb-gap));
  display: grid;
  grid-template-columns: repeat(var(--lab-cols), minmax(0, 1fr));
  gap: var(--pb-gap) 0;
  align-items: start;
}
@supports (height: 100dvh) {
  .pb-split { --pb-tall: calc(100dvh - 2 * var(--pb-gap)); }
}
.pb-split > * { grid-column: span 6; }
.pb-split--sticky > .pb-split-media {
  position: sticky;
  top: var(--pb-gap);
}
/* Mirrored: the pinned half on the right */
.pb-split--reverse > .pb-split-media { order: 2; }
/* width: 100% keeps a capped box on the full half (a grid item with
   an aspect ratio would otherwise narrow to keep 4:5) */
.pb-split-media,
.pb-split-text,
.pb-split-col > .pb-photo {
  width: 100%;
  aspect-ratio: 4 / 5;
  max-height: var(--pb-tall);
}
/* a card in two layers: the background fills whatever box the screen
   gives, the artwork fits inside it, so nothing is ever cropped */
.pb-media--art { background-size: cover; background-position: center; }
.pb-media--art img { object-fit: contain; }
.pb-split-col {
  display: flex;
  flex-direction: column;
}
/* text beside a picture keeps Lab's inset off the centre line */
.pb-split-text {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--edge-y);
  padding-left: var(--pb-text-inset);
  padding-bottom: var(--pb-text-inset);   /* as much air below as beside it */
  box-sizing: border-box;
}
.pb-split--reverse .pb-split-text { padding-left: 0; padding-right: var(--pb-text-inset); }
.pb-split-text h3,
.pb-card h3 { font-size: var(--text-lg); line-height: 1.1; max-width: 18ch; }

/* Card variant: the pinned half carries the text on the client
   colour; the other half runs the same 4:5 pictures, card-sized. */
.pb-card {
  background: var(--pb-card);
  color: var(--pb-on-accent);
  padding: clamp(18px, 1.6vw, 28px);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--edge-y);
}
.pb-card h3 { max-width: 20ch; }
.pb-card .pb-body { color: inherit; max-width: 42ch; }
/* A picture that has to stay whole (a web screen, a page) sits on a
   light sheet inside its 4:5 box, as the pages in 08 do. */
.pb-photo--sheet { background: var(--pb-sheet); }
.pb-photo--sheet + .pb-photo--sheet { background: var(--pb-sheet-2, var(--pb-sheet)); }
.pb-photo--sheet img,
.pb-photo--sheet video { object-fit: contain; padding: var(--pb-sheet-inset); box-sizing: border-box; }

/* A transparent PNG that has to stay whole: 10 % white under it, the
   page shows through. */
.pb-media--tint { background: var(--pb-tint); }
.pb-media--tint img { object-fit: contain; padding: var(--pb-sheet-inset); box-sizing: border-box; }
.pb-media--clear { background: transparent; }   /* a vector straight on the page */
.pb-media--clear svg { display: block; width: 100%; height: 100%; }

/* 06 · Big quote and 07 · Small quote — a centred line or a few,
   free to sit anywhere on the page, each on its own screen ─ */
.pb-quote {
  text-align: center;
  margin-inline: auto;
}
.pb-quote--big { font-size: var(--text-2xl); line-height: 0.95; }
.pb-quote--small { font-size: var(--text-lg); line-height: 1.15; max-width: 30ch; }
/* closing quote: every sentence starts its own line and wraps balanced,
   so a narrow screen never leaves a single word on a line */
.pb-quote--lines { max-width: none; }
.pb-quote-line { display: block; text-wrap: balance; }

/* 06 as a filling claim: the block pins the claim mid-screen and
   scrolling lifts its letters one after another, from dim to full
   (blocks.js). More scroll here = more time for the cursor card. */
.pb-fill {
  --pb-fill-pin: calc(100dvh - var(--pb-space));
  height: calc(var(--pb-fill-pin) + var(--pb-fill-length));
  justify-content: flex-start;
}
.pb-fill-pin {
  position: sticky;
  top: calc((100dvh - var(--pb-fill-pin)) / 2);   /* mid-screen */
  height: var(--pb-fill-pin);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.pb-fill .pb-quote { letter-spacing: var(--pb-fill-spacing); }
.pb-fill .pb-quote--big { font-size: var(--pb-fill-size); }
.pb-fill-line { display: block; position: relative; }
.pb-fill-ink { display: block; }
.pb-fill-ghost { display: none; }
.pb-fill .pb-quote { transform: scale(calc(var(--pb-fill-grow) + (1 - var(--pb-fill-grow)) * var(--pb-fill-p, 1))); }
.pb-fill-char {
  --t: 1;
  display: inline-block;
  white-space: pre;
  opacity: calc(var(--pb-fill-from) + (1 - var(--pb-fill-from)) * var(--t));
  transform: translateY(calc((1 - var(--t)) * var(--pb-fill-rise)));
  will-change: transform, opacity;
}
/* wipe variant: each line stays as a ghost and the full text rises over it */
.pb-fill[data-pb-fill="wipe"] .pb-fill-ghost {
  display: block;
  position: absolute;
  inset: 0;
  opacity: var(--pb-fill-from);
}
.pb-fill[data-pb-fill="wipe"] .pb-fill-ink {
  clip-path: inset(calc(-0.2em + (1 - var(--l, 1)) * (100% + 0.4em)) -1em -0.2em -1em);
  transform: translateY(calc((1 - var(--l, 1)) * var(--pb-fill-rise)));
}
.pb-fill[data-pb-fill="wipe"] .pb-fill-char { opacity: 1; transform: none; }
/* focus variant: the whole claim sharpens and closes up as one */
.pb-fill[data-pb-fill="focus"] .pb-quote { letter-spacing: calc((1 - var(--pb-fill-p, 1)) * var(--pb-fill-track)); }
.pb-fill[data-pb-fill="focus"] .pb-fill-char {
  filter: blur(calc((1 - var(--t)) * var(--pb-fill-blur)));
  transform: none;
}

/* 07 as a call to action: the whole block is a link and sprays the
   homepage outro pills (blocks.js), with the project's words */
.pb-cta { color: inherit; text-decoration: none; }
.pb-trail { position: fixed; inset: 0 auto 0 0; width: calc(100vw - var(--navbar-width)); overflow: hidden; pointer-events: none; z-index: 5; }
.pb-trail-pill {
  position: absolute;
  top: 0;
  left: 0;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: var(--pb-pill-h);
  padding: 0 14px;
  border-radius: 999px;
  white-space: nowrap;
  background: var(--c, var(--pb-hl-1));
  color: var(--color-text-secondary);
  font-family: var(--font-mono);
  font-size: var(--pb-pill-text);
  letter-spacing: 0.02em;
  transform-origin: 50% 50%;
  will-change: transform, opacity;
}
.pb-trail-pill svg { flex: 0 0 auto; display: block; width: 13px; height: 13px; }

/* 08 · Horizontal scroll — the homepage showreel mechanic. Full
   bleed; the pin is one viewport tall and clips a single row: the
   lead (note + headline) followed by the catalog pages. On desktop
   blocks.js makes the section taller and slides the whole row left
   with the scroll, so the lead leaves first and the pages follow.
   The headline tail bleeds over the first page. Width as 01. */
.pb-teaser {
  margin-left: calc(var(--lab-edge-l) * -1);
  width: calc(100vw - var(--navbar-width));
}
.pb-teaser-pin {
  position: relative;
  overflow-x: auto;
  scrollbar-width: none;
}
.pb-teaser-pin::-webkit-scrollbar { display: none; }
.pb-teaser.is-driven .pb-teaser-pin {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}
/* the end padding (pin edge → last grid line) makes the last page
   stop on grid line 12 */
.pb-teaser-track {
  display: flex;
  gap: var(--pb-gap);
  width: max-content;
  height: 100%;
  min-height: clamp(520px, 72vh, 900px);
  padding-right: calc(100vw - var(--navbar-width) - var(--grid-right, calc(100vw - var(--navbar-width) - var(--lab-edge-r))));
}
.pb-teaser.is-driven .pb-teaser-track { will-change: transform; padding-block: var(--pb-gap); box-sizing: border-box; }
/* The same lead as the homepage strip (horizontal.css): same place, same type.
   It ends one gap short of grid line 8, so at rest the first
   page starts on that line; min-width 0 lets a long headline
   bleed over the page instead of widening the lead */
.pb-teaser-lead {
  flex: 0 0 calc(var(--lab-edge-l) + var(--pb-col) * 8 - var(--pb-gap));
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--edge-y);
  padding: 0 var(--edge-x) 0 var(--lab-edge-l);   /* note on the pages' top edge, title on their bottom edge */
  box-sizing: border-box;
}
/* note image spans two grid columns; the text keeps Lab's inset */
.pb-teaser-note { display: grid; grid-template-columns: calc(var(--pb-col) * 2) 1fr; gap: var(--pb-text-inset); max-width: calc(var(--pb-col) * 6); }
.pb-teaser-note .pb-media { aspect-ratio: 2 / 3; }
/* margin: the capitals sit on the edge, not the line box */
.pb-teaser-note p { font-size: var(--text-base); line-height: 1.3; margin: -0.19em 0 0; max-width: 24ch; }
.pb-teaser h2 {
  font-size: var(--text-2xl);
  line-height: 1.0;
  margin-bottom: -0.045em;   /* the descenders on the edge, not the line box */
  white-space: nowrap;
  color: var(--color-pure-white);
  /* the tail runs over the first page — difference keeps the
     overlapping letters readable on light paper */
  position: relative;
  z-index: 3;
  mix-blend-mode: difference;
}
/* catalog pages sit whole on a light sheet, never cropped */
.pb-sheet {
  flex: 0 0 52vw;
  background: var(--color-text-primary);
}
.pb-sheet img { object-fit: contain; padding: var(--pb-sheet-inset); box-sizing: border-box; }
/* a finished 4:5 photo stays whole: the panel takes the photo's shape
   at the strip's height */
.pb-sheet--full { flex: 0 0 auto; height: 100%; aspect-ratio: 4 / 5; background: none; }
.pb-sheet--full img { object-fit: cover; padding: 0; }
/* the same for a landscape 3:2 picture or video */
.pb-sheet--wide { flex: 0 0 auto; height: 100%; aspect-ratio: 3 / 2; background: none; }
.pb-sheet--wide img { object-fit: cover; padding: 0; }
/* A full-screen panel, as in the Work showreel on the homepage: a
   16:9 photo or video loop across the whole visible strip (the pin,
   up to the nav) and its full height, cropped to the centre. A video
   panel can carry the full film: the muted loop is the teaser, the
   film with sound loads only when played (preload none). Play button
   and crossfade as on the homepage (services.css, horizontal.css). */
.pb-panel {
  position: relative;
  flex: 0 0 calc(100vw - var(--navbar-width));
  overflow: hidden;
  background: var(--color-bg-primary);
}
.pb-teaser.is-driven .pb-panel { margin-block: calc(var(--pb-gap) * -1); }
.pb-panel img,
.pb-panel video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.pb-video .pb-full { z-index: 1; opacity: 0; visibility: hidden; transition: opacity var(--dur-2) ease; }
.pb-video .pb-preview { z-index: 2; }
.pb-video.is-playing .pb-full { z-index: 3; opacity: 1; visibility: visible; }
.pb-video.is-playing .pb-preview { opacity: 0; visibility: hidden; transition: opacity var(--dur-2) ease; }
.pb-play {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 4;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: clamp(72px, 7vw, 104px);
  height: clamp(72px, 7vw, 104px);
  border-radius: 50%;
  background: color-mix(in srgb, var(--color-pure-black) 45%, transparent);
  border: 1px solid color-mix(in srgb, var(--color-text-primary) 70%, transparent);
  color: var(--color-pure-white);
  cursor: pointer;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: background var(--dur-1) ease, border-color var(--dur-1) ease,
              transform var(--dur-2) var(--ease-out-expo),
              opacity var(--dur-1) ease;
}
.pb-play svg { width: 36%; height: 36%; fill: currentColor; margin-left: 6%; }
.pb-play:hover,
.pb-video:hover .pb-play {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--pb-on-accent);
  transform: translate(-50%, -50%) scale(1.08);
}
.pb-video.is-playing .pb-play { opacity: 0; pointer-events: none; }
/* right edge on the last grid line (the pin starts at x 0) */
.pb-round {
  position: absolute;
  top: 50%;
  right: calc(100% - var(--grid-right, calc(100vw - var(--navbar-width) - var(--lab-edge-r))));
  transform: translateY(-50%);
  z-index: 4;
  width: clamp(64px, 6vw, 96px);
  aspect-ratio: 1;
  border: 0;
  border-radius: 50%;
  background: var(--accent);
  color: var(--pb-on-accent);
  display: grid;
  place-items: center;
  cursor: pointer;
}
.pb-round svg { width: 46%; height: auto; }
/* The strip follows the scroll, and on desktop the cursor is the button
   (blocks.js): the round button only shows when a keyboard reaches it */
.pb-teaser.is-driven .pb-round { opacity: 0; pointer-events: none; }
.pb-teaser.is-driven .pb-round:focus-visible { opacity: 1; }
/* the cursor sits outside .pb: it takes the project's accent from the page */
#cursor, #cursor-label {
  --accent: var(--pb-page-accent, var(--color-bg-secondary));
  --cl-fg: var(--pb-page-on-accent, var(--color-pure-black));
}
/* the site's arrow cursor (shared.css .cursor.arrow: yellow disc), with
   the arrow turned to the right */
.cursor.arrow.pb-arrow-right .cursor-dot {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 80" fill="none"><line x1="20" y1="40" x2="58" y2="40" stroke="black" stroke-width="4" stroke-linecap="round"/><path d="M42 24 L58 40 L42 56" stroke="black" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>');
}

/* on a dark accent the arrow is white (data-arrow on .pb, blocks.js) */
[data-arrow="light"] .cursor.arrow .cursor-dot {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 80" fill="none"><line x1="40" y1="60" x2="40" y2="22" stroke="white" stroke-width="4" stroke-linecap="round"/><path d="M24 38 L40 22 L56 38" stroke="white" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>');
}
[data-arrow="light"] .cursor.arrow.pb-arrow-right .cursor-dot {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 80" fill="none"><line x1="20" y1="40" x2="58" y2="40" stroke="white" stroke-width="4" stroke-linecap="round"/><path d="M42 24 L58 40 L42 56" stroke="white" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>');
}

/* …and swings round to point back (blocks.js) */
.cursor.arrow.pb-arrow-right .cursor-dot { transition: rotate var(--dur-2) var(--ease-out-expo); }
.cursor.arrow.pb-arrow-right.pb-arrow-back .cursor-dot { rotate: 180deg; }

/* 09 · Gallery — reuses the Lab slider as-is (.lab-slider) ─ */
.pb-gallery .lab-slider-item .lab-ph { aspect-ratio: 2 / 3; }
/* arrows and photos always fit one screen: the photo is never wider than
   its 2:3 at the height that is left. A landscape photo keeps its shape:
   same height, 2.25 × the width */
.pb-gallery .lab-slider-track {
  --pb-slide: calc((100vw - var(--lab-edge-l) - var(--navbar-width) - var(--slider-peek) - 3 * var(--slider-gap)) / 3);
  --pb-slide-fit: calc((100dvh - var(--pb-gallery-bar, 0px) - var(--pb-gallery-head) - 2 * var(--pb-gap)) * 2 / 3);
}
.pb-gallery .lab-slider-item { flex-basis: min(var(--pb-slide), var(--pb-slide-fit)); }
.pb-gallery .lab-slider-item.is-wide { flex-basis: min(calc(var(--pb-slide) * 2.25), calc(var(--pb-slide-fit) * 2.25)); }
.pb-gallery .lab-slider-item.is-wide .lab-ph { aspect-ratio: 3 / 2; }
/* Ads keep their own shape, never cropped, at the height of the 2:3 photos:
   --ad-w is the width against a 2:3 slide. */
.pb-gallery .lab-slider-item.is-ad-45 { --ad-w: 1.2; --ad-shape: 4 / 5; }
.pb-gallery .lab-slider-item.is-ad-11 { --ad-w: 1.5; --ad-shape: 1 / 1; }
.pb-gallery .lab-slider-item.is-ad-916 { --ad-w: 0.84375; --ad-shape: 9 / 16; }
.pb-gallery .lab-slider-item.is-ad { flex-basis: min(calc(var(--pb-slide) * var(--ad-w)), calc(var(--pb-slide-fit) * var(--ad-w))); }
.pb-gallery .lab-slider-item.is-ad .lab-ph { aspect-ratio: var(--ad-shape); }
@media (max-width: 1024px) {
  .pb-gallery .lab-slider-track {
    --pb-slide: calc((100vw - var(--lab-edge-l) - var(--navbar-width) - var(--slider-peek) - 2 * var(--slider-gap)) / 2);
  }
}
/* arrows as on Lab: white, grey only at a dead end (blocks.js) */
.pb-gallery .lab-slider-btn,
.pb-gallery .lab-slider-btn.is-prev {
  opacity: 1;
  transition: opacity var(--dur-2) ease, color var(--dur-1) ease, transform var(--dur-1) ease;
}
.pb-gallery .lab-slider-btn.is-disabled {
  opacity: 0.4;
  cursor: default;
  pointer-events: none;
}
.pb-gallery .lab-ph img,
.pb-gallery .lab-ph video { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Reels that play with sound: teaser and full reel on top of each other. */
.pb-gallery .pb-video { cursor: pointer; }
.pb-gallery .pb-video video { position: absolute; inset: 0; }
/* no placeholder stripes over real photos */
.pb-gallery .lab-ph::before { content: none; }

/* 10 · More projects — four other projects as 4:5 pictures, three
   grid columns each, touching as on Lab, no captions. Never the current project;
   the one seen just before goes first, like a Back button
   (blocks.js). Title on the top edge of the screen, cards on the
   bottom edge. ─────────────────────────────────────────── */
.pb-more { border-top: 1px solid var(--line); padding-top: var(--frame-y); justify-content: flex-start; }
/* last block: at the end of the page its rule sits as far from the
   top of the screen as its left end is from the left edge */
.pb-more { --pb-more-h: calc(100dvh - var(--lab-edge-l)); }
.pb-more.pb-screen { min-height: var(--pb-more-h); }
.pb-more h2 { font-size: var(--text-2xl); margin-bottom: var(--pb-more-gap); }
.pb-more-head {
  display: flex;
  justify-content: flex-end;
  margin: auto 0 var(--frame-y);
  padding-top: var(--edge-y);
}
.pb-more-head a {
  color: var(--fg);
  text-decoration: none;
  font-size: var(--text-base);
  display: inline-flex;
  gap: 14px;
  align-items: center;
}
.pb-more-head svg { width: 26px; height: 26px; }
.pb-more-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  column-gap: 0;
}
.pb-more-grid > li:nth-child(n+5) { display: none; }
.pb-more-grid a { position: relative; display: block; color: var(--fg); text-decoration: none; }
/* the "VIEW …" pill at the cursor takes a highlighter colour per card,
   by position, so four cards always show four colours: the homepage
   outro pill palette. blocks.js hands it to the shared cursor label
   (data-cl-bg). */
.pb-more-grid > li:nth-child(4n+1) { --pb-hl: var(--pb-hl-1); }
.pb-more-grid > li:nth-child(4n+2) { --pb-hl: var(--pb-hl-2); }
.pb-more-grid > li:nth-child(4n+3) { --pb-hl: var(--pb-hl-3); }
.pb-more-grid > li:nth-child(4n+4) { --pb-hl: var(--pb-hl-4); }
.pb-more-grid .pb-media {
  aspect-ratio: 4 / 5;
  width: 100%;                             /* lower, never narrower: the columns stay on the grid */
  /* on a low, wide screen the cards give way, so the rule stays put:
     the block minus title, the air under it, its offsets and the All
     projects row */
  max-height: calc(var(--pb-more-h) - var(--text-2xl) - var(--pb-more-gap) - 2 * var(--frame-y) - var(--edge-y) - var(--pb-more-row));
}

/* Cursor card with the curtain wave ("peřina") — case pages only.
   A square trails the cursor over the page. Each block marked
   data-pb-wave has its own picture in it; where two such blocks meet,
   a horizontal line splits the card into the picture above and the
   picture below (blocks.js sets each layer's clip). Over other blocks
   it shrinks away, entering a card block it grows back.
   Mouse only. */
.pb-cursor-card {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 50;
  width: var(--pb-cursor-size);
  aspect-ratio: 1;
  border-radius: var(--radius-card);
  overflow: hidden;
  pointer-events: none;
  /* out: shrinks away; in: grows from nothing at the cursor while the
     picture zooms out */
  opacity: 0;
  scale: 0;
  transition: scale var(--pb-cursor-out) var(--ease-in-out), opacity var(--pb-fade) ease var(--dur-1);
  will-change: transform;
}
.pb-cursor-card.is-on {
  opacity: 1;
  scale: 1;
  transition: scale var(--pb-cursor-in) var(--ease-out-expo), opacity var(--pb-fade) ease;
}
.pb-cursor-layer > * { scale: 1.6; transition: scale var(--pb-cursor-out) var(--ease-in-out); }
.pb-cursor-card.is-on .pb-cursor-layer > * { scale: 1; transition: scale var(--dur-5) var(--ease-out-expo); }
@media (prefers-reduced-motion: reduce) {
  .pb-fill { height: auto; }
  .pb-fill-pin { position: static; height: auto; }
  .pb-cursor-card, .pb-cursor-card.is-on,
  .pb-cursor-layer > *, .pb-cursor-card.is-on .pb-cursor-layer > * { transition: opacity var(--pb-fade) ease; scale: 1; }
}
.pb-cursor-layer { position: absolute; inset: 0; clip-path: inset(0 0 100% 0); }
.pb-cursor-layer img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pb-cursor-layer img:not([src]) { visibility: hidden; }
/* the WebGL curtain-wave layer (blocks.js) sits over the fallback img */
.pb-wave { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.has-wave > img { visibility: hidden; }
@media (hover: none) {
  .pb-cursor-card { display: none; }
}

/* Review aid — block names show with ?labels in the URL, and
   always in the block catalog */
.pb-label { display: none; }
body.pb-show-labels .pb-label,
.pb-catalog .pb-label {
  display: block;
  position: absolute;
  top: -22px;
  left: 0;
  z-index: 9;
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}
body.pb-show-labels .pb-hero .pb-label,
.pb-catalog .pb-hero .pb-label { top: 8px; left: var(--lab-edge-l); }
/* readable over light placeholders too */
.pb-catalog .pb-label { padding: 3px 6px; background: var(--bg); }

/* ── Mobile ─────────────────────────────────────────────── */
@media (max-width: 760px), (max-width: 1024px) and (orientation: portrait) {
  .pb { --pb-space: var(--lab-rhythm-tight); }
  /* the nav is a bottom bar here (--navbar-width is 100vw) */
  .pb-hero, .pb-teaser { width: auto; margin-right: calc(var(--lab-edge-r) * -1); }
  .pb-desc { grid-template-columns: 1fr; }
  .pb-desc .pb-body { grid-column: 1; }
  .pb-window .pb-media { aspect-ratio: 1; }
  /* a wide piece that must stay whole keeps its shape on a phone */
  .pb-window .pb-media--wide { aspect-ratio: 1404 / 640; }
  .pb-statement { font-size: clamp(30px, 8.6vw, 48px); }
  .pb-statement--lines { font-size: 6.2vw; }   /* the longest line stays inside a phone */
  .pb-split { grid-template-columns: 1fr; }
  .pb-split > * { grid-column: auto; }
  .pb-split--sticky > .pb-split-media { position: relative; top: auto; }
  .pb-split--reverse > .pb-split-media { order: 0; }
  /* text panels keep the 4:5 of the pictures: heading on top, copy at
     the bottom; a long text may only make its panel taller */
  .pb-split .pb-split-text { padding: 0 0 var(--pb-gap); }
  /* claims and windows take the height they need on a phone: a full
     screen would leave a big hole between blocks */
  .pb-screen:not(.pb-intro):not(.pb-more) { min-height: 0; }
  .pb-screen:not(.pb-intro):not(.pb-more):not(.pb-window) { min-height: var(--pb-claim-mobile); }
  /* 14vw keeps a long single word ("photography") inside a 320 px phone */
  .pb-quote--big,
  .pb-fill .pb-quote--big { font-size: clamp(44px, 14vw, 96px); }
  .pb-quote--small { font-size: clamp(24px, 6.4vw, 34px); }
  /* driven by the scroll here too: the pin is as tall as the row (blocks.js)
     and sits centred above the bottom bar, in steady dvh units */
  .pb-teaser.is-driven .pb-teaser-pin {
    --pb-strip-bar: var(--navbar-height-mobile, 64px);
    height: var(--pb-strip-pin, 100dvh);
    top: calc((100dvh - var(--pb-strip-bar) - var(--pb-strip-pin, 100dvh)) / 2);
  }
  .pb-teaser-track { min-height: 0; padding-left: var(--lab-edge-l); padding-right: var(--lab-edge-r); }
  .pb-teaser.is-driven .pb-teaser-track {
    align-items: center;
    padding-block: var(--pb-gap);
  }
  .pb-teaser.is-driven .pb-panel { margin-block: 0; }
  .pb-teaser-lead { flex-basis: var(--pb-strip-mobile); height: var(--pb-strip-h-mobile); padding: 0; }
  .pb-teaser-note { grid-template-columns: 30% 1fr; gap: var(--pb-gap); max-width: 640px; }
  .pb-teaser h2 { margin-bottom: 0; font-size: var(--pb-title-mobile); line-height: 0.95; letter-spacing: -0.035em; }
  .pb-sheet { flex-basis: var(--pb-strip-mobile); aspect-ratio: 4 / 5; }
  .pb-sheet--full { flex-basis: var(--pb-strip-mobile); height: auto; }
  .pb-sheet--wide { flex-basis: auto; height: var(--pb-strip-h-mobile); aspect-ratio: 3 / 2; align-self: center; }
  .pb-panel { flex-basis: var(--pb-strip-mobile); aspect-ratio: 16 / 9; align-self: center; }
  .pb-round { top: auto; bottom: var(--edge-y); transform: none; right: var(--lab-edge-r); }
  .pb-more {
    --pb-more-h: calc(100dvh - var(--lab-edge-l) - var(--navbar-height-mobile, 64px) - 24px);
    --pb-more-card: calc(var(--pb-more-h) - var(--pb-title-mobile) - var(--pb-more-gap) - 2 * var(--frame-y) - var(--edge-y) - var(--pb-more-row));
  }
  .pb-more h2 { font-size: var(--pb-title-mobile); }
  .pb-more-grid .pb-media { max-height: var(--pb-more-card); }
  /* cards swipe sideways, sized as the Lab slider on mobile */
  .pb-more-grid {
    display: flex;
    gap: var(--pb-gap);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
  }
  .pb-more-grid::-webkit-scrollbar { display: none; }
  .pb-more-grid > li { flex: 0 0 min(80%, calc(var(--pb-more-card) * 0.8)); scroll-snap-align: start; }
  /* No hover on a phone: the pill the cursor brings on a desktop sits in the
     middle of every card, and says what is behind it or that nothing is yet. */
  .pb-more-grid a::after {
    content: attr(data-cursor-label);
    position: absolute;
    top: 50%;
    left: 50%;
    z-index: 2;
    transform: translate(-50%, -50%);
    padding: 0.55em 1.25em;
    border-radius: 999px;
    background: var(--pb-hl);
    color: var(--color-text-secondary);
    font-family: var(--font-mono);
    font-size: var(--text-micro);
    line-height: 1.2;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    white-space: nowrap;
    pointer-events: none;
  }
  .pb-more-grid a:not([href])::after { background: var(--color-pure-white); }
  /* Same fix the Lab page ships: no side navbar on mobile, so the
     slider must not break out by the (100vw) navbar width. */
  .pb-gallery.lab-slider { margin-right: 0; }
  .pb-gallery .lab-slider-head,
  .pb-gallery .lab-slider-track { padding-right: 0; }
  .pb-gallery .lab-slider-track { --pb-gallery-bar: var(--navbar-height-mobile, 64px); }
  .pb-gallery .lab-slider-item { flex: 0 0 min(var(--pb-slide-mobile), var(--pb-slide-fit)); }
  .pb-gallery .lab-slider-item.is-wide { flex-basis: min(calc(var(--pb-slide-mobile) * 2.25), calc(var(--pb-slide-fit) * 2.25)); }   /* as tall as the 2:3 photos */
  .pb-gallery .lab-slider-item.is-ad { flex-basis: min(calc(var(--pb-slide-mobile) * var(--ad-w)), calc(var(--pb-slide-fit) * var(--ad-w))); }
}
