/* ============================================================================
   Studio portfolio
   ----------------------------------------------------------------------------
   DESIGN NOTE. The work on this page is loud: photoreal renders, saturated
   skies, heavy condensed type burned into every cover. So the page itself is
   deliberately almost colourless — a near-black ground with a single warm bone
   for text and one restrained accent used only for structure, never decoration.
   The thumbnails supply every bit of chroma on the page. A gallery is painted
   neutral so the paintings can sing; same reasoning here.

   Three sections, three rhythms, on purpose: a drifting wall (volume), a
   horizontal rail (motion), then full-bleed single cases (craft). Three
   identical grids would make varied work look like one thing.

   No webfonts, no build step, no dependencies — the same constraints as every
   site we hand to a client.
   ========================================================================== */

:root{
  /* Neutrals carry a slight warm bias so the near-black reads as ink, not as
     switched-off screen. Pure #000/#fff would fight the warm work. */
  --ink:#0b0c0f;
  --ink-2:#131519;
  --ink-3:#1c1f25;
  --bone:#f4f1ea;
  --bone-2:#b9b6ae;
  --bone-3:#7c7a75;
  --line:#262a31;
  --accent:#c8a86b;          /* structural only: rules, numerals, focus */
  --maxw:1240px;
  --gap:clamp(18px,3.2vw,40px);
  --sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Inter,system-ui,sans-serif;
  --mono:ui-monospace,"SF Mono",Menlo,monospace;
  --ease:cubic-bezier(.22,.61,.36,1);
}

*,*::before,*::after{box-sizing:border-box}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
body{
  margin:0;background:var(--ink);color:var(--bone);
  font-family:var(--sans);line-height:1.55;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  /* `clip` rather than `hidden`: overflow-x:hidden silently makes the body a scroll
     container, which lets a wide descendant establish a containing block wider than the
     viewport — the text then renders past the screen edge instead of wrapping into it.
     `clip` cuts the overflow without creating that scroll container. */
  overflow-x:clip;
}
/* Flex and grid children default to min-width:auto, so one long word or one wide image
   can refuse to shrink and push the whole column past the screen. Opting every layout
   child out of that is the single most effective guard against phone overflow. */
.hero__inner,.sec,.sec__head,.case,.case__meta,.feature,.feature__body,.hand{min-width:0}
/* height:auto is load-bearing, not tidiness. The images carry width/height attributes
   (correctly — they reserve space and stop layout shift), but with only max-width:100%
   the width shrinks while the HTML height stays pinned. The Dimble frame rendered
   354x506 against a true 900x506 — squeezed to 40% of its correct width. Reported from
   a real phone 2026-08-06. Images with their own sizing rules (.card__img, .compare)
   were unaffected, which is why it hid for so long. */
img{max-width:100%;height:auto;display:block}
h1,h2,h3{margin:0;text-wrap:balance;letter-spacing:-.03em;line-height:1.02;font-weight:800}
p{margin:0}

.skip{position:absolute;left:-9999px;top:0;background:var(--bone);color:var(--ink);
  padding:12px 18px;z-index:100;border-radius:0 0 8px 0;font-weight:700}
.skip:focus{left:0}
:focus-visible{outline:2px solid var(--accent);outline-offset:4px;border-radius:3px}

.eyebrow,.kicker{
  font-family:var(--mono);font-size:11px;letter-spacing:.24em;text-transform:uppercase;
  color:var(--accent);font-weight:600;margin:0 0 18px;
}
.kicker{margin-bottom:12px}

