:root {
  --bg: #1a1a1a;
  --fg: #fff;
  --muted: #8c8c8c;
  --placeholder: #d9d9d9;
  --on-placeholder: #5c5c5c;
  --accent: #fe803d;
  --selection: #c2561d;
  --lime: #befa0a;
  --col: 500px;
  --card-h: 250px;
  --ease: cubic-bezier(.22, .8, .2, 1);
  --mono: "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace;
  --tag: "Space Mono", ui-monospace, monospace;
}

* { box-sizing: border-box; }

html { background: var(--bg); }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 400 14px/normal var(--mono);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h2, p, ul { margin: 0; padding: 0; font: inherit; }
ul { list-style: none; }
a { color: inherit; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
/* Text selection in a darker shade of the accent orange. */
::selection { background: var(--selection); color: #fff; }

/* Focus ring only while navigating with Tab (html.tabbing, set in JS),
   not after arrow keys or programmatic focus. */
:focus-visible { outline: none; }
html.tabbing :focus-visible { outline: 1px solid var(--lime); outline-offset: 3px; }

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.page {
  padding: 40px 20px 80px;
}

.col {
  width: min(var(--col), 100%);
  margin-inline: auto;
}

.col, main {
  display: flex;
  flex-direction: column;
  gap: 32px;
}

.block { display: flex; flex-direction: column; gap: 16px; }
.label, .muted { color: var(--muted); }

/* header */
.top {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.me {
  display: flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
}

.avatar {
  position: relative;
  width: 16px;
  height: 16px;
  border: 1px solid rgba(255, 255, 255, .1);
}
.avatar img { display: block; width: 100%; height: 100%; object-fit: cover; }
.avatar::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, .1) 100%);
}

.links { display: flex; gap: 16px; color: var(--muted); }
.links a {
  text-underline-position: from-font;
  transition: color .2s;
}
.links a:hover { color: var(--fg); }

/* work */
.row {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.arrows { display: flex; gap: 8px; }
.arrow { display: block; transition: opacity .2s; }
.arrow img { display: block; width: 16px; height: 16px; }
.arrow:hover { opacity: .7; }
.arrow:disabled { opacity: .3; cursor: default; }

/* The rail spans the whole page width (set in JS); this is the no-JS fallback. */
.rail-wrap {
  position: relative;
  width: calc(100% + (100vw - 100%) / 2);
}

.rail {
  overflow-x: auto;
  scrollbar-width: none;
  user-select: none;
  -webkit-user-select: none;
}
.rail::-webkit-scrollbar { display: none; }
.rail.dragging { cursor: grabbing; }
.rail.dragging .card { pointer-events: none; }

.track {
  position: relative;
  display: flex;
  gap: 8px;
  width: max-content;
}

.card {
  position: relative;
  display: block;
  width: calc(var(--w) * 1px);
  height: var(--card-h);
  overflow: hidden;
  background: var(--placeholder);
  transition: opacity .45s var(--ease), transform .25s var(--ease);
}
/* Brief press before the shot opens. */
.card.pressed { transform: scale(.98); transition-duration: .45s, .12s; }
.card img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .8s var(--ease);
}
.card:hover img { transform: scale(1.02); }
.card .soon {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: var(--on-placeholder);
  pointer-events: none;
}

/* Every shot except the active one sits under a dark veil. */
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--bg);
  opacity: .45;
  pointer-events: none;
  transition: opacity .5s var(--ease);
}
.card.active::after { opacity: 0; }

/* With a mouse, the hovered shot takes the highlight from the active one
   until the pointer leaves it. Right after a drag (.calm) the active shot keeps
   it, so letting go over another card doesn't flash. */
@media (hover: hover) {
  .rail:not(.calm) .track:has(.card:hover) .card.active:not(:hover)::after { opacity: .45; }
  .rail:not(.calm) .track .card:hover::after { opacity: 0; }
}

.fade {
  position: absolute;
  top: 0;
  right: 0;
  width: 100px;
  height: var(--card-h);
  background: linear-gradient(to left, rgba(25, 25, 25, .6), rgba(25, 25, 25, 0));
  backdrop-filter: blur(1px);
  -webkit-backdrop-filter: blur(1px);
  pointer-events: none;
  transition: opacity .3s;
}
.fade.off { opacity: 0; }

/* experience */
.xp {
  display: grid;
  grid-template-columns: 177.5px 1fr 55px;
  min-height: 16px;
}

/* Phones: columns sized in characters (longest entries: "experience",
   "product, sole designer", "always") with a 1ch gap, at 13px so a row
   still fits on a 360px-wide screen. */
