/* htut.life — bold & kinetic.
   The page changes colour as you scroll: deep blue → black → blue → cream →
   amber. Sections are transparent; main.js interpolates --bg and --ink behind
   them, so the journey is continuous rather than a set of stacked panels.
   Work and the timeline are swipeable decks inside that vertical scroll. */

:root {
  --deep:  #0a1a4f;
  --night: #0b0d12;
  --cream: #f2eee6;
  --amber: #e8631a;
  --sky:   #2f6bff;
  --ember: #ff8a3d;

  /* driven from JS — these are only the opening values */
  --bg: var(--deep);
  --ink: var(--cream);

  --pad: clamp(1.15rem, 5vw, 5rem);
  --maxw: 1240px;
  --ease: cubic-bezier(.22, 1, .36, 1);
  --spring: cubic-bezier(.22, 1.5, .36, 1);
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: "Helvetica Neue", Helvetica, Inter, system-ui, -apple-system, Arial, sans-serif;
  font-size: clamp(15px, .5vw + 13px, 17px);
  line-height: 1.5;
  letter-spacing: -.01em;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  transition: background-color .1s linear;
}

h1, h2, h3 { margin: 0; line-height: .94; letter-spacing: -.045em; font-weight: 800; }
p { margin: 0; }
img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
.skip { position: absolute; left: -9999px; }
.vh {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.skip:focus { left: 0; top: 0; z-index: 200; background: #fff; color: #000; padding: .7rem 1rem; }
:focus-visible { outline: 2px solid currentColor; outline-offset: 4px; border-radius: 6px; }

/* scroll rail ───────────────────────────────────────────────────────── */
/* The bar itself is scaled by JS, so its glass track cannot live on the same
   element without being squashed along with it. It rides on a pseudo-element
   instead, which also means no extra markup. Three pixels is too thin for a
   blur to register, so the track earns its keep a different way: it shows how
   far there is still to go, not just how far you have come.
   Only the story has a rail. The CV would otherwise carry a stray strip along
   its top edge with nothing ever travelling it. */
body:not(.doc)::before {
  content: ""; position: fixed; top: 0; left: 0; height: 3px; width: 100%; z-index: 59;
  pointer-events: none;
  background: rgba(242, 238, 230, .14);
  -webkit-backdrop-filter: blur(6px) saturate(1.3);
  backdrop-filter: blur(6px) saturate(1.3);
}
:root[data-theme="light"] body::before { background: rgba(11, 13, 18, .14); }
.rail-top {
  position: fixed; top: 0; left: 0; height: 3px; width: 100%; z-index: 60;
  transform: scaleX(0); transform-origin: 0 50%; pointer-events: none;
  background: var(--ember);
}

/* the one persistent affordance ──────────────────────────────────────── */
.cc-float {
  position: fixed; right: clamp(.9rem, 3vw, 2rem); bottom: clamp(.9rem, 3vw, 2rem);
  z-index: 65; display: inline-flex; align-items: center; gap: .55rem;
  height: 2.9rem; padding: 0 1.25rem; border-radius: 999px;
  background: var(--ember); color: #1a0c04; font-weight: 800; font-size: .82rem;
  letter-spacing: -.01em; white-space: nowrap;
  box-shadow: 0 8px 30px -8px rgba(255, 138, 61, .8);
  opacity: 0; transform: translateY(16px) scale(.9); pointer-events: none;
  transition: opacity .45s var(--ease), transform .55s var(--spring);
}
.cc-float.show { opacity: 1; transform: none; pointer-events: auto; }
.cc-float:hover { transform: translateY(-2px); }
.cc-float .dot {
  width: 7px; height: 7px; border-radius: 50%; background: #1a0c04;
  animation: blip 2s infinite;
}
@keyframes blip { 0%,100% { opacity: 1; } 50% { opacity: .25; } }

/* sections ──────────────────────────────────────────────────────────── */
.sec { position: relative; padding: clamp(4rem, 11vw, 8rem) var(--pad); }
.sec > * { position: relative; z-index: 1; }

/* Section openings used to be five identical small labels. The number is
   now the event — set large in amber, with the name riding its baseline. */
.tag {
  display: flex; align-items: baseline; gap: .7rem;
  font-size: .7rem; letter-spacing: .24em; text-transform: uppercase;
  font-weight: 700; opacity: .8; margin-bottom: clamp(.8rem, 2.5vw, 1.4rem);
}
.tag::before {
  content: attr(data-n);
  font-size: clamp(2.4rem, 9vw, 3.6rem); letter-spacing: -.05em; line-height: .8;
  color: var(--amber); opacity: 1; font-variant-numeric: tabular-nums;
  -webkit-text-stroke: 0;
}
.tag:not([data-n]) { display: inline-block; opacity: .55; }

/* ═══ HERO ═══════════════════════════════════════════════════════════ */
.sec--hero {
  min-height: 100svh; display: grid; align-content: center;
  padding-top: clamp(4.5rem, 12vw, 7rem); overflow: hidden;
}
.hero { max-width: var(--maxw); margin: 0 auto; width: 100%; }
.hero__mark {
  width: 52px; height: 52px; margin-bottom: clamp(1.6rem, 4vw, 2.6rem);
  opacity: 0; animation: pop .7s var(--spring) .1s forwards; animation-play-state: paused;
}
/* The opening waits for the gate as well as the loader. Without the :not(),
   the hero would play itself out behind the gate and whoever answered
   correctly would arrive to a page that had already finished greeting them. */
html.loaded:not(.gated) .hero__mark { animation-play-state: running; }
@keyframes pop { from { opacity: 0; transform: scale(.6) rotate(-20deg); } to { opacity: 1; transform: none; } }

.big-type { font-size: clamp(2.5rem, 10.5vw, 7.6rem); letter-spacing: -.05em; }
.big-type .ln { display: block; overflow: hidden; }
.big-type .ln > span {
  display: block; transform: translateY(105%);
  animation: rise .95s var(--ease) forwards; animation-play-state: paused;
}
html.loaded:not(.gated) .big-type .ln > span { animation-play-state: running; }
.big-type .ln:nth-child(1) > span { animation-delay: .10s; }
.big-type .ln:nth-child(2) > span { animation-delay: .17s; }
.big-type .ln:nth-child(3) > span { animation-delay: .24s; }
.big-type .ln:nth-child(4) > span { animation-delay: .31s; }
.big-type .ln:nth-child(5) > span { animation-delay: .38s; }
@keyframes rise { to { transform: none; } }
.big-type .hl { color: var(--ember); }

.hero__sub {
  margin-top: clamp(1.4rem, 3vw, 2.2rem); font-size: clamp(.85rem, 2vw, 1.05rem);
  font-weight: 700; letter-spacing: .02em; opacity: 0;
  animation: fadeUp .7s var(--ease) .75s forwards; animation-play-state: paused;
}
.hero__meta {
  margin-top: .7rem; font-size: .78rem; opacity: 0;
  animation: fadeUp .7s var(--ease) .88s forwards; animation-play-state: paused;
}
html.loaded:not(.gated) .hero__sub, html.loaded:not(.gated) .hero__meta { animation-play-state: running; }
@keyframes fadeUp { from { opacity: 0; transform: translateY(12px); } to { opacity: .78; transform: none; } }

.hero__photo {
  position: absolute; inset: 0 0 0 auto; width: min(46%, 620px); z-index: 0;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 42%);
  mask-image: linear-gradient(90deg, transparent, #000 42%);
  opacity: .5;
}
.hero__photo img {
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 30%;
  will-change: transform;
}
.cue {
  position: absolute; left: 50%; bottom: 1.6rem; translate: -50% 0;
  width: 1px; height: 46px; background: currentColor; opacity: .3;
  transform-origin: top; animation: cue 2.2s var(--ease) infinite;
}
@keyframes cue { 0% { transform: scaleY(0); } 45% { transform: scaleY(1); } 100% { transform: scaleY(0); transform-origin: bottom; } }

/* ═══ THE TURN ═══════════════════════════════════════════════════════ */
.sec--turn { min-height: 78svh; display: grid; align-content: center; }
.statement {
  max-width: 20ch; font-size: clamp(1.9rem, 7vw, 5rem); font-weight: 800;
  letter-spacing: -.045em; line-height: 1.06; margin: 0 auto; width: 100%;
  max-width: min(20ch, var(--maxw));
}
.statement .w { opacity: .16; transition: opacity .3s linear; }
.statement .w.lit { opacity: 1; }

/* ═══ DECKS ══════════════════════════════════════════════════════════ */
.deck__head { max-width: var(--maxw); margin: 0 auto 2rem; display: grid; }
.deck__head h2 { font-size: clamp(2.15rem, 9vw, 4.8rem); }
.swipe-hint {
  justify-self: start; margin-top: 1.1rem; font-size: .7rem; letter-spacing: .22em;
  text-transform: uppercase; font-weight: 700; opacity: .5;
  animation: slideHint 2s var(--ease) infinite;
}
@keyframes slideHint { 0%,100% { transform: none; } 50% { transform: translateX(8px); } }

.deck {
  display: flex; gap: clamp(.9rem, 2.5vw, 1.4rem);
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
  padding: .4rem var(--pad) 1.4rem;
  margin-inline: calc(var(--pad) * -1);
  scroll-padding-left: var(--pad);
  scrollbar-width: none; cursor: grab;
}
.deck::-webkit-scrollbar { display: none; }
.deck.dragging { cursor: grabbing; scroll-snap-type: none; }

.card {
  flex: 0 0 clamp(280px, 42vw, 560px); scroll-snap-align: start;
  border-radius: 24px; overflow: hidden; display: flex; flex-direction: column;
  background: rgba(255, 255, 255, .05);
  border: 1px solid rgba(255, 255, 255, .12);
  transition: transform .5s var(--ease), border-color .4s;
}
.card--a { background: linear-gradient(160deg, rgba(47,107,255,.22), rgba(255,255,255,.04)); }
.card--b { background: linear-gradient(160deg, rgba(232,99,26,.22), rgba(255,255,255,.04)); }
.card--c { background: linear-gradient(160deg, rgba(255,255,255,.13), rgba(255,255,255,.03)); }
.card--d { background: linear-gradient(160deg, rgba(232,99,26,.14), rgba(47,107,255,.14)); }
.card:hover { border-color: rgba(255, 255, 255, .3); }



.card__body { padding: clamp(1.2rem, 3vw, 1.7rem); display: flex; flex-direction: column; flex: 1; }
.card__body h3 { font-size: clamp(1.3rem, 4vw, 1.9rem); margin-bottom: .7rem; line-height: 1.02; }
.card__body > p { font-size: .9rem; opacity: .78; line-height: 1.55; }


/* ── The path: a vertical journey ──────────────────────────────────────
   Each year is a moment you land on — headline, one line, and the detail
   behind a tap. The spine fills continuously as you travel it, and the
   year beside you counts up. Built on <details>, so it all opens with no
   JavaScript; the script only adds the height animation. */
.sec--path { padding-bottom: clamp(3rem, 8vw, 6rem); }
.deck__note { margin-top: .8rem; font-size: .74rem; letter-spacing: .1em; text-transform: uppercase; opacity: .5; }

.tl { position: relative; margin-top: clamp(1.4rem, 4vw, 2.4rem); }

.tl__aside {
  position: sticky; top: 0; z-index: 3;
  display: flex; align-items: center; gap: .85rem;
  padding: .75rem 0 .6rem; background: var(--bg);
}
.tl__ghost { display: none; }
.tl__aside::after {
  content: ""; position: absolute; left: 0; right: 0; top: 100%; height: 3.4rem;
  background: linear-gradient(var(--bg), transparent); pointer-events: none;
}
.tl__ghost {
  font-size: clamp(2.6rem, 12vw, 4rem); font-weight: 800; letter-spacing: -.05em;
  line-height: .9; color: var(--amber); font-variant-numeric: tabular-nums;
  animation: yrIn .45s var(--spring) both;
}
@keyframes yrIn { from { opacity: 0; transform: translateY(.24em) } to { opacity: 1; transform: none } }
.tl__rail {
  flex: 1; height: 2px; border-radius: 2px; align-self: center; overflow: hidden;
  background: color-mix(in srgb, var(--ink) 13%, transparent);
}
.tl__rail i {
  display: block; height: 100%; width: 0;
  background: linear-gradient(90deg, color-mix(in srgb, var(--amber) 45%, transparent), var(--amber));
}

.tl__list { position: relative; list-style: none; padding-left: 2.2rem; }
.tl__list::before, .tl__list::after { z-index: 0; }
.tl__stop { z-index: 1; }
.tl__list::before {
  content: ""; position: absolute; left: 6px; top: .4rem; bottom: 8rem; width: 2px;
  background: color-mix(in srgb, var(--ink) 12%, transparent);
}
/* the travelled part of the spine, drawn over the faint one */
.tl__list::after {
  content: ""; position: absolute; left: 6px; top: .4rem; width: 2px;
  height: var(--travelled, 0px); max-height: calc(100% - 3.4rem);
  background: linear-gradient(color-mix(in srgb, var(--amber) 35%, transparent), var(--amber));
}

.tl__stop {
  position: relative; padding: 0 0 clamp(3.6rem, 11vw, 6rem);
  transition: opacity .5s ease;
}
.tl__dot {
  position: absolute; left: -2.2rem; top: .5rem;
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--bg); border: 2px solid color-mix(in srgb, var(--ink) 24%, transparent);
  transition: background .45s, border-color .45s, transform .55s var(--spring), box-shadow .45s;
}
.tl__stop--key .tl__dot { width: 18px; height: 18px; left: -2.32rem; top: .36rem; }
.tl__stop.on .tl__dot {
  background: var(--amber); border-color: var(--amber); transform: scale(1.12);
  box-shadow: 0 0 0 6px color-mix(in srgb, var(--amber) 15%, transparent);
}
/* the year you are standing in gets a ring that breathes */
.tl__stop.now .tl__dot { animation: dotPulse 2.6s ease-in-out infinite; }
@keyframes dotPulse {
  0%, 100% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--amber) 15%, transparent) }
  50%      { box-shadow: 0 0 0 12px color-mix(in srgb, var(--amber) 0%, transparent) }
}

