/* ============================================================
   bgfilms — Bryan Gomez, photography & videography
   Type: Inter for the micro UI, Space Grotesk for display.
   Swap the two --f-* vars to change the whole typographic voice.
   ============================================================ */

:root{
  --bg:#ececec;
  --ink:#1e1e1e;
  --ink-50:rgba(31,31,31,.52);
  --ink-20:rgba(31,31,31,.18);
  --paper:#fff;
  --white-50:rgba(255,255,255,.5);
  --edge:rgba(31,31,31,.14);
  --accent:#e0281c;
  --grain: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='.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.34'/%3E%3C/svg%3E");
  --r-card:6px;      /* corner radius on the deck's media */
  --r-hero:9px;

  --f-ui:"Inter",-apple-system,"Helvetica Neue",Arial,sans-serif;
  --f-display:"Space Grotesk","Inter",-apple-system,sans-serif;

  --pad:20px;
  --micro:10px;
  --micro-lh:13px;
  --ease:cubic-bezier(.16,1,.3,1);
}

*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
html{-webkit-text-size-adjust:100%}

body{
  background-color:var(--bg);
  color:var(--ink);
  font-family:var(--f-ui);
  font-size:var(--micro);
  line-height:var(--micro-lh);
  letter-spacing:.1px;
  font-weight:500;
  overflow:hidden;
  overscroll-behavior:none;
  -webkit-font-smoothing:antialiased;
}

img{display:block;max-width:100%}
button{font:inherit;letter-spacing:inherit;color:inherit;background:none;border:0;cursor:pointer}
a{color:inherit;text-decoration:none}
ul{list-style:none}
sup{font-size:.5em;vertical-align:super}

.lbl{color:var(--ink-50)}

/* ── grain ─────────────────────────────────────────────────── */
/* Texture belongs to the paper, not to the pictures. The grain is painted
   into the ground itself — see the .view--* rules, which multiply a noise
   tile into the background colour — so photographs and films sit on top of
   it completely untouched. It used to ride over everything at z-60, which
   tinted every frame on the site.

   It has to be part of the ground's own paint rather than a layer above or
   below it: the deck counter and meta are white type in `difference`, and
   they need an opaque backdrop to invert against. Make the views
   transparent to reveal a grain layer underneath and the counter turns
   white on white. */

/* ── preloader ─────────────────────────────────────────────── */
.preloader{position:fixed;inset:0;z-index:90;pointer-events:none}
.preloader__panel{
  position:absolute;inset:0;background:#000;
  transform:translate3d(0,0,0);will-change:transform;
}
.preloader__edge{
  position:absolute;left:0;top:0;height:100%;width:0;
  display:flex;flex-direction:column;justify-content:space-between;
  align-items:flex-start;padding:var(--pad) 0 var(--pad) 18px;
  color:#fff;white-space:nowrap;
}
.preloader__word{font-family:var(--f-display);font-size:19px;line-height:1;letter-spacing:.19px}
.preloader__count{font-variant-numeric:tabular-nums}
.preloader.is-done{opacity:0;transition:opacity .35s .5s linear}

/* ── page-transition curtain ───────────────────────────────── */
.curtain{
  position:fixed;inset:0;z-index:80;background:#000;pointer-events:none;
  transform:scaleY(0);transform-origin:100% 100%;
}
.curtain.is-in{transform:scaleY(1);transition:transform .5s var(--ease)}
.curtain.is-out{transform:scaleY(0);transform-origin:100% 0%;transition:transform .5s var(--ease)}

