/* Apotek (Process Type) via Adobe Fonts web project — desktop-synced fonts are invisible to browsers.
   Mattone stays as fallback until the kit loads. */
@import url("https://use.typekit.net/phb2zzx.css");

/* Mattone — © Nunzio Mazzaferro & Collletttivo, SIL Open Font License (self-hosting OK) */
@font-face { font-family: Mattone; src: url(/fonts/Mattone-400.woff2) format("woff2"); font-weight: 400; font-display: swap; }
@font-face { font-family: Mattone; src: url(/fonts/Mattone-700.woff2) format("woff2"); font-weight: 700; font-display: swap; }
@font-face { font-family: Mattone; src: url(/fonts/Mattone-900.woff2) format("woff2"); font-weight: 800; font-display: swap; }

/* v2: Caldera layout system (pill nav, rounded cards, display headline, dotted dividers)
   in OWELV colours and type. Blue is the single accent, like Ember in the reference.

   SYSTEM — every size below comes from these tokens; don't add raw numbers.
   Space: 8px steps (s-1…s-7). Grid: 4 / 8 / 12 columns, 16px gutter, max 1280px.
   Type: 7 steps (display…label). Radius: outer = inner + padding (card 36 = media 20 + inset 16).
   Media ratios: 16:9 (default), 21:9 (featured), 3:4 (poster), 1:1, or the asset's own. */