.tl__body {
  opacity: .38; transform: translateY(14px);
  transition: opacity .55s ease, transform .55s var(--spring);
}
.tl__stop.on .tl__body { opacity: 1; transform: none; }

/* The year is the loudest thing in the row. Scale contrast against the
   headline is what stops nine entries reading as nine identical rows. */
.tl__yr {
  display: block; font-size: clamp(2.1rem, 8.5vw, 3.2rem); font-weight: 800;
  letter-spacing: -.055em; line-height: .88; color: var(--amber);
  margin-bottom: .5rem; font-variant-numeric: tabular-nums;
}
.tl__stop h3 {
  font-size: clamp(1.24rem, 4.8vw, 1.85rem); font-weight: 800; letter-spacing: -.028em;
  line-height: 1.14; margin-bottom: .55rem; text-wrap: balance;
}
.tl__stop--key h3 { font-size: clamp(1.42rem, 5.8vw, 2.2rem); }

/* ── The pivots break the line ─────────────────────────────────────────
   Six of these years are steps. Three are turns. The turns leave the
   column entirely — full width on a phone, inverted, with the spine
   disappearing behind them and picking up again underneath. That
   interruption is what keeps nine entries from reading as a list. */
.tl__stop--key { padding-bottom: clamp(3.6rem, 11vw, 6rem); }
.tl__stop--key > .tl__dot { display: none; }
.tl__stop--key .tl__inner {
  position: relative; z-index: 1;
  margin-left: calc(-1 * (var(--pad) + 2.2rem));
  margin-right: calc(-1 * var(--pad));
  padding: clamp(1.6rem, 6vw, 2.4rem) var(--pad);
  background: var(--deep); color: var(--cream);
  box-shadow: 0 22px 60px rgba(10, 26, 79, .22);
}
/* a rule of accent down its leading edge, drawn as it arrives */
.tl__stop--key .tl__inner::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 5px;
  background: var(--amber); transform: scaleY(0); transform-origin: top;
  transition: transform .7s cubic-bezier(.22, 1, .36, 1) .1s;
}
.tl__stop--key.on .tl__inner::before { transform: scaleY(1); }
.tl__stop--night .tl__inner { background: var(--night); }
.tl__stop--key .tl__yr { color: var(--ember); font-size: clamp(2.6rem, 11vw, 4rem); }
.tl__stop--key h3 { color: var(--cream); }
.tl__stop--key .tl__lead { opacity: .85; }
.tl__stop--key .tl__panel p { opacity: .8; }
.tl__stop--key .tl__plus { border-color: rgba(242, 238, 230, .34); }
.tl__stop--key .tl__d[open] .tl__plus { background: var(--ember); border-color: var(--ember); color: var(--deep); }
.tl__stop--key .tl__stats b { color: var(--ember); }
.tl__stop--key .tl__tags li { border-color: rgba(242, 238, 230, .26); }
.tl__stop--key .tl__body { opacity: 1; }
.tl__stop--key:not(.on) .tl__inner { transform: translateY(20px); }
.tl__stop--key .tl__inner { transition: transform .6s cubic-bezier(.22, 1, .36, 1); }