/* ── HUD ───────────────────────────────────────────────────── */
.hud{color:#fff}
.hud > *{position:fixed;z-index:40;mix-blend-mode:difference}

.hud__logo{
  left:var(--pad);top:var(--pad);
  display:flex;gap:6px;align-items:flex-start;
  /* extra room on the right so the frame clears the vertical stamp lines */
  padding:11px 26px 11px 12px;
  border:3px solid var(--accent);
  /* A solid accent has to opt out of the difference blend the rest of the
     chrome runs on — inverted against the light ground, red comes out cyan.
     Nothing ever covers this corner, so plain dark type is safe here. */
  mix-blend-mode:normal;
  color:#000;
}
.hud__logo .hud__stamp{color:rgba(0,0,0,.5)}
/* the vertical stamp does not fit a phone; a single line under the mark does */
.hud__tag{display:none}
.hud__mark{
  writing-mode:vertical-rl;transform:rotate(180deg);
  font-family:var(--f-display);font-weight:500;
  font-size:34px;line-height:.86;letter-spacing:-.02em;
}
.hud__stamp{
  writing-mode:vertical-rl;transform:rotate(180deg);
  display:flex;gap:9px;color:var(--ink-50);font-size:8px;letter-spacing:.3px;
}

.hud__nav{left:198px;top:var(--pad)}
.menu{margin-top:24px;display:grid}
.menu__item{
  position:relative;display:flex;align-items:center;gap:8px;
  font-family:var(--f-display);font-size:19px;line-height:19px;letter-spacing:.19px;
  padding:0;height:19px;
}
.menu__arrow{
  font-style:normal;width:0;opacity:0;overflow:hidden;
  transition:width .35s var(--ease),opacity .25s linear;
}
.menu__item:hover .menu__arrow,.menu__item.is-active .menu__arrow{width:18px;opacity:1}
.menu__item span{transition:opacity .2s linear}
.menu:hover .menu__item:not(:hover) span{opacity:.4}

.hud__focus{left:562px;top:var(--pad);display:grid;gap:0;max-width:150px}

.hud__clock{left:732px;top:var(--pad);display:grid;gap:0}
.hud__mail{right:var(--pad);top:var(--pad);display:flex;gap:10px}
.hud__mail a{text-decoration:underline;text-underline-offset:2px;text-decoration-thickness:.5px}

/* The chrome is white type in `difference` blend: it reads dark over the
   light ground and light over imagery, without ever being recoloured. */
.hud .lbl,.foot .lbl,.hud__stamp{color:var(--white-50)}


/* ── footer chrome ─────────────────────────────────────────── */
.foot{color:#fff}
.foot > *{position:fixed;bottom:var(--pad);z-index:40;mix-blend-mode:difference}
.foot__reel{right:var(--pad)}
.foot__scroll{left:var(--pad);animation:bob 2.4s var(--ease) infinite}
@keyframes bob{0%,100%{transform:translateY(0);opacity:.5}50%{transform:translateY(3px);opacity:1}}
.foot__reel{display:flex;align-items:center;gap:7px}
.foot__reel svg{width:7px;height:9px}
.foot__reel:hover{opacity:.6}

/* ── stage / views ─────────────────────────────────────────── */
.stage{position:fixed;inset:0;z-index:10}
.view{position:absolute;inset:0;opacity:0;visibility:hidden;transition:opacity .4s linear .05s}
.view.is-on{opacity:1;visibility:visible}

/* ── DECK ──────────────────────────────────────────────────── */
.view--deck{background-color:var(--bg);background-image:var(--grain);background-blend-mode:multiply}   /* textured ground the overlay type inverts against */
.deck{
  position:absolute;inset:0;
  perspective:1600px;
  perspective-origin:50% 50%;   /* tilt only — the ribbon's spacing is set in JS */
  transform-style:preserve-3d;
}
.card{
  position:absolute;
  --cw:clamp(205px,20vw,290px);
  left:50%;top:50%;              /* the ribbon passes through the centre */
  width:var(--cw);
  aspect-ratio:3/2;              /* photographs, not video frames */
  margin-left:calc(var(--cw) / -2);
  margin-top:calc(var(--cw) / -3);
  transform-origin:50% 50%;
  will-change:transform,opacity;
  background:#111;
  box-shadow:0 12px 30px rgba(0,0,0,.20);
  /* the radius rides the card's own scale, so it stays proportional as
     cards recede up the ribbon */
  border-radius:var(--r-card);
  overflow:hidden;
}
.card img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.card::after{
  content:"";position:absolute;inset:0;z-index:2;
  background:linear-gradient(115deg,rgba(0,0,0,.10),rgba(0,0,0,0) 62%);
}

.deck__hud{position:absolute;inset:0;pointer-events:none;color:#fff}
.deck__hud > *{pointer-events:auto}

/* Meta sits on the front card, at the coordinates the original uses. */
.deck__meta{
  position:absolute;inset:0;pointer-events:none;
  transition:opacity .4s linear;
}
.mrow{
  position:absolute;display:grid;grid-template-columns:var(--k) auto;
  color:#000;
}
.mrow .lbl{color:rgba(0,0,0,.58)}
.mrow .val{white-space:pre-line}
.mrow--a1{left:20px; top:43.4%; --k:70px}
.mrow--a2{left:20px; top:50.4%; --k:70px}
.mrow--b1{left:198px;top:43.4%; --k:96px}

.deck__index{
  position:absolute;left:198px;bottom:6px;text-align:left;
  display:flex;align-items:flex-start;
  mix-blend-mode:difference;color:#fff;
}
.deck__index > .lbl{width:83px;flex:0 0 auto;color:rgba(255,255,255,.75)}
.deck__total{width:auto;padding-left:54px}
.deck__no{
  font-family:var(--f-ui);font-weight:400;
  font-size:clamp(80px,12.5vw,180px);line-height:.85;letter-spacing:-.04em;
  font-variant-numeric:tabular-nums;width:183px;flex:0 0 auto;
}
/* ── the hero ─────────────────────────────────────────────────
   The active photograph, flat and dead centre, at its own
   proportions inside a fixed box — so portrait and landscape
   both sit still while the ribbon moves around them. Two
   stacked layers cross-fade on change. */
.hero{
  position:absolute;left:50%;top:50%;
  transform:translate(-50%,-50%);
  width:min(38vw,545px);height:min(50vh,455px);
  cursor:pointer;
  /* the centring translate has to be restated on hover or the zoom
     would drop it back to the top-left corner */
  transition:transform .55s var(--ease);
}
.hero__layer{
  /* left/top/width/height are set in JS to the picture's fitted rect, so
     the box is the photograph and nothing else */
  position:absolute;overflow:hidden;
  border-radius:var(--r-hero);
  opacity:0;
  /* opacity and transform are driven inline as a picture slides in */
  transition:opacity .38s linear, transform .6s var(--ease);
  will-change:transform,opacity;
  box-shadow:0 22px 46px rgba(0,0,0,.20);
}
.hero__layer img,.hero__layer video{
  width:100%;height:100%;object-fit:cover;display:block;
  transition:transform .75s var(--ease);
}
/* a film covers its own poster, so the frame never blinks on swap */
.hero__layer video{position:absolute;inset:0;animation:heroFade .45s linear}
@keyframes heroFade{from{opacity:0}to{opacity:1}}
/* the picture zooms inside its own frame; the frame itself holds still */
.hero:hover .hero__layer.is-on img,
.hero:hover .hero__layer.is-on video{transform:scale(1.07)}

/* ── the album rail ───────────────────────────────────────────
   The three albums, stacked; the one the ribbon is inside sits
   centred and full strength while the others hold back. */
.rail{
  --rail-step:176px;
  position:absolute;right:8vw;top:50%;
  width:min(25vw,300px);height:0;
}
.rail__track{
  display:grid;grid-auto-rows:var(--rail-step);
  transition:transform .75s var(--ease);
}
.rail__item{
  display:grid;gap:7px;justify-items:center;text-align:center;align-content:center;
  padding:0 4px;color:var(--ink);
  opacity:.24;transition:opacity .55s var(--ease);
}
.rail__item.is-active{opacity:1}
.rail__name{
  font-family:var(--f-display);font-size:clamp(17px,1.7vw,25px);
  line-height:1.1;letter-spacing:-.01em;
}
.rail__desc{color:var(--ink-50);line-height:16px;max-width:34ch}
.rail__item:not(.is-active):hover{opacity:.55}

/* ── INDEX ─────────────────────────────────────────────────── */
.view--index{background-color:var(--bg);background-image:var(--grain);background-blend-mode:multiply}
.index__head{
  position:absolute;left:198px;right:var(--pad);top:206px;
  display:flex;gap:24px;align-items:center;
}
.index__close{margin-left:auto}
.index__close:hover{opacity:.55}
.index__scroll{position:absolute;inset:236px 0 44px;overflow-y:auto;overflow-x:hidden;scrollbar-width:none}
.index__scroll::-webkit-scrollbar{display:none}
.index__rows{padding:0 var(--pad) 40px 198px}

.row{
  display:flex;align-items:flex-start;gap:34px;
  padding:16px 0 15px;border-top:.5px solid var(--edge);
  position:relative;text-align:left;width:100%;
}
.row:hover{color:var(--ink)}
.row__id{position:absolute;left:-38px;top:19px;color:var(--ink-50);font-variant-numeric:tabular-nums}
.row__name{
  font-family:var(--f-display);font-size:10px;line-height:11px;letter-spacing:-.1px;
  min-width:112px;flex:0 0 auto;
}
.row__slug,.row__date{flex:0 0 auto;color:var(--ink-50)}
.ph{font-style:normal;vertical-align:super;font-size:.85em;opacity:.8}
.row__date{min-width:118px}
.row__awards{min-width:150px}
.row__awards{flex:0 0 auto;min-width:150px;white-space:pre-line}
.row__roles{flex:0 0 auto;min-width:96px;white-space:pre-line;color:var(--ink-50)}
.row__cat{flex:0 0 auto;min-width:96px}
.row--collection{padding:30px 0 29px;gap:40px;align-items:flex-start}
.row--collection .row__id{top:33px}
.row--collection .row__name{
  font-family:var(--f-display);font-size:19px;line-height:20px;letter-spacing:.19px;min-width:230px;
}
.row--collection .row__slug{min-width:130px}
.row--collection .row__date{min-width:80px}
.row--collection .row__desc{flex:1 1 340px;line-height:16px;max-width:64ch}
.row__desc{flex:1 1 260px;min-width:200px;color:var(--ink-50)}
.row::before{
  content:"";position:absolute;left:0;right:0;top:0;height:100%;
  background:var(--ink);transform:scaleY(0);transform-origin:50% 100%;
  transition:transform .35s var(--ease);z-index:-1;
}
.row:hover::before{transform:scaleY(1)}
.row{transition:color .25s linear;isolation:isolate}
.row:hover,.row:hover .lbl,.row:hover .row__slug,.row:hover .row__date,
.row:hover .row__roles,.row:hover .row__desc{color:var(--bg)}

.index__peek{
  position:fixed;z-index:35;width:170px;aspect-ratio:3/2;overflow:hidden;
  pointer-events:none;opacity:0;transform:translate3d(-50%,-50%,0) scale(.9);
  transition:opacity .25s linear,transform .35s var(--ease);
}
.index__peek.is-on{opacity:1;transform:translate3d(-50%,-50%,0) scale(1)}
.index__peek img{width:100%;height:100%;object-fit:cover}

/* ── DOC views (about / playground / contact) ──────────────── */
.view--doc{background-color:var(--bg);background-image:var(--grain);background-blend-mode:multiply;overflow-y:auto;scrollbar-width:none}
.view--doc::-webkit-scrollbar{display:none}
.doc{padding:214px var(--pad) 90px 198px;max-width:1200px}
.doc__lead{
  font-family:var(--f-display);font-weight:400;
  font-size:clamp(22px,3.1vw,44px);line-height:1.06;letter-spacing:-.02em;
  max-width:19ch;text-wrap:balance;
}
.doc__lead em{font-style:normal;color:var(--ink-50)}
.doc__grid{
  margin-top:90px;display:grid;gap:38px 34px;
  grid-template-columns:repeat(auto-fit,minmax(190px,1fr));max-width:940px;
}
.doc__grid p{margin-top:8px;max-width:34ch}

.doc__mail{
  font-family:var(--f-display);font-size:clamp(24px,4.6vw,64px);line-height:1;letter-spacing:-.03em;
}
.doc__mail:hover{opacity:.55}
.doc__social{display:flex;flex-wrap:wrap;gap:22px;margin-top:10px}
.doc__social a{text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:.5px}
.doc__social a:hover{opacity:.5}
.doc__note{margin-top:40px}

/* A gallery drops the column's left indent so the pictures sit on the
   centre of the screen; the heading keeps the indent on its own. */
.doc--gal{--gal-indent:178px;padding:214px var(--pad) 90px;max-width:none}
.gal__head{margin-left:var(--gal-indent);will-change:opacity,transform}
.gal__eyebrow{display:block;margin-bottom:18px}
.gal__title{max-width:none}
.gal__desc{margin-top:22px;max-width:58ch;line-height:17px;color:var(--ink-50)}
.gal__title{margin-left:-2px}

/* one clean column of large frames, the way the galleries read before */
/* Two frames abreast, in reading order — 01 beside 02, not beside 06,
   which is what CSS columns would have given. Rows take the height of the
   taller frame and the shorter one just ends early; with numbered frames,
   keeping the sequence right is worth the ragged bottoms. */
.stack{
  margin:76px auto 0;max-width:920px;
  display:grid;grid-template-columns:repeat(2,1fr);gap:34px 30px;
  align-items:start;
}
.stack__fig{position:relative;overflow:hidden;cursor:pointer}
.stack__fig img{
  width:100%;height:auto;display:block;
  transition:transform .8s var(--ease)}
.stack__fig:hover img{transform:scale(1.02)}
.stack__num{position:absolute;left:12px;bottom:10px;color:#fff;mix-blend-mode:difference}
/* a film tile earns a play mark and keeps its colour — it is motion work,
   not a still, and the greyscale treatment would misrepresent it */
.stack__fig--video img{filter:none}
.stack__play{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:54px;height:54px;border-radius:50%;
  display:grid;place-items:center;color:#fff;
  background:rgba(20,20,20,.42);backdrop-filter:blur(3px);
  border:1px solid rgba(255,255,255,.5);
  transition:transform .4s var(--ease),background .3s linear;
}
.stack__play svg{width:13px;height:15px;margin-left:3px}
.stack__fig--video:hover .stack__play{transform:translate(-50%,-50%) scale(1.12);background:rgba(20,20,20,.62)}
.stack__cap{
  position:absolute;right:12px;bottom:10px;color:#fff;
  text-shadow:0 1px 3px rgba(0,0,0,.6);
}

/* ── About ─────────────────────────────────────────────────────
   A centred reading column with the photographs hung in the two
   gutters. The figures are taken out of flow and given a `top` in
   JS, anchored to the paragraph they belong beside — so they sit
   in the margin instead of punching a hole in the text. */
.doc--about{
  --ab-col:620px;
  position:relative;
  padding:214px var(--pad) 140px;max-width:none;
}
.doc--about > :not(.ab__fig){width:min(var(--ab-col),100%);margin:0 auto}
.ab__top{margin-bottom:74px}

.ab__hook{
  font-family:var(--f-display);font-weight:400;
  font-size:clamp(28px,4vw,54px);line-height:1.04;letter-spacing:-.025em;
  margin-bottom:26px;
}
/* the degree gets crossed out — the rule draws itself on arrival */
.ab__code{
  font-family:"IBM Plex Mono",ui-monospace,monospace;
  font-size:.68em;letter-spacing:-.02em;text-decoration:none;
  position:relative;white-space:nowrap;
}
.ab__code::after{
  content:"";position:absolute;left:-.04em;right:-.04em;top:52%;height:2px;
  background:currentColor;transform:scaleX(0);transform-origin:0 50%;
  transition:transform .8s var(--ease) .5s;
}
.ab__top.is-in .ab__code::after{transform:scaleX(1)}
.ab__cam{font-style:normal;color:var(--accent)}

.ab__lead{font-size:clamp(15px,1.4vw,19px);line-height:1.62;color:var(--ink-50)}
.ab__p{font-size:clamp(15px,1.32vw,18px);line-height:1.72;margin-bottom:28px}
.ab__aside{
  margin:10px 0 32px;
  font-family:var(--f-display);font-size:clamp(21px,2.3vw,31px);line-height:1.24;
}
.ab__h{
  font-family:var(--f-display);font-weight:400;text-transform:uppercase;
  font-size:clamp(14px,1.4vw,19px);letter-spacing:.07em;
  margin:92px auto 30px;padding-top:18px;border-top:1px solid var(--edge);
}
.ab__end{margin-top:190px;padding-top:30px;border-top:1px solid var(--edge)}
.ab__end p{font-family:var(--f-display);font-size:clamp(20px,2.5vw,34px);line-height:1.22}
.ab__end p:last-child{color:var(--accent)}

/* arrivals */
.ab__p,.ab__aside,.ab__h,.ab__end,.ab__top{
  opacity:0;transform:translateY(16px);
  transition:opacity .6s var(--ease),transform .7s var(--ease);
}
.ab__p.is-in,.ab__aside.is-in,.ab__h.is-in,.ab__end.is-in,.ab__top.is-in{
  opacity:1;transform:none;
}

/* the photographs, hung either side of the column */
.ab__fig{
  position:absolute;top:0;margin:0;
  width:clamp(180px,20vw,290px);
  will-change:transform;
}
.ab__fig--right{left:calc(50% + 340px)}
.ab__fig--left {right:calc(50% + 340px)}
.ab__inner{
  cursor:pointer;background:var(--paper);padding:9px 9px 0;
  box-shadow:0 16px 40px rgba(0,0,0,.14);
  transform:rotate(var(--tilt));
  opacity:0;
  transition:opacity .7s var(--ease),transform .8s var(--ease),box-shadow .4s linear;
}
.ab__fig.is-in .ab__inner{opacity:1}
.ab__inner:hover{transform:rotate(0deg) scale(1.035);box-shadow:0 26px 60px rgba(0,0,0,.22)}
.ab__inner img{width:100%;height:auto;display:block}
.ab__inner figcaption{padding:9px 2px 10px}

/* ── deep-scroll: the chrome gets out of the way ───────────────
   Opacity goes on each fixed child, never on .hud or .foot. Those
   wrappers are deliberately unpositioned so their children blend
   against the page; giving a wrapper opacity makes it a stacking
   context and the difference blend collapses. */
.hud > *,.foot > *{transition:opacity .35s linear}
body.is-deep .hud > *,body.is-deep .foot > *{opacity:0;pointer-events:none}

.totop{
  position:fixed;right:var(--pad);bottom:var(--pad);z-index:45;
  display:flex;align-items:center;gap:9px;
  padding:11px 16px;border-radius:999px;
  background:var(--paper);color:var(--ink);
  border:1px solid var(--ink-20);
  box-shadow:0 10px 26px rgba(0,0,0,.10);
  opacity:0;transform:translateY(12px);pointer-events:none;
  transition:opacity .3s var(--ease),transform .45s var(--ease),
             background .2s linear,color .2s linear,border-color .2s linear;
}
.totop.is-on{opacity:1;transform:none;pointer-events:auto}
.totop:hover{background:var(--ink);color:var(--bg);border-color:var(--ink)}
.totop svg{width:9px;height:11px;flex:0 0 auto}

/* ── contact dialog ────────────────────────────────────────────
   A panel rather than a page: the form is the point, so it opens
   over whatever you were looking at instead of taking you away. */
body.is-contact .hud > *,body.is-contact .foot > *{opacity:0;pointer-events:none}
.cx{
  position:fixed;inset:0;z-index:78;background:rgba(10,10,10,.62);
  display:grid;place-items:center;padding:28px var(--pad);
  overflow-y:auto;
}
.cx[hidden]{display:none}
.cx__panel{
  position:relative;width:min(560px,100%);
  background:var(--paper);border:1px solid var(--ink-20);
  padding:42px 34px 30px;
  box-shadow:0 34px 90px rgba(0,0,0,.30);
  transform-origin:50% 50%;
  animation:cxOn .62s cubic-bezier(.2,.8,.3,1);
}
/* switches on like an old set: a point, out to a scanline, then open */
@keyframes cxOn{
  0%   {transform:scale(.05,.004); filter:brightness(7); opacity:.85}
  22%  {transform:scale(1.02,.004);filter:brightness(4.5);opacity:1}
  44%  {transform:scale(1.02,.004);filter:brightness(4.5)}
  74%  {transform:scale(1,1.015);  filter:brightness(1.3)}
  100% {transform:scale(1,1);      filter:brightness(1)}
}
/* and off the same way, in reverse */
.cx.is-closing .cx__panel{animation:cxOff .4s cubic-bezier(.5,0,.3,1) forwards}
@keyframes cxOff{
  0%   {transform:scale(1,1);      filter:brightness(1)}
  52%  {transform:scale(1.02,.005);filter:brightness(4)}
  100% {transform:scale(.05,.002); filter:brightness(9); opacity:0}
}

/* the colour bars ride across the top of the set */
.cx__panel::before{
  content:"";position:absolute;left:0;right:0;top:0;height:9px;
  background:linear-gradient(90deg,
    #b9b9b9 0 14.2857%, #b9b900 14.2857% 28.5714%, #00b9b9 28.5714% 42.857%,
    #00b900 42.857% 57.142%, #b900b9 57.142% 71.428%, #b90000 71.428% 85.714%,
    #1414b9 85.714% 100%);
}
/* scanlines over the whole panel, clicks pass straight through */
.cx__panel::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:repeating-linear-gradient(to bottom,
    rgba(0,0,0,.05) 0 1px, rgba(0,0,0,0) 1px 3px);
}
.cx__close{position:absolute;right:16px;top:12px;font-size:22px;line-height:1;color:var(--ink-50)}
.cx__close:hover{color:var(--ink)}
.cx__title{
  font-family:var(--f-display);font-weight:400;
  font-size:clamp(21px,2.6vw,32px);line-height:1.12;letter-spacing:-.02em;
  margin:8px 0 12px;max-width:18ch;
}
.cx__mail{
  display:inline-block;margin-bottom:26px;font-size:14px;
  text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:.5px;
}
.cx__mail:hover{color:var(--accent)}

.cx__form{display:grid;gap:15px}
.cx__pot{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.cx__row{display:grid;grid-template-columns:1fr 1fr;gap:15px}
.cx__field{display:grid;gap:6px}
.cx__field input,.cx__field select,.cx__field textarea{
  font:inherit;font-size:14px;color:var(--ink);
  background:transparent;border:0;border-bottom:1px solid var(--ink-20);
  padding:7px 2px;border-radius:0;
  transition:border-color .2s linear;
}
.cx__field textarea{resize:vertical;min-height:64px;line-height:1.5}
.cx__field select{cursor:pointer}
.cx__field input:focus,.cx__field select:focus,.cx__field textarea:focus{
  outline:none;border-bottom-color:#00b9b9;
}
.cx__field input::placeholder,.cx__field textarea::placeholder{color:rgba(31,31,31,.34)}

.cx__send{
  justify-self:start;margin-top:8px;
  padding:12px 26px;border-radius:999px;
  background:var(--ink);color:var(--bg);
  transition:background .2s linear,opacity .2s linear;
}
.cx__send:hover{background:#b90000}
.cx__send:disabled{opacity:.5;cursor:default}
.cx__note{margin-top:-2px}
.cx__status{display:none;font-size:13px;line-height:1.5}
.cx__status.is-on{display:block}
.cx__status.is-ok{color:var(--ink)}
.cx__status.is-warn{color:var(--accent)}

/* ── lightbox ──────────────────────────────────────────────── */
body.is-lightbox .hud,body.is-lightbox .foot{display:none}
.lb{position:fixed;inset:0;z-index:75;background:#0a0a0a;
  display:grid;place-items:center;padding:56px 64px}
.lb[hidden]{display:none}
.lb__frame{max-width:100%;max-height:100%;display:grid;gap:12px;justify-items:center}
.lb__frame img,.lb__frame video{
  max-width:100%;max-height:calc(100vh - 130px);object-fit:contain;display:block;
}
.lb__frame video{width:auto;background:#000}
.lb__frame [hidden]{display:none}
.lb__frame figcaption{color:rgba(255,255,255,.55)}
.lb__close{position:absolute;right:var(--pad);top:var(--pad);color:#fff;font-size:22px;line-height:1}
.lb__nav{position:absolute;top:50%;transform:translateY(-50%);color:#fff;font-size:17px;
  width:44px;height:44px;display:grid;place-items:center;opacity:.6}
.lb__nav:hover{opacity:1}
.lb__nav--prev{left:10px}
.lb__nav--next{right:10px}

/* ── responsive ────────────────────────────────────────────── */
@media (max-width:1100px){
  .hud__nav{left:110px}
  .hud__focus,.hud__clock{display:none}
  .deck__meta,.deck__index,.index__head{left:110px}
  .rail{right:5vw;width:min(30vw,250px)}
  .index__rows,.doc{padding-left:110px}
}
@media (max-width:760px){
  :root{--pad:14px}
  .hud__mark{font-size:24px}
  .hud__stamp{display:none}
  /* the three-line stamp does not fit a phone, so a single line stands in —
     set the same way as the desktop stamp: vertical, beside the mark, and
     centred against it rather than hanging from the top */
  /* the 26px right padding is for the desktop stamp's three lines; one
     line needs no more room than the mark does on the left */
  .hud__logo{align-items:center;padding-right:12px}
  .hud__tag{
    display:block;
    writing-mode:vertical-rl;transform:rotate(180deg);
    font-size:8px;line-height:1;letter-spacing:.3px;
    color:rgba(0,0,0,.55);white-space:nowrap;
  }

  /* nav moves to the top-right; the email lives on the contact view */
  .hud__nav{left:auto;right:var(--pad);top:var(--pad);text-align:right}
  .hud__nav > .lbl{display:none}
  .menu{margin-top:0;justify-items:end}
  .menu__item{font-size:14px;line-height:17px;height:17px}
  .menu__arrow{order:2}
  .hud__mail,.hud__focus,.hud__clock,.foot__scroll{display:none}
  .menu__item{font-size:12px;line-height:16px;height:16px}

  /* the ribbon still runs through the picture, just tighter */
  .card{--cw:min(52vw,220px);left:50%;top:44%}

  .deck__meta{display:none}
  .deck__index{left:var(--pad);bottom:var(--pad)}
  .deck__index > .lbl{width:auto;padding-right:12px}
  .deck__no{font-size:64px;width:auto;padding-right:10px}
  .deck__total{padding-left:0}
  /* three columns will not fit: the picture sits high, the album rail
     runs underneath it */
  .hero{top:44%;width:74vw;height:32vh}
  .rail{
    --rail-step:92px;
    /* Centred in the gap between the picture and the counter. The hero
       ends at 60vh (top 44% + height 32vh) and the counter starts 68px off
       the floor, so the midpoint sits at 80vh - 34px from the top.
       `bottom` carries a -46px correction for the half-step below. */
    left:var(--pad);right:var(--pad);top:auto;width:auto;
    bottom:calc(20vh - 12px);
    /* One slot tall, and clipped. Hiding the neighbours by opacity alone is
       not enough: the fade runs 0.55s while the track slides for 0.75s, so
       mid-scroll the outgoing album name is still painted and lands behind
       the photograph. Clipping means only the current slot can ever draw. */
    height:var(--rail-step);
    overflow:hidden;
  }
  /* the track centres its active item inside that one-slot window */
  .rail__track{margin-top:calc(var(--rail-step) / 2)}
  .rail__desc{display:none}
  .rail__name{font-size:19px}
  /* only the album you are in — the neighbours would land on the counter */
  .rail__item:not(.is-active){opacity:0}

  .index__head{left:var(--pad);top:110px}
  .index__head .lbl:nth-child(2){display:none}
  .index__scroll{inset:138px 0 44px}
  .index__rows{padding-left:var(--pad)}
  .row{flex-wrap:wrap;gap:5px 16px;padding:14px 0}
  .row__id{position:static}
  .row__name{min-width:0;font-size:12px;flex-basis:100%}
  .row__awards,.row__roles,.row__cat{min-width:0}
  .row__desc{flex-basis:100%}

  .doc{padding:184px var(--pad) 90px}
  .doc__grid{margin-top:56px;gap:26px}
}
@media (prefers-reduced-motion:reduce){
  .cx__panel,.cx.is-closing .cx__panel{animation:none}
  .hero__layer,.hero__layer img,.rail__track,.rail__item{transition:none}
  .grain{animation:none}
  .foot__scroll{animation:none}
  *{scroll-behavior:auto}
}

/* five nav items sit taller than four — keep the doc views clear */
@media (max-width:760px){
  .doc--gal{--gal-indent:0px}
  .doc--about{padding:184px var(--pad) 90px}
  .ab__fig{position:static;width:min(74%,300px);margin:6px auto 34px;transform:none!important}
  .ab__h{margin-top:48px}
  .stack{margin-top:44px;grid-template-columns:1fr;gap:26px}
  .lb{padding:52px 12px}
  .cx__panel{padding:28px 20px 24px}
  .cx__row{grid-template-columns:1fr}
  .row--collection{padding:18px 0;gap:6px 16px}
  .row--collection .row__name{min-width:0;font-size:15px;flex-basis:100%}
  .row--collection .row__slug,.row--collection .row__date{min-width:0}
  .row--collection .row__desc{flex-basis:100%}
}
