/* ─────────────────────────────────────────────────────────────────
   Paul Flannery Photography — shared styles
   Every page is film: the same frame, rebate and perforation system,
   arranged differently per room.
   ───────────────────────────────────────────────────────────────── */

@font-face{font-family:"Special Elite";src:url("fonts/special-elite.woff2") format("woff2");font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"Type Machine";src:url("fonts/typemachine.woff2") format("woff2");font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"Courier Prime";src:url("fonts/courier-prime.woff2") format("woff2");font-weight:400;font-style:normal;font-display:swap}

:root{
  --ground:#0D0C0B;
  --ground-2:#151312;
  --ink:#EFEAE2;
  --ink-dim:#8B8479;
  --rule:#272321;
  --rebate:#1C1917;
  --edge:#B3A288;
  --chinagraph:#FFAC1C;
  --lamp:rgba(255,248,235,.055);
  --base:#B5A894;                 /* film base, shown before a frame loads */

  /* Display and body are single-weight faces: there is no bold to reach for,
     so emphasis is carried by colour, not weight. --mono keeps the small
     technical type legible at 11px, where 1942's distressing breaks down. */
  --display:"Special Elite","Courier New",Courier,monospace;
  --body:"Type Machine","Courier New",Courier,monospace;
  --mono:"Courier Prime","Courier New",Courier,monospace;

  --frame-h:clamp(140px,22vw,300px);
  --band:calc(var(--frame-h) * 6 / 24);
  --gap:calc(var(--frame-h) * 2 / 24);

  /* 35mm KS perforation, horizontal run and vertical run */
  --perf:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2047.5%2055'%3E%3Cpath%20fill-rule='evenodd'%20fill='white'%20d='M0%200H47.5V55H0Z%20M14.3%2017.6H33.2A4.5%204.5%200%200%201%2037.7%2022.1V33.1A4.5%204.5%200%200%201%2033.2%2037.6H14.3A4.5%204.5%200%200%201%209.8%2033.1V22.1A4.5%204.5%200%200%201%2014.3%2017.6Z'/%3E%3C/svg%3E");
  --perf-v:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2055%2047.5'%3E%3Cpath%20fill-rule='evenodd'%20fill='white'%20d='M0%200H55V47.5H0Z%20M17.6%2014.3V33.2A4.5%204.5%200%200%200%2022.1%2037.7H33.1A4.5%204.5%200%200%200%2037.6%2033.2V14.3A4.5%204.5%200%200%200%2033.1%209.8H22.1A4.5%204.5%200%200%200%2017.6%2014.3Z'/%3E%3C/svg%3E");

  --neg:grayscale(1) invert(1) contrast(.68) sepia(.34) brightness(.96);
}
/* There is no light theme. A sheet of negatives on a lit table is a dark
   room with one bright thing in it -- inverted onto paper white it is a
   different photograph, and every muted grey here stops being legible
   against it. The palette above is the palette, whatever the visitor's
   machine prefers. */

*{box-sizing:border-box}
body{
  margin:0;background:var(--ground);color:var(--ink);
  font-family:var(--body);font-size:1rem;
  font-synthesis:none;            /* never fake a bold these faces don't have */
  -webkit-font-smoothing:antialiased;
}
b,strong{font-weight:400;color:var(--ink)}   /* emphasis is colour, not weight */
.wrap{max-width:1180px;margin-inline:auto;padding-inline:clamp(20px,5vw,64px)}
.mono{font-family:var(--mono);text-transform:uppercase;letter-spacing:.16em;font-size:.7rem}

/* ── Masthead ─────────────────────────────────────────────────────
   Everything here is a real link, and looks like one. Nothing else
   in the header is styled to suggest it can be clicked.            */
.top{
  display:flex;flex-wrap:wrap;gap:10px 28px;align-items:baseline;justify-content:space-between;
  padding-block:22px 0;
}
.wordmark{
  font-family:var(--mono);text-transform:uppercase;letter-spacing:.16em;font-size:.72rem;
  color:var(--ink);text-decoration:none;border-bottom:1px solid var(--rule);padding-bottom:3px;
}
.wordmark:hover,.wordmark:focus-visible{border-bottom-color:var(--chinagraph)}
.top nav{display:flex;flex-wrap:wrap;gap:6px 20px}
.top nav a{
  font-family:var(--mono);text-transform:uppercase;letter-spacing:.14em;font-size:.7rem;
  color:var(--ink-dim);text-decoration:none;
  border-bottom:1px solid var(--rule);padding-bottom:3px;
}
.top nav a:hover{color:var(--ink);border-bottom-color:var(--chinagraph)}
.top nav a[aria-current="page"]{color:var(--ink);border-bottom-color:var(--chinagraph)}
a:focus-visible,button:focus-visible,[tabindex]:focus-visible{
  outline:2px solid var(--chinagraph);outline-offset:3px;
}