@media (min-width: 860px) {
  /* no full bleed to fight the sticky column — a block with real depth */
  .tl__stop--key .tl__inner {
    margin-left: -2.6rem; margin-right: 0; border-radius: 20px;
    padding: clamp(2rem, 3vw, 2.8rem);
  }
  .tl__stop--key .tl__inner::before { border-radius: 20px 0 0 20px; }
}

/* the tap target: one line of copy with a plus that turns into a minus */
.tl__d summary {
  display: flex; align-items: center; gap: .9rem; cursor: pointer;
  list-style: none; padding: .1rem 0; border-radius: 10px;
  -webkit-tap-highlight-color: transparent;
}
.tl__d summary::-webkit-details-marker { display: none; }
.tl__d summary:focus-visible { outline: 2px solid var(--amber); outline-offset: 6px; }
.tl__lead { flex: 1; font-size: clamp(.92rem, 3.6vw, 1.02rem); line-height: 1.5; opacity: .74; }
.tl__plus {
  position: relative; flex: none; width: 30px; height: 30px; border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--ink) 22%, transparent);
  transition: transform .4s var(--spring), border-color .3s, background .3s;
}
.tl__plus::before, .tl__plus::after {
  content: ""; position: absolute; inset: 0; margin: auto;
  width: 11px; height: 2px; border-radius: 2px; background: currentColor;
  transition: transform .4s var(--spring), opacity .3s;
}
.tl__plus::after { transform: rotate(90deg); }
.tl__d summary:hover .tl__plus { border-color: var(--amber); }
.tl__d[open] .tl__plus { transform: rotate(180deg); background: var(--amber); border-color: var(--amber); color: var(--cream); }
.tl__d[open] .tl__plus::after { transform: rotate(90deg) scaleX(0); opacity: 0; }

