/* ==========================================================
   LUKAS GILL — PORTFOLIO  (v3)
   warm paper · navy accent · carousel · micro-motion
   ----------------------------------------------------------
   EDIT COLORS + FONTS HERE. Everything inherits these.
   ========================================================== */

/* Melange Grotesk - licensed from Kimera (kimeracorp.eu), self-hosted.
   To swap a weight, drop the .woff2 in /fonts/ and add a block below. */
@font-face{ font-family:"Melange"; src:url("fonts/KMRMelangeGrotesk-Medium.woff2") format("woff2");
  font-weight:500; font-style:normal; font-display:swap; }
@font-face{ font-family:"Melange"; src:url("fonts/KMRMelangeGrotesk-SemiBold.woff2") format("woff2");
  font-weight:600; font-style:normal; font-display:swap; }
@font-face{ font-family:"Melange"; src:url("fonts/KMRMelangeGrotesk-Bold.woff2") format("woff2");
  font-weight:700; font-style:normal; font-display:swap; }
@font-face{ font-family:"Melange"; src:url("fonts/KMRMelangeGrotesk-ExtraBold.woff2") format("woff2");
  font-weight:800; font-style:normal; font-display:swap; }

:root{
  --paper:    #EFEFEC;   /* cool paper - light, neutral, no almond */
  --ink:      #171716;   /* near-black, neutral */
  --zinc:     #E4E4E1;   /* panel grey - exactly the render stage colour */
  --graphite: #6E6E68;   /* muted metadata text */
  --line:     #D4D4D0;   /* hairlines */

  /* ACCENT - one line to change the whole site's color story.
     Current: deep navy w/ a grey tinge.
     Alternates:  #1533E0 cobalt · #FF4B00 orange · #E22B12 signal red */
  --accent:   #1B294B;
  --on-accent:#EFEFEC;

  --pad: 16px;
  --gap: 20px;
  --maxw: 1680px;        /* content stops growing here and centres */

  --ease: cubic-bezier(.22,.61,.36,1);
  /* One family, two jobs: Melange for display AND for spec labels. */
  --sans: "Melange","Helvetica Neue",Arial,sans-serif;
  --mono: "Melange","Helvetica Neue",Arial,sans-serif;
}

*{ box-sizing:border-box; }
/* Sticky footer, done without changing body's display. Making body a flex or
   grid container collapsed every page to its content width, which is what
   turned the desktop layout into the mobile one. Reserving height on main
   pushes the footer down and touches nothing else. */
main{ min-height:calc(100dvh - 190px); }
@media (max-width:760px){ main{ min-height:calc(100dvh - 210px); } }
body{ margin:0; }
body{
  background:var(--paper); color:var(--ink);
  font-family:var(--sans); font-weight:500; font-size:15px; line-height:1.5;
  -webkit-font-smoothing:antialiased;
}
a{ color:inherit; text-decoration:none; }
body{ -webkit-tap-highlight-color:rgba(27,41,75,.25); }

/* Melange ships eleven stylistic sets and a full figure kit. These three
   are switched on site-wide:
     case  hyphens and brackets rise to cap height in uppercase labels
     tnum  tabular figures - scoped to the resume date column only
     ss01  the single-storey geometric "a"
   Others available if wanted: zero slashed zero, ss02 alt l, ss03 alt t,
   ss04 alt u, ss05 alt G, ss06 alt I, ss07 alt J, ss08 alt R,
   ss09 schoolbook set, ss10 round punctuation. */
body{ font-feature-settings:"case" 1,"ss01" 1; }
/* tabular figures only where numbers stack in a column. Site-wide they
   spaced out every year and turned "2.1" into "2 . 1". */
.row .when{ font-feature-settings:"case" 1,"tnum" 1; }
a:focus-visible, button:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
img{ display:block; width:100%; height:100%; object-fit:cover; }
.frame picture{ display:block; width:100%; height:100%; }
main{ padding:0 var(--pad); max-width:var(--maxw); margin-inline:auto; }
@media (prefers-reduced-motion:no-preference){ html{ scroll-behavior:smooth; } }
::selection{ background:var(--accent); color:var(--on-accent); }

/* tactile press — every interactive element "clicks" down 1px */
a:active, button:active{ transform:translate(1px,1px); }

/* (hatched drafting band removed in Rev 12 - see README to restore) */

/* ----------------------------------------------------------
   HEADER — no bar. Floating text; the nav links follow you down.
   ---------------------------------------------------------- */
.top{
  position:sticky; top:0; z-index:30;
  display:flex; justify-content:flex-end; align-items:baseline;
  gap:18px; flex-wrap:wrap;
  padding:12px var(--pad) 10px;
  max-width:var(--maxw); margin-inline:auto;
  pointer-events:none;            /* only the text itself is clickable */
}
.top a{ pointer-events:auto; }
.brand{
  font-weight:800;
  text-transform:uppercase; letter-spacing:.02em; font-size:12.5px;
}
/* homepage: the small name only exists once the big one has scrolled away */
.brand--reveal{ opacity:0; pointer-events:none !important;
  transition:opacity .22s var(--ease); }
.brand--reveal.show{ opacity:1; pointer-events:auto !important; }
.nav{ display:flex; gap:16px; flex-wrap:wrap; margin-right:-6px; }
.nav a{
  font-family:var(--mono); font-size:11px; font-weight:700;
  text-transform:uppercase; letter-spacing:.06em;
  padding:4px 6px;
  transition:background .18s var(--ease), color .18s var(--ease);
}
.nav a:hover{ background:var(--accent); color:var(--on-accent); }
.nav a[aria-current="page"]{ box-shadow:inset 0 -2px 0 var(--ink); }

/* ----------------------------------------------------------
   HOME HERO
   ---------------------------------------------------------- */