/* ─────────────────────────  HERO  ───────────────────────── */
.hero{
  min-height:100svh;display:flex;flex-direction:column;justify-content:center;
  padding:clamp(80px,12vh,140px) var(--gap) 0;position:relative;
  /* A single soft bloom, off-centre. Not a gradient hero — just enough to stop
     the flat black reading as an unstyled page. */
  background:
    radial-gradient(120vw 80vh at 72% -10%, #1a1d24 0%, transparent 62%),
    radial-gradient(60vw 50vh at 8% 108%, #15171c 0%, transparent 60%);
}
.hero__inner{max-width:var(--maxw);margin:0 auto;width:100%;min-width:0;flex:1;display:flex;
  flex-direction:column;justify-content:center;padding-bottom:60px}
/* Measured at 390px: the headline wraps inside its 354px box at every size from 28px to
   52px, so the floor is a purely aesthetic choice rather than a safety one. 46px keeps the
   opening line strong on a phone without running to four lines. `max-width:100%` stays as a
   cheap guard for narrower devices than we can test. */
.hero h1{font-size:clamp(46px,9.2vw,132px);margin-bottom:26px;max-width:100%}
.hero__em{color:var(--bone-3)}
.hero__lede{max-width:min(56ch,100%);font-size:clamp(15px,1.9vw,21px);color:var(--bone-2);margin-bottom:38px}
.btn{
  align-self:flex-start;display:inline-block;text-decoration:none;
  font-family:var(--mono);font-size:12.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink);background:var(--bone);padding:16px 30px;border-radius:999px;font-weight:700;
  transition:transform .25s var(--ease),background .25s var(--ease);
}
.btn:hover{transform:translateY(-2px);background:#fff}

/* Ticker: states the operational facts without a stat-card row, which every
   agency site has. Duplicated content is aria-hidden. */
.ticker{border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  overflow:hidden;padding:16px 0;margin-top:auto}
.ticker__track{display:flex;gap:26px;white-space:nowrap;width:max-content;
  animation:slide 46s linear infinite;font-family:var(--mono);font-size:12px;
  letter-spacing:.11em;text-transform:uppercase;color:var(--bone-3)}
.ticker i{color:var(--accent);font-style:normal}
@keyframes slide{from{transform:translateX(0)}to{transform:translateX(-50%)}}
@media (prefers-reduced-motion:reduce){
  /* This previously set flex-wrap:wrap + white-space:normal, which turned the marquee
     into a wall of twelve stacked lines on a phone — reported from a real device with
     Reduce Motion enabled, which is common on iOS. Honour the preference by stopping the
     ANIMATION, not by re-flowing the layout: keep the single line and let it be scrolled
     by hand. */
  .ticker{overflow-x:auto;scrollbar-width:none}
  .ticker::-webkit-scrollbar{display:none}
  .ticker__track{animation:none;flex-wrap:nowrap;white-space:nowrap;width:max-content}
}

/* ─────────────────────────  SECTIONS  ───────────────────────── */
.sec{padding:clamp(90px,13vh,170px) var(--gap);max-width:var(--maxw);margin:0 auto}
.sec--social,.sec--video{border-top:1px solid var(--line)}
.sec__head{max-width:780px;margin-bottom:clamp(40px,6vw,72px)}
.num{font-family:var(--mono);font-size:12px;letter-spacing:.2em;color:var(--accent);margin:0 0 14px}
.sec h2{font-size:clamp(34px,6.2vw,74px);margin-bottom:22px}
.sec__lede{font-size:clamp(15.5px,1.75vw,19px);color:var(--bone-2);max-width:62ch}
.sec__foot{margin-top:44px;color:var(--bone-3);font-size:15px;max-width:60ch}
.sec__foot em{color:var(--bone-2);font-style:italic}

.stats{display:flex;flex-wrap:wrap;gap:32px 54px;margin:34px 0 0;padding:0}
.stats div{margin:0}
.stats dt{font-family:var(--mono);font-size:10.5px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--bone-3);margin-bottom:6px}
.stats dd{margin:0;font-size:clamp(24px,3.4vw,38px);font-weight:800;letter-spacing:-.03em;
  font-variant-numeric:tabular-nums}

/* ───────────  1 · the wall  ─────────── */
.wall{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(10px,1.4vw,20px);align-items:start}
.wall__col{display:flex;flex-direction:column;gap:clamp(10px,1.4vw,20px);will-change:transform}
.wall__col:nth-child(even){margin-top:clamp(24px,5vw,64px)}
.wall figure{margin:0;position:relative;overflow:hidden;border-radius:5px;background:var(--ink-2)}
.wall img{width:100%;height:auto;transition:transform .8s var(--ease),filter .5s var(--ease);
  filter:saturate(.94)}
.wall figure:hover img{transform:scale(1.035);filter:saturate(1.06)}
.wall figcaption{
  position:absolute;left:0;right:0;bottom:0;padding:26px 12px 10px;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--bone);background:linear-gradient(transparent,rgba(6,7,9,.86));
  opacity:0;transform:translateY(6px);transition:opacity .3s var(--ease),transform .3s var(--ease);
}
.wall figure:hover figcaption,.wall figure:focus-within figcaption{opacity:1;transform:none}