/* ── Page head ────────────────────────────────────────────────── */
.hero{padding-block:clamp(22px,3.6vw,40px) clamp(20px,3vw,34px)}
.hero h1{
  margin:0;font-family:var(--display);font-weight:400;
  font-size:clamp(2.1rem,6.4vw,5.5rem);line-height:1.08;letter-spacing:0;text-wrap:balance;
}
.hero h1 .mark{position:relative;display:inline-block}
.hero h1 .mark svg{position:absolute;inset:-14% -7%;width:114%;height:128%;overflow:visible;pointer-events:none}
.hero h1 .mark path{fill:none;stroke:var(--chinagraph);stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round;opacity:.9;vector-effect:non-scaling-stroke}
.hero p.lede{margin:clamp(18px,2.4vw,26px) 0 0;max-width:44ch;font-size:clamp(1rem,1.65vw,1.18rem);line-height:1.6;color:var(--ink-dim)}
.hero p.lede b{color:var(--ink)}

.gallery-head{padding-block:clamp(20px,3vw,34px) clamp(16px,2.4vw,26px)}
.gallery-head h1{
  margin:0;font-family:var(--display);font-weight:400;
  font-size:clamp(1.35rem,4.4vw,3.6rem);line-height:1.1;letter-spacing:0;
}
.gallery-head .kick{display:block;color:var(--edge);font-family:var(--mono);font-size:.7rem;letter-spacing:.18em;text-transform:uppercase;margin-bottom:12px}

/* ── The frame ────────────────────────────────────────────────────
   One negative. Width follows --frame-h so every room can resize it. */
.cell{position:relative;flex:0 0 auto;width:calc(var(--frame-h) * 1.5);height:var(--frame-h)}
.cell img{
  display:block;width:100%;height:100%;object-fit:cover;object-position:50% 50%;
  opacity:0;                       /* until it comes into view -- see .in */
  background:var(--base);-webkit-user-drag:none;user-select:none;
  filter:var(--neg);
  transition:filter .3s ease;
}
/* A vertical shot sits sideways in the frame, the way a turned camera
   records it. At 90° an h × 1.5h image fills the landscape frame exactly. */
.cell.port img{
  position:absolute;top:50%;left:50%;
  width:var(--frame-h);height:calc(var(--frame-h) * 1.5);
  margin-top:calc(var(--frame-h) * -0.75);
  margin-left:calc(var(--frame-h) * -0.5);
  transform:rotate(90deg);
}
.cell img.in{opacity:1;transition:opacity .55s ease}
/* the loupe's copy is never observed, and must not start invisible */
.loupe .cell img,
:root:not(.js) .cell img{opacity:1}
@media (prefers-reduced-motion:reduce){.cell img{opacity:1}}

.cell .edge{
  position:absolute;left:0;color:var(--edge);font-size:calc(var(--band) * .235);
  font-family:var(--mono);letter-spacing:.12em;text-transform:uppercase;
  white-space:nowrap;opacity:.85;pointer-events:none;
}
.cell .stock{bottom:100%;margin-bottom:calc(var(--band) * .055)}
.cell .num{top:100%;margin-top:calc(var(--band) * .055)}
.cell .grease{position:absolute;inset:4% 3%;width:94%;height:92%;overflow:visible;pointer-events:none}
.cell .grease path{fill:none;stroke:var(--chinagraph);stroke-width:3;stroke-linecap:round;opacity:.92}
.cell.sel .num{color:var(--chinagraph);opacity:1}

.band{position:absolute;background-color:var(--rebate)}
.band-t,.band-b{
  left:0;width:100%;height:var(--band);
  -webkit-mask-image:var(--perf);mask-image:var(--perf);
  -webkit-mask-repeat:repeat-x;mask-repeat:repeat-x;
  -webkit-mask-size:calc(var(--band) * 47.5 / 55) var(--band);
  mask-size:calc(var(--band) * 47.5 / 55) var(--band);
}
.band-t{top:0}
.band-b{bottom:0}
.band-l,.band-r{
  top:0;height:100%;width:var(--band);
  -webkit-mask-image:var(--perf-v);mask-image:var(--perf-v);
  -webkit-mask-repeat:repeat-y;mask-repeat:repeat-y;
  -webkit-mask-size:var(--band) calc(var(--band) * 47.5 / 55);
  mask-size:var(--band) calc(var(--band) * 47.5 / 55);
}
.band-l{left:0}
.band-r{right:0}