.hero{
  /* Callout pinned to the top, name pinned to the bottom, and the gap between
     them is the composition rather than leftover space. Same move as the card. */
  min-height:68vh; min-height:68svh;
  display:flex; flex-direction:column; justify-content:space-between;
  padding-top:22px;
}
.hero .dim{ margin-bottom:0; }
.hero-foot{ display:flex; flex-direction:column; }
@media (max-width:760px){
  .hero{ min-height:60vh; min-height:60svh; padding-top:14px; }
}
.wordmark{
  margin:0;
  font-weight:800;
  text-transform:uppercase; letter-spacing:-.025em;
  font-weight:800; line-height:.82; white-space:nowrap;
  /* 16.5% of the container. Past --maxw the viewport keeps growing but the
     container does not, so vw alone would size the name off the grid. */
  font-size:min(16.5vw, 277px);
  margin-left:-0.035em;              /* optical: big L's sidebearing */
  /* script.js scales this up so the name spans the full width */
  animation:rise .7s cubic-bezier(.2,.7,.2,1) both;
}
@keyframes rise{ from{ opacity:0; transform:translateY(26px); } }

/* drafting dimension callout above the name:  |———  label  ———| */
.dim{
  display:flex; align-items:center; gap:12px;
  margin-bottom:16px;
  font-family:var(--mono); font-size:10.5px;
  text-transform:uppercase; letter-spacing:.03em; color:var(--graphite);
}
.dim i{ flex:1; height:9px; border-bottom:1px solid var(--graphite); position:relative; }
.dim i::before{ content:""; position:absolute; bottom:-4px; width:1px; height:9px; background:var(--graphite); }
.dim i:first-child::before{ left:0; }
.dim i:last-child::before{ left:auto; right:0; }
.dim .sq{ width:9px; height:9px; background:var(--accent); flex:0 0 auto; }
.hero-sub{
  display:flex; justify-content:space-between; gap:12px; flex-wrap:wrap;
  padding:10px 0 26px;
  font-family:var(--mono); font-size:11px; text-transform:uppercase;
}

/* ----------------------------------------------------------
   PROJECT INDEX
   ---------------------------------------------------------- */
.sec{
  display:flex; justify-content:space-between; align-items:baseline;
  margin:30px 0 14px;
}
.sec h2{
  margin:0; font-size:12px; font-weight:700;
  letter-spacing:.08em; text-transform:uppercase;
}
.cap{
  font-family:var(--mono); font-size:10.5px;
  text-transform:uppercase; letter-spacing:.02em; color:var(--graphite);
}

.grid{ display:grid; grid-template-columns:1fr 1fr; gap:var(--gap); }

/* Secondary tier. Smaller cards in a three-up row so the flagship projects
   keep the visual weight - a portfolio should be ranked, not flat. */
.grid--minor{
  display:grid; grid-template-columns:repeat(3, 1fr); gap:var(--gap);
  margin-top:calc(var(--gap) * 2);
}
.grid--minor .title{ font-size:13px; }
.grid--minor .meta { font-size:10px; }
@media (max-width:760px){
  .grid--minor{ grid-template-columns:1fr 1fr; gap:12px; }
}
.card{ display:block; }
.card--wide{ grid-column:1 / -1; }

.frame{
  position:relative; overflow:hidden;
  border:1px solid var(--line);
  background-color:var(--zinc);
  transition:border-color .18s var(--ease);
}
.card:hover .frame{ border-color:var(--ink); }
.r219{ aspect-ratio:21/9; }
.r169{ aspect-ratio:16/9; }
.r43 { aspect-ratio:4/3;  }
.r11 { aspect-ratio:1/1;  }
.r45 { aspect-ratio:4/5;  }

/* NO-CROP FRAME. The frame takes its height from the image instead of
   forcing the image into a fixed box, so object-fit never has anything to
   trim. Use this for any photograph that is already framed the way it
   should appear. Cropping here is structurally impossible. */
.frame--nat{ aspect-ratio:auto; }
.frame--nat img{ height:auto; object-fit:fill; }
.ph{
  position:absolute; inset:0;
  display:flex; align-items:center; justify-content:center;
  padding:12px; text-align:center;
  font-family:var(--mono); font-size:10.5px;
  text-transform:uppercase; color:var(--graphite);
}

.cap-row{
  display:flex; justify-content:space-between; align-items:baseline; gap:10px;
  margin-top:9px;
}
.cap-row .title{
  font-size:12.5px; font-weight:700;
  letter-spacing:.05em; text-transform:uppercase;
  padding:2px 5px; margin-left:-5px;
  transition:background .18s var(--ease), color .18s var(--ease);
}
.card:hover .title,
a.card:focus-visible .title{ background:var(--accent); color:var(--on-accent); }
.idx{ font-family:var(--mono); font-size:11px; color:var(--graphite); transition:color .18s var(--ease); }
.card:hover .idx{ color:var(--accent); }
.meta{
  margin:3px 0 0;
  font-family:var(--mono); font-size:11px; line-height:1.7;
  text-transform:uppercase; color:var(--graphite);
}

/* scroll-reveal (class added by script.js; no-JS users see everything) */
.rv{ opacity:0; transform:translateY(12px);
     transition:opacity .6s var(--ease), transform .6s var(--ease); }
.rv.in{ opacity:1; transform:none; }

/* ----------------------------------------------------------
   PROJECT DETAIL - SE-store split: specs left, product right
   ---------------------------------------------------------- */
.p-head{ padding-top:44px; }
.p-split{
  display:grid; grid-template-columns:minmax(320px,5fr) 6fr;
  gap:calc(var(--gap)*2); align-items:start;
  padding-top:44px; margin-bottom:var(--gap);
}
.p-split .cutsheet{ max-width:640px; }
.p-split .p-body{ max-width:none; margin-bottom:0; }
.p-hero{ margin:0; }
/* The hero always fills its column at a true 4:5, so its edges line up with
   the full-width figures further down the page. No height cap: the content
   container is capped at --maxw, which keeps the tallest case near 1120px.
   A hero that runs a little past the fold is fine and invites the scroll. */
.p-title--logo{ margin:0 0 24px; }
.p-title--logo img{ display:block; width:min(430px,84%); height:auto; }
.p-title--wide img{ width:min(600px,100%); }   /* the 3082 lockup is ~12:1 */
.frame--seamless{ border-color:transparent; background:none; }
.p-title{
  margin:0;
  font-weight:800;
  text-transform:uppercase; letter-spacing:-.02em;
  line-height:.85; font-size:clamp(34px, 5.6vw, 84px);
}