/* ───────────  2 · the rail  ─────────── */
.rail{
  display:flex;gap:clamp(12px,1.6vw,22px);overflow-x:auto;padding-bottom:22px;
  scroll-snap-type:x mandatory;scrollbar-width:thin;
  scrollbar-color:var(--line) transparent;
  /* break the max-width so the rail runs to the edge — motion work should feel
     like it continues past the frame */
  margin-inline:calc(var(--gap)*-1);padding-inline:var(--gap);
}
.rail::-webkit-scrollbar{height:6px}
.rail::-webkit-scrollbar-thumb{background:var(--line);border-radius:99px}
.card{margin:0;flex:0 0 clamp(190px,23vw,268px);scroll-snap-align:start}
.card__img{border-radius:6px;overflow:hidden;background:var(--ink-2);aspect-ratio:9/16}
.card__img img{width:100%;height:100%;object-fit:cover;transition:transform .7s var(--ease)}
.card:hover .card__img img{transform:scale(1.04)}
.card figcaption{padding-top:14px;display:flex;flex-direction:column;gap:3px}
.card b{font-size:14.5px;font-weight:700}
.card span{font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--bone-3)}

.feature{display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(24px,4vw,58px);
  align-items:center;margin-top:clamp(56px,8vw,96px);
  border-top:1px solid var(--line);padding-top:clamp(40px,6vw,68px)}
.feature__media{border-radius:8px;overflow:hidden;background:var(--ink-2)}
.feature h3{font-size:clamp(28px,4vw,44px);margin-bottom:16px}
.feature p{color:var(--bone-2);margin-bottom:14px;max-width:52ch}
.pills{list-style:none;display:flex;flex-wrap:wrap;gap:8px;padding:0;margin:22px 0 0}
.pills li{font-family:var(--mono);font-size:10.5px;letter-spacing:.13em;text-transform:uppercase;
  color:var(--bone-2);border:1px solid var(--line);border-radius:999px;padding:7px 13px}

/* ───────────  3 · cases  ─────────── */
/* Stacked, not side-by-side. The comparison IS the case study — squeezing it into a half-
   width column made the single most persuasive thing on the page the smallest. Text above,
   slider full width beneath it, so the work is seen at something close to real size. */
.case{margin-bottom:clamp(72px,10vw,132px)}
.case__meta{max-width:62ch;margin-bottom:clamp(20px,3vw,34px)}
.case h3{font-size:clamp(28px,4.2vw,50px);margin-bottom:16px}
.case p{color:var(--bone-2);margin-bottom:14px}
.case__hint{font-family:var(--mono);font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--bone-3);margin-top:16px;text-align:center}

/* before/after — the single strongest proof a portfolio can carry */
/* Full-bleed to the section edges and a shallower ratio, so the comparison is large enough
   to actually read the old site against the new one. */
.compare{position:relative;border-radius:10px;overflow:hidden;background:var(--ink-2);
  cursor:ew-resize;touch-action:pan-y;user-select:none;aspect-ratio:16/10;
  box-shadow:0 24px 70px -30px rgba(0,0,0,.9);border:1px solid var(--line)}