:root {
  --blue: #2855ff;
  --light: #e1e3e8;   /* canvas */
  --paper: #f4f3ef;   /* card surface */
  --gray: #a8a8a5;
  --hover: #cbd2eb;   /* tags + hover wash */
  --dots: 1px solid var(--blue);
  --font: apotek, Mattone, sans-serif;

  /* Space */
  --s-1: 4px;
  --s-2: 8px;
  --s-3: 16px;
  --s-4: 24px;
  --s-5: 40px;
  --s-6: 56px;
  --s-7: 80px;

  /* Grid (mobile first; overridden at 640 / 1024px) */
  --max: 1280px;
  --cols: 4;
  --gutter: var(--s-3);
  --margin: var(--s-3);
  --content: min(100% - 2 * var(--margin), var(--max));
  --section: var(--s-5);       /* 40 phones, 56 from 640px, 80 from 1024px */
  --label-gap: var(--s-3);     /* label → its content: 16 phones, 24 from 640px */
  --pad: var(--s-4);           /* card padding */

  /* Type: size / line-height / tracking */
  --t-display: clamp(56px, 11vw, 168px);
  --t-h1: clamp(40px, 7.5vw, 96px);
  --t-h2: clamp(32px, 4.4vw, 56px);
  --t-h3: clamp(24px, 2.8vw, 36px);
  --t-lead: clamp(19px, 1.9vw, 24px);
  --t-body: 17px;
  --t-label: 13px;

  /* Shape */
  --r-pill: 800px;
  --r-media: 20px;
  --inset: var(--s-3);                            /* card edge around a media card */
  --r-card: calc(var(--r-media) + var(--inset));  /* 36: outer = inner + inset keeps nested corners concentric */
  --nav-h: 56px;
  --top: calc(var(--nav-h) + 2 * var(--s-3));   /* content starts below the fixed nav */
  --ctl: 40px;                                   /* control / button height */
}
@media (min-width: 640px) {
  :root { --cols: 8; --margin: var(--s-4); --section: var(--s-6); --label-gap: var(--s-4); }
}
@media (min-width: 1024px) {
  :root { --cols: 12; --margin: var(--s-5); --section: var(--s-7); --pad: var(--s-5); }
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { background: var(--light); scroll-behavior: smooth; scroll-padding-top: var(--top); -webkit-tap-highlight-color: transparent; } /* no blue tap box on Android Chrome; keyboard focus rings stay */
body {
  font-family: var(--font);
  font-size: var(--t-body); line-height: 1.5; font-weight: 500;
  color: var(--blue);
  background: var(--light);
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
button { font: inherit; }
ul { list-style: none; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* ---------- Grid + type primitives ---------- */
.wrap, .showreel, .contact, .project, .nav { width: var(--content); margin-inline: auto; }
/* minmax(0, 1fr), not 1fr: Safari keeps a media card's old min-content width (aspect-ratio box
   + video) after a window resize, so with 1fr the cards stay enlarged. */
.grid { display: grid; grid-template-columns: repeat(var(--cols), minmax(0, 1fr)); gap: var(--gutter); }

.display, .project-title, .contact .word { font-size: var(--t-display); line-height: 0.86; font-weight: 800; letter-spacing: -0.02em; text-transform: uppercase; }
.next h2, .next .arrow { font-size: var(--t-h1); line-height: 0.9; font-weight: 800; letter-spacing: -0.02em; text-transform: uppercase; }
.contact-top h2 { font-size: var(--t-h2); line-height: 0.95; font-weight: 800; letter-spacing: -0.01em; text-transform: uppercase; }
.work-info h2, .index-row h2 { font-size: var(--t-h3); line-height: 1; font-weight: 800; letter-spacing: -0.01em; text-transform: uppercase; }
@media (max-width: 639px) { .work-info h2, .index-row h2 { font-size: clamp(18px, 5.6vw, 20px); } } /* phones: 20px, easing to 18px under 360px so one-word titles (Ampersand) clear the year */
.lead, .about-text, .intro-sub { font-size: var(--t-lead); line-height: 1.3; }
.label, .section-head, .project-meta, .tag, .index-tags, .hero-cap, .btn, .nav nav, .nav-back, .year, .place {
  font-size: var(--t-label); line-height: 1.2; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
}
/* section labels (Featured Projects, Index, About, Capabilities, Challenge/Solution, Next project) read bigger and lighter */
.section-head, .label:not(.tweak) { font-size: var(--t-body); font-weight: 500; }

/* ---------- Pill nav ---------- */
/* --glass: 0 = solid paper, 1 = glass. site.js eases it with scroll over the first 64px, so the nav melts into
   the glass instead of switching. The glass layers are always on and fade in with it.
   Glass = CSS port of @ybouane/liquidglass "Frosted" minus the WebGL edge refraction Safari can't do: light blur,
   +6% brightening, top-weighted 1.5px inner stroke, edge glow, and the 0.3 / 10px / +1px drop shadow. */
.nav {
  --glass: 0;
  position: fixed; top: var(--s-3); left: 0; right: 0; z-index: 10;
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-3);
  height: var(--nav-h); padding: 0 var(--s-2) 0 var(--s-4);
  border-radius: var(--r-pill);
  color: color-mix(in srgb, #fff calc(var(--glass) * var(--ink, 0) * 100%), var(--blue)); /* white over video/blue (--ink), blue over light; CONTACT keeps its own */
}
/* Shared liquid glass: the nav fades into it with --glass; the showreel caption, video buttons and seek bar sit on video, so always 1.
   Chromium adds the edge refraction per element (site.js liquid()). */
.hero-cap, .controls button, .seek { --glass: 1; }
.nav, .hero-cap, .controls button, .seek {
  background-color: rgba(244, 243, 239, calc(1 - var(--glass)));
  background-image: linear-gradient(rgba(255, 255, 255, calc(var(--glass-a, 0) * var(--glass))) 0 0);
  -webkit-backdrop-filter: blur(3px) brightness(1.06); backdrop-filter: blur(3px) brightness(1.06);
  box-shadow:
    inset 0 1.5px 0 rgba(255, 255, 255, calc(0.55 * var(--glass))), inset 0 -1px 0 rgba(255, 255, 255, calc(0.22 * var(--glass))),
    inset 0 0 6px rgba(255, 255, 255, calc(0.3 * var(--glass))),
    0 1px 10px rgba(0, 0, 0, calc(0.2 * var(--glass))), 0 1px 2px rgba(0, 0, 0, calc(0.1 * var(--glass)));
}
.nav .logo { font-size: var(--t-h3); line-height: 1; font-weight: 800; letter-spacing: -0.02em; }
.nav nav { display: flex; align-items: center; gap: var(--s-1); }
.nav nav { --link-pad: calc(var(--s-2) + var(--s-1)); } /* 12px on phones so CONTACT fits at 360px; 16px from 640px */
.nav nav a { display: flex; align-items: center; height: var(--ctl); padding: 0 var(--link-pad); border-radius: var(--r-pill); transition: background-color 0.2s; }
.nav nav a:hover { background: color-mix(in srgb, rgba(255, 255, 255, 0.2) calc(var(--glass) * var(--ink, 0) * 100%), var(--hover)); }
.btn {
  display: inline-flex; align-items: center; gap: var(--s-2);
  height: var(--ctl); padding: 0 var(--s-4); border-radius: var(--r-pill);
  background: var(--blue); color: var(--paper);
  transition: opacity 0.2s;
}
.btn:hover { opacity: 0.85; }
.btn.ghost { background: transparent; color: inherit; box-shadow: inset 0 0 0 1.5px currentColor; }
.nav nav .btn { padding: 0 var(--link-pad); } /* same side padding as WORK/ABOUT, so all three labels sit the same distance apart */
.nav nav .btn:hover { background: var(--blue); }
/* Project pages: BACK on the left; the negative margin puts its pill as close to the edge as CONTACT is on the right */
.nav-back { display: flex; align-items: center; gap: var(--s-1); height: var(--ctl); margin-left: calc(var(--s-2) - var(--s-4)); padding: 0 var(--s-3) 0 var(--s-2); border-radius: var(--r-pill); transition: background-color 0.2s; }
.nav-back:hover { background: color-mix(in srgb, rgba(255, 255, 255, 0.2) calc(var(--glass) * var(--ink, 0) * 100%), var(--hover)); }
.nav-back svg { flex: none; width: 1.2em; height: 1.2em; stroke: currentColor; stroke-width: 2.6; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.nav-back + .logo { margin-right: auto; } /* keep the logo left instead of centred by space-between */
@media (max-width: 479px) { .nav-back span { display: none; } .nav-back { padding: 0 var(--s-2); } .nav:has(.nav-back) { gap: var(--s-1); } } /* arrow only + tighter gaps, so CONTACT still fits at 360px */

/* ---------- Media ---------- */
.media { position: relative; overflow: hidden; background-color: #000; aspect-ratio: var(--ar, 16 / 9); cursor: zoom-in; border-radius: var(--r-media); }
.media > video, .media > img { display: block; width: 100%; height: 100%; object-fit: cover; }
.media.contain > video, .media.contain > img { object-fit: contain; }
.media > video, .media > img { transition: opacity 0.4s ease; }
img.pending { opacity: 0; } /* site.js: until the image arrives */
/* Poster cover over a clip until it can play without stalling (site.js sets --poster and .cold on the box). Above the clip even
   when the clip is transformed (z 1); the play/mute buttons and caption sit above it (z 2). */
.media::before, .thumb::before {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: var(--poster) center / cover no-repeat; background-color: inherit; opacity: 0; transition: opacity 0.4s ease;
}
.media.contain::before, .thumb.fit-contain::before { background-size: contain; }
.cold::before { opacity: 1; }
video::-webkit-media-controls-start-playback-button { display: none !important; -webkit-appearance: none; } /* iOS: no play glyph over the poster when autoplay is blocked */
.media.hero { background-color: #171717; }

/* Squircle corners: Figma-style corner smoothing (60%, iOS) as a 9-slice mask of one SVG
   (assets/squircle.svg, made by tools/squircle.py). The 45° cut equals a plain radius R, so it reads as
   round as a circle and nests exactly (outer = inner + padding), but eases into the edges over 1.6R.
   Slice width = R * 49/30 (file: R 30, slice 49). border-radius is the fallback (Firefox) and is
   zeroed at the end of this file where the mask works. */
.media, .thumb, .hero-reel, .work-card, .card, .contact, .cols, .next {
  --r: var(--r-card);
  -webkit-mask-box-image: url(/assets/squircle.svg) 49 fill / calc(var(--r) * 49 / 30) stretch;
  mask-border: url(/assets/squircle.svg) 49 fill / calc(var(--r) * 49 / 30) stretch;
}
.media, .thumb { --r: var(--r-media); }

.controls { position: absolute; z-index: 2; right: var(--s-3); bottom: var(--s-3); display: flex; gap: var(--s-2); }
.controls button {
  display: flex; align-items: center; justify-content: center;
  width: var(--ctl); height: var(--ctl); color: #fff; cursor: pointer; border: 0; border-radius: 50%;
}

/* ---------- Home: showreel hero ---------- */
.showreel { padding: var(--top) 0 var(--s-3); }
.hero-reel { aspect-ratio: 16 / 9; background-color: #171717; border-radius: var(--r-card); }
.hero-cap {
  position: absolute; z-index: 2; left: var(--s-3); bottom: var(--s-3);
  display: flex; align-items: center; height: var(--ctl); padding: 0 var(--s-3);
  color: var(--paper); border-radius: var(--r-pill);
}

.intro { padding: var(--s-6) 0 var(--section); }
.intro-sub { max-width: 30em; margin-top: var(--s-4); }
@media (max-width: 639px) { .intro { padding: var(--s-3) 0 var(--section); } .intro-sub { margin-top: var(--s-3); } } /* phones: title+sub read as one block (16 apart), Featured opens a new section (40) */

.section-head { display: flex; justify-content: space-between; margin-bottom: var(--label-gap); }

/* ---------- Work grid ---------- */
.work-card {
  grid-column: 1 / -1;
  display: flex; flex-direction: column; gap: var(--s-3); padding: var(--inset) var(--inset) var(--s-4);
  background: var(--paper); border-radius: var(--r-card); transition: background-color 0.25s, color 0.25s;
}
.thumb { position: relative; overflow: hidden; aspect-ratio: 16 / 9; background-color: #171717; border-radius: var(--r-media); }
.thumb video { display: block; width: 100%; height: 100%; object-fit: cover; transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.4s ease; }
.work-card.on .thumb video { transform: scale(1.03); }
.thumb.fit-contain { background-color: #000; } /* wide clips on black (Dieter Rams, 1234×300): show the whole frame, letterboxed */
.media:has(> .pending), .thumb:has(> .pending) { background-color: var(--paper); } /* loading: card colour everywhere; black/#171717 letterbox returns once the clip shows */
.thumb.fit-contain video { object-fit: contain; }
.work-info { display: grid; grid-template-columns: 1fr auto; align-items: baseline; gap: var(--s-2) var(--s-3); padding: 0 var(--s-2); }
.tags { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: var(--s-2); }
.tag { padding: var(--s-1) var(--s-2); border-radius: var(--r-pill); background: var(--light); }
.work-card.on .tag { background: rgba(244, 243, 239, 0.16); }


/* ---------- All Work index (/work/): plain list; rows go solid blue on hover like the cards ---------- */
.index { margin: 0; list-style: none; }
.index li { transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.3s, margin 0.3s; }
.index li.dim { opacity: 0.35; }
.index.scrolls { overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--blue) var(--hover); margin-inline: calc(-1 * var(--s-3)); padding-inline: var(--s-3); /* room for the rows' hover bleed inside the scroll box */ -webkit-mask-image: linear-gradient(#000 calc(100% - 64px), transparent); mask-image: linear-gradient(#000 calc(100% - 64px), transparent); }
/* Safari ignores scrollbar-color: same blue thumb on a hover-wash track, drawn with the WebKit pseudo-elements */
.index.scrolls::-webkit-scrollbar { width: 6px; }
.index.scrolls::-webkit-scrollbar-track { background: var(--hover); border-radius: 3px; }
.index.scrolls::-webkit-scrollbar-thumb { background: var(--blue); border-radius: 3px; }
.index.scrolls.end { -webkit-mask-image: none; mask-image: none; }
.index li.dim:hover { opacity: 1; }
.index li.first-dim { margin-top: var(--s-5); } /* gap between the matches and the rest */
.chips { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-bottom: var(--s-4); }
.chip {
  display: inline-flex; align-items: center; gap: var(--s-1); padding: var(--s-1) var(--s-2);
  border: 0; border-radius: var(--r-pill); background: var(--light); color: var(--blue); cursor: pointer;
  font: inherit; font-size: var(--t-label); line-height: 1.2; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  transition: background-color 0.2s, color 0.2s;
}
.chip span { opacity: 0.6; }
.chip:hover { background: var(--hover); }
.chip[aria-pressed="true"] { background: var(--blue); color: var(--paper); }
.index-row {
  display: grid; grid-template-columns: min(112px, 30vw) minmax(0, 1fr) auto; grid-template-areas: "thumb title year" "thumb tags tags"; /* thumb gives way on very narrow phones */
  align-items: center; gap: var(--s-1) var(--s-3);
  margin: var(--s-1) calc(-1 * var(--s-3)); padding: var(--s-3);
  border-radius: var(--r-media); transition: background-color 0.25s, color 0.25s;
}
.index-row .thumb { grid-area: thumb; --r: var(--s-2); border-radius: var(--s-2); }
.index-row h2 { grid-area: title; }
.index-row .year { grid-area: year; }
.index-tags { grid-area: tags; display: flex; flex-wrap: wrap; gap: 0 var(--s-3); color: var(--gray); transition: color 0.25s; }
.index-tags span { white-space: nowrap; } /* a tag wraps whole ("Poster Design"), never mid-name */
/* Mouse, any window width: no inline thumbs (hidden ones never lazy-load); the clip floats beside the cursor.
   Same query as `float` in site.js. Narrow windows stack the tags under the title; wide ones fit one line. */
@media (hover: hover) and (pointer: fine) {
  .index-row { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "title year" "tags tags"; }
  .index-row .thumb { display: none; }
}
@media (hover: hover) and (pointer: fine) and (min-width: 640px) {
  .index-row { grid-template-columns: minmax(min-content, 1fr) minmax(0, auto) 4em; grid-template-areas: "title tags year"; } /* title never narrower than its longest word; the tags wrap instead of sliding under it */
  .index-row .year { text-align: right; }
  .index-tags { justify-content: flex-end; } /* wrapped tags stay flush with the one-line rows */
}
/* Phones: no cursor AND a narrow screen (both, so a narrow laptop window or a touch laptop keeps them): rows drop the tags. */
@media (hover: none) and (pointer: coarse) and (max-width: 1023px) {
  .index-row { grid-template-areas: "thumb title year"; align-items: start; } /* title and year sit on the thumb's top edge */
  .index-tags { display: none; }
}
.index-preview {
  position: fixed; left: 0; top: 0; z-index: 9; width: clamp(200px, 24vw, 360px); pointer-events: none;
  opacity: 0; transform: scale(0.92); transition: opacity 0.2s, transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}
.index-preview.on { opacity: 1; transform: none; }

/* ---------- About ---------- */
.about { margin-top: var(--section); }
.about > * { grid-column: 1 / -1; }
.card { padding: var(--pad); background: var(--paper); border-radius: var(--r-card); }
.card .label { margin-bottom: var(--label-gap); }
.card-blue { position: relative; overflow: hidden; background: var(--blue); color: var(--paper); }
.card-blue > * { position: relative; }
/* Halftone: the reference's signature motif, in paper-on-blue, fading to solid. Also the hover state of the clickable cards. */
.halftone::before, .work-card::before, .next::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(circle, rgba(244, 243, 239, 0.28) 1.3px, transparent 1.8px) 0 0 / var(--s-2) var(--s-2);
  -webkit-mask-image: linear-gradient(200deg, #000, transparent 65%); mask-image: linear-gradient(200deg, #000, transparent 65%);
}
.about-text { max-width: 26em; font-size: 19px; }
.about-text + .about-text { margin-top: 1em; }
.caps li { display: flex; justify-content: space-between; align-items: baseline; column-gap: var(--s-3); padding: var(--s-2) 0; }
.caps .tools { margin-left: auto; color: var(--gray); font-size: var(--t-body); text-align: right; }
@media (min-width: 640px) { .caps br { display: none; } } /* phones: break long names/tool lists instead of pushing the tools to a second row */

/* ---------- Contact footer (all pages) ---------- */
.contact {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; gap: var(--s-6);
  margin: var(--section) auto var(--s-3);
  padding: var(--pad); background: var(--blue); color: var(--paper); border-radius: var(--r-card);
}
.contact > * { position: relative; } /* above the dot-wave canvas */
.contact-top, .contact-bottom { display: flex; flex-direction: column; align-items: flex-start; gap: var(--s-4); }
.contact-top h2 { max-width: 12em; }
.contact-links { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.contact .btn { background: var(--paper); color: var(--blue); }
.contact .btn.ghost { background: transparent; color: var(--paper); }
.contact .word { font-size: var(--word-size, var(--t-h1)); white-space: nowrap; text-transform: none; line-height: 1; /* --word-size: 수정 모드 slider only; lh 1 leaves room for the j and @ */ letter-spacing: -0.03em; margin-left: -0.03em; }
.contact .place { flex: none; }
.ig { width: var(--s-3); height: var(--s-3); fill: currentColor; flex: none; }

/* ---------- Project page ---------- */
.project { display: flex; flex-direction: column; gap: var(--gutter); padding-top: var(--top); }
.project-meta { display: flex; flex-direction: column; gap: var(--s-2); margin-bottom: calc(var(--s-5) - var(--gutter)); } /* tags → first media = 40 */
.project-meta .tag { background: var(--paper); } /* --light is the canvas colour, so pills sit on paper here */
.project-title { margin: var(--s-4) 0 calc(var(--label-gap) - var(--gutter)); line-height: 0.82; } /* .project already gaps 16, so title → tags = --label-gap */
.project-title + .card { margin-top: calc(var(--s-5) - var(--label-gap)); } /* All Work: no tags, title → list = 40 */

.cols { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--s-4); padding: var(--pad); background: var(--paper); border-radius: var(--r-card); }
.cols .label { margin-bottom: var(--s-3); }
/* text card + a media tile beside it on one line */
.cols-side { display: grid; gap: var(--gutter); }
.cols-side > .media { aspect-ratio: 1; }

.row { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--gutter); }
.split { display: grid; grid-template-rows: 1fr 1fr; gap: var(--gutter); }
.split .media { aspect-ratio: auto; }

.ticker { overflow: hidden; cursor: grab; user-select: none; touch-action: pan-y; } /* site.js moves .ticker-track; vertical swipes still scroll the page */
.ticker-track { display: flex; gap: var(--gutter); width: max-content; will-change: transform; }
.ticker .media { flex: 0 0 200px; height: 200px; aspect-ratio: 1; }

/* Next project */
.next {
  display: flex; justify-content: space-between; align-items: flex-end; gap: var(--s-4);
  margin-top: var(--section); padding: var(--pad); background: var(--paper); border-radius: var(--r-card);
  transition: background-color 0.25s, color 0.25s;
}
/* Clickable cards on hover (or .on: the home card playing on phones): solid OWELV blue, white text, halftone fades in */
.work-card, .next { position: relative; }
.work-card > *, .next > * { position: relative; }
.work-card::before, .next::before { opacity: 0; transition: opacity 0.25s; }
.work-card.on { background: var(--blue); color: var(--paper); }
.work-card.on::before { opacity: 1; }
/* JS dot wave (site.js) replaces the static dots; kept after the `> *` rules so its absolute position wins */
.live::before { content: none; }
.live > canvas { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.work-card > canvas, .next > canvas { opacity: 0; transition: opacity 0.25s; }
.work-card.on > canvas { opacity: 1; }
.next .label { margin-bottom: var(--label-gap); }
.next .arrow { flex: none; width: 1em; height: 1em; transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1); } /* the custom cursor's arrow, turned to point down-right */
/* Blue hover states only for a real pointer: on touch screens a tap leaves :hover stuck on the tapped card. */
@media (hover: hover) {
  .work-card:hover .thumb video { transform: scale(1.03); }
  .work-card:hover .tag { background: rgba(244, 243, 239, 0.16); }
  .index-row:hover { background: var(--blue); color: var(--paper); }
  .index-row:hover .index-tags { color: rgba(244, 243, 239, 0.7); }
  .work-card:hover, .next:hover { background: var(--blue); color: var(--paper); }
  .work-card:hover::before, .next:hover::before { opacity: 1; }
  .work-card:hover > canvas, .next:hover > canvas { opacity: 1; }
  .next:hover .arrow { transform: translate(4px, 4px); } /* nudges toward where it points (Next Project + All Work cards) */
}
/* Home: the Next Project card (paper, blue + dot wave on hover) closing the grid as the way to /work/ */
.all-work { margin-top: var(--gutter); }
.project .contact { width: 100%; margin-top: 0; }
.project .next { margin-top: calc(var(--section) - var(--gutter)); } /* lands exactly on --section after the flex gap */

/* ---------- Tablet (8 cols) ---------- */
@media (min-width: 640px) {
  .nav nav { --link-pad: var(--s-3); }
  .project-meta { flex-direction: row; justify-content: space-between; align-items: center; }
  .contact-bottom { flex-flow: row wrap; justify-content: space-between; align-items: flex-end; } /* place drops below the wordmark when it doesn't fit */
  /* Rows go 2-up; an odd last item (3-item rows) spans the full width */
  .row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .row > :last-child:nth-child(odd) { grid-column: 1 / -1; }
  .ticker .media { flex-basis: 320px; height: 320px; }
}

/* ---------- Desktop (12 cols) ---------- */
@media (min-width: 1024px) {
  .hero-reel { aspect-ratio: auto; height: calc(100svh - var(--top) - var(--s-3)); max-height: calc(var(--max) * 9 / 16); }
  .work-card { grid-column: span 6; }
  .contact-top { flex-direction: row; justify-content: space-between; }
  .cols { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--s-5); }
  .cols-side { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  .cols-side > .cols { grid-column: span 10; grid-template-columns: minmax(0, 1fr); } /* stacked text sets the row height */
  .cols-side > .media { grid-column: span 2; aspect-ratio: auto; }
  .cols-side > .media > img { position: absolute; inset: 0; } /* fills the card height, never drives it */
  .row { grid-template-columns: repeat(var(--n, 2), minmax(0, 1fr)); }
  .row > :last-child:nth-child(odd) { grid-column: auto; }
}
/* About side by side only once the 5-col Capabilities card fits its longest row (name + tools) on one line;
   below this it stays stacked like tablet. */
@media (min-width: 1152px) {
  .about > :first-child { grid-column: span 7; }
  .about > :last-child { grid-column: span 5; }
}

/* Grid overlay: press G to check alignment (see site.js) */
.grid-overlay {
  position: fixed; inset: 0 0 0 0; z-index: 2147483645; pointer-events: none;
  display: none; width: var(--content); margin-inline: auto;
}
.grid-overlay.on { display: grid; }
/* T key: nav glass tweak panel */
.tweak { position: fixed; right: var(--s-3); bottom: var(--s-3); z-index: 2147483647; /* above the media viewer so its colour can be tuned live */ display: none; gap: var(--s-3); width: 260px; padding: var(--s-3); background: #111; color: #fff; border-radius: var(--s-3); }
.tweak.on { display: grid; }
.tweak label { display: grid; grid-template-columns: 1fr auto; gap: var(--s-1); }
.tweak input { grid-column: 1 / -1; accent-color: var(--blue); }
.tweak input[type=color] { width: 100%; height: var(--ctl); padding: 0; border: 0; background: none; cursor: pointer; }
.tweak .btn { height: var(--ctl); justify-content: center; }
.grid-overlay i { background: rgba(255, 0, 80, 0.08); border-inline: 1px solid rgba(255, 0, 80, 0.25); }
.grid-overlay i:nth-child(n + 5) { display: none; }
@media (min-width: 640px) { .grid-overlay i:nth-child(n + 5) { display: block; } .grid-overlay i:nth-child(n + 9) { display: none; } }
@media (min-width: 1024px) { .grid-overlay i:nth-child(n + 9) { display: block; } }

/* Appear on scroll (_lab/reveal.html "D+줄페이드"): progress follows the scroll and rewinds going back up.
   Cards rise 48px, text rises line by line, a project card's title then tags trail it.
   Browsers without view timelines get the one-time .reveal fade instead. */
.reveal { opacity: 0; transform: translateY(12px); transition: opacity 0.6s cubic-bezier(0.22, 1, 0.36, 1), transform 0.6s cubic-bezier(0.22, 1, 0.36, 1); }
.reveal.in { opacity: 1; transform: none; }
@keyframes rise { from { opacity: 0; transform: translateY(48px); } }
@keyframes rise-sm { from { opacity: 0; transform: translateY(20px); } }
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .rise { animation: rise linear both; animation-timeline: view(); animation-range: entry 0% cover 30%; }
    .lines .line { display: block; view-timeline-name: --line; }
    .lines .line > span { display: block; animation: rise linear both; animation-timeline: --line; animation-range: entry 0% cover 30%; }
    .rise-sm { animation: rise-sm linear both; animation-timeline: view(); animation-range: entry calc(var(--i, 0) * 8%) cover calc(25% + var(--i, 0) * 8%); }
  }
}

/* ---------- Lightbox ---------- */
.lightbox {
  position: fixed; inset: 0; z-index: 2147483646;
  display: grid; place-items: center;
  padding: max(var(--s-3), env(safe-area-inset-top)) var(--margin) max(var(--s-3), env(safe-area-inset-bottom));
  background: var(--viewer-bg, #010816); /* 수정 모드 panel can set --viewer-bg */
  opacity: 0; transition: opacity 180ms cubic-bezier(0.22, 1, 0.36, 1);
}
.lightbox.open { opacity: 1; }
/* Stage = × row, media, controls row. Its width is the media's: the grid content width (margin to margin, max 1280),
   or less when the height runs out — (viewport - padding - both rows) x aspect ratio (--ar from the media). */
.lightbox .stage {
  --rows: calc(2 * (var(--ctl) + var(--s-2)) + 2 * var(--s-3));
  display: grid; gap: var(--s-2);
  width: min(100%, var(--max), (100dvh - var(--rows)) * var(--ar, 16 / 9));
  transform: scale(0.985); transition: transform 220ms cubic-bezier(0.22, 1, 0.36, 1);
}
.lightbox.open .stage { transform: none; }
.lightbox .stage > video, .lightbox .stage > img { display: block; width: 100%; height: auto; border-radius: var(--r-media); }
.lightbox .close {
  justify-self: end; display: flex; align-items: center; justify-content: flex-end; /* icon's edge on the media's edge */
  width: var(--ctl); height: var(--ctl); padding: 0; border: 0; background: transparent; cursor: pointer; color: var(--blue);
}
.lightbox .controls { position: static; }
.lightbox .controls button { flex: none; }
/* Seek bar: 4px track with round ends (the cursor's stroke), white fill + knob; a transparent range input on top takes the input */
.seek { flex: 1; display: flex; align-items: center; gap: var(--s-3); height: var(--ctl); padding: 0 var(--s-3); border-radius: var(--r-pill); color: #fff; font-variant-numeric: tabular-nums; }
.seek .track { position: relative; flex: 1; height: 4px; border-radius: 2px; background: rgba(255, 255, 255, 0.3); }
.seek .track i { position: absolute; inset: 0; border-radius: inherit; background: #fff; transform: scaleX(var(--p, 0)); transform-origin: left; }
.seek .track::after { content: ""; position: absolute; top: 50%; left: calc(var(--p, 0) * 100%); width: 12px; height: 12px; margin: -6px 0 0 -6px; border-radius: 50%; background: #fff; pointer-events: none; }
.seek input { position: absolute; inset: -18px 0; width: 100%; height: auto; margin: 0; opacity: 0; cursor: pointer; }
.seek .track:has(input:focus-visible) { outline: 2px solid #fff; outline-offset: 8px; }

/* Custom cursor (fine pointers only) */
@media (pointer: fine) { html.has-cursor, html.has-cursor * { cursor: none !important; } }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; transition: none; }
  .thumb video { transition: none; }
}

/* Last so it beats the component rules: only the squircle mask clips where it's supported */
@supports (-webkit-mask-box-image: none) or (mask-border: none) {
  .media, .thumb, .hero-reel, .work-card, .card, .contact, .cols, .next { border-radius: 0; }
}