.cutsheet{
  max-width:620px; margin:24px 0 26px;
  border-top:1px solid var(--ink);
}
.cutsheet > div{
  display:grid; grid-template-columns:160px 1fr; gap:12px;
  padding:9px 0; border-bottom:1px solid var(--line);
}
.cutsheet .k{
  font-family:var(--mono); font-size:10.5px;
  text-transform:uppercase; color:var(--graphite); padding-top:2px;
}
.cutsheet .v{
  font-size:13px; font-weight:600;
  letter-spacing:.03em; text-transform:uppercase;
}

.p-body{ max-width:620px; margin:0 0 30px; font-size:16px; line-height:1.65; }

.stack{ display:grid; gap:var(--gap); }
/* align-items:start so a portrait and a square can sit side by side at their
   own proportions without either being cropped to match the other */
.stack .two{ display:grid; grid-template-columns:1fr 1fr; gap:var(--gap); align-items:start; }
figure{ margin:0; }
figcaption{
  display:flex; justify-content:space-between; gap:12px;
  padding:6px 0 0;
  font-family:var(--mono); font-size:10.5px; text-transform:uppercase;
}

/* ----------------------------------------------------------
   CAROUSEL — flip-through block (touch swipe + arrows + keys)
   ---------------------------------------------------------- */
.carousel{ position:relative; }
.c-track{
  display:flex; overflow-x:auto;
  scroll-snap-type:x mandatory; scroll-behavior:smooth;
  scrollbar-width:none; -ms-overflow-style:none;
  border:1px solid var(--line);
}
.c-track::-webkit-scrollbar{ display:none; }
.c-slide{
  flex:0 0 100%; scroll-snap-align:start; position:relative;
  background-color:var(--zinc);
  aspect-ratio:16/9;
}
.c-bar{
  display:flex; align-items:center; gap:12px;
  padding:6px 0 0;
  font-family:var(--mono); font-size:10.5px; text-transform:uppercase;
}
.c-cap{ flex:1; display:flex; justify-content:space-between; gap:12px; }
.c-count{ color:var(--graphite); }
.cbtn{
  width:34px; height:30px;
  display:inline-flex; align-items:center; justify-content:center;
  border:1px solid var(--ink); background:var(--paper); color:var(--ink);
  font-family:var(--mono); font-size:13px; cursor:pointer;
  transition:background .18s var(--ease), color .18s var(--ease), opacity .18s var(--ease);
}
.cbtn:hover{ background:var(--accent); color:var(--on-accent); border-color:var(--accent); }
.cbtn[aria-disabled="true"]{ opacity:.3; pointer-events:none; }

/* Click the left/right half of the image to flip. The arrow is a real
   element that follows the pointer (a CSS `cursor:` image proved
   unreliable across browsers). Pointer devices only - never on touch. */
/* ----------------------------------------------------------
   CURSOR - one square, always. It never becomes a different shape.
   Four modifiers carry meaning, and they stack:
     fill   this responds to a click
     l / r  a hairline leads out the way the sequence will move
     rot    hairlines both sides: drag either way
     zoom   the square opens up to frame what will expand
     turn   45 degrees, used only for close
   The square is the site's own mark: same one in the dimension
   callout and the loader. Drawn with borders, nothing to load.
   ---------------------------------------------------------- */
.cur{
  position:fixed; top:0; left:0; z-index:1000; pointer-events:none;
  width:44px; height:44px; margin:-22px 0 0 -22px; display:none;
  opacity:0; transition:opacity .16s var(--ease);
  filter:drop-shadow(0 0 1.5px var(--paper)) drop-shadow(0 0 3px var(--paper));
}
@media (hover:hover) and (pointer:fine){ .cur{ display:block; } }
.cur.show{ opacity:1; }

/* the square */
.cur i{
  position:absolute; left:50%; top:50%;
  width:10px; height:10px; margin:-5px 0 0 -5px;
  border:1.5px solid var(--accent); background:transparent;
  transition:width .2s var(--ease), height .2s var(--ease), margin .2s var(--ease),
             background .2s var(--ease), transform .2s var(--ease);
}
.cur.fill i{ background:var(--accent); }
.cur.zoom i{ width:22px; height:22px; margin:-11px 0 0 -11px; }
.cur.turn i{ transform:rotate(45deg); }
.cur.down i{ transform:scale(.72); }
.cur.turn.down i{ transform:rotate(45deg) scale(.72); }

/* hairline leaders - drafting language, not a second shape */
.cur::before, .cur::after{
  content:""; position:absolute; top:50%; margin-top:-.75px;
  height:1.5px; width:0; background:var(--accent); opacity:0;
  transition:width .2s var(--ease), opacity .2s var(--ease);
}
.cur::before{ right:50%; margin-right:9px; }
.cur::after { left:50%;  margin-left:9px; }
.cur.l::before, .cur.rot::before,
.cur.r::after,  .cur.rot::after{ width:14px; opacity:1; }

/* Native cursors are hidden only once JS confirms the follower is alive,
   so a script failure leaves normal cursors rather than none at all.
   Text fields keep their caret. */
html.cur-on, html.cur-on *{ cursor:none !important; }
html.cur-on input, html.cur-on textarea{ cursor:text !important; }

/* ----------------------------------------------------------
   LIGHTBOX - click a figure to see it full size
   ---------------------------------------------------------- */
.lb{
  position:fixed; inset:0; z-index:900; display:none;
  background:color-mix(in srgb, var(--paper) 97%, transparent);
}
.lb.open{ display:grid; grid-template-rows:auto 1fr; }