.compare img{width:100%;height:100%;object-fit:cover;object-position:top center;pointer-events:none}
/* CLIP-PATH, not width. Two earlier attempts sized the "before" layer by changing its own
   width — first with `min-width:100%` (which squeezed the image as the handle moved) and
   then by pinning a pixel width from JS (which rendered it 0px wide, and therefore blank,
   whenever the script ran before layout had settled).
   Both were the same mistake: making the image's SIZE do the job of a MASK. With clip-path
   the layer is always full size and perfectly aligned with the layer beneath it; only the
   visible region changes. Nothing can squeeze, and nothing depends on JS for geometry. */
.compare__clip{position:absolute;inset:0;width:100%;overflow:hidden;
  clip-path:inset(0 50% 0 0);will-change:clip-path}
.compare__clip img{width:100%;height:100%;object-fit:cover;object-position:top center}
.compare__handle{position:absolute;top:0;bottom:0;left:50%;width:2px;background:var(--bone);
  transform:translateX(-1px);will-change:left;pointer-events:none}
.compare__handle span{position:absolute;top:50%;left:50%;width:42px;height:42px;
  transform:translate(-50%,-50%);border-radius:50%;background:var(--bone);
  box-shadow:0 4px 18px rgba(0,0,0,.5)}
.compare__handle span::before,.compare__handle span::after{
  content:"";position:absolute;top:50%;width:0;height:0;border:5px solid transparent}
.compare__handle span::before{left:8px;border-right-color:var(--ink);transform:translateY(-50%)}
.compare__handle span::after{right:8px;border-left-color:var(--ink);transform:translateY(-50%)}
.compare__tag{position:absolute;bottom:14px;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.16em;text-transform:uppercase;background:rgba(8,9,12,.74);
  color:var(--bone);padding:6px 11px;border-radius:4px;pointer-events:none}
.compare__tag--l{left:14px}.compare__tag--r{right:14px}
/* The double-click is the shortcut, not the affordance. Nobody double-clicks a photograph on
   spec, and on a phone a double-tap is the browser's zoom gesture — so the way OUT of the
   comparison and into the real site has to be a real link you can see, tab to and tap once. */
/* Below the frame, not inside it (Danny 2026-08-11). It began in the top right corner, where it
   landed on Fischpan's own phone number and read like a button on HIS site; moving it down to
   sit beside our Before/After tags fixed the confusion but still spent pixels of the screenshot
   the visitor came to look at. Out here it owes the comparison nothing, and it can be a plain
   centred link that survives any screenshot we ever put behind it. */
.case__visit{display:block;width:max-content;max-width:100%;margin:14px auto 0;
  font-family:var(--mono);font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--bone);background:var(--ink-2);padding:11px 20px;border-radius:5px;
  text-decoration:none;border:1px solid var(--line);text-align:center;
  transition:background .18s ease,border-color .18s ease,color .18s ease}
.case__visit:hover,.case__visit:focus-visible{background:var(--ink);border-color:var(--bone)}
@media (max-width:700px){.case__visit{font-size:10.5px;padding:10px 16px;letter-spacing:.1em}}

/* min-width:0 is the whole fix here. A grid item defaults to min-width:auto, meaning it
   refuses to shrink below its content's intrinsic size — and this grid holds 1400px-wide
   screenshots. Two of them set an intrinsic floor of ~2800px, so the column blew past the
   viewport and the case study rendered enormous and cropped. Every grid/flex child that
   contains an image needs this, which is why the rule below is broad rather than targeted. */
.shots{display:grid;grid-template-columns:1fr 1fr;gap:clamp(10px,1.4vw,16px);min-width:0}
.shots img{width:100%;height:auto;border-radius:6px;background:var(--ink-2)}
.case>*,.feature>*,.wall__col,.rail>*{min-width:0}