/* The browser collapses <details> through ::details-content, so that is the
   box to animate — interpolate-size lets it travel to and from auto. Where
   that is unsupported the panel simply snaps open, and the contents still
   fade up, so it never looks broken. */
@supports (interpolate-size: allow-keywords) {
  :root { interpolate-size: allow-keywords; }
  .tl__d::details-content {
    block-size: 0; overflow: hidden;
    transition: block-size .44s cubic-bezier(.22, 1, .36, 1),
                content-visibility .44s allow-discrete;
  }
  .tl__d[open]::details-content { block-size: auto; }
}
.tl__panel { overflow: hidden; }
.tl__panel > * { animation: panelIn .5s .08s var(--spring) both; }
@keyframes panelIn { from { opacity: 0; transform: translateY(10px) } to { opacity: 1; transform: none } }
.tl__panel p {
  padding-top: .9rem; font-size: clamp(.9rem, 3.5vw, 1rem); line-height: 1.62;
  opacity: .72; max-width: 44ch;
}

.tl__stats {
  display: flex; flex-wrap: wrap; gap: 1.2rem 1.8rem;
  margin-top: 1.1rem; padding: 0; list-style: none;
}
.tl__stats b {
  display: block; font-size: clamp(1.3rem, 5.2vw, 1.8rem); font-weight: 800;
  letter-spacing: -.045em; line-height: 1; color: var(--amber);
  font-variant-numeric: tabular-nums;
}
.tl__stats span { display: block; margin-top: .26rem; font-size: .67rem; letter-spacing: .05em; opacity: .6; }