.lb-bar{
  display:flex; justify-content:space-between; align-items:baseline; gap:14px;
  font-size:10px; font-weight:600; text-transform:uppercase; letter-spacing:.11em;
  color:var(--graphite); padding:10px var(--pad) 6px;
}
.lb-bar b{ color:var(--ink); font-weight:600; }
.lb-nav{ display:flex; gap:4px; }
.lb-nav button{
  font:inherit; letter-spacing:inherit; text-transform:inherit;
  border:1px solid var(--line); background:none; color:var(--ink);
  padding:5px 11px; min-width:40px;
  transition:background .18s var(--ease), color .18s var(--ease);
}
.lb-nav button:hover{ background:var(--accent); color:var(--on-accent); border-color:var(--accent); }

/* The stage fills everything under the bar. Nav zones are the full height of
   the stage, not just the picture, so the pointer never falls outside them. */
.lb-img{
  /* Even breathing room top and bottom, roughly a tenth of the picture. */
  position:relative; min-height:0;
  display:flex; align-items:center; justify-content:center;
  padding:0 clamp(56px, 9vw, 120px);
}
.lb-img img{
  /* One height for every image, width free to vary. Before this a square tile
     and a wide sheet opened at completely different sizes and flipping felt
     like the page was jumping. 80% of the stage leaves an even 10% of clear
     space above and below, and the cap stops a big monitor blowing anything up. */
  height:min(80vh, 1000px);
  width:auto; max-width:100%;
  object-fit:contain; cursor:pointer;
  animation:lbin .28s var(--ease) both;
  transition:transform .18s var(--ease), opacity .18s var(--ease);
  user-select:none; -webkit-user-drag:none;
}
@keyframes lbin{ from{ opacity:0; transform:scale(.985) } to{ opacity:1; transform:none } }

/* Persistent arrows, always in the same place regardless of how big the
   picture happens to be. This is what was missing: the affordance used to
   depend on the image's own edges. */
.lb-step{
  position:absolute; top:0; bottom:0; width:clamp(56px, 9vw, 120px);
  display:flex; align-items:center; justify-content:center;
  border:0; background:none; cursor:pointer; padding:0;
  color:var(--ink); opacity:.35;
  transition:opacity .2s var(--ease), background .2s var(--ease);
}
.lb-step:hover{ opacity:1; background:color-mix(in srgb, var(--ink) 5%, transparent); }
.lb-step--prev{ left:0; }
.lb-step--next{ right:0; }
.lb-step i{
  width:13px; height:13px; display:block;
  border-left:2.5px solid currentColor; border-bottom:2.5px solid currentColor;
}
.lb-step--prev i{ transform:rotate(45deg); }
.lb-step--next i{ transform:rotate(-135deg); }
@media (max-width:760px){
  .lb-img{ padding:0 8px var(--pad); }
  .lb-step{ width:44px; opacity:.22; }
  .lb-img img{ height:min(74%, 520px); }
}

[data-zoom]{ cursor:zoom-in; }

/* ----------------------------------------------------------
   BUILD ARCHIVE - the way into the deeper photo record. Shows what is
   behind the door rather than just naming it.
   ---------------------------------------------------------- */
.archive{
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:calc(var(--gap) * 1.5); align-items:center;
  border:1px solid var(--line); background:var(--zinc);
  padding:var(--gap); margin-top:calc(var(--gap) * 2);
  transition:background .22s var(--ease), border-color .22s var(--ease),
             color .22s var(--ease);
}
.archive-thumbs{ display:grid; grid-template-columns:repeat(4,1fr); gap:5px; }
.archive-thumbs img{
  width:100%; aspect-ratio:1/1; object-fit:cover; display:block;
  transition:transform .35s var(--ease);
}
.archive:hover .archive-thumbs img{ transform:scale(1.04); }
.archive-thumbs{ overflow:hidden; }
.archive-thumbs img:nth-child(2){ transition-delay:.03s; }
.archive-thumbs img:nth-child(3){ transition-delay:.06s; }
.archive-thumbs img:nth-child(4){ transition-delay:.09s; }

.archive-k{
  display:block; margin-top:6px; font-family:var(--mono); font-size:10px;
  font-weight:600; text-transform:uppercase; letter-spacing:.1em;
  color:var(--graphite); transition:color .22s var(--ease);
}
.archive-txt h3{
  margin:8px 0 8px; font-size:clamp(20px, 2.2vw, 28px); font-weight:800;
  text-transform:uppercase; letter-spacing:0; line-height:1.05;
}
.archive-txt p{
  margin:0 0 14px; max-width:44ch; font-size:14px; line-height:1.55;
  color:var(--graphite); transition:color .22s var(--ease);
}
.archive-go{
  display:inline-block; font-size:11px; font-weight:700;
  text-transform:uppercase; letter-spacing:.09em;
  border-bottom:2px solid var(--accent); padding-bottom:3px;
  transition:border-color .22s var(--ease);
}
.archive:hover{ background:var(--accent); color:var(--on-accent); border-color:var(--accent); }
.archive:hover .archive-k,
.archive:hover .archive-txt p{ color:var(--on-accent); }
.archive:hover .archive-go{ border-color:var(--on-accent); }

@media (max-width:760px){
  .archive{ grid-template-columns:1fr; gap:var(--gap); }
  .archive-thumbs{ order:-1; }
}

/* ----------------------------------------------------------
   SPOTLIGHT - a small preview row opens every photo in that group
   over a translucent field, the same feel as the lightbox. All
   inline-block: flex inside a clickable box is what broke this before.
   ---------------------------------------------------------- */
.strip{
  display:block; border:1px solid var(--line); background:var(--zinc);
  padding:10px; margin-top:var(--gap); cursor:pointer;
  transition:background .18s var(--ease), border-color .18s var(--ease), color .18s var(--ease);
}
.strip:hover{ background:var(--accent); border-color:var(--accent); color:var(--on-accent); }
.strip-row{
  /* must be a block: overflow has no effect on an inline box, so as a span
     this laid out at its full natural width and pushed the page sideways */
  display:block; white-space:nowrap; overflow:hidden; font-size:0;
}
.strip-row img{
  width:74px; height:74px; object-fit:cover;
  display:inline-block; vertical-align:middle; margin-right:4px;
}
.strip-row img:last-child{ margin-right:0; }
.strip-meta{
  display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; margin-top:9px;
  font-family:var(--mono); font-size:10px; font-weight:600;
  text-transform:uppercase; letter-spacing:.11em; color:var(--graphite);
}
.strip:hover .strip-meta{ color:var(--on-accent); }
.strip-meta b{ color:var(--ink); font-weight:800; font-size:12px; letter-spacing:0; }
.strip:hover .strip-meta b{ color:var(--on-accent); }