/* ───────────  demonstration builds  ───────────
   Two side by side rather than full bleed like the case studies above. That is a
   deliberate demotion: the client work is the argument, these are the sample, and
   giving spec work the same width as a paid rebuild would misrepresent both. Pairing
   them also states what they are — one format, two houses — in the layout itself.

   The media box is 16/10 to match the recordings exactly, so the poster, the video
   and the reserved space are all the same shape and nothing shifts on load. */
.demos__head{border-top:1px solid var(--line);padding-top:clamp(38px,5vw,62px);
  max-width:66ch;margin-bottom:clamp(28px,4vw,44px)}
.demos__head h3{font-size:clamp(26px,3.6vw,42px);margin-bottom:16px}
.demos__head p{color:var(--bone-2)}
/* Two across, in two rows. Four narrow columns would put a ~274px column under a
   15.5px paragraph — about 19 characters a line — and squeeze the credit into a
   ten-line block. Two across is also the only even split that cannot orphan a
   card, and the wider column is CHEAPER than the old three-up on quality terms:
   ~596px at the 1240px cap paints 1192 device px on a retina screen, still under
   the 1280px source frame, so the tile is not upscaled here either. */
.demos{display:grid;grid-template-columns:repeat(2,1fr);gap:clamp(22px,3.4vw,48px);min-width:0}
/* Flex column with the credit pushed to the bottom, so the cards line their
   credits and their buttons up with each other even though one description runs
   two lines longer than the others. Rows are independent grid rows, so this does
   the work within a row; `align-items` cannot do it across rows. */
.demo{margin:0;min-width:0;display:flex;flex-direction:column}
.demo__media{position:relative;display:block;border-radius:10px;overflow:hidden;
  background:var(--ink-2);border:1px solid var(--line);aspect-ratio:16/10;
  box-shadow:0 24px 70px -34px rgba(0,0,0,.9)}
/* object-fit:cover on both layers: the poster and the video must crop identically or the
   frame visibly jumps at the moment playback starts. */
.demo__vid{width:100%;height:100%;object-fit:cover;display:block;
  transition:transform .8s var(--ease)}
.demo__media:hover .demo__vid{transform:scale(1.015)}
/* This label began as a chip inside the frame and had to come out. The pages being
   recorded put their own headline in the bottom-left corner, so wherever the chip
   sat it covered somebody's copy — on a phone it landed squarely across "Your
   listing photos, walked through". A caption underneath owes the picture nothing. */
.demo__hint{font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--bone-3);margin:12px 0 0}
/* The nudge to open these on a desktop is the one line here that has to persuade, so it
   is set in the body face at reading size rather than in the 10.5px uppercase mono above
   it — letter-spaced caps are a label, and nobody reads three lines of them. */
/* The nudge to open these on a desktop is the one line here that has to persuade, so it
   is set in the body face at reading size rather than in the 10.5px uppercase mono of the
   captions — letter-spaced caps are a label, and nobody reads three lines of them. It sits
   in the section head, not on the cards: three identical copies of it read as filler. */
.demos__desktop{font-size:14px;line-height:1.6;color:var(--bone-2);margin:16px 0 0;max-width:60ch}
.demo__body{padding-top:20px;display:flex;flex-direction:column;flex:1}
.demo__body h4{font-size:clamp(21px,2.5vw,28px);margin:0 0 6px;letter-spacing:-.02em}
.demo__body p{color:var(--bone-2);margin:0 0 14px;font-size:15.5px}
/* Both of these have to be scoped under .demo__body to outrank the plain `p` rule
   above them. Unscoped they lose on specificity, however far down the file they
   sit — which silently reset the credit's auto margin and left the two buttons
   25px out of line with each other. */
.demo__body .demo__where{font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--accent);margin:0 0 14px}
/* The credit is the part that stops this being a claim about work we were hired to do,
   so it is quiet but never hidden — small, dimmed, and always in the flow of the card.
   margin-top:auto eats whatever slack the shorter card has, so the credit and the
   button below it sit flush with the bottom of both cards and the two calls to action
   line up with each other. */