/* ── Room 1: the running roll (home) ──────────────────────────── */
.stage{position:relative;overflow:hidden;padding-block:clamp(14px,3vw,30px)}
.stage::before{content:"";position:absolute;inset:0;pointer-events:none;background:radial-gradient(120% 78% at 50% 50%,var(--lamp),transparent 72%)}
.lightbox{width:106%;margin-left:-3%;transform:rotate(-1.05deg)}
.viewport{overflow:hidden;touch-action:pan-y;cursor:grab;outline:none}
.viewport:focus-visible{box-shadow:0 0 0 2px var(--ground),0 0 0 4px var(--chinagraph);outline:none}
.viewport.grabbing{cursor:grabbing}
.track{position:relative;display:flex;align-items:center;gap:var(--gap);padding-block:var(--band);width:max-content;will-change:transform}
.track .cell::after{content:"";position:absolute;top:0;bottom:0;right:calc(var(--gap) * -1);width:var(--gap);background:var(--rebate)}
@media (hover:hover){
  .viewport:hover .cell img{filter:grayscale(1) invert(1) contrast(.68) sepia(.34) brightness(.62)}
  .viewport:hover .cell:hover img{filter:grayscale(1) invert(1) contrast(.68) sepia(.34) brightness(1.1)}
}

/* ── Room 2: the contact sheet (portraits) ────────────────────── */
.sheet{--frame-h:clamp(96px,12vw,142px);--band:calc(var(--frame-h) * 6 / 24);--gap:calc(var(--frame-h) * 2 / 24);display:flex;flex-direction:column;gap:clamp(24px,3.4vw,44px);padding-bottom:clamp(30px,4vw,50px)}
.sitter h2{
  margin:0 0 10px;font-family:var(--mono);font-size:.7rem;letter-spacing:.2em;text-transform:uppercase;
  color:var(--edge);font-weight:400;
}
.sheet .row{position:relative;display:flex;gap:var(--gap);padding-block:var(--band);width:max-content;max-width:100%}
.sheet .row + .row{margin-top:calc(var(--gap) * 1.5)}
.sheet .cell::after{content:"";position:absolute;top:0;bottom:0;right:calc(var(--gap) * -1);width:var(--gap);background:var(--rebate)}
.sheet .cell:last-child::after{display:none}
.sheet .cell{cursor:pointer}
@media (hover:hover){
  .sheet .row:hover .cell img{filter:grayscale(1) invert(1) contrast(.68) sepia(.34) brightness(.62)}
  .sheet .row:hover .cell:hover img{filter:none}   /* hover develops the frame */
}

/* ── Room 3: hanging strips (fashion) ─────────────────────────── */
.hang{
  --strip-w:clamp(120px,15vw,170px);
  --frame-h:calc(var(--strip-w) / 1.5);
  --band:calc(var(--frame-h) * 6 / 24);--gap:calc(var(--frame-h) * 2 / 24);
  display:flex;flex-wrap:wrap;gap:clamp(16px,2.2vw,28px);
  justify-content:center;align-items:flex-start;
  padding-block:clamp(28px,4vw,52px) clamp(40px,5vw,70px);
  /* The strips sway, and at the narrowest widths the outermost one swings a
     few pixels past the edge -- enough to give the whole page a sideways
     wobble. clip rather than hidden: it stops the overflow without turning
     this into a scroller, and the margin lets the swing still show. */
  overflow-x:clip;overflow-clip-margin:14px;
}
.hung{position:relative;padding-top:26px;transform-origin:50% 8px;animation:sway 8s ease-in-out infinite}
.hung:nth-child(2n){animation-duration:9.5s;animation-delay:-2.2s}
.hung:nth-child(3n){animation-duration:7.2s;animation-delay:-4.1s}
.hung .strip{position:relative;display:flex;flex-direction:column;gap:var(--gap);padding-inline:var(--band);width:max-content}
.hung .cell{width:var(--strip-w);height:var(--frame-h)}
.hung .cell::after{content:"";position:absolute;left:0;right:0;bottom:calc(var(--gap) * -1);height:var(--gap);background:var(--rebate)}
.hung .cell:last-child::after{display:none}
.hung .cell .edge{writing-mode:vertical-rl;left:auto;right:100%;top:0;margin-right:calc(var(--band) * .06)}
.hung .cell .stock,.hung .cell .num{bottom:auto;top:0;margin-bottom:0;margin-top:0}
.hung .peg{
  position:absolute;top:0;left:50%;transform:translateX(-50%);
  width:34px;height:20px;color:var(--ink-dim);
}
.hung .peg svg{width:100%;height:100%;display:block}
.hung .label{
  display:block;text-align:center;margin-top:12px;color:var(--edge);
  font-family:var(--mono);font-size:.66rem;letter-spacing:.18em;text-transform:uppercase;
}
@keyframes sway{
  0%,100%{transform:rotate(-.55deg)}
  50%{transform:rotate(.55deg)}
}
@media (hover:hover){
  .hung .strip:hover .cell img{filter:grayscale(1) invert(1) contrast(.68) sepia(.34) brightness(.62)}
  .hung .strip:hover .cell:hover img{filter:none}  /* hover develops the frame */
}