.spot{
  position:fixed; inset:0; z-index:890; display:none;
  width:100vw; max-width:100vw;
  background:color-mix(in srgb, var(--paper) 97%, transparent);
}
.spot.open{ display:block; animation:spotin .26s var(--ease) both; }
@keyframes spotin{ from{ opacity:0; transform:scale(.975) } to{ opacity:1; transform:none } }
.spot-head{
  position:sticky; top:0; z-index:2; background:var(--paper);
  border-bottom:1px solid var(--line); padding:12px var(--pad);
  font-family:var(--mono); font-size:10px; font-weight:600;
  text-transform:uppercase; letter-spacing:.11em; color:var(--graphite);
}
.spot-head b{ color:var(--ink); font-weight:800; font-size:15px; letter-spacing:0; margin-right:12px; }
.spot-head button{
  float:right; font:inherit; letter-spacing:inherit; text-transform:inherit;
  border:1px solid var(--line); background:none; color:var(--ink);
  padding:4px 11px; cursor:pointer;
}
.spot-head button:hover{ background:var(--accent); color:var(--on-accent); border-color:var(--accent); }
.spot-grid{
  height:calc(100% - 44px); overflow-y:auto;
  padding:10px var(--pad) var(--gap);
  font-size:0;                       /* kills inline-block whitespace gaps */
}
.spot-fig{
  display:inline-block; vertical-align:top;
  width:15.6%; margin:0 .5% 14px 0;
  font-size:10px;                    /* restored for the caption */
}
.spot-fig span{
  /* 4:3 box via padding, not aspect-ratio. padding percentages resolve
     against width in every engine, so this cannot collapse or stretch. */
  position:relative; display:block; width:100%; height:0; padding-bottom:75%;
  background:none; overflow:hidden;
}
.spot-fig span img{
  position:absolute; top:0; left:0; width:100%; height:100%;
  object-fit:contain; display:block;
}
.spot-fig i{
  /* fixed height so a two-line caption cannot push the next row out of line */
  display:block; padding-top:5px; min-height:2.6em; font-style:normal;
  text-align:center;
  font-family:var(--mono); font-size:9px; font-weight:600; line-height:1.3;
  text-transform:uppercase; letter-spacing:.09em; color:var(--graphite);
}
@media (max-width:900px){ .spot-fig{ width:32%; } }
@media (max-width:560px){
  .spot-fig{ width:47%; }
  .strip-row img{ width:52px; height:52px; margin-right:3px; }
}
html.spot-open, html.spot-open body{ overflow:hidden; }

.sec--tight{
  /* the group headings were floating between blocks; sitting them on their
     own rule with tighter space below ties them to the row underneath */
  margin-top:calc(var(--gap) * 2); margin-bottom:0;
  border-bottom:1px solid var(--line); padding-bottom:9px;
}

/* ----------------------------------------------------------
   ROW - one horizontal line of finished images, arrows to step.
   ---------------------------------------------------------- */
.row-wrap{
  /* min-width:0 is the whole fix: a grid item defaults to min-width:auto, so
     without it the wrapper grows to fit all the cards and the row runs off
     the page instead of scrolling inside it. */
  position:relative; margin-top:14px; min-width:0; max-width:100%; overflow:hidden;
}
.row-scroll{
  min-width:0; max-width:100%;
  overflow-x:auto; overflow-y:hidden; white-space:nowrap; font-size:0;
  scroll-behavior:smooth; scrollbar-width:none; -ms-overflow-style:none;
}
.row-scroll::-webkit-scrollbar{ display:none; }
.row-scroll figure{
  display:inline-block; vertical-align:top; white-space:normal;
  width:300px;                                   /* fallback first */
  width:calc((100% - var(--gap) * 3) / 4);       /* four across, never more */
  min-width:230px; max-width:400px;
  margin-right:var(--gap);
}
.row-scroll figure:last-child{ margin-right:0; }

.row-arrow{
  position:absolute; top:38%; transform:translateY(-50%);
  /* same behaviour as the lightbox: a tall edge zone, chevron only, quiet
     until the pointer is over the row */
  top:0; bottom:auto; transform:none; height:var(--rowimg, 220px);
  width:clamp(46px, 5vw, 72px); z-index:3; cursor:pointer;
  border:0; padding:0; color:var(--ink); font:inherit;
  background:none; opacity:0;
  display:flex; align-items:center; justify-content:center;
  transition:opacity .2s var(--ease), background .2s var(--ease);
}
.row-wrap:hover .row-arrow{ opacity:.55; }
.row-wrap:hover .row-arrow:hover{ opacity:1; }
.row-arrow:hover{ background:color-mix(in srgb, var(--ink) 6%, transparent); }
.row-arrow--prev{ left:0; }
.row-arrow--next{ right:0; }
.row-arrow i{
  width:12px; height:12px; display:inline-block;
  border-left:2.5px solid currentColor; border-bottom:2.5px solid currentColor;
}
.row-arrow--prev i{ transform:rotate(45deg); }
.row-arrow--next i{ transform:rotate(-135deg); }
@media (max-width:760px){
  /* vw units ignore the page padding, so 72vw overflowed. Size against the
     container instead and let the row scroll inside it. */
  .row-scroll figure{ width:76%; min-width:0; max-width:none; }
  .row-arrow{ display:none; }
}

/* ----------------------------------------------------------
   PART - one component of a larger project. Numbered header,
   short spec, then its own images.
   ---------------------------------------------------------- */