.demo__body .demo__credit{font-size:12.5px;color:var(--bone-3);line-height:1.5;
  margin:auto 0 0;padding-top:22px;border-top:1px solid var(--line)}
.demo__visit{margin-left:0;margin-top:18px}
@media (max-width:1100px){
  .demos{grid-template-columns:1fr;gap:clamp(38px,7vw,56px)}
}
@media (prefers-reduced-motion:reduce){
  .demo__vid,.demo__media:hover .demo__vid{transition:none;transform:none}
}

/* ───────────  4 · handover  ─────────── */
.sec--hand{border-top:1px solid var(--line)}
.hand{max-width:900px}
.hand__list{list-style:none;counter-reset:h;padding:0;margin:44px 0 0;
  display:grid;grid-template-columns:1fr 1fr;gap:0}
.hand__list li{counter-increment:h;padding:22px 26px 22px 0;border-top:1px solid var(--line);
  display:flex;flex-direction:column;gap:5px}
.hand__list li::before{content:"0" counter(h);font-family:var(--mono);font-size:10.5px;
  letter-spacing:.16em;color:var(--accent);margin-bottom:4px}
.hand__list b{font-size:17px;font-weight:700}
.hand__list span{color:var(--bone-3);font-size:14.5px}

/* ─────────────────────────  FOOT  ───────────────────────── */
.foot{border-top:1px solid var(--line);padding:clamp(70px,10vh,120px) var(--gap);
  max-width:var(--maxw);margin:0 auto;text-align:center}
.foot .eyebrow{margin-bottom:16px}
.foot__big{font-size:clamp(26px,4.6vw,58px);font-weight:800;letter-spacing:-.03em;
  line-height:1.06;text-wrap:balance;margin-bottom:18px;max-width:100%}
.foot__lede{color:var(--bone-2);font-size:clamp(15px,1.7vw,18px);max-width:52ch;
  margin:0 auto clamp(28px,4vw,44px)}
/* The address is the call to action, so it is sized like one rather than tucked into small
   print. Underline offset keeps the descenders clear at this weight. */
.foot__mail{display:inline-block;font-size:clamp(20px,3.4vw,40px);font-weight:800;
  letter-spacing:-.02em;color:var(--bone);text-decoration:underline;
  text-decoration-color:var(--accent);text-decoration-thickness:2px;text-underline-offset:7px;
  word-break:break-word;transition:color .25s var(--ease),text-decoration-color .25s var(--ease)}
.foot__mail:hover{color:var(--accent);text-decoration-color:var(--bone)}
.foot__small{font-family:var(--mono);font-size:11px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--bone-3);margin-top:clamp(34px,5vw,56px)}

/* ─────────────────────────  REVEAL  ─────────────────────────
   Content is VISIBLE BY DEFAULT. The hidden-then-reveal state only exists once JS has
   confirmed it is running, by putting .js-reveal on <html>.

   This is not defensive tidiness — it is the difference between a portfolio and a blank
   page. Hiding first and revealing later means any failure in between (JS blocked, a
   script error, an observer that evaluated against a zero-size viewport — which is exactly
   what happened here) leaves the client looking at nothing at all. Whatever goes wrong,
   the work should still be on screen. */
.js-reveal .reveal{opacity:0;transform:translateY(22px);
  transition:opacity .7s var(--ease),transform .7s var(--ease)}
.js-reveal .reveal.in{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){
  .reveal{opacity:1;transform:none;transition:none}
  .wall__col{transform:none!important}
  .wall img,.card__img img{transition:none}
}