.tl__tags { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: 1rem; padding: 0 0 .3rem; list-style: none; }
.tl__tags li {
  font-size: .67rem; letter-spacing: .04em; padding: .3rem .66rem; border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--ink) 16%, transparent); opacity: .7;
}

@media (min-width: 860px) {
  .tl { display: grid; grid-template-columns: minmax(0, 14rem) minmax(0, 1fr); gap: 3rem; }
  .tl__aside {
    position: sticky; top: 30vh; align-self: start; height: max-content;
    flex-direction: column; align-items: flex-start; gap: 1rem;
    padding: 0; background: none;
  }
  .tl__aside::after { display: none; }
  .tl__aside { align-items: flex-start; }
  .tl__ghost { display: block; font-size: clamp(4rem, 7vw, 6.5rem); }
  .tl__rail { width: 100%; flex: none; height: 3px; align-self: stretch; }
  .tl__panel p { max-width: 48ch; }
}

@media (prefers-reduced-motion: reduce) {
  .tl__ghost, .tl__panel > * { animation: none; }
  .tl__d::details-content { transition: none; }
  .tl__stop.now .tl__dot { animation: none; }
  .tl__body { opacity: 1; transform: none; }
}

.dots { display: flex; gap: .45rem; justify-content: center; margin-top: .6rem; }
.dots button {
  width: 7px; height: 7px; border-radius: 50%; padding: 0;
  background: currentColor; opacity: .22; transition: opacity .3s, transform .35s var(--spring);
}
.dots button.on { opacity: 1; transform: scale(1.6); }

/* ═══ GALLERY ════════════════════════════════════════════════════════ */
.gal {
  max-width: var(--maxw); margin: 0 auto;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(46%, 230px), 1fr));
  gap: clamp(.7rem, 2vw, 1.1rem);
}
.gal__item {
  display: flex; flex-direction: column; gap: .6rem; padding: 0; text-align: left;
  transition: transform .5s var(--ease);
}
.gal__item:hover { transform: translateY(-4px); }
.gal__thumb {
  display: block; position: relative; overflow: hidden; border-radius: 16px;
  aspect-ratio: 4 / 3; background: rgba(11, 13, 18, .08);
  border: 1px solid rgba(11, 13, 18, .1);
}
.gal__thumb img { width: 100%; height: 100%; object-fit: cover; transition: transform .8s var(--ease); }
.gal__item:hover .gal__thumb img { transform: scale(1.07); }
.gal__item[data-group="Architecture"] .gal__thumb img { object-position: 50% 62%; transform: scale(1.18); }
.gal__item[data-group="Architecture"]:hover .gal__thumb img { transform: scale(1.24); }
/* ═══ WORK ═══════════════════════════════════════════════════════════ */
/* Stacked rows rather than a swipeable deck: everything is visible at once, and
   each row's logo bounces in its own partition on the right. */
.wl { max-width: var(--maxw); margin: 0 auto; list-style: none; padding: 0; }
.wl__row {
  position: relative; overflow: hidden;
  border-top: 1px solid rgba(242, 238, 230, .16);
  padding: clamp(1.7rem, 4vw, 3rem) 0;
  transition: border-color .5s var(--ease), background-color .45s var(--ease);
}
.wl__row:last-child { border-bottom: 1px solid rgba(242, 238, 230, .16); }
.wl__top {
  position: relative; z-index: 1;
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 1rem 1.6rem; flex-wrap: wrap; margin-bottom: .7rem;
}
.wl__name {
  font-size: .72rem; letter-spacing: .18em; text-transform: uppercase;
  opacity: .55; font-weight: 600;
}
.wl__link { font-size: .78rem; opacity: .55; transition: opacity .3s; white-space: nowrap; }
.wl__link:hover { opacity: 1; }
.wl__title {
  position: relative; z-index: 1;
  font-size: clamp(1.5rem, 3.6vw, 2.5rem); letter-spacing: -.025em;
  line-height: 1.1; margin: 0 0 .8rem;
}
.wl__body { position: relative; z-index: 1; max-width: min(64ch, 64%); opacity: .78; line-height: 1.6; margin: 0; }
/* Each row keeps its logo bouncing inside its own partition, the way a DVD logo
   wanders a screen. Two linear alternating animations of different lengths give
   the path, so no JavaScript is needed. */
/* Nothing here moves on its own. The row is calm typography until you hover it or
   tab into it, and then its logo arrives. Motion that answers the reader rather
   than motion that runs regardless. The rounding is for LUMNHS alone, whose crest
   is an opaque tile where the other three are transparent. */
.wl__logo {
  position: absolute; right: clamp(1rem, 4vw, 3rem); top: 50%;
  width: clamp(56px, 7vw, 88px); height: clamp(56px, 7vw, 88px);
  display: grid; place-items: center;
  border-radius: 14px; overflow: hidden; pointer-events: none;
  opacity: 0; transform: translate(22px, -50%);
  transition: opacity .45s var(--ease), transform .45s var(--ease);
}
.wl__row:hover .wl__logo, .wl__row:focus-within .wl__logo {
  opacity: 1; transform: translate(0, -50%);
}
.wl__row:hover, .wl__row:focus-within { background-color: rgba(242, 238, 230, .03); }
.wl__logo img { width: 100%; height: 100%; object-fit: contain; display: block; }