/* ── Room 4: the light table (character) ──────────────────────── */
.table{
  --frame-h:clamp(100px,13vw,168px);
  --band:calc(var(--frame-h) * 6 / 24);--gap:calc(var(--frame-h) * 2 / 24);
  position:relative;margin-block:clamp(16px,2.6vw,30px) clamp(40px,5vw,70px);
  border:1px solid var(--rule);
  background:
    radial-gradient(120% 90% at 50% 45%,var(--lamp),transparent 70%),
    var(--ground-2);
  /* pan-y, not none: a finger that lands on the table between frames is
     trying to read the page, and the page should move. A finger that lands
     ON a frame is handled in the room's own script. */
  touch-action:pan-y;overflow:hidden;
}
.loose{
  position:absolute;
  /* top/bottom: the real 25%-of-frame rebate, so whole perforations show.
     left/right: half the inter-frame gap, jittered per frame, as if the
     scissors landed slightly differently on each one. */
  padding:var(--band) calc(var(--gap) * var(--cutR,.5)) var(--band) calc(var(--gap) * var(--cutL,.5));
  /* No fill here: the perforations are punched out of the bands and must
     reveal the light table behind, not more rebate. The rebate between the
     two bands is drawn by ::before instead. */
  /* pan-y, not none: the browser decides the first few pixels. Mostly
     vertical and it takes the gesture and scrolls the page itself -- which
     is smooth, and has momentum, in a way that scrolling by hand from
     pointermove never is. Anything else and the gesture stays with us, and
     the frame can then be dragged in both directions freely. */
  background:transparent;cursor:grab;touch-action:pan-y;
  box-shadow:0 10px 26px rgba(0,0,0,.45),0 2px 5px rgba(0,0,0,.35);
  will-change:transform;
}
.loose::before{
  content:"";position:absolute;left:0;right:0;top:var(--band);bottom:var(--band);
  background:var(--rebate);
}
.loose.lifted{cursor:grabbing;box-shadow:0 22px 48px rgba(0,0,0,.55),0 3px 8px rgba(0,0,0,.4)}
@media (hover:hover){
  .loose:hover .cell img{filter:grayscale(1) invert(1) contrast(.68) sepia(.34) brightness(1.1)}
}

/* Table controls, and the two states the viewer can put the table in. */
.table-controls{display:flex;flex-wrap:wrap;gap:10px;margin-bottom:clamp(12px,1.8vw,18px)}
.ctl{
  background:none;border:1px solid var(--rule);color:var(--ink-dim);
  font-family:var(--mono);font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;
  padding:11px 15px;cursor:pointer;line-height:1;
  transition:color .2s ease,border-color .2s ease;
}
.ctl:hover{color:var(--ink);border-color:var(--chinagraph)}
.ctl[aria-pressed="true"]{color:var(--chinagraph);border-color:var(--chinagraph)}
.table.positive .cell img{filter:none}
@media (hover:hover){
  .table.positive .loose:hover .cell img{filter:brightness(1.06)}
}
.loose{transition:opacity .25s ease}
.loose.gone{opacity:0;pointer-events:none}