.part{ margin-top:calc(var(--gap) * 2.4); }
.part-h{
  display:grid; grid-template-columns:44px 1fr auto; gap:12px; align-items:baseline;
  border-top:1px solid var(--ink); padding-top:12px; margin-bottom:4px;
}
.part-h .no{
  font-family:var(--mono); font-size:11px; font-weight:700;
  color:var(--accent); letter-spacing:.06em;
}
.part-h h3{
  margin:0; font-size:clamp(16px, 1.8vw, 21px); font-weight:800;
  text-transform:uppercase; letter-spacing:-.005em;
}
.part-h .spec{
  font-family:var(--mono); font-size:10px; font-weight:600;
  text-transform:uppercase; letter-spacing:.1em; color:var(--graphite);
  text-align:right;
}
/* "and N more" - the way from three shown images into the full set for
   that component. Reads as a caption, not a button. */
.part-more{
  display:inline-flex; align-items:center; gap:8px;
  margin:10px 0 0 56px; padding:7px 12px;
  border:1px solid var(--line); background:var(--zinc);
  font-family:var(--mono); font-size:10px; font-weight:600;
  text-transform:uppercase; letter-spacing:.1em; color:var(--graphite);
  transition:background .2s var(--ease), color .2s var(--ease), border-color .2s var(--ease);
}
.part-more:hover{ background:var(--accent); color:var(--on-accent); border-color:var(--accent); }
@media (max-width:760px){ .part-more{ margin-left:0; } }

.part > p{
  margin:0 0 14px 56px; max-width:62ch;
  font-size:13.5px; line-height:1.6; color:var(--graphite);
}
@media (max-width:760px){
  .part-h{ grid-template-columns:34px 1fr; }
  .part-h .spec{ grid-column:1 / -1; text-align:left; margin-top:2px; }
  /* "and N more" - the way from three shown images into the full set for
   that component. Reads as a caption, not a button. */
.part-more{
  display:inline-flex; align-items:center; gap:8px;
  margin:10px 0 0 56px; padding:7px 12px;
  border:1px solid var(--line); background:var(--zinc);
  font-family:var(--mono); font-size:10px; font-weight:600;
  text-transform:uppercase; letter-spacing:.1em; color:var(--graphite);
  transition:background .2s var(--ease), color .2s var(--ease), border-color .2s var(--ease);
}
.part-more:hover{ background:var(--accent); color:var(--on-accent); border-color:var(--accent); }
@media (max-width:760px){ .part-more{ margin-left:0; } }

.part > p{ margin-left:0; }
}

/* Sketching: the subject carries the caption, the medium sits under it as
   a quiet spec line rather than competing at the same size. */
.sk-cap{ display:block; }
.sk-cap .subject{
  display:block; font-size:15px; font-weight:800;
  text-transform:uppercase; letter-spacing:-.005em; color:var(--ink);
}
.sk-cap .medium{
  display:block; margin-top:3px;
  font-family:var(--mono); font-size:10px; font-weight:600;
  text-transform:uppercase; letter-spacing:.1em; color:var(--graphite);
}
.stack figure .sk-row{
  display:flex; justify-content:space-between; align-items:flex-start; gap:14px;
  padding-top:8px;
}
@media (max-width:760px){
  /* On a phone the caption row was a two-across flex, so the subject and the
     construction tag squeezed each other into a narrow column. Stack them and
     let the tag sit under the spec line where it has room. */
  .stack figure .sk-row{
    display:block; padding-top:9px;
    border-top:1px solid var(--line);
  }
  .sk-cap .subject{ font-size:14px; line-height:1.15; }
  .sk-cap .medium{ margin-top:4px; font-size:9.5px; letter-spacing:.08em; }
  .fig-more{
    display:inline-block; margin:8px 0 0; padding:4px 8px; font-size:9px;
  }
}

.fig-more{
  margin-left:8px; padding:3px 8px;
  font-family:var(--mono); font-size:9px; font-weight:600;
  text-transform:uppercase; letter-spacing:.08em;
  color:var(--accent); border:1px solid var(--accent);
  background:none; cursor:pointer; white-space:nowrap;
  transition:background .18s var(--ease), color .18s var(--ease);
}
.fig-more:hover, .fig-more:focus-visible{
  background:var(--accent); color:var(--on-accent); outline:none;
}

/* ----------------------------------------------------------
   BAR LINK - a full-width way into a page that is not a project
   ---------------------------------------------------------- */
.barlink{
  display:grid; grid-template-columns:auto 1fr auto; gap:18px; align-items:center;
  border:1px solid var(--line); background:var(--zinc);
  padding:14px var(--gap); margin-top:calc(var(--gap) * 2);
  transition:background .22s var(--ease), color .22s var(--ease), border-color .22s var(--ease);
}
.barlink-thumbs{ display:flex; gap:5px; }
.barlink-thumbs img{
  width:74px; height:56px; object-fit:cover; display:block;
  transition:transform .35s var(--ease);
}
.barlink:hover .barlink-thumbs img{ transform:scale(1.05); }
.barlink-thumbs{ overflow:hidden; }
.barlink-thumbs img:nth-child(2){ transition-delay:.04s; }
.barlink-thumbs img:nth-child(3){ transition-delay:.08s; }

.barlink h3{
  margin:0; font-size:clamp(19px, 2.1vw, 26px); font-weight:800;
  text-transform:uppercase; letter-spacing:0; line-height:1;
}
.barlink .k{
  display:block; margin-top:6px;
  font-family:var(--mono); font-size:10px; font-weight:600;
  text-transform:uppercase; letter-spacing:.1em; color:var(--graphite);
  transition:color .22s var(--ease);
}
.barlink .go{
  font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.09em;
  border-bottom:2px solid var(--accent); padding-bottom:3px;
  transition:border-color .22s var(--ease);
}
.barlink:hover{ background:var(--accent); color:var(--on-accent); border-color:var(--accent); }
.barlink:hover .k{ color:var(--on-accent); }
.barlink:hover .go{ border-color:var(--on-accent); }
@media (max-width:760px){
  .barlink{ grid-template-columns:1fr auto; gap:12px; padding:12px; }
  .barlink-thumbs{ grid-column:1 / -1; }
  .barlink-thumbs img{ width:33%; height:60px; }
}

/* ----------------------------------------------------------
   CREDIT HEAD - introduces work made by someone else, so the
   attribution reads as part of the section rather than fine print
   ---------------------------------------------------------- */