/* ─────────────────────────  RESPONSIVE  ───────────────────────── */
@media (max-width:900px){
  .feature,.case,.case--alt{grid-template-columns:1fr}
  .case--alt .case__meta{order:0}
  .wall{grid-template-columns:repeat(3,1fr)}
  /* The wall is four hand-built columns. Narrowing the GRID to three or two does not
     re-flow them -- it wraps the spare column onto a row of its own and leaves a
     column-wide hole beside it, which is exactly what a phone showed on 2026-08-06:
     everything below the second cover ran single-file down the left with the right
     half empty. Below 900px the columns stop being layout and the covers become grid
     items themselves, so they pack. The counts are chosen to come out even: 15 covers
     across three columns, and 12 across two once the fourth column is dropped. */
  .wall__col{display:contents}
  .hand__list{grid-template-columns:1fr}
}
@media (max-width:620px){
  .wall{grid-template-columns:repeat(2,1fr)}
  /* Still a real display:none, not display:contents -- it has to remove those three
     covers, and it only wins because it is declared after the rule above. */
  .wall__col--hide-sm{display:none}
  .wall__col{transform:none!important}   /* no parallax on a small screen */
  .stats{gap:22px 34px}
  .compare{aspect-ratio:4/3}
  .shots{grid-template-columns:1fr}
}

/* ─────────────────────────  NAV  ─────────────────────────
   Added 2026-08-06. Same restraint as everything else on the page: mono caps
   at eyebrow scale, the numerals in --accent because that is the only job the
   accent has here, and no colour anywhere else.

   STICKY, NOT REVEALED (Danny 2026-08-06: "static and visible, not a dropdown").
   An earlier version slid in once you left the hero; a bar that appears out of
   nowhere reads as a dropdown and makes the page feel like it is reacting to
   you. `sticky` keeps it in normal flow at the top — so it occupies its own
   space instead of covering the headline — and then pins as you scroll. It is
   present from the first frame and never animates. */
.nav{
  position:sticky;top:0;z-index:80;
  background:color-mix(in srgb, var(--ink) 88%, transparent);
  border-bottom:1px solid var(--line);
}
@supports (backdrop-filter:blur(10px)){
  .nav{backdrop-filter:blur(14px) saturate(1.3)}
}

.nav__inner{
  max-width:var(--maxw);margin:0 auto;min-width:0;
  padding:0 var(--gap);height:60px;
  display:flex;align-items:center;justify-content:space-between;gap:var(--gap);
}
.nav__mark{
  font-family:var(--mono);font-size:12px;letter-spacing:.18em;text-transform:uppercase;
  font-weight:700;color:var(--bone);text-decoration:none;white-space:nowrap;flex:none;
}
.nav__mark span{border-bottom:1px solid var(--accent);padding-bottom:2px}

.nav__list{
  list-style:none;margin:0;padding:0;min-width:0;
  display:flex;align-items:center;gap:clamp(14px,2.4vw,30px);
  /* On a narrow screen the titles scroll sideways instead of collapsing into a
     hamburger: one tap fewer, no JS, and the section names stay legible — which
     is the entire point of the bar. */
  overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;
  scrollbar-width:none;
}
.nav__list::-webkit-scrollbar{display:none}
.nav__list a{
  display:inline-flex;align-items:baseline;gap:7px;white-space:nowrap;
  font-family:var(--mono);font-size:11.5px;letter-spacing:.13em;text-transform:uppercase;
  color:var(--bone-3);text-decoration:none;padding:6px 0;
  border-bottom:1px solid transparent;
  transition:color .25s var(--ease),border-color .25s var(--ease);
}
.nav__list i{font-style:normal;color:var(--accent);font-size:10px;letter-spacing:.08em}
.nav__list a:hover{color:var(--bone)}
.nav__list a[aria-current="true"]{color:var(--bone);border-bottom-color:var(--accent)}

/* The pinned bar would otherwise cover the top of whatever a link jumps to. */
.sec,.hero{scroll-margin-top:60px}
/* The bar now takes 60px of real layout at the top, so a 100svh hero would push
   the page just past one screen and invent a scrollbar on the first view. */
.hero{min-height:calc(100svh - 60px)}