/* Taking one off the table. Dragging a frame past the edge still works, but
   nobody finds a gesture nothing points at, so every frame also carries the
   mark an editor puts on a reject: a chinagraph cross in the corner. */
.toss{
  position:absolute;z-index:3;
  top:calc(var(--band) + var(--frame-h) * .07);
  right:calc(var(--frame-h) * .07);
  width:calc(var(--frame-h) * .2);height:calc(var(--frame-h) * .2);
  padding:0;border:0;background:none;cursor:pointer;color:var(--chinagraph);
  opacity:.48;transition:opacity .2s ease,transform .2s ease;
}
.toss svg{display:block;width:100%;height:100%}
/* the mark stays small; the thing you can hit does not */
.toss::before{content:"";position:absolute;inset:-11px}
.toss path{fill:none;stroke:currentColor;stroke-width:11;stroke-linecap:round}
.toss:hover,.toss:focus-visible{opacity:1;transform:scale(1.14)}
.toss:focus-visible{outline:2px solid var(--chinagraph);outline-offset:3px}
/* and the cross lands on the frame on its way out */
.loose.struck::after{
  content:"";position:absolute;inset:var(--band) 0;z-index:2;pointer-events:none;
  background:
    linear-gradient(to bottom right,transparent calc(50% - 1.5px),var(--chinagraph) calc(50% - 1.5px),var(--chinagraph) calc(50% + 1.5px),transparent calc(50% + 1.5px)),
    linear-gradient(to bottom left, transparent calc(50% - 1.5px),var(--chinagraph) calc(50% - 1.5px),var(--chinagraph) calc(50% + 1.5px),transparent calc(50% + 1.5px));
}
/* the table's edge lights up while a frame is held over it */
.table.tossing{border-color:var(--chinagraph)}

/* ── Room 4: the bench (ecommerce) ─────────────────────────────
   Packshots laid out as clipped frames, and a loupe you move over them.
   The frames are negatives like everywhere else; the glass is the only
   place on the page where the product appears as it was shot.        */
.bench{
  --frame-h:clamp(104px,13.5vw,176px);
  --band:calc(var(--frame-h) * 6 / 24);--gap:calc(var(--frame-h) * 2 / 24);
  display:flex;flex-wrap:wrap;justify-content:center;
  gap:calc(var(--frame-h) * .16) calc(var(--frame-h) * .1);
  margin-block:clamp(18px,2.8vw,34px) clamp(40px,5vw,70px);
  padding:clamp(14px,2vw,26px) clamp(8px,1.4vw,18px);
  border:1px solid var(--rule);
  background:radial-gradient(120% 90% at 50% 45%,var(--lamp),transparent 70%),var(--ground-2);
  /* pan-y so the page still scrolls under a finger; a sideways drag is
     what picks the glass up */
  touch-action:pan-y;
}
.pack{
  position:relative;flex:0 0 auto;
  padding:var(--band) calc(var(--gap) * .5);
  background:transparent;cursor:zoom-in;
  box-shadow:0 10px 26px rgba(0,0,0,.4),0 2px 5px rgba(0,0,0,.3);
}
.pack::before{
  content:"";position:absolute;left:0;right:0;top:var(--band);bottom:var(--band);
  background:var(--rebate);
}
.pack:focus-visible{outline:2px solid var(--chinagraph);outline-offset:3px}
/* A packshot is nearly always vertical, and a vertical frame on a roll is
   recorded turned. Everywhere else the photo is turned to lie in a
   landscape frame; here the strip itself is turned instead, so the product
   stands up and the perforations run down the sides. */
.pack.turned{padding:calc(var(--gap) * .5) var(--band)}
.pack.turned::before{left:var(--band);right:var(--band);top:0;bottom:0}
.pack.turned .cell{width:var(--frame-h);height:calc(var(--frame-h) * 1.5)}
.pack.turned .cell img{
  position:static;width:100%;height:100%;margin:0;transform:none;object-fit:cover;
}
.pack.turned .edge{left:auto;right:0;transform-origin:100% 100%}