.credit-head{
  border-top:1px solid var(--ink); padding-top:14px;
  margin:calc(var(--gap) * 2) 0 var(--gap);
}
.credit-head h2{
  margin:0 0 10px; font-family:var(--mono); font-size:11px; font-weight:600;
  text-transform:uppercase; letter-spacing:.11em;
}
.credit-head p{
  margin:0; max-width:66ch; font-size:14px; line-height:1.6; color:var(--graphite);
}
.credit-head b{ color:var(--ink); font-weight:700; }

/* ----------------------------------------------------------
   CONTACT SHEET - dense uniform grid for the build archive.
   Same size and crop for every tile, so a garage phone photo and a
   studio shot sit together as a record rather than looking mismatched.
   ---------------------------------------------------------- */
.csheet{
  display:grid; gap:6px;
  grid-template-columns:repeat(auto-fill, minmax(148px, 1fr));
  margin-bottom:calc(var(--gap) * 2);
}
.csheet .frame{ aspect-ratio:1/1; }
.csheet .frame--p34{ aspect-ratio:3/4; }   /* portrait 3:4 for opener/shelter archives */
/* Grid items default to min-width:auto, so a long caption refuses to shrink
   and pushes the whole track wider than the screen. This is what was
   overflowing the page on a phone. */
.csheet figure{ min-width:0; }
.csheet figcaption{ overflow-wrap:anywhere; hyphens:auto; }
.csheet figcaption{
  font-size:9px; letter-spacing:.09em; color:var(--graphite);
  padding-top:4px; display:block;
}
@media (max-width:900px){
  .csheet{ grid-template-columns:repeat(auto-fill, minmax(120px, 1fr)); gap:5px; }
}
@media (max-width:560px){
  .csheet{ grid-template-columns:repeat(3, 1fr); gap:5px; }
  .csheet figcaption{ font-size:7.5px; letter-spacing:.05em; padding-top:3px; }
}

/* ----------------------------------------------------------
   TURNTABLE - drag to rotate. Progressive: if the frames are not
   there, the static hero image simply stays put.
   ---------------------------------------------------------- */
.spin{ position:relative; touch-action:pan-y; }
.spin.on{ user-select:none; -webkit-user-select:none; }
.spin.on img{ pointer-events:none; }
/* the frame swaps constantly while dragging - give the compositor a hint
   and stop it re-laying-out the page around it */
.spin.on{ contain:paint; }
.spin.on img{ will-change:contents; }

.spin-hint{
  position:absolute; left:10px; bottom:10px;
  font-size:9.5px; font-weight:500; text-transform:uppercase; letter-spacing:.11em;
  color:var(--on-accent); background:var(--accent);
  padding:4px 7px; opacity:0; transition:opacity .3s var(--ease);
}
.spin.on .spin-hint{ opacity:1; }
.spin.used .spin-hint{ opacity:0; }

/* text anywhere in the carousel selects + copies cleanly */
.c-slide, .ph, .c-cap, figcaption{ user-select:text; -webkit-user-select:text; }
.cbtn, .c-count{ user-select:none; -webkit-user-select:none; }

/* prev / next */
.pn{
  display:flex; justify-content:space-between; gap:12px;
  margin-top:44px; padding-top:12px;
  border-top:1px solid var(--ink);
}
.pn a{
  font-size:12px; font-weight:700;
  letter-spacing:.05em; text-transform:uppercase;
  padding:2px 5px;
  transition:background .18s var(--ease), color .18s var(--ease);
}
.pn a:hover{ background:var(--accent); color:var(--on-accent); }
.pn a:first-child{ margin-left:-5px; }
.pn a:last-child{ margin-right:-5px; }

/* ----------------------------------------------------------
   RESUME
   ---------------------------------------------------------- */
.sheet{ max-width:900px; margin:0 auto; }
.rsec{ border:1px solid var(--line); margin-bottom:var(--gap); }
.rsec-h{
  display:flex; justify-content:space-between; align-items:center;
  padding:9px 12px;
  background-color:var(--zinc);
  border-bottom:1px solid var(--line);
  font-size:12px; font-weight:700; letter-spacing:.07em; text-transform:uppercase;
}
.row{
  display:grid; grid-template-columns:160px 1fr auto; gap:12px;
  padding:12px; border-bottom:1px solid var(--line);
}
.row:last-child{ border-bottom:0; }
.row .when, .row .where{
  font-family:var(--mono); font-size:11px;
  text-transform:uppercase; color:var(--graphite); padding-top:2px;
}
.row h3{ margin:0 0 2px; font-size:14px; text-transform:uppercase; letter-spacing:.03em; }
.row p{ margin:0; font-size:14px; }
.row ul{ margin:4px 0 0; padding-left:18px; font-size:14px; }
.row li{ margin:2px 0; }
.btn{
  display:inline-block; padding:11px 15px;
  border:1px solid var(--ink); background:var(--ink); color:var(--paper);
  font-size:12px; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
  cursor:pointer;
  transition:background .18s var(--ease), color .18s var(--ease), border-color .18s var(--ease);
}
.btn:hover{ background:var(--accent); border-color:var(--accent); color:var(--on-accent); }

/* ----------------------------------------------------------
   CONTACT
   ---------------------------------------------------------- */
.c-lede{ max-width:44ch; margin:20px 0 34px; font-size:11px; font-weight:500;
  text-transform:uppercase; letter-spacing:.1em; line-height:1.85; }
/* inquiry form */
.inquiry{ max-width:620px; margin:0 0 40px; }
.field{ display:grid; gap:6px; margin-bottom:14px; }
.field label{
  font-family:var(--mono); font-size:10.5px;
  text-transform:uppercase; letter-spacing:.04em; color:var(--graphite);
  transition:color .18s var(--ease);
}
.field:focus-within label{ color:var(--accent); }
.field input, .field textarea{
  width:100%; padding:12px;
  border:1px solid var(--line); border-radius:0;
  background:var(--paper); color:var(--ink);
  font-family:var(--sans); font-weight:500; font-size:15px;
  transition:border-color .18s var(--ease);
}
.field input:focus, .field textarea:focus{
  outline:none; border-color:var(--accent);
}
.field textarea{ min-height:140px; resize:vertical; }