@media (max-width:640px){
  .nav__inner{height:54px;gap:14px}
  .nav__mark{font-size:11px;letter-spacing:.14em}
  /* The numerals are the first thing to go when space is tight — the words carry
     the meaning, the numbers are decoration at this size. */
  .nav__list i{display:none}
  .sec,.hero{scroll-margin-top:54px}
  .hero{min-height:calc(100svh - 54px)}
}

/* ─────────────────────────  LEAD FORM  ─────────────────────────
   Added 2026-08-06. Deliberately plain: dark fields, one accent line on focus, nothing that
   looks like a marketing funnel. The page argues for restraint; the form has to agree with it.

   Inputs are 16px on purpose. Anything smaller makes iOS Safari zoom the whole page on focus,
   which on a phone reads as the site breaking the moment you try to contact someone. */
.lead{margin:34px 0 26px;max-width:640px;display:flex;flex-direction:column;gap:16px}
.lead__row{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.lead__f{display:flex;flex-direction:column;gap:7px;min-width:0}
.lead__f span{font-family:var(--mono);font-size:10.5px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--bone-3)}
.lead input,.lead textarea{
  font:400 16px/1.5 var(--sans);color:var(--bone);background:var(--ink-2);
  border:1px solid var(--line);border-radius:8px;padding:13px 14px;width:100%;
  transition:border-color .2s var(--ease),background .2s var(--ease);
  -webkit-appearance:none;appearance:none;
}
.lead textarea{resize:vertical;min-height:110px}
.lead input:focus,.lead textarea:focus{outline:none;border-color:var(--accent);background:var(--ink-3)}
.lead input:user-invalid,.lead textarea:user-invalid{border-color:var(--crit,#c8686b)}
.lead__send{align-self:flex-start;margin-top:4px;border:0;cursor:pointer;font-family:var(--mono)}
.lead__send[disabled]{opacity:.55;cursor:default}
.lead__note{font-size:13px;color:var(--bone-2);min-height:1.2em}
.lead__note.is-bad{color:#e0908f}
.lead__note.is-good{color:#8fd6a8}
/* Off-screen rather than display:none — some bots skip hidden fields but not positioned ones. */
.lead__hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.foot__or{font-size:13.5px;color:var(--bone-3)}
.foot__or .foot__mail{font-size:inherit}

@media (max-width:620px){
  .lead__row{grid-template-columns:1fr}
  .lead__send{align-self:stretch;text-align:center}
}

/* ─────────────────────  CLICKABLE WORK  ─────────────────────
   Added 2026-08-06. Every cover, frame and episode still links to the channel it came from, so
   the portfolio proves itself: a visitor can go and see the account rather than take our word.

   `display:block` matters — an inline <a> around a block image adds a phantom descender and
   knocks the wall columns out of alignment. All three wrappers are blocks. */
.wall__link,.card__link,.feature__link{display:block;text-decoration:none;color:inherit;
  border-radius:inherit;position:relative;-webkit-tap-highlight-color:transparent}
.wall__link{overflow:hidden;border-radius:4px}
.feature__link{overflow:hidden;border-radius:8px}

/* The affordance is deliberately quiet: the work is the hero, not the interaction. */
.wall__link img,.card__link img,.feature__link img{transition:transform .55s var(--ease),
  filter .35s var(--ease)}
.wall__link:hover img,.card__link:hover img,.feature__link:hover img{transform:scale(1.03)}
.feature__link:hover img{transform:scale(1.02)}

/* Focus must be obvious for keyboard users even though hover is subtle. */
.wall__link:focus-visible,.card__link:focus-visible,.feature__link:focus-visible{
  outline:2px solid var(--accent);outline-offset:3px}

@media (prefers-reduced-motion:reduce){
  .wall__link img,.card__link img,.feature__link img{transition:none}
  .wall__link:hover img,.card__link:hover img,.feature__link:hover img{transform:none}
}
/* On touch there is no hover, so the scale would fire on tap and look like a glitch. */
@media (hover:none){
  .wall__link:hover img,.card__link:hover img,.feature__link:hover img{transform:none}
}