.loupe{
  position:fixed;z-index:60;display:none;pointer-events:none;
  width:clamp(132px,19vw,208px);aspect-ratio:1;transform:translate(-50%,-50%);
  border-radius:50%;overflow:hidden;background:var(--rebate);
  border:2px solid rgba(255,248,235,.22);
  box-shadow:0 18px 40px rgba(0,0,0,.55),inset 0 0 26px rgba(0,0,0,.55);
}
.loupe.on{display:block}
.loupe-inner{position:absolute;top:0;left:0;transform-origin:0 0}
/* what the glass shows is the frame as shot, not the negative */
.loupe .cell img{filter:none}
.loupe .edge{display:none}
/* A turned frame is un-rotated by a rule scoped to .pack.turned, and the
   glass holds a copy that lives outside it -- so the copy fell back to the
   rotation every other room wants and the product lay down inside the glass.
   The glass carries the same state, and the same instruction with it. */
.loupe.turned .cell img{
  position:static;width:100%;height:100%;margin:0;transform:none;object-fit:cover;
}

/* ── Index of rooms (home) ────────────────────────────────────── */
.index{border-top:1px solid var(--rule);margin-top:clamp(30px,4.4vw,52px)}
.index ol{list-style:none;margin:0;padding:0}
.index li{border-bottom:1px solid var(--rule)}
.index a{
  display:grid;grid-template-columns:5.5ch 1fr auto;gap:4px 22px;align-items:baseline;
  padding-block:clamp(20px,2.6vw,30px);text-decoration:none;color:inherit;
}
.index a:hover .genre,.index a:focus-visible .genre{color:var(--chinagraph)}
.index a:hover .go,.index a:focus-visible .go{color:var(--chinagraph);transform:translateX(4px)}
.index .fno{grid-column:1;grid-row:1;color:var(--edge);font-family:var(--mono);font-size:.72rem;letter-spacing:.1em}
.index .genre{grid-column:2;grid-row:1;font-family:var(--display);font-size:clamp(1.15rem,3vw,2.1rem);line-height:1.24;letter-spacing:0}
.index .what{grid-column:2;grid-row:2;color:var(--ink-dim);font-size:.92rem;line-height:1.58;max-width:60ch;margin-top:6px}
.index .go{grid-column:3;grid-row:1;color:var(--ink-dim);display:flex;align-items:center;transition:transform .2s ease,color .2s ease}
.index .go svg{display:block}

/* ── Client ticker ────────────────────────────────────────────────
   A short strip of film running along the foot of every page. Each logo
   sits in its own frame, and the perforations live on the moving row so
   they travel with the film instead of sitting behind a fixed gate. */
.ticker{
  --frame-h:clamp(70px,8.6vw,118px);
  --band:calc(var(--frame-h) * 6 / 24);
  --gap:calc(var(--frame-h) * 2 / 24);
  position:relative;overflow:hidden;
  margin-top:clamp(26px,3.6vw,46px);
  /* the same breathing room the stage gives the roll, and enough of it for
     the strip to lie at an angle without its edges being trimmed */
  padding-block:clamp(14px,3vw,30px);
  /* fade both ends so logos arrive and leave rather than being cut off */
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);
}
/* the lamp under the strip, same as the one under the roll */
.ticker::before{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(120% 78% at 50% 50%,var(--lamp),transparent 72%);
}
/* .ticker-strip is to .ticker-row what .lightbox is to .track: it holds the
   tilt, so the row underneath is free to do nothing but travel sideways. */
.ticker-strip{width:106%;margin-left:-3%;transform:rotate(-1.05deg);overflow:hidden}
.ticker-row{
  position:relative;display:flex;width:max-content;padding-block:var(--band);
  animation:ticker linear infinite;animation-duration:40s;
}
.ticker-row::before{
  content:"";position:absolute;left:0;right:0;top:var(--band);bottom:var(--band);
  background:var(--rebate);
}
.client{
  position:relative;flex:0 0 auto;
  width:calc(var(--frame-h) * 1.5);height:var(--frame-h);
  /* margin rather than flex gap: the row must travel exactly one set per
     cycle for the loop to be seamless, and gap breaks that arithmetic */
  margin-right:var(--gap);
  /* Film base -- the tone a frame on the roll upstairs actually is. The marks
     go dark on it, which is what lets the strip keep the roll's dark rebate
     and dark sprocket holes instead of needing to be lit from behind. */
  background:var(--base);display:grid;place-items:center;
  /* No padding here: each mark is rendered onto a 3:2 canvas at build time
     with its own margin baked in, and optically sized so a wide wordmark and
     a square device carry the same weight. The file IS the frame. */
}
.client img{
  width:100%;height:100%;object-fit:contain;
  /* flat black, so a dozen mismatched brand colours sit together as one set */
  filter:brightness(0);opacity:.82;
  transition:opacity .35s ease;
}
/* Frame numbers and edge printing, the same marks at the same size the roll
   upstairs carries them. Tiny on purpose: on a real strip this type is 2mm. */