/* No hover to give: show it once as the row arrives, then leave it alone. */
@media (hover: none) {
  .wl__row.in .wl__logo { opacity: 1; transform: translate(0, -50%); }
}

.wl__title { transition: transform .5s var(--ease); }

.wl__row:hover, .wl__row:focus-within { border-top-color: rgba(242, 238, 230, .42); }
.wl__row:hover .wl__title, .wl__row:focus-within .wl__title { transform: translateX(7px); }

.gal__cap { font-size: .76rem; opacity: .62; line-height: 1.4; transition: opacity .3s; }
.gal__item:hover .gal__cap { opacity: 1; }

/* The photographs run as two rows drifting opposite ways, no captions. Each row
   holds the same set twice, so translating exactly one group width loops with no
   seam. The trailing padding on a group makes that width include its own gap. */
.gal--marq { display: block; max-width: none; }
.marq {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
}
.marq + .marq { margin-top: clamp(.7rem, 2vw, 1.1rem); }
.marq__track { display: flex; width: max-content; animation: marq 72s linear infinite; }
.marq[data-dir="r"] .marq__track { animation-direction: reverse; }
.gal--marq:hover .marq__track,
.marq__track:focus-within { animation-play-state: paused; }
.marq__grp {
  display: flex; gap: clamp(.7rem, 2vw, 1.1rem);
  padding-right: clamp(.7rem, 2vw, 1.1rem);
}
.gal--marq .gal__item { flex: 0 0 auto; width: clamp(140px, 17vw, 220px); gap: 0; }
@keyframes marq { to { transform: translateX(-50%); } }

.gal__sub {
  max-width: var(--maxw); margin: clamp(2.2rem, 5vw, 3.6rem) auto .9rem;
  font-size: .74rem; letter-spacing: .18em; text-transform: uppercase; opacity: .5;
}

/* ═══ NOW ════════════════════════════════════════════════════════════ */
.sec--now { min-height: 92svh; display: flex; flex-direction: column; justify-content: center; }
.now__h { font-size: clamp(2.6rem, 12vw, 7.5rem); letter-spacing: -.055em; margin-bottom: 1.6rem; }
.now__p { max-width: 44ch; font-size: clamp(.95rem, 2vw, 1.15rem); opacity: .8; line-height: 1.55; }
.now__links { display: flex; flex-wrap: wrap; gap: .7rem; margin-top: 2.4rem; }
.pill {
  display: inline-flex; align-items: center; height: 3rem; padding: 0 1.5rem;
  border-radius: 999px; background: var(--night); color: var(--cream);
  font-weight: 800; font-size: .88rem;
  transition: transform .35s var(--spring), background .3s;
}
.pill:hover { transform: translateY(-3px); }
.pill--ghost { background: transparent; color: inherit; box-shadow: inset 0 0 0 1.5px currentColor; }

.foot {
  display: flex; align-items: center; gap: 1.2rem; flex-wrap: wrap;
  margin-top: clamp(3rem, 8vw, 5rem); padding-top: 1.6rem;
  border-top: 1px solid rgba(11, 13, 18, .18); font-size: .76rem; opacity: .7;
}
.foot img { width: 66px; height: auto; }

/* ═══ LIGHTBOX ═══════════════════════════════════════════════════════ */
.lb {
  border: 0; padding: 0; width: 100%; height: 100%; max-width: 100vw; max-height: 100vh;
  /* The gallery used to vanish behind an almost opaque sheet. Frosting it
     instead keeps the room you came from visible while you look at one photo. */
  background: rgba(11, 13, 18, .55); color: var(--cream);
  -webkit-backdrop-filter: blur(26px) saturate(1.4);
  backdrop-filter: blur(26px) saturate(1.4);
  align-items: center; justify-content: center; gap: .6rem;
}
.lb[open] { display: flex; }
.lb::backdrop { background: rgba(11, 13, 18, .55); }
.lb__fig { margin: 0; max-width: min(1200px, 90vw); display: flex; flex-direction: column; gap: .9rem; }
.lb__fig img { max-height: 78vh; width: auto; margin-inline: auto; border-radius: 10px; }
.lb__fig figcaption { text-align: center; font-size: .84rem; opacity: .7; }
.lb__x { position: absolute; top: 1rem; right: 1.2rem; font-size: 1.6rem; opacity: .7; padding: .5rem; }
.lb__nav { font-size: 2.6rem; opacity: .5; padding: .4rem 1rem; line-height: 1; }
.lb__x:hover, .lb__nav:hover { opacity: 1; }

/* ═══ REVEALS ════════════════════════════════════════════════════════ */
.rv { opacity: 0; transform: translateY(28px); }
.rv.in {
  opacity: 1; transform: none;
  transition: opacity .8s var(--ease) calc(var(--i, 0) * 70ms),
              transform .8s var(--ease) calc(var(--i, 0) * 70ms);
}