@media (max-width: 480px) {
  .xp { grid-template-columns: 11ch 1fr 6ch; column-gap: 1ch; font-size: 13px; }
}
.xp > :last-child { text-align: right; }
/* Rows touch (padding instead of gap) so moving between them never leaves
   a dead zone that would flash the whole list back. */
.xp-list { display: flex; flex-direction: column; margin-block: -4px; }
.xp-list .xp { padding-block: 4px; }

/* With a mouse, the hovered row turns fully white and the others fade back. */
@media (hover: hover) {
  .xp-list .xp { transition: opacity .3s var(--ease); }
  .xp-list .xp .muted { transition: color .3s var(--ease); }
  .xp-list:has(.xp:hover) .xp:not(:hover) { opacity: .35; }
  .xp-list .xp:hover .muted { color: var(--fg); }
}

/* contact */
.contact {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px 16px;
}
.accent { color: var(--accent); text-decoration: none; }
.accent:hover { text-decoration: underline; text-underline-position: from-font; }

/* lime tag: cursor label and "copied" */
.tag {
  display: inline-flex;
  align-items: center;
  height: 21px;
  padding: 0 4px;
  background: var(--tag-bg, var(--lime));
  color: #000;
  font: 400 14px/normal var(--tag);
  white-space: nowrap;
  filter: drop-shadow(0 2px 2px rgba(10, 10, 12, .06)) drop-shadow(0 4px 3px rgba(10, 10, 12, .1));
}

/* The copied tag floats over the link, so the header never reflows. */
.links [data-copy] {
  position: relative;
  display: inline-block;
}
.links .tag {
  position: absolute;
  left: 50%;
  top: 50%;
  translate: -50% -50%;
  animation: swipe-in .28s var(--ease) both;
}
.links .tag.out { animation: swipe-out .22s cubic-bezier(.6, 0, .8, .4) both; }

/* Highlighter swipe: wipes in from the left, leaves to the right. */
@keyframes swipe-in {
  from { clip-path: inset(0 100% 0 0); }
  to { clip-path: inset(0 0 0 0); }
}
@keyframes swipe-out {
  from { clip-path: inset(0 0 0 0); }
  to { clip-path: inset(0 0 0 100%); }
}

.cursor {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 30;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity .15s, visibility 0s .15s;
  will-change: transform;
}
.cursor.on {
  opacity: 1;
  visibility: visible;
  transition: opacity .15s;
}
/* Only the drag tag blends between colours; every other tag stays a flat swatch. */
.cursor.on.drag { transition: opacity .15s, background-color .4s linear; }

/* lightbox */
/* --sbw: scrollbar width, set in JS so hiding the scrollbar doesn't shift the page. */
body.lb-open { overflow: hidden; padding-right: var(--sbw, 0px); }
/* Other cards fade out one by one, starting next to the opened one (--d set in JS). */
body.lb-open .card:not(.is-open) {
  opacity: 0;
  transition: opacity .5s var(--ease) var(--d, 0s);
}
body.lb-open .fade { opacity: 0; }

.lb {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: grid;
  place-items: center;
  padding: 20px;
  background: rgba(0, 0, 0, 0);
  transition: background .5s var(--ease), backdrop-filter .5s var(--ease);
}
.lb[hidden] { display: none; }
.lb.on {
  background: rgba(0, 0, 0, .1);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}

.lb-inner {
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* --ar (width / height) is set per shot in JS, so portrait shots stay portrait.
     The view fills most of the window height, up to 1200px wide. */
  width: min(1200px, 100%, (100svh - 160px) * var(--ar, 4 / 3));
}

.lb-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  opacity: 0;
}
/* Title and close fade in as the shot finishes growing, and vanish at once on close. */
.lb.on .lb-head { opacity: 1; transition: opacity .25s var(--ease) .5s; }
.lb-close { color: var(--muted); transition: color .2s; }
.lb-close:hover { color: var(--fg); }

.lb-ph {
  display: grid;
  place-items: center;
  width: 100%;
  aspect-ratio: var(--ar, 4 / 3);
  background: var(--placeholder);
  color: var(--on-placeholder);
  transform-origin: 0 0;
  will-change: transform, clip-path;
}
.lb-ph[hidden], .lb-img[hidden] { display: none; }

.lb-img {
  display: block;
  width: 100%;
  height: auto;
  transform-origin: 0 0;
  will-change: transform, clip-path;
}

@media (pointer: coarse) {
  .rail { scroll-snap-type: x mandatory; }
  .rail.animating { scroll-snap-type: none; }
  .card { scroll-snap-align: start; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0s !important; animation-duration: 0s !important; }
}