.client .edge{
  position:absolute;left:0;color:var(--edge);font-size:calc(var(--band) * .235);
  font-family:var(--mono);letter-spacing:.12em;text-transform:uppercase;
  white-space:nowrap;opacity:.85;pointer-events:none;
}
.client .stock{bottom:100%;margin-bottom:calc(var(--band) * .055)}
.client .num{top:100%;margin-top:calc(var(--band) * .055)}
.client.empty{background:var(--ground-2)}
.client.empty span{
  font-family:var(--mono);font-size:calc(var(--frame-h) * .155);
  letter-spacing:.14em;text-transform:uppercase;color:var(--edge);opacity:.6;
}
@media (hover:hover){
  .client:hover img{opacity:1}          /* the mark comes up; the roll keeps running */
}
@keyframes ticker{from{transform:translate3d(0,0,0)}to{transform:translate3d(-50%,0,0)}}

.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ── The door out of a room ───────────────────────────────────────
   Every gallery used to end at the footer, which is a wall. This is the
   next room, drawn as one more frame on the roll.                     */
.nextroom{
  --frame-h:clamp(64px,8vw,96px);
  --band:calc(var(--frame-h) * 6 / 24);
  position:relative;display:flex;align-items:center;gap:clamp(12px,2vw,24px);
  margin-block:clamp(34px,5vw,64px) clamp(10px,1.5vw,18px);
  padding:var(--band) clamp(16px,3vw,34px);
  text-decoration:none;color:var(--ink);isolation:isolate;
  transition:gap .25s ease;
}
.nextroom::before{
  content:"";position:absolute;left:0;right:0;top:var(--band);bottom:var(--band);
  background:var(--rebate);z-index:-1;
}
.nextroom .kick{
  font-family:var(--mono);font-size:.68rem;letter-spacing:.18em;text-transform:uppercase;
  color:var(--edge);
}
.nextroom .name{
  font-family:var(--display);font-size:clamp(1.3rem,3.4vw,2rem);line-height:1;
  color:var(--base);
}
.nextroom .go{display:flex;color:var(--edge);transition:transform .25s ease}
.nextroom:hover .go,.nextroom:focus-visible .go{transform:translateX(-7px);color:var(--chinagraph)}
.nextroom:hover .name,.nextroom:focus-visible .name{color:var(--chinagraph)}
.nextroom:focus-visible{outline:2px solid var(--chinagraph);outline-offset:4px}

/* ── Where an enquiry actually starts ─────────────────────────────
   The address used to be one line in the footer, under everything else on
   the page. This is a room of its own.                                   */
.contact{
  border-top:1px solid var(--rule);
  margin-top:clamp(34px,5vw,64px);padding-top:clamp(24px,3.4vw,40px);
  max-width:60ch;
}
.contact h2{
  font-family:var(--display);font-weight:400;
  font-size:clamp(1.6rem,5vw,2.6rem);line-height:1.05;margin:0 0 .5em;color:var(--ink);
}
.contact p{margin:0 0 .7em;color:var(--ink-dim);line-height:1.6}
.contact p:last-child{margin-bottom:0}
.contact .reach{margin-bottom:1em}
.contact .reach a{
  font-family:var(--mono);font-size:clamp(.92rem,2.6vw,1.08rem);letter-spacing:.04em;
  color:var(--ink);text-decoration:none;
  border-bottom:1px solid var(--rule);padding-bottom:4px;
  overflow-wrap:anywhere;transition:border-color .2s ease,color .2s ease;
}
.contact .reach a:hover,.contact .reach a:focus-visible{
  color:var(--chinagraph);border-bottom-color:var(--chinagraph);
}
.contact .elsewhere{margin-top:1.1em}
.contact .elsewhere a{
  color:var(--ink);text-decoration:none;
  border-bottom:1px solid var(--rule);padding-bottom:2px;
  transition:color .2s ease,border-color .2s ease;
}
.contact .elsewhere a:hover,.contact .elsewhere a:focus-visible{
  color:var(--chinagraph);border-bottom-color:var(--chinagraph);
}

/* ── Who took these ──────────────────────────────────────────────── */
.about{
  max-width:52ch;margin-block:clamp(30px,4.5vw,56px);
  border-left:1px solid var(--rule);padding-left:clamp(14px,2vw,22px);
}
.about p{margin:0 0 .8em;color:var(--ink-dim);line-height:1.6}
.about p:last-child{margin-bottom:0}
.about b{color:var(--ink)}