/* ═══ RESPONSIVE ═════════════════════════════════════════════════════ */
@media (max-width: 900px) {
  .hero__photo { width: 100%; opacity: .22;
    -webkit-mask-image: linear-gradient(180deg, transparent, #000 55%);
    mask-image: linear-gradient(180deg, transparent, #000 55%); }
  .sec--hero { min-height: 100svh; }
  .card { flex-basis: 84vw; }
  .gal { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .big-type .ln > span { transform: none; }
  .hero__mark, .hero__sub, .hero__meta { opacity: 1; }
  .statement .w { opacity: 1; }
  .rv { opacity: 1; transform: none; }
  .deck { scroll-snap-type: none; }
  .marq__track { animation: none !important; }
  .marq { overflow-x: auto; }
  /* No slide for anyone who asked for less motion; it simply appears. */
  .wl__logo { transform: translateY(-50%); }
}

/* The float sits over every section in turn, so it inverts to stay legible —
   amber on the dark sections, near-black on the cream and amber ones. */
:root[data-theme="light"] .cc-float {
  background: var(--night); color: var(--cream);
  box-shadow: 0 8px 30px -10px rgba(11, 13, 18, .7);
}
:root[data-theme="light"] .cc-float .dot { background: var(--ember); }
:root[data-theme="light"] .rail-top { background: var(--night); }

/* Where the browser cannot frost, a translucent tint is just a washed out
   panel, so hand these back the solid fills they used to have. */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .lb { background: rgba(11, 13, 18, .97); }
  body:not(.doc)::before { background: rgba(242, 238, 230, .2); }
}

/* ─── CV PAGE ───────────────────────────────────────────────────────── */
/* A document, not an experience — quiet, high contrast, easy to scan. */
.doc { background: var(--night); color: var(--cream); }
.cv { max-width: 60rem; margin: 0 auto; padding: 6rem var(--pad) 3rem; }
.cv__home { position: fixed; top: 1.2rem; left: 1.2rem; z-index: 55; opacity: .8; transition: opacity .3s, transform .4s var(--spring); }
.cv__home:hover { opacity: 1; transform: rotate(-12deg) scale(1.08); }
.cv__home img { width: 34px; height: 34px; }
.cv__head { padding-bottom: 2.2rem; border-bottom: 1px solid rgba(242,238,230,.16); margin-bottom: 2.4rem; }
.cv__head h1 { font-size: clamp(2rem, 6vw, 3.4rem); margin-bottom: .8rem; }
.cv__role { opacity: .7; font-size: .95rem; margin-bottom: .9rem; }
.cv__meta { font-size: .84rem; opacity: .65; display: flex; flex-wrap: wrap; gap: .6rem; }
.cv__meta a:hover { color: var(--ember); }
.cv__back { margin-top: 1.3rem; font-size: .82rem; opacity: .6; }
.cv__back a:hover { color: var(--ember); }
.cv__back--end { margin-top: 3rem; padding-top: 2rem; border-top: 1px solid rgba(242,238,230,.16); }
.cv__sec { margin-bottom: 3.2rem; }
.cv__sec > h2 { font-size: .74rem; letter-spacing: .22em; text-transform: uppercase; color: var(--ember);
  margin-bottom: 1.5rem; padding-bottom: .7rem; border-bottom: 1px solid rgba(242,238,230,.14); }
.cv__intro { max-width: 46rem; }
.cv__intro p { font-size: .95rem; opacity: .75; line-height: 1.6; }
.cv__intro p + p { margin-top: 1rem; }
.role { display: grid; grid-template-columns: 11rem minmax(0,1fr); gap: .6rem 2rem; padding: 1.2rem 0; }
.role + .role { border-top: 1px solid rgba(242,238,230,.1); }
.role__when { font-size: .78rem; opacity: .55; padding-top: .25rem; }
.role__what h3 { font-size: 1.06rem; margin-bottom: .25rem; }
.role__pt { font-weight: 500; font-size: .72rem; opacity: .6; letter-spacing: 0; }
.role__org { font-size: .86rem; color: var(--ember); margin-bottom: .7rem; opacity: .9; }
.role__what ul { margin: 0; padding-left: 1.1rem; }
.role__what li { font-size: .88rem; opacity: .7; margin-bottom: .4rem; line-height: 1.55; }
.cv__cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px,1fr)); gap: 2rem 2.4rem; }
.cv__sub { font-size: .76rem; letter-spacing: .12em; text-transform: uppercase; opacity: .55; margin-bottom: .9rem; }
.cv__list { list-style: none; margin: 0; padding: 0; }
.cv__list li { font-size: .86rem; opacity: .75; margin-bottom: .8rem; line-height: 1.5; }
.cv__list b { font-weight: 700; opacity: 1; }
.cv__list i { font-style: normal; opacity: .55; font-size: .78rem; display: block; }
.years { list-style: none; margin: 0; padding: 0; }
.years li { display: flex; gap: 1.4rem; padding: .8rem 0; border-top: 1px solid rgba(242,238,230,.1); align-items: baseline; }
.years li:first-child { border-top: 0; }
.years b { font-size: .84rem; color: var(--ember); min-width: 3rem; }
.years span { font-size: 1rem; font-weight: 700; }
@media (max-width: 760px) { .role { grid-template-columns: 1fr; gap: .3rem; } .role__when { padding-top: 0; } }