/* inline validation — replaces the browser popup */
.field .err{
  display:none;
  font-family:var(--mono); font-size:10.5px;
  text-transform:uppercase; letter-spacing:.03em;
  color:var(--accent);
}
.field.bad input, .field.bad textarea{ border-color:var(--accent); }
.field.bad .err{ display:block; }

.c-rows{ border-top:1px solid var(--ink); }
.c-row{
  display:flex; justify-content:space-between; gap:12px;
  padding:13px 0; border-bottom:1px solid var(--line);
  transition:background .18s var(--ease);
}
.c-row .k{ font-family:var(--mono); font-size:11px; text-transform:uppercase; color:var(--graphite); padding-top:2px; }
.c-row .v{ font-size:13px; font-weight:600; text-transform:uppercase; letter-spacing:.03em; }
a.c-row:hover{ background:var(--zinc); }

/* ----------------------------------------------------------
   FOOTER
   ---------------------------------------------------------- */
.footer{ padding:60px var(--pad) 14px; max-width:var(--maxw); margin-inline:auto; }
.f-line{
  display:flex; justify-content:space-between; align-items:baseline;
  gap:14px; flex-wrap:wrap; padding-top:10px;
}
.f-name{
  font-weight:800;
  text-transform:uppercase; letter-spacing:.02em; font-size:12.5px;
}
.f-links{ display:flex; gap:14px; flex-wrap:wrap; align-items:baseline; }
.f-links a, .f-links span{
  font-family:var(--mono); font-size:11px;
  text-transform:uppercase; letter-spacing:.02em; color:var(--graphite);
}
.f-links a{ padding:2px 4px; transition:background .18s var(--ease), color .18s var(--ease); }
.f-links a:hover{ background:var(--accent); color:var(--on-accent); }

/* ----------------------------------------------------------
   LOADER — once per session; a drafting callout that lifts away
   ---------------------------------------------------------- */
.loader{
  display:none; position:fixed; inset:0; z-index:999;
  background:var(--paper);
  align-items:center; justify-content:center;
  padding:0 var(--pad);
}
html.js-load .loader{ display:flex; }     /* only exists when JS says so */
.loader.done{
  transform:translateY(-100%);
  transition:transform .55s cubic-bezier(.75,0,.2,1);
}
.loader-row{
  display:flex; align-items:center; gap:12px;
  width:min(420px, 82%);
  font-family:var(--mono); font-size:11px;
  text-transform:uppercase; letter-spacing:.06em; color:var(--ink);
}
.loader-row i{ flex:1; height:9px; border-bottom:1px solid var(--graphite); position:relative; }
.loader-row i::before{ content:""; position:absolute; bottom:-4px; width:1px; height:9px; background:var(--graphite); }
.loader-row i:first-child::before{ left:0; }
.loader-row i:last-child::before{ right:0; }
.loader-row .sq{ width:9px; height:9px; background:var(--accent);
  animation:blink .8s steps(1) infinite; }
@keyframes blink{ 50%{ opacity:.15; } }

/* ----------------------------------------------------------
   RESPONSIVE + A11Y + PRINT
   ---------------------------------------------------------- */
@media (max-width:760px){
  html, body{ overflow-x:hidden; max-width:100vw; }   /* hard stop: nothing on
    a phone can force horizontal scroll, whatever the cause turns out to be */
  :root{ --pad:14px; --gap:16px; }              /* tighter page rhythm */
  .grid{ grid-template-columns:1fr; }
  .stack .two{ grid-template-columns:1fr; }
  /* the revealed namemark was landing on top of the nav once it wrapped.
     Put it on its own side instead of letting flex stack them. */
  .top{ justify-content:space-between; flex-wrap:nowrap; gap:10px; }
  .top .brand{ flex:0 0 auto; }
  .top .nav{ flex:1 1 auto; justify-content:flex-end; gap:12px; }

  .row{
    grid-template-columns:auto 1fr;
    grid-template-areas:"when where" "body body";
    gap:6px 10px; padding:14px 12px;
  }
  .row .when { grid-area:when; }
  .row .where{ grid-area:where; text-align:right; }
  .row > div { grid-area:body; }
  .cutsheet > div{ grid-template-columns:110px 1fr; }
  .r219{ aspect-ratio:4/3; }                    /* every card the same shape on a phone */
  .hero{ min-height:72vh; min-height:72svh; }
  .hero-sub{ flex-direction:column; gap:3px; padding-bottom:22px; }
  .top{ gap:12px; padding-top:10px; }
  .nav{ gap:8px; }
  .nav a{ padding:8px 7px; }                    /* real thumb targets */
  .pn a{ padding:8px 5px; }
  .cbtn{ width:44px; height:38px; }
  .c-bar{ flex-wrap:wrap; row-gap:8px; }
  .c-cap{ flex:1 1 100%; order:-1; }            /* caption on its own line */
  .c-count{ margin-right:auto; }
  .p-head{ padding-top:32px; }
  .p-split{ grid-template-columns:1fr; gap:var(--gap); padding-top:32px; }
  .p-hero{ order:-1; }                          /* product first on phones */
  .footer{ padding-top:44px; }
}
@media (max-width:560px){
  .wordmark{ white-space:normal; line-height:.86; font-size:21vw; margin-left:-0.03em; }
  .wordmark span{ display:block; }   /* two lines, each fitted to width */
  .dim{ gap:8px; font-size:10px; }
  .brand{ font-size:12px; }
}
@media (prefers-reduced-motion:reduce){
  *{ transition:none !important; animation:none !important; }
  .rv{ opacity:1; transform:none; }
}
@media print{
  .top,.footer,.btn,.nav,.pn{ display:none !important; }
  body{ background:#fff; }
  .csheet{ max-width:100%; }
  .p-head{ padding-top:0; }
}

.p-body .roles{ color:var(--graphite); font-size:13px; }