/* ── Foot ─────────────────────────────────────────────────────── */
footer{padding-block:clamp(34px,4.4vw,58px) clamp(30px,4vw,48px);color:var(--ink-dim);border-top:1px solid var(--rule);margin-top:clamp(20px,3vw,34px)}
footer .say{font-family:var(--display);font-size:clamp(1.15rem,2.8vw,1.9rem);color:var(--ink);margin:0 0 12px;letter-spacing:0;line-height:1.2}
footer a{color:var(--ink);text-decoration:none;border-bottom:1px solid var(--chinagraph);overflow-wrap:anywhere}
.note{margin-top:clamp(24px,3vw,36px);padding-top:16px;border-top:1px solid var(--rule);color:var(--ink-dim);line-height:1.6;max-width:62ch;font-size:.76rem;font-family:var(--mono);text-transform:none;letter-spacing:.02em}

/* ── The print (shared viewer) ────────────────────────────────── */
.lb{position:fixed;inset:0;z-index:50;display:grid;place-items:center;background:color-mix(in srgb,var(--ground) 93%,black);padding:clamp(14px,3.5vw,44px)}
.lb[hidden]{display:none!important}
.lb figure{margin:0;max-width:min(1000px,100%);display:flex;flex-direction:column;gap:12px;align-items:center}
.lb img{
  display:block;max-width:100%;max-height:72vh;object-fit:contain;
  background:var(--ground-2);cursor:zoom-in;touch-action:none;
  -webkit-user-select:none;user-select:none;-webkit-user-drag:none;
  transition:transform .28s cubic-bezier(.2,.7,.3,1);
}
.lb.zoomed img{cursor:grab;transition:none}
.lb .cap{
  margin:0;width:100%;color:var(--ink);font-size:.92rem;line-height:1.45;
}
.lb .cap[hidden]{display:none}
.lb figcaption{display:flex;justify-content:space-between;gap:16px;width:100%;color:var(--edge);font-family:var(--mono);font-size:.7rem;letter-spacing:.16em;text-transform:uppercase}
.lb button{
  position:absolute;background:none;border:1px solid var(--rule);color:var(--ink);
  font-family:var(--mono);font-size:.72rem;letter-spacing:.14em;text-transform:uppercase;
  padding:12px 16px;cursor:pointer;line-height:1;
}
.lb button:hover{border-color:var(--chinagraph);color:var(--chinagraph)}
.lb .close{top:clamp(14px,3.5vw,44px);right:clamp(14px,3.5vw,44px)}
.lb .prev{left:clamp(14px,3.5vw,44px);top:50%;transform:translateY(-50%)}
.lb .next{right:clamp(14px,3.5vw,44px);top:50%;transform:translateY(-50%)}
@media (max-width:640px){
  .lb .prev{left:14px;top:auto;bottom:18px;transform:none}
  .lb .next{right:14px;top:auto;bottom:18px;transform:none}
}

@media (max-width:560px){
  .index a{grid-template-columns:1fr auto}
  .index .fno{grid-column:1;grid-row:1}
  .index .genre{grid-column:1;grid-row:2}
  .index .what{grid-column:1;grid-row:3}
  .index .go{grid-column:2;grid-row:2}
}

@media (prefers-reduced-motion: reduce){
  .ticker-row{animation:none}
  .ticker{overflow-x:auto}
  .viewport{overflow-x:auto;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch}
  .track .cell{scroll-snap-align:center}
  .cell img{transition:none}
  .hung{animation:none}
}

/* ── Nothing on this frame ─────────────────────────────────────────
   The 404. Same masthead, same ticker, same voice: a wrong address
   should look like it landed somewhere, not like the site broke. */
.hero.lost{padding-block:clamp(56px,14vh,132px)}
.hero.lost .fno{margin:0 0 18px;font-family:var(--mono);font-size:13px;
  letter-spacing:.22em;color:var(--chinagraph)}
.hero.lost .back{margin:28px 0 0}
.hero.lost .back a{font-family:var(--mono);font-size:13px;letter-spacing:.06em;
  color:var(--ink);text-decoration:none;border-bottom:1px solid var(--chinagraph);
  padding-bottom:3px}
.hero.lost .back a:hover{color:var(--chinagraph)}