/* ═══ THE GATE ═══════════════════════════════════════════════════════
   Two numbers stand between a visitor and the site. The screen says nothing
   about what it wants: if you know Htut, you know, and if you do not, the
   slash is the only clue you get.

   `gated` is written into the HTML by hand and only ever removed by script,
   so with JavaScript switched off the site stays shut rather than falling
   open. Content is hidden with visibility rather than display, because
   main.js measures every section on its way up and would read a collapsed
   page as a page of zero height. */
/* scrollbar-gutter keeps the gated page exactly as wide as the open one, so
   nothing shifts sideways at the moment the door lifts. */
html.gated { overflow: hidden; overscroll-behavior: none; scrollbar-gutter: stable; }
html.gated body > *:not(.gate) { visibility: hidden; }
html.gated .ldr { display: none; }
/* The second :not() matters. Without it, `gated` coming off would hide the door
   instantly and the lift below would never get a frame to play in. */
html:not(.gated):not(.gate-open) .gate { display: none; }

.gate {
  position: fixed; inset: 0; z-index: 1000; overflow: hidden;
  display: grid; align-content: center; justify-items: center;
  gap: clamp(1rem, 3vw, 1.5rem);
  /* biased above centre: on a phone the keyboard takes the bottom of the screen
     the moment a box is tapped, and a fixed overlay does not shrink for it */
  padding: var(--pad) var(--pad) clamp(6rem, 22vh, 13rem);
  background: var(--deep);
}
/* the CV runs on its own near-black, and its theme-color meta says so */
.doc .gate { background: var(--night); }
/* Glass needs something behind it or it is just a grey box. The site is not
   available to stand in, so the gate brings its own weather. */
.gate::before, .gate::after {
  content: ""; position: absolute; border-radius: 50%; pointer-events: none;
  filter: blur(70px); opacity: .55;
}
.gate::before {
  width: 46vmax; height: 46vmax; top: -14vmax; left: -10vmax;
  background: radial-gradient(circle, var(--amber), transparent 70%);
}
.gate::after {
  width: 40vmax; height: 40vmax; bottom: -16vmax; right: -8vmax;
  background: radial-gradient(circle, var(--sky), transparent 70%);
}

.gate__panel {
  position: relative; z-index: 1;
  display: flex; align-items: center; gap: clamp(.5rem, 2vw, .9rem);
  padding: clamp(1.6rem, 5vw, 2.6rem) clamp(1.4rem, 5vw, 2.8rem);
  border-radius: 22px;
  background: rgba(242, 238, 230, .09);
  -webkit-backdrop-filter: blur(24px) saturate(1.6);
  backdrop-filter: blur(24px) saturate(1.6);
  border: 1px solid rgba(242, 238, 230, .18);
  box-shadow: 0 30px 80px -30px rgba(0, 0, 0, .75),
              inset 0 1px 0 rgba(255, 255, 255, .2);
}
.gate__in {
  width: clamp(64px, 16vw, 92px); height: clamp(76px, 18vw, 108px);
  border: 1px solid rgba(242, 238, 230, .22); border-radius: 14px;
  background: rgba(11, 13, 18, .22); color: var(--cream);
  /* never below 16px, or iOS zooms the page the moment it is focused */
  font-size: clamp(2rem, 7vw, 2.8rem); font-weight: 800; letter-spacing: -.04em;
  font-variant-numeric: tabular-nums; text-align: center;
  padding: 0; -webkit-appearance: none; appearance: none;
  transition: border-color .3s var(--ease), background-color .3s var(--ease);
}
.gate__in::-webkit-outer-spin-button, .gate__in::-webkit-inner-spin-button {
  -webkit-appearance: none; margin: 0;
}
.gate__in:focus { outline: none; border-color: rgba(242, 238, 230, .6); background: rgba(11, 13, 18, .34); }
.gate__slash {
  font-size: clamp(1.8rem, 6vw, 2.6rem); font-weight: 300;
  opacity: .4; user-select: none; line-height: 1;
}

/* Wrong. A shake and a colour carry it for most people, but a shake is nothing
   to anyone who asked for less motion and nothing at all to a screen reader, so
   two words carry it for them. "Try again" explains no part of the question. */
.gate__say {
  position: relative; z-index: 1; min-height: 1.4em;
  font-size: .72rem; letter-spacing: .22em; text-transform: uppercase;
  font-weight: 700; opacity: 0; transition: opacity .3s var(--ease);
}
.gate__say.on { opacity: .6; }
.gate.is-wrong .gate__in { border-color: rgba(255, 138, 61, .85); }
.gate.is-wrong .gate__panel { animation: gateNo .4s var(--ease); }
@keyframes gateNo {
  10%, 90% { transform: translateX(-3px); }
  30%, 70% { transform: translateX(6px); }
  50%      { transform: translateX(-6px); }
}

html.gate-open .gate {
  opacity: 0; transform: scale(1.06); pointer-events: none;
  transition: opacity .55s var(--ease), transform .7s var(--ease);
}

@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .gate__panel { background: rgba(11, 13, 18, .55); }
}

@media (prefers-reduced-motion: reduce) {
  .gate.is-wrong .gate__panel { animation: none; }
  .gate::before, .gate::after { filter: blur(70px); }
}
